001package com.fs.starfarer.api.impl.campaign.econ;
002
003import java.awt.Color;
004import java.util.ArrayList;
005import java.util.List;
006import java.util.Map;
007
008import com.fs.starfarer.api.Global;
009import com.fs.starfarer.api.campaign.econ.CommodityOnMarketAPI;
010import com.fs.starfarer.api.campaign.econ.MarketAPI;
011import com.fs.starfarer.api.campaign.econ.MarketConditionAPI;
012import com.fs.starfarer.api.combat.MutableStatWithTempMods;
013import com.fs.starfarer.api.combat.MutableStat.StatMod;
014import com.fs.starfarer.api.impl.campaign.ids.Conditions;
015import com.fs.starfarer.api.ui.TooltipMakerAPI;
016import com.fs.starfarer.api.util.CountingMap;
017import com.fs.starfarer.api.util.Misc;
018
019public class ShippingDisruption extends BaseMarketConditionPlugin {
020        
021        public static String COMMODITY_LOSS_PREFIX = "sh_loss";
022        public static float ACCESS_LOSS_DURATION = 90f;
023        
024        public static float ACCESS_PER_UNITS_LOST = 0.1f; // accessibility penalty per marketSize units lost
025        
026        
027        public static float getPenaltyForShippingLost(float marketSize, float unitsLost) {
028                float result = Math.round(unitsLost / marketSize * ACCESS_PER_UNITS_LOST  * 100f) / 100f;
029                if (result == 0) result = 0.01f;
030                return result;
031        }
032        
033        public static ShippingDisruption getDisruption(MarketAPI market) {
034                MarketConditionAPI mc = market.getCondition(Conditions.SHIPPING_DISRUPTION);
035                if (mc == null) {
036                        String id = market.addCondition(Conditions.SHIPPING_DISRUPTION);
037                        mc = market.getSpecificCondition(id);
038                        //mc.setFromEvent(true);
039                }
040                return (ShippingDisruption) mc.getPlugin();
041        }
042        
043        protected MutableStatWithTempMods shippingLost = new MutableStatWithTempMods(0f); 
044        
045        protected float disruptionTimeLeft = 0f;
046        public ShippingDisruption() {
047        }
048        
049        /**
050         * "units" is the largest number of econ-units of a commodity being carried by a trade fleet. 
051         * For example, 5 food, 3 organics, 2 fuel = 5 units = approximate "size" of that trade fleet, in economy terms.
052         * @param units
053         */
054        public void addShippingLost(float units) {
055                shippingLost.addTemporaryModFlat(ACCESS_LOSS_DURATION, getModId() + Misc.genUID(), units);
056                updatePenaltyValue();
057        }
058
059        protected void updatePenaltyValue() {
060                unapply(getModId());
061                apply(getModId());
062        }
063
064        public float getDisruptionTimeLeft() {
065                return disruptionTimeLeft;
066        }
067
068        public void setDisruptionTimeLeft(float disruptionTimeLeft) {
069                this.disruptionTimeLeft = disruptionTimeLeft;
070        }
071
072        public void notifyDisrupted(float duration) {
073                disruptionTimeLeft = Math.max(disruptionTimeLeft, duration);
074        }
075        public void apply(String id) {
076                float penalty = getPenaltyForShippingLost(market.getSize(), shippingLost.getModifiedValue());
077                String name = "Trade fleets lost";
078                market.getAccessibilityMod().modifyFlat(id, -penalty, name);
079                
080                if (market.isPlayerOwned()) {
081                        for (CommodityOnMarketAPI com : market.getCommoditiesCopy()) {
082                                List<String> unmodify = new ArrayList<String>();
083                                if (com.getMaxSupply() >= com.getAvailable() + 1) {
084                                        for (String key : com.getAvailableStat().getFlatMods().keySet()) {
085                                                StatMod mod = com.getAvailableStat().getFlatStatMod(key);
086                                                int val = (int)Math.round(Math.abs(mod.value));
087                                                if (key.startsWith(COMMODITY_LOSS_PREFIX) && val != 0) {
088                                                        unmodify.add(mod.source);
089                                                }
090                                        }
091                                }
092                                for (String modId : unmodify) {
093                                        com.getAvailableStat().unmodifyFlat(modId);
094                                }
095                        }
096                }
097        }
098
099        public void unapply(String id) {
100                market.getAccessibilityMod().unmodifyFlat(id);
101        }
102        
103        
104        @Override
105        public void advance(float amount) {
106                float days = Global.getSector().getClock().convertToDays(amount);
107                shippingLost.advance(days);
108                updatePenaltyValue();
109                
110                disruptionTimeLeft -= days;
111                if (disruptionTimeLeft <= 0) {
112                        disruptionTimeLeft = 0;
113                        if (shippingLost.isUnmodified()) {
114                                market.removeSpecificCondition(condition.getIdForPluginModifications());
115                        }
116                }
117        }
118
119        public Map<String, String> getTokenReplacements() {
120                return super.getTokenReplacements();
121                //return event.getTokenReplacements();
122        }
123
124        @Override
125        public String[] getHighlights() {
126                return super.getHighlights();
127                //return event.getHighlights("report_td");
128        }
129        
130        @Override
131        public boolean isTransient() {
132                return false;
133        }
134
135        @Override
136        public void createTooltip(TooltipMakerAPI tooltip, boolean expanded) {
137                tooltip.addTitle("Shipping Disruption");
138                
139                int loss = shippingLost.getModifiedInt();
140                
141                int penalty = (int)Math.round(getPenaltyForShippingLost(market.getSize(), shippingLost.getModifiedValue()) * 100f);
142                
143                Color h = Misc.getHighlightColor();
144                Color n = Misc.getNegativeHighlightColor();
145                
146                float pad = 3f;
147                float small = 5f;
148                float opad = 10f;
149                
150                //tooltip.addPara("Loss: %s, Accesibility penalty: %s", pad, h, "" + loss, "" + penalty);
151                if (penalty > 0) {
152                        tooltip.addPara("Trade fleets launched from " + market.getName() + " have suffered losses, " +
153                                        "resulting in a temporary accessibility penalty of %s.", opad, h, "" + penalty + "%");
154                }
155                
156                CountingMap<CommodityOnMarketAPI> losses = new CountingMap<CommodityOnMarketAPI>();
157                
158                for (CommodityOnMarketAPI com : market.getCommoditiesCopy()) {
159                        for (String key : com.getAvailableStat().getFlatMods().keySet()) {
160                                StatMod mod = com.getAvailableStat().getFlatStatMod(key);
161                                
162                                int val = (int)Math.round(Math.abs(mod.value));
163                                if (key.startsWith(COMMODITY_LOSS_PREFIX) && val != 0) {
164                                        losses.add(com, val); 
165                                }
166                        }
167                }
168                
169                if (!losses.isEmpty()) {
170                        tooltip.addPara("The local availability of some commodities has been reduced by trade fleet losses. " +
171                                        "Provided no further losses occur, commodity availability should return to normal levels within at most three months.", opad);
172                        tooltip.beginGridFlipped(400, 1, 30, opad);
173                        int j = 0;
174                        for (CommodityOnMarketAPI com : losses.keySet()) {
175                                tooltip.addToGrid(0, j++, com.getCommodity().getName(), 
176                                                                                "-" + losses.getCount(com), h);
177                        }
178                        tooltip.addGrid(pad);
179                }
180                
181                //tooltip.addPara(com.getCommodity().getName() + ": %s", pad, h, "" + (int) mod.value);
182        }
183
184        @Override
185        public float getTooltipWidth() {
186                return super.getTooltipWidth();
187        }
188
189        @Override
190        public boolean hasCustomTooltip() {
191                return true;
192        }
193
194        @Override
195        public boolean isTooltipExpandable() {
196                return super.isTooltipExpandable();
197        }
198        
199
200}
201
202
203
204
205