001package com.fs.starfarer.api.impl.campaign;
002
003import java.util.List;
004
005import com.fs.starfarer.api.EveryFrameScript;
006import com.fs.starfarer.api.Global;
007import com.fs.starfarer.api.campaign.CampaignFleetAPI;
008import com.fs.starfarer.api.campaign.FactionAPI;
009import com.fs.starfarer.api.campaign.FleetAssignment;
010import com.fs.starfarer.api.campaign.SectorEntityToken;
011import com.fs.starfarer.api.campaign.ai.CampaignFleetAIAPI.ActionType;
012import com.fs.starfarer.api.campaign.ai.FleetAssignmentDataAPI;
013import com.fs.starfarer.api.campaign.ai.ModularFleetAIAPI;
014import com.fs.starfarer.api.campaign.rules.MemoryAPI;
015import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
016import com.fs.starfarer.api.util.IntervalUtil;
017import com.fs.starfarer.api.util.Misc;
018
019public class MilitaryResponseScript implements EveryFrameScript {
020        
021        public static String RESPONSE_ASSIGNMENT = "response"; // custom value added to assignments so we know which to clear
022        
023        public static class MilitaryResponseParams {
024                public ActionType type;
025                public String responseReason;
026                public FactionAPI faction;
027                
028                public SectorEntityToken actor;
029                public SectorEntityToken target;
030                public float responseFraction;
031                public float responseDuration;
032                public String travelText;
033                public String actionText;
034                
035                public MilitaryResponseParams(ActionType type, String responseReason,
036                                                                          FactionAPI faction, SectorEntityToken target,
037                                                                          float responseFraction, float responseDuration) {
038                        this.type = type;
039                        this.responseReason = responseReason;
040                        this.faction = faction;
041                        this.target = target;
042                        this.responseFraction = responseFraction;
043                        this.responseDuration = responseDuration;
044                }
045                
046                
047        }
048        
049        
050        protected IntervalUtil tracker = new IntervalUtil(0.05f, 0.15f);
051        protected MilitaryResponseParams params;
052        protected float elapsed;
053        
054        public MilitaryResponseScript(MilitaryResponseParams params) {
055                this.params = params;
056                addToResponseTotal();
057                initiateResponse();
058        }
059
060        public void advance(float amount) {
061                float days = Global.getSector().getClock().convertToDays(amount);
062                tracker.advance(days);
063                
064                elapsed += days;
065                
066                
067//              if (params != null) {
068//                      System.out.println("MRS: " + params.responseReason);
069//              } else {
070//                      System.out.println("NULL MRS params");
071//              }
072                
073                if (tracker.intervalElapsed()) {
074                        initiateResponse();
075                }
076        }
077
078        
079        public void initiateResponse() {
080                if (params.target.getContainingLocation() == null) return;
081//              if (params.faction.getId().equals(Factions.PIRATES) && params.target.isInCurrentLocation()) {
082//                      System.out.println("wefwefwe");
083//              }
084                List<CampaignFleetAPI> fleets = params.target.getContainingLocation().getFleets();
085                for (CampaignFleetAPI fleet : fleets) {
086                        seeIfFleetShouldRespond(fleet);
087                }
088        }
089
090        protected boolean isTemporarilyNotResponding(CampaignFleetAPI fleet) {
091                if (fleet.getBattle() != null) return true;
092                
093                if (fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.FLEET_BUSY)) return true;
094                FleetAssignmentDataAPI curr = fleet.getCurrentAssignment();
095                if (curr != null && curr.getAssignment() == FleetAssignment.STANDING_DOWN) return true;
096                
097                MemoryAPI memory = fleet.getMemoryWithoutUpdate();
098                if (memory.getBoolean(MemFlags.FLEET_MILITARY_RESPONSE)) return true;
099                
100                return false;
101        }
102        
103        protected void seeIfFleetShouldRespond(CampaignFleetAPI fleet) {
104//              if (fleet.getContainingLocation() == Global.getSector().getCurrentLocation()) {
105//                      System.out.println("fwefwef");
106//              }
107                
108                if (!couldRespond(fleet)) return;
109                
110                if (isTemporarilyNotResponding(fleet)) return;
111                
112                List<CampaignFleetAPI> fleets = params.target.getContainingLocation().getFleets();
113                float potentialFP = 0;
114                float respondingFP = 0f;
115                
116                float closestDist = Float.MAX_VALUE;
117                CampaignFleetAPI closestNonResponder = null;
118                
119                for (CampaignFleetAPI other : fleets) {
120                        if (!couldRespond(other)) continue;
121                        
122                        float fp = other.getFleetPoints();
123                        
124                        potentialFP += fp;
125                        boolean responding = isResponding(other);
126                        if (responding) {
127                                respondingFP += fp;
128                        }
129                        
130                        //if (other == fleet) continue;
131                        
132                        if (!responding && !isTemporarilyNotResponding(other)) {
133                                float distOther = Misc.getDistance(params.target, other);
134                                if (distOther < closestDist) {
135                                        closestDist = distOther;
136                                        closestNonResponder = other;
137                                }
138                        }
139                }
140                
141                float fraction = params.responseFraction / getResponseTotal();
142                
143                //float dist = Misc.getDistance(params.target, fleet);
144                if (potentialFP > 0 &&
145                                respondingFP / potentialFP < fraction &&
146                                closestNonResponder == fleet) {
147                        
148                        respond(fleet);
149                }
150        }
151        
152        protected void respond(CampaignFleetAPI fleet) {
153                unrespond(fleet);
154                
155//              if (fleet.getContainingLocation() != null && fleet.getContainingLocation().getName().startsWith("Corvus")) {
156//                      System.out.println("fwefwe");
157//              }
158                //fleet.getAssignmentsCopy().get(0)
159                Misc.setFlagWithReason(fleet.getMemoryWithoutUpdate(), 
160                                                                MemFlags.FLEET_MILITARY_RESPONSE, params.responseReason, true, (1.5f + (float) Math.random()) * 0.2f);
161                
162                fleet.addAssignmentAtStart(FleetAssignment.PATROL_SYSTEM, params.target, 3f, params.actionText, null);
163                FleetAssignmentDataAPI curr = fleet.getCurrentAssignment();
164                if (curr != null) {
165                        curr.setCustom(RESPONSE_ASSIGNMENT);
166                }
167                
168                float dist = Misc.getDistance(params.target, fleet);
169                if (dist > 2000f) {
170                        fleet.addAssignmentAtStart(FleetAssignment.GO_TO_LOCATION, params.target, 3f, params.travelText, null);
171                        //fleet.addAssignmentAtStart(FleetAssignment.DELIVER_CREW, params.target, 3f, params.travelText, null);
172                        curr = fleet.getCurrentAssignment();
173                        if (curr != null) {
174                                curr.setCustom(RESPONSE_ASSIGNMENT);
175                        }
176                }
177                
178                //Global.getSector().addPing(fleet, Pings.DANGER);
179        }
180        
181        protected void unrespond(CampaignFleetAPI fleet) {
182                Misc.setFlagWithReason(fleet.getMemoryWithoutUpdate(), 
183                                                           MemFlags.FLEET_MILITARY_RESPONSE, params.responseReason, false, 0f);
184                boolean firstOrbitPassive = true;
185                for (FleetAssignmentDataAPI curr : fleet.getAI().getAssignmentsCopy()) {
186                        if (RESPONSE_ASSIGNMENT.equals(curr.getCustom())) {
187                                fleet.getAI().removeAssignment(curr);
188                        } else if (curr.getAssignment() == FleetAssignment.ORBIT_PASSIVE && firstOrbitPassive) {
189                                // "preparing for patrol" or some such, very likely - don't want to go back to that
190                                // after the response is done
191                                fleet.getAI().removeAssignment(curr);
192                                firstOrbitPassive = false;
193                        }
194                }
195        }
196        
197        protected boolean isResponding(CampaignFleetAPI fleet) {
198                return Misc.flagHasReason(fleet.getMemoryWithoutUpdate(), MemFlags.FLEET_MILITARY_RESPONSE, params.responseReason);
199        }
200        
201        protected boolean couldRespond(CampaignFleetAPI fleet) {
202                if (fleet.getFaction() != params.faction) return false;
203                if (fleet.getAI() == null) return false;
204                if (fleet.isPlayerFleet()) return false;
205                if (fleet.isStationMode()) return false;
206                
207                // don't check for this here as it would skew proportiions of what's assigned where if a fleet is busy for a bit
208                //if (fleet.getMemoryWithoutUpdate().getBoolean(MemFlags.FLEET_BUSY)) return false;
209                
210                if (fleet.getAI() instanceof ModularFleetAIAPI) {
211                        ModularFleetAIAPI ai = (ModularFleetAIAPI) fleet.getAI();
212                        if (ai.getAssignmentModule().areAssignmentsFrozen()) return false;
213                }
214                
215                if (fleet.getCurrentAssignment() != null && 
216                                fleet.getCurrentAssignment().getAssignment() == FleetAssignment.GO_TO_LOCATION_AND_DESPAWN) {
217                        return false;
218                }
219                
220                MemoryAPI memory = fleet.getMemoryWithoutUpdate();
221                
222                boolean patrol = memory.getBoolean(MemFlags.MEMORY_KEY_PATROL_FLEET);
223                boolean warFleet = memory.getBoolean(MemFlags.MEMORY_KEY_WAR_FLEET);
224                boolean pirate = memory.getBoolean(MemFlags.MEMORY_KEY_PIRATE);
225                boolean noMilitary = memory.getBoolean(MemFlags.FLEET_NO_MILITARY_RESPONSE);
226                if (!(patrol || warFleet || pirate) || noMilitary) return false;
227                
228                return true;
229        }
230        
231        protected String getResponseTotalKey() {
232                return "$mrs_" + params.responseReason;
233        }
234        
235        protected void addToResponseTotal() {
236                MemoryAPI memory = params.faction.getMemoryWithoutUpdate();
237                String key = getResponseTotalKey();
238                
239                float curr = memory.getFloat(key);
240                memory.set(key, curr + params.responseFraction, 60f);
241        }
242        
243        protected void removeFromResponseTotal() {
244                MemoryAPI memory = params.faction.getMemoryWithoutUpdate();
245                String key = getResponseTotalKey();
246                
247                float curr = memory.getFloat(key);
248                if (curr > params.responseFraction) {
249                        memory.set(key, Math.max(0, curr - params.responseFraction), 60f);
250                } else {
251                        memory.unset(key);
252                }
253        }
254        
255        protected float getResponseTotal() {
256                MemoryAPI memory = params.faction.getMemoryWithoutUpdate();
257                String key = getResponseTotalKey();
258                
259                float curr = memory.getFloat(key);
260                if (curr < params.responseFraction) curr = params.responseFraction;
261                if (curr < 1) curr = 1;
262                return curr;
263        }
264        
265        public void forceDone() {
266                if (params != null) {
267                        elapsed = params.responseDuration;
268                }
269        }
270        
271        public boolean isDone() {
272                if (params == null || elapsed >= params.responseDuration) {
273                        removeFromResponseTotal();
274                        params = null;
275                        return true;
276                }
277                return false;
278        }
279
280        public boolean runWhilePaused() {
281                return false;
282        }
283
284        public MilitaryResponseParams getParams() {
285                return params;
286        }
287
288        public float getElapsed() {
289                return elapsed;
290        }
291
292        public void setElapsed(float elapsed) {
293                this.elapsed = elapsed;
294        }
295        
296        
297
298}