1
Modding / Re: Misc modding questions that are too minor to warrant their own thread
« on: Today at 12:17:15 AM »ShipSystemAPI.deactivate() *should* work, I believe, so that may be worth revisiting. If your ship system code just assumes the 20 second duration and does stuff, that wouldn't be interrupted, though, so depending on how it's implemented... well, it's just hard to say.
Thank you!! The ship.getTravelDrive().deactivate() methodology worked, BUT yes it must only be called after the GFX/final exit from warp is executed. Appreciate the help!
crimescene
Code: java
public class fed_TravelDriveStats extends BaseShipSystemScript {
public static Logger log = Global.getLogger(fed_TravelDriveStats.class);
@Override
public void apply(MutableShipStatsAPI stats, String id, State state, float effectLevel) {
//ShipAPI ship = null;
CombatEngineAPI engine = Global.getCombatEngine();
if (engine == null) {
return;
}
if (engine.isPaused()) {
//return;
}
Boolean validPlayerShip = false;
// We can get ship APIs from a MutableShipStatAPI using getEntity()
if (stats.getEntity() instanceof ShipAPI) { // Needed? maybe not, but I didn't touch bc im lazy
ShipAPI ship = (ShipAPI) stats.getEntity();
// Magic-ish number, will use later to make escaping fleets spawn inside the map (if they are far OoB, they autoescape)
float retreatNerfMult = 0.05f;
// We want ships to warp in from offscreen when deployed
// We only want do this for newly deployed ships once.
// So we will use some custom data (or lack thereof) to make sure the move-back is a one-off
// Reminder: ship_systems.csv matters a lot to this travel drive. It runs on strict 20sec intervals
// so that unfortunately means there are a few magic numbers here that mostly make it work as intended.
// literally ill-advised modifications hullmod, but in IRL
// Look for custom data tag to prevent double move-backs.
// We will insert it once we move the ship back, but simply run stat changes/gfx if we see it.
if (!ship.getCustomData().containsKey(id)) {
// DEBUG
/*log.info(
"Moving back - Ship ID: " + ship.getId()
+ " | Ship FMID: " + ship.getFleetMemberId()
+ " | Ship TimeDeployed: " + ship.getFullTimeDeployed()
+ " | Ship Name: " + ship.getName());
for ( Object value : ship.getCustomData().values()) {
log.info(value.toString());
}
log.info("Esc Dburn Dur " + engine.getContext().getEscapeDeploymentBurnDuration());
log.info("Flank Dburn Dist " + engine.getContext().getFlankDeploymentDistance());
log.info("Init Dburn Dur " + engine.getContext().getInitialDeploymentBurnDuration());
log.info("Init Esc Range " + engine.getContext().getInitialEscapeRange());
log.info("Init Num Step " + engine.getContext().getInitialNumSteps());
log.info("Init Step Size " + engine.getContext().getInitialStepSize());
log.info("Stdoff range " + engine.getContext().getStandoffRange());
log.info("Norm Dburn Dur " + engine.getContext().getNormalDeploymentBurnDuration());
log.info("Other goal " + engine.getContext().getOtherGoal());
log.info("player goal " + engine.getContext().getPlayerGoal());*/
// Look for burn duration for new ships depending on battle context.
// It appears ships don't ALWAYS burn in from offscreen, ex) they are being pursued and start in the lower area
// or are pushed up to reinforce a station. Still WIP determination through playtesting.
// First magic number. Gotta test via debugging printing log messages in all the various combat situations.
// I think it's usually 1.5f? NormalDeploymentBurn is 6, and EscapeDeploymentBurn is 1.5 as well.
// Don't quote me on that though
float initalBurnSeconds = engine.getContext().getInitialDeploymentBurnDuration();
// Second magic number, correlating with ship_system.csv's ACTIVE time for this travel drive.
// Don't ask me why or how it works. Because it kinda doesn't if put under real scrutiny.
float penalty = 10000f - engine.getMapHeight() * 0.03f;
// So we need to deal with ships that sometimes CANNOT be moved offscreen, lest they auto-retreat
// Thus we start with the player escaping.
if (engine.getContext().getPlayerGoal() != null && engine.getContext().getPlayerGoal().equals(FleetGoal.ESCAPE)) {
// Magic number *** for NPC ships, don't make pursing starfed AI hostiles start too close yknow?
penalty = penalty - (1000f + engine.getMapHeight() * 0.03f);
// But here we make player warp-ins start much closer, but move much slower.
// This means they don't run off the map but still work with the 20 second ACTIVE time defined in the csv.
if (ship.getOwner() == engine.getPlayerShip().getOwner() || ship.isAlly()) {
retreatNerfMult = 0.3333333333f;
initalBurnSeconds = engine.getContext().getEscapeDeploymentBurnDuration() * 0.15f;
stats.getMaxSpeed().modifyMult(id, retreatNerfMult);
//Probably the most unreliable of magic numbers. Doesn't always place it on-point in retreating formations.
penalty = penalty * 0.4f - (1200f - engine.getMapHeight() * 0.05f);
}
}
// CASE: Enemy fleet is escaping. We can't move them too far back off the map or they autoretreat.
if (engine.getContext().getOtherGoal() != null && engine.getContext().getOtherGoal().equals(FleetGoal.ESCAPE)) {
// Wohoo magic numbers
initalBurnSeconds = engine.getContext().getEscapeDeploymentBurnDuration() * 0.15f;
if (ship.getOwner() == engine.getPlayerShip().getOwner() || ship.isAlly()) {
// What I determined to be the distance that friendly ships will burn to
// Even if starfed warping ships rushing past might make them stop halfway. Oops.
penalty = penalty - (2000f + engine.getMapHeight() * 0.05f);
} else {
// this makes them really slow so they can start kinda on the map and not auto retreat.
retreatNerfMult = 0.16666666666f;
initalBurnSeconds = engine.getContext().getEscapeDeploymentBurnDuration() * 0.15f;
stats.getMaxSpeed().modifyMult(id, retreatNerfMult);
// A magic number I determined would make them start relatively fairly, like normal retreating ships.
penalty = penalty * 0.2f - (1200f - engine.getMapHeight() * 0.03f);
}
}
// We need to know how theoretically far back these ships are moving.
// So we calcualte the burn time * the mostly-hard speed limit of combat entities, not accounting for time mults.
float burnDistanceProbablyCovered = ((initalBurnSeconds * 610f));
// Double that for our new burn time, as we will be moving back an additional distance.
// Honestly these numbers are messed up or don't work at all...
// They all rely on the 20 second ACTIVE time in the ship_systems.csv, you can't really
// So you can't make ship travel drives turn on a set amount of time I think.
float newTimeToBurn = ((initalBurnSeconds));
// log.info("burnDistanceProbablyCovered " + burnDistanceProbablyCovered);
// log.info("penalty " + penalty);
// Now we determine what direciton we need to shift the ship "backwards", depending on heading.
// Pretty sure the center of the map is 0,0 in terms of X, Y, with -X being the left and -Y being the south.
// You can probably do this moveback purely by manipulating vectors... but I am not smart.
if (ship.getFacing() == 0f) {
// Facing 0 means facing to the left, so we add more X value to make it slide right.
ship.getLocation().setX(ship.getLocation().getX() - burnDistanceProbablyCovered - (penalty * 1.05f));
ship.turnOnTravelDrive(newTimeToBurn);
} else if (ship.getFacing() == 90f) {
// Facing 90 means facing upwards, so we reduce Y value to make the ship go lower
ship.getLocation().setY(ship.getLocation().getY() - burnDistanceProbablyCovered - penalty * 0.98f);
ship.turnOnTravelDrive();
} else if (ship.getFacing() == 180f) {
// Facing 180 means facing to the right, so we reduce the X value to make it slide left.
ship.getLocation().setX(ship.getLocation().getX() + burnDistanceProbablyCovered + (penalty * 1.05f));
ship.turnOnTravelDrive(newTimeToBurn);
} else if (ship.getFacing() == 270f) {
// Facing 270 means facing downards, so we add more Y value to make the ship go higher.
ship.getLocation().setY(ship.getLocation().getY() + burnDistanceProbablyCovered + penalty * 0.98f );
ship.turnOnTravelDrive(newTimeToBurn);
} else {
// If a ship is NOT in a designated facing, make it leave warp via the OUT state.
ship.getTravelDrive().forceState(ShipSystemAPI.SystemState.OUT, 0f);
}
//}
// Moving and warping is done, so now we add the data value to ensure it doesn't get moved back again.
// The TRUE value is used to signify the ship has been moved back out of the map.
// A FALSE value in this custom data entry will prevent a second moveback given the customData exists at all, BUT...
// we will assume that FALSE means it has left warp, and FALSE can only be gained from the OUT function.
// This entire complexity is because those allied ships you can reinforce in battle will have ACTIVE traveldrives
// that make them invisible and non-collidable. Unfortunately these ghost ships will remain ghosts because
// they refuse to enter the OUT stage unless the ACTIVE code has an exit somehow... hence the initial TRUE
// value indicating that the ship has not "left" warping and should probably leave via being forced into the OUT
// stage, thereby becoming tangible again and gaining a FALSE data value.
ship.setCustomData(id, true);
}
// Do not keep doing graphics/stat mod stuff when the screen is paused
if (engine.isPaused()) {
return;
}
if (null != state) {
switch (state) {
case IN: // UNUSED, probably, ship has no "in" time definied in shipsystems.csv
ship.setCustomData(id, true);
ship.setAlphaMult(1 - 1 * effectLevel);
ship.setCollisionClass(CollisionClass.FIGHTER);
// If a ship has modules, we need it to fade out/disable fleetshields too.
if (ship.isShipWithModules()) {
List<ShipAPI> modules = ship.getChildModulesCopy();
for (ShipAPI childModule : modules) {
childModule.setCollisionClass(CollisionClass.FIGHTER);
// Fookin null checks
if (childModule.getShield() != null) {
if (childModule.getShield().getType() == (ShieldAPI.ShieldType.FRONT) || (childModule.getShield().getType() == ShieldAPI.ShieldType.OMNI)) {
// Overkill never fails
childModule.getShield().setArc(0f);
childModule.getShield().setRadius(0f);
}
}
childModule.setAlphaMult(1 - 0.8f * effectLevel);
}
}
// Gee, how come mom lets you have three explosions instead of one!
// ... because I am a master of gfx, that's why.
fed_spawnTravelDriveExplosion(stats, ship, effectLevel);
fed_spawnTravelDriveExplosion(stats, ship, effectLevel);
fed_spawnTravelDriveExplosion(stats, ship, effectLevel);
break;
case ACTIVE:
// Hard to get allies already deployed ( IE you are reinforcing an existing battle ) out of this state.
// The if statement immediately below tries to solve that, it disqualifies most ships from using TD.
// But you can use the warp drive if retreating.
if (ship.getCustomData().get(id).equals(true) && !ship.isRetreating() && ship.getFullTimeDeployed() > 20f) {
ship.setCustomData(id, false);
effectLevel = 0;
ship.getTravelDrive().forceState(ShipSystemAPI.SystemState.OUT, 0f);
}
// Just make sure we know the ship has warped, cannot tell if it goes through logic above or not.
ship.setCustomData(id, true);
// Make ship not bonk things when warping.
ship.setAlphaMult(1 - 0.9f * effectLevel);
ship.setPhased(true);
ship.setCollisionClass(CollisionClass.FIGHTER);
// Zoom
stats.getMaxSpeed().modifyFlat(id, 600f);
stats.getAcceleration().modifyFlat(id, 600f);
// Only way to make it seem literally FTL, like tesseracts engaging temporal shell
stats.getTimeMult().modifyPercent(id, 600 * effectLevel);
// Some prerandomized variables to argument size in cosmetic particle calls
// RENDER PARTICLES FOR WARPING SHIPS
/*ship.addAfterimage(
new Color(125, 125, 1, 255), //color
MathUtils.getRandomNumberInRange(-5f, 5f), //X Location rel to ship center
MathUtils.getRandomNumberInRange(-5f, 5f), //Y Location rel to ship center
(stats.getEntity().getVelocity().getX()) * -1f, //X Velocity
(stats.getEntity().getVelocity().getY()) * -1f, //Y Velocity
5f, //Max Jitter, units of distance
0f, //Fade-in time
0f, //Regular duration
0.5f, //Fade-out time
true, //Is Additive (whiteness adds up)
true, //Combine with sprite color
true); //Above ship
*/
// GD modules need afterimages/no hitbox too waaaah
if (ship.isShipWithModules()) {
List<ShipAPI> modules = ship.getChildModulesCopy();
for (ShipAPI childModule : modules) {
childModule.addAfterimage(
new Color(125, 100, 25, 55), //color
MathUtils.getRandomNumberInRange(-5f, 5f), //X Location rel to ship center
MathUtils.getRandomNumberInRange(-5f, 5f), //Y Location rel to ship center
(stats.getEntity().getVelocity().getX()) * -1f, //X Velocity
(stats.getEntity().getVelocity().getY()) * -1f, //Y Velocity
5f, //Max Jitter, units of distance
0f, //Fade-in time
0f, //Regular duration
0.2f, //Fade-out time
true, //Is Additive (whiteness adds up)
true, //Combine with sprite color
true);
childModule.setCollisionClass(CollisionClass.FIGHTER);
// Morrrre null checks
if (childModule.getShield() != null) {
if (childModule.getShield().getType() == (ShieldAPI.ShieldType.FRONT) || (childModule.getShield().getType() == ShieldAPI.ShieldType.OMNI)) {
// Overkill
childModule.getShield().setArc(0f);
childModule.getShield().setRadius(0f);
}
}
childModule.setAlphaMult(1 - 0.8f * effectLevel);
}
}
// We don't always want to render the warp trail, keeps it lighter
fed_spawnTravelDriveWake(stats, ship, effectLevel);
break;
case OUT:
// Hard to trigger this unless forced when with exisiting battles with allies you are reinforcing.
// See first lines of code in ACTIVE state contents above.
ship.setCustomData(id, false);
ship.setPhased(false);
stats.getMaxSpeed().unmodify(id);
float shipExitSpeed = (stats.getDeceleration().modified) * 10 + ship.getMutableStats().getZeroFluxSpeedBoost().modified;
//engine.addFloatingText(ship.getLocation(), "Y: " + ship.getLocation().y, 15f, Color.RED, ship, 1f, 0.5f);
if (shipExitSpeed > 500f) {
shipExitSpeed = 500f;
}
if (ship.getHullSize().equals(ShipAPI.HullSize.CAPITAL_SHIP)) {
shipExitSpeed = (220f);
}
ship.getVelocity().scale(shipExitSpeed / (ship.getVelocity().length()));
stats.getTimeMult().unmodify(id);
ship.setAlphaMult(1 - 0.8f * effectLevel);
// Give modules back shields as we come out of warp.
//if (ship.getVelocity().length() <= ship.getMaxSpeed()) { //&& ship.getFullTimeDeployed() > 1) {
if (ship.isShipWithModules()) {
List<ShipAPI> modules = ship.getChildModulesCopy();
for (ShipAPI childModule : modules) {
if (!childModule.getVariant().hasHullMod("fed_fleetshieldeffect")) {
childModule.setCollisionClass(CollisionClass.SHIP);
}
childModule.ensureClonedStationSlotSpec();
if (childModule.getShield() != null) {
if (childModule.getShield().getType() == (ShieldAPI.ShieldType.FRONT) || (childModule.getShield().getType() == ShieldAPI.ShieldType.OMNI)) {
childModule.getShield().setType(childModule.getHullSpec().getShieldType());
childModule.getShield().setArc(childModule.getHullSpec().getShieldSpec().getArc());
// This doesn't nuke shields because FederationDesign.java sets shield radiuses constantly.
childModule.getShield().setRadius(0f);
}
}
childModule.setAlphaMult(1f);
}
}
stats.getEntity().setCollisionClass(CollisionClass.SHIP);
ship.getTravelDrive().deactivate();
fed_spawnTravelDriveExplosion(stats, ship, effectLevel);
fed_spawnTravelDriveExplosion(stats, ship, effectLevel);
fed_spawnTravelDriveExplosion(stats, ship, effectLevel);
// Immediate sound based on nearby arrivals
Global.getSoundPlayer().playSound(ship.getTravelDrive().getSpecAPI().getOutOfUsesSound(), 1, 1, ship.getLocation(), new Vector2f(0f, 0f));
// Faint UI sound for distant arrivals
Global.getSoundPlayer().playUISound(ship.getTravelDrive().getSpecAPI().getOutOfUsesSound(), 1, 0.1f);
// }
break;
default: //Unused
break;
}
}
/* DEBUGGING
log.info(
" | Ship Name: " + ship.getName()
+ " | Ship TD State: " + ship.getTravelDrive().getState()
+ " | Ship Effect Level: " + ship.getTravelDrive().getEffectLevel()
+ " | Ship TimeDeployed: " + ship.getFullTimeDeployed()
+ " | Combat Time Elapsed: " + engine.getTotalElapsedTime(false)
+ " HAS DATA: " + ship.getCustomData().containsKey(id)
);*/
}
}
@Override
public void unapply(MutableShipStatsAPI stats, String id
) {
stats.getTimeMult().unmodify(id);
stats.getMaxSpeed().unmodify(id);
stats.getAcceleration().unmodify(id);
stats.getDeceleration().unmodify(id);
stats.getMaxTurnRate().unmodify(id);
stats.getMaxTurnRate().unmodify(id);
stats.getTurnAcceleration().unmodify(id);
stats.getTurnAcceleration().unmodify(id);
Global.getCombatEngine().getTimeMult().unmodify(id);
}
}
[close]