Starsector API
Loading...
Searching...
No Matches
EconomyFleetAssignmentAI.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.fleets;
2
3import java.util.ArrayList;
4import java.util.Collections;
5import java.util.Comparator;
6import java.util.LinkedHashMap;
7import java.util.List;
8import java.util.Map;
9import java.util.Random;
10
11import com.fs.starfarer.api.Global;
12import com.fs.starfarer.api.campaign.CampaignFleetAPI;
13import com.fs.starfarer.api.campaign.CargoAPI;
14import com.fs.starfarer.api.campaign.FactionAPI.ShipPickParams;
15import com.fs.starfarer.api.campaign.econ.CommoditySpecAPI;
16import com.fs.starfarer.api.campaign.econ.MarketAPI;
17import com.fs.starfarer.api.fleet.FleetMemberAPI;
18import com.fs.starfarer.api.fleet.ShipRolePick;
19import com.fs.starfarer.api.impl.campaign.econ.impl.BaseIndustry;
20import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteData;
21import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteSegment;
22import com.fs.starfarer.api.impl.campaign.ids.Commodities;
23import com.fs.starfarer.api.impl.campaign.ids.Factions;
24import com.fs.starfarer.api.impl.campaign.ids.ShipRoles;
25import com.fs.starfarer.api.impl.campaign.procgen.themes.RouteFleetAssignmentAI;
26import com.fs.starfarer.api.util.IntervalUtil;
27import com.fs.starfarer.api.util.Misc;
28import com.fs.starfarer.api.util.WeightedRandomPicker;
29
30public class EconomyFleetAssignmentAI extends RouteFleetAssignmentAI {
31
32 public static class CargoQuantityData {
33 public String cargo;
34 public int units;
35 public CargoQuantityData(String cargo, int units) {
36 this.cargo = cargo;
37 this.units = units;
38 }
39
40 public CommoditySpecAPI getCommodity() {
41 CommoditySpecAPI spec = Global.getSettings().getCommoditySpec(cargo);
42 return spec;
43 }
44 }
45
46 public static class EconomyRouteData {
47 public float cargoCap, fuelCap, personnelCap;
48 public float size;
49 public boolean smuggling = false;
50 public MarketAPI from;
51 public MarketAPI to;
52
53 public List<CargoQuantityData> cargoDeliver = new ArrayList<CargoQuantityData>();
54 public List<CargoQuantityData> cargoReturn = new ArrayList<CargoQuantityData>();
55
56 public void addDeliver(String id, int qty) {
57 cargoDeliver.add(new CargoQuantityData(id, qty));
58 }
59 public void addReturn(String id, int qty) {
60 cargoReturn.add(new CargoQuantityData(id, qty));
61 }
62
63 public static String getCargoList(List<CargoQuantityData> cargo) {
64 List<String> strings = new ArrayList<String>();
65
66 List<CargoQuantityData> sorted = new ArrayList<CargoQuantityData>(cargo);
67 Collections.sort(sorted, new Comparator<CargoQuantityData>() {
68 public int compare(CargoQuantityData o1, CargoQuantityData o2) {
69 if (o1.getCommodity().isPersonnel() && !o2.getCommodity().isPersonnel()) {
70 return 1;
71 }
72 if (o2.getCommodity().isPersonnel() && !o1.getCommodity().isPersonnel()) {
73 return -1;
74 }
75 return o2.units - o1.units;
76 }
77 });
78
79 for (CargoQuantityData curr : sorted) {
80 CommoditySpecAPI spec = curr.getCommodity();
81 //CommodityOnMarketAPI com = from.getCommodityData(curr.cargo);
82 //if (com.getId().equals(Commodities.SHIPS)) {
83 if (spec.getId().equals(Commodities.SHIPS)) {
84 strings.add("ship hulls");
85 continue;
86 }
87 //if (com.getCommodity().isMeta()) continue;
88 //strings.add(com.getCommodity().getName().toLowerCase());
89 if (spec.isMeta()) continue;
90 strings.add(spec.getName().toLowerCase());
91 }
92 if (strings.size() > 4) {
93 List<String> copy = new ArrayList<String>();
94 copy.add(strings.get(0));
95 copy.add(strings.get(1));
96 copy.add("other commodities");
97 strings = copy;
98 }
99 return Misc.getAndJoined(strings);
100 }
101 }
102
103
104 private String origFaction;
105 private IntervalUtil factionChangeTracker = new IntervalUtil(0.1f, 0.3f);
106 public EconomyFleetAssignmentAI(CampaignFleetAPI fleet, RouteData route) {
107 super(fleet, route);
108 //origFaction = fleet.getFaction().getId();
109 origFaction = route.getFactionId();
110 if (!getData().smuggling) {
111 origFaction = null;
112 factionChangeTracker = null;
113 } else {
114 factionChangeTracker.forceIntervalElapsed();
116 }
117 }
118
119 public static String getCargoListDeliver(RouteData route) {
120 return getCargoList(route, route.getSegments().get(0));
121 }
122 public static String getCargoListReturn(RouteData route) {
123 return getCargoList(route, route.getSegments().get(3));
124 }
125 public static String getCargoList(RouteData route, RouteSegment segment) {
126// int index = route.getSegments().indexOf(segment);
127 EconomyRouteData data = (EconomyRouteData) route.getCustom();
128
129 Integer id = segment.getId();
130
132 return EconomyRouteData.getCargoList(data.cargoDeliver);
133 }
134 return EconomyRouteData.getCargoList(data.cargoReturn);
135 }
136 protected String getCargoList(RouteSegment segment) {
137 return getCargoList(route, segment);
138 }
139
140 protected void updateCargo(RouteSegment segment) {
141 //int index = route.getSegments().indexOf(segment);
142
143 // 0: loading from
144 // 1: moving to
145 // 2: unloading to
146 // 3: loading to
147 // 4: moving from
148 // 5: unloading from
149
150 Integer id = segment.getId();
151
152 if (route.isExpired() || id == EconomyFleetRouteManager.ROUTE_SRC_LOAD ||
154 fleet.getCargo().clear();
155 syncMothballedShips(0f, null);
156 return;
157 }
158
159 EconomyRouteData data = getData();
160 MarketAPI cargoSource = data.from;
161 List<CargoQuantityData> list = data.cargoDeliver;
163 cargoSource = data.to;
164 list = data.cargoReturn;
165 }
166
167 CargoAPI cargo = fleet.getCargo();
168 cargo.clear();
169
170 float total = 0f;
171 Map<String, Float> target = new LinkedHashMap<String, Float>();
172 float ships = 0f;
173 for (CargoQuantityData curr : list) {
174 CommoditySpecAPI spec = Global.getSettings().getCommoditySpec(curr.cargo);
175 float qty = (int) (BaseIndustry.getSizeMult(curr.units) * spec.getEconUnit());
176
177 if (curr.cargo.equals(Commodities.SHIPS)) {
178 ships = Math.max(ships, curr.units);
179 continue;
180 }
181
182 if (curr.cargo.equals(Commodities.FUEL)) {
183 cargo.addFuel(Math.min(qty, cargo.getMaxFuel()));
184 continue;
185 }
186
187 if (curr.cargo.equals(Commodities.CREW)) continue;
188 if (curr.cargo.equals(Commodities.MARINES)) continue;
189
190 total += qty;
191 target.put(curr.cargo, qty);
192 }
193
194 syncMothballedShips(ships, cargoSource);
195
196 if (total <= 0) return;
197
198 float maxCargo = cargo.getMaxCapacity();
199 for (String cid : target.keySet()) {
200 float qty = target.get(cid);
201
202 cargo.addCommodity(cid, ((int) qty * Math.min(1f, maxCargo / total)));
203 }
204 }
205
206 protected void syncMothballedShips(float units, MarketAPI market) {
207 for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
208 if (member.isMothballed()) {
209 fleet.getFleetData().removeFleetMember(member);
210 }
211 }
212
213 if (units <= 0) return;
214
215
216 Random random = new Random();
217 if (route.getSeed() != null) {
218 random = new Random(route.getSeed());
219 }
220
221 float add = units * 1.5f + random.nextInt(3);
222
223 EconomyRouteData data = getData();
224 boolean sameFaction = data.from.getFaction() == data.to.getFaction();
225 for (int i = 0; i < add; i++) {
226 WeightedRandomPicker<String> roles = new WeightedRandomPicker<String>(random);
227 roles.add(ShipRoles.COMBAT_FREIGHTER_SMALL, 20f);
228 roles.add(ShipRoles.FREIGHTER_SMALL, 20f);
229 roles.add(ShipRoles.TANKER_SMALL, 10f);
230 if (i >= 2) {
231 roles.add(ShipRoles.COMBAT_FREIGHTER_MEDIUM, 20f * (i - 1));
232 roles.add(ShipRoles.FREIGHTER_MEDIUM, 20f * (i - 1));
233 roles.add(ShipRoles.TANKER_MEDIUM, 10f * (i - 1));
234 }
235 if (i >= 5) {
236 roles.add(ShipRoles.COMBAT_FREIGHTER_LARGE, 20f * (i - 2));
237 roles.add(ShipRoles.FREIGHTER_LARGE, 20f * (i - 2));
238 roles.add(ShipRoles.TANKER_LARGE, 10f * (i - 2));
239 }
240
241 String role = roles.pick();
242 ShipPickParams params = ShipPickParams.priority();
243 if (!sameFaction) params = ShipPickParams.imported();
244 List<ShipRolePick> picks = market.pickShipsForRole(role, params, random, null);
245 for (ShipRolePick pick : picks) {
246 FleetMemberAPI member = fleet.getFleetData().addFleetMember(pick.variantId);
247 member.getRepairTracker().setMothballed(true);
248 }
249 }
250 fleet.getFleetData().sort();
251 }
252
253
254 @Override
255 protected String getStartingActionText(RouteSegment segment) {
256 String list = getCargoList(segment);
257 if (list.isEmpty()) {
258 return "preparing for a voyage to " + getData().to.getName();
259 }
260 return "loading " + list + " at " + getData().from.getName();
261 }
262 @Override
263 protected String getEndingActionText(RouteSegment segment) {
264 String list = getCargoList(segment);
265 if (list.isEmpty()) {
266 return "orbiting " + getData().from.getName();
267 }
268 return "unloading " + list + " at " + getData().from.getName();
269 }
270
271 @Override
272 protected String getTravelActionText(RouteSegment segment) {
273 String list = getCargoList(segment);
274
275 //int index = route.getSegments().indexOf(segment);
276 Integer id = segment.getId();
278 if (list.isEmpty()) {
279 return "traveling to " + getData().to.getName();
280 }
281 return "delivering " + list + " to " + getData().to.getName();
283 if (list.isEmpty()) {
284 return "returning to " + getData().from.getName();
285 }
286 return "returning to " + getData().from.getName() + " with " + list;
287 }
288 return super.getTravelActionText(segment);
289 }
290
291 @Override
292 protected String getInSystemActionText(RouteSegment segment) {
293 String list = getCargoList(segment);
294 //int index = route.getSegments().indexOf(segment);
295 Integer id = segment.getId();
296
298 if (list.isEmpty()) {
299 return "orbiting " + getData().to.getName();
300 }
301 return "unloading " + list + " at " + getData().to.getName();
302 } else if (id == EconomyFleetRouteManager.ROUTE_DST_LOAD) {
303 if (list.isEmpty()) {
304 return "orbiting " + getData().to.getName();
305 }
306 return "loading " + list + " at " + getData().to.getName();
308 return "resupplying";
309 }
310
311 return super.getInSystemActionText(segment);
312 }
313
314
315 @Override
316 protected void addEndingAssignment(RouteSegment current, boolean justSpawned) {
317 super.addEndingAssignment(current, justSpawned);
318 updateCargo(current);
319 }
320
321 @Override
322 protected void addLocalAssignment(RouteSegment current, boolean justSpawned) {
323 super.addLocalAssignment(current, justSpawned);
324 updateCargo(current);
325 }
326
327 @Override
328 protected void addStartingAssignment(RouteSegment current, boolean justSpawned) {
329 super.addStartingAssignment(current, justSpawned);
330 updateCargo(current);
331 }
332
333 @Override
334 protected void addTravelAssignment(RouteSegment current, boolean justSpawned) {
335 super.addTravelAssignment(current, justSpawned);
336 updateCargo(current);
337 }
338
339
340 protected EconomyRouteData getData() {
341 EconomyRouteData data = (EconomyRouteData) route.getCustom();
342 return data;
343 }
344
345
346 @Override
347 public void advance(float amount) {
348 super.advance(amount);
350 }
351
352
353 public void doSmugglingFactionChangeCheck(float amount) {
354 EconomyRouteData data = getData();
355 if (!data.smuggling) return;
356 float days = Global.getSector().getClock().convertToDays(amount);
357
358// if (fleet.isInCurrentLocation()) {
359// System.out.println("23wefwf23");
360// days *= 100000f;
361// }
362
363 factionChangeTracker.advance(days);
364 if (factionChangeTracker.intervalElapsed() && fleet.getAI() != null) {
365 MarketAPI align = null;
366 if (data.from.getStarSystem() == fleet.getContainingLocation()) {
367 align = data.from;
368 } else if (data.to.getStarSystem() == fleet.getContainingLocation()) {
369 align = data.to;
370 }
371
372 if (align != null) {
373 String targetFac = origFaction;
374 boolean hostile = align.getFaction().isHostileTo(targetFac);
375 if (hostile) {
376 targetFac = Factions.INDEPENDENT;
377 hostile = align.getFaction().isHostileTo(targetFac);
378 }
379 if (hostile) {
380 targetFac = align.getFactionId();
381 }
382 if (!fleet.getFaction().getId().equals(targetFac)) {
383 fleet.setFaction(targetFac, true);
384 }
385 } else {
386 String targetFac = origFaction;
387 if (fleet.isInHyperspace()) {
388 targetFac = Factions.INDEPENDENT;
389 }
390 if (!fleet.getFaction().getId().equals(targetFac)) {
391 fleet.setFaction(targetFac, true);
392 }
393 }
394
395// SectorEntityToken target = route.getMarket().getPrimaryEntity();
396// FleetAssignmentDataAPI assignment = fleet.getAI().getCurrentAssignment();
397// if (assignment != null && assignment.getAssignment() != FleetAssignment.STANDING_DOWN) {
398// target = assignment.getTarget();
399// }
400// if (target != null && target.getFaction() != null) {
401// boolean targetHostile = target.getFaction().isHostileTo(origFaction);
402// boolean mathchesTarget = fleet.getFaction().getId().equals(target.getFaction().getId());
403// boolean mathchesOrig = fleet.getFaction().getId().equals(origFaction);
404// float dist = Misc.getDistance(fleet.getLocation(), target.getLocation());
405// if (dist < target.getRadius() + fleet.getRadius() + 1000) {
406// if (targetHostile && !mathchesTarget) {
407// fleet.setFaction(target.getFaction().getId(), true);
408// }
409// } else {
410// if (!mathchesOrig) {
411// fleet.setFaction(origFaction, true);
412// }
413// }
414// }
415 }
416 }
417
418}
419
420
421
422
423
424
425
426
427
428
static SettingsAPI getSettings()
Definition Global.java:51
static SectorAPI getSector()
Definition Global.java:59
static String getCargoList(RouteData route, RouteSegment segment)
CommoditySpecAPI getCommoditySpec(String commodityId)