No Erekir default AI / Core unit tweaks

This commit is contained in:
Anuken
2022-02-06 20:54:57 -05:00
parent cb110e5e6f
commit ce82b3943e
13 changed files with 147 additions and 73 deletions

View File

@@ -19,6 +19,7 @@ public class SuicideAI extends GroundAI{
@Override
public void updateUnit(){
if(disabled()) return;
if(Units.invalidateTarget(target, unit.team, unit.x, unit.y, Float.MAX_VALUE)){
target = null;

View File

@@ -2546,7 +2546,7 @@ public class Blocks{
thrusterLength = 34/4f;
armor = 5f;
unitCapModifier = 6;
unitCapModifier = 4;
researchCostMultiplier = 0.07f;
}};
@@ -2561,7 +2561,7 @@ public class Blocks{
thrusterLength = 40/4f;
armor = 10f;
unitCapModifier = 10;
unitCapModifier = 8;
researchCostMultiplier = 0.11f;
}};
@@ -2576,7 +2576,7 @@ public class Blocks{
thrusterLength = 48/4f;
armor = 15f;
unitCapModifier = 14;
unitCapModifier = 12;
researchCostMultiplier = 0.11f;
}};

View File

@@ -2674,14 +2674,12 @@ public class UnitTypes{
//endregion
//region erekir - mech
bulwark = new UnitType("bulwark"){{
bulwark = new ErekirUnitType("bulwark"){{
drag = 0.1f;
speed = 0.6f;
hitSize = 23f;
health = 7000;
armor = 5f;
outlineColor = Pal.darkOutline;
envDisabled = Env.space;
abilities.add(new ShieldArcAbility(){{
region = "bulwark-shield";
@@ -2771,14 +2769,12 @@ public class UnitTypes{
}});
}};
krepost = new UnitType("krepost"){{
krepost = new ErekirUnitType("krepost"){{
drag = 0.1f;
speed = 1.1f;
hitSize = 44f;
health = 18000;
armor = 8f;
outlineColor = Pal.darkOutline;
envDisabled = Env.space;
rotateSpeed = 1.6f;
lockLegBase = true;
legContinuousMove = true;
@@ -2887,11 +2883,10 @@ public class UnitTypes{
//endregion
//region erekir - flying
quell = new UnitType("quell"){{
quell = new ErekirUnitType("quell"){{
defaultController = FlyingFollowAI::new;
envDisabled = 0;
outlineColor = Pal.darkOutline;
lowAltitude = false;
flying = true;
drag = 0.06f;
@@ -2953,11 +2948,10 @@ public class UnitTypes{
);
}};
disrupt = new UnitType("disrupt"){{
disrupt = new ErekirUnitType("disrupt"){{
defaultController = FlyingFollowAI::new;
envDisabled = 0;
outlineColor = Pal.darkOutline;
lowAltitude = false;
flying = true;
drag = 0.07f;
@@ -3122,12 +3116,11 @@ public class UnitTypes{
//region erekir - core
//TODO bad name
evoke = new UnitType("evoke"){{
evoke = new ErekirUnitType("evoke"){{
defaultController = BuilderAI::new;
isCounted = false;
envDisabled = 0;
outlineColor = Pal.darkOutline;
lowAltitude = false;
mineWalls = true;
mineFloor = false;
@@ -3136,15 +3129,14 @@ public class UnitTypes{
mineSpeed = 4f;
mineTier = 4;
buildSpeed = 0.8f;
drag = 0.06f;
speed = 2.9f;
rotateSpeed = 9f;
accel = 0.1f;
drag = 0.08f;
speed = 5.3f;
rotateSpeed = 7f;
accel = 0.09f;
itemCapacity = 60;
health = 300f;
armor = 1f;
hitSize = 9f;
commandLimit = 5;
engineSize = 0;
setEnginesMirror(
@@ -3152,43 +3144,37 @@ public class UnitTypes{
new UnitEngine(23 / 4f, -22 / 4f, 2.2f, 315f)
);
weapons.add(new Weapon(){{
reload = 17f;
weapons.add(new RepairBeamWeapon(){{
reload = 25f;
x = 0f;
y = 1f;
top = false;
y = 6.5f;
rotate = false;
shootY = 0f;
beamWidth = 0.7f;
repairSpeed = 0.25f;
aimDst = 0f;
shootCone = 15f;
fractionRepair = true;
mirror = false;
bullet = new LaserBoltBulletType(){{
speed = 4.2f;
frontColor = Color.white;
backColor = hitColor = trailColor = Pal.accent;
targetUnits = false;
targetBuildings = true;
autoTarget = false;
controllable = true;
laserColor = Pal.accent;
healColor = Pal.accent;
height = 6f;
trailLength = 5;
trailWidth = 2f;
healColor = Pal.accent;
healPercent = 1f;
healAmount = 25f;
collidesTeam = true;
lifetime = 31f;
shootEffect = Fx.colorSpark;
hitEffect = smokeEffect = despawnEffect = Fx.hitLaserColor;
//TODO 0, or 1?
damage = 0;
bullet = new BulletType(){{
maxRange = 70f;
}};
}});
}};
incite = new UnitType("incite"){{
incite = new ErekirUnitType("incite"){{
defaultController = BuilderAI::new;
isCounted = false;
envDisabled = 0;
outlineColor = Pal.darkOutline;
lowAltitude = false;
flying = true;
mineWalls = true;
@@ -3206,7 +3192,6 @@ public class UnitTypes{
health = 600f;
armor = 2f;
hitSize = 18f;
commandLimit = 7;
buildBeamOffset = 10f;
engineSize = 0;
payloadCapacity = Mathf.sqr(2f) * tilePayload;
@@ -3243,12 +3228,11 @@ public class UnitTypes{
}});
}};
emanate = new UnitType("emanate"){{
emanate = new ErekirUnitType("emanate"){{
defaultController = BuilderAI::new;
isCounted = false;
envDisabled = 0;
outlineColor = Pal.darkOutline;
lowAltitude = false;
flying = true;
targetAir = false;
@@ -3266,7 +3250,6 @@ public class UnitTypes{
health = 1300f;
armor = 3f;
hitSize = 36f;
commandLimit = 9;
buildBeamOffset = 72f / 4f;
engineSize = 0;
payloadCapacity = Mathf.sqr(3f) * tilePayload;
@@ -3328,14 +3311,14 @@ public class UnitTypes{
internal = true;
}};
manifold = new UnitType("manifold"){{
manifold = new ErekirUnitType("manifold"){{
defaultController = CargoAI::new;
defaultAI = true;
isCounted = false;
allowedInPayloads = false;
logicControllable = false;
envDisabled = 0;
outlineColor = Pal.darkOutline;
lowAltitude = false;
flying = true;
drag = 0.06f;
@@ -3345,7 +3328,6 @@ public class UnitTypes{
itemCapacity = 60;
health = 200f;
hitSize = 11f;
commandLimit = 0;
engineSize = 2.3f;
engineOffset = 6.5f;
hidden = true;
@@ -3355,9 +3337,10 @@ public class UnitTypes{
);
}};
assemblyDrone = new UnitType("assembly-drone"){{
assemblyDrone = new ErekirUnitType("assembly-drone"){{
defaultController = AssemblerAI::new;
defaultAI = true;
flying = true;
drag = 0.06f;
accel = 0.11f;

View File

@@ -231,7 +231,7 @@ public class BulletType extends Content implements Cloneable{
/** Returns maximum distance the bullet this bullet type has can travel. */
public float range(){
if(rangeOverride > 0) return rangeOverride;
return Mathf.zero(drag) ? speed * lifetime : Math.max(speed * (1f - Mathf.pow(1f - drag, lifetime)) / drag, maxRange);
return Math.max(Mathf.zero(drag) ? speed * lifetime : speed * (1f - Mathf.pow(1f - drag, lifetime)) / drag, maxRange);
}
/** @return continuous damage in damage/sec, or -1 if not continuous. */

View File

@@ -33,6 +33,10 @@ public class AIController implements UnitController{
@Override
public void updateUnit(){
if(disabled()){
return;
}
//use fallback AI when possible
if(useFallback() && (fallback != null || (fallback = fallback()) != null)){
if(fallback.unit != unit) fallback.unit(unit);
@@ -45,6 +49,10 @@ public class AIController implements UnitController{
updateMovement();
}
public boolean disabled(){
return !unit.team.isAI() && !unit.type.defaultAI;
}
@Nullable
public AIController fallback(){
return null;

View File

@@ -67,6 +67,10 @@ public class UnitType extends UnlockableContent{
public boolean logicControllable = true;
public boolean playerControllable = true;
public boolean allowedInPayloads = true;
/** If false, this unit has no AI when not controlled by a player, regardless of AI controller. */
public boolean defaultAI = true;
/** TODO If true, core units need to "dock" to this unit to work, and can un-dock at the unit instead of respawning at core. */
public boolean coreUnitDock = false;
public boolean createWreck = true;
public boolean createScorch = true;
public boolean useUnitCap = true;
@@ -503,6 +507,8 @@ public class UnitType extends UnlockableContent{
}
this.weapons = mapped;
weapons.each(Weapon::init);
//dynamically create ammo capacity based on firing rate
if(ammoCapacity < 0){
float shotsPerSecond = weapons.sumf(w -> w.useAmmo ? 60f / w.reload : 0f);

View File

@@ -465,6 +465,10 @@ public class Weapon implements Cloneable{
}
}
public void init(){
}
public void load(){
region = Core.atlas.find(name);
heatRegion = Core.atlas.find(name + "-heat");

View File

@@ -0,0 +1,18 @@
package mindustry.type.unit;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.world.meta.*;
/** Config class for special Erekir unit properties. */
public class ErekirUnitType extends UnitType{
public ErekirUnitType(String name){
super(name);
commandLimit = 0;
outlineColor = Pal.darkOutline;
envDisabled = Env.space;
defaultAI = false;
coreUnitDock = true;
}
}

View File

@@ -2,6 +2,7 @@ package mindustry.type.unit;
import mindustry.ai.types.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.world.meta.*;
@@ -31,6 +32,7 @@ public class MissileUnitType extends UnitType{
rotateSpeed = 2.5f;
range = 30f;
targetPriority = -1f;
//TODO weapons, etc
outlineColor = Pal.darkOutline;
//TODO weapon configs, etc?
}
}

View File

@@ -1,10 +1,8 @@
package mindustry.type.unit;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.world.meta.*;
public class TankUnitType extends UnitType{
public class TankUnitType extends ErekirUnitType{
public TankUnitType(String name){
super(name);
@@ -14,7 +12,6 @@ public class TankUnitType extends UnitType{
rotateSpeed = 1.3f;
envDisabled = Env.none;
speed = 0.8f;
outlineColor = Pal.darkOutline;
}
}

View File

@@ -7,9 +7,12 @@ import arc.math.*;
import arc.math.geom.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.units.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.world.blocks.units.*;
import mindustry.world.meta.*;
@@ -19,7 +22,9 @@ import mindustry.world.meta.*;
* Rotation must be set to true. Fixed repair points are not supported.
* */
public class RepairBeamWeapon extends Weapon{
public boolean targetBuildings = false;
public boolean targetBuildings = false, targetUnits = true;
//TODO leads to wrong stats
public boolean fractionRepair = false;
public float repairSpeed = 0.3f;
public float beamWidth = 1f;
@@ -29,6 +34,9 @@ public class RepairBeamWeapon extends Weapon{
public TextureRegion laser, laserEnd, laserTop, laserTopEnd;
public Color laserColor = Color.valueOf("98ffa9"), laserTopColor = Color.white.cpy();
//only for blocks
public Color healColor = Pal.heal;
public Effect healEffect = Fx.healBlockFull;
public RepairBeamWeapon(String name){
super(name);
@@ -72,9 +80,8 @@ public class RepairBeamWeapon extends Weapon{
@Override
protected Teamc findTarget(Unit unit, float x, float y, float range, boolean air, boolean ground){
var out = Units.closest(unit.team, x, y, range, u -> u != unit && u.damaged());
var out = targetUnits ? Units.closest(unit.team, x, y, range, u -> u != unit && u.damaged()) : null;
if(out != null || !targetBuildings) return out;
//TODO maybe buildings shouldn't be allowed at all
return Units.findAllyTile(unit.team, x, y, range, Building::damaged);
}
@@ -92,11 +99,48 @@ public class RepairBeamWeapon extends Weapon{
public void update(Unit unit, WeaponMount mount){
super.update(unit, mount);
HealBeamMount heal = (HealBeamMount)mount;
heal.strength = Mathf.lerpDelta(heal.strength, Mathf.num(mount.target != null), 0.2f);
float
weaponRotation = unit.rotation - 90,
wx = unit.x + Angles.trnsx(weaponRotation, x, y),
wy = unit.y + Angles.trnsy(weaponRotation, x, y);
if(mount.target instanceof Healthc u){
u.heal(repairSpeed * heal.strength * Time.delta);
HealBeamMount heal = (HealBeamMount)mount;
heal.target = null;
boolean canShoot = mount.shoot;
if(!autoTarget){
if(canShoot){
heal.lastEnd.set(heal.aimX, heal.aimY);
if(!rotate && !Angles.within(Angles.angle(wx, wy, heal.aimX, heal.aimY), unit.rotation, shootCone)){
canShoot = false;
}
}
//limit range
heal.lastEnd.sub(wx, wy).limit(range()).add(wx, wy);
if(targetBuildings){
var build = Vars.world.buildWorld(mount.aimX, mount.aimY);
if(build != null && build.team == unit.team){
heal.target = build;
}
}
if(targetUnits){
//TODO does not support healing units manually yet
}
}
heal.strength = Mathf.lerpDelta(heal.strength, Mathf.num(autoTarget ? mount.target != null : canShoot), 0.2f);
//create heal effect periodically
if(canShoot && mount.target instanceof Building b && b.damaged() && (heal.effectTimer += Time.delta) >= reload){
healEffect.at(b.x, b.y, b.block.size, healColor);
heal.effectTimer = 0f;
}
if(canShoot && mount.target instanceof Healthc u){
u.heal(repairSpeed * heal.strength * Time.delta * (fractionRepair ? u.maxHealth() / 100f : 1f));
}
}
@@ -112,15 +156,22 @@ public class RepairBeamWeapon extends Weapon{
wy = unit.y + Angles.trnsy(weaponRotation, x, y);
float z = Draw.z();
RepairPoint.drawBeam(wx, wy, unit.rotation + mount.rotation, shootY, unit.id, mount.target == null ? null : (Sized)mount.target, unit.team, heal.strength,
RepairPoint.drawBeam(wx, wy, unit.rotation + mount.rotation, shootY, unit.id, mount.target == null || controllable ? null : (Sized)mount.target, unit.team, heal.strength,
pulseStroke, pulseRadius, beamWidth, heal.lastEnd, heal.offset, laserColor, laserTopColor,
laser, laserEnd, laserTop, laserTopEnd);
Draw.z(z);
}
@Override
public void init(){
if(fractionRepair){
bullet.healPercent = repairSpeed;
}
}
public static class HealBeamMount extends WeaponMount{
public Vec2 offset = new Vec2(), lastEnd = new Vec2();
public float strength;
public float strength, effectTimer;
public HealBeamMount(Weapon weapon){
super(weapon);

View File

@@ -98,18 +98,18 @@ public class RepairPoint extends Block{
return new TextureRegion[]{baseRegion, region};
}
public static void drawBeam(float x, float y, float rotation, float length, int id, Sized target, Team team,
public static void drawBeam(float x, float y, float rotation, float length, int id, @Nullable Sized target, Team team,
float strength, float pulseStroke, float pulseRadius, float beamWidth,
Vec2 lastEnd, Vec2 offset,
Color laserColor, Color laserTopColor,
TextureRegion laser, TextureRegion laserEnd, TextureRegion laserTop, TextureRegion laserTopEnd){
rand.setSeed(id + (target instanceof Entityc e ? e.id() : 0));
if(target != null){
float
originX = x + Angles.trnsx(rotation, length),
originY = y + Angles.trnsy(rotation, length);
rand.setSeed(id + (target instanceof Entityc e ? e.id() : 0));
lastEnd.set(target).sub(originX, originY);
lastEnd.setLength(Math.max(2f, lastEnd.len()));

View File

@@ -172,7 +172,7 @@ public class UnitAssembler extends PayloadBlock{
public Seq<Unit> units = new Seq<>();
public Seq<UnitAssemblerModuleBuild> modules = new Seq<>();
public BlockSeq blocks = new BlockSeq();
public float progress, warmup, droneWarmup;
public float progress, warmup, droneWarmup, powerWarmup;
public float invalidWarmup = 0f;
public int currentTier = 0;
public boolean wasOccupied = false;
@@ -284,6 +284,7 @@ public class UnitAssembler extends PayloadBlock{
units.removeAll(u -> !u.isAdded() || u.dead || !(u.controller() instanceof AssemblerAI));
powerWarmup = Mathf.lerpDelta(powerWarmup, efficiency(), 0.1f);
droneWarmup = Mathf.lerpDelta(droneWarmup, units.size < dronesCreated ? efficiency() : 0f, 0.1f);
totalDroneProgress += droneWarmup * Time.delta;
@@ -380,6 +381,7 @@ public class UnitAssembler extends PayloadBlock{
var plan = plan();
//draw the unit construction as outline
Draw.draw(Layer.blockBuilding, () -> {
Draw.color(Pal.accent, warmup);
@@ -397,8 +399,9 @@ public class UnitAssembler extends PayloadBlock{
Draw.z(Layer.buildBeam);
//draw unit outline
//draw unit silhouette
Draw.mixcol(Tmp.c1.set(Pal.accent).lerp(Pal.remove, invalidWarmup), 1f);
Draw.alpha(powerWarmup);
Draw.rect(plan.unit.fullIcon, spawn.x, spawn.y);
//build beams do not draw when invalid
@@ -423,6 +426,7 @@ public class UnitAssembler extends PayloadBlock{
//draw full area
Lines.stroke(2f, Pal.accent);
Draw.alpha(powerWarmup);
Drawf.dashRectBasic(spawn.x - fulls, spawn.y - fulls, fulls*2f, fulls*2f);
Draw.reset();