001package com.fs.starfarer.api.impl.campaign.fleets; 002 003import java.util.Random; 004 005import com.fs.starfarer.api.Global; 006import com.fs.starfarer.api.campaign.CampaignFleetAPI; 007import com.fs.starfarer.api.campaign.SectorEntityToken; 008import com.fs.starfarer.api.campaign.econ.MarketAPI; 009import com.fs.starfarer.api.impl.campaign.fleets.FleetFactory.MercType; 010import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.OptionalFleetData; 011import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteData; 012import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteSegment; 013import com.fs.starfarer.api.impl.campaign.ids.Factions; 014import com.fs.starfarer.api.impl.campaign.ids.Tags; 015import com.fs.starfarer.api.impl.campaign.intel.SystemBountyManager; 016import com.fs.starfarer.api.util.Misc; 017import com.fs.starfarer.api.util.WeightedRandomPicker; 018 019public class MercFleetManagerV2 extends BaseRouteFleetManager { 020 021 public static final Integer ROUTE_PREPARE = 1; 022 public static final Integer ROUTE_TRAVEL = 2; 023 public static final Integer ROUTE_PATROL = 3; 024 public static final Integer ROUTE_RETURN = 4; 025 public static final Integer ROUTE_STAND_DOWN = 5; 026 027 public MercFleetManagerV2() { 028 super(0.5f, 1.5f); 029 } 030 031 @Override 032 protected void addRouteFleetIfPossible() { 033 MarketAPI from = pickMarket(); 034 if (from == null) return; 035 036 MarketAPI to = pickNearbyMarketToDefend(from); 037 if (to == null) return; 038 039 Long seed = new Random().nextLong(); 040 String id = getRouteSourceId(); 041 042 OptionalFleetData extra = new OptionalFleetData(from); 043 044 RouteData route = RouteManager.getInstance().addRoute(id, from, seed, extra, this); 045 046 float orbitDays = 2f + (float) Math.random() * 3f; 047 float deorbitDays = 2f + (float) Math.random() * 3f; 048 float patrolDays = 2f + (float) Math.random() * 3f; 049 050 SectorEntityToken target = to.getPrimaryEntity(); 051 if ((float) Math.random() > 0.25f && to.getStarSystem() != null) { 052 if ((float) Math.random() > 0.25f) { 053 target = to.getStarSystem().getCenter(); 054 } else { 055 target = to.getStarSystem().getHyperspaceAnchor(); 056 } 057 } 058 059 if (from.getContainingLocation() == to.getContainingLocation() && !from.getContainingLocation().isHyperspace()) { 060 route.addSegment(new RouteSegment(ROUTE_PREPARE, orbitDays, from.getPrimaryEntity())); 061 route.addSegment(new RouteSegment(ROUTE_PATROL, patrolDays, target)); 062 route.addSegment(new RouteSegment(ROUTE_STAND_DOWN, deorbitDays, from.getPrimaryEntity())); 063 } else { 064 route.addSegment(new RouteSegment(ROUTE_PREPARE, orbitDays, from.getPrimaryEntity())); 065 route.addSegment(new RouteSegment(ROUTE_TRAVEL, from.getPrimaryEntity(), to.getPrimaryEntity())); 066 route.addSegment(new RouteSegment(ROUTE_PATROL, patrolDays, target)); 067 route.addSegment(new RouteSegment(ROUTE_RETURN, to.getPrimaryEntity(), from.getPrimaryEntity())); 068 route.addSegment(new RouteSegment(ROUTE_STAND_DOWN, deorbitDays, from.getPrimaryEntity())); 069 } 070 } 071 072 public MercType pickFleetType(Random random) { 073 WeightedRandomPicker<MercType> picker = new WeightedRandomPicker<MercType>(random); 074 picker.add(MercType.SCOUT, 10f); 075 picker.add(MercType.BOUNTY_HUNTER, 10f); 076 picker.add(MercType.PRIVATEER, 10f); 077 picker.add(MercType.PATROL, 10f); 078 picker.add(MercType.ARMADA, 3f); 079 MercType type = picker.pick(); 080 return type; 081 } 082 083 public CampaignFleetAPI spawnFleet(RouteData route) { 084 Random random = route.getRandom(); 085 086 MercType type = pickFleetType(random); 087 088 float combat = 0f; 089 float tanker = 0f; 090 float freighter = 0f; 091 String fleetType = type.fleetType; 092 switch (type) { 093 case SCOUT: 094 combat = Math.round(1f + random.nextFloat() * 2f); 095 break; 096 case PRIVATEER: 097 case BOUNTY_HUNTER: 098 combat = Math.round(3f + random.nextFloat() * 2f); 099 break; 100 case PATROL: 101 combat = Math.round(9f + random.nextFloat() * 3f); 102 tanker = Math.round(random.nextFloat()) * 5f; 103 break; 104 case ARMADA: 105 combat = Math.round(10f + random.nextFloat() * 4f); 106 tanker = Math.round(random.nextFloat()) * 10f; 107 freighter = Math.round(random.nextFloat()) * 10f; 108 break; 109 } 110 111 combat *= 5f; 112 113 FleetParamsV3 params = new FleetParamsV3( 114 route.getMarket(), 115 null, 116 Factions.INDEPENDENT, 117 route.getQualityOverride() + 0.2f, 118 fleetType, 119 combat, // combatPts 120 freighter, // freighterPts 121 tanker, // tankerPts 122 0f, // transportPts 123 0f, // linerPts 124 0f, // utilityPts 125 0f // qualityMod 126 ); 127 params.timestamp = route.getTimestamp(); 128 params.random = random; 129 CampaignFleetAPI fleet = FleetFactoryV3.createFleet(params); 130 131 if (fleet == null || fleet.isEmpty()) return null; 132 133 route.getMarket().getContainingLocation().addEntity(fleet); 134 fleet.setFacing((float) Math.random() * 360f); 135 // this will get overridden by the patrol assignment AI, depending on route-time elapsed etc 136 fleet.setLocation(route.getMarket().getPrimaryEntity().getLocation().x, route.getMarket().getPrimaryEntity().getLocation().x); 137 138 MercAssignmentAIV2 ai = new MercAssignmentAIV2(fleet, route); 139 fleet.addScript(ai); 140 141 142 return fleet; 143 } 144 145 146 protected MarketAPI pickMarket() { 147 WeightedRandomPicker<MarketAPI> picker = new WeightedRandomPicker<MarketAPI>(); 148 for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) { 149 if (market.isHidden()) continue; 150 if (market.getFactionId().equals(Factions.PIRATES)) continue; 151 if (market.getFaction().isHostileTo(Factions.INDEPENDENT)) continue; 152 153 if (!market.hasSpaceport()) continue; 154 155 if (market.getStarSystem() != null && market.getStarSystem().hasTag(Tags.SYSTEM_CUT_OFF_FROM_HYPER)) { 156 continue; 157 } 158 159 if (market.getDaysInExistence() < Global.getSettings().getFloat("minMarketExistenceDaysForMercs")) { 160 continue; 161 } 162 if (market.getSize() < Global.getSettings().getFloat("minMarketSizeForMercs")) { 163 continue; 164 } 165 166 167 float mult = Misc.getSpawnChanceMult(market.getLocationInHyperspace()); 168 float w = market.getStabilityValue() + market.getSize(); 169 170 w *= mult; 171 picker.add(market, w); 172 } 173 return picker.pick(); 174 } 175 176 177 protected MarketAPI pickNearbyMarketToDefend(MarketAPI source) { 178 WeightedRandomPicker<MarketAPI> picker = new WeightedRandomPicker<MarketAPI>(); 179 180 //CampaignEventManagerAPI eventManager = Global.getSector().getEventManager(); 181 182 for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) { 183 //if (market.getFactionId().equals(Factions.PIRATES)) continue; 184 if (market.getFaction().isHostileTo(Factions.INDEPENDENT)) continue; 185 if (market.getStarSystem() == null) continue; 186 if (market.isHidden()) continue; 187 188 if (market.getStarSystem() != null && market.getStarSystem().hasTag(Tags.SYSTEM_CUT_OFF_FROM_HYPER)) { 189 continue; 190 } 191 192 float dist = Misc.getDistance(market.getLocationInHyperspace(), source.getLocationInHyperspace()); 193 if (dist < 1000) dist = 1000; 194 float weight = 10000f / dist; 195 196 if (SystemBountyManager.getInstance().isActive(market)) { 197 weight *= 5f; 198 } 199 200 picker.add(market, weight); 201 } 202 MarketAPI market = picker.pick(); 203// if (market == null) return null; 204// return market.getStarSystem(); 205 return market; 206 } 207 208 209 210 @Override 211 protected int getMaxFleets() { 212 return (int) Global.getSettings().getFloat("maxMercFleets"); 213 } 214 215 @Override 216 protected String getRouteSourceId() { 217 return "mercs_global"; 218 } 219 220 public void reportAboutToBeDespawnedByRouteManager(RouteData route) { 221 222 } 223 224 public boolean shouldCancelRouteAfterDelayCheck(RouteData route) { 225 return false; 226 } 227 228 public boolean shouldRepeat(RouteData route) { 229 return false; 230 } 231 232 233 234} 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249