001package com.fs.starfarer.api.impl.campaign.missions.academy; 002 003import java.awt.Color; 004import java.util.ArrayList; 005import java.util.HashMap; 006import java.util.List; 007import java.util.Map; 008 009import org.lwjgl.util.vector.Vector2f; 010 011import com.fs.starfarer.api.Global; 012import com.fs.starfarer.api.campaign.FactionAPI; 013import com.fs.starfarer.api.campaign.InteractionDialogAPI; 014import com.fs.starfarer.api.campaign.StarSystemAPI; 015import com.fs.starfarer.api.campaign.econ.MarketAPI; 016import com.fs.starfarer.api.campaign.rules.MemoryAPI; 017import com.fs.starfarer.api.characters.ImportantPeopleAPI.PersonDataAPI; 018import com.fs.starfarer.api.characters.PersonAPI; 019import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepRewards; 020import com.fs.starfarer.api.impl.campaign.ids.Factions; 021import com.fs.starfarer.api.impl.campaign.ids.FleetTypes; 022import com.fs.starfarer.api.impl.campaign.ids.Ranks; 023import com.fs.starfarer.api.impl.campaign.missions.DelayedFleetEncounter; 024import com.fs.starfarer.api.ui.TooltipMakerAPI; 025import com.fs.starfarer.api.util.Misc; 026import com.fs.starfarer.api.util.Misc.Token; 027import com.fs.starfarer.api.util.WeightedRandomPicker; 028 029@SuppressWarnings("unchecked") 030public class GADeliverVIP extends GABaseMission { 031 032 033 public static float MISSION_DAYS = 60f; 034 public static float PROB_KANTA = 0.1f; 035 public static float PROB_MERC_KIDNAPPER = 0.5f; 036 public static float PROB_PIRATE_KIDNAPPER = 0.5f; 037 038 public static float SPECIFIC_FACTION_SUBJECT_EVENT_LIKELIHOOD = 2f; 039 040 041 042 public static class FactionData { 043 //public Pair<String, String>[] subjects; 044 public String[] subjects; 045 public String[] events; 046 } 047 048 public static FactionData ALL_FACTIONS; 049 public static Map<String, FactionData> FACTION_DATA = new HashMap<String, FactionData>(); 050 public static List<String> ALLOWED_FACTIONS = new ArrayList<String>(); 051 public static List<String> MERC_FACTIONS = new ArrayList<String>(); 052 static { 053 ALLOWED_FACTIONS.add(Factions.INDEPENDENT); 054 ALLOWED_FACTIONS.add(Factions.PERSEAN); 055 ALLOWED_FACTIONS.add(Factions.TRITACHYON); 056 ALLOWED_FACTIONS.add(Factions.HEGEMONY); 057 ALLOWED_FACTIONS.add(Factions.LUDDIC_CHURCH); 058 059 MERC_FACTIONS.add(Factions.TRITACHYON); 060 MERC_FACTIONS.add(Factions.HEGEMONY); 061 MERC_FACTIONS.add(Factions.DIKTAT); 062 MERC_FACTIONS.add(Factions.LUDDIC_CHURCH); 063 064 ALL_FACTIONS = new FactionData(); 065 ALL_FACTIONS.subjects = new String[] { 066 "child", 067 "son", 068 "daughter", 069 "niece", 070 "nephew", 071 "ward", 072 }; 073 ALL_FACTIONS.events = new String [] { 074 "a wedding", "a funeral", "a reunion", "a judicial procedure", "an operation", "a family gathering", "their legitimation" 075 }; 076 077 FactionData luddic = new FactionData(); 078 FACTION_DATA.put(Factions.LUDDIC_CHURCH, luddic); 079 luddic.subjects = new String[] { 080 "godchild", 081 "goddaughter", 082 "godson", 083 "apprentice", 084 }; 085 luddic.events = new String [] { 086 "a spiritual retreat", "a penitent seclusion", "their Path-stepping", "their godnaming", "their blessing", "their contemplation", 087 "their consecration", "their invocation", "their witnessing", "their ministration", "an ordination ceremony", "an Exodus Fast" 088 }; 089 090 FactionData hegemony = new FactionData(); 091 FACTION_DATA.put(Factions.HEGEMONY, hegemony); 092 hegemony.subjects = new String[] { 093 "unit-ward", 094 }; 095 hegemony.events = new String [] { 096 "their service induction", "cadet training", "survival school", "a warship launching", "a COMSEC interview", 097 "a unit commemoration", "Legion remembrance day" 098 }; 099 100 FactionData tritach = new FactionData(); 101 FACTION_DATA.put(Factions.TRITACHYON, tritach); 102 tritach.subjects = new String[] { 103 "contract-ward", 104 }; 105 tritach.events = new String [] { 106 "a cybernetic enhancement", "gene therapy", "an enrichment retreat", "a cryo-sabbatical ceremony", 107 "a promotion celebration" 108 }; 109 110 FactionData league = new FactionData(); 111 FACTION_DATA.put(Factions.PERSEAN, league); 112 league.subjects = new String[] { 113 "gensheir", 114 }; 115 league.events = new String [] { 116 "a coronation", "a premiere", "their coming-of-majority", "a landing commemoration", "a titanium jubilee", 117 "a grand fete", "a carnival" 118 }; 119 120 FactionData pirates = new FactionData(); 121 FACTION_DATA.put(Factions.PIRATES, pirates); 122 pirates.subjects = new String[] { 123 "clanward", "clone-variant", 124 }; 125 pirates.events = new String [] { 126 "a \"blooding\"", "their induction", "their \"making\"", "a grand castigation", "a Grand Division", "an \"unmaking\"" 127 }; 128 } 129 130 public String pickSubject(String factionId) { 131 WeightedRandomPicker<String> picker = new WeightedRandomPicker<String>(genRandom); 132 for (String p : ALL_FACTIONS.subjects) { 133 picker.add(p, 1f); 134 } 135 FactionData data = FACTION_DATA.get(factionId); 136 if (data != null) { 137 float w = Math.max(1f, data.subjects.length) / Math.max(1f, picker.getTotal()); 138 w *= SPECIFIC_FACTION_SUBJECT_EVENT_LIKELIHOOD; // faction-specific is more likely than generic, overall 139 for (String p : data.subjects) { 140 picker.add(p, w); 141 } 142 } 143 return picker.pick(); 144 } 145 146 public String pickEvent(String factionId) { 147 WeightedRandomPicker<String> picker = new WeightedRandomPicker<String>(genRandom); 148 for (String event : ALL_FACTIONS.events) { 149 picker.add(event, 1f); 150 } 151 FactionData data = FACTION_DATA.get(factionId); 152 if (data != null) { 153 float w = Math.max(1f, data.events.length) / Math.max(1f, picker.getTotal()); 154 w *= SPECIFIC_FACTION_SUBJECT_EVENT_LIKELIHOOD; // faction-specific is more likely than generic, overall 155 for (String event : data.events) { 156 picker.add(event, w); 157 } 158 } 159 return picker.pick(); 160 } 161 162 163 public static enum Stage { 164 DELIVER_VIP, 165 COMPLETED, 166 FAILED, 167 FAILED_DECIV, 168 } 169 170 public static enum Variation { 171 BASIC, 172 KANTA, 173 } 174 175 protected StarSystemAPI system; 176 protected MarketAPI destination; 177 protected Variation variation; 178 protected FactionAPI faction; 179 protected String theMercFaction; 180 protected String mercFactionId; 181 182 protected String subjectRelation; 183 protected String event; 184 protected PersonAPI target; 185 protected String kantaRelationFirstName; 186 187 protected int piratePayment; 188 protected int mercPayment; 189 190 @Override 191 protected boolean create(MarketAPI createdAt, boolean barEvent) { 192 // if this mission type was already accepted by the player, abort 193 if (!setGlobalReference("$gaVIP_ref")) { 194 return false; 195 } 196 197 requireMarketFaction(ALLOWED_FACTIONS.toArray(new String [0])); 198 requireMarketLocationNot("galatia"); 199 requireMarketNotHidden(); 200 requireMarketNotInHyperspace(); 201 preferMarketInDirectionOfOtherMissions(); 202 203// PROB_KANTA = 1f; 204// PROB_MERC_KIDNAPPER = 1f; 205 206 destination = pickMarket(); 207 variation = Variation.BASIC; 208 if (rollProbability(PROB_KANTA)) { 209 MarketAPI kantasDen = Global.getSector().getEconomy().getMarket("kantas_den"); 210 if (kantasDen != null) { 211 destination = kantasDen; 212 variation = Variation.KANTA; 213 kantaRelationFirstName = Global.getSector().getFaction(Factions.PIRATES).createRandomPerson(genRandom).getName().getFirst(); 214 } 215 } 216 if (destination == null) return false; 217 218 faction = destination.getFaction(); 219 subjectRelation = pickSubject(faction.getId()); 220 if (subjectRelation == null) return false; 221 222 event = pickEvent(faction.getId()); 223 if (event == null) return false; 224 225 if (variation == Variation.BASIC) { 226 target = findOrCreatePerson(faction.getId(), destination, true, Ranks.CITIZEN, 227 Ranks.POST_ADMINISTRATOR, Ranks.POST_BASE_COMMANDER, Ranks.POST_STATION_COMMANDER, 228 Ranks.POST_OUTPOST_COMMANDER, Ranks.POST_PORTMASTER, Ranks.POST_FACTION_LEADER 229 ); 230// target.addTag(Tags.CONTACT_TRADE); 231// setPersonIsPotentialContactOnSuccess(target); 232 } else if (variation == Variation.KANTA) { 233 // set the VIP to Kanta, for rep purposes, since the sub-boss that's the actual relation doesn't exist 234 PersonDataAPI pd = Global.getSector().getImportantPeople().getData("kanta"); 235 if (pd != null) target = pd.getPerson(); 236 } 237 if (target == null) return false; 238 239 240 system = destination.getStarSystem(); 241 242 setStartingStage(Stage.DELIVER_VIP); 243 addSuccessStages(Stage.COMPLETED); 244 addFailureStages(Stage.FAILED); 245 addNoPenaltyFailureStages(Stage.FAILED_DECIV); 246 247 // used for generic pirate reaction 248 if (variation == Variation.KANTA) { 249 setGlobalFlag("$gaVIP_workingForKanta", true, Stage.DELIVER_VIP); 250 } 251 252 makeImportant(destination, "$gaVIP_target", Stage.DELIVER_VIP); 253 254 setStageOnGlobalFlag(Stage.COMPLETED, "$gaVIP_delivered"); 255 setStageOnGlobalFlag(Stage.FAILED, "$gaVIP_failed"); 256 connectWithMarketDecivilized(Stage.DELIVER_VIP, Stage.FAILED_DECIV, destination); 257 258 setTimeLimit(Stage.FAILED, MISSION_DAYS, null); 259 if (variation == Variation.BASIC) { 260 //setCreditReward(30000, 40000); 261 setCreditReward(CreditReward.AVERAGE); 262 setRepPenaltyPerson(RepRewards.VERY_HIGH); 263 setRepPenaltyFaction(RepRewards.HIGH); 264 } else { 265 //setCreditReward(50000, 70000); 266 setCreditReward(CreditReward.HIGH); 267 setRepPenaltyPerson(RepRewards.EXTREME); 268 setRepPenaltyFaction(RepRewards.HIGH); 269 } 270 271 setDefaultGARepRewards(); 272 273// beginStageTrigger(Stage.DELIVER_VIP); 274// LocData data = new LocData(EntityLocationType.HIDDEN_NOT_NEAR_STAR, null, system); 275// triggerSpawnShipGraveyard(Factions.REMNANTS, 10, 10, data); 276// endTrigger(); 277 278 piratePayment = genRoundNumber(40000, 60000); 279 mercPayment = getCreditsReward() / 2; 280 281 if (variation == Variation.BASIC && rollProbability(PROB_PIRATE_KIDNAPPER)) { 282 beginWithinHyperspaceRangeTrigger(destination, 3f, false, Stage.DELIVER_VIP); 283 triggerCreateFleet(FleetSize.LARGE, FleetQuality.HIGHER, Factions.PIRATES, FleetTypes.PATROL_MEDIUM, system); 284 triggerSetFleetOfficers(OfficerNum.MORE, OfficerQuality.HIGHER); 285 triggerAutoAdjustFleetStrengthMajor(); 286 triggerSetStandardAggroPirateFlags(); 287 triggerFleetAllowLongPursuit(); 288 triggerSetFleetAlwaysPursue(); 289 triggerPickLocationTowardsPlayer(system.getHyperspaceAnchor(), 90f, getUnits(1.5f)); 290 triggerSpawnFleetAtPickedLocation("$gaVIP_pirate", null); 291 triggerOrderFleetInterceptPlayer(); 292 triggerFleetMakeImportant(null, Stage.DELIVER_VIP); 293 endTrigger(); 294 } 295 296 if (variation == Variation.KANTA && rollProbability(PROB_MERC_KIDNAPPER)) { 297 mercFactionId = pickOne(MERC_FACTIONS.toArray(new String[0])); 298 FactionAPI mercFaction = Global.getSector().getFaction(mercFactionId); 299 theMercFaction = mercFaction.getDisplayNameWithArticle(); 300 301 beginWithinHyperspaceRangeTrigger(destination, 3f, true, Stage.DELIVER_VIP); 302 triggerCreateFleet(FleetSize.VERY_LARGE, FleetQuality.VERY_HIGH, Factions.MERCENARY, FleetTypes.PATROL_LARGE, system); 303 triggerSetFleetFaction(Factions.INDEPENDENT); 304 triggerSetFleetOfficers(OfficerNum.MORE, OfficerQuality.HIGHER); 305 triggerAutoAdjustFleetStrengthMajor(); 306 triggerMakeHostileAndAggressive(); 307 triggerFleetMakeFaster(true, 2, true); 308 //triggerMakeNoRepImpact(); // this happens in dialog instead 309 triggerFleetAllowLongPursuit(); 310 triggerSetFleetAlwaysPursue(); 311 triggerPickLocationTowardsPlayer(system.getHyperspaceAnchor(), 90f, getUnits(1.5f)); 312 triggerSpawnFleetAtPickedLocation("$gaVIP_merc", null); 313 triggerOrderFleetInterceptPlayer(); 314 triggerFleetMakeImportant(null, Stage.DELIVER_VIP); 315 endTrigger(); 316 } 317 318 return true; 319 } 320 321 @Override 322 protected boolean callAction(String action, String ruleId, InteractionDialogAPI dialog, List<Token> params, 323 Map<String, MemoryAPI> memoryMap) { 324 if (action.equals("betrayal")) { 325 DelayedFleetEncounter e = new DelayedFleetEncounter(genRandom, getMissionId()); 326 e.setDelayMedium(); 327 e.setLocationInnerSector(false, Factions.INDEPENDENT); 328 e.beginCreate(); 329 e.triggerCreateFleet(FleetSize.LARGE, FleetQuality.SMOD_3, Factions.MERCENARY, FleetTypes.PATROL_LARGE, new Vector2f()); 330 e.triggerSetFleetOfficers(OfficerNum.MORE, OfficerQuality.UNUSUALLY_HIGH); 331 e.triggerFleetSetFaction(Factions.INDEPENDENT); 332 e.triggerFleetMakeFaster(true, 2, true); 333 e.triggerSetFleetFlag("$gaVIP_kantaConsequences"); 334 e.triggerMakeNoRepImpact(); 335 e.triggerSetStandardAggroInterceptFlags(); 336 e.endCreate(); 337 return true; 338 } 339 return false; 340 } 341 342 protected void updateInteractionDataImpl() { 343 if (getCurrentStage() != null) { 344 set("$gaVIP_stage", ((Enum)getCurrentStage()).name()); 345 } 346 set("$gaVIP_starName", system.getNameWithNoType()); 347 set("$gaVIP_marketName", destination.getName()); 348 set("$gaVIP_systemName", system.getNameWithLowercaseTypeShort()); 349 350 set("$gaVIP_subjectRelation", subjectRelation); 351 set("$gaVIP_kantaRelationFirstName", kantaRelationFirstName); 352 set("$gaVIP_VIP", target); 353 set("$gaVIP_VIP_faction", target.getFaction().getId()); 354 set("$gaVIP_VIPName", target.getNameString()); 355 set("$gaVIP_VIPhisOrHer", target.getHisOrHer()); 356 set("$gaVIP_VIPPost", target.getPost().toLowerCase()); 357 set("$gaVIP_event", event); 358 359 set("$gaVIP_reward", Misc.getWithDGS(getCreditsReward())); 360 set("$gaVIP_piratePayment", Misc.getWithDGS(piratePayment)); 361 set("$gaVIP_mercPayment", Misc.getWithDGS(mercPayment)); 362 set("$gaVIP_theMercFaction", theMercFaction); 363 set("$gaVIP_mercFactionId", mercFactionId); 364 set("$gaVIP_timeLimit", (int)MISSION_DAYS); 365 set("$gaVIP_variation", variation); 366 } 367 368 @Override 369 public void addDescriptionForNonEndStage(TooltipMakerAPI info, float width, float height) { 370 float opad = 10f; 371 Color h = Misc.getHighlightColor(); 372 if (currentStage == Stage.DELIVER_VIP) { 373 if (variation == Variation.BASIC) { 374 info.addPara("Deliver the " + subjectRelation + " of " + target.getNameString() + " to " + 375 destination.getName() + " in the " + system.getNameWithLowercaseTypeShort() + ", for " + 376 event + ". " + 377 target.getNameString() + " is the " + target.getPost().toLowerCase() + ".", opad); 378 } else if (variation == Variation.KANTA) { 379 info.addPara("Deliver the " + subjectRelation + " of " + kantaRelationFirstName + " Kanta to " + 380 destination.getName() + " in the " + system.getNameWithLowercaseTypeShort() + ", for " + 381 event + ". " + 382 kantaRelationFirstName + " is kin to Kanta herself.", opad); 383 } 384 } 385 } 386 387 @Override 388 public boolean addNextStepText(TooltipMakerAPI info, Color tc, float pad) { 389 Color h = Misc.getHighlightColor(); 390 if (currentStage == Stage.DELIVER_VIP) { 391 info.addPara("Deliver student to " + destination.getName() + " in the " + system.getNameWithLowercaseTypeShort(), tc, pad); 392 return true; 393 } 394 return false; 395 } 396 397 398 @Override 399 public String getBaseName() { 400 return "Deliver VIP"; 401 } 402 403} 404 405