001package com.fs.starfarer.api.impl.combat.dweller;
002
003import org.lwjgl.util.vector.Vector2f;
004
005import com.fs.starfarer.api.Global;
006import com.fs.starfarer.api.campaign.CargoAPI.CargoItemType;
007import com.fs.starfarer.api.campaign.CargoStackAPI;
008import com.fs.starfarer.api.campaign.SpecialItemData;
009import com.fs.starfarer.api.combat.CombatEngineAPI;
010import com.fs.starfarer.api.combat.MutableShipStatsAPI;
011import com.fs.starfarer.api.combat.ShipAPI;
012import com.fs.starfarer.api.combat.ShipAPI.HullSize;
013import com.fs.starfarer.api.combat.ShipCommand;
014import com.fs.starfarer.api.impl.campaign.ids.Items;
015import com.fs.starfarer.api.impl.combat.threat.RoilingSwarmEffect.SwarmMember;
016import com.fs.starfarer.api.util.IntervalUtil;
017import com.fs.starfarer.api.util.Misc;
018
019/**
020 * For non-dweller ships with a sort-of shroud.
021 */
022public class ShroudedMantleHullmod extends HumanShipShroudedHullmod {
023        
024        public static float HEAL_MULT = 0.5f;
025        
026        public static float LUNGE_COOLDOWN = 10f;
027        public static float LUNGE_DUR = 4f;
028        public static float LUNGE_SPEED = 250f;
029        
030        @Override
031        public void applyEffectsBeforeShipCreation(HullSize hullSize, MutableShipStatsAPI stats, String id) {
032                super.applyEffectsBeforeShipCreation(hullSize, stats, id);
033                
034                boolean sMod = isSMod(stats);
035                if (sMod) {
036                        stats.getDynamic().getMod(AssayingRiftEffect.HUNGERING_RIFT_HEAL_MOD_HUMAN_SHIPS).modifyFlat(id, HEAL_MULT);
037                }
038        }
039
040        public String getDescriptionParam(int index, HullSize hullSize) {
041                if (index == 0) return "" + (int) CREW_CASUALTIES + "%";
042                return null;
043        }
044        
045        @Override
046        public String getSModDescriptionParam(int index, HullSize hullSize, ShipAPI ship) {
047                if (index == 0) return "" + (int) Math.round(HEAL_MULT * 100f) + "%";
048                return null;
049        }       
050        
051        @Override
052        public CargoStackAPI getRequiredItem() {
053                return Global.getSettings().createCargoStack(CargoItemType.SPECIAL, 
054                                                                new SpecialItemData(Items.SHROUDED_MANTLE, null), null);
055        }
056
057        
058        public static String DATA_KEY = "core_ShroudedMantleHullmod_data_key";
059        public static class ShroudedMantleHullmodData {
060                IntervalUtil interval = new IntervalUtil(0.75f, 1.25f);
061                float hullAtPrevLunge = 1f;
062                float cooldown = 0f;
063                boolean lunging = false;
064                Vector2f lungeDest;
065                float lungeElapsed = 0f;
066                boolean fadedFlash = false;
067        }
068        
069        @Override
070        public void advanceInCombat(ShipAPI ship, float amount) {
071                super.advanceInCombat(ship, amount);
072                
073                if (!ship.isAlive()) return;
074                if (amount <= 0f) return;
075                
076                CombatEngineAPI engine = Global.getCombatEngine();
077                
078                String key = DATA_KEY + "_" + ship.getId();
079                ShroudedMantleHullmodData data = (ShroudedMantleHullmodData) engine.getCustomData().get(key);
080                if (data == null) {
081                        data = new ShroudedMantleHullmodData();
082                        engine.getCustomData().put(key, data);
083                }
084                
085                boolean forceUse = false;
086                
087//              if (Keyboard.isKeyDown(Keyboard.KEY_K)) {
088//                      forceUse = true;
089//                      data.cooldown = 0f;
090//              }
091                
092                if (data.cooldown > 0) {
093                        data.cooldown -= amount;
094                        if (data.cooldown < 0) data.cooldown = 0;
095                        if (data.cooldown > 0) {
096                                return;
097                        }
098                }
099
100                if (ship.getFluxLevel() > 0.95f && ship.getHullLevel() > 0.25f && 
101                                ship.getShield() != null && ship.getShield().isOn()) {
102                        forceUse = true;
103                }
104                if (ship.getFluxTracker().isOverloaded()) {
105                        forceUse = true;
106                }
107                
108                data.interval.advance(amount * 2f);
109                if ((data.interval.intervalElapsed() || forceUse) && !data.lunging) {
110                        float hull = ship.getHullLevel();
111                        data.hullAtPrevLunge = Math.max(hull, data.hullAtPrevLunge);
112                        if (hull <= data.hullAtPrevLunge - ConvulsiveLungeSystemAI.HULL_LOSS_FOR_PULLBACK || forceUse) {
113                                data.lunging = true;
114                                data.lungeElapsed = 0f;
115                                data.lungeDest = null;
116                                data.fadedFlash = false;
117                                data.hullAtPrevLunge = hull;
118                        }
119                }
120                
121                doLunge(data, ship, amount);
122        }
123        
124        protected void doLunge(ShroudedMantleHullmodData data, ShipAPI ship, float amount) {
125                if (!data.lunging) return;
126                //if (ship.getFluxTracker().isOverloadedOrVenting()) return;
127                
128                DwellerShroud shroud = DwellerShroud.getShroudFor(ship);
129                
130                if (data.lungeElapsed < 1f || data.lungeDest == null) {
131                        if (data.lungeDest == null) {
132                                data.lungeDest = Misc.getUnitVectorAtDegreeAngle(Global.getSettings().getSafeMovementDir(ship));
133                                data.lungeDest.scale(ConvulsiveLungeSystemScript.PULL_DIST);
134                                Vector2f.add(data.lungeDest, ship.getLocation(), data.lungeDest);
135                        }
136                        
137                        if (data.lungeDest != null) {
138                                if (shroud != null) {
139                                        Vector2f dir = Misc.getUnitVector(ship.getLocation(), data.lungeDest);
140                                        float accel = ConvulsiveLungeSystemScript.PARTICLE_WINDUP_ACCEL * amount * 1f;
141                                        if (!ship.isFrigate()) accel *= 2f;
142                                        boolean affect = true;
143                                        for (SwarmMember p : shroud.getMembers()) {
144                                                if (affect) {
145                                                        p.vel.x += dir.x * accel;
146                                                        p.vel.y += dir.y * accel;
147                                                }
148                                                if (ship.isFrigate()) {
149                                                        affect = !affect;
150                                                }
151                                        }
152                                }
153                        }
154                } else if (data.lungeDest != null) {
155                        Vector2f dir = Misc.getUnitVectorAtDegreeAngle(Misc.getAngleInDegrees(ship.getLocation(), data.lungeDest));
156                        
157                        boolean slowdown = data.lungeElapsed > LUNGE_DUR - 1f;
158                        if (slowdown) {
159                                dir = Misc.normalise(new Vector2f(ship.getVelocity()));
160                                dir.negate();
161                        }
162                        
163                        if (!data.fadedFlash) {
164                                if (shroud != null) {
165                                        for (SwarmMember p : shroud.getMembers()) {
166                                                if (p.flash != null) {
167                                                        p.flash.fadeOut();
168                                                }
169                                        }
170                                }
171                                data.fadedFlash = true;
172                        }
173                        
174                        Vector2f loc = ship.getLocation();
175                        float dist = Misc.getDistance(loc, data.lungeDest);
176                        
177                        //Vector2f perp = new Vector2f(-dir.y, dir.x);
178                        
179                        float friction = ConvulsiveLungeSystemScript.FRICTION;
180                        float k = ConvulsiveLungeSystemScript.SPRING_CONSTANT;
181                        float freeLength = 0f;
182                        float stretch = dist - freeLength;
183
184                        float forceMag = k * Math.abs(stretch);
185                        
186                        float speedInDir = Vector2f.dot(dir, ship.getVelocity());
187                        if (speedInDir > LUNGE_SPEED) {
188                                float mult = 1f - Math.min(1f, (speedInDir - LUNGE_SPEED) / 100f);
189                                forceMag *= mult;
190                        }
191                        
192                        
193                        float forceMagReduction = Math.min(Math.abs(forceMag), friction);
194                        forceMag -= forceMagReduction;
195                        friction -= forceMagReduction;
196                        
197                        Vector2f force = new Vector2f(dir);
198                        if (slowdown) {
199                                forceMag = ship.getVelocity().length() * 2f;
200                                force.scale(forceMag);
201                        } else {
202                                force.scale(forceMag * Math.signum(stretch));
203                        }
204                        
205                        Vector2f acc = new Vector2f(force);
206                        acc.scale(amount);
207                        Vector2f.add(ship.getVelocity(), acc, ship.getVelocity());
208                }
209                
210                ship.giveCommand(ShipCommand.DECELERATE, null, 0);
211                
212                data.lungeElapsed += amount;
213                if (data.lungeElapsed > LUNGE_DUR) {
214                        data.lunging = false;
215                        data.cooldown = LUNGE_COOLDOWN;
216                }
217        }
218        
219}
220
221
222
223
224
225
226
227
228
229
230
231
232
233