001package com.fs.starfarer.api.impl.campaign.intel.events;
002
003import java.awt.Color;
004import java.util.LinkedHashSet;
005import java.util.List;
006import java.util.Random;
007import java.util.Set;
008
009import org.lwjgl.util.vector.Vector2f;
010
011import com.fs.starfarer.api.Global;
012import com.fs.starfarer.api.campaign.BattleAPI;
013import com.fs.starfarer.api.campaign.CampaignEventListener.FleetDespawnReason;
014import com.fs.starfarer.api.campaign.CampaignFleetAPI;
015import com.fs.starfarer.api.campaign.CargoAPI;
016import com.fs.starfarer.api.campaign.InteractionDialogAPI;
017import com.fs.starfarer.api.campaign.StarSystemAPI;
018import com.fs.starfarer.api.campaign.comm.IntelInfoPlugin.ListInfoMode;
019import com.fs.starfarer.api.campaign.econ.Industry;
020import com.fs.starfarer.api.campaign.econ.MarketAPI;
021import com.fs.starfarer.api.campaign.listeners.ColonyPlayerHostileActListener;
022import com.fs.starfarer.api.campaign.listeners.FleetEventListener;
023import com.fs.starfarer.api.fleet.FleetMemberAPI;
024import com.fs.starfarer.api.impl.campaign.fleets.EconomyFleetAssignmentAI.EconomyRouteData;
025import com.fs.starfarer.api.impl.campaign.fleets.EconomyFleetRouteManager;
026import com.fs.starfarer.api.impl.campaign.fleets.RouteManager;
027import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteData;
028import com.fs.starfarer.api.impl.campaign.ids.Conditions;
029import com.fs.starfarer.api.impl.campaign.ids.Factions;
030import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
031import com.fs.starfarer.api.impl.campaign.ids.Industries;
032import com.fs.starfarer.api.impl.campaign.ids.Skills;
033import com.fs.starfarer.api.impl.campaign.ids.Strings;
034import com.fs.starfarer.api.impl.campaign.intel.events.BaseEventIntel.EventStageData;
035import com.fs.starfarer.api.impl.campaign.intel.events.HostileActivityEventIntel.HAERandomEventData;
036import com.fs.starfarer.api.impl.campaign.intel.events.HostileActivityEventIntel.Stage;
037import com.fs.starfarer.api.impl.campaign.intel.events.TriTachyonStandardActivityCause.CompetitorData;
038import com.fs.starfarer.api.impl.campaign.intel.events.ttcr.TTCRCommerceRaidersDestroyedFactor;
039import com.fs.starfarer.api.impl.campaign.intel.events.ttcr.TTCRIndustryDisruptedFactor;
040import com.fs.starfarer.api.impl.campaign.intel.events.ttcr.TTCRMercenariesDefeatedFactor;
041import com.fs.starfarer.api.impl.campaign.intel.events.ttcr.TTCRPoints;
042import com.fs.starfarer.api.impl.campaign.intel.events.ttcr.TTCRTradeFleetsDestroyedFactor;
043import com.fs.starfarer.api.impl.campaign.intel.events.ttcr.TriTachyonCommerceRaiding;
044import com.fs.starfarer.api.impl.campaign.intel.group.FGRaidAction.FGRaidType;
045import com.fs.starfarer.api.impl.campaign.intel.group.FleetGroupIntel;
046import com.fs.starfarer.api.impl.campaign.intel.group.FleetGroupIntel.FGIEventListener;
047import com.fs.starfarer.api.impl.campaign.intel.group.GenericRaidFGI.GenericRaidParams;
048import com.fs.starfarer.api.impl.campaign.intel.group.TTMercenaryAttack;
049import com.fs.starfarer.api.impl.campaign.missions.FleetCreatorMission;
050import com.fs.starfarer.api.impl.campaign.missions.FleetCreatorMission.FleetStyle;
051import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.ComplicationRepImpact;
052import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.FleetQuality;
053import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD.TempData;
054import com.fs.starfarer.api.ui.TooltipMakerAPI;
055import com.fs.starfarer.api.ui.TooltipMakerAPI.TooltipCreator;
056import com.fs.starfarer.api.util.CountingMap;
057import com.fs.starfarer.api.util.Misc;
058import com.fs.starfarer.api.util.TimeoutTracker;
059
060public class TriTachyonHostileActivityFactor extends BaseHostileActivityFactor 
061                                                        implements FGIEventListener, FleetEventListener, ColonyPlayerHostileActListener {
062
063        public static String COUNTER_RAIDED_TRITACH = "$counterRaidedTriTach";
064        public static String DEFEATED_MERC_ATTACK = "$defeatedTTMercAttack";
065        public static String BRIBED_MERC_ATTACK = "$bribedTTMercAttack";
066        
067        public static String COMMERCE_RAIDER_FLEET = "$triTachCommerceRaider";
068        
069        public static float DEALT_WITH_MERC_PROGRESS_MULT = 0.25f;
070        
071        public static boolean isPlayerCounterRaidedTriTach() {
072                return Global.getSector().getPlayerMemoryWithoutUpdate().getBoolean(COUNTER_RAIDED_TRITACH);
073        }
074        public static void setPlayerCounterRaidedTriTach() {
075                Global.getSector().getPlayerMemoryWithoutUpdate().set(COUNTER_RAIDED_TRITACH, true);
076        }
077        
078        public static boolean isPlayerDefeatedMercAttack() {
079                return Global.getSector().getPlayerMemoryWithoutUpdate().getBoolean(DEFEATED_MERC_ATTACK);
080        }
081        public static void setPlayerDefeatedMercAttack() {
082                Global.getSector().getPlayerMemoryWithoutUpdate().set(DEFEATED_MERC_ATTACK, true);
083        }
084        
085        public static boolean isDealtWithMercAttack() {
086                return isPlayerDefeatedMercAttack() || isPlayerBribedMercAttack();
087        }
088        
089        /**
090         * This is actually set in rules, so: method never called
091         */
092        public static boolean isPlayerBribedMercAttack() {
093                return Global.getSector().getPlayerMemoryWithoutUpdate().getBoolean(BRIBED_MERC_ATTACK);
094        }
095        public static void setPlayerBribedMercAttack() {
096                Global.getSector().getPlayerMemoryWithoutUpdate().set(BRIBED_MERC_ATTACK, true);
097        }
098        
099        
100        
101        protected TimeoutTracker<Industry> recentlyDisrupted = new TimeoutTracker<Industry>();
102        
103        
104        public TriTachyonHostileActivityFactor(HostileActivityEventIntel intel) {
105                super(intel);
106                
107                Global.getSector().getListenerManager().addListener(this);
108        }
109        
110        protected Object readResolve() {
111                if (recentlyDisrupted == null) {
112                        recentlyDisrupted = new TimeoutTracker<Industry>();
113                }
114                return this;
115        }
116        
117        public String getProgressStr(BaseEventIntel intel) {
118                return "";
119        }
120        
121        @Override
122        public int getProgress(BaseEventIntel intel) {
123                if (!checkFactionExists(Factions.TRITACHYON, true)) {
124                        return 0;
125                }
126                return super.getProgress(intel);
127        }
128        
129        public String getDesc(BaseEventIntel intel) {
130                return "Tri-Tachyon Corporation";
131        }
132        
133        public String getNameForThreatList(boolean first) {
134                return "Tri-Tachyon";
135        }
136
137
138        public Color getDescColor(BaseEventIntel intel) {
139                if (getProgress(intel) <= 0) {
140                        return Misc.getGrayColor();
141                }
142                return Global.getSector().getFaction(Factions.TRITACHYON).getBaseUIColor();
143        }
144
145        public TooltipCreator getMainRowTooltip(BaseEventIntel intel) {
146                return new BaseFactorTooltip() {
147                        public void createTooltip(TooltipMakerAPI tooltip, boolean expanded, Object tooltipParam) {
148                                float opad = 10f;
149                                tooltip.addPara("Your independent polity has become enough of a presence in the Sector to "
150                                                + "start cutting into the profit margins of the Tri-Tachyon Corporation.", 0f);
151                                
152                                tooltip.addPara("Independent-flagged commerce raiders - little more than sanctioned pirates - "
153                                                + "have been sighted in your space, "
154                                                + "attacking trade fleets regardless of their factional allegiance.", opad);
155                                
156                                addDealtSectionToTooltip(tooltip, opad);
157                        }
158                };
159        }
160        
161        public static void addDealtSectionToTooltip(TooltipMakerAPI tooltip, float opad) {
162                if (isDealtWithMercAttack()) {
163                        tooltip.addPara("You've dealt with the mercenary attack sent against you, and " +
164                                        "this has considerably cooled the enthusiasm for continued aggression. " +
165                                        "Commerce-raiding continues, but the event progress value is reduced by %s, "
166                                        + "and no further large-scale attacks are likely to be mounted.", opad,
167                                        Misc.getHighlightColor(), Strings.X + DEALT_WITH_MERC_PROGRESS_MULT);
168                }
169        }
170
171        public boolean shouldShow(BaseEventIntel intel) {
172                return getProgress(intel) > 0;
173        }
174
175
176        public Color getNameColor(float mag) {
177                if (mag <= 0f) {
178                        return Misc.getGrayColor();
179                }
180                return Global.getSector().getFaction(Factions.TRITACHYON).getBaseUIColor();
181        }
182        
183        
184        @Override
185        public int getMaxNumFleets(StarSystemAPI system) {
186                return Global.getSettings().getInt("triTachyonMaxFleets");
187        }
188        
189        public CampaignFleetAPI createFleet(StarSystemAPI system, Random random) {
190        
191                float f = intel.getMarketPresenceFactor(system);
192                
193                // even if magnitude is not factored in, if it's 0 fleets won't spawn
194                // and its value affects the likelihood of tritach fleets spawning
195                //getEffectMagnitude(system);
196                
197                int difficulty = 4 + (int) Math.round(f * 4f);
198                
199                FleetCreatorMission m = new FleetCreatorMission(random);
200                m.beginFleet();
201                
202                Vector2f loc = system.getLocation();
203                String factionId = Factions.TRITACHYON;
204                if (random.nextFloat() < 0.5f) {
205                        factionId = Factions.MERCENARY;
206                }
207                
208                m.createQualityFleet(difficulty, factionId, loc);
209                
210                if (difficulty <= 5) {
211                        m.triggerSetFleetQuality(FleetQuality.SMOD_1);
212                } else if (difficulty <= 7) {
213                        m.triggerSetFleetQuality(FleetQuality.SMOD_2);
214                } else {
215                        m.triggerSetFleetQuality(FleetQuality.SMOD_3);
216                }
217                
218                m.triggerSetFleetFaction(Factions.INDEPENDENT);
219                m.triggerSetFleetType(FleetTypes.COMMERCE_RAIDERS);
220                
221                m.triggerSetPirateFleet();
222                //m.triggerMakeHostile();
223                m.triggerMakeNonHostileToFaction(Factions.TRITACHYON);
224                m.triggerMakeHostileToAllTradeFleets();
225                m.triggerMakeEveryoneJoinBattleAgainst();
226                
227                m.triggerMakeNonHostileToFaction(Factions.PIRATES);
228                m.triggerMakeNoRepImpact();
229                m.triggerFleetAllowLongPursuit();
230                
231                m.triggerFleetAddCommanderSkill(Skills.COORDINATED_MANEUVERS, 1);
232                m.triggerFleetAddCommanderSkill(Skills.ELECTRONIC_WARFARE, 1);
233//              m.triggerFleetAddCommanderSkill(Skills.FLUX_REGULATION, 1);
234//              m.triggerFleetAddCommanderSkill(Skills.PHASE_CORPS, 1);
235//              m.triggerFleetAddCommanderSkill(Skills.CARRIER_GROUP, 1);
236                
237                m.triggerSetFleetFlag(COMMERCE_RAIDER_FLEET);
238                
239                int tugs = 0;
240                if (Factions.MERCENARY.equals(factionId)) {
241                        tugs = random.nextInt(3);
242                }
243                
244                m.triggerFleetMakeFaster(true, tugs, true);
245                m.triggerSetFleetMaxShipSize(3);
246                
247                
248                CampaignFleetAPI fleet = m.createFleet();
249
250                return fleet;
251        }
252        
253
254        
255        
256        public void addBulletPointForEvent(HostileActivityEventIntel intel, EventStageData stage, TooltipMakerAPI info,
257                                                                                 ListInfoMode mode, boolean isUpdate, Color tc, float initPad) {
258                Color c = Global.getSector().getFaction(Factions.TRITACHYON).getBaseUIColor();
259                info.addPara("Impending Tri-Tachyon mercenary attack", initPad, tc, c, "Tri-Tachyon");
260        }
261        
262        public void addBulletPointForEventReset(HostileActivityEventIntel intel, EventStageData stage, TooltipMakerAPI info,
263                        ListInfoMode mode, boolean isUpdate, Color tc, float initPad) {
264                info.addPara("Tri-Tachyon mercenary attack averted", tc, initPad);
265        }
266        
267        public void addStageDescriptionForEvent(HostileActivityEventIntel intel, EventStageData stage, TooltipMakerAPI info) {
268                float small = 0f;
269                float opad = 10f;
270                
271                small = 8f;
272
273                Color c = Global.getSector().getFaction(Factions.TRITACHYON).getBaseUIColor();
274                
275                Color h = Misc.getHighlightColor();
276                info.addPara("You've received intel that the Tri-Tachyon Corporation is allocating funds to hire and "
277                                + "equip a mercenary company to raid and disrupt your industrial base.",
278                                small, Misc.getNegativeHighlightColor(), "raid and disrupt your industrial base");
279
280                info.addPara("If the mercenary attack is defeated, it will go a long way towards convincing "
281                                + "the Tri-Tachyon Corporation to abandon its anti-competitive efforts.", 
282                                //opad, tri, "Tri-Tachyon Corporation");
283                                opad, h, "abandon its anti-competitive efforts");
284                
285                stage.beginResetReqList(info, true, "crisis", opad);
286                info.addPara("The %s is convinced that its efforts are unprofitable", 0f, c, "Tri-Tachyon Corporation");
287                stage.endResetReqList(info, false, "crisis", -1, -1);
288                
289                addBorder(info, Global.getSector().getFaction(Factions.TRITACHYON).getBaseUIColor());
290        }
291        
292        
293        public String getEventStageIcon(HostileActivityEventIntel intel, EventStageData stage) {
294                return Global.getSector().getFaction(Factions.TRITACHYON).getCrest();
295        }
296
297        public TooltipCreator getStageTooltipImpl(final HostileActivityEventIntel intel, final EventStageData stage) {
298                if (stage.id == Stage.HA_EVENT) {
299                        return getDefaultEventTooltip("Tri-Tachyon mercenary attack", intel, stage);
300                }
301                return null;
302        }
303        
304        
305        public float getEventFrequency(HostileActivityEventIntel intel, EventStageData stage) {
306                if (stage.id == Stage.HA_EVENT) {
307                        
308                        if (isPlayerCounterRaidedTriTach() || getPrimaryTriTachyonSystem() == null) {
309                                return 0f;
310                        }
311                        
312                        if (isPlayerDefeatedMercAttack() || isPlayerBribedMercAttack()) {
313                                return 0f;
314                        }
315                        
316                        StarSystemAPI target = findExpeditionTarget(intel, stage);
317                        MarketAPI source = findExpeditionSource(intel, stage, target);
318                        if (target != null && source != null) {
319                                return 10f;
320                        }
321                }
322                return 0;
323        }
324        
325
326        public void rollEvent(HostileActivityEventIntel intel, EventStageData stage) {
327                HAERandomEventData data = new HAERandomEventData(this, stage);
328                stage.rollData = data;
329                intel.sendUpdateIfPlayerHasIntel(data, false);
330        }
331        
332        public boolean fireEvent(HostileActivityEventIntel intel, EventStageData stage) {
333                StarSystemAPI target = findExpeditionTarget(intel, stage);
334                MarketAPI source = findExpeditionSource(intel, stage, target);
335                
336                if (source == null || target == null) {
337                        return false;
338                }
339        
340                stage.rollData = null;
341                return startMercenaryAttack(source, target, stage, intel, getRandomizedStageRandom(3));
342        }
343        
344        
345        public static StarSystemAPI findExpeditionTarget(HostileActivityEventIntel intel, EventStageData stage) {
346                List<CompetitorData> data = TriTachyonStandardActivityCause.computePlayerCompetitionData();
347                CountingMap<StarSystemAPI> counts = new CountingMap<StarSystemAPI>();
348                
349                for (CompetitorData curr : data) {
350                        for (MarketAPI market : curr.competitorProducers) {
351                                StarSystemAPI system = market.getStarSystem();
352                                if (system == null) continue;
353                                int weight = market.getCommodityData(curr.commodityId).getMaxSupply();
354                                counts.add(system, weight);
355                        }
356                }
357                
358                return counts.getLargest();
359        }
360        
361        public static MarketAPI findExpeditionSource(HostileActivityEventIntel intel, EventStageData stage, StarSystemAPI target) {
362                if (getNortia() != null) return getNortia();
363                
364                
365                CountingMap<MarketAPI> scores = new CountingMap<MarketAPI>();
366                for (MarketAPI market : Misc.getFactionMarkets(Factions.TRITACHYON)) {
367                        int size = market.getSize();
368                        int weight = size;
369                        if (!Misc.isMilitary(market)) weight += size * 10;
370                        if (market.hasIndustry(Industries.ORBITALWORKS)) weight += size;
371                        if (market.hasIndustry(Industries.HEAVYINDUSTRY)) weight += size;
372                        
373                        scores.add(market, weight);
374                }
375                
376                return scores.getLargest();
377        }
378        
379        public static MarketAPI getNortia() {
380                MarketAPI nortia = Global.getSector().getEconomy().getMarket("nortia");
381                if (nortia == null || nortia.hasCondition(Conditions.DECIVILIZED) ||
382                                !nortia.getFactionId().equals(Factions.INDEPENDENT)) {
383                        return null;
384                }
385                return nortia;
386        }
387        
388
389        
390        
391        public void reportFGIAborted(FleetGroupIntel intel) {
392                setPlayerDefeatedMercAttack();
393                TriTachyonCommerceRaiding.addFactorCreateIfNecessary(new TTCRMercenariesDefeatedFactor(), null);
394        }
395        
396        
397        
398        @Override
399        public void notifyFactorRemoved() {
400                Global.getSector().getListenerManager().removeListener(this);
401        }
402
403        public void notifyEventEnding() {
404                notifyFactorRemoved();
405        }
406
407
408        @Override
409        public void advance(float amount) {
410                super.advance(amount);
411                
412                float days = Misc.getDays(amount);
413                recentlyDisrupted.advance(days);
414        
415//              if (!Global.getSector().getListenerManager().hasListener(this)) {
416//                      Global.getSector().getListenerManager().addListener(this);
417//              }
418                
419//              System.out.println("LISTENERS:");
420//              for (Object o : Global.getSector().getListenerManager().getListeners(Object.class)) {
421//                      System.out.println("Listener: " + o.getClass().getSimpleName() + " [" + o.hashCode() + "]");
422//              }
423//              System.out.println("-----");
424//              System.out.println("-----");
425//              System.out.println("-----");
426//              System.out.println("-----");
427                
428                EventStageData stage = intel.getDataFor(Stage.HA_EVENT);
429                if (stage != null && stage.rollData instanceof HAERandomEventData && 
430                                ((HAERandomEventData)stage.rollData).factor == this) {
431                        if (isPlayerCounterRaidedTriTach()) {
432                                intel.resetHA_EVENT();
433                        }                       
434                }
435                if (isPlayerCounterRaidedTriTach() && TTMercenaryAttack.get() != null) {
436                        TTMercenaryAttack.get().finish(false);
437                }
438        }
439        
440        
441        public static StarSystemAPI getPrimaryTriTachyonSystem() {
442                CountingMap<StarSystemAPI> counts = new CountingMap<StarSystemAPI>();
443                for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) {
444                        if (!Factions.TRITACHYON.equals(market.getFactionId())) continue;
445                        StarSystemAPI system = market.getStarSystem();
446                        if (system == null) continue;
447                        int size = market.getSize();
448                        int weight = size;
449                        if (Misc.isMilitary(market)) weight += size;
450                        if (market.hasIndustry(Industries.ORBITALWORKS)) weight += size;
451                        if (market.hasIndustry(Industries.HEAVYINDUSTRY)) weight += size;
452                        
453                        counts.add(system, weight);
454                }
455                return counts.getLargest();
456        }
457
458        
459        public boolean startMercenaryAttack(MarketAPI source, StarSystemAPI target, 
460                                                EventStageData stage, HostileActivityEventIntel intel, Random random) {
461                if (isPlayerCounterRaidedTriTach()) return false;
462                if (source == null || target == null) return false;
463                
464                GenericRaidParams params = new GenericRaidParams(new Random(random.nextLong()), true);
465                params.makeFleetsHostile = false; // will be made hostile when they arrive, not before
466                params.source = source;
467                
468                params.prepDays = 21f + random.nextFloat() * 7f;
469                params.payloadDays = 27f + 7f * random.nextFloat();
470                
471                params.raidParams.where = target;
472                params.raidParams.type = FGRaidType.SEQUENTIAL;
473                
474                Set<String> disrupt = new LinkedHashSet<String>();
475                for (MarketAPI market : Misc.getMarketsInLocation(target, Factions.PLAYER)) {
476                        params.raidParams.allowedTargets.add(market);
477                        params.raidParams.allowNonHostileTargets = true;
478                        for (Industry ind : market.getIndustries()) {
479                                if (ind.getSpec().hasTag(Industries.TAG_UNRAIDABLE)) continue;
480                                disrupt.add(ind.getId());
481                                
482                        }
483                }
484                
485                params.raidParams.disrupt.addAll(disrupt);
486                params.raidParams.raidsPerColony = Math.min(disrupt.size(), 4);
487                if (disrupt.isEmpty()) {
488                        params.raidParams.raidsPerColony = 2;
489                }
490                
491                if (params.raidParams.allowedTargets.isEmpty()) {
492                        return false;
493                }
494                
495                params.factionId = Factions.INDEPENDENT;
496                params.style = FleetStyle.QUALITY;
497                params.repImpact = ComplicationRepImpact.NONE;
498                
499                
500                float fleetSizeMult = 1f;
501                
502                float f = intel.getMarketPresenceFactor(target);
503                
504                float totalDifficulty = fleetSizeMult * 50f * (0.5f + 0.5f * f);
505
506                totalDifficulty -= 10;
507                params.fleetSizes.add(10); // first size 10 pick becomes the Operational Command
508                
509                while (totalDifficulty > 0) {
510                        int min = 3;
511                        int max = 8;
512                        
513                        //int diff = Math.round(StarSystemGenerator.getNormalRandom(random, min, max));
514                        int diff = min + random.nextInt(max - min + 1);
515                        
516                        params.fleetSizes.add(diff);
517                        totalDifficulty -= diff;
518                }
519                
520                TTMercenaryAttack attack = new TTMercenaryAttack(params);
521                attack.setListener(this);
522                //attack.setPreFleetDeploymentDelay(30f + random.nextFloat() * 60f);
523                //attack.setPreFleetDeploymentDelay(1f);
524                Global.getSector().getIntelManager().addIntel(attack, false);           
525                
526                return true;
527        }
528        
529        
530        
531        public void reportFleetDespawnedToListener(CampaignFleetAPI fleet, FleetDespawnReason reason, Object param) {
532                
533        }
534        public void reportBattleOccurred(CampaignFleetAPI fleet, CampaignFleetAPI primaryWinner, BattleAPI battle) {
535                if (isPlayerCounterRaidedTriTach()) return;
536                
537                if (!battle.isPlayerInvolved()) return;
538                
539                if (getProgress(null) <= 0 && TriTachyonCommerceRaiding.get() == null) return;
540                
541                int traderFP = 0;
542                int raiderFP = 0;
543                for (CampaignFleetAPI otherFleet : battle.getNonPlayerSideSnapshot()) {
544                        //if (!Global.getSector().getPlayerFaction().isHostileTo(otherFleet.getFaction())) continue;
545                        boolean trader = isTraderServingATTColony(otherFleet);
546                        boolean raider = isCommerceRaider(otherFleet);
547                        
548                        if (!trader && !raider) continue;
549                        
550                        int mult = 1;
551                        if (trader) mult = TTCRPoints.TRADE_FLEET_FP_MULT;
552                        
553                        for (FleetMemberAPI loss : Misc.getSnapshotMembersLost(otherFleet)) {
554                                int fp = loss.getFleetPointCost() * mult;
555                                if (trader) {
556                                        traderFP += fp;
557                                } else if (raider) {
558                                        raiderFP += fp;
559                                }
560                        }
561                }
562        
563                if (traderFP > 0) {
564                        int points = computeTTCRProgressPoints(traderFP);
565                        if (points > 0) {
566                                TTCRTradeFleetsDestroyedFactor factor = new TTCRTradeFleetsDestroyedFactor(points);
567                                TriTachyonCommerceRaiding.addFactorCreateIfNecessary(factor, null);
568                        }
569                }
570                if (raiderFP > 0) {
571                        int points = computeTTCRProgressPoints(raiderFP);
572                        if (points > 0) {
573                                TTCRCommerceRaidersDestroyedFactor factor = new TTCRCommerceRaidersDestroyedFactor(points);
574                                TriTachyonCommerceRaiding.addFactorCreateIfNecessary(factor, null);
575                        }
576                }
577        }
578        
579        public static boolean isCommerceRaider(CampaignFleetAPI fleet) {
580                return fleet.getMemoryWithoutUpdate().getBoolean(TriTachyonHostileActivityFactor.COMMERCE_RAIDER_FLEET);
581        }
582        public static boolean isTraderServingATTColony(CampaignFleetAPI fleet) {
583                boolean trader = Misc.isTrader(fleet);
584                boolean smuggler = Misc.isSmuggler(fleet);
585                
586                if (!trader && !smuggler) return false;
587                
588                RouteData route = RouteManager.getInstance().getRoute(EconomyFleetRouteManager.SOURCE_ID, fleet);
589                if (route == null) return false;
590                
591                EconomyRouteData data = (EconomyRouteData) route.getCustom();
592                if (data == null) return false;
593                
594                if (data.from != null && Factions.TRITACHYON.equals(data.from.getFactionId())) {
595                        return true;
596                }
597                if (data.to != null && Factions.TRITACHYON.equals(data.to.getFactionId())) {
598                        return true;
599                }
600                        
601                return false;
602        }
603        
604        public static int computeTTCRProgressPoints(float fleetPointsDestroyed) {
605                if (fleetPointsDestroyed <= 0) return 0;
606                
607                int points = Math.round(fleetPointsDestroyed / (float) TTCRPoints.FP_PER_POINT);
608                if (points < 1) points = 1;
609                return points;
610        }
611        
612        public static int computeIndustryDisruptPoints(Industry ind) {
613                float base = ind.getSpec().getDisruptDanger().disruptionDays;
614                float per = TTCRPoints.BASE_POINTS_FOR_INDUSTRY_DISRUPT;
615                
616                float days = ind.getDisruptedDays();
617                
618                int points = (int) Math.round(days / base * per);
619                if (points > TTCRPoints.MAX_POINTS_FOR_INDUSTRY_DISRUPT) {
620                        points = TTCRPoints.MAX_POINTS_FOR_INDUSTRY_DISRUPT;
621                }
622                return points;
623        }
624        
625        public void reportRaidForValuablesFinishedBeforeCargoShown(InteractionDialogAPI dialog, MarketAPI market,
626                        TempData actionData, CargoAPI cargo) {
627                
628        }
629        public void reportRaidToDisruptFinished(InteractionDialogAPI dialog, MarketAPI market, TempData actionData,
630                        Industry industry) {
631                if (isPlayerCounterRaidedTriTach()) return;
632                if (getProgress(null) <= 0 && TriTachyonCommerceRaiding.get() == null) return;
633                
634                if (market != null && Factions.TRITACHYON.equals(market.getFactionId())) {
635                        applyIndustryDisruptionToTTCR(industry, dialog);
636                }
637        }
638        public void reportTacticalBombardmentFinished(InteractionDialogAPI dialog, MarketAPI market, TempData actionData) {
639                if (isPlayerCounterRaidedTriTach()) return;
640                if (getProgress(null) <= 0 && TriTachyonCommerceRaiding.get() == null) return;
641                
642                if (market != null && Factions.TRITACHYON.equals(market.getFactionId())) {
643                        applyMassIndustryDisruptionToTTCR(market, dialog);
644                }
645        }
646        public void reportSaturationBombardmentFinished(InteractionDialogAPI dialog, MarketAPI market,
647                        TempData actionData) {
648                if (isPlayerCounterRaidedTriTach()) return;
649                if (getProgress(null) <= 0 && TriTachyonCommerceRaiding.get() == null) return;
650                
651                if (market != null && Factions.TRITACHYON.equals(market.getFactionId())) {
652                        applyMassIndustryDisruptionToTTCR(market, dialog);
653                }
654        }
655        
656        public void applyMassIndustryDisruptionToTTCR(MarketAPI market, InteractionDialogAPI dialog) {
657                if (isPlayerCounterRaidedTriTach()) return;
658                if (getProgress(null) <= 0 && TriTachyonCommerceRaiding.get() == null) return;
659                
660                int points = 0;
661                for (Industry industry : market.getIndustries()) {
662                        if (recentlyDisrupted.contains(industry)) continue;
663                        if (industry.getSpec().hasTag(Industries.TAG_UNRAIDABLE)) continue;
664                        
665                        int curr = computeIndustryDisruptPoints(industry);
666                        if (curr > 0) {
667                                points += curr;
668                                recentlyDisrupted.add(industry, industry.getDisruptedDays());
669                        }
670                }
671                
672                if (points > 0) {
673                        TTCRIndustryDisruptedFactor factor = new TTCRIndustryDisruptedFactor(
674                                        "Disrupted industries " + market.getOnOrAt() + " " + market.getName(), points);
675                        TriTachyonCommerceRaiding.addFactorCreateIfNecessary(factor, dialog);
676                }
677        }
678        public void applyIndustryDisruptionToTTCR(Industry industry, InteractionDialogAPI dialog) {
679                if (isPlayerCounterRaidedTriTach()) return;
680                if (getProgress(null) <= 0 && TriTachyonCommerceRaiding.get() == null) return;
681                
682                if (!recentlyDisrupted.contains(industry)) {
683                        if (industry.getSpec().hasTag(Industries.TAG_UNRAIDABLE)) return;
684                        MarketAPI market = industry.getMarket();
685                        if (market == null) return;
686                        
687                        int points = computeIndustryDisruptPoints(industry);
688                        if (points > 0) {
689                                TTCRIndustryDisruptedFactor factor = new TTCRIndustryDisruptedFactor(
690                                                industry.getCurrentName() + " " + market.getOnOrAt() + " " + market.getName() + 
691                                                " disrupted", points);
692                                TriTachyonCommerceRaiding.addFactorCreateIfNecessary(factor, dialog);
693                                recentlyDisrupted.add(industry, industry.getDisruptedDays());
694                        }
695                }
696        }
697        @Override
698        public Color getNameColorForThreatList() {
699                return super.getNameColorForThreatList();
700        }
701        
702        
703}
704
705
706
707