001package com.fs.starfarer.api.impl.campaign.fleets;
002
003import java.util.ArrayList;
004import java.util.List;
005
006import org.apache.log4j.Logger;
007
008import com.fs.starfarer.api.FactoryAPI;
009import com.fs.starfarer.api.Global;
010import com.fs.starfarer.api.campaign.CampaignFleetAPI;
011import com.fs.starfarer.api.campaign.FactionAPI;
012import com.fs.starfarer.api.campaign.FactionAPI.ShipPickParams;
013import com.fs.starfarer.api.campaign.econ.MarketAPI;
014import com.fs.starfarer.api.fleet.FleetMemberAPI;
015import com.fs.starfarer.api.fleet.FleetMemberType;
016import com.fs.starfarer.api.impl.campaign.ids.Factions;
017import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
018import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
019import com.fs.starfarer.api.impl.campaign.ids.ShipRoles;
020import com.fs.starfarer.api.loading.AbilitySpecAPI;
021import com.fs.starfarer.api.util.WeightedRandomPicker;
022
023public class FleetFactory {
024
025        public static Logger log = Global.getLogger(FleetFactory.class);
026        
027        public static enum PatrolType {
028                FAST(FleetTypes.PATROL_SMALL),
029                COMBAT(FleetTypes.PATROL_MEDIUM),
030                HEAVY(FleetTypes.PATROL_LARGE);
031                
032                private String fleetType;
033                private PatrolType(String fleetType) {
034                        this.fleetType = fleetType;
035                }
036                public String getFleetType() {
037                        return fleetType;
038                }
039        }
040        
041        public static CampaignFleetAPI createPatrol(MarketAPI market, PatrolType type) {
042                float stability = market.getStabilityValue();
043                String factionId = market.getFactionId();
044                FactionAPI faction = Global.getSector().getFaction(factionId);
045                float qf = market.getShipQualityFactor();
046                return createPatrol(type, faction, stability, qf, market); 
047                
048        }
049        
050        public static CampaignFleetAPI createPatrol(PatrolType type, FactionAPI faction, float stability, float qf, MarketAPI market) {
051                String fleetType = FleetTypes.PATROL_SMALL;
052                switch (type) {
053                case FAST:
054                        fleetType = FleetTypes.PATROL_SMALL;
055                        break;
056                case COMBAT:
057                        fleetType = FleetTypes.PATROL_MEDIUM;
058                        break;
059                case HEAVY:
060                        fleetType = FleetTypes.PATROL_LARGE;
061                        break;
062                }
063                CampaignFleetAPI fleet = createEmptyFleet(faction.getId(), fleetType, market);
064
065                switch (type) {
066                case FAST:
067                        faction.pickShipAndAddToFleet(ShipRoles.COMBAT_SMALL, ShipPickParams.all(), fleet);
068                        faction.pickShipAndAddToFleet(ShipRoles.FAST_ATTACK, ShipPickParams.all(), fleet);
069                        faction.pickShipAndAddToFleet(ShipRoles.FAST_ATTACK, ShipPickParams.all(), fleet);
070                        if (stability > (float) Math.random() * 20f) {
071                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_SMALL, ShipPickParams.all(), fleet);
072                        }
073                        if (stability > (float) Math.random() * 20f) {
074                                faction.pickShipAndAddToFleet(ShipRoles.FAST_ATTACK, ShipPickParams.all(), fleet);
075                        }
076                        break;
077                case COMBAT:
078                        faction.pickShipAndAddToFleet(ShipRoles.COMBAT_SMALL, ShipPickParams.all(), fleet);
079                        faction.pickShipAndAddToFleet(ShipRoles.FAST_ATTACK, ShipPickParams.all(), fleet);
080                        
081                        faction.pickShipAndAddToFleet(ShipRoles.COMBAT_SMALL, ShipPickParams.all(), fleet);
082                        faction.pickShipAndAddToFleet(ShipRoles.COMBAT_MEDIUM, ShipPickParams.all(), fleet);
083                        faction.pickShipAndAddToFleet(ShipRoles.COMBAT_MEDIUM, ShipPickParams.all(), fleet);
084                        
085                        if (stability > (float) Math.random() * 20f) {
086                                faction.pickShipAndAddToFleet(ShipRoles.FREIGHTER_SMALL, ShipPickParams.all(), fleet);
087                        }
088                        if (stability > (float) Math.random() * 20f) {
089                                faction.pickShipAndAddToFleet(ShipRoles.TANKER_SMALL, ShipPickParams.all(), fleet);
090                        }
091                        if (stability > (float) Math.random() * 20f) {
092                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_SMALL, ShipPickParams.all(), fleet);
093                        }
094                        if (stability > (float) Math.random() * 20f) {
095                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_SMALL, ShipPickParams.all(), fleet);
096                        }
097                        if (stability > (float) Math.random() * 20f) {
098                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_MEDIUM, ShipPickParams.all(), fleet);
099                        }
100                        break;
101                case HEAVY:
102                        faction.pickShipAndAddToFleet(ShipRoles.FAST_ATTACK, ShipPickParams.all(), fleet);
103                        
104                        if ((float) Math.random() > 0.5f) {
105                                faction.pickShipAndAddToFleet(ShipRoles.CARRIER_MEDIUM, ShipPickParams.all(), fleet);
106                        } else {
107                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_SMALL, ShipPickParams.all(), fleet);
108                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_LARGE, ShipPickParams.all(), fleet);
109                        }
110                        
111                        faction.pickShipAndAddToFleet(ShipRoles.COMBAT_SMALL, ShipPickParams.all(), fleet);
112                        faction.pickShipAndAddToFleet(ShipRoles.COMBAT_MEDIUM, ShipPickParams.all(), fleet);
113                        faction.pickShipAndAddToFleet(ShipRoles.COMBAT_LARGE, ShipPickParams.all(), fleet);
114
115                        faction.pickShipAndAddToFleet(ShipRoles.FREIGHTER_MEDIUM, ShipPickParams.all(), fleet);
116                        faction.pickShipAndAddToFleet(ShipRoles.TANKER_MEDIUM, ShipPickParams.all(), fleet);
117                        
118                        if (stability > (float) Math.random() * 20f) {
119                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_SMALL, ShipPickParams.all(), fleet);
120                        }
121                        if (stability > (float) Math.random() * 20f) {
122                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_MEDIUM, ShipPickParams.all(), fleet);
123                        }
124                        if (stability > (float) Math.random() * 20f) {
125                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_LARGE, ShipPickParams.all(), fleet);
126                        }
127                        break;
128                }
129        
130                setAIMode(fleet, true);
131                
132                return fleet;
133        }
134        
135        
136        
137        
138        public static enum MercType {
139                SCOUT(FleetTypes.MERC_SCOUT),
140                BOUNTY_HUNTER(FleetTypes.MERC_BOUNTY_HUNTER),
141                PRIVATEER(FleetTypes.MERC_PRIVATEER),
142                PATROL(FleetTypes.MERC_PATROL),
143                ARMADA(FleetTypes.MERC_ARMADA);
144                
145                public String fleetType;
146                private MercType(String fleetType) {
147                        this.fleetType = fleetType;
148                }
149                
150        }
151        
152        public static CampaignFleetAPI createMerc(MarketAPI market, float qf, MercType type, String factionIdForShipPicking) {
153                float stability = market.getStabilityValue();
154                
155                String factionId = Factions.INDEPENDENT;
156                FactionAPI faction = Global.getSector().getFaction(factionIdForShipPicking);
157//              FactionAPI factionForInitialName = Global.getSector().getFaction(factionId);
158//              //float qf = market.getShipQualityFactor();
159//              String fleetName = factionForInitialName.getFleetTypeName(type.fleetType); 
160//              CampaignFleetAPI fleet = Global.getFactory().createEmptyFleet(factionId, fleetName, true);
161                //CampaignFleetAPI fleet = createEmptyFleet(factionId, type.fleetType);
162                CampaignFleetAPI fleet = createEmptyFleet(factionIdForShipPicking, type.fleetType, market);
163                switch (type) {
164                case SCOUT:
165                        faction.pickShipAndAddToFleet(ShipRoles.FAST_ATTACK, ShipPickParams.all(), fleet);
166                        if ((float) Math.random() > 0.5f) {
167                                faction.pickShipAndAddToFleet(ShipRoles.FAST_ATTACK, ShipPickParams.all(), fleet);
168                        }
169                        if (stability < (float) Math.random() * 20f) {
170                                faction.pickShipAndAddToFleet(ShipRoles.FAST_ATTACK, ShipPickParams.all(), fleet);
171                        }
172                        break;
173                case PRIVATEER:
174                        faction.pickShipAndAddToFleet(ShipRoles.COMBAT_SMALL, ShipPickParams.all(), fleet);
175                        faction.pickShipAndAddToFleet(ShipRoles.COMBAT_MEDIUM, ShipPickParams.all(), fleet);
176                        if (stability < (float) Math.random() * 20f) {
177                                faction.pickShipAndAddToFleet(ShipRoles.FAST_ATTACK, ShipPickParams.all(), fleet);
178                        }
179                        if (stability < (float) Math.random() * 20f) {
180                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_MEDIUM, ShipPickParams.all(), fleet);
181                        }
182                        if (stability < (float) Math.random() * 20f) {
183                                if ((float) Math.random() > 0.5f) {
184                                        faction.pickShipAndAddToFleet(ShipRoles.COMBAT_FREIGHTER_MEDIUM, ShipPickParams.all(), fleet);
185                                } else {
186                                        faction.pickShipAndAddToFleet(ShipRoles.FREIGHTER_MEDIUM, ShipPickParams.all(), fleet);
187                                }
188                        }
189                        break;
190                case BOUNTY_HUNTER:
191                        faction.pickShipAndAddToFleet(ShipRoles.FAST_ATTACK, ShipPickParams.all(), fleet);
192                        faction.pickShipAndAddToFleet(ShipRoles.FAST_ATTACK, ShipPickParams.all(), fleet);
193                        if ((float) Math.random() > 0.5f) {
194                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_SMALL, ShipPickParams.all(), fleet);
195                        }
196                        if (stability < (float) Math.random() * 20f) {
197                                faction.pickShipAndAddToFleet(ShipRoles.FAST_ATTACK, ShipPickParams.all(), fleet);
198                        }
199                        if (stability < (float) Math.random() * 20f) {
200                                faction.pickShipAndAddToFleet(ShipRoles.FAST_ATTACK, ShipPickParams.all(), fleet);
201                        }
202                        if (stability < (float) Math.random() * 20f) {
203                                faction.pickShipAndAddToFleet(ShipRoles.TANKER_SMALL, ShipPickParams.all(), fleet);
204                        }
205                        break;
206                case PATROL:
207                        if ((float) Math.random() > 0.33f) {
208                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_SMALL, ShipPickParams.all(), fleet);
209                                faction.pickShipAndAddToFleet(ShipRoles.ESCORT_SMALL, ShipPickParams.all(), fleet);
210                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_MEDIUM, ShipPickParams.all(), fleet);
211                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_MEDIUM, ShipPickParams.all(), fleet);
212                        } else {
213                                faction.pickShipAndAddToFleet(ShipRoles.CARRIER_SMALL, ShipPickParams.all(), fleet);
214                                if (stability < (float) Math.random() * 20f) {
215                                        faction.pickShipAndAddToFleet(ShipRoles.CARRIER_SMALL, ShipPickParams.all(), fleet);
216                                }
217                        }
218                        if (stability < (float) Math.random() * 20f) {
219                                faction.pickShipAndAddToFleet(ShipRoles.ESCORT_SMALL, ShipPickParams.all(), fleet);
220                        }
221                        if (stability < (float) Math.random() * 20f) {
222                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_MEDIUM, ShipPickParams.all(), fleet);
223                        }
224                        if (stability < (float) Math.random() * 20f) {
225                                faction.pickShipAndAddToFleet(ShipRoles.ESCORT_SMALL, ShipPickParams.all(), fleet);
226                        }
227                        if (stability < (float) Math.random() * 20f) {
228                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_MEDIUM, ShipPickParams.all(), fleet);
229                        }
230                        if (stability < (float) Math.random() * 20f) {
231                                faction.pickShipAndAddToFleet(ShipRoles.FREIGHTER_MEDIUM, ShipPickParams.all(), fleet);
232                        }
233                        if (stability < (float) Math.random() * 20f) {
234                                faction.pickShipAndAddToFleet(ShipRoles.TANKER_SMALL, ShipPickParams.all(), fleet);
235                        }
236                        break;
237                case ARMADA:
238                        if ((float) Math.random() > 0.33f) {
239                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_SMALL, ShipPickParams.all(), fleet);
240                                faction.pickShipAndAddToFleet(ShipRoles.ESCORT_SMALL, ShipPickParams.all(), fleet);
241                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_MEDIUM, ShipPickParams.all(), fleet);
242                                faction.pickShipAndAddToFleet(ShipRoles.ESCORT_MEDIUM, ShipPickParams.all(), fleet);
243                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_LARGE, ShipPickParams.all(), fleet);
244                        } else {
245                                faction.pickShipAndAddToFleet(ShipRoles.CARRIER_MEDIUM, ShipPickParams.all(), fleet);
246                                if (stability < (float) Math.random() * 20f) {
247                                        faction.pickShipAndAddToFleet(ShipRoles.CARRIER_SMALL, ShipPickParams.all(), fleet);
248                                }
249                        }
250                        if (stability < (float) Math.random() * 20f) {
251                                faction.pickShipAndAddToFleet(ShipRoles.ESCORT_MEDIUM, ShipPickParams.all(), fleet);
252                        }
253                        if (stability < (float) Math.random() * 20f) {
254                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_LARGE, ShipPickParams.all(), fleet);
255                        }
256                        if (stability < (float) Math.random() * 20f) {
257                                faction.pickShipAndAddToFleet(ShipRoles.ESCORT_SMALL, ShipPickParams.all(), fleet);
258                        }
259                        if (stability < (float) Math.random() * 20f) {
260                                faction.pickShipAndAddToFleet(ShipRoles.COMBAT_MEDIUM, ShipPickParams.all(), fleet);
261                        }
262                        if (stability < (float) Math.random() * 20f) {
263                                faction.pickShipAndAddToFleet(ShipRoles.FREIGHTER_MEDIUM, ShipPickParams.all(), fleet);
264                        }
265                        if (stability < (float) Math.random() * 20f) {
266                                faction.pickShipAndAddToFleet(ShipRoles.TANKER_MEDIUM, ShipPickParams.all(), fleet);
267                        }
268                        break;
269                }
270        
271                setAIMode(fleet, true);
272                return fleet;
273        }
274        
275        private static List<String> startingAbilities = null;
276        public static CampaignFleetAPI createEmptyFleet(String factionId, String fleetType, MarketAPI market) {
277                FactionAPI faction = Global.getSector().getFaction(factionId);
278                String fleetName = null;
279                if (fleetType != null) fleetName = faction.getFleetTypeName(fleetType);
280                CampaignFleetAPI fleet = Global.getFactory().createEmptyFleet(factionId, fleetName, true);
281                if (fleetType != null) {
282                        fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_FLEET_TYPE, fleetType);
283                }
284                
285                if (market != null) {
286                        fleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_SOURCE_MARKET, market.getId());
287                }
288                
289                if (startingAbilities == null) {
290                        startingAbilities = new ArrayList<String>();
291                        for (String id : Global.getSettings().getSortedAbilityIds()) {
292                                AbilitySpecAPI spec = Global.getSettings().getAbilitySpec(id);
293                                if (spec.isAIDefault()) {
294                                        startingAbilities.add(id);
295                                }
296                        }
297                }
298                
299                for (String id : startingAbilities) {
300                        fleet.addAbility(id);
301                }
302                
303                return fleet;
304        }
305        
306        
307//      public static final float SUPPLIES_FRACTION = 0.15f;
308//      public static final float FUEL_FRACTION = 0.5f;
309        public static final float SUPPLIES_FRACTION = 0;
310        public static final float FUEL_FRACTION = 0;
311        public static void finishAndSync(CampaignFleetAPI fleet) {
312                setAIMode(fleet, false);
313        }
314        private static void setAIMode(CampaignFleetAPI fleet, boolean addSuppliesAndFuel) {
315//              for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
316//                      //member.setCrewXPLevel(CrewXPLevel.REGULAR);
317//                      member.setCrewXPLevel(member.getCrewXPLevel());
318//              }
319//              fleet.setAIMode(true);
320//              if (addSuppliesAndFuel) {
321//                      float maxCargo = fleet.getCargo().getMaxCapacity();
322//                      float maxFuel = fleet.getCargo().getMaxFuel();
323//                      fleet.getCargo().clear();
324//                      fleet.getCargo().addItems(CargoItemType.RESOURCES, Commodities.SUPPLIES, maxCargo * SUPPLIES_FRACTION);
325//                      fleet.getCargo().addItems(CargoItemType.RESOURCES, Commodities.FUEL, maxFuel * FUEL_FRACTION);
326//              }
327                fleet.forceSync();
328        }
329        
330        
331        public static CampaignFleetAPI createGenericFleet(String factionId, String name, float qualityFactor, int maxFP) {
332                FactionAPI faction = Global.getSector().getFaction(factionId);
333                CampaignFleetAPI fleet = Global.getFactory().createEmptyFleet(factionId, name, true);
334                
335                WeightedRandomPicker<String> main = new WeightedRandomPicker<String>();
336                
337                main.add(ShipRoles.COMBAT_SMALL, 5);
338                main.add(ShipRoles.COMBAT_SMALL, 5);
339                
340                main.add(ShipRoles.ESCORT_SMALL, 6);
341                main.add(ShipRoles.COMBAT_SMALL, 20);
342                main.add(ShipRoles.FAST_ATTACK, 10);
343
344                if (maxFP >= 20) {
345                        main.add(ShipRoles.COMBAT_MEDIUM, 10);
346                        main.add(ShipRoles.ESCORT_MEDIUM, 10);
347                }
348                if (maxFP >= 40) {
349                        main.add(ShipRoles.COMBAT_LARGE, 5);
350                        main.add(ShipRoles.COMBAT_SMALL, 5);
351                }
352                if (maxFP >= 60) {
353                        main.add(ShipRoles.COMBAT_LARGE, 5);
354                        main.add(ShipRoles.COMBAT_CAPITAL, 3);
355                }
356                
357                // add ships and/or fighters, leave some headroom for carriers
358                int failCount = 0;
359                while (fleet.getFleetPoints() < maxFP * 0.75f) {
360                        String role = main.pick();
361                        boolean added = faction.pickShipAndAddToFleet(role, ShipPickParams.all(), fleet) > 0;
362                        if (added) {
363                                failCount = 0;
364                        } else {
365                                failCount++;
366                                if (failCount >= 10) break;
367                        }
368                }
369                
370                // add a flagship if all we'd added before this were fighters
371                if (fleet.getFlagship() == null) {
372                        faction.pickShipAndAddToFleet(ShipRoles.COMBAT_SMALL, ShipPickParams.all(), fleet);
373                        if (fleet.getFlagship() == null) {
374                                FactoryAPI f = Global.getFactory();
375                                FleetMemberAPI flagship = f.createFleetMember(FleetMemberType.SHIP, "tempest_Attack");
376                                fleet.getFleetData().addFleetMember(flagship);
377                        }
378                }
379                
380                int fighterFP = 0;
381                for (FleetMemberAPI member : fleet.getFleetData().getMembersListCopy()) {
382                        if (member.isFighterWing()) {
383                                fighterFP += member.getFleetPointCost();
384                        }
385                }
386                
387                float pointsLeft = maxFP - fleet.getFleetPoints();
388                float carrierPoints = Math.min(pointsLeft, fighterFP * 0.33f);
389                
390                WeightedRandomPicker<String> carriers = new WeightedRandomPicker<String>();
391                if (fighterFP >= 10) {
392                        carriers.add(ShipRoles.CARRIER_SMALL, 5);
393                } 
394                if (fighterFP >= 30) {
395                        carriers.add(ShipRoles.CARRIER_MEDIUM, 5);
396                } 
397                if (fighterFP >= 50) {
398                        carriers.add(ShipRoles.CARRIER_LARGE, 5);
399                }
400                
401                // add carriers, if needed
402                failCount = 0;
403                int startingFP = fleet.getFleetPoints();
404                while (fleet.getFleetPoints() < startingFP + carrierPoints) {
405                        String role = carriers.pick();
406                        boolean added = faction.pickShipAndAddToFleet(role, ShipPickParams.all(), fleet) > 0;
407                        if (added) {
408                                failCount = 0;
409                        } else {
410                                failCount++;
411                                if (failCount >= 10) break;
412                        }
413                }
414                
415                // finish out by adding more ships with any leftover points
416                failCount = 0;
417                while (fleet.getFleetPoints() < maxFP) {
418                        String role = main.pick();
419                        boolean added = faction.pickShipAndAddToFleet(role, ShipPickParams.all(), fleet) > 0;
420                        if (added) {
421                                failCount = 0;
422                        } else {
423                                failCount++;
424                                if (failCount >= 10) break;
425                        }
426                }
427                
428                finishAndSync(fleet);
429                
430                return fleet;
431        }
432        
433        
434        public static void addGenericCombatShips(CampaignFleetAPI fleet, FactionAPI faction, MarketAPI market, int extraFP) {
435                float qualityFactor = market.getShipQualityFactor();
436                
437                WeightedRandomPicker<String> main = new WeightedRandomPicker<String>();
438                
439                main.add(ShipRoles.COMBAT_SMALL, 5);
440                main.add(ShipRoles.COMBAT_SMALL, 5);
441                
442                main.add(ShipRoles.ESCORT_SMALL, 6);
443                main.add(ShipRoles.COMBAT_SMALL, 20);
444                main.add(ShipRoles.FAST_ATTACK, 10);
445
446                if (extraFP >= 20) {
447                        main.add(ShipRoles.COMBAT_MEDIUM, 10);
448                        main.add(ShipRoles.ESCORT_MEDIUM, 10);
449                }
450                if (extraFP >= 40) {
451                        main.add(ShipRoles.COMBAT_LARGE, 5);
452                        main.add(ShipRoles.COMBAT_SMALL, 5);
453                }
454                if (extraFP >= 60) {
455                        main.add(ShipRoles.COMBAT_LARGE, 5);
456                        main.add(ShipRoles.COMBAT_CAPITAL, 3);
457                }
458                
459                // add ships and/or fighters, leave some headroom for carriers
460                int failCount = 0;
461                int starting = fleet.getFleetPoints();
462                while (fleet.getFleetPoints() < starting + extraFP) {
463                        String role = main.pick();
464                        boolean added = faction.pickShipAndAddToFleet(role, ShipPickParams.all(), fleet) > 0;
465                        if (added) {
466                                failCount = 0;
467                        } else {
468                                failCount++;
469                                if (failCount >= 10) break;
470                        }
471                }
472        }
473}
474
475
476
477
478
479
480
481
482
483
484
485
486
487