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