mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-10-01 18:50:27 +03:00
Grouped targeting (closes #11537)
This commit is contained in:
@@ -3652,7 +3652,7 @@ public class Blocks{
|
||||
size = 1;
|
||||
health = 260;
|
||||
shootSound = Sounds.shootArc;
|
||||
|
||||
|
||||
consumePower(3.3f);
|
||||
coolant = consumeCoolant(0.1f);
|
||||
coolantMultiplier = 30f;
|
||||
@@ -4014,6 +4014,8 @@ public class Blocks{
|
||||
frontColor = Pal.siliconAmmoFront;
|
||||
lifeScaleRandMax = 1.08f;
|
||||
lifeScaleRandMin = 0.95f;
|
||||
|
||||
unitSort = UnitSorts.closest;
|
||||
}},
|
||||
Items.pyratite, new ArtilleryBulletType(3f, 48){{
|
||||
hitEffect = new MultiEffect(Fx.blastExplosion, Fx.shockwave);
|
||||
@@ -4091,7 +4093,6 @@ public class Blocks{
|
||||
ammoPerShot = 2;
|
||||
velocityRnd = 0.2f;
|
||||
|
||||
scaleLifetimeOffset = 1f / 9f;
|
||||
recoil = 6f;
|
||||
shake = 2f;
|
||||
range = 290f;
|
||||
@@ -4101,6 +4102,8 @@ public class Blocks{
|
||||
scaledHealth = 130;
|
||||
depositCooldown = 2.0f;
|
||||
shootSound = Sounds.shootRipple;
|
||||
scaleLifetimeOffset = 1f / 10f;
|
||||
unitSort = UnitSorts.grouped;
|
||||
}};
|
||||
|
||||
cyclone = new ItemTurret("cyclone"){{
|
||||
@@ -4694,6 +4697,8 @@ public class Blocks{
|
||||
shrinkX = 0.2f;
|
||||
shrinkY = 0.1f;
|
||||
buildingDamageMultiplier = 0.3f;
|
||||
|
||||
unitSort = UnitSorts.grouped;
|
||||
}},
|
||||
Items.carbide, new ArtilleryBulletType(3.25f, 700, "shell"){{
|
||||
hitEffect = new MultiEffect(Fx.titanExplosionSmall, Fx.titanSmokeSmall);
|
||||
@@ -4732,6 +4737,8 @@ public class Blocks{
|
||||
buildingDamageMultiplier = 0.2f;
|
||||
fragLifeMin = 1.5f;
|
||||
|
||||
unitSort = UnitSorts.strongest;
|
||||
|
||||
fragBullets = 12;
|
||||
fragBullet = new ArtilleryBulletType(0.5f, 50, "shell"){{
|
||||
hitEffect = new MultiEffect(Fx.titanExplosionFrag, Fx.titanLightSmall, new WaveEffect(){{
|
||||
@@ -4808,6 +4815,8 @@ public class Blocks{
|
||||
buildingDamageMultiplier = 0f;
|
||||
}};
|
||||
}};
|
||||
|
||||
unitSort = UnitSorts.grouped;
|
||||
}}
|
||||
);
|
||||
|
||||
|
||||
@@ -15,10 +15,16 @@ public class UnitSorts{
|
||||
mostArmor = (u, x, y) -> -u.armor + Mathf.dst2(u.x, u.y, x, y) / 6400f,
|
||||
leastArmor = (u, x, y) -> u.armor + Mathf.dst2(u.x, u.y, x, y) / 6400f,
|
||||
mostShield = (u, x, y) -> -u.shield + Mathf.dst2(u.x, u.y, x, y) / 6400f,
|
||||
leastShield = (u, x, y) -> u.shield + Mathf.dst2(u.x, u.y, x, y) / 6400f;
|
||||
leastShield = (u, x, y) -> u.shield + Mathf.dst2(u.x, u.y, x, y) / 6400f,
|
||||
grouped = grouped(0.003f);
|
||||
|
||||
public static BuildingPriorityf
|
||||
|
||||
buildingDefault = b -> b.block.priority,
|
||||
buildingWater = b -> b.block.priority + (b.liquids != null && b.liquids.get(Liquids.water) > 5f ? 10f : 0f);
|
||||
|
||||
/** @param dstWeight higher values make distance more important. Set to <= 0 to ignore distance. Ignores flying units. */
|
||||
public static Sortf grouped(float dstWeight){
|
||||
return (u, x, y) -> -u.team.data().getClustered(u.x, u.y) + (dstWeight > 0 ? Mathf.dst(u.x, u.y, x, y) * dstWeight : 0f);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.Units.*;
|
||||
import mindustry.entities.part.*;
|
||||
import mindustry.entities.pattern.*;
|
||||
import mindustry.game.EventType.*;
|
||||
@@ -120,6 +121,8 @@ public class BulletType extends Content implements Cloneable{
|
||||
public StatusEffect status = StatusEffects.none;
|
||||
/** Intensity of applied status effect in terms of duration. */
|
||||
public float statusDuration = 60 * 8f;
|
||||
/** Turret only. Function for choosing which unit to target. Overrides turret sorting */
|
||||
public Sortf unitSort = UnitSorts.closest;
|
||||
/** Chance for this bullet to apply a status effect */
|
||||
public float statusChance = 1f;
|
||||
/** Turret only. If false, blocks will not be targeted. */
|
||||
|
||||
@@ -269,6 +269,7 @@ public class Teams{
|
||||
|
||||
public static class TeamData{
|
||||
private static final IntSeq derelictBuffer = new IntSeq();
|
||||
private static final float clusterChunkSize = 70f;
|
||||
|
||||
public final Team team;
|
||||
|
||||
@@ -278,6 +279,8 @@ public class Teams{
|
||||
public @Nullable RtsAI rtsAi;
|
||||
|
||||
private boolean presentFlag;
|
||||
private IntIntMap clusteredCounts = new IntIntMap();
|
||||
private float lastClusterUpdateTimer = -100f;
|
||||
|
||||
/** Enemies with cores or spawn points. */
|
||||
public Team[] coreEnemies = {};
|
||||
@@ -470,6 +473,26 @@ public class Teams{
|
||||
return team.rules().rtsAi || team.rules().buildAi;
|
||||
}
|
||||
|
||||
/** @return approximate number of clustered ground units at a specific position */
|
||||
public int getClustered(float x, float y){
|
||||
//update based on ticks passed (no increment)
|
||||
if(Time.time > lastClusterUpdateTimer + 10f){
|
||||
lastClusterUpdateTimer = Time.time;
|
||||
clusteredCounts.clear();
|
||||
units.each(u -> {
|
||||
//clusters are for artillery, which can't hit flying units
|
||||
if(!u.isFlying()){
|
||||
clusteredCounts.increment(clusterKey(u.x, u.y));
|
||||
}
|
||||
});
|
||||
}
|
||||
return clusteredCounts.get(clusterKey(x, y));
|
||||
}
|
||||
|
||||
private static int clusterKey(float x, float y){
|
||||
return ((Mathf.floor(x / clusterChunkSize) & 0xFFF) << 12) | (Mathf.floor(y / clusterChunkSize) & 0xFFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return "TeamData{" +
|
||||
|
||||
@@ -639,14 +639,15 @@ public class Turret extends ReloadTurret{
|
||||
}
|
||||
|
||||
protected Posc findEnemy(float range){
|
||||
var ammo = peekAmmo();
|
||||
Sortf sort = ammo.unitSort != UnitSorts.closest ? ammo.unitSort : unitSort;
|
||||
if(targetAir && !targetGround){
|
||||
return Units.bestEnemy(team, x, y, range, e -> !e.dead() && !e.isGrounded() && unitFilter.get(e), unitSort);
|
||||
return Units.bestEnemy(team, x, y, range, e -> !e.dead() && !e.isGrounded() && unitFilter.get(e), sort);
|
||||
}else{
|
||||
var ammo = peekAmmo();
|
||||
boolean buildings = targetGround && targetBlocks && (ammo == null || ammo.targetBlocks), missiles = ammo == null || ammo.targetMissiles;
|
||||
return Units.bestTarget(team, x, y, range,
|
||||
e -> !e.dead() && unitFilter.get(e) && (e.isGrounded() || targetAir) && (!e.isGrounded() || targetGround) && (missiles || !(e instanceof TimedKillc)),
|
||||
b -> buildings && buildingFilter.get(b), unitSort);
|
||||
b -> buildings && buildingFilter.get(b), sort);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user