Starsector API
Loading...
Searching...
No Matches
BattleCreationPluginImpl.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.combat;
2
3import java.awt.Color;
4import java.util.ArrayList;
5import java.util.Arrays;
6import java.util.List;
7import java.util.Random;
8
9import org.lwjgl.util.vector.Vector2f;
10
11import com.fs.starfarer.api.Global;
12import com.fs.starfarer.api.campaign.BattleCreationPlugin;
13import com.fs.starfarer.api.campaign.CampaignFleetAPI;
14import com.fs.starfarer.api.campaign.CampaignTerrainAPI;
15import com.fs.starfarer.api.campaign.CustomCampaignEntityAPI;
16import com.fs.starfarer.api.campaign.LocationAPI;
17import com.fs.starfarer.api.campaign.PlanetAPI;
18import com.fs.starfarer.api.campaign.SectorEntityToken;
19import com.fs.starfarer.api.campaign.StarSystemAPI;
20import com.fs.starfarer.api.combat.BaseEveryFrameCombatPlugin;
21import com.fs.starfarer.api.combat.BattleCreationContext;
22import com.fs.starfarer.api.combat.CombatEngineAPI;
23import com.fs.starfarer.api.combat.MissileAPI;
24import com.fs.starfarer.api.combat.ShipAPI;
25import com.fs.starfarer.api.fleet.FleetGoal;
26import com.fs.starfarer.api.fleet.FleetMemberAPI;
27import com.fs.starfarer.api.impl.campaign.ids.Planets;
28import com.fs.starfarer.api.impl.campaign.ids.Tags;
29import com.fs.starfarer.api.impl.campaign.ids.Terrain;
30import com.fs.starfarer.api.impl.campaign.terrain.HyperspaceAbyssPluginImpl;
31import com.fs.starfarer.api.impl.campaign.terrain.PulsarBeamTerrainPlugin;
32import com.fs.starfarer.api.impl.campaign.terrain.StarCoronaTerrainPlugin;
33import com.fs.starfarer.api.input.InputEventAPI;
34import com.fs.starfarer.api.mission.FleetSide;
35import com.fs.starfarer.api.mission.MissionDefinitionAPI;
36import com.fs.starfarer.api.util.Misc;
37import com.fs.starfarer.api.util.WeightedRandomPicker;
38
39public class BattleCreationPluginImpl implements BattleCreationPlugin {
40
41 public interface NebulaTextureProvider {
42 String getNebulaTex();
44 }
45
46
47 public static float ABYSS_SHIP_SPEED_PENALTY = 20f;
48 public static float ABYSS_MISSILE_SPEED_PENALTY = 20f;
49 //public static float ABYSS_MISSILE_FLIGHT_TIME_MULT = 1.25f;
50 public static float ABYSS_OVERLAY_ALPHA = 0.2f;
51
52 protected float width, height;
53
54 protected float xPad = 2000;
55 protected float yPad = 2000;
56
57 protected List<String> objs = null;
58
59 protected float prevXDir = 0;
60 protected float prevYDir = 0;
61 protected boolean escape;
62
63 protected BattleCreationContext context;
64 protected MissionDefinitionAPI loader;
65
66 public void initBattle(final BattleCreationContext context, MissionDefinitionAPI loader) {
67
68 this.context = context;
69 this.loader = loader;
70 CampaignFleetAPI playerFleet = context.getPlayerFleet();
71 CampaignFleetAPI otherFleet = context.getOtherFleet();
72 FleetGoal playerGoal = context.getPlayerGoal();
73 FleetGoal enemyGoal = context.getOtherGoal();
74
75 // doesn't work for consecutive engagements; haven't investigated why
76 //Random random = Misc.getRandom(Misc.getNameBasedSeed(otherFleet), 23);
77
78 Random random = Misc.getRandom(Misc.getSalvageSeed(otherFleet) *
79 (long)otherFleet.getFleetData().getNumMembers(), 23);
80 //System.out.println("RNG: " + random.nextLong());
81 //random = new Random(1213123L);
82 //Random random = Misc.random;
83
84 escape = playerGoal == FleetGoal.ESCAPE || enemyGoal == FleetGoal.ESCAPE;
85
86 int maxFP = (int) Global.getSettings().getFloat("maxNoObjectiveBattleSize");
87 int fpOne = 0;
88 int fpTwo = 0;
89 for (FleetMemberAPI member : playerFleet.getFleetData().getMembersListCopy()) {
90 if (member.canBeDeployedForCombat() || playerGoal == FleetGoal.ESCAPE) {
91 fpOne += member.getUnmodifiedDeploymentPointsCost();
92 }
93 }
94 for (FleetMemberAPI member : otherFleet.getFleetData().getMembersListCopy()) {
95 if (member.canBeDeployedForCombat() || playerGoal == FleetGoal.ESCAPE) {
96 fpTwo += member.getUnmodifiedDeploymentPointsCost();
97 }
98 }
99
100 int smaller = Math.min(fpOne, fpTwo);
101
102 boolean withObjectives = smaller > maxFP;
103 if (!context.objectivesAllowed) {
104 withObjectives = false;
105 }
106
107 int numObjectives = 0;
108 if (withObjectives) {
109// if (fpOne + fpTwo > maxFP + 70) {
110// numObjectives = 3
111// numObjectives = 3 + (int)(Math.random() * 2.0);
112// } else {
113// numObjectives = 2 + (int)(Math.random() * 2.0);
114// }
115 if (fpOne + fpTwo > maxFP + 70) {
116 numObjectives = 4;
117 //numObjectives = 3 + (int)(Math.random() * 2.0);
118 } else {
119 numObjectives = 3 + random.nextInt(2);
120 //numObjectives = 2 + (int)(Math.random() * 2.0);
121 }
122 }
123
124 // shouldn't be possible, but..
125 if (numObjectives > 4) {
126 numObjectives = 4;
127 }
128
129 int baseCommandPoints = (int) Global.getSettings().getFloat("startingCommandPoints");
130
131 //
132 loader.initFleet(FleetSide.PLAYER, "ISS", playerGoal, false,
133 context.getPlayerCommandPoints() - baseCommandPoints,
134 (int) playerFleet.getCommanderStats().getCommandPoints().getModifiedValue() - baseCommandPoints);
135 loader.initFleet(FleetSide.ENEMY, "", enemyGoal, true,
136 (int) otherFleet.getCommanderStats().getCommandPoints().getModifiedValue() - baseCommandPoints);
137
138 List<FleetMemberAPI> playerShips = playerFleet.getFleetData().getCombatReadyMembersListCopy();
139 if (playerGoal == FleetGoal.ESCAPE) {
140 playerShips = playerFleet.getFleetData().getMembersListCopy();
141 }
142 for (FleetMemberAPI member : playerShips) {
143 loader.addFleetMember(FleetSide.PLAYER, member);
144 }
145
146
147 List<FleetMemberAPI> enemyShips = otherFleet.getFleetData().getCombatReadyMembersListCopy();
148 if (enemyGoal == FleetGoal.ESCAPE) {
149 enemyShips = otherFleet.getFleetData().getMembersListCopy();
150 }
151 for (FleetMemberAPI member : enemyShips) {
152 loader.addFleetMember(FleetSide.ENEMY, member);
153 }
154
155 width = 18000f;
156 height = 18000f;
157
158 if (escape) {
159 width = 18000f;
160 //height = 24000f;
161 height = 18000f;
162 } else if (withObjectives) {
163 width = 24000f;
164 if (numObjectives == 2) {
165 height = 14000f;
166 } else {
167 height = 18000f;
168 }
169 }
170
171 createMap(random);
172
173 context.setInitialDeploymentBurnDuration(1.5f);
174 context.setNormalDeploymentBurnDuration(6f);
175 context.setEscapeDeploymentBurnDuration(1.5f);
176
177 xPad = 2000f;
178 yPad = 3000f;
179
180 if (escape) {
181// addEscapeObjectives(loader, 4);
182// context.setInitialEscapeRange(7000f);
183// context.setFlankDeploymentDistance(9000f);
184 addEscapeObjectives(loader, 2, random);
185// context.setInitialEscapeRange(4000f);
186// context.setFlankDeploymentDistance(8000f);
187
188 context.setInitialEscapeRange(Global.getSettings().getFloat("escapeStartDistance"));
189 context.setFlankDeploymentDistance(Global.getSettings().getFloat("escapeFlankDistance"));
190
191 loader.addPlugin(new EscapeRevealPlugin(context));
192 } else {
193 if (withObjectives) {
194 addObjectives(loader, numObjectives, random);
195 context.setStandoffRange(height - 4500f);
196 } else {
197 context.setStandoffRange(6000f);
198 }
199
200 context.setFlankDeploymentDistance(height/2f); // matters for Force Concentration
201 }
202 }
203
204 public void afterDefinitionLoad(final CombatEngineAPI engine) {
205 if (coronaIntensity > 0 && (corona != null || pulsar != null)) {
206 String name = "Corona";
207 if (pulsar != null) name = pulsar.getTerrainName();
208 else if (corona != null) name = corona.getTerrainName();
209
210 final String name2 = name;
211
212// CombatFleetManagerAPI manager = engine.getFleetManager(FleetSide.PLAYER);
213// for (FleetMemberAPI member : manager.getReservesCopy()) {
214// }
215 final Object key1 = new Object();
216 final Object key2 = new Object();
217 final String icon = Global.getSettings().getSpriteName("ui", "icon_tactical_cr_penalty");
218 engine.addPlugin(new BaseEveryFrameCombatPlugin() {
219 @Override
220 public void advance(float amount, List<InputEventAPI> events) {
221 engine.maintainStatusForPlayerShip(key1, icon, name2, "reduced peak time", true);
222 engine.maintainStatusForPlayerShip(key2, icon, name2, "faster CR degradation", true);
223 }
224 });
225 }
226
227 if (abyssalDepth > 0) {
228 Color color = Misc.scaleColor(Color.white, 1f - abyssalDepth);
229 engine.setBackgroundColor(color);
230
231 color = Misc.scaleAlpha(Color.black, abyssalDepth * ABYSS_OVERLAY_ALPHA);
232 engine.setBackgroundGlowColor(color);
233 engine.setBackgroundGlowColorNonAdditive(true);
234
235 if (abyssalDepth > HyperspaceAbyssPluginImpl.DEPTH_THRESHOLD_FOR_NO_DUST_PARTICLES_IN_COMBAT) {
236 engine.setRenderStarfield(false);
237 }
238
239 final Object key1 = new Object();
240 final Object key2 = new Object();
241 final String icon = Global.getSettings().getSpriteName("ui", "icon_tactical_engine_damage");
242 final String name = "Abyssal hyperspace";
243 engine.addPlugin(new BaseEveryFrameCombatPlugin() {
244 @Override
245 public void advance(float amount, List<InputEventAPI> events) {
246 String percentSpeed = "-" + (int)Math.round(ABYSS_SHIP_SPEED_PENALTY) + "%";
247 String percentMissile = "-" + (int)Math.round(ABYSS_MISSILE_SPEED_PENALTY) + "%";
248 engine.maintainStatusForPlayerShip(key1, icon, name, percentSpeed + " top speed", true);
249 engine.maintainStatusForPlayerShip(key2, icon, name, percentMissile + " missle speed / range", true);
250
251 String modId = "abyssal";
252 float modW = -0.0f * abyssalDepth;
253 float modL = -0.33f * abyssalDepth;
254 float modG = -0.5f * abyssalDepth;
255
256 for (ShipAPI curr : engine.getShips()) {
257 if (curr.isHulk()) continue;
258
259 curr.getEngineController().fadeToOtherColor(this, Color.black, null, 1f, abyssalDepth * 0.4f);
260 curr.getEngineController().extendFlame(this, modL, modW, modG);
261
262 curr.getMutableStats().getMaxSpeed().modifyMult(modId,
264 curr.getMutableStats().getMissileWeaponRangeBonus().modifyMult(modId,
266 curr.getMutableStats().getMissileMaxSpeedBonus().modifyMult(modId,
268 }
269
270 for (MissileAPI missile : engine.getMissiles()) {
271 missile.getEngineController().fadeToOtherColor(this, Color.black, null, 1f, abyssalDepth * 0.4f);
272 missile.getEngineController().extendFlame(this, modL, modW, 0f);
273 }
274
275 }
276 });
277
278 }
279 }
280
281
282 protected float abyssalDepth = 0f;
283 protected float coronaIntensity = 0f;
284 protected StarCoronaTerrainPlugin corona = null;
285 protected PulsarBeamTerrainPlugin pulsar = null;
286 protected void createMap(Random random) {
287 loader.initMap((float)-width/2f, (float)width/2f, (float)-height/2f, (float)height/2f);
288
289 CampaignFleetAPI playerFleet = context.getPlayerFleet();
290 String nebulaTex = null;
291 String nebulaMapTex = null;
292 boolean inNebula = false;
293
294 boolean protectedFromCorona = false;
295 for (CustomCampaignEntityAPI curr : playerFleet.getContainingLocation().getCustomEntitiesWithTag(Tags.PROTECTS_FROM_CORONA_IN_BATTLE)) {
296 if (Misc.getDistance(curr.getLocation(), playerFleet.getLocation()) <= curr.getRadius() + Global.getSector().getPlayerFleet().getRadius() + 10f) {
297 protectedFromCorona = true;
298 break;
299 }
300 }
301
302 abyssalDepth = Misc.getAbyssalDepth(playerFleet);
303
304 float numRings = 0;
305
306 Color coronaColor = null;
307 // this assumes that all nebula in a system are of the same color
308 for (CampaignTerrainAPI terrain : playerFleet.getContainingLocation().getTerrainCopy()) {
309 //if (terrain.getType().equals(Terrain.NEBULA)) {
310 if (terrain.getPlugin() instanceof NebulaTextureProvider) {
311 if (terrain.getPlugin().containsEntity(playerFleet)) {
312 inNebula = true;
313 if (terrain.getPlugin() instanceof NebulaTextureProvider) {
314 NebulaTextureProvider provider = (NebulaTextureProvider) terrain.getPlugin();
315 nebulaTex = provider.getNebulaTex();
316 nebulaMapTex = provider.getNebulaMapTex();
317 }
318 } else {
319 if (nebulaTex == null) {
320 if (terrain.getPlugin() instanceof NebulaTextureProvider) {
321 NebulaTextureProvider provider = (NebulaTextureProvider) terrain.getPlugin();
322 nebulaTex = provider.getNebulaTex();
323 nebulaMapTex = provider.getNebulaMapTex();
324 }
325 }
326 }
327 } else if (terrain.getPlugin() instanceof StarCoronaTerrainPlugin && pulsar == null && !protectedFromCorona) {
328 StarCoronaTerrainPlugin plugin = (StarCoronaTerrainPlugin) terrain.getPlugin();
329 if (plugin.containsEntity(playerFleet)) {
330 float angle = Misc.getAngleInDegrees(terrain.getLocation(), playerFleet.getLocation());
331 Color color = plugin.getAuroraColorForAngle(angle);
332 float intensity = plugin.getIntensityAtPoint(playerFleet.getLocation());
333 intensity = 0.4f + 0.6f * intensity;
334 int alpha = (int)(80f * intensity);
335 color = Misc.setAlpha(color, alpha);
336 if (coronaColor == null || coronaColor.getAlpha() < alpha) {
337 coronaColor = color;
338 coronaIntensity = intensity;
339 corona = plugin;
340 }
341 }
342 } else if (terrain.getPlugin() instanceof PulsarBeamTerrainPlugin && !protectedFromCorona) {
343 PulsarBeamTerrainPlugin plugin = (PulsarBeamTerrainPlugin) terrain.getPlugin();
344 if (plugin.containsEntity(playerFleet)) {
345 float angle = Misc.getAngleInDegreesStrict(terrain.getLocation(), playerFleet.getLocation());
346 Color color = plugin.getPulsarColorForAngle(angle);
347 float intensity = plugin.getIntensityAtPoint(playerFleet.getLocation());
348 intensity = 0.4f + 0.6f * intensity;
349 int alpha = (int)(80f * intensity);
350 color = Misc.setAlpha(color, alpha);
351 if (coronaColor == null || coronaColor.getAlpha() < alpha) {
352 coronaColor = color;
353 coronaIntensity = intensity;
354 pulsar = plugin;
355 corona = null;
356 }
357 }
358 } else if (terrain.getType().equals(Terrain.RING)) {
359 if (terrain.getPlugin().containsEntity(playerFleet)) {
360 numRings++;
361 }
362 }
363 }
364 if (nebulaTex != null) {
365 loader.setNebulaTex(nebulaTex);
366 loader.setNebulaMapTex(nebulaMapTex);
367 }
368
369 if (coronaColor != null) {
370 loader.setBackgroundGlowColor(coronaColor);
371 }
372
373 int numNebula = 15;
374 if (inNebula) {
375 numNebula = 100;
376 }
377 if (!inNebula && playerFleet.isInHyperspace()) {
378 numNebula = 0;
379 }
380
381 for (int i = 0; i < numNebula; i++) {
382 float x = random.nextFloat() * width - width/2;
383 float y = random.nextFloat() * height - height/2;
384 float radius = 100f + random.nextFloat() * 400f;
385 if (inNebula) {
386 radius += 100f + 500f * random.nextFloat();
387 }
388 loader.addNebula(x, y, radius);
389 }
390
391 float numAsteroidsWithinRange = countNearbyAsteroids(playerFleet);
392
393 int numAsteroids = Math.min(400, (int)((numAsteroidsWithinRange + 1f) * 20f));
394
395 loader.addAsteroidField(0, 0, random.nextFloat() * 360f, width,
396 20f, 70f, numAsteroids);
397
398 if (numRings > 0) {
399 int numRingAsteroids = (int) (numRings * 300 + (numRings * 600f) * random.nextFloat());
400 //int numRingAsteroids = (int) (numRings * 1600 + (numRings * 600f) * (float) Math.random());
401 if (numRingAsteroids > 1500) {
402 numRingAsteroids = 1500;
403 }
404 loader.addRingAsteroids(0, 0, random.nextFloat() * 360f, width,
405 100f, 200f, numRingAsteroids);
406 }
407
408 //setRandomBackground(loader);
409 loader.setBackgroundSpriteName(playerFleet.getContainingLocation().getBackgroundTextureFilename());
410// loader.setBackgroundSpriteName("graphics/backgrounds/hyperspace_bg_cool.jpg");
411// loader.setBackgroundSpriteName("graphics/ships/onslaught/onslaught_base.png");
412
413 if (playerFleet.getContainingLocation() == Global.getSector().getHyperspace()) {
414 loader.setHyperspaceMode(true);
415 } else {
416 loader.setHyperspaceMode(false);
417 }
418
419 //addMultiplePlanets();
421 }
422
423 protected void addClosestPlanet() {
424 float bgWidth = 2048f;
425 float bgHeight = 2048f;
426
427 PlanetAPI planet = getClosestPlanet(context.getPlayerFleet());
428 if (planet == null) return;
429
430 float dist = Vector2f.sub(context.getPlayerFleet().getLocation(), planet.getLocation(), new Vector2f()).length() - planet.getRadius();
431 if (dist < 0) dist = 0;
432 float baseRadius = planet.getRadius();
433 float scaleFactor = 1.5f;
434 float maxRadius = 500f;
435 float minRadius = 100f;
436
437// if (planet.isStar()) {
438// scaleFactor = 0.01f;
439// maxRadius = 20f;
440// }
441
442 float maxDist = SINGLE_PLANET_MAX_DIST - planet.getRadius();
443 if (maxDist < 1) maxDist = 1;
444
445
446 boolean playerHasStation = false;
447 boolean enemyHasStation = false;
448
449 for (FleetMemberAPI curr : context.getPlayerFleet().getFleetData().getMembersListCopy()) {
450 if (curr.isStation()) {
451 playerHasStation = true;
452 break;
453 }
454 }
455
456 for (FleetMemberAPI curr : context.getOtherFleet().getFleetData().getMembersListCopy()) {
457 if (curr.isStation()) {
458 enemyHasStation = true;
459 break;
460 }
461 }
462
463 float planetYOffset = 0;
464
465 if (playerHasStation) {
466 planetYOffset = -bgHeight / 2f * 0.5f;
467 }
468 if (enemyHasStation) {
469 planetYOffset = bgHeight / 2f * 0.5f;
470 }
471
472
473 float f = (maxDist - dist) / maxDist * 0.65f + 0.35f;
474 float radius = baseRadius * f * scaleFactor;
475 if (radius > maxRadius) radius = maxRadius;
476 if (radius < minRadius) radius = minRadius;
477 loader.setPlanetBgSize(bgWidth * f, bgHeight * f);
478 loader.addPlanet(0f, planetYOffset, radius, planet, 0f, true);
479 }
480
481 protected void addMultiplePlanets() {
482 float bgWidth = 2048f;
483 float bgHeight = 2048f;
484 loader.setPlanetBgSize(bgWidth, bgHeight);
485
486
487 List<NearbyPlanetData> planets = getNearbyPlanets(context.getPlayerFleet());
488 if (!planets.isEmpty()) {
489 float maxDist = PLANET_MAX_DIST;
490 for (NearbyPlanetData data : planets) {
491 float dist = Vector2f.sub(context.getPlayerFleet().getLocation(), data.planet.getLocation(), new Vector2f()).length();
492 float baseRadius = data.planet.getRadius();
493 float scaleFactor = 1.5f;
494 float maxRadius = 500f;
495
496 if (data.planet.isStar()) {
497 // skip stars in combat, bright and annoying
498 continue;
499// scaleFactor = 0.1f;
500// maxRadius = 50f;
501 }
502
503 float f = (maxDist - dist) / maxDist * 0.65f + 0.35f;
504 float radius = baseRadius * f * scaleFactor;
505 if (radius > maxRadius) radius = maxRadius;
506
507 loader.addPlanet(data.offset.x * bgWidth / PLANET_AREA_WIDTH * scaleFactor,
508 data.offset.y * bgHeight / PLANET_AREA_HEIGHT * scaleFactor,
509 radius, data.planet.getTypeId(), 0f, true);
510 }
511
512 }
513 }
514
515
516 protected void setRandomBackground(MissionDefinitionAPI loader, Random random) {
517 // these have to be loaded using the graphics section in settings.json
518 String [] bgs = new String [] {
519 "graphics/backgrounds/background1.jpg",
520 "graphics/backgrounds/background2.jpg",
521 "graphics/backgrounds/background3.jpg",
522 "graphics/backgrounds/background4.jpg"
523 };
524 String pick = bgs[Math.min(bgs.length - 1, (int)(random.nextDouble() * bgs.length))];
525 loader.setBackgroundSpriteName(pick);
526 }
527
528 protected static String COMM = "comm_relay";
529 protected static String SENSOR = "sensor_array";
530 protected static String NAV = "nav_buoy";
531
532 protected void addObjectives(MissionDefinitionAPI loader, int num, Random random) {
533 //if (true) return;
534
535 objs = new ArrayList<String>(Arrays.asList(new String [] {
536 SENSOR,
537 SENSOR,
538 NAV,
539 NAV,
540 //COMM,
541 //COMM,
542 }));
543
544 if (num == 2) { // minimum is 3 now, so this shouldn't happen
545 objs = new ArrayList<String>(Arrays.asList(new String [] {
546 SENSOR,
547 SENSOR,
548 NAV,
549 NAV,
550 COMM,
551 }));
552 addObjectiveAt(0.25f, 0.5f, 0f, 0f, random);
553 addObjectiveAt(0.75f, 0.5f, 0f, 0f, random);
554 } else if (num == 3) {
555 float r = random.nextFloat();
556 if (r < 0.33f) {
557 addObjectiveAt(0.25f, 0.7f, 1f, 1f, random);
558 addObjectiveAt(0.25f, 0.3f, 1f, 1f, random);
559 addObjectiveAt(0.75f, 0.5f, 1f, 1f, COMM, random);
560 } else if (r < 0.67f) {
561 addObjectiveAt(0.75f, 0.7f, 1f, 1f, random);
562 addObjectiveAt(0.75f, 0.3f, 1f, 1f, random);
563 addObjectiveAt(0.25f, 0.5f, 1f, 1f, COMM, random);
564 } else {
565 if (random.nextFloat() < 0.5f) {
566 addObjectiveAt(0.22f, 0.7f, 1f, 1f, random);
567 addObjectiveAt(0.5f, 0.5f, 1f, 1f, COMM, random);
568 addObjectiveAt(0.78f, 0.3f, 1f, 1f, random);
569 } else {
570 addObjectiveAt(0.22f, 0.3f, 1f, 1f, random);
571 addObjectiveAt(0.5f, 0.5f, 1f, 1f, COMM, random);
572 addObjectiveAt(0.78f, 0.7f, 1f, 1f, random);
573 }
574 }
575 } else if (num == 4) {
576 float r = random.nextFloat();
577 if (r < 0.33f) {
578 String [] maybeRelays = pickCommRelays(2, 2, false, true, true, false, random);
579 addObjectiveAt(0.25f, 0.25f, 2f, 1f, maybeRelays[0], random);
580 addObjectiveAt(0.25f, 0.75f, 2f, 1f, maybeRelays[1], random);
581 addObjectiveAt(0.75f, 0.25f, 2f, 1f, maybeRelays[2], random);
582 addObjectiveAt(0.75f, 0.75f, 2f, 1f, maybeRelays[3], random);
583 } else if (r < 0.67f) {
584 String [] maybeRelays = pickCommRelays(1, 2, true, false, true, false, random);
585 addObjectiveAt(0.25f, 0.5f, 1f, 1f, maybeRelays[0], random);
586 addObjectiveAt(0.5f, 0.75f, 1f, 1f, maybeRelays[1], random);
587 addObjectiveAt(0.75f, 0.5f, 1f, 1f, maybeRelays[2], random);
588 addObjectiveAt(0.5f, 0.25f, 1f, 1f, maybeRelays[3], random);
589 } else {
590 if (random.nextFloat() < 0.5f) {
591 String [] maybeRelays = pickCommRelays(1, 2, true, false, true, false, random);
592 addObjectiveAt(0.25f, 0.25f, 1f, 0f, maybeRelays[0], random);
593 addObjectiveAt(0.4f, 0.6f, 1f, 0f, maybeRelays[1], random);
594 addObjectiveAt(0.6f, 0.4f, 1f, 0f, maybeRelays[2], random);
595 addObjectiveAt(0.75f, 0.75f, 1f, 0f, maybeRelays[3], random);
596 } else {
597 String [] maybeRelays = pickCommRelays(1, 2, false, true, false, true, random);
598 addObjectiveAt(0.25f, 0.75f, 1f, 0f, maybeRelays[0], random);
599 addObjectiveAt(0.4f, 0.4f, 1f, 0f, maybeRelays[1], random);
600 addObjectiveAt(0.6f, 0.6f, 1f, 0f, maybeRelays[2], random);
601 addObjectiveAt(0.75f, 0.25f, 1f, 0f, maybeRelays[3], random);
602 }
603 }
604 }
605 }
606
607 protected String [] pickCommRelays(int min, int max, boolean comm1, boolean comm2, boolean comm3, boolean comm4, Random random) {
608 String [] result = new String [4];
609
610 WeightedRandomPicker<Integer> picker = new WeightedRandomPicker<Integer>(random);
611 if (comm1) picker.add(0);
612 if (comm2) picker.add(1);
613 if (comm3) picker.add(2);
614 if (comm4) picker.add(3);
615
616 int num = min + random.nextInt(max - min + 1);
617
618 for (int i = 0; i < num && !picker.isEmpty(); i++) {
619 result[picker.pickAndRemove()] = COMM;
620 }
621 return result;
622 }
623
624
625 protected void addEscapeObjectives(MissionDefinitionAPI loader, int num, Random random) {
626 objs = new ArrayList<String>(Arrays.asList(new String [] {
627 SENSOR,
628 SENSOR,
629 NAV,
630 NAV,
631 COMM,
632 }));
633
634 if (num == 2) {
635 float r = random.nextFloat();
636 if (r < 0.33f) {
637 addObjectiveAt(0.25f, 0.25f, 1f, 1f, random);
638 addObjectiveAt(0.75f, 0.75f, 1f, 1f, random);
639 } else if (r < 0.67f) {
640 addObjectiveAt(0.75f, 0.25f, 1f, 1f, random);
641 addObjectiveAt(0.25f, 0.75f, 1f, 1f, random);
642 } else {
643 addObjectiveAt(0.5f, 0.25f, 4f, 2f, random);
644 addObjectiveAt(0.5f, 0.75f, 4f, 2f, random);
645 }
646 } else if (num == 3) {
647 float r = random.nextFloat();
648 if (r < 0.33f) {
649 addObjectiveAt(0.25f, 0.75f, 1f, 1f, random);
650 addObjectiveAt(0.25f, 0.25f, 1f, 1f, random);
651 addObjectiveAt(0.75f, 0.5f, 1f, 6f, random);
652 } else if (r < 0.67f) {
653 addObjectiveAt(0.25f, 0.5f, 1f, 6f, random);
654 addObjectiveAt(0.75f, 0.75f, 1f, 1f, random);
655 addObjectiveAt(0.75f, 0.25f, 1f, 1f, random);
656 } else {
657 addObjectiveAt(0.5f, 0.25f, 4f, 1f, random);
658 addObjectiveAt(0.5f, 0.5f, 4f, 1f, random);
659 addObjectiveAt(0.5f, 0.75f, 4f, 1f, random);
660 }
661 } else if (num == 4) {
662 float r = random.nextFloat();
663 if (r < 0.33f) {
664 addObjectiveAt(0.25f, 0.25f, 1f, 1f, random);
665 addObjectiveAt(0.25f, 0.75f, 1f, 1f, random);
666 addObjectiveAt(0.75f, 0.25f, 1f, 1f, random);
667 addObjectiveAt(0.75f, 0.75f, 1f, 1f, random);
668 } else if (r < 0.67f) {
669 addObjectiveAt(0.35f, 0.25f, 2f, 0f, random);
670 addObjectiveAt(0.65f, 0.35f, 2f, 0f, random);
671 addObjectiveAt(0.5f, 0.6f, 4f, 1f, random);
672 addObjectiveAt(0.5f, 0.8f, 4f, 1f, random);
673 } else {
674 addObjectiveAt(0.65f, 0.25f, 2f, 0f, random);
675 addObjectiveAt(0.35f, 0.35f, 2f, 0f, random);
676 addObjectiveAt(0.5f, 0.6f, 4f, 1f, random);
677 addObjectiveAt(0.5f, 0.8f, 4f, 1f, random);
678 }
679 }
680 }
681
682 protected void addObjectiveAt(float xMult, float yMult, float xOff, float yOff, Random random) {
683 addObjectiveAt(xMult, yMult, xOff, yOff, null, random);
684 }
685 protected void addObjectiveAt(float xMult, float yMult, float xOff, float yOff, String type, Random random) {
686 //String type = pickAny();
687 if (type == null) {
688 type = pickAny(random);
689 if (objs != null && objs.size() > 0) {
690 int index = (int) (random.nextDouble() * objs.size());
691 type = objs.remove(index);
692 }
693 }
694
695 float minX = -width/2 + xPad;
696 float minY = -height/2 + yPad;
697
698 float x = (width - xPad * 2f) * xMult + minX;
699 float y = (height - yPad * 2f) * yMult + minY;
700
701 x = ((int) x / 1000) * 1000f;
702 y = ((int) y / 1000) * 1000f;
703
704 float offsetX = Math.round((random.nextFloat() - 0.5f) * xOff * 1f) * 1000f;
705 float offsetY = Math.round((random.nextFloat() - 0.5f) * yOff * 1f) * 1000f;
706
707// offsetX = 0;
708// offsetY = 0;
709
710 float xDir = (float) Math.signum(offsetX);
711 float yDir = (float) Math.signum(offsetY);
712
713 if (xDir == prevXDir && xOff > 0) {
714 xDir = -xDir;
715 offsetX = Math.abs(offsetX) * -prevXDir;
716 }
717
718 if (yDir == prevYDir && yOff > 0) {
719 yDir = -yDir;
720 offsetY = Math.abs(offsetY) * -prevYDir;
721 }
722
723 prevXDir = xDir;
724 prevYDir = yDir;
725
726 x += offsetX;
727 y += offsetY;
728
729 loader.addObjective(x, y, type);
730
731 if (random.nextFloat() > 0.6f && loader.hasNebula()) {
732 float nebulaSize = random.nextFloat() * 1500f + 500f;
733 loader.addNebula(x, y, nebulaSize);
734 }
735 }
736
737 protected String pickAny(Random random) {
738 float r = random.nextFloat();
739 if (r < 0.33f) return "nav_buoy";
740 else if (r < 0.67f) return "sensor_array";
741 else return "comm_relay";
742 }
743
744 protected float countNearbyAsteroids(CampaignFleetAPI playerFleet) {
745 float numAsteroidsWithinRange = 0;
746 LocationAPI loc = playerFleet.getContainingLocation();
747 if (loc instanceof StarSystemAPI) {
748 StarSystemAPI system = (StarSystemAPI) loc;
749 List<SectorEntityToken> asteroids = system.getAsteroids();
750 for (SectorEntityToken asteroid : asteroids) {
751 float range = Vector2f.sub(playerFleet.getLocation(), asteroid.getLocation(), new Vector2f()).length();
752 if (range < 300) numAsteroidsWithinRange ++;
753 }
754 }
755 return numAsteroidsWithinRange;
756 }
757
758 protected static class NearbyPlanetData {
759 protected Vector2f offset;
760 protected PlanetAPI planet;
761 public NearbyPlanetData(Vector2f offset, PlanetAPI planet) {
762 this.offset = offset;
763 this.planet = planet;
764 }
765 }
766
767 protected static float PLANET_AREA_WIDTH = 2000;
768 protected static float PLANET_AREA_HEIGHT = 2000;
769 protected static float PLANET_MAX_DIST = (float) Math.sqrt(PLANET_AREA_WIDTH/2f * PLANET_AREA_WIDTH/2f + PLANET_AREA_HEIGHT/2f * PLANET_AREA_WIDTH/2f);
770
771 protected static float SINGLE_PLANET_MAX_DIST = 1000f;
772
773 protected List<NearbyPlanetData> getNearbyPlanets(CampaignFleetAPI playerFleet) {
774 LocationAPI loc = playerFleet.getContainingLocation();
775 List<NearbyPlanetData> result = new ArrayList<NearbyPlanetData>();
776 if (loc instanceof StarSystemAPI) {
777 StarSystemAPI system = (StarSystemAPI) loc;
778 List<PlanetAPI> planets = system.getPlanets();
779 for (PlanetAPI planet : planets) {
780 float diffX = planet.getLocation().x - playerFleet.getLocation().x;
781 float diffY = planet.getLocation().y - playerFleet.getLocation().y;
782
783 if (Math.abs(diffX) < PLANET_AREA_WIDTH/2f && Math.abs(diffY) < PLANET_AREA_HEIGHT/2f) {
784 result.add(new NearbyPlanetData(new Vector2f(diffX, diffY), planet));
785 }
786 }
787 }
788 return result;
789 }
790
791 protected PlanetAPI getClosestPlanet(CampaignFleetAPI playerFleet) {
792 LocationAPI loc = playerFleet.getContainingLocation();
793 PlanetAPI closest = null;
794 float minDist = Float.MAX_VALUE;
795 if (loc instanceof StarSystemAPI) {
796 StarSystemAPI system = (StarSystemAPI) loc;
797 List<PlanetAPI> planets = system.getPlanets();
798 for (PlanetAPI planet : planets) {
799 if (planet.isStar()) continue;
800 if (Planets.PLANET_LAVA.equals(planet.getTypeId())) continue;
801 if (Planets.PLANET_LAVA_MINOR.equals(planet.getTypeId())) continue;
802 if (planet.getSpec().isDoNotShowInCombat()) continue;
803
804 float dist = Vector2f.sub(context.getPlayerFleet().getLocation(), planet.getLocation(), new Vector2f()).length();
805 if (dist < minDist && dist < SINGLE_PLANET_MAX_DIST) {
806 closest = planet;
807 minDist = dist;
808 }
809 }
810 }
811 return closest;
812 }
813}
814
815
816
817
static SettingsAPI getSettings()
Definition Global.java:51
static SectorAPI getSector()
Definition Global.java:59
List< NearbyPlanetData > getNearbyPlanets(CampaignFleetAPI playerFleet)
void addEscapeObjectives(MissionDefinitionAPI loader, int num, Random random)
void addObjectiveAt(float xMult, float yMult, float xOff, float yOff, String type, Random random)
void addObjectives(MissionDefinitionAPI loader, int num, Random random)
void addObjectiveAt(float xMult, float yMult, float xOff, float yOff, Random random)
String[] pickCommRelays(int min, int max, boolean comm1, boolean comm2, boolean comm3, boolean comm4, Random random)
void initBattle(final BattleCreationContext context, MissionDefinitionAPI loader)
void setRandomBackground(MissionDefinitionAPI loader, Random random)
String getSpriteName(String category, String id)