I just realized. I miscommunicated the problem. This is for my Armor Regeneration Intrinsic mod, as well as Command point regeneration.
While the second might be covered by this, the first won't be.
Specifically, I need to be able to get a multiplier to apply to the attached data for each ship based on the ship's captain and that of the fleet commander. Currently, I am picking all existing ships, and going from there, rather than, I guess, picking each fleet in battle, or however that is supposed to work.
package data.scripts.plugins;
import com.fs.starfarer.api.combat.ArmorGridAPI;
import com.fs.starfarer.api.combat.EveryFrameCombatPlugin;
import com.fs.starfarer.api.combat.CombatEngineAPI;
import com.fs.starfarer.api.combat.CombatEntityAPI;
import com.fs.starfarer.api.combat.ShipAPI;
import com.fs.starfarer.api.combat.ViewportAPI;
import com.fs.starfarer.api.combat.ShipVariantAPI;
import com.fs.starfarer.api.fleet.FleetMemberAPI;
import com.fs.starfarer.api.input.InputEventAPI;
import com.fs.starfarer.api.impl.campaign.ids.HullMods;
import com.fs.starfarer.api.Global;
import org.apache.log4j.Logger;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
import java.util.Collection;
/**
*
* @author Ranakastrasz
* fragments derived from orost's Armor Repair Hullmod plugin
*
* This script is intended to allow all ships to regenerate in combat, and reduce the difference in attrition between shield and armor-based ships.
*/
public static int getCommanderRepairSkill(FleetSide side)
{
// First we have to find a fleet member, any fleet member
CombatFleetManagerAPI fm = Global.getCombatEngine().getFleetManager(side);
List<FleetMemberAPI> members = fm.getDeployedCopy();
if (members.isEmpty())
{
members = fm.getReservesCopy();
}
if (members.isEmpty())
{
return 0;
}
// Use the fleet member to retrieve this side's fleet commander
PersonAPI captain = members.get(0).getFleetCommanderForStats();
if (captain == null)
{
return 0;
}
// Return the fleet commander's skill
MutableCharacterStatsAPI stats = captain.getStats();
return (int) stats.getSkillLevel(Skills.FIELD_REPAIRS);
}
//Yes. Check out the BeamAPI. You might want to getDamageTarget() then cast it as a ShipAPI, then get the FluxTracker for the ship's ShipAPI interface then increaseFlux(amount,true) through the FluxTracker to give give the ship hard flux.
class Constants {
//Up to how much HP in total will be repaired, in multiples of ship's total armor HP
//Default: 1
public static final float TOTAL_REPAIR_FACTOR = 1f;
//How much CR will be lost to repair the maximum amount of armor, in fractions of 100%
//Default: 0.1 (10%)
//public static final float TOTAL_CR_LOSS = 0.1f;
//How much of damage taken will be repaired, in fractions of 100%
//Default: 0.8 (80%)
//public static final float BASE_REPAIR_EFFICIENCY = 0.8f;
//How long after taking damage until repair starts, in seconds
//Default: 10
public static final float ARMOR_REPAIR_TIMEOUT = 5f;
//Base repair rate, in HP per armor cell per second
//Default: 0.2
public static final float ARMOR_BASE_REPAIR_RATE = 0.5f;
//Scaling repair rate, in percent per second
//Default: 0.005 (0.5% per second)
public static final float ARMOR_REPAIR_RATE = 0.005f;
public static final float HULL_BASE_REPAIR_RATE = 5f;
public static final float HULL_REPAIR_RATE = 0.002f;
public static final float HULL_REPAIR_MAX = 0.8f;
//How the repair efficiency drops off over time
//1 is linear, 2 is default, higher values start dropping off later but drop more sharply
//See curves.png in root directory of the mod for reference
//public static final float EFFICIENCY_CURVE_POWER = 2f;
//
//
//
//
// Repair rate NEEDS to be based on flux. Otherwise flux capacity/venting won't do anything to adjust repair.
//
//
// each tile regens proportional to adjacent tiles. 20% from 4 adj, 5% from diagonals.
// Center 1/2/4 tiles regen at 100/50/25% bonus rate, potentially doubled regen rate (not that that will matter)
// Edge of hull gets no bonus from extra tiles.
//
//
// Current armor per cell is 1/15 of rated value. Not sure where constant, if applicable, is stored.
//
//
// Armor rate + for higher armor fractions
// Lower for each ship tier??
// No, lower based on ship size.
// Wolf @10/tile
// Medusa @ 20/tile
// Hound @ 26.66/tile
//
// Hound should be faster than medusa by significantly more due to lower size.
//
// Base rate of 1/second, + 0.02%/second.
// Wolf -> 1 + 10*0.02 = 1 + 0.2 or 1.2/sec, or 8.33 sec
//
//public static final float ARMOR_BASE_REPAIR_RATE = 1.0f;
//Scaling repair rate, in percent per second
//Default: 0.005 (0.5% per second)
//public static final float ARMOR_REPAIR_RATE = 0.02f;
}
class ShipArmorData {
public ArmorGridAPI armorGrid;
public int armorCellsX, armorCellsY;
public float[][] sinceLastDamage;
public float[][] expectedRepair;
public float[][] armorCells;
public float repairCoef;
//public float repairEfficiency;
//public float totalRepaired;
//public float totalRepairedLast;
//public float totalCRLost;
//public float totalRepairCapacity;
public float maxArmor;
public boolean initialArmorLoaded;
public boolean CRSynched = false;
//public RepairTrackerAPI RepairTracker;
public ShipArmorData(ShipAPI ship)
{
//repairEfficiency = Constants.BASE_REPAIR_EFFICIENCY;
//totalRepaired = 0f;
//totalRepairedLast = 0f;
//totalCRLost = 0f;
armorGrid = ship.getArmorGrid();
maxArmor = armorGrid.getMaxArmorInCell();
float[][] armorCellsT = armorGrid.getGrid();
armorCellsX = armorCellsT.length;
armorCellsY = armorCellsT[0].length;
//totalRepairCapacity = armorGrid.getArmorRating() * Constants.TOTAL_REPAIR_FACTOR * armorCellsX * armorCellsY / 15f;
sinceLastDamage = new float[armorCellsX][armorCellsY];
armorCells = new float[armorCellsX][armorCellsY];
//expectedRepair = new float[armorCellsX][armorCellsY];
initialArmorLoaded = false;
repairCoef = 1.0f;
}
}
public class ArmorRepair implements EveryFrameCombatPlugin {
private transient Logger log;
private Logger getLog()
{
if (log == null) log = Global.getLogger(ArmorRepair.class);
return log;
}
Map<String, ShipArmorData> Ships = new HashMap<String, ShipArmorData>();
private static CombatEngineAPI engine;
@Override
public void advance(float amount,List<InputEventAPI> events)
{
if (engine.isPaused())
{
return;
}
for (ShipAPI ship : engine.getShips())
{
/*FluxTrackerAPI fluxTracker = ship.getFluxTracker()
MutableShipStatsAPI mutableStats = getMutableStats()
float fluxLevel = fluxTracker.getFluxLevel
float availableFlux = mutableStats.getFluxDissipation()
float usedFlux = 0
if (fluxLevel < 0.1)
{
//
}
else if (fluxLevel < 0.5)
{
availableFlux *= 0.5
}
else
{
}*/
//if (ship.isAlive())
{
String Id = ship.getFleetMemberId();
ShipArmorData armorData;
if(Id != null)
{
//getLog().info("ID = "+Id);
armorData = (ShipArmorData) Ships.get(Id);
}
else
{
//getLog().info("Hash = "+ship.hashCode());
armorData = (ShipArmorData) Ships.get("" + ship.hashCode());
}
if (armorData == null)
{
armorData = new ShipArmorData(ship);
if(Id != null)
{
Ships.put(ship.getFleetMemberId(), armorData);
}
else
{
Ships.put("" + ship.hashCode(), armorData);
}
}
if(!armorData.initialArmorLoaded)
{// Initilized Armor values.
getLog().info("Armor("+ship.getVariant().getFullDesignationWithHullName()+") = "+armorData.maxArmor);
for(int x = 0; x < armorData.armorCellsX; x++)
{
for(int y = 0; y < armorData.armorCellsY; y++)
{
armorData.armorCells[x][y] = armorData.armorGrid.getArmorValue(x, y);
}
}
armorData.initialArmorLoaded = true;
Collection<java.lang.String> hullMods = ship.getVariant().getHullMods();
if (hullMods.contains("autorepair"))
{
armorData.repairCoef *= 1.5;
// Need a list of some kind and a loop, and a config option for extra hull mods.
}
//ship.getFle
// ShipAPI -> fleetmemberAPI -> captain, getfleetcommanderforstats.
// apply commander's repair skill here as well.
}
boolean needRepairs = false;
int oldestTime;
for(int x = 0; x < armorData.armorCellsX; x++)
{
for(int y = 0; y < armorData.armorCellsY; y++)
{
float armorValue = armorData.armorGrid.getArmorValue(x, y);
if(armorValue < armorData.armorCells[x][y]) // Took damage.
{
armorData.sinceLastDamage[x][y] = 0f;
}
else
{
armorData.sinceLastDamage[x][y] += amount; // Increment time.
}
armorData.armorCells[x][y] = armorValue; // record new value for future detection
}
}
for(int x = 0; x < armorData.armorCellsX; x++)
{
for(int y = 0; y < armorData.armorCellsY; y++)
{
float armorValue = armorData.armorGrid.getArmorValue(x, y);
if(armorData.sinceLastDamage[x][y] > Constants.ARMOR_REPAIR_TIMEOUT && armorValue < armorData.maxArmor/* && armorData.expectedRepair[x][y] > 0*/)
{// It has been long enough for repairs to start in this cell, AND repairs are possible, AND we expect repairs here...
//float maxRepairFromExpected = armorData.expectedRepair[x][y];// * armorData.repairEfficiency;
float maxRepairFromRate = amount * armorData.repairCoef * (Constants.ARMOR_BASE_REPAIR_RATE + (armorData.maxArmor * Constants.ARMOR_REPAIR_RATE));
/*float adjustment = 0f;
for (int xz = Math.max(x-1,0); xz <= Math.min(x+1,armorData.armorCellsX); xz++)
{
for (int yz = Math.max(y-1,0); yz <= Math.min(y+1,armorData.armorCellsY); yz++)
{
float weight = 4f;
if (Math.abs(xz-x) == 1)
{
weight = weight - 1f;
}
if (Math.abs(yz-y) == 1)
{
weight = weight - 1f;
}
if (weight != 4f)
{
if(armorData.armorGrid.getArmorValue(xz, yz)/armorData.maxArmor > 0.9f)
{
adjustment+= weight;
}
getLog().info("weight("+xz+","+yz+") = "+weight);
}
else
{
getLog().info("Invalid weight("+xz+","+yz+") = "+weight);
}
}
}
adjustment = adjustment;
if (adjustment != 0f)
{
getLog().info("adjustment("+x+","+y+") = "+adjustment);
}*/
float maxRepairAdjusted = maxRepairFromRate;// * adjustment;
float repairAmount = Math.min(armorData.maxArmor - armorValue, maxRepairAdjusted);
//repairAmount = Math.min(armorData.maxArmor - armorValue, repairAmount);
armorData.armorGrid.setArmorValue(x, y, armorValue + repairAmount);
/*if(maxRepairFromExpected < maxRepairFromRate)
{
armorData.expectedRepair[x][y] = 0;
}
else
{
armorData.expectedRepair[x][y] -= maxRepairFromRate;// / armorData.repairEfficiency;
}*/
//armorData.totalRepaired += repairAmount;
}
}
}
// Hull Regen second
{
float hitpoints = ship.getHitpoints();
float maxHitpoints = ship.getMaxHitpoints();
//float toRepair = (maxHitpoints * Constants.HULL_REPAIR_RATE) + Constants.HULL_BASE_REPAIR_RATE
float repairWanted = maxHitpoints - hitpoints;
float repairPossible = amount * armorData.repairCoef * (Constants.HULL_BASE_REPAIR_RATE + (maxHitpoints * Constants.HULL_REPAIR_RATE));
float repairAmount = Math.min(repairWanted, repairPossible);
hitpoints += repairAmount;
ship.setHitpoints(hitpoints);
}
}
}
}
@Override
public void init(CombatEngineAPI eng) {
engine = eng;
}
@Override
public void renderInUICoords(ViewportAPI viewport) {
}
@Override
public void renderInWorldCoords(ViewportAPI viewport) {
}
}