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: Codex Overhaul (05/11/24)

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - AtlanticAccent

Pages: [1] 2 3 ... 5
1
Could someone please explain to me what I am doing wrong with my Script?

I get this error in the log file:
Spoiler
java.lang.RuntimeException: Error loading [data.shipsystems.scripts.SensorJammerStats]
   at com.fs.starfarer.loading.scripts.ScriptStore$3.run(Unknown Source)
   at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: Parsing compilation unit 'data.shipsystems.scripts.SensorJammerStats'
   at org.codehaus.janino.JavaSourceIClassLoader.findIClass(JavaSourceIClassLoader.java:172)
   at org.codehaus.janino.IClassLoader.loadIClass(IClassLoader.java:254)
   at org.codehaus.janino.JavaSourceClassLoader.generateBytecodes(JavaSourceClassLoader.java:214)
   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
Caused by: org.codehaus.commons.compiler.CompileException: Compilation unit 'data.shipsystems.scripts.SensorJammerStats' does not declare a class with the same name
   at org.codehaus.janino.JavaSourceIClassLoader.findIClass(JavaSourceIClassLoader.java:160)
   ... 7 more
[close]

I am pretty sure that with "public class SensorJammerStats extends BaseShipSystemScript {" I do declare a class of the same name so I really do not understand the error.

Script:
Spoiler
package com.fs.starfarer.api.impl.combat;

import java.awt.Color;
import java.util.List;

import com.fs.starfarer.api.Global;
import com.fs.starfarer.api.combat.BaseEveryFrameCombatPlugin;
import com.fs.starfarer.api.combat.EveryFrameCombatPlugin;
import com.fs.starfarer.api.combat.MutableShipStatsAPI;
import com.fs.starfarer.api.combat.ShipAPI;
import com.fs.starfarer.api.combat.ShipAPI.HullSize;
import com.fs.starfarer.api.combat.ShipSystemAPI;
import com.fs.starfarer.api.combat.ShipSystemAPI.SystemState;
import com.fs.starfarer.api.combat.ShipwideAIFlags.AIFlags;
import com.fs.starfarer.api.input.InputEventAPI;
import com.fs.starfarer.api.util.Misc;

public class SensorJammerStats extends BaseShipSystemScript {
   public static Object KEY_SHIP = new Object();
   public static Object KEY_TARGET = new Object();
   
   public static float RANGE_MULT = 0.8f;
   public static float SENSOR_MULT = 0.6f;   
   protected static float RANGE = 1500f;
   
   public static Color TEXT_COLOR = new Color(255,55,55,255);
   
   public static Color JITTER_COLOR = new Color(255,50,50,75);
   public static Color JITTER_UNDER_COLOR = new Color(255,100,100,155);

   
   public static class TargetData {
      public ShipAPI ship;
      public ShipAPI target;
      public EveryFrameCombatPlugin targetEffectPlugin;
      public float currRange_Mult;
      public float currSensor_Mult;      
      public float elaspedAfterInState;
      public TargetData(ShipAPI ship, ShipAPI target) {
         this.ship = ship;
         this.target = target;
      }
   }
   
   
   public void apply(MutableShipStatsAPI stats, final String id, State state, float effectLevel) {
      ShipAPI ship = null;
      if (stats.getEntity() instanceof ShipAPI) {
         ship = (ShipAPI) stats.getEntity();
      } else {
         return;
      }
      
      final String targetDataKey = ship.getId() + "_Jammer_target_data";
      
      Object targetDataObj = Global.getCombatEngine().getCustomData().get(targetDataKey);
      if (state == State.IN && targetDataObj == null) {
         ShipAPI target = findTarget(ship);
         Global.getCombatEngine().getCustomData().put(targetDataKey, new TargetData(ship, target));
         if (target != null) {
            if (target.getFluxTracker().showFloaty() ||
                  ship == Global.getCombatEngine().getPlayerShip() ||
                  target == Global.getCombatEngine().getPlayerShip()) {
               target.getFluxTracker().showOverloadFloatyIfNeeded("Sensors Jammed!", TEXT_COLOR, 4f, true);
            }
         }
      } else if (state == State.IDLE && targetDataObj != null) {
         Global.getCombatEngine().getCustomData().remove(targetDataKey);
         ((TargetData)targetDataObj).currRange_Mult = 1f;
         ((TargetData)targetDataObj).currSensor_Mult = 1f;         
         targetDataObj = null;
      }
      if (targetDataObj == null || ((TargetData) targetDataObj).target == null) return;
      
      final TargetData targetData = (TargetData) targetDataObj;
      targetData.currRange_Mult = RANGE_MULT * (1f - effectLevel);
      targetData.currSensor_Mult = SENSOR_MULT * (1f - effectLevel);      
      if (targetData.targetEffectPlugin == null) {
         targetData.targetEffectPlugin = new BaseEveryFrameCombatPlugin() {
            @Override
            public void advance(float amount, List<InputEventAPI> events) {
               if (Global.getCombatEngine().isPaused()) return;
               if (targetData.target == Global.getCombatEngine().getPlayerShip()) {
                  Global.getCombatEngine().maintainStatusForPlayerShip(KEY_TARGET,
                        targetData.ship.getSystem().getSpecAPI().getIconSpriteName(),
                        targetData.ship.getSystem().getDisplayName(),
                        "" + (int)((targetData.currRange_Mult - 1f) * 100f) + "% Weapon Range and " + (int)((targetData.currSensor_Mult - 1f) * 100f) + "% Sensor Range", true);
               }
               
               if (targetData.currRange_Mult <= 1f || !targetData.ship.isAlive()) {
                  targetData.target.getMutableStats().getBallisticWeaponRangeBonus().unmodify(id);
                  targetData.target.getMutableStats().getEnergyWeaponRangeBonus().unmodify(id);
                  targetData.target.getMutableStats().getSightRadiusMod().unmodify(id);
                  Global.getCombatEngine().removePlugin(targetData.targetEffectPlugin);
               } else {
                  targetData.target.getMutableStats().getBallisticWeaponRangeBonus().modifyMult(id, currRange_Mult);
                  targetData.target.getMutableStats().getEnergyWeaponRangeBonus().modifyMult(id, currRange_Mult);
                  targetData.target.getMutableStats().getSightRadiusMod().modifyMult(id, currSensor_Mult);
               }
            }
         };
         Global.getCombatEngine().addPlugin(targetData.targetEffectPlugin);
      }
      
      
      if (effectLevel > 0) {
         if (state != State.IN) {
            targetData.elaspedAfterInState += Global.getCombatEngine().getElapsedInLastFrame();
         }
         float shipJitterLevel = 0;
         if (state == State.IN) {
            shipJitterLevel = effectLevel;
         } else {
            float durOut = 0.5f;
            shipJitterLevel = Math.max(0, durOut - targetData.elaspedAfterInState) / durOut;
         }
         float targetJitterLevel = effectLevel;
         
         float maxRangeBonus = 50f;
         float jitterRangeBonus = shipJitterLevel * maxRangeBonus;
         
         Color color = JITTER_COLOR;
         if (shipJitterLevel > 0) {
            //ship.setJitterUnder(KEY_SHIP, JITTER_UNDER_COLOR, shipJitterLevel, 21, 0f, 3f + jitterRangeBonus);
            ship.setJitter(KEY_SHIP, color, shipJitterLevel, 4, 0f, 0 + jitterRangeBonus * 1f);
         }
         
         if (targetJitterLevel > 0) {
            //target.setJitterUnder(KEY_TARGET, JITTER_UNDER_COLOR, targetJitterLevel, 5, 0f, 15f);
            targetData.target.setJitter(KEY_TARGET, color, targetJitterLevel, 3, 0f, 5f);
         }
      }
   }
   
   
   public void unapply(MutableShipStatsAPI stats, String id) {
      
   }
   
   protected ShipAPI findTarget(ShipAPI ship) {
      float range = getMaxRange(ship);
      boolean player = ship == Global.getCombatEngine().getPlayerShip();
      ShipAPI target = ship.getShipTarget();
      
      if (ship.getShipAI() != null && ship.getAIFlags().hasFlag(AIFlags.TARGET_FOR_SHIP_SYSTEM)){
         target = (ShipAPI) ship.getAIFlags().getCustom(AIFlags.TARGET_FOR_SHIP_SYSTEM);
      }
      
      if (target != null) {
         float dist = Misc.getDistance(ship.getLocation(), target.getLocation());
         float radSum = ship.getCollisionRadius() + target.getCollisionRadius();
         if (dist > range + radSum) target = null;
      } else {
         if (target == null || target.getOwner() == ship.getOwner()) {
            if (player) {
               target = Misc.findClosestShipEnemyOf(ship, ship.getMouseTarget(), HullSize.FIGHTER, range, true);
            } else {
               Object test = ship.getAIFlags().getCustom(AIFlags.MANEUVER_TARGET);
               if (test instanceof ShipAPI) {
                  target = (ShipAPI) test;
                  float dist = Misc.getDistance(ship.getLocation(), target.getLocation());
                  float radSum = ship.getCollisionRadius() + target.getCollisionRadius();
                  if (dist > range + radSum) target = null;
               }
            }
         }
         if (target == null) {
            target = Misc.findClosestShipEnemyOf(ship, ship.getLocation(), HullSize.FIGHTER, range, true);
         }
      }
      
      return target;
   }
   
   
   public static float getMaxRange(ShipAPI ship) {
      return ship.getMutableStats().getSystemRangeBonus().computeEffective(RANGE);
   }

   
   public StatusData getStatusData(int index, State state, float effectLevel) {
      if (effectLevel > 0) {
         if (index == 0) {
            float damMult = 1f + (DAM_MULT - 1f) * effectLevel;
            return new StatusData("" + (int)((targetData.currRange_Mult - 1f) * 100f) + "% Weapon Range and " + (int)((targetData.currSensor_Mult - 1f) * 100f) + "% Sensor Range", false);
         }
      }
      return null;
   }


   @Override
   public String getInfoText(ShipSystemAPI system, ShipAPI ship) {
      if (system.isOutOfAmmo()) return null;
      if (system.getState() != SystemState.IDLE) return null;
      
      ShipAPI target = findTarget(ship);
      if (target != null && target != ship) {
         return "READY";
      }
      if ((target == null) && ship.getShipTarget() != null) {
         return "OUT OF RANGE";
      }
      return "NO TARGET";
   }

   
   @Override
   public boolean isUsable(ShipSystemAPI system, ShipAPI ship) {
      //if (true) return true;
      ShipAPI target = findTarget(ship);
      return target != null && target != ship;
   }

}
[close]

In your apply method, where you create a new BaseEveryFrameCombatPlugin, you reference the type "List<InputEventAPI>". Unfortunately Janino, the runtime compiler bundled with the game does not understand this type as it uses generics, and Janino does not support generics.
In order for the above to work, you will need to compile your code prior to it being loaded by the game and include the compilation output in a .jar file. Whilst this sounds complicated, there is a tutorial on how to do so here: https://starsector.fandom.com/wiki/IntelliJ_IDEA_Setup

2
Mods / [0.97a] Auto-Continue-Inator 0.0.4
« on: February 15, 2024, 02:01:03 PM »
Behold! The Auto-Continue-Inator!
With this mod, I can automatically continue any game in the Tri-State area!

Immediately loads your last save, bypassing the main menu, as soon as you start the game (and it finishes starting up).

Note: Includes a terrible, terrible hack involving setting the CombatEngine manually avoid a NPE I occasionally experienced. If this concerns you, don't use the mod lol

DOWNLOAD HERE

3
Hi,

I'm glad you're enjoying MOSS!

I'm currently in the middle of rewriting MOSS pretty heavily. However, I've just checked and mods like Seeker seem to be handled fine - nested folder handling has been part of MOSS from the very first version, seeing as handling them was one of the reasons I wrote it in the first place.

As for mass rewriting the supported game version in mods' mod_info.json files, it's something I've considered (it was also suggested to SMOL) and the conclusion I and others came to was that it would create more issues than it solves. It would encourage fairly reckless usage of mods between game versions, and whilst it is often the case that mods are fully compatible between versions they should be checked individually and carefully. If someone else were to write the code and contribute it, I would certainly consider integrating it, but it's not something I will spend my own time writing right now.

4
Suggestions / Re: API request thread (please read OP before posting!)
« on: January 22, 2024, 09:46:33 AM »
Hi Alex.

Two linked requests.

Could you please add methods like `public bool hasConfirmationDialog` and `public void onSelected` to StoryPointActionDelegate. The former would, on returning false, prevent the confirmation dialog triggered by story point action delegates currently from appearing, and the latter would allow arbitrary code to be executed when the dialog option the delegate is attached to is selected. As discussed in https://fractalsoftworks.com/forum/index.php?topic=28698.0 there are workarounds for these currently, but they are fragile and require multiple (two) frames to execute.

Hybrid bug report/API request - currently `OptionPanelAPI.restoreSavedOptions(List<Object>)` does not restore delegates, confirmation dialogs or hotkeys as expected. Current users likely expect this to fully restore all option selection functionality (ie: [Esc] triggering the common "Leave" option). Again, we discuss workarounds to this in https://fractalsoftworks.com/forum/index.php?topic=28698.0

5
I think I've expressed this elsewhere, but a minimal subset of this I'd like to see is renaming StoryPointActionDelegate and adding methods to it like
Code
public bool hasConfirmationDialog
and
Code
public void onSelected
.

Code
hasConfirmationDialog
would stop the game from displaying the confirmation popup that story point options currently always display.
Code
onSelected
would allow running some arbitrary code when the option the delegate is attached to is chosen/clicked.

These two would allow us to a) stop using the
Code
createDescription
method of the delegate to run code, and b) remove the need for our multi-frame workaround to dismissing the stock story-point-spending confirmation dialog.

Though, to be honest, it would be nice if the existing exposed API method
Code
restoreSavedOptions
were to be more "complete" and also restore delegates and hotkeys - this is an issue even when not trying to change the order of the options list.

6
Code
public static final float COST_REDUCTION  = 3;
This needs to be 3.0 not 3, as 3 is an int type not float

7
Announcements / Re: Starsector 0.96.1a (In Development) Patch Notes
« on: January 01, 2024, 12:04:10 PM »
Quote
Safety Overrides: can no longer be installed on ships with Flux Shunt (i.e. the Monitor)

It would be lovely if this hullmod incompatibility mechanism were available to modders  ;D

8
Modding / Re: Is it possible to 'debug' a save file?
« on: November 17, 2023, 06:24:49 AM »
Debugging save files is generally quite difficult. I think the easier thing to do here would be to have a look at your mod source to try and understand why it might be bricking the save file. The complexity of the code is generally lower than the complexity of the save file.

9
While looking at how certain text is set in the game, I saw that most (all?) instances of "story points" have the "story" word set by Misc.STORY, leading to the following in Misc.java:

Code
/**
* Name of "story points".
*/
public static String STORY = "story";
This seems to allow their name to be easily changed across the game. I tried my hand at changing them with a small mod and the following:
Spoiler
Code
package data.scripts;

import com.fs.starfarer.api.BaseModPlugin;
import com.fs.starfarer.api.Global.*;
import com.fs.starfarer.api.impl.campaign.ids.Strings.*;

public class StorypointMod extends BaseModPlugin {

    @Override
public void onApplicationLoad() {   

String STORY = "placeholder";


    }


}
[close]

-but I am not seeing a change (although it's not crashing). My java knowledge is next to zero so I am most certainly messing up - or I'm not understanding when this is being loaded. Thank you if you can help.

You're just setting a local variable (essentially a holder for data that you can operate on or reference later) here. This doesn't change anything about the values in the game itself. To do so, you must reference the value and alter it, like so:

Code
package data.scripts;

import com.fs.starfarer.api.BaseModPlugin;
import com.fs.starfarer.api.util.Misc;

public class StorypointMod extends BaseModPlugin {
    @Override
    public void onApplicationLoad() {   
Misc.STORY = "placeholder";
    }
}

10
Mods / Re: [0.96a] Officer Extension (0.5)
« on: September 15, 2023, 07:58:38 AM »
Hi,

Your reflection work was one of the original inspirations for me to get into messing with officers and UI.

One thing I'd like to request in the name of cross-mod compatibility is the ability to prevent certain skills from being "demotable". In my case, I'm (mis)using the skill system to represent non-skill/skill-adjacent concepts[1]. In vanilla, there is already a way to indicate that a skill is unremovable by adding
Code
"unremovable" : true
to the .skill file. This can be retrieved in code through SkillSpecAPI.isPermanent(). I should note that no vanilla skill makes use of this but it is still handled correctly by the game.

Additionally, you can add arbitrary tags to skills in their entry in the skill_data.csv file. If it's not too much trouble, I'd like to propose adding a tag that Officer Extension recognises as opting a skill out from being demotable, for cases where the skill author does not want to use the permanent field in the skill file.

These changes would effectively require adding some filtering on the list returned by getSkillButtons in injectSkillButtons.

Happy to discuss this in a proper issue on GitHub or a PR if you'd like.

[1]
Spoiler
In my mod I call them Conditions, the most prominent being Injuries that temporarily remove a skill from an officer when they are, naturally, injured. Source: https://github.com/atlanticaccent/price-of-command/
[close]

11
It's a weird take considering Alex's current official stance:
https://fractalsoftworks.com/forum/index.php?topic=27431.msg407743#msg407743

12
Modding / Re: [QUESTION] Questmaking and guides/resources
« on: July 21, 2023, 08:44:57 AM »
Internal Affairs is specifically written as a demo of how one might write a quest mod as of the 0.95 update.

https://fractalsoftworks.com/forum/index.php?topic=20281.0

13
For option-ordering, though, there's a sorting parameter in rules, e.g.:
<sort value>:<option id>:<option text>

Ah, this actually kind of cuts right to what I'm dealing with. Rules.csv doesn't work for adding options to the top level FleetInteractionDialogImpl, so I'm appending my options through code, hence why they're always last.

Not really sure what you can do with that information though, because as we've said, this is pretty far beyond how you're supposed to do this.

14
Hi!

Would it be possible to get an explanation of how
Code
OptionPanelAPI.getSavedOptionList()
and
Code
OptionPanelAPI.restoreSaveOptions()
work? I understand that they were only created for debugging purposes, but they potentially open up some interesting possiblities.

Most notably, manipulating the order of options in an option panel. Many option panels have a final "Leave" or similar option, and appending any new options will result in them appearing after the "Leave" option. Unfortunately using the mentioned methods and reordering the returned list seems to break the leave functionality and any previous shortcuts assigned to the reordered options.

Of course, if the answer is "that's absolutely not how you're supposed to use any of this" I'd accept that  ;D

15
Modding / Re: Looking for specific mod.
« on: May 23, 2023, 10:36:12 AM »
Pretty sure this came up not after a balance change, but after the discovery that some mod was literally sending information out over the web.

Ok I can't say that I've ever heard this about Tahlan (which isn't proof of anything) but I have absolutely heard about it in Boggled's Terraforming. In fact that was a huge blowup, that has since been resolved, and I don't think it's fair to accuse another mod of it without proof.

Any other points are fine, but this one in particular I think it's good to be clear about.

Pages: [1] 2 3 ... 5