001package com.fs.starfarer.api.impl.combat;
002
003import java.awt.Color;
004import java.util.HashMap;
005import java.util.List;
006import java.util.Map;
007
008import org.lwjgl.util.vector.Vector2f;
009
010import com.fs.starfarer.api.Global;
011import com.fs.starfarer.api.characters.PersonAPI;
012import com.fs.starfarer.api.combat.BaseEveryFrameCombatPlugin;
013import com.fs.starfarer.api.combat.CollisionClass;
014import com.fs.starfarer.api.combat.CombatEngineAPI;
015import com.fs.starfarer.api.combat.CombatEntityAPI;
016import com.fs.starfarer.api.combat.CombatFleetManagerAPI;
017import com.fs.starfarer.api.combat.MutableShipStatsAPI;
018import com.fs.starfarer.api.combat.ShipAPI;
019import com.fs.starfarer.api.combat.ShipCommand;
020import com.fs.starfarer.api.combat.listeners.ApplyDamageResultAPI;
021import com.fs.starfarer.api.combat.listeners.DamageListener;
022import com.fs.starfarer.api.impl.campaign.ids.Personalities;
023import com.fs.starfarer.api.impl.campaign.ids.Skills;
024import com.fs.starfarer.api.impl.hullmods.ShardSpawner;
025import com.fs.starfarer.api.input.InputEventAPI;
026import com.fs.starfarer.api.loading.FighterWingSpecAPI;
027import com.fs.starfarer.api.util.Misc;
028
029public class ChiralFigmentStats extends BaseShipSystemScript {
030        
031        public static Map<String, String> FIGMENTS = new HashMap<String, String>();
032        static {
033                FIGMENTS.put("shard_left_Attack", "shard_right_Attack");
034                FIGMENTS.put("shard_left_Attack2", "shard_right_Attack");
035                FIGMENTS.put("shard_right_Attack", "shard_left_Attack");
036                FIGMENTS.put("shard_left_Armorbreaker", "shard_right_Attack");
037                FIGMENTS.put("shard_left_Shieldbreaker", "shard_right_Shieldbreaker");
038                FIGMENTS.put("shard_right_Shieldbreaker", "shard_left_Shieldbreaker");
039                FIGMENTS.put("shard_left_Defense", "shard_right_Shock");
040                FIGMENTS.put("shard_right_Shock", "shard_left_Defense");
041                FIGMENTS.put("shard_left_Missile", "shard_right_Missile");
042                FIGMENTS.put("shard_right_Missile", "shard_left_Missile");
043        }
044        
045        public static final Color JITTER_COLOR = ShardSpawner.JITTER_COLOR;
046        public static final Color JITTER_UNDER_COLOR = Misc.setAlpha(JITTER_COLOR, 155);
047
048        
049        public static float DAMAGE_TAKEN_MULT = 1f;
050        public static float JITTER_PER_DAMAGE_DIVISOR = 100f;
051        public static float JITTER_PER_DAMAGE_DECAY_SECONDS = 1f;
052        
053        
054        public static float getSpawnAngle(ShipAPI ship) {
055                String variant = FIGMENTS.get(ship.getVariant().getHullVariantId());
056                if (ship.getVariant().getOriginalVariant() != null && variant == null) {
057                        variant = FIGMENTS.get(ship.getVariant().getOriginalVariant());
058                }
059                if (variant != null && variant.contains("_left")) {
060                        return 90f;
061                }
062                return -90f;
063        }
064        
065        public void apply(MutableShipStatsAPI stats, String id, State state, float effectLevel) {
066                ShipAPI ship = null;
067                //boolean player = false;
068                if (stats.getEntity() instanceof ShipAPI) {
069                        ship = (ShipAPI) stats.getEntity();
070                } else {
071                        return;
072                }
073                
074                
075                float jitterLevel = effectLevel;
076                if (state == State.OUT) {
077                        jitterLevel *= jitterLevel;
078                }
079                float maxRangeBonus = 25f;
080                float jitterRangeBonus = jitterLevel * maxRangeBonus;
081                if (state == State.OUT) {
082                }
083                
084                ship.setJitterUnder(this, JITTER_UNDER_COLOR, jitterLevel, 11, 0f, 3f + jitterRangeBonus);
085                ship.setJitter(this, JITTER_COLOR, jitterLevel, 4, 0f, 0 + jitterRangeBonus);
086                
087                if (state == State.IN) {
088                } else if (effectLevel >= 1) {
089                        String variant = FIGMENTS.get(ship.getVariant().getHullVariantId());
090                        if (ship.getVariant().getOriginalVariant() != null && variant == null) {
091                                variant = FIGMENTS.get(ship.getVariant().getOriginalVariant());
092                        }
093                        if (variant != null) {
094                                float angle = getSpawnAngle(ship);
095                                float dist = ship.getCollisionRadius() * 1.25f;
096                                Vector2f loc = Misc.getUnitVectorAtDegreeAngle(ship.getFacing() + angle);
097                                loc.scale(dist);
098                                Vector2f.add(loc, ship.getLocation(), loc);
099                                if (isLocationClear(ship, loc, dist / 2f)) {
100                                        FigmentPlugin figment = new FigmentPlugin(variant, ship, 1f, 20f, loc);
101                                        Global.getCombatEngine().addPlugin(figment);
102                                }
103                        }
104                } else if (state == State.OUT ) {
105                }
106        }
107        
108        
109        public void unapply(MutableShipStatsAPI stats, String id) {
110        }
111        
112        
113        private boolean isLocationClear(ShipAPI ship, Vector2f loc, float minDist) {
114                for (ShipAPI other : Global.getCombatEngine().getShips()) {
115                        if (other.isShuttlePod()) continue;
116                        if (other.isFighter()) continue;
117                        if (other == ship) continue;
118                        
119                        Vector2f otherLoc = other.getShieldCenterEvenIfNoShield();
120                        float otherR = other.getShieldRadiusEvenIfNoShield();
121                        
122                        
123                        float dist = Misc.getDistance(loc, otherLoc);
124                        float r = otherR;
125                        if (dist < r + minDist) {
126                                return false;
127                        }
128                }
129                for (CombatEntityAPI other : Global.getCombatEngine().getAsteroids()) {
130                        float dist = Misc.getDistance(loc, other.getLocation());
131                        if (dist < other.getCollisionRadius() + minDist) {
132                                return false;
133                        }
134                }
135                
136                return true;
137        }
138
139        public static class FigmentDamageListener implements DamageListener {
140                public FigmentPlugin plugin;
141                public FigmentDamageListener(FigmentPlugin plugin) {
142                        this.plugin = plugin;
143                }
144
145                public void reportDamageApplied(Object source, CombatEntityAPI target, ApplyDamageResultAPI result) {
146                        float totalDamage = result.getDamageToHull() + result.getDamageToShields() + result.getTotalDamageToArmor();
147                        //plugin.recentHits += totalDamage / JITTER_PER_DAMAGE_DIVISOR;
148                        float max = 1f;
149                        if (result.isDps()) max = 0.1f;
150                        plugin.recentHits += Math.min(max, totalDamage / 10f);
151                }
152        }
153        public static class FigmentPlugin extends BaseEveryFrameCombatPlugin {
154                float elapsed = 0f;
155                ShipAPI [] ships = null;
156                CollisionClass collisionClass;
157
158                String variantId;
159                ShipAPI source;
160                float fadeInTime;
161                Vector2f loc;
162                float dur;
163                
164                boolean finishedFadingIn = false;
165                
166                float recentHits = 0f;
167
168                public FigmentPlugin(String variantId, ShipAPI source, float fadeInTime, float dur, Vector2f loc) {
169                        this.variantId = variantId;
170                        this.source = source;
171                        this.fadeInTime = fadeInTime;
172                        this.dur = dur;
173                        this.loc = loc;
174                }
175
176
177                @Override
178                public void advance(float amount, List<InputEventAPI> events) {
179                        if (Global.getCombatEngine().isPaused()) return;
180
181                        elapsed += amount;
182
183                        CombatEngineAPI engine = Global.getCombatEngine();
184                        
185                        if (ships == null) {
186                                float facing = source.getFacing() + 15f * ((float) Math.random() - 0.5f);
187                                CombatFleetManagerAPI fleetManager = engine.getFleetManager(source.getOriginalOwner());
188                                boolean wasSuppressed = fleetManager.isSuppressDeploymentMessages();
189                                fleetManager.setSuppressDeploymentMessages(true);
190                                if (variantId.endsWith("_wing")) {
191                                        FighterWingSpecAPI spec = Global.getSettings().getFighterWingSpec(variantId);
192                                        ships = new ShipAPI[spec.getNumFighters()];
193                                        PersonAPI captain = Global.getSettings().createPerson();
194                                        captain.setPersonality(Personalities.RECKLESS); // doesn't matter for fighters
195                                        captain.getStats().setSkillLevel(Skills.POINT_DEFENSE, 2);
196                                        captain.getStats().setSkillLevel(Skills.GUNNERY_IMPLANTS, 2);
197                                        captain.getStats().setSkillLevel(Skills.IMPACT_MITIGATION, 2);
198                                        ShipAPI leader = engine.getFleetManager(source.getOriginalOwner()).spawnShipOrWing(variantId, loc, facing, 0f, captain);
199                                        for (int i = 0; i < ships.length; i++) {
200                                                ships[i] = leader.getWing().getWingMembers().get(i);
201                                                ships[i].getLocation().set(loc);
202                                        }
203                                        collisionClass = ships[0].getCollisionClass();
204                                } else {
205                                        ships = new ShipAPI[1];
206                                        ships[0] = engine.getFleetManager(source.getOriginalOwner()).spawnShipOrWing(variantId, loc, facing, 0f, source.getOriginalCaptain());
207                                }
208                                fleetManager.setSuppressDeploymentMessages(wasSuppressed);
209                                collisionClass = ships[0].getCollisionClass();
210                        }
211
212
213                        float progress = elapsed / fadeInTime;
214                        
215                        float maxAlpha = 0.67f;
216                        if (progress <= 1f) {
217                                for (int i = 0; i < ships.length; i++) {
218                                        ShipAPI ship = ships[i];
219                                        ship.setAlphaMult(progress * maxAlpha);
220        
221                                        if (progress < 0.5f) {
222                                                ship.blockCommandForOneFrame(ShipCommand.ACCELERATE);
223                                                ship.blockCommandForOneFrame(ShipCommand.TURN_LEFT);
224                                                ship.blockCommandForOneFrame(ShipCommand.TURN_RIGHT);
225                                                ship.blockCommandForOneFrame(ShipCommand.STRAFE_LEFT);
226                                                ship.blockCommandForOneFrame(ShipCommand.STRAFE_RIGHT);
227                                        }
228        
229                                        ship.blockCommandForOneFrame(ShipCommand.USE_SYSTEM);
230                                        ship.blockCommandForOneFrame(ShipCommand.TOGGLE_SHIELD_OR_PHASE_CLOAK);
231                                        ship.blockCommandForOneFrame(ShipCommand.FIRE);
232                                        ship.blockCommandForOneFrame(ShipCommand.PULL_BACK_FIGHTERS);
233                                        ship.blockCommandForOneFrame(ShipCommand.VENT_FLUX);
234                                        ship.setHoldFireOneFrame(true);
235                                        ship.setHoldFire(true);
236        
237        
238                                        ship.setCollisionClass(CollisionClass.NONE);
239                                        ship.getMutableStats().getHullDamageTakenMult().modifyMult("FigmentInvuln", 0f);
240                                        if (progress < 0.5f) {
241                                                ship.getVelocity().set(source.getVelocity());
242                                        } else if (progress > 0.75f){
243                                                ship.setCollisionClass(collisionClass);
244                                                ship.getMutableStats().getHullDamageTakenMult().unmodifyMult("FigmentInvuln");
245                                        }
246        
247                                        float jitterLevel = progress;
248//                                      if (jitterLevel < 0.5f) {
249//                                              jitterLevel *= 2f;
250//                                      } else {
251//                                              jitterLevel = (1f - jitterLevel) * 2f;
252//                                      }
253        
254                                        float jitterRange = 1f - progress * 0.5f;
255                                        float maxRangeBonus = 50f;
256                                        maxRangeBonus -= 30f * progress;
257                                        float jitterRangeBonus = jitterRange * maxRangeBonus;
258                                        Color c = JITTER_COLOR;
259                                        float num = 18f * (1f - progress * progress) + 7f;
260        
261                                        ship.setJitter(this, c, jitterLevel, (int)Math.round(num), 0f, jitterRangeBonus);
262                                }
263                        }
264
265                        if (elapsed > fadeInTime && !finishedFadingIn) {
266                                for (int i = 0; i < ships.length; i++) {
267                                        ShipAPI ship = ships[i];
268                                        ship.setAlphaMult(maxAlpha);
269                                        ship.setHoldFire(false);
270                                        ship.setCollisionClass(collisionClass);
271                                        ship.getMutableStats().getHullDamageTakenMult().unmodifyMult("FigmentInvuln");
272                                        
273                                        DAMAGE_TAKEN_MULT = 1f;
274                                        ship.getMutableStats().getHullDamageTakenMult().modifyMult("FigmentExtraDamage", DAMAGE_TAKEN_MULT);
275                                        ship.getMutableStats().getShieldDamageTakenMult().modifyMult("FigmentExtraDamage", DAMAGE_TAKEN_MULT);
276                                        ship.getMutableStats().getArmorDamageTakenMult().modifyMult("FigmentExtraDamage", DAMAGE_TAKEN_MULT);
277                                        
278                                        ship.addListener(new FigmentDamageListener(this));
279                                }
280                                finishedFadingIn = true;
281                        }
282                        
283                        if (elapsed > fadeInTime) {
284                                for (int i = 0; i < ships.length; i++) {
285                                        ShipAPI ship = ships[i];
286                                        
287                                        if (!ship.isAlive() || !engine.isInPlay(ship)) {
288                                                engine.removePlugin(this);
289                                                return;
290                                        }
291                                        
292                                        ship.setAlphaMult(maxAlpha);
293                                        ship.blockCommandForOneFrame(ShipCommand.USE_SYSTEM);
294                                        ship.blockCommandForOneFrame(ShipCommand.TOGGLE_SHIELD_OR_PHASE_CLOAK);
295                                        
296                                        
297                                        //float minus = recentHits * amount / JITTER_PER_DAMAGE_DECAY_SECONDS;
298                                        float minus = recentHits * amount * 2f;
299                                        minus += 0.1f * amount;
300                                        recentHits -= minus;
301                                        if (recentHits < 0) recentHits = 0;
302                                        if (recentHits > 5f) recentHits = 5f;
303                                        
304                                        float jitterLevel = 1f;
305                                        float jitterRange = 0.5f;
306                                        float maxRangeBonus = 50f;
307                                        maxRangeBonus = 20f;
308                                        maxRangeBonus += recentHits * 40f;
309                                        float jitterRangeBonus = jitterRange * maxRangeBonus;
310                                        Color c = JITTER_COLOR;
311        
312                                        float numCopies = 7f;
313                                        numCopies += recentHits * 2f;
314                                        
315                                        ship.setJitter(this, c, jitterLevel, (int) Math.round(numCopies), 0f, jitterRangeBonus);
316                                }
317                        }
318                        
319                        if (elapsed > dur) {
320                                // destroy ship here?
321                                //engine.removePlugin(this);
322                        }
323                }
324        }
325        
326}
327
328
329
330
331
332
333
334