001package com.fs.starfarer.api.impl.campaign.missions;
002
003import java.awt.Color;
004import java.util.Map;
005
006import com.fs.starfarer.api.Global;
007import com.fs.starfarer.api.campaign.BattleAPI;
008import com.fs.starfarer.api.campaign.CampaignEventListener.FleetDespawnReason;
009import com.fs.starfarer.api.campaign.CampaignFleetAPI;
010import com.fs.starfarer.api.campaign.FactionAPI;
011import com.fs.starfarer.api.campaign.InteractionDialogAPI;
012import com.fs.starfarer.api.campaign.ReputationActionResponsePlugin.ReputationAdjustmentResult;
013import com.fs.starfarer.api.campaign.SectorEntityToken;
014import com.fs.starfarer.api.campaign.StarSystemAPI;
015import com.fs.starfarer.api.campaign.econ.MarketAPI;
016import com.fs.starfarer.api.campaign.listeners.FleetEventListener;
017import com.fs.starfarer.api.campaign.rules.MemoryAPI;
018import com.fs.starfarer.api.characters.PersonAPI;
019import com.fs.starfarer.api.fleet.FleetMemberAPI;
020import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin;
021import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.MissionCompletionRep;
022import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActionEnvelope;
023import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepActions;
024import com.fs.starfarer.api.impl.campaign.CoreReputationPlugin.RepRewards;
025import com.fs.starfarer.api.impl.campaign.ids.Factions;
026import com.fs.starfarer.api.impl.campaign.ids.FleetTypes;
027import com.fs.starfarer.api.impl.campaign.ids.Ranks;
028import com.fs.starfarer.api.impl.campaign.ids.Tags;
029import com.fs.starfarer.api.impl.campaign.intel.bases.PirateBaseIntel;
030import com.fs.starfarer.api.impl.campaign.missions.hub.HubMissionWithBarEvent;
031import com.fs.starfarer.api.impl.campaign.missions.hub.ReqMode;
032import com.fs.starfarer.api.ui.SectorMapAPI;
033import com.fs.starfarer.api.ui.TooltipMakerAPI;
034import com.fs.starfarer.api.util.Misc;
035
036public class PirateSystemBounty extends HubMissionWithBarEvent implements FleetEventListener {
037
038        public static float BOUNTY_DAYS = 120f;
039        public static float BASE_BOUNTY = 1000f;
040        //public static float VS_STATION_BONUS = 50000f;
041        
042        public static class BountyResult {
043                public int payment;
044                public float fraction;
045                public ReputationAdjustmentResult repFaction;
046                public ReputationAdjustmentResult repPerson;
047                public BountyResult(int payment, float fraction, ReputationAdjustmentResult repPerson, ReputationAdjustmentResult repFaction) {
048                        this.payment = payment;
049                        this.fraction = fraction;
050                        this.repFaction = repFaction;
051                        this.repPerson = repPerson;
052                }
053                
054        }
055        
056        
057        public static enum Stage {
058                BOUNTY,
059                DONE,
060        }
061
062        protected StarSystemAPI system;
063        protected MarketAPI market;
064        protected FactionAPI faction;
065        protected FactionAPI enemy;
066        protected int baseBounty;
067        protected BountyResult latestResult;
068        
069        @Override
070        protected boolean create(MarketAPI createdAt, boolean barEvent) {
071                //genRandom = Misc.random;
072                
073                if (barEvent) {
074                        String post = null;
075                        setGiverRank(Ranks.CITIZEN);
076                        post = pickOne(Ranks.POST_TRADER, Ranks.POST_COMMODITIES_AGENT, 
077                                                   Ranks.POST_MERCHANT, Ranks.POST_INVESTOR, Ranks.POST_EXECUTIVE,
078                                                   Ranks.POST_PORTMASTER,
079                                                   Ranks.POST_SENIOR_EXECUTIVE);
080                        setGiverTags(Tags.CONTACT_TRADE);
081                        setGiverPost(post);
082                        if (post.equals(Ranks.POST_SENIOR_EXECUTIVE)) {
083                                setGiverImportance(pickHighImportance());
084                        } else {
085                                setGiverImportance(pickImportance());
086                                
087                        }
088                        findOrCreateGiver(createdAt, false, false);
089                        setGiverIsPotentialContactOnSuccess();
090                }
091                
092                PersonAPI person = getPerson();
093                if (person == null) return false;
094                
095                if (Factions.PIRATES.equals(person.getFaction().getId())) return false;
096                
097                if (!setPersonMissionRef(person, "$psb_ref")) {
098                        return false;
099                }
100                
101                //requireMarketFaction(Factions.PIRATES);
102                requireMarketFactionCustom(ReqMode.ALL, Factions.CUSTOM_MAKES_PIRATE_BASES);
103                requireMarketMemoryFlag(PirateBaseIntel.MEM_FLAG, true);
104                requireMarketFactionNot(person.getFaction().getId());
105                requireMarketHidden();
106                requireMarketIsMilitary();
107                preferMarketInDirectionOfOtherMissions();
108                market = pickMarket();
109                
110                if (market == null || market.getStarSystem() == null) return false;
111                if (!setMarketMissionRef(market, "$psb_ref")) { // just to avoid targeting the same base with multiple bounties
112                        return false;
113                }
114                
115                makeImportant(market, "$psb_target", Stage.BOUNTY);
116                
117                system = market.getStarSystem();
118
119                faction = person.getFaction();
120                enemy = market.getFaction();
121                
122                baseBounty = getRoundNumber(BASE_BOUNTY * getRewardMult()); 
123                
124                setStartingStage(Stage.BOUNTY);
125                setSuccessStage(Stage.DONE);
126                setNoAbandon();
127                setNoRepChanges();
128                
129                connectWithDaysElapsed(Stage.BOUNTY, Stage.DONE, BOUNTY_DAYS);
130                
131                addTag(Tags.INTEL_BOUNTY);
132                
133                
134                int numPirates = 2 + genRandom.nextInt(3);
135
136                FleetSize [] sizes = new FleetSize [] {
137                                FleetSize.MEDIUM,
138                                FleetSize.MEDIUM,
139                                FleetSize.LARGE,
140                                FleetSize.VERY_LARGE,
141                };
142                
143                for (int i = 0; i < numPirates; i++) {
144                        FleetSize size = sizes[i % sizes.length];
145                        beginWithinHyperspaceRangeTrigger(system, 3f, false, Stage.BOUNTY);
146                        triggerCreateFleet(size, FleetQuality.DEFAULT, market.getFactionId(), FleetTypes.PATROL_MEDIUM, system);
147                        triggerAutoAdjustFleetStrengthMajor();
148                        triggerSetPirateFleet();
149                        triggerSpawnFleetNear(system.getCenter(), null, null);
150                        triggerOrderFleetPatrol(system, true, Tags.STATION, Tags.JUMP_POINT);
151                        endTrigger();
152                }
153                
154                return true;
155        }
156
157        protected void updateInteractionDataImpl() {
158                set("$psb_barEvent", isBarEvent());
159                set("$psb_manOrWoman", getPerson().getManOrWoman());
160                set("$psb_baseBounty", Misc.getWithDGS(baseBounty));
161                set("$psb_days", "" + (int) BOUNTY_DAYS);
162                set("$psb_systemName", system.getNameWithLowercaseType());
163                set("$psb_systemNameShort", system.getNameWithLowercaseTypeShort());
164                set("$psb_baseName", market.getName());
165                set("$psb_dist", getDistanceLY(market));
166        }
167        
168        @Override
169        public void addDescriptionForCurrentStage(TooltipMakerAPI info, float width, float height) {
170                float opad = 10f;
171                float pad = 3f;
172                Color h = Misc.getHighlightColor();
173                Color tc = getBulletColorForMode(ListInfoMode.IN_DESC);
174                if (currentStage == Stage.BOUNTY) {
175                        float elapsed = getElapsedInCurrentStage();
176                        int d = (int) Math.round(BOUNTY_DAYS - elapsed);
177                        PersonAPI person = getPerson();
178                        
179                        String locStr = "in or near the " + market.getStarSystem().getNameWithLowercaseType();
180                        
181                        info.addPara("Applies to all %s fleets " + locStr + ", which is home to " + market.getName() + ", a pirate base.",
182                                        opad, enemy.getBaseUIColor(), enemy.getPersonNamePrefix());
183
184                        if (isEnding()) {
185                                info.addPara("This bounty is no longer on offer.", opad);
186                                return;
187                        }
188                        
189                        bullet(info);
190                        info.addPara("%s base reward per frigate", opad, tc, h, Misc.getDGSCredits(baseBounty));
191                        addDays(info, "remaining", d, tc);
192                        unindent(info);
193                        
194                        info.addPara("Payment depends on the number and size of ships destroyed. " +
195                                                 "Standing with " + faction.getDisplayNameWithArticle() + ", as well as " +
196                                                 "with " + person.getNameString() + ", will improve.",
197                                                 opad);
198                        
199                } else if (currentStage == Stage.DONE) {
200                        info.addPara("This bounty is no longer on offer.", opad);
201                }
202                
203                if (latestResult != null) {
204                        //Color color = faction.getBaseUIColor();
205                        //Color dark = faction.getDarkUIColor();
206                        //info.addSectionHeading("Most Recent Reward", color, dark, Alignment.MID, opad);
207                        info.addPara("Most recent bounty payment:", opad);
208                        bullet(info);
209                        info.addPara("%s received", pad, tc, h, Misc.getDGSCredits(latestResult.payment));
210                        if (Math.round(latestResult.fraction * 100f) < 100f) {
211                                info.addPara("%s share based on damage dealt", 0f, tc, h, 
212                                                "" + (int) Math.round(latestResult.fraction * 100f) + "%");
213                        }
214                        if (latestResult.repPerson != null) {
215                                CoreReputationPlugin.addAdjustmentMessage(latestResult.repPerson.delta, null, getPerson(), 
216                                                                                                                  null, null, info, tc, false, 0f);
217                        }
218                        if (latestResult.repFaction != null) {
219                                CoreReputationPlugin.addAdjustmentMessage(latestResult.repFaction.delta, faction, null, 
220                                                                                                                  null, null, info, tc, false, 0f);
221                        }
222                        unindent(info);
223                }
224        }
225
226        @Override
227        public boolean addNextStepText(TooltipMakerAPI info, Color tc, float pad) {
228                Color h = Misc.getHighlightColor();
229                
230                boolean isUpdate = getListInfoParam() != null;
231                if (isUpdate && latestResult == getListInfoParam()) {
232                        info.addPara("%s received", pad, tc, h, Misc.getDGSCredits(latestResult.payment));
233                        if (Math.round(latestResult.fraction * 100f) < 100f) {
234                                info.addPara("%s share based on damage dealt", 0f, tc, h, 
235                                                "" + (int) Math.round(latestResult.fraction * 100f) + "%");
236                        }
237                        if (latestResult.repPerson != null) {
238                                CoreReputationPlugin.addAdjustmentMessage(latestResult.repPerson.delta, null, getPerson(), 
239                                                                                                                null, null, info, tc, isUpdate, 0f);
240                        }
241                        if (latestResult.repFaction != null) {
242                                CoreReputationPlugin.addAdjustmentMessage(latestResult.repFaction.delta, faction, null, 
243                                                                                                                null, null, info, tc, isUpdate, 0f);
244                        }
245                        return true;
246                }
247                
248                if (currentStage == Stage.BOUNTY) {
249                        float elapsed = getElapsedInCurrentStage();
250                        int d = (int) Math.round(BOUNTY_DAYS - elapsed);
251                        
252                        info.addPara("%s base reward per frigate", pad, tc, h, Misc.getDGSCredits(baseBounty));
253                        addDays(info, "remaining", d, tc);
254                        return true;
255                } else if (currentStage == Stage.DONE) {
256                        return false;
257                }
258                return false;
259        }
260        
261        public String getPostfixForState() {
262                if (currentStage == Stage.DONE) return " - Over";
263                return super.getPostfixForState();
264        }
265
266        @Override
267        public String getBaseName() {
268                return "Pirate Fleet Bounty";
269        }
270        
271        protected String getMissionTypeNoun() {
272                return "bounty";
273        }
274        
275
276        @Override
277        public SectorEntityToken getMapLocation(SectorMapAPI map) {
278                return getMapLocationFor(market.getPrimaryEntity());
279        }
280        
281        @Override
282        public void acceptImpl(InteractionDialogAPI dialog, Map<String, MemoryAPI> memoryMap) {
283                Global.getSector().getListenerManager().addListener(this);
284//              AddRemoveCommodity.addCreditsLossText(cost, dialog.getTextPanel());
285//              Global.getSector().getPlayerFleet().getCargo().getCredits().subtract(cost);
286//              adjustRep(dialog.getTextPanel(), null, RepActions.MISSION_SUCCESS);
287//              addPotentialContacts(dialog);
288        }
289        
290        @Override
291        protected void notifyEnding() {
292                Global.getSector().getListenerManager().removeListener(this);
293                super.notifyEnding();
294        }
295
296        public void reportFleetDespawnedToListener(CampaignFleetAPI fleet, FleetDespawnReason reason, Object param) {
297        }
298
299        public void reportBattleOccurred(CampaignFleetAPI fleet, CampaignFleetAPI primaryWinner, BattleAPI battle) {
300                if (isEnded() || isEnding()) return;
301                
302                if (!battle.isPlayerInvolved()) return;
303                
304                if (!Misc.isNear(primaryWinner, market.getLocationInHyperspace())) return;
305                
306                int payment = 0;
307                float fpDestroyed = 0;
308                for (CampaignFleetAPI otherFleet : battle.getNonPlayerSideSnapshot()) {
309                        if (enemy != otherFleet.getFaction()) continue;
310                        
311                        float bounty = 0;
312                        for (FleetMemberAPI loss : Misc.getSnapshotMembersLost(otherFleet)) {
313                                float mult = Misc.getSizeNum(loss.getHullSpec().getHullSize());
314                                bounty += mult * baseBounty;
315                                fpDestroyed += loss.getFleetPointCost();
316                        }
317                        
318                        payment += (int) (bounty * battle.getPlayerInvolvementFraction());
319                }
320        
321                if (payment > 0) {
322                        Global.getSector().getPlayerFleet().getCargo().getCredits().add(payment);
323                        
324                        float repFP = (int)(fpDestroyed * battle.getPlayerInvolvementFraction());
325                        
326                        float fDelta = 0f;
327                        float pDelta = 0f;
328                        if (repFP < 30) {
329                                fDelta = RepRewards.TINY;
330                                pDelta = RepRewards.TINY;
331                        } else if (repFP < 70) {
332                                fDelta = RepRewards.SMALL;
333                                pDelta = RepRewards.SMALL;
334                        } else {
335                                fDelta = RepRewards.SMALL;
336                                pDelta = RepRewards.MEDIUM;
337                        }
338                        
339                        MissionCompletionRep completionRepPerson = new MissionCompletionRep(
340                                                                                        pDelta, getRewardLimitPerson(), 0, null);
341                        MissionCompletionRep completionRepFaction = new MissionCompletionRep(
342                                                                                        fDelta, getRewardLimitFaction(), 0, null);
343                        
344                        boolean addContacts = latestResult == null;
345                        latestResult = new BountyResult(payment, battle.getPlayerInvolvementFraction(), null, null);
346                        if (pDelta != 0) {
347                                ReputationAdjustmentResult rep = Global.getSector().adjustPlayerReputation(
348                                                new RepActionEnvelope(RepActions.MISSION_SUCCESS, completionRepPerson,
349                                                                null, true, false), 
350                                                                getPerson());
351                                latestResult.repPerson = rep;
352                        }
353
354                        if (completionRepFaction.successDelta != 0) {
355                                ReputationAdjustmentResult rep = Global.getSector().adjustPlayerReputation(
356                                                new RepActionEnvelope(RepActions.MISSION_SUCCESS, completionRepFaction,
357                                                                null, true, false), 
358                                                                getPerson().getFaction().getId());
359                                latestResult.repFaction = rep;
360                        }
361                        
362                        sendUpdateIfPlayerHasIntel(latestResult, false);
363                        
364                        if (addContacts) {
365                                addPotentialContacts(null);
366                        }
367                }
368        }
369        
370}
371
372
373
374
375
376
377
378
379
380
381