001package com.fs.starfarer.api.impl.campaign.missions; 002 003import java.util.ArrayList; 004import java.util.List; 005import java.util.Map; 006import java.util.Random; 007 008import com.fs.starfarer.api.Global; 009import com.fs.starfarer.api.campaign.FactionAPI; 010import com.fs.starfarer.api.campaign.FactionAPI.ShipPickMode; 011import com.fs.starfarer.api.campaign.FactionAPI.ShipPickParams; 012import com.fs.starfarer.api.campaign.InteractionDialogAPI; 013import com.fs.starfarer.api.campaign.PersonImportance; 014import com.fs.starfarer.api.campaign.econ.MarketAPI; 015import com.fs.starfarer.api.campaign.rules.MemoryAPI; 016import com.fs.starfarer.api.characters.PersonAPI; 017import com.fs.starfarer.api.combat.ShipVariantAPI; 018import com.fs.starfarer.api.fleet.FleetMemberAPI; 019import com.fs.starfarer.api.fleet.FleetMemberType; 020import com.fs.starfarer.api.fleet.ShipRolePick; 021import com.fs.starfarer.api.impl.campaign.DModManager; 022import com.fs.starfarer.api.impl.campaign.econ.impl.ShipQuality; 023import com.fs.starfarer.api.impl.campaign.fleets.DefaultFleetInflater; 024import com.fs.starfarer.api.impl.campaign.ids.Factions; 025import com.fs.starfarer.api.impl.campaign.ids.Ranks; 026import com.fs.starfarer.api.impl.campaign.ids.ShipRoles; 027import com.fs.starfarer.api.impl.campaign.ids.Tags; 028import com.fs.starfarer.api.impl.campaign.intel.bases.PirateBaseManager; 029import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithBarEvent; 030import com.fs.starfarer.api.util.Misc; 031import com.fs.starfarer.api.util.Misc.Token; 032import com.fs.starfarer.api.util.WeightedRandomPicker; 033 034public class SurplusShipHull extends HubMissionWithBarEvent { 035 036 public static float BASE_PRICE_MULT = 0.5f; 037 038 protected FleetMemberAPI member; 039 protected int price; 040 041 @Override 042 protected boolean create(MarketAPI createdAt, boolean barEvent) { 043 if (barEvent) { 044 List<String> posts = new ArrayList<String>(); 045 posts.add(Ranks.POST_SUPPLY_OFFICER); 046 if (Misc.isMilitary(createdAt)) { 047 posts.add(Ranks.POST_BASE_COMMANDER); 048 } 049 if (Misc.hasOrbitalStation(createdAt)) { 050 posts.add(Ranks.POST_STATION_COMMANDER); 051 } 052 053 String post = pickOne(posts); 054 setGiverPost(post); 055 if (post.equals(Ranks.POST_SUPPLY_OFFICER)) { 056 setGiverRank(Ranks.SPACE_COMMANDER); 057 setGiverImportance(pickImportance()); 058 } else if (post.equals(Ranks.POST_BASE_COMMANDER)) { 059 setGiverRank(Ranks.GROUND_COLONEL); 060 setGiverImportance(pickImportance()); 061 } else if (post.equals(Ranks.POST_STATION_COMMANDER)) { 062 setGiverRank(Ranks.SPACE_CAPTAIN); 063 setGiverImportance(pickHighImportance()); 064 } 065 if (Factions.PIRATES.equals(createdAt.getFaction().getId())) { 066 setGiverTags(Tags.CONTACT_UNDERWORLD); 067 setGiverFaction(Factions.PIRATES); 068 } else { 069 setGiverTags(Tags.CONTACT_MILITARY); 070 } 071 findOrCreateGiver(createdAt, false, false); 072 } 073 074 PersonAPI person = getPerson(); 075 if (person == null) return false; 076 MarketAPI market = person.getMarket(); 077 if (market == null) return false; 078 079 if (market.isPlayerOwned()) return false; 080 if (!Misc.isMilitary(market) && market.getSize() < 7) return false; 081 082 if (!setPersonMissionRef(person, "$sShip_ref")) { 083 return false; 084 } 085 086 if (barEvent) { 087 setGiverIsPotentialContactOnSuccess(); 088 } 089 090 //genRandom = Misc.random; 091 092 093 ShipPickParams params = new ShipPickParams(ShipPickMode.PRIORITY_THEN_ALL); 094 String role = pickRole(getQuality(), person.getFaction(), person.getImportance(), genRandom); 095 096 ShipVariantAPI variant = null; 097 for (int i = 0; i < 10; i++) { 098 List<ShipRolePick> picks = market.getFaction().pickShip(role, params, null, genRandom); 099 if (picks.isEmpty()) return false; 100 String variantId = picks.get(0).variantId; 101 variant = Global.getSettings().getVariant(variantId); 102 variant = Global.getSettings().getVariant(variant.getHullSpec().getHullId() + "_Hull").clone(); 103 if (variant.getHullSpec().hasTag(Tags.NO_SELL)) { 104 variant = null; 105 continue; 106 } 107 break; 108 } 109 if (variant == null) return false; 110 111 member = Global.getFactory().createFleetMember(FleetMemberType.SHIP, variant); 112 assignShipName(member, Factions.INDEPENDENT); 113 114 float quality = ShipQuality.getShipQuality(market, person.getFaction().getId()); 115 float averageDmods = DefaultFleetInflater.getAverageDmodsForQuality(quality); 116 int addDmods = DefaultFleetInflater.getNumDModsToAdd(variant, averageDmods, genRandom); 117 if (addDmods > 0) { 118 DModManager.setDHull(variant); 119 DModManager.addDMods(member, true, addDmods, genRandom); 120 } 121 member.getCrewComposition().setCrew(100000); 122 member.getRepairTracker().setCR(0.7f); 123 124 if (BASE_PRICE_MULT == 1f) { 125 price = (int) Math.round(variant.getHullSpec().getBaseValue()); 126 } else { 127 price = getRoundNumber(variant.getHullSpec().getBaseValue() * BASE_PRICE_MULT); 128 } 129 130 setRepFactionChangesTiny(); 131 setRepPersonChangesVeryLow(); 132 133 return true; 134 } 135 136 protected void updateInteractionDataImpl() { 137 // this is weird - in the accept() method, the mission is aborted, which unsets 138 // $sShip_ref. So: we use $sShip_ref2 in the ContactPostAccept rule 139 // and $sShip_ref2 has an expiration of 0, so it'll get unset on its own later. 140 set("$sShip_ref2", this); 141 142 set("$sShip_barEvent", isBarEvent()); 143 set("$sShip_hullSize", member.getHullSpec().getDesignation().toLowerCase()); 144 set("$sShip_hullClass", member.getHullSpec().getHullNameWithDashClass()); 145 set("$sShip_price", Misc.getWithDGS(price)); 146 set("$sShip_manOrWoman", getPerson().getManOrWoman()); 147 set("$sShip_rank", getPerson().getRank().toLowerCase()); 148 set("$sShip_rankAOrAn", getPerson().getRankArticle()); 149 set("$sShip_hisOrHer", getPerson().getHisOrHer()); 150 set("$sShip_member", member); 151 } 152 153 @Override 154 protected boolean callAction(String action, String ruleId, InteractionDialogAPI dialog, List<Token> params, 155 Map<String, MemoryAPI> memoryMap) { 156 if ("showShip".equals(action)) { 157 dialog.getVisualPanel().showFleetMemberInfo(member, true); 158 return true; 159 } else if ("showPerson".equals(action)) { 160 dialog.getVisualPanel().showPersonInfo(getPerson(), true); 161 return true; 162 } 163 return false; 164 } 165 166 @Override 167 public String getBaseName() { 168 return "Surplus Ship Hull"; // not used I don't think 169 } 170 171 @Override 172 public void accept(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) { 173 // it's just an transaction immediate transaction handled in rules.csv 174 // no intel item etc 175 176 currentStage = new Object(); // so that the abort() assumes the mission was successful 177 abort(); 178 } 179 180 public static String pickRole(float quality, FactionAPI faction, PersonImportance imp, Random random) { 181 WeightedRandomPicker<String> picker = new WeightedRandomPicker<String>(random); 182 183 float cycles = PirateBaseManager.getInstance().getDaysSinceStart() / 365f; 184 185 if (imp == PersonImportance.VERY_HIGH && cycles < 3) imp = PersonImportance.HIGH; 186 if (imp == PersonImportance.HIGH && cycles < 1) imp = PersonImportance.MEDIUM; 187 188 if (quality < 0.5f && imp.ordinal() > PersonImportance.MEDIUM.ordinal()) { 189 imp = PersonImportance.MEDIUM; 190 } 191 192 float w = faction.getDoctrine().getWarships() - 1f; 193 float c = faction.getDoctrine().getCarriers() - 1f; 194 float p = faction.getDoctrine().getPhaseShips() - 1f; 195 if (w + c + p < 1) w = 1; 196 197 switch (imp) { 198 case VERY_LOW: 199 picker.add(ShipRoles.COMBAT_SMALL, w); 200 picker.add(ShipRoles.COMBAT_MEDIUM, w/2f); 201 picker.add(ShipRoles.CARRIER_SMALL, c); 202 picker.add(ShipRoles.PHASE_SMALL, p); 203 break; 204 case LOW: 205 picker.add(ShipRoles.COMBAT_SMALL, w/2f); 206 picker.add(ShipRoles.COMBAT_MEDIUM, w); 207 picker.add(ShipRoles.CARRIER_SMALL, c); 208 picker.add(ShipRoles.PHASE_SMALL, p); 209 break; 210 case MEDIUM: 211 picker.add(ShipRoles.COMBAT_MEDIUM, w/2f); 212 picker.add(ShipRoles.COMBAT_LARGE, w); 213 picker.add(ShipRoles.CARRIER_SMALL, c/2f); 214 picker.add(ShipRoles.CARRIER_MEDIUM, c); 215 picker.add(ShipRoles.PHASE_SMALL, p/2f); 216 picker.add(ShipRoles.PHASE_MEDIUM, p); 217 break; 218 case HIGH: 219 picker.add(ShipRoles.COMBAT_MEDIUM, w/4f); 220 picker.add(ShipRoles.COMBAT_LARGE, w); 221 picker.add(ShipRoles.COMBAT_CAPITAL, w/2f); 222 picker.add(ShipRoles.CARRIER_MEDIUM, c); 223 picker.add(ShipRoles.CARRIER_LARGE, c/2f); 224 picker.add(ShipRoles.PHASE_MEDIUM, p); 225 picker.add(ShipRoles.PHASE_LARGE, p/2f); 226 break; 227 case VERY_HIGH: 228 picker.add(ShipRoles.COMBAT_MEDIUM, w/4f); 229 picker.add(ShipRoles.COMBAT_LARGE, w/2f); 230 picker.add(ShipRoles.COMBAT_CAPITAL, w); 231 picker.add(ShipRoles.CARRIER_MEDIUM, c/2f); 232 picker.add(ShipRoles.CARRIER_LARGE, c); 233 picker.add(ShipRoles.PHASE_MEDIUM, p/2f); 234 picker.add(ShipRoles.PHASE_LARGE, p); 235 picker.add(ShipRoles.PHASE_CAPITAL, p/2f); 236 break; 237 } 238 return picker.pick(); 239 } 240 241} 242