Starsector API
Loading...
Searching...
No Matches
PirateRaidActionStage.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.intel.raid;
2
3import java.awt.Color;
4import java.util.ArrayList;
5import java.util.HashSet;
6import java.util.List;
7import java.util.Set;
8
9import com.fs.starfarer.api.campaign.CampaignFleetAPI;
10import com.fs.starfarer.api.campaign.FactionAPI;
11import com.fs.starfarer.api.campaign.SectorEntityToken;
12import com.fs.starfarer.api.campaign.StarSystemAPI;
13import com.fs.starfarer.api.campaign.ai.CampaignFleetAIAPI.ActionType;
14import com.fs.starfarer.api.campaign.econ.Industry;
15import com.fs.starfarer.api.campaign.econ.MarketAPI;
16import com.fs.starfarer.api.impl.campaign.MilitaryResponseScript;
17import com.fs.starfarer.api.impl.campaign.MilitaryResponseScript.MilitaryResponseParams;
18import com.fs.starfarer.api.impl.campaign.command.WarSimScript;
19import com.fs.starfarer.api.impl.campaign.econ.impl.OrbitalStation;
20import com.fs.starfarer.api.impl.campaign.fleets.RouteManager;
21import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteData;
22import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteSegment;
23import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
24import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin;
25import com.fs.starfarer.api.impl.campaign.intel.raid.RaidIntel.RaidStageStatus;
26import com.fs.starfarer.api.impl.campaign.procgen.themes.BaseAssignmentAI.FleetActionDelegate;
27import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD;
28import com.fs.starfarer.api.ui.TooltipMakerAPI;
29import com.fs.starfarer.api.util.Misc;
30import com.fs.starfarer.api.util.Pair;
31import com.fs.starfarer.api.util.WeightedRandomPicker;
32
33public class PirateRaidActionStage extends ActionStage implements FleetActionDelegate {
34
35 public static class RaidActionSubStage {
36 public List<Pair<SectorEntityToken, Float>> targets = new ArrayList<Pair<SectorEntityToken,Float>>();
37 public float duration = 30f;
38 }
39
40 protected StarSystemAPI system;
41
42 protected float untilNextStage = 0f;
43 protected List<MilitaryResponseScript> scripts = new ArrayList<MilitaryResponseScript>();
44 protected List<RaidActionSubStage> steps = new ArrayList<RaidActionSubStage>();
45 protected List<MarketAPI> targets = new ArrayList<MarketAPI>();
46 protected boolean playerTargeted = false;
47
48 public PirateRaidActionStage(RaidIntel raid, StarSystemAPI system) {
49 super(raid);
50
51 this.system = system;
52
53 for (MarketAPI target : getTargets()) {
54 if (target.isPlayerOwned()) {
55 playerTargeted = true;
56 }
57 }
58 }
59
60 @Override
61 public void advance(float amount) {
62 super.advance(amount);
63
64 float days = Misc.getDays(amount);
65 untilNextStage -= days;
66
67 if (!steps.isEmpty() && untilNextStage <= 0) {
69
70 RaidActionSubStage step = steps.remove(0);
71 untilNextStage = step.duration;
72
73 // scripts get removed anyway so we don't care about when they expire naturally
74 // just make sure they're around for long enough
75 float duration = 100f;
76
77 for (Pair<SectorEntityToken, Float> curr : step.targets) {
78 MilitaryResponseParams params = new MilitaryResponseParams(ActionType.HOSTILE,
79 "raid_" + curr.one.getId(),
81 curr.one,
82 curr.two,
83 duration);
85 curr.one.getContainingLocation().addScript(script);
86 scripts.add(script);
87
88 MilitaryResponseParams defParams = new MilitaryResponseParams(ActionType.HOSTILE,
89 "defRaid_" + curr.one.getId(),
90 curr.one.getFaction(),
91 curr.one,
92 curr.two,
93 duration);
94 MilitaryResponseScript defScript = new MilitaryResponseScript(defParams);
95 curr.one.getContainingLocation().addScript(defScript);
96 scripts.add(defScript);
97 }
98 }
99 }
100
101 protected void removeMilScripts() {
102 if (scripts != null) {
104 s.forceDone();
105 }
106 }
107 }
108
109 @Override
110 protected void updateStatus() {
111// if (true) {
112// status = RaidStageStatus.SUCCESS;
113// return;
114// }
115
117 if (status != RaidStageStatus.ONGOING) return;
118
119 if (getTargets().isEmpty()) {
120 status = RaidStageStatus.FAILURE;
123 return;
124 }
125
126 if (steps.isEmpty()) {
127 boolean inSpawnRange = RouteManager.isPlayerInSpawnRange(system.getCenter());
128 if (!inSpawnRange && elapsed > maxDays) {
129 autoresolve();
130 return;
131 }
132
133 boolean someUnraided = false;
134 boolean someRaided = false;
135 for (MarketAPI market : targets) {
136 if (!market.getFaction().isHostileTo(intel.getFaction())) {
137 someUnraided = true;
138 continue;
139 }
140 if (Misc.flagHasReason(market.getMemoryWithoutUpdate(),
141 MemFlags.RECENTLY_RAIDED, intel.getFaction().getId())) {
142 someRaided = true;
143 } else {
144 someUnraided = true;
145 }
146 }
147 if (targets.isEmpty()) {
148 someUnraided = true;
149 }
150
151 if (!someUnraided || (elapsed > maxDays && someRaided)) {
152 status = RaidStageStatus.SUCCESS;
154 return;
155 }
156
157 if (elapsed > maxDays && !someRaided) {
158 status = RaidStageStatus.FAILURE;
161 return;
162 }
163 }
164 }
165
166
167 protected List<MarketAPI> getTargets() {
168 List<MarketAPI> targets = new ArrayList<MarketAPI>();
169 for (MarketAPI market : Misc.getMarketsInLocation(system)) {
170 if (market.getFaction().isHostileTo(intel.getFaction())) {
171 targets.add(market);
172 }
173 }
174 return targets;
175 }
176
177 protected void updateRoutes() {
178 resetRoutes();
179
180 if (playerTargeted) {
182 }
183
184
185 FactionAPI faction = intel.getFaction();
186
187 List<RouteData> routes = RouteManager.getInstance().getRoutesForSource(intel.getRouteSourceId());
188
189 for (RouteData route : routes) {
190 route.addSegment(new RouteSegment(1000f, system.getCenter()));
191 }
192
193 List<MarketAPI> targets = getTargets();
194 if (targets.isEmpty()) return;
195
196 WeightedRandomPicker<MarketAPI> picker = new WeightedRandomPicker<MarketAPI>();
197 for (MarketAPI target : targets) {
198 picker.add(target, target.getSize() * target.getSize());
199 }
200
201 float str = WarSimScript.getFactionStrength(faction, system);
202 float enemyStr = 0;
203 Set<String> seen = new HashSet<String>();
204 for (MarketAPI market : targets) {
205 if (seen.contains(market.getFactionId())) continue;
206 seen.add(market.getFactionId());
207 enemyStr += WarSimScript.getFactionStrength(market.getFaction(), system);
208 }
209 if (str < 1) str = 1;
210 if (enemyStr < 1) enemyStr = 1;
211
212 boolean concurrent = false;
213 int numRaids = 1;
214 if (str > enemyStr * 2 && (float) Math.random() > 0.5f) {
215 numRaids = 2;
216 }
217 if (str > enemyStr * 4) {
218 concurrent = true;
219 numRaids++;
220 }
221
222 if (!concurrent) {
223 for (int i = 0; i < numRaids && !picker.isEmpty(); numRaids++) {
224 MarketAPI target = picker.pickAndRemove();
225
226 float defensiveStr = enemyStr + WarSimScript.getStationStrength(target.getFaction(), system, target.getPrimaryEntity());
227 if (defensiveStr > str) {
228 continue;
229 }
230
231 RaidActionSubStage step = new RaidActionSubStage();
232 step.duration = 20f + 10f * (float) Math.random();
233
234 float weight = 1f;
235 Industry station = Misc.getStationIndustry(target);
236 if (station != null && station.getDisruptedDays() < step.duration) {
237 step.duration += 10f + (float) Math.random() * 5f;
238 weight += 1f;
239 }
240
241
242 step.targets.add(new Pair<SectorEntityToken, Float>(target.getPrimaryEntity(), weight));
243 steps.add(step);
244
245 this.targets.add(target);
246 }
247
248 maxDays = 0f;
249 for (RaidActionSubStage step : steps) {
250 maxDays += step.duration;
251 }
252 } else {
253 RaidActionSubStage step = new RaidActionSubStage();
254 boolean stationPresent = false;
255 for (int i = 0; i < numRaids && !picker.isEmpty(); numRaids++) {
256 MarketAPI target = picker.pickAndRemove();
257
258 float defensiveStr = enemyStr + WarSimScript.getStationStrength(target.getFaction(), system, target.getPrimaryEntity());
259 if (defensiveStr > str) {
260 continue;
261 }
262
263 float weight = 1f;
264 Industry station = Misc.getStationIndustry(target);
265 if (station != null && station.getDisruptedDays() < 20f) {
266 stationPresent = true;
267 weight += 1f;
268 }
269
270
271 step.targets.add(new Pair<SectorEntityToken, Float>(target.getPrimaryEntity(), weight));
272
273 this.targets.add(target);
274 }
275
276 steps.add(step);
277
278 step.duration = 20f + 10f * (float) Math.random();
279 if (stationPresent) {
280 step.duration += 10f + (float) Math.random() * 5f;
281 }
282
283 maxDays = step.duration;
284 }
285
286 if (this.targets.isEmpty()) {
287 steps.clear();
288 maxDays = 0f;
289 return;
290 }
291 }
292
293
294 public void showStageInfo(TooltipMakerAPI info) {
295 int curr = intel.getCurrentStage();
296 int index = intel.getStageIndex(this);
297
298 Color h = Misc.getHighlightColor();
299 Color g = Misc.getGrayColor();
300 Color tc = Misc.getTextColor();
301 float pad = 3f;
302 float opad = 10f;
303
304 if (status == RaidStageStatus.FAILURE) {
305 info.addPara("The raiding forces have been defeated by the defenders of the " +
306 intel.getSystem().getNameWithLowercaseType() + ". The raid is now over.", opad);
307 } else if (status == RaidStageStatus.SUCCESS) {
308 List<MarketAPI> raided = new ArrayList<MarketAPI>();
309 for (MarketAPI market : targets) {
310 if (!market.getFaction().isHostileTo(intel.getFaction())) {
311 continue;
312 }
313 if (Misc.flagHasReason(market.getMemoryWithoutUpdate(),
314 MemFlags.RECENTLY_RAIDED, intel.getFaction().getId())) {
315 raided.add(market);
316 }
317 }
318 if (!raided.isEmpty()) {
319 info.addPara("The raiding forces have been successful in raiding the following colonies:", opad);
320 float initPad = opad;
321 for (MarketAPI market : raided) {
322 BaseIntelPlugin.addMarketToList(info, market, initPad, tc);
323 initPad = 0f;
324 }
325 }
326 } else if (curr == index) {
327 info.addPara("The raiding forces are currently operating in the " +
328 intel.getSystem().getNameWithLowercaseType() + ".", opad);
329
330 }
331 }
332
333 @Override
334 public boolean isPlayerTargeted() {
335 return playerTargeted;
336 }
337
338
339
340 protected void autoresolve() {
341 float str = WarSimScript.getFactionStrength(intel.getFaction(), system);
342
343 float enemyStr = WarSimScript.getEnemyStrength(intel.getFaction(), system);
344
345 status = RaidStageStatus.FAILURE;
346 for (MarketAPI target : targets) {
347 if (!target.getFaction().isHostileTo(intel.getFaction())) continue;
348
349 float defensiveStr = enemyStr + WarSimScript.getStationStrength(target.getFaction(), system, target.getPrimaryEntity());
350 if (defensiveStr >= str) {
351 continue;
352 }
353
354 Industry station = Misc.getStationIndustry(target);
355 if (station != null) {
356 OrbitalStation.disrupt(station);
357 }
358
359// float raidStr = intel.getRaidFP() / intel.getNumFleets() * Misc.FP_TO_GROUND_RAID_STR_APPROX_MULT;
360// new MarketCMD(target.getPrimaryEntity()).doGenericRaid(intel.getFaction(), raidStr);
361 performRaid(null, target);
362
363 str -= defensiveStr * 0.5f;
364 status = RaidStageStatus.SUCCESS;
365 }
366
368 }
369
370 public String getRaidActionText(CampaignFleetAPI fleet, MarketAPI market) {
371 return "raiding " + market.getName();
372 }
373
374 public String getRaidApproachText(CampaignFleetAPI fleet, MarketAPI market) {
375 return "moving in to raid " + market.getName();
376 }
377
378
379 public void performRaid(CampaignFleetAPI fleet, MarketAPI market) {
380 float raidStr = intel.getRaidFPAdjusted() / intel.getNumFleets() * Misc.FP_TO_GROUND_RAID_STR_APPROX_MULT;
381 if (fleet != null) {
382 raidStr = MarketCMD.getRaidStr(fleet);
383 }
384
385 float maxPenalty = 3f;
386// if (fleet == null) {
387// maxPenalty += (intel.getNumFleets() - 1);
388// }
389
390 new MarketCMD(market.getPrimaryEntity()).doGenericRaid(intel.getFaction(), raidStr, maxPenalty);
391
392// float re = MarketCMD.getRaidEffectiveness(market, raidStr);
393// MarketCMD.applyRaidStabiltyPenalty(market, Misc.ucFirst(intel.getFaction().getPersonNamePrefix()) + " raid", re);
394// //RecentUnrest.get(market).add(3, Misc.ucFirst(faction.getPersonNamePrefix()) + " raid");
395//
396// Misc.setFlagWithReason(market.getMemoryWithoutUpdate(), MemFlags.RECENTLY_RAIDED,
397// faction.getId(), true, 30f);
398 }
399
400
401
402 public boolean canRaid(CampaignFleetAPI fleet, MarketAPI market) {
403 if (Misc.flagHasReason(market.getMemoryWithoutUpdate(),
404 MemFlags.RECENTLY_RAIDED, intel.getFaction().getId())) {
405 return false;
406 }
407 return market.getFaction().isHostileTo(fleet.getFaction());
408 }
409
410 public String getRaidPrepText(CampaignFleetAPI fleet, SectorEntityToken from) {
411 return "preparing for raid";
412 }
413
414 public String getRaidInSystemText(CampaignFleetAPI fleet) {
415 return "raiding";
416 }
417
418 public String getRaidDefaultText(CampaignFleetAPI fleet) {
419 return "raiding";
420 }
421
422}
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
static void addMarketToList(TooltipMakerAPI info, MarketAPI market, float pad)
void giveReturnOrdersToStragglers(List< RouteData > stragglers)
String getRaidActionText(CampaignFleetAPI fleet, MarketAPI market)
String getRaidApproachText(CampaignFleetAPI fleet, MarketAPI market)
String getRaidPrepText(CampaignFleetAPI fleet, SectorEntityToken from)