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