diff --git a/core/assets/scripts/global.js b/core/assets/scripts/global.js index d09954ca52..4c5ebc75ca 100755 --- a/core/assets/scripts/global.js +++ b/core/assets/scripts/global.js @@ -53,33 +53,13 @@ function extend(/*Base, ..., def*/){ const extendContent = extend; importPackage(Packages.arc) -importPackage(Packages.arc.audio) -importPackage(Packages.arc.func) importPackage(Packages.arc.graphics) importPackage(Packages.arc.graphics.g2d) importPackage(Packages.arc.graphics.gl) -importPackage(Packages.arc.input) importPackage(Packages.arc.math) -importPackage(Packages.arc.math.geom) -importPackage(Packages.arc.scene) -importPackage(Packages.arc.scene.actions) -importPackage(Packages.arc.scene.event) -importPackage(Packages.arc.scene.style) -importPackage(Packages.arc.scene.ui) -importPackage(Packages.arc.scene.ui.layout) -importPackage(Packages.arc.scene.utils) -importPackage(Packages.arc.struct) importPackage(Packages.arc.util) -importPackage(Packages.arc.util.async) -importPackage(Packages.arc.util.io) -importPackage(Packages.arc.util.noise) -importPackage(Packages.arc.util.pooling) -importPackage(Packages.arc.util.serialization) -importPackage(Packages.arc.util.viewport) importPackage(Packages.mindustry) importPackage(Packages.mindustry.ai) -importPackage(Packages.mindustry.ai.formations) -importPackage(Packages.mindustry.ai.formations.patterns) importPackage(Packages.mindustry.ai.types) importPackage(Packages.mindustry.async) importPackage(Packages.mindustry.audio) @@ -91,6 +71,8 @@ importPackage(Packages.mindustry.entities) importPackage(Packages.mindustry.entities.abilities) importPackage(Packages.mindustry.entities.bullet) importPackage(Packages.mindustry.entities.effect) +importPackage(Packages.mindustry.entities.part) +importPackage(Packages.mindustry.entities.pattern) importPackage(Packages.mindustry.entities.units) importPackage(Packages.mindustry.game) importPackage(Packages.mindustry.gen) @@ -121,7 +103,6 @@ importPackage(Packages.mindustry.world.blocks.defense) importPackage(Packages.mindustry.world.blocks.defense.turrets) importPackage(Packages.mindustry.world.blocks.distribution) importPackage(Packages.mindustry.world.blocks.environment) -importPackage(Packages.mindustry.world.blocks.experimental) importPackage(Packages.mindustry.world.blocks.heat) importPackage(Packages.mindustry.world.blocks.legacy) importPackage(Packages.mindustry.world.blocks.liquid) @@ -164,6 +145,7 @@ const CoreChangeEvent = Packages.mindustry.game.EventType.CoreChangeEvent const BuildTeamChangeEvent = Packages.mindustry.game.EventType.BuildTeamChangeEvent const TileChangeEvent = Packages.mindustry.game.EventType.TileChangeEvent const TilePreChangeEvent = Packages.mindustry.game.EventType.TilePreChangeEvent +const BuildDamageEvent = Packages.mindustry.game.EventType.BuildDamageEvent const GameOverEvent = Packages.mindustry.game.EventType.GameOverEvent const UnitControlEvent = Packages.mindustry.game.EventType.UnitControlEvent const PickupEvent = Packages.mindustry.game.EventType.PickupEvent diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index c5c0b421a5..fd413e6284 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -12,6 +12,7 @@ import mindustry.entities.abilities.*; import mindustry.entities.bullet.*; import mindustry.entities.effect.*; import mindustry.entities.part.*; +import mindustry.entities.pattern.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; @@ -194,9 +195,10 @@ public class UnitTypes{ shake = 2f; ejectEffect = Fx.casing3; shootSound = Sounds.bang; - shots = 3; inaccuracy = 3f; - shotDelay = 4f; + + shoot.shots = 3; + shoot.shotDelay = 4f; bullet = new BasicBulletType(7f, 50){{ width = 11f; @@ -350,10 +352,11 @@ public class UnitTypes{ shootY = 2.5f; reload = 36f; - shots = 3; inaccuracy = 35; - shotDelay = 0.5f; - spacing = 0f; + + shoot.shots = 3; + shoot.shotDelay = 0.5f; + ejectEffect = Fx.none; recoil = 2.5f; shootSound = Sounds.spark; @@ -459,7 +462,7 @@ public class UnitTypes{ shootY = 13f; x = y = 0f; - firstShotDelay = Fx.greenLaserChargeSmall.lifetime - 1f; + shoot.firstShotDelay = Fx.greenLaserChargeSmall.lifetime - 1f; parentizeEffects = true; reload = 155f; @@ -493,7 +496,7 @@ public class UnitTypes{ }}; shootStatus = StatusEffects.slow; - shootStatusDuration = bullet.lifetime + firstShotDelay; + shootStatusDuration = bullet.lifetime + shoot.firstShotDelay; }}); weapons.add(new RepairBeamWeapon("repair-beam-weapon-center-large"){{ @@ -547,7 +550,7 @@ public class UnitTypes{ shootStatusDuration = 60f * 2f; shootStatus = StatusEffects.unmoving; - firstShotDelay = Fx.greenLaserCharge.lifetime; + shoot.firstShotDelay = Fx.greenLaserCharge.lifetime; parentizeEffects = true; bullet = new LaserBulletType(){{ @@ -870,8 +873,11 @@ public class UnitTypes{ rotate = true; shadow = 12f; recoil = 3f; - shots = 2; - spacing = 17f; + + shoot = new SpreadPattern(){{ + shots = 2; + spread = 17f; + }}; bullet = new ShrapnelBulletType(){{ length = 90f; @@ -998,6 +1004,7 @@ public class UnitTypes{ range = 140f; faceTarget = false; armor = 3f; + itemCapacity = 0; targetFlags = new BlockFlag[]{BlockFlag.factory, null}; circleTarget = true; ammoType = new ItemAmmoType(Items.graphite); @@ -1036,6 +1043,7 @@ public class UnitTypes{ lowAltitude = true; forceMultiTarget = true; armor = 5f; + itemCapacity = 0; targetFlags = new BlockFlag[]{BlockFlag.launchPad, BlockFlag.storage, BlockFlag.battery, null}; engineOffset = 12f; @@ -1047,7 +1055,7 @@ public class UnitTypes{ x = 7f; rotate = true; shake = 1f; - shots = 2; + shoot.shots = 2; inaccuracy = 5f; velocityRnd = 0.2f; shootSound = Sounds.missile; @@ -1279,7 +1287,6 @@ public class UnitTypes{ ejectEffect = Fx.none; recoil = 2f; shootSound = Sounds.missile; - shots = 1; velocityRnd = 0.5f; inaccuracy = 15f; alternate = true; @@ -1586,7 +1593,6 @@ public class UnitTypes{ recoil = 4f; shadow = 12f; - shots = 1; inaccuracy = 3f; ejectEffect = Fx.casing3; shootSound = Sounds.artillery; @@ -1623,8 +1629,9 @@ public class UnitTypes{ rotateSpeed = 4f; rotate = true; - shots = 2; - shotDelay = 3f; + shoot.shots = 2; + shoot.shotDelay = 3f; + inaccuracy = 5f; velocityRnd = 0.1f; shootSound = Sounds.missile; @@ -1679,18 +1686,21 @@ public class UnitTypes{ shadow = 20f; - shootY = 2f; + shootY = 4.5f; recoil = 4f; reload = 45f; - shots = 6; - spacing = 10f; velocityRnd = 0.4f; inaccuracy = 7f; ejectEffect = Fx.none; - shake = 3f; + shake = 1f; shootSound = Sounds.missile; - xRand = 8f; - shotDelay = 1f; + + shoot = new AlternatePattern(){{ + shots = 6; + shotDelay = 1.5f; + spread = 4f; + barrels = 3; + }}; bullet = new MissileBulletType(4.2f, 42){{ homingPower = 0.12f; @@ -1727,8 +1737,9 @@ public class UnitTypes{ ejectEffect = Fx.casing3; shootSound = Sounds.shootBig; - shots = 3; - shotDelay = 4f; + shoot.shots = 3; + shoot.shotDelay = 4f; + inaccuracy = 1f; bullet = new BasicBulletType(7f, 57){{ width = 13f; @@ -1773,7 +1784,6 @@ public class UnitTypes{ shadow = 50f; shootSound = Sounds.railgun; - shots = 1; ejectEffect = Fx.none; bullet = new RailBulletType(){{ @@ -1828,13 +1838,14 @@ public class UnitTypes{ mirror = false; rotate = true; reload = 90f; - shots = 3; - shotDelay = 7f; x = y = shootX = shootY = 0f; shootSound = Sounds.mineDeploy; rotateSpeed = 180f; targetAir = false; + shoot.shots = 3; + shoot.shotDelay = 7f; + bullet = new BasicBulletType(){{ sprite = "mine-bullet"; width = height = 8f; @@ -2357,9 +2368,8 @@ public class UnitTypes{ x = 3f; y = 0.5f; rotate = true; - shots = 2; - shotDelay = 4f; - spacing = 0f; + shoot.shots = 2; + shoot.shotDelay = 4f; ejectEffect = Fx.casing1; bullet = new BasicBulletType(3f, 11){{ @@ -2396,10 +2406,13 @@ public class UnitTypes{ reload = 15f; x = 1f; y = 2f; - shots = 2; - spacing = 2f; + shoot = new SpreadPattern(){{ + shots = 2; + shotDelay = 3f; + spread = 2f; + }}; + inaccuracy = 3f; - shotDelay = 3f; ejectEffect = Fx.casing1; bullet = new BasicBulletType(3.5f, 11){{ @@ -2482,7 +2495,8 @@ public class UnitTypes{ heatColor = Color.valueOf("f9350f"); cooldownTime = 30f; - shots = 2; + //TODO alternating double pattern + shoot.shots = 2; bullet = new BasicBulletType(5f, 50){{ sprite = "missile-large"; @@ -2804,7 +2818,7 @@ public class UnitTypes{ shake = 3f; cooldownTime = 40f; - shots = 3; + shoot.shots = 3; inaccuracy = 3f; velocityRnd = 0.33f; heatColor = Color.red; @@ -2898,8 +2912,8 @@ public class UnitTypes{ cooldownTime = 20f; layerOffset = 0.02f; - shots = 3; - shotDelay = 3f; + shoot.shots = 3; + shoot.shotDelay = 3f; inaccuracy = 2f; velocityRnd = 0.1f; heatColor = Color.red; @@ -3100,8 +3114,8 @@ public class UnitTypes{ shootWarmupSpeed = 0.1f; shootY = 2f; shootCone = 40f; - shots = 3; - shotDelay = 5f; + shoot.shots = 3; + shoot.shotDelay = 5f; inaccuracy = 28f; parts.add(new RegionPart("-blade"){{ diff --git a/core/src/mindustry/entities/pattern/AlternatePattern.java b/core/src/mindustry/entities/pattern/AlternatePattern.java new file mode 100644 index 0000000000..ca7e277131 --- /dev/null +++ b/core/src/mindustry/entities/pattern/AlternatePattern.java @@ -0,0 +1,18 @@ +package mindustry.entities.pattern; + +public class AlternatePattern extends ShotPattern{ + /** number of barrels used for shooting. */ + public int barrels = 2; + /** spread between barrels, in world units - not degrees. */ + public float spread = 5f; + /** offset of barrel to start on */ + public int barrelOffset = 0; + + @Override + public void shoot(int totalShots, BulletHandler handler){ + for(int i = 0; i < shots; i++){ + float index = ((totalShots + i + barrelOffset) % barrels) - (barrels-1)/2f; + handler.shoot(index * spread, 0, 0f, firstShotDelay + shotDelay * i); + } + } +} diff --git a/core/src/mindustry/entities/pattern/MultiPattern.java b/core/src/mindustry/entities/pattern/MultiPattern.java new file mode 100644 index 0000000000..9333ba12ed --- /dev/null +++ b/core/src/mindustry/entities/pattern/MultiPattern.java @@ -0,0 +1,25 @@ +package mindustry.entities.pattern; + +public class MultiPattern extends ShotPattern{ + public ShotPattern source; + public ShotPattern[] dest = {}; + + public MultiPattern(ShotPattern source, ShotPattern... dest){ + this.source = source; + this.dest = dest; + } + + public MultiPattern(){ + } + + @Override + public void shoot(int totalShots, BulletHandler handler){ + source.shoot(totalShots, (x, y, rotation, delay) -> { + for(var pattern : dest){ + pattern.shoot(totalShots, (x2, y2, rot2, delay2) -> { + handler.shoot(x + x2, y + y2, rotation + rot2, delay + delay2); + }); + } + }); + } +} diff --git a/core/src/mindustry/entities/pattern/ShotPattern.java b/core/src/mindustry/entities/pattern/ShotPattern.java index 01f183e527..86a987b46f 100644 --- a/core/src/mindustry/entities/pattern/ShotPattern.java +++ b/core/src/mindustry/entities/pattern/ShotPattern.java @@ -1,12 +1,28 @@ package mindustry.entities.pattern; -import arc.func.*; -import arc.math.geom.*; - -//TODO +/** Handles different types of bullet patterns for shooting. */ public class ShotPattern{ + /** amount of shots per "trigger pull" */ + public int shots = 1; + /** delay in ticks before first shot */ + public float firstShotDelay = 0; + /** delay in ticks between shots */ + public float shotDelay = 0; - public void shoot(float x, float y, Cons positionHandler){ + /** Called on a single "trigger pull". This function should call the handler with any bullets that result. */ + public void shoot(int totalShots, BulletHandler handler){ + for(int i = 0; i < shots; i++){ + handler.shoot(0, 0, 0, firstShotDelay + shotDelay * i); + } + } + public interface BulletHandler{ + /** + * @param x x offset of bullet, should be transformed by weapon rotation + * @param y y offset of bullet, should be transformed by weapon rotation + * @param rotation rotation offset relative to weapon + * @param delay bullet delay in ticks + * */ + void shoot(float x, float y, float rotation, float delay); } } diff --git a/core/src/mindustry/entities/pattern/SinePattern.java b/core/src/mindustry/entities/pattern/SinePattern.java new file mode 100644 index 0000000000..bc6163d911 --- /dev/null +++ b/core/src/mindustry/entities/pattern/SinePattern.java @@ -0,0 +1,26 @@ +package mindustry.entities.pattern; + +import arc.math.*; + +public class SinePattern extends ShotPattern{ + /** scaling applied to bullet index */ + public float scl = 4f; + /** magnitude of sine curve for position displacement */ + public float mag = 20f; + + public SinePattern(float scl, float mag){ + this.scl = scl; + this.mag = mag; + } + + public SinePattern(){ + } + + @Override + public void shoot(int totalShots, BulletHandler handler){ + for(int i = 0; i < shots; i++){ + float angleOffset = Mathf.sin(i + totalShots, scl, mag); + handler.shoot(0, 0, angleOffset, firstShotDelay + shotDelay * i); + } + } +} diff --git a/core/src/mindustry/entities/pattern/SpreadPattern.java b/core/src/mindustry/entities/pattern/SpreadPattern.java new file mode 100644 index 0000000000..fd10d04fef --- /dev/null +++ b/core/src/mindustry/entities/pattern/SpreadPattern.java @@ -0,0 +1,14 @@ +package mindustry.entities.pattern; + +public class SpreadPattern extends ShotPattern{ + /** spread between bullets, in degrees. */ + public float spread = 5f; + + @Override + public void shoot(int totalShots, BulletHandler handler){ + for(int i = 0; i < shots; i++){ + float angleOffset = i * spread - (shots - 1) * spread / 2f; + handler.shoot(0, 0, angleOffset, firstShotDelay + shotDelay * i); + } + } +} diff --git a/core/src/mindustry/entities/units/WeaponMount.java b/core/src/mindustry/entities/units/WeaponMount.java index 8473edaf9c..31cf3b4246 100644 --- a/core/src/mindustry/entities/units/WeaponMount.java +++ b/core/src/mindustry/entities/units/WeaponMount.java @@ -30,6 +30,8 @@ public class WeaponMount{ public boolean rotate = false; /** extra state for alternating weapons */ public boolean side; + /** total bullets fired from this mount; used for alternating patterns */ + public int totalShots; /** current bullet for continuous weapons */ public @Nullable Bullet bullet; /** sound loop for continuous weapons */ diff --git a/core/src/mindustry/graphics/CacheLayer.java b/core/src/mindustry/graphics/CacheLayer.java index 746c39a8b4..c68fd0db3d 100644 --- a/core/src/mindustry/graphics/CacheLayer.java +++ b/core/src/mindustry/graphics/CacheLayer.java @@ -10,7 +10,8 @@ import static mindustry.Vars.*; public class CacheLayer{ public static CacheLayer - water, mud, cryofluid, tar, slag, arkycite, space, normal, walls; + water, mud, cryofluid, tar, slag, arkycite, + space, normal, walls; public static CacheLayer[] all = {}; diff --git a/core/src/mindustry/maps/filters/BlendFilter.java b/core/src/mindustry/maps/filters/BlendFilter.java index 773459d75a..70b3b0408b 100644 --- a/core/src/mindustry/maps/filters/BlendFilter.java +++ b/core/src/mindustry/maps/filters/BlendFilter.java @@ -7,8 +7,8 @@ import mindustry.world.*; import static mindustry.maps.filters.FilterOption.*; public class BlendFilter extends GenerateFilter{ - float radius = 2f; - Block block = Blocks.sand, floor = Blocks.sandWater, ignore = Blocks.air; + public float radius = 2f; + public Block block = Blocks.sand, floor = Blocks.sandWater, ignore = Blocks.air; @Override public FilterOption[] options(){ diff --git a/core/src/mindustry/maps/filters/ClearFilter.java b/core/src/mindustry/maps/filters/ClearFilter.java index 6d9073dba5..f7e1203985 100644 --- a/core/src/mindustry/maps/filters/ClearFilter.java +++ b/core/src/mindustry/maps/filters/ClearFilter.java @@ -7,8 +7,8 @@ import mindustry.world.*; import static mindustry.maps.filters.FilterOption.*; public class ClearFilter extends GenerateFilter{ - protected Block target = Blocks.stone; - protected Block replace = Blocks.air; + public Block target = Blocks.stone; + public Block replace = Blocks.air; @Override public FilterOption[] options(){ diff --git a/core/src/mindustry/maps/filters/CoreSpawnFilter.java b/core/src/mindustry/maps/filters/CoreSpawnFilter.java index 5e18726d45..3e0e0b611f 100644 --- a/core/src/mindustry/maps/filters/CoreSpawnFilter.java +++ b/core/src/mindustry/maps/filters/CoreSpawnFilter.java @@ -9,7 +9,7 @@ import static mindustry.Vars.*; /** Selects X spawns from the core spawn pool.*/ public class CoreSpawnFilter extends GenerateFilter{ - int amount = 1; + public int amount = 1; @Override public FilterOption[] options(){ diff --git a/core/src/mindustry/maps/filters/DistortFilter.java b/core/src/mindustry/maps/filters/DistortFilter.java index c1d6baa69e..6c20e19276 100644 --- a/core/src/mindustry/maps/filters/DistortFilter.java +++ b/core/src/mindustry/maps/filters/DistortFilter.java @@ -5,7 +5,7 @@ import mindustry.maps.filters.FilterOption.*; import mindustry.world.*; public class DistortFilter extends GenerateFilter{ - float scl = 40, mag = 5; + public float scl = 40, mag = 5; @Override public FilterOption[] options(){ diff --git a/core/src/mindustry/maps/filters/EnemySpawnFilter.java b/core/src/mindustry/maps/filters/EnemySpawnFilter.java index 7d2a5d8d1d..ba38a81e32 100644 --- a/core/src/mindustry/maps/filters/EnemySpawnFilter.java +++ b/core/src/mindustry/maps/filters/EnemySpawnFilter.java @@ -8,7 +8,7 @@ import mindustry.world.*; /** Selects X spawns from the spawn pool.*/ public class EnemySpawnFilter extends GenerateFilter{ - int amount = 1; + public int amount = 1; @Override public FilterOption[] options(){ diff --git a/core/src/mindustry/maps/filters/MedianFilter.java b/core/src/mindustry/maps/filters/MedianFilter.java index 35d08f814d..04074ece5c 100644 --- a/core/src/mindustry/maps/filters/MedianFilter.java +++ b/core/src/mindustry/maps/filters/MedianFilter.java @@ -11,8 +11,8 @@ import static mindustry.Vars.*; public class MedianFilter extends GenerateFilter{ private static final IntSeq blocks = new IntSeq(), floors = new IntSeq(); - float radius = 2; - float percentile = 0.5f; + public float radius = 2; + public float percentile = 0.5f; @Override public FilterOption[] options(){ diff --git a/core/src/mindustry/maps/filters/MirrorFilter.java b/core/src/mindustry/maps/filters/MirrorFilter.java index d96c3a6b5f..1a53d8077b 100644 --- a/core/src/mindustry/maps/filters/MirrorFilter.java +++ b/core/src/mindustry/maps/filters/MirrorFilter.java @@ -14,8 +14,8 @@ import mindustry.world.*; public class MirrorFilter extends GenerateFilter{ private static final Vec2 v1 = new Vec2(), v2 = new Vec2(), v3 = new Vec2(); - int angle = 45; - boolean rotate = false; + public int angle = 45; + public boolean rotate = false; @Override public FilterOption[] options(){ diff --git a/core/src/mindustry/maps/filters/OreMedianFilter.java b/core/src/mindustry/maps/filters/OreMedianFilter.java index 9409604c23..072b8bb632 100644 --- a/core/src/mindustry/maps/filters/OreMedianFilter.java +++ b/core/src/mindustry/maps/filters/OreMedianFilter.java @@ -9,11 +9,11 @@ import mindustry.maps.filters.FilterOption.*; import mindustry.world.*; public class OreMedianFilter extends GenerateFilter{ + private static IntSeq blocks = new IntSeq(); + public float radius = 2; public float percentile = 0.5f; - private IntSeq blocks = new IntSeq(); - @Override public FilterOption[] options(){ return new SliderOption[]{ diff --git a/core/src/mindustry/maps/filters/RiverNoiseFilter.java b/core/src/mindustry/maps/filters/RiverNoiseFilter.java index eb91954b43..171b72ebe7 100644 --- a/core/src/mindustry/maps/filters/RiverNoiseFilter.java +++ b/core/src/mindustry/maps/filters/RiverNoiseFilter.java @@ -7,8 +7,8 @@ import mindustry.world.*; import static mindustry.maps.filters.FilterOption.*; public class RiverNoiseFilter extends GenerateFilter{ - float scl = 40, threshold = 0f, threshold2 = 0.1f, octaves = 1, falloff = 0.5f; - Block floor = Blocks.water, floor2 = Blocks.deepwater, block = Blocks.sandWall, target = Blocks.air; + public float scl = 40, threshold = 0f, threshold2 = 0.1f, octaves = 1, falloff = 0.5f; + public Block floor = Blocks.water, floor2 = Blocks.deepwater, block = Blocks.sandWall, target = Blocks.air; @Override public FilterOption[] options(){ diff --git a/core/src/mindustry/maps/filters/TerrainFilter.java b/core/src/mindustry/maps/filters/TerrainFilter.java index 8f05530004..290f65b4cd 100644 --- a/core/src/mindustry/maps/filters/TerrainFilter.java +++ b/core/src/mindustry/maps/filters/TerrainFilter.java @@ -8,8 +8,8 @@ import mindustry.world.*; import static mindustry.maps.filters.FilterOption.*; public class TerrainFilter extends GenerateFilter{ - float scl = 40, threshold = 0.9f, octaves = 3f, falloff = 0.5f, magnitude = 1f, circleScl = 2.1f, tilt = 0f; - Block floor = Blocks.air, block = Blocks.stoneWall; + public float scl = 40, threshold = 0.9f, octaves = 3f, falloff = 0.5f, magnitude = 1f, circleScl = 2.1f, tilt = 0f; + public Block floor = Blocks.air, block = Blocks.stoneWall; @Override public FilterOption[] options(){ diff --git a/core/src/mindustry/mod/ClassMap.java b/core/src/mindustry/mod/ClassMap.java index 3172b00a07..f76581b351 100644 --- a/core/src/mindustry/mod/ClassMap.java +++ b/core/src/mindustry/mod/ClassMap.java @@ -1,10 +1,6 @@ package mindustry.mod; import arc.struct.*; -import mindustry.type.*; -import mindustry.world.blocks.legacy.*; -import mindustry.world.consumers.*; - /** Generated class. Maps simple class names to concrete classes. For use in JSON mods. */ @SuppressWarnings("deprecation") public class ClassMap{ @@ -68,6 +64,12 @@ public class ClassMap{ classes.put("SeqEffect", mindustry.entities.effect.SeqEffect.class); classes.put("WaveEffect", mindustry.entities.effect.WaveEffect.class); classes.put("WrapEffect", mindustry.entities.effect.WrapEffect.class); + classes.put("AlternatePattern", mindustry.entities.pattern.AlternatePattern.class); + classes.put("MultiPattern", mindustry.entities.pattern.MultiPattern.class); + classes.put("ShotPattern", mindustry.entities.pattern.ShotPattern.class); + classes.put("BulletHandler", mindustry.entities.pattern.ShotPattern.BulletHandler.class); + classes.put("SinePattern", mindustry.entities.pattern.SinePattern.class); + classes.put("SpreadPattern", mindustry.entities.pattern.SpreadPattern.class); classes.put("Objectives", mindustry.game.Objectives.class); classes.put("Objective", mindustry.game.Objectives.Objective.class); classes.put("OnPlanet", mindustry.game.Objectives.OnPlanet.class); @@ -76,8 +78,6 @@ public class ClassMap{ classes.put("Research", mindustry.game.Objectives.Research.class); classes.put("SectorComplete", mindustry.game.Objectives.SectorComplete.class); classes.put("AmmoType", mindustry.type.AmmoType.class); - classes.put("BlockSeq", PayloadSeq.class); - classes.put("BlockStack", PayloadStack.class); classes.put("Category", mindustry.type.Category.class); classes.put("CellLiquid", mindustry.type.CellLiquid.class); classes.put("ErrorContent", mindustry.type.ErrorContent.class); @@ -86,6 +86,8 @@ public class ClassMap{ classes.put("ItemStack", mindustry.type.ItemStack.class); classes.put("Liquid", mindustry.type.Liquid.class); classes.put("LiquidStack", mindustry.type.LiquidStack.class); + classes.put("PayloadSeq", mindustry.type.PayloadSeq.class); + classes.put("PayloadStack", mindustry.type.PayloadStack.class); classes.put("Planet", mindustry.type.Planet.class); classes.put("Publishable", mindustry.type.Publishable.class); classes.put("Satellite", mindustry.type.Satellite.class); @@ -238,6 +240,8 @@ public class ClassMap{ classes.put("HeatProducer", mindustry.world.blocks.heat.HeatProducer.class); classes.put("HeatProducerBuild", mindustry.world.blocks.heat.HeatProducer.HeatProducerBuild.class); classes.put("LegacyBlock", mindustry.world.blocks.legacy.LegacyBlock.class); + classes.put("LegacyCommandCenter", mindustry.world.blocks.legacy.LegacyCommandCenter.class); + classes.put("CommandBuild", mindustry.world.blocks.legacy.LegacyCommandCenter.CommandBuild.class); classes.put("LegacyMechPad", mindustry.world.blocks.legacy.LegacyMechPad.class); classes.put("LegacyMechPadBuild", mindustry.world.blocks.legacy.LegacyMechPad.LegacyMechPadBuild.class); classes.put("LegacyUnitFactory", mindustry.world.blocks.legacy.LegacyUnitFactory.class); @@ -297,10 +301,8 @@ public class ClassMap{ classes.put("BatteryBuild", mindustry.world.blocks.power.Battery.BatteryBuild.class); classes.put("BeamNode", mindustry.world.blocks.power.BeamNode.class); classes.put("BeamNodeBuild", mindustry.world.blocks.power.BeamNode.BeamNodeBuild.class); - classes.put("ConditionalConsumePower", ConsumePowerCondition.class); classes.put("ConsumeGenerator", mindustry.world.blocks.power.ConsumeGenerator.class); classes.put("ConsumeGeneratorBuild", mindustry.world.blocks.power.ConsumeGenerator.ConsumeGeneratorBuild.class); - classes.put("DynamicConsumePower", ConsumePowerDynamic.class); classes.put("ImpactReactor", mindustry.world.blocks.power.ImpactReactor.class); classes.put("ImpactReactorBuild", mindustry.world.blocks.power.ImpactReactor.ImpactReactorBuild.class); classes.put("LightBlock", mindustry.world.blocks.power.LightBlock.class); @@ -368,8 +370,6 @@ public class ClassMap{ classes.put("Unloader", mindustry.world.blocks.storage.Unloader.class); classes.put("ContainerStat", mindustry.world.blocks.storage.Unloader.ContainerStat.class); classes.put("UnloaderBuild", mindustry.world.blocks.storage.Unloader.UnloaderBuild.class); - classes.put("CommandCenter", LegacyCommandCenter.class); - classes.put("CommandBuild", LegacyCommandCenter.CommandBuild.class); classes.put("ControlCore", mindustry.world.blocks.units.ControlCore.class); classes.put("DroneCenter", mindustry.world.blocks.units.DroneCenter.class); classes.put("DroneCenterBuild", mindustry.world.blocks.units.DroneCenter.DroneCenterBuild.class); diff --git a/core/src/mindustry/mod/ContentParser.java b/core/src/mindustry/mod/ContentParser.java index c67901a980..d30eb85a6b 100644 --- a/core/src/mindustry/mod/ContentParser.java +++ b/core/src/mindustry/mod/ContentParser.java @@ -27,6 +27,7 @@ import mindustry.entities.bullet.*; import mindustry.entities.effect.*; import mindustry.entities.part.*; import mindustry.entities.part.DrawPart.*; +import mindustry.entities.pattern.*; import mindustry.game.*; import mindustry.game.Objectives.*; import mindustry.gen.*; @@ -136,6 +137,13 @@ public class ContentParser{ readFields(result, data); return result; }); + put(ShotPattern.class, (type, data) -> { + var bc = resolve(data.getString("type", ""), ShotPattern.class); + data.remove("type"); + var result = make(bc); + readFields(result, data); + return result; + }); put(DrawPart.class, (type, data) -> { var bc = resolve(data.getString("type", ""), RegionPart.class); data.remove("type"); diff --git a/core/src/mindustry/type/Weapon.java b/core/src/mindustry/type/Weapon.java index 3fe2cfca3b..7577b4cf96 100644 --- a/core/src/mindustry/type/Weapon.java +++ b/core/src/mindustry/type/Weapon.java @@ -15,6 +15,7 @@ import mindustry.content.*; import mindustry.entities.*; import mindustry.entities.bullet.*; import mindustry.entities.part.*; +import mindustry.entities.pattern.*; import mindustry.entities.units.*; import mindustry.gen.*; import mindustry.graphics.*; @@ -55,10 +56,7 @@ public class Weapon implements Cloneable{ public float rotateSpeed = 20f; /** weapon reload in frames */ public float reload; - /** amount of shots per fire */ - public int shots = 1; - /** spacing in degrees between multiple shots, if applicable */ - public float spacing = 0; + /** inaccuracy of degrees of each shot */ public float inaccuracy = 0f; /** intensity and duration of each shot's screen shake */ @@ -71,16 +69,12 @@ public class Weapon implements Cloneable{ public float shootX = 0f, shootY = 3f; /** offsets of weapon position on unit */ public float x = 5f, y = 0f; - /** random spread on the X axis */ - public float xRand = 0f; + /** pattern used for bullets */ + public ShotPattern shoot = new ShotPattern(); /** radius of shadow drawn under the weapon; <0 to disable */ public float shadow = -1f; /** fraction of velocity that is random */ public float velocityRnd = 0f; - /** delay in ticks between shots */ - public float firstShotDelay = 0; - /** delay in ticks between shots */ - public float shotDelay = 0; /** The half-radius of the cone in which shooting will start. */ public float shootCone = 5f; /** Cone in which the weapon can rotate relative to its mount. */ @@ -144,13 +138,13 @@ public class Weapon implements Cloneable{ t.add("[lightgray]" + Stat.inaccuracy.localized() + ": [white]" + (int)inaccuracy + " " + StatUnit.degrees.localized()); } t.row(); - t.add("[lightgray]" + Stat.reload.localized() + ": " + (mirror ? "2x " : "") + "[white]" + Strings.autoFixed(60f / reload * shots, 2) + " " + StatUnit.perSecond.localized()); + t.add("[lightgray]" + Stat.reload.localized() + ": " + (mirror ? "2x " : "") + "[white]" + Strings.autoFixed(60f / reload * shoot.shots, 2) + " " + StatUnit.perSecond.localized()); StatValues.ammo(ObjectMap.of(u, bullet)).display(t); } public float dps(){ - return (bullet.estimateDPS() / reload) * shots * 60f; + return (bullet.estimateDPS() / reload) * shoot.shots * 60f; } //TODO copy-pasted code @@ -371,34 +365,29 @@ public class Weapon implements Cloneable{ protected void shoot(Unit unit, WeaponMount mount, float shootX, float shootY, float rotation){ unit.apply(shootStatus, shootStatusDuration); - if(firstShotDelay > 0){ + if(shoot.firstShotDelay > 0){ chargeSound.at(shootX, shootY, Mathf.random(soundPitchMin, soundPitchMax)); bullet.chargeEffect.at(shootX, shootY, rotation, bullet.keepVelocity || parentizeEffects ? unit : null); } - //shot patterns should be able to customize: - //- the position of a specific bullet index - //- the delay of a specific bullet index - - //TODO merge with Turret behavior if possible - for(int i = 0; i < shots; i++){ - float angleOffset = i * spacing - (shots - 1) * spacing / 2f; - if(firstShotDelay + shotDelay > 0f){ - Time.run(i * shotDelay + firstShotDelay, () -> shoot(unit, mount, angleOffset)); + shoot.shoot(mount.totalShots, (xOffset, yOffset, angle, delay) -> { + if(delay > 0f){ + Time.run(delay, () -> setupBullet(unit, mount, xOffset, yOffset, angle)); }else{ - shoot(unit, mount, angleOffset); + setupBullet(unit, mount, xOffset, yOffset, angle); } - } + mount.totalShots ++; + }); } - protected void shoot(Unit unit, WeaponMount mount, float angleOffset){ + protected void setupBullet(Unit unit, WeaponMount mount, float xOffset, float yOffset, float angleOffset){ float weaponRotation = unit.rotation - 90 + (rotate ? mount.rotation : 0), mountX = unit.x + Angles.trnsx(unit.rotation - 90, x, y), mountY = unit.y + Angles.trnsy(unit.rotation - 90, x, y), - bulletX = mountX + Angles.trnsx(weaponRotation, this.shootX, this.shootY), - bulletY = mountY + Angles.trnsy(weaponRotation, this.shootX, this.shootY), - shootAngle = bulletRotation(unit, mount, bulletX, bulletY), + bulletX = mountX + Angles.trnsx(weaponRotation, this.shootX, this.shootY) + Angles.trnsx(weaponRotation, xOffset, yOffset), + bulletY = mountY + Angles.trnsy(weaponRotation, this.shootX, this.shootY) + Angles.trnsy(weaponRotation, xOffset, yOffset), + shootAngle = bulletRotation(unit, mount, bulletX, bulletY) + angleOffset, lifeScl = bullet.scaleVelocity ? Mathf.clamp(Mathf.dst(shootX, shootY, mount.aimX, mount.aimY) / bullet.range) : 1f; bullet(mount, unit, bulletX, bulletY, angleOffset + shootAngle + Mathf.range(inaccuracy), lifeScl, shootAngle, mountX, mountY); @@ -407,10 +396,7 @@ public class Weapon implements Cloneable{ protected void bullet(WeaponMount mount, Unit unit, float shootX, float shootY, float angle, float lifescl, float mountRotation, float mountX, float mountY){ if(!unit.isAdded()) return; - //TODO should be part of shoot pattern. - float xr = Mathf.range(xRand), x = shootX + Angles.trnsx(angle, 0, xr), y = shootY + Angles.trnsy(angle, 0, xr); - - mount.bullet = bullet.create(unit, unit.team, x, y, angle, (1f - velocityRnd) + Mathf.random(velocityRnd), lifescl); + mount.bullet = bullet.create(unit, unit.team, shootX, shootY, angle, (1f - velocityRnd) + Mathf.random(velocityRnd), lifescl); if(!continuous){ shootSound.at(shootX, shootY, Mathf.random(soundPitchMin, soundPitchMax)); diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java index 2259264cbd..c23b72822e 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java @@ -538,8 +538,8 @@ public class Turret extends ReloadTurret{ for(int c = 0; c < count; c++){ float i = (shotCounter % shots) - (shots-1)/2f; - bulletOffset.trns(rotation - 90, (spread) * i + Mathf.range(xRand), shootLength); + bullet(type, rotation + Mathf.range(inaccuracy + type.inaccuracy)); shotCounter ++; } diff --git a/tools/src/mindustry/tools/ScriptMainGenerator.java b/tools/src/mindustry/tools/ScriptMainGenerator.java index 8a7b8004b1..5f489d4e4a 100644 --- a/tools/src/mindustry/tools/ScriptMainGenerator.java +++ b/tools/src/mindustry/tools/ScriptMainGenerator.java @@ -84,7 +84,8 @@ public class ScriptMainGenerator{ "mindustry.game.Objectives", "mindustry.world.blocks", "mindustry.world.draw", - "mindustry.type" + "mindustry.type", + "mindustry.entities.pattern" ); String classTemplate = "package mindustry.mod;\n" +