Starsector API
Loading...
Searching...
No Matches
DropGroupRow.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign.procgen;
2
3import java.util.ArrayList;
4import java.util.Collection;
5import java.util.Iterator;
6import java.util.List;
7import java.util.Random;
8
9import org.json.JSONArray;
10import org.json.JSONException;
11import org.json.JSONObject;
12
13import com.fs.starfarer.api.Global;
14import com.fs.starfarer.api.campaign.CargoAPI.CargoItemType;
15import com.fs.starfarer.api.campaign.CargoStackAPI;
16import com.fs.starfarer.api.campaign.SpecialItemData;
17import com.fs.starfarer.api.campaign.SpecialItemPlugin;
18import com.fs.starfarer.api.campaign.SpecialItemSpecAPI;
19import com.fs.starfarer.api.campaign.econ.CommoditySpecAPI;
20import com.fs.starfarer.api.combat.WeaponAPI.WeaponSize;
21import com.fs.starfarer.api.combat.WeaponAPI.WeaponType;
22import com.fs.starfarer.api.impl.campaign.ids.Tags;
23import com.fs.starfarer.api.loading.FighterWingSpecAPI;
24import com.fs.starfarer.api.loading.WeaponSpecAPI;
25import com.fs.starfarer.api.util.Misc;
26import com.fs.starfarer.api.util.WeightedRandomPicker;
27
28public class DropGroupRow implements Cloneable {
29 public static final String NOTHING = "nothing";
30
31
32 public static final String WEAPON_PREFIX = "wpn_";
33 //public static final String MOD_PREFIX = "mod_";
34 public static final String FIGHTER_PREFIX = "ftr_";
35 public static final String ITEM_PREFIX = "item_";
36
37
38 private String commodity, group;
39 private float freq;
40 private boolean percent = false;
41
42 private boolean multiValued = false;
43 private int tier = -1;
44 private List<String> tags = new ArrayList<String>();
45 //private List<String> tags2 = new ArrayList<String>();
46 private WeaponType weaponType = null;
47 private WeaponSize weaponSize = null;
48
49// private String itemId = null;
50// private String itemParams = null;
51
52 Object writeReplace() {
53 DropGroupRow copy = clone();
54 if (tags != null && tags.isEmpty()) {
55 copy.tags = null;
56 }
57// if (tags2 != null && tags2.isEmpty()) {
58// copy.tags2 = null;
59// }
60 return copy;
61 //return this;
62 }
63
64 @Override
66 try {
67 DropGroupRow copy = (DropGroupRow) super.clone();
68 return copy;
69 } catch (CloneNotSupportedException e) {
70 return null;
71 }
72 }
73
74 public DropGroupRow(JSONObject row) throws JSONException {
75 commodity = row.getString("commodity");
76 group = row.getString("group");
77
78 String fStr = row.getString("freq");
79 if (fStr.endsWith("%")) {
80 percent = true;
81 fStr = fStr.substring(0, fStr.length() - 1);
82 freq = Float.parseFloat(fStr);
83 } else {
84 freq = (float) row.getDouble("freq");
85 }
86 parseData();
87 }
88
89 private void parseData() throws JSONException {
90 if (commodity.contains(":")) {
91 multiValued = true;
92
93 if (commodity.startsWith(ITEM_PREFIX)) {
94// item_factory_core resolved
95// item_modspec:converted_hangar resolved
96// item_modspec:{} unresolved
97// item_:{} unresolved
98// item_modspec:{tier:3, tags:[shields]} unresolved
99// item_:{tags:[modspec], p:{tier:3, tags:[engines]} unresolved
100
101 String test = commodity.replaceFirst(ITEM_PREFIX, "");
102 int index = test.indexOf(':');
103 if (index < 0) {
104 multiValued = false;
105 } else {
106 String itemId = test.substring(0, index);
107 String secondPart = test.substring(index + 1);
108
109 if (itemId.isEmpty() && secondPart.startsWith("{")) {
110 JSONObject json = new JSONObject(secondPart);
111
112 tier = json.optInt("tier", -1);
113 if (json.has("tags")) {
114 JSONArray tags = json.getJSONArray("tags");
115 for (int i = 0; i < tags.length(); i++) {
116 this.tags.add(tags.getString(i));
117 }
118 }
119 } else if (!secondPart.startsWith("{")) {
120 multiValued = false;
121 }
122 }
123 return;
124 }
125
126
127 JSONObject json = new JSONObject(commodity.substring(commodity.indexOf(":") + 1));
128 tier = json.optInt("tier", -1);
129 if (json.has("tags")) {
130 JSONArray tags = json.getJSONArray("tags");
131 for (int i = 0; i < tags.length(); i++) {
132 this.tags.add(tags.getString(i));
133 }
134 }
135 if (json.has("weaponType")) {
136 weaponType = Misc.mapToEnum(json, "weaponType", WeaponType.class, null);
137 }
138 if (json.has("weaponSize")) {
139 weaponSize = Misc.mapToEnum(json, "weaponSize", WeaponSize.class, null);
140 }
141 }
142 }
143
144 public DropGroupRow(String commodity, String group, float freq) {
145 this.commodity = commodity;
146 this.group = group;
147 this.freq = freq;
148 try {
149 parseData();
150 } catch (JSONException e) {
151 throw new RuntimeException(e);
152 }
153 }
154
155 public CommoditySpecAPI getSpec() {
156 if (isNothing() || isWeapon()) return null;
157
158 CommoditySpecAPI spec = Global.getSector().getEconomy().getCommoditySpec(commodity);
159 return spec;
160 }
161
162 public WeaponSpecAPI getWeaponSpec() {
163 if (!isWeapon()) return null;
164
165 WeaponSpecAPI spec = Global.getSettings().getWeaponSpec(getWeaponId());
166 return spec;
167 }
168
169// public HullModSpecAPI getHullModSpec() {
170// if (!isHullMod()) return null;
171//
172// HullModSpecAPI spec = Global.getSettings().getHullModSpec(getHullModId());
173// return spec;
174// }
175
176 public float getBaseUnitValue() {
177 if (isMultiValued()) throw new RuntimeException("Call resolveToSpecificItem() before calling getBaseUnitValue()");
178
179 if (isWeapon()) {
180 return getWeaponSpec().getBaseValue();
181// } else if (isHullMod()) {
182// return getHullModSpec().getBaseValue();
183 } else if (isFighterWing()) {
184 return getFighterWingSpec().getBaseValue();
185 } else if (isSpecialItem()) {
186 CargoStackAPI stack = Global.getFactory().createCargoStack(CargoItemType.SPECIAL,
187 new SpecialItemData(getSpecialItemId(), getSpecialItemData()), null);
188 return stack.getPlugin().getPrice(null, null);
189 } else {
190 return getSpec().getBasePrice();
191 }
192 }
193
194 public FighterWingSpecAPI getFighterWingSpec() {
195 if (!isFighterWing()) return null;
196
197 FighterWingSpecAPI spec = Global.getSettings().getFighterWingSpec(getFighterWingId());
198 return spec;
199 }
200
201 public boolean isCommodity() {
202 return !isNothing() && !isWeapon() && !isFighterWing() && !isSpecialItem();
203 }
204
205 public boolean isWeapon() {
206 return commodity != null && commodity.startsWith(WEAPON_PREFIX);
207 }
208
209 public String getWeaponId() {
210 return commodity.substring(WEAPON_PREFIX.length());
211 }
212
213 public String getSpecialItemId() {
214 String afterPrefix = commodity.substring(ITEM_PREFIX.length());
215 int index = afterPrefix.indexOf(":");
216 if (index >= 0) {
217 afterPrefix = afterPrefix.substring(0, index);
218 }
219 return afterPrefix;
220 }
221 public String getSpecialItemData() {
222 String afterPrefix = commodity.substring(ITEM_PREFIX.length());
223 int index = afterPrefix.indexOf(":");
224 if (index >= 0) {
225 afterPrefix = afterPrefix.substring(index + 1);
226 return afterPrefix;
227 }
228 return null;
229 }
230
231 public SpecialItemSpecAPI getSpecialItemSpec() {
232 if (!isSpecialItem()) return null;
233
234 SpecialItemSpecAPI spec = Global.getSettings().getSpecialItemSpec(getSpecialItemId());
235 return spec;
236 }
237
238 public boolean isFighterWing() {
239 return commodity != null && commodity.startsWith(FIGHTER_PREFIX);
240 }
241 public boolean isSpecialItem() {
242 return commodity != null && commodity.startsWith(ITEM_PREFIX);
243 }
244
245 public String getFighterWingId() {
246 return commodity.substring(FIGHTER_PREFIX.length());
247 }
248
249// public boolean isHullMod() {
250// return commodity != null && commodity.startsWith(MOD_PREFIX);
251// }
252//
253// public String getHullModId() {
254// return commodity.substring(MOD_PREFIX.length());
255// }
256
257 public boolean isMultiValued() {
258 return multiValued;
259 }
260
261 public boolean isNothing() {
262 return commodity == null || commodity.equals(NOTHING);
263 }
264
265 public String getCommodity() {
266 return commodity;
267 }
268
269 public void setCommodity(String commodity) {
270 this.commodity = commodity;
271 }
272
273 public String getGroup() {
274 return group;
275 }
276
277 public void setGroup(String group) {
278 this.group = group;
279 }
280
281 public float getFreq() {
282 return freq;
283 }
284
285 public void setFreq(float freq) {
286 this.freq = freq;
287 }
288
289
290 public static WeightedRandomPicker<DropGroupRow> getPicker(String group) {
291 WeightedRandomPicker<DropGroupRow> picker = new WeightedRandomPicker<DropGroupRow>();
292 Collection<DropGroupRow> specs = Global.getSettings().getAllSpecs(DropGroupRow.class);
293
294 for (DropGroupRow spec : specs) {
295// if (!spec.isMultiValued() && spec.isHullMod() && spec.getHullModSpec().hasTag(Tags.HULLMOD_NO_DROP)) {
296// continue;
297// }
298 if (!spec.isMultiValued() && spec.isFighterWing() && spec.getFighterWingSpec().hasTag(Tags.WING_NO_DROP)) {
299 continue;
300 }
301
302 if (spec.getGroup().equals(group)) {
303 picker.add(spec, spec.getFreq());
304 }
305 }
306
307 for (DropGroupRow curr : picker.getItems()) {
308 if (curr.isNothing() && curr.percent) {
309 float totalOther = picker.getTotal() - curr.freq;
310
311 float fNothing = curr.freq / 100f;
312 if (fNothing < 0) fNothing = 0;
313 if (fNothing > 1) fNothing = 1;
314
315 float weightNothing = totalOther * fNothing / (1f - fNothing);
316
317 picker.setWeight(picker.getItems().indexOf(curr), weightNothing);
318 break;
319 }
320 }
321
322 if (picker.isEmpty()) {
323 throw new RuntimeException("No drop data found for drop group [" + group + "], probably an error in drop_groups.csv");
324 }
325
326 return picker;
327 }
328
329
330 public DropGroupRow resolveToSpecificItem(Random random) {
331 if (random == null) random = new Random();
332
333 if (!isMultiValued()) return this;
334
335 DropGroupRow copy = clone();
336 copy.multiValued = false;
337
338 if (isSpecialItem()) {
339// item_factory_core resolved
340// item_modspec:converted_hangar resolved
341// item_modspec:{} unresolved
342// item_:{} unresolved
343// item_modspec:{tier:3, tags:[shields]} unresolved
344// item_:{tags:[modspec], p:{tier:3, tags:[engines]} unresolved
345
346 String test = commodity.replaceFirst(ITEM_PREFIX, "");
347 int index = test.indexOf(':');
348 if (index < 0) {
349 } else {
350 boolean getParamsFromP = false;
351 String itemId = test.substring(0, index);
352 String params = test.substring(index + 1);
353
354 if (!itemId.isEmpty()) {
355 // params are already set properly, and we have an item id - do nothing
356 } else {
357 List<SpecialItemSpecAPI> specs = Global.getSettings().getAllSpecialItemSpecs();
358
359 Iterator<SpecialItemSpecAPI> iter = specs.iterator();
360// while (iter.hasNext()) {
361// SpecialItemSpecAPI curr = iter.next();
362// if (curr.isHidden() || curr.isHiddenEverywhere()) iter.remove();
363// }
364
365 if (!tags.isEmpty()) {
366 iter = specs.iterator();
367 while (iter.hasNext()) {
368 SpecialItemSpecAPI curr = iter.next();
369 for (String tag : tags) {
370 boolean not = tag.startsWith("!");
371 tag = not ? tag.substring(1) : tag;
372 boolean has = curr.hasTag(tag);
373 if (not == has) {
374 iter.remove();
375 break;
376 }
377 }
378 }
379 }
380
381 WeightedRandomPicker<SpecialItemSpecAPI> picker = new WeightedRandomPicker<SpecialItemSpecAPI>(random);
382 for (SpecialItemSpecAPI spec : specs) {
383 picker.add(spec, 1f * spec.getRarity());
384 }
385 SpecialItemSpecAPI pick = picker.pick();
386 if (pick == null) {
387 copy.commodity = NOTHING;
388 } else {
389 itemId = pick.getId();
390 getParamsFromP = true;
391 }
392 }
393
394 // we've picked an itemId to use
395 if (!itemId.isEmpty()) {
396// item_:{tags:[modspec], p:{tier:3, tags:[engines]} unresolved
397 try {
398 if (getParamsFromP) {
399 JSONObject json = new JSONObject(params);
400 if (json.has("p")) {
401 params = json.getJSONObject("p").toString();
402 } else {
403 params = "{}";
404 }
405 }
406
407 SpecialItemSpecAPI spec = Global.getSettings().getSpecialItemSpec(itemId);
408 SpecialItemPlugin plugin = spec.getNewPluginInstance(null);
409 String itemData = plugin.resolveDropParamsToSpecificItemData(params, random);
410
411 if (itemData == null) {
412 copy.commodity = NOTHING;
413 } else if (itemData.isEmpty()) {
414 copy.commodity = ITEM_PREFIX + itemId;
415 } else {
416 copy.commodity = ITEM_PREFIX + itemId + ":" + itemData;
417 }
418// if (copy.commodity.contains("{")) {
419// System.out.println("wefwefew");
420// }
421 } catch (JSONException e) {
422 throw new RuntimeException("Params: " + params, e);
423 }
424 } else {
425 copy.commodity = NOTHING;
426 }
427 }
428// } else if (isHullMod()) {
429// List<HullModSpecAPI> specs = Global.getSettings().getAllHullModSpecs();
430//
431// Iterator<HullModSpecAPI> iter = specs.iterator();
432// while (iter.hasNext()) {
433// HullModSpecAPI curr = iter.next();
434// if (curr.isHidden() || curr.isHiddenEverywhere()) iter.remove();
435// }
436//
437// if (tier >= 0) {
438// iter = specs.iterator();
439// while (iter.hasNext()) {
440// HullModSpecAPI curr = iter.next();
444// if (curr.getTier() != tier) iter.remove();
445// }
446// }
447//
448// if (!tags.isEmpty()) {
449// iter = specs.iterator();
450// while (iter.hasNext()) {
451// HullModSpecAPI curr = iter.next();
452// for (String tag : tags) {
453// boolean not = tag.startsWith("!");
454// tag = not ? tag.substring(1) : tag;
455// boolean has = curr.hasTag(tag);
456// if (not == has) {
457// iter.remove();
458// break;
459// }
460// }
461// }
462// }
463//
464// WeightedRandomPicker<HullModSpecAPI> picker = new WeightedRandomPicker<HullModSpecAPI>(random);
465// //picker.addAll(specs);
466// for (HullModSpecAPI spec : specs) {
467// picker.add(spec, 1f * spec.getRarity());
468// }
469// HullModSpecAPI pick = picker.pick();
470// if (pick == null) {
471// copy.commodity = NOTHING;
472// } else {
473// copy.commodity = MOD_PREFIX + pick.getId();
474// }
475 } else if (isWeapon()) {
476 List<WeaponSpecAPI> specs = Global.getSettings().getAllWeaponSpecs();
477 if (tier >= 0) {
478 Iterator<WeaponSpecAPI> iter = specs.iterator();
479 while (iter.hasNext()) {
480 WeaponSpecAPI curr = iter.next();
481 if (curr.getTier() != tier) iter.remove();
482 }
483 }
484
485 if (!tags.isEmpty()) {
486 Iterator<WeaponSpecAPI> iter = specs.iterator();
487 while (iter.hasNext()) {
488 WeaponSpecAPI curr = iter.next();
489 for (String tag : tags) {
490 boolean not = tag.startsWith("!");
491 tag = not ? tag.substring(1) : tag;
492 boolean has = curr.hasTag(tag);
493 if (not == has) {
494 iter.remove();
495 break;
496 }
497 }
498 }
499 }
500
501 if (weaponType != null || weaponSize != null) {
502 Iterator<WeaponSpecAPI> iter = specs.iterator();
503 while (iter.hasNext()) {
504 WeaponSpecAPI curr = iter.next();
505 if ((weaponType != null && curr.getType() != weaponType) ||
506 (weaponSize != null && curr.getSize() != weaponSize)) {
507 iter.remove();
508 }
509 }
510 }
511
512
513 WeightedRandomPicker<WeaponSpecAPI> picker = new WeightedRandomPicker<WeaponSpecAPI>(random);
514 //picker.addAll(specs);
515 for (WeaponSpecAPI spec : specs) {
516 picker.add(spec, 1f * spec.getRarity());
517 }
518 WeaponSpecAPI pick = picker.pick();
519 if (pick == null) {
520 copy.commodity = NOTHING;
521 } else {
522 copy.commodity = WEAPON_PREFIX + pick.getWeaponId();
523 }
524 } else if (isFighterWing()) {
525 List<FighterWingSpecAPI> specs = Global.getSettings().getAllFighterWingSpecs();
526 Iterator<FighterWingSpecAPI> iter = specs.iterator();
527 while (iter.hasNext()) {
528 FighterWingSpecAPI curr = iter.next();
529 if (curr.hasTag(Tags.WING_NO_DROP)) iter.remove();
530 }
531 if (tier >= 0) {
532 iter = specs.iterator();
533 while (iter.hasNext()) {
534 FighterWingSpecAPI curr = iter.next();
535 if (curr.getTier() != tier) iter.remove();
536 }
537 }
538
539 if (!tags.isEmpty()) {
540 iter = specs.iterator();
541 while (iter.hasNext()) {
542 FighterWingSpecAPI curr = iter.next();
543 for (String tag : tags) {
544 boolean not = tag.startsWith("!");
545 tag = not ? tag.substring(1) : tag;
546 boolean has = curr.hasTag(tag);
547 if (not == has) {
548 iter.remove();
549 break;
550 }
551 }
552 }
553 }
554 WeightedRandomPicker<FighterWingSpecAPI> picker = new WeightedRandomPicker<FighterWingSpecAPI>(random);
555 //picker.addAll(specs);
556 for (FighterWingSpecAPI spec : specs) {
557 picker.add(spec, 1f * spec.getRarity());
558 }
559 FighterWingSpecAPI pick = picker.pick();
560 if (pick == null) {
561 copy.commodity = NOTHING;
562 } else {
563 copy.commodity = FIGHTER_PREFIX + pick.getId();
564 }
565 }
566
567
568 return copy;
569 }
570
571 @Override
572 public String toString() {
573 return super.toString() + " " + commodity;
574 }
575
576
577}
578
579
580
581
582
583
584
585
static SettingsAPI getSettings()
Definition Global.java:51
static FactoryAPI getFactory()
Definition Global.java:35
static SectorAPI getSector()
Definition Global.java:59
static WeightedRandomPicker< DropGroupRow > getPicker(String group)
DropGroupRow(String commodity, String group, float freq)
CargoStackAPI createCargoStack(CargoItemType type, Object data, CargoAPI cargo)
SpecialItemSpecAPI getSpecialItemSpec(String itemId)
< T > Collection< T > getAllSpecs(Class< T > c)
List< WeaponSpecAPI > getAllWeaponSpecs()
FighterWingSpecAPI getFighterWingSpec(String wingId)
List< SpecialItemSpecAPI > getAllSpecialItemSpecs()
WeaponSpecAPI getWeaponSpec(String weaponId)
List< FighterWingSpecAPI > getAllFighterWingSpecs()