Starsector API
Loading...
Searching...
No Matches
OfficerLevelupPluginImpl.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign;
2
3import java.util.ArrayList;
4import java.util.List;
5import java.util.Random;
6
7import com.fs.starfarer.api.Global;
8import com.fs.starfarer.api.characters.MutableCharacterStatsAPI;
9import com.fs.starfarer.api.characters.MutableCharacterStatsAPI.SkillLevelAPI;
10import com.fs.starfarer.api.characters.PersonAPI;
11import com.fs.starfarer.api.characters.SkillSpecAPI;
12import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
13import com.fs.starfarer.api.impl.campaign.ids.Skills;
14import com.fs.starfarer.api.impl.campaign.ids.Stats;
15import com.fs.starfarer.api.plugins.OfficerLevelupPlugin;
16import com.fs.starfarer.api.util.Misc;
17import com.fs.starfarer.api.util.SkillData;
18import com.fs.starfarer.api.util.SkillData.SkillsForAptitude;
19import com.fs.starfarer.api.util.WeightedRandomPicker;
20
21public class OfficerLevelupPluginImpl implements OfficerLevelupPlugin {
22
23 //public static float XP_MULT = 5f;
24 public static float XP_MULT = Global.getSettings().getFloat("officerXPRequiredMult");
25
26 public static float EXPONENT_BEYOND_MAX_SPECIFIED_LEVEL = 1.1f;
27
28 public static long [] XP_PER_LEVEL = new long [] {
29 0, // level 1
30 12000,
31 20000,
32 35000,
33 45000, // level 5
34 50000,
35 50000,
36 50000,
37 50000,
38 50000,
39 };
40
41 public static long [] TOTAL_XP_PER_LEVEL = new long [XP_PER_LEVEL.length];
42
43 static {
44 long total = 0;
45 for (int i = 0; i < XP_PER_LEVEL.length; i++) {
46 total += XP_PER_LEVEL[i];
47 TOTAL_XP_PER_LEVEL[i] = total;
48 }
49 }
50
51 public long getXPForLevel(int level) {
52 if (level <= 1) return 0;
53
54 if (level - 1 < TOTAL_XP_PER_LEVEL.length) {
55 return (long) (TOTAL_XP_PER_LEVEL[level - 1] * XP_MULT);
56 }
57
58 int maxSpecified = TOTAL_XP_PER_LEVEL.length;
59 long curr = TOTAL_XP_PER_LEVEL[maxSpecified - 1];
60 long last = XP_PER_LEVEL[maxSpecified - 1];
61 for (int i = maxSpecified; i < level; i++) {
63 curr += last;
64 }
65
66 return (long) (curr * XP_MULT);
67 }
68
69 public static void main(String[] args) {
70 for (int i = 1; i <= 6; i++) {
71 System.out.println("Level " + i + ": " + new OfficerLevelupPluginImpl().getXPForLevel(i));
72 }
73 }
74
75 public int getMaxLevel(PersonAPI person) {
76 if (person != null && person.getMemoryWithoutUpdate().contains(MemFlags.OFFICER_MAX_LEVEL)) {
77 return person.getMemoryWithoutUpdate().getInt(MemFlags.OFFICER_MAX_LEVEL);
78 }
79 int bonus = 0;
80 if (person != null) {
81 MutableCharacterStatsAPI stats = person.getFleetCommanderStats();
82 if (stats != null) {
83 bonus = (int) stats.getDynamic().getMod(Stats.OFFICER_MAX_LEVEL_MOD).computeEffective(0);
84 }
85 }
86 return (int) Global.getSettings().getFloat("officerMaxLevel") + bonus;
87 }
88
89 public int getMaxEliteSkills(PersonAPI person) {
90 if (person != null && person.getMemoryWithoutUpdate().contains(MemFlags.OFFICER_MAX_ELITE_SKILLS)) {
91 return person.getMemoryWithoutUpdate().getInt(MemFlags.OFFICER_MAX_ELITE_SKILLS);
92 }
93 int bonus = 0;
94 if (person != null) {
95 MutableCharacterStatsAPI stats = person.getFleetCommanderStats();
96 if (stats != null) {
97 bonus = (int) stats.getDynamic().getMod(Stats.OFFICER_MAX_ELITE_SKILLS_MOD).computeEffective(0);
98 }
99 }
100 return (int) Global.getSettings().getFloat("officerMaxEliteSkills") + bonus;
101 }
102
103 public List<String> pickLevelupSkillsV2(PersonAPI person, Random random) {
104 if (random == null) random = new Random();
105
106
107 List<SkillSpecAPI> leftovers = new ArrayList<SkillSpecAPI>();
108 List<List<SkillSpecAPI>> unknownTiers = new ArrayList<List<SkillSpecAPI>>();
109
110 MutableCharacterStatsAPI stats = person.getStats();
111 int level = stats.getLevel();
112
113 for (String ap : SkillData.getAptitudes().keySet()) {
114 SkillsForAptitude skills = SkillData.getSkills(ap);
115 int tier = 0;
116 for (List<SkillSpecAPI> list : skills.tiers) {
117 tier++;
118
119 List<SkillSpecAPI> unknown = new ArrayList<SkillSpecAPI>();
120 for (SkillSpecAPI skill : list) {
121 if (!skill.isCombatOfficerSkill()) continue;
122 if (skill.hasTag(Skills.TAG_DEPRECATED)) continue;
123 if (skill.hasTag(Skills.TAG_PLAYER_ONLY)) continue;
124 if (stats.getSkillLevel(skill.getId()) <= 0) {
125 unknown.add(skill);
126 }
127 }
128 if (list.size() == unknown.size() && (tier < 4 || level >= 3)) {
129 unknownTiers.add(list);
130 } else {
131 leftovers.addAll(unknown);
132 }
133 }
134 }
135
136 int max = 4;
137 if (Misc.isMentored(person)) {
138 max = 6;
139 }
140 List<String> result = new ArrayList<String>();
141
142 if (!unknownTiers.isEmpty()) {
143 WeightedRandomPicker<List<SkillSpecAPI>> picker = new WeightedRandomPicker<List<SkillSpecAPI>>(random);
144 picker.addAll(unknownTiers);
145 while (!picker.isEmpty() && result.size() < max) {
146 List<SkillSpecAPI> pick = picker.pickAndRemove();
147 for (SkillSpecAPI s : pick) {
148 if (result.size() >= max) break;
149 result.add(s.getId());
150 }
151 }
152 }
153
154 if (!leftovers.isEmpty()) {
155 WeightedRandomPicker<SkillSpecAPI> picker = new WeightedRandomPicker<SkillSpecAPI>(random);
156 picker.addAll(leftovers);
157 while (!picker.isEmpty() && result.size() < max) {
158 SkillSpecAPI pick = picker.pickAndRemove();
159 result.add(pick.getId());
160 }
161 }
162
163 return result;
164 }
165
166
167 public List<String> pickLevelupSkillsV3(PersonAPI person, Random random) {
168 if (random == null) random = new Random();
169
170
171 List<SkillSpecAPI> top = new ArrayList<SkillSpecAPI>();
172 List<SkillSpecAPI> leftovers = new ArrayList<SkillSpecAPI>();
173
174 MutableCharacterStatsAPI stats = person.getStats();
175 int level = stats.getLevel();
176
177 for (String ap : SkillData.getAptitudes().keySet()) {
178 SkillsForAptitude skills = SkillData.getSkills(ap);
179 for (List<SkillSpecAPI> list : skills.tiers) {
180 boolean topTier = false;
181 for (SkillSpecAPI skill : list) {
182 if (!skill.isCombatOfficerSkill()) continue;
183 if (skill.hasTag(Skills.TAG_DEPRECATED)) continue;
184 if (skill.hasTag(Skills.TAG_PLAYER_ONLY)) continue;
185 if (stats.getSkillLevel(skill.getId()) <= 0) {
186 if (skill.getTier() == 5) topTier = true;
187 if (!topTier || level >= 3) {
188 if (topTier) {
189 top.add(skill);
190 } else {
191 leftovers.add(skill);
192 }
193 }
194 }
195 }
196 }
197 }
198
199 int max = 4;
200 if (Misc.isMentored(person)) {
201 max = 6;
202 }
203 if (person.getMemoryWithoutUpdate().contains(MemFlags.OFFICER_SKILL_PICKS_PER_LEVEL)) {
204 max = person.getMemoryWithoutUpdate().getInt(MemFlags.OFFICER_SKILL_PICKS_PER_LEVEL);
205 }
206 List<String> result = new ArrayList<String>();
207
208 if (!top.isEmpty()) {
209 WeightedRandomPicker<SkillSpecAPI> picker = new WeightedRandomPicker<SkillSpecAPI>(random);
210 picker.addAll(top);
211 while (!picker.isEmpty() && result.size() < max) {
212 SkillSpecAPI pick = picker.pickAndRemove();
213 result.add(pick.getId());
214 }
215 }
216 if (!leftovers.isEmpty()) {
217 WeightedRandomPicker<SkillSpecAPI> picker = new WeightedRandomPicker<SkillSpecAPI>(random);
218 picker.addAll(leftovers);
219 while (!picker.isEmpty() && result.size() < max) {
220 SkillSpecAPI pick = picker.pickAndRemove();
221 result.add(pick.getId());
222 }
223 }
224
225 return result;
226 }
227
228
229 public List<String> pickLevelupSkills(PersonAPI person, Random random) {
230 if (true) return pickLevelupSkillsV3(person, random);
231 if (random == null) random = new Random();
232
233 boolean hasCarrierSkills = false;
234 for (SkillLevelAPI skill : person.getStats().getSkillsCopy()) {
235 if (!skill.getSkill().isCombatOfficerSkill()) continue;
236
237 if (skill.getSkill().hasTag(Skills.TAG_CARRIER)) {
238 hasCarrierSkills = true;
239 break;
240 }
241 }
242
243 WeightedRandomPicker<String> nonMaxedSkills = new WeightedRandomPicker<String>(random);
244 WeightedRandomPicker<String> knownSkills = new WeightedRandomPicker<String>(random);
245 WeightedRandomPicker<String> carrierSkills = new WeightedRandomPicker<String>(random);
246 WeightedRandomPicker<String> knownCarrierSkills = new WeightedRandomPicker<String>(random);
247 WeightedRandomPicker<String> nonCarrierSkills = new WeightedRandomPicker<String>(random);
248 WeightedRandomPicker<String> knownNonCarrierSkills = new WeightedRandomPicker<String>(random);
249 List<String> allSkillIds = Global.getSettings().getSortedSkillIds();
250 int knownSkillCount = 0;
251 for (String skillId : allSkillIds) {
252 SkillSpecAPI skill = Global.getSettings().getSkillSpec(skillId);
253 if (skill.isCombatOfficerSkill()) {
254 addSkill(person, nonMaxedSkills, skillId);
255 float level = person.getStats().getSkillLevel(skillId);
256 if (level > 0) {
257 knownSkillCount++;
258 addSkill(person, knownSkills, skillId);
259 }
260 if (skill.hasTag(Skills.TAG_CARRIER)) {
261 addSkill(person, carrierSkills, skillId);
262 if (level > 0) addSkill(person, knownCarrierSkills, skillId);
263 } else {
264 addSkill(person, nonCarrierSkills, skillId);
265 if (level > 0) addSkill(person, knownNonCarrierSkills, skillId);
266 }
267 }
268 }
269 List<String> result = new ArrayList<String>();
270
271 if (!knownSkills.isEmpty()) {
272 String pick = knownSkills.pickAndRemove();
273 nonMaxedSkills.remove(pick);
274 carrierSkills.remove(pick);
275 nonCarrierSkills.remove(pick);
276 knownCarrierSkills.remove(pick);
277 knownNonCarrierSkills.remove(pick);
278 result.add(pick);
279 }
280
281 int maxSkillsPerOfficer = 10;
282 if (knownSkillCount >= maxSkillsPerOfficer) {
283 if (hasCarrierSkills && !knownCarrierSkills.isEmpty()) {
284 String pick = knownCarrierSkills.pickAndRemove();
285 result.add(pick);
286 } else if (!knownNonCarrierSkills.isEmpty() && result.size() == 0) {
287 String pick = knownNonCarrierSkills.pickAndRemove();
288 result.add(pick);
289 } else if (!knownSkills.isEmpty()) {
290 String pick = knownSkills.pickAndRemove();
291 result.add(pick);
292 }
293 } else {
294 if (hasCarrierSkills && !carrierSkills.isEmpty()) {
295 String pick = carrierSkills.pickAndRemove();
296 result.add(pick);
297 } else if (!nonCarrierSkills.isEmpty() && result.size() == 0) {
298 String pick = nonCarrierSkills.pickAndRemove();
299 result.add(pick);
300 } else if (!nonMaxedSkills.isEmpty()) {
301 String pick = nonMaxedSkills.pickAndRemove();
302 result.add(pick);
303 }
304 }
305
306 if (result.size() < 2 && knownSkillCount < maxSkillsPerOfficer) {
307 for (String id : result) {
308 nonMaxedSkills.remove(id);
309 }
310 if (!nonMaxedSkills.isEmpty()) {
311 String pick = nonMaxedSkills.pickAndRemove();
312 knownSkills.remove(pick);
313 result.add(pick);
314 }
315 }
316
317 return result;
318 }
319
320
321
322 private void addSkill(PersonAPI person, WeightedRandomPicker<String> picker, String skill) {
323 if (person.getStats().getSkillLevel(skill) >= 3) return;
324 picker.add(skill);
325 }
326
327
328
329// public static void main(String[] args) {
330// LevelupPluginImpl impl = new LevelupPluginImpl();
331// for (int i = 0; i <= 100; i++) {
332// System.out.println(String.format("% 4d: % 20d", i, impl.getXPForLevel(i)));
333// }
334// }
335
336}
337
338
339
340
341
static SettingsAPI getSettings()
Definition Global.java:51
List< String > pickLevelupSkillsV3(PersonAPI person, Random random)
List< String > pickLevelupSkills(PersonAPI person, Random random)
List< String > pickLevelupSkillsV2(PersonAPI person, Random random)
SkillSpecAPI getSkillSpec(String skillId)
List< String > getSortedSkillIds()