001package com.fs.starfarer.api.impl.campaign.procgen.themes;
002
003import java.util.Random;
004
005import org.lwjgl.util.vector.Vector2f;
006
007import com.fs.starfarer.api.campaign.CampaignFleetAPI;
008import com.fs.starfarer.api.campaign.InteractionDialogAPI;
009import com.fs.starfarer.api.campaign.SectorEntityToken;
010import com.fs.starfarer.api.campaign.StarSystemAPI;
011import com.fs.starfarer.api.combat.BattleCreationContext;
012import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl.BaseFIDDelegate;
013import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl.FIDConfig;
014import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl.FIDConfigGen;
015import com.fs.starfarer.api.impl.campaign.fleets.FleetFactoryV3;
016import com.fs.starfarer.api.impl.campaign.fleets.FleetParamsV3;
017import com.fs.starfarer.api.impl.campaign.fleets.SeededFleetManager;
018import com.fs.starfarer.api.impl.campaign.ids.Abilities;
019import com.fs.starfarer.api.impl.campaign.ids.Factions;
020import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
021import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
022import com.fs.starfarer.api.impl.campaign.ids.Tags;
023import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator;
024import com.fs.starfarer.api.util.Misc;
025import com.fs.starfarer.api.util.WeightedRandomPicker;
026
027public class RemnantSeededFleetManager extends SeededFleetManager {
028
029//      public static class DerelictFleetInteractionConfigGen implements FIDConfigGen {
030//              public FIDConfig createConfig() {
031//                      FIDConfig config = new FIDConfig();
032//                      config.showTransponderStatus = false;
033//                      config.delegate = new BaseFIDDelegate() {
034//                              public void postPlayerSalvageGeneration(InteractionDialogAPI dialog, FleetEncounterContext context, CargoAPI salvage) {
035//                                      if (!(dialog.getInteractionTarget() instanceof CampaignFleetAPI)) return;
036//                                      
037//                                      CampaignFleetAPI fleet = (CampaignFleetAPI) dialog.getInteractionTarget();
038//                                      
039//                                      DataForEncounterSide data = context.getDataFor(fleet);
040//                                      List<FleetMemberAPI> losses = new ArrayList<FleetMemberAPI>();
041//                                      for (FleetMemberData fmd : data.getOwnCasualties()) {
042//                                              losses.add(fmd.getMember());
043//                                      }
044//                                      
045//                                      List<DropData> dropRandom = new ArrayList<DropData>();
046//                                      
047//                                      int [] counts = new int[5];
048//                                      String [] groups = new String [] {Drops.REM_FRIGATE, Drops.REM_DESTROYER, 
049//                                                                                                        Drops.REM_CRUISER, Drops.REM_CAPITAL,
050//                                                                                                        Drops.GUARANTEED_ALPHA};
051//                                      
052//                                      //for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
053//                                      for (FleetMemberAPI member : losses) {
054//                                              if (member.isStation()) {
055//                                                      counts[4] += 1;
056//                                                      counts[3] += 1;
057//                                              } else if (member.isCapital()) {
058//                                                      counts[3] += 1;
059//                                              } else if (member.isCruiser()) {
060//                                                      counts[2] += 1;
061//                                              } else if (member.isDestroyer()) {
062//                                                      counts[1] += 1;
063//                                              } else if (member.isFrigate()) {
064//                                                      counts[0] += 1;
065//                                              }
066//                                      }
067//                                      
068////                                    if (fleet.isStationMode()) {
069////                                            counts[2] += 10;
070////                                    }
071//
072//                                      for (int i = 0; i < counts.length; i++) {
073//                                              int count = counts[i];
074//                                              if (count <= 0) continue;
075//                                              
076//                                              DropData d = new DropData();
077//                                              d.group = groups[i];
078//                                              d.chances = (int) Math.ceil(count * 1f);
079//                                              dropRandom.add(d);
080//                                      }
081//                                      
082//                                      Random salvageRandom = new Random(Misc.getSalvageSeed(fleet));
083//                                      //salvageRandom = new Random();
084//                                      CargoAPI extra = SalvageEntity.generateSalvage(salvageRandom, 1f, 1f, 1f, 1f, null, dropRandom);
085//                                      for (CargoStackAPI stack : extra.getStacksCopy()) {
086//                                              salvage.addFromStack(stack);
087//                                      }
088//                              }
089//                              public void battleContextCreated(InteractionDialogAPI dialog, BattleCreationContext bcc) {
090//                                      bcc.aiRetreatAllowed = false;
091//                                      bcc.objectivesAllowed = false;
092//                              }
093//                      };
094//                      return config;
095//              }
096//      }
097        
098        
099        public static class RemnantFleetInteractionConfigGen implements FIDConfigGen {
100                public FIDConfig createConfig() {
101                        FIDConfig config = new FIDConfig();
102                        config.showTransponderStatus = false;
103                        config.delegate = new BaseFIDDelegate() {
104//                              public void postPlayerSalvageGeneration(InteractionDialogAPI dialog, FleetEncounterContext context, CargoAPI salvage) {
105//                                      if (!(dialog.getInteractionTarget() instanceof CampaignFleetAPI)) return;
106//                                      
107//                                      CampaignFleetAPI fleet = (CampaignFleetAPI) dialog.getInteractionTarget();
108//                                      
109//                                      DataForEncounterSide data = context.getDataFor(fleet);
110//                                      List<FleetMemberAPI> losses = new ArrayList<FleetMemberAPI>();
111//                                      for (FleetMemberData fmd : data.getOwnCasualties()) {
112//                                              losses.add(fmd.getMember());
113//                                      }
114//                                      
115//                                      List<DropData> dropRandom = new ArrayList<DropData>();
116//                                      
117//                                      int [] counts = new int[5];
118//                                      String [] groups = new String [] {Drops.REM_FRIGATE, Drops.REM_DESTROYER, 
119//                                                                                                        Drops.REM_CRUISER, Drops.REM_CAPITAL,
120//                                                                                                        Drops.GUARANTEED_ALPHA};
121//                                      
122//                                      //for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
123//                                      for (FleetMemberAPI member : losses) {
124//                                              if (member.isStation()) {
125//                                                      counts[4] += 1;
126//                                                      counts[3] += 1;
127//                                              } else if (member.isCapital()) {
128//                                                      counts[3] += 1;
129//                                              } else if (member.isCruiser()) {
130//                                                      counts[2] += 1;
131//                                              } else if (member.isDestroyer()) {
132//                                                      counts[1] += 1;
133//                                              } else if (member.isFrigate()) {
134//                                                      counts[0] += 1;
135//                                              }
136//                                      }
137//                                      
138////                                    if (fleet.isStationMode()) {
139////                                            counts[2] += 10;
140////                                    }
141//
142//                                      for (int i = 0; i < counts.length; i++) {
143//                                              int count = counts[i];
144//                                              if (count <= 0) continue;
145//                                              
146//                                              DropData d = new DropData();
147//                                              d.group = groups[i];
148//                                              d.chances = (int) Math.ceil(count * 1f);
149//                                              dropRandom.add(d);
150//                                      }
151//                                      
152//                                      Random salvageRandom = new Random(Misc.getSalvageSeed(fleet));
153//                                      //salvageRandom = new Random();
154//                                      CargoAPI extra = SalvageEntity.generateSalvage(salvageRandom, 1f, 1f, 1f, 1f, null, dropRandom);
155//                                      for (CargoStackAPI stack : extra.getStacksCopy()) {
156//                                              salvage.addFromStack(stack);
157//                                      }
158//                              }
159                                public void battleContextCreated(InteractionDialogAPI dialog, BattleCreationContext bcc) {
160                                        bcc.aiRetreatAllowed = false;
161                                        //bcc.objectivesAllowed = false;
162                                }
163                        };
164                        return config;
165                }
166        }
167        
168        
169        protected int minPts;
170        protected int maxPts;
171        protected float activeChance;
172
173        public RemnantSeededFleetManager(StarSystemAPI system, int minFleets, int maxFleets, int minPts, int maxPts, float activeChance) {
174                super(system, 1f);
175                this.minPts = minPts;
176                this.maxPts = maxPts;
177                this.activeChance = activeChance;
178                
179                int num = minFleets + StarSystemGenerator.random.nextInt(maxFleets - minFleets + 1);
180                for (int i = 0; i < num; i++) {
181                        long seed = StarSystemGenerator.random.nextLong();
182                        addSeed(seed);
183                }
184        }
185
186        @Override
187        protected CampaignFleetAPI spawnFleet(long seed) {
188                Random random = new Random(seed);
189                
190                int combatPoints = minPts + random.nextInt(maxPts - minPts + 1);
191                
192                String type = FleetTypes.PATROL_SMALL;
193                if (combatPoints > 8) type = FleetTypes.PATROL_MEDIUM;
194                if (combatPoints > 16) type = FleetTypes.PATROL_LARGE;
195                
196                combatPoints *= 8f; // 8 is fp cost of remnant frigate
197                
198                FleetParamsV3 params = new FleetParamsV3(
199                                system.getLocation(),
200                                Factions.REMNANTS,
201                                1f,
202                                type,
203                                combatPoints, // combatPts
204                                0f, // freighterPts 
205                                0f, // tankerPts
206                                0f, // transportPts
207                                0f, // linerPts
208                                0f, // utilityPts
209                                0f // qualityMod
210                );
211                params.withOfficers = false;
212                params.random = random;
213                
214                CampaignFleetAPI fleet = FleetFactoryV3.createFleet(params);
215                if (fleet == null) return null;
216                
217                system.addEntity(fleet);
218                fleet.setFacing(random.nextFloat() * 360f);
219                
220                
221                boolean dormant = random.nextFloat() >= activeChance;
222                //dormant = false;
223                int numActive = 0;
224                for (SeededFleet f : fleets) {
225                        if (f.fleet != null) numActive++;
226                }
227                if (numActive == 0 && activeChance > 0) { // first fleet is not dormant, to ensure one active fleet always
228                        dormant = false;
229                }
230                initRemnantFleetProperties(random, fleet, dormant);
231                
232                if (dormant) {
233                        SectorEntityToken target = pickEntityToGuard(random, system, fleet);
234                        if (target != null) {
235//                              Vector2f loc = Misc.getPointAtRadius(target.getLocation(), 300f, random);
236//                              fleet.setLocation(loc.x, loc.y);
237                                
238                                fleet.setCircularOrbit(target, 
239                                                random.nextFloat() * 360f, 
240                                                fleet.getRadius() + target.getRadius() + 100f + 100f * random.nextFloat(),
241                                                25f + 5f * random.nextFloat());
242                        } else {
243                                Vector2f loc = Misc.getPointAtRadius(new Vector2f(), 4000f, random);
244                                fleet.setLocation(loc.x, loc.y);
245                        }
246                } else {
247                        fleet.addScript(new RemnantAssignmentAI(fleet, system, null));
248                }
249                
250                return fleet;
251        }
252        
253        
254        public static SectorEntityToken pickEntityToGuard(Random random, StarSystemAPI system, CampaignFleetAPI fleet) {
255                WeightedRandomPicker<SectorEntityToken> picker = new WeightedRandomPicker<SectorEntityToken>(random);
256                
257                for (SectorEntityToken entity : system.getEntitiesWithTag(Tags.SALVAGEABLE)) {
258                        float w = 1f;
259                        if (entity.hasTag(Tags.NEUTRINO_HIGH)) w = 3f;
260                        if (entity.hasTag(Tags.NEUTRINO_LOW)) w = 0.33f;
261                        picker.add(entity, w);
262                }
263                
264                for (SectorEntityToken entity : system.getJumpPoints()) {
265                        picker.add(entity, 1f);
266                }
267                
268                return picker.pick();
269        }
270        
271        
272        
273        public static void initRemnantFleetProperties(Random random, CampaignFleetAPI fleet, boolean dormant) {
274                if (random == null) random = new Random();
275                
276                fleet.removeAbility(Abilities.EMERGENCY_BURN);
277                fleet.removeAbility(Abilities.SENSOR_BURST);
278                fleet.removeAbility(Abilities.GO_DARK);
279                
280                // to make sure they attack the player on sight when player's transponder is off
281                fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_SAW_PLAYER_WITH_TRANSPONDER_ON, true);
282                fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_PATROL_FLEET, true);
283                fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_ALLOW_LONG_PURSUIT, true);
284                fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_MAKE_HOLD_VS_STRONGER, true);
285                
286                // to make dormant fleets not try to retreat and get harried repeatedly for CR loss 
287                if (dormant) {
288                        //fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_MAKE_AGGRESSIVE, true);
289                }
290                
291                fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_NO_JUMP, true);
292                
293                if (dormant) {
294                        fleet.setTransponderOn(false);
295//                      fleet.getMemoryWithoutUpdate().unset(MemFlags.MEMORY_KEY_PATROL_FLEET);
296//                      fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_PIRATE, true); // so they don't turn transponder on
297//                      fleet.addAssignment(FleetAssignment.HOLD, null, 1000000f, "dormant");
298                        fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_MAKE_ALLOW_DISENGAGE, true);
299                        fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_MAKE_AGGRESSIVE, true);
300                        fleet.setAI(null);
301                        fleet.setNullAIActionText("dormant");
302                }
303                
304                addRemnantInteractionConfig(fleet);
305                //addRemnantAICoreDrops(random, fleet, 1f);
306                
307                long salvageSeed = random.nextLong();
308                fleet.getMemoryWithoutUpdate().set(MemFlags.SALVAGE_SEED, salvageSeed);
309        }
310        
311        public static void addRemnantInteractionConfig(CampaignFleetAPI fleet) {
312                fleet.getMemoryWithoutUpdate().set(MemFlags.FLEET_INTERACTION_DIALOG_CONFIG_OVERRIDE_GEN, 
313                                   new RemnantFleetInteractionConfigGen());             
314        }
315        
316//      public static void addRemnantAICoreDrops(Random random, CampaignFleetAPI fleet, float mult) {
317//              if (random == null) random = new Random();
318//              long salvageSeed = random.nextLong();
319//              fleet.getMemoryWithoutUpdate().set(MemFlags.SALVAGE_SEED, salvageSeed);
320//              
321//              int [] counts = new int[3];
322//              String [] groups = new String [] {Drops.AI_CORES1, Drops.AI_CORES2, Drops.AI_CORES3};
323//              for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
324//                      if (member.isCapital()) {
325//                              counts[2] += 2;
326//                      } else if (member.isCruiser()) {
327//                              counts[2] += 1;
328//                      } else if (member.isDestroyer()) {
329//                              counts[1] += 1;
330//                      } else if (member.isFrigate()) {
331//                              counts[0] += 1;
332//                      }
333//              }
334//              
335//              if (fleet.isStationMode()) {
336//                      counts[2] += 10;
337//              }
338//
339//              for (int i = 0; i < counts.length; i++) {
340//                      int count = counts[i];
341//                      if (count <= 0) continue;
342//                      
343//                      DropData d = new DropData();
344//                      d.group = groups[i];
345//                      d.chances = (int) Math.ceil(count * mult);
346//                      fleet.addDropRandom(d);
347//              }
348//              
349//      }
350
351}
352
353
354
355
356
357
358