001package com.fs.starfarer.api.impl.campaign.missions.hub; 002 003import java.util.ArrayList; 004import java.util.List; 005import java.util.Random; 006 007import org.lwjgl.util.vector.Vector2f; 008 009import com.fs.starfarer.api.EveryFrameScript; 010import com.fs.starfarer.api.Global; 011import com.fs.starfarer.api.campaign.CampaignFleetAPI; 012import com.fs.starfarer.api.campaign.FleetAssignment; 013import com.fs.starfarer.api.campaign.LocationAPI; 014import com.fs.starfarer.api.campaign.SectorEntityToken; 015import com.fs.starfarer.api.campaign.StarSystemAPI; 016import com.fs.starfarer.api.campaign.ai.ModularFleetAIAPI; 017import com.fs.starfarer.api.campaign.comm.IntelInfoPlugin; 018import com.fs.starfarer.api.util.Misc; 019import com.fs.starfarer.api.util.WeightedRandomPicker; 020 021public class TriggerFleetAssignmentAI implements EveryFrameScript { 022 023 protected CampaignFleetAPI fleet; 024 protected LocationAPI system; 025 026 protected List<SectorEntityToken> patrolPoints = new ArrayList<SectorEntityToken>(); 027 protected float elapsedWaitingForDespawn = 0f; 028 protected HubMission mission; 029 protected String patrolText; 030 protected String travelText; 031 032 public TriggerFleetAssignmentAI(String travelText, String patrolText, HubMission mission, LocationAPI system, boolean randomLocation, CampaignFleetAPI fleet, SectorEntityToken ... patrolPoints) { 033 this.travelText = travelText; 034 this.patrolText = patrolText; 035 this.mission = mission; 036 this.fleet = fleet; 037 this.system = system; 038 039 if (patrolPoints != null) { 040 for (SectorEntityToken curr : patrolPoints) { 041 if (curr == null) continue; 042 if (curr == fleet) continue; 043 this.patrolPoints.add(curr); 044 } 045 } 046 047 if (!fleet.hasScriptOfClass(MissionFleetAutoDespawn.class)) { 048 fleet.addScript(new MissionFleetAutoDespawn(mission, fleet)); 049 } 050 051 // moving this to CreateFleetAction, since most mission fleets are likely to want to ignore WarSimScript 052 //fleet.getMemoryWithoutUpdate().set(MemFlags.FLEET_BUSY, true); 053 054 giveInitialAssignments(randomLocation); 055 } 056 057 protected void giveInitialAssignments(boolean randomLocation) { 058 if (randomLocation) { 059 // start at random location 060 SectorEntityToken target = pickPatrolPoint(); 061 if (target != null) { 062 Vector2f loc = Misc.getPointAtRadius(target.getLocation(), target.getRadius() + 100f); 063 fleet.setLocation(loc.x, loc.y); 064 } else { 065 Vector2f loc = Misc.getPointAtRadius(new Vector2f(), 5000f); 066 fleet.setLocation(loc.x, loc.y); 067 } 068 } 069 pickNext(); 070 } 071 072 protected SectorEntityToken pickPatrolPoint() { 073 if (patrolPoints != null) { 074 Random random = null; 075 if (mission instanceof BaseHubMission) random = ((BaseHubMission)mission).getGenRandom(); 076 WeightedRandomPicker<SectorEntityToken> picker = new WeightedRandomPicker<SectorEntityToken>(random); 077 for (SectorEntityToken curr : patrolPoints) { 078 if (!curr.isAlive()) continue; 079 picker.addAll(patrolPoints); 080 } 081 return picker.pick(); 082 } 083 return null; 084 } 085 086 protected SectorEntityToken currTarget; 087 protected void pickNext() { 088 currTarget = pickPatrolPoint(); 089 if (currTarget != null) { 090 float speed = Misc.getSpeedForBurnLevel(8); 091 float dist = Misc.getDistance(fleet.getLocation(), currTarget.getLocation()); 092 float seconds = dist / speed; 093 float days = seconds / Global.getSector().getClock().getSecondsPerDay(); 094 days += 5f + 5f * (float) Math.random(); 095 fleet.addAssignment(FleetAssignment.PATROL_SYSTEM, currTarget, days, patrolText == null ? "patrolling" : patrolText); 096 return; 097 } else if (system instanceof StarSystemAPI) { 098 float days = 5f + 5f * (float) Math.random(); 099 fleet.addAssignment(FleetAssignment.PATROL_SYSTEM, ((StarSystemAPI)system).getCenter(), days, patrolText == null ? "patrolling" : patrolText); 100 } 101 } 102 103 public void advance(float amount) { 104 if (fleet.getCurrentAssignment() == null) { 105 pickNext(); 106 } else { 107 String travel = travelText; 108 if (travel == null) { 109 if (Misc.isPatrol(fleet)) { 110 travel = "patrolling"; 111 } else { 112 travel = "traveling"; 113 } 114 } 115 if (fleet.getAI() != null && 116 travel != null && currTarget != null && fleet.getCurrentAssignment().getTarget() == currTarget && 117 fleet.getCurrentAssignment().getAssignment() == FleetAssignment.PATROL_SYSTEM) { 118 float dist = Misc.getDistance(fleet, currTarget); 119 if (dist > 1500 || fleet.getContainingLocation() != currTarget.getContainingLocation()) { 120 boolean standingDown = fleet.getAI() instanceof ModularFleetAIAPI && 121 ((ModularFleetAIAPI) fleet.getAI()).getTacticalModule() != null && 122 ((ModularFleetAIAPI) fleet.getAI()).getTacticalModule().isStandingDown(); 123 if (standingDown) { 124 fleet.getAI().setActionTextOverride(null); 125 } else { 126 fleet.getAI().setActionTextOverride(travel); 127 } 128 } else { 129 fleet.getAI().setActionTextOverride(null); 130 } 131 } else if (fleet.getAI() != null) { 132 fleet.getAI().setActionTextOverride(null); 133 } 134 } 135 136 // replaced with separate MissionFleetAutoDespawn script 137 //despawnIfNeeded(amount); 138 } 139 140// protected void despawnIfNeeded(float amount) { 141// if (isMissionEnded()) { 142// if (!fleet.isInCurrentLocation()) { 143// elapsedWaitingForDespawn += Global.getSector().getClock().convertToDays(amount); 144// if (elapsedWaitingForDespawn > 30f && fleet.getBattle() == null) { 145// fleet.despawn(FleetDespawnReason.PLAYER_FAR_AWAY, null); 146// elapsedWaitingForDespawn = 0f; 147// } 148// } else { 149// elapsedWaitingForDespawn = 0f; 150// } 151// } 152// } 153 154 public boolean isMissionEnded() { 155 return mission instanceof IntelInfoPlugin && ((IntelInfoPlugin)mission).isEnded(); 156 } 157 158 public boolean isDone() { 159 return false; 160 } 161 162 public boolean runWhilePaused() { 163 return false; 164 } 165 166 167 168} 169 170 171 172 173 174 175 176 177 178