Starsector API
Loading...
Searching...
No Matches
CoreScript.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign;
2
3import java.awt.Color;
4import java.util.ArrayList;
5import java.util.HashSet;
6import java.util.List;
7import java.util.Random;
8import java.util.Set;
9
10import org.apache.log4j.Logger;
11import org.lwjgl.util.vector.Vector2f;
12
13import com.fs.starfarer.api.EveryFrameScript;
14import com.fs.starfarer.api.Global;
15import com.fs.starfarer.api.campaign.BaseCampaignEventListener;
16import com.fs.starfarer.api.campaign.BattleAPI;
17import com.fs.starfarer.api.campaign.CampaignFleetAPI;
18import com.fs.starfarer.api.campaign.CampaignTerrainAPI;
19import com.fs.starfarer.api.campaign.CargoAPI;
20import com.fs.starfarer.api.campaign.CargoAPI.CargoItemType;
21import com.fs.starfarer.api.campaign.CargoStackAPI;
22import com.fs.starfarer.api.campaign.CustomCampaignEntityAPI;
23import com.fs.starfarer.api.campaign.FactionAPI;
24import com.fs.starfarer.api.campaign.FactionAPI.ShipPickMode;
25import com.fs.starfarer.api.campaign.FactionProductionAPI;
26import com.fs.starfarer.api.campaign.FactionProductionAPI.ItemInProductionAPI;
27import com.fs.starfarer.api.campaign.FactionProductionAPI.ProductionItemType;
28import com.fs.starfarer.api.campaign.FleetInflater;
29import com.fs.starfarer.api.campaign.JumpPointAPI.JumpDestination;
30import com.fs.starfarer.api.campaign.LocationAPI;
31import com.fs.starfarer.api.campaign.PlanetAPI;
32import com.fs.starfarer.api.campaign.PlayerMarketTransaction;
33import com.fs.starfarer.api.campaign.PlayerMarketTransaction.ShipSaleInfo;
34import com.fs.starfarer.api.campaign.SectorAPI;
35import com.fs.starfarer.api.campaign.SectorEntityToken;
36import com.fs.starfarer.api.campaign.SpecialItemData;
37import com.fs.starfarer.api.campaign.SpecialItemPlugin;
38import com.fs.starfarer.api.campaign.StarSystemAPI;
39import com.fs.starfarer.api.campaign.comm.CommMessageAPI.MessageClickAction;
40import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI;
41import com.fs.starfarer.api.campaign.econ.Industry;
42import com.fs.starfarer.api.campaign.econ.MarketAPI;
43import com.fs.starfarer.api.campaign.econ.MarketAPI.SurveyLevel;
44import com.fs.starfarer.api.campaign.econ.MonthlyReport;
45import com.fs.starfarer.api.campaign.econ.MonthlyReport.FDNode;
46import com.fs.starfarer.api.campaign.econ.SubmarketAPI;
47import com.fs.starfarer.api.campaign.listeners.ListenerUtil;
48import com.fs.starfarer.api.campaign.rules.MemoryAPI;
49import com.fs.starfarer.api.characters.AdminData;
50import com.fs.starfarer.api.characters.OfficerDataAPI;
51import com.fs.starfarer.api.characters.PersonAPI;
52import com.fs.starfarer.api.characters.SkillsChangeRemoveExcessOPEffect;
53import com.fs.starfarer.api.characters.SkillsChangeRemoveVentsCapsEffect;
54import com.fs.starfarer.api.combat.ShipVariantAPI;
55import com.fs.starfarer.api.fleet.FleetMemberAPI;
56import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin.DerelictShipData;
57import com.fs.starfarer.api.impl.campaign.econ.impl.InstallableItemEffect;
58import com.fs.starfarer.api.impl.campaign.econ.impl.ItemEffectsRepo;
59import com.fs.starfarer.api.impl.campaign.events.BaseEventPlugin.MarketFilter;
60import com.fs.starfarer.api.impl.campaign.fleets.DefaultFleetInflaterParams;
61import com.fs.starfarer.api.impl.campaign.fleets.RouteManager;
62import com.fs.starfarer.api.impl.campaign.ids.Commodities;
63import com.fs.starfarer.api.impl.campaign.ids.Drops;
64import com.fs.starfarer.api.impl.campaign.ids.Entities;
65import com.fs.starfarer.api.impl.campaign.ids.Factions;
66import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
67import com.fs.starfarer.api.impl.campaign.ids.Stats;
68import com.fs.starfarer.api.impl.campaign.ids.Tags;
69import com.fs.starfarer.api.impl.campaign.intel.MessageIntel;
70import com.fs.starfarer.api.impl.campaign.intel.misc.ProductionReportIntel;
71import com.fs.starfarer.api.impl.campaign.intel.misc.ProductionReportIntel.ProductionData;
72import com.fs.starfarer.api.impl.campaign.procgen.SalvageEntityGenDataSpec.DropData;
73import com.fs.starfarer.api.impl.campaign.procgen.themes.BaseThemeGenerator;
74import com.fs.starfarer.api.impl.campaign.procgen.themes.SalvageSpecialAssigner;
75import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial;
76import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial.PerShipData;
77import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial.ShipCondition;
78import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.ShipRecoverySpecial.ShipRecoverySpecialData;
79import com.fs.starfarer.api.impl.campaign.shared.SharedData;
80import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin;
81import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin.DebrisFieldParams;
82import com.fs.starfarer.api.impl.campaign.terrain.DebrisFieldTerrainPlugin.DebrisFieldSource;
83import com.fs.starfarer.api.impl.campaign.tutorial.TutorialMissionIntel;
84import com.fs.starfarer.api.loading.FighterWingSpecAPI;
85import com.fs.starfarer.api.loading.HullModSpecAPI;
86import com.fs.starfarer.api.loading.WeaponSpecAPI;
87import com.fs.starfarer.api.util.IntervalUtil;
88import com.fs.starfarer.api.util.Misc;
89import com.fs.starfarer.api.util.WeightedRandomPicker;
90
91public class CoreScript extends BaseCampaignEventListener implements EveryFrameScript {
92
93 public static Logger log = Global.getLogger(CoreScript.class);
94
95 public static final String SHARED_DATA_KEY = "core_CEFSSharedDataKey";
96
97 private SharedData shared;
98
99 private IntervalUtil timer = new IntervalUtil(0.5f, 1.5f);
100 //private Set<String> marketsWithAssignedPatrolScripts = new HashSet<String>();
101
102 public CoreScript() {
103 super(true);
104// shared = new SharedData();
105 shared = SharedData.getData();
106 }
107
108 private boolean firstFrame = true;
109 public void advance(float amount) {
110 SectorAPI sector = Global.getSector();
111 playRepChangeSoundsIfNeeded();
112
113 if (sector.isPaused()) {
114 if (Global.getSettings().isDevMode()) {
115 //RouteManager.getInstance().advance(amount);
116 RouteManager.getInstance().advance(0f);
117 }
118 return;
119 }
120
121 if (firstFrame) {
122 firstFrame = false;
123 }
124
125 float days = sector.getClock().convertToDays(amount);
126 shared.advance(amount);
127
128 timer.advance(days);
129 if (timer.intervalElapsed()) {
130 }
131
132 RouteManager.getInstance().advance(amount);
133
134 Misc.computeCoreWorldsExtent();
135
136 //updateSlipstreamVisibility(amount);
137 }
138
139// protected transient CampaignTerrainAPI currentStream = null;
140// public void updateSlipstreamVisibility(float amount) {
141// float sw = Global.getSettings().getFloat("sectorWidth");
142// float sh = Global.getSettings().getFloat("sectorHeight");
143// float minCellSize = 12000f;
144// float cellSize = Math.max(minCellSize, sw * 0.05f);
145// CollisionGridUtil grid = new CollisionGridUtil(-sw/2f, sw/2f, -sh/2f, sh/2f, cellSize);
146// Set<String> seenSystems = new LinkedHashSet<String>();
147// for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) {
148// if (market.isHidden()) continue;
149// if (market.getContainingLocation() == null) continue;
150// if (!market.getContainingLocation().isHyperspace()) {
151// String systemId = market.getContainingLocation().getId();
152// if (seenSystems.contains(systemId)) continue;
153// seenSystems.add(systemId);
154// }
155// //if (market.hasIndustry(Industries.SPACEPORT)) continue;
156// Industry spaceport = market.getIndustry(Industries.SPACEPORT);
157// if (spaceport == null || !spaceport.isFunctional()) continue;
158//
159// Vector2f loc = market.getLocationInHyperspace();
160// float size = 10000f;
161// if (!market.getContainingLocation().hasTag(Tags.THEME_CORE)) {
162// size = 10000f;
163// }
164// //size = 200000;
168// CustomStreamRevealer revealer = new CustomStreamRevealer(loc, size);
169// grid.addObject(revealer, loc, size * 2f, size * 2f);
170// }
171//
172// //System.out.println("BEGIN");
173// float maxDist = 0f;
174// List<CampaignTerrainAPI> terrainList = Global.getSector().getHyperspace().getTerrainCopy();
175// boolean processNext = false;
176// for (CampaignTerrainAPI terrain : terrainList) {
177// if (terrain.getPlugin() instanceof SlipstreamTerrainPlugin2) {
178// boolean process = false;
179// if (currentStream == null || processNext) {
180// process = true;
181// } else if (currentStream == terrain) {
182// processNext = true;
183// }
184//
185// if (!process) continue;
186//
187// currentStream = terrain;
188// if (terrainList.indexOf(terrain) == terrainList.size() - 1) {
189// currentStream = null;
190// }
191// //System.out.println("Processing: " + terrain.getId());
192// SlipstreamTerrainPlugin2 stream = (SlipstreamTerrainPlugin2) terrain.getPlugin();
193// for (SlipstreamSegment curr : stream.getSegments()) {
194// if (curr.discovered) continue;
195// Iterator<Object> iter = grid.getCheckIterator(curr.loc, curr.width / 2f, curr.width / 2f);
196// //Iterator<Object> iter = grid.getCheckIterator(curr.loc, 100f, 100f);
197// while (iter.hasNext()) {
198// Object obj = iter.next();
199// if (obj instanceof CustomStreamRevealer) {
200// CustomStreamRevealer rev = (CustomStreamRevealer) obj;
201// Vector2f loc = rev.loc;
202// float radius = rev.radius;
203//
204// float dist = Misc.getDistance(loc, curr.loc);
205// if (dist > maxDist) {
206// maxDist = dist;
211// }
212// if (dist < radius) {
213// curr.discovered = true;
214// break;
215// }
216// }
217// }
218// }
219// break;
220// }
221// }
222// //System.out.println("Max dist: " + maxDist);
223// }
224
225
226 private void playRepChangeSoundsIfNeeded() {
227 if (deltaFaction != null) {
228 if (highestDelta > 0) {
229 Global.getSoundPlayer().playUISound("ui_rep_raise", 1, 1);
230 } else if (highestDelta < 0) {
231 Global.getSoundPlayer().playUISound("ui_rep_drop", 1, 1);
232 }
233 }
234
235 highestDelta = 0f;
236 deltaFaction = null;
237 }
238
239
240 private float highestDelta = 0f;
241 private String deltaFaction = null;
242 @Override
243 public void reportPlayerReputationChange(String faction, float delta) {
244 super.reportPlayerReputationChange(faction, delta);
245 if (Math.abs(delta) > Math.abs(highestDelta)) {
246 highestDelta = delta;
247 deltaFaction = faction;
248 }
249 }
250
251
252 @Override
253 public void reportPlayerReputationChange(PersonAPI person, float delta) {
254 super.reportPlayerReputationChange(person, delta);
255 if (Math.abs(delta) > Math.abs(highestDelta)) {
256 highestDelta = delta;
257 deltaFaction = person.getFaction().getId();
258 }
259 }
260
261
262 public boolean isDone() {
263 return false;
264 }
265
266 public boolean runWhilePaused() {
267 return true;
268 }
269
270
271 @Override
272 public void reportPlayerMarketTransaction(PlayerMarketTransaction transaction) {
273 super.reportPlayerMarketTransaction(transaction);
274
275 for (ShipSaleInfo info : transaction.getShipsBought()) {
276 FleetMemberAPI member = info.getMember();
277 if (!member.getVariant().hasTag(Tags.VARIANT_ALLOW_EXCESS_OP_ETC)){
278 SkillsChangeRemoveExcessOPEffect.clampOP(member, Global.getSector().getPlayerStats());
279 SkillsChangeRemoveVentsCapsEffect.clampNumVentsAndCaps(member, Global.getSector().getPlayerStats());
280 }
281 }
282
283
284
285 SubmarketAPI submarket = transaction.getSubmarket();
286 MarketAPI market = transaction.getMarket();
287
288 if (!market.isPlayerOwned() && submarket.getPlugin().isParticipatesInEconomy() &&
289 !submarket.getPlugin().isBlackMarket() && submarket.getFaction() == market.getFaction()) {
290 CargoAPI cargo = transaction.getSubmarket().getCargo();
291 boolean didAnything = false;
292 OUTER: for (CargoStackAPI stack : transaction.getSold().getStacksCopy()) {
293 SpecialItemPlugin plugin = stack.getPlugin();
294 if (plugin == null) continue;
295
296 SpecialItemData data = stack.getSpecialDataIfSpecial();
297
298 InstallableItemEffect effect = ItemEffectsRepo.ITEM_EFFECTS.get(data.getId());
299 for (Industry ind : market.getIndustries()) {
300 if (ind.wantsToUseSpecialItem(data)) {
301 if (effect != null) {
302 List<String> unmet = effect.getUnmetRequirements(ind);
303 if (unmet != null && !unmet.isEmpty()) {
304 continue;
305 }
306 }
307
308 if (ind.getSpecialItem() != null) { // upgrade, put item into cargo
309 cargo.addItems(CargoItemType.SPECIAL, ind.getSpecialItem(), 1);
310 }
311 cargo.removeItems(CargoItemType.SPECIAL, data, 1);
312 ind.setSpecialItem(data);
313 didAnything = true;
314 continue OUTER;
315 }
316 }
317 }
318
319 if (didAnything) {
320 cargo.sort();
321 }
322
323 // not sure about doing this for major factions:
324 // - it can mess with their flavor, unintentionally if the player just sells blueprints
325 // - it can be a way to make their fleets weaker, by selling loads of blueprints for poor ships
326 //BlackMarketPlugin.delayedLearnBlueprintsFromTransaction(submarket.getFaction(), cargo, transaction);
327 }
328
329 //SharedData.getData().getPlayerActivityTracker().updateLastVisit(transaction.getMarket());
330
331 // moved below code to BaseSubmarketPlugin
332// SubmarketAPI sub = transaction.getSubmarket();
333// if (sub.getPlugin().isParticipatesInEconomy()) {
334// SharedData.getData().getPlayerActivityTracker().getPlayerTradeData(sub).addTransaction(transaction);
335// }
336 }
337
338 @Override
339 public void reportPlayerOpenedMarket(MarketAPI market) {
340 super.reportPlayerOpenedMarket(market);
341 SharedData.getData().getPlayerActivityTracker().updateLastVisit(market);
342 }
343
344
345
346 @Override
347 public void reportBattleOccurred(CampaignFleetAPI primaryWinner, BattleAPI battle) {
348
349 generateOrAddToDebrisFieldFromBattle(primaryWinner, battle);
350
351 if (!battle.isPlayerInvolved()) return;
352
353
354 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
355 if (!playerFleet.isValidPlayerFleet()) {
356 float fp = 0;
357 float crew = 0;
358 for (FleetMemberAPI member : Misc.getSnapshotMembersLost(playerFleet)) {
359 fp += member.getFleetPointCost();
360 crew = member.getMinCrew();
361 }
362 shared.setPlayerPreLosingBattleFP(fp);
363 shared.setPlayerPreLosingBattleCrew(crew);
364 shared.setPlayerLosingBattleTimestamp(Global.getSector().getClock().getTimestamp());
365 }
366
367
368 for (final CampaignFleetAPI otherFleet : battle.getNonPlayerSideSnapshot()) {
369 if (otherFleet.hasScriptOfClass(TOffAlarm.class)) continue;
370 MemoryAPI memory = otherFleet.getMemoryWithoutUpdate();
371 //if (!playerFleet.isTransponderOn()) {
372 //if (!memory.getBoolean(MemFlags.MEMORY_KEY_LOW_REP_IMPACT)) {
373 Misc.setFlagWithReason(memory, MemFlags.MEMORY_KEY_MAKE_HOSTILE_WHILE_TOFF, "battle", true, 7f + (float) Math.random() * 7f);
374 //}
375 //}
376
377 if (!otherFleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_LOW_REP_IMPACT) ||
378 otherFleet.getMemoryWithoutUpdate().getBoolean(MemFlags.SPREAD_TOFF_HOSTILITY_IF_LOW_IMPACT)) {
379 otherFleet.addScript(new TOffAlarm(otherFleet));
380 }
381
382
383 float fpLost = Misc.getSnapshotFPLost(otherFleet);
384
385 List<MarketAPI> markets = Misc.findNearbyLocalMarkets(otherFleet,
386 Global.getSettings().getFloat("sensorRangeMax") + 500f,
387 new MarketFilter() {
388 public boolean acceptMarket(MarketAPI market) {
389 //return market.getFaction().isAtWorst(otherFleet.getFaction(), RepLevel.COOPERATIVE);
390 return market.getFaction() != null && market.getFaction() == otherFleet.getFaction();
391 }
392 });
393
394 for (MarketAPI market : markets) {
395 MemoryAPI mem = market.getMemoryWithoutUpdate();
396 float expire = fpLost;
397 if (mem.contains(MemFlags.MEMORY_KEY_PLAYER_HOSTILE_ACTIVITY_NEAR_MARKET)) {
398 expire += mem.getExpire(MemFlags.MEMORY_KEY_PLAYER_HOSTILE_ACTIVITY_NEAR_MARKET);
399 }
400 if (expire > 180) expire = 180;
401 if (expire > 0) {
402 mem.set(MemFlags.MEMORY_KEY_PLAYER_HOSTILE_ACTIVITY_NEAR_MARKET, true, expire);
403 }
404 }
405 }
406 }
407
408
409 @Override
410 public void reportFleetJumped(CampaignFleetAPI fleet, SectorEntityToken from, JumpDestination to) {
411 super.reportFleetJumped(fleet, from, to);
412
413 if (!fleet.isPlayerFleet()) return;
414
415 FactionAPI faction = Global.getSector().getPlayerFaction();
416 Color color = faction.getBaseUIColor();
417 Color dark = faction.getDarkUIColor();
418 Color grid = faction.getGridUIColor();
419 Color bright = faction.getBrightUIColor();
420
421 if (fleet.getContainingLocation() instanceof StarSystemAPI) {
422 StarSystemAPI system = (StarSystemAPI) fleet.getContainingLocation();
423 markSystemAsEntered(system, true);
424 }
425 }
426
427 public static void markSystemAsEntered(StarSystemAPI system, boolean withMessages) {
428 system.setEnteredByPlayer(true);
429
430 for (PlanetAPI planet : system.getPlanets()) {
431 if (planet.isStar()) continue;
432
433 MarketAPI market = planet.getMarket();
434 if (market == null) continue;
435 if (market.getSurveyLevel() == SurveyLevel.NONE) {
436 market.setSurveyLevel(SurveyLevel.SEEN);
437 String type = planet.getSpec().getName();
438 if (!planet.isGasGiant()) type += " World";
439// Global.getSector().getCampaignUI().addMessage(
440// "New planet data: " + planet.getName() + ", " + type,
441// color);
442
443
444 if (withMessages) {
445// CommMessageAPI message = Global.getFactory().createMessage();
446// message.setSubject("New planet data: " + planet.getName() + ", " + type);
447// message.setAction(MessageClickAction.INTEL_TAB);
448// message.setCustomData(planet);
449// message.setAddToIntelTab(false);
450// message.setSmallIcon(Global.getSettings().getSpriteName("intel_categories", "star_systems"));
451// Global.getSector().getCampaignUI().addMessage(message);
452
453 MessageIntel intel = new MessageIntel("New planet data: " + planet.getName() + ", " + type,
454 Misc.getBasePlayerColor());//, new String[] {"" + points}, Misc.getHighlightColor());
455 intel.setIcon(Global.getSettings().getSpriteName("intel", "new_planet_info"));
456 Global.getSector().getCampaignUI().addMessage(intel, MessageClickAction.INTEL_TAB, planet);
457 }
458 }
459 }
460 }
461
462
463 public static void addMiscToDropData(DropData data, FleetMemberAPI member,
464 boolean weapons, boolean mods, boolean fighters) {
465 ShipVariantAPI variant = member.getVariant();
466
467 if (weapons) {
468 float p = Global.getSettings().getFloat("salvageWeaponProb");
469 for (String slotId : variant.getNonBuiltInWeaponSlots()) {
470 String weaponId = variant.getWeaponId(slotId);
471 data.addWeapon(weaponId, 1f * p);
472 }
473 }
474
475 if (mods) {
476 float p = Global.getSettings().getFloat("salvageHullmodProb");
477 for (String id : member.getVariant().getHullMods()) {
478 HullModSpecAPI spec = Global.getSettings().getHullModSpec(id);
479 if (spec.isHidden() || spec.isHiddenEverywhere()) continue;
480 if (spec.hasTag(Tags.HULLMOD_NO_DROP)) continue;
481 data.addHullMod(id, 1f * p);
482 }
483 }
484
485 if (fighters) {
486 float p = Global.getSettings().getFloat("salvageWingProb");
487
488 for (String id : member.getVariant().getFittedWings()) {
489 FighterWingSpecAPI spec = Global.getSettings().getFighterWingSpec(id);
490 if (spec.hasTag(Tags.WING_NO_DROP)) continue;
491 data.addFighterChip(id, 1f * p);
492 }
493 }
494
495 data.valueMult = Global.getSettings().getFloat("salvageDebrisFieldFraction");
496 }
497
498 public static Set<String> getCargoCommodities(CargoAPI cargo) {
499 Set<String> result = new HashSet<String>();
500 for (CargoStackAPI stack : cargo.getStacksCopy()) {
501 if (stack.isCommodityStack()) {
502 result.add(stack.getCommodityId());
503 }
504 }
505 return result;
506 }
507
508 public static void generateOrAddToDebrisFieldFromBattle(CampaignFleetAPI primaryWinner, BattleAPI battle) {
509
510 if (primaryWinner == null) return;
511 LocationAPI location = primaryWinner.getContainingLocation();
512 if (location == null) return;
513
514 //if (location.isHyperspace()) return;
515
516 boolean allowDebris = !location.isHyperspace();
517
518
519 boolean playerInvolved = battle.isPlayerInvolved();
520
521 DropData misc = new DropData();
522 int miscChances = 0;
523
524 List<DropData> cargoList = new ArrayList<DropData>();
525
526 WeightedRandomPicker<FleetMemberAPI> recoverySpecialChoices = new WeightedRandomPicker<FleetMemberAPI>();
527
528 Vector2f com = new Vector2f();
529 float count = 0f;
530 float fpDestroyed = 0;
531 for (CampaignFleetAPI fleet : battle.getSnapshotSideOne()) {
532 count++;
533 com.x += fleet.getLocation().x;
534 com.y += fleet.getLocation().y;
535
536 float fpForThisFleet = 0;
537 for (FleetMemberAPI loss : Misc.getSnapshotMembersLost(fleet)) {
538 //if (loss.getVariant().isStockVariant()) {
539 if (!loss.getVariant().hasTag(Tags.SHIP_RECOVERABLE)) { // was not recoverable by player
540 if (!loss.isStation() && !fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_NO_SHIP_RECOVERY)) {
541 recoverySpecialChoices.add(loss);
542 }
543 }
544 fpDestroyed += loss.getFleetPointCost();
545 fpForThisFleet += loss.getFleetPointCost();
546 if (allowDebris && !fleet.isPlayerFleet()) {
547 addMiscToDropData(misc, loss, true, true, true);
548 miscChances++;
549 }
550 }
551 if (allowDebris && !fleet.isPlayerFleet()) {
552 DropData cargo = new DropData();
553 float cargoValue = fpForThisFleet * Global.getSettings().getFloat("salvageValuePerFP");
554 cargoValue *= Global.getSettings().getFloat("salvageDebrisFieldFraction");
555 if (cargoValue >= 1) {
556 for (String cid : getCargoCommodities(fleet.getCargo())) {
557 cargo.addCommodity(cid, 1f);
558 }
559 cargo.value = (int) cargoValue;
560 cargo.chances = 1;
561 cargoList.add(cargo);
562 }
563 }
564 }
565 for (CampaignFleetAPI fleet : battle.getSnapshotSideTwo()) {
566 count++;
567 com.x += fleet.getLocation().x;
568 com.y += fleet.getLocation().y;
569
570 float fpForThisFleet = 0;
571 for (FleetMemberAPI loss : Misc.getSnapshotMembersLost(fleet)) {
572 //if (loss.getVariant().isStockVariant()) {
573 if (!loss.getVariant().hasTag(Tags.SHIP_RECOVERABLE)) { // was not recoverable by player
574 if (!loss.isStation() && !fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.MEMORY_KEY_NO_SHIP_RECOVERY)) {
575 recoverySpecialChoices.add(loss);
576 }
577 } else {
578 loss.getVariant().removeTag(Tags.SHIP_RECOVERABLE);
579 }
580
581 fpDestroyed += loss.getFleetPointCost();
582 fpForThisFleet += loss.getFleetPointCost();
583 if (allowDebris && !fleet.isPlayerFleet()) {
584 addMiscToDropData(misc, loss, true, true, true);
585 miscChances++;
586 }
587 }
588 if (allowDebris && !fleet.isPlayerFleet()) {
589 DropData cargo = new DropData();
590 float cargoValue = fpForThisFleet * Global.getSettings().getFloat("salvageValuePerFP");
591 cargoValue *= Global.getSettings().getFloat("salvageDebrisFieldFraction");
592 if (cargoValue >= 1) {
593 for (String cid : getCargoCommodities(fleet.getCargo())) {
594 cargo.addCommodity(cid, 1f);
595 }
596 cargo.value = (int) cargoValue;
597 cargo.chances = 1;
598 cargoList.add(cargo);
599 }
600 }
601 }
602 //Global.getSector().getPlayerFleet().getLocation()
603 if (count <= 0) return;
604
605 com.scale(1f / count);
606
607 // spawn some derelict ships, maybe. do this here, regardless of whether the value is enough to
608 // warrant a debris field
609 float numShips = recoverySpecialChoices.getItems().size();
610 float chanceDerelict = 1f - 10f / (numShips + 10f);
611 //chanceNothing = 0f;
612 //Vector2f com = battle.computeCenterOfMass();
613
614 // in a battle that involves the player, recoverable ships are non-stock variants
615 // (due to being prepared for recovery; dmods etc) and so don't show up as possible recovery choices here
616 // which is good! since 1) they could've been actually recovered, and 2) they already contributed to player salvage
617 // replaced this with Tags.SHIP_RECOVERABLE tag in recoverable variant for cleanness
618 int max = 3;
619 if (playerInvolved) {
620 max = 2;
621 chanceDerelict *= 0.25f;
622 }
623 for (int i = 0; i < max && !recoverySpecialChoices.isEmpty(); i++) {
624 boolean spawnShip = Math.random() < chanceDerelict;
625 if (spawnShip) {
626 FleetMemberAPI member = recoverySpecialChoices.pickAndRemove();
627 String variantId = member.getVariant().getHullVariantId();
628 if (!member.getVariant().isStockVariant()) variantId = member.getVariant().getOriginalVariant();
629 if (variantId == null) continue;
630 DerelictShipData params = new DerelictShipData(new PerShipData(variantId,
632 params.durationDays = DerelictShipEntityPlugin.getBaseDuration(member.getHullSpec().getHullSize());
633 CustomCampaignEntityAPI entity = (CustomCampaignEntityAPI) BaseThemeGenerator.addSalvageEntity(
634 primaryWinner.getContainingLocation(),
635 Entities.WRECK, Factions.NEUTRAL, params);
636 entity.addTag(Tags.EXPIRES);
637 SalvageSpecialAssigner.assignSpecialForBattleWreck(entity);
638
639// entity.getLocation().x = com.x + (50f - (float) Math.random() * 100f);
640// entity.getLocation().y = com.y + (50f - (float) Math.random() * 100f);
641
642 float angle = (float) Math.random() * 360f;
643 float speed = 10f + 10f * (float) Math.random();
644 Vector2f vel = Misc.getUnitVectorAtDegreeAngle(angle);
645 vel.scale(speed);
646 entity.getVelocity().set(vel);
647
648 entity.getLocation().x = com.x + vel.x * 3f;
649 entity.getLocation().y = com.y + vel.y * 3f;
650 }
651 }
652
653
654
655 float salvageValue = fpDestroyed * Global.getSettings().getFloat("salvageValuePerFP");
656 if (Misc.isEasy()) {
657 salvageValue *= Global.getSettings().getFloat("easySalvageMult");
658 }
659
660
661 salvageValue *= Global.getSettings().getFloat("salvageDebrisFieldFraction");
662 float salvageXP = salvageValue * 0.1f;
663
664 float minForField = Global.getSettings().getFloat("minSalvageValueForDebrisField");
665 //if (playerInvolved) minForField *= 6f;
666 if (playerInvolved) minForField = 2500f + (float) Math.random() * 1000f;
667
668 if (salvageValue < minForField || !allowDebris) return;
669
670
671 CampaignTerrainAPI debris = null;
672 for (CampaignTerrainAPI curr : primaryWinner.getContainingLocation().getTerrainCopy()) {
673 if (curr.getPlugin() instanceof DebrisFieldTerrainPlugin) {
674 DebrisFieldTerrainPlugin plugin = (DebrisFieldTerrainPlugin) curr.getPlugin();
675 if (plugin.params.source == DebrisFieldSource.BATTLE &&
676 plugin.params.density >= 1f &&
677 plugin.containsPoint(com, 100f)) {
678 debris = curr;
679 break;
680 }
681 }
682 }
683
684 if (debris == null) {
685 DebrisFieldParams params = new DebrisFieldParams(
686 200f, // field radius - should not go above 1000 for performance reasons
687 -1f, // density, visual - affects number of debris pieces
688 1f, // duration in days
689 1f); // days the field will keep generating glowing pieces
690 params.source = DebrisFieldSource.BATTLE;
691 params.baseSalvageXP = (long) salvageXP; // base XP for scavenging in field
692
693 debris = (CampaignTerrainAPI) Misc.addDebrisField(location, params, null);
694
695 // makes the debris field always visible on map/sensors and not give any xp or notification on being discovered
696 //debris.setSensorProfile(null);
697 //debris.setDiscoverable(null);
698
699 // makes it discoverable and give 200 xp on being found
700 // sets the range at which it can be detected (as a sensor contact) to 2000 units
701 //debris.setDiscoverable(true);
702 //debris.setDiscoveryXP(200f);
703 //debris.setSensorProfile(1f);
704 //debris.getDetectedRangeMod().modifyFlat("gen", 2000);
705
706 debris.setDiscoverable(null);
707 debris.setDiscoveryXP(null);
708 //debris.setSensorProfile(1f);
709 //debris.getDetectedRangeMod().modifyFlat("gen", 1000);
710
711 debris.getLocation().set(com);
712
713 debris.getDropValue().clear();
714 debris.getDropRandom().clear();
715 }
716
717
718 DebrisFieldTerrainPlugin plugin = (DebrisFieldTerrainPlugin) debris.getPlugin();
719 DropData basicDrop = null;
720 for (DropData data : debris.getDropValue()) {
721 if (Drops.BASIC.equals(data.group)) {
722 basicDrop = data;
723 break;
724 }
725 }
726
727 // since we're only adding to fields with density 1 (i.e. ones the player hasn't salvaged)
728 // no need to worry about how density would affect the salvage value of what we're adding
729 if (basicDrop == null) {
730 basicDrop = new DropData();
731 basicDrop.group = Drops.BASIC;
732 debris.addDropValue(basicDrop);
733 }
734 basicDrop.value += salvageValue;
735
736 if (misc.getCustom() != null) {
737 misc.chances = miscChances;
738
739 float total = misc.getCustom().getTotal();
740 if (total > 0) {
741 misc.addNothing(Math.max(1f, total));
742 }
743 debris.addDropRandom(misc);
744 //misc.getCustom().print("MISC DROP");
745 }
746
747 for (DropData cargo : cargoList) {
748 debris.addDropRandom(cargo);
749 }
750
751
752 //if (!battle.isPlayerInvolved()) {
753 ShipRecoverySpecialData data = ShipRecoverySpecial.getSpecialData(debris, null, true, false);
754 if (data != null && data.ships.size() < 3) {
755 float items = recoverySpecialChoices.getTotal();
756 float total = items + 25f;
757 for (int i = 0; i < 3; i++) {
758 if ((float) Math.random() * total < items) {
759 FleetMemberAPI pick = recoverySpecialChoices.pick();
760 if (pick != null) {
761 String variantId = pick.getVariant().getHullVariantId();
762 if (!pick.getVariant().isStockVariant()) variantId = pick.getVariant().getOriginalVariant();
763 data.addShip(variantId, ShipCondition.WRECKED, 0f);
764 }
765 }
766 }
767 }
768 //}
769
770// basicDrop = new DropData();
771// basicDrop.group = "misc_test";
772// basicDrop.value = 100000;
773// existing.addDropValue(basicDrop);
774
775 // resize and adjust duration here
776
777 float radius = 100f + (float) Math.min(900, Math.sqrt(basicDrop.value));
778 float durationExtra = (float) Math.sqrt(salvageValue) * 0.1f;
779
780 float minDays = DebrisFieldTerrainPlugin.DISSIPATE_DAYS + 1f;
781 if (durationExtra < minDays) durationExtra = minDays;
782
783 float time = durationExtra + plugin.params.lastsDays;
784 if (time > 30f) time = 30f;
785
786 plugin.params.lastsDays = time;
787 plugin.params.glowsDays = time;
788
789 plugin.params.bandWidthInEngine = radius;
790 plugin.params.middleRadius = plugin.params.bandWidthInEngine / 2f;
791
792 float range = DebrisFieldTerrainPlugin.computeDetectionRange(plugin.params.bandWidthInEngine);
793 debris.getDetectedRangeMod().modifyFlat("gen", range);
794 }
795
796
797
798
799 @Override
800 public void reportPlayerDumpedCargo(CargoAPI cargo) {
801 super.reportPlayerDumpedCargo(cargo);
802
803
804 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
805
806 CustomCampaignEntityAPI pods = Misc.addCargoPods(playerFleet.getContainingLocation(), playerFleet.getLocation());
807 pods.getCargo().addAll(cargo);
808
809 CargoPodsResponse script = new CargoPodsResponse(pods);
810 pods.getContainingLocation().addScript(script);
811 ListenerUtil.reportPlayerLeftCargoPods(pods);
812// pods.getMemoryWithoutUpdate().set(CargoPods.LOCKED, true);
813// pods.getMemoryWithoutUpdate().set(CargoPods.CAN_UNLOCK, true);
814 //pods.getMemoryWithoutUpdate().set(CargoPods.TRAPPED, true);
815
816 //pods.getDetectedRangeMod().modifyFlat("gen", 1000);
817 }
818
819 @Override
820 public void reportPlayerDidNotTakeCargo(CargoAPI cargo) {
821 super.reportPlayerDumpedCargo(cargo);
822
823 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
824
825 CustomCampaignEntityAPI pods = Misc.addCargoPods(playerFleet.getContainingLocation(), playerFleet.getLocation());
826 pods.getCargo().addAll(cargo);
827
828 ListenerUtil.reportPlayerLeftCargoPods(pods);
829 }
830
831 protected Random prodRandom = new Random();
832 public void doCustomProduction() {
833 FactionAPI pf = Global.getSector().getPlayerFaction();
834 FactionProductionAPI prod = pf.getProduction();
835
836 MarketAPI gatheringPoint = prod.getGatheringPoint();
837 if (gatheringPoint == null) return;
838
839 //CargoAPI local = Misc.getLocalResourcesCargo(gatheringPoint);
840 CargoAPI local = Misc.getStorageCargo(gatheringPoint);
841 if (local == null) return;
842
843 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
844 MonthlyReport report = SharedData.getData().getCurrentReport();
845 report.computeTotals();
846
847 // limit production capacity by available credits - the net coming in this month plus what the player has
848 int total = (int) (report.getRoot().totalIncome - report.getRoot().totalUpkeep);
849 int credits = (int) playerFleet.getCargo().getCredits().get();
850 credits += total;
851 if (credits < 0) credits = 0;
852
853 int capacity = prod.getMonthlyProductionCapacity();
854 capacity = Math.min(capacity, credits);
855 //capacity = 1000000;
856
857 int remainingValue = capacity + prod.getAccruedProduction();
858 //if (remainingValue <= 0) return;
859
860
861
862 //Random random = new Random();
863 if (prodRandom == null) prodRandom = new Random();
864 Random random = prodRandom;
865
866 WeightedRandomPicker<ItemInProductionAPI> picker = new WeightedRandomPicker<ItemInProductionAPI>(random);
867 for (ItemInProductionAPI item : prod.getCurrent()) {
868 if (item.getBuildDelay() > 0 && !Global.getSettings().isDevMode()) continue;
869 picker.add(item, item.getQuantity());
870 }
871 int accrued = 0;
872
873 boolean wantedToDoProduction = !picker.isEmpty();
874 boolean unableToDoProduction = capacity <= 0;
875
876 ProductionData data = new ProductionData();
877 //CargoAPI cargo = Global.getFactory().createCargo(true);
878 //cargo.initMothballedShips(Factions.PLAYER);
879 CargoAPI cargo = data.getCargo("Heavy Industry - Custom Production");
880
881 float quality = -1f;
882 for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) {
883 if (!market.isPlayerOwned()) continue;
884 //quality = Math.max(quality, ShipQuality.getShipQuality(market, Factions.PLAYER));
885 float currQuality = market.getStats().getDynamic().getMod(Stats.PRODUCTION_QUALITY_MOD).computeEffective(0f);
886 currQuality += market.getStats().getDynamic().getMod(Stats.FLEET_QUALITY_MOD).computeEffective(0f);
887 quality = Math.max(quality, currQuality);
888 }
889 quality -= Global.getSector().getFaction(Factions.PLAYER).getDoctrine().getShipQualityContribution();
890 quality += 4f * Global.getSettings().getFloat("doctrineFleetQualityPerPoint");
891
892 CampaignFleetAPI ships = Global.getFactory().createEmptyFleet(Factions.PLAYER, "temp", true);
893 ships.setCommander(Global.getSector().getPlayerPerson());
894 DefaultFleetInflaterParams p = new DefaultFleetInflaterParams();
895 p.quality = quality;
896 p.mode = ShipPickMode.PRIORITY_THEN_ALL;
897 p.persistent = false;
898 p.seed = random.nextLong();
899 p.timestamp = null;
900
901 FleetInflater inflater = Misc.getInflater(ships, p);
902 ships.setInflater(inflater);
903
904 int totalCost = 0;
905 while (remainingValue > 0 && !picker.isEmpty()) {
906 ItemInProductionAPI pick = picker.pick();
907 int baseCost = pick.getBaseCost();
908
909 int count = Math.min(pick.getQuantity(), remainingValue / Math.max(1, baseCost));
910 if (count > 0) {
911 count = random.nextInt(count) + 1;
912 }
913 if (count <= 0) {
914 accrued = remainingValue;
915 remainingValue = 0;
916 } else {
917 int currCost = count * baseCost;
918 totalCost += currCost;
919 remainingValue -= currCost;
920
921 if (pick.getType() == ProductionItemType.SHIP) {
922 List<String> variants = Global.getSettings().getHullIdToVariantListMap().get(pick.getSpecId());
923 if (variants.isEmpty()) {
924 variants.add(pick.getSpecId() + "_Hull");
925 continue;
926 }
927
928 int index = random.nextInt(variants.size());
929 //cargo.addMothballedShip(FleetMemberType.SHIP, variants.get(index), null);
930 for (int i = 0; i < count; i++) {
931 ships.getFleetData().addFleetMember(variants.get(index));
932 }
933 } else if (pick.getType() == ProductionItemType.FIGHTER) {
934 cargo.addFighters(pick.getSpecId(), count);
935 } else if (pick.getType() == ProductionItemType.WEAPON) {
936 cargo.addWeapons(pick.getSpecId(), count);
937 }
938
939 prod.removeItem(pick.getType(), pick.getSpecId(), count);
940 if (pick.getQuantity() <= 0) {
941 picker.remove(pick);
942 }
943 }
944 }
945
946 int weaponCost = 0;
947 ships.inflateIfNeeded();
948 for (FleetMemberAPI member : ships.getFleetData().getMembersListCopy()) {
949 cargo.getMothballedShips().addFleetMember(member);
950 for (String wingId : member.getVariant().getNonBuiltInWings()) {
951 FighterWingSpecAPI spec = Global.getSettings().getFighterWingSpec(wingId);
952 weaponCost += spec.getBaseValue();
953 }
954 for (String slotId : member.getVariant().getNonBuiltInWeaponSlots()) {
955 WeaponSpecAPI spec = member.getVariant().getWeaponSpec(slotId);
956 weaponCost += spec.getBaseValue();
957 }
958 }
960 weaponCost = 0;
961 }
962
963 // add some supplies, fuel, and crew
964 int addedValue = (int) (totalCost * Global.getSettings().getFloat("productionSuppliesBonusFraction"));
965 int sCost = (int) Global.getSettings().getCommoditySpec(Commodities.SUPPLIES).getBasePrice();
966 int fCost = (int) Global.getSettings().getCommoditySpec(Commodities.FUEL).getBasePrice();
967 int cCost = (int) Global.getSettings().getCommoditySpec(Commodities.CREW).getBasePrice();
968
969 int supplies = (int) (addedValue * (0.5f * (0.5f + random.nextFloat() * 0.5f))) / sCost;
970 int fuel = (int) (addedValue * (0.3f * (0.5f + random.nextFloat() * 0.5f))) / fCost;
971 int crew = (addedValue - sCost * supplies - fCost * fuel) / cCost;
972
973 supplies = supplies / 10 * 10;
974 fuel = fuel / 10 * 10;
975 crew = crew / 10 * 10;
976
977 cargo.addSupplies(supplies);
978 cargo.addFuel(fuel);
979 cargo.addCrew(crew);
980
981 //accrued += remainingValue; // don't do that, only want to accrue when trying to produce something
982
983 totalCost -= prod.getAccruedProduction();
984 totalCost += accrued;
985 if (totalCost < 0) totalCost = 0;
986 prod.setAccruedProduction(accrued);
987
988 for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) {
989 if (!market.isPlayerOwned()) continue;
990
991 for (Industry ind : market.getIndustries()) {
992 Random curr = Misc.getRandom(random.nextLong(), 11);
993 CargoAPI added = ind.generateCargoForGatheringPoint(curr);
994 if (added != null && (!added.isEmpty() ||
995 (added.getMothballedShips() != null && !added.getMothballedShips().getMembersListCopy().isEmpty()))) {
996 String title = ind.getCargoTitleForGatheringPoint();
997 data.getCargo(title).addAll(added, true);
998 }
999 }
1000 }
1001
1002
1003 // done with production
1004
1005
1006
1007 if (!data.isEmpty() || totalCost > 0 || (wantedToDoProduction && unableToDoProduction)) {
1008 if (totalCost > 0) {
1009 //MonthlyReport report = SharedData.getData().getCurrentReport();
1010
1011 FDNode marketsNode = report.getNode(MonthlyReport.OUTPOSTS);
1012 if (marketsNode.name == null) {
1013 marketsNode.name = "Colonies";
1014 marketsNode.custom = MonthlyReport.OUTPOSTS;
1015 marketsNode.tooltipCreator = report.getMonthlyReportTooltip();
1016 }
1017
1018 FDNode production = report.getNode(marketsNode, MonthlyReport.PRODUCTION);
1019 production.name = "Custom production orders";
1020 production.custom = MonthlyReport.PRODUCTION;
1021 production.custom2 = cargo;
1022 production.tooltipCreator = report.getMonthlyReportTooltip();
1023
1024 production.upkeep += totalCost;
1025
1026 if (weaponCost > 0) {
1027 FDNode productionWeapons = report.getNode(marketsNode, MonthlyReport.PRODUCTION_WEAPONS);
1028 productionWeapons.name = "Weapons & fighter LPCs for produced ships";
1029 productionWeapons.custom = MonthlyReport.PRODUCTION_WEAPONS;
1030 productionWeapons.tooltipCreator = report.getMonthlyReportTooltip();
1031 productionWeapons.upkeep += weaponCost;
1032 }
1033 }
1034
1035 for (CargoAPI curr : data.data.values()) {
1036 local.addAll(curr);
1037 local.initMothballedShips(Factions.PLAYER);
1038 for (FleetMemberAPI member : curr.getMothballedShips().getMembersListCopy()) {
1039// member.getRepairTracker().setCR(0f);
1040// member.getRepairTracker().setMothballed(true);
1041 member.getRepairTracker().setMothballed(false);
1042 member.getRepairTracker().setCR(0.5f);
1043 local.getMothballedShips().addFleetMember(member);
1044 }
1045 }
1046 local.sort();
1047
1048 ProductionReportIntel intel = new ProductionReportIntel(gatheringPoint, data,
1049 totalCost + weaponCost, prod.getAccruedProduction(),
1050 wantedToDoProduction && unableToDoProduction);
1051 Global.getSector().getIntelManager().addIntel(intel);
1052 }
1053
1054 }
1055
1056
1057 @Override
1059 super.reportEconomyMonthEnd();
1060
1061 if (TutorialMissionIntel.isTutorialInProgress()) {
1062 return;
1063 }
1064
1065 MonthlyReport report = SharedData.getData().getCurrentReport();
1066 FDNode marketsNode = report.getNode(MonthlyReport.OUTPOSTS);
1067 if (marketsNode.custom != null) {
1068 for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) {
1069 if (!market.isPlayerOwned()) continue;
1070
1071 float incentive = market.getIncentiveCredits();
1072 if (incentive > 0) {
1073 FDNode mNode = report.getNode(marketsNode, market.getId());
1074 if (mNode.custom != null) {
1075 FDNode incNode = report.getNode(mNode, "incentives");
1076 incNode.name = "Hazard pay";
1077 incNode.custom = MonthlyReport.INCENTIVES;
1078 incNode.mapEntity = market.getPrimaryEntity();
1079 incNode.tooltipCreator = report.getMonthlyReportTooltip();
1080 incNode.upkeep += incentive;
1081 }
1082 market.setIncentiveCredits(0);
1083 }
1084 }
1085 }
1086
1087
1088 MonthlyReport previous = SharedData.getData().getPreviousReport();
1089 float debt = previous.getDebt();
1090 if (debt > 0) {
1091 MonthlyReport current = SharedData.getData().getCurrentReport();
1092 current.getDebtNode().upkeep = debt;
1093 }
1094
1096
1097 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
1098
1099 //MonthlyReport previous = SharedData.getData().getPreviousReport();
1100 SharedData.getData().rollOverReport();
1101 report = SharedData.getData().getPreviousReport();
1102 report.setPreviousDebt(previous.getDebt());
1103 report.setTimestamp(Global.getSector().getClock().getTimestamp());
1104
1105 report.computeTotals();
1106 int total = (int) (report.getRoot().totalIncome - report.getRoot().totalUpkeep);
1107 float credits = (int) playerFleet.getCargo().getCredits().get();
1108
1109 float newCredits = credits + total;
1110 if (newCredits < 0) {
1111 report.setDebt((int) Math.abs(newCredits));
1112 newCredits = 0;
1113 }
1114 playerFleet.getCargo().getCredits().set(newCredits);
1115
1116
1117 String totalStr = Misc.getDGSCredits(Math.abs(total));
1118 //Global.getSector().getCampaignUI().showCoreUITab(CoreUITabId.OUTPOSTS);
1119
1120 String title = "Monthly income: " + totalStr;
1121 Color highlight = Misc.getHighlightColor();
1122 if (total < 0) {
1123 title = "Monthly expenses: " + totalStr;
1124 highlight = Misc.getNegativeHighlightColor();
1125 }
1126
1127 MessageIntel intel = new MessageIntel(title,
1128 Misc.getBasePlayerColor(), new String[] {totalStr}, highlight);
1129 intel.setIcon(Global.getSettings().getSpriteName("intel", "monthly_income_report"));
1130
1131 if (total >= 0) {
1132 intel.setSound("ui_intel_monthly_income_positive");
1133 } else {
1134 intel.setSound("ui_intel_monthly_income_negative");
1135 }
1136
1137 Global.getSector().getCampaignUI().addMessage(intel, MessageClickAction.INCOME_TAB, Tags.INCOME_REPORT);
1138
1139
1140// CommMessageAPI message = FleetLog.beginEntry(
1141// title,
1142// playerFleet,
1143// highlight,
1144// totalStr
1145// );
1146//
1147// message.setSmallIcon(Global.getSettings().getSpriteName("intel_categories", "bounties"));
1148// if (total >= 0) {
1149// message.getSection1().addPara("Over the last month, your fleet, outposts, and other ventures have" +
1150// " produced an income of " + totalStr + ".");
1151// } else {
1152// message.getSection1().addPara("Over the last month, your fleet, outposts, and other ventures have" +
1153// " produced expenses of " + totalStr + ".");
1154// }
1155//
1156// if (total < 0 && Math.abs(total) > credits) {
1157// message.getSection1().addPara("Your expenses have exceeded your credit balance. If this continues for more than a month, " +
1158// "some crew and officers may begin to leave, and other undertakings requiring credit expenditures may fail.");
1159// //message.getSection1().addPara(".");
1160// }
1161// message.getSection1().addPara("See the \"Income\" tab in the command screen for a detailed breakdown.");
1162//
1163// message.getSection1().setHighlights(totalStr);
1164// message.getSection1().setHighlightColors(highlight);
1165//
1166// message.setShowInCampaignList(true);
1167// message.setAddToIntelTab(true);
1168// message.setAction(MessageClickAction.INCOME_TAB);
1169// message.addTag(Tags.FLEET_LOG);
1170// message.addTag(Tags.INCOME_REPORT);
1171//
1172// Global.getSector().getCampaignUI().addMessage(message);
1173 }
1174
1175// private MonthlyReportNodeTooltipCreator monthlyReportTooltip;
1176// public static MonthlyReportNodeTooltipCreator getMonthlyReportTooltip() {
1177// if (monthlyReportTooltip == null) {
1178// monthlyReportTooltip = new MonthlyReportNodeTooltipCreator();
1179// }
1180// return monthlyReportTooltip;
1181// }
1182
1183
1184 @Override
1185 public void reportEconomyTick(int iterIndex) {
1186 super.reportEconomyTick(iterIndex);
1187
1188 if (TutorialMissionIntel.isTutorialInProgress()) {
1189 return;
1190 }
1191
1192 //for (int i = 0; i < 100; i++) {
1193 int crewSalary = Global.getSettings().getInt("crewSalary");
1194 int marineSalary = Global.getSettings().getInt("marineSalary");
1195
1196 float numIter = Global.getSettings().getFloat("economyIterPerMonth");
1197 float f = 1f / numIter;
1198
1199 //f = 1f;
1200
1201 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
1202 MonthlyReport report = SharedData.getData().getCurrentReport();
1203
1204
1205 FDNode fleetNode = report.getNode(MonthlyReport.FLEET);
1206 fleetNode.name = "Fleet";
1207 fleetNode.custom = MonthlyReport.FLEET;
1208 fleetNode.tooltipCreator = report.getMonthlyReportTooltip();
1209
1210 int crewCost = playerFleet.getCargo().getCrew() * crewSalary;
1211 FDNode crewNode = report.getNode(fleetNode, MonthlyReport.CREW);
1212 crewNode.upkeep += crewCost * f;
1213 crewNode.name = "Crew payroll";
1214 crewNode.custom = MonthlyReport.CREW;
1215 crewNode.tooltipCreator = report.getMonthlyReportTooltip();
1216
1217 int marineCost = playerFleet.getCargo().getMarines() * marineSalary;
1218 if (marineSalary > 0) {
1219 FDNode marineNode = report.getNode(fleetNode, MonthlyReport.MARINES);
1220 marineNode.upkeep += marineCost * f;
1221 marineNode.name = "Marine payroll";
1222 marineNode.custom = MonthlyReport.MARINES;
1223 marineNode.tooltipCreator = report.getMonthlyReportTooltip();
1224 }
1225
1226
1227// List<PersonnelAtEntity> droppedOffMarines = PlayerFleetPersonnelTracker.getInstance().getDroppedOff();
1228// for (PersonnelAtEntity curr : droppedOffMarines) {
1229//
1230// }
1231// for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) {
1232// if (Misc.playerHasStorageAccess(market)) {
1233//
1234// }
1235// }
1236
1237
1238
1239 //FDNode officersNode = report.getNode(MonthlyReport.OFFICERS);
1240 FDNode officersNode = report.getNode(fleetNode, MonthlyReport.OFFICERS);
1241 officersNode.name = "Officer payroll";
1242 officersNode.custom = MonthlyReport.OFFICERS;
1243 officersNode.tooltipCreator = report.getMonthlyReportTooltip();
1244
1245
1246 for (OfficerDataAPI od : playerFleet.getFleetData().getOfficersCopy()) {
1247 float salary = Misc.getOfficerSalary(od.getPerson());
1248 FDNode oNode = report.getNode(officersNode, od.getPerson().getId());
1249 oNode.name = od.getPerson().getName().getFullName();
1250 oNode.upkeep += salary * f;
1251 oNode.custom = od;
1252 }
1253
1254 FDNode marketsNode = report.getNode(MonthlyReport.OUTPOSTS);
1255 marketsNode.name = "Colonies";
1256 marketsNode.custom = MonthlyReport.OUTPOSTS;
1257 marketsNode.tooltipCreator = report.getMonthlyReportTooltip();
1258
1259 FDNode storageNode = null;
1260// storageNode = report.getNode(MonthlyReport.STORAGE);
1261// storageNode.name = "Storage";
1262// storageNode.custom = MonthlyReport.STORAGE;
1263// storageNode.tooltipCreator = report.getMonthlyReportTooltip();
1264
1265 float storageFraction = Global.getSettings().getFloat("storageFreeFraction");
1266
1267 int index = 0;
1268 for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) {
1269// if (index % 10 != 3 || index == 0) {
1270// index++;
1271// continue;
1272// }
1273
1274 if (!market.isPlayerOwned() && Misc.playerHasStorageAccess(market)) {
1275 float vc = Misc.getStorageCargoValue(market);
1276 float vs = Misc.getStorageShipValue(market);
1277
1278 float fc = (int) (vc * storageFraction);
1279 float fs = (int) (vs * storageFraction);
1280 if (fc > 0 || fs > 0) {
1281 if (storageNode == null) {
1282 storageNode = report.getNode(MonthlyReport.STORAGE);
1283 storageNode.name = "Storage";
1284 storageNode.custom = MonthlyReport.STORAGE;
1285 storageNode.tooltipCreator = report.getMonthlyReportTooltip();
1286 }
1287 FDNode mNode = report.getNode(storageNode, market.getId());
1288 String desc = "";
1289 if (fc > 0 && fs > 0) {
1290 desc = "ships & cargo";
1291 } else if (fc > 0) {
1292 desc = "cargo";
1293 } else {
1294 desc = "ships";
1295 }
1296 mNode.name = market.getName() + " (" + desc + ")";
1297 mNode.custom = market;
1298 mNode.custom2 = MonthlyReport.STORAGE;
1299 //mNode.tooltipCreator = report.getMonthlyReportTooltip();
1300
1301 mNode.upkeep += (fc + fs) * f;
1302 }
1303 continue;
1304 }
1305
1306
1307 //if (market.isHidden()) continue;
1308 //if (!Factions.DIKTAT.equals(market.getFaction().getId()) && !market.isPlayerOwned()) continue;
1309 if (!market.isPlayerOwned()) continue;
1310
1311 FDNode mNode = report.getNode(marketsNode, market.getId());
1312 mNode.name = market.getName() + " (" + market.getSize() + ")";
1313 mNode.custom = market;
1314
1315 FDNode indNode = report.getNode(mNode, "industries");
1316 indNode.name = "Industries & structures";
1317 indNode.custom = MonthlyReport.INDUSTRIES;
1318 indNode.mapEntity = market.getPrimaryEntity();
1319 indNode.tooltipCreator = report.getMonthlyReportTooltip();
1320// node.income += (int) market.getIndustryIncome();
1321// node.upkeep += (int) market.getIndustryUpkeep();
1322
1323 for (Industry curr : market.getIndustries()) {
1324 FDNode iNode = report.getNode(indNode, curr.getId());
1325 iNode.name = curr.getCurrentName();
1326 iNode.income += curr.getIncome().getModifiedInt() * f;
1327 iNode.upkeep += curr.getUpkeep().getModifiedInt() * f;
1328 iNode.custom = curr;
1329 iNode.mapEntity = market.getPrimaryEntity();
1330 }
1331
1332 FDNode exportNode = report.getNode(mNode, "exports");
1333 exportNode.name = "Exports";
1334 exportNode.custom = MonthlyReport.EXPORTS;
1335 exportNode.mapEntity = market.getPrimaryEntity();
1336 exportNode.tooltipCreator = report.getMonthlyReportTooltip();
1337
1338 addExportsGroupedByCommodity(report, exportNode, market, f);
1339 //addExportsGroupedByFaction(report, exportNode, market, f);
1340
1341
1342// FDNode overheadNode = report.getNode(exportNode, "overhead");
1343// if (overheadNode.name == null) {
1344// overheadNode.name = "Overhead";
1345// overheadNode.icon = Global.getSettings().getSpriteName("income_report", "overhead");
1346// overheadNode.custom = market;
1347// overheadNode.mapEntity = market.getPrimaryEntity();
1348// overheadNode.tooltipCreator = new OverheadTooltipCreator();
1349// }
1350//
1351// OverheadData overhead = computeOverhead(market);
1352// if (overhead.fraction > 0) {
1353// float totalIncome = market.getExportIncome(false);
1354// overheadNode.upkeep += totalIncome * overhead.fraction * f;
1355// }
1356
1357 index++;
1358 }
1359 //}
1360
1361
1362 FDNode adminNode = report.getNode(marketsNode, MonthlyReport.ADMIN);
1363 adminNode.name = "Administrators";
1364 adminNode.custom = MonthlyReport.ADMIN;
1365 adminNode.tooltipCreator = report.getMonthlyReportTooltip();
1366
1367 for (AdminData data : Global.getSector().getCharacterData().getAdmins()) {
1368 float salary = Misc.getAdminSalary(data.getPerson());
1369 if (salary <= 0) continue;
1370
1371 FDNode aNode = report.getNode(adminNode, data.getPerson().getId());
1372 aNode.name = data.getPerson().getName().getFullName();
1373 if (data.getMarket() != null) {
1374 aNode.name += " (" + data.getMarket().getName() + ")";
1375 } else {
1376 aNode.name += " (unassigned)";
1377 salary *= Global.getSettings().getFloat("idleAdminSalaryMult");
1378 }
1379 aNode.upkeep += salary * f;
1380 aNode.custom = data;
1381 }
1382
1383 //reportEconomyMonthEnd();
1384 }
1385
1386// public static class OverheadData {
1387// public SupplierData max;
1388// public float fraction;
1389// }
1390//
1391// public static OverheadData computeOverhead(MarketAPI market) {
1392// OverheadData result = new OverheadData();
1393//
1394// SupplierData max = null;
1395// float maxValue = 0;
1396// float total = 0f;
1397// List<CommodityOnMarketAPI> comList = market.getCommoditiesCopy();
1398// for (CommodityOnMarketAPI com : comList) {
1399// for (SupplierData sd : com.getExports()) {
1400// int income = sd.getExportValue(market);
1401// if (income <= 0) continue;
1402//
1403// total += income;
1404// if (income > maxValue) {
1405// max = sd;
1406// maxValue = income;
1407// }
1408// }
1409// }
1410//
1411// if (max != null && maxValue > 0) {
1412// result.max = max;
1413// float units = total / maxValue;
1414// float mult = Misc.logOfBase(2f, units) + 1f;
1415// result.fraction = 1f - (mult / units);
1416// if (result.fraction < 0) result.fraction = 0;
1417// if (result.fraction > 0) {
1418// result.fraction = Math.round(result.fraction * 100f) / 100f;
1419// result.fraction = Math.max(result.fraction, 0.01f);
1420// }
1421// }
1422// return result;
1423// }
1424
1425 public static class ExportCommodityGroupData {
1426 public CommodityOnMarketAPI com;
1427 public int quantity;
1428 }
1429
1430 protected void addExportsGroupedByCommodity(MonthlyReport report, FDNode parent, MarketAPI market, float f) {
1431 for (CommodityOnMarketAPI com : market.getCommoditiesCopy()) {
1432 FDNode eNode = report.getNode(parent, com.getId());
1433 eNode.name = com.getCommodity().getName();
1434 eNode.income += com.getExportIncome() * f;
1435 eNode.custom = com;
1436 eNode.mapEntity = market.getPrimaryEntity();
1437 }
1438
1439// List<FDNode> sorted = new ArrayList<FDNode>(parent.getChildren().values());
1440// Collections.sort(sorted, new Comparator<FDNode>() {
1441// public int compare(FDNode o1, FDNode o2) {
1442// return o2.income - o1.income;
1443// }
1444// });
1445// parent.getChildren().clear();
1446// parent.getChildren().
1447 }
1448
1449
1450
1451}
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
static SettingsAPI getSettings()
Definition Global.java:51
static SoundPlayerAPI getSoundPlayer()
Definition Global.java:43
static FactoryAPI getFactory()
Definition Global.java:35
static Logger getLogger(Class c)
Definition Global.java:26
static SectorAPI getSector()
Definition Global.java:59
void reportBattleOccurred(CampaignFleetAPI primaryWinner, BattleAPI battle)
static void markSystemAsEntered(StarSystemAPI system, boolean withMessages)
void reportPlayerReputationChange(String faction, float delta)
void addExportsGroupedByCommodity(MonthlyReport report, FDNode parent, MarketAPI market, float f)
void reportPlayerReputationChange(PersonAPI person, float delta)
static void generateOrAddToDebrisFieldFromBattle(CampaignFleetAPI primaryWinner, BattleAPI battle)
static void addMiscToDropData(DropData data, FleetMemberAPI member, boolean weapons, boolean mods, boolean fighters)
void reportPlayerMarketTransaction(PlayerMarketTransaction transaction)
void reportFleetJumped(CampaignFleetAPI fleet, SectorEntityToken from, JumpDestination to)
static Set< String > getCargoCommodities(CargoAPI cargo)
CampaignFleetAPI createEmptyFleet(String factionId, String name, boolean aiMode)
ListMap< String > getHullIdToVariantListMap()
String getSpriteName(String category, String id)
HullModSpecAPI getHullModSpec(String modId)
CommoditySpecAPI getCommoditySpec(String commodityId)
FighterWingSpecAPI getFighterWingSpec(String wingId)
SoundAPI playUISound(String id, float pitch, float volume)