001package com.fs.starfarer.api.impl.campaign.terrain;
002
003import java.util.EnumSet;
004import java.util.List;
005
006import java.awt.Color;
007
008import org.lwjgl.util.vector.Vector2f;
009
010import com.fs.starfarer.api.Global;
011import com.fs.starfarer.api.campaign.CampaignEngineLayers;
012import com.fs.starfarer.api.campaign.CampaignFleetAPI;
013import com.fs.starfarer.api.campaign.CampaignTerrainPlugin;
014import com.fs.starfarer.api.campaign.SectorEntityToken;
015import com.fs.starfarer.api.campaign.rules.MemoryAPI;
016import com.fs.starfarer.api.combat.ViewportAPI;
017import com.fs.starfarer.api.loading.TerrainSpecAPI;
018import com.fs.starfarer.api.ui.Alignment;
019import com.fs.starfarer.api.ui.TooltipMakerAPI;
020import com.fs.starfarer.api.util.Misc;
021
022public class BaseTerrain implements CampaignTerrainPlugin {
023
024        public static final float EXTRA_SOUND_RADIUS = 100f;
025
026        protected SectorEntityToken entity;
027        protected String terrainId;
028        protected String name = "Unknown";
029
030        public void init(String terrainId, SectorEntityToken entity, Object param) {
031                this.terrainId = terrainId;
032                this.entity = entity;
033        }
034
035        public String getIconSpriteName() {
036                return null;
037        }
038
039        public SectorEntityToken getRelatedEntity() {
040                return null;
041        }
042
043        public SectorEntityToken getEntity() {
044                return entity;
045        }
046        
047        @Override
048        public void setEntity(SectorEntityToken entity) {
049                this.entity = entity;
050        }
051
052        public String getTerrainId() {
053                return terrainId;
054        }
055        
056        @Override
057        public void setTerrainId(String id) {
058                terrainId = id;
059        }
060
061        protected boolean shouldCheckFleetsToApplyEffect() {
062                return true;
063        }
064
065        public void advance(float amount) {
066                if (amount <= 0) {
067                        return; // happens during game load
068                }
069                List<CampaignFleetAPI> fleets = entity.getContainingLocation().getFleets();
070
071                // if (entity.isInCurrentLocation()) return;
072                // if (entity.isInCurrentLocation() &&
073                // entity.getContainingLocation().isHyperspace()) {
074                // System.out.println(entity.getContainingLocation().getTerrainCopy().size());
075                // System.out.println(entity.getContainingLocation().getFleets().size());
076                // }
077//              if (entity.isPlayerFleet()) {
078//                      System.out.println("23fwefe");
079//              }
080                if (shouldCheckFleetsToApplyEffect()) {
081                        float renderRange = getRenderRange();
082                        // renderRange *= renderRange;
083                        float days = Global.getSector().getClock().convertToDays(amount);
084                        for (CampaignFleetAPI fleet : fleets) {
085                                if (fleet.isStationMode()) {
086                                        continue;
087                                }
088                                
089                                float dist = Misc.getDistance(fleet.getLocation(), entity.getLocation());
090                                if (dist > renderRange) {
091                                        continue;
092                                }
093
094                                String cat = getEffectCategory();
095                                String key = "$terrain_" + cat;
096
097                                MemoryAPI mem = fleet.getMemoryWithoutUpdate();
098                                if (cat != null && !stacksWithSelf() && mem.contains(key)) {
099                                        continue;
100                                }
101                                // if (entity.isInCurrentLocation()) continue;
102                                if (containsEntity(fleet)) {
103                                        applyEffect(fleet, days);
104                                        if (cat != null) {
105                                                mem.set(key, true, 0);
106                                        }
107                                }
108                        }
109                }
110
111                CampaignFleetAPI fleet = Global.getSector().getPlayerFleet();
112                if (fleet != null && entity.isInCurrentLocation()) {
113                        if (containsPoint(fleet.getLocation(), fleet.getRadius() + getExtraSoundRadius())) {
114                                float prox = getProximitySoundFactor();
115                                // System.out.println(getTerrainId() + " prox: " + prox);
116                                float volumeMult = prox;
117                                float suppressionMult = prox;
118                                // suppressionMult = 1f;
119                                // System.out.println(suppressionMult);
120                                if (volumeMult > 0) {
121                                        if (shouldPlayLoopOne()) {
122                                                String soundId = getSpec().getLoopOne();
123                                                if (soundId != null) {
124                                                        Global.getSector().getCampaignUI()
125                                                                        .suppressMusic(spec.getMusicSuppression() * suppressionMult);
126                                                        Global.getSoundPlayer().playLoop(soundId, fleet, getLoopOnePitch(),
127                                                                        getLoopOneVolume() * volumeMult, fleet.getLocation(), Misc.ZERO);
128                                                }
129                                        }
130                                        if (shouldPlayLoopTwo()) {
131                                                String soundId = getSpec().getLoopTwo();
132                                                if (soundId != null) {
133                                                        Global.getSector().getCampaignUI()
134                                                                        .suppressMusic(spec.getMusicSuppression() * suppressionMult);
135                                                        Global.getSoundPlayer().playLoop(soundId, fleet, getLoopTwoPitch(),
136                                                                        getLoopTwoVolume() * volumeMult, fleet.getLocation(), Misc.ZERO);
137                                                }
138                                        }
139                                        if (shouldPlayLoopThree()) {
140                                                String soundId = getSpec().getLoopThree();
141                                                if (soundId != null) {
142                                                        Global.getSector().getCampaignUI()
143                                                                        .suppressMusic(spec.getMusicSuppression() * suppressionMult);
144                                                        Global.getSoundPlayer().playLoop(soundId, fleet, getLoopThreePitch(),
145                                                                        getLoopThreeVolume() * volumeMult, fleet.getLocation(), Misc.ZERO);
146                                                }
147                                        }
148                                        if (shouldPlayLoopFour()) {
149                                                String soundId = getSpec().getLoopFour();
150                                                if (soundId != null) {
151                                                        Global.getSector().getCampaignUI()
152                                                                        .suppressMusic(spec.getMusicSuppression() * suppressionMult);
153                                                        Global.getSoundPlayer().playLoop(soundId, fleet, getLoopFourPitch(),
154                                                                        getLoopFourVolume() * volumeMult, fleet.getLocation(), Misc.ZERO);
155                                                }
156                                        }
157                                }
158                        }
159                }
160        }
161
162        protected float getExtraSoundRadius() {
163                return EXTRA_SOUND_RADIUS;
164        }
165
166        public String getEffectCategory() {
167                throw new RuntimeException("Override BaseTerrain.getEffectCategory()");
168        }
169
170        public boolean containsEntity(SectorEntityToken other) {
171                return containsPoint(other.getLocation(), other.getRadius()) && !isPreventedFromAffecting(other);
172        }
173
174        public boolean containsPoint(Vector2f point, float radius) {
175                return false;
176        }
177
178        public boolean stacksWithSelf() {
179                return false;
180        }
181
182        public void applyEffect(SectorEntityToken entity, float days) {
183
184        }
185
186        public float getProximitySoundFactor() {
187                return 1f;
188        }
189
190        public String getModId() {
191                return terrainId + "_stat_mod";
192        }
193
194        public EnumSet<CampaignEngineLayers> getActiveLayers() {
195                throw new RuntimeException(
196                                "Override BaseTerrain.getActiveLayers() to return the CampaignEngineLayers the terrain should render in.");
197        }
198
199        public float getRenderRange() {
200                throw new RuntimeException(
201                                "Override BaseTerrain.getRenderRange() to return the maximum distance to render this terrain at (should exceed visible radius).");
202        }
203
204        public void render(CampaignEngineLayers layer, ViewportAPI viewport) {
205
206        }
207
208        public void renderOnMap(float factor, float alphaMult) {
209
210        }
211
212        public void renderOnMapAbove(float factor, float alphaMult) {
213
214        }
215
216        public boolean hasTooltip() {
217                return false;
218        }
219
220        // public void createTooltip(TooltipMakerAPI tooltip, boolean expanded) {
221        // }
222
223        protected void createFirstSection(TooltipMakerAPI tooltip, boolean expanded) {
224        }
225
226        protected void createTravelSection(TooltipMakerAPI tooltip, boolean expanded, float firstPad) {
227        }
228
229        protected void createCombatSection(TooltipMakerAPI tooltip, boolean expanded) {
230        }
231
232        protected boolean shouldPlayLoopOne() {
233                return getSpec().getLoopOne() != null;
234        }
235
236        protected boolean shouldPlayLoopTwo() {
237                return getSpec().getLoopTwo() != null;
238        }
239
240        protected boolean shouldPlayLoopThree() {
241                return getSpec().getLoopThree() != null;
242        }
243
244        protected boolean shouldPlayLoopFour() {
245                return getSpec().getLoopFour() != null;
246        }
247
248        protected float getLoopOnePitch() {
249                return 1f;
250        }
251
252        protected float getLoopOneVolume() {
253                return 1f;
254        }
255
256        protected float getLoopTwoPitch() {
257                return 1f;
258        }
259
260        protected float getLoopTwoVolume() {
261                return 1f;
262        }
263
264        protected float getLoopThreePitch() {
265                return 1f;
266        }
267
268        protected float getLoopThreeVolume() {
269                return 1f;
270        }
271
272        protected float getLoopFourPitch() {
273                return 1f;
274        }
275
276        protected float getLoopFourVolume() {
277                return 1f;
278        }
279
280        public void createTooltip(TooltipMakerAPI tooltip, boolean expanded) {
281                float pad = 10f;
282                float small = 5f;
283
284                createFirstSection(tooltip, expanded);
285
286                float nextPad = pad;
287                if (expanded) {
288                        tooltip.addSectionHeading("Travel", Alignment.MID, pad);
289                        nextPad = small;
290                }
291
292                createTravelSection(tooltip, expanded, nextPad);
293
294                if (expanded) {
295                        tooltip.addSectionHeading("Combat", Alignment.MID, pad);
296                        createCombatSection(tooltip, expanded);
297                }
298        }
299
300        public boolean isTooltipExpandable() {
301                return true;
302        }
303
304        public float getTooltipWidth() {
305                return 350f;
306        }
307
308        public String getTerrainName() {
309                return name;
310        }
311
312        public String getNameAOrAn() {
313                return "a";
314        }
315
316        public void setTerrainName(String name) {
317                this.name = name;
318        }
319
320        public Color getNameColor() {
321                return Global.getSettings().getColor("buttonText");
322        }
323
324        public boolean hasAIFlag(Object flag) {
325                return false;
326        }
327
328        public boolean hasAIFlag(Object flag, CampaignFleetAPI fleet) {
329                return hasAIFlag(flag);
330        }
331
332        public float getMaxEffectRadius(Vector2f locFrom) {
333                return 0f;
334        }
335
336        public float getMinEffectRadius(Vector2f locFrom) {
337                return 0f;
338        }
339
340        public float getOptimalEffectRadius(Vector2f locFrom) {
341                return 0f;
342        }
343
344        public boolean hasMapIcon() {
345                return true;
346        }
347
348        private transient TerrainSpecAPI spec = null;
349
350        public TerrainSpecAPI getSpec() {
351                if (spec != null)
352                        return spec;
353                spec = Global.getSettings().getTerrainSpec(terrainId);
354                return spec;
355        }
356
357        public boolean canPlayerHoldStationIn() {
358                return true;
359        }
360
361        public void renderOnRadar(Vector2f radarCenter, float factor, float alphaMult) {
362
363        }
364
365        public String getNameForTooltip() {
366                return getTerrainName();
367        }
368
369        // protected boolean doNotLowerCaseName = false;
370        // public String getTerrainNameLowerCase() {
371        // if (doNotLowerCaseName) return getTerrainName();
372        // return getTerrainName().toLowerCase();
373        // }
374
375        
376        public static String TERRAIN_LOCK_KEY = "$terrain_mutex_key";
377        
378        public boolean isPreventedFromAffecting(SectorEntityToken other) {
379                if (other.getMemoryWithoutUpdate() == null) return false;
380                String id = entity.getId();
381                String key = TERRAIN_LOCK_KEY;
382                String lockId = other.getMemoryWithoutUpdate().getString(key);
383                return lockId != null && !lockId.equals(id);
384        }
385        protected void preventOtherTerrainFromAffecting(SectorEntityToken other) {
386                preventOtherTerrainFromAffecting(other, 0.1f);
387        }
388        protected void preventOtherTerrainFromAffecting(SectorEntityToken other, float dur) {
389                String id = entity.getId();
390                other.getMemoryWithoutUpdate().set(TERRAIN_LOCK_KEY, id, dur);
391        }
392
393}
394
395
396