001package com.fs.starfarer.api.impl.campaign.fleets.misc; 002 003import java.util.ArrayList; 004import java.util.List; 005import java.util.Random; 006 007import org.lwjgl.util.vector.Vector2f; 008 009import com.fs.starfarer.api.Global; 010import com.fs.starfarer.api.campaign.BattleAPI; 011import com.fs.starfarer.api.campaign.CampaignFleetAPI; 012import com.fs.starfarer.api.campaign.SectorEntityToken; 013import com.fs.starfarer.api.campaign.econ.MarketAPI; 014import com.fs.starfarer.api.impl.campaign.fleets.RouteManager; 015import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteData; 016import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteSegment; 017import com.fs.starfarer.api.impl.campaign.fleets.misc.MiscFleetRouteManager.MiscRouteData; 018import com.fs.starfarer.api.impl.campaign.ids.Conditions; 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.missions.DelayedFleetEncounter; 024import com.fs.starfarer.api.impl.campaign.missions.FleetCreatorMission; 025import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.FleetQuality; 026import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.FleetSize; 027import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.OfficerNum; 028import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithTriggers.OfficerQuality; 029import com.fs.starfarer.api.impl.campaign.missions.hub.MissionFleetAutoDespawn; 030import com.fs.starfarer.api.impl.campaign.shared.SharedData; 031import com.fs.starfarer.api.util.Misc; 032import com.fs.starfarer.api.util.WeightedRandomPicker; 033 034public class MiscPilgrimFleetCreator extends BaseMiscFleetCreatorPlugin { 035 036 public String SHRINE_LIST_KEY = "shrine_list_key"; 037 038 039 @Override 040 public float getFrequency() { 041 return Global.getSettings().getFloat("miscFleetPilgrimFrequency"); 042 } 043 044 @Override 045 public int getMaxFleetsForThisCreator() { 046 return Global.getSettings().getInt("miscFleetPilgrimMaxFleets"); 047 } 048 049 050 051 public List<SectorEntityToken> getShrines(MiscFleetRouteManager manager) { 052 List<SectorEntityToken> shrines = (List<SectorEntityToken>) manager.getData().get(SHRINE_LIST_KEY); 053 if (shrines == null) { 054 shrines = Global.getSector().getEntitiesWithTag(Tags.LUDDIC_SHRINE); 055 manager.getData().put(SHRINE_LIST_KEY, shrines); 056 } 057 return shrines; 058 } 059 060 061 @Override 062 public MiscRouteData createRouteParams(MiscFleetRouteManager manager, Random random) { 063 MarketAPI from = pickSourceMarket(manager); 064 if (from == null) return null; 065 SectorEntityToken to = pickDestShrine(manager, from); 066 if (to == null) return null; 067 068// from = Global.getSector().getEconomy().getMarket("chalcedon"); 069// to = Global.getSector().getEconomy().getMarket("eochu_bres").getPrimaryEntity(); 070// to = Global.getSector().getEntityById("beholder_station"); 071 072 MiscRouteData result = createData(from, to); 073 074 return result; 075 } 076 077 078 @Override 079 public CampaignFleetAPI createFleet(MiscFleetRouteManager manager, RouteData route, Random random) { 080 MiscRouteData data = (MiscRouteData) route.getCustom(); 081 082 FleetCreatorMission m = new FleetCreatorMission(random); 083 m.beginFleet(); 084 085 086 m.triggerCreateFleet(FleetSize.MEDIUM, FleetQuality.LOWER, data.factionId, 087 FleetTypes.SHRINE_PILGRIMS, data.from.getLocationInHyperspace()); 088 m.triggerSetFleetOfficers(OfficerNum.FC_ONLY, OfficerQuality.LOWER); 089 m.triggerSetFleetSizeFraction(data.size * 0.5f * (0.5f + random.nextFloat() * 0.5f)); 090 m.triggerFleetSetNoFactionInName(); 091 m.triggerSetTraderFleet(); 092 m.triggerSetFleetComposition(0f, 0f, 0f, 1f, 0f); 093 m.triggerSetFleetMemoryValue(MemFlags.MEMORY_KEY_SOURCE_MARKET, data.from); 094 m.triggerSetFleetMemoryValue("$destShrine", data.to.getId()); 095 m.triggerSetFleetMemoryValue(MemFlags.SHRINE_PILGRIM_FLEET, true); 096 097 CampaignFleetAPI fleet = m.createFleet(); 098 fleet.removeScriptsOfClass(MissionFleetAutoDespawn.class); 099 100 return fleet; 101 } 102 103 104 public MiscRouteData createData(MarketAPI from, SectorEntityToken to) { 105 MiscRouteData data = new MiscRouteData(getId()); 106 data.from = from; 107 data.to = to; 108 109 if (from.getFaction().isHostileTo(Factions.LUDDIC_CHURCH)) { 110 data.factionId = Factions.INDEPENDENT; 111 } else { 112 data.factionId = Factions.LUDDIC_CHURCH; 113 } 114 115 116 MarketAPI market = to.getMarket(); 117 boolean realMarket = market != null && !market.isPlanetConditionMarketOnly(); 118 if (realMarket && market.getFaction().isHostileTo(from.getFaction())) { 119 if (market.getFaction().isHostileTo(data.factionId)) { 120 data.smuggling = true; 121 } 122// if (market.getFaction().isHostileTo(Factions.INDEPENDENT)) { 123// data.smuggling = true; 124// } else { 125// data.factionId = Factions.INDEPENDENT; 126// } 127 } 128 129 130 float sizeBasis; 131 if (realMarket) { 132 sizeBasis = market.getSize() + from.getSize(); 133 } else { 134 sizeBasis = from.getSize() * 0.5f; 135 } 136 data.size = sizeBasis / 40f; 137 138 return data; 139 } 140 141 public MarketAPI pickSourceMarket(MiscFleetRouteManager manager) { 142 143 WeightedRandomPicker<MarketAPI> markets = new WeightedRandomPicker<MarketAPI>(manager.getRandom()); 144 for (MarketAPI market : Global.getSector().getEconomy().getMarketsCopy()) { 145 if (market.isHidden()) continue; 146 if (!market.hasSpaceport()) continue; // markets w/o spaceports don't launch fleets 147 if (manager.getTimeout(getId()).contains(market.getId())) continue; 148 if (market.getContainingLocation().hasTag(Tags.SYSTEM_CUT_OFF_FROM_HYPER)) continue; 149 if (market.getFaction().isHostileTo(Factions.INDEPENDENT) && 150 market.getFaction().isHostileTo(Factions.LUDDIC_CHURCH)) { 151 continue; 152 } 153 154 // use this for shrines also 155 if (SharedData.getData().getMarketsWithoutTradeFleetSpawn().contains(market.getId())) continue; 156 157 float distLY = Misc.getDistanceToPlayerLY(market.getPrimaryEntity()); 158 float mult = 1f - Math.min(0.99f, distLY / 10f); 159 160 String fid = market.getFactionId(); 161 if (Factions.LUDDIC_CHURCH.equals(fid) || 162 Factions.LUDDIC_PATH.equals(fid) || 163 Factions.KOL.equals(fid)) { 164 mult *= 10f; 165 } 166 167 markets.add(market, market.getSize() * mult); 168 169// if (market.getName().toLowerCase().equals("jannow")) { 170// markets.add(market, 100000f); 171// } 172 } 173 return markets.pick(); 174 } 175 176 public SectorEntityToken pickDestShrine(MiscFleetRouteManager manager, MarketAPI from) { 177 if (from == null) return null; 178 179 WeightedRandomPicker<SectorEntityToken> picker = new WeightedRandomPicker<SectorEntityToken>(manager.getRandom()); 180 181 for (SectorEntityToken shrine : new ArrayList<SectorEntityToken>(getShrines(manager))) { 182 if (!shrine.isAlive()) continue; 183 if (shrine.getContainingLocation().hasTag(Tags.SYSTEM_CUT_OFF_FROM_HYPER)) continue; 184 185 MarketAPI market = shrine.getMarket(); 186 boolean realMarket = market != null && !market.isPlanetConditionMarketOnly(); 187 if (realMarket) { 188 if (market.hasCondition(Conditions.DECIVILIZED)) continue; 189 if (market.getFaction().isHostileTo(Factions.INDEPENDENT) && 190 market.getFaction().isHostileTo(Factions.LUDDIC_CHURCH)) { 191 continue; 192 } 193 } 194 195 float mult = 1f; 196 if (realMarket) { 197 mult = 10f * market.getSize(); 198 } else { 199 //mult *= 100f; 200 } 201 picker.add(shrine, mult); 202 } 203 204 return picker.pick(); 205 } 206 207 @Override 208 public void reportBattleOccurred(MiscFleetRouteManager manager, CampaignFleetAPI fleet, CampaignFleetAPI primaryWinner, BattleAPI battle) { 209 RouteData route = RouteManager.getInstance().getRoute(manager.getRouteSourceId(), fleet); 210 if (route == null || !(route.getCustom() instanceof MiscRouteData)) return; 211 212 if (route.isExpired()) return; 213 if (!battle.isPlayerInvolved()) return; 214 215 // player was involved, no the opposite side of the pilgrim fleet 216 if (battle.getNonPlayerSideSnapshot().contains(fleet)) { 217 MiscRouteData data = (MiscRouteData) route.getCustom(); 218 219 DelayedFleetEncounter e = new DelayedFleetEncounter(new Random(), "luddicPilgrims"); 220 e.setDelayShort(); 221 //e.setDelayNone(); 222 e.setLocationCoreOnly(true, Factions.LUDDIC_CHURCH); 223 e.beginCreate(); 224 e.triggerCreateFleet(FleetSize.MEDIUM, FleetQuality.DEFAULT, Factions.LUDDIC_CHURCH, FleetTypes.PATROL_MEDIUM, new Vector2f()); 225 e.triggerSetFleetSizeFraction(Math.min(1f, data.size * 3f)); 226 e.autoAdjustFleetTypeName(); 227 e.triggerSetPatrol(); 228 e.triggerSetStandardAggroInterceptFlags(); 229 e.triggerSetFleetGenericHailPermanent("PilgrimRevengeHail"); 230 e.endCreate(); 231 } 232 } 233 234 235 public String getStartingActionText(CampaignFleetAPI fleet, RouteSegment segment, MiscRouteData data) { 236 return "preparing for pilgrimage to shrine on " + data.to.getName(); 237 } 238 239 public String getEndingActionText(CampaignFleetAPI fleet, RouteSegment segment, MiscRouteData data) { 240 return "disembarking pilgrims at " + data.from.getName(); 241 } 242 243 public String getTravelToDestActionText(CampaignFleetAPI fleet, RouteSegment segment, MiscRouteData data) { 244 return "taking pilgrims to shrine on " + data.to.getName(); 245 } 246 247 public String getTravelReturnActionText(CampaignFleetAPI fleet, RouteSegment segment, MiscRouteData data) { 248 return "returning pilgrims to " + data.from.getName(); 249 } 250 251 public String getAtDestUnloadActionText(CampaignFleetAPI fleet, RouteSegment segment, MiscRouteData data) { 252 return "disembarking pilgrims at shrine on " + data.to.getName(); 253 } 254 255 public String getAtDestLoadActionText(CampaignFleetAPI fleet, RouteSegment segment, MiscRouteData data) { 256 return "embarking pilgrims for return voyage to " + data.from.getName(); 257 } 258 259}