Fractal Softworks Forum

Please login or register.

Login with username, password and session length
Advanced search  

News:

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

Author Topic: Very Specific Beam cannon woes  (Read 1362 times)

ElPresidente

  • Commander
  • ***
  • Posts: 152
    • View Profile
Very Specific Beam cannon woes
« on: May 15, 2021, 12:24:51 AM »

I'm trying to basically re-create this, and thus have certain requirements that just...don't work ATM.

https://www.youtube.com/watch?v=vHDxYYHBDZE

The issue is the 9 second charge seqence and long cooldown. The problem with the charge sequence is two fold
- the animation. I really only need several frames for the entire sequence, but they have to repeat themselves. Standard method would mean I would have to have far to many repeating sprites. I know it's possible to customize with code, but I'm terrible at java. I learn best trough exampled. Any example code of something similar?

- the sequence itself. It should charge for 9 seconds, then fire at full strength; instead if starts fireing a weak beam that grows bigger, wider and reached max power after 9 seconds. Any way to change that?

- MAX beam duration. Any way to control it? Flux cost is unreliable.

« Last Edit: May 15, 2021, 03:05:17 AM by ElPresidente »
Logged

Lprsti99

  • Ensign
  • *
  • Posts: 25
    • View Profile
Re: Very Specific Beam cannon woes
« Reply #1 on: May 16, 2021, 12:09:02 PM »

I'm trying to basically re-create this, and thus have certain requirements that just...don't work ATM.

https://www.youtube.com/watch?v=vHDxYYHBDZE

The issue is the 9 second charge seqence and long cooldown. The problem with the charge sequence is two fold
- the animation. I really only need several frames for the entire sequence, but they have to repeat themselves. Standard method would mean I would have to have far to many repeating sprites. I know it's possible to customize with code, but I'm terrible at java. I learn best trough exampled. Any example code of something similar?

- the sequence itself. It should charge for 9 seconds, then fire at full strength; instead if starts fireing a weak beam that grows bigger, wider and reached max power after 9 seconds. Any way to change that?

- MAX beam duration. Any way to control it? Flux cost is unreliable.

Not a modder, but my brain immediately jumps to the Ristreza from Tahlan Shipworks, specifically the Numistri variant. It's got an inbuilt laser that can only be fired after the ship system is charged, which takes 5 seconds after activation, and lasts for 5 more at full charge. Dunno if you can tie your animation to something similar, might be worth looking into.  Also sounds like you'd want to make the weapon fire automatically, instead of just allowing it to be fired.
Logged

Harmful Mechanic

  • Admiral
  • *****
  • Posts: 1340
  • On break.
    • View Profile
Re: Very Specific Beam cannon woes
« Reply #2 on: May 16, 2021, 05:11:06 PM »

You'll want to add this line to your .wpn file:
Code
"beamFireOnlyOnFullCharge":true,
That's it for the easy part. Now the hard part.

The ship AI can't really handle long chargeups. Values greater than 1 in that field are just a bad idea. That said, yeah; look at the Ristreza variant that does something similar. If I were in your shoes, I'd rig up a system that shuts off all energy weapons while it's charging, something that feels good thematically. I would still keep your chargeup pretty short; 5 seconds is reasonable.

You may want to drop a line to Nicke535 here on the forum, as he's the person who was likely responsible for that code.
Logged

ElPresidente

  • Commander
  • ***
  • Posts: 152
    • View Profile
Re: Very Specific Beam cannon woes
« Reply #3 on: May 16, 2021, 11:48:43 PM »

You'll want to add this line to your .wpn file:
Code
"beamFireOnlyOnFullCharge":true,
That's it for the easy part. Now the hard part.

The ship AI can't really handle long chargeups. Values greater than 1 in that field are just a bad idea. That said, yeah; look at the Ristreza variant that does something similar. If I were in your shoes, I'd rig up a system that shuts off all energy weapons while it's charging, something that feels good thematically. I would still keep your chargeup pretty short; 5 seconds is reasonable.

You may want to drop a line to Nicke535 here on the forum, as he's the person who was likely responsible for that code.

Odd. I'm quite sure I've put that in and it still behaves the same... hold on.
Yup, I did put it in. It still seem to start fireing without waiting for 9 seconds.


Code
{
"specClass":"beam",
"id":"vns_reflex_cannon",
"type":"ENERGY",
"size":"LARGE",
"displayArcRadius":1500,

"turretUnderSprite":"",
"turretSprite":"graphics/weapons/animated/vns_reflexcannon/vns_reflex_Cannon_00.png",
"turretGlowSprite":"",
"hardpointSprite":"graphics/weapons/animated/vns_reflexcannon/vns_reflex_Cannon_00.png",
"hardpointGlowSprite":"",

"numFrames":12,
"frameRate":10,
"interruptibleBurst":true,
"beamFireOnlyOnFullCharge":true,
"turretOffsets":[12, 0],
"turretAngleOffsets":[0],
"hardpointOffsets":[12, 0],
"hardpointAngleOffsets":[0],

"fringeColor":[250,250,0,100],
"coreColor":[5,0,10,155],
"glowColor":[220,180,0,0],
"width":120.0,
#"textureType":ROUGH,
"textureType":["graphics/fx/vns_beam_core_1.png","graphics/fx/vns_beam_core_HE2.png"],
"textureScrollSpeed":-100.0,
"pixelsPerTexel":5.0,

"animationType":"GLOW",  # NONE, GLOW, MUZZLE_FLASH, SMOKE
"pierceSet":[PROJECTILE_FF,PROJECTILE_NO_FF,PROJECTILE_FIGHTER],
"fireSoundOne":"vns_Reflex_charge",
"fireSoundTwo":"vns_Reflex_fire",
"fireSoundThree":"vns_Reflex_powerdown",

and from weapon_data:
Code
Reflex Cannon,vns_reflex_cannon,5,,50000,1500,2500,,100,30,10,40,1,0.05,1,ENERGY,,3000,9,1,,,,,,,5000,,,,,"SYSTEM,SHOW_IN_CODEX","LR, energy10",,,,,,,,,,,,,,20005


And thanks, I'll look into the Ristreza.

The ship in question only has 4 small weapon slots for PD (and 2 med missiles), so shutting down all energy weapons seems a bit pointless. I might still try to do it, as it sounds right.
Logged

ElPresidente

  • Commander
  • ***
  • Posts: 152
    • View Profile
Re: Very Specific Beam cannon woes
« Reply #4 on: May 17, 2021, 12:46:21 AM »

Not a modder, but my brain immediately jumps to the Ristreza from Tahlan Shipworks, specifically the Numistri variant. It's got an inbuilt laser that can only be fired after the ship system is charged, which takes 5 seconds after activation, and lasts for 5 more at full charge. Dunno if you can tie your animation to something similar, might be worth looking into.  Also sounds like you'd want to make the weapon fire automatically, instead of just allowing it to be fired.

I can't find the Numustri variant in the files. Did you mean the g variant with the Gigantomachia weapon? I'm looking at it right now and the code is strange.

Code
package data.scripts.weapons;

import com.fs.starfarer.api.combat.*;
import com.fs.starfarer.api.util.IntervalUtil;
import org.lazywizard.lazylib.MathUtils;
import org.lazywizard.lazylib.combat.entities.SimpleEntity;
import org.lwjgl.util.vector.Vector2f;

public class tahlan_GigantomachyBeamEffect implements BeamEffectPlugin {

    private IntervalUtil fireInterval = new IntervalUtil(0.2f, 0.3f);
    private IntervalUtil effectInterval = new IntervalUtil(0.2f, 0.3f);
    private boolean wasZero = true;

    public void advance(float amount, CombatEngineAPI engine, BeamAPI beam) {

        if (engine.isPaused()) {
            return;
        }

        CombatEntityAPI target = beam.getDamageTarget();
        if (target instanceof ShipAPI && beam.getBrightness() >= 1f) {
            float dur = beam.getDamage().getDpsDuration();
            // needed because when the ship is in fast-time, dpsDuration will not be reset every frame as it should be
            if (!wasZero) dur = 0;
            wasZero = beam.getDamage().getDpsDuration() <= 0;
            fireInterval.advance(dur);
            if (fireInterval.intervalElapsed()) {
                EmpArcEntityAPI arc =  engine.spawnEmpArc(beam.getSource(), beam.getFrom(), beam.getSource(), beam.getDamageTarget(),
                        DamageType.ENERGY,
                        500f,
                        500f,
                        3000f,
                        "tachyon_lance_emp_impact",
                        beam.getWidth(),
                        beam.getFringeColor(),
                        beam.getCoreColor()
                );
            }
        }
        if (beam.getBrightness() >= 1) {
            effectInterval.advance(engine.getElapsedInLastFrame());
            if (effectInterval.intervalElapsed()) {
                Vector2f point = MathUtils.getRandomPointInCircle(beam.getFrom(), 50f);
                EmpArcEntityAPI arc =  engine.spawnEmpArcPierceShields(beam.getSource(), beam.getFrom(), beam.getSource(),
                        new SimpleEntity(point),
                        DamageType.FRAGMENTATION,
                        0f,
                        0f,
                        75f,
                        null,
                        beam.getWidth() * 0.5f,
                        beam.getFringeColor(),
                        beam.getCoreColor()
                );
            }
        }
    }
}


It seems to only handle spawning of EMP arcs at certain intervals...
Logged

Lprsti99

  • Ensign
  • *
  • Posts: 25
    • View Profile
Re: Very Specific Beam cannon woes
« Reply #5 on: May 17, 2021, 05:59:54 AM »

I can't find the Numustri variant in the files. Did you mean the g variant with the Gigantomachia weapon? I'm looking at it right now and the code is strange.

Yeah, that's the one.
Logged

ElPresidente

  • Commander
  • ***
  • Posts: 152
    • View Profile
Re: Very Specific Beam cannon woes
« Reply #6 on: May 17, 2021, 12:37:41 PM »

I did contact Nike353 and he was of great help.
The only issue left is the sound (chargeup sound doesn't seem to play).


In case anyone needs to know how, basically:

Animation script:
Code
 package data.scripts.weapons;

import com.fs.starfarer.api.combat.*;
import org.lazywizard.lazylib.MathUtils;
import org.lazywizard.lazylib.VectorUtils;
import org.lwjgl.util.vector.Vector2f;

import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class reflex_cannon_animation implements EveryFrameWeaponEffectPlugin {

private int currentFrame = 0;
private int chargeStage = 0;

    @Override
    public void advance(float amount, CombatEngineAPI engine, WeaponAPI weapon) {
        /* Only run when charging up or down */
        if (weapon.getChargeLevel() < 1f)
{
chargeStage = (int) Math.round(weapon.getChargeLevel() * 5); //should return value from 1 to 5
            currentFrame++; /* Go forward one frame */

switch (chargeStage) {
  case 1:
if (currentFrame > 4) {currentFrame = 0;} /* loop frames 0-3 */
weapon.getAnimation().setFrame(currentFrame);/* And set the weapon to use the current frame */
break;
  case 2:
if (currentFrame > 6) {currentFrame = 3;} /* loop frames 3-6 */
weapon.getAnimation().setFrame(currentFrame);
break;
  case 3:
if (currentFrame > 9) {currentFrame = 6;} /* loop frames 6-9 */
weapon.getAnimation().setFrame(currentFrame);
break;
  case 4:
if (currentFrame > 11) {currentFrame = 6;}  /* loop 6 to 11 */
weapon.getAnimation().setFrame(currentFrame);
break;
  default:
//do nothing
weapon.getAnimation().setFrame(0);
break;
}
        }

        /* Run at full charge */
        if (weapon.getChargeLevel() >= 1f)
{
            //currentFrame = 12; /* If we assume frame ID 10 [11th frame in total] is the "fire" frame */
if (currentFrame > 12) {currentFrame = 10;}  /* loop 10 to 12 */

            weapon.getAnimation().setFrame(currentFrame);
        }
    }
}   


weapons file:
Code
	"specClass":"beam",
"id":"vns_reflex_cannon",
"type":"ENERGY",
"size":"LARGE",
"displayArcRadius":1500,
"everyFrameEffect": "data.scripts.weapons.reflex_cannon_animation",

"turretUnderSprite":"",
"turretSprite":"graphics/weapons/animated/vns_reflexcannon/vns_reflex_Cannon_00.png",
"turretGlowSprite":"",
"hardpointSprite":"graphics/weapons/animated/vns_reflexcannon/vns_reflex_Cannon_00.png",
"hardpointGlowSprite":"",

"numFrames":12,
"frameRate":0,
"interruptibleBurst":false,   //should be here fo5 this weapon
"beamFireOnlyOnFullCharge":true,
"turretOffsets":[12, 0],
"turretAngleOffsets":[0],
"hardpointOffsets":[12, 0],
"hardpointAngleOffsets":[0],

"fringeColor":[250,250,0,100],
"coreColor":[5,0,10,155],
"glowColor":[220,180,0,0],
"width":120.0,
#"textureType":ROUGH,
"textureType":["graphics/fx/vns_beam_core_1.png","graphics/fx/vns_beam_core_HE2.png"],
"textureScrollSpeed":-100.0,
"pixelsPerTexel":5.0,

"animationType":"GLOW",  # NONE, GLOW, MUZZLE_FLASH, SMOKE
"pierceSet":[PROJECTILE_FF,PROJECTILE_NO_FF,PROJECTILE_FIGHTER],
"fireSoundOne":"vns_Reflex_charge",
"fireSoundTwo":"vns_Reflex_fire",
"fireSoundThree":"vns_Reflex_powerdown",
}

Set "burst size" (the amount of seconds the beam is at full strength) as well as "burst delay" (the amount of seconds the weapon has to wait between firing two bursts). Without these set, the weapon doesn't count as a burst beam.
Logged

ElPresidente

  • Commander
  • ***
  • Posts: 152
    • View Profile
Re: Very Specific Beam cannon woes
« Reply #7 on: May 18, 2021, 03:28:18 AM »

I'll add one more note: with this setup weapon sounds don't work correctly, so you'll have to comment them out and control them from the script.
Logged

ElPresidente

  • Commander
  • ***
  • Posts: 152
    • View Profile
Re: Very Specific Beam cannon woes
« Reply #8 on: May 18, 2021, 11:55:03 AM »

One final snafu with the weapons - the sounds.
Got everything to work properly EXCEPT the regular fire sound.

Triggering a sound from script just means it's re-played every frame, which sound TERRIBLE.
So I made some checks for the chargup and chargedown, to make sure they trigger only once. As it works, the chargup audio lasts as long as the startup sequence, so I fire it once and it's OK.

but I cannot do the same for the fire....unless I re-do the sound to be the exact same length as fire duration.



Code
 package data.scripts.weapons;

import com.fs.starfarer.api.Global;
import com.fs.starfarer.api.combat.*;
import org.lazywizard.lazylib.MathUtils;
import org.lazywizard.lazylib.VectorUtils;
import org.lwjgl.util.vector.Vector2f;

import java.awt.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.fs.starfarer.api.util.Misc.ZERO;

public class reflex_cannon_animation implements EveryFrameWeaponEffectPlugin {

private int currentFrame = 0;
private int chargeStage = 0;
private boolean hasRun = false;
private boolean isChargeSoundPlaying = false;
private boolean isPowerdownSoundPlaying = false;

    @Override
    public void advance(float amount, CombatEngineAPI engine, WeaponAPI weapon) {


Vector2f point = weapon.getLocation();

//NEW CODE FOR SOUND CONTROL AND ANIMATION COMBINED
if (weapon.getChargeLevel() >= 1f) {
hasRun = true;
// We are in main fire sequence for all code in here
Global.getSoundPlayer().playSound("vns_Reflex_fire", 1f, 1f, point, ZERO);  //this is the problem. This sound should loop, not re-start constatnly

} else if (weapon.getChargeLevel() <= 0f) {
hasRun = false;
// We are not firing for all code in here
weapon.getAnimation().setFrame(0);
isPowerdownSoundPlaying = false;
isChargeSoundPlaying = false;

} else {
if (!hasRun) {
// We are in charge-up here
if(!isChargeSoundPlaying)
{
Global.getSoundPlayer().playSound("vns_Reflex_charge", 1f, 1f, point, ZERO);
isChargeSoundPlaying = true;
}

chargeStage = (int) Math.round(weapon.getChargeLevel() * 5); //should return vaue from 1 to 5
currentFrame++; // Go forward one frame

switch (chargeStage) {
  case 1:
if (currentFrame > 4) {currentFrame = 0;} // loop frames 0-3
weapon.getAnimation().setFrame(currentFrame);// And set the weapon to use the current frame
break;
  case 2:
if (currentFrame > 6) {currentFrame = 3;} // loop frames 3-6
weapon.getAnimation().setFrame(currentFrame);
break;
  case 3:
if (currentFrame > 9) {currentFrame = 6;} // loop frames 6-9
weapon.getAnimation().setFrame(currentFrame);
break;
  case 4:
if (currentFrame > 11) {currentFrame = 6;}  // loop 6 to 11
weapon.getAnimation().setFrame(currentFrame);
break;
  case 5:
if (currentFrame > 12) {currentFrame = 10;}  // loop 10 to 12
weapon.getAnimation().setFrame(currentFrame);
break;
  default:
//do nothing
weapon.getAnimation().setFrame(0);
break;
}


} else {
// We are in charge-down here
//currentFrame++; // Go forward one frame
//if (currentFrame > 4) {currentFrame = 1;} // loop frames 1-4
//weapon.getAnimation().setFrame(currentFrame);
weapon.getAnimation().setFrame(0);

isChargeSoundPlaying = false;

if(!isPowerdownSoundPlaying) //to prevent audio re-start and spam
{
Global.getSoundPlayer().playSound("vns_Reflex_powerdown", 1f, 1f, point, ZERO);
isPowerdownSoundPlaying = true;
}

}
}
}
}

« Last Edit: May 18, 2021, 11:57:19 AM by ElPresidente »
Logged