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