001package com.fs.starfarer.api.impl.campaign.missions;
002
003import java.util.Map;
004
005import java.awt.Color;
006
007import com.fs.starfarer.api.Global;
008import com.fs.starfarer.api.campaign.CargoAPI;
009import com.fs.starfarer.api.campaign.CargoStackAPI;
010import com.fs.starfarer.api.campaign.InteractionDialogAPI;
011import com.fs.starfarer.api.campaign.SectorEntityToken;
012import com.fs.starfarer.api.campaign.SpecialItemData;
013import com.fs.starfarer.api.campaign.StarSystemAPI;
014import com.fs.starfarer.api.campaign.econ.MarketAPI;
015import com.fs.starfarer.api.campaign.listeners.CargoGainedListener;
016import com.fs.starfarer.api.campaign.listeners.ShowLootListener;
017import com.fs.starfarer.api.campaign.rules.MemoryAPI;
018import com.fs.starfarer.api.characters.PersonAPI;
019import com.fs.starfarer.api.combat.ShipAPI.HullSize;
020import com.fs.starfarer.api.combat.ShipHullSpecAPI;
021import com.fs.starfarer.api.combat.WeaponAPI.WeaponSize;
022import com.fs.starfarer.api.impl.campaign.ids.Factions;
023import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
024import com.fs.starfarer.api.impl.campaign.ids.Items;
025import com.fs.starfarer.api.impl.campaign.ids.Ranks;
026import com.fs.starfarer.api.impl.campaign.ids.Tags;
027import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithBarEvent;
028import com.fs.starfarer.api.impl.campaign.missions.hub.ReqMode;
029import com.fs.starfarer.api.loading.FighterWingSpecAPI;
030import com.fs.starfarer.api.loading.WeaponSpecAPI;
031import com.fs.starfarer.api.ui.SectorMapAPI;
032import com.fs.starfarer.api.ui.TooltipMakerAPI;
033import com.fs.starfarer.api.util.Misc;
034import com.fs.starfarer.api.util.WeightedRandomPicker;
035
036public class BlueprintIntel extends HubMissionWithBarEvent implements ShowLootListener, CargoGainedListener {
037
038        public static float PROB_PATHER = 0.5f;
039        public static float PROB_MERC = 0.5f;
040        
041        public static float PROB_TRY_TO_FIND_RUINS = 0.5f;
042        public static float FREQ_WEAPON = 10f;
043        public static float FREQ_FIGHTER = 10f;
044        public static float FREQ_SHIP = 10f;
045        
046        public static enum Stage {
047                GET_ITEM,
048                COMPLETED,
049        }
050        
051        protected StarSystemAPI system;
052        
053        protected SpecialItemData item;
054        protected int price;
055        protected SectorEntityToken entity;
056        
057        protected float getQualityMultForTier(int tier) {
058                float q = getQuality();
059                float qWeight = 1f;
060                if (tier <= 0) qWeight = 0;
061                else if (tier == 1) qWeight = 1f;
062                else if (tier == 2) qWeight = 2f;
063                else if (tier >= 3) qWeight = 4f;
064
065                return (1f - qWeight) + qWeight * (1f + q);
066        }
067        
068        protected void pickItem() {
069                
070                WeightedRandomPicker<String> typePicker = new WeightedRandomPicker<String>(genRandom);
071                typePicker.add(Items.FIGHTER_BP, FREQ_FIGHTER);
072                typePicker.add(Items.WEAPON_BP, FREQ_WEAPON);
073                typePicker.add(Items.SHIP_BP, FREQ_SHIP);
074                
075                while (item == null && !typePicker.isEmpty()) {
076                        String type = typePicker.pick();
077                        
078                        if (type.equals(Items.FIGHTER_BP)) {
079                                WeightedRandomPicker<FighterWingSpecAPI> picker = new WeightedRandomPicker<FighterWingSpecAPI>(genRandom);
080                                for (FighterWingSpecAPI spec : Global.getSettings().getAllFighterWingSpecs()) {
081                                        if (!spec.hasTag(Items.TAG_RARE_BP)) continue;
082                                        if (spec.hasTag(Tags.NO_DROP)) continue;
083                                        if (Global.getSector().getPlayerFaction().knowsFighter(spec.getId())) continue;
084                                        float w = spec.getRarity() * getQualityMultForTier(spec.getTier());
085                                        picker.add(spec, w);
086                                }
087                                FighterWingSpecAPI pick = picker.pick();
088                                if (pick != null) {
089                                        item = new SpecialItemData(type, pick.getId());
090                                        price = (int) pick.getBaseValue();
091                                } else {
092                                        typePicker.remove(type);
093                                }
094                        } else if (type.equals(Items.WEAPON_BP)) {
095                                WeightedRandomPicker<WeaponSpecAPI> picker = new WeightedRandomPicker<WeaponSpecAPI>(genRandom);
096                                for (WeaponSpecAPI spec : Global.getSettings().getAllWeaponSpecs()) {
097                                        if (!spec.hasTag(Items.TAG_RARE_BP)) continue;
098                                        if (spec.hasTag(Tags.NO_DROP)) continue;
099                                        if (Global.getSector().getPlayerFaction().knowsWeapon(spec.getWeaponId())) continue;
100                                        float w = spec.getRarity() * getQualityMultForTier(spec.getTier());;
101                                        picker.add(spec, w);
102                                }
103                                WeaponSpecAPI pick = picker.pick();
104                                if (pick != null) {
105                                        item = new SpecialItemData(type, pick.getWeaponId());
106                                        price = (int) pick.getBaseValue();
107                                } else {
108                                        typePicker.remove(type);
109                                }
110                        } else if (type.equals(Items.SHIP_BP)) {
111                                WeightedRandomPicker<ShipHullSpecAPI> picker = new WeightedRandomPicker<ShipHullSpecAPI>(genRandom);
112                                for (ShipHullSpecAPI spec : Global.getSettings().getAllShipHullSpecs()) {
113                                        if (!spec.hasTag(Items.TAG_RARE_BP)) continue;
114                                        if (spec.hasTag(Tags.NO_DROP)) continue;
115                                        if (Global.getSector().getPlayerFaction().knowsShip(spec.getHullId())) continue;
116                                        float w = spec.getRarity() * getQualityMultForTier(spec.getFleetPoints() / 6);;
117                                        picker.add(spec, w);
118                                }
119                                ShipHullSpecAPI pick = picker.pick();
120                                if (pick != null) {
121                                        item = new SpecialItemData(type, pick.getHullId());
122                                        price = (int) pick.getBaseValue();
123                                } else {
124                                        typePicker.remove(type);
125                                }
126                        } else {
127                                // ???
128                                break;
129                        }
130                }
131                
132                if (price != 0) {
133                        price = getRoundNumber(price * (1.5f + (1f - getRewardMultFraction())));
134                }
135        }
136        
137        protected String getItemNameLowercaseItem() {
138                String item = getItemName();
139                item = item.replaceFirst(" Item", " item");
140                item = item.replaceFirst(" Blueprint", " blueprint");
141                return item;
142        }
143        protected String getItemName() {
144                if (item == null) return "an Invalid Item";
145                
146                String name = "Invalid Item";
147                if (item.getId().equals(Items.FIGHTER_BP)) {
148                        FighterWingSpecAPI spec = Global.getSettings().getFighterWingSpec(item.getData());
149                        name = spec.getWingName() + " Blueprint";
150                } else if (item.getId().equals(Items.WEAPON_BP)) {
151                        WeaponSpecAPI spec = Global.getSettings().getWeaponSpec(item.getData());
152                        name = spec.getWeaponName() + " Blueprint";
153                } else if (item.getId().equals(Items.SHIP_BP)) {
154                        ShipHullSpecAPI spec = Global.getSettings().getHullSpec(item.getData());
155                        name = spec.getHullName() + " Blueprint";
156                }
157                return Misc.getAOrAnFor(name) + " " + name;
158        }
159        
160        protected boolean isVeryValuable() {
161                if (item.getId().equals(Items.FIGHTER_BP)) {
162                        //FighterWingSpecAPI spec = Global.getSettings().getFighterWingSpec(item.getData());
163                        return false;
164                } else if (item.getId().equals(Items.WEAPON_BP)) {
165                        WeaponSpecAPI spec = Global.getSettings().getWeaponSpec(item.getData());
166                        return spec.getSize() == WeaponSize.LARGE;
167                } else if (item.getId().equals(Items.SHIP_BP)) {
168                        ShipHullSpecAPI spec = Global.getSettings().getHullSpec(item.getData());
169                        return spec.getHullSize().ordinal() >= HullSize.DESTROYER.ordinal();
170                }
171                return false;
172        }
173        
174        
175        @Override
176        protected boolean create(MarketAPI createdAt, boolean barEvent) {
177                //genRandom = Misc.random;
178                
179                if (barEvent) {
180                        setGiverRank(Ranks.CITIZEN);
181                        setGiverPost(pickOne(Ranks.POST_AGENT, Ranks.POST_SMUGGLER, Ranks.POST_GANGSTER, 
182                                                                 Ranks.POST_FENCE, Ranks.POST_CRIMINAL));
183                        setGiverImportance(pickImportance());
184                        setGiverFaction(Factions.PIRATES);
185                        setGiverTags(Tags.CONTACT_UNDERWORLD);
186                        findOrCreateGiver(createdAt, false, false);
187                }
188                
189                PersonAPI person = getPerson();
190                if (person == null) return false;
191                
192                pickItem();
193                if (item == null) return false;
194                
195                
196                if (!setPersonMissionRef(person, "$sitm_ref")) {
197                        return false;
198                }
199                
200                if (barEvent) {
201                        setGiverIsPotentialContactOnSuccess();
202                }
203                
204                requireSystemInterestingAndNotCore();
205                preferSystemUnexplored();
206                preferSystemTags(ReqMode.NOT_ANY, Tags.THEME_DERELICT);
207
208                entity = null;
209                if (rollProbability(PROB_TRY_TO_FIND_RUINS)) {
210                        requirePlanetUnpopulated();
211                        requirePlanetWithRuins();
212                        requirePlanetNotFullySurveyed();
213                        requirePlanetUnexploredRuins();
214                        preferPlanetInDirectionOfOtherMissions();
215                        entity = pickPlanet();
216                }
217                
218                if (entity == null) {
219                        requireEntityTags(ReqMode.ANY, Tags.SALVAGEABLE);
220                        requireEntityUndiscovered();
221                        preferEntityInDirectionOfOtherMissions();
222                        entity = pickEntity();
223                }
224                
225                if (entity == null) {
226                        return false;
227                }
228                
229                system = entity.getStarSystem();
230                if (system == null) return false;
231                
232                setStartingStage(Stage.GET_ITEM);
233                setSuccessStage(Stage.COMPLETED);
234                
235                addTag(Tags.INTEL_EXPLORATION);
236                
237                boolean veryValuable = isVeryValuable();
238                
239                int numScav = genRandom.nextInt(3);
240                if (veryValuable) numScav += 2;
241                
242                for (int i = 0; i < numScav; i++) {
243                        beginWithinHyperspaceRangeTrigger(system, 3f, false, Stage.GET_ITEM);
244                        triggerCreateFleet(FleetSize.LARGE, FleetQuality.DEFAULT, Factions.SCAVENGERS, FleetTypes.SCAVENGER_MEDIUM, system);
245                        triggerAutoAdjustFleetStrengthMajor();
246                        triggerSetFleetFaction(Factions.INDEPENDENT);
247                        
248                        triggerMakeLowRepImpact();
249                        
250                        triggerSpawnFleetNear(system.getCenter(), null, "$sitm_ref");
251                        triggerFleetSetTravelActionText("exploring system");
252                        triggerFleetSetPatrolActionText("scanning local volume");
253                        triggerOrderFleetPatrol(system, true, Tags.SALVAGEABLE, Tags.PLANET);
254                        triggerFleetSetWarnAttack("SITMScavWarning", "SITMScavAttack", Stage.GET_ITEM);
255                        endTrigger();
256                }
257                
258                
259                if (veryValuable && rollProbability(PROB_MERC)) {
260                        beginWithinHyperspaceRangeTrigger(system, 3f, false, Stage.GET_ITEM);
261                        triggerCreateFleet(FleetSize.VERY_LARGE, FleetQuality.VERY_HIGH, Factions.MERCENARY, FleetTypes.PATROL_LARGE, system);
262                        triggerSetFleetFaction(Factions.INDEPENDENT);
263                        triggerSetFleetOfficers(OfficerNum.MORE, OfficerQuality.HIGHER);
264                        triggerAutoAdjustFleetStrengthMajor();
265                        triggerMakeLowRepImpact();
266                        triggerFleetAllowLongPursuit();
267                        triggerSetFleetAlwaysPursue();
268                        triggerSpawnFleetNear(system.getCenter(), null, "$sitm_ref");
269                        triggerOrderFleetPatrol(system, true, Tags.JUMP_POINT);
270                        triggerFleetSetWarnAttack("SITMMercWarning", "SITMMercAttack", Stage.GET_ITEM);
271                        endTrigger();
272                }
273                
274                return true;
275        }
276        
277
278        public void reportAboutToShowLootToPlayer(CargoAPI loot, InteractionDialogAPI dialog) {
279                for (CargoStackAPI stack : loot.getStacksCopy()) {
280                        if (item.equals(stack.getData())) {
281                                Global.getSector().getListenerManager().removeListener(this);
282                                setCurrentStage(Stage.COMPLETED, dialog, dialog.getPlugin().getMemoryMap());
283                                break;
284                        }
285                }
286        }
287        
288        public void reportSpecialCargoGainedFromRecoveredDerelict(CargoAPI loot, InteractionDialogAPI dialog) {
289                reportAboutToShowLootToPlayer(loot, dialog);
290        }
291        
292        @Override
293        public void acceptImpl(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) {
294                super.acceptImpl(dialog, memoryMap);
295                addSpecialItemDropOnlyUseInAcceptImplNotUndoneOnAbort(entity, item);
296                Global.getSector().getListenerManager().addListener(this);
297        }
298        
299        @Override
300        protected void notifyEnding() {
301                super.notifyEnding();
302                
303                Global.getSector().getListenerManager().removeListener(this);
304                
305                if (!rollProbability(PROB_PATHER)) return;
306                
307                PersonAPI person = getPerson();
308                if (person == null || person.getMarket() == null) return;
309                String patrolFaction = person.getMarket().getFactionId();
310                if (patrolFaction.equals(person.getFaction().getId()) || 
311                                Misc.isPirateFaction(person.getMarket().getFaction())) {
312                        return;
313                }
314                
315                DelayedFleetEncounter e = new DelayedFleetEncounter(genRandom, getMissionId());
316                e.setDelayNone();
317                e.setEncounterInHyper();
318                e.setLocationAnywhere(true, Factions.LUDDIC_PATH);
319                e.beginCreate();
320                e.triggerCreateFleet(FleetSize.LARGE, FleetQuality.DEFAULT, Factions.LUDDIC_PATH, FleetTypes.PATROL_LARGE, system);
321                e.triggerSetAdjustStrengthBasedOnQuality(true, getQuality());
322                e.triggerSetStandardAggroInterceptFlags();
323                e.triggerSetFleetGenericHailPermanent("SITMPatherHail");
324                e.triggerFleetPatherNoDefaultTithe();
325                e.endCreate();
326        }
327
328
329        protected void updateInteractionDataImpl() {
330                set("$sitm_barEvent", isBarEvent());
331                set("$sitm_manOrWoman", getPerson().getManOrWoman());
332                set("$sitm_heOrShe", getPerson().getHeOrShe());
333                
334                set("$sitm_price", Misc.getWithDGS(price));
335                
336                set("$sitm_aOrAnItem", getItemNameLowercaseItem());
337                set("$sitm_item", getWithoutArticle(getItemNameLowercaseItem()));
338                
339                set("$sitm_personName", getPerson().getNameString());
340                set("$sitm_systemName", system.getNameWithLowercaseTypeShort());
341                set("$sitm_dist", getDistanceLY(system));
342        }
343        
344        @Override
345        public void addDescriptionForNonEndStage(TooltipMakerAPI info, float width, float height) {
346                float opad = 10f;
347                Color h = Misc.getHighlightColor();
348                if (currentStage == Stage.GET_ITEM) {
349                        info.addPara("There is " + getItemNameLowercaseItem() + 
350                                        " to be found somewhere in the " + system.getNameWithLowercaseTypeShort() + ".", opad);
351                }
352        }
353
354        @Override
355        public boolean addNextStepText(TooltipMakerAPI info, Color tc, float pad) {
356                Color h = Misc.getHighlightColor();
357                if (currentStage == Stage.GET_ITEM) {
358                        info.addPara("There is " + getItemNameLowercaseItem() + " in the " +  
359                                        system.getNameWithLowercaseTypeShort(), tc, pad);
360                        return true;
361                }
362                return false;
363        }       
364        
365        @Override
366        public String getBaseName() {
367                return Misc.ucFirst(getWithoutArticle(getItemName())) + " Intel";
368        }
369        
370        protected String getMissionTypeNoun() {
371                return "intel";
372        }
373        
374        protected String getMissionCompletionVerb() {
375                return "acted on";
376        }
377        
378        @Override
379        public SectorEntityToken getMapLocation(SectorMapAPI map) {
380                return getMapLocationFor(system.getHyperspaceAnchor());
381        }
382
383
384}
385
386
387
388
389
390