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