mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-07-31 15:09:07 +07:00
Ammo stats
This commit is contained in:
@ -397,6 +397,19 @@ blocks.fuelburntime = Fuel Burn Time
|
||||
blocks.inputcapacity = Input capacity
|
||||
blocks.outputcapacity = Output capacity
|
||||
blocks.ammo = Ammo
|
||||
|
||||
bullet.damage = [stat]{0}[lightgray] dmg
|
||||
bullet.splashdamage = [stat]{0}[lightgray] area dmg ~[stat] {1}[lightgray] tiles
|
||||
bullet.incendiary = [stat]incendiary
|
||||
bullet.homing = [stat]homing
|
||||
bullet.shock = [stat]shock
|
||||
bullet.frag = [stat]frag
|
||||
bullet.knockback = [stat]{0}[lightgray] knockback
|
||||
bullet.freezing = [stat]freezing
|
||||
bullet.tarred = [stat]tarred
|
||||
bullet.multiplier = [stat]{0}[lightgray]x ammo multiplier
|
||||
bullet.reload = [stat]{0}[lightgray]x reload
|
||||
|
||||
unit.blocks = blocks
|
||||
unit.powersecond = power units/second
|
||||
unit.liquidsecond = liquid units/second
|
||||
|
@ -294,7 +294,6 @@ public class Bullets implements ContentList{
|
||||
standardDense = new BasicBulletType(3.5f, 18, "bullet"){{
|
||||
bulletWidth = 9f;
|
||||
bulletHeight = 12f;
|
||||
armorPierce = 0.2f;
|
||||
reloadMultiplier = 0.6f;
|
||||
ammoMultiplier = 2;
|
||||
}};
|
||||
@ -302,7 +301,6 @@ public class Bullets implements ContentList{
|
||||
standardThorium = new BasicBulletType(4f, 29, "bullet"){{
|
||||
bulletWidth = 10f;
|
||||
bulletHeight = 13f;
|
||||
armorPierce = 0.5f;
|
||||
shootEffect = Fx.shootBig;
|
||||
smokeEffect = Fx.shootBigSmoke;
|
||||
ammoMultiplier = 2;
|
||||
@ -348,14 +346,12 @@ public class Bullets implements ContentList{
|
||||
standardDenseBig = new BasicBulletType(7f, 42, "bullet"){{
|
||||
bulletWidth = 15f;
|
||||
bulletHeight = 21f;
|
||||
armorPierce = 0.2f;
|
||||
shootEffect = Fx.shootBig;
|
||||
}};
|
||||
|
||||
standardThoriumBig = new BasicBulletType(8f, 65, "bullet"){{
|
||||
bulletWidth = 16f;
|
||||
bulletHeight = 23f;
|
||||
armorPierce = 0.5f;
|
||||
shootEffect = Fx.shootBig;
|
||||
}};
|
||||
|
||||
|
@ -108,6 +108,7 @@ public class UI implements ApplicationListener{
|
||||
});
|
||||
|
||||
Colors.put("accent", Pal.accent);
|
||||
Colors.put("stat", Pal.stat);
|
||||
|
||||
loadCursors();
|
||||
}
|
||||
|
@ -4,13 +4,6 @@ import io.anuke.arc.Core;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.math.Angles;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.mindustry.entities.Damage;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.effect.Lightning;
|
||||
import io.anuke.mindustry.entities.traits.TargetTrait;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
|
||||
/**An extended BulletType for most ammo-based bullets shot from turrets and units.*/
|
||||
@ -20,28 +13,9 @@ public class BasicBulletType extends BulletType{
|
||||
public float bulletShrink = 0.5f;
|
||||
public String bulletSprite;
|
||||
|
||||
public int fragBullets = 9;
|
||||
public float fragVelocityMin = 0.2f, fragVelocityMax = 1f;
|
||||
public BulletType fragBullet = null;
|
||||
|
||||
/**Use a negative value to disable splash damage.*/
|
||||
public float splashDamageRadius = -1f;
|
||||
|
||||
public int incendAmount = 0;
|
||||
public float incendSpread = 8f;
|
||||
public float incendChance = 1f;
|
||||
|
||||
public float homingPower = 0f;
|
||||
public float homingRange = 50f;
|
||||
|
||||
public int lightining;
|
||||
public int lightningLength = 5;
|
||||
|
||||
public TextureRegion backRegion;
|
||||
public TextureRegion frontRegion;
|
||||
|
||||
public float hitShake = 0f;
|
||||
|
||||
public BasicBulletType(float speed, float damage, String bulletSprite){
|
||||
super(speed, damage);
|
||||
this.bulletSprite = bulletSprite;
|
||||
@ -63,51 +37,4 @@ public class BasicBulletType extends BulletType{
|
||||
Draw.rect(frontRegion, b.x, b.y, bulletWidth, height, b.rot() - 90);
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Bullet b){
|
||||
super.update(b);
|
||||
|
||||
if(homingPower > 0.0001f){
|
||||
TargetTrait target = Units.getClosestTarget(b.getTeam(), b.x, b.y, homingRange);
|
||||
if(target != null){
|
||||
b.velocity().setAngle(Mathf.slerpDelta(b.velocity().angle(), b.angleTo(target), 0.08f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hit(Bullet b, float x, float y){
|
||||
super.hit(b, x, y);
|
||||
|
||||
Effects.shake(hitShake, hitShake, b);
|
||||
|
||||
if(fragBullet != null){
|
||||
for(int i = 0; i < fragBullets; i++){
|
||||
float len = Mathf.random(1f, 7f);
|
||||
float a = Mathf.random(360f);
|
||||
Bullet.create(fragBullet, b, x + Angles.trnsx(a, len), y + Angles.trnsy(a, len), a, Mathf.random(fragVelocityMin, fragVelocityMax));
|
||||
}
|
||||
}
|
||||
|
||||
if(Mathf.chance(incendChance)){
|
||||
Damage.createIncend(x, y, incendSpread, incendAmount);
|
||||
}
|
||||
|
||||
if(splashDamageRadius > 0){
|
||||
Damage.damage(b.getTeam(), x, y, splashDamageRadius, splashDamage);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void despawned(Bullet b){
|
||||
super.despawned(b);
|
||||
if(fragBullet != null || splashDamageRadius > 0){
|
||||
hit(b);
|
||||
}
|
||||
|
||||
for (int i = 0; i < lightining; i++) {
|
||||
Lightning.create(b.getTeam(), Pal.surge, damage, b.x, b.y, Mathf.random(360f), lightningLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,17 @@
|
||||
package io.anuke.mindustry.entities.bullet;
|
||||
|
||||
import io.anuke.arc.math.Angles;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.content.StatusEffects;
|
||||
import io.anuke.mindustry.entities.Damage;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Effects.Effect;
|
||||
import io.anuke.mindustry.content.StatusEffects;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.effect.Lightning;
|
||||
import io.anuke.mindustry.entities.traits.TargetTrait;
|
||||
import io.anuke.mindustry.game.Content;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.type.StatusEffect;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
@ -41,8 +48,6 @@ public abstract class BulletType extends Content{
|
||||
public StatusEffect status = StatusEffects.none;
|
||||
/**Intensity of applied status effect in terms of duration.*/
|
||||
public float statusDuration = 60 * 1f;
|
||||
/**What fraction of armor is pierced, 0-1*/
|
||||
public float armorPierce = 0f;
|
||||
/**Whether to sync this bullet to clients.*/
|
||||
public boolean syncable;
|
||||
/**Whether this bullet type collides with tiles.*/
|
||||
@ -56,6 +61,27 @@ public abstract class BulletType extends Content{
|
||||
/**Whether velocity is inherited from the shooter.*/
|
||||
public boolean keepVelocity = true;
|
||||
|
||||
//additional effects
|
||||
|
||||
public int fragBullets = 9;
|
||||
public float fragVelocityMin = 0.2f, fragVelocityMax = 1f;
|
||||
public BulletType fragBullet = null;
|
||||
|
||||
/**Use a negative value to disable splash damage.*/
|
||||
public float splashDamageRadius = -1f;
|
||||
|
||||
public int incendAmount = 0;
|
||||
public float incendSpread = 8f;
|
||||
public float incendChance = 1f;
|
||||
|
||||
public float homingPower = 0f;
|
||||
public float homingRange = 50f;
|
||||
|
||||
public int lightining;
|
||||
public int lightningLength = 5;
|
||||
|
||||
public float hitShake = 0f;
|
||||
|
||||
public BulletType(float speed, float damage){
|
||||
this.speed = speed;
|
||||
this.damage = damage;
|
||||
@ -81,12 +107,38 @@ public abstract class BulletType extends Content{
|
||||
hit(b, b.x, b.y);
|
||||
}
|
||||
|
||||
public void hit(Bullet b, float hitx, float hity){
|
||||
Effects.effect(hitEffect, hitx, hity, b.rot());
|
||||
public void hit(Bullet b, float x, float y){
|
||||
Effects.effect(hitEffect, x, y, b.rot());
|
||||
|
||||
Effects.shake(hitShake, hitShake, b);
|
||||
|
||||
if(fragBullet != null){
|
||||
for(int i = 0; i < fragBullets; i++){
|
||||
float len = Mathf.random(1f, 7f);
|
||||
float a = Mathf.random(360f);
|
||||
Bullet.create(fragBullet, b, x + Angles.trnsx(a, len), y + Angles.trnsy(a, len), a, Mathf.random(fragVelocityMin, fragVelocityMax));
|
||||
}
|
||||
}
|
||||
|
||||
if(Mathf.chance(incendChance)){
|
||||
Damage.createIncend(x, y, incendSpread, incendAmount);
|
||||
}
|
||||
|
||||
if(splashDamageRadius > 0){
|
||||
Damage.damage(b.getTeam(), x, y, splashDamageRadius, splashDamage);
|
||||
}
|
||||
}
|
||||
|
||||
public void despawned(Bullet b){
|
||||
Effects.effect(despawnEffect, b.x, b.y, b.rot());
|
||||
|
||||
if(fragBullet != null || splashDamageRadius > 0){
|
||||
hit(b);
|
||||
}
|
||||
|
||||
for (int i = 0; i < lightining; i++) {
|
||||
Lightning.create(b.getTeam(), Pal.surge, damage, b.x, b.y, Mathf.random(360f), lightningLength);
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(Bullet b){
|
||||
@ -96,6 +148,13 @@ public abstract class BulletType extends Content{
|
||||
}
|
||||
|
||||
public void update(Bullet b){
|
||||
|
||||
if(homingPower > 0.0001f){
|
||||
TargetTrait target = Units.getClosestTarget(b.getTeam(), b.x, b.y, homingRange);
|
||||
if(target != null){
|
||||
b.velocity().setAngle(Mathf.slerpDelta(b.velocity().angle(), b.angleTo(target), 0.08f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -48,6 +48,7 @@ public class Pal{
|
||||
heal = Color.valueOf("98ffa9"),
|
||||
bar = Color.SLATE,
|
||||
accent = Color.valueOf("ffd37f"),
|
||||
stat = Color.valueOf("ffd37f"),
|
||||
locked = Color.valueOf("989aa4"),
|
||||
accentBack = Color.valueOf("d4816b"),
|
||||
place = Color.valueOf("6335f8"),
|
||||
|
@ -3,6 +3,8 @@ package io.anuke.mindustry.world.blocks.defense.turrets;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.meta.BlockStat;
|
||||
import io.anuke.mindustry.world.meta.StatUnit;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
|
||||
@ -14,6 +16,14 @@ public class DoubleTurret extends ItemTurret{
|
||||
shots = 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.remove(BlockStat.reload);
|
||||
stats.add(BlockStat.reload, 60f / reload, StatUnit.none);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void shoot(Tile tile, BulletType ammo){
|
||||
TurretEntity entity = tile.entity();
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.anuke.mindustry.world.blocks.defense.turrets;
|
||||
|
||||
import io.anuke.arc.collection.ObjectMap;
|
||||
import io.anuke.arc.collection.OrderedMap;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
@ -11,7 +12,7 @@ import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.ui.Bar;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.meta.BlockStat;
|
||||
import io.anuke.mindustry.world.meta.values.ItemFilterValue;
|
||||
import io.anuke.mindustry.world.meta.values.AmmoListValue;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
@ -28,7 +29,7 @@ public class ItemTurret extends CooledTurret{
|
||||
|
||||
/**Initializes accepted ammo map. Format: [item1, bullet1, item2, bullet2...]*/
|
||||
protected void ammo(Object... objects){
|
||||
ammo = ObjectMap.of(objects);
|
||||
ammo = OrderedMap.of(objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -36,7 +37,7 @@ public class ItemTurret extends CooledTurret{
|
||||
super.setStats();
|
||||
|
||||
stats.remove(BlockStat.itemCapacity);
|
||||
stats.add(BlockStat.inputItems, new ItemFilterValue(item -> ammo.containsKey(item)));
|
||||
stats.add(BlockStat.ammo, new AmmoListValue<>(ammo));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.anuke.mindustry.world.blocks.defense.turrets;
|
||||
|
||||
import io.anuke.arc.collection.ObjectMap;
|
||||
import io.anuke.arc.collection.OrderedMap;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
import io.anuke.mindustry.entities.effect.Fire;
|
||||
@ -8,7 +9,7 @@ import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Liquid;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.meta.BlockStat;
|
||||
import io.anuke.mindustry.world.meta.values.LiquidFilterValue;
|
||||
import io.anuke.mindustry.world.meta.values.AmmoListValue;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
@ -23,14 +24,14 @@ public abstract class LiquidTurret extends Turret{
|
||||
|
||||
/**Initializes accepted ammo map. Format: [liquid1, bullet1, liquid2, bullet2...]*/
|
||||
protected void ammo(Object... objects){
|
||||
ammo = ObjectMap.of(objects);
|
||||
ammo = OrderedMap.of(objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
stats.add(BlockStat.inputLiquid, new LiquidFilterValue(item -> ammo.containsKey(item)));
|
||||
stats.add(BlockStat.ammo, new AmmoListValue<>(ammo));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -106,7 +106,7 @@ public abstract class Turret extends Block{
|
||||
|
||||
stats.add(BlockStat.shootRange, range, StatUnit.blocks);
|
||||
stats.add(BlockStat.inaccuracy, (int) inaccuracy, StatUnit.degrees);
|
||||
stats.add(BlockStat.reload, 60f / reload, StatUnit.none);
|
||||
stats.add(BlockStat.reload, 60f / reload * shots, StatUnit.none);
|
||||
stats.add(BlockStat.shots, shots, StatUnit.none);
|
||||
stats.add(BlockStat.targetsAir, targetAir);
|
||||
stats.add(BlockStat.targetsGround, targetGround);
|
||||
|
@ -41,6 +41,7 @@ public enum BlockStat{
|
||||
drillSpeed(StatCategory.crafting),
|
||||
maxUnits(StatCategory.crafting),
|
||||
|
||||
ammo(StatCategory.shooting),
|
||||
shootRange(StatCategory.shooting),
|
||||
inaccuracy(StatCategory.shooting),
|
||||
shots(StatCategory.shooting),
|
||||
|
@ -0,0 +1,87 @@
|
||||
package io.anuke.mindustry.world.meta.values;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.ObjectMap;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.util.Strings;
|
||||
import io.anuke.mindustry.content.StatusEffects;
|
||||
import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
import io.anuke.mindustry.game.UnlockableContent;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Item.Icon;
|
||||
import io.anuke.mindustry.world.meta.StatValue;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
|
||||
public class AmmoListValue<T extends UnlockableContent> implements StatValue{
|
||||
private final ObjectMap<T, BulletType> map;
|
||||
|
||||
public AmmoListValue(ObjectMap<T, BulletType> map){
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void display(Table table){
|
||||
|
||||
table.row();
|
||||
for(T t : map.keys()){
|
||||
BulletType type = map.get(t);
|
||||
table.addImage(icon(t)).size(3*8).padRight(4).right().top();
|
||||
table.add(t.localizedName()).padRight(10).left().top();
|
||||
table.table("underline", bt -> {
|
||||
bt.left().defaults().padRight(3).left();
|
||||
bt.add(Core.bundle.format("bullet.damage", type.damage));
|
||||
|
||||
if(type.splashDamage > 0){
|
||||
sep(bt, Core.bundle.format("bullet.splashdamage", (int)type.splashDamage, Strings.toFixed(type.splashDamageRadius / tilesize, 1)));
|
||||
}
|
||||
|
||||
if(!Mathf.isEqual(type.ammoMultiplier, 1f)) sep(bt, Core.bundle.format("bullet.multiplier", (int)type.ammoMultiplier));
|
||||
if(!Mathf.isEqual(type.reloadMultiplier, 1f)) sep(bt, Core.bundle.format("bullet.reload", Strings.toFixed(type.reloadMultiplier, 1)));
|
||||
|
||||
if(type.knockback > 0){
|
||||
sep(bt, Core.bundle.format("bullet.knockback", Strings.toFixed(type.knockback, 1)));
|
||||
}
|
||||
|
||||
if((type.status == StatusEffects.burning || type.status == StatusEffects.melting) || type.incendAmount > 0){
|
||||
sep(bt, "$bullet.incendiary");
|
||||
}
|
||||
|
||||
if(type.status == StatusEffects.freezing){
|
||||
sep(bt, "$bullet.freezing");
|
||||
}
|
||||
|
||||
if(type.status == StatusEffects.tarred){
|
||||
sep(bt, "$bullet.tarred");
|
||||
}
|
||||
|
||||
if(type.homingPower > 0.01f){
|
||||
sep(bt, "$bullet.homing");
|
||||
}
|
||||
|
||||
if(type.lightining > 0){
|
||||
sep(bt, "$bullet.shock");
|
||||
}
|
||||
|
||||
if(type.fragBullet != null){
|
||||
sep(bt, "$bullet.frag");
|
||||
}
|
||||
}).left().padTop(-9);
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
|
||||
void sep(Table table, String text){
|
||||
table.row();
|
||||
table.add(text);
|
||||
}
|
||||
|
||||
TextureRegion icon(T t){
|
||||
if(t instanceof Item){
|
||||
return ((Item)t).icon(Icon.medium);
|
||||
}
|
||||
return t.getContentIcon();
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user