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