001package com.fs.starfarer.api.impl.campaign.entities; 002 003import java.util.ArrayList; 004import java.util.List; 005 006import java.awt.Color; 007 008import org.lwjgl.util.vector.Vector2f; 009 010import com.fs.starfarer.api.Global; 011import com.fs.starfarer.api.Script; 012import com.fs.starfarer.api.campaign.CampaignEngineLayers; 013import com.fs.starfarer.api.campaign.SectorEntityToken; 014import com.fs.starfarer.api.campaign.SectorEntityToken.VisibilityLevel; 015import com.fs.starfarer.api.combat.ViewportAPI; 016import com.fs.starfarer.api.impl.campaign.BaseCustomEntityPlugin; 017import com.fs.starfarer.api.impl.campaign.ids.Pings; 018import com.fs.starfarer.api.impl.campaign.ids.Tags; 019import com.fs.starfarer.api.util.CampaignEngineGlowIndividualEngine; 020import com.fs.starfarer.api.util.CampaignEngineGlowUtil; 021import com.fs.starfarer.api.util.CampaignEntityMovementUtil; 022import com.fs.starfarer.api.util.Misc; 023 024/** 025 * Not fully implemented. Approximate TODO: 026 * 027 * Sprite size/facing 028 * Smoother movement rather than move/turn/move 029 * Smoother transition into orbit 030 * Add trigger range for detecting when travel to a destination is finished 031 * Add failsafe to detect when travel is taking too long 032 * Make not clickable/figure out if it should have a tooltip 033 * Possibly: add contrail? 034 * 035 * @author Alex 036 * 037 */ 038public class GenericProbeEntityPlugin extends BaseCustomEntityPlugin { // implements EngineGlowControls { 039 040 public static enum ProbeActionType { 041 TRAVEL, 042 ASSUME_ORBIT, 043 EMIT_PING, 044 PERFORM_ACTION, 045 STOP, 046 WAIT, 047 } 048 049 public static class GenericProbeParams { 050 public float maxBurn = 20f; 051 public float burnAccel = 5f; 052 public float maxTurnRate = 120f; 053 public float turnAccel = 120f; 054 055 public Color fringe = new Color(255, 100, 0, 255); 056 public Color flame = new Color(255, 165, 100, 255); 057 public Color core = new Color(255, 255, 255, 255); 058 public float engineGlowShiftRate = 2f; 059 public float engineGlowLength = 100f; 060 public float engineGlowWidth = 15f; 061 public float engineGlowGlowSize = 100f; 062 public float engineGlowTexSpanMult = 0.1f; 063 064 protected List<ProbeAction> actions = new ArrayList<>(); 065 066 public void travelTo(Vector2f location) { 067 ProbeAction a = new ProbeAction(ProbeActionType.TRAVEL); 068 a.location = location; 069 actions.add(a); 070 } 071 public void travelTo(SectorEntityToken target) { 072 ProbeAction a = new ProbeAction(ProbeActionType.TRAVEL); 073 a.target = target; 074 actions.add(a); 075 } 076 public void travelInDir(float dir, float duration) { 077 ProbeAction a = new ProbeAction(ProbeActionType.TRAVEL); 078 a.dir = dir; 079 a.duration = duration; 080 actions.add(a); 081 } 082 083 public void assumeOrbit(SectorEntityToken target, float radius, float duration) { 084 ProbeAction a = new ProbeAction(ProbeActionType.ASSUME_ORBIT); 085 a.target = target; 086 a.radius = radius; 087 a.duration = duration; 088 actions.add(a); 089 } 090 091 public void emitPing(String pingId) { 092 ProbeAction a = new ProbeAction(ProbeActionType.EMIT_PING); 093 a.pingId = pingId; 094 actions.add(a); 095 } 096 public void performAction(Script action) { 097 ProbeAction a = new ProbeAction(ProbeActionType.PERFORM_ACTION); 098 a.action = action; 099 actions.add(a); 100 } 101 public void wait(float duration) { 102 ProbeAction a = new ProbeAction(ProbeActionType.WAIT); 103 a.duration = duration; 104 actions.add(a); 105 } 106 public void stop(float duration) { 107 ProbeAction a = new ProbeAction(ProbeActionType.STOP); 108 a.duration = duration; 109 actions.add(a); 110 } 111 } 112 113 114 public static class ProbeAction { 115 public ProbeActionType type; 116 public SectorEntityToken target; 117 public Vector2f location; 118 public float dir; 119 public float radius; 120 public float duration; 121 public String pingId; 122 public Script action; 123 public ProbeAction(ProbeActionType type) { 124 this.type = type; 125 } 126 127 } 128 129 protected GenericProbeParams params; 130 protected CampaignEntityMovementUtil movement; 131 protected CampaignEngineGlowUtil engineGlow; 132 133 public void init(SectorEntityToken entity, Object pluginParams) { 134 super.init(entity, pluginParams); 135 this.params = (GenericProbeParams) pluginParams; 136 readResolve(); 137 } 138 139 Object readResolve() { 140 if (engineGlow == null) { 141 engineGlow = new CampaignEngineGlowUtil(entity, params.fringe, params.core, params.flame, 142 params.engineGlowShiftRate); 143 CampaignEngineGlowIndividualEngine engine = new CampaignEngineGlowIndividualEngine( 144 90f, params.engineGlowLength, params.engineGlowWidth, params.engineGlowGlowSize, 145 new Vector2f(-10f, 0f), engineGlow); 146 engine.setFlameTexSpanMult(params.engineGlowTexSpanMult); 147 engineGlow.addEngine(engine); 148 } 149 150 if (movement == null) { 151 float maxSpeed = Misc.getSpeedForBurnLevel(params.maxBurn); 152 float accel = Misc.getSpeedForBurnLevel(params.burnAccel); 153 movement = new CampaignEntityMovementUtil(entity, params.turnAccel, params.maxBurn, accel, maxSpeed); 154 movement.setEngineGlow(engineGlow); 155 } 156 157 return this; 158 } 159 160 public CampaignEntityMovementUtil getMovement() { 161 return movement; 162 } 163 164 public CampaignEngineGlowUtil getEngineGlow() { 165 return engineGlow; 166 } 167 168 public void advance(float amount) { 169 if (entity.isInCurrentLocation()) { 170 engineGlow.advance(amount); 171 } 172 173 if (entity.hasTag(Tags.FADING_OUT_AND_EXPIRING) || params.actions.isEmpty()) { 174 Misc.fadeAndExpire(entity); 175 engineGlow.showSuppressed(); 176 return; 177 } 178 179 ProbeAction curr = params.actions.get(0); 180 ProbeAction next = null; 181 if (params.actions.size() > 1) next = params.actions.get(1); 182 183 if (curr.type == ProbeActionType.TRAVEL) { 184 if (curr.location == null && curr.target == null) { 185 movement.moveInDirection(curr.dir); 186 curr.duration -= amount; 187 if (curr.duration <= 0) { 188 params.actions.remove(0); 189 } 190 } else { 191 Vector2f loc = curr.location; 192 if (loc == null) loc = curr.target.getLocation(); 193 float dist = Misc.getDistance(entity.getLocation(), loc); 194 195 if (next != null && next.type == ProbeActionType.ASSUME_ORBIT) { 196 float orbitAngle = Misc.getAngleInDegrees(next.target.getLocation(), entity.getLocation()); 197 Vector2f away = Misc.getUnitVectorAtDegreeAngle(orbitAngle); 198 away.scale(next.target.getRadius() + next.radius * 0.8f); 199 loc = Vector2f.add(loc, away, new Vector2f()); 200 } 201 movement.moveToLocation(loc); 202 203 float checkDist = 100f + entity.getRadius(); 204 if (curr.target != null) checkDist += curr.target.getRadius(); 205 if (next != null && next.type == ProbeActionType.ASSUME_ORBIT) { 206 checkDist -= 100f; 207 checkDist += next.radius; 208 } 209 if (dist < checkDist) { 210 params.actions.remove(0); 211 } 212 } 213 214 } else if (curr.type == ProbeActionType.ASSUME_ORBIT) { 215 if (entity.getOrbit() == null || entity.getOrbitFocus() != curr.target) { 216 movement.leaveOrbit(); 217 float orbitAngle = Misc.getAngleInDegrees(curr.target.getLocation(), entity.getLocation()); 218 float orbitRadius = Misc.getDistance(entity.getLocation(), curr.target.getLocation()); 219 float orbitDays = orbitRadius / (10f + (float) Math.random() * 5f); 220 orbitDays *= 0.2f; 221 entity.setCircularOrbit(curr.target, orbitAngle, orbitRadius, orbitDays); 222 } 223 curr.duration -= amount; 224 if (curr.duration <= 0) { 225 params.actions.remove(0); 226 } 227 } else if (curr.type == ProbeActionType.EMIT_PING) { 228 VisibilityLevel level = entity.getVisibilityLevelToPlayerFleet(); 229 if (level != VisibilityLevel.NONE) { 230 Global.getSector().addPing(entity, Pings.REMOTE_SURVEY); 231 } 232 params.actions.remove(0); 233 } else if (curr.type == ProbeActionType.STOP || curr.type == ProbeActionType.WAIT) { 234 if (curr.type == ProbeActionType.STOP) { 235 movement.stop(); 236 } 237 curr.duration -= amount; 238 if (curr.duration <= 0) { 239 params.actions.remove(0); 240 } 241 } else if (curr.type == ProbeActionType.PERFORM_ACTION) { 242 curr.action.run(); 243 params.actions.remove(0); 244 } 245 246 movement.advance(amount); 247 248 } 249 250 public void render(CampaignEngineLayers layer, ViewportAPI viewport) { 251 float alphaMult = viewport.getAlphaMult(); 252 alphaMult *= entity.getSensorFaderBrightness(); 253 alphaMult *= entity.getSensorContactFaderBrightness(); 254 if (alphaMult <= 0f) return; 255 256 engineGlow.render(alphaMult); 257 } 258 259 public float getRenderRange() { 260 return entity.getRadius() + 1000f; // for engine glow/trails 261 } 262 263 264 265} 266 267 268 269 270 271 272 273