001package com.fs.starfarer.api.impl.campaign.rulecmd.salvage; 002 003import java.util.ArrayList; 004import java.util.List; 005import java.util.Map; 006 007import com.fs.starfarer.api.Global; 008import com.fs.starfarer.api.campaign.CampaignFleetAPI; 009import com.fs.starfarer.api.campaign.CargoAPI; 010import com.fs.starfarer.api.campaign.CargoStackAPI; 011import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.DataForEncounterSide; 012import com.fs.starfarer.api.campaign.FleetEncounterContextPlugin.FleetMemberData; 013import com.fs.starfarer.api.campaign.InteractionDialogAPI; 014import com.fs.starfarer.api.campaign.InteractionDialogPlugin; 015import com.fs.starfarer.api.campaign.SectorEntityToken; 016import com.fs.starfarer.api.campaign.rules.MemoryAPI; 017import com.fs.starfarer.api.combat.BattleCreationContext; 018import com.fs.starfarer.api.fleet.FleetMemberAPI; 019import com.fs.starfarer.api.impl.campaign.FleetEncounterContext; 020import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl; 021import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl.BaseFIDDelegate; 022import com.fs.starfarer.api.impl.campaign.FleetInteractionDialogPluginImpl.FIDConfig; 023import com.fs.starfarer.api.impl.campaign.ids.Drops; 024import com.fs.starfarer.api.impl.campaign.ids.Factions; 025import com.fs.starfarer.api.impl.campaign.ids.MemFlags; 026import com.fs.starfarer.api.impl.campaign.ids.Stats; 027import com.fs.starfarer.api.impl.campaign.ids.Tags; 028import com.fs.starfarer.api.impl.campaign.procgen.SalvageEntityGenDataSpec.DropData; 029import com.fs.starfarer.api.impl.campaign.rulecmd.BaseCommandPlugin; 030import com.fs.starfarer.api.impl.campaign.rulecmd.FireBest; 031import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.SalvageGenFromSeed.SDMParams; 032import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.SalvageGenFromSeed.SalvageDefenderModificationPlugin; 033import com.fs.starfarer.api.loading.WeaponSpecAPI; 034import com.fs.starfarer.api.util.Misc; 035import com.fs.starfarer.api.util.Misc.Token; 036 037/** 038 * SalvageDefenderInteraction 039 */ 040public class SalvageDefenderInteraction extends BaseCommandPlugin { 041 042 public boolean execute(String ruleId, InteractionDialogAPI dialog, List<Token> params, final Map<String, MemoryAPI> memoryMap) { 043 if (dialog == null) return false; 044 045 final SectorEntityToken entity = dialog.getInteractionTarget(); 046 final MemoryAPI memory = getEntityMemory(memoryMap); 047 048 final CampaignFleetAPI defenders = memory.getFleet("$defenderFleet"); 049 if (defenders == null) return false; 050 051 dialog.setInteractionTarget(defenders); 052 053 final FIDConfig config = new FIDConfig(); 054 config.leaveAlwaysAvailable = true; 055 config.showCommLinkOption = false; 056 config.showEngageText = false; 057 config.showFleetAttitude = false; 058 config.showTransponderStatus = false; 059 config.showWarningDialogWhenNotHostile = false; 060 config.alwaysAttackVsAttack = true; 061 config.impactsAllyReputation = true; 062 config.impactsEnemyReputation = false; 063 config.pullInAllies = false; 064 config.pullInEnemies = false; 065 config.pullInStations = false; 066 config.lootCredits = false; 067 068 config.firstTimeEngageOptionText = "Engage the automated defenses"; 069 config.afterFirstTimeEngageOptionText = "Re-engage the automated defenses"; 070 config.noSalvageLeaveOptionText = "Continue"; 071 072 config.dismissOnLeave = false; 073 config.printXPToDialog = true; 074 075 long seed = memory.getLong(MemFlags.SALVAGE_SEED); 076 config.salvageRandom = Misc.getRandom(seed, 75); 077 078 079 final FleetInteractionDialogPluginImpl plugin = new FleetInteractionDialogPluginImpl(config); 080 081 final InteractionDialogPlugin originalPlugin = dialog.getPlugin(); 082 config.delegate = new BaseFIDDelegate() { 083 @Override 084 public void notifyLeave(InteractionDialogAPI dialog) { 085 // nothing in there we care about keeping; clearing to reduce savefile size 086 defenders.getMemoryWithoutUpdate().clear(); 087 // there's a "standing down" assignment given after a battle is finished that we don't care about 088 defenders.clearAssignments(); 089 defenders.deflate(); 090 091 dialog.setPlugin(originalPlugin); 092 dialog.setInteractionTarget(entity); 093 094 //Global.getSector().getCampaignUI().clearMessages(); 095 096 if (plugin.getContext() instanceof FleetEncounterContext) { 097 FleetEncounterContext context = (FleetEncounterContext) plugin.getContext(); 098 if (context.didPlayerWinEncounterOutright()) { 099 100 SDMParams p = new SDMParams(); 101 p.entity = entity; 102 p.factionId = defenders.getFaction().getId(); 103 104 SalvageDefenderModificationPlugin plugin = Global.getSector().getGenericPlugins().pickPlugin( 105 SalvageDefenderModificationPlugin.class, p); 106 if (plugin != null) { 107 plugin.reportDefeated(p, entity, defenders); 108 } 109 110 memory.unset("$hasDefenders"); 111 memory.unset("$defenderFleet"); 112 memory.set("$defenderFleetDefeated", true); 113 entity.removeScriptsOfClass(FleetAdvanceScript.class); 114 FireBest.fire(null, dialog, memoryMap, "BeatDefendersContinue"); 115 } else { 116 boolean persistDefenders = false; 117 if (context.isEngagedInHostilities()) { 118 persistDefenders |= !Misc.getSnapshotMembersLost(defenders).isEmpty(); 119 for (FleetMemberAPI member : defenders.getFleetData().getMembersListCopy()) { 120 if (member.getStatus().needsRepairs()) { 121 persistDefenders = true; 122 break; 123 } 124 } 125 } 126 127 if (persistDefenders) { 128 if (!entity.hasScriptOfClass(FleetAdvanceScript.class)) { 129 defenders.setDoNotAdvanceAI(true); 130 defenders.setContainingLocation(entity.getContainingLocation()); 131 // somewhere far off where it's not going to be in terrain or whatever 132 defenders.setLocation(1000000, 1000000); 133 entity.addScript(new FleetAdvanceScript(defenders)); 134 } 135 memory.expire("$defenderFleet", 10); // defenders may have gotten damaged; persist them for a bit 136 } 137 dialog.dismiss(); 138 } 139 } else { 140 dialog.dismiss(); 141 } 142 } 143 @Override 144 public void battleContextCreated(InteractionDialogAPI dialog, BattleCreationContext bcc) { 145 bcc.aiRetreatAllowed = false; 146 bcc.objectivesAllowed = false; 147 bcc.enemyDeployAll = true; 148 } 149 @Override 150 public void postPlayerSalvageGeneration(InteractionDialogAPI dialog, FleetEncounterContext context, CargoAPI salvage) { 151 DataForEncounterSide winner = context.getWinnerData(); 152 DataForEncounterSide loser = context.getLoserData(); 153 154 if (winner == null || loser == null) return; 155 156 float playerContribMult = context.computePlayerContribFraction(); 157 158 List<DropData> dropRandom = new ArrayList<DropData>(); 159 List<DropData> dropValue = new ArrayList<DropData>(); 160 161 float valueMultFleet = Global.getSector().getPlayerFleet().getStats().getDynamic().getValue(Stats.BATTLE_SALVAGE_MULT_FLEET); 162 float valueModShips = context.getSalvageValueModPlayerShips(); 163 164 for (FleetMemberData data : winner.getEnemyCasualties()) { 165 // add at least one of each weapon that was present on the OMEGA ships, since these 166 // are hard to get; don't want them to be too RNG 167 if (data.getMember() != null && context.getBattle() != null) { 168 CampaignFleetAPI fleet = context.getBattle().getSourceFleet(data.getMember()); 169 170 if (fleet != null && fleet.getFaction().getId().equals(Factions.OMEGA)) { 171 for (String slotId : data.getMember().getVariant().getNonBuiltInWeaponSlots()) { 172 String weaponId = data.getMember().getVariant().getWeaponId(slotId); 173 if (weaponId == null) continue; 174 if (salvage.getNumWeapons(weaponId) <= 0) { 175 WeaponSpecAPI spec = Global.getSettings().getWeaponSpec(weaponId); 176 if (spec.hasTag(Tags.NO_DROP)) continue; 177 178 salvage.addWeapons(weaponId, 1); 179 } 180 } 181 } 182 183 if (fleet != null && 184 fleet.getFaction().getCustomBoolean(Factions.CUSTOM_NO_AI_CORES_FROM_AUTOMATED_DEFENSES)) { 185 continue; 186 } 187 } 188 if (config.salvageRandom.nextFloat() < playerContribMult) { 189 DropData drop = new DropData(); 190 drop.chances = 1; 191 drop.value = -1; 192 switch (data.getMember().getHullSpec().getHullSize()) { 193 case CAPITAL_SHIP: 194 drop.group = Drops.AI_CORES3; 195 drop.chances = 2; 196 break; 197 case CRUISER: 198 drop.group = Drops.AI_CORES3; 199 break; 200 case DESTROYER: 201 drop.group = Drops.AI_CORES2; 202 break; 203 case FIGHTER: 204 case FRIGATE: 205 drop.group = Drops.AI_CORES1; 206 break; 207 } 208 if (drop.group != null) { 209 dropRandom.add(drop); 210 } 211 } 212 } 213 214 float fuelMult = Global.getSector().getPlayerFleet().getStats().getDynamic().getValue(Stats.FUEL_SALVAGE_VALUE_MULT_FLEET); 215 //float fuel = salvage.getFuel(); 216 //salvage.addFuel((int) Math.round(fuel * fuelMult)); 217 218 CargoAPI extra = SalvageEntity.generateSalvage(config.salvageRandom, valueMultFleet + valueModShips, 1f, 1f, fuelMult, dropValue, dropRandom); 219 for (CargoStackAPI stack : extra.getStacksCopy()) { 220 if (stack.isFuelStack()) { 221 stack.setSize((int)(stack.getSize() * fuelMult)); 222 } 223 salvage.addFromStack(stack); 224 } 225 226 } 227 228 }; 229 230 231 dialog.setPlugin(plugin); 232 plugin.init(dialog); 233 234 return true; 235 } 236 237 238} 239 240 241 242