package mindustry.entities; import arc.graphics.*; import arc.math.*; import arc.math.geom.*; import arc.struct.*; import arc.util.*; import mindustry.content.*; import mindustry.core.*; import mindustry.entities.bullet.*; import mindustry.game.*; import mindustry.gen.*; import mindustry.world.*; import static mindustry.Vars.*; public class Lightning{ private static final Rand random = new Rand(); private static final Rect rect = new Rect(); private static final Seq entities = new Seq<>(); private static final IntSet hit = new IntSet(); private static final int maxChain = 8; private static final float hitRange = 30f; private static boolean bhit = false; private static int lastSeed = 0; /** Create a lighting branch at a location. Use Team.derelict to damage everyone. */ public static void create(Team team, Color color, float damage, float x, float y, float targetAngle, int length){ createLightningInternal(null, lastSeed++, team, color, damage, x, y, targetAngle, length); } /** Create a lighting branch at a location. Uses bullet parameters. */ public static void create(Bullet bullet, Color color, float damage, float x, float y, float targetAngle, int length){ createLightningInternal(bullet, lastSeed++, bullet.team, color, damage, x, y, targetAngle, length); } private static void createLightningInternal(@Nullable Bullet hitter, int seed, Team team, Color color, float damage, float x, float y, float rotation, int length){ random.setSeed(seed); hit.clear(); BulletType hitCreate = hitter == null || hitter.type.lightningType == null ? Bullets.damageLightning : hitter.type.lightningType; Seq lines = new Seq<>(); bhit = false; for(int i = 0; i < length / 2; i++){ hitCreate.create(null, team, x, y, rotation, damage, 1f, 1f, hitter); lines.add(new Vec2(x + Mathf.range(3f), y + Mathf.range(3f))); if(lines.size > 1){ bhit = false; Vec2 from = lines.get(lines.size - 2); Vec2 to = lines.get(lines.size - 1); world.raycastEach(World.toTile(from.getX()), World.toTile(from.getY()), World.toTile(to.getX()), World.toTile(to.getY()), (wx, wy) -> { Tile tile = world.tile(wx, wy); if(tile != null && (tile.build != null && tile.build.isInsulated()) && tile.team() != team){ bhit = true; //snap it instead of removing lines.get(lines.size - 1).set(wx * tilesize, wy * tilesize); return true; } return false; }); if(bhit) break; } rect.setSize(hitRange).setCenter(x, y); entities.clear(); if(hit.size < maxChain){ Units.nearbyEnemies(team, rect, u -> { if(!hit.contains(u.id()) && (hitter == null || u.checkTarget(hitter.type.collidesAir, hitter.type.collidesGround))){ entities.add(u); } }); } Unitc furthest = Geometry.findFurthest(x, y, entities); if(furthest != null){ hit.add(furthest.id()); x = furthest.x(); y = furthest.y(); }else{ rotation += random.range(20f); x += Angles.trnsx(rotation, hitRange / 2f); y += Angles.trnsy(rotation, hitRange / 2f); } } Fx.lightning.at(x, y, rotation, color, lines); } }