001package com.fs.starfarer.api.impl.campaign.ghosts;
002
003import java.util.ArrayList;
004import java.util.List;
005
006import org.lwjgl.util.vector.Vector2f;
007
008import com.fs.starfarer.api.EveryFrameScript;
009import com.fs.starfarer.api.Global;
010import com.fs.starfarer.api.campaign.CampaignTerrainAPI;
011import com.fs.starfarer.api.impl.campaign.ids.Tags;
012import com.fs.starfarer.api.impl.campaign.ids.Terrain;
013import com.fs.starfarer.api.impl.campaign.velfield.SlipstreamTerrainPlugin2;
014import com.fs.starfarer.api.impl.campaign.velfield.SlipstreamTerrainPlugin2.SlipstreamParams2;
015import com.fs.starfarer.api.impl.campaign.velfield.SlipstreamTerrainPlugin2.SlipstreamSegment;
016import com.fs.starfarer.api.util.Misc;
017
018public class GBIGenerateSlipstream extends BaseGhostBehaviorInterrupt implements EveryFrameScript {
019        
020        public static interface GhostBehaviorWithSlipstream {
021                void setSlipstream(SlipstreamTerrainPlugin2 plugin);
022        }
023
024        protected boolean addedScript = false;
025        protected float minWidth;
026        protected float maxWidth;
027        protected int burnLevel;
028        protected SensorGhost ghost;
029        protected GhostBehavior behavior;
030        protected float widenRate = 50f;
031        protected int maxSegments = 20;
032        protected float duration;
033        public GBIGenerateSlipstream(float minWidth, float maxWidth, int burnLevel, float widenRate, int maxSegments, float duration) {
034                super(0f);
035                this.minWidth = minWidth;
036                this.maxWidth = maxWidth;
037                this.burnLevel = burnLevel;
038                this.widenRate = widenRate;
039                this.maxSegments = maxSegments;
040                this.duration = duration;
041        }
042
043        @Override
044        public boolean shouldInterruptBehavior(SensorGhost ghost, GhostBehavior behavior) {
045                return false;
046        }
047        
048        public void advance(float amount, SensorGhost ghost, GhostBehavior behavior) {
049                this.behavior = behavior;
050                if (!addedScript) {
051                        if (ghost != null && ghost.getEntity() != null && ghost.getEntity().getContainingLocation() != null) {
052                                this.ghost = ghost;
053                                //ghost.getEntity().getContainingLocation().addScript(this);
054                                ghost.getEntity().addScript(this);
055                                ghost.getEntity().addTag(Tags.UNAFFECTED_BY_SLIPSTREAM);
056                        }
057                        addedScript = true;
058                }
059        }
060
061        
062        public boolean isDone() {
063                return duration <= 0;
064        }
065
066        public boolean runWhilePaused() {
067                return false;
068        }
069
070        protected CampaignTerrainAPI slipstream = null;
071        protected SlipstreamTerrainPlugin2 plugin = null;
072        protected Vector2f prev = null;
073        
074        
075        public void advance(float amount) {
076                float days = Global.getSector().getClock().convertToDays(amount);
077                duration -= days;
078                if (ghost.getEntity() == null || ghost.getEntity().getContainingLocation() == null || duration <= 0f) {
079                        if (!plugin.isDespawning()) {
080                                plugin.despawn(0f, 1f + Misc.random.nextFloat(), Misc.random);
081                        }
082                        return;
083                }
084                Vector2f loc = ghost.getEntity().getLocation();
085                boolean forceAdd = false;
086                if (slipstream == null) {
087                        SlipstreamParams2 params = new SlipstreamParams2();
088                        
089                        params.burnLevel = burnLevel;
090                        params.widthForMaxSpeed = minWidth + widenRate * 5f;
091                        //params.widthForMaxSpeedMaxMult = 1f; // no faster than base burn, otherwise will catch up with ghost too easily
092                        params.minSpeed = Misc.getSpeedForBurnLevel(params.burnLevel - 5);
093                        params.maxSpeed = Misc.getSpeedForBurnLevel(params.burnLevel + 5);
094                        params.lineLengthFractionOfSpeed = 0.25f * Math.max(0.25f, Math.min(1f, 30f / (float) params.burnLevel));
095                        
096                        //slipstream = (CampaignTerrainAPI) Global.getSector().getCurrentLocation().addTerrain(Terrain.SLIPSTREAM, params);
097                        slipstream = (CampaignTerrainAPI) ghost.getEntity().getContainingLocation().addTerrain(Terrain.SLIPSTREAM, params);
098                        slipstream.setLocation(loc.x, loc.y);
099                        plugin = (SlipstreamTerrainPlugin2) slipstream.getPlugin();
100                        plugin.setDynamic(true);
101                        prev = new Vector2f(loc);
102                        forceAdd = true;
103                        
104                        if (behavior instanceof GhostBehaviorWithSlipstream) {
105                                GhostBehaviorWithSlipstream b = (GhostBehaviorWithSlipstream) behavior;
106                                b.setSlipstream(plugin);
107                        }
108                }
109                //ghost.getMovement().getLocation()
110                
111                //System.out.println("Location: [" + (int)ghost.getEntity().getLocation().x + "," + (int)ghost.getEntity().getLocation().y + "] (from GBIGenerateSlipstream)");
112                
113                float distPerSegment = 300f;
114                
115                float dist = Misc.getDistance(loc, prev);
116                if (dist >= distPerSegment || forceAdd) {
117                        
118//                      if (plugin.getSegments().size() > 0 &&
119//                                      plugin.getSegments().get(plugin.getSegments().size() - 1).loc.y < loc.y) {
120//                              System.out.println("ADDING BAD STREAM SEGMENT at [" + (int)loc.x + ", " + (int)loc.y + "] (from GBIGenerateSlipstream)");
121//                      } else {
122//                              System.out.println("ADDING STREAM SEGMENT at [" + (int)loc.x + ", " + (int)loc.y + "] (from GBIGenerateSlipstream)");                           
123//                      }
124                        
125                        float width = minWidth + (maxWidth - minWidth) * Misc.random.nextFloat();
126                        plugin.addSegment(loc, width);
127                        prev = new Vector2f(loc);
128                        
129                        List<SlipstreamSegment> segments = plugin.getSegments();
130                        if (segments.size() == 1) {
131                                segments.get(0).bMult = 0f;
132                                segments.get(0).fader.forceOut();
133                        } else {
134                                segments.get(segments.size() - 1).fader.forceOut();
135                                //segments.get(segments.size() - 1).bMult = 0.67f;
136                        }
137                        
138                        List<SlipstreamSegment> remove = new ArrayList<SlipstreamSegment>();
139                        for (int i = 0; i < segments.size() - maxSegments - 1; i++) { 
140                                SlipstreamSegment curr = segments.get(i);
141                                SlipstreamSegment next = segments.get(i + 1);
142                                curr.fader.setDurationOut(3f);
143                                curr.fader.fadeOut();
144                                if (curr.fader.isFadedOut() && next.fader.isFadedOut()) {
145                                        remove.add(curr);
146                                }
147                        }
148                        // don't do it - messes up texture offsets
149                        //segments.removeAll(remove);
150                        plugin.recompute();
151                }
152                
153                
154                List<SlipstreamSegment> segments = plugin.getSegments();
155                float fadeInDist = Math.min(minWidth * 4f, distPerSegment * maxSegments / 4f);
156                for (int i = Math.max(0, segments.size() - maxSegments); i < segments.size() - 1; i++) {
157                        SlipstreamSegment curr = segments.get(i);
158                        SlipstreamSegment next = segments.get(i + 1);
159                        
160                        if (!curr.fader.isFadedOut()) {
161                                dist = Misc.getDistance(ghost.getEntity().getLocation(), curr.loc);
162                                float b = dist / fadeInDist;
163                                if (b < 0) b = 0;
164                                if (b > 1) b = 1;
165                                curr.bMult = b;
166                        }
167                        
168                        
169                        if (next.fader.getBrightness() == 0 && !next.fader.isFadingOut()) {
170                                float durIn = distPerSegment / Math.max(ghost.getEntity().getVelocity().length(), 1f);
171                                if (durIn > 2f) durIn = 2f;
172                                durIn *= 2f;
173                                curr.fader.setDurationIn(durIn);
174                                curr.fader.fadeIn();
175                        }
176                        
177                        curr.width += widenRate * amount;
178//                      if (curr.width > 100f) {
179//                              curr.width -= widenRate * amount;
180//                      }
181                }
182        }
183
184        
185}
186
187
188
189