1
0
mirror of https://github.com/Anuken/Mindustry.git synced 2024-09-11 08:15:35 +03:00

New weapon pattern system

This commit is contained in:
Anuken 2022-02-24 20:06:52 -05:00
parent 30787e49ad
commit c3e9a961c5
24 changed files with 219 additions and 126 deletions

View File

@ -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

View File

@ -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"){{

View File

@ -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);
}
}
}

View File

@ -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);
});
}
});
}
}

View File

@ -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<Vec2> 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);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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 */

View File

@ -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 = {};

View File

@ -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(){

View File

@ -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(){

View File

@ -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(){

View File

@ -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(){

View File

@ -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(){

View File

@ -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(){

View File

@ -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(){

View File

@ -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[]{

View File

@ -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(){

View File

@ -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(){

View File

@ -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);

View File

@ -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");

View File

@ -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));

View File

@ -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 ++;
}

View File

@ -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" +