001package com.fs.starfarer.api.impl.campaign.fleets.misc;
002
003import java.util.ArrayList;
004import java.util.LinkedHashMap;
005import java.util.List;
006import java.util.Map;
007import java.util.Random;
008
009import org.apache.log4j.Logger;
010
011import com.fs.starfarer.api.Global;
012import com.fs.starfarer.api.campaign.BattleAPI;
013import com.fs.starfarer.api.campaign.CampaignEventListener.FleetDespawnReason;
014import com.fs.starfarer.api.campaign.CampaignFleetAPI;
015import com.fs.starfarer.api.campaign.SectorEntityToken;
016import com.fs.starfarer.api.campaign.econ.MarketAPI;
017import com.fs.starfarer.api.campaign.listeners.FleetEventListener;
018import com.fs.starfarer.api.impl.campaign.fleets.BaseRouteFleetManager;
019import com.fs.starfarer.api.impl.campaign.fleets.RouteManager;
020import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.OptionalFleetData;
021import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteData;
022import com.fs.starfarer.api.impl.campaign.fleets.RouteManager.RouteSegment;
023import com.fs.starfarer.api.util.IntervalUtil;
024import com.fs.starfarer.api.util.TimeoutTracker;
025import com.fs.starfarer.api.util.WeightedRandomPicker;
026
027public class MiscFleetRouteManager extends BaseRouteFleetManager implements FleetEventListener {
028        
029        public static List<MiscFleetCreatorPlugin> CREATORS = new ArrayList<MiscFleetCreatorPlugin>();
030        static {
031                CREATORS.add(new MiscPilgrimFleetCreator());
032                CREATORS.add(new MiscAcademyFleetCreator());
033        }
034        
035        public static class MiscRouteData {
036                public String creatorId;
037                public boolean smuggling = false;
038                public MarketAPI from;
039                public SectorEntityToken to;
040                public float size;
041                public String factionId;
042                public Object custom;
043                public MiscRouteData(String creatorId) {
044                        this.creatorId = creatorId;
045                }
046                
047        }
048        
049        
050        public static final Integer ROUTE_SRC_LOAD = 1;
051        public static final Integer ROUTE_TRAVEL_DST = 2;
052        public static final Integer ROUTE_DST_UNLOAD = 5;
053        public static final Integer ROUTE_DST_LOAD = 6;
054        public static final Integer ROUTE_TRAVEL_BACK_WS = 7;
055        public static final Integer ROUTE_RESUPPLY_BACK_WS = 8;
056        public static final Integer ROUTE_TRAVEL_SRC = 9;
057        public static final Integer ROUTE_SRC_UNLOAD = 10;
058        
059        public static final String SOURCE_ID = "misc_fleet_";
060        public static Logger log = Global.getLogger(MiscFleetRouteManager.class);
061        
062        
063        //protected TimeoutTracker<String> recentlySentPilgrims = new TimeoutTracker<String>();
064        protected Map<String, TimeoutTracker<String>> recentlySent = new LinkedHashMap<String, TimeoutTracker<String>>();
065        protected Random random = new Random();
066        transient protected LinkedHashMap data = new LinkedHashMap();
067        
068        public MiscFleetRouteManager() {
069                super(1f, 14f); // whatever values; overridden below
070                
071                float min = Global.getSettings().getFloatFromArray("miscSpawnInterval", 0);
072                float max = Global.getSettings().getFloatFromArray("miscSpawnInterval", 1);
073                interval = new IntervalUtil(min, max);
074        }
075        
076        protected Object readResolve() {
077                if (recentlySent == null) {
078                        recentlySent = new LinkedHashMap<String, TimeoutTracker<String>>();
079                }
080                if (data == null) {
081                        data = new LinkedHashMap();
082                }
083                return this;
084        }
085        
086        
087        
088        public Random getRandom() {
089                return random;
090        }
091
092        public TimeoutTracker<String> getTimeout(String creatorId) {
093                TimeoutTracker<String> result = recentlySent.get(creatorId);
094                if (result == null) {
095                        result = new TimeoutTracker<String>();
096                        recentlySent.put(creatorId, result);
097                }
098                return result;
099        }
100
101        @Override
102        public void advance(float amount) {
103                
104                //super.advance(amount * 10f);
105                super.advance(amount);
106                
107                float days = Global.getSector().getClock().convertToDays(amount);
108                for (TimeoutTracker<String> curr : recentlySent.values()) {
109                        curr.advance(days);
110                }
111        }
112
113        protected String getRouteSourceId() {
114                return SOURCE_ID;
115        }
116        
117        protected int getMaxFleets() {
118                //if (true) return 1;
119                int numMarkets = Global.getSector().getEconomy().getNumMarkets();
120                int maxBasedOnMarkets = numMarkets * 1;
121                return Math.min(maxBasedOnMarkets, Global.getSettings().getInt("maxMiscFleets"));
122        }
123        
124        
125        protected void addRouteFleetIfPossible() {
126                
127                WeightedRandomPicker<MiscFleetCreatorPlugin> picker = new WeightedRandomPicker<MiscFleetCreatorPlugin>(random);
128                for (MiscFleetCreatorPlugin curr : CREATORS) {
129                        int count = 0;
130                        for (RouteData route : RouteManager.getInstance().getRoutesForSource(getRouteSourceId())) {
131                                if (route.getCustom() instanceof MiscRouteData) {
132                                        MiscRouteData data = (MiscRouteData) route.getCustom();
133                                        if (curr.getId().equals(data.creatorId)) {
134                                                count++;
135                                        }
136                                }
137                        }
138                        if (count >= curr.getMaxFleetsForThisCreator()) {
139                                continue;
140                        }
141                        
142                        picker.add(curr, curr.getFrequency());
143                }
144                
145                MiscFleetCreatorPlugin creator = picker.pick();
146                if (creator == null) return;
147                
148                MiscRouteData params = creator.createRouteParams(this, random);
149                
150                if (params != null) {
151                        
152                        MarketAPI from = params.from;
153                        SectorEntityToken to = params.to;
154                        log.info("Created misc [" + creator.getId() + "] " + from.getName() + " to " + to.getName());
155                        
156                        //Long seed = Misc.genRandomSeed();
157                        Long seed = random.nextLong();
158                        String id = getRouteSourceId();
159                        
160                        OptionalFleetData extra = new OptionalFleetData(from);
161                        extra.factionId = params.factionId;
162                        
163                        RouteData route = RouteManager.getInstance().addRoute(id, from, seed, extra, this);
164                        route.setCustom(params);
165                        
166                        float orbitDays = params.size * (0.75f + random.nextFloat() * 0.5f);
167                        orbitDays *= 30f;
168                        if (orbitDays < 1f) orbitDays = 1f;
169                        if (orbitDays > 3f) orbitDays = 3f;
170                        
171                        route.addSegment(new RouteSegment(ROUTE_SRC_LOAD, orbitDays, from.getPrimaryEntity()));
172                        route.addSegment(new RouteSegment(ROUTE_TRAVEL_DST, from.getPrimaryEntity(), to));
173                        route.addSegment(new RouteSegment(ROUTE_DST_UNLOAD, orbitDays * 0.5f, to));
174                        route.addSegment(new RouteSegment(ROUTE_DST_LOAD, orbitDays * 0.5f, to));
175                        route.addSegment(new RouteSegment(ROUTE_TRAVEL_SRC, to, from.getPrimaryEntity()));
176                        route.addSegment(new RouteSegment(ROUTE_SRC_UNLOAD, orbitDays, from.getPrimaryEntity()));
177                        
178                        float min = Global.getSettings().getFloatFromArray("miscSpawnTimeoutPerMarket", 0);
179                        float max = Global.getSettings().getFloatFromArray("miscSpawnTimeoutPerMarket", 1);
180                        float timeout = min + (max - min) * random.nextFloat();
181                        
182                        getTimeout(creator.getId()).add(from.getId(), timeout);
183                }
184        }
185
186        
187        public boolean shouldCancelRouteAfterDelayCheck(RouteData route) {
188                return false;
189        }
190        
191        public static MiscFleetCreatorPlugin getCreator(String id) {
192                for (MiscFleetCreatorPlugin curr : CREATORS) {
193                        if (curr.getId().equals(id)) {
194                                return curr;
195                        }
196                }
197                return null;
198        }
199        
200        
201        public CampaignFleetAPI spawnFleet(RouteData route) {
202                Random random = this.random;
203                if (route.getSeed() != null) {
204                        random = new Random(route.getSeed());
205                }
206                
207                MiscRouteData data = (MiscRouteData) route.getCustom();
208                
209                MiscFleetCreatorPlugin curr = getCreator(data.creatorId);
210                if (curr != null) {
211                        CampaignFleetAPI fleet = curr.createFleet(this, route, random);
212                        if (fleet != null) {
213                                fleet.addEventListener(this);
214                                fleet.addScript(new MiscFleetAssignmentAI(fleet, route));
215                        }
216                        return fleet;
217                }
218                return null;
219        }
220        
221        public void reportBattleOccurred(CampaignFleetAPI fleet, CampaignFleetAPI primaryWinner, BattleAPI battle) {
222                RouteData route = RouteManager.getInstance().getRoute(getRouteSourceId(), fleet);
223                if (route == null || !(route.getCustom() instanceof MiscRouteData)) return;
224                
225                //if (route.isExpired()) return;
226                if (!battle.isPlayerInvolved()) return;
227                
228                MiscRouteData data = (MiscRouteData) route.getCustom();
229                
230                MiscFleetCreatorPlugin curr = getCreator(data.creatorId);
231                if (curr != null) {
232                        curr.reportBattleOccurred(this, fleet, primaryWinner, battle);
233                }
234        }
235
236        public void reportFleetDespawnedToListener(CampaignFleetAPI fleet, FleetDespawnReason reason, Object param) {
237                RouteData route = RouteManager.getInstance().getRoute(getRouteSourceId(), fleet);
238                if (route == null || !(route.getCustom() instanceof MiscRouteData)) return;
239                
240                MiscRouteData data = (MiscRouteData) route.getCustom();
241                
242                MiscFleetCreatorPlugin curr = getCreator(data.creatorId);
243                if (curr != null) {
244                        curr.reportFleetDespawnedToListener(this, fleet, reason, param);
245                }
246        }
247
248        public boolean shouldRepeat(RouteData route) {
249                return false;
250        }
251        
252        public void reportAboutToBeDespawnedByRouteManager(RouteData route) {
253                
254        }
255
256        public LinkedHashMap getData() {
257                return data;
258        }
259        
260        
261}
262
263
264
265
266
267
268