001package com.fs.starfarer.api.impl.campaign.tutorial; 002 003import org.lwjgl.util.vector.Vector2f; 004 005import com.fs.starfarer.api.EveryFrameScript; 006import com.fs.starfarer.api.Global; 007import com.fs.starfarer.api.campaign.CampaignFleetAPI; 008import com.fs.starfarer.api.campaign.CampaignTerrainAPI; 009import com.fs.starfarer.api.campaign.CoreUITabId; 010import com.fs.starfarer.api.campaign.PlanetAPI; 011import com.fs.starfarer.api.campaign.SectorEntityToken; 012import com.fs.starfarer.api.campaign.StarSystemAPI; 013import com.fs.starfarer.api.characters.AbilityPlugin; 014import com.fs.starfarer.api.fleet.FleetMemberAPI; 015import com.fs.starfarer.api.fleet.FleetMemberType; 016import com.fs.starfarer.api.impl.campaign.DModManager; 017import com.fs.starfarer.api.impl.campaign.fleets.FleetFactoryV3; 018import com.fs.starfarer.api.impl.campaign.ids.Abilities; 019import com.fs.starfarer.api.impl.campaign.ids.Factions; 020import com.fs.starfarer.api.impl.campaign.ids.FleetTypes; 021import com.fs.starfarer.api.impl.campaign.ids.HullMods; 022import com.fs.starfarer.api.impl.campaign.ids.MemFlags; 023import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.TransmitterTrapSpecial; 024import com.fs.starfarer.api.ui.HintPanelAPI; 025import com.fs.starfarer.api.util.Misc; 026 027public class CampaignTutorialScript implements EveryFrameScript { 028 029 public static final String USE_TUTORIAL_RESPAWN = "$tutorialRespawn"; 030 031 public static enum CampaignTutorialStage { 032 SHOW_WELCOME_DIALOG, 033 SHOW_DEBRIS_HINT, 034 HEADING_TO_DEBRIS, 035 REACHED_DEBRIS, 036 SAVE_NAG_1, 037 SHOW_PIRATE_DIALOG, 038 SHOW_PIRATE_HINT, 039 PIRATE_APPROACHES, 040 SAVE_NAG_2, 041 SHOW_LEVELUP_DIALOG, 042 SHOW_LEVELUP_HINT, 043 WAIT_CHAR_TAB, 044 SHOW_LAY_IN_COURSE_DIALOG, 045 SHOW_LAY_IN_COURSE_HINT, 046 WAITING_TO_LAY_IN_COURSE, 047 SHOW_GO_SLOW_DIALOG, 048 SHOW_GO_SLOW_HINT, 049 WAITING_TO_GO_SLOW, 050 SHOW_SUSTAINED_BURN_DIALOG, 051 SHOW_SUSTAINED_BURN_HINT, 052 WAIT_SUSTAINED_BURN_USE, 053 SHOW_TRANSPONDER_DIALOG, 054 SHOW_TRANSPONDER_HINT, 055 WAIT_TRANSPONDER_USE, 056 DONE, 057 058 WAITING_TO_QUICKSAVE, 059 } 060 061 062 protected boolean askedPlayerToSave = false; 063 protected boolean playerSaved = false; 064 protected float elapsed = 0f; 065 protected float lastCheckDistToAncyra = -1f; 066 067 protected StarSystemAPI system; 068 protected PlanetAPI ancyra; 069 protected SectorEntityToken derinkuyu; 070 protected CampaignTutorialStage stage = CampaignTutorialStage.SHOW_WELCOME_DIALOG; 071 072 protected boolean orbitalResetDone = false; 073 074 protected CampaignTerrainAPI debrisField; 075 protected CampaignFleetAPI pirateFleet; 076 protected CampaignFleetAPI detachment; 077 protected TutorialMissionIntel intel; 078 079 public CampaignTutorialScript(StarSystemAPI system) { 080 this.system = system; 081 debrisField = (CampaignTerrainAPI) system.getEntityById("debris_tutorial"); 082 ancyra = (PlanetAPI) system.getEntityById("ancyra"); 083 derinkuyu = system.getEntityById("derinkuyu_station"); 084 085 Global.getSector().getMemoryWithoutUpdate().set(USE_TUTORIAL_RESPAWN, true); 086 } 087 088 protected Object readResolve() { 089 return this; 090 } 091 092 protected Object writeReplace() { 093 if (askedPlayerToSave) { 094 playerSaved = true; 095 HintPanelAPI hints = Global.getSector().getCampaignUI().getHintPanel(); 096 if (hints != null) { 097 hints.clearHints(false); 098 } 099 } 100 return this; 101 } 102 103 protected CampaignTutorialStage quickSaveFrom = null; 104 protected boolean quickSaveNag(CampaignTutorialStage nagStage, CampaignTutorialStage next, float timeout) { 105 HintPanelAPI hints = Global.getSector().getCampaignUI().getHintPanel(); 106 107 if (stage == nagStage) { 108 quickSaveFrom = nagStage; 109 hints.clearHints(); 110 111 String control = Global.getSettings().getControlStringForEnumName("QUICK_SAVE"); 112 if (timeout > 0) { 113 hints.setHint(0, "- Press %s to quick-save, if you like", true, Misc.getHighlightColor(), control); 114 } else { 115 hints.setHint(0, "- Press %s to quick-save and advance the tutorial", true, Misc.getHighlightColor(), control); 116 } 117 118 stage = CampaignTutorialStage.WAITING_TO_QUICKSAVE; 119 elapsed = 0f; 120 askedPlayerToSave = true; 121 playerSaved = false; 122 123 return true; 124 } 125 126 if (quickSaveFrom == nagStage && stage == CampaignTutorialStage.WAITING_TO_QUICKSAVE && 127 (playerSaved || (timeout > 0 && elapsed > timeout))) { 128 hints.clearHints(); 129 stage = next; 130 elapsed = 0f; 131 playerSaved = false; 132 askedPlayerToSave = false; 133 quickSaveFrom = null; 134 return true; 135 } 136 137 return false; 138 } 139 140 protected void leashToStartLocation() { 141 CampaignFleetAPI pf = Global.getSector().getPlayerFleet(); 142 float dist = Misc.getDistance(pf.getLocation(), debrisField.getLocation()); 143 if (dist > 1500) { 144 Vector2f loc = debrisField.getLocation(); 145 pf.setLocation(loc.x, loc.y); 146 Global.getSector().getCampaignUI().showMessageDialog("Please follow the instructions near the bottom of the screen and quicksave to advance the tutorial."); 147 } 148 } 149 150 protected boolean charTabWasOpen = false; 151 public void advance(float amount) { 152 if (Global.getSector().isInFastAdvance()) return; 153 154 if (!orbitalResetDone) { 155 system.getEntityById("ancyra").setCircularOrbitAngle(55f); 156 system.getEntityById("ancyra_relay").setCircularOrbitAngle(55 - 60);; 157 158 system.getEntityById("pontus").setCircularOrbitAngle(230); 159 system.getEntityById("pontus_L4").setCircularOrbitAngle(230 + 60); 160 system.getEntityById("pontus_L5").setCircularOrbitAngle(230 - 60); 161 system.getEntityById("galatia_probe").setCircularOrbitAngle(230); 162 system.getEntityById("galatia_jump_point_alpha").setCircularOrbitAngle(230 + 180f); 163 164 system.getEntityById("tetra").setCircularOrbitAngle(340); 165 system.getEntityById("derinkuyu_station").setCircularOrbitAngle(135); 166 system.getEntityById("galatia_jump_point_fringe").setCircularOrbitAngle(160);; 167 168 orbitalResetDone = true; 169 } 170 171 172 if (amount == 0) return; 173 174 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet(); 175 if (playerFleet == null) return; 176 177 HintPanelAPI hints = Global.getSector().getCampaignUI().getHintPanel(); 178 if (hints == null) return; 179 180 //playerFleet.addAbility(Abilities.SENSOR_BURST); 181 182 if (lastCheckDistToAncyra < 0) { 183 lastCheckDistToAncyra = Misc.getDistance(playerFleet.getLocation(), ancyra.getLocation()); 184 } 185 186 elapsed += amount; 187 188 if (stage == CampaignTutorialStage.SHOW_WELCOME_DIALOG && elapsed > 1f) { 189 if (Global.getSector().getCampaignUI().showInteractionDialog(new TutorialWelcomeDialogPluginImpl(), null)) { 190 addFleets(); 191 stage = CampaignTutorialStage.SHOW_DEBRIS_HINT; 192 } 193 return; 194 } 195 196 if (stage == CampaignTutorialStage.SHOW_DEBRIS_HINT) { 197 String control = Global.getSettings().getControlStringForAbilitySlot(5); 198 hints.setHint(1, "- Move up into the debris field"); 199 hints.setHint(0, "- Press %s to start scavenging", false, Misc.getHighlightColor(), control); 200 hints.makeDim(0); 201 stage = CampaignTutorialStage.HEADING_TO_DEBRIS; 202 return; 203 } 204 205 if (stage == CampaignTutorialStage.HEADING_TO_DEBRIS) { 206 if (debrisField.getPlugin().containsEntity(playerFleet)) { 207 stage = CampaignTutorialStage.REACHED_DEBRIS; 208 hints.fadeOutHint(1); 209 //hints.makeNormal(0); 210 String control = Global.getSettings().getControlStringForAbilitySlot(5); 211 hints.setHint(0, "- Press %s to start scavenging", true, Misc.getHighlightColor(), control); 212 } 213 return; 214 } 215 216 if (stage == CampaignTutorialStage.REACHED_DEBRIS) { 217 AbilityPlugin scavenge = playerFleet.getAbility(Abilities.SCAVENGE); 218 if (scavenge != null && scavenge.isOnCooldown()) { 219 stage = CampaignTutorialStage.SAVE_NAG_1; 220 } 221 return; 222 } 223 224 if (quickSaveFrom == CampaignTutorialStage.SAVE_NAG_1) { 225 leashToStartLocation(); 226 } 227 if (quickSaveNag(CampaignTutorialStage.SAVE_NAG_1, CampaignTutorialStage.SHOW_PIRATE_DIALOG, 0)) { 228 return; 229 } 230 231 if (stage == CampaignTutorialStage.SHOW_PIRATE_DIALOG && elapsed >= 1f) { 232 if (Global.getSector().getCampaignUI().showInteractionDialog(new TutorialPirateApproachesDialogPluginImpl(), null)) { 233 stage = CampaignTutorialStage.SHOW_PIRATE_HINT; 234 } 235 return; 236 } 237 238 if (stage == CampaignTutorialStage.SHOW_PIRATE_HINT) { 239 addPirateFleet(); 240 241 hints.setHint(0, "- Wait for the pirates to approach, then engage and defeat them!"); 242 stage = CampaignTutorialStage.PIRATE_APPROACHES; 243 return; 244 } 245 246 if (stage == CampaignTutorialStage.PIRATE_APPROACHES) { 247 if (pirateFleet == null || !pirateFleet.isAlive()) { 248 hints.clearHints(); 249 stage = CampaignTutorialStage.SAVE_NAG_2; 250 elapsed = 0f; 251 252 long xp = Global.getSector().getPlayerPerson().getStats().getXP(); 253 long add = Global.getSettings().getLevelupPlugin().getXPForLevel(2) - xp; 254 if (add > 0) { 255 Global.getSector().getPlayerPerson().getStats().addPoints(1); 256 Global.getSector().getPlayerPerson().getStats().addXP(add); 257 } 258 } 259 return; 260 } 261 262 if (quickSaveNag(CampaignTutorialStage.SAVE_NAG_2, CampaignTutorialStage.SHOW_LEVELUP_DIALOG, 0)) { 263 return; 264 } 265 266 if (stage == CampaignTutorialStage.SHOW_LEVELUP_DIALOG && elapsed >= 1f) { 267 if (Global.getSector().getCampaignUI().showInteractionDialog(new TutorialLevelUpDialogPluginImpl(), null)) { 268 stage = CampaignTutorialStage.SHOW_LEVELUP_HINT; 269 } 270 return; 271 } 272 273 if (stage == CampaignTutorialStage.SHOW_LEVELUP_HINT) { 274 String character = Global.getSettings().getControlStringForEnumName("CORE_CHARACTER"); 275 hints.setHint(0, "- Press %s to open the character tab and consider your options", true, Misc.getHighlightColor(), character); 276 stage = CampaignTutorialStage.WAIT_CHAR_TAB; 277 return; 278 } 279 280 if (stage == CampaignTutorialStage.WAIT_CHAR_TAB) { 281 CoreUITabId tab = Global.getSector().getCampaignUI().getCurrentCoreTab(); 282 if (tab == CoreUITabId.CHARACTER) { 283 charTabWasOpen = true; 284 } 285 if (charTabWasOpen && !Global.getSector().getCampaignUI().isShowingDialog()) { 286 stage = CampaignTutorialStage.SHOW_LAY_IN_COURSE_DIALOG; 287 elapsed = 0f; 288 hints.clearHints(); 289 } 290 } 291 292 if (stage == CampaignTutorialStage.SHOW_LAY_IN_COURSE_DIALOG && elapsed >= 1f) { 293 startTutorialMissionEvent(); 294 if (Global.getSector().getCampaignUI().showInteractionDialog( 295 new TutorialLayInCourseDialogPluginImpl(ancyra.getMarket(), intel.getMainContact()), null)) { 296 stage = CampaignTutorialStage.SHOW_LAY_IN_COURSE_HINT; 297 } 298 return; 299 } 300 301 302 if (stage == CampaignTutorialStage.SHOW_LAY_IN_COURSE_HINT) { 303 String intel = Global.getSettings().getControlStringForEnumName("CORE_INTEL"); 304 String map = Global.getSettings().getControlStringForEnumName("CORE_MAP"); 305 String openMap = Global.getSettings().getControlStringForEnumName("SUBTAB_4"); 306 307 hints.setHint(2, "- Press %s to open the intel tab, and select the mission", false, Misc.getHighlightColor(), intel); 308 hints.setHint(1, "- Press %s to open the map on the mission target", false, Misc.getHighlightColor(), openMap); 309 hints.setHint(0, "- Click on " + ancyra.getName() + " and select " + 310 "%s, then press %s to close the map", false, Misc.getHighlightColor(), "\"Lay in Course\"", map); 311 stage = CampaignTutorialStage.WAITING_TO_LAY_IN_COURSE; 312 313// hints.setHint(1, "- Press %s to open the map", Misc.getHighlightColor(), map); 314// hints.setHint(0, "- Find " + ancyra.getName() + ", left-click on it and select " + 315// "\"Lay in Course\", then close the map", Misc.getHighlightColor(), "\"Lay in Course\""); 316// stage = CampaignTutorialStage.WAITING_TO_LAY_IN_COURSE; 317 return; 318 } 319 320 if (stage == CampaignTutorialStage.WAITING_TO_LAY_IN_COURSE) { 321 float dist = Misc.getDistance(playerFleet.getLocation(), ancyra.getLocation()); 322 boolean closedIn = dist < lastCheckDistToAncyra * 0.75f; 323 if (closedIn || (playerFleet.getInteractionTarget() != null && 324 playerFleet.getInteractionTarget().getMarket() == ancyra.getMarket())) { 325 lastCheckDistToAncyra = dist; 326 hints.clearHints(); 327 stage = CampaignTutorialStage.SHOW_SUSTAINED_BURN_DIALOG; 328 elapsed = 0; 329 } 330 return; 331 } 332 333 334 if (stage == CampaignTutorialStage.SHOW_SUSTAINED_BURN_DIALOG && elapsed > 5f) { 335 if (Global.getSector().getCampaignUI().showInteractionDialog(new TutorialSustainedBurnDialogPluginImpl(ancyra.getMarket()), null)) { 336 stage = CampaignTutorialStage.SHOW_SUSTAINED_BURN_HINT; 337 } 338 return; 339 } 340 341 if (stage == CampaignTutorialStage.SHOW_SUSTAINED_BURN_HINT) { 342 String control = Global.getSettings().getControlStringForAbilitySlot(4); 343 hints.setHint(0, "- Press %s to engage sustained burn", true, Misc.getHighlightColor(), control); 344 stage = CampaignTutorialStage.WAIT_SUSTAINED_BURN_USE; 345 elapsed = 0; 346 return; 347 } 348 349 if (stage == CampaignTutorialStage.WAIT_SUSTAINED_BURN_USE) { 350 AbilityPlugin sb = playerFleet.getAbility(Abilities.SUSTAINED_BURN); 351 float dist = Misc.getDistance(playerFleet.getLocation(), ancyra.getLocation()); 352 boolean closedIn = dist < lastCheckDistToAncyra * 0.75f; 353 if ((sb != null && sb.isActive() && elapsed > 5f) || closedIn) { 354 lastCheckDistToAncyra = dist; 355 hints.clearHints(); 356 stage = CampaignTutorialStage.SHOW_GO_SLOW_DIALOG; 357 elapsed = 0f; 358 } 359 return; 360 } 361 362 363 if (stage == CampaignTutorialStage.SHOW_GO_SLOW_DIALOG && 364 Global.getSector().getPlayerFleet().getLocation().length() < 9300) { 365 if (Global.getSector().getCampaignUI().showInteractionDialog(new TutorialGoSlowDialogPluginImpl(), null)) { 366 stage = CampaignTutorialStage.SHOW_GO_SLOW_HINT; 367 } 368 return; 369 } 370 371 if (stage == CampaignTutorialStage.SHOW_GO_SLOW_HINT) { 372 String control = Global.getSettings().getControlStringForEnumName("GO_SLOW"); 373 hints.clearHints(); 374 hints.setHint(0, "- Press and hold %s to move slowly through the asteroid belt", true, Misc.getHighlightColor(), control); 375 stage = CampaignTutorialStage.WAITING_TO_GO_SLOW; 376 elapsed = 0; 377 return; 378 } 379 380 381 if (stage == CampaignTutorialStage.WAITING_TO_GO_SLOW && 382 Global.getSector().getPlayerFleet().getLocation().length() < 7850) { 383 float dist = Misc.getDistance(playerFleet.getLocation(), ancyra.getLocation()); 384 boolean closedIn = dist < lastCheckDistToAncyra * 0.75f; 385 if (closedIn || (playerFleet.getInteractionTarget() != null && 386 playerFleet.getInteractionTarget().getMarket() == ancyra.getMarket())) { 387 lastCheckDistToAncyra = dist; 388 hints.clearHints(); 389 stage = CampaignTutorialStage.SHOW_TRANSPONDER_DIALOG; 390 elapsed = 0; 391 } 392 return; 393 } 394 395 396 if (stage == CampaignTutorialStage.SHOW_TRANSPONDER_DIALOG) { 397 float dist = Misc.getDistance(playerFleet.getLocation(), ancyra.getLocation()); 398 if (dist < 6000) { 399 if (Global.getSector().getCampaignUI().showInteractionDialog(new TutorialTransponderDialogPluginImpl(ancyra.getMarket()), null)) { 400 stage = CampaignTutorialStage.SHOW_TRANSPONDER_HINT; 401 } 402 } 403 return; 404 } 405 406 if (stage == CampaignTutorialStage.SHOW_TRANSPONDER_HINT) { 407 String control = Global.getSettings().getControlStringForAbilitySlot(0); 408 hints.setHint(0, "- Press %s twice to turn on the transponder", true, Misc.getHighlightColor(), control); 409 stage = CampaignTutorialStage.WAIT_TRANSPONDER_USE; 410 elapsed = 0; 411 return; 412 } 413 414 if (stage == CampaignTutorialStage.WAIT_TRANSPONDER_USE) { 415 AbilityPlugin transponder = playerFleet.getAbility(Abilities.TRANSPONDER); 416 if ((transponder != null && transponder.isActive())) { 417 hints.clearHints(); 418 stage = CampaignTutorialStage.DONE; 419 elapsed = 0f; 420 } 421 return; 422 } 423 } 424 425 426 protected void addFleets() { 427 addSecurityDetachment(); 428 429 SectorEntityToken inner = system.getEntityById("galatia_jump_point_alpha"); 430 SectorEntityToken fringe = system.getEntityById("galatia_jump_point_fringe"); 431 SectorEntityToken derinkuyu = system.getEntityById("derinkuyu_station"); 432 433 CampaignFleetAPI g1 = RogueMinerMiscFleetManager.createGuardFleet(false); 434 g1.addScript(new TutorialLeashAssignmentAI(g1, system, derinkuyu)); 435 system.addEntity(g1); 436 g1.setLocation(derinkuyu.getLocation().x, derinkuyu.getLocation().y); 437 438 CampaignFleetAPI g2 = RogueMinerMiscFleetManager.createGuardFleet(Misc.isEasy()); 439 440 if (!Misc.isEasy()) { 441 FleetMemberAPI member = Global.getFactory().createFleetMember(FleetMemberType.SHIP, "venture_Outdated"); 442 member.setVariant(member.getVariant().clone(), false, false); 443 DModManager.setDHull(member.getVariant()); 444 member.getVariant().addPermaMod(HullMods.COMP_ARMOR, false); 445 member.getVariant().addPermaMod(HullMods.FAULTY_GRID, false); 446 g2.getFleetData().addFleetMember(member); 447 } 448 449 g2.getFleetData().sort(); 450 g2.addScript(new TutorialLeashAssignmentAI(g2, system, inner)); 451 system.addEntity(g2); 452 g2.setLocation(inner.getLocation().x, inner.getLocation().y); 453 454 CampaignFleetAPI g3 = RogueMinerMiscFleetManager.createGuardFleet(true); 455 g3.addScript(new TutorialLeashAssignmentAI(g3, system, inner)); 456 system.addEntity(g3); 457 g3.setLocation(inner.getLocation().x, inner.getLocation().y); 458 459 460 CampaignFleetAPI g4 = RogueMinerMiscFleetManager.createGuardFleet(true); 461 g4.addScript(new TutorialLeashAssignmentAI(g4, system, fringe)); 462 system.addEntity(g4); 463 g4.setLocation(fringe.getLocation().x, fringe.getLocation().y); 464 465 CampaignFleetAPI g5 = RogueMinerMiscFleetManager.createGuardFleet(true); 466 g5.addScript(new TutorialLeashAssignmentAI(g5, system, fringe)); 467 system.addEntity(g5); 468 g5.setLocation(fringe.getLocation().x, fringe.getLocation().y); 469 470 } 471 472 473 protected void startTutorialMissionEvent() { 474 if (intel == null) intel = new TutorialMissionIntel(); 475 } 476 477 protected void addPirateFleet() { 478 pirateFleet = RogueMinerMiscFleetManager.createEmptyRogueFleet("Rogue Miner", false); 479 pirateFleet.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_NO_SHIP_RECOVERY, true); 480 481 FleetMemberAPI member = Global.getFactory().createFleetMember(FleetMemberType.SHIP, "cerberus_d_pirates_Standard"); 482 pirateFleet.getFleetData().addFleetMember(member); 483 484 system.addEntity(pirateFleet); 485 CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet(); 486 pirateFleet.setLocation(playerFleet.getLocation().x + 750f, playerFleet.getLocation().y + 750f); 487 488 TransmitterTrapSpecial.makeFleetInterceptPlayer(pirateFleet, true, true, 100f); 489 } 490 491 protected void addSecurityDetachment() { 492 detachment = FleetFactoryV3.createEmptyFleet(Factions.HEGEMONY, FleetTypes.PATROL_MEDIUM, ancyra.getMarket()); 493 detachment.setName("Security Detachment"); 494 detachment.setNoFactionInName(true); 495 496 //detachment.getFleetData().addFleetMember("eagle_xiv_Elite"); 497 detachment.getFleetData().addFleetMember("dominator_XIV_Elite"); 498 detachment.getFleetData().addFleetMember("mora_Strike"); 499 detachment.getFleetData().addFleetMember("enforcer_Escort"); 500 detachment.getFleetData().addFleetMember("enforcer_Assault"); 501 detachment.getFleetData().addFleetMember("lasher_CS"); 502 detachment.getFleetData().addFleetMember("lasher_CS"); 503 504 detachment.clearAbilities(); 505 detachment.addAbility(Abilities.TRANSPONDER); 506 detachment.addAbility(Abilities.GO_DARK); 507 detachment.addAbility(Abilities.SENSOR_BURST); 508 detachment.addAbility(Abilities.EMERGENCY_BURN); 509 510 detachment.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_PATROL_FLEET, true); 511 detachment.getMemoryWithoutUpdate().set(MemFlags.MEMORY_KEY_NO_JUMP, true); 512 513 system.addEntity(detachment); 514 detachment.setLocation(ancyra.getLocation().x, ancyra.getLocation().y); 515 516 detachment.addScript(new TutorialLeashAssignmentAI(detachment, system, ancyra)); 517 518 detachment.setId("tutorial_security_detachment"); 519 } 520 521 522 523 public boolean isDone() { 524 return stage == CampaignTutorialStage.DONE; 525 } 526 527 public boolean runWhilePaused() { 528 return stage == CampaignTutorialStage.WAIT_CHAR_TAB; 529 } 530 531}