001package com.fs.starfarer.api.impl.campaign.missions;
002
003import java.awt.Color;
004import java.util.Map;
005
006import org.lwjgl.util.vector.Vector2f;
007
008import com.fs.starfarer.api.Global;
009import com.fs.starfarer.api.campaign.InteractionDialogAPI;
010import com.fs.starfarer.api.campaign.PersonImportance;
011import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI;
012import com.fs.starfarer.api.campaign.econ.CommoditySpecAPI;
013import com.fs.starfarer.api.campaign.econ.MarketAPI;
014import com.fs.starfarer.api.campaign.rules.MemoryAPI;
015import com.fs.starfarer.api.characters.PersonAPI;
016import com.fs.starfarer.api.impl.campaign.ids.Commodities;
017import com.fs.starfarer.api.impl.campaign.ids.Factions;
018import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
019import com.fs.starfarer.api.impl.campaign.ids.Ranks;
020import com.fs.starfarer.api.impl.campaign.ids.Tags;
021import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithBarEvent;
022import com.fs.starfarer.api.impl.campaign.missions.hub.ReqMode;
023import com.fs.starfarer.api.ui.TooltipMakerAPI;
024import com.fs.starfarer.api.util.Misc;
025
026public class ProcurementMission extends HubMissionWithBarEvent {
027
028        public static float PROB_COMPLICATIONS = 0.5f;
029        
030        public static float MISSION_DAYS = 60f;
031        
032        public static float MIN_BASE_VALUE = 10000;
033        public static float MAX_BASE_VALUE = 100000;
034        public static float BASE_PRICE_MULT = 1.5f;
035        
036        public static float PROB_REMOTE = 0.5f;
037        
038        public static float PROB_BAR_UNDERWORLD = 0.25f;
039        public static float PROB_ILLEGAL_IF_UNDERWORLD = 0.5f;
040        public static float ILLEGAL_QUANTITY_MULT = 0.5f;
041        
042        
043        public static enum Stage {
044                TALK_TO_PERSON,
045                COMPLETED,
046                FAILED,
047        }
048        public static enum Variation {
049                LOCAL,
050                REMOTE,
051        }
052        
053        protected String commodityId;
054        protected int quantity;
055        protected int pricePerUnit;
056        
057        protected Variation variation;
058        protected MarketAPI deliveryMarket;
059        protected PersonAPI deliveryContact;
060        
061        
062        @Override
063        protected boolean create(MarketAPI createdAt, boolean barEvent) {
064                //genRandom = Misc.random;
065                if (barEvent) {
066                        if (rollProbability(PROB_BAR_UNDERWORLD)) {
067                                setGiverRank(Ranks.CITIZEN);
068                                setGiverPost(pickOne(Ranks.POST_SMUGGLER, Ranks.POST_GANGSTER, 
069                                                                         Ranks.POST_FENCE, Ranks.POST_CRIMINAL));
070                                setGiverImportance(pickImportance());
071                                setGiverTags(Tags.CONTACT_UNDERWORLD);
072                                setGiverFaction(Factions.PIRATES);
073                        } else {
074                                setGiverRank(Ranks.CITIZEN);
075                                String post = pickOne(Ranks.POST_TRADER, Ranks.POST_COMMODITIES_AGENT, 
076                                                                          Ranks.POST_MERCHANT, Ranks.POST_INVESTOR, 
077                                                                          Ranks.POST_EXECUTIVE, Ranks.POST_SENIOR_EXECUTIVE, 
078                                                                          Ranks.POST_PORTMASTER);
079                                setGiverPost(post);
080                                if (post.equals(Ranks.POST_SENIOR_EXECUTIVE)) {
081                                        setGiverImportance(pickHighImportance());
082                                } else {
083                                        setGiverImportance(pickImportance());
084                                }
085                                setGiverTags(Tags.CONTACT_TRADE);
086                        }
087                        findOrCreateGiver(createdAt, false, false);
088                }
089                
090                
091                PersonAPI person = getPerson();
092                if (person == null) return false;
093                MarketAPI market = person.getMarket();
094                if (market == null) return false;
095                
096                if (!setPersonMissionRef(person, "$proCom_ref")) {
097                        return false;
098                }
099                
100                if (barEvent) {
101                        setGiverIsPotentialContactOnSuccess();
102                }
103                
104                PersonImportance importance = person.getImportance();
105                boolean canOfferRemote = importance.ordinal() >= PersonImportance.MEDIUM.ordinal();
106                boolean preferExpensive = getQuality() >= PersonImportance.HIGH.getValue();
107                variation = Variation.LOCAL;
108                if (canOfferRemote && rollProbability(PROB_REMOTE)) {
109                        variation = Variation.REMOTE;
110                }
111                if (CheapCommodityMission.SAME_CONTACT_DEBUG) {
112                        variation = Variation.REMOTE;
113                }
114
115                CommodityOnMarketAPI com = null;
116                if (variation == Variation.LOCAL) {
117                        requireMarketIs(market);
118                        requireCommodityIsNotPersonnel();
119                        if (person.hasTag(Tags.CONTACT_UNDERWORLD) && rollProbability(PROB_ILLEGAL_IF_UNDERWORLD)) {
120                                preferCommodityIllegal();
121                        } else {
122                                requireCommodityLegal();
123                                requireCommodityDemandAtLeast(1);
124                        }
125                        requireCommoditySurplusAtMost(0);
126                        requireCommodityDeficitAtLeast(1);
127                        if (preferExpensive) {
128                                preferCommodityTags(ReqMode.ALL, Commodities.TAG_EXPENSIVE);
129                        }
130                        com = pickCommodity();
131                } 
132                
133                if (com == null && canOfferRemote) {
134                        variation = Variation.REMOTE;
135                }
136                
137                if (variation == Variation.REMOTE) {
138                        if (CheapCommodityMission.SAME_CONTACT_DEBUG) {
139                                requireMarketIs("jangala");
140                        } else {
141                                requireMarketIsNot(market);
142                        }
143                        requireMarketFaction(market.getFactionId());
144                        requireMarketNotHidden();
145                        requireMarketLocationNot(createdAt.getContainingLocation());
146                        requireCommodityIsNotPersonnel();
147                        if (person.hasTag(Tags.CONTACT_UNDERWORLD) && rollProbability(PROB_ILLEGAL_IF_UNDERWORLD)) {
148                                preferCommodityIllegal();
149                        } else {
150                                requireMarketFactionNotHostileTo(Factions.PLAYER);
151                                requireCommodityLegal();
152                                requireCommodityDemandAtLeast(1);
153                        }
154                        requireCommoditySurplusAtMost(0);
155                        requireCommodityDeficitAtLeast(1);
156                        if (preferExpensive) {
157                                preferCommodityTags(ReqMode.ALL, Commodities.TAG_EXPENSIVE);
158                        }
159                        com = pickCommodity();
160                }
161                
162                if (com == null) return false;
163                
164                deliveryMarket = com.getMarket();
165                
166                commodityId = com.getId();
167                
168                float value = MIN_BASE_VALUE + (MAX_BASE_VALUE - MIN_BASE_VALUE) * getQuality();
169                quantity = getRoundNumber(value / com.getCommodity().getBasePrice());
170                if (com.isIllegal()) {
171                        quantity *= ILLEGAL_QUANTITY_MULT;
172                }
173                
174                if (quantity < 10) quantity = 10;
175                pricePerUnit = (int) (com.getMarket().getSupplyPrice(com.getId(), quantity, true) / (float) quantity * 
176                                                          BASE_PRICE_MULT / getRewardMult());
177                pricePerUnit = getRoundNumber(pricePerUnit);
178                if (pricePerUnit < 2) pricePerUnit = 2;
179                
180                
181                if (variation == Variation.REMOTE) {
182                        if (com.isIllegal()) {
183                                deliveryContact = findOrCreateCriminal(deliveryMarket, true);
184                        } else {
185                                deliveryContact = findOrCreateTrader(deliveryMarket.getFactionId(), deliveryMarket, true);
186                        }
187                } else {
188                        deliveryContact = person;
189                }
190                ensurePersonIsInCommDirectory(deliveryMarket, deliveryContact);
191                //setPersonIsPotentialContactOnSuccess(deliveryContact);
192                
193                if (deliveryContact == null ||
194                                (variation == Variation.REMOTE && !setPersonMissionRef(deliveryContact, "$proCom_ref"))) {
195                        return false;
196                }
197                setPersonDoGenericPortAuthorityCheck(deliveryContact);
198                makeImportant(deliveryContact, "$proCom_needsCommodity", Stage.TALK_TO_PERSON);
199                
200                setStartingStage(Stage.TALK_TO_PERSON);
201                setSuccessStage(Stage.COMPLETED);
202                setFailureStage(Stage.FAILED);
203                
204                setStageOnMemoryFlag(Stage.COMPLETED, deliveryContact, "$proCom_completed");
205                setTimeLimit(Stage.FAILED, MISSION_DAYS, null);
206                
207                
208                if (getQuality() < 0.5f) {
209                        setRepFactionChangesVeryLow();
210                } else {
211                        setRepFactionChangesLow();
212                }
213                setRepPersonChangesMedium();
214                
215                return true;
216        }
217        
218        protected void updateInteractionDataImpl() {
219                set("$proCom_barEvent", isBarEvent());
220                
221                set("$proCom_commodityId", commodityId);
222                set("$proCom_underworld", getPerson().hasTag(Tags.CONTACT_UNDERWORLD));
223                set("$proCom_playerHasEnough", playerHasEnough(commodityId, quantity));
224                set("$proCom_commodityName", getSpec().getLowerCaseName());
225                set("$proCom_quantity", Misc.getWithDGS(quantity));
226                set("$proCom_pricePerUnit", Misc.getDGSCredits(pricePerUnit));
227                set("$proCom_totalPrice", Misc.getDGSCredits(pricePerUnit * quantity));
228                set("$proCom_variation", variation);
229                set("$proCom_manOrWoman", getPerson().getManOrWoman());
230                //set("$proCom_heOrShe", getPerson().getHeOrShe());
231                //set("$proCom_HeOrShe", getPerson().getHeOrShe().substring(0, 1).toUpperCase() + getPerson().getHeOrShe().substring(1));
232                
233                
234                if (variation == Variation.REMOTE) {
235                        set("$proCom_personName", deliveryContact.getNameString());
236                        set("$proCom_personPost", deliveryContact.getPost().toLowerCase());
237                        set("$proCom_PersonPost", Misc.ucFirst(deliveryContact.getPost()));
238                        set("$proCom_marketName", deliveryMarket.getName());
239                        set("$proCom_marketOnOrAt", deliveryMarket.getOnOrAt());
240                        set("$proCom_dist", getDistanceLY(deliveryMarket));
241                }
242        }
243        
244        @Override
245        public void addDescriptionForNonEndStage(TooltipMakerAPI info, float width, float height) {
246                float opad = 10f;
247                Color h = Misc.getHighlightColor();
248                if (currentStage == Stage.TALK_TO_PERSON) {
249                        TooltipMakerAPI text = info.beginImageWithText(deliveryContact.getPortraitSprite(), 48f);
250                        text.addPara("Deliver %s units of " + getSpec().getLowerCaseName() + " to " + deliveryContact.getNameString() + " " +
251                                        deliveryMarket.getOnOrAt() + " " + deliveryMarket.getName() + ". You will be paid %s per unit, or " + 
252                                        "%s total.", 0f, h,
253                                        Misc.getWithDGS(quantity),
254                                        Misc.getDGSCredits(pricePerUnit), 
255                                        Misc.getDGSCredits(pricePerUnit * quantity));
256                        info.addImageWithText(opad);
257                        if (playerHasEnough(commodityId, quantity)) {
258                                info.addPara("You have enough " + getSpec().getLowerCaseName() + " in your cargo holds to complete " +
259                                                "the delivery.", opad);
260                        } else {
261                                info.addPara("You do not have enough " + getSpec().getLowerCaseName() + " in your cargo holds to complete " +
262                                                "the delivery.", opad);
263                        }
264                }
265        }
266
267//      need to mention that need to acquire the item
268//      check whether player has enough and chance desc/bullet point depending?
269        
270        @Override
271        public boolean addNextStepText(TooltipMakerAPI info, Color tc, float pad) {
272                Color h = Misc.getHighlightColor();
273                if (currentStage == Stage.TALK_TO_PERSON) {
274                        if (playerHasEnough(commodityId, quantity)) {
275                                info.addPara("Go to " + deliveryMarket.getName() + " and contact " + deliveryContact.getNameString() + " to arrange delivery", tc, pad);
276                        } else {
277                                String name = getSpec().getLowerCaseName();
278                                info.addPara("Acquire %s units of " + name, pad, tc, h, "" + (int) quantity);                           
279                        }
280                        return true;
281                }
282                return false;
283        }       
284        
285        @Override
286        public String getBaseName() {
287                return getSpec().getName() + " Procurement";
288        }
289        
290        @Override
291        public void accept(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) {
292                super.accept(dialog, memoryMap);
293                
294                if (variation == Variation.REMOTE && rollProbability(PROB_COMPLICATIONS)) {
295                        DelayedFleetEncounter e = new DelayedFleetEncounter(genRandom, getMissionId());
296                        e.setDelay(10f);
297                        e.setLocationCoreOnly(true, Factions.PIRATES);
298                        e.setEncounterInHyper();
299                        e.beginCreate();
300                        e.triggerCreateFleet(FleetSize.MEDIUM, FleetQuality.DEFAULT, Factions.PIRATES, FleetTypes.PATROL_MEDIUM, new Vector2f());
301                        e.triggerSetAdjustStrengthBasedOnQuality(true, getQuality());
302                        e.triggerSetStandardAggroPirateFlags();
303                        e.triggerSetStandardAggroInterceptFlags();
304                        e.triggerSetFleetMemoryValue("$proCom_commodityName", getSpec().getLowerCaseName());
305                        e.triggerSetFleetGenericHailPermanent("PROCOMPirateHail");
306                        e.endCreate();
307                }
308        }
309        
310        
311        
312        protected transient CommoditySpecAPI spec;
313        protected CommoditySpecAPI getSpec() {
314                if (spec == null) {
315                        spec = Global.getSettings().getCommoditySpec(commodityId);
316                }
317                return spec;
318        }
319}
320