Starsector API
Loading...
Searching...
No Matches
BaseAssignmentAI.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.procgen.themes;
2
3import org.lwjgl.util.vector.Vector2f;
4
5import com.fs.starfarer.api.EveryFrameScript;
6import com.fs.starfarer.api.Global;
7import com.fs.starfarer.api.Script;
8import com.fs.starfarer.api.campaign.CampaignFleetAPI;
9import com.fs.starfarer.api.campaign.CustomCampaignEntityAPI;
10import com.fs.starfarer.api.campaign.CustomEntitySpecAPI;
11import com.fs.starfarer.api.campaign.FleetAssignment;
12import com.fs.starfarer.api.campaign.SectorEntityToken;
13import com.fs.starfarer.api.campaign.SectorEntityToken.VisibilityLevel;
14import com.fs.starfarer.api.campaign.ai.FleetAIFlags;
15import com.fs.starfarer.api.campaign.ai.FleetAssignmentDataAPI;
16import com.fs.starfarer.api.campaign.ai.ModularFleetAIAPI;
17import com.fs.starfarer.api.campaign.econ.MarketAPI;
18import com.fs.starfarer.api.campaign.rules.MemoryAPI;
19import com.fs.starfarer.api.impl.campaign.fleets.RouteManager;
20import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
21import com.fs.starfarer.api.impl.campaign.ids.Tags;
22import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD;
23import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.Objectives;
24import com.fs.starfarer.api.plugins.BuildObjectiveTypePicker;
25import com.fs.starfarer.api.plugins.BuildObjectiveTypePicker.BuildObjectiveParams;
26import com.fs.starfarer.api.util.IntervalUtil;
27import com.fs.starfarer.api.util.Misc;
28
29public abstract class BaseAssignmentAI implements EveryFrameScript {
30
31 public interface FleetActionDelegate {
32 boolean canRaid(CampaignFleetAPI fleet, MarketAPI market);
33 String getRaidApproachText(CampaignFleetAPI fleet, MarketAPI market);
34 String getRaidActionText(CampaignFleetAPI fleet, MarketAPI market);
35 void performRaid(CampaignFleetAPI fleet, MarketAPI market);
36
37 String getRaidPrepText(CampaignFleetAPI fleet, SectorEntityToken from);
38 String getRaidInSystemText(CampaignFleetAPI fleet);
39 String getRaidDefaultText(CampaignFleetAPI fleet);
40 }
41
42 protected CampaignFleetAPI fleet;
43 protected Boolean done = null;
44 protected Boolean giveInitial = true;
45 protected FleetActionDelegate delegate = null;
46
48 }
49
50 public BaseAssignmentAI(CampaignFleetAPI fleet) {
51 this.fleet = fleet;
53 }
54
56 return delegate;
57 }
58
60 this.delegate = delegate;
61 }
62
63 protected abstract void giveInitialAssignments();
64 protected abstract void pickNext();
65
66 public void advance(float amount) {
67 if (fleet.getCurrentAssignment() == null) {
68 pickNext();
69 }
70 }
71
72
73 public boolean isDone() {
74 return done != null;
75 }
76
77 public void setDone() {
78 done = true;
79 }
80
81 public boolean runWhilePaused() {
82 return false;
83 }
84
85
86
87 protected IntervalUtil raidTracker;
88 protected IntervalUtil capTracker;
89 protected IntervalUtil buildTracker;
90 protected void checkRaid(float amount) {
91 if (fleet.isInHyperspace()) return;
92
93 if (raidTracker == null) {
94 raidTracker = new IntervalUtil(0.3f, 0.7f);
95 }
96 raidTracker.advance(Misc.getDays(amount));
97 if (!raidTracker.intervalElapsed()) return;
98
100 }
101
102 protected void checkCapture(float amount) {
103 if (fleet.isInHyperspace()) return;
104
105 if (capTracker == null) {
106 capTracker = new IntervalUtil(0.3f, 0.7f);
107 }
108 capTracker.advance(Misc.getDays(amount));
109 if (!capTracker.intervalElapsed()) return;
110
112 }
113
114 protected void checkBuild(float amount) {
115 if (fleet.isInHyperspace()) return;
116
117 if (buildTracker == null) {
118 buildTracker = new IntervalUtil(0.3f, 0.7f);
119 }
120 buildTracker.advance(Misc.getDays(amount));
121 if (!buildTracker.intervalElapsed()) return;
122
124 }
125
126 protected void checkObjectiveAction(boolean build) {
127// if (!fleet.isInCurrentLocation() && fleet.getName().contains("Tactistar")) {
128// System.out.println("efwfe2534324");
129// }
130
131 if (!canTakeAction()) return;
132
133
134// if (fleet.isInCurrentLocation()) {
135// System.out.println("fwewefe");
136// }
137 SectorEntityToken closest = null;
138 float minDist = Float.MAX_VALUE;
139
140 if (build) {
141 for (SectorEntityToken objective : fleet.getContainingLocation().getEntitiesWithTag(Tags.STABLE_LOCATION)) {
142 if (objective.hasTag(Tags.NON_CLICKABLE)) continue;
143 if (objective.hasTag(Tags.FADING_OUT_AND_EXPIRING)) continue;
144
145 // so that it's not continuously rebuilt if it keeps being salvaged by the player
146 if (objective.getMemoryWithoutUpdate().getBoolean(MemFlags.RECENTLY_SALVAGED)) continue;
147
148 float dist = Misc.getDistance(fleet, objective);
149 if (dist < minDist) {
150 closest = objective;
151 minDist = dist;
152 }
153 }
154 } else {
155 for (SectorEntityToken objective : fleet.getContainingLocation().getEntitiesWithTag(Tags.OBJECTIVE)) {
156 if (objective.getFaction() == fleet.getFaction()) continue;
157 if (!objective.getFaction().isHostileTo(fleet.getFaction()) &&
158 !Misc.isFleetMadeHostileToFaction(fleet, objective.getFaction())) {
159 boolean ownerHasColonyInSystem = false;
160 for (MarketAPI curr : Misc.getMarketsInLocation(objective.getContainingLocation())) {
161 if (curr.getFaction() == objective.getFaction() &&
162 !curr.getFaction().isNeutralFaction()) {
163 ownerHasColonyInSystem = true;
164 break;
165 }
166 }
167 if (ownerHasColonyInSystem) continue;
168 }
169
170 float dist = Misc.getDistance(fleet, objective);
171 if (dist < minDist) {
172 closest = objective;
173 minDist = dist;
174 }
175 }
176 }
177
178 if (closest == null || minDist > 2000f) return;
179
180 for (CampaignFleetAPI other : Misc.getNearbyFleets(closest, 2000f)) {
181 if (other == fleet) continue;
182
183 if (other.isHostileTo(fleet)) {
184 if (other.getFleetPoints() > fleet.getFleetPoints() * 0.25f) return;
185 }
186
187 if (other.getFaction() == fleet.getFaction()) {
188 float dist = Misc.getDistance(other, closest);
189 if (dist < minDist) return;
190 }
191 }
192
193 if (build) {
194 BuildObjectiveParams params = new BuildObjectiveParams();
195 params.faction = fleet.getFaction();
196 params.fleet = fleet;
197 params.stableLoc = closest;
198 BuildObjectiveTypePicker pick = Global.getSector().getGenericPlugins().pickPlugin(BuildObjectiveTypePicker.class, params);
199 String type = null;
200 if (pick != null) {
201 type = pick.pickObjectiveToBuild(params);
202 }
203 if (type != null) {
204 giveBuildOrder(closest, type);
205 }
206 } else {
207 giveCaptureOrder(closest);
208 }
209 }
210
211
212 protected void giveCaptureOrder(final SectorEntityToken target) {
214
215// if (!fleet.isInCurrentLocation() && fleet.getName().contains("Tactistar")) {
216// System.out.println("efwfe2534324");
217// }
218
219 Misc.setFlagWithReason(fleet.getMemoryWithoutUpdate(),
220 MemFlags.FLEET_BUSY, TEMP_BUSY_REASON, true, (1.5f + (float) Math.random()));
221
222 String name = ((CustomCampaignEntityAPI)target).getCustomEntitySpec().getNameInText();
223 String capText = "taking control of " + name;
224 String moveText = "moving to take control of " + name;
225
226 Vector2f loc = Misc.getUnitVectorAtDegreeAngle(
227 Misc.getAngleInDegrees(target.getLocation(), fleet.getLocation()));
228 float holdRadius = fleet.getRadius() + target.getRadius() - 10;
229 loc.scale(holdRadius);
230 Vector2f.add(loc, target.getLocation(), loc);
231 SectorEntityToken holdLoc = target.getContainingLocation().createToken(loc);
232
233 holdLoc.setCircularOrbit(target,
234 Misc.getAngleInDegrees(target.getLocation(), fleet.getLocation()),
235 holdRadius, 1000000f);
236 fleet.getContainingLocation().addEntity(holdLoc);
237 Misc.fadeAndExpire(holdLoc, 5f);
238
239 fleet.addAssignmentAtStart(FleetAssignment.HOLD, holdLoc, 0.5f, capText, new Script() {
240 public void run() {
241 if (target.isAlive()) {
242 Objectives o = new Objectives(target);
243 o.control(fleet.getFaction().getId());
244 }
246 }
247 });
248 FleetAssignmentDataAPI curr = fleet.getCurrentAssignment();
249 if (curr != null) {
250 curr.setCustom(TEMP_ASSIGNMENT);
251 }
252
253 float dist = Misc.getDistance(target, fleet);
254 if (dist > fleet.getRadius() + target.getRadius() + 300f) {
255
256 fleet.addAssignmentAtStart(FleetAssignment.DELIVER_CREW, target, 3f, moveText, null);
257 curr = fleet.getCurrentAssignment();
258 if (curr != null) {
259 curr.setCustom(TEMP_ASSIGNMENT);
260 }
261 }
262 }
263
264
265 protected void giveBuildOrder(final SectorEntityToken target, String type) {
267
268 CustomEntitySpecAPI spec = Global.getSettings().getCustomEntitySpec(type);
269
270 Misc.setFlagWithReason(fleet.getMemoryWithoutUpdate(),
271 MemFlags.FLEET_BUSY, TEMP_BUSY_REASON, true, (1.5f + (float) Math.random()));
272
273 String name = spec.getNameInText();
274 String capText = "constructing " + name;
275 String moveText = "moving to construct " + name;
276
277 Vector2f loc = Misc.getUnitVectorAtDegreeAngle(
278 Misc.getAngleInDegrees(target.getLocation(), fleet.getLocation()));
279 float holdRadius = fleet.getRadius() + target.getRadius();
280 loc.scale(holdRadius);
281 Vector2f.add(loc, target.getLocation(), loc);
282 SectorEntityToken holdLoc = target.getContainingLocation().createToken(loc);
283
284 holdLoc.setCircularOrbit(target,
285 Misc.getAngleInDegrees(target.getLocation(), fleet.getLocation()),
286 holdRadius, 1000000f);
287 fleet.getContainingLocation().addEntity(holdLoc);
288 Misc.fadeAndExpire(holdLoc, 5f);
289
290 fleet.addAssignmentAtStart(FleetAssignment.HOLD, holdLoc, 0.5f, capText, new Script() {
291 public void run() {
292 if (target.isAlive()) {
293 // re-figure-out the type to avoid duplicates
294 BuildObjectiveParams params = new BuildObjectiveParams();
295 params.faction = fleet.getFaction();
296 params.fleet = fleet;
297 params.stableLoc = target;
298 BuildObjectiveTypePicker pick = Global.getSector().getGenericPlugins().pickPlugin(BuildObjectiveTypePicker.class, params);
299 String type = null;
300 if (pick != null) {
301 type = pick.pickObjectiveToBuild(params);
302 }
303
304 Objectives o = new Objectives(target);
305 o.build(type, fleet.getFaction().getId());
306 }
308 }
309 });
310 FleetAssignmentDataAPI curr = fleet.getCurrentAssignment();
311 if (curr != null) {
312 curr.setCustom(TEMP_ASSIGNMENT);
313 }
314
315 float dist = Misc.getDistance(target, fleet);
316 if (dist > fleet.getRadius() + target.getRadius() + 300f) {
317
318 fleet.addAssignmentAtStart(FleetAssignment.DELIVER_CREW, target, 3f, moveText, null);
319 curr = fleet.getCurrentAssignment();
320 if (curr != null) {
321 curr.setCustom(TEMP_ASSIGNMENT);
322 }
323 }
324
325 }
326
327
328
329 public static String TEMP_ASSIGNMENT = "temp_PAV4";
330 public static String TEMP_BUSY_REASON = "temp_PAV4";
331 protected void clearTempAssignments(CampaignFleetAPI fleet) {
332 Misc.setFlagWithReason(fleet.getMemoryWithoutUpdate(),
333 MemFlags.FLEET_BUSY, TEMP_BUSY_REASON, false, 0f);
334 for (FleetAssignmentDataAPI curr : fleet.getAI().getAssignmentsCopy()) {
335 if (TEMP_ASSIGNMENT.equals(curr.getCustom())) {
336 fleet.getAI().removeAssignment(curr);
337 }
338 }
339 }
340
341
342
343
344
345
346
347 protected boolean canTakeAction() {
348 if (!RouteManager.isPlayerInSpawnRange(fleet)) return false;
349
350 if (fleet.getBattle() != null) return false;
351 if (fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.FLEET_BUSY)) {
352 return false;
353 }
354
355 if (fleet.isCurrentAssignment(FleetAssignment.GO_TO_LOCATION_AND_DESPAWN)) return false;
356
357 MemoryAPI mem = fleet.getMemoryWithoutUpdate();
358 if (Misc.flagHasReason(mem, MemFlags.FLEET_BUSY, TEMP_BUSY_REASON)) return false;
359
360
361 if (fleet.getAI() instanceof ModularFleetAIAPI) {
362 ModularFleetAIAPI ai = (ModularFleetAIAPI) fleet.getAI();
363 if (ai.getAssignmentModule().areAssignmentsFrozen()) return false;
364 }
365
366 CampaignFleetAPI pursueTarget = mem.getFleet(FleetAIFlags.PURSUIT_TARGET);
367 CampaignFleetAPI fleeingFrom = mem.getFleet(FleetAIFlags.NEAREST_FLEEING_FROM);
368
369 if (pursueTarget != null || fleeingFrom != null) {
370 return false;
371 }
372 return true;
373 }
374
375
376
377
378 protected void checkColonyAction() {
379 if (!canTakeAction()) return;
380
381 if (fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.RECENTLY_PERFORMED_RAID)) {
382 return;
383 }
384
385 MarketAPI closest = null;
386 float minDist = Float.MAX_VALUE;
387
388// if (fleet.getFaction().getId().equals(Factions.HEGEMONY)) {
389// System.out.println("wefwefwe");
390// }
391
392 for (MarketAPI market : Misc.getMarketsInLocation(fleet.getContainingLocation())) {
393 if (delegate != null) {
394 if (!delegate.canRaid(fleet, market)) continue;
395 } else {
396 if (!market.getFaction().isHostileTo(fleet.getFaction()) &&
397 !Misc.isFleetMadeHostileToFaction(fleet, market.getFaction())) continue;
398 }
399
400 float dist = Misc.getDistance(fleet, market.getPrimaryEntity());
401 if (dist < minDist) {
402 closest = market;
403 minDist = dist;
404 }
405 }
406
407 if (closest == null || minDist > 2000f) return;
408
409 for (CampaignFleetAPI other : Misc.getNearbyFleets(closest.getPrimaryEntity(), 2000f)) {
410 if (other == fleet) continue;
411
412 if (other.isHostileTo(fleet)) {
413 VisibilityLevel vis = other.getVisibilityLevelTo(fleet);
414 boolean canSee = vis == VisibilityLevel.COMPOSITION_AND_FACTION_DETAILS || vis == VisibilityLevel.COMPOSITION_DETAILS;
415 if (!canSee && other.getFaction() != fleet.getFaction()) continue;
416
417 if (other.getAI() instanceof ModularFleetAIAPI) {
418 ModularFleetAIAPI ai = (ModularFleetAIAPI) other.getAI();
419 if (ai.isFleeing()) continue;
420 if (ai.isMaintainingContact()) continue;
421
422 if (ai.getTacticalModule().getTarget() == fleet) return;
423
424 MemoryAPI mem = other.getMemoryWithoutUpdate();
425 boolean smuggler = mem.getBoolean(MemFlags.MEMORY_KEY_SMUGGLER);
426 boolean trader = mem.getBoolean(MemFlags.MEMORY_KEY_TRADE_FLEET);
427 if (smuggler || trader) continue;
428 }
429 if (other.getFleetPoints() > fleet.getFleetPoints() * 0.25f || other.isStationMode()) return;
430 }
431
432 if (other.getFaction() == fleet.getFaction()) {
433 if (other.isStationMode()) continue;
434
435 boolean otherFromSameRaid = delegate != null && delegate.canRaid(other, closest);
436 if (!(Misc.isRaider(other) && !Misc.isWarFleet(other) && !otherFromSameRaid)) continue;
437
438 if (other.getFleetPoints() > fleet.getFleetPoints()) return;
439 if (other.getFleetPoints() == fleet.getFleetPoints()) {
440 float dist = Misc.getDistance(other, closest.getPrimaryEntity());
441 if (dist < minDist) return;
442 }
443 }
444 }
445
446 giveRaidOrder(closest);
447 }
448
449
450 protected void giveRaidOrder(final MarketAPI target) {
452
453 Misc.setFlagWithReason(fleet.getMemoryWithoutUpdate(),
454 MemFlags.FLEET_BUSY, TEMP_BUSY_REASON, true, (1.5f + (float) Math.random()));
455
456 String name = target.getName();
457 String capText = "raiding " + name;
458 String moveText = "moving to raid " + name;
459 if (delegate != null) {
460 String s = delegate.getRaidApproachText(fleet, target);
461 if (s != null) moveText = s;
462
463 s = delegate.getRaidActionText(fleet, target);
464 if (s != null) capText = s;
465 }
466
467 Vector2f loc = Misc.getUnitVectorAtDegreeAngle(
468 Misc.getAngleInDegrees(target.getPrimaryEntity().getLocation(), fleet.getLocation()));
469 float holdRadius = fleet.getRadius() * 0.5f + target.getPrimaryEntity().getRadius();
470 loc.scale(holdRadius);
471 Vector2f.add(loc, target.getPrimaryEntity().getLocation(), loc);
472 SectorEntityToken holdLoc = target.getContainingLocation().createToken(loc);
473 holdLoc.setCircularOrbit(target.getPrimaryEntity(),
474 Misc.getAngleInDegrees(target.getPrimaryEntity().getLocation(), fleet.getLocation()),
475 holdRadius, 1000000f);
476 fleet.getContainingLocation().addEntity(holdLoc);
477 Misc.fadeAndExpire(holdLoc, 5f);
478
479 final int fpAtStart = fleet.getFleetPoints();
480 //holdLoc = Global.getSector().getPlayerFleet();
481 fleet.addAssignmentAtStart(FleetAssignment.HOLD, holdLoc, 0.5f, capText, new Script() {
482 public void run() {
483 if (fpAtStart == fleet.getFleetPoints()) {
484 boolean raided = false;
485 if (delegate != null) {
486 if (delegate.canRaid(fleet, target)) {
487 delegate.performRaid(fleet, target);
488 raided = true;
489 }
490 } else {
491 new MarketCMD(target.getPrimaryEntity()).doGenericRaid(fleet.getFaction(),
492 MarketCMD.getRaidStr(fleet));
493 raided = true;
494 }
495
496 if (raided) {
497 fleet.getMemoryWithoutUpdate().set(MemFlags.RECENTLY_PERFORMED_RAID, true, 3f);
498 }
500 }
501 }
502 });
503 FleetAssignmentDataAPI curr = fleet.getCurrentAssignment();
504 if (curr != null) {
505 curr.setCustom(TEMP_ASSIGNMENT);
506 }
507
508 float dist = Misc.getDistance(target.getPrimaryEntity(), fleet);
509 //if (dist > fleet.getRadius() + target.getPrimaryEntity().getRadius() + 300f) {
510 if (dist > fleet.getRadius() + target.getPrimaryEntity().getRadius()) {
511 fleet.addAssignmentAtStart(FleetAssignment.DELIVER_CREW, holdLoc, 3f, moveText, null);
512 curr = fleet.getCurrentAssignment();
513 if (curr != null) {
514 curr.setCustom(TEMP_ASSIGNMENT);
515 }
516 }
517 }
518
519
520
521
522}
523
524
525
526
527
528
529
530
531
532
static SettingsAPI getSettings()
Definition Global.java:51
static SectorAPI getSector()
Definition Global.java:59
void giveBuildOrder(final SectorEntityToken target, String type)
CustomEntitySpecAPI getCustomEntitySpec(String id)
String getRaidPrepText(CampaignFleetAPI fleet, SectorEntityToken from)