001package com.fs.starfarer.api.impl.campaign.intel.bases; 002 003import java.util.Random; 004 005import com.fs.starfarer.api.EveryFrameScript; 006import com.fs.starfarer.api.Global; 007import com.fs.starfarer.api.campaign.FactionAPI; 008import com.fs.starfarer.api.campaign.StarSystemAPI; 009import com.fs.starfarer.api.impl.campaign.Tuning; 010import com.fs.starfarer.api.impl.campaign.ids.Factions; 011import com.fs.starfarer.api.impl.campaign.ids.Tags; 012import com.fs.starfarer.api.impl.campaign.intel.BaseEventManager; 013import com.fs.starfarer.api.impl.campaign.intel.bases.PirateBaseIntel.PirateBaseTier; 014import com.fs.starfarer.api.util.Misc; 015import com.fs.starfarer.api.util.WeightedRandomPicker; 016 017public class PirateBaseManager extends BaseEventManager { 018 019 public static final String KEY = "$core_pirateBaseManager"; 020 021 public static final float CHECK_DAYS = 10f; 022 public static final float CHECK_PROB = 0.5f; 023 024 025 public static PirateBaseManager getInstance() { 026 Object test = Global.getSector().getMemoryWithoutUpdate().get(KEY); 027 return (PirateBaseManager) test; 028 } 029 030 protected long start = 0; 031 protected float extraDays = 0; 032 033 protected int numDestroyed = 0; 034 protected int numSpawnChecksToSkip = 0; 035 036 public PirateBaseManager() { 037 super(); 038 Global.getSector().getMemoryWithoutUpdate().set(KEY, this); 039 start = Global.getSector().getClock().getTimestamp(); 040 } 041 042 @Override 043 protected int getMinConcurrent() { 044 return Global.getSettings().getInt("minPirateBases"); 045 } 046 @Override 047 protected int getMaxConcurrent() { 048 return Global.getSettings().getInt("maxPirateBases"); 049 } 050 051 @Override 052 protected float getBaseInterval() { 053 return CHECK_DAYS; 054 } 055 056 057 @Override 058 public void advance(float amount) { 059 super.advance(amount); 060 } 061 062 063 064 065 066 protected Random random = new Random(); 067 @Override 068 protected EveryFrameScript createEvent() { 069 if (numSpawnChecksToSkip > 0) { 070 numSpawnChecksToSkip--; 071 return null; 072 } 073 074 if (random.nextFloat() < CHECK_PROB) return null; 075 076 StarSystemAPI system = pickSystemForPirateBase(); 077 if (system == null) return null; 078 079 //PirateBaseIntel intel = new PirateBaseIntel(system, Factions.PIRATES, PirateBaseTier.TIER_5_3MODULE); 080 //PirateBaseIntel intel = new PirateBaseIntel(system, Factions.PIRATES, PirateBaseTier.TIER_3_2MODULE); 081 PirateBaseTier tier = pickTier(); 082 083 //tier = PirateBaseTier.TIER_5_3MODULE; 084 085 String factionId = pickPirateFaction(); 086 if (factionId == null) return null; 087 088 PirateBaseIntel intel = new PirateBaseIntel(system, factionId, tier); 089 if (intel.isDone()) intel = null; 090 091 return intel; 092 } 093 094 public String pickPirateFaction() { 095 WeightedRandomPicker<String> picker = new WeightedRandomPicker<String>(random); 096 for (FactionAPI faction : Global.getSector().getAllFactions()) { 097 if (faction.getCustomBoolean(Factions.CUSTOM_MAKES_PIRATE_BASES)) { 098 picker.add(faction.getId(), 1f); 099 } 100 } 101 return picker.pick(); 102 } 103 104 public float getUnadjustedDaysSinceStart() { 105 float days = Global.getSector().getClock().getElapsedDaysSince(start); 106 return days; 107 } 108 109 public float getDaysSinceStart() { 110 float days = Global.getSector().getClock().getElapsedDaysSince(start) + extraDays; 111 if (Misc.isFastStartExplorer()) { 112 days += Tuning.FAST_START_EXTRA_DAYS - 30f; 113 } else if (Misc.isFastStart()) { 114 days += Tuning.FAST_START_EXTRA_DAYS + 60f; 115 } 116 return days; 117 } 118 119 /** 120 * 0 at six months (depending on start option chosen), goes up to 1 two years later. 121 * @return 122 */ 123 public float getStandardTimeFactor() { 124 float timeFactor = (PirateBaseManager.getInstance().getDaysSinceStart() - Tuning.FAST_START_EXTRA_DAYS) / (Tuning.DAYS_UNTIL_FULL_TIME_FACTOR); 125 if (timeFactor < 0) timeFactor = 0; 126 if (timeFactor > 1) timeFactor = 1; 127 return timeFactor; 128 } 129 130 public float getExtraDays() { 131 return extraDays; 132 } 133 134 public void setExtraDays(float extraDays) { 135 this.extraDays = extraDays; 136 } 137 138 protected PirateBaseTier pickTier() { 139 float days = getDaysSinceStart(); 140 141 days += numDestroyed * 200; 142 143 WeightedRandomPicker<PirateBaseTier> picker = new WeightedRandomPicker<PirateBaseTier>(); 144 145 if (days < 360) { 146 picker.add(PirateBaseTier.TIER_1_1MODULE, 10f); 147 picker.add(PirateBaseTier.TIER_2_1MODULE, 10f); 148 } else if (days < 720f) { 149 picker.add(PirateBaseTier.TIER_2_1MODULE, 10f); 150 picker.add(PirateBaseTier.TIER_3_2MODULE, 10f); 151 } else if (days < 1080f) { 152 picker.add(PirateBaseTier.TIER_3_2MODULE, 10f); 153 picker.add(PirateBaseTier.TIER_4_3MODULE, 10f); 154 } else { 155 picker.add(PirateBaseTier.TIER_3_2MODULE, 10f); 156 picker.add(PirateBaseTier.TIER_4_3MODULE, 10f); 157 picker.add(PirateBaseTier.TIER_5_3MODULE, 10f); 158 } 159 160 161// if (true) { 162// picker.clear(); 163// picker.add(PirateBaseTier.TIER_1_1MODULE, 10f); 164// picker.add(PirateBaseTier.TIER_2_1MODULE, 10f); 165// picker.add(PirateBaseTier.TIER_3_2MODULE, 10f); 166// picker.add(PirateBaseTier.TIER_4_3MODULE, 10f); 167// picker.add(PirateBaseTier.TIER_5_3MODULE, 10f); 168// } 169 170 171 return picker.pick(); 172 } 173 174 public static String RECENTLY_USED_FOR_BASE = "$core_recentlyUsedForBase"; 175 public static float genBaseUseTimeout() { 176 return 120f + 60f * (float) Math.random(); 177 } 178 public static void markRecentlyUsedForBase(StarSystemAPI system) { 179 if (system != null && system.getCenter() != null) { 180 system.getCenter().getMemoryWithoutUpdate().set(RECENTLY_USED_FOR_BASE, true, genBaseUseTimeout()); 181 } 182 } 183 184 protected StarSystemAPI pickSystemForPirateBase() { 185 WeightedRandomPicker<StarSystemAPI> far = new WeightedRandomPicker<StarSystemAPI>(random); 186 WeightedRandomPicker<StarSystemAPI> picker = new WeightedRandomPicker<StarSystemAPI>(random); 187 188 for (StarSystemAPI system : Global.getSector().getStarSystems()) { 189 if (system.hasPulsar()) continue; 190 if (system.hasTag(Tags.THEME_SPECIAL)) continue; 191 if (system.hasTag(Tags.THEME_HIDDEN)) continue; 192 193 float days = Global.getSector().getClock().getElapsedDaysSince(system.getLastPlayerVisitTimestamp()); 194 if (days < 45f) continue; 195 if (system.getCenter().getMemoryWithoutUpdate().contains(RECENTLY_USED_FOR_BASE)) continue; 196 197 float weight = 0f; 198 if (system.hasTag(Tags.THEME_MISC_SKIP)) { 199 weight = 1f; 200 } else if (system.hasTag(Tags.THEME_MISC)) { 201 weight = 3f; 202 } else if (system.hasTag(Tags.THEME_REMNANT_NO_FLEETS)) { 203 weight = 3f; 204 } else if (system.hasTag(Tags.THEME_REMNANT_DESTROYED)) { 205 weight = 3f; 206 } else if (system.hasTag(Tags.THEME_RUINS)) { 207 weight = 5f; 208 } else if (system.hasTag(Tags.THEME_CORE_UNPOPULATED)) { 209 //weight = 1f; 210 weight = 0f; 211 } 212 if (weight <= 0f) continue; 213 214 float usefulStuff = system.getCustomEntitiesWithTag(Tags.OBJECTIVE).size() + 215 system.getCustomEntitiesWithTag(Tags.STABLE_LOCATION).size(); 216 if (usefulStuff <= 0) continue; 217 218 if (Misc.hasPulsar(system)) continue; 219 if (Misc.getMarketsInLocation(system).size() > 0) continue; 220 221 float dist = system.getLocation().length(); 222 223 224 225// float distMult = 1f - dist / 20000f; 226// if (distMult > 1f) distMult = 1f; 227// if (distMult < 0.1f) distMult = 0.1f; 228 229 float distMult = 1f; 230 231 if (dist > 36000f) { 232 far.add(system, weight * usefulStuff * distMult); 233 } else { 234 picker.add(system, weight * usefulStuff * distMult); 235 } 236 } 237 238 if (picker.isEmpty()) { 239 picker.addAll(far); 240 } 241 242 return picker.pick(); 243 } 244 245 public int getNumDestroyed() { 246 return numDestroyed; 247 } 248 249 public void setNumDestroyed(int numDestroyed) { 250 this.numDestroyed = numDestroyed; 251 } 252 253 public void incrDestroyed() { 254 numDestroyed++; 255 numSpawnChecksToSkip = Math.max(numSpawnChecksToSkip, (Tuning.PIRATE_BASE_MIN_TIMEOUT_MONTHS + 256 Misc.random.nextInt(Tuning.PIRATE_BASE_MAX_TIMEOUT_MONTHS - Tuning.PIRATE_BASE_MIN_TIMEOUT_MONTHS + 1)) 257 * 3); // checks happen every 10 days on average, *3 to get months 258 } 259 260} 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275