001package com.fs.starfarer.api.impl.hullmods;
002
003import java.util.ArrayList;
004import java.util.List;
005import java.util.Random;
006
007import org.lwjgl.util.vector.Vector2f;
008
009import com.fs.starfarer.api.Global;
010import com.fs.starfarer.api.combat.BaseHullMod;
011import com.fs.starfarer.api.combat.CombatEngineAPI;
012import com.fs.starfarer.api.combat.CombatEntityAPI;
013import com.fs.starfarer.api.combat.MissileAPI;
014import com.fs.starfarer.api.combat.ShipAPI;
015import com.fs.starfarer.api.combat.WeaponAPI.WeaponType;
016import com.fs.starfarer.api.util.IntervalUtil;
017import com.fs.starfarer.api.util.Misc;
018import com.fs.starfarer.api.util.WeightedRandomPicker;
019
020public class StealthMinefield extends BaseHullMod {
021
022        public static String MINEFIELD_DATA_KEY = "minefield_data_key"; 
023        public static class IncomingMine {
024                Vector2f mineLoc;
025                float delay;
026                ShipAPI target;
027        }
028        public static class MinefieldData {
029                ShipAPI source;
030                IntervalUtil tracker = new IntervalUtil(0.5f, 1.5f);
031                List<IncomingMine> incoming = new ArrayList<IncomingMine>();
032        }
033        
034        
035        @Override
036        public void advanceInCombat(ShipAPI ship, float amount) { 
037                super.advanceInCombat(ship, amount);
038
039                //if (true) return;
040                
041                CombatEngineAPI engine = Global.getCombatEngine();
042                
043                MinefieldData data = (MinefieldData) engine.getCustomData().get(MINEFIELD_DATA_KEY);
044                if (data == null) {
045                        data = new MinefieldData();
046                        data.source = ship;
047                        engine.getCustomData().put(MINEFIELD_DATA_KEY, data);
048                }
049                
050                if (data.source != ship) return;
051                if (!ship.isAlive()) return;
052                
053                
054                for (IncomingMine inc : new ArrayList<IncomingMine>(data.incoming)) {
055                        inc.delay -= amount;
056                        if (inc.delay <= 0) {
057                                spawnMine(ship, inc.mineLoc, inc.target);
058                                data.incoming.remove(inc);
059                        }
060                }
061                
062                data.tracker.advance(amount);
063                if (!data.tracker.intervalElapsed()) return;
064                
065                WeightedRandomPicker<IncomingMine> picker = new WeightedRandomPicker<IncomingMine>();
066                
067                for (ShipAPI enemy : engine.getShips()) {
068                        if (enemy == ship) continue;
069                        if (enemy.isHulk()) continue;
070                        if (enemy.getOwner() == ship.getOwner()) continue;
071                        if (enemy.isFighter()) continue;
072                        if (enemy.isDrone()) continue;
073                        if (enemy.isStation()) continue;
074                        if (enemy.isStationModule()) continue;
075                        if (enemy.getTravelDrive() != null && enemy.getTravelDrive().isActive()) continue;
076                        
077                        if ((float) Math.random() > 0.25f) continue;
078                
079                        Vector2f mineLoc = Misc.getPointAtRadius(enemy.getLocation(), 
080                                                                                                         enemy.getCollisionRadius() + 400f + 200f * (float) Math.random());
081                        float minOk = 400f + enemy.getCollisionRadius();
082                        if (!isAreaClear(mineLoc, minOk)) continue;
083                        
084                        IncomingMine inc = new IncomingMine();
085                        inc.delay = (float) Math.random() * 1.5f;
086                        inc.target = enemy;
087                        inc.mineLoc = mineLoc;
088                        
089                        picker.add(inc);
090                }
091                
092                int numToSpawn = Math.max(1, Math.min(new Random().nextInt(6) + 5, picker.getItems().size()));
093                
094                for (int i = 0; i < numToSpawn && !picker.isEmpty(); i++) {
095                        IncomingMine inc = picker.pickAndRemove();
096                        data.incoming.add(inc);
097                }
098                
099        }
100
101
102        public void spawnMine(ShipAPI source, Vector2f mineLoc, ShipAPI target) {
103                float mineDir = Misc.getAngleInDegrees(mineLoc, target.getLocation());
104                CombatEngineAPI engine = Global.getCombatEngine();
105                Vector2f currLoc = Misc.getPointAtRadius(mineLoc, 50f + (float) Math.random() * 50f);
106                MissileAPI mine = (MissileAPI) engine.spawnProjectile(source, null, 
107                                                                                                                          getWeaponId(), 
108                                                                                                                          currLoc, 
109                                                                                                                          mineDir, null);
110                if (source != null) {
111                        Global.getCombatEngine().applyDamageModifiersToSpawnedProjectileWithNullWeapon(
112                                                                                        source, WeaponType.MISSILE, false, mine.getDamage());
113//                      float extraDamageMult = source.getMutableStats().getMissileWeaponDamageMult().getModifiedValue();
114//                      mine.getDamage().setMultiplier(mine.getDamage().getMultiplier() * extraDamageMult);
115                }
116                
117                mine.setFlightTime((float) Math.random());
118                mine.fadeOutThenIn(1f);
119                
120                Global.getSoundPlayer().playSound("mine_spawn", 1f, 1f, mine.getLocation(), mine.getVelocity());
121        }
122
123        protected String getWeaponId() {
124                return "minelayer2";
125        }
126        
127        public boolean isAreaClear(Vector2f loc, float range) {
128                CombatEngineAPI engine = Global.getCombatEngine();
129                for (ShipAPI other : engine.getShips()) {
130                        if (other.isFighter()) continue;
131                        if (other.isDrone()) continue;
132                        
133                        float dist = Misc.getDistance(loc, other.getLocation());
134                        if (dist < range) {
135                                return false;
136                        }
137                }
138                
139                for (CombatEntityAPI other : Global.getCombatEngine().getAsteroids()) {
140                        float dist = Misc.getDistance(loc, other.getLocation());
141                        if (dist < other.getCollisionRadius() + 100f) {
142                                return false;
143                        }
144                }
145                
146                return true;
147        }
148
149}
150
151
152
153