001package com.fs.starfarer.api.impl.campaign.intel;
002
003import java.util.ArrayList;
004import java.util.LinkedHashMap;
005import java.util.LinkedHashSet;
006import java.util.List;
007import java.util.Map;
008import java.util.Set;
009
010import com.fs.starfarer.api.EveryFrameScript;
011import com.fs.starfarer.api.Global;
012import com.fs.starfarer.api.util.CountingMap;
013import com.fs.starfarer.api.util.WeightedRandomPicker;
014
015public class GenericMissionManager extends BaseEventManager {
016        
017        public static interface GenericMissionCreator {
018                float getMissionFrequencyWeight();
019                EveryFrameScript createMissionIntel();
020        }
021        
022
023        public static final String KEY = "$core_genericMissionManager";
024        
025        public static GenericMissionManager getInstance() {
026                Object test = Global.getSector().getMemoryWithoutUpdate().get(KEY);
027                return (GenericMissionManager) test; 
028        }
029        
030        protected List<GenericMissionCreator> creators = new ArrayList<GenericMissionCreator>();
031        protected Set<GenericMissionCreator> failed = new LinkedHashSet<GenericMissionCreator>();
032        
033        protected Map<EveryFrameScript, GenericMissionCreator> missionCreators = new LinkedHashMap<EveryFrameScript, GenericMissionCreator>();
034        
035        public GenericMissionManager() {
036                super();
037                Global.getSector().getMemoryWithoutUpdate().set(KEY, this);
038        }
039        
040        protected Object readResolve() {
041                super.readResolve();
042                if (failed == null) {
043                        failed = new LinkedHashSet<GenericMissionCreator>();
044                }
045                return this;
046        }
047        
048        public void addMissionCreator(GenericMissionCreator creator) {
049                creators.add(creator);
050        }
051        
052        public boolean hasMissionCreator(Class<?> clazz) {
053                for (GenericMissionCreator script : creators) {
054                        if (clazz.isInstance(script)) return true;
055                }
056                return false;
057        }
058        
059        public List<GenericMissionCreator> getCreators() {
060                return creators;
061        }
062
063        @Override
064        protected int getMinConcurrent() {
065                return Global.getSettings().getInt("minGenericMissions");
066        }
067        @Override
068        protected int getMaxConcurrent() {
069                return Global.getSettings().getInt("maxGenericMissions");
070        }
071        
072        @Override
073        protected float getIntervalRateMult() {
074                float approximateMissionPostingDurationDays = 10f;
075                return (float) getCurrMax() / approximateMissionPostingDurationDays;
076        }
077
078        @Override
079        protected EveryFrameScript createEvent() {
080                //if ((float) Math.random() < 0.75f) return null;
081                
082//              if (getActive().size() >= 3) {
083//                      return null;
084//              }
085                
086                
087                List<EveryFrameScript> orphaned = new ArrayList<EveryFrameScript>(missionCreators.keySet());
088                CountingMap<GenericMissionCreator> current = new CountingMap<GenericMissionCreator>();
089                for (EveryFrameScript s : getActive()) {
090                        orphaned.remove(s);
091                        GenericMissionCreator c = missionCreators.get(s);
092                        if (c != null) { 
093                                current.add(c);
094                        }
095                }
096                
097                for (EveryFrameScript s : orphaned) {
098                        missionCreators.remove(s);
099                }
100                
101                
102                
103                float totalWeight = 0f;
104                for (GenericMissionCreator c : creators) {
105                        totalWeight += c.getMissionFrequencyWeight();
106                }
107                
108                WeightedRandomPicker<GenericMissionCreator> picker = new WeightedRandomPicker<GenericMissionCreator>();
109                for (GenericMissionCreator c : creators) {
110                        if (failed.contains(c)) continue;
111                        
112                        float currNum = current.getCount(c);
113                        if (currNum < 1) currNum = 1;
114                        
115                        float desiredNum = getCurrMax() * c.getMissionFrequencyWeight() / totalWeight;
116                        if (desiredNum < 0.1f) desiredNum = 0.1f;
117                
118                        float deviation = desiredNum * 0.25f;
119                        float exponent = (desiredNum - currNum) / deviation;
120                        if (exponent > 4) exponent = 4;
121                        
122                        float probMult = (float) Math.pow(10f, exponent);
123                        picker.add(c, c.getMissionFrequencyWeight() * probMult);
124                }
125                
126                GenericMissionCreator creator = picker.pick();
127                if (creator == null) {
128                        failed.clear();
129                        return null;
130                }
131                
132                EveryFrameScript intel = creator.createMissionIntel();
133                if (intel instanceof BaseIntelPlugin && ((BaseIntelPlugin)intel).isDone()) {
134                        intel = null;
135                }
136
137                if (intel != null) {
138//                      debug stuff: make mission intel visible to player and print some stats when adding a new mission
139//                      ((BaseIntelPlugin) intel).setPostingLocation(null);
140//                      String detail = "";
141//                      for (GenericMissionCreator c : creators) {
142//                              detail += c.getClass().getSimpleName() + ": " + current.getCount(c) + " | ";
143//                      }
144//                      detail = "[" + detail + "]";
145//                      System.out.println("Added mission by " + creator.getClass().getSimpleName() + ", weight: " + (int)picker.getWeight(creator) + " / " + (int)picker.getTotal() + " " + detail);
146                        missionCreators.put(intel, creator);
147                        failed.clear();
148                } else {
149                        failed.add(creator);
150                }
151                
152                return intel;
153        }
154        
155}
156
157
158
159
160
161
162