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