001package com.fs.starfarer.api.impl.combat.dweller;
002
003import java.util.ArrayList;
004import java.util.Collections;
005import java.util.List;
006
007import org.lwjgl.util.vector.Vector2f;
008
009import com.fs.starfarer.api.Global;
010import com.fs.starfarer.api.combat.CollisionClass;
011import com.fs.starfarer.api.combat.MutableShipStatsAPI;
012import com.fs.starfarer.api.combat.ShieldAPI;
013import com.fs.starfarer.api.combat.ShipAPI;
014import com.fs.starfarer.api.combat.ShipCommand;
015import com.fs.starfarer.api.combat.ShipSystemAPI;
016import com.fs.starfarer.api.combat.ShipwideAIFlags.AIFlags;
017import com.fs.starfarer.api.combat.WeaponAPI;
018import com.fs.starfarer.api.impl.combat.BaseShipSystemScript;
019import com.fs.starfarer.api.impl.combat.dweller.DwellerShroud.ShroudNegativeParticleFilter;
020import com.fs.starfarer.api.impl.combat.threat.RoilingSwarmEffect.SwarmMember;
021import com.fs.starfarer.api.loading.BeamWeaponSpecAPI;
022import com.fs.starfarer.api.util.Misc;
023
024public class DarkenedGazeSystemScript extends BaseShipSystemScript implements ShroudNegativeParticleFilter {
025        
026        public static float SHIELD_OPENING = 90f;
027        public static float TURN_RATE_REDUCTION = 0.85f;
028        
029        public static float DAMAGE_TAKEN_MULT = 2f;
030        
031        public static String DARKENED_GAZE_SYSTEM_TAG = "darkened_gaze_system_tag";
032        public static String DARKENED_GAZE_PRIMARY_WEAPON_TAG = "darkened_gaze_system_tag";
033        
034        
035        protected List<WeaponAPI> weapons = null; 
036        protected float elapsedActive = 0f; 
037
038        
039        protected void findWeapons(ShipAPI ship) {
040                if (weapons != null) return;
041                
042                ship.addTag(DARKENED_GAZE_SYSTEM_TAG);
043                
044                weapons = new ArrayList<>();
045                int index = 0;
046                for (WeaponAPI w : ship.getAllWeapons()) {
047                        if (w.getSlot().isDecorative()) {
048//                              if (index == 0 || index == 1 || index == 2 || index == 3) {
049//                                      index++;
050//                                      continue;
051//                              }
052                                //if (index == 8) weapons.clear();
053                                weapons.add(w);
054                                //if (index == 8) break;
055                                //break;
056                        }
057                        index++;
058                }
059                
060                float min = 10000000f;
061                WeaponAPI primary = null;
062                //middle-most weapon is "primary"
063                for (WeaponAPI w : weapons) {
064                        float test = w.getSlot().getLocation().y;
065                        if (test < min) {
066                                min = test;
067                                primary = w;
068                        }
069                }
070                if (primary != null) {
071                        primary.setCustom(DARKENED_GAZE_PRIMARY_WEAPON_TAG);
072                }
073                
074                Collections.sort(weapons, (w1, w2) -> {
075                        return (int) Math.signum(Math.abs(w1.getSlot().getLocation().y) - Math.abs(w2.getSlot().getLocation().y));
076                });
077                
078                // hardcoded to assume 9 beams
079                float incr = 0.15f;
080                float [] offsets = new float [] 
081                                {0f, incr, -incr, 2f * incr, -2f * incr, 3f * incr, -3f * incr, 4f * incr, -4f * incr}; 
082                for (int i = 0; i < weapons.size(); i++) {
083                        WeaponAPI w = weapons.get(i);
084                        w.ensureClonedSpec();
085                        w.getSpec().getHardpointAngleOffsets().clear();
086                        w.getSpec().getHardpointAngleOffsets().add(offsets[i]);
087                        w.getSpec().getTurretAngleOffsets().clear();
088                        w.getSpec().getTurretAngleOffsets().add(offsets[i]);
089                        // so that there's no FF
090                        ((BeamWeaponSpecAPI)w.getSpec()).setCollisionClass(CollisionClass.RAY_FIGHTER);
091                }
092        }
093        
094        public boolean isFFAConcern() {
095                if (weapons.size() == 0) return false;
096                return ((BeamWeaponSpecAPI)weapons.get(0).getSpec()).getCollisionClass() == CollisionClass.RAY;
097        }
098        
099        public float getRange() {
100                if (weapons == null || weapons.isEmpty()) return 0f;
101                return weapons.get(0).getRange();
102        }
103        
104        public void apply(MutableShipStatsAPI stats, String id, State state, float effectLevel) {
105                ShipAPI ship = null;
106                if (stats.getEntity() instanceof ShipAPI) {
107                        ship = (ShipAPI) stats.getEntity();
108                } else {
109                        return;
110                }
111                
112                findWeapons(ship);
113                
114                ShieldAPI shield = ship.getShield();
115                if (shield != null) {
116                        shield.forceFacing(ship.getFacing() + 180f);
117                        if (!ship.getFluxTracker().isOverloadedOrVenting()) {
118                                shield.toggleOn();
119                        }
120                        ship.blockCommandForOneFrame(ShipCommand.TOGGLE_SHIELD_OR_PHASE_CLOAK);
121                }
122                
123                DwellerShroud shroud = DwellerShroud.getShroudFor(ship);
124                
125                if (state == State.IN) {
126                        if (shield != null) {
127                                float currOpening = effectLevel * SHIELD_OPENING;
128                                shield.setArc(360f - currOpening);
129                        }
130//                      if (shroud != null && effectLevel < 0.5f) {
131//                              SwarmMember added = shroud.addMember();
132//                              //added.flash();
133//                              float arc = 360f - SHIELD_OPENING;
134//                              float angle = ship.getFacing() + 180f + arc/2f - arc * (float) Math.random();
135//                              added.offset = Misc.getUnitVectorAtDegreeAngle(angle);
136//                              added.offset.scale(shroud.getParams().maxOffset * 0.7f);
137//                              Vector2f offset = Misc.getUnitVectorAtDegreeAngle(angle);
138//                              offset.scale(shroud.getParams().maxOffset + 200f + (float) Math.random() * 100f);
139//                              Vector2f.add(ship.getLocation(), offset, added.loc);
140//                      }
141                        
142                } else if (state == State.ACTIVE) {
143                        for (WeaponAPI w : weapons) {
144                                //if ((float) Math.random() > 0.97f) {
145                                        w.setForceFireOneFrame(true);
146                                //}
147                        }
148                } else if (state == State.OUT) {
149                        if (shield != null) {
150                                float currOpening = effectLevel * SHIELD_OPENING;
151                                shield.setArc(360f - currOpening);
152                        }       
153                }
154                
155                if (state == State.IN || state == State.ACTIVE) {
156                        if (shroud != null) {
157                                shroud.getShroudParams().negativeParticleClearCenterAreaRadius = 150f; 
158                                shroud.getShroudParams().negativeParticleGenRate = 0.5f;
159                                //shroud.getShroudParams().negativeParticleColorOverride = new Color(0,0,0,255);
160                                shroud.getShroudParams().negativeParticleFilter = this;
161                        }
162                        
163                        
164                        Vector2f dir = Misc.getUnitVectorAtDegreeAngle(ship.getFacing() + 180f);
165                        float amount = Global.getCombatEngine().getElapsedInLastFrame();
166                        
167                        
168                        float accel = ConvulsiveLungeSystemScript.PARTICLE_WINDUP_ACCEL * amount * effectLevel;
169                        if (shroud != null) {
170                                for (SwarmMember p : shroud.getMembers()) {
171                                        float currAngle = Misc.getAngleInDegrees(ship.getLocation(), p.loc);
172                                        float angleDiff = Misc.getAngleDiff(currAngle, ship.getFacing());
173                                        float accelMult = 1f;
174                                        if (angleDiff > SHIELD_OPENING * 0.5f) {
175                                                //accelMult = SHIELD_OPENING * 0.5f / angleDiff;
176                                                accelMult = 0f;
177                                        }
178                                        
179                                        p.vel.x += dir.x * accel * accelMult;
180                                        p.vel.y += dir.y * accel * accelMult;
181                                }
182                        }
183                        if (state == State.ACTIVE) {
184                                elapsedActive += amount;
185                                float f = Math.min(elapsedActive, 1f) * 1f;
186                                f = 1f - f;
187                                //float beamSpeedMult = 1f + (float) Math.sqrt(f) * 2f;
188//                              float beamSpeedMult = 1f + f * f * 2f;
189//                              ship.getMutableStats().getBeamSpeedMod().modifyMult(id, beamSpeedMult);
190                        }
191                        
192                        ship.getMutableStats().getMaxTurnRate().modifyMult(id, 1f - TURN_RATE_REDUCTION * effectLevel);
193                        ship.getMutableStats().getHullDamageTakenMult().modifyMult(id, 1f + (DAMAGE_TAKEN_MULT - 1f) * effectLevel);
194                } else {
195                        if (shroud != null) {
196                                shroud.getShroudParams().negativeParticleClearCenterAreaRadius = 50f;
197                                shroud.getShroudParams().negativeParticleGenRate = 1f;
198                                //shroud.getShroudParams().negativeParticleColorOverride = null;
199                                shroud.getShroudParams().negativeParticleFilter = null;
200                        }
201                        elapsedActive = 0f;
202                        ship.getMutableStats().getMaxTurnRate().unmodifyMult(id);
203                        ship.getMutableStats().getHullDamageTakenMult().unmodifyMult(id);
204                        //ship.getMutableStats().getBeamSpeedMod().unmodifyMult(id);
205                }
206                
207                ship.getAIFlags().setFlag(AIFlags.BACK_OFF_MIN_RANGE, 1f, getRange() - 300f);
208                
209                if (state == State.IDLE) {
210                        shield.setArc(360f);
211                }
212                        
213        }
214        
215        public void unapply(MutableShipStatsAPI stats, String id) {
216        }
217        
218        public StatusData getStatusData(int index, State state, float effectLevel) {
219                return null;
220        }
221        
222        @Override
223        public String getInfoText(ShipSystemAPI system, ShipAPI ship) {
224                return super.getInfoText(system, ship);
225        }
226
227        @Override
228        public boolean isParticleOk(DwellerShroud shroud, Vector2f loc) {
229                // only filtering when in/active, not idle/out/cooldown, so don't worry about those cases
230                if (shroud == null || shroud.getAttachedTo() == null) return true;
231                float angle = Misc.getAngleInDegrees(shroud.getAttachedTo().getLocation(), loc);
232                return !Misc.isInArc(shroud.getAttachedTo().getFacing(), SHIELD_OPENING, angle);
233        }
234
235        
236}
237
238
239
240
241
242
243
244