Fractal Softworks Forum

Please login or register.

Login with username, password and session length
Pages: 1 ... 435 436 [437] 438 439 ... 709

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

DecoyGrenadeOut

  • Ensign
  • *
  • Posts: 21
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #6540 on: June 19, 2020, 03:48:36 AM »

Is it possible to make a mod that essentially notifies you when a given weapon group is able to all fire in game and/or display the ammo count of weapon in the group? I have quite some trouble timing weapons with long cool down (AM blaster) and strike weapon like AP lasers and it would be great if it's possible to have something like that in the game.
Logged

Yunru

  • Admiral
  • *****
  • Posts: 1560
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #6541 on: June 19, 2020, 05:04:26 AM »

So I'm at a loss trying to get Shared Flux to work on a individual ship basis.
I tried:
Code
package data.scripts;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.fs.starfarer.api.Global;
import com.fs.starfarer.api.combat.BaseHullMod;
import com.fs.starfarer.api.combat.CombatEngineAPI;
import com.fs.starfarer.api.combat.ShipAPI;
import com.fs.starfarer.api.combat.ShipAPI.HullSize;
import com.fs.starfarer.api.util.Misc;
import com.fs.starfarer.api.impl.hullmods.SharedFluxSink;

public class SharedShipFluxSink extends SharedFluxSink {

@Override
public void advanceInCombat(ShipAPI ship, float amount) {
super.advanceInCombat(ship, amount);

if (!ship.isAlive()) return;

CombatEngineAPI engine = Global.getCombatEngine();

String key = SINK_DATA_KEY + "_" + ship.getId();

FluxSinkData data = (FluxSinkData) engine.getCustomData().get(key);
if (data == null) {
data = new FluxSinkData();
engine.getCustomData().put(key, data);

for (ShipAPI module : ship.getChildModulesCopy()) {
if (module.getStationSlot() == null || !module.isAlive() || !Misc.isActiveModule(module)) continue;
float d = module.getMutableStats().getFluxDissipation().getModifiedValue();
d *= FLUX_FRACTION;
data.dissipation.put(module, d);
}
}
}
}
But then I get
Code
java.lang.RuntimeException: Error compiling [data.scripts.SharedShipFluxSink]
at com.fs.starfarer.loading.scripts.ScriptStore$3.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: File 'data/scripts/SharedShipFluxSink.java', Line 37, Column 26: Member with "/*default*/" access cannot be accessed from type "data.scripts.SharedShipFluxSink".
at org.codehaus.janino.JavaSourceClassLoader.generateBytecodes(JavaSourceClassLoader.java:226)
at org.codehaus.janino.JavaSourceClassLoader.findClass(JavaSourceClassLoader.java:178)
at java.lang.ClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 2 more

Morrokain

  • Admiral
  • *****
  • Posts: 2143
  • Megalith Dreadnought - Archean Order
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #6542 on: June 19, 2020, 03:07:08 PM »

Ok, so I implemented the interval (actually quite useful to prevent text popups from happening simultaneously when under the aura) and the map in the combat engines data to prevent persistence.

I wanted to do the same thing to the rotation Boolean in case I want to implement boss ships with this hullmod in the future so that nothing important will persist between the two entities.

But... IntelliJ is throwing a warning that the Boolean is "always false" or "always true" in this code: (And also says the initialization from  "(Boolean) combatEngine.getCustomData().get(rotatingKey);" is redundant in the last section)

Code
	private static void createAura(DreadAuraEffectOrigin aura, ShipAPI origin, CombatEngineAPI combatEngine, float amount) {
float radius;
        String rotatingKey = IS_ROTATING_KEY + "_" + origin.getId();
        Boolean isRotating = (Boolean) combatEngine.getCustomData().get(rotatingKey);
        if (isRotating == null) {
            isRotating = false;
            combatEngine.getCustomData().put(rotatingKey, isRotating);
        }
if (!isRotating) {
            radius = origin.getShieldRadiusEvenIfNoShield() * 1.5f + 50f;
            aura.sprite.setSize(radius, radius);
            aura.sprite.setAlphaMult(aura.alpha);
            aura.sprite.setAngle(aura.angle);
            aura.angle += 0.1f * amount;
            if (aura.angle > 10000f) {
                aura.angle -= 10000f;
            }
            isRotating = true;
            combatEngine.getCustomData().put(rotatingKey, isRotating);
            LOG.info("Aura created. Rotating logic engaged.");
        } else {
    aura.sprite.setAngle(aura.angle);
    aura.angle += 1;
        }
}

public final static class DreadAuraEffectOrigin {
public float alpha;
public float angle;
public boolean textPopupHappened;
public SpriteAPI sprite;

public DreadAuraEffectOrigin() {
alpha = 0f;
angle = 0f;
            textPopupHappened = false;
sprite = Global.getSettings().getSprite("misc", "dread_aura");
}

public void resetAura(CombatEngineAPI combatEngine, ShipAPI origin) {
            String rotatingKey = IS_ROTATING_KEY + "_" + origin.getId();
            Boolean isRotating = (Boolean) combatEngine.getCustomData().get(rotatingKey);
            isRotating = false;
            combatEngine.getCustomData().put(rotatingKey, isRotating);
sprite.setAlphaMult(0f);
alpha = 0f;
}
}

 -  is this IntelliJ getting confused because of the proprietary API? Or am I doing something wrong here and the Boolean is actually not getting updated in the map as intended? Sorry if this is obvious but just making sure.
Logged

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24103
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #6543 on: June 19, 2020, 03:29:50 PM »

Kind of need to know which lines it's showing which warnings for. That said, you've got:

Boolean isRotating = (Boolean) combatEngine.getCustomData().get(rotatingKey);
isRotating = false;

Which seems like leftover debug code or some such?
Logged

Morrokain

  • Admiral
  • *****
  • Posts: 2143
  • Megalith Dreadnought - Archean Order
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #6544 on: June 19, 2020, 04:16:30 PM »

Kind of need to know which lines it's showing which warnings for.

I'm probably just not understanding maps correctly to be honest.

From:
Code
        Boolean isRotating = (Boolean) combatEngine.getCustomData().get(rotatingKey);
        if (isRotating == null) {
            isRotating = false;
            combatEngine.getCustomData().put(rotatingKey, isRotating);
        }
The line for the warning "is always false":
Code
            combatEngine.getCustomData().put(rotatingKey, isRotating);

From:
Code
		if (!isRotating) {
            radius = origin.getShieldRadiusEvenIfNoShield() * 1.5f + 50f;
            aura.sprite.setSize(radius, radius);
            aura.sprite.setAlphaMult(aura.alpha);
            aura.sprite.setAngle(aura.angle);
            aura.angle += 0.1f * amount;
            if (aura.angle > 10000f) {
                aura.angle -= 10000f;
            }
            isRotating = true;
            combatEngine.getCustomData().put(rotatingKey, isRotating);
            LOG.info("Aura created. Rotating logic engaged.");
        } else {

The line for "is always true":
Code
            combatEngine.getCustomData().put(rotatingKey, isRotating);

-----------------------------------------------------------------------------------------------------------------------------
That said, you've got:

Boolean isRotating = (Boolean) combatEngine.getCustomData().get(rotatingKey);
isRotating = false;

Which seems like leftover debug code or some such?

Er, can you explain more? I'm not getting it, sorry. :( The idea here is that I initially check for the Boolean to be present in the data map (by the key). I chose Boolean since it can be null, and when it is null because the key doesn't exist in the map, I set it to false as a default and then (theoretically) re-add the Boolean to the map under the same key using:

Code
            combatEngine.getCustomData().put(rotatingKey, isRotating); // So it should be false now instead of null is the idea. I assume putting the same key into the map with a new value overrides it?

So, the next time         Boolean isRotating = (Boolean) combatEngine.getCustomData().get(rotatingKey); - is called it should return false instead of null. (createAura() runs under:    public void advanceInCombat(ShipAPI ship, float amount) so it should run every frame.)

After the Aura is created using:

Code
		if (!isRotating) {
            radius = origin.getShieldRadiusEvenIfNoShield() * 1.5f + 50f;
            aura.sprite.setSize(radius, radius);
            aura.sprite.setAlphaMult(aura.alpha);
            aura.sprite.setAngle(aura.angle);
            aura.angle += 0.1f * amount;
            if (aura.angle > 10000f) {
                aura.angle -= 10000f;
            }
            isRotating = true;
            combatEngine.getCustomData().put(rotatingKey, isRotating);
            LOG.info("Aura created. Rotating logic engaged.");

 -  the map is again overridden with a "true" instead of "false"

This way, the next frame "if (!isRotating)" will fail and so:

Code
        } else {
    aura.sprite.setAngle(aura.angle);
    aura.angle += 1;
        }

- will run instead. When the aura is "removed" the map should again set the value to "false" under the rotating key. See:

Code
		public void resetAura(CombatEngineAPI combatEngine, ShipAPI origin) {
            String rotatingKey = IS_ROTATING_KEY + "_" + origin.getId();
            Boolean isRotating = (Boolean) combatEngine.getCustomData().get(rotatingKey);
            isRotating = false;
            combatEngine.getCustomData().put(rotatingKey, isRotating);
sprite.setAlphaMult(0f);
alpha = 0f;
}

(Hope this makes sense lol! I'm probably not doing this the optimal way.  :-[ )
Logged

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24103
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #6545 on: June 19, 2020, 04:54:05 PM »

It's a bit of a strange warning - I mean, what it's saying is 100% correct, the variable IS going to always be true (or false) in the places where it warns that's the case, but I'm not sure *why* this merits a warning.

That said, code like this:
Boolean isRotating = (Boolean) combatEngine.getCustomData().get(rotatingKey);
isRotating = false;
combatEngine.getCustomData().put(rotatingKey, isRotating);

Why are you doing that instead of just:
combatEngine.getCustomData().put(rotatingKey, false);
Logged

Morrokain

  • Admiral
  • *****
  • Posts: 2143
  • Megalith Dreadnought - Archean Order
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #6546 on: June 19, 2020, 05:08:58 PM »

It's a bit of a strange warning - I mean, what it's saying is 100% correct, the variable IS going to always be true (or false) in the places where it warns that's the case, but I'm not sure *why* this merits a warning.

That said, code like this:
Boolean isRotating = (Boolean) combatEngine.getCustomData().get(rotatingKey);
isRotating = false;
combatEngine.getCustomData().put(rotatingKey, isRotating);

Why are you doing that instead of just:
combatEngine.getCustomData().put(rotatingKey, false);

My guess is that it doesn't understand that advanceInCombat() is actually run every frame? The warning is more of a "hey this isn't necessary" rather than a "this will cause problems" with possibly the assumption that if you were counting on the variable being changed it would alert you to the fact that it isn't. Usually this isn't shown if the IDE recognizes that the boolean is set somewhere else. (In this case in the next iteration of the EveryFrameScript.

As far as the second one, I just wasn't being efficient. Originally it stemmed from the idea of "if (!isRotating) {}" - being checked after  "Boolean isRotating = (Boolean) combatEngine.getCustomData().get(rotatingKey);" - where in the first iteration/frame "isRotating" could be null and throw an exception unless I explicitly set it to false - even though the map contains an actual boolean value.

But I can just change it to: "if (!(Boolean) combatEngine.getCustomData().get(rotatingKey)) {}" - so that it's guaranteed to not be null (since the earlier if statement would catch that and set the map correctly).
« Last Edit: June 19, 2020, 05:15:30 PM by Morrokain »
Logged

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24103
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #6547 on: June 19, 2020, 07:31:23 PM »

I think you might be operating under some misapprehension about how stuff works in Java. I mean in the resetAura() method, why not just set the map entry to false directly? Getting the value and storing it in a local variable and then changing that local variable isn't inefficient, it's more just completely unnecessary/pointless, if that makes sense.

What I mean is this:
public void resetAura(CombatEngineAPI combatEngine, ShipAPI origin) {
            String rotatingKey = IS_ROTATING_KEY + "_" + origin.getId();
            Boolean isRotating = (Boolean) combatEngine.getCustomData().get(rotatingKey);
            isRotating = false;
            combatEngine.getCustomData().put(rotatingKey, isRotating);
            sprite.setAlphaMult(0f);
            alpha = 0f;
}

Should just be:
public void resetAura(CombatEngineAPI combatEngine, ShipAPI origin) {
            combatEngine.getCustomData().put(rotatingKey, false);
            sprite.setAlphaMult(0f);
            alpha = 0f;
}

There's no functional difference. If you're thinking there is, that's the "misapprehension", so if you explain what you're thinking, I can hopefully clear it up. Edit: or do you just mean it was a copy-paste gone a bit bad? Just trying to clear it up!
Logged

Morrokain

  • Admiral
  • *****
  • Posts: 2143
  • Megalith Dreadnought - Archean Order
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #6548 on: June 19, 2020, 10:49:13 PM »

Edit: or do you just mean it was a copy-paste gone a bit bad? Just trying to clear it up!

This yeah. XD I was sort of copy pasting the concept from the ships data map- which requires the local object since the data map's value is a map itself.

That being said, even for a primitive if I needed to reassign the value from the data map multiple times without needing to add it back in the map, having a local variable is necessary so I might default to it anyway to be honest - especially if I'm unsure of the exact scope of the class at the start. Imo, it can also be "cleaner" from the perspective of read-ability to do things this way. Definitely not in this case, but you get the idea.

The IDE highlights all instances of variables when clicking on any one instance so that can be invaluable to me for times when the code gets complex. You can also do this with objects/object methods, sure, but if multiple objects of the same class use the same method for different values or the object is the same instance of the class but uses an individual method for different values, etc, it can get trickier/misleading to encompass a single value and its use in the code across the whole class using this technique. So that's another reason I would be tempted to go the local variable route anyway. At least initially. (My old team lead and a couple of teachers I had also hated anything hardcoded so I'm probably a little brainwashed by now too.)  :D

In the case of the rotation logic, though, once the local variable was just *sitting there* from the copy paste I was kind of "hardwired" to just use it lol. So I set up the if statement to check the local variable instead of realizing immediately that it would be the only instance of that engine data call in the actual logic. Read-ability doesn't matter there and so it makes much more sense to just skip the local variable all together for that use case and directly add it to the engine data - especially since each assignment requires an update to the data map anyway like you pointed out. (Unlike the ships data map.)

Still, after that first implementation I definitely went too "copy paste crazy" with it lol - which is sloppy. I tend to take an iterative approach to coding and likely would have caught it in the clean up phase. I actually already had it looking like your example before I saw this post due to your earlier comment and by catching the fact that I could directly call the value in the if statement - which made me go "oh this could be way cleaner than it is."

Basically, I make new code as efficient as I can while ensuring functionality and trying to think down the line of flexibility for use, then go back over it and think to myself "how can I scrape out anything unnecessary?" - which can sometimes even cause refactoring of the logic if I notice I can do something in a more efficient way that I didn't initially catch. For instance, if I feel a code block is too big and could be simplified with private helper methods, etc. That one in particular somewhat helps prevent the above use of instance highlighting from being as necessary so I usually don't regret it, hah. That's kind of how my thought process works if that makes sense. ;D

Anyway, thanks for taking the time you did to respond I always appreciate it.

Here's the updated code. (In a spoiler because this post is already huge.) Feel free to poke more holes if you see them as it really helps me learn! I also have a lot more to add to this class, so the more efficient it is the better!

Spoiler
Code
public class CHM_adamantine_consortium extends BaseHullMod {

private static final String ID = "CHM_adamantine_consortium";
private static final float MALFUNCTION_PROB = 0.05f;
private static final float CRIT_MALFUNCTION_PROB = 0.5f;

    public static String TEXT_POPUP_INTERVAL_KEY = "text_popup_interval_key";
public static String IS_ROTATING_KEY = "rotating_key";

// Logging components.
private static final Logger LOG = Global.getLogger(CHM_adamantine_consortium.class);

private static Map<HullSize, Float> mag = new HashMap<>();
static {
mag.put(HullSize.FRIGATE, 0.4f);
mag.put(HullSize.DESTROYER, 0.6f);
mag.put(HullSize.CRUISER, 0.8f);
mag.put(HullSize.CAPITAL_SHIP, 1f);
}

    public static class PeriodicTextPopupTracker {
        IntervalUtil interval = new IntervalUtil(8f, 12f);
    }

@Override
public void advanceInCombat(ShipAPI ship, float amount) {
CombatEngineAPI combatEngine = Global.getCombatEngine();
if (!combatEngine.getCustomData().containsKey(ID)) {
combatEngine.getCustomData().put(ID, new HashMap<>());
}
        String key = TEXT_POPUP_INTERVAL_KEY + "_" + ship.getId();
        PeriodicTextPopupTracker textTracker = (PeriodicTextPopupTracker) combatEngine.getCustomData().get(key);
        if (textTracker == null) {
            textTracker = new PeriodicTextPopupTracker();
            combatEngine.getCustomData().put(key, textTracker);
        }
        textTracker.interval.advance(amount);
try {
Map<ShipAPI, DreadAuraEffectOrigin> ships = (Map) combatEngine.getCustomData().get(ID);
            for (ShipAPI enemy : CombatExtensionsKt.getNearbyEnemies(ship, 1500f)) {
                if (!enemy.isDrone() && !enemy.isFighter() && enemy.isAlive()) {
                    DreadAuraEffectOrigin aura = ships.get(enemy);
                    if (aura == null) {
                        aura = new DreadAuraEffectOrigin();
                        ships.put(enemy, aura);
                        LOG.info("Adding ship: " + enemy.getName() + " to ships map.");
                    }
                    MutableShipStatsAPI stats = enemy.getMutableStats();
                    float effect = stats.getDynamic().getValue(Stats.DMOD_EFFECT_MULT);
                    stats.getWeaponMalfunctionChance().modifyFlat(ID, MALFUNCTION_PROB * effect);
                    stats.getCriticalMalfunctionChance().modifyFlat(ID, CRIT_MALFUNCTION_PROB * effect);
                    aura.alpha = 1f;
                    createAura(aura, enemy, combatEngine, amount);
                    if (!aura.textPopupHappened && textTracker.interval.intervalElapsed()) {
                        // Scared text popup here.
                        LOG.info("Text would popup here.");
                        aura.textPopupHappened = true;
                    }
                }
            }
            for (ShipAPI enemy : ships.keySet()) {
                if (enemy != null && (!enemy.isAlive() || MathUtils.getDistance(ship, enemy) > 1500)) {
                    DreadAuraEffectOrigin aura = ships.get(enemy);
                    aura.resetAura(combatEngine, enemy);
                    if (aura.textPopupHappened && textTracker.interval.intervalElapsed()) {
                        // Relief text popup here.
                        LOG.info("Text boolean has been reset.");
                    }
                    aura.textPopupHappened = false;
                }
            }
} catch (ClassCastException e) {
LOG.error(e);
            throw new RuntimeException(e);
}
}

public String getDescriptionParam(int index, HullSize hullSize) {
if (index == 0) return "" + "%";
return null;
}

public boolean isApplicableToShip(ShipAPI ship) {
return ship != null && ship.getCaptain().isPlayer();
}


private static void createAura(DreadAuraEffectOrigin aura, ShipAPI origin, CombatEngineAPI combatEngine, float amount) {
float radius;
        String rotatingKey = IS_ROTATING_KEY + "_" + origin.getId();
        Boolean isRotating = (Boolean) combatEngine.getCustomData().get(rotatingKey);
        if (isRotating == null) {
            combatEngine.getCustomData().put(rotatingKey, false);
        }
if (!(Boolean) combatEngine.getCustomData().get(rotatingKey)) {
            radius = origin.getShieldRadiusEvenIfNoShield() * 1.5f + 50f;
            aura.sprite.setSize(radius, radius);
            aura.sprite.setAlphaMult(aura.alpha);
            aura.sprite.setAngle(aura.angle);
            aura.angle += 0.1f * amount;
            if (aura.angle > 10000f) {
                aura.angle -= 10000f;
            }
            combatEngine.getCustomData().put(rotatingKey, true);
            LOG.info("Aura created. Rotating logic engaged.");
        } else {
    aura.sprite.setAngle(aura.angle);
    aura.angle += 1;
        }
}

public final static class DreadAuraEffectOrigin {
public float alpha;
public float angle;
public boolean textPopupHappened;
public SpriteAPI sprite;

public DreadAuraEffectOrigin() {
alpha = 0f;
angle = 0f;
            textPopupHappened = false;
sprite = Global.getSettings().getSprite("misc", "dread_aura");
}

public void resetAura(CombatEngineAPI combatEngine, ShipAPI origin) {
            String rotatingKey = IS_ROTATING_KEY + "_" + origin.getId();
            combatEngine.getCustomData().put(rotatingKey, false);
sprite.setAlphaMult(0f);
alpha = 0f;
}
}
}

[close]


*EDIT* Tiny nitpick here, but for the sake of other modders looking at this:

Should just be:
public void resetAura(CombatEngineAPI combatEngine, ShipAPI origin) {
            combatEngine.getCustomData().put(rotatingKey, false);
            sprite.setAlphaMult(0f);
            alpha = 0f;
}

 - is missing:

Code
            String rotatingKey = IS_ROTATING_KEY + "_" + origin.getId();

Since that is dependent upon the origin as a safeguard, and "rotatingKey" is not global and is not passed into the method.
« Last Edit: June 20, 2020, 01:53:52 AM by Morrokain »
Logged

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24103
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #6549 on: June 20, 2020, 03:47:26 PM »

Gotcha! And, yeah, you definitely want it in a variable if it's used multiple times (or even once); just that one case looked ... odd. Like sometimes people will do that if they think setting the variable will somehow affect the contents of the map or some such, wanted to make sure that wasn't the case here.
Logged

Morrokain

  • Admiral
  • *****
  • Posts: 2143
  • Megalith Dreadnought - Archean Order
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #6550 on: June 20, 2020, 04:55:52 PM »

Gotcha! And, yeah, you definitely want it in a variable if it's used multiple times (or even once); just that one case looked ... odd. Like sometimes people will do that if they think setting the variable will somehow affect the contents of the map or some such, wanted to make sure that wasn't the case here.

Haha yeah I saw it and went *facepalm* but that's the risk when you post code publicly! :P And thanks for the help in case I was misunderstanding. There are plenty of times where that likely is the case.

---------------------------------------

Ok, so new question that isn't time sensitive at all, I just want to confirm my logic and make sure I'm not missing something because I plan on writing a tutorial about it.

In regards to custom data in the faction file, I know how to use it with rules when its a single value.

In this use case, however, I want a full object with a set of values that I use in code to do various manipulations. The main thing I want to know is how resilient the code is to missing values in the faction file. I'm trying to make this as flexible to customize as possible.

For example, having:

JSON in faction file under "custom":

Code
		"dreadAuraData":{
"resistant":true,
"immune":true,
"isAI":false,
"saysText":true,
},

  - should work just as well (without crashes) as:

Code
		"dreadAuraData":{
"immune":true,
},

 - and only provide the relevant functionality.

What I have code wise:

Relevant globals across both classes:

Code
	private static DreadAuraFactionDataManager AURA_MANAGER = new DreadAuraFactionDataManager();

    private static String FACTION_AURA_DATA_KEY = "dreadAuraData";
    private static String FACTION_AURA_IMMUNE_KEY = "immune";
    private static String FACTION_AURA_RESISTANT_KEY = "resistant";

Code in hullmod class to get and manipulate the data based upon the settings that are found in the faction file:

Code
                    JSONObject factionAuraData = AURA_MANAGER.getFactionAuraData(enemy);
                    if (AURA_MANAGER.checkFactionImmunity(factionAuraData)) {
                        float malfunctionChance = AURA_MANAGER.calculateAuraMalfunctionStrength(factionAuraData, ship, enemy);
                        float critMalfunctionChance = AURA_MANAGER.calculateAuraCritMalfunctionStrength(factionAuraData, ship, enemy);

                        // you can ignore below here - just wanted to enclose the whole if code block.
                        MutableShipStatsAPI stats = enemy.getMutableStats();
                        float effect = stats.getDynamic().getValue(Stats.DMOD_EFFECT_MULT);
                        stats.getWeaponMalfunctionChance().modifyFlat(ID, malfunctionChance * effect);
                        stats.getCriticalMalfunctionChance().modifyFlat(ID, critMalfunctionChance * effect);
                        aura.alpha = 1f;
                        createAura(aura, enemy, combatEngine, amount);
                        if (!aura.textPopupHappened && textTracker.interval.intervalElapsed()) {
                            // Scared text popup here.
                            LOG.info("Text would popup here.");
                            aura.textPopupHappened = true;
                        }
                    }

Supporting helper class relevant methods:

Code
    public JSONObject getFactionAuraData(ShipAPI origin) {
        JSONObject factionCustomData = origin.getCaptain().getFaction().getCustom();
        if (factionCustomData == null) {
            return null;
        }
        try {
            return factionCustomData.getJSONObject(FACTION_AURA_DATA_KEY);
        } catch (JSONException e) {
            LOG.error(e);
            throw new RuntimeException(e);
        }
    }

    public boolean checkFactionImmunity(JSONObject factionAuraData) {
        if (factionAuraData != null) {
            try {
                return (!factionAuraData.has(FACTION_AURA_IMMUNE_KEY) || factionAuraData.getBoolean(FACTION_AURA_IMMUNE_KEY));
            } catch (JSONException e) {
                LOG.error(e);
                throw new RuntimeException(e);
            }
        } else {
            return true;
        }
    }
Logged

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24103
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #6551 on: June 20, 2020, 05:19:09 PM »

JSONObject has getXXXX and optXXXX methods for getting data out. The get variety throw an exception when the value is not specified. The opt variety takes a default value as a second parameter and returns that when the value is not specified. So:

json.getBoolean("resistant");  // will throw an exception when "resistant" is not specified
json.optBoolean("resistant", false); // will return false when "resistant" is not specified

This also seems like it'd be fairly straightforward to test...
Logged

Morrokain

  • Admiral
  • *****
  • Posts: 2143
  • Megalith Dreadnought - Archean Order
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #6552 on: June 20, 2020, 05:28:24 PM »

JSONObject has getXXXX and optXXXX methods for getting data out. The get variety throw an exception when the value is not specified. The opt variety takes a default value as a second parameter and returns that when the value is not specified. So:

json.getBoolean("resistant");  // will throw an exception when "resistant" is not specified
json.optBoolean("resistant", false); // will return false when "resistant" is not specified

This also seems like it'd be fairly straightforward to test...

Thanks!

(Not as straightforward as you would think unless I wrote specific dummy code to test it... which in my experience isn't always reliable in the use case for various reasons since the use case is often more complex. To truly test this reliably, I have to find the correct faction fleet after manually adding the hullmod in the refit screen because Commissioned Crews doesn't add it upon market dock for some reason, and then engage in combat and check the log for the right code path based upon added logging that currently doesn't exist if it doesn't crash outright - so you just saved me likely a whole day of testing at worst case scenario. I'll hold off on any questions for a while, though, I know you are super busy! Sorry!)
Logged

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 24103
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #6553 on: June 20, 2020, 05:34:55 PM »

I'll just say, if you haven't actually tested every code branch you've got, you should probably assume it's busted! This isn't me being extreme or anything, it's just a sad fact of life. About 90% of the time when I go, "sigh, but let me test this thing that's a pain to test, anyway, and that looks like it'll work", I find bugs...
Logged

Morrokain

  • Admiral
  • *****
  • Posts: 2143
  • Megalith Dreadnought - Archean Order
    • View Profile
Re: Misc modding questions that are too minor to warrant their own thread
« Reply #6554 on: June 20, 2020, 05:42:13 PM »

I'll just say, if you haven't actually tested every code branch you've got, you should probably assume it's busted! This isn't me being extreme or anything, it's just a sad fact of life. About 90% of the time when I go, "sigh, but let me test this thing that's a pain to test, anyway, and that looks like it'll work", I find bugs...

Hmm, ok I'll take your advice on that and yeah that's definitely happened to me sometimes. I haven't ever really gotten the debugger to work with Starsector so that is part of the reason it's a bigger pain unless I very carefully log everything (which I've done in the past) but that's more of a reflection of my lack of understanding of the IDE nuances/functionality than anything the core game does.

I shall double my efforts.

*EDIT* I also came from a team based environment where asking peers/superiors is preferred to slogging it out yourself so that probably influences the question flood somewhat and that's my fault. (One of my friends actually failed the interview because they answered "If you don't know something, what do you do?" with "Research and trial and error" instead of "Ask someone" - so it's a bad habit I have and this is obviously not the same environment. I'm taking time out of someones day to ask questions and I'll try to keep this in mind going forward.
« Last Edit: June 20, 2020, 05:50:02 PM by Morrokain »
Logged
Pages: 1 ... 435 436 [437] 438 439 ... 709