001package com.fs.starfarer.api.impl.campaign.intel.events.ht;
002
003import java.util.ArrayList;
004import java.util.EnumSet;
005import java.util.List;
006import java.util.Set;
007
008import java.awt.Color;
009
010import org.lwjgl.util.vector.Vector2f;
011
012import com.fs.starfarer.api.Global;
013import com.fs.starfarer.api.campaign.BattleAPI;
014import com.fs.starfarer.api.campaign.CampaignEventListener.FleetDespawnReason;
015import com.fs.starfarer.api.campaign.CampaignFleetAPI;
016import com.fs.starfarer.api.campaign.CargoAPI;
017import com.fs.starfarer.api.campaign.InteractionDialogAPI;
018import com.fs.starfarer.api.campaign.LocationAPI;
019import com.fs.starfarer.api.campaign.PersistentUIDataAPI.AbilitySlotAPI;
020import com.fs.starfarer.api.campaign.PersistentUIDataAPI.AbilitySlotsAPI;
021import com.fs.starfarer.api.campaign.SectorEntityToken;
022import com.fs.starfarer.api.campaign.SpecialItemData;
023import com.fs.starfarer.api.campaign.StarSystemAPI;
024import com.fs.starfarer.api.campaign.TextPanelAPI;
025import com.fs.starfarer.api.campaign.econ.Industry;
026import com.fs.starfarer.api.campaign.econ.MarketAPI;
027import com.fs.starfarer.api.campaign.listeners.CharacterStatsRefreshListener;
028import com.fs.starfarer.api.campaign.listeners.CurrentLocationChangedListener;
029import com.fs.starfarer.api.campaign.listeners.FleetEventListener;
030import com.fs.starfarer.api.combat.MutableStat;
031import com.fs.starfarer.api.combat.MutableStat.StatMod;
032import com.fs.starfarer.api.combat.StatBonus;
033import com.fs.starfarer.api.impl.campaign.ids.Abilities;
034import com.fs.starfarer.api.impl.campaign.ids.Industries;
035import com.fs.starfarer.api.impl.campaign.ids.Items;
036import com.fs.starfarer.api.impl.campaign.ids.Stats;
037import com.fs.starfarer.api.impl.campaign.ids.Tags;
038import com.fs.starfarer.api.impl.campaign.intel.events.BaseEventIntel;
039import com.fs.starfarer.api.impl.campaign.intel.events.BaseFactorTooltip;
040import com.fs.starfarer.api.impl.campaign.intel.events.EventFactor;
041import com.fs.starfarer.api.impl.campaign.rulecmd.AddAbility;
042import com.fs.starfarer.api.impl.campaign.velfield.SlipstreamTerrainPlugin2;
043import com.fs.starfarer.api.ui.SectorMapAPI;
044import com.fs.starfarer.api.ui.TooltipMakerAPI;
045import com.fs.starfarer.api.ui.TooltipMakerAPI.TooltipCreator;
046import com.fs.starfarer.api.util.Misc;
047import com.fs.starfarer.api.util.Misc.Token;
048import com.fs.starfarer.api.util.Misc.TokenType;
049import com.fs.starfarer.api.util.TimeoutTracker;
050
051public class HyperspaceTopographyEventIntel extends BaseEventIntel implements FleetEventListener,
052                                                                                                                                                          CharacterStatsRefreshListener,
053                                                                                                                                                          CurrentLocationChangedListener {
054        
055        public static Color BAR_COLOR = Global.getSettings().getColor("progressBarFleetPointsColor");
056
057        
058//      public static int PROGRESS_MAX = 1000;
059//      public static int PROGRESS_1 = 100;
060//      public static int PROGRESS_2 = 400;
061//      public static int PROGRESS_3 = 700;
062        public static int PROGRESS_MAX = 1000;
063        public static int PROGRESS_1 = 100;
064        public static int PROGRESS_2 = 250;
065        public static int PROGRESS_3 = 400;
066        public static int PROGRESS_4 = 550;
067        public static int PROGRESS_5 = 700;
068        
069        public static float BASE_DETECTION_RANGE_LY = 3f;
070        public static float RANGE_WITHIN_WHICH_SENSOR_ARRAYS_HELP_LY = 5f;
071        public static float RANGE_PER_DOMAIN_SENSOR_ARRAY = 2f;
072        public static float RANGE_PER_MAKESHIFT_SENSOR_ARRAY = 1f;
073        public static int MAX_SENSOR_ARRAYS = 3;
074        public static float WAYSTATION_BONUS = 2f;
075        
076        
077        public static float SLIPSTREAM_FUEL_MULT = 0.25f;
078        public static float HYPER_BURN_BONUS = 3f;
079        
080        public static String KEY = "$hte_ref";
081        
082        public static enum Stage {
083                START,
084                SLIPSTREAM_DETECTION,
085                SLIPSTREAM_NAVIGATION,
086                REVERSE_POLARITY,
087                HYPERFIELD_OPTIMIZATION,
088                GENERATE_SLIPSURGE,
089                TOPOGRAPHIC_DATA,
090        }
091        
092
093        public static float RECENT_READINGS_TIMEOUT = 30f;
094        public static float RECENT_READINGS_RANGE_LY = 10f;
095        
096        public static class RecentTopographyReadings {
097                public Vector2f loc;
098                public RecentTopographyReadings(Vector2f loc) {
099                        this.loc = loc;
100                }
101        }
102        
103        public static void addFactorCreateIfNecessary(EventFactor factor, InteractionDialogAPI dialog) {
104                if (get() == null) {
105                        //TextPanelAPI text = dialog == null ? null : dialog.getTextPanel();
106                        //new HyperspaceTopographyEventIntel(text);
107                        // adding a factor anyway, so it'll show a message - don't need to double up
108                        new HyperspaceTopographyEventIntel(null, false);
109                }
110                if (get() != null) {
111                        get().addFactor(factor, dialog);
112                }
113        }
114        
115        public static HyperspaceTopographyEventIntel get() {
116                return (HyperspaceTopographyEventIntel) Global.getSector().getMemoryWithoutUpdate().get(KEY);
117        }
118        
119        
120        protected TimeoutTracker<RecentTopographyReadings> recent = new TimeoutTracker<RecentTopographyReadings>();
121        
122//      public static float CHECK_DAYS = 0.1f;
123//      protected IntervalUtil interval = new IntervalUtil(CHECK_DAYS * 0.8f, CHECK_DAYS * 1.2f);
124//      protected float burnBasedPoints = 0f;
125        
126        public HyperspaceTopographyEventIntel(TextPanelAPI text, boolean withIntelNotification) {
127                super();
128                
129                Global.getSector().getMemoryWithoutUpdate().set(KEY, this);
130                
131                
132                setup();
133                
134                // now that the event is fully constructed, add it and send notification
135                Global.getSector().getIntelManager().addIntel(this, !withIntelNotification, text);
136        }
137        
138        protected void setup() {
139                factors.clear();
140                stages.clear();
141                
142                setMaxProgress(PROGRESS_MAX);
143                
144                addStage(Stage.START, 0);
145                addStage(Stage.SLIPSTREAM_NAVIGATION, PROGRESS_1, StageIconSize.MEDIUM);
146                addStage(Stage.REVERSE_POLARITY, PROGRESS_2, StageIconSize.LARGE);
147                addStage(Stage.SLIPSTREAM_DETECTION, PROGRESS_3, StageIconSize.MEDIUM);
148                addStage(Stage.HYPERFIELD_OPTIMIZATION, PROGRESS_4, StageIconSize.MEDIUM);
149                addStage(Stage.GENERATE_SLIPSURGE, PROGRESS_5, StageIconSize.LARGE);
150                addStage(Stage.TOPOGRAPHIC_DATA, PROGRESS_MAX, true, StageIconSize.SMALL);
151                
152                getDataFor(Stage.SLIPSTREAM_NAVIGATION).keepIconBrightWhenLaterStageReached = true;
153                getDataFor(Stage.SLIPSTREAM_DETECTION).keepIconBrightWhenLaterStageReached = true;
154                getDataFor(Stage.REVERSE_POLARITY).keepIconBrightWhenLaterStageReached = true;
155                getDataFor(Stage.HYPERFIELD_OPTIMIZATION).keepIconBrightWhenLaterStageReached = true;
156                getDataFor(Stage.GENERATE_SLIPSURGE).keepIconBrightWhenLaterStageReached = true;
157                
158        }
159        
160        protected Object readResolve() {
161                if (getDataFor(Stage.GENERATE_SLIPSURGE) == null) {
162                        setup();
163                }
164                return this;
165        }
166        
167        
168        @Override
169        protected void notifyEnding() {
170                super.notifyEnding();
171        }
172
173        @Override
174        protected void notifyEnded() {
175                super.notifyEnded();
176                Global.getSector().getMemoryWithoutUpdate().unset(KEY);
177        }
178        
179        protected void addBulletPoints(TooltipMakerAPI info, ListInfoMode mode, boolean isUpdate, 
180                                                                        Color tc, float initPad) {
181                
182                if (addEventFactorBulletPoints(info, mode, isUpdate, tc, initPad)) {
183                        return;
184                }
185                
186                Color h = Misc.getHighlightColor();
187                if (isUpdate && getListInfoParam() instanceof EventStageData) {
188                        EventStageData esd = (EventStageData) getListInfoParam();
189                        if (esd.id == Stage.SLIPSTREAM_DETECTION) {
190                                info.addPara("Able to detect slipstreams near your spaceports", tc, initPad);
191                        }
192                        if (esd.id == Stage.SLIPSTREAM_NAVIGATION) {
193//                              info.addPara("Fuel use while traversing slipstreams multiplied by %s", initPad, tc,
194//                                              h, "" + SLIPSTREAM_FUEL_MULT + Strings.X);
195                                info.addPara("Fuel use while traversing slipstreams reduced by %s", initPad, tc,
196                                                h, "" + (int)Math.round((1f - SLIPSTREAM_FUEL_MULT) * 100f) + "%");
197                        }
198                        if (esd.id == Stage.HYPERFIELD_OPTIMIZATION) {
199                                info.addPara("Maximum burn increased by %s while in hyperspace", initPad, tc, 
200                                                h, "" + (int) HYPER_BURN_BONUS);
201                        }
202                        if (esd.id == Stage.REVERSE_POLARITY) {
203                                info.addPara("%s ability unlocked", initPad, tc, h, "Reverse Polarity");
204                        }
205                        if (esd.id == Stage.GENERATE_SLIPSURGE) {
206                                info.addPara("%s ability unlocked", initPad, tc, h, "Generate Slipsurge");
207                        }
208                        if (esd.id == Stage.TOPOGRAPHIC_DATA) {
209                                info.addPara("Topographic data gained", tc, initPad);
210                        }
211                        return;
212                }
213                
214//              EventStageData esd = getLastActiveStage(false);
215//              if (esd != null && EnumSet.of(Stage.START, Stage.HA_1, Stage.HA_2, Stage.HA_3, Stage.HA_4).contains(esd.id)) {
216//                      
217//              }
218        }
219        
220        public float getImageSizeForStageDesc(Object stageId) {
221//              if (stageId == Stage.REVERSE_POLARITY || stageId == Stage.GENERATE_SLIPSURGE) {
222//                      return 48f;
223//              }
224                if (stageId == Stage.START) {
225                        return 64f;
226                }
227                return 48f;
228        }
229        public float getImageIndentForStageDesc(Object stageId) {
230//              if (stageId == Stage.REVERSE_POLARITY || stageId == Stage.GENERATE_SLIPSURGE) {
231//                      return 16f;
232//              }
233                if (stageId == Stage.START) {
234                        return 0f;
235                }
236                return 16f;
237        }
238
239        @Override
240        public void addStageDescriptionText(TooltipMakerAPI info, float width, Object stageId) {
241                float opad = 10f;
242                float small = 0f;
243                Color h = Misc.getHighlightColor();
244                
245                //setProgress(0);
246                //setProgress(199);
247                //setProgress(600);
248                //setProgress(899);
249                //setProgress(1000);
250                //setProgress(499);
251                //setProgress(600);
252                
253                EventStageData stage = getDataFor(stageId);
254                if (stage == null) return;
255                
256//              if (isStageActiveAndLast(stageId) &&  stageId == Stage.START) {
257//                      addStageDesc(info, stageId, small, false);
258//              } else if (isStageActive(stageId) && stageId != Stage.START) {
259//                      addStageDesc(info, stageId, small, false);
260//              }
261                
262                if (isStageActive(stageId)) {
263                        addStageDesc(info, stageId, small, false);
264                }
265        }
266        
267        
268        public void addStageDesc(TooltipMakerAPI info, Object stageId, float initPad, boolean forTooltip) {
269                float opad = 10f;
270                Color h = Misc.getHighlightColor();
271                if (stageId == Stage.START) {
272                        info.addPara("Detailed sensor readings greatly aid hyperspace navigation. "
273                                        + "There are many ways of acquiring this data, including using in-system sensor arrays,"
274                                        + " using an Active Sensor Burst near interesting phenomena, "
275                                        + "traveling through hyperspace at a very high burn level, or simply buying the data from scavengers.",
276                                        initPad);
277                } else if (stageId == Stage.SLIPSTREAM_DETECTION) {
278//                      info.addPara("The facilities and staff at a Spaceport are able to interpret data from various sources "
279//                                      + "to discover the presence of nearby slipstreams. The detection range is increased "
280//                                      + "for larger colonies. Claimed sensor arrays within %s light-years provide an additional "
281//                                      + "bonus - %s ly for Domain-era arrays, and %s ly for makeshift ones. "
282//                                      + "Up to %s sensor arrays can be of use.", initPad, 
283//                                      Misc.getHighlightColor(),
284//                                      "" + (int) RANGE_WITHIN_WHICH_SENSOR_ARRAYS_HELP_LY,
285//                                      "+" + (int) RANGE_PER_DOMAIN_SENSOR_ARRAY,
286//                                      "+" + (int) RANGE_PER_MAKESHIFT_SENSOR_ARRAY,
287//                                      "" + (int) MAX_SENSOR_ARRAYS
288//                                      );
289                        info.addPara("Allows a Spaceport "
290                                        + "to detect nearby slipstreams. Detection range increased "
291                                        + "for %s. Claimed sensor arrays within %s light-years provide extra detection range: "
292                                        + "%s ly for Domain-era arrays, and %s ly for makeshift ones. "
293                                        + "Up to %s sensor arrays can be used.", initPad, 
294                                        Misc.getHighlightColor(),
295                                        "larger colonies",
296                                        "" + (int) RANGE_WITHIN_WHICH_SENSOR_ARRAYS_HELP_LY,
297                                        "+" + (int) RANGE_PER_DOMAIN_SENSOR_ARRAY,
298                                        "+" + (int) RANGE_PER_MAKESHIFT_SENSOR_ARRAY,
299                                        "" + (int) MAX_SENSOR_ARRAYS
300                                        );
301                } else if (stageId == Stage.SLIPSTREAM_NAVIGATION) {
302                        info.addPara("Fuel use while traveling inside slipstreams reduced by %s. This reduction is multiplicative " +
303                                                 "with the baseline fuel use reduction for traveling inside a slipstream.",
304                                        initPad, h,
305                                        "" + (int)Math.round((1f - SLIPSTREAM_FUEL_MULT) * 100f) + "%");
306                } else if (stageId == Stage.REVERSE_POLARITY) {
307                        info.addPara("Unlocks the %s ability, which allows your fleet to "
308                                        + "travel against the current of slipstreams.", initPad, h,
309                                        "Reverse Polarity");
310                } else if (stageId == Stage.GENERATE_SLIPSURGE) {
311                        info.addPara("Unlocks the %s ability, which allows your fleet to "
312                                        + "create powerful, short-lived slipstreams useful for rapid travel.", initPad, h,
313                                        "Generate Slipsurge");
314                } else if (stageId == Stage.HYPERFIELD_OPTIMIZATION) {
315                        info.addPara("Maximum burn increased by %s while in hyperspace.", initPad, h,
316                                        "" + (int) HYPER_BURN_BONUS);
317                } else if (stageId == Stage.TOPOGRAPHIC_DATA) {
318                        int min = getTopoResetMin();
319                        int max = getTopoResetMax();
320                        info.addPara("A batch of topographic data that can be sold for a"
321                                        + " considerable number of credits.", initPad);
322                        info.addPara("Event progress will be reset to between %s and %s points when this outcome is reached.",
323                                        opad, h, "" + min, "" + max);
324                }
325        }
326        
327        public TooltipCreator getStageTooltipImpl(Object stageId) {
328                final EventStageData esd = getDataFor(stageId);
329                
330                if (esd != null && EnumSet.of(Stage.SLIPSTREAM_DETECTION, Stage.SLIPSTREAM_NAVIGATION,
331                                Stage.GENERATE_SLIPSURGE, Stage.REVERSE_POLARITY,
332                                Stage.HYPERFIELD_OPTIMIZATION, Stage.TOPOGRAPHIC_DATA).contains(esd.id)) {
333                        return new BaseFactorTooltip() {
334                                @Override
335                                public void createTooltip(TooltipMakerAPI tooltip, boolean expanded, Object tooltipParam) {
336                                        float opad = 10f;
337                                        
338                                        if (esd.id == Stage.SLIPSTREAM_DETECTION) {
339                                                tooltip.addTitle("Slipstream detection");
340                                        } else if (esd.id == Stage.SLIPSTREAM_NAVIGATION) {
341                                                tooltip.addTitle("Slipstream navigation");
342                                        } else if (esd.id == Stage.HYPERFIELD_OPTIMIZATION) {
343                                                tooltip.addTitle("Hyperfield optimization");
344                                        } else if (esd.id == Stage.REVERSE_POLARITY) {
345                                                tooltip.addTitle("Reverse Polarity");
346                                        } else if (esd.id == Stage.GENERATE_SLIPSURGE) {
347                                                tooltip.addTitle("Generate Slipsurge");
348                                        } else if (esd.id == Stage.TOPOGRAPHIC_DATA) {
349                                                tooltip.addTitle("Topographic data");
350                                        }
351
352                                        addStageDesc(tooltip, esd.id, opad, true);
353                                        
354                                        esd.addProgressReq(tooltip, opad);
355                                }
356                        };
357                }
358                
359                return null;
360        }
361
362
363
364        @Override
365        public String getIcon() {
366                return Global.getSettings().getSpriteName("events", "hyperspace_topography");
367        }
368
369        protected String getStageIconImpl(Object stageId) {
370                EventStageData esd = getDataFor(stageId);
371                if (esd == null) return null;
372                
373        
374                if (EnumSet.of(Stage.SLIPSTREAM_DETECTION, Stage.SLIPSTREAM_NAVIGATION, Stage.HYPERFIELD_OPTIMIZATION, 
375                                Stage.TOPOGRAPHIC_DATA, Stage.START).contains(esd.id)) {
376                        return Global.getSettings().getSpriteName("events", "hyperspace_topography_" + ((Stage)esd.id).name());
377                }
378                if (stageId == Stage.REVERSE_POLARITY) {
379                        return Global.getSettings().getAbilitySpec(Abilities.REVERSE_POLARITY).getIconName();
380                }
381                if (stageId == Stage.GENERATE_SLIPSURGE) {
382                        return Global.getSettings().getAbilitySpec(Abilities.GENERATE_SLIPSURGE).getIconName();
383                }
384                // should not happen - the above cases should handle all possibilities - but just in case
385                return Global.getSettings().getSpriteName("events", "hyperspace_topography");
386        }
387        
388        
389        @Override
390        public Color getBarColor() {
391                Color color = BAR_COLOR;
392                //color = Misc.getBasePlayerColor();
393                color = Misc.interpolateColor(color, Color.black, 0.25f);
394                return color;
395        }
396        
397        @Override
398        public Color getBarProgressIndicatorColor() {
399                return super.getBarProgressIndicatorColor();
400        }
401
402        @Override
403        protected int getStageImportance(Object stageId) {
404                return super.getStageImportance(stageId);
405        }
406
407
408        @Override
409        protected String getName() {
410                return "Hyperspace Topography";
411        }
412        
413
414        public void reportFleetDespawnedToListener(CampaignFleetAPI fleet, FleetDespawnReason reason, Object param) {
415                
416        }
417        public void reportBattleOccurred(CampaignFleetAPI fleet, CampaignFleetAPI primaryWinner, BattleAPI battle) {
418//              if (isEnded() || isEnding()) return;
419//              
420//              if (!battle.isPlayerInvolved()) return;
421                
422//              HAShipsDestroyedFactor factor = new HAShipsDestroyedFactor(-1 * points);
423//              sendUpdateIfPlayerHasIntel(factor, false);
424//              addFactor(factor);
425        }
426        
427
428        public int getTopoResetMin() {
429                EventStageData stage = getDataFor(Stage.GENERATE_SLIPSURGE);
430                return stage.progress;
431        }
432        public int getTopoResetMax() {
433                return getTopoResetMin() + 50;
434        }
435
436        public void resetTopographicData() {
437                int resetProgress = getTopoResetMin() + getRandom().nextInt(getTopoResetMax() - getTopoResetMin() + 1);
438                setProgress(resetProgress);
439        }
440
441        @Override
442        public Set<String> getIntelTags(SectorMapAPI map) {
443                Set<String> tags = super.getIntelTags(map);
444                tags.add(Tags.INTEL_EXPLORATION);
445                //tags.remove(Tags.INTEL_MAJOR_EVENT);
446                return tags;
447        }
448
449        @Override
450        protected void advanceImpl(float amount) {
451                super.advanceImpl(amount);
452                applyFleetEffects();
453                
454                float days = Global.getSector().getClock().convertToDays(amount);
455                recent.advance(days);
456                
457                //setProgress(getProgress() + 10);
458        }
459        
460        public void addAbility(String id) {
461                if (Global.getSector().getPlayerFleet().hasAbility(id)) {
462                        return;
463                }
464                List<Token> params = new ArrayList<Token>();
465                Token t = new Token(id, TokenType.LITERAL);
466                params.add(t);
467                t = new Token("-1", TokenType.LITERAL);
468                params.add(t); // don't want to assign it to a slot - will assign as hyper-only alternate later here
469                new AddAbility().execute(null, null, params, null);
470                
471                
472                AbilitySlotsAPI slots = Global.getSector().getUIData().getAbilitySlotsAPI();
473                int curr = slots.getCurrBarIndex();
474                OUTER: for (int i = 0; i < 5; i++) {
475                        slots.setCurrBarIndex(i);
476                        for (AbilitySlotAPI slot : slots.getCurrSlotsCopy()) {
477                                if (Abilities.REVERSE_POLARITY.equals(id) && Abilities.SCAVENGE.equals(slot.getAbilityId())) {
478                                        slot.setInHyperAbilityId(Abilities.REVERSE_POLARITY);
479                                        break OUTER;
480                                }
481                                if (Abilities.GENERATE_SLIPSURGE.equals(id) && Abilities.DISTRESS_CALL.equals(slot.getAbilityId())) {
482                                        slot.setInHyperAbilityId(Abilities.GENERATE_SLIPSURGE);
483                                        break OUTER;
484                                }
485                        }
486                }
487                slots.setCurrBarIndex(curr);
488        }
489        
490        
491        @Override
492        protected void notifyStageReached(EventStageData stage) {
493                //applyFleetEffects();
494                
495                if (stage.id == Stage.REVERSE_POLARITY) {
496                        addAbility(Abilities.REVERSE_POLARITY);
497                }
498                if (stage.id == Stage.GENERATE_SLIPSURGE) {
499                        addAbility(Abilities.GENERATE_SLIPSURGE);
500                }
501                if (stage.id == Stage.TOPOGRAPHIC_DATA) {
502                        resetTopographicData();
503                        
504                        CargoAPI cargo = Global.getSector().getPlayerFleet().getCargo();
505                        cargo.addSpecial(new SpecialItemData(Items.TOPOGRAPHIC_DATA, null), 1);
506                        //sendUpdateIfPlayerHasIntel(stage, getTextPanelForStageChange());
507                }
508        }
509        
510        public void reportCurrentLocationChanged(LocationAPI prev, LocationAPI curr) {
511                //applyFleetEffects();
512        }
513        
514        public void reportAboutToRefreshCharacterStatEffects() {
515                
516        }
517
518        public void reportRefreshedCharacterStatEffects() {
519                // called when opening colony screen, so the Spaceport tooltip gets the right values
520                updateMarketDetectionRanges();
521                applyFleetEffects();
522        }
523        
524        public void applyFleetEffects() {
525                String id1 = "hypertopology1";
526                
527                CampaignFleetAPI pf = Global.getSector().getPlayerFleet();
528                pf.getStats().getFleetwideMaxBurnMod().unmodifyFlat(id1);
529                
530                MutableStat stat = pf.getStats().getDynamic().getStat(Stats.FUEL_USE_NOT_SHOWN_ON_MAP_MULT);
531                stat.unmodifyMult(id1);
532                
533                //if (pf.isInHyperspace()) { // doesn't work; after reportCurrentLocationChanged()
534                // the current location is right but the player fleet hasn't been added to it yet
535                if (Global.getSector().getCurrentLocation().isHyperspace()) {
536                        if (isStageActive(Stage.SLIPSTREAM_NAVIGATION)) {
537                                for (StatMod mod : stat.getMultMods().values()) {
538                                        if (SlipstreamTerrainPlugin2.FUEL_USE_MODIFIER_DESC.equals(mod.desc)) {
539                                                stat.modifyMult(id1, SLIPSTREAM_FUEL_MULT, 
540                                                                SlipstreamTerrainPlugin2.FUEL_USE_MODIFIER_DESC + " (hyperspace topography)");
541                                                break;
542                                        }
543                                }
544                        }
545                        
546                        if (isStageActive(Stage.HYPERFIELD_OPTIMIZATION)) {
547                                pf.getStats().getFleetwideMaxBurnMod().modifyFlat(id1, HYPER_BURN_BONUS, "Hyperspace topography");
548                        }
549                        
550                }
551        }
552        
553        public void updateMarketDetectionRanges() {
554                if (isStageActive(Stage.SLIPSTREAM_DETECTION)) {
555                        String id1 = "hypertopology1";
556                        String id2 = "hypertopology2";
557                        String id3 = "hypertopology3";
558                        String id4 = "hypertopology4";
559                        for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) {
560                                if (market.isHidden()) continue;
561
562                                boolean unapplicable = false;
563                                Industry spaceport = market.getIndustry(Industries.SPACEPORT);
564                                if (spaceport == null) {
565                                        spaceport = market.getIndustry(Industries.MEGAPORT);
566                                }
567                                if (spaceport == null || !spaceport.isFunctional()) {
568                                        unapplicable = true;
569                                }
570                                
571                                StatBonus mod = market.getStats().getDynamic().getMod(Stats.SLIPSTREAM_REVEAL_RANGE_LY_MOD);
572                                if (!market.isPlayerOwned() || unapplicable) {
573                                        mod.unmodify(id1);
574                                        mod.unmodify(id2);
575                                        mod.unmodify(id3);
576                                        mod.unmodify(id4);
577                                        continue;
578                                }
579                                
580                                mod.modifyFlat(id1, BASE_DETECTION_RANGE_LY, "Base detection range");
581                                mod.modifyFlat(id2, market.getSize(), "Colony size");
582                                
583                                float arraysBonus = gerSensorArrayBonusFor(market, RANGE_WITHIN_WHICH_SENSOR_ARRAYS_HELP_LY);
584                                
585                                mod.modifyFlatAlways(id3, arraysBonus, 
586                                                "Claimed sensor arrays within " + (int) RANGE_WITHIN_WHICH_SENSOR_ARRAYS_HELP_LY + 
587                                                " ly (max: " + (int) MAX_SENSOR_ARRAYS + " arrays)");
588                        }
589                }
590        }
591        
592        public float gerSensorArrayBonusFor(MarketAPI market, float range) {
593                int countDomain = 0;
594                int countMakeshift= 0;
595                Vector2f locInHyper = market.getLocationInHyperspace();
596                for (StarSystemAPI system : Global.getSector().getStarSystems()) {
597                        float dist = Misc.getDistanceLY(locInHyper, system.getLocation());
598                        if (dist > range && Math.round(dist * 10f) <= range * 10f) {
599                                dist = range;
600                        }
601                        if (dist <= range) {
602                                for (SectorEntityToken entity : system.getEntitiesWithTag(Tags.SENSOR_ARRAY)) {
603                                        if (entity.getFaction() != null && entity.getFaction().isPlayerFaction()) {
604                                                if (entity.hasTag(Tags.MAKESHIFT)) {
605                                                        countMakeshift++;
606                                                } else {
607                                                        countDomain++;
608                                                }
609                                        }
610                                }
611                        }
612                }
613                
614                float bonus = Math.min(countDomain, MAX_SENSOR_ARRAYS) * RANGE_PER_DOMAIN_SENSOR_ARRAY;
615                float useMakeshift = Math.min(MAX_SENSOR_ARRAYS - countDomain, countMakeshift);
616                if (useMakeshift < 0) useMakeshift = 0;
617                bonus += useMakeshift * RANGE_PER_MAKESHIFT_SENSOR_ARRAY;
618                //bonus += Math.min(Math.max(0, countMakeshift - countDomain), MAX_SENSOR_ARRAYS) * RANGE_PER_MAKESHIFT_SENSOR_ARRAY;
619
620                return bonus;
621        }
622
623        public boolean withMonthlyFactors() {
624                return false;
625        }
626        
627        
628        public void addRecentReadings(Vector2f loc) {
629                recent.add(new RecentTopographyReadings(loc), RECENT_READINGS_TIMEOUT);
630        }
631        
632        public static boolean hasRecentReadingsNearPlayer() {
633                return get() != null && get().hasRecentReadingsNear(Global.getSector().getPlayerFleet().getLocationInHyperspace());
634        }
635        
636        public boolean hasRecentReadingsNear(Vector2f loc) {
637                for (RecentTopographyReadings curr : recent.getItems()) {
638                        float distLY = Misc.getDistanceLY(loc, curr.loc);
639                        if (distLY <= RECENT_READINGS_RANGE_LY) {
640                                return true;
641                        }
642                }
643                return false;
644        }
645        
646        protected String getSoundForStageReachedUpdate(Object stageId) {
647                if (stageId == Stage.REVERSE_POLARITY || stageId == Stage.GENERATE_SLIPSURGE) {
648                        return "ui_learned_ability";
649                }
650                return super.getSoundForStageReachedUpdate(stageId);
651        }
652
653        @Override
654        protected String getSoundForOneTimeFactorUpdate(EventFactor factor) {
655//              if (factor instanceof HTAbyssalLightFactor) {
656//                      return "sound_none";
657//              }
658                return null;
659        }
660        
661        
662        
663}
664
665
666
667
668
669
670
671