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: Get commander's skills from ship  (Read 3423 times)

Ranakastrasz

  • Admiral
  • *****
  • Posts: 702
  • Prince Corwin of Amber
    • View Profile
Get commander's skills from ship
« on: December 03, 2015, 09:27:01 PM »

I need to be able to access the level of field repairs, as well as the +command point trait, from inside an EveryFrameCombatPlugin, belonging to the owning fleet's supreme commander, and/or it's pilot. I have no idea how to do this.
Logged
I think is easy for Simba and Mufasa sing the Circle of Life when they're on the top of the food chain, I bet the zebras hate that song.

Cigarettes are a lot like hamsters. Perfectly harmless, until you put one in your mouth and light it on fire

LazyWizard

  • Global Moderator
  • Admiral
  • *****
  • Posts: 1363
    • View Profile
    • GitHub Profile
Re: Get commander's skills from ship
« Reply #1 on: December 03, 2015, 10:46:27 PM »

So you want to get the level of the actual campaign skill from within a battle? It's actually a bit tricky as the combat and campaign layers are very loosely linked.

This code is untested, but it should work:
Code: java
    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); 
    }
(there has to be a better way of doing this)


Edit: since the bonus from Advanced Tactics is 1 per level, you can just swap out Skills.FIELD_REPAIRS for Skills.ADVANCED_TACTICS to get the bonus to command points from that skill.

If you wanted to know exactly how many total command points they had, it'd be:
Code: java
    public static int getCommandPointsAtStart(FleetSide side, boolean ally)
    {
        CombatFleetManagerAPI fm = Global.getCombatEngine().getFleetManager(side);
        return (int) fm.getTaskManager(ally).getCommandPointsStat().getModifiedValue();
    }

And if you just want to know how many they currently have remaining, that'd be:
Code: java
    public static int getCommandPointsRemaining(FleetSide side, boolean ally)
    {
        CombatFleetManagerAPI fm = Global.getCombatEngine().getFleetManager(side);
        return fm.getTaskManager(ally).getCommandPointsLeft();
    }
« Last Edit: December 03, 2015, 11:00:37 PM by LazyWizard »
Logged

Ranakastrasz

  • Admiral
  • *****
  • Posts: 702
  • Prince Corwin of Amber
    • View Profile
Re: Get commander's skills from ship
« Reply #2 on: December 06, 2015, 03:23:26 PM »

That looks like 2/3 of what I need. I can't figure out how to get from shipAPI to Fleet however. I can get the owner (int), but have no idea where to go from there. No obvious reference possible.

While I'm at it, How can you get information on how many/what beacons are deployed, or when one is captured?

ShipAPI -> fleetmemberAPI -> captain, getfleetcommanderforstats.

That was what I got from the API database, but I realized that you can't actually get a fleetmemberAPI from a ship, just a number, and no "GetFleetMEmberAPIFromID" or whatever exists.
« Last Edit: December 06, 2015, 03:29:40 PM by Ranakastrasz »
Logged
I think is easy for Simba and Mufasa sing the Circle of Life when they're on the top of the food chain, I bet the zebras hate that song.

Cigarettes are a lot like hamsters. Perfectly harmless, until you put one in your mouth and light it on fire

Ranakastrasz

  • Admiral
  • *****
  • Posts: 702
  • Prince Corwin of Amber
    • View Profile
Re: Get commander's skills from ship
« Reply #3 on: December 07, 2015, 06:28:33 AM »

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.

Code
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) {  
    }
}  
« Last Edit: December 22, 2015, 01:41:32 PM by Ranakastrasz »
Logged
I think is easy for Simba and Mufasa sing the Circle of Life when they're on the top of the food chain, I bet the zebras hate that song.

Cigarettes are a lot like hamsters. Perfectly harmless, until you put one in your mouth and light it on fire

Ranakastrasz

  • Admiral
  • *****
  • Posts: 702
  • Prince Corwin of Amber
    • View Profile
Re: Get commander's skills from ship
« Reply #4 on: December 29, 2015, 01:53:17 PM »

Code
getShipFor

ShipAPI getShipFor(FleetMemberAPI fleetMember)
Returns ship that corresponds to the fleet member passed in. Returns the wing leader for fighter wings.
Parameters:
fleetMember -
Returns:

Code
getFleetMemberId

java.lang.String getFleetMemberId()
ID of FleetMemberAPI this Ship corresponds to. Can be null if there isn't one.
Returns:

Those are the two link functions I was able to find. The first is going the wrong way. The seconds gives a string instead of a FleetMemberAPI. I have no idea how to go from a string to an object here, as I doubt typecasting will work.
Logged
I think is easy for Simba and Mufasa sing the Circle of Life when they're on the top of the food chain, I bet the zebras hate that song.

Cigarettes are a lot like hamsters. Perfectly harmless, until you put one in your mouth and light it on fire

Ranakastrasz

  • Admiral
  • *****
  • Posts: 702
  • Prince Corwin of Amber
    • View Profile
Re: Get commander's skills from ship
« Reply #5 on: December 31, 2015, 04:32:46 PM »

Using lazylib's CombatUtils.getFleetMember, I have it almost working now.
However, it won't point at the admiral, just the captain for some reason. I am only getting "captain exists" and "fleet member exists" now, and I am unsure why.

edit: Apperently, "For stats" means the opposite, and instead returns null. I have no idea why, similar to how I have no idea why there are so many ways to try and get beam damage and none of them work properly.

However, GetFleetCommander works correctly.

Code
FleetMemberAPI fleetMember = CombatUtils.getFleetMember(ship);
                    if (fleetMember != null)
                    {
                        PersonAPI person = fleetMember.getCaptain();
                        
                        if (person != null)
                        {
                            MutableCharacterStatsAPI stats = person.getStats();    
                            float skillLevel = stats.getSkillLevel(Skills.DAMAGE_CONTROL);
                            armorData.repairCoef += 0.1f*skillLevel;
                            getLog().info("captain exists");
                        }
                        
                        person = fleetMember.getFleetCommanderForStats();
                        if (person != null)
                        {
                            MutableCharacterStatsAPI stats = person.getStats();    
                            float skillLevel = stats.getSkillLevel(Skills.FIELD_REPAIRS);
                            armorData.repairCoef += 0.1f*skillLevel;
                            getLog().info("admiral exists");
                        }
                        getLog().info("fleetMember exists");
                    }
                    else
                    {
                        getLog().info("fleetMember does not exist");
                    }
« Last Edit: December 31, 2015, 04:35:41 PM by Ranakastrasz »
Logged
I think is easy for Simba and Mufasa sing the Circle of Life when they're on the top of the food chain, I bet the zebras hate that song.

Cigarettes are a lot like hamsters. Perfectly harmless, until you put one in your mouth and light it on fire