001package com.fs.starfarer.api.impl.campaign.fleets;
002
003import java.util.Random;
004
005import org.lwjgl.util.vector.Vector2f;
006
007import com.fs.starfarer.api.EveryFrameScript;
008import com.fs.starfarer.api.Global;
009import com.fs.starfarer.api.campaign.CampaignFleetAPI;
010import com.fs.starfarer.api.campaign.FleetAssignment;
011import com.fs.starfarer.api.campaign.LocationAPI;
012import com.fs.starfarer.api.campaign.PlanetAPI;
013import com.fs.starfarer.api.campaign.SectorEntityToken;
014import com.fs.starfarer.api.campaign.StarSystemAPI;
015import com.fs.starfarer.api.campaign.econ.MarketAPI;
016import com.fs.starfarer.api.util.Misc;
017import com.fs.starfarer.api.util.WeightedRandomPicker;
018
019public class DisposableAggroAssignmentAI implements EveryFrameScript {
020
021        protected StarSystemAPI system;
022        protected CampaignFleetAPI fleet;
023        protected DisposableFleetManager manager;
024        
025        
026        public DisposableAggroAssignmentAI(CampaignFleetAPI fleet, StarSystemAPI system, 
027                                                                           DisposableFleetManager manager, float probStayInHyper) {
028                this.fleet = fleet;
029                this.system = system;
030                this.manager = manager;
031                
032                giveInitialAssignments(probStayInHyper);
033        }
034        
035        protected void giveInitialAssignments(float probStayInHyper) {
036                boolean playerInSameLocation = fleet.getContainingLocation() == Global.getSector().getCurrentLocation();
037                
038                SectorEntityToken target = null;
039                if (!playerInSameLocation && !fleet.isInHyperspace()) { // in system, player is in hyper
040                        target = pickEntityToGuard(new Random(), system, fleet);
041                        if (target != null) {
042                                Vector2f loc = Misc.getPointAtRadius(target.getLocation(), target.getRadius() + 100f);
043                                fleet.setLocation(loc.x, loc.y);
044                        } else {
045                                Vector2f loc = Misc.getPointAtRadius(new Vector2f(), 5000f);
046                                fleet.setLocation(loc.x, loc.y);
047                        }
048                } else if (fleet.isInHyperspace()) { // fleet in hyper; don't care about player being there or not
049                        SectorEntityToken from = Misc.getSourceEntity(fleet);
050                        if (from != null && system != null) {
051                                float angle = Misc.getAngleInDegrees(system.getLocation(), from.getLocationInHyperspace());
052                                float arc = 90f;
053                                angle = angle - arc / 2f + arc * (float) Math.random();
054                                //float dist = Global.getSettings().getMaxSensorRangeHyper() + 500f + 1000f * (float) Math.random();
055                                float dist = Global.getSettings().getMaxSensorRangeHyper() + 1000f;
056                                Vector2f loc = Misc.getUnitVectorAtDegreeAngle(angle);
057                                loc.scale(dist);
058                                Vector2f.add(loc, system.getLocation(), loc);
059                                
060                                loc = Misc.pickHyperLocationNotNearPlayer(new Vector2f(loc), Global.getSettings().getMaxSensorRangeHyper() + 500f);
061                                
062                                fleet.setLocation(loc.x, loc.y);
063                        } else {
064                                Vector2f loc = Misc.pickHyperLocationNotNearPlayer(system.getLocation(), Global.getSettings().getMaxSensorRangeHyper() + 500f);
065                                fleet.setLocation(loc.x, loc.y);
066                        }
067                } else { // player in same location, and in-system
068                        target = pickEntityToGuard(new Random(), system, fleet);
069                        Vector2f loc = new Vector2f(5000, 0);
070                        if (target != null) {
071                                Vector2f from = target.getLocation();
072                                loc = Misc.pickLocationNotNearPlayer(system, from, 
073                                                Global.getSettings().getMaxSensorRange() + 500f);
074                        } else { // no jump points case; ???
075                                loc = Misc.pickLocationNotNearPlayer(system, 
076                                                                        Misc.getPointAtRadius(new Vector2f(0, 0), 8000),
077                                                                        Global.getSettings().getMaxSensorRange() + 500f);
078                        }
079                        fleet.setLocation(loc.x, loc.y);
080                }
081                pickNext(target, probStayInHyper);
082        }
083        
084        protected void pickNext(SectorEntityToken target, float probStayInHyper) {
085                if (fleet.isInHyperspace()) {
086                        Vector2f dest = Misc.getPointAtRadius(system.getLocation(), 1000);
087                        LocationAPI hyper = Global.getSector().getHyperspace();
088                        SectorEntityToken token = hyper.createToken(dest.x, dest.y);
089                        fleet.addAssignment(FleetAssignment.GO_TO_LOCATION, token, 1000, 
090                                                                manager.getTravelText(system, fleet));
091                }
092                
093                if (fleet.isInHyperspace() && (float) Math.random() < probStayInHyper) {
094                        fleet.addAssignment(FleetAssignment.RAID_SYSTEM, system.getHyperspaceAnchor(), 10000,
095                                                                manager.getActionOutsideText(system, fleet));
096                } else {
097                        if (target == null) target = pickEntityToGuard(new Random(), system, fleet);
098                        if (target != null) {
099                                float speed = Misc.getSpeedForBurnLevel(8);
100                                float dist = Misc.getDistance(fleet.getLocation(), target.getLocation());
101                                float seconds = dist / speed;
102                                float days = seconds / Global.getSector().getClock().getSecondsPerDay();
103                                days += 30f + 10f * (float) Math.random();
104                                fleet.addAssignment(FleetAssignment.PATROL_SYSTEM, target, days,
105                                                                        manager.getActionInsideText(system, fleet));
106                                return;
107                        } else {
108                                float days = 5f + 5f * (float) Math.random();
109                                fleet.addAssignment(FleetAssignment.PATROL_SYSTEM, null, days,
110                                                                        manager.getActionInsideText(system, fleet));
111                        }
112                }
113        }
114
115        public void advance(float amount) {
116                if (fleet.getCurrentAssignment() == null) {
117                        pickNext(null, 0f);
118                }
119        }
120
121        public boolean isDone() {
122                return false;
123        }
124
125        public boolean runWhilePaused() {
126                return false;
127        }
128        
129        public static SectorEntityToken pickEntityToGuard(Random random, StarSystemAPI system, CampaignFleetAPI fleet) {
130                WeightedRandomPicker<SectorEntityToken> picker = new WeightedRandomPicker<SectorEntityToken>(random);
131                
132                for (SectorEntityToken entity : system.getJumpPoints()) {
133                        float mult = getWeightMultForPatrols(system, fleet, entity);
134                        picker.add(entity, 5f * mult);
135                }
136                
137                // gas giants are exits from hyperspace, so hang around there too
138                for (PlanetAPI planet : system.getPlanets()) {
139                        if (planet.isGasGiant()) {
140                                float mult = getWeightMultForPatrols(system, fleet, planet);
141                                picker.add(planet, 5f * mult);
142                        }
143                }
144                
145                for (MarketAPI market : Global.getSector().getEconomy().getMarkets(system)) {
146                        if (market.getFaction() != fleet.getFaction()) continue;
147                        
148                        float mult = getWeightMultForPatrols(system, fleet, market.getPrimaryEntity());
149                        picker.add(market.getPrimaryEntity(), 5f * mult);
150                }
151                
152                return picker.pick();
153        }
154        
155        public static float getWeightMultForPatrols(StarSystemAPI system, CampaignFleetAPI fleet, SectorEntityToken entity) {
156                float count = countNearbyPatrols(system, fleet, entity);
157                return 1f / (count * 10f + 1f);
158        }
159        
160        public static float countNearbyPatrols(StarSystemAPI system, CampaignFleetAPI fleet, SectorEntityToken entity) {
161                float count = 0;
162                for (CampaignFleetAPI other : system.getFleets()) {
163                        float dist = Misc.getDistance(other, entity);
164                        if (dist > 3000) continue;
165                        
166                        if (!Misc.isPatrol(other)) continue;
167                        
168                        if (fleet.isHostileTo(other)) {
169                                count++;
170                        }
171                }
172                return count;
173        }
174
175}
176
177
178
179
180
181
182
183
184
185