001package com.fs.starfarer.api.impl.campaign;
002
003import java.util.HashMap;
004import java.util.Map;
005
006import java.awt.Color;
007
008import com.fs.starfarer.api.Global;
009import com.fs.starfarer.api.campaign.CampaignFleetAPI;
010import com.fs.starfarer.api.campaign.InteractionDialogAPI;
011import com.fs.starfarer.api.campaign.InteractionDialogPlugin;
012import com.fs.starfarer.api.campaign.OptionPanelAPI;
013import com.fs.starfarer.api.campaign.RuleBasedDialog;
014import com.fs.starfarer.api.campaign.TextPanelAPI;
015import com.fs.starfarer.api.campaign.VisualPanelAPI;
016import com.fs.starfarer.api.campaign.econ.MarketAPI;
017import com.fs.starfarer.api.campaign.events.CampaignEventPlugin;
018import com.fs.starfarer.api.campaign.rules.MemKeys;
019import com.fs.starfarer.api.campaign.rules.MemoryAPI;
020import com.fs.starfarer.api.campaign.rules.RulesAPI;
021import com.fs.starfarer.api.characters.PersonAPI;
022import com.fs.starfarer.api.combat.EngagementResultAPI;
023import com.fs.starfarer.api.impl.campaign.ids.MemFlags;
024import com.fs.starfarer.api.impl.campaign.rulecmd.DismissDialog;
025import com.fs.starfarer.api.impl.campaign.rulecmd.DumpMemory;
026import com.fs.starfarer.api.impl.campaign.rulecmd.FireAll;
027import com.fs.starfarer.api.impl.campaign.rulecmd.FireBest;
028import com.fs.starfarer.api.util.Misc;
029
030/**
031 * @author Alex Mosolov
032 *
033 * Uses the data in data/campaign/rules.csv to drive the dialog interactions.
034 *
035 * Copyright 2014 Fractal Softworks, LLC
036 */
037public class RuleBasedInteractionDialogPluginImpl implements InteractionDialogPlugin, RuleBasedDialog {
038
039        public static final String FAILSAFE_LEAVE = "rbid_failsafe_leave";
040        
041        private InteractionDialogAPI dialog;
042        private TextPanelAPI textPanel;
043        private OptionPanelAPI options;
044        private VisualPanelAPI visual;
045        
046        private RulesAPI rules;
047        private MemoryAPI memory;
048        
049        private CampaignFleetAPI playerFleet;
050        
051        private Object custom1;
052        private Object custom2;
053        private Object custom3;
054        
055        private static final Color HIGHLIGHT_COLOR = Global.getSettings().getColor("buttonShortcut");
056        
057        private boolean embeddedMode = false;
058        public void setEmbeddedMode(boolean embeddedMode) {
059                this.embeddedMode = embeddedMode;
060        }
061
062        private final String initialTrigger;
063        
064        public RuleBasedInteractionDialogPluginImpl() {
065                this("OpenInteractionDialog");
066        }
067        public RuleBasedInteractionDialogPluginImpl(String initialTrigger) {
068                this.initialTrigger = initialTrigger;
069        }
070
071
072        public void reinit(boolean withContinueOnRuleFound) {
073                init(dialog);
074        }
075        
076        public void init(InteractionDialogAPI dialog) {
077                this.dialog = dialog;
078                
079                textPanel = dialog.getTextPanel();
080                options = dialog.getOptionPanel();
081                visual = dialog.getVisualPanel();
082
083                playerFleet = Global.getSector().getPlayerFleet();
084                
085                if (!embeddedMode) {
086                        visual.setVisualFade(0.25f, 0.25f);
087                }
088                
089                rules = Global.getSector().getRules();
090                
091                updateMemory();
092                
093                if (!embeddedMode) {
094                        fireBest(initialTrigger);
095                        if (!options.hasOptions()) {
096                                options.clearOptions();
097                                options.addOption("Leave", FAILSAFE_LEAVE);
098                                if (Global.getSettings().isDevMode()) {
099                                        DevMenuOptions.addOptions(dialog);
100                                }
101                        }
102                }
103        }
104        
105        public void updateMemory() {
106                if (memoryMap == null) {
107                        memoryMap = new HashMap<String, MemoryAPI>();
108                } else {
109                        memoryMap.clear();
110                }
111                memory = dialog.getInteractionTarget().getMemory();
112                
113                memoryMap.put(MemKeys.LOCAL, memory);
114                if (dialog.getInteractionTarget().getFaction() != null) {
115                        memoryMap.put(MemKeys.FACTION, dialog.getInteractionTarget().getFaction().getMemory());
116                } else {
117                        memoryMap.put(MemKeys.FACTION, Global.getFactory().createMemory());
118                }
119                memoryMap.put(MemKeys.GLOBAL, Global.getSector().getMemory());
120                memoryMap.put(MemKeys.PLAYER, Global.getSector().getCharacterData().getMemory());
121                
122                if (dialog.getInteractionTarget().getMarket() != null) {
123                        memoryMap.put(MemKeys.MARKET, dialog.getInteractionTarget().getMarket().getMemory());
124                }
125                
126                if (memory.contains(MemFlags.MEMORY_KEY_SOURCE_MARKET)) {
127                        String marketId = memory.getString(MemFlags.MEMORY_KEY_SOURCE_MARKET);
128                        MarketAPI market = Global.getSector().getEconomy().getMarket(marketId);
129                        if (market != null) {
130                                memoryMap.put(MemKeys.SOURCE_MARKET, market.getMemory());
131                        }
132                }
133                
134                updatePersonMemory();
135        }
136        
137        private void updatePersonMemory() {
138                PersonAPI person = dialog.getInteractionTarget().getActivePerson();
139//              if (person != null) {
140//                      memoryMap.put(MemKeys.PERSON, person.getMemory());
141//              } else {
142//                      memoryMap.remove(MemKeys.PERSON);
143//              }
144                if (person != null) {
145                        memory = person.getMemory();
146                        memoryMap.put(MemKeys.LOCAL, memory);
147                        memoryMap.put(MemKeys.PERSON_FACTION, person.getFaction().getMemory());
148                        memoryMap.put(MemKeys.ENTITY, dialog.getInteractionTarget().getMemory());
149                } else {
150                        memory = dialog.getInteractionTarget().getMemory();
151                        memoryMap.put(MemKeys.LOCAL, memory);
152                        memoryMap.remove(MemKeys.ENTITY);
153                        memoryMap.remove(MemKeys.PERSON_FACTION);
154                        
155                }
156        }
157        
158        
159        public void notifyActivePersonChanged() {
160                updatePersonMemory();
161        }
162        
163        public void setActiveMission(CampaignEventPlugin mission) {
164                if (mission == null) {
165                        memoryMap.remove(MemKeys.MISSION);
166                } else {
167                        MemoryAPI memory = mission.getMemory();
168                        if (memory != null) {
169                                memoryMap.put(MemKeys.MISSION, memory);
170                        } else {
171                                memoryMap.remove(MemKeys.MISSION);
172                        }
173                }
174        }
175        
176        
177        public boolean fireAll(String trigger) {
178                return FireAll.fire(null, dialog, memoryMap, trigger);
179        }
180        
181        public boolean fireBest(String trigger) {
182                return FireBest.fire(null, dialog, memoryMap, trigger);
183        }
184        
185        public void backFromEngagement(EngagementResultAPI result) {
186                // no combat here, so this won't get called
187        }
188        
189        public void optionSelected(String text, Object optionData) {
190                if (optionData == null || !(optionData instanceof String)) return;
191                
192                String optionId = (String) optionData;
193                
194                if (text != null) {
195                        //textPanel.addParagraph(text, Global.getSettings().getColor("buttonText"));
196                        dialog.addOptionSelectedText(optionData);
197                }
198                
199                if (optionId == FAILSAFE_LEAVE) {
200                        new DismissDialog().execute(null, dialog, null, memoryMap);
201                        return;
202                }
203                
204                if (optionId == DumpMemory.OPTION_ID) {
205                        new DumpMemory().execute(null, dialog, null, memoryMap);
206                        return;
207                } else if (DevMenuOptions.isDevOption(optionData)) {
208                        DevMenuOptions.execute(dialog, (String) optionData);
209                        return;
210                }
211                
212                memory.set("$option", optionId);
213                memory.expire("$option", 0);
214
215                boolean foundRule = fireBest("DialogOptionSelected");
216                if (!foundRule && !dialog.isCurrentOptionHadAConfirm()) {
217                        textPanel.addPara("ERROR: no rule found for option " + optionId + 
218                                        ", adding a failsafe option to exit dialog.", Misc.getNegativeHighlightColor());
219                        textPanel.addPara("Note: this may break any mission interaction in the current dialog, "
220                                                          + "it's recommended that you reload an earlier save if you use this option.");
221                        textPanel.highlightInLastPara(Misc.getNegativeHighlightColor(), "recommended that you reload an earlier save");
222                        options.addOption("Exit dialog", FAILSAFE_LEAVE);
223                }
224                
225        }
226        
227        
228        private String lastOptionMousedOver = null;
229        private Map<String, MemoryAPI> memoryMap;
230        public void optionMousedOver(String optionText, Object optionData) {
231
232        }
233        
234        public void advance(float amount) {
235//              if (Global.getSettings().isDevMode() && Keyboard.isKeyDown(Keyboard.KEY_F2)) {
236//                      new DumpMemory().execute(dialog, new ArrayList<Token>(), memoryMap);
237//              }
238        }
239        
240        private void addText(String text) {
241                if (text == null || text.isEmpty()) return;
242                
243                textPanel.addParagraph(text);
244        }
245        
246        private void appendText(String text) {
247                textPanel.appendToLastParagraph(" " + text);
248        }
249        
250        public Object getContext() {
251                return null;
252        }
253
254        public Map<String, MemoryAPI> getMemoryMap() {
255                return memoryMap;
256        }
257        public Object getCustom1() {
258                return custom1;
259        }
260        public void setCustom1(Object custom1) {
261                this.custom1 = custom1;
262        }
263        public Object getCustom2() {
264                return custom2;
265        }
266        public void setCustom2(Object custom2) {
267                this.custom2 = custom2;
268        }
269        public Object getCustom3() {
270                return custom3;
271        }
272        public void setCustom3(Object custom3) {
273                this.custom3 = custom3;
274        }
275        
276}
277
278
279