001package com.fs.starfarer.api.impl;
002
003import java.util.HashMap;
004import java.util.Map;
005
006import com.fs.starfarer.api.Global;
007import com.fs.starfarer.api.MusicPlayerPluginWithVolumeControl;
008import com.fs.starfarer.api.campaign.CampaignFleetAPI;
009import com.fs.starfarer.api.campaign.FactionAPI;
010import com.fs.starfarer.api.campaign.RepLevel;
011import com.fs.starfarer.api.campaign.SectorEntityToken;
012import com.fs.starfarer.api.campaign.StarSystemAPI;
013import com.fs.starfarer.api.campaign.ai.ModularFleetAIAPI;
014import com.fs.starfarer.api.campaign.econ.MarketAPI;
015import com.fs.starfarer.api.campaign.rules.MemoryAPI;
016import com.fs.starfarer.api.combat.CombatEngineAPI;
017import com.fs.starfarer.api.impl.campaign.ids.Entities;
018import com.fs.starfarer.api.impl.campaign.ids.Factions;
019import com.fs.starfarer.api.impl.campaign.ids.Tags;
020import com.fs.starfarer.api.impl.campaign.tutorial.TutorialMissionIntel;
021import com.fs.starfarer.api.util.Misc;
022
023public class MusicPlayerPluginImpl implements MusicPlayerPluginWithVolumeControl {
024
025        public static String KEEP_PLAYING_LOCATION_MUSIC_DURING_ENCOUNTER_MEM_KEY = "$playLocationMusicDuringEnc";
026        public static String COMBAT_MUSIC_SET_MEM_KEY = "$combatMusicSetId";
027        public static String COMBAT_MUSIC_SET_FACTION_KEY = "music_combat_set";
028        public static String MUSIC_SET_MEM_KEY = "$musicSetId";
029        public static String MUSIC_SET_MEM_KEY_MISSION = "$musicSetIdForMission";
030        
031        
032        public static String MUSIC_ENCOUNTER_MYSTERIOUS_AGGRO = "music_encounter_mysterious";
033        public static String MUSIC_ENCOUNTER_MYSTERIOUS_NON_AGGRESSIVE = "music_encounter_mysterious_non_aggressive";
034        public static String MUSIC_ENCOUNTER_NEUTRAL = "music_encounter_neutral";
035        public static String MUSIC_GALATIA_ACADEMY = "music_galatia_academy";
036        
037        
038        public static Object CAMPAIGN_SYSTEM = new Object();
039        public static Object CAMPAIGN_HYPERSPACE = new Object();
040        public static Object NO_MUSIC = new Object();
041        public static Object COMBAT = new Object();
042        public static Object TITLE = new Object();
043        public static Object MARKET = new Object();
044        public static Object ENCOUNTER = new Object();
045        public static Object PLANET_SURVEY = new Object();
046        
047        public static Object CUSTOM = new Object();
048        
049        public static Map<String, String> stringTokens = new HashMap<String, String>();
050        
051        /**
052         * Goal here is to return tokens for which an == comparison works.
053         * @param str
054         * @return
055         */
056        public static Object getToken(String str) {
057                if (!stringTokens.containsKey(str)) {
058                        stringTokens.put(str, str);
059                }
060                return stringTokens.get(str);
061        }
062        
063        public static String SYSTEM_MUSIC_PREFIX = "core_sys_music_";
064        
065        public Object getStateTokenForCampaignLocation() {
066                CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
067                if (playerFleet.getContainingLocation() instanceof StarSystemAPI) {
068                        /*
069                         Just returning CAMPAIGN_SYSTEM and letting getMusicSetIdForCampaignStateToken()
070                         return the musicSetId misses the case where there's a transition between
071                         two star systems with different music, without hyperspace travel in between -
072                         since there would be no state transition (due to it being the same CAMPAIGN_SYSTEM state), 
073                         a restart of the music - and a change to a different music set - would not be triggered.
074                         
075                         Since the state ID includes the music set id, this means that moving between
076                         two systems with the same $musicSetId will not trigger a state change and
077                         the same music will just keep playing uninterrupted.
078                         */
079                        StarSystemAPI system = (StarSystemAPI) playerFleet.getContainingLocation();
080                        String musicSetId = system.getMemoryWithoutUpdate().getString(MUSIC_SET_MEM_KEY_MISSION);
081                        if (musicSetId != null) {
082                                return getToken(SYSTEM_MUSIC_PREFIX + musicSetId);
083                        }
084                        musicSetId = system.getMemoryWithoutUpdate().getString(MUSIC_SET_MEM_KEY);
085                        if (musicSetId != null) {
086                                return getToken(SYSTEM_MUSIC_PREFIX + musicSetId);
087                        }
088                        return CAMPAIGN_SYSTEM;
089                }
090//              float depth = Misc.getAbyssalDepthOfPlayer();
091//              if (depth > 0.5f) {
092//                      return NO_MUSIC;
093//              }
094                return CAMPAIGN_HYPERSPACE;
095        }
096        
097        public String getMusicSetIdForCombat(CombatEngineAPI engine) {
098                if (engine.getContext() != null && engine.getContext().getOtherFleet() != null) {
099                        CampaignFleetAPI other = engine.getContext().getOtherFleet();
100                        MemoryAPI mem = other.getMemoryWithoutUpdate();
101                        if (mem.contains(COMBAT_MUSIC_SET_MEM_KEY)) {
102                                return mem.getString(COMBAT_MUSIC_SET_MEM_KEY);
103                        }
104                        String factionSet = other.getFaction().getMusicMap().get(COMBAT_MUSIC_SET_FACTION_KEY);
105                        if (factionSet != null) return factionSet;
106                }
107                return "music_combat";
108        }
109        
110        public String getMusicSetIdForTitle() {
111                return "music_title";
112        }
113        
114        
115        public float getMusicSetVolumeForCampaignStateToken(Object token, Object param) {
116                if (token == CAMPAIGN_HYPERSPACE) {
117                        //float depth = Misc.getAbyssalDepthOfPlayer();
118                        // need to check this way so that the hyperspace track doesn't fade back in
119                        // right after transitiong to an abyssal system (as the track fades out)
120                        CampaignFleetAPI pf = Global.getSector().getPlayerFleet();
121                        float depth = 0f;
122                        if (pf != null) depth = Misc.getAbyssalDepth(pf.getLocationInHyperspace());
123                        float vol = 1f - depth;
124                        if (vol > 1f) vol = 1f;
125                        if (vol < 0f) vol = 0f;
126                        return vol;
127                }
128                return 1f;
129        }
130        
131        public String getMusicSetIdForCampaignStateToken(Object token, Object param) {
132                if (token == MARKET) {
133                        return getMarketMusicSetId(param);
134                }
135                if (token == ENCOUNTER) {
136                        return getEncounterMusicSetId(param);
137                }
138                if (token == CAMPAIGN_SYSTEM || 
139                                (token instanceof String && ((String)token).startsWith(SYSTEM_MUSIC_PREFIX))) {
140                        return getStarSystemMusicSetId();
141                }
142                if (token == CAMPAIGN_HYPERSPACE) {
143                        return getHyperspaceMusicSetId();
144                }
145                if (token == PLANET_SURVEY) {
146                        return getPlanetSurveyMusicSetId(param);
147                }
148                if (token == NO_MUSIC) {
149                        return null;
150                }
151                return null;
152        }
153        
154        /**
155         * @param param is a MarketAPI.
156         * @return
157         */
158        protected String getPlanetSurveyMusicSetId(Object param) {
159                SectorEntityToken token = null;
160                if (param instanceof SectorEntityToken) {
161                        token = (SectorEntityToken) param;
162                } else if (param instanceof MarketAPI) {
163                        token = ((MarketAPI)param).getPlanetEntity();
164                }
165                if (token != null) {    
166                        String musicSetId = token.getMemoryWithoutUpdate().getString(MUSIC_SET_MEM_KEY_MISSION);
167                        if (musicSetId != null) return musicSetId;
168                        musicSetId = token.getMemoryWithoutUpdate().getString(MUSIC_SET_MEM_KEY);
169                        if (musicSetId != null) return musicSetId;
170                }
171                return "music_survey_and_scavenge";
172        }
173        
174        protected String getHyperspaceMusicSetId() {
175                return "music_campaign_hyperspace";
176        }
177        
178        protected String getStarSystemMusicSetId() {
179                CampaignFleetAPI playerFleet = Global.getSector().getPlayerFleet();
180                if (playerFleet.getContainingLocation() instanceof StarSystemAPI) {
181                        StarSystemAPI system = (StarSystemAPI) playerFleet.getContainingLocation();
182                        String musicSetId = system.getMemoryWithoutUpdate().getString(MUSIC_SET_MEM_KEY_MISSION);
183                        if (musicSetId != null) return musicSetId;
184                        musicSetId = system.getMemoryWithoutUpdate().getString(MUSIC_SET_MEM_KEY);
185                        if (musicSetId != null) return musicSetId;
186
187                        if (system.hasTag(Tags.SYSTEM_ABYSSAL)) {
188                                return "music_campaign_abyssal";
189                        }
190                        if (system.hasTag(Tags.THEME_CORE) ||
191                                        !Misc.getMarketsInLocation(system, Factions.PLAYER).isEmpty()) {
192                                return "music_campaign";
193                        }
194                }
195                
196                return "music_campaign_non_core";
197        }
198        
199        protected String getEncounterMusicSetId(Object param) {
200                if (param instanceof SectorEntityToken) {
201                        SectorEntityToken token = (SectorEntityToken) param;
202                        
203                        String musicSetId = token.getMemoryWithoutUpdate().getString(MUSIC_SET_MEM_KEY_MISSION);
204                        if (musicSetId != null) return musicSetId;
205                        musicSetId = token.getMemoryWithoutUpdate().getString(MUSIC_SET_MEM_KEY);
206                        if (musicSetId != null) return musicSetId;
207                        
208                        if (Entities.ABYSSAL_LIGHT.equals(token.getCustomEntityType())) {
209                                return MUSIC_ENCOUNTER_NEUTRAL;
210                        }
211                        if (Entities.CORONAL_TAP.equals(token.getCustomEntityType())) {
212                                return MUSIC_ENCOUNTER_MYSTERIOUS_AGGRO;
213                        }
214                        if (Entities.WRECK.equals(token.getCustomEntityType())) {
215                                return MUSIC_ENCOUNTER_NEUTRAL;
216                        }
217                        if (Entities.DERELICT_GATEHAULER.equals(token.getCustomEntityType())) {
218                                return MUSIC_ENCOUNTER_MYSTERIOUS_NON_AGGRESSIVE;
219                        }
220                        
221                        if (Entities.DEBRIS_FIELD_SHARED.equals(token.getCustomEntityType())) {
222                                return "music_survey_and_scavenge";
223                        }
224                        if (token.hasTag(Tags.GATE)) {
225                                return MUSIC_ENCOUNTER_NEUTRAL;
226                        }
227                        if (token.hasTag(Tags.OBJECTIVE)) {
228                                return MUSIC_ENCOUNTER_NEUTRAL;
229                        }
230                        if (token.hasTag(Tags.SALVAGEABLE)) {
231                                if (token.getMemoryWithoutUpdate() != null && token.getMemoryWithoutUpdate().getBoolean("$hasDefenders")) {
232                                        if (token.getMemoryWithoutUpdate().getBoolean("$limboMiningStation")) {
233                                                return MUSIC_ENCOUNTER_MYSTERIOUS_AGGRO;
234                                        }
235                                        if (token.getMemoryWithoutUpdate().getBoolean("$limboWormholeCache")) {
236                                                return MUSIC_ENCOUNTER_MYSTERIOUS_AGGRO;
237                                        }
238                                        return MUSIC_ENCOUNTER_NEUTRAL;
239                                }
240                                return "music_survey_and_scavenge";
241                        }
242                        if (token.hasTag(Tags.SALVAGE_MUSIC)) {
243                                return "music_survey_and_scavenge";
244                        }
245                        
246//                      MemoryAPI memory = token.getMemoryWithoutUpdate();
247//                      if (!memory.getBoolean("$defenderFleetDefeated") && memory.getBoolean("$hasDefenders")) { 
248//                              CampaignFleetAPI defenders = memory.getFleet("$defenderFleet");
249//                              if (defenders != null) token = defenders;
250//                      }
251                        
252                        if (token.getFaction() != null) {
253                                FactionAPI faction = (FactionAPI) token.getFaction();
254                                String type = null;
255                                //MemoryAPI mem = token.getMemoryWithoutUpdate();
256                                boolean hostile = false;
257                                boolean knowsWhoPlayerIs = false;
258                                if (token instanceof CampaignFleetAPI) {
259                                        CampaignFleetAPI fleet = (CampaignFleetAPI) token;
260                                        if (fleet.getAI() instanceof ModularFleetAIAPI) {
261                                                hostile = ((ModularFleetAIAPI) fleet.getAI()).isHostileTo(Global.getSector().getPlayerFleet());
262                                        }
263                                        knowsWhoPlayerIs = fleet.knowsWhoPlayerIs();
264                                }
265                                
266                                if (faction.isAtWorst(Factions.PLAYER, RepLevel.FAVORABLE) && knowsWhoPlayerIs && !hostile) {
267                                        type = "encounter_friendly";
268                                } else if ((faction.isAtBest(Factions.PLAYER, RepLevel.SUSPICIOUS) && knowsWhoPlayerIs) || hostile) {
269                                        type = "encounter_hostile";
270                                } else {
271                                        type = "encounter_neutral";
272                                }
273                                
274                                if (type != null) {
275                                        musicSetId = faction.getMusicMap().get(type);
276                                        if (musicSetId != null) {
277                                                return musicSetId;
278                                        }
279                                }
280                                
281                                musicSetId = null;
282                                if (faction.isAtWorst(Factions.PLAYER, RepLevel.FAVORABLE)) {
283                                        musicSetId = "music_default_encounter_friendly";
284                                } else if (faction.isAtBest(Factions.PLAYER, RepLevel.SUSPICIOUS)) {
285                                        musicSetId = "music_default_encounter_hostile";
286                                } else {
287                                        musicSetId = "music_default_encounter_neutral";
288                                }
289                                return musicSetId;
290                        }
291                }
292                return null;
293        }
294        
295
296        protected String getMarketMusicSetId(Object param) {
297                if (param instanceof MarketAPI) {
298                        MarketAPI market = (MarketAPI) param;
299                        
300                        String musicSetId = market.getMemoryWithoutUpdate().getString(MUSIC_SET_MEM_KEY_MISSION);
301                        if (musicSetId != null) return musicSetId;
302                        musicSetId = market.getMemoryWithoutUpdate().getString(MUSIC_SET_MEM_KEY);
303                        if (musicSetId != null) return musicSetId;
304                        
305                        if (market.getPrimaryEntity() != null &&
306                                        market.getPrimaryEntity().getMemoryWithoutUpdate().getBoolean("$abandonedStation")) {
307                                return getPlanetSurveyMusicSetId(param);
308                        }
309                        
310                        if (market.getPrimaryEntity() != null &&
311                                        market.getPrimaryEntity().getId().equals("station_galatia_academy")) {
312                                if (TutorialMissionIntel.isTutorialInProgress()) {
313                                        return MUSIC_ENCOUNTER_MYSTERIOUS_AGGRO;
314                                }
315                                return MUSIC_GALATIA_ACADEMY;
316                        }
317                        
318                        FactionAPI faction = market.getFaction();
319                        if (faction != null) {
320                                String type = null;
321                                if (faction.isAtWorst(Factions.PLAYER, RepLevel.FAVORABLE)) {
322                                        type = "market_friendly";
323                                } else if (faction.isAtBest(Factions.PLAYER, RepLevel.SUSPICIOUS)) {
324                                        type = "market_hostile";
325                                } else {
326                                        type = "market_neutral";
327                                }
328                                
329                                if (type != null) {
330                                        musicSetId = faction.getMusicMap().get(type);
331                                        if (musicSetId != null) {
332                                                return musicSetId;
333                                        }
334                                }
335                                
336                                musicSetId = null;
337                                if (faction.isAtWorst(Factions.PLAYER, RepLevel.FAVORABLE)) {
338                                        musicSetId = "music_default_market_friendly";
339                                } else if (faction.isAtBest(Factions.PLAYER, RepLevel.SUSPICIOUS)) {
340                                        musicSetId = "music_default_market_hostile";
341                                } else {
342                                        musicSetId = "music_default_market_neutral";
343                                }
344                                return musicSetId;
345                        }
346                }
347                return null;
348        }
349}
350
351
352
353
354
355
356
357