001package com.fs.starfarer.api.impl.campaign.rulecmd.missions;
002
003import java.util.ArrayList;
004import java.util.Collections;
005import java.util.Comparator;
006import java.util.List;
007import java.util.Map;
008import java.util.Random;
009
010import org.lwjgl.input.Keyboard;
011
012import com.fs.starfarer.api.EveryFrameScript;
013import com.fs.starfarer.api.Global;
014import com.fs.starfarer.api.campaign.InteractionDialogAPI;
015import com.fs.starfarer.api.campaign.InteractionDialogPlugin;
016import com.fs.starfarer.api.campaign.SectorEntityToken;
017import com.fs.starfarer.api.campaign.comm.IntelInfoPlugin;
018import com.fs.starfarer.api.campaign.econ.MarketAPI;
019import com.fs.starfarer.api.campaign.rules.MemKeys;
020import com.fs.starfarer.api.campaign.rules.MemoryAPI;
021import com.fs.starfarer.api.characters.ImportantPeopleAPI;
022import com.fs.starfarer.api.characters.PersonAPI;
023import com.fs.starfarer.api.combat.EngagementResultAPI;
024import com.fs.starfarer.api.impl.campaign.DebugFlags;
025import com.fs.starfarer.api.impl.campaign.DevMenuOptions;
026import com.fs.starfarer.api.impl.campaign.RuleBasedInteractionDialogPluginImpl;
027import com.fs.starfarer.api.impl.campaign.intel.bar.BarEventDialogPlugin;
028import com.fs.starfarer.api.impl.campaign.intel.bar.PortsideBarData;
029import com.fs.starfarer.api.impl.campaign.intel.bar.PortsideBarEvent;
030import com.fs.starfarer.api.impl.campaign.intel.bar.events.BarEventManager;
031import com.fs.starfarer.api.impl.campaign.intel.contacts.ContactIntel;
032import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionBarEventWrapper;
033import com.fs.starfarer.api.impl.campaign.rulecmd.BaseCommandPlugin;
034import com.fs.starfarer.api.impl.campaign.rulecmd.DumpMemory;
035import com.fs.starfarer.api.impl.campaign.rulecmd.FireAll;
036import com.fs.starfarer.api.impl.campaign.rulecmd.FireBest;
037import com.fs.starfarer.api.impl.campaign.rulecmd.ShowDefaultVisual;
038import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.AddBarEvent;
039import com.fs.starfarer.api.impl.campaign.rulecmd.salvage.AddBarEvent.BarEventData;
040import com.fs.starfarer.api.impl.campaign.tutorial.TutorialMissionIntel;
041import com.fs.starfarer.api.util.FaderUtil;
042import com.fs.starfarer.api.util.Misc;
043import com.fs.starfarer.api.util.Misc.Token;
044import com.fs.starfarer.api.util.WeightedRandomPicker;
045
046/**
047 *      BarCMD
048 */
049public class BarCMD extends BaseCommandPlugin implements InteractionDialogPlugin {
050
051        public static float BAR_EVENT_MIN_TIME_BEFORE_CHANGING = 20f;
052        public static float BAR_EVENT_MAX_TIME_BEFORE_CHANGING = 40f;
053        
054        protected SectorEntityToken entity;
055        protected InteractionDialogPlugin originalPlugin;
056        protected InteractionDialogAPI dialog;
057        protected Map<String, MemoryAPI> memoryMap;
058
059        public static class BarAmbiencePlayer implements EveryFrameScript {
060                public MarketAPI market;
061                public String soundId = "bar_ambience";
062                public float pitch = 1f;
063                public float volume = 1f;
064                public float musicSuppression = 0.95f;
065                public boolean done = false;
066                
067                public FaderUtil fader = new FaderUtil(0f, 0.5f);
068                public BarAmbiencePlayer(MarketAPI market) {
069                        this.market = market;
070                        if (market.getFaction() != null) {
071                                soundId = market.getFaction().getBarSound();
072                        }
073                        fader.fadeIn();
074                }
075                public void advance(float amount) {
076                        fader.advance(amount);
077                        Global.getSector().getCampaignUI().suppressMusic(fader.getBrightness() * musicSuppression);
078                        Global.getSoundPlayer().playUILoop(soundId, pitch, volume * fader.getBrightness());
079                        if (!Global.getSector().isPaused()) {
080                                stop();
081                        }
082                }
083                public boolean isDone() {
084                        return done;
085                }
086                public boolean runWhilePaused() {
087                        return true;
088                }
089                public void stop() {
090                        done = true;
091                }
092        }
093        
094        public boolean execute(String ruleId, InteractionDialogAPI dialog, List<Token> params, final Map<String, MemoryAPI> memoryMap) {
095                this.dialog = dialog;
096                this.memoryMap = memoryMap;
097                if (dialog == null) return false;
098
099                String command = params.get(0).getString(memoryMap);
100                if (command == null) return false;
101                
102                
103                if (command.equals("returnFromEvent")) {
104                        MemoryAPI mem = getEntityMemory(memoryMap);
105                        BarCMD cmd = (BarCMD) mem.get("$BarCMD");
106                        mem.unset("$BarCMD");
107                        //mem.unset("$currMission_ref");
108                        
109                        dialog.setPlugin(cmd);
110                        abortMissions(null);
111
112                        dialog.getInteractionTarget().setActivePerson(null);
113                        ((RuleBasedInteractionDialogPluginImpl)cmd.originalPlugin).updateMemory();
114//                      memoryMap.put(MemKeys.LOCAL, dialog.getInteractionTarget().getMemoryWithoutUpdate());
115//                      memoryMap.remove(MemKeys.ENTITY);
116
117                        
118                        boolean withContinue = params.size() > 1 && params.get(1).getBoolean(memoryMap);
119                        cmd.returningFromEvent(withContinue);
120                        
121                        return true;
122                } else if (command.equals("accept")) {
123                        //MemoryAPI mem = getEntityMemory(memoryMap);
124                        //Object ref = mem.get("$currMission_ref");
125                        
126                        String missionId = params.get(1).getString(memoryMap);
127                        HubMissionBarEventWrapper w = getWrapperFor(missionId);
128                        if (w != null && w.getMission() != null) {
129                                BarEventManager.getInstance().notifyWasInteractedWith(w);
130                                w.getMission().accept(dialog, memoryMap);
131                        }
132                        return true;
133                } else if (command.equals("leaveBar")) {
134                        leaveBar();
135                        return true;
136                } else if (command.equals("playAmbience")) {
137                        entity = dialog.getInteractionTarget();
138                        if (!Global.getSector().hasTransientScript(BarAmbiencePlayer.class)) {
139                                Global.getSector().addTransientScript(new BarAmbiencePlayer(entity.getMarket()));
140                        }
141                        return true;
142                }
143                
144//              else if (command.equals("addContact")) {
145//                      ContactIntel.addPotentialContact(contact, text)
146//              }
147                
148                entity = dialog.getInteractionTarget();
149                originalPlugin = dialog.getPlugin();
150                
151                //FireBest.fire(null, dialog, memoryMap, "SalvageSpecialFinishedNoContinue");
152                
153                if (command.equals("showOptions")) {
154                        showOptions(false);
155                        if (!Global.getSector().hasTransientScript(BarAmbiencePlayer.class)) {
156                                Global.getSector().addTransientScript(new BarAmbiencePlayer(entity.getMarket()));
157                        }
158                }
159                
160                return true;
161        }
162        
163        public void showOptions(boolean returningFromEvent) {
164                dialog.getVisualPanel().restoreSavedVisual();
165                dialog.getVisualPanel().saveCurrentVisual();
166                
167                PortsideBarData data = PortsideBarData.getInstance();
168                
169                MarketAPI market = entity.getMarket();
170                
171                dialog.getOptionPanel().clearOptions();
172                
173                Random random = new Random(BarEventManager.getInstance().getSeed(entity, null, null));
174                
175                int min = Global.getSettings().getInt("minBarEvents");
176                int max = Global.getSettings().getInt("maxBarEvents");
177                float pMult = Global.getSettings().getFloat("barEventProbOneMore");
178                //int num = min + random.nextInt(max - min + 1);
179                
180                WeightedRandomPicker<Integer> numPicker = new WeightedRandomPicker<Integer>(random);
181                float p = 1f;
182                for (int i = min; i <= max; i++) {
183                        numPicker.add(i, p);
184                        p *= pMult;
185                }
186                int num = numPicker.pick();
187                
188                if (DebugFlags.BAR_DEBUG) {
189                        max = 8;
190                        num = 7;
191                        //num = max;
192                }
193                
194                //num = 1000;
195                
196                List<PortsideBarEvent> events = new ArrayList<PortsideBarEvent>();
197                String key = "$BarCMD_shownEvents";
198                MemoryAPI mem = market.getMemoryWithoutUpdate();
199                boolean needToSaveShown = false;
200                if (mem.contains(key)) {
201                        List<String> eventIds = (List<String>) mem.get(key);
202                        for (String id : eventIds) {
203                                OUTER: for (PortsideBarEvent event : data.getEvents()) {
204//                                      for (GenericBarEventCreator c : BarEventManager.getInstance().getTimeout().getItems()) {
205//                                              if (c.getBarEventId() != null && c.getBarEventId().equals(id)) {
206//                                                      continue OUTER;
207//                                              }
208//                                      }
209                                        if (id.equals(event.getBarEventId())) {
210                                                events.add(event);
211                                        }
212                                }
213                        }
214                        num = Math.max(eventIds.size(), num);
215                } else {
216                        events.addAll(data.getEvents());
217                        Collections.shuffle(events, random);
218                        needToSaveShown = true;
219                }
220                
221                boolean addedSomething = false;
222                
223                AddBarEvent.clearTempEvents(market);
224                FireAll.fire(null, dialog, memoryMap, "AddBarEvents");
225                
226                List<BarEventData> temp = new ArrayList<BarEventData>(AddBarEvent.getTempEvents(market).events.values());
227                for (int i = 0; i < max && i < temp.size(); i++) {
228                        BarEventData b = temp.get(i);
229                        if (!b.blurb.isEmpty()) {
230                                dialog.getTextPanel().addPara(b.blurb);
231                        }
232                        dialog.getOptionPanel().addOption(b.option, b.optionId);
233                        if (b.optionColor != null) {
234                                dialog.setOptionColor(b.optionId, b.optionColor);
235                        }
236                        addedSomething = true;
237                }
238                
239                List<String> shown = new ArrayList<String>();
240                
241                // used alongside with ip.excludeFromGetPerson() to ensure that the same person isn't picked
242                // for multiple concurrent bar events
243                ImportantPeopleAPI ip = Global.getSector().getImportantPeople();
244                ip.resetExcludeFromGetPerson();
245                
246                // existing contacts don't show up at the bar, since the bar encounter dialogue is written
247                // assuming you're meeting them for the first time
248                for (IntelInfoPlugin intel : Global.getSector().getIntelManager().getIntel(ContactIntel.class)) {
249                        ip.excludeFromGetPerson(((ContactIntel)intel).getPerson());
250                }
251                
252//              BaseMissionHub.resetMissionAngle(null, market);
253//              BaseMissionHub.getMissionAngle(null, market, random);
254                
255                Collections.sort(events, new Comparator<PortsideBarEvent>() {
256                        public int compare(PortsideBarEvent o1, PortsideBarEvent o2) {
257                                boolean p1 = o1.isAlwaysShow();
258                                boolean p2 = o2.isAlwaysShow();
259                                if (p1 && !p2) return -1;
260                                if (p2 && !p1) return 1;
261                                return 0;
262                        }
263                });
264                
265                int curr = 0;
266                //for (PortsideBarEvent event : data.getEvents()) {
267                for (PortsideBarEvent event : events) {
268                        if (TutorialMissionIntel.isTutorialInProgress()) continue;
269                        if (curr + temp.size() >= max) break;
270                        
271//                      if (curr < 16) {
272//                              curr++;
273//                              continue;
274//                      }
275                        
276                        if (event.shouldRemoveEvent()) continue;
277                        if (!event.shouldShowAtMarket(market)) continue;
278                        
279                        event.addPromptAndOption(dialog, memoryMap);
280                        if (event instanceof HubMissionBarEventWrapper) {
281                                HubMissionBarEventWrapper w = (HubMissionBarEventWrapper) event;
282                                if (w.getMission() == null) { // aborted during creation
283                                        continue;
284                                }
285                        }
286                        event.wasShownAtMarket(market);
287                        
288                        if (event.getBarEventId() != null) {
289                                shown.add(event.getBarEventId());
290                        }
291                        
292                        addedSomething = true;
293                        
294                        if (!event.isAlwaysShow()) {
295                                curr++;
296                        }
297                        if (curr >= num) break;
298                }
299                
300                //BaseMissionHub.clearCreatedMissionsList(null, market);
301                ip.resetExcludeFromGetPerson();
302                
303                if (needToSaveShown) {
304                        float time = BAR_EVENT_MIN_TIME_BEFORE_CHANGING + 
305                                                 (BAR_EVENT_MAX_TIME_BEFORE_CHANGING - BAR_EVENT_MIN_TIME_BEFORE_CHANGING) * random.nextFloat();
306                        mem.set(key, shown, time);
307                }
308                
309                if (returningFromEvent) {
310                        if (!addedSomething) {
311                                dialog.getTextPanel().addPara("Nothing of note is going on at the bar.");
312                        } else {
313                                dialog.getTextPanel().addPara("You unobtrusively watch the patrons of the bar for " +
314                                                                                          "a few minutes before deciding what to do next.");
315                        }
316                }
317                
318                dialog.getOptionPanel().addOption("Leave the bar", "barLeave");
319                dialog.getOptionPanel().setShortcut("barLeave", Keyboard.KEY_ESCAPE, false, false, false, true);
320                
321                
322                if (Global.getSettings().isDevMode()) {
323                        DevMenuOptions.addOptions(dialog);
324                }
325                
326                dialog.setPlugin(this);
327                init(dialog);
328        }
329
330        public void optionSelected(String optionText, Object optionData) {
331                if (optionText != null) {
332                        //dialog.getTextPanel().addParagraph(optionText, Global.getSettings().getColor("buttonText"));
333                        dialog.addOptionSelectedText(optionData);
334                }
335                if (optionData == DumpMemory.OPTION_ID) {
336                        new DumpMemory().execute(null, dialog, null, getMemoryMap());
337                        return;
338                } else if (DevMenuOptions.isDevOption(optionData)) {
339                        DevMenuOptions.execute(dialog, (String) optionData);
340                        return;
341                }
342                
343                // need to abort any HubMissionBarEventWrapper missions that are *not* the current selection
344                String optionId = null;
345                if (optionData instanceof String) {
346                        optionId = (String) optionData;
347                }
348                
349                abortMissions(optionId);
350                
351                if (optionData instanceof PortsideBarEvent) {
352                        PortsideBarEvent event = (PortsideBarEvent) optionData;
353                        BarEventDialogPlugin plugin = new BarEventDialogPlugin(this, this, event, memoryMap);
354                        dialog.setPlugin(plugin);
355                        plugin.init(dialog);
356                        return;
357                } else if ("barLeave".equals(optionData)) {
358                        leaveBar();
359                } else if ("barContinue".equals(optionData)) {
360                        showOptions(true);
361                } else if (optionData instanceof String) {
362                        // a HubMissionBarEventWrapper option
363//                      HubMissionBarEventWrapper w = getWrapperFor(optionId);
364//                      if (w != null && w.getMission() != null) {
365//                              mem.set("$currMission_ref", w.getMission(), 0f);
366//                      } else {
367//                              mem.unset("$currMission_ref");
368//                      }
369                        
370                        MemoryAPI eMem = getEntityMemory(memoryMap);
371                        eMem.set("$BarCMD", this, 0f);
372                        
373                        HubMissionBarEventWrapper w = getWrapperFor(optionId);
374                        if (w != null && w.getMission() != null) {
375                                PersonAPI person = w.getMission().getPerson();
376                                if (person != null) {
377                                        dialog.getInteractionTarget().setActivePerson(person);
378                                        ((RuleBasedInteractionDialogPluginImpl)originalPlugin).updateMemory();
379//                                      memoryMap.put(MemKeys.ENTITY, memoryMap.get(MemKeys.LOCAL));
380//                                      memoryMap.put(MemKeys.LOCAL, person.getMemoryWithoutUpdate());
381                                        dialog.getVisualPanel().showPersonInfo(person, true);
382                                }
383                        }
384                        
385                        MemoryAPI mem = memoryMap.get(MemKeys.LOCAL);
386                        dialog.setPlugin(originalPlugin);
387                        mem.set("$option", (String) optionData, 0f);
388                        
389                        FireBest.fire(null, dialog, memoryMap, "DialogOptionSelected");
390                }
391        }
392        
393        public void returningFromEvent(PortsideBarEvent event) {
394                returningFromEvent(event.endWithContinue());
395        }
396        public void returningFromEvent(boolean withContinue) {
397                if (withContinue) {
398                        dialog.getOptionPanel().clearOptions();
399                        dialog.getOptionPanel().addOption("Continue", "barContinue");
400                } else {
401                        showOptions(true);
402                }
403        }
404        
405        public HubMissionBarEventWrapper getWrapperFor(String optionId) {
406                PortsideBarData data = PortsideBarData.getInstance();
407                for (PortsideBarEvent event : data.getEvents()) {
408                        if (event instanceof HubMissionBarEventWrapper) {
409                                HubMissionBarEventWrapper w = (HubMissionBarEventWrapper) event;
410                                if (w.getMission() == null) continue;
411                                if (optionId != null && optionId.startsWith(w.getMission().getTriggerPrefix())) {
412                                        return w;
413                                }
414                        }
415                }
416                return null;
417        }
418        public void abortMissions(String optionId) {
419                PortsideBarData data = PortsideBarData.getInstance();
420                for (PortsideBarEvent event : data.getEvents()) {
421                        if (event instanceof HubMissionBarEventWrapper) {
422                                HubMissionBarEventWrapper w = (HubMissionBarEventWrapper) event;
423                                if (w.getMission() == null) continue;
424                                if (optionId == null || !optionId.startsWith(w.getMission().getTriggerPrefix())) {
425                                        w.abortMission();
426                                }
427                        }
428                }
429        }
430        
431        
432        public static BarAmbiencePlayer getAmbiencePlayer() {
433                for (EveryFrameScript script : Global.getSector().getTransientScripts()) {
434                        if (script instanceof BarAmbiencePlayer) {
435                                return (BarAmbiencePlayer) script;
436                        }
437                }
438                return null;            
439        }
440        
441        public void leaveBar() {
442                
443                BarAmbiencePlayer player = getAmbiencePlayer();
444                if (player != null) {
445                        player.stop();
446                }
447                
448                if (originalPlugin != null) {
449                        dialog.setPlugin(originalPlugin);
450                }
451                
452                new ShowDefaultVisual().execute(null, dialog, Misc.tokenize(""), memoryMap);
453                FireBest.fire(null, dialog, memoryMap, "ReturnFromBar");
454        }
455        
456        public void advance(float amount) {
457        }
458        public void backFromEngagement(EngagementResultAPI battleResult) {
459        }
460        public Object getContext() {
461                return null;
462        }
463        public Map<String, MemoryAPI> getMemoryMap() {
464                return memoryMap;
465        }
466        public void optionMousedOver(String optionText, Object optionData) {
467        }
468        
469        public void init(InteractionDialogAPI dialog) {
470        }
471        
472}
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490