Starsector API
Loading...
Searching...
No Matches
ShipWeaponsGroundRaidObjectivePluginImpl.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.graid;
2
3import java.awt.Color;
4import java.util.Random;
5
6import com.fs.starfarer.api.Global;
7import com.fs.starfarer.api.campaign.CargoAPI;
8import com.fs.starfarer.api.campaign.CargoAPI.CargoItemType;
9import com.fs.starfarer.api.campaign.CargoStackAPI;
10import com.fs.starfarer.api.campaign.FactionAPI;
11import com.fs.starfarer.api.campaign.TextPanelAPI;
12import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI;
13import com.fs.starfarer.api.campaign.econ.CommoditySpecAPI;
14import com.fs.starfarer.api.campaign.econ.MarketAPI;
15import com.fs.starfarer.api.combat.WeaponAPI.AIHints;
16import com.fs.starfarer.api.impl.campaign.econ.CommodityIconCounts;
17import com.fs.starfarer.api.impl.campaign.ids.Commodities;
18import com.fs.starfarer.api.impl.campaign.ids.Tags;
19import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.MarketCMD.RaidDangerLevel;
20import com.fs.starfarer.api.loading.FighterWingSpecAPI;
21import com.fs.starfarer.api.loading.HullModSpecAPI;
22import com.fs.starfarer.api.loading.WeaponSpecAPI;
23import com.fs.starfarer.api.ui.IconGroupAPI;
24import com.fs.starfarer.api.ui.IconRenderMode;
25import com.fs.starfarer.api.ui.TooltipMakerAPI;
26import com.fs.starfarer.api.util.Misc;
27import com.fs.starfarer.api.util.WeightedRandomPicker;
28
30
31 public static float CARGO_SPACE_PER_LARGE = 8f;
32 public static float CARGO_SPACE_PER_MEDIUM = 4f;
33 public static float CARGO_SPACE_PER_SMALL = 2f;
34
35 public static float SELL_MULT = Global.getSettings().getFloat("shipWeaponSellPriceMult");
36
37
38 public static float VALUE_NORMAL = 1f;
39 public static float VALUE_EXCESS = 2f;
40 public static float VALUE_DEFICIT = -1f;
41 public static float VALUE_OVERALL = 1000f;
42
43 protected CommodityOnMarketAPI com;
44
46 super(market, Commodities.SHIPS);
47 com = market.getCommodityData(id);
49 }
50
51
52 public void addIcons(IconGroupAPI iconGroup) {
53 CommodityIconCounts counts = new CommodityIconCounts(com);
54
55 int deficit = counts.deficit;
56 int available = Math.max(0, counts.available - counts.extra);
57 int extra = counts.extra;
58
59 if (available > 0) {
60 iconGroup.addIconGroup(Commodities.SHIP_WEAPONS, IconRenderMode.NORMAL, available, null);
61 }
62 if (deficit > 0) {
63 iconGroup.addIconGroup(Commodities.SHIP_WEAPONS, IconRenderMode.RED, deficit, null);
64 }
65 if (extra > 0) {
66 iconGroup.addIconGroup(Commodities.SHIP_WEAPONS, IconRenderMode.GREEN, extra, null);
67 }
68 }
69
70// public int getCargoSpaceNeeded() {
71// return (int) getQuantity(getMarinesAssigned());
72// }
73
75 return (int) getQuantity(getMarinesAssigned());
76 }
77
78 public CommoditySpecAPI getWeaponsCommoditySpec() {
79 return Global.getSettings().getCommoditySpec(Commodities.SHIP_WEAPONS);
80 }
81
82 public RaidDangerLevel getDangerLevel() {
83 RaidDangerLevel danger = getWeaponsCommoditySpec().getBaseDanger();
84
85 CommodityIconCounts counts = new CommodityIconCounts(com);
86 if (counts.production >= counts.available) {
87 danger = danger.prev();
88 }
89 if (counts.deficit > 0) {
90 return danger.next();
91 }
92 if (counts.extra > 0) {
93 return danger.prev();
94 }
95
96 if (source != null) {
97 danger = source.adjustCommodityDangerLevel(id, danger);
98 }
99
100 return danger;
101 }
102
103 public float getQuantitySortValue() {
104 CommoditySpecAPI spec = getWeaponsCommoditySpec();
105 float add = 0;
106 if (spec != null) {
107 add = spec.getOrder();
108 }
109 return QUANTITY_SORT_TIER_1 + add;
110 }
111
112 public String getQuantityString(int marines) {
113// int value = (int) getQuantity(Math.max(1, marines));
114// return Misc.getDGSCredits(value);
115 return "";
116 }
117
118 @Override
119 public String getValueString(int marines) {
120 int value = (int) getQuantity(Math.max(1, marines));
121 return Misc.getDGSCredits(value);
122 }
123
124
125 public int getValue(int marines) {
126 return (int) getQuantity(marines);
127 }
128
129 public float getQuantity(int marines) {
130 float base = Math.round(getBaseRaidValue());
131 return base * marines;
132 }
133
134 public float getBaseRaidValue() {
135 CommodityOnMarketAPI com = market.getCommodityData(id);
136 float unit = 1f;
137
138 CommodityIconCounts counts = new CommodityIconCounts(com);
139
140 float result = 0f;
141
142 result += Math.max(0, counts.available - counts.extra) * unit * VALUE_NORMAL;
143 result += counts.extra * unit * VALUE_EXCESS;
144 result += counts.deficit * unit * VALUE_DEFICIT;
145
146 result *= VALUE_OVERALL;
147
148 if (result < 0) result = 0;
149
150 return result;
151 }
152
153 public String getName() {
154 return getWeaponsCommoditySpec().getName();
155 }
156
157 public CargoStackAPI getStackForIcon() {
158 CargoStackAPI stack = Global.getFactory().createCargoStack(CargoItemType.RESOURCES, Commodities.SHIP_WEAPONS, null);
159 return stack;
160 }
161
163 return com.getId();
164 }
165
166 protected CargoAPI looted = Global.getFactory().createCargo(true);
167
168 protected float getQMult(int tier) {
169 if (tier <= 0) return 0f;
170 if (tier <= 1) return 0.25f;
171 if (tier <= 2) return 0.5f;
172 return 0.75f;
173 }
174
175 public int performRaid(CargoAPI loot, Random random, float lootMult, TextPanelAPI text) {
176 if (marinesAssigned <= 0) return 0;
177
178 //random = new Random();
179
180 WeightedRandomPicker<WeaponSpecAPI> pickerW = new WeightedRandomPicker<WeaponSpecAPI>(random);
181 WeightedRandomPicker<FighterWingSpecAPI> pickerF = new WeightedRandomPicker<FighterWingSpecAPI>(random);
182 WeightedRandomPicker<HullModSpecAPI> pickerH = new WeightedRandomPicker<HullModSpecAPI>(random);
183
184 WeightedRandomPicker<WeaponSpecAPI> weaponSubset = new WeightedRandomPicker<WeaponSpecAPI>(random);
185 WeightedRandomPicker<FighterWingSpecAPI> fighterSubset = new WeightedRandomPicker<FighterWingSpecAPI>(random);
186
187 String factionId = market.getFactionId();
188 float quality = Misc.getShipQuality(market, factionId);
189 FactionAPI faction = Global.getSector().getFaction(factionId);
190
191 int maxTier = 0;
192 if (market.getSize() >= 6) {
193 maxTier = 1;
194 }
195 if (Misc.hasHeavyIndustry(market) || Misc.isMilitary(market)) {
196 maxTier = 1000;
197 }
198
199 float numSmall = 0;
200 float numMedium = 0;
201 float numLarge = 0;
202 for (String id : faction.getKnownWeapons()) {
203 WeaponSpecAPI spec = Global.getSettings().getWeaponSpec(id);
204 switch (spec.getSize()) {
205 case LARGE:
206 numLarge++;
207 break;
208 case MEDIUM:
209 numMedium++;
210 break;
211 case SMALL:
212 numSmall++;
213 break;
214 }
215 }
216 float numTotal = numSmall + numMedium + numLarge + 1f;
217
218 for (String id : faction.getKnownWeapons()) {
219 WeaponSpecAPI spec = Global.getSettings().getWeaponSpec(id);
220 if (spec.getAIHints().contains(AIHints.SYSTEM)) continue;
221 if (spec.getTier() > maxTier) continue;
222
223 float p = 1f * spec.getRarity() + quality * getQMult(spec.getTier());
224 switch (spec.getSize()) {
225 case LARGE:
226 p *= 1f - numLarge / numTotal;
227 p *= 2f;
228 break;
229 case MEDIUM:
230 p *= 1f - numMedium / numTotal;
231 p *= 3f;
232 break;
233 case SMALL:
234 p *= 1f - numSmall / numTotal;
235 p *= 4f;
236 break;
237 }
238 pickerW.add(spec, p);
239 }
240 for (int i = 0; i < 4 + marinesAssigned; i++) {
241 WeaponSpecAPI spec = pickerW.pick();
242 if (spec != null) {
243 float w = pickerW.getWeight(spec);
244 weaponSubset.add(spec, w);
245 pickerW.remove(spec);
246 }
247 }
248
249 for (String id : faction.getKnownFighters()) {
250 FighterWingSpecAPI spec = Global.getSettings().getFighterWingSpec(id);
251 if (spec.getTier() > maxTier) continue;
252
253 float p = 1f * spec.getRarity() + quality * getQMult(spec.getTier());
254 pickerF.add(spec, p);
255 }
256 for (int i = 0; i < 2 + marinesAssigned/2; i++) {
257 FighterWingSpecAPI spec = pickerF.pick();
258 if (spec != null) {
259 float w = pickerF.getWeight(spec);
260 fighterSubset.add(spec, w);
261 pickerF.remove(spec);
262 }
263 }
264
265 for (String id : faction.getKnownHullMods()) {
266 HullModSpecAPI spec = Global.getSettings().getHullModSpec(id);
267 if (spec.isHidden()) continue;
268 if (spec.isAlwaysUnlocked()) continue;
269 if (spec.hasTag(Tags.NO_DROP)) continue;
270 if (spec.getTier() > maxTier) continue;
271
272 float p = 1f * spec.getRarity();
273 if (Global.getSector().getPlayerFaction().knowsHullMod(id)) {
274 p *= 0.2f;
275 }
276 pickerH.add(spec, p);
277 }
278
279
280 float targetValue = getQuantity(marinesAssigned);
281 targetValue *= lootMult;
282 float mult = 0.9f + random.nextFloat() * 0.2f;
283 targetValue *= mult;
284
285 quantityLooted = (int) targetValue;
286
287 float weaponWeight = faction.getDoctrine().getWarships() + faction.getDoctrine().getPhaseShips();
288 float fighterWeight = 1f + faction.getDoctrine().getCarriers();
289 float hullmodWeight = 1f + quality * 1f;
290 float totalWeight = weaponWeight + fighterWeight + hullmodWeight;
291
292 float weaponValue = targetValue * weaponWeight / totalWeight;
293 float fighterValue = targetValue * fighterWeight / totalWeight;
294 float hullmodValue = targetValue * hullmodWeight / totalWeight;
295
296 float totalValue = 0;
297
298 looted.clear();
299
300 int tries = 0;
301 while (weaponValue > 0 && tries < 100) {
302 tries++;
303 WeaponSpecAPI weapon = weaponSubset.pick();
304 if (weapon != null) {
305 int min = 1, max = 2;
306 // don't do this since the odds of rolling large are smaller than medium smaller than small etc
307// switch (weapon.getSize()) {
308// case LARGE: min = 1; max = 2; break;
309// case MEDIUM: min = 1; max = 4; break;
310// case SMALL: min = 2; max = 6; break;
311// }
312 float val = weapon.getBaseValue() * SELL_MULT;
313 int num = min + random.nextInt(max - min + 1);
314 num = (int) Math.min(num, weaponValue / val);
315 if (num == 0) {
316 if (random.nextFloat() < weaponValue / val) num = 1;
317 }
318 if (num > 0) {
319 looted.addWeapons(weapon.getWeaponId(), num);
320 weaponValue -= val * num;
321 totalValue += val * num;
322 } else {
323 break;
324 }
325 } else {
326 break;
327 }
328 }
329
330 fighterValue += Math.max(0, weaponValue);
331
332 tries = 0;
333 while (fighterValue > 0 && tries < 100) {
334 tries++;
335 FighterWingSpecAPI fighter = fighterSubset.pick();
336 if (fighter != null) {
337 int min = 1, max = 2;
338 switch (fighter.getRole()) {
339 case ASSAULT:
340 case BOMBER:
341 case SUPPORT:
342 min = 1; max = 2;
343 break;
344 case FIGHTER:
345 min = 1; max = 3;
346 break;
347 case INTERCEPTOR:
348 min = 1; max = 4;
349 break;
350 }
351 float val = fighter.getBaseValue() * SELL_MULT;
352 int num = min + random.nextInt(max - min + 1);
353 num = (int) Math.min(num, fighterValue / val);
354 if (num == 0) {
355 if (random.nextFloat() < fighterValue / val) num = 1;
356 }
357 if (num > 0) {
358 looted.addFighters(fighter.getId(), num);
359 fighterValue -= val * num;
360 totalValue += val * num;
361 } else {
362 break;
363 }
364 } else {
365 break;
366 }
367 }
368
369 hullmodValue += Math.max(0, fighterValue);
370
371 tries = 0;
372 while (hullmodValue > 0 && tries < 100) {
373 tries++;
374 HullModSpecAPI mod = pickerH.pickAndRemove();
375 if (mod != null) {
376 float val = mod.getBaseValue();
377 int num = 0;
378 if (random.nextFloat() < hullmodValue / val) num = 1;
379 if (num > 0) {
380 looted.addHullmods(mod.getId(), num);
381 hullmodValue -= val * num;
382 totalValue += val * num;
383 } else {
384 break;
385 }
386 } else {
387 break;
388 }
389 }
390
391 loot.addAll(looted);
392
393 xpGained = (int) (totalValue * XP_GAIN_VALUE_MULT);
394 return xpGained;
395 }
396
397
398
399 @Override
400 public boolean hasTooltip() {
401 return true;
402 }
403
404 @Override
405 public void createTooltip(TooltipMakerAPI t, boolean expanded) {
406 float opad = 10f;
407 float pad = 3f;
408 Color h = Misc.getHighlightColor();
409 Color bad = Misc.getNegativeHighlightColor();
410 Color good = Misc.getPositiveHighlightColor();
411
412 CommodityOnMarketAPI com = market.getCommodityData(Commodities.SHIPS);
413
414 t.addPara("Ship weapons, fighter LPCs, and hullmod specs. Availability is based on the " +
415 "\"" + com.getCommodity().getName() + "\" commodity.", 0f);
416 t.addPara("The colony faction's doctrine affects the number of weapons vs fighter LPCs acquired. Higher ship quality " +
417 "increases the probability of finding modspecs..", opad);
418 //t.addPara("The \"projected value\" is the typical sell value of the equipment acquired.", opad);
419
420 if (Misc.hasHeavyIndustry(market) || Misc.isMilitary(market)) {
421 if (Misc.hasHeavyIndustry(market)) {
422 t.addPara("This colony has heavy industry and high-tier equipment may be found.", good, opad);
423 } else if (Misc.isMilitary(market)) {
424 t.addPara("This colony has a military presence and high-tier equipment may be found.", good, opad);
425 }
426 } else {
427 t.addPara("This colony does not have heavy industry or a military presence and has no access to high-tier ship equipment.", bad, opad);
428 }
429
430 // weapons fighters and hullmods
431 // based on S&W
432 // impact of doctrine
433 // impact of ship quality
434 // how hullmods get rolled
435 // impact of assigning more marines, explain that more marines = more stuff despite "variable"
436 // whether it has military or production, or size >= 6
437 }
438
439
440
441
442
443 public CargoAPI getLooted() {
444 return looted;
445 }
446
447
448
449}
450
451
452
453
454
455
456
457
static SettingsAPI getSettings()
Definition Global.java:51
static FactoryAPI getFactory()
Definition Global.java:35
static SectorAPI getSector()
Definition Global.java:59
CargoAPI createCargo(boolean unlimitedStacks)
CargoStackAPI createCargoStack(CargoItemType type, Object data, CargoAPI cargo)
HullModSpecAPI getHullModSpec(String modId)
CommoditySpecAPI getCommoditySpec(String commodityId)
FighterWingSpecAPI getFighterWingSpec(String wingId)
WeaponSpecAPI getWeaponSpec(String weaponId)