001package com.fs.starfarer.api.impl.campaign.enc; 002 003import java.util.ArrayList; 004import java.util.List; 005import java.util.Random; 006 007import org.lwjgl.util.vector.Vector2f; 008 009import com.fs.starfarer.api.EveryFrameScript; 010import com.fs.starfarer.api.Global; 011import com.fs.starfarer.api.campaign.CampaignFleetAPI; 012import com.fs.starfarer.api.campaign.CampaignTerrainAPI; 013import com.fs.starfarer.api.campaign.LocationAPI; 014import com.fs.starfarer.api.campaign.listeners.ListenerUtil; 015import com.fs.starfarer.api.impl.campaign.velfield.SlipstreamTerrainPlugin2; 016import com.fs.starfarer.api.util.IntervalUtil; 017import com.fs.starfarer.api.util.Misc; 018import com.fs.starfarer.api.util.TimeoutTracker; 019import com.fs.starfarer.api.util.WeightedRandomPicker; 020 021public class EncounterManager implements EveryFrameScript, EncounterPointProvider { 022 023 public static String EP_TYPE_SLIPSTREAM = "ep_type_slipstream"; 024 public static String EP_TYPE_OUTSIDE_SYSTEM = "ep_type_outside_system"; 025 026 public static float MAX_EP_DIST_ADD = 4000; 027 028 public static List<EPEncounterCreator> CREATORS = new ArrayList<EPEncounterCreator>(); 029 static { 030 CREATORS.add(new SlipstreamPirateEPEC()); 031 CREATORS.add(new SlipstreamLuddicPathEPEC()); 032 CREATORS.add(new SlipstreamMercenaryEPEC()); 033 CREATORS.add(new SlipstreamScavengerEPEC()); 034 CREATORS.add(new SlipstreamNoEPEC()); 035 036 CREATORS.add(new OutsideSystemRemnantEPEC()); 037 CREATORS.add(new OutsideSystemNoEPEC()); 038 039 CREATORS.add(new AbyssalLightEPEC()); 040 CREATORS.add(new AbyssalLightDwellerEPEC()); 041 CREATORS.add(new AbyssalRogueStellarObjectEPEC()); 042 CREATORS.add(new AbyssalRogueStellarObjectDireHintsEPEC()); 043 CREATORS.add(new AbyssalNoEPEC()); 044 } 045 046 047 public static EncounterManager getInstance() { 048 String key = "$encounterManager"; 049 EncounterManager manager = (EncounterManager) Global.getSector().getMemoryWithoutUpdate().get(key); 050 if (manager == null) { 051 for (EveryFrameScript curr : Global.getSector().getScripts()) { 052 if (curr instanceof EncounterManager) { 053 manager = (EncounterManager) curr; 054 Global.getSector().getMemoryWithoutUpdate().set(key, manager); 055 break; 056 } 057 } 058 } 059 return manager; 060 } 061 062 protected Object readResolve() { 063 return this; 064 } 065 066 protected Random random = new Random(); 067 protected IntervalUtil interval = new IntervalUtil(0.2f, 0.4f); 068 protected TimeoutTracker<String> pointTimeout = new TimeoutTracker<String>(); 069 protected TimeoutTracker<String> creatorTimeout = new TimeoutTracker<String>(); 070 071 public EncounterManager() { 072 Global.getSector().getListenerManager().addListener(this); 073 } 074 075 public void advance(float amount) { 076 CampaignFleetAPI pf = Global.getSector().getPlayerFleet(); 077 if (pf == null) return; 078 float days = Global.getSector().getClock().convertToDays(amount); 079 //days *= 1000f; 080 pointTimeout.advance(days); 081 creatorTimeout.advance(days); 082 083 if (interval.getRandom() == null) { 084 interval.setRandom(random); 085 } 086 087 interval.advance(days); 088 if (interval.intervalElapsed()) { 089 090 LocationAPI where = Global.getSector().getCurrentLocation(); 091 if (where == null) return; 092 093 float minRange = Global.getSettings().getMaxSensorRange(where); 094 float maxRange = minRange + MAX_EP_DIST_ADD; 095 096 List<EncounterPoint> points = ListenerUtil.generateEncounterPoints(where); 097 EncounterPoint closest = null; 098 float minDist = Float.MAX_VALUE; 099 100// System.out.println("EncounterManager potential points"); 101// System.out.println("---------------------------------"); 102// for (EncounterPoint p : points) { 103// System.out.println(p); 104// } 105// System.out.println("---------------------------------"); 106 107 for (EncounterPoint p : points) { 108 if (pointTimeout.contains(p.id)) { 109 continue; 110 } 111 float dist = Misc.getDistance(pf.getLocation(), p.loc); 112 if (dist < minRange || dist > maxRange) continue; 113 if (dist < minDist) { 114 closest = p; 115 minDist = dist; 116 } 117 } 118 119 //System.out.println("Point picked: " + closest); 120 121 if (closest != null) { 122 WeightedRandomPicker<EPEncounterCreator> picker = new WeightedRandomPicker<EPEncounterCreator>(random); 123 for (EPEncounterCreator c : CREATORS) { 124 if (creatorTimeout.contains(c.getId())) continue; 125 float f = c.getFrequencyForPoint(this, closest); 126 if (f > 0f) { 127 picker.add(c, f); 128 } 129 } 130 131 EPEncounterCreator c = picker.pick(); 132 if (c != null) { 133 c.createEncounter(this, closest); 134 135 float ptTO = c.getPointTimeoutMin() + (c.getPointTimeoutMax() - c.getPointTimeoutMin()) * random.nextFloat(); 136 float cTO = c.getCreatorTimeoutMin() + (c.getCreatorTimeoutMax() - c.getCreatorTimeoutMin()) * random.nextFloat(); 137 if (ptTO > 0) { 138 pointTimeout.set(closest.id, ptTO); 139 } 140 if (cTO > 0) { 141 creatorTimeout.set(c.getId(), cTO); 142 } 143 } 144 } 145 } 146 } 147 148 149 150 public boolean isDone() { 151 return false; 152 } 153 154 public boolean runWhilePaused() { 155 return false; 156 } 157 158 public Random getRandom() { 159 return random; 160 } 161 162 public TimeoutTracker<String> getPointTimeout() { 163 return pointTimeout; 164 } 165 166 public TimeoutTracker<String> getCreatorTimeout() { 167 return creatorTimeout; 168 } 169 170 171 public List<EncounterPoint> generateEncounterPoints(LocationAPI where) { 172 if (!where.isHyperspace()) return null; 173 174 List<EncounterPoint> result = new ArrayList<EncounterPoint>(); 175 CampaignFleetAPI pf = Global.getSector().getPlayerFleet(); 176 float velAngle = Misc.getAngleInDegrees(pf.getVelocity()); 177 if (pf.getVelocity().length() < 10f) { 178 velAngle = pf.getFacing(); 179 } 180 for (CampaignTerrainAPI ter : where.getTerrainCopy()) { 181 if (ter.getPlugin() instanceof SlipstreamTerrainPlugin2) { 182 SlipstreamTerrainPlugin2 plugin = (SlipstreamTerrainPlugin2) ter.getPlugin(); 183 List<Vector2f> points = plugin.getEncounterPoints(); 184 if (points != null) { 185 for (Vector2f p : points) { 186 float dist = Misc.getDistance(pf.getLocation(), p); 187 if (dist > 10000f) continue; 188 if (!Misc.isInsideSlipstream(p, 500f)) { 189 float diff = Misc.getAngleDiff(velAngle, Misc.getAngleInDegrees(pf.getLocation(), p)); 190 if (diff < 90f) { 191 String id = ter.getId() + "_" + (int)Math.round(p.x) + "_" + (int)Math.round(p.y); 192 EncounterPoint ep = new EncounterPoint(id, where, p, EP_TYPE_SLIPSTREAM); 193 result.add(ep); 194 } 195 } 196 } 197 } 198 } 199 } 200 return result; 201 } 202 203} 204 205 206 207 208 209 210