Starsector API
Loading...
Searching...
No Matches
BaseSensorGhost.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.ghosts;
2
3import java.util.ArrayList;
4import java.util.List;
5import java.util.Random;
6
7import org.lwjgl.util.vector.Vector2f;
8
9import com.fs.starfarer.api.Global;
10import com.fs.starfarer.api.campaign.CampaignFleetAPI;
11import com.fs.starfarer.api.campaign.CustomCampaignEntityAPI;
12import com.fs.starfarer.api.campaign.LocationAPI;
13import com.fs.starfarer.api.campaign.SectorEntityToken;
14import com.fs.starfarer.api.impl.campaign.abilities.InterdictionPulseAbility;
15import com.fs.starfarer.api.impl.campaign.ids.Entities;
16import com.fs.starfarer.api.impl.campaign.ids.Factions;
17import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
18import com.fs.starfarer.api.impl.campaign.ids.Tags;
19import com.fs.starfarer.api.util.Misc;
20import com.fs.starfarer.api.util.SmoothMovementUtil;
21
22public class BaseSensorGhost implements SensorGhost {
23
24 public static enum DespawnReason {
25 FLEET_IN_RANGE,
26 SCRIPT_ENDED,
27 }
28
29 protected CustomCampaignEntityAPI entity;
30 protected float despawnRange = 100f;
31 protected boolean despawnOutsideSector = true;
32 protected boolean despawnInAbyss = true;
33 protected boolean fleeing = false;
34 protected int fleeBurnLevel = 30;
35 protected float accelMult = 1f;
36 protected transient boolean creationFailed = false;
37
38 protected SmoothMovementUtil movement = new SmoothMovementUtil();
39
40 protected List<GhostBehavior> script = new ArrayList<GhostBehavior>();
42
44 this.manager = manager;
45 this.fleeBurnLevel = fleeBurnLevel;
46 }
47
48 protected Object readResolve() {
49 if (movement == null) {
50 movement = new SmoothMovementUtil();
51 }
52 return this;
53 }
54
55 public void addBehavior(GhostBehavior b) {
56 script.add(b);
57 }
58
59 public void addInterrupt(GhostBehaviorInterrupt interrupt) {
60 if (script.isEmpty()) return;
61 script.get(script.size() - 1).addInterrupt(interrupt);
62 }
63
64 public float getDespawnRange() {
65 return despawnRange;
66 }
67
68 public void setDespawnRange(float despawnRange) {
69 this.despawnRange = despawnRange;
70 }
71
72 public Random getRandom() {
73 Random random = Misc.random;
74 if (manager != null) random = manager.getRandom();
75 return random;
76 }
77
78 public float genSmallSensorProfile() {
79 return 700f + getRandom().nextFloat() * 300f;
80 }
81 public float genMediumSensorProfile() {
82 return 1000f + getRandom().nextFloat() * 500f;
83 }
84 public float genLargeSensorProfile() {
85 return 1500f + getRandom().nextFloat() * 500f;
86 }
87
88 public float genHugeSensorProfile() {
89 return 2500f + getRandom().nextFloat() * 1000f;
90 }
91
92 public float genTinyRadius() {
93 return 10f + getRandom().nextFloat() * 5f;
94 }
95 public float genVerySmallRadius() {
96 return 20f + getRandom().nextFloat() * 10f;
97 }
98 public float genSmallRadius() {
99 return 22f + getRandom().nextFloat() * 28f;
100 }
101 public float genMediumRadius() {
102 return 50f + getRandom().nextFloat() * 25f;
103 }
104 public float genLargeRadius() {
105 return 75f + getRandom().nextFloat() * 25f;
106 }
107
108 public float genFloat(float min, float max) {
109 return min + (max - min) * getRandom().nextFloat();
110 }
111 public float genInt(int min, int max) {
112 return min + getRandom().nextInt(max - min + 1);
113 }
114// public float genRadius(float min, float max) {
115// return min + (max - min) * getRandom().nextFloat();
116// }
117// public int genBurn(int min, int max) {
118// return min + getRandom().nextInt(max - min + 1);
119// }
120 public float genDelay(float base) {
121 return base * (0.75f + 0.5f * getRandom().nextFloat());
122 }
123
124 public boolean placeNearPlayer() {
125 return placeNearPlayer(1400f, 2200f); // 2000 is max range at which sensor ping plays
126 //placeNearPlayer(1000f, 1500f);
127 }
128 public boolean placeNearPlayer(float minDist, float maxDist) {
129 CampaignFleetAPI pf = Global.getSector().getPlayerFleet();
130
131 Random random = getRandom();
132 Vector2f loc = new Vector2f();
133
134 for (int i = 0; i < 20; i++) {
135 float r = minDist + random.nextFloat() * (maxDist - minDist);
136 loc = Misc.getPointAtRadius(pf.getLocation(), r, random);
137 if (!Misc.isInsideSlipstream(loc, 500f, pf.getContainingLocation())) {
138 break;
139 }
140 }
141 if (Misc.isInsideSlipstream(loc, 500f, pf.getContainingLocation())) {
142 return false;
143 }
144
145 getMovement().getLocation().set(loc);
146 entity.getLocation().set(movement.getLocation());
147 entity.getVelocity().set(movement.getVelocity());
148
149 return true;
150 }
151
152 public void placeNearEntity(SectorEntityToken entity, float minDist, float maxDist) {
153 Random random = getRandom();
154 Vector2f loc = new Vector2f();
155
156 float r = minDist + random.nextFloat() * (maxDist - minDist);
157 loc = Misc.getPointAtRadius(entity.getLocation(), r, random);
158
159 getMovement().getLocation().set(loc);
160 entity.getLocation().set(movement.getLocation());
161 entity.getVelocity().set(movement.getVelocity());
162 }
163
164 public void setLoc(Vector2f loc) {
165 getMovement().getLocation().set(loc);
166 entity.getLocation().set(movement.getLocation());
167 }
168 public void setVel(Vector2f vel) {
169 getMovement().getVelocity().set(vel);
170 entity.getVelocity().set(movement.getVelocity());
171 }
172
173 public void initEntity(float sensorProfile, float radius) {
174 float maxFleetRadius = Global.getSettings().getFloat("maxFleetSelectionRadius");
175 int extraInds = 0;
176 if (radius > maxFleetRadius) {
177 extraInds = (int) Math.round((radius - maxFleetRadius) / 20f);
178 }
179 initEntity(sensorProfile, radius, extraInds);
180 }
181 public void initEntity(float sensorProfile, float radius, int extraSensorInds) {
182 initEntity(sensorProfile, radius, extraSensorInds, Global.getSector().getHyperspace());
183 }
184 public void initEntity(float sensorProfile, float radius, int extraSensorInds, LocationAPI where) {
185 entity = where.addCustomEntity(null, null,
186 Entities.SENSOR_GHOST, Factions.NEUTRAL);
187 entity.setDiscoverable(true);
188 entity.setSensorProfile(sensorProfile);
189 entity.setDiscoveryXP(0f);
190 entity.setDetectionRangeDetailsOverrideMult(-100f);
191 entity.setRadius(radius);
192 entity.forceSensorFaderOut();
193
194 despawnRange = Math.max(100f, sensorProfile * 0.25f);
195 //if (despawnRange > 200f) despawnRange = 200f;
196 despawnRange = 100f;
197
198 if (extraSensorInds > 0) {
199 entity.getMemoryWithoutUpdate().set(MemFlags.EXTRA_SENSOR_INDICATORS, extraSensorInds);
200 }
201 }
202
203 public void setNumSensorIndicators(int min, int max, Random random) {
204 if (random == null) random = Misc.random;
205 int num = min + random.nextInt(max - min + 1);
206 entity.getMemoryWithoutUpdate().set(MemFlags.SENSOR_INDICATORS_OVERRIDE, num);
207 }
208
209 protected void reportDespawning(DespawnReason reason, Object param) {
210
211 }
212
213 public void advance(float amount) {
214 if (entity == null) {
215 return;
216 }
217 if (!entity.hasTag(Tags.FADING_OUT_AND_EXPIRING)) {
218 if (script.isEmpty() ||
219 (despawnOutsideSector && Misc.isOutsideSector(entity.getLocation())) ||
220 (despawnInAbyss && Misc.isInAbyss(entity))
221 ) {
222 Misc.fadeAndExpire(entity, 1f);
223 reportDespawning(DespawnReason.SCRIPT_ENDED, null);
224 entity = null;
225 return;
226 } else {
227 for (CampaignFleetAPI fleet : entity.getContainingLocation().getFleets()) {
228 float dist = Misc.getDistance(entity, fleet);
229 dist -= entity.getRadius() + fleet.getRadius();
230 if (dist < despawnRange) {
231 Misc.fadeAndExpire(entity, 1f);
232 reportDespawning(DespawnReason.FLEET_IN_RANGE, fleet);
233 entity = null;
234 return;
235 }
236 }
237 }
238 }
239
240 if (fleeBurnLevel > 0 && !fleeing &&
241 Global.getSector().getMemoryWithoutUpdate().getBoolean(MemFlags.GLOBAL_INTERDICTION_PULSE_JUST_USED_IN_CURRENT_LOCATION)) {
242 if (entity.getContainingLocation() != null) {
243 for (CampaignFleetAPI fleet : entity.getContainingLocation().getFleets()) {
244 float range = InterdictionPulseAbility.getRange(fleet);
245 float dist = Misc.getDistance(fleet.getLocation(), entity.getLocation());
246 if (dist > range) continue;
247 if (fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.JUST_DID_INTERDICTION_PULSE)) {
248 fleeing = true;
249 script.clear();
250 entity.addScript(new SpeedReduction(entity, 0.75f));
251 addBehavior(new GBStayInPlace(0.1f + 0.2f * Misc.random.nextFloat()));
252 addBehavior(new GBGoAwayFrom(3f + Misc.random.nextFloat() * 2f, fleet, fleeBurnLevel));
253 break;
254 }
255 }
256 }
257 }
258
259 if (!script.isEmpty()) {
260 GhostBehavior curr = script.get(0);
261 curr.advance(amount, this);
262
263 if (curr.isDone()) {
264 script.remove(curr);
265 }
266 }
267
268
269 movement.advance(amount);
270// if (this instanceof LeviathanGhost) {
271// Vector2f prev = entity.getLocation();
272// Vector2f next = movement.getLocation();
273// if (Misc.getDistance(prev, next) > 100f) {
274// System.out.println("LOCATION JUMP");
275// movement.advance(amount);
276// }
277// }
278
279
280 entity.getLocation().set(movement.getLocation());
281 entity.getVelocity().set(movement.getVelocity());
282 //entity.getVelocity().set(0f, 0f);
283 }
284
285
286 public float getAccelMult() {
287 return accelMult;
288 }
289
290 public void setAccelMult(float accelMult) {
291 this.accelMult = accelMult;
292 }
293
294 public void moveTo(Vector2f dest, float maxBurn) {
295 moveTo(dest, null, maxBurn);
296 }
297
298 public void moveTo(Vector2f dest, Vector2f destVel, float maxBurn) {
299 float speed = Misc.getSpeedForBurnLevel(maxBurn);
300 float accelMult = speed / Misc.getSpeedForBurnLevel(20f);;
301 if (accelMult < 0.5f) accelMult = 0.5f;
302 if (accelMult > 10f) accelMult = 10f;
303 movement.setAcceleration(speed * accelMult * this.accelMult);
304 movement.setMaxSpeed(speed);
305 movement.setDest(dest, destVel);
306 }
307
308 public int getMaxBurn() {
309 return (int) Misc.getBurnLevelForSpeed(movement.getMaxSpeed());
310 }
311 public int getCurrBurn() {
312 return (int) Misc.getBurnLevelForSpeed(entity.getVelocity().length());
313 }
314
315 public float getAcceleration() {
316 return movement.getAcceleration();
317 }
318
319 public SmoothMovementUtil getMovement() {
320 return movement;
321 }
322
323 public CustomCampaignEntityAPI getEntity() {
324 return entity;
325 }
326
327 public boolean isDone() {
328 return entity == null;
329 }
330
331 public boolean runWhilePaused() {
332 return false;
333 }
334
335 public boolean isDespawnOutsideSector() {
337 }
338
340 this.despawnOutsideSector = despawnOutsideSector;
341 }
342
343 public boolean isDespawnInAbyss() {
344 return despawnInAbyss;
345 }
346
347 public void setDespawnInAbyss(boolean despawnInAbyss) {
348 this.despawnInAbyss = despawnInAbyss;
349 }
350
351 public boolean isCreationFailed() {
352 return creationFailed;
353 }
354
355 public void setCreationFailed() {
356 this.creationFailed = true;
357 if (entity != null && entity.getContainingLocation() != null) {
358 entity.getContainingLocation().removeEntity(entity);
359 }
360 }
361
362 public List<GhostBehavior> getScript() {
363 return script;
364 }
365
366 public void clearScript() {
367 script.clear();
368 }
369}
370
371
372
static SettingsAPI getSettings()
Definition Global.java:51
static SectorAPI getSector()
Definition Global.java:59
void setNumSensorIndicators(int min, int max, Random random)
void initEntity(float sensorProfile, float radius, int extraSensorInds, LocationAPI where)
BaseSensorGhost(SensorGhostManager manager, int fleeBurnLevel)
void placeNearEntity(SectorEntityToken entity, float minDist, float maxDist)
void moveTo(Vector2f dest, Vector2f destVel, float maxBurn)
void addInterrupt(GhostBehaviorInterrupt interrupt)
void reportDespawning(DespawnReason reason, Object param)
void initEntity(float sensorProfile, float radius, int extraSensorInds)
void advance(float amount, SensorGhost ghost)