264 if (dataOne.fightingStrength <= 0 && dataTwo.fightingStrength <= 0) {
267 if (dataOne.fightingStrength <= 0.1f) {
268 dataOne.fightingStrength = 0.1f;
270 if (dataTwo.fightingStrength <= 0.1f) {
271 dataTwo.fightingStrength = 0.1f;
274 FleetAutoresolveData winner, loser;
277 report(
"--------------------------------------------");
281 report(
"--------------------------------------------");
287 boolean loserEscaping =
false;
288 if ((dataOne.fightingStrength > dataTwo.fightingStrength || twoEscaping) && !oneEscaping) {
289 report(String.format(
"%s won engagement",
one.getNameWithFaction()));
293 loserEscaping =
true;
296 report(String.format(
"%s won engagement",
two.getNameWithFaction()));
300 loserEscaping =
true;
304 float winnerAdvantage = winner.fightingStrength / loser.fightingStrength;
307 if (winnerAdvantage > 10f) winnerAdvantage = 10f;
308 if (winnerAdvantage < 0.1f) winnerAdvantage = 0.1f;
311 float damageDealtToWinner = loser.fightingStrength / winnerAdvantage;
312 float damageDealtToLoser = winner.fightingStrength * winnerAdvantage;
314 damageDealtToWinner = 0f;
318 damageDealtToWinner *= damMult;
319 damageDealtToLoser *= damMult;
327 report(
"Applying damage to loser's ships");
328 report(
"--------------------------------------------");
329 Collections.shuffle(loser.members);
331 for (FleetMemberAutoresolveData data : loser.members) {
332 report(String.format(
"Remaining damage to loser: %02.2f", damageDealtToLoser));
334 damageDealtToLoser -= data.strength;
335 if (damageDealtToLoser < 0) damageDealtToLoser = 0;
338 for (FleetMemberAutoresolveData data : loser.members) {
339 if (data.member.getStatus().getHullFraction() > 0) {
340 result.getLoserResult().getRetreated().add(data.member);
342 result.getLoserResult().getDisabled().add(data.member);
348 report(
"Applying damage to winner's ships");
349 report(
"--------------------------------------------");
350 Collections.shuffle(winner.members);
352 boolean winnerCarrierLeft =
false;
353 for (FleetMemberAutoresolveData data : winner.members) {
354 if (!data.combatReady)
continue;
355 report(String.format(
"Remaining damage to winner: %02.2f", damageDealtToWinner));
357 damageDealtToWinner -= data.strength;
358 if (damageDealtToWinner < 0) damageDealtToWinner = 0;
360 if (data.member.isMothballed())
continue;
361 if (data.member.getStatus().getHullFraction() > 0 && data.member.getNumFlightDecks() > 0) {
362 winnerCarrierLeft =
true;
368 float deployedStrength = 0f;
369 float maxDeployedStrength = loser.fightingStrength * 2f;
370 for (FleetMemberAutoresolveData data : winner.members) {
371 if (!(data.member.getStatus().getHullFraction() > 0 || (data.member.isFighterWing() && winnerCarrierLeft))) {
372 deployedStrength += data.strength;
376 for (FleetMemberAutoresolveData data : winner.members) {
379 result.getWinnerResult().getDeployed().add(data.member);
381 result.getWinnerResult().getReserves().add(data.member);
384 if (data.member.getStatus().getHullFraction() > 0) {
385 if (deployedStrength < maxDeployedStrength) {
386 result.getWinnerResult().getDeployed().add(data.member);
387 deployedStrength += data.strength;
389 result.getWinnerResult().getReserves().add(data.member);
392 result.getWinnerResult().getDisabled().add(data.member);
399 ((EngagementResultForFleetImpl)
result.getWinnerResult()).setGoal(FleetGoal.ATTACK);
400 ((EngagementResultForFleetImpl)
result.getWinnerResult()).setWinner(
true);
403 ((EngagementResultForFleetImpl)
result.getLoserResult()).setGoal(FleetGoal.ESCAPE);
405 ((EngagementResultForFleetImpl)
result.getLoserResult()).setGoal(FleetGoal.ATTACK);
407 ((EngagementResultForFleetImpl)
result.getLoserResult()).setWinner(
false);
426 if (!winner.fleet.isAIMode()) {
443 for (FleetMemberAutoresolveData data : loser.members) {
444 data.member.setOwner(1);
454 float hullFraction) {
455 if (member.isFighterWing())
return;
456 if (hullFraction <= 0)
return;
458 float num = member.getStatus().getNumStatuses();
459 boolean someActiveRemaining =
false;
460 for (
int i = 0; i < num; i++) {
461 ShipVariantAPI variant = member.getVariant();
463 String slotId = member.getVariant().getModuleSlots().get(i - 1);
464 variant = variant.getModuleVariant(slotId);
467 if (variant.hasHullMod(HullMods.VASTBULK)) {
468 float dam = Math.min(hullFraction, 0.9f);
469 float hits = Math.min(5f, dam / 0.1f);
470 if (hits < 1) hits = 1;
472 for (
int j = 0; j < hits; j++) {
473 member.getStatus().applyHullFractionDamage(dam / hits, i);
474 member.getStatus().setHullFraction(i, 1f);
479 if (i > 0 && !Misc.isActiveModule(variant))
continue;
481 float damageMult = 1f;
483 damageMult = (float) Math.random();
487 float damage = hullFraction * damageMult;
488 if (damage <= 0)
continue;
490 member.getStatus().applyHullFractionDamage(damage, i);
492 float hits = Math.min(5f, damage / 0.1f);
493 if (hits < 1) hits = 1;
494 for (
int j = 0; j < hits; j++) {
495 member.getStatus().applyHullFractionDamage((damage / hits) + 0.001f, i);
498 if (i > 0 && member.getStatus().getHullFraction(i) <= 0) {
499 member.getStatus().setDetached(i,
true);
502 if (Misc.isActiveModule(variant) && (!member.getStatus().isDetached(i) || member.getStatus().getHullFraction(i) > 0)) {
503 someActiveRemaining =
true;
508 float farthestDetached = 0;
509 for (
int i = 1; i < num; i++) {
510 ShipVariantAPI variant = member.getVariant();
511 if (member.getStatus().isDetached(i)) {
512 String slotId = variant.getModuleSlots().get(i - 1);
513 ShipVariantAPI mv = member.getVariant().getModuleVariant(slotId);
514 if (!Misc.isActiveModule(mv))
continue;
516 WeaponSlotAPI slot = variant.getHullSpec().getWeaponSlotAPI(slotId);
517 float dist = slot.getLocation().length();
518 if (dist > farthestDetached) {
519 farthestDetached = dist;
524 for (
int i = 1; i < num; i++) {
525 ShipVariantAPI variant = member.getVariant();
526 if (!member.getStatus().isDetached(i)) {
527 String slotId = variant.getModuleSlots().get(i - 1);
528 ShipVariantAPI mv = member.getVariant().getModuleVariant(slotId);
529 if (mv.hasHullMod(HullMods.VASTBULK))
continue;
530 if (!Misc.isActiveModule(mv)) {
531 WeaponSlotAPI slot = variant.getHullSpec().getWeaponSlotAPI(slotId);
532 float dist = slot.getLocation().length();
533 if (dist <= farthestDetached + 200f) {
534 member.getStatus().setHullFraction(i, 0f);
535 member.getStatus().setDetached(i,
true);
543 if (!someActiveRemaining || hullFraction >= 1f) {
544 for (
int i = 0; i < num; i++) {
545 member.getStatus().setHullFraction(i, 0f);
547 member.getStatus().setDetached(i,
true);
555 float maxDamage,
boolean escaping,
boolean enemyEscaping) {
556 ShipHullSpecAPI hullSpec = data.member.getHullSpec();
558 float unscathed = 1f;
559 float lightDamage = 0f;
560 float mediumDamage = 0f;
561 float heavyDamage = 0f;
564 switch (hullSpec.getHullSize()) {
580 float maxDamageRatio = maxDamage / data.strength;
581 if (maxDamageRatio > 1) maxDamageRatio = 1;
582 if (maxDamageRatio <= 0) maxDamageRatio = 0;
584 if (maxDamageRatio >= 0.8f) {
589 }
else if (maxDamageRatio >= 0.6f) {
594 }
else if (maxDamageRatio >= 0.4f) {
599 }
else if (maxDamageRatio >= 0.2f) {
604 }
else if (maxDamageRatio > 0) {
619 mediumDamage *= 0.7f;
625 unscathed *= advantageInBattle;
626 lightDamage *= advantageInBattle;
628 float shieldRatio = data.shieldRatio;
633 disabled *= 1.5f - shieldRatio * 1f;
634 heavyDamage *= 1.4f - shieldRatio * 0.8f;
635 mediumDamage *= 1.3f - shieldRatio * 0.6f;
636 lightDamage *= 1.2f - shieldRatio * 0.4f;
637 unscathed *= 0.9f + shieldRatio * 0.2f;
640 if (data.member.isStation()) {
641 heavyDamage += disabled;
646 WeightedRandomPicker<FleetMemberBattleOutcome> picker =
new WeightedRandomPicker<FleetMemberBattleOutcome>();
648 picker.add(FleetMemberBattleOutcome.DISABLED, disabled);
649 picker.add(FleetMemberBattleOutcome.HEAVY_DAMAGE, heavyDamage);
650 picker.add(FleetMemberBattleOutcome.MEDIUM_DAMAGE, mediumDamage);
651 picker.add(FleetMemberBattleOutcome.LIGHT_DAMAGE, lightDamage);
652 picker.add(FleetMemberBattleOutcome.UNSCATHED, unscathed);
655 report(String.format(
"Disabled: %d, Heavy: %d, Medium: %d, Light: %d, Unscathed: %d (Shield ratio: %3.2f)",
656 (
int) disabled, (
int) heavyDamage, (
int) mediumDamage, (
int) lightDamage, (
int) unscathed, shieldRatio));
658 FleetMemberBattleOutcome outcome = picker.pick();
663 data.member.getStatus().resetDamageTaken();
668 report(String.format(
"%40s: disabled", data.member.getVariant().getFullDesignationWithHullName()));
672 report(String.format(
"%40s: heavy damage", data.member.getVariant().getFullDesignationWithHullName()));
673 damage = 0.7f + (float) Math.random() * 0.1f;
676 report(String.format(
"%40s: medium damage", data.member.getVariant().getFullDesignationWithHullName()));
677 damage = 0.45f + (float) Math.random() * 0.1f;
680 report(String.format(
"%40s: light damage", data.member.getVariant().getFullDesignationWithHullName()));
681 damage = 0.2f + (float) Math.random() * 0.1f;
684 report(String.format(
"%40s: unscathed", data.member.getVariant().getFullDesignationWithHullName()));
717 FleetMemberAutoresolveData data =
new FleetMemberAutoresolveData();
719 data.member = member;
720 ShipHullSpecAPI hullSpec = data.member.getHullSpec();
722 data.strength = 0.25f;
723 if (hullSpec.getShieldType() != ShieldType.NONE) {
724 data.shieldRatio = 0.5f;
726 data.combatReady =
false;
730 data.combatReady =
true;
736 MutableShipStatsAPI stats = data.member.getStats();
738 float normalizedHullStr = stats.getHullBonus().computeEffective(hullSpec.getHitpoints()) +
739 stats.getArmorBonus().computeEffective(hullSpec.getArmorRating()) * 10f;
741 float normalizedShieldStr = stats.getFluxCapacity().getModifiedValue() +
742 stats.getFluxDissipation().getModifiedValue() * 10f;
745 if (hullSpec.getShieldType() == ShieldType.NONE) {
746 normalizedShieldStr = 0;
748 float shieldFluxPerDamage = hullSpec.getBaseShieldFluxPerDamageAbsorbed();
749 shieldFluxPerDamage *= stats.getShieldAbsorptionMult().getModifiedValue() * stats.getShieldDamageTakenMult().getModifiedValue();;
750 if (shieldFluxPerDamage < 0.1f) shieldFluxPerDamage = 0.1f;
751 float shieldMult = 1f / shieldFluxPerDamage;
752 normalizedShieldStr *= shieldMult;
755 if (normalizedHullStr < 1) normalizedHullStr = 1;
756 if (normalizedShieldStr < 1) normalizedShieldStr = 1;
758 data.shieldRatio = normalizedShieldStr / (normalizedShieldStr + normalizedHullStr);
759 if (member.isStation()) {
760 data.shieldRatio = 0.5f;
775 float strength = Misc.getMemberStrength(member,
true,
true,
true);
777 strength *= 0.85f + 0.3f * (float) Math.random();
779 data.strength = Math.max(strength, 0.25f);