Starsector API
Loading...
Searching...
No Matches
SensorArrayEntityPlugin.java
Go to the documentation of this file.
1package com.fs.starfarer.api.impl.campaign;
2
3import java.util.Random;
4
5import org.lwjgl.util.vector.Vector2f;
6
7import com.fs.starfarer.api.campaign.CampaignFleetAPI;
8import com.fs.starfarer.api.campaign.FleetAssignment;
9import com.fs.starfarer.api.campaign.SectorEntityToken;
10import com.fs.starfarer.api.campaign.TextPanelAPI;
11import com.fs.starfarer.api.campaign.ai.FleetAssignmentDataAPI;
12import com.fs.starfarer.api.campaign.rules.MemoryAPI;
13import com.fs.starfarer.api.combat.MutableStat.StatMod;
14import com.fs.starfarer.api.impl.campaign.ghosts.BaseSensorGhost;
15import com.fs.starfarer.api.impl.campaign.ghosts.GBGoInDirection;
16import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
17import com.fs.starfarer.api.impl.campaign.ids.Tags;
18import com.fs.starfarer.api.impl.campaign.intel.BaseIntelPlugin;
19import com.fs.starfarer.api.ui.TooltipMakerAPI;
20import com.fs.starfarer.api.util.Misc;
21
23
24 public static float SENSOR_BONUS = 700f;
25 public static float SENSOR_BONUS_MAKESHIFT = 400f;
26 //public static float SENSOR_PENALTY_MULT_FROM_HACK = 0.75f;
27
28 public void init(SectorEntityToken entity, Object pluginParams) {
29 super.init(entity, pluginParams);
30 readResolve();
31 }
32
33 Object readResolve() {
34 return this;
35 }
36
37 public void advance(float amount) {
38 if (entity.getContainingLocation() == null || entity.isInHyperspace()) return;
39 //if (isReset()) return;
40 boolean reset = isReset();
41
42 String id = getModId();
43 for (CampaignFleetAPI fleet : entity.getContainingLocation().getFleets()) {
44 if (fleet.isInHyperspaceTransition()) continue;
45
46 if (fleet.getFaction() == entity.getFaction() || (isHacked() && fleet.getFaction().isPlayerFaction())) {
47 if (reset && !fleet.getFaction().isPlayerFaction()) {
49 } else if (reset && fleet.isPlayerFleet()) {
51 }
52
53 String desc = "Sensor array";
54 float bonus = SENSOR_BONUS;
55 if (isMakeshift()) {
56 desc = "Makeshift sensor array";
58 }
59
60// if (fleet.getFaction() == entity.getFaction() && isHacked() && !entity.getFaction().isPlayerFaction()) {
61// fleet.getStats().addTemporaryModMult(0.1f, id,
62// desc, SENSOR_PENALTY_MULT_FROM_HACK,
63// fleet.getStats().getSensorRangeMod());
64// }
65
66 StatMod curr = fleet.getStats().getSensorRangeMod().getFlatBonus(id);
67 if (curr == null || curr.value <= bonus) {
68 fleet.getStats().addTemporaryModFlat(0.1f, id,
69 desc, bonus,
70 fleet.getStats().getSensorRangeMod());
71 }
72 }
73 }
74
75 }
76
77 protected boolean isMakeshift() {
78 return entity.hasTag(Tags.MAKESHIFT);
79 }
80
81 public void printEffect(TooltipMakerAPI text, float pad) {
82 int bonus = (int) SENSOR_BONUS;
83 if (isMakeshift()) {
84 bonus = (int) SENSOR_BONUS_MAKESHIFT;
85 }
86
87 text.addPara(BaseIntelPlugin.INDENT + "%s sensor range for all same-faction fleets in system",
88 pad, Misc.getHighlightColor(), "+" + bonus);
89 if (isReset()) {
90 //text.addPara(BaseIntelPlugin.INDENT + "Auto-calibrating after factory reset; non-functional", 3f);
91 text.addPara(BaseIntelPlugin.INDENT + "Generating false readings", 3f);
92 }
93
94// text.addPara(BaseIntelPlugin.INDENT + "%s sensor range to same-faction fleets when hacked",
95// 0f, Misc.getHighlightColor(), "-" + (int) Math.round((1f - SENSOR_PENALTY_MULT_FROM_HACK) * 100f) + "%");
96 }
97
98 public void printNonFunctionalAndHackDescription(TextPanelAPI text) {
99 if (entity.getMemoryWithoutUpdate().getBoolean(MemFlags.OBJECTIVE_NON_FUNCTIONAL)) {
100 text.addPara("This one, however, does not appear to be transmitting a sensor telemetry broadcast. The cause of its lack of function is unknown.");
101 }
102 if (isHacked()) {
103 text.addPara("You have a hack running on this sensor array.");
104 }
105// if (isReset()) {
106// text.addPara("This sensor array is auto-calibrating after a factory reset and is effectively non-functional.");
107// }
108 }
109
110
111
112 @Override
113 public void addHackStatusToTooltip(TooltipMakerAPI text, float pad) {
114 int bonus = (int) SENSOR_BONUS;
115 if (isMakeshift()) {
116 bonus = (int) SENSOR_BONUS_MAKESHIFT;
117 }
118 text.addPara("%s sensor range for in-system fleets",
119 pad, Misc.getHighlightColor(), "+" + bonus);
120
121// text.addPara("%s%% sensor range when hacked",
122// pad, Misc.getHighlightColor(), "-" + (int) Math.round((1f - SENSOR_PENALTY_MULT_FROM_HACK) * 100f));
123
124 super.addHackStatusToTooltip(text, pad);
125 }
126
127 protected String getModId() {
128 return "sensor_array";
129 }
130
131
132 public static String GHOST_RESPONSE = "ghost_response"; // custom value added to assignments so we know which to clear
133
134 protected void spawnPlayerSensorReading(CampaignFleetAPI fleet) {
135 Random random = Misc.random;
136
137 MemoryAPI mem = fleet.getMemoryWithoutUpdate();
138 if (mem.getBoolean(MemFlags.FLEET_NOT_CHASING_GHOST)) {
139 return;
140 }
141 if (mem.getBoolean(MemFlags.FLEET_CHASING_GHOST)) {
142 return;
143 }
144 boolean spawnReading = random.nextFloat() < 0.5f;
145 //spawnReading = true;
146 if (!spawnReading) {
147 mem.set(MemFlags.FLEET_NOT_CHASING_GHOST, true, 1f + 2f * random.nextFloat());
148 return;
149 }
150
151 float dur = 3f + 3f + random.nextFloat();
152 mem.set(MemFlags.FLEET_NOT_CHASING_GHOST, true, dur * 0.5f);
153
154 BaseSensorGhost g = new BaseSensorGhost(null, 0);
155
156 float r = random.nextFloat();
157 int maxBurn;
158 if (r < 0.25f) {
159 g.initEntity(g.genMediumSensorProfile(), g.genSmallRadius(), 0, fleet.getContainingLocation());
160 maxBurn = 9 + random.nextInt(3);
161 } else if (r < 0.6f) {
162 g.initEntity(g.genLargeSensorProfile(), g.genMediumRadius(), 0, fleet.getContainingLocation());
163 maxBurn = 8 + random.nextInt(3);
164 } else {
165 g.initEntity(g.genLargeSensorProfile(), g.genLargeRadius(), 0, fleet.getContainingLocation());
166 maxBurn = 7 + random.nextInt(3);
167 }
168
169
170 if (!g.placeNearPlayer()) {
171 return;
172 }
173 //g.setDespawnRange(200f);
174
175
176 float speed = Misc.getSpeedForBurnLevel(maxBurn);
177 float accelMult = speed / Misc.getSpeedForBurnLevel(20f);
178 if (accelMult < 0.1f) accelMult = 0.1f;
179 g.setAccelMult(1f/ accelMult);
180
181 float dir = Misc.getAngleInDegrees(g.getEntity().getLocation(), fleet.getLocation());
182 float sign = Math.signum(random.nextFloat() - 0.5f);
183 dir += sign * (30f + random.nextFloat() * 60f);
184
185
186 g.addBehavior(new GBGoInDirection(dur, dir, maxBurn));
187
188 fleet.getContainingLocation().addScript(g);
189
190 }
191
192 protected void respondToFalseSensorReadings(CampaignFleetAPI fleet) {
193 if (fleet.isStationMode()) return;
194 if (fleet.getAI() == null) {
195 return;
196 }
197 if (fleet.getAI().getAssignmentsCopy() == null) {
198 return;
199 }
200
201 MemoryAPI mem = fleet.getMemoryWithoutUpdate();
202 if (mem.getBoolean(MemFlags.FLEET_NOT_CHASING_GHOST)) {
203 return;
204 }
205 if (mem.getBoolean(MemFlags.FLEET_CHASING_GHOST)) {
206 return;
207 }
208 if (mem.getBoolean(MemFlags.FLEET_BUSY)) {
209 return;
210 }
211 boolean patrol = mem.getBoolean(MemFlags.MEMORY_KEY_PATROL_FLEET);
212 boolean warFleet = mem.getBoolean(MemFlags.MEMORY_KEY_WAR_FLEET);
213 boolean pirate = mem.getBoolean(MemFlags.MEMORY_KEY_PIRATE);
214 if (!patrol && !warFleet && !pirate) {
215 return;
216 }
217
218 Random random = (Random) mem.get(MemFlags.FLEET_CHASING_GHOST_RANDOM);
219 if (random == null) {
220 random = Misc.getRandom(Misc.getSalvageSeed(fleet), 7);
221 mem.set(MemFlags.FLEET_CHASING_GHOST_RANDOM, random, 30f);
222 }
223
224 boolean willRespond = random.nextFloat() < 0.75f;
225 //willRespond = true;
226 if (!willRespond) {
227 mem.set(MemFlags.FLEET_NOT_CHASING_GHOST, true, 1f + 1f * random.nextFloat());
228 Misc.setFlagWithReason(fleet.getMemoryWithoutUpdate(),
229 MemFlags.FLEET_CHASING_GHOST, GHOST_RESPONSE, false, 0f);
230 for (FleetAssignmentDataAPI curr : fleet.getAI().getAssignmentsCopy()) {
231 if (GHOST_RESPONSE.equals(curr.getCustom())) {
232 fleet.getAI().removeAssignment(curr);
233 }
234 }
235 return;
236 }
237
238 float chaseDur = (2.5f + (float) Math.random()) * 2f;
239 Misc.setFlagWithReason(fleet.getMemoryWithoutUpdate(),
240 MemFlags.FLEET_CHASING_GHOST, GHOST_RESPONSE, true, chaseDur);
241 mem.set(MemFlags.FLEET_BUSY, true, chaseDur);
242 mem.set(MemFlags.FLEET_NOT_CHASING_GHOST, true, chaseDur + 8f + 4f * random.nextFloat());
243
244 float angle = Misc.getAngleInDegrees(fleet.getLocation()); // away from center of system;
245 float arc = 270f;
246 angle += arc/2f - arc * random.nextFloat();
247 float dist = 3000f + 3000f * random.nextFloat();
248 Vector2f loc = Misc.getUnitVectorAtDegreeAngle(angle);
249 loc.scale(dist);
250 Vector2f.add(loc, fleet.getLocation(), loc);
251
252
253 String actionText = "investigating anomalous sensor reading";
254
255 SectorEntityToken target = fleet.getContainingLocation().createToken(loc);
256 fleet.addAssignmentAtStart(FleetAssignment.PATROL_SYSTEM, target, 3f, actionText, null);
257 FleetAssignmentDataAPI curr = fleet.getCurrentAssignment();
258 if (curr != null) {
259 curr.setCustom(GHOST_RESPONSE);
260 }
261
262 if (dist > 2000f) {
263 fleet.addAssignmentAtStart(FleetAssignment.GO_TO_LOCATION, target, 3f, actionText, null);
264 curr = fleet.getCurrentAssignment();
265 if (curr != null) {
266 curr.setCustom(GHOST_RESPONSE);
267 }
268 }
269 }
270
271// protected void unrespond(CampaignFleetAPI fleet) {
272// Misc.setFlagWithReason(fleet.getMemoryWithoutUpdate(),
273// MemFlags.FLEET_CHASING_GHOST, GHOST_RESPONSE, false, 0f);
274// for (FleetAssignmentDataAPI curr : fleet.getAI().getAssignmentsCopy()) {
275// if (GHOST_RESPONSE.equals(curr.getCustom())) {
276// fleet.getAI().removeAssignment(curr);
277// }
278// }
279// }
280//
281// protected void respond(CampaignFleetAPI fleet) {
282// unrespond(fleet);
283//
284// Misc.setFlagWithReason(fleet.getMemoryWithoutUpdate(),
285// MemFlags.FLEET_CHASING_GHOST, GHOST_RESPONSE, true, (1.5f + (float) Math.random()) * 0.2f);
286//
287// fleet.addAssignmentAtStart(FleetAssignment.PATROL_SYSTEM, params.target, 3f, params.actionText, null);
288// FleetAssignmentDataAPI curr = fleet.getCurrentAssignment();
289// if (curr != null) {
290// curr.setCustom(GHOST_RESPONSE);
291// }
292//
293// float dist = Misc.getDistance(params.target, fleet);
294// if (dist > 2000f) {
295// fleet.addAssignmentAtStart(FleetAssignment.GO_TO_LOCATION, params.target, 3f, params.travelText, null);
296// //fleet.addAssignmentAtStart(FleetAssignment.DELIVER_CREW, params.target, 3f, params.travelText, null);
297// curr = fleet.getCurrentAssignment();
298// if (curr != null) {
299// curr.setCustom(GHOST_RESPONSE);
300// }
301// }
302//
303// //Global.getSector().addPing(fleet, Pings.DANGER);
304// }
305}
306
307
308
void init(SectorEntityToken entity, Object pluginParams)