001package com.fs.starfarer.api.impl.campaign.intel;
002
003import java.util.ArrayList;
004import java.util.HashMap;
005import java.util.List;
006import java.util.Map;
007import java.util.Random;
008
009import com.fs.starfarer.api.EveryFrameScript;
010import com.fs.starfarer.api.Global;
011import com.fs.starfarer.api.campaign.FactionAPI;
012import com.fs.starfarer.api.campaign.RepLevel;
013import com.fs.starfarer.api.impl.campaign.ids.Factions;
014import com.fs.starfarer.api.util.Misc;
015import com.fs.starfarer.api.util.Pair;
016import com.fs.starfarer.api.util.TimeoutTracker;
017import com.fs.starfarer.api.util.WeightedRandomPicker;
018
019public class FactionHostilityManager extends BaseEventManager {
020
021        public static String getConflictId(FactionAPI a, FactionAPI b) {
022                String id1 = a.getId();
023                String id2 = b.getId();
024                if (id1.compareTo(id2) < 0) {
025                        return id1 + "_" + id2;
026                }
027                return id2 + "_" + id1;
028        }
029        
030        public static final String KEY = "$core_factionHostilityManager";
031        
032        public static final float TIMEOUT_AFTER_ENDING = 30f;
033        public static final float CHECK_DAYS = 10f;
034        public static final float CHECK_PROB = 0.5f;
035        
036        public static FactionHostilityManager getInstance() {
037                Object test = Global.getSector().getMemoryWithoutUpdate().get(KEY);
038                return (FactionHostilityManager) test; 
039        }
040        
041        public FactionHostilityManager() {
042                Global.getSector().getMemoryWithoutUpdate().set(KEY, this);
043        }
044        
045        public boolean areHostilitiesOngoing(FactionAPI a, FactionAPI b) {
046                FactionHostilityIntel intel = getHostilties(a, b);
047                return intel != null && !intel.isEnding();
048        }
049        
050        public FactionHostilityIntel getHostilties(FactionAPI a, FactionAPI b) {
051                String id = getConflictId(a, b);
052                for (EveryFrameScript s : getActive()) {
053                        FactionHostilityIntel intel = (FactionHostilityIntel) s;
054                        if (intel.getId().equals(id)) {
055                                return intel;
056                        }
057                }
058                return null;
059        }
060        
061        public List<FactionHostilityIntel> getHostilitiesInvolving(FactionAPI faction) {
062                List<FactionHostilityIntel> result = new ArrayList<FactionHostilityIntel>();
063                for (EveryFrameScript s : getActive()) {
064                        FactionHostilityIntel intel = (FactionHostilityIntel) s;
065                        if (intel.getOne() == faction || intel.getTwo() == faction) {
066                                result.add(intel);
067                        }
068                }
069                return result;
070        }
071        
072        
073        @Override
074        protected int getMinConcurrent() {
075                List<FactionAPI> factions = getEligibleFactions(true);
076                
077                float mult = Global.getSettings().getFloat("minFactionHostilitiesMult");
078                return (int) Math.ceil(factions.size() * mult);
079        }
080        
081        @Override
082        protected int getMaxConcurrent() {
083                List<FactionAPI> factions = getEligibleFactions(true);
084                
085                float mult = Global.getSettings().getFloat("maxFactionHostilitiesMult");
086                return (int) Math.ceil(factions.size() * mult);
087        }
088        
089        protected List<FactionAPI> getEligibleFactions(boolean checkNumMarkets) {
090                List<FactionAPI> factions = Global.getSector().getAllFactions();
091                List<FactionAPI> result = new ArrayList<FactionAPI>();
092                for (int i = 0; i < factions.size(); i++) {
093                        FactionAPI faction = factions.get(i);
094                        if (!faction.getCustom().optBoolean(Factions.CUSTOM_ENGAGES_IN_HOSTILITIES)) {
095                                continue;
096                        }
097                        
098                        if (faction.isPlayerFaction()) continue;
099                        
100                        if (checkNumMarkets) {
101                                int count = Misc.getFactionMarkets(faction).size();
102                                if (count <= 0) continue;
103                        }
104                        
105                        result.add(faction);
106                }
107                
108                return result;
109        }
110        
111        
112        @Override
113        protected float getBaseInterval() {
114                return CHECK_DAYS;
115        }
116        
117        public void startHostilities(String a, String b) {
118                startHostilities(Global.getSector().getFaction(a), Global.getSector().getFaction(b));
119                
120        }
121        public void startHostilities(FactionAPI a, FactionAPI b) {
122                if (areHostilitiesOngoing(a, b)) return;
123                
124                FactionHostilityIntel intel = new FactionHostilityIntel(a, b);
125                addActive(intel);
126        }
127
128        protected Random random = new Random();
129        
130        @Override
131        protected EveryFrameScript createEvent() {
132                if (random.nextFloat() < CHECK_PROB) return null;
133                
134                Pair<FactionAPI, FactionAPI> pick = pickFactions();
135                if (pick == null) return null;
136                
137                FactionHostilityIntel intel = new FactionHostilityIntel(pick.one, pick.two);
138                
139                return intel;
140        }
141        
142        public void notifyRecentlyEnded(String id) {
143                recentlyEnded.add(id, TIMEOUT_AFTER_ENDING);
144        }
145        
146        public TimeoutTracker<String> getRecentlyEnded() {
147                return recentlyEnded;
148        }
149
150        protected TimeoutTracker<String> recentlyEnded = new TimeoutTracker<String>();
151        @Override
152        public void advance(float amount) {
153                //amount *= 100f;
154                super.advance(amount);
155                
156                float days = Global.getSector().getClock().convertToDays(amount);
157                recentlyEnded.advance(days);
158        }
159
160        protected Pair<FactionAPI, FactionAPI> pickFactions() {
161                List<FactionAPI> factions = new ArrayList<FactionAPI>();
162                Map<FactionAPI, Integer> marketCounts = new HashMap<FactionAPI, Integer>();
163                
164                for (FactionAPI faction : getEligibleFactions(false)) {
165                        int count = Misc.getFactionMarkets(faction).size();
166                        if (count <= 0) continue;
167                        marketCounts.put(faction, count);
168                        
169                        factions.add(faction);
170                }
171                
172                WeightedRandomPicker<FactionAPI> picker = new WeightedRandomPicker<FactionAPI>(random);
173                
174                boolean weighCommissionedMore = false;
175                FactionAPI commission = Misc.getCommissionFaction();
176                if (commission != null && getHostilitiesInvolving(commission).isEmpty()) {
177                        weighCommissionedMore = true;
178                }
179                
180                for (FactionAPI faction : factions) {
181                        float w = 1f;
182                        if (commission == faction && weighCommissionedMore) {
183                                w = factions.size();
184                        }
185                        picker.add(faction, w);
186                }
187                
188                FactionAPI one = picker.pick();
189                if (one == null) return null;
190                
191                picker.clear();
192                for (FactionAPI faction : factions) {
193                        if (faction == one) continue;
194                        if (faction.isHostileTo(one)) continue;
195                        if (faction.isAtWorst(one, RepLevel.COOPERATIVE)) continue;
196                        
197                        String id = getConflictId(one, faction);
198                        if (recentlyEnded.contains(id)) continue;
199                        
200                        float w = marketCounts.get(faction);
201                        picker.add(faction, w);
202                }
203                
204                FactionAPI two = picker.pick();
205                if (two == null) return null;
206                
207                return new Pair<FactionAPI, FactionAPI>(one, two);
208                
209        }
210        
211}
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226