Various tweaks and speculative changes
This commit is contained in:
@@ -5,20 +5,14 @@ import arc.math.geom.*;
|
|||||||
import mindustry.ai.formations.*;
|
import mindustry.ai.formations.*;
|
||||||
|
|
||||||
public class CircleFormation extends FormationPattern{
|
public class CircleFormation extends FormationPattern{
|
||||||
/** The radius of one member. This is needed to determine how close we can pack a given number of members around circle. */
|
|
||||||
public float memberRadius;
|
|
||||||
/** Angle offset. */
|
/** Angle offset. */
|
||||||
public float angleOffset = 0;
|
public float angleOffset = 0;
|
||||||
|
|
||||||
public CircleFormation(float memberRadius){
|
|
||||||
this.memberRadius = memberRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Vec3 calculateSlotLocation(Vec3 outLocation, int slotNumber){
|
public Vec3 calculateSlotLocation(Vec3 outLocation, int slotNumber){
|
||||||
if(slots > 1){
|
if(slots > 1){
|
||||||
float angle = (360f * slotNumber) / slots;
|
float angle = (360f * slotNumber) / slots;
|
||||||
float radius = memberRadius / (float)Math.sin(180f / slots * Mathf.degRad);
|
float radius = spacing / (float)Math.sin(180f / slots * Mathf.degRad);
|
||||||
outLocation.set(Angles.trnsx(angle, radius), Angles.trnsy(angle, radius), angle);
|
outLocation.set(Angles.trnsx(angle, radius), Angles.trnsy(angle, radius), angle);
|
||||||
}else{
|
}else{
|
||||||
outLocation.set(0, 0, 360f * slotNumber);
|
outLocation.set(0, 0, 360f * slotNumber);
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ package mindustry.ai.types;
|
|||||||
|
|
||||||
import arc.math.geom.*;
|
import arc.math.geom.*;
|
||||||
import arc.util.ArcAnnotate.*;
|
import arc.util.ArcAnnotate.*;
|
||||||
import mindustry.*;
|
|
||||||
import mindustry.ai.formations.*;
|
import mindustry.ai.formations.*;
|
||||||
import mindustry.entities.units.*;
|
import mindustry.entities.units.*;
|
||||||
import mindustry.gen.*;
|
import mindustry.gen.*;
|
||||||
|
import mindustry.type.*;
|
||||||
|
|
||||||
public class FormationAI extends AIController implements FormationMember{
|
public class FormationAI extends AIController implements FormationMember{
|
||||||
public Unit leader;
|
public Unit leader;
|
||||||
@@ -25,33 +25,33 @@ public class FormationAI extends AIController implements FormationMember{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateUnit(){
|
public void updateUnit(){
|
||||||
|
UnitType type = unit.type();
|
||||||
|
|
||||||
if(leader.dead){
|
if(leader.dead){
|
||||||
unit.resetController();
|
unit.resetController();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
unit.controlWeapons(leader.isRotate(), leader.isShooting);
|
unit.controlWeapons(true, leader.isShooting);
|
||||||
// unit.moveAt(Tmp.v1.set(deltaX, deltaY).limit(unit.type().speed));
|
// unit.moveAt(Tmp.v1.set(deltaX, deltaY).limit(unit.type().speed));
|
||||||
if(leader.isShooting){
|
|
||||||
unit.aimLook(leader.aimX(), leader.aimY());
|
unit.aim(leader.aimX(), leader.aimY());
|
||||||
}else{
|
|
||||||
if(!leader.moving() || !unit.type().rotateShooting){
|
if(unit.type().rotateShooting){
|
||||||
if(unit.moving()){
|
unit.lookAt(leader.aimX(), leader.aimY());
|
||||||
unit.lookAt(unit.vel.angle());
|
}else if(unit.moving()){
|
||||||
}
|
unit.lookAt(unit.vel.angle());
|
||||||
}else{
|
|
||||||
unit.lookAt(leader.rotation);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Vec2 realtarget = vec.set(target);
|
Vec2 realtarget = vec.set(target);
|
||||||
|
|
||||||
if(unit.isGrounded() && Vars.world.raycast(unit.tileX(), unit.tileY(), leader.tileX(), leader.tileY(), Vars.world::solid)){
|
float margin = 3f;
|
||||||
//TODO pathfind
|
|
||||||
//realtarget.set(Vars.pathfinder.getTargetTile(unit.tileOn(), unit.team, leader));
|
|
||||||
}
|
|
||||||
|
|
||||||
unit.moveAt(realtarget.sub(unit).limit(unit.type().speed));
|
if(unit.dst(realtarget) <= margin){
|
||||||
|
unit.vel.approachDelta(Vec2.ZERO, type.speed * type.accel / 2f);
|
||||||
|
}else{
|
||||||
|
unit.moveAt(realtarget.sub(unit).limit(type.speed));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -68,7 +68,7 @@ public class FormationAI extends AIController implements FormationMember{
|
|||||||
//TODO return formation size
|
//TODO return formation size
|
||||||
//eturn ((Commanderc)unit).formation().
|
//eturn ((Commanderc)unit).formation().
|
||||||
}
|
}
|
||||||
return unit.hitSize * 1.7f;
|
return unit.hitSize * 1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -747,6 +747,7 @@ public class UnitTypes implements ContentList{
|
|||||||
accel = 0.08f;
|
accel = 0.08f;
|
||||||
drag = 0.016f;
|
drag = 0.016f;
|
||||||
flying = true;
|
flying = true;
|
||||||
|
hitsize = 9f;
|
||||||
targetAir = false;
|
targetAir = false;
|
||||||
engineOffset = 7.8f;
|
engineOffset = 7.8f;
|
||||||
range = 140f;
|
range = 140f;
|
||||||
|
|||||||
@@ -338,8 +338,6 @@ public class NetClient implements ApplicationListener{
|
|||||||
@Remote(variants = Variant.both)
|
@Remote(variants = Variant.both)
|
||||||
public static void setRules(Rules rules){
|
public static void setRules(Rules rules){
|
||||||
state.rules = rules;
|
state.rules = rules;
|
||||||
//campaign is not valid in multiplayer
|
|
||||||
state.rules.sector = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Remote(variants = Variant.both)
|
@Remote(variants = Variant.both)
|
||||||
@@ -442,7 +440,7 @@ public class NetClient implements ApplicationListener{
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true)
|
@Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true)
|
||||||
public static void stateSnapshot(float waveTime, int wave, int enemies, boolean paused, boolean gameOver, short coreDataLen, byte[] coreData){
|
public static void stateSnapshot(float waveTime, int wave, int enemies, boolean paused, boolean gameOver, int timeData, short coreDataLen, byte[] coreData){
|
||||||
try{
|
try{
|
||||||
if(wave > state.wave){
|
if(wave > state.wave){
|
||||||
state.wave = wave;
|
state.wave = wave;
|
||||||
@@ -455,6 +453,8 @@ public class NetClient implements ApplicationListener{
|
|||||||
state.enemies = enemies;
|
state.enemies = enemies;
|
||||||
state.serverPaused = paused;
|
state.serverPaused = paused;
|
||||||
|
|
||||||
|
universe.updateNetSeconds(timeData);
|
||||||
|
|
||||||
netClient.byteStream.setBytes(net.decompressSnapshot(coreData, coreDataLen));
|
netClient.byteStream.setBytes(net.decompressSnapshot(coreData, coreDataLen));
|
||||||
DataInputStream input = netClient.dataStream;
|
DataInputStream input = netClient.dataStream;
|
||||||
|
|
||||||
|
|||||||
@@ -846,7 +846,7 @@ public class NetServer implements ApplicationListener{
|
|||||||
byte[] stateBytes = syncStream.toByteArray();
|
byte[] stateBytes = syncStream.toByteArray();
|
||||||
|
|
||||||
//write basic state data.
|
//write basic state data.
|
||||||
Call.stateSnapshot(player.con, state.wavetime, state.wave, state.enemies, state.serverPaused, state.gameOver, (short)stateBytes.length, net.compressSnapshot(stateBytes));
|
Call.stateSnapshot(player.con, state.wavetime, state.wave, state.enemies, state.serverPaused, state.gameOver, universe.seconds(), (short)stateBytes.length, net.compressSnapshot(stateBytes));
|
||||||
|
|
||||||
viewport.setSize(player.con.viewWidth, player.con.viewHeight).setCenter(player.con.viewX, player.con.viewY);
|
viewport.setSize(player.con.viewWidth, player.con.viewHeight).setCenter(player.con.viewX, player.con.viewY);
|
||||||
|
|
||||||
|
|||||||
@@ -519,7 +519,7 @@ public class World{
|
|||||||
dark = Math.max((edgeBlend - edgeDst) * (4f / edgeBlend), dark);
|
dark = Math.max((edgeBlend - edgeDst) * (4f / edgeBlend), dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(state.hasSector()){
|
if(state.hasSector() && state.getSector().preset == null){
|
||||||
int circleBlend = 14;
|
int circleBlend = 14;
|
||||||
//quantized angle
|
//quantized angle
|
||||||
float offset = state.getSector().rect.rotation + 90;
|
float offset = state.getSector().rect.rotation + 90;
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ abstract class CommanderComp implements Unitc{
|
|||||||
@Override
|
@Override
|
||||||
public void update(){
|
public void update(){
|
||||||
if(formation != null){
|
if(formation != null){
|
||||||
formation.anchor.set(x, y, rotation);
|
formation.anchor.set(x, y, /*rotation*/ 0); //TODO rotation set to 0 because rotating is pointless
|
||||||
formation.updateSlots();
|
formation.updateSlots();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -73,7 +73,7 @@ abstract class CommanderComp implements Unitc{
|
|||||||
void command(Formation formation, Seq<Unit> units){
|
void command(Formation formation, Seq<Unit> units){
|
||||||
clearCommand();
|
clearCommand();
|
||||||
|
|
||||||
float spacing = hitSize() * 1.7f;
|
float spacing = hitSize() * 1f;
|
||||||
minFormationSpeed = type().speed;
|
minFormationSpeed = type().speed;
|
||||||
|
|
||||||
controlling.addAll(units);
|
controlling.addAll(units);
|
||||||
|
|||||||
@@ -87,6 +87,9 @@ public class SectorInfo{
|
|||||||
/** Update averages of various stats, updates some special sector logic.
|
/** Update averages of various stats, updates some special sector logic.
|
||||||
* Called every frame. */
|
* Called every frame. */
|
||||||
public void update(){
|
public void update(){
|
||||||
|
//updating in multiplayer as a client doesn't make sense
|
||||||
|
if(net.client()) return;
|
||||||
|
|
||||||
internalTimeSpent += Time.delta;
|
internalTimeSpent += Time.delta;
|
||||||
|
|
||||||
//create last stored core items
|
//create last stored core items
|
||||||
|
|||||||
@@ -14,7 +14,8 @@ import static mindustry.Vars.*;
|
|||||||
|
|
||||||
/** Updates and handles state of the campaign universe. Has no relevance to other gamemodes. */
|
/** Updates and handles state of the campaign universe. Has no relevance to other gamemodes. */
|
||||||
public class Universe{
|
public class Universe{
|
||||||
private long seconds;
|
private int seconds;
|
||||||
|
private int netSeconds;
|
||||||
private float secondCounter;
|
private float secondCounter;
|
||||||
private int turn;
|
private int turn;
|
||||||
|
|
||||||
@@ -76,15 +77,19 @@ public class Universe{
|
|||||||
|
|
||||||
/** Update planet rotations, global time and relevant state. */
|
/** Update planet rotations, global time and relevant state. */
|
||||||
public void update(){
|
public void update(){
|
||||||
secondCounter += Time.delta / 60f;
|
|
||||||
|
|
||||||
if(secondCounter >= 1){
|
//only update time when not in multiplayer
|
||||||
seconds += (int)secondCounter;
|
if(!net.client()){
|
||||||
secondCounter %= 1f;
|
secondCounter += Time.delta / 60f;
|
||||||
|
|
||||||
//save every few seconds
|
if(secondCounter >= 1){
|
||||||
if(seconds % 10 == 1){
|
seconds += (int)secondCounter;
|
||||||
save();
|
secondCounter %= 1f;
|
||||||
|
|
||||||
|
//save every few seconds
|
||||||
|
if(seconds % 10 == 1){
|
||||||
|
save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,25 +196,30 @@ public class Universe{
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float secondsMod(float mod, float scale){
|
public void updateNetSeconds(int value){
|
||||||
return (seconds / scale) % mod;
|
netSeconds = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long seconds(){
|
public float secondsMod(float mod, float scale){
|
||||||
return seconds;
|
return (seconds() / scale) % mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int seconds(){
|
||||||
|
//use networked seconds when playing as client
|
||||||
|
return net.client() ? netSeconds : seconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
public float secondsf(){
|
public float secondsf(){
|
||||||
return seconds + secondCounter;
|
return seconds() + secondCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void save(){
|
private void save(){
|
||||||
Core.settings.put("utime", seconds);
|
Core.settings.put("utimei", seconds);
|
||||||
Core.settings.put("turn", turn);
|
Core.settings.put("turn", turn);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void load(){
|
private void load(){
|
||||||
seconds = Core.settings.getLong("utime");
|
seconds = Core.settings.getInt("utimei");
|
||||||
turn = Core.settings.getInt("turn");
|
turn = Core.settings.getInt("turn");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -324,7 +324,8 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
|||||||
commander.clearCommand();
|
commander.clearCommand();
|
||||||
}else{
|
}else{
|
||||||
|
|
||||||
commander.commandNearby(new SquareFormation());
|
//TODO try out some other formations
|
||||||
|
commander.commandNearby(new CircleFormation());
|
||||||
Fx.commandSend.at(player);
|
Fx.commandSend.at(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,8 +42,6 @@ public class NetworkIO{
|
|||||||
try(DataInputStream stream = new DataInputStream(is)){
|
try(DataInputStream stream = new DataInputStream(is)){
|
||||||
Time.clear();
|
Time.clear();
|
||||||
state.rules = JsonIO.read(Rules.class, stream.readUTF());
|
state.rules = JsonIO.read(Rules.class, stream.readUTF());
|
||||||
//campaign is not valid in multiplayer
|
|
||||||
state.rules.sector = null;
|
|
||||||
state.map = new Map(SaveIO.getSaveWriter().readStringMap(stream));
|
state.map = new Map(SaveIO.getSaveWriter().readStringMap(stream));
|
||||||
|
|
||||||
state.wave = stream.readInt();
|
state.wave = stream.readInt();
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ public class LaunchPad extends Block{
|
|||||||
//launch when full and base conditions are met
|
//launch when full and base conditions are met
|
||||||
if(items.total() >= itemCapacity && efficiency() >= 1f && timer(timerLaunch, launchTime / timeScale)){
|
if(items.total() >= itemCapacity && efficiency() >= 1f && timer(timerLaunch, launchTime / timeScale)){
|
||||||
LaunchPayload entity = LaunchPayload.create();
|
LaunchPayload entity = LaunchPayload.create();
|
||||||
items.each((item, amount) -> entity.stacks().add(new ItemStack(item, amount)));
|
items.each((item, amount) -> entity.stacks.add(new ItemStack(item, amount)));
|
||||||
entity.set(this);
|
entity.set(this);
|
||||||
entity.lifetime(120f);
|
entity.lifetime(120f);
|
||||||
entity.team(team);
|
entity.team(team);
|
||||||
@@ -174,9 +174,14 @@ public class LaunchPad extends Block{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remove(){
|
public void remove(){
|
||||||
|
if(!state.isCampaign()) return;
|
||||||
|
|
||||||
|
//on multiplayer the destination is a the first captured sector (basically random)
|
||||||
|
Sector destsec = !net.client() ? state.secinfo.origin : state.rules.sector.planet.sectors.find(Sector::hasBase);
|
||||||
|
|
||||||
//actually launch the items upon removal
|
//actually launch the items upon removal
|
||||||
if(team() == state.rules.defaultTeam && state.secinfo.origin != null){
|
if(team() == state.rules.defaultTeam && destsec != null){
|
||||||
ItemSeq dest = state.secinfo.origin.getExtraItems();
|
ItemSeq dest = destsec.getExtraItems();
|
||||||
|
|
||||||
for(ItemStack stack : stacks){
|
for(ItemStack stack : stacks){
|
||||||
dest.add(stack);
|
dest.add(stack);
|
||||||
@@ -186,7 +191,7 @@ public class LaunchPad extends Block{
|
|||||||
Events.fire(new LaunchItemEvent(stack));
|
Events.fire(new LaunchItemEvent(stack));
|
||||||
}
|
}
|
||||||
|
|
||||||
state.secinfo.origin.setExtraItems(dest);
|
destsec.setExtraItems(dest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user