[Starsector Mods][0.95a] Weapon Arcs 1.7.0

  • Post category:Mods
  • Post comments:0 Comments

This is a simple mod that draws the weapon arcs of all weapons groups on the players ship, in contrast to vanilla which only draws the selected group.

Is it useful? If you use missiles you have likely noticed that there is no way to select the missile group and still see the weapon arcs of your other weapons, which you might want to see for aiming etc. This mod fixes that.

Github
Download

Requirements

Controls
Use “ALT + 1-7” to toggle drawing of weapon groups on/off.
If for some reason using ALT does not work, first press “h” and then the 1-7 you want to activate, then “h” again to stop toggling arcs.
If “h” is used for something else, you can change the key from settings.

It is recommended (but not required) to disable vanilla weapon arcs while using this mod. Default hotkey for disabling vanilla is “~”.

In the root folder of the mod you will find “weapon-arcs-settings.json”. From there you can:

  • Change the color of the weapon arcs
  • Set options to auto enable arcs on weapon groups
  • Set the roughness of the displayed weapon arc. For more smooth arch, set a lower number (minimum 1. This will draw for each degree in the arc). For a blocky arc, set a higher number (don’t go over 50)
  • Turn on individual colors for each weapon group (default off)
  • set a key which will toggle whether 1-7 triggers the arcs. This is mainly for users where the Alt key does not work, such as on a mac
  • Set the amount of range bands on the arcs

Changelog

1.7.0 – Added a config setting for range bands. Default is 4 and it can be set to other amounts. Credit goes to Lrizika for implementing this feature https://github.com/archigo/WeaponArcsStarsector/pull/2

1.6.0 – Added toggle key as workaround for Mac users. Added functionality to have individual colors on each weapon group.

1.5.0 – Added setting to change the “roughness” of the displayed Weapon arcs. Fixed a potential crash.

1.4.1 – Support weapon groups 6 and 7.

1.4.0 – Update game version number. Add additional crash check.

1.3.1 – Fixed possible crash on entering combat

1.3.0 – Introduced in memory caching of active groups, will persist as long as you do not change ship. Introduced settings file in the main folder of the mod. Can set weapon arc colors and set group to auto enable.

1.2.2 – Fixed a case sensitivity issue with version checker files on Linux.

1.2.1 – Updated the download link, so the new version can actually be downloaded! Also implemented version checker support

1.2 – updated mod info for 0.9. Weapon arcs are now off by default simply turn them on with “ALT + 1-5”.

1.1 – Introduced the ability to toggle drawing of individual weapon groups off, with “ALT + 1-5”.

Compatibility
This mod should be compatible with all other mods. Other mods might use the same hotkeys, but both mods should still work.

Save games
This mod is save game safe. Add it to you existing saves, or remove it, the saves will still work.

In game examples

Spoiler: click to expand
Spoiler
Vanilla:

Mod:

Vanilla:

Mod:

Credits
LazyWizard – the creator of Lazylib, which is used for vector rotation in this mod.


Edit: These issues have been solved – Solution: Compile as jar instead of letting Janino compile on game run.

I’ve been trying to implement switching weapon groups off, but i hit a snag:

Code
List weaponGroups = engine.getPlayerShip().getWeaponGroupsCopy();
List weapons = weaponGroups.get(0).getWeaponsCopy();

When i run startsector this gives me:
“A method name “getWeaponsCopy” is not declared in any enclosing class nor any supertype, nor through a static import”

The method is right here though: http://fractalsoftworks.com/starfarer.api/com/fs/starfarer/api/combat/WeaponGroupAPI.html#getWeaponsCopy() and netbeans also find it in the starfarer api file

Any idea why this is?

Additionally i tried using ArrayList for some stuff, but when using methods like “isEmpty()” and “size()” i would get errors as well. Is it not possible to use ArrayLists in a script? If i try to use the “List” type that the api returns i apparently have to implement all the interface methods on it.

full code:

Spoiler: click to expand
Spoiler
Code
package data.scripts.plugins;

import com.fs.starfarer.api.Global;
import com.fs.starfarer.api.combat.*;
import com.fs.starfarer.api.input.InputEventAPI;
import com.fs.starfarer.api.combat.ShipAPI;
import com.fs.starfarer.api.combat.WeaponAPI;
import com.fs.starfarer.api.combat.WeaponGroupAPI;
import org.json.JSONException;
import org.json.JSONObject;
import org.lazywizard.lazylib.FastTrig;
import org.lazywizard.lazylib.JSONUtils;
import org.lazywizard.lazylib.MathUtils;
import org.lazywizard.lazylib.VectorUtils;
import org.lazywizard.lazylib.opengl.DrawUtils;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.vector.Vector2f;

import java.awt.*;
import java.io.IOException;
import java.util.List;

public class WeaponArcs extends BaseEveryFrameCombatPlugin {
    
    private CombatEngineAPI engine;
    private ShipAPI player;
    private static Color WEAPON_ARC_COLOR;
    private static String[][] DO_NO_DRAW_WEAPONS;
    
    @Override
    public void init(CombatEngineAPI engine) {
        this.engine = engine;
        WEAPON_ARC_COLOR = Global.getSettings().getColor("weaponArcColor");
        if (DO_NO_DRAW_WEAPONS == null) {
            DO_NO_DRAW_WEAPONS = new String[5][40];
        }
    }
    
    public void advance(float amount, List events) {
        
        for (InputEventAPI event : events) {
            if (event.isAltDown() && event.getEventChar() == '1' || event.getEventChar() == '2' || event.getEventChar() == '3' || event.getEventChar() == '4' || event.getEventChar() == '5') {
                int index;
                switch (event.getEventChar()) {
                    case '1':
                        index = 0;
                        if (DO_NO_DRAW_WEAPONS[index].length == 0) {
                            List weaponGroups = engine.getPlayerShip().getWeaponGroupsCopy();
                            List weapons = weaponGroups.get(0).getWeaponsCopy();
                            for (int i = 0; i < weapons.size(); i++) {
                                WeaponAPI weapon = weapons.get(i);
                                DO_NO_DRAW_WEAPONS[index][i] = weapon.getId();
                            }
                        } else {
                            for (int i = 0; i < DO_NO_DRAW_WEAPONS[index].length; i++) {
                                DO_NO_DRAW_WEAPONS[index][i] = null;
                            }
                        }
                        break;
                    case '2':
                        index = 1;
                        if (DO_NO_DRAW_WEAPONS[index].length == 0) {
                            List weaponGroups = engine.getPlayerShip().getWeaponGroupsCopy();
                            List weapons = weaponGroups.get(0).getWeaponsCopy();
                            for (int i = 0; i < weapons.size(); i++) {
                                WeaponAPI weapon = weapons.get(i);
                                DO_NO_DRAW_WEAPONS[index][i] = weapon.getId();
                            }
                        } else {
                            for (int i = 0; i < DO_NO_DRAW_WEAPONS[index].length; i++) {
                                DO_NO_DRAW_WEAPONS[index][i] = null;
                            }
                        }
                        break;
                    case '3':
                        index = 2;
                        if (DO_NO_DRAW_WEAPONS[index].length == 0) {
                            List weaponGroups = engine.getPlayerShip().getWeaponGroupsCopy();
                            List weapons = weaponGroups.get(0).getWeaponsCopy();
                            for (int i = 0; i < weapons.size(); i++) {
                                WeaponAPI weapon = weapons.get(i);
                                DO_NO_DRAW_WEAPONS[index][i] = weapon.getId();
                            }
                        } else {
                            for (int i = 0; i < DO_NO_DRAW_WEAPONS[index].length; i++) {
                                DO_NO_DRAW_WEAPONS[index][i] = null;
                            }
                        }
                        break;
                    case '4':
                        index = 3;
                        if (DO_NO_DRAW_WEAPONS[index].length == 0) {
                            List weaponGroups = engine.getPlayerShip().getWeaponGroupsCopy();
                            List weapons = weaponGroups.get(0).getWeaponsCopy();
                            for (int i = 0; i < weapons.size(); i++) {
                                WeaponAPI weapon = weapons.get(i);
                                DO_NO_DRAW_WEAPONS[index][i] = weapon.getId();
                            }
                        } else {
                            for (int i = 0; i < DO_NO_DRAW_WEAPONS[index].length; i++) {
                                DO_NO_DRAW_WEAPONS[index][i] = null;
                            }
                        }
                        break;
                    case '5':
                        index = 4;
                        if (DO_NO_DRAW_WEAPONS[index].length == 0) {
                            List weaponGroups = engine.getPlayerShip().getWeaponGroupsCopy();
                            List weapons = weaponGroups.get(0).getWeaponsCopy();
                            for (int i = 0; i < weapons.size(); i++) {
                                WeaponAPI weapon = weapons.get(i);
                                DO_NO_DRAW_WEAPONS[index][i] = weapon.getId();
                            }
                        } else {
                            for (int i = 0; i < DO_NO_DRAW_WEAPONS[index].length; i++) {
                                DO_NO_DRAW_WEAPONS[index][i] = null;
                            }
                        }
                        break;
                }
            }
        }
        
        if (engine == null || engine.getCombatUI() == null) {
            return;
        }
        
        if (engine.isUIShowingDialog()) {
            return;
        }
        
        if (!engine.isSimulation() && !engine.isUIShowingHUD()) {
            return;
        }
        if (engine.getCombatUI().isShowingCommandUI()) {
            return;
        }
        
        player = engine.getPlayerShip();
        if (player == null || !engine.isEntityInPlay(player)) {
            return;
        }
        
        ViewportAPI viewport = engine.getViewport();
        
        GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
        final int width = (int) (Display.getWidth() * Display.getPixelScaleFactor()), height
                = (int) (Display.getHeight()
                * Display.getPixelScaleFactor());
        GL11.glViewport(0, 0, width, height);
        
        GL11.glMatrixMode(GL11.GL_PROJECTION);
        GL11.glPushMatrix();
        GL11.glLoadIdentity();
        GL11.glOrtho(viewport.getLLX(), viewport.getLLX() + viewport.getVisibleWidth(), viewport.getLLY(),
                viewport.getLLY() + viewport.getVisibleHeight(), -1,
                1);
        
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glPushMatrix();
        GL11.glLoadIdentity();
        
        GL11.glDisable(GL11.GL_TEXTURE_2D);
        GL11.glEnable(GL11.GL_BLEND);
        GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
        GL11.glTranslatef(0.01f, 0.01f, 0);
        
        this.handleDraw();
        
        GL11.glDisable(GL11.GL_BLEND);
        
        GL11.glMatrixMode(GL11.GL_MODELVIEW);
        GL11.glPopMatrix();
        GL11.glMatrixMode(GL11.GL_PROJECTION);
        GL11.glPopMatrix();
        
        GL11.glPopAttrib();
    }
    
    private static void glColor(Color color) {
        GL11.glColor4ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue(),
                (byte) (41f));
    }
    
    private void handleDraw() {
        List weapons = engine.getPlayerShip().getAllWeapons();
        
        for (WeaponAPI weapon : weapons) {
            boolean skip = false;
            for (int i = 0; i < DO_NO_DRAW_WEAPONS.length; i++) {
                for (int j = 0; j < DO_NO_DRAW_WEAPONS[i].length; j++) {
                    if (DO_NO_DRAW_WEAPONS[i][j] == weapon.getId()) {
                    skip = true;
                }
                }
            }
            if (skip) {
                continue;
            }
            
            this.drawWeaponFacing(weapon);
            this.drawWeaponArc(weapon);
        }
    }
    
    private void drawWeaponFacing(WeaponAPI weapon) {
        
        if (!weapon.isDisabled()) {
            Vector2f location = weapon.getLocation();
            float cangle = weapon.getCurrAngle();
            Vector2f toRotate = new Vector2f(location.x + weapon.getRange(), location.y);
            Vector2f dest = new Vector2f(0, 0);
            VectorUtils.rotateAroundPivot(toRotate, location, cangle, dest);
            
            toRotate = new Vector2f(location.x + 5, location.y);
            Vector2f start = new Vector2f(0, 0);
            VectorUtils.rotateAroundPivot(toRotate, location, cangle, start);
            
            this.glColor(WEAPON_ARC_COLOR);
            
            this.drawLine(start, dest);
        }
        
    }
    
    private void drawWeaponArc(WeaponAPI weapon) {
        
        if (!weapon.isDisabled()) {
            Vector2f location = weapon.getLocation();
            float arc = weapon.getArc();
            float arcFacing = weapon.getArcFacing();
            float left = arcFacing - (arc / 2);
            float right = arcFacing + (arc / 2);
            Vector2f toRotateLeft = new Vector2f(location.x + weapon.getRange(), location.y);
            Vector2f destLeft = new Vector2f(0, 0);
            VectorUtils.rotateAroundPivot(toRotateLeft, location, left, destLeft);
            Vector2f toRotateRight = new Vector2f(location.x + weapon.getRange(), location.y);
            Vector2f destRight = new Vector2f(0, 0);
            VectorUtils.rotateAroundPivot(toRotateRight, location, right, destRight);
            
            float shipFacing = engine.getPlayerShip().getFacing();
            
            Vector2f finalLeft = new Vector2f(0, 0);
            Vector2f finalRight = new Vector2f(0, 0);
            
            VectorUtils.rotateAroundPivot(destLeft, location, shipFacing, finalLeft);
            VectorUtils.rotateAroundPivot(destRight, location, shipFacing, finalRight);
            
            Vector2f toRotateLeft2 = new Vector2f(location.x + 10, location.y);
            Vector2f destLeft2 = new Vector2f(0, 0);
            VectorUtils.rotateAroundPivot(toRotateLeft2, location, left, destLeft2);
            Vector2f toRotateRight2 = new Vector2f(location.x + 10, location.y);
            Vector2f destRight2 = new Vector2f(0, 0);
            VectorUtils.rotateAroundPivot(toRotateRight2, location, right, destRight2);
            
            Vector2f finalLeft2 = new Vector2f(0, 0);
            Vector2f finalRight2 = new Vector2f(0, 0);
            
            VectorUtils.rotateAroundPivot(destLeft2, location, shipFacing, finalLeft2);
            VectorUtils.rotateAroundPivot(destRight2, location, shipFacing, finalRight2);
            
            this.glColor(WEAPON_ARC_COLOR);
            
            this.drawLine(finalLeft2, finalLeft);
            this.drawLine(finalRight2, finalRight);
            
            int segments = (int) arc / 10;
            
            float startArc = right;
            
            float xdif = (finalLeft.x - location.x) / 4;
            float ydif = (finalLeft.y - location.y) / 4;
            
            this.drawArc(location,
                    finalLeft,
                    arc,
                    segments);
            
            this.drawArc(location,
                    new Vector2f(finalLeft.x - xdif, finalLeft.y - ydif),
                    arc,
                    segments);
            
            this.drawArc(location,
                    new Vector2f(finalLeft.x - xdif * 2, finalLeft.y - ydif * 2),
                    arc,
                    segments);
            
            this.drawArc(location,
                    new Vector2f(finalLeft.x - xdif * 3, finalLeft.y - ydif * 3),
                    arc,
                    segments);
            
        }
    }
    
    private void drawArc(Vector2f center, Vector2f start, float range, int segments) {
        Vector2f oldPoint = start;
        
        float rotation = range / segments;
        for (int i = 0; i < segments; i++) {
            Vector2f newpoint = new Vector2f(0f, 0f);
            VectorUtils.rotateAroundPivot(oldPoint, center, rotation, newpoint);
            this.drawLine(oldPoint, newpoint);
            oldPoint = newpoint;
        }
    }
    
    private void drawLine(Vector2f start, Vector2f end) {
        GL11.glBegin(GL11.GL_LINES);
        GL11.glVertex2f(start.x, start.y);
        GL11.glVertex2f(end.x, end.y);
        GL11.glEnd();
    }
}


I’ve been trying to implement switching weapon groups off, but i hit a snag:

Already exist, do not implement thing than people have already made :p


You misunderstand, i meant switching the drawing on and off, not the actual weapon group. So that you could, for example, draw only group 1, 2, 3 but not 4 and 5.

You misunderstand, i meant switching the drawing on and off, not the actual weapon group. So that you could, for example, draw only group 1, 2, 3 but not 4 and 5.

After, on my head: getWeaponGroupsCopy();

A copy  is not linked to the ship where you got the copy, this is just for take informations without modify the ship per error.


That’s okay for my purposes. What i don’t understand is why i get the compile error.

I do not found these “isempty” and size, on your code.

But ArrayList is the standard list you use when you need a list.

You have not forgot to import the ArrayList?


The arraylist issues is not in the code i posted.

Have you tried copying the code from the spoilers, into the java file in the mod and running starsector? That is the issue i am having trouble with.

Edit: All my issues got solved by compiling as a jar instead of letting Janino compile.


Version 1.1 of the mod has been released. Check OP.

I never knew I needed this.  :o
Thanks for making my mods list +1 longer!

released for 0.9. Also updated the mod to have arcs off by default. It was kinda obnoxious to turn the groups you didn’t want to see off every time


Updated the download link, so that it actually points to the new version. Also implemented version checker support.

Very usefull mod,I like it, huge Thank You.

I’m just asking, if You could implement some features. (Not like You should, just asking)

1. Automatically turn off/on vanilla weapon arcs, (even if hotkey is changed) and turn on/off modded ones, every battle.
2. Change and/or toggle transparency of modded arcs.
3. Make .cfg file for configuring those functions. Maybe also turning on arcs for each weapon group separately. Maybe make currently used arc less transparent while other stay transparent.
4. (Is it even possible) Show arcs for hostile/friendly ships with a hotkey for each group.

It would be awesome if You added those. Still very nice mod, I think devs should integrate it into the game.
Actually maybe propose to integrate it? I mean this looks like it should be in game permanently, not just mod.
Maybe add a poll about integration before proposing to devs, just as an idea?

Thank You for such usefull mod!


Also implemented version checker support.

I’m on linux which has case sensitive filenames, and I encountered an error until I changed the filename “weaponarcs.version” to “WeaponArcs.version”. Cheers!

Leave a Reply