001package com.fs.starfarer.api.impl.campaign.missions.hub;
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.EveryFrameScript;
010import com.fs.starfarer.api.Global;
011import com.fs.starfarer.api.campaign.CampaignFleetAPI;
012import com.fs.starfarer.api.campaign.FleetAssignment;
013import com.fs.starfarer.api.campaign.LocationAPI;
014import com.fs.starfarer.api.campaign.SectorEntityToken;
015import com.fs.starfarer.api.campaign.StarSystemAPI;
016import com.fs.starfarer.api.campaign.ai.ModularFleetAIAPI;
017import com.fs.starfarer.api.campaign.comm.IntelInfoPlugin;
018import com.fs.starfarer.api.util.Misc;
019import com.fs.starfarer.api.util.WeightedRandomPicker;
020
021public class TriggerFleetAssignmentAI implements EveryFrameScript {
022
023        protected CampaignFleetAPI fleet;
024        protected LocationAPI system;
025        
026        protected List<SectorEntityToken> patrolPoints = new ArrayList<SectorEntityToken>();
027        protected float elapsedWaitingForDespawn = 0f;
028        protected HubMission mission;
029        protected String patrolText;
030        protected String travelText;
031        
032        public TriggerFleetAssignmentAI(String travelText, String patrolText, HubMission mission, LocationAPI system, boolean randomLocation, CampaignFleetAPI fleet, SectorEntityToken ... patrolPoints) {
033                this.travelText = travelText;
034                this.patrolText = patrolText;
035                this.mission = mission;
036                this.fleet = fleet;
037                this.system = system;
038                
039                if (patrolPoints != null) {
040                        for (SectorEntityToken curr : patrolPoints) {
041                                if (curr == null) continue;
042                                if (curr == fleet) continue;
043                                this.patrolPoints.add(curr);
044                        }
045                }
046                
047                if (!fleet.hasScriptOfClass(MissionFleetAutoDespawn.class)) {
048                        fleet.addScript(new MissionFleetAutoDespawn(mission, fleet));
049                }
050                
051                // moving this to CreateFleetAction, since most mission fleets are likely to want to ignore WarSimScript
052                //fleet.getMemoryWithoutUpdate().set(MemFlags.FLEET_BUSY, true);
053                
054                giveInitialAssignments(randomLocation);
055        }
056        
057        protected void giveInitialAssignments(boolean randomLocation) {
058                if (randomLocation) {
059                        // start at random location
060                        SectorEntityToken target = pickPatrolPoint();
061                        if (target != null) {
062                                Vector2f loc = Misc.getPointAtRadius(target.getLocation(), target.getRadius() + 100f);
063                                fleet.setLocation(loc.x, loc.y);
064                        } else {
065                                Vector2f loc = Misc.getPointAtRadius(new Vector2f(), 5000f);
066                                fleet.setLocation(loc.x, loc.y);
067                        }
068                }
069                pickNext();
070        }
071
072        protected SectorEntityToken pickPatrolPoint() {
073                if (patrolPoints != null) {
074                        Random random = null;
075                        if (mission instanceof BaseHubMission) random = ((BaseHubMission)mission).getGenRandom();
076                        WeightedRandomPicker<SectorEntityToken> picker = new WeightedRandomPicker<SectorEntityToken>(random);
077                        for (SectorEntityToken curr : patrolPoints) {
078                                if (!curr.isAlive()) continue;
079                                picker.addAll(patrolPoints);
080                        }
081                        return picker.pick();
082                }
083                return null;
084        }
085        
086        protected SectorEntityToken currTarget;
087        protected void pickNext() {
088                currTarget = pickPatrolPoint();
089                if (currTarget != null) {
090                        float speed = Misc.getSpeedForBurnLevel(8);
091                        float dist = Misc.getDistance(fleet.getLocation(), currTarget.getLocation());
092                        float seconds = dist / speed;
093                        float days = seconds / Global.getSector().getClock().getSecondsPerDay();
094                        days += 5f + 5f * (float) Math.random();
095                        fleet.addAssignment(FleetAssignment.PATROL_SYSTEM, currTarget, days, patrolText == null ? "patrolling" : patrolText);
096                        return;
097                } else if (system instanceof StarSystemAPI) {
098                        float days = 5f + 5f * (float) Math.random();
099                        fleet.addAssignment(FleetAssignment.PATROL_SYSTEM, ((StarSystemAPI)system).getCenter(), days, patrolText == null ? "patrolling" : patrolText);
100                }
101        }
102
103        public void advance(float amount) {
104                if (fleet.getCurrentAssignment() == null) {
105                        pickNext();
106                } else {
107                        String travel = travelText;
108                        if (travel == null) {
109                                if (Misc.isPatrol(fleet)) {
110                                        travel = "patrolling";
111                                } else {
112                                        travel = "traveling";
113                                }
114                        }
115                        if (fleet.getAI() != null && 
116                                        travel != null && currTarget != null && fleet.getCurrentAssignment().getTarget() == currTarget &&
117                                        fleet.getCurrentAssignment().getAssignment() == FleetAssignment.PATROL_SYSTEM) {
118                                float dist = Misc.getDistance(fleet, currTarget);
119                                if (dist > 1500 || fleet.getContainingLocation() != currTarget.getContainingLocation()) {
120                                        boolean standingDown = fleet.getAI() instanceof ModularFleetAIAPI &&
121                                                                ((ModularFleetAIAPI) fleet.getAI()).getTacticalModule() != null &&
122                                                                ((ModularFleetAIAPI) fleet.getAI()).getTacticalModule().isStandingDown();
123                                        if (standingDown) {
124                                                fleet.getAI().setActionTextOverride(null);
125                                        } else {
126                                                fleet.getAI().setActionTextOverride(travel);
127                                        }
128                                } else {
129                                        fleet.getAI().setActionTextOverride(null);
130                                }
131                        } else if (fleet.getAI() != null) {
132                                fleet.getAI().setActionTextOverride(null);
133                        }
134                }
135                
136                // replaced with separate MissionFleetAutoDespawn script
137                //despawnIfNeeded(amount);
138        }
139        
140//      protected void despawnIfNeeded(float amount) {
141//              if (isMissionEnded()) {
142//                      if (!fleet.isInCurrentLocation()) {
143//                              elapsedWaitingForDespawn += Global.getSector().getClock().convertToDays(amount);
144//                              if (elapsedWaitingForDespawn > 30f && fleet.getBattle() == null) {
145//                                      fleet.despawn(FleetDespawnReason.PLAYER_FAR_AWAY, null);
146//                                      elapsedWaitingForDespawn = 0f;
147//                              }
148//                      } else {
149//                              elapsedWaitingForDespawn = 0f;
150//                      }
151//              }
152//      }
153        
154        public boolean isMissionEnded() {
155                return mission instanceof IntelInfoPlugin && ((IntelInfoPlugin)mission).isEnded();
156        }
157
158        public boolean isDone() {
159                return false;
160        }
161
162        public boolean runWhilePaused() {
163                return false;
164        }
165        
166        
167
168}
169
170
171
172
173
174
175
176
177
178