001package com.fs.starfarer.api.impl.campaign.missions.hub;
002
003import java.util.ArrayList;
004import java.util.Arrays;
005import java.util.EnumSet;
006import java.util.List;
007import java.util.Random;
008
009import org.lwjgl.util.vector.Vector2f;
010
011import com.fs.starfarer.api.EveryFrameScript;
012import com.fs.starfarer.api.Global;
013import com.fs.starfarer.api.Script;
014import com.fs.starfarer.api.campaign.CampaignFleetAPI;
015import com.fs.starfarer.api.campaign.CargoAPI;
016import com.fs.starfarer.api.campaign.FactionAPI;
017import com.fs.starfarer.api.campaign.FactionAPI.ShipPickMode;
018import com.fs.starfarer.api.campaign.FactionAPI.ShipPickParams;
019import com.fs.starfarer.api.campaign.FactionDoctrineAPI;
020import com.fs.starfarer.api.campaign.FleetInflater;
021import com.fs.starfarer.api.campaign.LocationAPI;
022import com.fs.starfarer.api.campaign.PlanetAPI;
023import com.fs.starfarer.api.campaign.SectorEntityToken;
024import com.fs.starfarer.api.campaign.SpecialItemData;
025import com.fs.starfarer.api.campaign.StarSystemAPI;
026import com.fs.starfarer.api.campaign.econ.CommoditySpecAPI;
027import com.fs.starfarer.api.campaign.econ.MarketAPI;
028import com.fs.starfarer.api.campaign.rules.HasMemory;
029import com.fs.starfarer.api.campaign.rules.MemoryAPI;
030import com.fs.starfarer.api.characters.AbilityPlugin;
031import com.fs.starfarer.api.characters.PersonAPI;
032import com.fs.starfarer.api.combat.ShipVariantAPI;
033import com.fs.starfarer.api.fleet.FleetMemberAPI;
034import com.fs.starfarer.api.fleet.ShipRolePick;
035import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin.DerelictShipData;
036import com.fs.starfarer.api.impl.campaign.DerelictShipEntityPlugin.DerelictType;
037import com.fs.starfarer.api.impl.campaign.fleets.DefaultFleetInflater;
038import com.fs.starfarer.api.impl.campaign.fleets.DefaultFleetInflaterParams;
039import com.fs.starfarer.api.impl.campaign.fleets.FleetFactoryV3;
040import com.fs.starfarer.api.impl.campaign.fleets.FleetParamsV3;
041import com.fs.starfarer.api.impl.campaign.ids.Abilities;
042import com.fs.starfarer.api.impl.campaign.ids.Conditions;
043import com.fs.starfarer.api.impl.campaign.ids.Factions;
044import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
045import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
046import com.fs.starfarer.api.impl.campaign.ids.ShipRoles;
047import com.fs.starfarer.api.impl.campaign.ids.Skills;
048import com.fs.starfarer.api.impl.campaign.missions.hub.MissionTrigger.TriggerAction;
049import com.fs.starfarer.api.impl.campaign.missions.hub.MissionTrigger.TriggerActionContext;
050import com.fs.starfarer.api.impl.campaign.procgen.StarSystemGenerator;
051import com.fs.starfarer.api.impl.campaign.procgen.themes.RemnantSeededFleetManager;
052import com.fs.starfarer.api.impl.campaign.procgen.themes.SalvageSpecialAssigner;
053import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.BaseSalvageSpecial;
054import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.special.TransmitterTrapSpecial;
055import com.fs.starfarer.api.impl.campaign.skills.OfficerTraining;
056import com.fs.starfarer.api.impl.campaign.terrain.StarCoronaTerrainPlugin;
057import com.fs.starfarer.api.util.Misc;
058import com.fs.starfarer.api.util.WeightedRandomPicker;
059
060/**
061 * The methods/classes defined in this class could easily
062 * be in BaseHubMission instead; this class exists purely for organizational purposes.
063 * 
064 * @author Alex Mosolov
065 *
066 * Copyright 2019 Fractal Softworks, LLC
067 */
068public abstract class HubMissionWithTriggers extends BaseHubMission {
069        
070        public static enum FleetSize {
071                TINY(0.06f),
072                VERY_SMALL(0.1f),
073                SMALL(0.2f),
074                MEDIUM(0.35f),
075                LARGE(0.5f),
076                LARGER(0.6f),
077                VERY_LARGE(0.7f),
078                HUGE(0.9f),
079                MAXIMUM(1.1f);
080                
081                public float maxFPFraction;
082                private FleetSize(float maxFPFraction) {
083                        this.maxFPFraction = maxFPFraction;
084                }
085                
086                private static FleetSize [] vals = values();
087                public FleetSize next() {
088                        int index = this.ordinal() + 1;
089                        if (index >= vals.length) index = vals.length - 1;
090                        return vals[index];
091                }
092                public FleetSize prev() {
093                        int index = this.ordinal() - 1;
094                        if (index < 0) index = 0;
095                        return vals[index];
096                }
097        }
098        
099        public static enum FleetQuality {
100                VERY_LOW(-1f, 0),
101                LOWER(-0.5f, 0),
102                DEFAULT(0f, 0),
103                HIGHER(0.5f, 0),
104                VERY_HIGH(1f, 0),
105                SMOD_1(1.5f, 1),
106                SMOD_2(1.5f, 2),
107                SMOD_3(1.5f, 3);
108                
109                
110                public float qualityMod;
111                public int numSMods;
112                private FleetQuality(float qualityMod, int numSMods) {
113                        this.qualityMod = qualityMod;
114                        this.numSMods = numSMods;
115                }
116                
117                private static FleetQuality [] vals = values();
118                public FleetQuality next() {
119                        int index = this.ordinal() + 1;
120                        if (index >= vals.length) index = vals.length - 1;
121                        return vals[index];
122                }
123                public FleetQuality prev() {
124                        int index = this.ordinal() - 1;
125                        if (index < 0) index = 0;
126                        return vals[index];
127                }
128        }
129        
130        public static enum OfficerNum {
131                NONE,
132                FC_ONLY,
133                FEWER,
134                DEFAULT,
135                MORE,
136                ALL_SHIPS;
137                
138                private static OfficerNum [] vals = values();
139                public OfficerNum next() {
140                        int index = this.ordinal() + 1;
141                        if (index >= vals.length) index = vals.length - 1;
142                        return vals[index];
143                }
144                public OfficerNum prev() {
145                        int index = this.ordinal() - 1;
146                        if (index < 0) index = 0;
147                        return vals[index];
148                }
149        }
150        
151        public static enum OfficerQuality {
152                LOWER,
153                DEFAULT,
154                HIGHER,
155                UNUSUALLY_HIGH, /** officers like this can only be found in cryopods by the player */
156                AI_GAMMA,
157                AI_BETA,
158                AI_BETA_OR_GAMMA,
159                AI_ALPHA,
160                AI_OMEGA, /** made you look */
161                AI_MIXED;
162                
163                private static OfficerQuality [] vals = values();
164                public OfficerQuality next() {
165                        int index = this.ordinal() + 1;
166                        if (index >= vals.length) index = vals.length - 1;
167                        return vals[index];
168                }
169                public OfficerQuality prev() {
170                        int index = this.ordinal() - 1;
171                        if (index < 0) index = 0;
172                        return vals[index];
173                }
174        }
175        
176        public static class FleetAddTugs implements TriggerAction {
177                int numTugs = 0;
178                public FleetAddTugs(int numTugs) {
179                        this.numTugs = numTugs;
180                }
181                public void doAction(TriggerActionContext context) {
182                        if (context.fleet != null) {
183                                addTugsToFleet(context.fleet, numTugs, ((BaseHubMission)context.mission).genRandom);
184                        }
185                }
186        }
187        
188        public static class UnhideCommListing implements TriggerAction {
189                protected PersonAPI person;
190                public UnhideCommListing(PersonAPI person) {
191                        this.person = person;
192                }
193
194                public void doAction(TriggerActionContext context) {
195                        if (person.getMarket() != null) {
196                                MarketAPI market = person.getMarket();
197                                if (market.getCommDirectory().getEntryForPerson(person) == null) {
198                                        market.getCommDirectory().addPerson(person);
199                                }
200                                if (market.getCommDirectory().getEntryForPerson(person) != null) {
201                                        market.getCommDirectory().getEntryForPerson(person).setHidden(false);
202                                }
203                        }
204                }
205        }
206        
207        /**
208         * Person must be "important", i.e. in the ImportantPeople directory.
209         */
210        public static class HideCommListing implements TriggerAction {
211                protected PersonAPI person;
212                public HideCommListing(PersonAPI person) {
213                        this.person = person;
214                }
215
216                public void doAction(TriggerActionContext context) {
217                        if (person.getMarket() != null) {
218                                MarketAPI market = person.getMarket();
219                                if (market.getCommDirectory().getEntryForPerson(person) == null) {
220                                        market.getCommDirectory().addPerson(person);
221                                }
222                                if (market.getCommDirectory().getEntryForPerson(person) != null) {
223                                        market.getCommDirectory().getEntryForPerson(person).setHidden(true);
224                                }
225                        }
226                }
227        }
228        
229        public static class MovePersonToMarket implements TriggerAction {
230                protected PersonAPI person;
231                protected MarketAPI market;
232                protected boolean alwaysAddToComms;
233                
234                public MovePersonToMarket(PersonAPI person, MarketAPI market, boolean alwaysAddToComms) {
235                        super();
236                        this.person = person;
237                        this.market = market;
238                        this.alwaysAddToComms = alwaysAddToComms;
239                }
240
241
242                public void doAction(TriggerActionContext context) {
243                        Misc.moveToMarket(person, market, alwaysAddToComms);
244                }
245        }
246        
247        
248        public static class DespawnEntityAction implements TriggerAction {
249                protected SectorEntityToken entity;
250                public DespawnEntityAction(SectorEntityToken entity) {
251                        this.entity = entity;
252                }
253
254                public void doAction(TriggerActionContext context) {
255                        Misc.fadeAndExpire(entity);
256                }
257        }
258        
259        public static class MakeDiscoverableAction implements TriggerAction {
260                protected float range;
261                protected float xp;
262                public MakeDiscoverableAction(float range, float xp) {
263                        this.range = range;
264                        this.xp = xp;
265                }
266                
267                public void doAction(TriggerActionContext context) {
268                        ((BaseHubMission)context.mission).makeDiscoverable(context.entity, range, xp);
269                        
270                }
271        }
272        
273        //public void spawnShipGraveyard(String factionId, int minShips, int maxShips, LocData data) {
274        public static class SpawnShipGraveyardAction implements TriggerAction {
275                protected String factionId;
276                protected int minShips;
277                protected int maxShips;
278                protected LocData data;
279                public SpawnShipGraveyardAction(String factionId, int minShips, int maxShips, LocData data) {
280                        this.factionId = factionId;
281                        this.minShips = minShips;
282                        this.maxShips = maxShips;
283                        this.data = data;
284                }
285                
286                public void doAction(TriggerActionContext context) {
287                        ((BaseHubMission)context.mission).spawnShipGraveyard(factionId, minShips, maxShips, data); 
288                }
289                
290        }
291        public static class SpawnDebrisFieldAction implements TriggerAction {
292                protected float radius;
293                protected float density;
294                protected LocData data;
295                
296                public SpawnDebrisFieldAction(float radius, float density, LocData data) {
297                        this.radius = radius;
298                        this.density = density;
299                        this.data = data;
300                }
301
302                public void doAction(TriggerActionContext context) {
303                        SectorEntityToken entity = ((BaseHubMission)context.mission).spawnDebrisField(radius, density, data); 
304                        context.entity = entity;
305                }
306        }
307        
308        
309        public static class SpawnEntityAction implements TriggerAction {
310                protected String entityId;
311                protected LocData data;
312
313                public SpawnEntityAction(String entityId, LocData data) {
314                        this.entityId = entityId;
315                        this.data = data;
316                }
317
318                public void doAction(TriggerActionContext context) {
319                        SectorEntityToken entity = ((BaseHubMission)context.mission).spawnEntity(entityId, data);
320                        context.entity = entity;
321                }
322        }
323        
324        public static class SpawnDerelictAction implements TriggerAction {
325                protected String hullId;
326                protected String factionId;
327                protected DerelictType type;
328                protected DerelictShipData shipData;
329                protected LocData data;
330                
331                /**
332                 * Specify hullId OR factionId, not both.
333                 * @param data
334                 */
335                public SpawnDerelictAction(String hullId, String factionId, DerelictType type, LocData data) {
336                        this.hullId = hullId;
337                        this.factionId = factionId;
338                        this.data = data;
339                        this.type = type;
340                }
341                
342                public SpawnDerelictAction(DerelictType type, LocData data) {
343                        this.data = data;
344                        this.type = type;
345                }
346                public SpawnDerelictAction(DerelictShipData shipData, LocData data) {
347                        this.shipData = shipData;
348                        this.data = data;
349                }
350                
351                public void doAction(TriggerActionContext context) {
352                        SectorEntityToken entity = null;
353                        if (hullId != null) {
354                                entity = ((BaseHubMission)context.mission).spawnDerelictHull(hullId, data);
355                        } else if (factionId != null) {
356                                entity = ((BaseHubMission)context.mission).spawnDerelict(factionId, type, data);
357                        } else if (shipData != null) {
358                                entity = ((BaseHubMission)context.mission).spawnDerelict(shipData, data);
359                        } else {
360                                entity = ((BaseHubMission)context.mission).spawnDerelictOfType(type, data);
361                        }
362                        context.entity = entity;
363                }
364        }
365
366        
367
368        public static class SpawnFleetNearAction implements TriggerAction {
369                protected SectorEntityToken entity;
370                protected float range;
371
372                public SpawnFleetNearAction(SectorEntityToken entity, float range) {
373                        this.entity = entity;
374                        this.range = range;
375                }
376
377                public void doAction(TriggerActionContext context) {
378                        entity.getContainingLocation().addEntity(context.fleet);
379                        Vector2f loc = Misc.getPointWithinRadius(entity.getLocation(), range);
380                        context.fleet.setLocation(loc.x, loc.y);
381                }
382        }
383        public static class SetFleetFactionAction implements TriggerAction {
384                protected String factionId;
385
386                public SetFleetFactionAction(String factionId) {
387                        this.factionId = factionId;
388                }
389
390                public void doAction(TriggerActionContext context) {
391                        context.fleet.setFaction(factionId, true);
392                }
393        }
394        
395        public static class SetEntityToPickedJumpPoint implements TriggerAction {
396                public SetEntityToPickedJumpPoint() {
397                }
398                
399                public void doAction(TriggerActionContext context) {
400                        context.entity = context.jumpPoint;
401                }
402        }
403
404        public static class FleetMakeImportantAction implements TriggerAction {
405                protected String flag;
406                protected Enum[] stages;
407                public FleetMakeImportantAction(String flag, Enum ... stages) {
408                        this.flag = flag;
409                        this.stages = stages;
410                }
411                public void doAction(TriggerActionContext context) {
412                        BaseHubMission bhm = (BaseHubMission) context.mission;
413                        bhm.makeImportant(context.fleet, flag, stages);
414                        
415                        if (stages != null && Arrays.asList(stages).contains(bhm.getCurrentStage())) {
416                                Misc.makeImportant(context.fleet.getMemoryWithoutUpdate(), bhm.getReason());
417                                bhm.changes.add(new MadeImportant(context.fleet.getMemoryWithoutUpdate(), bhm.getReason()));
418                                
419                                if (flag != null) {
420                                        context.fleet.getMemoryWithoutUpdate().set(flag, true);
421                                        bhm.changes.add(new VariableSet(context.fleet.getMemoryWithoutUpdate(), flag, true));
422                                }
423                        }
424//                      else if (stages == null) {
425//                              Misc.makeImportant(context.fleet.getMemoryWithoutUpdate(), bhm.getReason());
426//                      }
427                        
428//                      if (context.mission instanceof BaseHubMission) {
429//                              Misc.makeImportant(context.fleet.getMemoryWithoutUpdate(), reason);
430//                              BaseHubMission bhm = (BaseHubMission) context.mission;
431//                              bhm.changes.add(new MadeImportant(context.fleet.getMemoryWithoutUpdate(), reason));
432//                      }
433                }
434        }
435        
436        public static class EntityMakeImportantAction implements TriggerAction {
437                protected String flag;
438                protected Enum[] stages;
439                public EntityMakeImportantAction(String flag, Enum ... stages) {
440                        this.flag = flag;
441                        this.stages = stages;
442                }
443                public void doAction(TriggerActionContext context) {
444                        BaseHubMission bhm = (BaseHubMission) context.mission;
445                        bhm.makeImportant(context.entity, flag, stages);
446                        
447                        if (Arrays.asList(stages).contains(bhm.getCurrentStage())) {
448                                Misc.makeImportant(context.entity.getMemoryWithoutUpdate(), bhm.getReason());
449                                bhm.changes.add(new MadeImportant(context.entity.getMemoryWithoutUpdate(), bhm.getReason()));
450                                
451                                if (flag != null) {
452                                        context.entity.getMemoryWithoutUpdate().set(flag, true);
453                                        bhm.changes.add(new VariableSet(context.entity.getMemoryWithoutUpdate(), flag, true));
454                                }
455                        }
456                        
457//                      if (context.mission instanceof BaseHubMission) {
458//                              Misc.makeImportant(context.entity.getMemoryWithoutUpdate(), reason);
459//                              BaseHubMission bhm = (BaseHubMission) context.mission;
460//                              bhm.changes.add(new MadeImportant(context.entity.getMemoryWithoutUpdate(), reason));
461//                      }
462                }
463        }
464
465        public static class SetFleetFlagsWithReasonAction implements TriggerAction {
466                protected String[] flags;
467                protected String reason;
468                protected boolean permanent;
469
470                public SetFleetFlagsWithReasonAction(String reason, boolean permanent, String ... flags) {
471                        this.permanent = permanent;
472                        this.flags = flags;
473                        this.reason = reason;
474                }
475
476                public void doAction(TriggerActionContext context) {
477                        BaseHubMission bhm = (BaseHubMission) context.mission;
478                        for (String flag : flags) {
479                                Misc.setFlagWithReason(context.fleet.getMemoryWithoutUpdate(),
480                                                                           flag, reason, true, -1f);
481                                
482                                if (context.makeAllFleetFlagsPermanent) {
483                                        permanent = true;
484                                }
485                                
486                                if (!permanent && bhm != null) {
487                                        String requiredKey = flag + "_" + reason;
488                                        bhm.changes.add(new VariableSet(context.fleet.getMemoryWithoutUpdate(), requiredKey, true));
489                                }
490                        }
491                }
492        }
493
494        public static class UnsetFleetFlagsWithReasonAction implements
495                        TriggerAction {
496                protected String[] flags;
497                protected String reason;
498
499                public UnsetFleetFlagsWithReasonAction(String reason, String ... flags) {
500                        this.reason = reason;
501                        this.flags = flags;
502                }
503
504                public void doAction(TriggerActionContext context) {
505                        for (String flag : flags) {
506                                Misc.setFlagWithReason(context.fleet.getMemoryWithoutUpdate(),
507                                                flag, reason, false, -1f);
508                        }
509                }
510        }
511
512
513        public static class SetPersonMissionRefAction implements TriggerAction {
514                protected String key;
515
516                public SetPersonMissionRefAction(String key) {
517                        this.key = key;
518                }
519
520                public void doAction(TriggerActionContext context) {
521                        context.person.getMemoryWithoutUpdate().set(key, context.mission);
522                }
523        }
524
525
526        public static class SetFleetMissionRefAction implements TriggerAction {
527                protected String key;
528
529                public SetFleetMissionRefAction(String key) {
530                        this.key = key;
531                }
532
533                public void doAction(TriggerActionContext context) {
534                        context.fleet.getMemoryWithoutUpdate().set(key, context.mission);
535                }
536        }
537
538
539        public static class SetMemoryValueAction implements TriggerAction {
540                protected String key;
541                protected Object value;
542                protected MemoryAPI memory;
543                protected boolean removeOnMissionOver;
544                
545                public SetMemoryValueAction(MemoryAPI memory, String key, Object value, boolean removeOnMissionOver) {
546                        this.memory = memory;
547                        this.key = key;
548                        this.value = value;
549                        this.removeOnMissionOver = removeOnMissionOver;
550                }
551                
552                public void doAction(TriggerActionContext context) {
553                        memory.set(key, value);
554                        BaseHubMission bhm = (BaseHubMission) context.mission;
555                        bhm.changes.add(new VariableSet(memory, key, removeOnMissionOver));
556                }
557        }
558        
559        public static class SetMemoryValueAfterDelay implements TriggerAction, EveryFrameScript {
560                protected String key;
561                protected Object value;
562                protected MemoryAPI memory;
563                protected float delay;
564                
565                public SetMemoryValueAfterDelay(float delay, MemoryAPI memory, String key, Object value) {
566                        this.memory = memory;
567                        this.key = key;
568                        this.value = value;
569                        this.delay = delay;
570                }
571                
572                public void doAction(TriggerActionContext context) {
573                        if (delay <= 0) {
574                                memory.set(key, value);
575                        } else {
576                                Global.getSector().addScript(this);
577                        }
578                }
579
580                public boolean isDone() {
581                        return delay < 0;
582                }
583
584                public boolean runWhilePaused() {
585                        return false;
586                }
587
588                public void advance(float amount) {
589                        if (delay < 0) return; 
590                        float days = Global.getSector().getClock().convertToDays(amount);
591                        delay -= days;
592                        if (delay < 0) {
593                                memory.set(key, value);
594                        }
595                }
596        }
597        
598        public static class AddTagAfterDelay implements TriggerAction, EveryFrameScript {
599                protected String tag;
600                protected float delay;
601                protected StarSystemAPI system;
602                
603                public AddTagAfterDelay(float delay, StarSystemAPI system, String tag) {
604                        this.delay = delay;
605                        this.system = system;
606                        this.tag = tag;
607                }
608                
609                public void doAction(TriggerActionContext context) {
610                        Global.getSector().addScript(this);
611                }
612                
613                public boolean isDone() {
614                        return delay < 0;
615                }
616                
617                public boolean runWhilePaused() {
618                        return false;
619                }
620                
621                public void advance(float amount) {
622                        if (delay < 0) return; 
623                        float days = Global.getSector().getClock().convertToDays(amount);
624                        delay -= days;
625                        if (delay < 0) {
626                                system.addTag(tag);
627                        }
628                }
629        }
630        
631        public static class RunScriptAfterDelay implements TriggerAction, EveryFrameScript {
632                protected float delay;
633                protected Script script;
634                
635                public RunScriptAfterDelay(float delay, Script script) {
636                        this.script = script;
637                        this.delay = delay;
638                }
639                
640                public void doAction(TriggerActionContext context) {
641                        Global.getSector().addScript(this);
642                }
643                
644                public boolean isDone() {
645                        return delay < 0;
646                }
647                
648                public boolean runWhilePaused() {
649                        return false;
650                }
651                
652                public void advance(float amount) {
653                        if (delay < 0) return; 
654                        float days = Global.getSector().getClock().convertToDays(amount);
655                        delay -= days;
656                        if (delay < 0 && script != null) {
657                                script.run();
658                                script = null;
659                        }
660                }
661        }
662        
663        public static class IncreaseMarketHostileTimeout implements TriggerAction {
664                protected MarketAPI market;
665                protected float days;
666                
667                public IncreaseMarketHostileTimeout(MarketAPI market, float days) {
668                        this.market = market;
669                        this.days = days;
670                }
671
672                public void doAction(TriggerActionContext context) {
673                        Misc.increaseMarketHostileTimeout(market, days);
674                }
675        }
676        
677        public static class SetFleetMemoryValueAction implements TriggerAction {
678                protected String key;
679                protected Object value;
680
681                public SetFleetMemoryValueAction(String key, Object value) {
682                        this.key = key;
683                        this.value = value;
684                }
685
686                public void doAction(TriggerActionContext context) {
687                        context.fleet.getMemoryWithoutUpdate().set(key, value);
688                }
689        }
690        
691        public static class AddFleetDefeatTriggerAction implements TriggerAction {
692                protected String trigger;
693                protected boolean permanent;
694                public AddFleetDefeatTriggerAction(String trigger, boolean permanent) {
695                        this.trigger = trigger;
696                        this.permanent = permanent;
697                }
698                public void doAction(TriggerActionContext context) {
699                        ((BaseHubMission)context.mission).addFleetDefeatTrigger(context.fleet, trigger, permanent);
700                }
701        }
702        
703        public static class MakeFleetFlagsPermanentAction implements TriggerAction {
704                protected boolean permanent;
705                public MakeFleetFlagsPermanentAction(boolean permanent) {
706                        this.permanent = permanent;
707                }
708                public void doAction(TriggerActionContext context) {
709                        context.makeAllFleetFlagsPermanent = permanent;
710                }
711        }
712
713
714        public static class AddTagsAction implements TriggerAction {
715                protected String [] tags;
716                
717                public AddTagsAction(String ... tags) {
718                        this.tags = tags;
719                }
720                
721                public void doAction(TriggerActionContext context) {
722                        for (String tag : tags) {
723                                context.fleet.addTag(tag);
724                        }
725                }
726        }
727        
728        public static class AddCommanderSkillAction implements TriggerAction {
729                protected String skill;
730                protected int level;
731                
732                public AddCommanderSkillAction(String skill, int level) {
733                        this.skill = skill;
734                        this.level = level;
735                }
736                
737                public void doAction(TriggerActionContext context) {
738                        context.fleet.getCommanderStats().setSkillLevel(skill, level);
739                }
740        }
741        
742        public static class SetFleetFlagAction implements TriggerAction {
743                protected String flag;
744                protected Object[] stages;
745                protected boolean permanent;
746
747                public SetFleetFlagAction(String flag, boolean permanent, Object ... stages) {
748                        this.flag = flag;
749                        this.permanent = permanent;
750                        this.stages = stages;
751                }
752
753                public void doAction(TriggerActionContext context) {
754                        if (context.makeAllFleetFlagsPermanent) {
755                                permanent = true;
756                        }
757                        ((BaseHubMission)context.mission).setFlag(context.fleet, flag, permanent, stages);
758                }
759        }
760        
761        public static class SetEntityFlagAction implements TriggerAction {
762                protected String flag;
763                protected Object[] stages;
764                protected boolean permanent;
765
766                public SetEntityFlagAction(String flag, boolean permanent, Object ... stages) {
767                        this.flag = flag;
768                        this.permanent = permanent;
769                        this.stages = stages;
770                }
771
772                public void doAction(TriggerActionContext context) {
773                        ((BaseHubMission)context.mission).setFlag(context.entity, flag, permanent, stages);
774                }
775        }
776
777
778        public static class UnsetFleetFlagsAction implements TriggerAction {
779                protected String[] flags;
780
781                public UnsetFleetFlagsAction(String ... flags) {
782                        this.flags = flags;
783                }
784
785                public void doAction(TriggerActionContext context) {
786                        for (String flag : flags) {
787                                context.fleet.getMemoryWithoutUpdate().unset(flag);
788                        }
789                }
790        }
791        
792        public static class UnsetEntityFlagsAction implements TriggerAction {
793                protected String[] flags;
794                
795                public UnsetEntityFlagsAction(String ... flags) {
796                        this.flags = flags;
797                }
798                
799                public void doAction(TriggerActionContext context) {
800                        for (String flag : flags) {
801                                context.entity.getMemoryWithoutUpdate().unset(flag);
802                        }
803                }
804        }
805
806
807        public static class SaveEntityReferenceAction implements TriggerAction {
808                protected MemoryAPI memory;
809                protected String key;
810                public SaveEntityReferenceAction(MemoryAPI memory, String key) {
811                        this.memory = memory;
812                        this.key = key;
813                }
814                
815                public void doAction(TriggerActionContext context) {
816                        memory.set(key, context.entity);
817                        ((BaseHubMission) context.mission).changes.add(new VariableSet(memory, key, true));
818                }
819        }
820        
821        public static class SaveFleetReferenceAction implements TriggerAction {
822                protected MemoryAPI memory;
823                protected String key;
824                public SaveFleetReferenceAction(MemoryAPI memory, String key) {
825                        this.memory = memory;
826                        this.key = key;
827                }
828                
829                public void doAction(TriggerActionContext context) {
830                        memory.set(key, context.fleet);
831                        ((BaseHubMission) context.mission).changes.add(new VariableSet(memory, key, true));
832                }
833        }
834        
835        public static class RemoveAbilitiesAction implements TriggerAction {
836                protected String[] abilities;
837
838                public RemoveAbilitiesAction(String ... abilities) {
839                        this.abilities = abilities;
840                }
841
842                public void doAction(TriggerActionContext context) {
843                        for (String ability : abilities) {
844                                context.fleet.removeAbility(ability);
845                        }
846                }
847        }
848
849
850        public static class AddAbilitiesAction implements TriggerAction {
851                protected String[] abilities;
852
853                public AddAbilitiesAction(String ... abilities) {
854                        this.abilities = abilities;
855                }
856
857                public void doAction(TriggerActionContext context) {
858                        for (String ability : abilities) {
859                                context.fleet.addAbility(ability);
860                        }
861                }
862        }
863        
864        public static class GenericAddTagsAction implements TriggerAction {
865                protected String [] tags;
866                protected SectorEntityToken entity;
867                
868                public GenericAddTagsAction(SectorEntityToken entity, String ... tags) {
869                        this.tags = tags;
870                        this.entity = entity;
871                }
872                
873                public void doAction(TriggerActionContext context) {
874                        for (String tag : tags) {
875                                entity.addTag(tag);
876                        }
877                }
878        }
879        
880        public static class GenericRemoveTagsAction implements TriggerAction {
881                protected String [] tags;
882                protected SectorEntityToken entity;
883                
884                public GenericRemoveTagsAction(SectorEntityToken entity, String ... tags) {
885                        this.tags = tags;
886                        this.entity = entity;
887                }
888                
889                public void doAction(TriggerActionContext context) {
890                        for (String tag : tags) {
891                                entity.removeTag(tag);
892                        }
893                }
894        }
895        
896        public static class MakeNonStoryCriticalAction implements TriggerAction {
897                protected MemoryAPI [] memoryArray;
898
899                public MakeNonStoryCriticalAction(MemoryAPI ... memoryArray) {
900                        this.memoryArray = memoryArray;
901                }
902                public void doAction(TriggerActionContext context) {
903                        BaseHubMission bhm = (BaseHubMission) context.mission;
904                        for (MemoryAPI memory : memoryArray) {
905                                Misc.makeNonStoryCritical(memory, bhm.getReason());
906                        }
907                }
908        }
909
910
911        public static class SetInflaterAction implements TriggerAction {
912                protected FleetInflater inflater;
913
914                public SetInflaterAction(FleetInflater inflater) {
915                        this.inflater = inflater;
916                }
917
918                public void doAction(TriggerActionContext context) {
919                        context.fleet.setInflater(inflater);
920                }
921        }
922
923
924        public static class SetRemnantConfigAction implements TriggerAction {
925                protected boolean dormant;
926                protected long seed;
927
928                public SetRemnantConfigAction(boolean dormant, long seed) {
929                        this.dormant = dormant;
930                        this.seed = seed;
931                }
932
933                public void doAction(TriggerActionContext context) {
934                        Random random = new Random(seed);
935                        RemnantSeededFleetManager.initRemnantFleetProperties(random, context.fleet, dormant);
936                }
937        }
938
939
940        public static class AddCustomDropAction implements TriggerAction {
941                protected CargoAPI cargo;
942
943                public AddCustomDropAction(CargoAPI cargo) {
944                        this.cargo = cargo;
945                }
946
947                public void doAction(TriggerActionContext context) {
948                        BaseSalvageSpecial.addExtraSalvage(context.fleet, cargo);
949                }
950        }
951
952
953        public static class AddCommodityDropAction implements TriggerAction {
954                protected int quantity;
955                protected String commodityId;
956                protected boolean dropQuantityBasedOnShipsDestroyed;
957
958                public AddCommodityDropAction(int quantity, String commodityId, boolean dropQuantityBasedOnShipsDestroyed) {
959                        this.quantity = quantity;
960                        this.commodityId = commodityId;
961                        this.dropQuantityBasedOnShipsDestroyed = dropQuantityBasedOnShipsDestroyed;
962                }
963
964                public void doAction(TriggerActionContext context) {
965                        if (dropQuantityBasedOnShipsDestroyed) {
966                                context.fleet.getCargo().addCommodity(commodityId, quantity);
967                        } else {
968                                CargoAPI cargo = Global.getFactory().createCargo(true);
969                                cargo.addCommodity(commodityId, quantity);
970                                BaseSalvageSpecial.addExtraSalvage(context.fleet, cargo);
971                        }
972                }
973        }
974        
975        public static class AddCommodityFractionDropAction implements TriggerAction {
976                protected float fraction;
977                protected String commodityId;
978                protected boolean dropQuantityBasedOnShipsDestroyed;
979                
980                public AddCommodityFractionDropAction(float fraction, String commodityId) {
981                        this.fraction = fraction;
982                        this.commodityId = commodityId;
983                }
984                
985                public void doAction(TriggerActionContext context) {
986                        CommoditySpecAPI spec = Global.getSettings().getCommoditySpec(commodityId);
987                        float capacity = context.fleet.getCargo().getMaxCapacity();
988                        if (spec.isFuel()) {
989                                capacity = context.fleet.getCargo().getMaxFuel();
990                        } else if (spec.isPersonnel()) {
991                                capacity = context.fleet.getCargo().getMaxPersonnel();
992                        }
993                        int quantity = (int) Math.round(fraction * capacity);
994                        if (quantity > 0) {
995                                context.fleet.getCargo().addCommodity(commodityId, quantity);
996                        }
997                }
998        }
999
1000
1001        public static class AddWeaponDropAction implements TriggerAction {
1002                protected int quantity;
1003                protected String weaponId;
1004
1005                public AddWeaponDropAction(int quantity, String weaponId) {
1006                        this.quantity = quantity;
1007                        this.weaponId = weaponId;
1008                }
1009
1010                public void doAction(TriggerActionContext context) {
1011                        CargoAPI cargo = Global.getFactory().createCargo(true);
1012                        cargo.addWeapons(weaponId, quantity);
1013                        BaseSalvageSpecial.addExtraSalvage(context.fleet, cargo);
1014                }
1015        }
1016
1017
1018        public static class AddFighterLPCDropAction implements TriggerAction {
1019                protected String wingId;
1020                protected int quantity;
1021
1022                public AddFighterLPCDropAction(String wingId, int quantity) {
1023                        this.wingId = wingId;
1024                        this.quantity = quantity;
1025                }
1026
1027                public void doAction(TriggerActionContext context) {
1028                        CargoAPI cargo = Global.getFactory().createCargo(true);
1029                        cargo.addFighters(wingId, quantity);
1030                        BaseSalvageSpecial.addExtraSalvage(context.fleet, cargo);
1031                }
1032        }
1033
1034
1035        public static class AddHullmodDropAction implements TriggerAction {
1036                protected String hullmodId;
1037
1038                public AddHullmodDropAction(String hullmodId) {
1039                        this.hullmodId = hullmodId;
1040                }
1041
1042                public void doAction(TriggerActionContext context) {
1043                        CargoAPI cargo = Global.getFactory().createCargo(true);
1044                        cargo.addHullmods(hullmodId, 1);
1045                        BaseSalvageSpecial.addExtraSalvage(context.fleet, cargo);
1046                }
1047        }
1048
1049
1050        public static class AddSpecialItemDropAction implements TriggerAction {
1051                protected String data;
1052                protected String itemId;
1053
1054                public AddSpecialItemDropAction(String data, String itemId) {
1055                        this.data = data;
1056                        this.itemId = itemId;
1057                }
1058
1059                public void doAction(TriggerActionContext context) {
1060                        CargoAPI cargo = Global.getFactory().createCargo(true);
1061                        cargo.addSpecial(new SpecialItemData(itemId, data), 1);
1062                        BaseSalvageSpecial.addExtraSalvage(context.fleet, cargo);
1063                }
1064        }
1065
1066
1067        public static class SpawnFleetAtPickedLocationAction implements
1068                        TriggerAction {
1069                protected float range;
1070
1071                public SpawnFleetAtPickedLocationAction(float range) {
1072                        this.range = range;
1073                }
1074
1075                public void doAction(TriggerActionContext context) {
1076                        context.containingLocation.addEntity(context.fleet);
1077                        Vector2f loc = Misc.getPointWithinRadius(context.coordinates, range);
1078                        context.fleet.setLocation(loc.x, loc.y);
1079                }
1080        }
1081
1082
1083        public static class PickSetLocationAction implements TriggerAction {
1084                protected Vector2f coordinates;
1085                protected LocationAPI location;
1086
1087                public PickSetLocationAction(Vector2f coordinates, LocationAPI location) {
1088                        this.coordinates = coordinates;
1089                        this.location = location;
1090                }
1091
1092                public void doAction(TriggerActionContext context) {
1093                        context.coordinates = coordinates;
1094                        context.containingLocation = location;
1095                }
1096        }
1097
1098
1099        public static class PickLocationInHyperspaceAction implements TriggerAction {
1100                protected StarSystemAPI system;
1101
1102                public PickLocationInHyperspaceAction(StarSystemAPI system) {
1103                        this.system = system;
1104                }
1105
1106                public void doAction(TriggerActionContext context) {
1107                        //CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
1108                        Vector2f pick = pickLocationWithinArc(((BaseHubMission)context.mission).genRandom, system.getHyperspaceAnchor(), 0, 360f, 2000f, 0f, 1000f);
1109                        
1110                        context.coordinates = pick;
1111                        //context.containingLocation = playerFleet.getContainingLocation();
1112                        context.containingLocation = Global.getSector().getHyperspace();
1113                }
1114        }
1115
1116
1117        public static class PickLocationTowardsPlayerAction implements TriggerAction {
1118                protected SectorEntityToken entity;
1119                protected float arc;
1120                protected float minDist;
1121                protected float maxDist;
1122                protected float minDistFromPlayer;
1123
1124                public PickLocationTowardsPlayerAction(SectorEntityToken entity,
1125                                float arc, float minDist, float maxDist, float minDistFromPlayer) {
1126                        this.entity = entity;
1127                        this.arc = arc;
1128                        this.minDist = minDist;
1129                        this.maxDist = maxDist;
1130                        this.minDistFromPlayer = minDistFromPlayer;
1131                }
1132
1133                public void doAction(TriggerActionContext context) {
1134                        if (entity == null) entity = context.entity;
1135                        if (entity == null) entity = context.jumpPoint;
1136                        
1137                        CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
1138                        float dir = Misc.getAngleInDegrees(playerFleet.getLocation(), entity.getLocation());
1139                        dir += 180f;
1140                        if (playerFleet.getContainingLocation() != entity.getContainingLocation()) {
1141                                dir = ((BaseHubMission)context.mission).genRandom.nextFloat() * 360f;
1142                        }
1143                        
1144                        Vector2f pick = pickLocationWithinArc(((BaseHubMission)context.mission).genRandom, entity, dir, arc, minDistFromPlayer, minDist, maxDist);
1145                        
1146                        context.coordinates = pick;
1147                        //context.containingLocation = playerFleet.getContainingLocation();
1148                        context.containingLocation = entity.getContainingLocation();
1149                }
1150        }
1151        public static class PickLocationTowardsEntityAction implements TriggerAction {
1152                protected SectorEntityToken entity;
1153                protected float arc;
1154                protected float minDist;
1155                protected float maxDist;
1156                protected float minDistFromPlayer;
1157                
1158                public PickLocationTowardsEntityAction(SectorEntityToken entity,
1159                                float arc, float minDist, float maxDist, float minDistFromPlayer) {
1160                        this.entity = entity;
1161                        this.arc = arc;
1162                        this.minDist = minDist;
1163                        this.maxDist = maxDist;
1164                        this.minDistFromPlayer = minDistFromPlayer;
1165                }
1166                
1167                public void doAction(TriggerActionContext context) {
1168                        if (entity == null) entity = context.entity;
1169                        if (entity == null) entity = context.jumpPoint;
1170                        
1171                        CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
1172                        float dir = Misc.getAngleInDegrees(playerFleet.getLocation(), entity.getLocation());
1173                        //dir += 180f;
1174                        if (playerFleet.getContainingLocation() != entity.getContainingLocation()) {
1175                                dir = ((BaseHubMission)context.mission).genRandom.nextFloat() * 360f;
1176                        }
1177                        
1178                        Vector2f pick = pickLocationWithinArc(((BaseHubMission)context.mission).genRandom, playerFleet, dir, arc, minDistFromPlayer, minDist, maxDist);
1179                        
1180                        context.coordinates = pick;
1181                        //context.containingLocation = playerFleet.getContainingLocation();
1182                        context.containingLocation = entity.getContainingLocation();
1183                }
1184        }
1185
1186
1187        public static class PickLocationAwayFromPlayerAction implements
1188                        TriggerAction {
1189                protected float minDist;
1190                protected SectorEntityToken entity;
1191                protected float maxDist;
1192                protected float arc;
1193                protected float minDistFromPlayer;
1194
1195                public PickLocationAwayFromPlayerAction(float minDist,
1196                                SectorEntityToken entity, float maxDist, float arc,
1197                                float minDistFromPlayer) {
1198                        this.minDist = minDist;
1199                        this.entity = entity;
1200                        this.maxDist = maxDist;
1201                        this.arc = arc;
1202                        this.minDistFromPlayer = minDistFromPlayer;
1203                }
1204
1205                public void doAction(TriggerActionContext context) {
1206                        if (entity == null) entity = context.entity;
1207                        if (entity == null) entity = context.jumpPoint;
1208                        
1209                        CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
1210                        float dir = Misc.getAngleInDegrees(playerFleet.getLocation(), entity.getLocation());
1211                        if (playerFleet.getContainingLocation() != entity.getContainingLocation()) {
1212                                dir = ((BaseHubMission)context.mission).genRandom.nextFloat() * 360f;
1213                        }
1214                        
1215                        Vector2f pick = pickLocationWithinArc(((BaseHubMission)context.mission).genRandom, entity, dir, arc, minDistFromPlayer, minDist, maxDist);
1216                        
1217                        context.coordinates = pick;
1218                        //context.containingLocation = playerFleet.getContainingLocation();
1219                        context.containingLocation = entity.getContainingLocation();
1220                }
1221        }
1222
1223
1224        public static class PickLocationAroundPlayerAction implements TriggerAction {
1225                protected float maxDist;
1226                protected float minDist;
1227
1228                public PickLocationAroundPlayerAction(float maxDist, float minDist) {
1229                        this.maxDist = maxDist;
1230                        this.minDist = minDist;
1231                }
1232
1233                public void doAction(TriggerActionContext context) {
1234                        CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
1235                        Vector2f pick = pickLocationWithinArc(((BaseHubMission)context.mission).genRandom, playerFleet, 0, 360f, minDist, minDist, maxDist);
1236                        
1237                        context.coordinates = pick;
1238                        context.containingLocation = playerFleet.getContainingLocation();
1239                }
1240        }
1241
1242
1243        public static class PickLocationAroundEntityAction implements TriggerAction {
1244                protected float minDist;
1245                protected SectorEntityToken entity;
1246                protected float maxDist;
1247                protected float minDistFromPlayer;
1248
1249                public PickLocationAroundEntityAction(float minDist,
1250                                SectorEntityToken entity, float maxDist, float minDistFromPlayer) {
1251                        this.minDist = minDist;
1252                        this.entity = entity;
1253                        this.maxDist = maxDist;
1254                        this.minDistFromPlayer = minDistFromPlayer;
1255                }
1256
1257                public void doAction(TriggerActionContext context) {
1258                        if (entity == null) entity = context.entity;
1259                        if (entity == null) entity = context.jumpPoint;
1260                        Vector2f pick = pickLocationWithinArc(((BaseHubMission)context.mission).genRandom, entity, 0, 360f, minDistFromPlayer, minDist, maxDist);
1261                        
1262                        context.coordinates = pick;
1263                        context.containingLocation = entity.getContainingLocation();
1264                }
1265        }
1266
1267
1268        public static class PickLocationWithinArcAction implements TriggerAction {
1269                protected float arc;
1270                protected SectorEntityToken entity;
1271                protected float maxDist;
1272                protected float minDist;
1273                protected float minDistFromPlayer;
1274                protected float dir;
1275
1276                public PickLocationWithinArcAction(float arc, SectorEntityToken entity,
1277                                float maxDist, float minDist, float minDistFromPlayer, float dir) {
1278                        this.arc = arc;
1279                        this.entity = entity;
1280                        this.maxDist = maxDist;
1281                        this.minDist = minDist;
1282                        this.minDistFromPlayer = minDistFromPlayer;
1283                        this.dir = dir;
1284                }
1285
1286                public void doAction(TriggerActionContext context) {
1287                        if (entity == null) entity = context.entity;
1288                        if (entity == null) entity = context.jumpPoint;
1289                        
1290                        Vector2f pick = pickLocationWithinArc(((BaseHubMission)context.mission).genRandom, entity, dir, arc, minDistFromPlayer, minDist, maxDist);
1291                        
1292                        context.coordinates = pick;
1293                        context.containingLocation = entity.getContainingLocation();
1294                }
1295        }
1296
1297
1298        public static class FleetSetPatrolActionText implements TriggerAction {
1299                protected String text;
1300                public FleetSetPatrolActionText(String text) {
1301                        this.text = text;
1302                }
1303                
1304                public void doAction(TriggerActionContext context) {
1305                        context.patrolText = text;
1306                }
1307        }
1308        
1309        public static class FleetSetTravelActionText implements TriggerAction {
1310                protected String text;
1311                public FleetSetTravelActionText(String text) {
1312                        this.text = text;
1313                }
1314                
1315                public void doAction(TriggerActionContext context) {
1316                        context.travelText = text;
1317                }
1318        }
1319        
1320        public static class OrderFleetPatrolSystemAction implements TriggerAction {
1321                protected StarSystemAPI system;
1322
1323                public OrderFleetPatrolSystemAction(StarSystemAPI system) {
1324                        this.system = system;
1325                }
1326
1327                public void doAction(TriggerActionContext context) {
1328                        context.fleet.addScript(new TriggerFleetAssignmentAI(context.travelText, context.patrolText, context.mission, system, false, 
1329                                                                                                                                 context.fleet, (SectorEntityToken[])null));
1330                }
1331        }
1332
1333
1334        public static class OrderFleetPatrolPointsAction implements TriggerAction {
1335                protected List<SectorEntityToken> patrolPoints;
1336                protected boolean randomizeLocation;
1337                protected StarSystemAPI system;
1338
1339                public OrderFleetPatrolPointsAction(SectorEntityToken[] patrolPoints,
1340                                boolean randomizeLocation, StarSystemAPI system) {
1341                        this.patrolPoints = new ArrayList<SectorEntityToken>();
1342                        for (SectorEntityToken curr : patrolPoints) {
1343                                this.patrolPoints.add(curr);
1344                        }
1345                        this.randomizeLocation = randomizeLocation;
1346                        this.system = system;
1347                }
1348
1349                public void doAction(TriggerActionContext context) {
1350                        context.fleet.addScript(new TriggerFleetAssignmentAI(context.travelText, context.patrolText, 
1351                                        context.mission, system, randomizeLocation, context.fleet, patrolPoints.toArray(new SectorEntityToken[0])));
1352                }
1353        }
1354        
1355        public static class OrderFleetPatrolSpawnedEntity implements TriggerAction {
1356                protected boolean moveToNearEntity;
1357
1358                public OrderFleetPatrolSpawnedEntity(boolean moveToNearEntity) {
1359                        this.moveToNearEntity = moveToNearEntity;
1360                }
1361                
1362                public void doAction(TriggerActionContext context) {
1363                        SectorEntityToken entity = context.entity;
1364                        if (entity == null) entity = context.jumpPoint;
1365                        if (entity == null) entity = context.token;
1366                        if (entity == null) entity = context.planet;
1367                        context.fleet.addScript(
1368                                        new TriggerFleetAssignmentAI(context.travelText, context.patrolText, context.mission,
1369                                                        context.entity.getContainingLocation(), moveToNearEntity, context.fleet, entity));
1370                }
1371        }
1372
1373
1374        public static class OrderFleetPatrolTagsAction implements TriggerAction {
1375                protected List<SectorEntityToken> added;
1376                protected StarSystemAPI system;
1377                protected boolean randomizeLocation;
1378                protected String[] tags;
1379
1380                public OrderFleetPatrolTagsAction(StarSystemAPI system,
1381                                boolean randomizeLocation, String ... tags) {
1382                        this.system = system;
1383                        this.randomizeLocation = randomizeLocation;
1384                        this.tags = tags;
1385                }
1386
1387                public void doAction(TriggerActionContext context) {
1388                        List<SectorEntityToken> points = new ArrayList<SectorEntityToken>();
1389                        for (SectorEntityToken entity : system.getAllEntities()) {
1390                                for (String tag : tags) {
1391                                        if (entity.hasTag(tag)) {
1392                                                points.add(entity);
1393                                                break;
1394                                        }
1395                                }
1396                        }
1397                        if (added != null) points.addAll(added);
1398                        context.fleet.addScript(new TriggerFleetAssignmentAI(context.travelText, context.patrolText, context.mission, system, randomizeLocation, context.fleet,
1399                                                                        points.toArray(new SectorEntityToken[0])));
1400                }
1401        }
1402
1403        public static class OrderFleetStopPursuingPlayerUnlessInStage implements TriggerAction {
1404                protected List<Object> stages;
1405                protected BaseHubMission mission;
1406                public OrderFleetStopPursuingPlayerUnlessInStage(BaseHubMission mission, Object...stages) {
1407                        this.mission = mission;
1408                        this.stages = Arrays.asList(stages);
1409                }
1410
1411                public void doAction(TriggerActionContext context) {
1412                        context.fleet.addScript(new MissionFleetStopPursuingPlayer(context.fleet, mission, stages));
1413                }
1414        }
1415        
1416        public static class OrderFleetInterceptNearbyPlayerInStage implements TriggerAction {
1417                protected List<Object> stages;
1418                protected BaseHubMission mission;
1419                protected float maxRange;
1420                protected boolean repeatable;
1421                protected boolean mustBeStrongEnoughToFight;
1422                protected float repeatDelay;
1423                public OrderFleetInterceptNearbyPlayerInStage(BaseHubMission mission, 
1424                                boolean mustBeStrongEnoughToFight,
1425                                float maxRange, 
1426                                boolean repeatable, float repeatDelay, Object...stages) {
1427                        this.mission = mission;
1428                        this.mustBeStrongEnoughToFight = mustBeStrongEnoughToFight;
1429                        this.maxRange = maxRange;
1430                        this.repeatable = repeatable;
1431                        this.repeatDelay = repeatDelay;
1432                        this.stages = Arrays.asList(stages);
1433                }
1434                
1435                public void doAction(TriggerActionContext context) {
1436                        context.fleet.addScript(new MissionFleetInterceptPlayerIfNearby(context.fleet, mission, 
1437                                        mustBeStrongEnoughToFight, maxRange, repeatable, repeatDelay, stages));
1438                }
1439        }
1440        
1441
1442        public static class OrderFleetInterceptPlayerAction implements TriggerAction {
1443                protected boolean makeHostile;
1444                public OrderFleetInterceptPlayerAction(boolean makeHostile) {
1445                        this.makeHostile = makeHostile;
1446                }
1447
1448                public void doAction(TriggerActionContext context) {
1449                        TransmitterTrapSpecial.makeFleetInterceptPlayer(context.fleet, false, false, makeHostile, 1000f);
1450                        if (!context.fleet.hasScriptOfClass(MissionFleetAutoDespawn.class)) {
1451                                context.fleet.addScript(new MissionFleetAutoDespawn(context.mission, context.fleet));
1452                        }
1453                }
1454        }
1455        
1456        public static class OrderFleetEBurn implements TriggerAction {
1457                public OrderFleetEBurn() {
1458                }
1459                
1460                public void doAction(TriggerActionContext context) {
1461                        AbilityPlugin eb = context.fleet.getAbility(Abilities.EMERGENCY_BURN);
1462                        if (eb != null && eb.isUsable()) eb.activate();
1463                }
1464        }
1465
1466
1467        public static class FleetNoAutoDespawnAction implements TriggerAction {
1468                public void doAction(TriggerActionContext context) {
1469                        context.fleet.removeScriptsOfClass(MissionFleetAutoDespawn.class);
1470                }
1471        }
1472
1473
1474        public static class PickLocationAtInSystemJumpPointAction implements TriggerAction {
1475                protected StarSystemAPI system;
1476                protected float minDistFromPlayer;
1477
1478                public PickLocationAtInSystemJumpPointAction(StarSystemAPI system,
1479                                float minDistFromPlayer) {
1480                        this.system = system;
1481                        this.minDistFromPlayer = minDistFromPlayer;
1482                }
1483
1484                public void doAction(TriggerActionContext context) {
1485                        WeightedRandomPicker<SectorEntityToken> picker = new WeightedRandomPicker<SectorEntityToken>(((BaseHubMission)context.mission).genRandom);
1486                        picker.addAll(system.getJumpPoints());
1487                        
1488                        SectorEntityToken pick = picker.pick();
1489                        Vector2f loc = pickLocationWithinArc(((BaseHubMission)context.mission).genRandom, pick, 0, 360f, minDistFromPlayer, 0f, 0f);
1490                        
1491                        context.jumpPoint = pick;
1492                        context.coordinates = loc;
1493                        context.containingLocation = system;
1494                }
1495        }
1496        
1497        public static class PickLocationAtClosestToPlayerJumpPointAction implements TriggerAction {
1498                protected StarSystemAPI system;
1499                protected float minDistFromPlayer;
1500                
1501                public PickLocationAtClosestToPlayerJumpPointAction(StarSystemAPI system, float minDistFromPlayer) {
1502                        this.system = system;
1503                        this.minDistFromPlayer = minDistFromPlayer;
1504                }
1505                
1506                public void doAction(TriggerActionContext context) {
1507                        WeightedRandomPicker<SectorEntityToken> picker = new WeightedRandomPicker<SectorEntityToken>(((BaseHubMission)context.mission).genRandom);
1508                        
1509                        SectorEntityToken closest = null;
1510                        float minDist = Float.MAX_VALUE;
1511                        for (SectorEntityToken jp : system.getJumpPoints()) {
1512                                if (system.isCurrentLocation()) {
1513                                        float dist = Misc.getDistance(jp, Global.getSector().getPlayerFleet());
1514                                        if (dist < minDist) {
1515                                                closest = jp;
1516                                                minDist = dist;
1517                                        }
1518                                } else {
1519                                        picker.add(jp);
1520                                }
1521                        }
1522                        if (closest != null) {
1523                                picker.add(closest);
1524                        }
1525                        
1526                        SectorEntityToken pick = picker.pick();
1527                        Vector2f loc = pickLocationWithinArc(((BaseHubMission)context.mission).genRandom, pick, 0, 360f, minDistFromPlayer, 0f, 0f);
1528                        
1529                        context.jumpPoint = pick;
1530                        context.coordinates = loc;
1531                        context.containingLocation = system;
1532                }
1533        }
1534        
1535        /**
1536         * Should not use this for player fleet since that entity can change if it respawns.
1537         * @author Alex Mosolov
1538         *
1539         * Copyright 2020 Fractal Softworks, LLC
1540         */
1541        public static class PickLocationAtClosestToEntityJumpPointAction implements TriggerAction {
1542                protected StarSystemAPI system;
1543                protected float minDistFromEntity;
1544                protected SectorEntityToken entity;
1545                
1546                public PickLocationAtClosestToEntityJumpPointAction(StarSystemAPI system, SectorEntityToken entity, float minDistFromEntity) {
1547                        this.system = system;
1548                        this.entity = entity;
1549                        this.minDistFromEntity = minDistFromEntity;
1550                }
1551                
1552                public void doAction(TriggerActionContext context) {
1553                        WeightedRandomPicker<SectorEntityToken> picker = new WeightedRandomPicker<SectorEntityToken>(((BaseHubMission)context.mission).genRandom);
1554                        
1555                        SectorEntityToken closest = null;
1556                        float minDist = Float.MAX_VALUE;
1557                        for (SectorEntityToken jp : system.getJumpPoints()) {
1558                                if (system.isCurrentLocation()) {
1559                                        float dist = Misc.getDistance(jp, entity);
1560                                        if (dist < minDist) {
1561                                                closest = jp;
1562                                                minDist = dist;
1563                                        }
1564                                } else {
1565                                        picker.add(jp);
1566                                }
1567                        }
1568                        if (closest != null) {
1569                                picker.add(closest);
1570                        }
1571                        
1572                        SectorEntityToken pick = picker.pick();
1573                        Vector2f loc = pickLocationWithinArc(((BaseHubMission)context.mission).genRandom, pick, 0, 360f, minDistFromEntity, 0f, 0f);
1574                        
1575                        context.jumpPoint = pick;
1576                        context.coordinates = loc;
1577                        context.containingLocation = system;
1578                }
1579        }
1580        
1581        public static class CreateFleetAction implements TriggerAction {
1582                public long seed;
1583                
1584                public FleetParamsV3 params;
1585                public FleetSize fSize;
1586                public Float fSizeOverride;
1587                public Float combatFleetPointsOverride;
1588                public FleetQuality fQuality;
1589                public Float fQualityMod;
1590                public Integer fQualitySMods;
1591                public OfficerNum oNum;
1592                public OfficerQuality oQuality;
1593                public Boolean doNotIntegrateAICores;
1594                public String faction = null;
1595                
1596                public Float freighterMult = null;
1597                public Float tankerMult = null;
1598                public Float linerMult = null;
1599                public Float transportMult = null;
1600                public Float utilityMult = null;
1601                public Float qualityMod = null;
1602                public Float qualityOverride = null;
1603                
1604                public Float damage = null;
1605                
1606                public Boolean allWeapons;
1607                public ShipPickMode shipPickMode;
1608                public Boolean removeInflater;
1609                
1610                public String nameOverride = null;
1611                public Boolean noFactionInName = null;
1612
1613                public CreateFleetAction(String type, Vector2f locInHyper,
1614                                FleetSize fSize, FleetQuality fQuality, String factionId) {
1615                        seed = Misc.genRandomSeed();
1616                        params = new FleetParamsV3(locInHyper, factionId, null, type, 0f, 0f, 0f, 0f, 0f, 0f, 0f);
1617                        params.ignoreMarketFleetSizeMult = true;
1618                        
1619                        this.fSize = fSize;
1620                        this.fQuality = fQuality;
1621                        
1622                        freighterMult = 0.1f;
1623                        tankerMult = 0.1f;
1624                }
1625
1626                public void doAction(TriggerActionContext context) {
1627                        //Random random = new Random(seed);
1628                        Random random = null;
1629                        if (context.mission != null) {
1630                                random = ((BaseHubMission)context.mission).genRandom; 
1631                        } else {
1632                                random = Misc.random;
1633                        }
1634                        FactionAPI faction = Global.getSector().getFaction(params.factionId);
1635                        float maxPoints = faction.getApproximateMaxFPPerFleet(ShipPickMode.PRIORITY_THEN_ALL);
1636                        
1637                        //strength = FleetStrength.MAXIMUM;
1638                        
1639                        //float fraction = fSize.maxFPFraction * (0.9f + random.nextFloat() * 0.2f);
1640                        float min = fSize.maxFPFraction - (fSize.maxFPFraction - fSize.prev().maxFPFraction) / 2f; 
1641                        float max = fSize.maxFPFraction + (fSize.next().maxFPFraction - fSize.maxFPFraction) / 2f;
1642                        float fraction = min + (max - min) * random.nextFloat();
1643                        
1644                        float excess = 0;
1645                        
1646                        if (fSizeOverride != null) {
1647                                fraction = fSizeOverride * (0.95f + random.nextFloat() * 0.1f);
1648                        }
1649                        else {
1650                                int numShipsDoctrine = 1;
1651                                if (params.doctrineOverride != null) numShipsDoctrine = params.doctrineOverride.getNumShips();
1652                                else if (faction != null) numShipsDoctrine = faction.getDoctrine().getNumShips();
1653                                float doctrineMult = FleetFactoryV3.getDoctrineNumShipsMult(numShipsDoctrine);
1654                                fraction *= 0.75f * doctrineMult;
1655                                if (fraction > FleetSize.MAXIMUM.maxFPFraction) {
1656                                        excess = fraction - FleetSize.MAXIMUM.maxFPFraction;
1657                                        fraction = FleetSize.MAXIMUM.maxFPFraction;
1658                                }
1659                        }
1660                        
1661                        //fraction = 1f;
1662                        
1663                        float combatPoints = fraction * maxPoints;
1664                        if (combatFleetPointsOverride != null) {
1665                                combatPoints = combatFleetPointsOverride;
1666                        }
1667
1668                        FactionDoctrineAPI doctrine = params.doctrineOverride;
1669                        if (excess > 0) {
1670                                if (doctrine == null) {
1671                                        doctrine = faction.getDoctrine().clone();
1672                                }
1673                                int added = (int)Math.round(excess / 0.1f);
1674                                if (added > 0) {
1675                                        doctrine.setOfficerQuality(Math.min(5, doctrine.getOfficerQuality() + added));
1676                                        doctrine.setShipQuality(doctrine.getShipQuality() + added);
1677                                }
1678                        }
1679//                      if (fraction > 0.5f && false) {
1680//                              if (doctrine == null) {
1681//                                      doctrine = faction.getDoctrine().clone();
1682//                              }
1683//                              int added = (int)Math.round((fraction - 0.5f) / 0.1f);
1684//                              if (added > 0) {
1685//                                      doctrine.setNumShips(Math.max(1, doctrine.getNumShips() - added));
1686//                                      doctrine.setOfficerQuality(Math.min(5, doctrine.getOfficerQuality() + added));
1687//                                      doctrine.setShipQuality(doctrine.getShipQuality() + added);
1688//                              }
1689//                      }
1690                        
1691                        if (freighterMult == null) freighterMult = 0f;
1692                        if (tankerMult == null) tankerMult = 0f;
1693                        if (linerMult == null) linerMult = 0f;
1694                        if (transportMult == null) transportMult = 0f;
1695                        if (utilityMult == null) utilityMult = 0f;
1696                        if (qualityMod == null) qualityMod = 0f;
1697                        
1698                        params.combatPts = combatPoints;
1699                        params.freighterPts = combatPoints * freighterMult; 
1700                        params.tankerPts = combatPoints * tankerMult;
1701                        params.transportPts = combatPoints * transportMult;
1702                        params.linerPts = combatPoints * linerMult;
1703                        params.utilityPts = combatPoints * utilityMult;
1704                        params.qualityMod = qualityMod;
1705                        
1706//                      if (damage != null && damage > 0) {
1707//                              if (damage > 1) damage = 1f;
1708//                              float mult1 = 1f - damage;
1709//                              float mult2 = 1f - damage * 0.5f;
1710//                              params.combatPts *= mult1;
1711//                              params.freighterPts *= mult2;
1712//                              params.tankerPts *= mult2;
1713//                              params.transportPts *= mult2;
1714//                              params.linerPts *= mult2;
1715//                              params.utilityPts *= mult2;
1716//                      }
1717                        
1718                        //params.modeOverride = ShipPickMode.PRIORITY_THEN_ALL; 
1719                        params.doctrineOverride = doctrine;
1720                        params.random = random;
1721                        
1722
1723                        if (fQuality != null) {
1724                                switch (fQuality) {
1725                                case VERY_LOW:
1726                                        if (fQualityMod != null) {
1727                                                params.qualityMod += fQuality.qualityMod;
1728                                        } else {
1729                                                params.qualityOverride = 0f;
1730                                        }
1731                                        break;
1732                                case LOWER:
1733                                        params.qualityMod += fQuality.qualityMod;
1734                                        break;
1735                                case DEFAULT:
1736                                        params.qualityMod += fQuality.qualityMod;
1737                                        break;
1738                                case HIGHER:
1739                                        params.qualityMod += fQuality.qualityMod;
1740                                        break;
1741                                case VERY_HIGH:
1742                                        if (fQualityMod != null) {
1743                                                params.qualityMod += fQuality.qualityMod;
1744                                        } else {
1745                                                params.qualityMod += fQuality.qualityMod;
1746                                                //params.qualityOverride = 1f;
1747                                        }
1748                                        break;
1749                                case SMOD_1:
1750                                        params.qualityMod += fQuality.qualityMod;
1751                                        params.averageSMods = fQuality.numSMods;
1752                                        break;
1753                                case SMOD_2:
1754                                        params.qualityMod += fQuality.qualityMod;
1755                                        params.averageSMods = fQuality.numSMods;
1756                                        break;
1757                                case SMOD_3:
1758                                        params.qualityMod += fQuality.qualityMod;
1759                                        params.averageSMods = fQuality.numSMods;
1760                                        break;
1761                                }
1762                        }
1763                        if (fQualityMod != null) {
1764                                params.qualityMod += fQualityMod;
1765                        }
1766                        if (fQualitySMods != null) {
1767                                params.averageSMods = fQualitySMods;
1768                        }
1769                        
1770                        if (oNum != null) {
1771                                switch (oNum) {
1772                                case NONE:
1773                                        params.withOfficers = false;
1774                                        break;
1775                                case FC_ONLY:
1776                                        params.officerNumberMult = 0f;
1777                                        break;
1778                                case FEWER:
1779                                        params.officerNumberMult = 0.5f;
1780                                        break;
1781                                case DEFAULT:
1782                                        break;
1783                                case MORE:
1784                                        params.officerNumberMult = 1.5f;
1785                                        break;
1786                                case ALL_SHIPS:
1787                                        params.officerNumberBonus = Global.getSettings().getInt("maxShipsInAIFleet");
1788                                        break;
1789                                }
1790                        }
1791                        
1792                        if (oQuality != null) {
1793                                switch (oQuality) {
1794                                case LOWER:
1795                                        params.officerLevelBonus = -3;
1796                                        params.officerLevelLimit = Global.getSettings().getInt("officerMaxLevel") - 1;
1797                                        params.commanderLevelLimit = Global.getSettings().getInt("maxAIFleetCommanderLevel") - 2;
1798                                        if (params.commanderLevelLimit < params.officerLevelLimit) {
1799                                                params.commanderLevelLimit = params.officerLevelLimit;
1800                                        }
1801                                        break;
1802                                case DEFAULT:
1803                                        break;
1804                                case HIGHER:
1805                                        params.officerLevelBonus = 2;
1806                                        params.officerLevelLimit = Global.getSettings().getInt("officerMaxLevel") + (int) OfficerTraining.MAX_LEVEL_BONUS;
1807                                        break;
1808                                case UNUSUALLY_HIGH:
1809                                        params.officerLevelBonus = 4;
1810                                        params.officerLevelLimit = SalvageSpecialAssigner.EXCEPTIONAL_PODS_OFFICER_LEVEL;
1811                                        break;
1812                                case AI_GAMMA:
1813                                case AI_BETA:
1814                                case AI_BETA_OR_GAMMA:
1815                                case AI_ALPHA:
1816                                case AI_MIXED:
1817                                case AI_OMEGA:
1818                                        params.aiCores = oQuality;
1819                                        break;
1820                                }
1821                                if (doNotIntegrateAICores != null) {
1822                                        params.doNotIntegrateAICores = doNotIntegrateAICores;
1823                                }
1824                        }
1825                        
1826                        if (shipPickMode != null) {
1827                                params.modeOverride = shipPickMode;
1828                        }
1829                        
1830                        params.updateQualityAndProducerFromSourceMarket();
1831                        if (qualityOverride != null) {
1832                                params.qualityOverride = qualityOverride + params.qualityMod;;
1833                        }
1834                        context.fleet = FleetFactoryV3.createFleet(params);
1835                        context.fleet.setFacing(random.nextFloat() * 360f);
1836                        
1837                        if (this.faction != null) {
1838                                context.fleet.setFaction(this.faction, true);
1839                        }
1840                        
1841                        if (this.nameOverride != null) {
1842                                context.fleet.setName(this.nameOverride);
1843                        }
1844                        if (this.noFactionInName != null && this.noFactionInName) {
1845                                context.fleet.setNoFactionInName(noFactionInName);
1846                        }
1847                        
1848                        if (removeInflater != null && removeInflater) {
1849                                context.fleet.setInflater(null);
1850                        } else {
1851                                if (context.fleet.getInflater() instanceof DefaultFleetInflater) {
1852                                        DefaultFleetInflater inflater = (DefaultFleetInflater) context.fleet.getInflater();
1853                                        if (inflater.getParams() instanceof DefaultFleetInflaterParams) {
1854                                                DefaultFleetInflaterParams p = (DefaultFleetInflaterParams) inflater.getParams();
1855                                                if (allWeapons != null) {
1856                                                        p.allWeapons = allWeapons;
1857                                                }
1858                                                if (shipPickMode != null) {
1859                                                        p.mode = shipPickMode;
1860                                                }
1861                                        }
1862                                }
1863                        }
1864                        
1865                        context.fleet.getMemoryWithoutUpdate().set(MemFlags.FLEET_BUSY, true);
1866                        //context.fleet.getMemoryWithoutUpdate().set("$LP_titheAskedFor", true);
1867                        
1868                        context.allFleets.add(context.fleet);
1869                        
1870                        if (!context.fleet.hasScriptOfClass(MissionFleetAutoDespawn.class)) {
1871                                context.fleet.addScript(new MissionFleetAutoDespawn(context.mission, context.fleet));
1872                        }
1873                        
1874                        if (damage != null) {
1875                                FleetFactoryV3.applyDamageToFleet(context.fleet, damage, false, random);
1876                        }
1877                        
1878//                      if (Factions.PIRATES.equals(params.factionId)) {
1879//                              
1880//                      }
1881                }
1882        }
1883        
1884        
1885//      public TriggerAction getPreviousAction() {
1886//              if (currTrigger.getActions().isEmpty()) return null;
1887//              return currTrigger.getActions().get(currTrigger.getActions().size() - 1);
1888//      }
1889        public CreateFleetAction getPreviousCreateFleetAction() {
1890                for (int i = currTrigger.getActions().size() - 1; i >= 0; i--) {
1891                        TriggerAction action = currTrigger.getActions().get(i);
1892                        if (action instanceof CreateFleetAction) {
1893                                return (CreateFleetAction) action;
1894                        }
1895                }
1896                return null;
1897        }
1898
1899        public void triggerMovePersonToMarket(PersonAPI person, MarketAPI market, boolean alwaysAddToComms) {
1900                triggerCustomAction(new MovePersonToMarket(person, market, alwaysAddToComms));
1901        }
1902        public void triggerIncreaseMarketHostileTimeout(MarketAPI market, float days) {
1903                triggerCustomAction(new IncreaseMarketHostileTimeout(market, days));
1904        }
1905        public void triggerRunScriptAfterDelay(float delay, Script script) {
1906                triggerCustomAction(new RunScriptAfterDelay(delay, script));
1907        }
1908        public void triggerAddTagAfterDelay(float delay, StarSystemAPI system, String tag) {
1909                triggerCustomAction(new AddTagAfterDelay(delay, system, tag));
1910        }
1911        public void triggerSetMemoryValueAfterDelay(float delay, HasMemory hasMemory, String key, Object value) {
1912                triggerSetMemoryValueAfterDelay(delay, hasMemory.getMemory(), key, value);
1913        }
1914        public void triggerSetMemoryValueAfterDelay(float delay, MemoryAPI memory, String key, Object value) {
1915                triggerCustomAction(new SetMemoryValueAfterDelay(delay, memory, key, value));
1916        }
1917        public void triggerSetGlobalMemoryValueAfterDelay(float delay, String key, Object value) {
1918                triggerCustomAction(new SetMemoryValueAfterDelay(delay, Global.getSector().getMemory(), key, value));
1919        }
1920        public float genDelay(float base) {
1921                return base * StarSystemGenerator.getNormalRandom(genRandom, 0.75f, 1.25f);
1922        }
1923        
1924        public void triggerUnhideCommListing(PersonAPI person) {
1925                triggerCustomAction(new UnhideCommListing(person));
1926        }
1927        public void triggerHideCommListing(PersonAPI person) {
1928                triggerCustomAction(new HideCommListing(person));
1929        }
1930        public void triggerSaveGlobalEntityRef(String key) {
1931                triggerSaveEntityRef(Global.getSector().getMemoryWithoutUpdate(), key);
1932        }
1933        public void triggerSaveEntityRef(MemoryAPI memory, String key) {
1934                triggerCustomAction(new SaveEntityReferenceAction(memory, key));
1935        }
1936        public void triggerSaveGlobalFleetRef(String key) {
1937                triggerSaveFleetRef(Global.getSector().getMemoryWithoutUpdate(), key);
1938        }
1939        public void triggerSaveFleetRef(MemoryAPI memory, String key) {
1940                triggerCustomAction(new SaveFleetReferenceAction(memory, key));
1941        }
1942        
1943        public SectorEntityToken getEntityFromGlobal(String key) {
1944                return Global.getSector().getMemoryWithoutUpdate().getEntity(key);
1945        }
1946        
1947        public void triggerCreateFleet(FleetSize size, FleetQuality quality, String factionId, String type, StarSystemAPI roughlyWhere) {
1948                triggerCustomAction(new CreateFleetAction(type, roughlyWhere.getLocation(), size, quality, factionId));
1949        }
1950        public void triggerCreateFleet(FleetSize size, FleetQuality quality, String factionId, String type, SectorEntityToken roughlyWhere) {
1951                triggerCustomAction(new CreateFleetAction(type, roughlyWhere.getLocationInHyperspace(), size, quality, factionId));
1952        }
1953        public void triggerCreateFleet(FleetSize size, FleetQuality quality, String factionId, String type, Vector2f locInHyper) {
1954                triggerCustomAction(new CreateFleetAction(type, locInHyper, size, quality, factionId));
1955        }
1956        
1957        public void triggerAutoAdjustFleetSize(FleetSize min, FleetSize max) {
1958                float f = getQualityFraction();
1959                CreateFleetAction cfa = getPreviousCreateFleetAction();
1960                cfa.fSizeOverride = min.maxFPFraction + (max.maxFPFraction - min.maxFPFraction) * f;
1961                
1962                autoAdjustFleetTypeName();
1963        }
1964        
1965        public void triggerSetFleetSizeFraction(float fractionOfMax) {
1966                CreateFleetAction cfa = getPreviousCreateFleetAction();
1967                cfa.fSizeOverride = fractionOfMax;
1968        }
1969        public void triggerSetFleetCombatFleetPoints(float combatFleetPointsOverride) {
1970                CreateFleetAction cfa = getPreviousCreateFleetAction();
1971                cfa.combatFleetPointsOverride = combatFleetPointsOverride;
1972        }
1973        public void triggerAutoAdjustFleetQuality(FleetQuality min, FleetQuality max) {
1974                float f = getQualityFraction();
1975                CreateFleetAction cfa = getPreviousCreateFleetAction();
1976                cfa.fQualityMod = min.qualityMod + (max.qualityMod - min.qualityMod) * f;
1977                cfa.fQualitySMods = (int) Math.round(min.numSMods + (max.numSMods - min.numSMods) * f);
1978                if (cfa.fQualitySMods <= 0) {
1979                        cfa.fQualitySMods = null;
1980                }
1981        }
1982        
1983        public void triggerAutoAdjustOfficerNum(OfficerNum min, OfficerNum max) {
1984                float f = getQualityFraction();
1985                CreateFleetAction cfa = getPreviousCreateFleetAction();
1986                cfa.oNum = (OfficerNum) pickEnum(f, getEnums(min, max));
1987        }
1988        public void triggerAutoAdjustOfficerQuality(OfficerQuality min, OfficerQuality max) {
1989                float f = getQualityFraction();
1990                CreateFleetAction cfa = getPreviousCreateFleetAction();
1991                cfa.oQuality = (OfficerQuality) pickEnum(f, getEnums(min, max));
1992        }
1993        
1994        public void triggerSetFleetQuality(FleetQuality quality) {
1995                CreateFleetAction cfa = getPreviousCreateFleetAction();
1996                if (cfa != null) {
1997                        cfa.fQuality = quality;
1998                }
1999        }
2000        public void triggerSetFleetSize(FleetSize size) {
2001                CreateFleetAction cfa = getPreviousCreateFleetAction();
2002                if (cfa != null) {
2003                        cfa.fSize= size;
2004                }
2005        }
2006        
2007        public void triggerRandomizeFleetStrengthMinor() {
2008                CreateFleetAction cfa = getPreviousCreateFleetAction();
2009                FleetSize size = cfa.fSize;
2010                if (size == null) size = FleetSize.MEDIUM;
2011                
2012                float min = size.maxFPFraction - (size.maxFPFraction - size.prev().maxFPFraction) / 2f; 
2013                float max = size.maxFPFraction + (size.next().maxFPFraction - size.maxFPFraction) / 2f;
2014                cfa.fSizeOverride = min + (max - min) * genRandom.nextFloat();
2015                //triggerAutoAdjustFleetSize(size.prev(), size.next());
2016                
2017                FleetQuality fq = cfa.fQuality;
2018                if (fq == null) fq = FleetQuality.DEFAULT;
2019                min = fq.qualityMod - (fq.qualityMod - fq.prev().qualityMod) / 2f; 
2020                max = fq.qualityMod + (fq.next().qualityMod - fq.qualityMod) / 2f;
2021                cfa.fQualityMod = min + (max - min) * genRandom.nextFloat();
2022                //triggerAutoAdjustFleetQuality(fq.prev(), fq.next());
2023        }
2024        
2025        public void triggerAutoAdjustFleetStrengthModerate() {
2026                CreateFleetAction cfa = getPreviousCreateFleetAction();
2027                FleetSize size = cfa.fSize;
2028                if (size == null) size = FleetSize.MEDIUM;
2029                
2030                triggerAutoAdjustFleetSize(size.prev(), size.next());
2031                
2032                FleetQuality fq = cfa.fQuality;
2033                if (fq == null) fq = FleetQuality.DEFAULT;
2034                FleetQuality limit = FleetQuality.VERY_HIGH;
2035                FleetQuality next = fq;
2036                int steps = 1;
2037                while (next.next().ordinal() <= limit.ordinal() && steps > 0) {
2038                        next = next.next();
2039                        steps--;
2040                }
2041                limit = FleetQuality.LOWER;
2042                FleetQuality prev = fq;
2043                steps = 1;
2044                while (prev.prev().ordinal() >= limit.ordinal() && steps > 0) {
2045                        prev = prev.prev();
2046                        steps--;
2047                }
2048                triggerAutoAdjustFleetQuality(prev, next);
2049                
2050                
2051                OfficerNum oNum = cfa.oNum;
2052                if (oNum == null) oNum = OfficerNum.DEFAULT;
2053                if (oNum == OfficerNum.FEWER || oNum == OfficerNum.DEFAULT) {
2054                        switch (oNum) {
2055                        case FEWER:
2056                                triggerAutoAdjustOfficerNum(OfficerNum.FEWER, OfficerNum.DEFAULT);
2057                                break;
2058                        case DEFAULT:
2059                                triggerAutoAdjustOfficerNum(OfficerNum.DEFAULT, OfficerNum.MORE);
2060                                break;
2061                        }
2062                }
2063                
2064                OfficerQuality oQuality = cfa.oQuality;
2065                if (oQuality == null) oQuality = OfficerQuality.DEFAULT;
2066                if (oQuality == OfficerQuality.LOWER || oQuality == OfficerQuality.DEFAULT) {
2067                        switch (oQuality) {
2068                        case LOWER:
2069                                triggerAutoAdjustOfficerQuality(OfficerQuality.LOWER, OfficerQuality.DEFAULT);
2070                                break;
2071                        case DEFAULT:
2072                                triggerAutoAdjustOfficerQuality(OfficerQuality.DEFAULT, OfficerQuality.HIGHER);
2073                                break;
2074                        }
2075                }
2076        }
2077        
2078        public void triggerAutoAdjustFleetStrengthMajor() {
2079                CreateFleetAction cfa = getPreviousCreateFleetAction();
2080                FleetSize size = cfa.fSize;
2081                if (size == null) size = FleetSize.MEDIUM;
2082                
2083                triggerAutoAdjustFleetSize(size.prev().prev(), size.next().next());
2084                
2085                FleetQuality fq = cfa.fQuality;
2086                if (fq == null) fq = FleetQuality.DEFAULT;
2087                FleetQuality limit = FleetQuality.VERY_HIGH;
2088                FleetQuality next = fq;
2089                int steps = 2;
2090                while (next.next().ordinal() <= limit.ordinal() && steps > 0) {
2091                        next = next.next();
2092                        steps--;
2093                }
2094                limit = FleetQuality.LOWER;
2095                FleetQuality prev = fq;
2096                steps = 2;
2097                while (prev.prev().ordinal() >= limit.ordinal() && steps > 0) {
2098                        prev = prev.prev();
2099                        steps--;
2100                }
2101                triggerAutoAdjustFleetQuality(prev, next);
2102                
2103                
2104                OfficerNum oNum = cfa.oNum;
2105                if (oNum == null) oNum = OfficerNum.DEFAULT;
2106                if (oNum == OfficerNum.FEWER || oNum == OfficerNum.DEFAULT) {
2107                        switch (oNum) {
2108                        case FEWER:
2109                                triggerAutoAdjustOfficerNum(OfficerNum.FEWER, OfficerNum.DEFAULT);
2110                                break;
2111                        case DEFAULT:
2112                                triggerAutoAdjustOfficerNum(OfficerNum.DEFAULT, OfficerNum.MORE);
2113                                break;
2114                        }
2115                }
2116                
2117                OfficerQuality oQuality = cfa.oQuality;
2118                if (oQuality == null) oQuality = OfficerQuality.DEFAULT;
2119                if (oQuality == OfficerQuality.LOWER || oQuality == OfficerQuality.DEFAULT) {
2120                        switch (oQuality) {
2121                        case LOWER:
2122                                triggerAutoAdjustOfficerQuality(OfficerQuality.LOWER, OfficerQuality.DEFAULT);
2123                                break;
2124                        case DEFAULT:
2125                                triggerAutoAdjustOfficerQuality(OfficerQuality.DEFAULT, OfficerQuality.HIGHER);
2126                                break;
2127                        }
2128                }
2129        }
2130        
2131        public void triggerAutoAdjustFleetStrengthExtreme() {
2132                CreateFleetAction cfa = getPreviousCreateFleetAction();
2133                FleetSize size = cfa.fSize;
2134                if (size == null) size = FleetSize.MEDIUM;
2135                
2136                triggerAutoAdjustFleetSize(size.prev().prev(), size.next().next().next());
2137                
2138                FleetQuality fq = cfa.fQuality;
2139                if (fq == null) fq = FleetQuality.DEFAULT;
2140                FleetQuality limit = FleetQuality.SMOD_1;
2141                FleetQuality next = fq;
2142                int steps = 3;
2143                while (next.next().ordinal() <= limit.ordinal() && steps > 0) {
2144                        next = next.next();
2145                        steps--;
2146                }
2147                limit = FleetQuality.LOWER;
2148                FleetQuality prev = fq;
2149                steps = 2;
2150                while (prev.prev().ordinal() >= limit.ordinal() && steps > 0) {
2151                        prev = prev.prev();
2152                        steps--;
2153                }
2154                triggerAutoAdjustFleetQuality(prev, next);
2155                
2156                
2157                OfficerNum oNum = cfa.oNum;
2158                if (oNum == null) oNum = OfficerNum.DEFAULT;
2159                if (oNum == OfficerNum.FEWER || oNum == OfficerNum.DEFAULT || oNum == OfficerNum.MORE) {
2160                        switch (oNum) {
2161                        case FEWER:
2162                                triggerAutoAdjustOfficerNum(OfficerNum.FEWER, OfficerNum.MORE);
2163                                break;
2164                        case DEFAULT:
2165                                triggerAutoAdjustOfficerNum(OfficerNum.FEWER, OfficerNum.ALL_SHIPS);
2166                                break;
2167                        case MORE:
2168                                triggerAutoAdjustOfficerNum(OfficerNum.DEFAULT, OfficerNum.ALL_SHIPS);
2169                                break;
2170                        }
2171                }
2172                
2173                OfficerQuality oQuality = cfa.oQuality;
2174                if (oQuality == null) oQuality = OfficerQuality.DEFAULT;
2175                if (oQuality == OfficerQuality.LOWER || oQuality == OfficerQuality.DEFAULT) {
2176                        switch (oQuality) {
2177                        case LOWER:
2178                                triggerAutoAdjustOfficerQuality(OfficerQuality.LOWER, OfficerQuality.DEFAULT);
2179                                break;
2180                        case DEFAULT:
2181                                triggerAutoAdjustOfficerQuality(OfficerQuality.DEFAULT, OfficerQuality.HIGHER);
2182                                break;
2183                        }
2184                }
2185        }
2186        
2187        
2188        protected transient boolean useQualityInsteadOfQualityFraction = false;
2189        /**
2190         * Set to true when methods that auto-adjust fleet strength should do so based on the mission quality
2191         * rather than the mission qualityFactor - i.e. absolute mission quality rather than where it is within
2192         * the range of possible qualities given the giver's importance and your relationship level with them.
2193         * @param temporarilyUseQualityInsteadOfQualityFraction
2194         */
2195        public void setUseQualityInsteadOfQualityFraction(boolean temporarilyUseQualityInsteadOfQualityFraction) {
2196                this.useQualityInsteadOfQualityFraction = temporarilyUseQualityInsteadOfQualityFraction;
2197        }
2198
2199        /**
2200         * Where the current quality is relative to min and max quality for this mission giver.
2201         * @return
2202         */
2203        protected float getQualityFraction() {
2204                float quality = getQuality();
2205                if (useQualityInsteadOfQualityFraction) {
2206                        return quality;
2207                }
2208                
2209                float minQuality = getMinQuality();
2210                float maxQuality = getMaxQuality();
2211                float base = getBaseQuality();
2212                
2213                float f;
2214                if (quality < base) {
2215                        float range = base - minQuality;
2216                        f = 0f;
2217                        if (range > 0) {
2218                                f = (quality - minQuality) / range;
2219                        }
2220                        if (f < 0) f = 0;
2221                        if (f > 1) f = 1;
2222                        f = f * 0.5f;
2223                } else {
2224                        float range = maxQuality - base;
2225                        f = 1f;
2226                        if (range > 0) {
2227                                f = (quality - base) / range;
2228                        }
2229                        if (f < 0) f = 0;
2230                        if (f > 1) f = 1;
2231                        f = 0.5f + f * 0.5f;
2232                }
2233                return f;
2234        }
2235        
2236        @SuppressWarnings("unchecked")
2237        protected Object [] getEnums(Enum from, Enum to) {
2238                return EnumSet.range(from, to).toArray();
2239        }
2240        
2241        protected Object pickEnum(float f, Object ... enums) {
2242                float num = enums.length;
2243                f *= (num - 1f);
2244                
2245                float rem = (float)(f - (int) f);
2246                if (rem < 0.2f) rem = 0f;
2247                if (rem > 0.8f) rem = 1f;
2248                
2249                int index = (int) f;
2250                if (genRandom.nextFloat() < rem) {
2251                        index++;
2252                } 
2253                if (index > enums.length - 1) index = enums.length - 1;
2254                if (index < 0) index = 0;
2255                return enums[index];
2256        }
2257
2258//      defaults to this
2259//      public void triggerSetFleetCompositionStandardSupportShips() {
2260//              triggerSetFleetComposition(0.1f, 0.1f, 0f, 0f, 0f, 0f);
2261//      }
2262        
2263        public void triggerSetFleetCompositionNoSupportShips() {
2264                triggerSetFleetComposition(0f, 0f, 0f, 0f, 0f);
2265        }
2266                        
2267        public void triggerSetFleetComposition(float freighterMult, float tankerMult,
2268                                                                                   float transportMult, float linerMult,
2269                                                                                   float utilityMult) {
2270                CreateFleetAction cfa = getPreviousCreateFleetAction();
2271                if (freighterMult > 0) cfa.freighterMult = freighterMult;
2272                else cfa.freighterMult = null;
2273                
2274                if (tankerMult > 0) cfa.tankerMult = tankerMult;
2275                else cfa.tankerMult = null;
2276                
2277                if (transportMult > 0) cfa.transportMult = transportMult;
2278                else cfa.transportMult = null;
2279                
2280                if (linerMult > 0) cfa.linerMult = linerMult;
2281                else cfa.linerMult = null;
2282                
2283                if (utilityMult > 0) cfa.utilityMult = utilityMult;
2284                else cfa.utilityMult = null;
2285        }
2286        
2287        public void triggerSetFleetDoctrineComp(int warships, int carriers, int phaseShips) {
2288                CreateFleetAction cfa = getPreviousCreateFleetAction();
2289                
2290                if (cfa.params.doctrineOverride == null) {
2291                        FactionAPI faction = Global.getSector().getFaction(cfa.params.factionId);
2292                        cfa.params.doctrineOverride = faction.getDoctrine().clone();
2293                }
2294                
2295                cfa.params.doctrineOverride.setWarships(warships);
2296                cfa.params.doctrineOverride.setCarriers(carriers);
2297                cfa.params.doctrineOverride.setPhaseShips(phaseShips);
2298        }
2299        
2300        public void triggerAddShips(String ...variants) {
2301                CreateFleetAction cfa = getPreviousCreateFleetAction();
2302                if (cfa.params.addShips == null) {
2303                        cfa.params.addShips = new ArrayList<String>();
2304                }
2305                for (String id : variants) {
2306                        cfa.params.addShips.add(id);
2307                }
2308        }
2309        
2310        public void triggerSetFleetProbabilityCombatFreighters(float prob) {
2311                CreateFleetAction cfa = getPreviousCreateFleetAction();
2312                if (cfa.params.doctrineOverride == null) {
2313                        FactionAPI faction = Global.getSector().getFaction(cfa.params.factionId);
2314                        cfa.params.doctrineOverride = faction.getDoctrine().clone();
2315                }
2316                
2317                cfa.params.doctrineOverride.setCombatFreighterProbability(prob);
2318        }
2319        
2320        public void triggerSetFleetDoctrineQuality(int officerQuality, int shipQuality, int numShips) {
2321                CreateFleetAction cfa = getPreviousCreateFleetAction();
2322                
2323                if (cfa.params.doctrineOverride == null) {
2324                        FactionAPI faction = Global.getSector().getFaction(cfa.params.factionId);
2325                        cfa.params.doctrineOverride = faction.getDoctrine().clone();
2326                }
2327                
2328                if (officerQuality >= 0) {
2329                        cfa.params.doctrineOverride.setOfficerQuality(officerQuality);
2330                }
2331                
2332                if (shipQuality >= 0) {
2333                        cfa.params.doctrineOverride.setShipQuality(shipQuality);
2334                }
2335                
2336                if (numShips >= 0) {
2337                        cfa.params.doctrineOverride.setNumShips(numShips);
2338                }
2339        }
2340        
2341        public void triggerSetFleetDoctrineOther(int shipSize, int aggression) {
2342                CreateFleetAction cfa = getPreviousCreateFleetAction();
2343                
2344                if (cfa.params.doctrineOverride == null) {
2345                        FactionAPI faction = Global.getSector().getFaction(cfa.params.factionId);
2346                        cfa.params.doctrineOverride = faction.getDoctrine().clone();
2347                }
2348                
2349                if (shipSize >= 0) {
2350                        cfa.params.doctrineOverride.setShipSize(shipSize);
2351                }
2352                if (aggression >= 0) {
2353                        cfa.params.doctrineOverride.setAggression(aggression);
2354                }
2355        }
2356        
2357        public void triggerSetFleetDoctrineRandomize(float randomizeProb) {
2358                CreateFleetAction cfa = getPreviousCreateFleetAction();
2359                
2360                if (cfa.params.doctrineOverride == null) {
2361                        FactionAPI faction = Global.getSector().getFaction(cfa.params.factionId);
2362                        cfa.params.doctrineOverride = faction.getDoctrine().clone();
2363                }
2364                
2365                cfa.params.doctrineOverride.setAutofitRandomizeProbability(randomizeProb);
2366        }
2367        
2368        public void triggerSetFleetSizeAndQuality(FleetSize size, FleetQuality quality, String fleetType) {
2369                CreateFleetAction cfa = getPreviousCreateFleetAction();
2370                cfa.fSize = size;
2371                cfa.fQuality = quality;
2372                cfa.params.fleetType = fleetType;
2373                cfa.fSizeOverride = null;
2374        }
2375        public void triggerSetFleetType(String fleetType) {
2376                CreateFleetAction cfa = getPreviousCreateFleetAction();
2377                cfa.params.fleetType = fleetType;
2378        }
2379        
2380        public void triggerSetFleetOfficers(OfficerNum num, OfficerQuality quality) {
2381                CreateFleetAction cfa = getPreviousCreateFleetAction();
2382                cfa.oNum = num;
2383                cfa.oQuality = quality;
2384        }
2385        
2386        public void triggerFleetSetCommander(PersonAPI commander) {
2387                CreateFleetAction cfa = getPreviousCreateFleetAction();
2388                cfa.params.commander = commander;
2389        }
2390        
2391        public void triggerSetFleetNoCommanderSkills() {
2392                CreateFleetAction cfa = getPreviousCreateFleetAction();
2393                cfa.params.noCommanderSkills = true;
2394        }
2395        
2396        public void triggerSetFleetMaxShipSize(int max) {
2397                CreateFleetAction cfa = getPreviousCreateFleetAction();
2398                cfa.params.maxShipSize = max;
2399        }
2400        public void triggerSetFleetMinShipSize(int min) {
2401                CreateFleetAction cfa = getPreviousCreateFleetAction();
2402                cfa.params.minShipSize = min;
2403        }
2404        public void triggerSetFleetMaxNumShips(int num) {
2405                CreateFleetAction cfa = getPreviousCreateFleetAction();
2406                cfa.params.maxNumShips = num;
2407        }
2408        
2409        public void triggerFleetSetSingleShipOnly() {
2410                CreateFleetAction cfa = getPreviousCreateFleetAction();
2411                cfa.params.onlyRetainFlagship = true;
2412        }
2413        public void triggerFleetSetFlagship(String variantId) {
2414                CreateFleetAction cfa = getPreviousCreateFleetAction();
2415                cfa.params.flagshipVariantId = variantId;
2416        }
2417        
2418        public void triggerFleetSetFlagship(ShipVariantAPI variant) {
2419                CreateFleetAction cfa = getPreviousCreateFleetAction();
2420                cfa.params.flagshipVariant = variant;
2421        }
2422        
2423        public void triggerFleetRemoveInflater() {
2424                CreateFleetAction cfa = getPreviousCreateFleetAction();
2425                cfa.removeInflater = true;
2426        }
2427        
2428        public void triggerFleetSetShipPickMode(ShipPickMode mode) {
2429                CreateFleetAction cfa = getPreviousCreateFleetAction();
2430                cfa.shipPickMode = mode;
2431        }
2432        
2433        public void triggerFleetSetAllWeapons() {
2434                CreateFleetAction cfa = getPreviousCreateFleetAction();
2435                cfa.allWeapons = true;
2436        }
2437        
2438//      public void triggerFleetSetFaction(String factionId) {
2439//              CreateFleetAction cfa = getPreviousCreateFleetAction();
2440//              cfa.faction = factionId;
2441//      }
2442        public void triggerSetFleetFaction(final String factionId) {
2443//              triggerCustomAction(new SetFleetFactionAction(factionId));
2444                CreateFleetAction cfa = getPreviousCreateFleetAction();
2445                cfa.faction = factionId;
2446        }
2447        
2448        public void triggerFleetSetName(String name) {
2449                CreateFleetAction cfa = getPreviousCreateFleetAction();
2450                cfa.nameOverride = name;
2451        }
2452        public void triggerFleetSetNoFactionInName() {
2453                CreateFleetAction cfa = getPreviousCreateFleetAction();
2454                cfa.noFactionInName = true;
2455        }
2456        public void triggerFleetDoNotIntegrateAICores() {
2457                CreateFleetAction cfa = getPreviousCreateFleetAction();
2458                cfa.doNotIntegrateAICores = true;
2459        }
2460        
2461        public FleetParamsV3 triggerGetFleetParams() {
2462                CreateFleetAction cfa = getPreviousCreateFleetAction();
2463                return cfa.params;
2464        }
2465        
2466        
2467        public void triggerSetFleetCommander(final PersonAPI commander) {
2468                CreateFleetAction cfa = getPreviousCreateFleetAction();
2469                if (cfa != null && cfa.params != null) {
2470                        cfa.params.commander = commander;
2471                } else {
2472                        triggerCustomAction(new TriggerAction() {
2473                                public void doAction(TriggerActionContext context) {
2474                                        context.fleet.setCommander(commander);
2475                                        context.fleet.getFleetData().ensureHasFlagship();
2476                                }
2477                        });
2478                }
2479        }
2480// commander will get overriden by default inflater so uh
2481// will it? doesn't seem like it would, looking at DFI
2482//      public void triggerSetFleetCommanderFlags(final String ... flags) {
2483//              triggerCustomAction(new TriggerAction() {
2484//                      public void doAction(TriggerActionContext context) {
2485//                              for (String flag : flags) {
2486//                                      context.fleet.getCommander().getMemoryWithoutUpdate().set(flag, true);
2487//                              }
2488//                      }
2489//              });
2490//      }
2491        
2492        public void triggerFleetMakeImportantPermanent(String flag) {
2493                triggerCustomAction(new FleetMakeImportantAction(flag, (Enum[]) null));
2494        }
2495        public void triggerFleetMakeImportant(String flag, Enum ... stages) {
2496                triggerCustomAction(new FleetMakeImportantAction(flag, stages));
2497        }
2498        public void triggerEntityMakeImportant(String flag, Enum ... stages) {
2499                triggerCustomAction(new EntityMakeImportantAction(flag, stages));
2500        }
2501        
2502        public void triggerSetFleetFlagsWithReasonPermanent(final String ... flags) {
2503                triggerCustomAction(new SetFleetFlagsWithReasonAction(getReason(), true, flags));
2504        }
2505        public void triggerSetFleetFlagsWithReason(final String ... flags) {
2506                triggerCustomAction(new SetFleetFlagsWithReasonAction(getReason(), false, flags));
2507        }
2508        
2509//      public void setFleetFlagsWithReason(final String ... flags) {
2510//              new SetFleetFlagsWithReasonAction(getReason(), false, flags).doAction(null);
2511//      }
2512//      
2513//      public void setFleetFlag(String flag) {
2514//              new SetFleetFlagAction(flag, false, (Object[])null).doAction(null);;
2515//      }
2516        
2517        public void triggerUnsetFleetFlagsWithReason(final String ... flags) {
2518                triggerCustomAction(new UnsetFleetFlagsWithReasonAction(getReason(), flags));
2519        }
2520        public void triggerSetPersonMissionRef(final String key) {
2521                triggerCustomAction(new SetPersonMissionRefAction(key));
2522        }
2523        public void triggerSetFleetMissionRef(final String key) {
2524                triggerCustomAction(new SetFleetMissionRefAction(key));
2525        }
2526        
2527        public void triggerSetFleetMemoryValue(final String key, final Object value) {
2528                triggerCustomAction(new SetFleetMemoryValueAction(key, value));
2529        }
2530        
2531        public void triggerSetMemoryValue(HasMemory withMemory, String key, Object value) {
2532                triggerCustomAction(new SetMemoryValueAction(withMemory.getMemoryWithoutUpdate(), key, value, true));
2533        }
2534        public void triggerSetMemoryValuePermanent(HasMemory withMemory, String key, Object value) {
2535                triggerCustomAction(new SetMemoryValueAction(withMemory.getMemoryWithoutUpdate(), key, value, false));
2536        }
2537        
2538        public void triggerSetGlobalMemoryValue(final String key, final Object value) {
2539                triggerCustomAction(new SetMemoryValueAction(Global.getSector().getMemoryWithoutUpdate(), key, value, true));
2540        }
2541        public void triggerSetGlobalMemoryValuePermanent(final String key, final Object value) {
2542                triggerCustomAction(new SetMemoryValueAction(Global.getSector().getMemoryWithoutUpdate(), key, value, false));
2543        }
2544        
2545        public void triggerSetFleetFlagPermanent(String flag) {
2546                triggerCustomAction(new SetFleetFlagAction(flag, true, (Object[])null));
2547        }
2548        public void triggerSetFleetGenericHailPermanent(String commsTrigger) {
2549                triggerSetFleetGenericHail(commsTrigger, (Object[])null);
2550        }
2551        public void triggerSetFleetGenericHail(String commsTrigger, Object ...stages) {
2552                if (stages == null || stages.length <= 0) {
2553                        triggerSetFleetFlagPermanent("$genericHail");
2554                } else {
2555                        triggerSetFleetFlag("$genericHail", stages);
2556                }
2557                triggerSetFleetMemoryValue("$genericHail_openComms", commsTrigger);
2558        }
2559        public void triggerSetFleetGenericHailIfNonHostilePermanent(String commsTrigger) {
2560                triggerSetFleetGenericHail(commsTrigger, (Object[])null);
2561        }
2562        public void triggerSetFleetGenericHailIfNonHostile(String commsTrigger, Object ...stages) {
2563                if (stages == null || stages.length <= 0) {
2564                        triggerSetFleetFlagPermanent("$genericHail_nonHostile");
2565                } else {
2566                        triggerSetFleetFlag("$genericHail_nonHostile", stages);
2567                }
2568                triggerSetFleetMemoryValue("$genericHail_openComms", commsTrigger);
2569        }
2570        public void triggerSetFleetFlag(String flag) {
2571                triggerCustomAction(new SetFleetFlagAction(flag, false, (Object[])null));
2572        }
2573        public void triggerSetEntityFlagPermanent(String flag) {
2574                triggerCustomAction(new SetEntityFlagAction(flag, true, (Object[])null));
2575        }
2576        public void triggerSetEntityFlag(String flag) {
2577                triggerCustomAction(new SetEntityFlagAction(flag, false, (Object[])null));
2578        }
2579        public void triggerSetFleetFlagPermanent(String flag, Object ... stages) {
2580                triggerCustomAction(new SetFleetFlagAction(flag, true, stages));
2581        }
2582        public void triggerSetFleetFlag(String flag, Object ... stages) {
2583                triggerCustomAction(new SetFleetFlagAction(flag, false, stages));
2584        }
2585        public void triggerUnsetFleetFlag(String flag) {
2586                triggerCustomAction(new UnsetFleetFlagsAction(flag));
2587        }
2588        public void triggerSetEntityFlagPermanent(String flag, Object ... stages) {
2589                triggerCustomAction(new SetEntityFlagAction(flag, true, stages));
2590        }
2591        public void triggerSetEntityFlag(String flag, Object ... stages) {
2592                triggerCustomAction(new SetEntityFlagAction(flag, false, stages));
2593        }
2594        public void triggerUnsetEntityFlag(String flag) {
2595                triggerCustomAction(new UnsetEntityFlagsAction(flag));
2596        }
2597//      public void triggerMakeHostileAndAggressiveNotPermanent(Object ... stages) {
2598//              triggerSetFleetFlagsWithReason(MemFlags.MEMORY_KEY_MAKE_HOSTILE, 
2599//                                                                         MemFlags.MEMORY_KEY_MAKE_AGGRESSIVE);
2600//              triggerSetFleetFlag(MemFlags.MEMORY_KEY_MAKE_AGGRESSIVE_ONE_BATTLE_ONLY);
2601//      }
2602        public void triggerMakeHostileAndAggressive() {
2603                triggerSetFleetFlagsWithReason(MemFlags.MEMORY_KEY_MAKE_HOSTILE, 
2604                                                         //MemFlags.MEMORY_KEY_MAKE_HOSTILE_WHILE_TOFF,
2605                                                         MemFlags.MEMORY_KEY_MAKE_AGGRESSIVE);
2606                triggerSetFleetFlag(MemFlags.MEMORY_KEY_MAKE_AGGRESSIVE_ONE_BATTLE_ONLY);
2607        }
2608        
2609        public void triggerMakeFleetIgnoreOtherFleetsExceptPlayer() {
2610                triggerMakeFleetIgnoreOtherFleets();
2611                triggerMakeFleetNotIgnorePlayer();
2612        }
2613        public void triggerMakeFleetNotIgnorePlayer() {
2614                triggerSetFleetFlag(MemFlags.FLEET_DO_NOT_IGNORE_PLAYER);
2615        }
2616        public void triggerMakeFleetIgnoreOtherFleets() {
2617                triggerSetFleetFlag(MemFlags.FLEET_IGNORES_OTHER_FLEETS);
2618        }
2619        public void triggerMakeFleetIgnoredByOtherFleets() {
2620                triggerSetFleetFlag(MemFlags.FLEET_IGNORED_BY_OTHER_FLEETS);
2621        }
2622        public void triggerMakeFleetAllowDisengage() {
2623                triggerSetFleetFlag(MemFlags.MEMORY_KEY_MAKE_ALLOW_DISENGAGE);
2624        }
2625        
2626        public void makeHostileAndAggressive(CampaignFleetAPI fleet, boolean permanent) {
2627                setFlagWithReason(fleet, MemFlags.MEMORY_KEY_MAKE_HOSTILE, permanent);
2628                setFlagWithReason(fleet, MemFlags.MEMORY_KEY_MAKE_AGGRESSIVE, permanent);
2629                setFlag(fleet, MemFlags.MEMORY_KEY_MAKE_AGGRESSIVE_ONE_BATTLE_ONLY, permanent);
2630        }
2631        
2632        public void triggerMakeNonHostile() {
2633                triggerSetFleetFlagsWithReason(MemFlags.MEMORY_KEY_MAKE_NON_HOSTILE);
2634        }
2635        public void triggerMakeHostile() {
2636                triggerSetFleetFlagsWithReason(MemFlags.MEMORY_KEY_MAKE_HOSTILE);
2637        }
2638        public void triggerMakeHostileToPlayerTradeFleets() {
2639                triggerSetFleetFlagsWithReason(MemFlags.MEMORY_KEY_MAKE_HOSTILE_TO_PLAYER_TRADE_FLEETS);
2640        }
2641        public void triggerMakeHostileToAllTradeFleets() {
2642                triggerSetFleetFlagsWithReason(MemFlags.MEMORY_KEY_MAKE_HOSTILE_TO_ALL_TRADE_FLEETS);
2643        }
2644        public void triggerMakeHostileWhileTransponderOff() {
2645//              triggerSetFleetFlagsWithReason(MemFlags.MEMORY_KEY_MAKE_HOSTILE,
2646//                                                       MemFlags.MEMORY_KEY_MAKE_HOSTILE_WHILE_TOFF);
2647                triggerSetFleetFlagsWithReason(MemFlags.MEMORY_KEY_MAKE_HOSTILE_WHILE_TOFF);
2648        }
2649        public void triggerMakeLowRepImpact() {
2650                triggerSetFleetFlagsWithReason(MemFlags.MEMORY_KEY_LOW_REP_IMPACT);
2651        }
2652        public void triggerMakeEveryoneJoinBattleAgainst() {
2653                triggerSetFleetFlagsWithReason(MemFlags.MEMORY_KEY_EVERYONE_JOINS_BATTLE_AGAINST);
2654        }
2655//      public void triggerMakeNoOneJoinBattleToHelp() {
2656//              triggerSetFleetFlagsWithReason(MemFlags.MEMORY_KEY_NO_ONE_JOINTS_BATTLE_TO_HELP);
2657//      }
2658        public void triggerMakeAlwaysSpreadTOffHostility() {
2659                triggerSetFleetFlagsWithReason(MemFlags.SPREAD_TOFF_HOSTILITY_IF_LOW_IMPACT);
2660        }
2661        public void triggerMakeNoRepImpact() {
2662                triggerSetFleetFlagsWithReason(MemFlags.MEMORY_KEY_LOW_REP_IMPACT,
2663                                                                           MemFlags.MEMORY_KEY_NO_REP_IMPACT);
2664        }
2665        public void triggerPatrolAllowTransponderOff() {
2666                triggerSetFleetFlag(MemFlags.MEMORY_KEY_PATROL_ALLOW_TOFF);
2667        }
2668        public void triggerDoNotShowFleetDesc() {
2669                triggerSetFleetFlagPermanent(MemFlags.MEMORY_KEY_DO_NOT_SHOW_FLEET_DESC);
2670        }
2671        
2672        public void triggerFleetForceAutofitOnAllShips() {
2673                triggerSetFleetFlag(MemFlags.MEMORY_KEY_FORCE_AUTOFIT_ON_NO_AUTOFIT_SHIPS);
2674        }
2675        
2676        public void triggerFleetOnlyEngageableWhenVisibleToPlayer() {
2677                triggerSetFleetFlag(MemFlags.CAN_ONLY_BE_ENGAGED_WHEN_VISIBLE_TO_PLAYER);
2678        }
2679        
2680        public void triggerFleetNoJump() {
2681                triggerSetFleetFlagPermanent(MemFlags.MEMORY_KEY_NO_JUMP);
2682        }
2683        public void triggerFleetAllowJump() {
2684                triggerUnsetFleetFlag(MemFlags.MEMORY_KEY_NO_JUMP);
2685        }
2686        
2687        /**
2688         * Fleet will respond to WarSimScript orders and get distracted by false sensor readings from a sensor array, etc. 
2689         */
2690        public void triggerSetFleetNotBusy() {
2691                triggerUnsetFleetFlag(MemFlags.FLEET_BUSY);
2692        }
2693        
2694        public void triggerSetPatrol() {
2695                triggerSetFleetFlagPermanent(MemFlags.MEMORY_KEY_PATROL_FLEET);
2696        }
2697        public void triggerSetFleetHasslePlayer(String hassleType) {
2698                triggerSetFleetFlag(MemFlags.WILL_HASSLE_PLAYER);
2699                triggerSetFleetMemoryValue(MemFlags.HASSLE_TYPE, hassleType);
2700        }
2701        public void triggerSetFleetExtraSmugglingSuspicion(float extraSuspicion) {
2702                triggerSetFleetMemoryValue(MemFlags.PATROL_EXTRA_SUSPICION, extraSuspicion);
2703        }
2704        public void triggerMakeNonHostileToFaction(String factionId) {
2705                String flag = MemFlags.MEMORY_KEY_MAKE_NON_HOSTILE + "_" + factionId;
2706                triggerSetFleetFlag(flag);
2707        }
2708        public void triggerMakeHostileToFaction(String factionId) {
2709                String flag = MemFlags.MEMORY_KEY_MAKE_HOSTILE + "_" + factionId;
2710                triggerSetFleetFlag(flag);
2711        }
2712        public void triggerSetPirateFleet() {
2713                triggerSetFleetFlagPermanent(MemFlags.MEMORY_KEY_PIRATE);
2714        }
2715        public void triggerSetTraderFleet() {
2716                triggerSetFleetFlagPermanent(MemFlags.MEMORY_KEY_TRADE_FLEET);
2717        }
2718        public void triggerSetWarFleet() {
2719                triggerSetFleetFlagPermanent(MemFlags.MEMORY_KEY_WAR_FLEET);
2720        }
2721        public void triggerSetSmugglerFleet() {
2722                triggerSetFleetFlagPermanent(MemFlags.MEMORY_KEY_SMUGGLER);
2723        }
2724        public void triggerFleetAllowLongPursuit() {
2725                triggerSetFleetFlagPermanent(MemFlags.MEMORY_KEY_ALLOW_LONG_PURSUIT);
2726        }
2727        public void triggerFleetPatherAllowTithe() {
2728                triggerUnsetFleetFlag("$LP_titheAskedFor");
2729        }
2730        public void triggerFleetPatherNoDefaultTithe() {
2731                triggerSetFleetFlagPermanent("$LP_titheAskedFor");
2732        }
2733//      public void triggerFleetAllowLongPursuitNotPermanent() {
2734//              triggerSetFleetFlag(MemFlags.MEMORY_KEY_ALLOW_LONG_PURSUIT);
2735//      }
2736        public void triggerFleetUnsetAllowLongPursuit() {
2737                triggerUnsetFleetFlag(MemFlags.MEMORY_KEY_ALLOW_LONG_PURSUIT);
2738        }
2739        public void triggerFleetSetAvoidPlayerSlowly() {
2740                triggerSetFleetFlag(MemFlags.MEMORY_KEY_AVOID_PLAYER_SLOWLY);
2741        }
2742        public void triggerUnsetAvoidPlayerSlowly() {
2743                triggerUnsetFleetFlag(MemFlags.MEMORY_KEY_AVOID_PLAYER_SLOWLY);
2744        }
2745        
2746        public void triggerSetFleetAlwaysPursue() {
2747                triggerSetFleetFlag(MemFlags.MEMORY_KEY_MAKE_ALWAYS_PURSUE);
2748        }
2749//      public void triggerSetFleetAlwaysPursueNotPermanent() {
2750//              triggerSetFleetFlag(MemFlags.MEMORY_KEY_MAKE_ALWAYS_PURSUE);
2751//      }
2752        public void triggerUnsetFleetAlwaysPursue() {
2753                triggerUnsetFleetFlag(MemFlags.MEMORY_KEY_MAKE_ALWAYS_PURSUE);
2754        }
2755        
2756        public void triggerSetStandardHostilePirateFlags() {
2757                triggerSetPirateFleet();
2758                triggerMakeHostile();
2759                triggerMakeLowRepImpact();
2760        }
2761        public void triggerSetStandardHostileNonPirateFlags() {
2762                triggerMakeHostile();
2763                triggerMakeLowRepImpact();
2764        }
2765        public void triggerSetStandardAggroPirateFlags() {
2766                triggerSetPirateFleet();
2767                triggerMakeHostileAndAggressive();
2768                triggerMakeLowRepImpact();
2769        }
2770        public void triggerSetStandardAggroNonPirateFlags() {
2771                triggerMakeHostileAndAggressive();
2772                triggerMakeLowRepImpact();
2773        }
2774        public void triggerRemoveAbilities(final String ... abilities) {
2775                triggerCustomAction(new RemoveAbilitiesAction(abilities));
2776        }       
2777        public void triggerAddAbilities(final String ... abilities) {
2778                triggerCustomAction(new AddAbilitiesAction(abilities));
2779        }
2780        public void triggerSetInflater(final FleetInflater inflater) {
2781                triggerCustomAction(new SetInflaterAction(inflater));
2782        }
2783        public void triggerSetRemnantConfig() {
2784                triggerSetRemnantConfig(false);
2785        }
2786        public void triggerSetRemnantConfigDormant() {
2787                triggerSetRemnantConfig(true);
2788        }
2789        public void triggerSetRemnantConfig(boolean dormant) {
2790                //final long seed = Misc.genRandomSeed();
2791                long seed = Misc.seedUniquifier() ^ genRandom.nextLong();
2792                triggerCustomAction(new SetRemnantConfigAction(dormant, seed));
2793        }
2794        
2795        public void triggerSetRemnantConfigActive() {
2796                triggerSetRemnantConfig();
2797                triggerAddAbilities(Abilities.EMERGENCY_BURN);
2798                triggerAddAbilities(Abilities.SENSOR_BURST);
2799                triggerAddAbilities(Abilities.GO_DARK);
2800                triggerFleetAllowJump();
2801        }
2802        
2803        public void triggerAddCustomDrop(final CargoAPI cargo) {
2804                triggerCustomAction(new AddCustomDropAction(cargo));
2805        }
2806        public void triggerAddCommodityDrop(String commodityId, int quantity, boolean dropQuantityBasedOnShipsDestroyed) {
2807                triggerCustomAction(new AddCommodityDropAction(quantity, commodityId, dropQuantityBasedOnShipsDestroyed));
2808        }
2809        public void triggerAddCommodityFractionDrop(String commodityId, float fraction) {
2810                triggerCustomAction(new AddCommodityFractionDropAction(fraction, commodityId));
2811        }
2812        public void triggerAddWeaponDrop(final String weaponId, final int quantity) {
2813                triggerCustomAction(new AddWeaponDropAction(quantity, weaponId));
2814        }
2815        public void triggerAddFighterLPCDrop(final String wingId, final int quantity) {
2816                triggerCustomAction(new AddFighterLPCDropAction(wingId, quantity));
2817        }
2818        public void triggerAddHullmodDrop(final String hullmodId) {
2819                triggerCustomAction(new AddHullmodDropAction(hullmodId));
2820        }
2821        public void triggerAddSpecialItemDrop(final String itemId, final String data) {
2822                triggerCustomAction(new AddSpecialItemDropAction(data, itemId));
2823        }
2824        
2825        
2826        public void triggerSpawnFleetAtPickedLocation() {
2827                triggerSpawnFleetAtPickedLocation(null, null);
2828        }
2829        /**
2830         * refKey could be needed if there's no global mission reference set.
2831         * @param flag
2832         * @param refKey
2833         */
2834        public void triggerSpawnFleetAtPickedLocation(final String flag, final String refKey) {
2835                triggerSpawnFleetAtPickedLocation(200f, flag, refKey);
2836        }
2837        public void triggerSpawnFleetAtPickedLocation(final float range, final String flag, final String refKey) {
2838                triggerCustomAction(new SpawnFleetAtPickedLocationAction(range));
2839                if (flag != null) {
2840                        triggerSetFleetFlag(flag);
2841                }
2842                if (refKey != null) {
2843                        triggerSetFleetMissionRef(refKey);
2844                }
2845        }
2846        public void triggerSpawnFleetNear(final SectorEntityToken entity, final String flag, final String refKey) {
2847                triggerSpawnFleetNear(entity, 200f, flag, refKey);
2848        }
2849        public void triggerSpawnFleetNear(final SectorEntityToken entity, final float range, final String flag, final String refKey) {
2850                triggerCustomAction(new SpawnFleetNearAction(entity, range));
2851                if (flag != null) {
2852                        triggerSetFleetFlag(flag);
2853                }
2854                if (refKey != null) {
2855                        triggerSetFleetMissionRef(refKey);
2856                }
2857        }
2858        
2859        public void triggerPickSetLocation(final LocationAPI location, final Vector2f coordinates) {
2860                triggerCustomAction(new PickSetLocationAction(coordinates, location));
2861        }
2862        public void triggerPickLocationInHyperspace(final StarSystemAPI system) {
2863                triggerCustomAction(new PickLocationInHyperspaceAction(system));
2864        }
2865        
2866        public void triggerPickLocationFromEntityTowardsPlayer(final float arc, final float dist) {
2867                triggerPickLocationTowardsPlayer(null, arc, DEFAULT_MIN_DIST_FROM_PLAYER, dist, dist);
2868        }
2869        public void triggerPickLocationTowardsPlayer(final SectorEntityToken entity, final float arc, final float dist) {
2870                triggerPickLocationTowardsPlayer(entity, arc, DEFAULT_MIN_DIST_FROM_PLAYER, dist, dist);
2871        }
2872        public void triggerPickLocationFromEntityTowardsPlayer(final float arc, 
2873                        final float minDist, final float maxDist) {
2874                triggerPickLocationAwayFromPlayer(null, arc, DEFAULT_MIN_DIST_FROM_PLAYER, minDist, maxDist);
2875        }
2876        public void triggerPickLocationTowardsPlayer(final SectorEntityToken entity, final float arc, 
2877                                                                                                  final float minDist, final float maxDist) {
2878                triggerPickLocationAwayFromPlayer(entity, arc, DEFAULT_MIN_DIST_FROM_PLAYER, minDist, maxDist);
2879        }
2880        public void triggerPickLocationFromEntityTowardsPlayer(final float arc, 
2881                        final float minDistFromPlayer, final float minDist, final float maxDist) {
2882                triggerCustomAction(new PickLocationTowardsPlayerAction(null, arc, minDist, maxDist, minDistFromPlayer));
2883        }
2884        public void triggerPickLocationTowardsPlayer(final SectorEntityToken entity, final float arc, 
2885                                                                                                 final float minDistFromPlayer, final float minDist, final float maxDist) {
2886                triggerCustomAction(new PickLocationTowardsPlayerAction(entity, arc, minDist, maxDist, minDistFromPlayer));
2887        }
2888        
2889        public void triggerPickLocationTowardsEntity(SectorEntityToken entity, float arc, float dist) {
2890                triggerPickLocationTowardsEntity(entity, arc, DEFAULT_MIN_DIST_FROM_PLAYER, dist, dist);
2891        }
2892        public void triggerPickLocationTowardsEntity(final SectorEntityToken entity, final float arc, 
2893                        final float minDistFromPlayer, final float minDist, final float maxDist) {
2894                triggerCustomAction(new PickLocationTowardsEntityAction(entity, arc, minDist, maxDist, minDistFromPlayer));
2895        }
2896        
2897        
2898        public void triggerPickLocationFromEntityAwayFromPlayer(final float arc, final float dist) {
2899                triggerPickLocationAwayFromPlayer(null, arc, DEFAULT_MIN_DIST_FROM_PLAYER, dist, dist);
2900        }
2901        public void triggerPickLocationFromEntityAwayFromPlayer(final float arc, 
2902                        final float minDist, final float maxDist) {
2903                triggerPickLocationAwayFromPlayer(null, arc, DEFAULT_MIN_DIST_FROM_PLAYER, minDist, maxDist);
2904        }
2905        public void triggerPickLocationFromEntityAwayFromPlayer(final float arc, 
2906                        final float minDistFromPlayer, final float minDist, final float maxDist) {
2907                triggerCustomAction(new PickLocationAwayFromPlayerAction(minDist, null, maxDist, arc, minDistFromPlayer));
2908        }
2909        public void triggerPickLocationAwayFromPlayer(final SectorEntityToken entity, final float arc, final float dist) {
2910                triggerPickLocationAwayFromPlayer(entity, arc, DEFAULT_MIN_DIST_FROM_PLAYER, dist, dist);
2911        }
2912        public void triggerPickLocationAwayFromPlayer(final SectorEntityToken entity, final float arc, 
2913                                                                                                  final float minDist, final float maxDist) {
2914                triggerPickLocationAwayFromPlayer(entity, arc, DEFAULT_MIN_DIST_FROM_PLAYER, minDist, maxDist);
2915        }
2916        public void triggerPickLocationAwayFromPlayer(final SectorEntityToken entity, final float arc, 
2917                                                                                                  final float minDistFromPlayer, final float minDist, final float maxDist) {
2918                triggerCustomAction(new PickLocationAwayFromPlayerAction(minDist, entity, maxDist, arc, minDistFromPlayer));
2919        }
2920        
2921        public void triggerPickLocationAroundPlayer(final float dist) {
2922                triggerPickLocationAroundPlayer(dist, dist);
2923        }
2924        public void triggerPickLocationAroundPlayer(final float minDist, final float maxDist) {
2925                triggerCustomAction(new PickLocationAroundPlayerAction(maxDist, minDist));
2926        }
2927        
2928        public static float DEFAULT_MIN_DIST_FROM_PLAYER = 3000f;
2929        public void triggerPickLocationAroundEntity(final float dist) {
2930                triggerPickLocationAroundEntity(null, DEFAULT_MIN_DIST_FROM_PLAYER, dist, dist);
2931        }
2932        public void triggerPickLocationAroundEntity(final SectorEntityToken entity, final float dist) {
2933                triggerPickLocationAroundEntity(entity, DEFAULT_MIN_DIST_FROM_PLAYER, dist, dist);
2934        }
2935        public void triggerPickLocationAroundEntity(final SectorEntityToken entity, final float minDist, final float maxDist) {
2936                triggerPickLocationAroundEntity(entity, DEFAULT_MIN_DIST_FROM_PLAYER, minDist, maxDist);
2937        }
2938        public void triggerPickLocationAroundEntity(final SectorEntityToken entity, final float minDistFromPlayer, final float minDist, final float maxDist) {
2939                triggerCustomAction(new PickLocationAroundEntityAction(minDist, entity, maxDist, minDistFromPlayer));
2940        }
2941        
2942        public void triggerPickLocationAtInSystemJumpPoint(final StarSystemAPI system) {
2943                triggerPickLocationAtInSystemJumpPoint(system, DEFAULT_MIN_DIST_FROM_PLAYER);
2944        }
2945        public void triggerPickLocationAtInSystemJumpPoint(final StarSystemAPI system, final float minDistFromPlayer) {
2946                triggerCustomAction(new PickLocationAtInSystemJumpPointAction(system, minDistFromPlayer));
2947        }
2948        
2949        public void triggerPickLocationAtClosestToPlayerJumpPoint(final StarSystemAPI system) {
2950                triggerPickLocationAtClosestToPlayerJumpPoint(system, DEFAULT_MIN_DIST_FROM_PLAYER);
2951        }
2952        public void triggerPickLocationAtClosestToPlayerJumpPoint(final StarSystemAPI system, final float minDistFromPlayer) {
2953                triggerCustomAction(new PickLocationAtClosestToPlayerJumpPointAction(system, minDistFromPlayer));
2954        }
2955        
2956        public void triggerPickLocationAtClosestToEntityJumpPoint(StarSystemAPI system, SectorEntityToken entity) {
2957                triggerCustomAction(new PickLocationAtClosestToEntityJumpPointAction(system, entity, 0f));
2958        }
2959        public void triggerPickLocationAtClosestToEntityJumpPoint(StarSystemAPI system, SectorEntityToken entity, float minDistFromEntity) {
2960                triggerCustomAction(new PickLocationAtClosestToEntityJumpPointAction(system, entity, minDistFromEntity));
2961        }
2962        
2963        public void triggerPickLocationWithinArc(final float dir, final float arc,
2964                                                        final float minDistFromPlayer, final float minDist, final float maxDist) {
2965                triggerPickLocationWithinArc(null, dir, arc, minDistFromPlayer, minDist, maxDist);
2966        }
2967        public void triggerPickLocationWithinArc(final SectorEntityToken entity, final float dir, final float arc,
2968                                                                                         final float minDistFromPlayer, final float minDist, final float maxDist) {
2969                triggerCustomAction(new PickLocationWithinArcAction(arc, entity, maxDist, minDist, minDistFromPlayer, dir));
2970        }
2971        
2972        public void triggerSetEntityToPickedJumpPoint() {
2973                triggerCustomAction(new SetEntityToPickedJumpPoint());
2974        }
2975        public void triggerFleetSetPatrolActionText(String patrolText) {
2976                triggerCustomAction(new FleetSetPatrolActionText(patrolText));
2977        }
2978        
2979        public void triggerFleetSetPatrolLeashRange(float dist) {
2980                triggerSetFleetMemoryValue(MemFlags.FLEET_PATROL_DISTANCE, dist);
2981        }
2982        public void triggerFleetSetTravelActionText(String travelText) {
2983                triggerCustomAction(new FleetSetTravelActionText(travelText));
2984        }
2985        
2986        public void triggerOrderFleetPatrol(final StarSystemAPI system) {
2987                triggerCustomAction(new OrderFleetPatrolSystemAction(system));
2988        }
2989        public void triggerOrderFleetPatrol(final SectorEntityToken ... patrolPoints) {
2990                triggerOrderFleetPatrol(null, false, patrolPoints);
2991        }
2992        public void triggerOrderFleetPatrol(final boolean randomizeLocation, final SectorEntityToken ... patrolPoints) {
2993                triggerOrderFleetPatrol(null, randomizeLocation, patrolPoints);
2994        }
2995        public void triggerOrderFleetPatrol(final StarSystemAPI system, final boolean randomizeLocation, 
2996                                                                                final SectorEntityToken ... patrolPoints) {
2997                triggerCustomAction(new OrderFleetPatrolPointsAction(patrolPoints, randomizeLocation, system));
2998        }
2999        public void triggerOrderFleetPatrol(final StarSystemAPI system, final boolean randomizeLocation, final String ... tags) {
3000                triggerCustomAction(new OrderFleetPatrolTagsAction(system, randomizeLocation, tags));
3001        }
3002        public void triggerOrderExtraPatrolPoints(SectorEntityToken ... points) {
3003                for (int i = currTrigger.getActions().size() - 1; i >= 0; i--) {
3004                        TriggerAction action = currTrigger.getActions().get(i);
3005                        if (action instanceof OrderFleetPatrolTagsAction) {
3006                                OrderFleetPatrolTagsAction a = (OrderFleetPatrolTagsAction) action;
3007                                if (a.added == null) a.added = new ArrayList<SectorEntityToken>();
3008                                for (SectorEntityToken curr : points) {
3009                                        if (curr != null) {
3010                                                a.added.add(curr);
3011                                        }
3012                                }
3013                                return;
3014                        }
3015                        if (action instanceof OrderFleetPatrolPointsAction) {
3016                                OrderFleetPatrolPointsAction a = (OrderFleetPatrolPointsAction) action;
3017                                for (SectorEntityToken curr : points) {
3018                                        if (curr != null) {
3019                                                a.patrolPoints.add(curr);
3020                                        }
3021                                }
3022                                return;
3023                        }
3024                }
3025        }
3026        
3027        public void triggerOrderFleetPatrolEntity(boolean moveToNearEntity) {
3028                triggerCustomAction(new OrderFleetPatrolSpawnedEntity(moveToNearEntity));
3029        }
3030        
3031        public void triggerOrderFleetPatrolHyper(final StarSystemAPI system) {
3032                triggerOrderFleetPatrol(system, false, system.getHyperspaceAnchor());
3033        }
3034
3035        public void triggerFleetAddDefeatTrigger(String trigger) {
3036                triggerCustomAction(new AddFleetDefeatTriggerAction(trigger, false));
3037        }
3038        
3039        public void triggerFleetAddDefeatTriggerPermanent(String trigger) {
3040                triggerCustomAction(new AddFleetDefeatTriggerAction(trigger, true));
3041        }
3042        
3043        public void triggerMakeFleetGoAwayAfterDefeat() {
3044                triggerCustomAction(new AddFleetDefeatTriggerAction("GoAwayAfterDefeatTrigger", true));
3045        }
3046        
3047        public void triggerOrderFleetInterceptPlayer() {
3048                triggerOrderFleetInterceptPlayer(false, true);
3049        }
3050        public void triggerOrderFleetInterceptPlayer(boolean makeHostile, boolean allowLongPursuit) {
3051                triggerCustomAction(new OrderFleetInterceptPlayerAction(makeHostile));
3052                if (allowLongPursuit) {
3053                        triggerFleetAllowLongPursuit();
3054                }
3055        }
3056        
3057        public void triggerOrderFleetMaybeEBurn() {
3058                triggerOrderFleetEBurn(0.5f);
3059        }
3060        public void triggerOrderFleetEBurn(float probabilityToEBurn) {
3061                if (genRandom.nextFloat() < probabilityToEBurn) {
3062                        triggerCustomAction(new OrderFleetEBurn());
3063                }
3064        }
3065        
3066        public void triggerOrderFleetAttackLocation(final SectorEntityToken entity) {
3067                triggerOrderFleetPatrol(null, false, entity);
3068        }
3069        
3070        public void triggerFleetNoAutoDespawn() {
3071                triggerCustomAction(new FleetNoAutoDespawnAction());
3072        }
3073        
3074        public void triggerFleetStopPursuingPlayerUnlessInStage(Object ... stages) {
3075                triggerCustomAction(new OrderFleetStopPursuingPlayerUnlessInStage(this, stages));
3076        }
3077        
3078        public void triggerFleetInterceptPlayerWithinRange(boolean mustBeStrongEnoughToFight, float maxRange, 
3079                                                                                        boolean repeatable, float repeatDelay, Object ... stages) {
3080                triggerCustomAction(
3081                                new OrderFleetInterceptNearbyPlayerInStage(this, mustBeStrongEnoughToFight, maxRange, repeatable, repeatDelay, stages));
3082                triggerFleetStopPursuingPlayerUnlessInStage(stages);
3083        }
3084        
3085        public void triggerFleetInterceptPlayerNearby(boolean mustBeStrongEnoughToFight, Object ... stages) {
3086                triggerFleetInterceptPlayerWithinRange(mustBeStrongEnoughToFight, 500f, true, 5f, stages);
3087        }
3088        
3089        public void triggerFleetInterceptPlayerOnSight(boolean mustBeStrongEnoughToFight,Object ... stages) {
3090                triggerFleetInterceptPlayerWithinRange(mustBeStrongEnoughToFight, 10000f, true, 5f, stages);
3091        }
3092        
3093        
3094        public static Vector2f pickLocationWithinArc(Random random, final SectorEntityToken entity, final float dir, final float arc,
3095                        final float minDistToPlayer, final float minDist, final float maxDist) {
3096                float angleIncr = 10f;
3097                float distIncr = (maxDist - minDist) / 5f;
3098                if (distIncr < 1000f) {
3099                        distIncr = (maxDist - minDist) / 2f;
3100                }
3101                if (distIncr < 1) distIncr = 1;
3102
3103
3104                WeightedRandomPicker<Vector2f> picker = new WeightedRandomPicker<Vector2f>(random);
3105                for (float currAngle = dir - arc / 2f; currAngle < dir + arc / 2f; currAngle += angleIncr) {
3106                        for (float dist = minDist; dist <= maxDist; dist += distIncr) {
3107                                Vector2f loc = Misc.getUnitVectorAtDegreeAngle(currAngle);
3108                                loc.scale(dist);
3109                                Vector2f.add(entity.getLocation(), loc, loc);
3110                                picker.add(loc);
3111                        }
3112                }
3113
3114                WeightedRandomPicker<Vector2f> copy = new WeightedRandomPicker<Vector2f>(random);
3115                copy.addAll(picker);
3116                
3117                
3118                StarSystemAPI system = entity.getStarSystem();
3119                CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
3120                Vector2f pick = null;
3121                LocationAPI containingLocation = entity.getContainingLocation();
3122
3123                while (!picker.isEmpty()) {
3124                        Vector2f loc = picker.pickAndRemove();
3125                        if (isNearCorona(system, loc)) continue;
3126
3127                        float distToPlayer = Float.MAX_VALUE;
3128                        if (playerFleet != null && playerFleet.getContainingLocation() == containingLocation) {
3129                                distToPlayer = Misc.getDistance(playerFleet.getLocation(), loc);
3130                                if (distToPlayer < minDistToPlayer) {
3131                                        continue;
3132                                }
3133                        }
3134                        pick = loc;
3135                }
3136
3137                if (pick == null) {
3138                        pick = copy.pick();
3139                }
3140
3141                float distToPlayer = Float.MAX_VALUE;
3142                if (playerFleet != null && playerFleet.getContainingLocation() == containingLocation) {
3143                        distToPlayer = Misc.getDistance(playerFleet.getLocation(), pick);
3144                        if (distToPlayer < minDistToPlayer) {
3145                                Vector2f away = Misc.getUnitVectorAtDegreeAngle(
3146                                                Misc.getAngleInDegrees(playerFleet.getLocation(), pick));
3147                                away.scale(minDistToPlayer);
3148                                Vector2f.add(playerFleet.getLocation(), away, away);
3149                                pick = away;
3150                        }
3151                }
3152                
3153                return pick;
3154        }
3155        
3156        public static boolean isNearCorona(StarSystemAPI system, Vector2f loc) {
3157                if (system == null) return false;
3158                for (PlanetAPI planet : system.getPlanets()) {
3159                        if (!planet.isStar()) continue;
3160                        StarCoronaTerrainPlugin corona = Misc.getCoronaFor(planet);
3161                        if (corona == null) continue;
3162                        float dist = Misc.getDistance(planet.getLocation(), loc);
3163                        float radius = corona.getParams().middleRadius + corona.getParams().bandWidthInEngine * 0.5f;
3164                        if (dist < radius + 500f) {
3165                                return true;
3166                        }
3167                }
3168                return false;
3169        }
3170        
3171        
3172        public void triggerCustomAction(TriggerAction action) {
3173                currTrigger.getActions().add(action);
3174        }
3175        
3176        
3177        
3178        
3179        
3180
3181        protected transient MissionTrigger currTrigger = null;
3182        public void beginGlobalFlagTrigger(String flag, Object ... stages) {
3183                beginCustomTrigger(new GlobalBooleanChecker(flag), stages); 
3184        }
3185        public void beginDaysElapsedTrigger(float days, Object ... stages) {
3186                beginCustomTrigger(new DaysElapsedChecker(days, this), stages); 
3187        }
3188        public void beginDaysElapsedTrigger(float days, Object stage, Object ... stages) {
3189                beginCustomTrigger(new DaysElapsedChecker(days, getData(stage)), stages); 
3190        }
3191        public void beginInCommRelayRangeTrigger(Object ... stages) {
3192                beginCustomTrigger(new InCommRelayRangeChecker(), stages);
3193        }
3194        public void beginEnteredLocationTrigger(LocationAPI location, Object ... stages) {
3195                beginCustomTrigger(new EnteredLocationChecker(location), stages);
3196        }
3197        public void beginInRangeOfEntityTrigger(SectorEntityToken entity, float range, Object ... stages) {
3198                beginCustomTrigger(new InRangeOfEntityChecker(entity, range), stages);
3199        }
3200//      public void beginWithinHyperspaceRangeTrigger(SectorEntityToken entity, float rangeLY, Object ... stages) {
3201//              beginWithinHyperspaceRangeTrigger(entity, rangeLY, false, stages);
3202//      }
3203        public void beginWithinHyperspaceRangeTrigger(SectorEntityToken entity, float rangeLY, boolean requirePlayerInHyperspace, 
3204                                                                        Object ... stages) {
3205                beginCustomTrigger(new InHyperRangeOfEntityChecker(entity, rangeLY, requirePlayerInHyperspace), stages);
3206        }
3207        
3208        public void beginWithinHyperspaceRangeTrigger(StarSystemAPI system, float rangeLY, boolean requirePlayerInHyperspace, 
3209                                                                                                  Object ... stages) {
3210                beginWithinHyperspaceRangeTrigger(system.getCenter(), rangeLY, requirePlayerInHyperspace, stages);
3211        }
3212        
3213//      public void beginWithinHyperspaceRangeTrigger(MarketAPI market, float rangeLY, Object ... stages) {
3214//              beginWithinHyperspaceRangeTrigger(market, rangeLY, false, stages);
3215//      }
3216        public void beginWithinHyperspaceRangeTrigger(MarketAPI market, float rangeLY, boolean requirePlayerInHyperspace,
3217                                                                Object ... stages) {
3218                beginCustomTrigger(new InHyperRangeOfEntityChecker(market.getPrimaryEntity(), rangeLY, requirePlayerInHyperspace), stages);
3219        }
3220        
3221        public void beginStageTrigger(Object ... stages) {
3222                beginCustomTrigger(new AlwaysTrueChecker(), stages);
3223        }
3224        public void beginCustomTrigger(ConditionChecker condition, Object ... stages) {
3225                checkExistingTrigger();
3226                
3227                currTrigger = new MissionTrigger();
3228                currTrigger.setCondition(condition);
3229                if (stages != null) {
3230                        for (Object stage : stages) {
3231                                currTrigger.getStages().add(stage);
3232                        }
3233                }
3234        }
3235        
3236        
3237        public void endTrigger() {
3238                if (currTrigger == null) {
3239                        throw new RuntimeException("endTrigger() called without a corresponding beginTrigger()");
3240                }
3241                triggers.add(currTrigger);
3242                currTrigger = null;
3243        }
3244        protected void checkExistingTrigger() {
3245                if (currTrigger != null) throw new RuntimeException("Already began a trigger, call endTrigger() to finish it");
3246        }
3247        
3248        public MissionTrigger getCurrTrigger() {
3249                return currTrigger;
3250        }
3251        public void setCurrTrigger(MissionTrigger currTrigger) {
3252                this.currTrigger = currTrigger;
3253        }
3254        
3255        
3256        public void triggerSpawnEntity(final String entityId, LocData data) {
3257                triggerCustomAction(new SpawnEntityAction(entityId, data));
3258        }
3259        
3260        public void triggerSpawnDebrisField(float radius, float density, LocData data) {
3261                triggerCustomAction(new SpawnDebrisFieldAction(radius, density, data));
3262        }
3263        
3264        public void triggerDespawnEntity(SectorEntityToken entity) {
3265                triggerCustomAction(new DespawnEntityAction(entity));
3266        }
3267        
3268
3269        public void triggerSpawnDerelictHull(String hullId, LocData data) {
3270                triggerCustomAction(new SpawnDerelictAction(hullId, null, null, data));
3271        }
3272        
3273        public void triggerSpawnDerelict(String factionId, DerelictType type, LocData data) {
3274                triggerCustomAction(new SpawnDerelictAction(null, factionId, type, data));
3275        }
3276        public void triggerSpawnDerelict(DerelictType type, LocData data) {
3277                triggerCustomAction(new SpawnDerelictAction(type, data));
3278        }
3279        
3280        public void triggerSpawnDerelict(DerelictShipData shipData, LocData data) {
3281                triggerCustomAction(new SpawnDerelictAction(shipData, data));
3282        }
3283        
3284        public void triggerSpawnShipGraveyard(String factionId, int minShips, int maxShips, LocData data) {
3285                triggerCustomAction(new SpawnShipGraveyardAction(factionId, minShips, maxShips, data));
3286        }
3287        
3288        public void triggerMakeMissionNodeDiscoverable() {
3289                triggerCustomAction(new MakeDiscoverableAction(1000f, 200f));
3290        }
3291        public void triggerMakeDiscoverable(float range, float xp) {
3292                triggerCustomAction(new MakeDiscoverableAction(range, xp));
3293        }
3294        
3295        public void triggerFleetAddTags(String ... tags) {
3296                triggerCustomAction(new AddTagsAction(tags));
3297        }
3298        
3299        public void triggerAddTags(SectorEntityToken entity, String ... tags) {
3300                triggerCustomAction(new GenericAddTagsAction(entity, tags));
3301        }
3302        public void triggerRemoveTags(SectorEntityToken entity, String ... tags) {
3303                triggerCustomAction(new GenericRemoveTagsAction(entity, tags));
3304        }
3305        public void triggerMakeNonStoryCritical(MemoryAPI ... memoryArray) {
3306                triggerCustomAction(new MakeNonStoryCriticalAction(memoryArray));
3307        }
3308        public void triggerMakeNonStoryCritical(String ... markets) {
3309                for (String id : markets) {
3310                        MarketAPI market = Global.getSector().getEconomy().getMarket(id);
3311                        if (market != null) {
3312                                triggerCustomAction(new MakeNonStoryCriticalAction(market.getMemory()));
3313                        }
3314                }
3315        }
3316        public void triggerMakeNonStoryCritical(MarketAPI ... markets) {
3317                for (MarketAPI market : markets) {
3318                        triggerCustomAction(new MakeNonStoryCriticalAction(market.getMemory()));
3319                }
3320        }
3321        
3322        public void triggerFleetAddCommanderSkill(String skill, int level) {
3323                CreateFleetAction cfa = getPreviousCreateFleetAction();
3324                if (cfa != null && cfa.params != null && cfa.params.commander != null) {
3325                        cfa.params.commander.getStats().setSkillLevel(skill, level);
3326                } else {
3327                        triggerCustomAction(new AddCommanderSkillAction(skill, level));
3328                }
3329        }
3330        
3331        /**
3332         * Used if a fleet being aggressive/allowed to long-pursue the player/etc needs to persist after
3333         * the mission has ended. Some flags - such as whether a fleet is a pirate/patrol/trader/smuggler -
3334         * are always permanent regardless of this setting.
3335         */
3336        public void triggerMakeAllFleetFlagsPermanent() {
3337                triggerCustomAction(new MakeFleetFlagsPermanentAction(true));
3338        }
3339        public void triggerUndoMakeAllFleetFlagsPermanent() {
3340                triggerCustomAction(new MakeFleetFlagsPermanentAction(false));
3341        }
3342        
3343        
3344        public static CampaignFleetAPI createFleet(FleetSize size, FleetQuality quality, 
3345                        OfficerNum oNum, OfficerQuality oQuality, String factionId, String fleetFactionId, String type, Vector2f locInHyper) {
3346                CreateFleetAction action = new CreateFleetAction(type, locInHyper, size, quality, factionId);
3347                action.oNum = oNum;
3348                action.oQuality = oQuality;
3349                action.faction = fleetFactionId;
3350                TriggerActionContext context = new TriggerActionContext(null);
3351                action.doAction(context);
3352                return context.fleet;
3353        }
3354        
3355        
3356        public void triggerCreateSmallPatrolAroundMarket(MarketAPI market, Object stage, float extraSuspicion) {
3357                triggerCreatePatrolAroundMarket(market, null, stage, FleetSize.VERY_SMALL, FleetTypes.PATROL_MEDIUM, extraSuspicion);
3358        }
3359        public void triggerCreateMediumPatrolAroundMarket(MarketAPI market, Object stage, float extraSuspicion) {
3360                triggerCreatePatrolAroundMarket(market, null, stage, FleetSize.MEDIUM, FleetTypes.PATROL_MEDIUM, extraSuspicion);
3361        }
3362        public void triggerCreateLargePatrolAroundMarket(MarketAPI market, Object stage, float extraSuspicion) {
3363                triggerCreatePatrolAroundMarket(market, null, stage, FleetSize.LARGE, FleetTypes.PATROL_LARGE, extraSuspicion);
3364        }
3365        public void triggerCreateSmallPatrol(MarketAPI from, String factionId, SectorEntityToken entityToPatrol, Object stage, float extraSuspicion) {
3366                triggerCreatePatrolAroundMarket(from, factionId, entityToPatrol, stage, FleetSize.VERY_SMALL, FleetTypes.PATROL_MEDIUM, extraSuspicion);
3367        }
3368        public void triggerCreateMediumPatrol(MarketAPI from, String factionId, SectorEntityToken entityToPatrol, Object stage, float extraSuspicion) {
3369                triggerCreatePatrolAroundMarket(from, factionId, entityToPatrol, stage, FleetSize.MEDIUM, FleetTypes.PATROL_MEDIUM, extraSuspicion);
3370        }
3371        public void triggerCreateLargePatrol(MarketAPI from, String factionId, SectorEntityToken entityToPatrol, Object stage, float extraSuspicion) {
3372                triggerCreatePatrolAroundMarket(from, factionId, entityToPatrol, stage, FleetSize.LARGE, FleetTypes.PATROL_LARGE, extraSuspicion);
3373        }
3374        public void triggerCreatePatrolAroundMarket(MarketAPI market, SectorEntityToken entityToPatrol, 
3375                                                                                                Object stage, FleetSize size, String fleetType,
3376                                                                                                float extraSuspicion) {
3377                triggerCreatePatrolAroundMarket(market, null, entityToPatrol, stage, size, fleetType, extraSuspicion);
3378        }
3379        public void triggerCreatePatrolAroundMarket(MarketAPI market, String factionId, SectorEntityToken entityToPatrol, 
3380                                                                Object stage, FleetSize size, String fleetType,
3381                                                                float extraSuspicion) {
3382                if (entityToPatrol == null) entityToPatrol = market.getPrimaryEntity();
3383                if (factionId == null) factionId = market.getFactionId();
3384                
3385                beginWithinHyperspaceRangeTrigger(entityToPatrol, 1f, false, stage);
3386                triggerCreateFleet(size, FleetQuality.DEFAULT, factionId, fleetType, entityToPatrol);
3387                triggerAutoAdjustFleetStrengthModerate();
3388                triggerMakeAllFleetFlagsPermanent();
3389                FactionAPI faction = Global.getSector().getFaction(factionId);
3390                if (faction.getCustomBoolean(Factions.CUSTOM_PIRATE_BEHAVIOR)) {
3391                        triggerSetPirateFleet();
3392                } else {
3393                        triggerSetPatrol();
3394                }
3395                triggerPickLocationAroundEntity(entityToPatrol, 100f);
3396                triggerSpawnFleetAtPickedLocation(null, null);
3397                triggerOrderFleetPatrol(entityToPatrol);
3398                triggerSetFleetExtraSmugglingSuspicion(extraSuspicion);
3399                triggerSetFleetNotBusy(); // so that it can be distracted and in general acts like a normal patrol
3400                if (market != null) {
3401                        triggerSetFleetMemoryValue(MemFlags.MEMORY_KEY_SOURCE_MARKET, market.getId());
3402                }
3403                endTrigger();
3404        }
3405        
3406        
3407        public static enum ComplicationSpawn {
3408                APPROACHING_OR_ENTERING,
3409                APPROACHING_SYSTEM,
3410                ENTERING_SYSTEM,
3411                EXITING_SYSTEM,
3412        }
3413        public static enum ComplicationRepImpact{
3414                NONE,
3415                LOW,
3416                FULL,
3417        }
3418        
3419        public ComplicationSpawn pickComplicationSpawnType() {
3420                WeightedRandomPicker<ComplicationSpawn> picker = new WeightedRandomPicker<ComplicationSpawn>(genRandom);
3421                picker.add(ComplicationSpawn.APPROACHING_SYSTEM);
3422                picker.add(ComplicationSpawn.ENTERING_SYSTEM);
3423                picker.add(ComplicationSpawn.EXITING_SYSTEM);
3424                return picker.pick();
3425        }
3426        
3427        public void triggerRandomizeFleetProperties() {
3428                CreateFleetAction cfa = getPreviousCreateFleetAction();
3429                
3430                if (genRandom.nextFloat() < 0.33f && cfa.fSize != FleetSize.TINY && getQuality() > 0.25f) {
3431                        // less ships, better quality and more officers
3432                        cfa.fSize = cfa.fSize.prev();
3433                        if (cfa.fQuality == null) cfa.fQuality = FleetQuality.DEFAULT;
3434                        cfa.fQuality = cfa.fQuality.next();
3435                        
3436                        if (cfa.oNum == null) cfa.oNum = OfficerNum.DEFAULT;
3437                        cfa.oNum = cfa.oNum.next();
3438                } else if (genRandom.nextFloat() < 0.5f && cfa.fSize != FleetSize.MAXIMUM) {
3439                        // more ships, lower quality, same officers
3440                        cfa.fSize = cfa.fSize.next();
3441                        if (cfa.fQuality == null) cfa.fQuality = FleetQuality.DEFAULT;
3442                        cfa.fQuality = cfa.fQuality.prev();
3443                }
3444                
3445        }
3446        
3447        @SuppressWarnings("rawtypes")
3448        public void triggerComplicationBegin(Object stage, ComplicationSpawn spawnType, StarSystemAPI system,
3449                                                String factionId,
3450                                                String thing,
3451                                                String thingItOrThey,
3452                                                String thingDesc,
3453                                                int paymentOffered,
3454                                                boolean aggressiveIfDeclined,
3455                                                ComplicationRepImpact repImpact,
3456                                                String failTrigger) {
3457                if (spawnType == ComplicationSpawn.APPROACHING_OR_ENTERING) spawnType = pickComplicationSpawnType();
3458                
3459                if ("them".equals(thingItOrThey)) thingItOrThey = "they";
3460                
3461                if (spawnType == ComplicationSpawn.APPROACHING_SYSTEM) {
3462                        beginWithinHyperspaceRangeTrigger(system.getCenter(), 3f, true, stage);
3463                } else if (spawnType == ComplicationSpawn.ENTERING_SYSTEM) {
3464                        beginEnteredLocationTrigger(system, stage);
3465                } else if (spawnType == ComplicationSpawn.EXITING_SYSTEM) {
3466                        //beginEnteredLocationTrigger(Global.getSector().getHyperspace(), stage);
3467                        // so that it doesn't trigger if the player exits the system through alternate means and is far away
3468                        beginWithinHyperspaceRangeTrigger(system, 1f, true, stage);
3469                }
3470                
3471                triggerCreateFleet(FleetSize.LARGE, FleetQuality.DEFAULT, factionId, FleetTypes.PATROL_MEDIUM, system);
3472                
3473                triggerSetFleetMissionRef("$" + getMissionId() + "_ref");
3474                triggerSetFleetMissionRef("$fwt_ref");
3475                
3476                FactionAPI faction = Global.getSector().getFaction(factionId);
3477                if (aggressiveIfDeclined) {
3478                        triggerSetPirateFleet();
3479                        triggerMakeHostileAndAggressive();
3480                }
3481                
3482                if (repImpact == ComplicationRepImpact.LOW) {
3483                        triggerMakeLowRepImpact();
3484                } else if (repImpact == ComplicationRepImpact.NONE) {
3485                        triggerMakeNoRepImpact();
3486                }
3487                
3488                triggerFleetAllowLongPursuit();
3489                triggerSetFleetAlwaysPursue();
3490                
3491                if (faction.getCustomBoolean(Factions.CUSTOM_SPAWNS_AS_INDEPENDENT)) {
3492                        triggerSetFleetFaction(Factions.INDEPENDENT);
3493                        triggerSetFleetMemoryValue("$fwt_originalFaction", factionId);
3494                }
3495                
3496                
3497                if (spawnType == ComplicationSpawn.APPROACHING_SYSTEM) {
3498                        triggerPickLocationTowardsPlayer(system.getHyperspaceAnchor(), 90f, getUnits(1.5f));
3499                } else if (spawnType == ComplicationSpawn.ENTERING_SYSTEM) {
3500                        triggerPickLocationTowardsPlayer(system.getCenter(), 90, 2000);
3501                } else if (spawnType == ComplicationSpawn.EXITING_SYSTEM) {
3502                        triggerPickLocationAroundPlayer(2000);
3503                }
3504                
3505                triggerOrderFleetInterceptPlayer();
3506                triggerFleetStopPursuingPlayerUnlessInStage(stage);
3507                
3508                triggerSpawnFleetAtPickedLocation("$fwt_wantsThing", null);
3509                triggerSetFleetMemoryValue("$fwt_aggressive", aggressiveIfDeclined);
3510                triggerSetFleetMemoryValue("$fwt_thing", getWithoutArticle(thing));
3511                triggerSetFleetMemoryValue("$fwt_Thing", Misc.ucFirst(getWithoutArticle(thing)));
3512                triggerSetFleetMemoryValue("$fwt_theThing", thing);
3513                triggerSetFleetMemoryValue("$fwt_TheThing", Misc.ucFirst(thing));
3514                triggerSetFleetMemoryValue("$fwt_payment", Misc.getWithDGS(paymentOffered));
3515                triggerSetFleetMemoryValue("$fwt_itOrThey", thingItOrThey);
3516                triggerSetFleetMemoryValue("$fwt_ItOrThey", Misc.ucFirst(thingItOrThey));
3517                
3518                String thingItOrThem = "them";
3519                if ("it".equals(thingItOrThey)) thingItOrThem = "it";
3520                triggerSetFleetMemoryValue("$fwt_itOrThem", thingItOrThem);
3521                triggerSetFleetMemoryValue("$fwt_ItOrThem", Misc.ucFirst(thingItOrThem));
3522                
3523                triggerSetFleetMemoryValue("$fwt_thingDesc", thingDesc);
3524                triggerSetFleetMemoryValue("$fwt_ThingDesc", Misc.ucFirst(thingDesc));
3525                
3526                if (failTrigger == null) {
3527                        failTrigger = "FWTDefaultFailTrigger";
3528                }
3529                triggerSetFleetMemoryValue("$fwt_missionFailTrigger", failTrigger);
3530                
3531                triggerFleetMakeImportant(null, (Enum) stage);
3532                
3533                //endTrigger();
3534        }
3535        
3536        public void triggerComplicationEnd(boolean randomizeAndAdjustFleetSize) {
3537                if (randomizeAndAdjustFleetSize) {
3538                        triggerRandomizeFleetProperties();
3539                        
3540                        setUseQualityInsteadOfQualityFraction(true);
3541                        triggerAutoAdjustFleetStrengthMajor();
3542                        setUseQualityInsteadOfQualityFraction(false);
3543                }
3544                autoAdjustFleetTypeName();
3545                
3546                endTrigger();
3547        }
3548        
3549        public void autoAdjustFleetTypeName() {
3550                CreateFleetAction cfa = getPreviousCreateFleetAction();
3551                if (cfa.params.fleetType != null && cfa.fSizeOverride != null &&
3552                                (cfa.params.fleetType.equals(FleetTypes.PATROL_SMALL) ||
3553                                 cfa.params.fleetType.equals(FleetTypes.PATROL_MEDIUM) ||
3554                                 cfa.params.fleetType.equals(FleetTypes.PATROL_LARGE))) {
3555                        if (cfa.fSizeOverride <= 0.2f) {
3556                                cfa.params.fleetType = FleetTypes.PATROL_SMALL; 
3557                        } else if (cfa.fSizeOverride < 0.7f) {
3558                                cfa.params.fleetType = FleetTypes.PATROL_MEDIUM;        
3559                        } else {
3560                                cfa.params.fleetType = FleetTypes.PATROL_LARGE; 
3561                        }
3562                } else if (cfa.params.fleetType != null && cfa.fSizeOverride != null &&
3563                                (cfa.params.fleetType.equals(FleetTypes.SCAVENGER_SMALL) ||
3564                                                cfa.params.fleetType.equals(FleetTypes.SCAVENGER_MEDIUM) ||
3565                                                cfa.params.fleetType.equals(FleetTypes.SCAVENGER_LARGE))) {
3566                        if (cfa.fSizeOverride <= 0.2f) {
3567                                cfa.params.fleetType = FleetTypes.SCAVENGER_SMALL;      
3568                        } else if (cfa.fSizeOverride < 0.7f) {
3569                                cfa.params.fleetType = FleetTypes.SCAVENGER_MEDIUM;     
3570                        } else {
3571                                cfa.params.fleetType = FleetTypes.SCAVENGER_LARGE;      
3572                        }
3573                }
3574        }
3575        
3576        
3577        public void triggerFleetSetWarnAttack(String warnCommsTrigger, String attackCommsTrigger, Object ... stages) {
3578                triggerSetFleetFlag("$warnAttack", stages);
3579                triggerSetFleetMemoryValue("$warnAttack_warningComms", warnCommsTrigger);
3580                triggerSetFleetMemoryValue("$warnAttack_attackComms", attackCommsTrigger);
3581                triggerFleetInterceptPlayerOnSight(true, stages);
3582                
3583                CreateFleetAction cfa = getPreviousCreateFleetAction();
3584                if (cfa != null && cfa.params != null && cfa.params.factionId != null) {
3585                        triggerSetFleetMemoryValue("$warnAttack_factionId", cfa.params.factionId);
3586                }
3587        }
3588        
3589        public void triggerFleetAddTugsFlag(int tugs) {
3590                triggerCustomAction(new FleetAddTugs(tugs));
3591        }
3592
3593        public void triggerFleetMakeFaster(boolean navigationSkill, int numTugs, boolean allowLongPursuit) {
3594                if (navigationSkill) {
3595                        triggerFleetAddCommanderSkill(Skills.NAVIGATION, 1);
3596                }
3597                if (numTugs > 0) {
3598                        triggerFleetAddTugsFlag(numTugs);
3599                }
3600                if (allowLongPursuit) {
3601                        triggerFleetAllowLongPursuit();
3602                }
3603        }
3604        
3605        public static void addTugsToFleet(CampaignFleetAPI fleet, int tugs, Random random) {
3606                //if (true) return;
3607                
3608                int max = Global.getSettings().getInt("maxShipsInAIFleet");
3609                if (fleet.getNumMembersFast() + tugs > max) {
3610                        FleetFactoryV3.pruneFleet(max - tugs, 0, fleet, 100000, random);
3611                }
3612                
3613                FactionAPI faction = fleet.getFaction();
3614                for (int i = 0; i < tugs; i++) {
3615                        ShipPickParams params = new ShipPickParams(ShipPickMode.ALL);
3616                        List<ShipRolePick> picks = faction.pickShip(ShipRoles.TUG, params, null, random);
3617                        for (ShipRolePick pick : picks) {
3618                                FleetMemberAPI member = fleet.getFleetData().addFleetMember(pick.variantId);
3619                                member.updateStats();
3620                                member.getRepairTracker().setCR(member.getRepairTracker().getMaxCR());
3621                                break;
3622                        }
3623                }
3624        }
3625        
3626        public void setFleetDamageTaken(float damage) {
3627                getPreviousCreateFleetAction().damage = damage;
3628        }
3629        
3630        
3631        public void setFleetSource(MarketAPI... preferred) {
3632                if (preferred == null) return;
3633                
3634                for (MarketAPI market : preferred) {
3635                        if (!market.hasCondition(Conditions.DECIVILIZED)) {
3636                                getPreviousCreateFleetAction().params.setSource(market, true);
3637                                break;
3638                        }
3639                }
3640        }
3641        
3642        public void setFleetSource(String ... preferred) {
3643                if (preferred == null) return;
3644                
3645                for (String id : preferred) {
3646                        MarketAPI market = Global.getSector().getEconomy().getMarket(id);
3647                        if (market != null && !market.hasCondition(Conditions.DECIVILIZED)) {
3648                                getPreviousCreateFleetAction().params.setSource(market, true);
3649                                break;
3650                        }
3651                }
3652        }
3653}
3654
3655
3656
3657
3658
3659