001package com.fs.starfarer.api.impl.combat.dweller;
002
003import java.util.List;
004
005import java.awt.Color;
006
007import org.lwjgl.util.vector.Vector2f;
008
009import com.fs.starfarer.api.Global;
010import com.fs.starfarer.api.combat.CombatEngineAPI;
011import com.fs.starfarer.api.combat.CombatEntityAPI;
012import com.fs.starfarer.api.combat.DamagingProjectileAPI;
013import com.fs.starfarer.api.combat.EveryFrameWeaponEffectPlugin;
014import com.fs.starfarer.api.combat.MissileAIPlugin;
015import com.fs.starfarer.api.combat.MissileAPI;
016import com.fs.starfarer.api.combat.OnFireEffectPlugin;
017import com.fs.starfarer.api.combat.OnHitEffectPlugin;
018import com.fs.starfarer.api.combat.ShipAPI;
019import com.fs.starfarer.api.combat.WeaponAPI;
020import com.fs.starfarer.api.combat.listeners.ApplyDamageResultAPI;
021import com.fs.starfarer.api.impl.campaign.ids.Tags;
022import com.fs.starfarer.api.impl.combat.NegativeExplosionVisual.NEParams;
023import com.fs.starfarer.api.impl.combat.RiftCascadeEffect;
024import com.fs.starfarer.api.impl.combat.RiftCascadeMineExplosion;
025import com.fs.starfarer.api.impl.combat.RiftLanceEffect;
026import com.fs.starfarer.api.impl.combat.RiftTrailEffect;
027import com.fs.starfarer.api.input.InputEventAPI;
028import com.fs.starfarer.api.loading.MissileSpecAPI;
029import com.fs.starfarer.api.util.WeightedRandomPicker;
030
031/**
032 * IMPORTANT: will be multiple instances of this, one for the the OnFire (per weapon) and one for the OnHit (per missile) effects.
033 * 
034 * (Well, no data members, so not *that* important.)
035 */
036public class AssayingRiftEffect implements OnFireEffectPlugin, OnHitEffectPlugin, EveryFrameWeaponEffectPlugin {
037
038        
039        public static String HUNGERING_RIFT_HEAL_MULT_STAT = "hungering_rift_heal_mult_stat";
040        public static String HUNGERING_RIFT_HEAL_MOD_HUMAN_SHIPS = "hungering_rift_heal_mod";
041        
042        public static float HEAL_AMOUNT = 1000f;
043        
044        //public static float HITPOINTS_MULT_WHEN_BY_DWELLER_SHIP = 2f;
045        
046        public static String ASSAYING_RIFT = "assaying_rift";
047        
048        /**
049         * One Hungering Rift weapon can produce up to 5 or so rifts at a time if they're fired non-stop and don't hit anything early.
050         */
051        public static int MAX_RIFTS = 10; 
052        
053        
054        public static class AssayingRiftCount {
055                int count = 0;
056                float totalElapsed = 0;
057                
058                public void update() {
059                        float elapsed = Global.getCombatEngine().getTotalElapsedTime(false);
060                        if (totalElapsed >= elapsed) return;
061                        
062                        totalElapsed = elapsed;
063                        
064                        count = 0;
065                        for (MissileAPI m : Global.getCombatEngine().getMissiles()) {
066                                if (m.hasTag(ASSAYING_RIFT)) {
067                                        count++;
068                                }
069                        }
070                }
071        }
072        
073
074        @Override
075        public void advance(float amount, CombatEngineAPI engine, WeaponAPI weapon) {
076                if (weapon.getShip() != null && weapon.getShip().getHullSpec().hasTag(Tags.DWELLER)) {
077                        return;
078                }
079                
080                String key = "AssayingRiftSharedDataKey";
081                AssayingRiftCount data = (AssayingRiftCount) engine.getCustomData().get(key);
082                if (data == null) {
083                        data = new AssayingRiftCount();
084                        engine.getCustomData().put(key, data);
085                }
086                
087                data.update();
088                
089                boolean disable = data.count >= MAX_RIFTS;
090                weapon.setForceDisabled(disable);               
091        }       
092        
093        public void onHit(DamagingProjectileAPI projectile, CombatEntityAPI target, Vector2f point, boolean shieldHit, ApplyDamageResultAPI damageResult, CombatEngineAPI engine) {
094                Color color = RiftCascadeEffect.STANDARD_RIFT_COLOR;
095                Object o = projectile.getWeapon().getSpec().getProjectileSpec();
096                if (o instanceof MissileSpecAPI) {
097                        MissileSpecAPI spec = (MissileSpecAPI) o;
098                        color = spec.getExplosionColor();
099                }
100                
101                if (!shieldHit && target instanceof ShipAPI) {
102                        ShipAPI targetShip = (ShipAPI) target;
103                        ShipAPI source = projectile.getSource();
104                        
105//                      DwellerShroud shroud = DwellerShroud.getShroudFor(source);
106//                      if (shroud != null && source != null && !source.isHulk() && !targetShip.isHulk()) {
107//                              source.setHitpoints(Math.min(source.getMaxHitpoints(), source.getHitpoints() + HEAL_AMOUNT));
108//                      }
109                        
110                        if (!targetShip.isHulk()) {
111                                WeightedRandomPicker<ShipAPI> healTargets = new WeightedRandomPicker<>();
112                                WeightedRandomPicker<ShipAPI> healNeedLess = new WeightedRandomPicker<>();
113                                for (ShipAPI other : Global.getCombatEngine().getShips()) {
114                                        if (other.isHulk()) continue;
115                                        if (other.isFighter()) continue;
116                                        if (other.getOwner() != source.getOwner()) continue;
117                                        
118                                        if (getHealMult(other) <= 0) continue;
119                                        
120                                        DwellerShroud otherShroud = DwellerShroud.getShroudFor(source);
121                                        if (otherShroud == null) continue;
122                                        
123                                        float missingHp = other.getMaxHitpoints() - other.getHitpoints();
124                                        if (missingHp < HEAL_AMOUNT * 0.7f && missingHp > 0f) {
125                                                healNeedLess.add(other, missingHp);
126                                        } else {
127                                                healTargets.add(other, missingHp);
128                                        }
129                                }
130                                
131                                ShipAPI toHeal = healTargets.pick();
132                                if (toHeal == null) toHeal = healNeedLess.pick();
133                                if (toHeal != null) {
134                                        float healAmount = HEAL_AMOUNT;
135                                        healAmount *= getHealMult(toHeal);
136                                        toHeal.setHitpoints(Math.min(toHeal.getMaxHitpoints(), toHeal.getHitpoints() + healAmount));
137                                }
138                        }
139                }
140                
141                NEParams p = RiftCascadeMineExplosion.createStandardRiftParams(color, 15f);
142                p.fadeOut = 1f;
143                p.hitGlowSizeMult = 1f;
144                //p.invertForDarkening = NSProjEffect.STANDARD_RIFT_COLOR;
145                RiftCascadeMineExplosion.spawnStandardRift(projectile, p);
146                
147                Vector2f vel = new Vector2f();
148                if (target != null) vel.set(target.getVelocity());
149                Global.getSoundPlayer().playSound("assaying_rift_explosion", 1f, 1f, point, vel);
150        }
151        
152        public static float getHealMult(ShipAPI toHeal) {
153                float base = toHeal.getMutableStats().getDynamic().getValue(HUNGERING_RIFT_HEAL_MULT_STAT);
154                base += toHeal.getMutableStats().getDynamic().getValue(HUNGERING_RIFT_HEAL_MOD_HUMAN_SHIPS, 0f);
155                return base;
156        }
157        
158        
159        public void onFire(DamagingProjectileAPI projectile, WeaponAPI weapon, CombatEngineAPI engine) {
160                MissileAIPlugin proxAI = Global.getCombatEngine().createProximityFuseAI((MissileAPI)projectile);
161                RiftTrailEffect trail = new RiftTrailEffect((MissileAPI) projectile, null) {
162                        boolean exploded = false;
163                        float elapsed = 0f;
164                        @Override
165                        public void advance(float amount, List<InputEventAPI> events) {
166                                super.advance(amount, events);
167                                proxAI.advance(amount);
168                                if (!exploded && !missile.didDamage() && missile.wasRemoved()) {// !engine.isMissileAlive(missile)) {
169                                        onHit(missile, null, missile.getLocation(), false, null, engine);
170                                        exploded = true;
171                                }
172                                
173//                              if (!exploded) {
174//                                      elapsed += amount;
175//                                      if (elapsed > 1f) {
176//                                              float speedBonus = Math.min(100f, (elapsed - 1f) * 100f);
177//                                              String id = "AssayingRiftSpeedBonus";
178//                                              missile.getEngineStats().getMaxSpeed().modifyFlat(id, speedBonus);
179//                                              missile.getEngineStats().getAcceleration().modifyFlat(id, speedBonus * 2f);
180//                                              missile.getEngineStats().getDeceleration().modifyFlat(id, speedBonus * 2f);
181//                                              missile.updateMaxSpeed();
182//                                      }
183//                              }
184                        }
185                        protected Color getUndercolor() {
186                                //return new Color(100, 0, 20, 255);
187                                return DwellerShroud.SHROUD_COLOR;
188                        }
189                        protected Color getDarkeningColor() {
190                                return RiftLanceEffect.getColorForDarkening(getUndercolor());
191                        }
192                        @Override
193                        protected float getBaseParticleDuration() {
194                                return 1.5f;
195                        }
196                        
197                        
198                };
199                
200                MissileAPI missile = ((MissileAPI) projectile);
201                
202                missile.setEmpResistance(1000);
203                missile.setEccmChanceOverride(1f);
204                missile.addTag(ASSAYING_RIFT);
205                
206//              if (weapon.getShip().getHullSpec().hasTag(Tags.DWELLER)) {
207//                      missile.setHitpoints(missile.getHitpoints() * HITPOINTS_MULT_WHEN_BY_DWELLER_SHIP);
208//              }
209                
210                Global.getCombatEngine().addPlugin(trail);
211        }
212
213}
214
215
216
217
218
219
220
221
222
223
224
225
226
227