001package com.fs.starfarer.api.impl.campaign.ghosts; 002 003import org.lwjgl.util.vector.Vector2f; 004 005import com.fs.starfarer.api.Global; 006import com.fs.starfarer.api.campaign.CampaignFleetAPI; 007import com.fs.starfarer.api.campaign.CustomCampaignEntityAPI; 008import com.fs.starfarer.api.campaign.SectorEntityToken; 009import com.fs.starfarer.api.characters.AbilityPlugin; 010import com.fs.starfarer.api.impl.campaign.ghosts.GBIGenerateSlipstream.GhostBehaviorWithSlipstream; 011import com.fs.starfarer.api.impl.campaign.ids.Abilities; 012import com.fs.starfarer.api.impl.campaign.ids.MemFlags; 013import com.fs.starfarer.api.impl.campaign.velfield.SlipstreamTerrainPlugin2; 014import com.fs.starfarer.api.util.Misc; 015 016 017public class GBLeviathanCalfRun extends BaseGhostBehavior implements GhostBehaviorWithSlipstream { 018 019 public static float SENSOR_BURST_TURN_RATE = 30f; 020 public static float PULSE_BURN_BONUS = 10; 021 public static float PULSE_BURN_BONUS_DECAY = 0.25f; 022 023 protected boolean dirSet = false; 024 protected float dir; 025 protected float burnBonus; 026 protected int origPluginBurn; 027 protected SectorEntityToken from; 028 protected float phase = (float) Math.random(); 029 protected int maxBurn; 030 protected SlipstreamTerrainPlugin2 plugin; 031 protected boolean affectedByPulse = false; 032 protected float wobbleRate; 033 protected float maxWobble; 034 035 public GBLeviathanCalfRun(float duration, SectorEntityToken from, float wobbleRate, float maxWobble, 036 int maxBurn, boolean affectedByPulse) { 037 super(duration); 038 this.from = from; 039 this.wobbleRate = wobbleRate; 040 this.maxWobble = maxWobble; 041 this.maxBurn = maxBurn; 042 this.affectedByPulse = affectedByPulse; 043 } 044 045 046 047 @Override 048 public void advance(float amount, SensorGhost ghost) { 049 if (from.getContainingLocation() != ghost.getEntity().getContainingLocation() || 050 ghost.getEntity().getContainingLocation() == null || !from.isAlive()) { 051 end(); 052 return; 053 } 054 super.advance(amount, ghost); 055 056 if (!dirSet || ghost.getEntity().getVelocity().length() < 10f) { 057 dir = Misc.getAngleInDegrees(from.getLocation(), ghost.getEntity().getLocation()); 058 dirSet = true; 059 } else { 060 //dir = Misc.getAngleInDegrees(ghost.getEntity().getVelocity()); 061 } 062 063 float pi = (float) Math.PI; 064 float sin = (float) Math.sin(phase * pi * 2f); 065 phase += amount * wobbleRate; 066 067 float maxAngleOffset = maxWobble; 068 float angle = dir + sin * maxAngleOffset; 069 070// float maxSteeringOffset = 30f; 071// maxSteeringOffset = 0f; 072// if (maxSteeringOffset > 0f && plugin != null && plugin.containsEntity(from)) { 073// float [] coords = plugin.getLengthAndWidthFractionWithinStream(from.getLocation()); 074// if (coords != null) { 075// float dist = Misc.getDistance(ghost.getEntity(), from); 076// if (dist < 2000f) { 077// float mag = (1f - Math.max(0f, dist - 1000f) / 1000f) * 078// Math.signum(coords[1]) * Math.max(0f, Math.abs(coords[1]) - 0.3f) * 079// maxSteeringOffset; 080// angle += mag; 081// } 082// } 083// } 084 085 if (affectedByPulse) { 086 checkInterdictionPulses(ghost); 087 } 088 //checkSensorBursts(ghost, amount); 089 090 int useBonus = 0; 091 if (plugin != null) { 092 burnBonus -= PULSE_BURN_BONUS_DECAY * amount; 093 if (burnBonus < 0) burnBonus = 0; 094 095 useBonus = (int) burnBonus; 096 plugin.getParams().burnLevel = origPluginBurn + useBonus; 097 } 098 099 Vector2f loc = Misc.getUnitVectorAtDegreeAngle(angle); 100 loc.scale(10000f); 101 Vector2f.add(loc, ghost.getEntity().getLocation(), loc); 102 ghost.moveTo(loc, maxBurn + useBonus); 103 104 } 105 106 public void checkInterdictionPulses(SensorGhost ghost) { 107 if (!Global.getSector().getMemoryWithoutUpdate().getBoolean(MemFlags.GLOBAL_INTERDICTION_PULSE_JUST_USED_IN_CURRENT_LOCATION)) { 108 return; 109 } 110 CustomCampaignEntityAPI entity = ghost.getEntity(); 111 if (entity == null || entity.getContainingLocation() == null || plugin == null) return; 112 for (CampaignFleetAPI fleet : entity.getContainingLocation().getFleets()) { 113// float range = InterdictionPulseAbility.getRange(fleet); 114// float dist = Misc.getDistance(fleet.getLocation(), entity.getLocation()); 115// if (dist > range) continue; 116 // anywhere inside the stream is fine, actually 117 if (!plugin.containsEntity(fleet)) continue; 118 119 if (fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.JUST_DID_INTERDICTION_PULSE)) { 120 burnBonus = PULSE_BURN_BONUS; 121 if (fleet.isPlayerFleet()) { 122 String key = "$leviathanCalvesPulsed"; 123 int count = Global.getSector().getMemoryWithoutUpdate().getInt(key); 124 Global.getSector().getMemoryWithoutUpdate().set(key, count + 1); 125 } 126 return; 127 } 128 } 129 } 130 public void checkSensorBursts(SensorGhost ghost, float amount) { 131 CustomCampaignEntityAPI entity = ghost.getEntity(); 132 if (entity == null || entity.getContainingLocation() == null || plugin == null) return; 133 for (CampaignFleetAPI fleet : entity.getContainingLocation().getFleets()) { 134 // anywhere inside the stream is fine, actually 135 if (!plugin.containsEntity(fleet)) continue; 136 137 AbilityPlugin asb = fleet.getAbility(Abilities.SENSOR_BURST); 138 if (asb.isInProgress()) {// && asb.getLevel() == 1f) { 139 float [] coords = plugin.getLengthAndWidthFractionWithinStream(fleet.getLocation()); 140 if (coords != null) { 141 dir += coords[1] * SENSOR_BURST_TURN_RATE * amount; 142 ((BaseSensorGhost)ghost).setAccelMult(1f); 143 } 144// float velDir = Misc.getAngleInDegrees(entity.getVelocity()); 145// float toFleet = Misc.getAngleInDegrees(entity.getLocation(), fleet.getLocation()); 146// float turnDir = Misc.getClosestTurnDirection(toFleet, velDir); 147// dir += turnDir * SENSOR_BURST_TURN_RATE * amount; 148 } 149 } 150 } 151 152 153 public void setSlipstream(SlipstreamTerrainPlugin2 plugin) { 154 this.plugin = plugin; 155 origPluginBurn = plugin.getParams().burnLevel; 156 } 157 158 159 160} 161 162 163 164 165 166 167 168 169 170 171 172 173