Flare AI changed

This commit is contained in:
Anuken
2025-11-15 23:04:08 -05:00
parent cc693f97b6
commit ed860e8395
10 changed files with 58 additions and 21 deletions

View File

@@ -472,7 +472,7 @@ editor.generation = Generation
editor.objectives = Objectives editor.objectives = Objectives
editor.locales = Locale Bundles editor.locales = Locale Bundles
editor.patches.guide = Patch Guide editor.patches.guide = Patch Guide
editor.patches = Content Patches editor.patches = Data Patches
editor.patch: Patchset: {0} editor.patch: Patchset: {0}
editor.patches.none = [lightgray]No patchsets loaded. editor.patches.none = [lightgray]No patchsets loaded.
editor.patches.errors = Patchset Errors editor.patches.errors = Patchset Errors

View File

@@ -270,7 +270,6 @@ public class CommandAI extends AIController{
Building targetBuild = world.buildWorld(targetPos.x, targetPos.y); Building targetBuild = world.buildWorld(targetPos.x, targetPos.y);
//TODO: should the unit stop when it finds a target? //TODO: should the unit stop when it finds a target?
if( if(
(hasStance(UnitStance.patrol) && !hasStance(UnitStance.pursueTarget) && target != null && unit.within(target, unit.type.range - 2f) && !unit.type.circleTarget) || (hasStance(UnitStance.patrol) && !hasStance(UnitStance.pursueTarget) && target != null && unit.within(target, unit.type.range - 2f) && !unit.type.circleTarget) ||
@@ -347,7 +346,7 @@ public class CommandAI extends AIController{
if(move){ if(move){
if(unit.type.circleTarget && attackTarget != null){ if(unit.type.circleTarget && attackTarget != null){
target = attackTarget; target = attackTarget;
circleAttack(80f); circleAttack(unit.type.circleTargetRadius);
}else{ }else{
moveTo(vecOut, moveTo(vecOut,
withinAttackRange ? engageRange : withinAttackRange ? engageRange :
@@ -362,7 +361,7 @@ public class CommandAI extends AIController{
attackTarget = null; attackTarget = null;
} }
if(unit.isFlying() && move && (attackTarget == null || !unit.within(attackTarget, unit.type.range))){ if(unit.isFlying() && move && !(unit.type.circleTarget && !unit.type.omniMovement) && (attackTarget == null || !unit.within(attackTarget, unit.type.range))){
unit.lookAt(vecMovePos); unit.lookAt(vecMovePos);
}else{ }else{
faceTarget(); faceTarget();
@@ -379,7 +378,11 @@ public class CommandAI extends AIController{
} }
}else if(target != null){ }else if(target != null){
faceTarget(); if(unit.type.circleTarget && shouldFire()){
circleAttack(unit.type.circleTargetRadius);
}else{
faceTarget();
}
} }
} }

View File

@@ -19,7 +19,7 @@ public class FlyingAI extends AIController{
if(target != null && unit.hasWeapons()){ if(target != null && unit.hasWeapons()){
if(unit.type.circleTarget){ if(unit.type.circleTarget){
circleAttack(120f); circleAttack(unit.type.circleTargetRadius);
}else{ }else{
moveTo(target, unit.type.range * 0.8f); moveTo(target, unit.type.range * 0.8f);
unit.lookAt(target); unit.lookAt(target);

View File

@@ -30,7 +30,7 @@ public class RepairAI extends AIController{
if(target != null && target instanceof Building b && b.team == unit.team){ if(target != null && target instanceof Building b && b.team == unit.team){
if(unit.type.circleTarget){ if(unit.type.circleTarget){
circleAttack(120f); circleAttack(unit.type.circleTargetRadius);
}else if(!target.within(unit, unit.type.range * 0.65f)){ }else if(!target.within(unit, unit.type.range * 0.65f)){
moveTo(target, unit.type.range * 0.65f); moveTo(target, unit.type.range * 0.65f);
} }

View File

@@ -995,18 +995,25 @@ public class UnitTypes{
flying = true; flying = true;
health = 70; health = 70;
engineOffset = 5.75f; engineOffset = 5.75f;
//TODO balance
//targetAir = false;
targetFlags = new BlockFlag[]{BlockFlag.generator, null}; targetFlags = new BlockFlag[]{BlockFlag.generator, null};
hitSize = 9; hitSize = 9;
itemCapacity = 10; itemCapacity = 10;
circleTarget = true;
omniMovement = false;
rotateSpeed = 5f;
circleTargetRadius = 60f;
weapons.add(new Weapon(){{ weapons.add(new Weapon(){{
y = 0f; y = 1f;
x = 2f; x = 0f;
reload = 20f; minShootVelocity = 2f;
shootCone = 10f;
reload = 80f;
shoot.shots = 3;
shoot.shotDelay = 3f;
ejectEffect = Fx.casing1; ejectEffect = Fx.casing1;
bullet = new BasicBulletType(2.5f, 9){{ mirror = false;
bullet = new BasicBulletType(2.5f, 15){{
width = 7f; width = 7f;
height = 9f; height = 9f;
lifetime = 45f; lifetime = 45f;
@@ -1014,7 +1021,7 @@ public class UnitTypes{
smokeEffect = Fx.shootSmallSmoke; smokeEffect = Fx.shootSmallSmoke;
ammoMultiplier = 2; ammoMultiplier = 2;
}}; }};
shootSound = Sounds.pew; shootSound = Sounds.shootDagger;
}}); }});
}}; }};
@@ -1035,9 +1042,12 @@ public class UnitTypes{
targetFlags = new BlockFlag[]{BlockFlag.factory, null}; targetFlags = new BlockFlag[]{BlockFlag.factory, null};
circleTarget = true; circleTarget = true;
ammoType = new ItemAmmoType(Items.graphite); ammoType = new ItemAmmoType(Items.graphite);
omniMovement = false;
rotateSpeed = 4.5f;
circleTargetRadius = 40f;
weapons.add(new Weapon(){{ weapons.add(new Weapon(){{
minShootVelocity = 0.75f; minShootVelocity = 1f;
x = 3f; x = 3f;
shootY = 0f; shootY = 0f;
reload = 12f; reload = 12f;

View File

@@ -44,7 +44,7 @@ public class GameState{
/** Team data. Gets reset every new game. */ /** Team data. Gets reset every new game. */
public Teams teams = new Teams(); public Teams teams = new Teams();
/** Handles JSON edits of game content. */ /** Handles JSON edits of game content. */
public ContentPatcher patcher = new ContentPatcher(); public DataPatcher patcher = new DataPatcher();
/** Number of enemies in the game; only used clientside in servers. */ /** Number of enemies in the game; only used clientside in servers. */
public int enemies; public int enemies;
/** Map being playtested (not edited!) */ /** Map being playtested (not edited!) */

View File

@@ -98,7 +98,7 @@ public class RegionPart extends DrawPart{
int i = params.sideOverride == -1 ? s : params.sideOverride; int i = params.sideOverride == -1 ? s : params.sideOverride;
//can be null //can be null
var region = drawRegion ? regions[Math.min(i, regions.length - 1)] : null; var region = drawRegion && regions.length > 0 ? regions[Math.min(i, regions.length - 1)] : null;
float sign = (i == 0 ? 1 : -1) * params.sideMultiplier; float sign = (i == 0 ? 1 : -1) * params.sideMultiplier;
Tmp.v1.set((x + mx) * sign, y + my).rotateRadExact((params.rotation - 90) * Mathf.degRad); Tmp.v1.set((x + mx) * sign, y + my).rotateRadExact((params.rotation - 90) * Mathf.degRad);

View File

@@ -28,6 +28,7 @@ public class AIController implements UnitController{
/** main target that is being faced */ /** main target that is being faced */
protected @Nullable Teamc target; protected @Nullable Teamc target;
protected @Nullable Teamc bomberTarget; protected @Nullable Teamc bomberTarget;
protected boolean turningAway;
{ {
resetTimers(); resetTimers();
@@ -155,7 +156,8 @@ public class AIController implements UnitController{
} }
public void targetInvalidated(){ public void targetInvalidated(){
//TODO: try this for normal units, reset the target timer //immediately find a new target
timer.reset(timerTarget, -1f);
} }
public void updateWeapons(){ public void updateWeapons(){
@@ -169,7 +171,7 @@ public class AIController implements UnitController{
noTargetTime += Time.delta; noTargetTime += Time.delta;
if(invalid(target)){ if(invalid(target)){
if(target != null && !target.isAdded()){ if(target instanceof Healthc h && !h.isValid()){
targetInvalidated(); targetInvalidated();
} }
target = null; target = null;
@@ -300,14 +302,32 @@ public class AIController implements UnitController{
} }
public void circleAttack(float circleLength){ public void circleAttack(float circleLength){
if(target == null) return;
vec.set(target).sub(unit); vec.set(target).sub(unit);
float ang = unit.angleTo(target); float ang = unit.angleTo(target);
float diff = Angles.angleDist(ang, unit.rotation()); float diff = Angles.angleDist(ang, unit.rotation());
if(target instanceof Unit u && u.collisionLayer() == unit.collisionLayer()){
float avoidDist = u.physicSize() + 30f;
if(turningAway){
vec.setLength(prefSpeed()).scl(-1f);
unit.movePref(vec);
if(!unit.within(u, unit.type.circleTargetRadius*0.5f + u.physicSize())){
turningAway = false;
}
return;
}else if(unit.within(u, avoidDist)){
turningAway = true;
}
}
if(diff > 70f && vec.len() < circleLength){ if(diff > 70f && vec.len() < circleLength){
vec.setAngle(unit.vel().angle()); vec.setAngle(unit.vel().angle());
}else{ }else if(unit.type.omniMovement){ //non-omni movement units don't need to do this as the turning is already smoothed out
vec.setAngle(Angles.moveToward(unit.vel().angle(), vec.angle(), 6f)); vec.setAngle(Angles.moveToward(unit.vel().angle(), vec.angle(), 6f));
} }

View File

@@ -22,7 +22,7 @@ import java.util.*;
/** The current implementation is awful. Consider it a proof of concept. */ /** The current implementation is awful. Consider it a proof of concept. */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class ContentPatcher{ public class DataPatcher{
private static final Object root = new Object(); private static final Object root = new Object();
private static final ObjectMap<String, ContentType> nameToType = new ObjectMap<>(); private static final ObjectMap<String, ContentType> nameToType = new ObjectMap<>();
private static ContentParser parser = createParser(); private static ContentParser parser = createParser();
@@ -129,6 +129,8 @@ public class ContentPatcher{
if(!Vars.headless){ if(!Vars.headless){
if(object instanceof DrawPart part && parent instanceof MappableContent cont){ if(object instanceof DrawPart part && parent instanceof MappableContent cont){
part.load(cont.name); part.load(cont.name);
}else if(object instanceof DrawPart part && parent instanceof Weapon w){
part.load(w.name);
}else if(object instanceof DrawBlock draw && parent instanceof Block block){ }else if(object instanceof DrawBlock draw && parent instanceof Block block){
draw.load(block); draw.load(block);
}else if(object instanceof Weapon weapon){ }else if(object instanceof Weapon weapon){

View File

@@ -93,6 +93,8 @@ public class UnitType extends UnlockableContent implements Senseable{
mineRange = 70f, mineRange = 70f,
/** range at which this unit can build */ /** range at which this unit can build */
buildRange = Vars.buildingRange, buildRange = Vars.buildingRange,
/** radius for circleTarget, if true */
circleTargetRadius = 80f,
/** multiplier for damage this (flying) unit deals when crashing on enemy things */ /** multiplier for damage this (flying) unit deals when crashing on enemy things */
crashDamageMultiplier = 1f, crashDamageMultiplier = 1f,
/** multiplier for health that this flying unit has for its wreck, based on its max health. */ /** multiplier for health that this flying unit has for its wreck, based on its max health. */