Merge branch 'master' into port-field
This commit is contained in:
@@ -60,6 +60,8 @@ public class Vars implements Loadable{
|
||||
public static final String serverJsonURL = "https://raw.githubusercontent.com/Anuken/Mindustry/master/servers.json";
|
||||
/** URL to the JSON file containing all the BE servers. Only queried in BE. */
|
||||
public static final String serverJsonBeURL = "https://raw.githubusercontent.com/Anuken/Mindustry/master/servers_be.json";
|
||||
/** URL to the JSON file containing all the BE servers. Only queried in the V6 alpha (will be removed once it's out). */
|
||||
public static final String serverJsonV6URL = "https://raw.githubusercontent.com/Anuken/Mindustry/master/servers_v6.json";
|
||||
/** URL of the github issue report template.*/
|
||||
public static final String reportIssueURL = "https://github.com/Anuken/Mindustry/issues/new?template=bug_report.md";
|
||||
/** list of built-in servers.*/
|
||||
@@ -70,6 +72,8 @@ public class Vars implements Loadable{
|
||||
public static final int maxTextLength = 150;
|
||||
/** max player name length in bytes */
|
||||
public static final int maxNameLength = 40;
|
||||
/** shadow color for turrets */
|
||||
public static final float turretShadowColor = Color.toFloatBits(0, 0, 0, 0.22f);
|
||||
/** displayed item size when ingame. */
|
||||
public static final float itemSize = 5f;
|
||||
/** units outside of this bound will die instantly */
|
||||
@@ -85,15 +89,17 @@ public class Vars implements Loadable{
|
||||
/** turns needed to destroy a sector completely */
|
||||
public static final float sectorDestructionTurns = 3f;
|
||||
/** min armor fraction damage; e.g. 0.05 = at least 5% damage */
|
||||
public static final float minArmorDamage = 0.05f;
|
||||
public static final float minArmorDamage = 0.1f;
|
||||
/** launch animation duration */
|
||||
public static final float launchDuration = 140f;
|
||||
/** size of tiles in units */
|
||||
public static final int tilesize = 8;
|
||||
/** size of one tile payload (^2) */
|
||||
public static final float tilePayload = tilesize * tilesize;
|
||||
/** tile used in certain situations, instead of null */
|
||||
public static Tile emptyTile;
|
||||
/** for map generator dialog */
|
||||
public static boolean updateEditorOnChange = false;
|
||||
/** size of tiles in units */
|
||||
public static final int tilesize = 8;
|
||||
/** all choosable player colors in join/host dialog */
|
||||
public static final Color[] playerColors = {
|
||||
Color.valueOf("82759a"),
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package mindustry.ai;
|
||||
|
||||
import arc.*;
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import arc.util.*;
|
||||
@@ -68,7 +69,7 @@ public class BaseRegistry{
|
||||
}
|
||||
schem.tiles.removeAll(s -> s.block.buildVisibility == BuildVisibility.sandboxOnly);
|
||||
|
||||
part.tier = schem.tiles.sumf(s -> s.block.buildCost / s.block.buildCostMultiplier);
|
||||
part.tier = schem.tiles.sumf(s -> Mathf.pow(s.block.buildCost / s.block.buildCostMultiplier, 1.2f));
|
||||
|
||||
if(part.core != null){
|
||||
cores.add(part);
|
||||
|
||||
@@ -6,6 +6,7 @@ import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.struct.EnumSet;
|
||||
import arc.struct.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
@@ -33,7 +34,7 @@ public class BlockIndexer{
|
||||
/** Maps each team ID to a quarant. A quadrant is a grid of bits, where each bit is set if and only if there is a block of that team in that quadrant. */
|
||||
private GridBits[] structQuadrants;
|
||||
/** Stores all damaged tile entities by team. */
|
||||
private BuildingArray[] damagedTiles = new BuildingArray[Team.all.length];
|
||||
private ObjectSet<Building>[] damagedTiles = new ObjectSet[Team.all.length];
|
||||
/** All ores available on this map. */
|
||||
private ObjectSet<Item> allOres = new ObjectSet<>();
|
||||
/** Stores teams that are present here as tiles. */
|
||||
@@ -70,7 +71,7 @@ public class BlockIndexer{
|
||||
Events.on(WorldLoadEvent.class, event -> {
|
||||
scanOres.clear();
|
||||
scanOres.addAll(Item.getAllOres());
|
||||
damagedTiles = new BuildingArray[Team.all.length];
|
||||
damagedTiles = new ObjectSet[Team.all.length];
|
||||
flagMap = new TileArray[Team.all.length][BlockFlag.all.length];
|
||||
unitCaps = new int[Team.all.length];
|
||||
activeTeams = new Seq<>(Team.class);
|
||||
@@ -139,14 +140,14 @@ public class BlockIndexer{
|
||||
}
|
||||
|
||||
/** Returns all damaged tiles by team. */
|
||||
public BuildingArray getDamaged(Team team){
|
||||
returnArray.clear();
|
||||
public ObjectSet<Building> getDamaged(Team team){
|
||||
breturnArray.clear();
|
||||
|
||||
if(damagedTiles[team.id] == null){
|
||||
damagedTiles[team.id] = new BuildingArray();
|
||||
damagedTiles[team.id] = new ObjectSet<>();
|
||||
}
|
||||
|
||||
BuildingArray set = damagedTiles[team.id];
|
||||
ObjectSet<Building> set = damagedTiles[team.id];
|
||||
for(Building build : set){
|
||||
if((!build.isValid() || build.team != team || !build.damaged()) || build.block instanceof ConstructBlock){
|
||||
breturnArray.add(build);
|
||||
@@ -165,6 +166,11 @@ public class BlockIndexer{
|
||||
return flagMap[team.id][type.ordinal()];
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Tile findClosestFlag(float x, float y, Team team, BlockFlag flag){
|
||||
return Geometry.findClosest(x, y, getAllied(team, flag));
|
||||
}
|
||||
|
||||
public boolean eachBlock(Teamc team, float range, Boolf<Building> pred, Cons<Building> cons){
|
||||
return eachBlock(team.team(), team.getX(), team.getY(), range, pred, cons);
|
||||
}
|
||||
@@ -214,7 +220,7 @@ public class BlockIndexer{
|
||||
|
||||
public void notifyTileDamaged(Building entity){
|
||||
if(damagedTiles[entity.team.id] == null){
|
||||
damagedTiles[entity.team.id] = new BuildingArray();
|
||||
damagedTiles[entity.team.id] = new ObjectSet<Building>();
|
||||
}
|
||||
|
||||
damagedTiles[entity.team.id].add(entity);
|
||||
@@ -476,35 +482,4 @@ public class BlockIndexer{
|
||||
return tiles.iterator();
|
||||
}
|
||||
}
|
||||
|
||||
//TODO copy-pasted code, generics would be nice here
|
||||
public static class BuildingArray implements Iterable<Building>{
|
||||
private Seq<Building> tiles = new Seq<>(false, 16);
|
||||
private IntSet contained = new IntSet();
|
||||
|
||||
public void add(Building tile){
|
||||
if(contained.add(tile.pos())){
|
||||
tiles.add(tile);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(Building tile){
|
||||
if(contained.remove(tile.pos())){
|
||||
tiles.remove(tile);
|
||||
}
|
||||
}
|
||||
|
||||
public int size(){
|
||||
return tiles.size;
|
||||
}
|
||||
|
||||
public Building first(){
|
||||
return tiles.first();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Building> iterator(){
|
||||
return tiles.iterator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,8 @@ public class Pathfinder implements Runnable{
|
||||
PathTile.health(tile) * 5 +
|
||||
(PathTile.nearSolid(tile) ? 2 : 0) +
|
||||
(PathTile.nearLiquid(tile) ? 6 : 0) +
|
||||
(PathTile.deep(tile) ? 70 : 0),
|
||||
(PathTile.deep(tile) ? 70 : 0) +
|
||||
(PathTile.damages(tile) ? 30 : 0),
|
||||
|
||||
//legs
|
||||
(team, tile) -> PathTile.legSolid(tile) ? impassable : 1 +
|
||||
@@ -52,14 +53,15 @@ public class Pathfinder implements Runnable{
|
||||
//water
|
||||
(team, tile) -> PathTile.solid(tile) || !PathTile.liquid(tile) ? 200 : 2 + //TODO cannot go through blocks - pathfinding isn't great
|
||||
(PathTile.nearGround(tile) || PathTile.nearSolid(tile) ? 14 : 0) +
|
||||
(PathTile.deep(tile) ? -1 : 0)
|
||||
(PathTile.deep(tile) ? -1 : 0) +
|
||||
(PathTile.damages(tile) ? 35 : 0)
|
||||
);
|
||||
|
||||
//maps team, cost, type to flow field
|
||||
Flowfield[][][] cache;
|
||||
|
||||
/** tile data, see PathTileStruct */
|
||||
int[][] tiles;
|
||||
int[][] tiles = new int[0][0];
|
||||
/** unordered array of path data for iteration only. DO NOT iterate or access this in the main thread. */
|
||||
Seq<Flowfield> threadList = new Seq<>(), mainList = new Seq<>();
|
||||
/** handles task scheduling on the update thread. */
|
||||
@@ -122,7 +124,8 @@ public class Pathfinder implements Runnable{
|
||||
nearLiquid,
|
||||
nearGround,
|
||||
nearSolid,
|
||||
tile.floor().isDeep()
|
||||
tile.floor().isDeep(),
|
||||
tile.floor().damageTaken > 0.00001f
|
||||
);
|
||||
}
|
||||
|
||||
@@ -514,5 +517,7 @@ public class Pathfinder implements Runnable{
|
||||
boolean nearSolid;
|
||||
//whether this block is deep / drownable
|
||||
boolean deep;
|
||||
//whether the floor damages
|
||||
boolean damages;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,20 +5,14 @@ import arc.math.geom.*;
|
||||
import mindustry.ai.formations.*;
|
||||
|
||||
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. */
|
||||
public float angleOffset = 0;
|
||||
|
||||
public CircleFormation(float memberRadius){
|
||||
this.memberRadius = memberRadius;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3 calculateSlotLocation(Vec3 outLocation, int slotNumber){
|
||||
if(slots > 1){
|
||||
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);
|
||||
}else{
|
||||
outLocation.set(0, 0, 360f * slotNumber);
|
||||
|
||||
@@ -12,7 +12,7 @@ import mindustry.world.blocks.ConstructBlock.*;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class BuilderAI extends AIController{
|
||||
float buildRadius = 700;
|
||||
float buildRadius = 1500;
|
||||
boolean found = false;
|
||||
@Nullable Builderc following;
|
||||
|
||||
@@ -87,7 +87,7 @@ public class BuilderAI extends AIController{
|
||||
}
|
||||
|
||||
//find new request
|
||||
if(!unit.team().data().blocks.isEmpty() && following == null){
|
||||
if(!unit.team().data().blocks.isEmpty() && following == null && timer.get(timerTarget3, 60 * 2f)){
|
||||
Queue<BlockPlan> blocks = unit.team().data().blocks;
|
||||
BlockPlan block = blocks.first();
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package mindustry.ai.types;
|
||||
|
||||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.world.meta.*;
|
||||
@@ -12,14 +11,6 @@ public class FlyingAI extends AIController{
|
||||
|
||||
@Override
|
||||
public void updateMovement(){
|
||||
if(unit.moving()){
|
||||
unit.lookAt(unit.vel.angle());
|
||||
}
|
||||
|
||||
if(unit.isFlying()){
|
||||
unit.wobble();
|
||||
}
|
||||
|
||||
if(target != null && unit.hasWeapons() && command() == UnitCommand.attack){
|
||||
if(unit.type().weapons.first().rotate){
|
||||
moveTo(target, unit.range() * 0.8f);
|
||||
@@ -34,8 +25,7 @@ public class FlyingAI extends AIController{
|
||||
}
|
||||
|
||||
if(command() == UnitCommand.rally){
|
||||
target = targetFlag(unit.x, unit.y, BlockFlag.rally, false);
|
||||
moveTo(target, 60f);
|
||||
moveTo(targetFlag(unit.x, unit.y, BlockFlag.rally, false), 60f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +57,7 @@ public class FlyingAI extends AIController{
|
||||
vec.setAngle(Mathf.slerpDelta(unit.vel().angle(), vec.angle(), 0.6f));
|
||||
}
|
||||
|
||||
vec.setLength(unit.type().speed * Time.delta);
|
||||
vec.setLength(unit.type().speed);
|
||||
|
||||
unit.moveAt(vec);
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package mindustry.ai.types;
|
||||
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import mindustry.*;
|
||||
import mindustry.ai.formations.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
|
||||
public class FormationAI extends AIController implements FormationMember{
|
||||
public Unit leader;
|
||||
@@ -25,39 +26,44 @@ public class FormationAI extends AIController implements FormationMember{
|
||||
|
||||
@Override
|
||||
public void updateUnit(){
|
||||
UnitType type = unit.type();
|
||||
|
||||
if(leader.dead){
|
||||
unit.resetController();
|
||||
return;
|
||||
}
|
||||
|
||||
unit.controlWeapons(leader.isRotate(), leader.isShooting);
|
||||
if(unit.type().canBoost && unit.canPassOn()){
|
||||
unit.elevation = Mathf.approachDelta(unit.elevation, 0f, 0.08f);
|
||||
}
|
||||
|
||||
unit.controlWeapons(true, leader.isShooting);
|
||||
// unit.moveAt(Tmp.v1.set(deltaX, deltaY).limit(unit.type().speed));
|
||||
if(leader.isShooting){
|
||||
unit.aimLook(leader.aimX(), leader.aimY());
|
||||
}else{
|
||||
if(!leader.moving() || !unit.type().rotateShooting){
|
||||
if(unit.moving()){
|
||||
unit.lookAt(unit.vel.angle());
|
||||
}
|
||||
}else{
|
||||
unit.lookAt(leader.rotation);
|
||||
}
|
||||
|
||||
unit.aim(leader.aimX(), leader.aimY());
|
||||
|
||||
if(unit.type().rotateShooting){
|
||||
unit.lookAt(leader.aimX(), leader.aimY());
|
||||
}else if(unit.moving()){
|
||||
unit.lookAt(unit.vel.angle());
|
||||
}
|
||||
|
||||
Vec2 realtarget = vec.set(target);
|
||||
|
||||
if(unit.isGrounded() && Vars.world.raycast(unit.tileX(), unit.tileY(), leader.tileX(), leader.tileY(), Vars.world::solid)){
|
||||
//TODO pathfind
|
||||
//realtarget.set(Vars.pathfinder.getTargetTile(unit.tileOn(), unit.team, leader));
|
||||
}
|
||||
float margin = 3f;
|
||||
|
||||
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
|
||||
public void removed(Unit unit){
|
||||
if(formation != null){
|
||||
formation.removeMember(this);
|
||||
unit.resetController();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +73,7 @@ public class FormationAI extends AIController implements FormationMember{
|
||||
//TODO return formation size
|
||||
//eturn ((Commanderc)unit).formation().
|
||||
}
|
||||
return unit.hitSize * 1.7f;
|
||||
return unit.hitSize * 1f;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -45,14 +45,14 @@ public class GroundAI extends AIController{
|
||||
}
|
||||
}
|
||||
|
||||
if(unit.type().canBoost && !unit.onSolid()){
|
||||
if(unit.type().canBoost && unit.canPassOn()){
|
||||
unit.elevation = Mathf.approachDelta(unit.elevation, 0f, 0.08f);
|
||||
}
|
||||
|
||||
if(!Units.invalidateTarget(target, unit, unit.range())){
|
||||
if(!Units.invalidateTarget(target, unit, unit.range()) && unit.type().rotateShooting){
|
||||
if(unit.type().hasWeapons()){
|
||||
//TODO certain units should not look at the target, e.g. ships
|
||||
unit.aimLook(Predict.intercept(unit, target, unit.type().weapons.first().bullet.speed));
|
||||
unit.lookAt(Predict.intercept(unit, target, unit.type().weapons.first().bullet.speed));
|
||||
}
|
||||
}else if(unit.moving()){
|
||||
unit.lookAt(unit.vel().angle());
|
||||
@@ -74,15 +74,12 @@ public class GroundAI extends AIController{
|
||||
}*/
|
||||
}
|
||||
|
||||
protected void moveTo(int pathType){
|
||||
int costType =
|
||||
unit instanceof Legsc ? Pathfinder.costLegs :
|
||||
unit instanceof WaterMovec ? Pathfinder.costWater :
|
||||
Pathfinder.costGround;
|
||||
protected void moveTo(int pathTarget){
|
||||
int costType = unit.pathType();
|
||||
|
||||
Tile tile = unit.tileOn();
|
||||
if(tile == null) return;
|
||||
Tile targetTile = pathfinder.getTargetTile(tile, pathfinder.getField(unit.team, costType, pathType));
|
||||
Tile targetTile = pathfinder.getTargetTile(tile, pathfinder.getField(unit.team, costType, pathTarget));
|
||||
|
||||
if(tile == targetTile || (costType == Pathfinder.costWater && !targetTile.floor().isLiquid)) return;
|
||||
|
||||
|
||||
@@ -15,14 +15,6 @@ public class MinerAI extends AIController{
|
||||
|
||||
@Override
|
||||
protected void updateMovement(){
|
||||
if(unit.moving()){
|
||||
unit.lookAt(unit.vel.angle());
|
||||
}
|
||||
|
||||
if(unit.isFlying()){
|
||||
unit.wobble();
|
||||
}
|
||||
|
||||
Building core = unit.closestCore();
|
||||
|
||||
if(!(unit instanceof Minerc) || core == null) return;
|
||||
@@ -52,7 +44,7 @@ public class MinerAI extends AIController{
|
||||
}
|
||||
|
||||
if(ore != null){
|
||||
moveTo(ore, unit.type().range / 1.5f);
|
||||
moveTo(ore, unit.type().range / 2f);
|
||||
|
||||
if(unit.within(ore, unit.type().range)){
|
||||
miner.mineTile(ore);
|
||||
|
||||
34
core/src/mindustry/ai/types/RepairAI.java
Normal file
34
core/src/mindustry/ai/types/RepairAI.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package mindustry.ai.types;
|
||||
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.world.blocks.ConstructBlock.*;
|
||||
|
||||
//note that repair AI doesn't attack anything even if it theoretically can
|
||||
public class RepairAI extends AIController{
|
||||
|
||||
@Override
|
||||
protected void updateMovement(){
|
||||
boolean shoot = false;
|
||||
|
||||
if(target != null){
|
||||
if(!target.within(unit, unit.type().range * 0.8f)){
|
||||
moveTo(target, unit.type().range * 0.8f);
|
||||
}
|
||||
|
||||
if(target.within(unit, unit.type().range)){
|
||||
unit.aim(target);
|
||||
shoot = true;
|
||||
}
|
||||
}
|
||||
|
||||
unit.controlWeapons(shoot);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateTargeting(){
|
||||
target = Units.findDamagedTile(unit.team, unit.x, unit.y);
|
||||
|
||||
if(target instanceof ConstructBuild) target = null;
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ public class SuicideAI extends GroundAI{
|
||||
|
||||
Building core = unit.closestEnemyCore();
|
||||
|
||||
boolean rotate = false, shoot = false;
|
||||
boolean rotate = false, shoot = false, moveToTarget = false;
|
||||
|
||||
if(!Units.invalidateTarget(target, unit, unit.range())){
|
||||
rotate = true;
|
||||
@@ -55,11 +55,14 @@ public class SuicideAI extends GroundAI{
|
||||
}
|
||||
|
||||
if(!blocked){
|
||||
moveToTarget = true;
|
||||
//move towards target directly
|
||||
unit.moveAt(vec.set(target).sub(unit).limit(unit.type().speed));
|
||||
}
|
||||
|
||||
}else{
|
||||
}
|
||||
|
||||
if(!moveToTarget){
|
||||
if(command() == UnitCommand.rally){
|
||||
Teamc target = targetFlag(unit.x, unit.y, BlockFlag.rally, false);
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ public class PhysicsProcess implements AsyncProcess{
|
||||
refs.removeAll(ref -> {
|
||||
if(!ref.entity.isAdded()){
|
||||
physics.destroyBody(ref.body);
|
||||
ref.entity.physref(null);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -43,7 +44,7 @@ public class PhysicsProcess implements AsyncProcess{
|
||||
//find entities without bodies and assign them
|
||||
for(Physicsc entity : group){
|
||||
boolean grounded = entity.isGrounded();
|
||||
int bits = grounded ? flying.maskBits : ground.maskBits;
|
||||
int bits = grounded ? ground.maskBits : flying.maskBits;
|
||||
|
||||
if(entity.physref() == null){
|
||||
//add bodies to entities that have none
|
||||
|
||||
@@ -5,6 +5,7 @@ import mindustry.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.blocks.payloads.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -13,7 +14,6 @@ public class TeamIndexProcess implements AsyncProcess{
|
||||
private QuadTree<Unit>[] trees = new QuadTree[Team.all.length];
|
||||
private int[] counts = new int[Team.all.length];
|
||||
private int[][] typeCounts = new int[Team.all.length][0];
|
||||
private int[][] activeCounts = new int[Team.all.length][0];
|
||||
|
||||
public QuadTree<Unit> tree(Team team){
|
||||
if(trees[team.id] == null) trees[team.id] = new QuadTree<>(Vars.world.getQuadBounds(new Rect()));
|
||||
@@ -29,10 +29,6 @@ public class TeamIndexProcess implements AsyncProcess{
|
||||
return typeCounts[team.id].length <= type.id ? 0 : typeCounts[team.id][type.id];
|
||||
}
|
||||
|
||||
public int countActive(Team team, UnitType type){
|
||||
return activeCounts[team.id].length <= type.id ? 0 : activeCounts[team.id][type.id];
|
||||
}
|
||||
|
||||
public void updateCount(Team team, UnitType type, int amount){
|
||||
counts[team.id] += amount;
|
||||
if(typeCounts[team.id].length <= type.id){
|
||||
@@ -41,11 +37,16 @@ public class TeamIndexProcess implements AsyncProcess{
|
||||
typeCounts[team.id][type.id] += amount;
|
||||
}
|
||||
|
||||
public void updateActiveCount(Team team, UnitType type, int amount){
|
||||
if(activeCounts[team.id].length <= type.id){
|
||||
activeCounts[team.id] = new int[Vars.content.units().size];
|
||||
private void count(Unit unit){
|
||||
updateCount(unit.team, unit.type(), 1);
|
||||
|
||||
if(unit instanceof Payloadc){
|
||||
((Payloadc)unit).payloads().each(p -> {
|
||||
if(p instanceof UnitPayload){
|
||||
count(((UnitPayload)p).unit);
|
||||
}
|
||||
});
|
||||
}
|
||||
activeCounts[team.id][type.id] += amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,7 +64,6 @@ public class TeamIndexProcess implements AsyncProcess{
|
||||
}
|
||||
|
||||
Arrays.fill(typeCounts[team.id], 0);
|
||||
Arrays.fill(activeCounts[team.id], 0);
|
||||
}
|
||||
|
||||
Arrays.fill(counts, 0);
|
||||
@@ -71,8 +71,7 @@ public class TeamIndexProcess implements AsyncProcess{
|
||||
for(Unit unit : Groups.unit){
|
||||
tree(unit.team).insert(unit);
|
||||
|
||||
updateCount(unit.team, unit.type(), 1);
|
||||
if(!unit.deactivated) updateActiveCount(unit.team, unit.type(), 1);
|
||||
count(unit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ public class Blocks implements ContentList{
|
||||
public static Block
|
||||
|
||||
//environment
|
||||
air, spawn, cliff, deepwater, water, taintedWater, tar, slag, stone, craters, charr, sand, darksand, dirt, ice, snow, darksandTaintedWater,
|
||||
dacite, stoneWall, dirtWall, sporeWall, iceWall, daciteWall, cliffs, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster,
|
||||
air, spawn, cliff, deepwater, water, taintedWater, tar, slag, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater,
|
||||
dacite, stoneWall, dirtWall, sporeWall, iceWall, daciteWall, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster,
|
||||
iceSnow, sandWater, darksandWater, duneWall, sandWall, moss, sporeMoss, shale, shaleWall, shaleBoulder, sandBoulder, daciteBoulder, grass, salt,
|
||||
metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, basalt, magmarock, hotrock, snowWall, boulder, snowBoulder, saltWall,
|
||||
darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal,
|
||||
@@ -83,7 +83,7 @@ public class Blocks implements ContentList{
|
||||
repairPoint, resupplyPoint,
|
||||
|
||||
//logic
|
||||
message, switchBlock, microProcessor, logicProcessor, hyperProcessor, logicDisplay, memoryCell,
|
||||
message, switchBlock, microProcessor, logicProcessor, hyperProcessor, largeLogicDisplay, logicDisplay, memoryCell, memoryBank,
|
||||
|
||||
//campaign
|
||||
launchPad, launchPadLarge,
|
||||
@@ -260,6 +260,16 @@ public class Blocks implements ContentList{
|
||||
|
||||
dirt = new Floor("dirt");
|
||||
|
||||
mud = new Floor("mud"){{
|
||||
speedMultiplier = 0.6f;
|
||||
variants = 3;
|
||||
status = StatusEffects.muddy;
|
||||
statusDuration = 30f;
|
||||
attributes.set(Attribute.water, 1f);
|
||||
cacheLayer = CacheLayer.mud;
|
||||
albedo = 0.35f;
|
||||
}};
|
||||
|
||||
((ShallowLiquid)darksandTaintedWater).set(Blocks.taintedWater, Blocks.darksand);
|
||||
((ShallowLiquid)sandWater).set(Blocks.water, Blocks.sand);
|
||||
((ShallowLiquid)darksandWater).set(Blocks.water, Blocks.darksand);
|
||||
@@ -292,11 +302,6 @@ public class Blocks implements ContentList{
|
||||
attributes.set(Attribute.water, 0.3f);
|
||||
}};
|
||||
|
||||
cliffs = new StaticWall("cliffs"){{
|
||||
variants = 1;
|
||||
fillsTile = false;
|
||||
}};
|
||||
|
||||
stoneWall = new StaticWall("stone-wall"){{
|
||||
variants = 2;
|
||||
}};
|
||||
@@ -311,6 +316,7 @@ public class Blocks implements ContentList{
|
||||
|
||||
snowBoulder = new Boulder("snow-boulder"){{
|
||||
variants = 2;
|
||||
snow.asFloor().decoration = ice.asFloor().decoration = iceSnow.asFloor().decoration = this;
|
||||
}};
|
||||
|
||||
dirtWall = new StaticWall("dirt-wall"){{
|
||||
@@ -332,11 +338,12 @@ public class Blocks implements ContentList{
|
||||
|
||||
duneWall = new StaticWall("dune-wall"){{
|
||||
variants = 2;
|
||||
basalt.asFloor().wall = this;
|
||||
basalt.asFloor().wall = darksandWater.asFloor().wall = darksandTaintedWater.asFloor().wall = this;
|
||||
}};
|
||||
|
||||
sandWall = new StaticWall("sand-wall"){{
|
||||
variants = 2;
|
||||
sandWater.asFloor().wall = this;
|
||||
}};
|
||||
|
||||
saltWall = new StaticWall("salt-wall");
|
||||
@@ -796,7 +803,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
door = new Door("door"){{
|
||||
requirements(Category.defense, with(Items.graphite, 6, Items.silicon, 4));
|
||||
requirements(Category.defense, with(Items.titanium, 6, Items.silicon, 4));
|
||||
health = 100 * wallHealthMultiplier;
|
||||
}};
|
||||
|
||||
@@ -1016,7 +1023,7 @@ public class Blocks implements ContentList{
|
||||
|
||||
mechanicalPump = new Pump("mechanical-pump"){{
|
||||
requirements(Category.liquid, with(Items.copper, 15, Items.metaglass, 10));
|
||||
pumpAmount = 0.1f;
|
||||
pumpAmount = 0.11f;
|
||||
}};
|
||||
|
||||
rotaryPump = new Pump("rotary-pump"){{
|
||||
@@ -1141,7 +1148,7 @@ public class Blocks implements ContentList{
|
||||
requirements(Category.power, with(Items.copper, 35, Items.graphite, 25, Items.lead, 40, Items.silicon, 30));
|
||||
powerProduction = 5.5f;
|
||||
itemDuration = 90f;
|
||||
consumes.liquid(Liquids.water, 0.05f);
|
||||
consumes.liquid(Liquids.water, 0.09f);
|
||||
hasLiquids = true;
|
||||
size = 2;
|
||||
}};
|
||||
@@ -1261,7 +1268,7 @@ public class Blocks implements ContentList{
|
||||
rotateSpeed = 1.4f;
|
||||
attribute = Attribute.water;
|
||||
|
||||
consumes.power(1f);
|
||||
consumes.power(1.25f);
|
||||
}};
|
||||
|
||||
cultivator = new Cultivator("cultivator"){{
|
||||
@@ -1274,7 +1281,7 @@ public class Blocks implements ContentList{
|
||||
hasItems = true;
|
||||
|
||||
consumes.power(0.80f);
|
||||
consumes.liquid(Liquids.water, 0.18f);
|
||||
consumes.liquid(Liquids.water, 0.2f);
|
||||
}};
|
||||
|
||||
oilExtractor = new Fracker("oil-extractor"){{
|
||||
@@ -1314,7 +1321,7 @@ public class Blocks implements ContentList{
|
||||
requirements(Category.effect, with(Items.copper, 3000, Items.lead, 3000, Items.silicon, 2000));
|
||||
|
||||
unitType = UnitTypes.beta;
|
||||
health = 2000;
|
||||
health = 3500;
|
||||
itemCapacity = 9000;
|
||||
size = 4;
|
||||
|
||||
@@ -1325,7 +1332,7 @@ public class Blocks implements ContentList{
|
||||
requirements(Category.effect, with(Items.copper, 8000, Items.lead, 8000, Items.silicon, 5000, Items.thorium, 4000));
|
||||
|
||||
unitType = UnitTypes.gamma;
|
||||
health = 4000;
|
||||
health = 6000;
|
||||
itemCapacity = 13000;
|
||||
size = 5;
|
||||
|
||||
@@ -1371,7 +1378,7 @@ public class Blocks implements ContentList{
|
||||
ammoUseEffect = Fx.shellEjectSmall;
|
||||
health = 250;
|
||||
inaccuracy = 2f;
|
||||
rotatespeed = 10f;
|
||||
rotateSpeed = 10f;
|
||||
}};
|
||||
|
||||
scatter = new ItemTurret("scatter"){{
|
||||
@@ -1389,7 +1396,7 @@ public class Blocks implements ContentList{
|
||||
targetGround = false;
|
||||
|
||||
recoilAmount = 2f;
|
||||
rotatespeed = 15f;
|
||||
rotateSpeed = 15f;
|
||||
inaccuracy = 17f;
|
||||
shootCone = 35f;
|
||||
|
||||
@@ -1486,14 +1493,14 @@ public class Blocks implements ContentList{
|
||||
arc = new PowerTurret("arc"){{
|
||||
requirements(Category.turret, with(Items.copper, 35, Items.lead, 50));
|
||||
shootType = new LightningBulletType(){{
|
||||
damage = 21;
|
||||
damage = 20;
|
||||
lightningLength = 25;
|
||||
collidesAir = false;
|
||||
}};
|
||||
reloadTime = 35f;
|
||||
shootCone = 40f;
|
||||
rotatespeed = 8f;
|
||||
powerUse = 4f;
|
||||
rotateSpeed = 8f;
|
||||
powerUse = 3f;
|
||||
targetAir = false;
|
||||
range = 90f;
|
||||
shootEffect = Fx.lightningShoot;
|
||||
@@ -1565,14 +1572,14 @@ public class Blocks implements ContentList{
|
||||
segment = new PointDefenseTurret("segment"){{
|
||||
requirements(Category.turret, with(Items.silicon, 130, Items.thorium, 80, Items.phasefabric, 40));
|
||||
|
||||
health = 250 * size * size;
|
||||
range = 140f;
|
||||
hasPower = true;
|
||||
consumes.power(3f);
|
||||
consumes.power(8f);
|
||||
size = 2;
|
||||
shootLength = 5f;
|
||||
bulletDamage = 25f;
|
||||
reloadTime = 10f;
|
||||
health = 190 * size * size;
|
||||
}};
|
||||
|
||||
fuse = new ItemTurret("fuse"){{
|
||||
@@ -1591,8 +1598,10 @@ public class Blocks implements ContentList{
|
||||
health = 220 * size * size;
|
||||
shootSound = Sounds.shotgun;
|
||||
|
||||
float brange = range + 10f;
|
||||
|
||||
ammo(Items.thorium, new ShrapnelBulletType(){{
|
||||
length = range + 10f;
|
||||
length = brange;
|
||||
damage = 105f;
|
||||
ammoMultiplier = 6f;
|
||||
}});
|
||||
@@ -1641,7 +1650,7 @@ public class Blocks implements ContentList{
|
||||
range = 200f;
|
||||
size = 3;
|
||||
recoilAmount = 3f;
|
||||
rotatespeed = 10f;
|
||||
rotateSpeed = 10f;
|
||||
inaccuracy = 10f;
|
||||
shootCone = 30f;
|
||||
shootSound = Sounds.shootSnap;
|
||||
@@ -1650,7 +1659,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
spectre = new ItemTurret("spectre"){{
|
||||
requirements(Category.turret, with(Items.copper, 350, Items.graphite, 300, Items.surgealloy, 250, Items.plastanium, 175, Items.thorium, 250));
|
||||
requirements(Category.turret, with(Items.copper, 900, Items.graphite, 300, Items.surgealloy, 250, Items.plastanium, 175, Items.thorium, 250));
|
||||
ammo(
|
||||
Items.graphite, Bullets.standardDenseBig,
|
||||
Items.pyratite, Bullets.standardIncendiaryBig,
|
||||
@@ -1676,7 +1685,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
meltdown = new LaserTurret("meltdown"){{
|
||||
requirements(Category.turret, with(Items.copper, 250, Items.lead, 350, Items.graphite, 300, Items.surgealloy, 325, Items.silicon, 325));
|
||||
requirements(Category.turret, with(Items.copper, 1200, Items.lead, 350, Items.graphite, 300, Items.surgealloy, 325, Items.silicon, 325));
|
||||
shootEffect = Fx.shootBigSmoke2;
|
||||
shootCone = 40f;
|
||||
recoilAmount = 4f;
|
||||
@@ -1686,7 +1695,7 @@ public class Blocks implements ContentList{
|
||||
reloadTime = 90f;
|
||||
firingMoveFract = 0.5f;
|
||||
shootDuration = 220f;
|
||||
powerUse = 14f;
|
||||
powerUse = 17f;
|
||||
shootSound = Sounds.laserbig;
|
||||
activeSound = Sounds.beam;
|
||||
activeSoundVolume = 2f;
|
||||
@@ -1741,7 +1750,6 @@ public class Blocks implements ContentList{
|
||||
new UnitPlan(UnitTypes.risso, 60f * 45f, with(Items.silicon, 20, Items.metaglass, 35)),
|
||||
};
|
||||
size = 3;
|
||||
requiresWater = true;
|
||||
consumes.power(1.2f);
|
||||
}};
|
||||
|
||||
@@ -1798,6 +1806,9 @@ public class Blocks implements ContentList{
|
||||
{UnitTypes.zenith, UnitTypes.antumbra},
|
||||
{UnitTypes.spiroct, UnitTypes.arkyid},
|
||||
{UnitTypes.fortress, UnitTypes.scepter},
|
||||
{UnitTypes.bryde, UnitTypes.sei},
|
||||
{UnitTypes.mega, UnitTypes.quad},
|
||||
{UnitTypes.quasar, UnitTypes.vela},
|
||||
};
|
||||
}};
|
||||
|
||||
@@ -1816,6 +1827,9 @@ public class Blocks implements ContentList{
|
||||
{UnitTypes.antumbra, UnitTypes.eclipse},
|
||||
{UnitTypes.arkyid, UnitTypes.toxopid},
|
||||
{UnitTypes.scepter, UnitTypes.reign},
|
||||
{UnitTypes.sei, UnitTypes.omura},
|
||||
{UnitTypes.quad, UnitTypes.oct},
|
||||
{UnitTypes.vela, UnitTypes.corvus}
|
||||
};
|
||||
}};
|
||||
|
||||
@@ -1831,6 +1845,8 @@ public class Blocks implements ContentList{
|
||||
|
||||
size = 2;
|
||||
range = 80f;
|
||||
itemCapacity = 20;
|
||||
ammoAmount = 5;
|
||||
|
||||
consumes.item(Items.copper, 1);
|
||||
}};
|
||||
@@ -1946,18 +1962,33 @@ public class Blocks implements ContentList{
|
||||
size = 3;
|
||||
}};
|
||||
|
||||
memoryCell = new MemoryBlock("memory-cell"){{
|
||||
requirements(Category.logic, with(Items.graphite, 30, Items.silicon, 30));
|
||||
|
||||
memoryCapacity = 64;
|
||||
}};
|
||||
|
||||
memoryBank = new MemoryBlock("memory-bank"){{
|
||||
requirements(Category.logic, with(Items.graphite, 80, Items.silicon, 80, Items.phasefabric, 30));
|
||||
|
||||
memoryCapacity = 512;
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
logicDisplay = new LogicDisplay("logic-display"){{
|
||||
requirements(Category.logic, with(Items.copper, 200, Items.lead, 120, Items.silicon, 100, Items.metaglass, 50));
|
||||
requirements(Category.logic, with(Items.lead, 100, Items.silicon, 50, Items.metaglass, 50));
|
||||
|
||||
displaySize = 80;
|
||||
|
||||
size = 3;
|
||||
}};
|
||||
|
||||
memoryCell = new MemoryBlock("memory-cell"){{
|
||||
requirements(Category.logic, with(Items.graphite, 40, Items.silicon, 40));
|
||||
largeLogicDisplay = new LogicDisplay("large-logic-display"){{
|
||||
requirements(Category.logic, with(Items.lead, 200, Items.silicon, 150, Items.metaglass, 100, Items.phasefabric, 75));
|
||||
|
||||
memoryCapacity = 64;
|
||||
displaySize = 176;
|
||||
|
||||
size = 6;
|
||||
}};
|
||||
|
||||
//endregion
|
||||
|
||||
@@ -42,7 +42,7 @@ public class Bullets implements ContentList{
|
||||
@Override
|
||||
public void load(){
|
||||
|
||||
artilleryDense = new ArtilleryBulletType(3f, 12, "shell"){{
|
||||
artilleryDense = new ArtilleryBulletType(3f, 20, "shell"){{
|
||||
hitEffect = Fx.flakExplosion;
|
||||
knockback = 0.8f;
|
||||
lifetime = 80f;
|
||||
@@ -63,7 +63,7 @@ public class Bullets implements ContentList{
|
||||
collidesAir = false;
|
||||
}};
|
||||
|
||||
artilleryPlastic = new ArtilleryBulletType(3.4f, 12, "shell"){{
|
||||
artilleryPlastic = new ArtilleryBulletType(3.4f, 20, "shell"){{
|
||||
hitEffect = Fx.plasticExplosion;
|
||||
knockback = 1f;
|
||||
lifetime = 80f;
|
||||
@@ -77,7 +77,7 @@ public class Bullets implements ContentList{
|
||||
frontColor = Pal.plastaniumFront;
|
||||
}};
|
||||
|
||||
artilleryHoming = new ArtilleryBulletType(3f, 12, "shell"){{
|
||||
artilleryHoming = new ArtilleryBulletType(3f, 20, "shell"){{
|
||||
hitEffect = Fx.flakExplosion;
|
||||
knockback = 0.8f;
|
||||
lifetime = 80f;
|
||||
@@ -91,7 +91,7 @@ public class Bullets implements ContentList{
|
||||
homingRange = 50f;
|
||||
}};
|
||||
|
||||
artilleryIncendiary = new ArtilleryBulletType(3f, 12, "shell"){{
|
||||
artilleryIncendiary = new ArtilleryBulletType(3f, 20, "shell"){{
|
||||
hitEffect = Fx.blastExplosion;
|
||||
knockback = 0.8f;
|
||||
lifetime = 80f;
|
||||
@@ -105,7 +105,7 @@ public class Bullets implements ContentList{
|
||||
trailEffect = Fx.incendTrail;
|
||||
}};
|
||||
|
||||
artilleryExplosive = new ArtilleryBulletType(2f, 12, "shell"){{
|
||||
artilleryExplosive = new ArtilleryBulletType(2f, 20, "shell"){{
|
||||
hitEffect = Fx.blastExplosion;
|
||||
knockback = 0.8f;
|
||||
lifetime = 80f;
|
||||
@@ -269,13 +269,13 @@ public class Bullets implements ContentList{
|
||||
status = StatusEffects.burning;
|
||||
}};
|
||||
|
||||
missileSurge = new MissileBulletType(3.7f, 20){{
|
||||
missileSurge = new MissileBulletType(3.7f, 18){{
|
||||
width = 8f;
|
||||
height = 8f;
|
||||
shrinkY = 0f;
|
||||
drag = -0.01f;
|
||||
splashDamageRadius = 28f;
|
||||
splashDamage = 35f;
|
||||
splashDamageRadius = 25f;
|
||||
splashDamage = 25f;
|
||||
hitEffect = Fx.blastExplosion;
|
||||
despawnEffect = Fx.blastExplosion;
|
||||
lightning = 2;
|
||||
@@ -433,6 +433,7 @@ public class Bullets implements ContentList{
|
||||
hitSize = 7f;
|
||||
lifetime = 18f;
|
||||
pierce = true;
|
||||
collidesAir = false;
|
||||
statusDuration = 60f * 4;
|
||||
shootEffect = Fx.shootSmallFlame;
|
||||
hitEffect = Fx.hitFlameSmall;
|
||||
@@ -447,6 +448,7 @@ public class Bullets implements ContentList{
|
||||
hitSize = 7f;
|
||||
lifetime = 18f;
|
||||
pierce = true;
|
||||
collidesAir = false;
|
||||
statusDuration = 60f * 6;
|
||||
shootEffect = Fx.shootPyraFlame;
|
||||
hitEffect = Fx.hitFlameSmall;
|
||||
|
||||
@@ -36,7 +36,7 @@ public class Fx{
|
||||
TextureRegion region = unit.icon(Cicon.full);
|
||||
|
||||
rect(region, e.x, e.y,
|
||||
region.getWidth() * Draw.scl * scl, region.getHeight() * Draw.scl * scl, 180f);
|
||||
region.width * Draw.scl * scl, region.height * Draw.scl * scl, 180f);
|
||||
|
||||
}),
|
||||
|
||||
@@ -145,7 +145,7 @@ public class Fx{
|
||||
|
||||
int i = 0;
|
||||
for(Vec2 p : lines){
|
||||
Fill.square(p.x, p.y, (5f - (float)i++ / lines.size * 2f) * e.fout(), 45);
|
||||
Fill.circle(p.x, p.y, Lines.getStroke() / 2f);
|
||||
}
|
||||
}),
|
||||
|
||||
@@ -290,6 +290,50 @@ public class Fx{
|
||||
Lines.spikes(e.x, e.y, 1f + e.fin() * 6f, e.fout() * 4f, 6);
|
||||
}),
|
||||
|
||||
greenBomb = new Effect(40f, 100f, e -> {
|
||||
color(Pal.heal);
|
||||
stroke(e.fout() * 2f);
|
||||
Lines.circle(e.x, e.y, 4f + e.finpow() * 65f);
|
||||
|
||||
color(Pal.heal);
|
||||
for(int i = 0; i < 4; i++){
|
||||
Drawf.tri(e.x, e.y, 6f, 100f * e.fout(), i*90);
|
||||
}
|
||||
|
||||
color();
|
||||
for(int i = 0; i < 4; i++){
|
||||
Drawf.tri(e.x, e.y, 3f, 35f * e.fout(), i*90);
|
||||
}
|
||||
}),
|
||||
|
||||
greenLaserCharge = new Effect(80f, 100f, e -> {
|
||||
color(Pal.heal);
|
||||
stroke(e.fin() * 2f);
|
||||
Lines.circle(e.x, e.y, 4f + e.fout() * 100f);
|
||||
|
||||
Fill.circle(e.x, e.y, e.fin() * 20);
|
||||
|
||||
randLenVectors(e.id, 20, 40f * e.fout(), (x, y) -> {
|
||||
Fill.circle(e.x + x, e.y + y, e.fin() * 5f);
|
||||
});
|
||||
|
||||
color();
|
||||
|
||||
Fill.circle(e.x, e.y, e.fin() * 10);
|
||||
}),
|
||||
|
||||
greenLaserChargeSmall = new Effect(40f, 100f, e -> {
|
||||
color(Pal.heal);
|
||||
stroke(e.fin() * 2f);
|
||||
Lines.circle(e.x, e.y, e.fout() * 50f);
|
||||
}),
|
||||
|
||||
healWaveDynamic = new Effect(22, e -> {
|
||||
color(Pal.heal);
|
||||
stroke(e.fout() * 2f);
|
||||
Lines.circle(e.x, e.y, 4f + e.finpow() * e.rotation);
|
||||
}),
|
||||
|
||||
healWave = new Effect(22, e -> {
|
||||
color(Pal.heal);
|
||||
stroke(e.fout() * 2f);
|
||||
@@ -400,6 +444,17 @@ public class Fx{
|
||||
|
||||
}),
|
||||
|
||||
hitMeltHeal = new Effect(12, e -> {
|
||||
color(Pal.heal);
|
||||
stroke(e.fout() * 2f);
|
||||
|
||||
randLenVectors(e.id, 6, e.finpow() * 18f, e.rotation, 360f, (x, y) -> {
|
||||
float ang = Mathf.angle(x, y);
|
||||
lineAngle(e.x + x, e.y + y, ang, e.fout() * 4 + 1f);
|
||||
});
|
||||
|
||||
}),
|
||||
|
||||
hitLaser = new Effect(8, e -> {
|
||||
color(Color.white, Pal.heal, e.fin());
|
||||
stroke(0.5f + e.fout());
|
||||
@@ -686,6 +741,13 @@ public class Fx{
|
||||
|
||||
Fill.circle(e.x, e.y, e.fout() * 1f);
|
||||
}),
|
||||
|
||||
muddy = new Effect(80f, e -> {
|
||||
color(Color.valueOf("432722"));
|
||||
alpha(Mathf.clamp(e.fin() * 2f));
|
||||
|
||||
Fill.circle(e.x, e.y, e.fout() * 1f);
|
||||
}),
|
||||
|
||||
sapped = new Effect(40f, e -> {
|
||||
color(Pal.sap);
|
||||
@@ -989,6 +1051,53 @@ public class Fx{
|
||||
|
||||
}).ground(400f),
|
||||
|
||||
railShoot = new Effect(24f, e -> {
|
||||
e.scaled(10f, b -> {
|
||||
color(Color.white, Color.lightGray, b.fin());
|
||||
stroke(b.fout() * 3f + 0.2f);
|
||||
Lines.circle(b.x, b.y, b.fin() * 50f);
|
||||
});
|
||||
|
||||
color(Pal.orangeSpark);
|
||||
|
||||
for(int i : Mathf.signs){
|
||||
Drawf.tri(e.x, e.y, 13f * e.fout(), 85f, e.rotation + 90f * i);
|
||||
}
|
||||
}),
|
||||
|
||||
railTrail = new Effect(16f, e -> {
|
||||
color(Pal.orangeSpark);
|
||||
|
||||
for(int i : Mathf.signs){
|
||||
Drawf.tri(e.x, e.y, 10f * e.fout(), 24f, e.rotation + 90 + 90f * i);
|
||||
}
|
||||
}),
|
||||
|
||||
railHit = new Effect(18f, 200f, e -> {
|
||||
if(true){
|
||||
color(Pal.orangeSpark);
|
||||
|
||||
for(int i : Mathf.signs){
|
||||
Drawf.tri(e.x, e.y, 10f * e.fout(), 60f, e.rotation + 140f * i);
|
||||
}
|
||||
}else{
|
||||
e.scaled(7f, b -> {
|
||||
color(Color.white, Color.lightGray, b.fin());
|
||||
stroke(b.fout() * 2f + 0.2f);
|
||||
Lines.circle(b.x, b.y, b.fin() * 28f);
|
||||
});
|
||||
|
||||
color(Pal.orangeSpark);
|
||||
float rot = e.rotation + Mathf.randomSeedRange(e.id, 20f);
|
||||
float w = 9f * e.fout();
|
||||
|
||||
Drawf.tri(e.x, e.y, w, 100f, rot);
|
||||
Drawf.tri(e.x, e.y, w, 10f, rot + 180f);
|
||||
}
|
||||
|
||||
|
||||
}),
|
||||
|
||||
lancerLaserShoot = new Effect(21f, e -> {
|
||||
color(Pal.lancerLaser);
|
||||
|
||||
@@ -1000,7 +1109,7 @@ public class Fx{
|
||||
|
||||
lancerLaserShootSmoke = new Effect(26f, e -> {
|
||||
color(Color.white);
|
||||
float length = e.data == null ? 70f : (Float)e.data;
|
||||
float length = e.data == null || !(e.data instanceof Float) ? 70f : (Float)e.data;
|
||||
|
||||
randLenVectors(e.id, 7, length, e.rotation, 0f, (x, y) -> {
|
||||
lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fout() * 9f);
|
||||
@@ -1070,6 +1179,15 @@ public class Fx{
|
||||
});
|
||||
}),
|
||||
|
||||
cloudsmoke = new Effect(70, e -> {
|
||||
randLenVectors(e.id, 12, 15f + e.fin() * 45f, (x, y) -> {
|
||||
float size = e.fslope() * 2f;
|
||||
color(Color.gray);
|
||||
alpha(e.fslope());
|
||||
Fill.circle(e.x + x, e.y + y, size);
|
||||
});
|
||||
}),
|
||||
|
||||
nuclearcloud = new Effect(90, 200f, e -> {
|
||||
randLenVectors(e.id, 10, e.finpow() * 90f, (x, y) -> {
|
||||
float size = e.fout() * 14f;
|
||||
@@ -1166,6 +1284,14 @@ public class Fx{
|
||||
Fill.square(e.x + x, e.y + y, 1f + e.fout() * 3f, 45);
|
||||
});
|
||||
}),
|
||||
|
||||
smokeCloud = new Effect(70, e -> {
|
||||
randLenVectors(e.id, e.fin(), 30, 30f, (x, y, fin, fout) -> {
|
||||
color(Color.gray);
|
||||
alpha((0.5f - Math.abs(fin - 0.5f)) * 2f);
|
||||
Fill.circle(e.x + x, e.y + y, 0.5f + fout * 4f);
|
||||
});
|
||||
}),
|
||||
|
||||
smeltsmoke = new Effect(15, e -> {
|
||||
randLenVectors(e.id, 6, 4f + e.fin() * 5f, (x, y) -> {
|
||||
@@ -1295,10 +1421,11 @@ public class Fx{
|
||||
|
||||
}),
|
||||
|
||||
//TODO fix false in constructor
|
||||
ripple = new Effect(30, e -> {
|
||||
e.lifetime = 30f*e.rotation;
|
||||
|
||||
color(Tmp.c1.set(e.color).mul(1.5f));
|
||||
stroke(e.fout() + 0.4f);
|
||||
stroke(e.fout() * 1.4f);
|
||||
Lines.circle(e.x, e.y, (2f + e.fin() * 4f) * e.rotation);
|
||||
}).ground(),
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import mindustry.type.StatusEffect;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class StatusEffects implements ContentList{
|
||||
public static StatusEffect none, burning, freezing, wet, melting, sapped, tarred, overdrive, overclock, shielded, shocked, blasted, corroded, boss, sporeSlowed;
|
||||
public static StatusEffect none, burning, freezing, unmoving, slow, wet, muddy, melting, sapped, tarred, overdrive, overclock, shielded, shocked, blasted, corroded, boss, sporeSlowed;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
@@ -45,6 +45,14 @@ public class StatusEffects implements ContentList{
|
||||
});
|
||||
}};
|
||||
|
||||
unmoving = new StatusEffect("unmoving"){{
|
||||
speedMultiplier = 0.001f;
|
||||
}};
|
||||
|
||||
slow = new StatusEffect("slow"){{
|
||||
speedMultiplier = 0.4f;
|
||||
}};
|
||||
|
||||
wet = new StatusEffect("wet"){{
|
||||
color = Color.royal;
|
||||
speedMultiplier = 0.94f;
|
||||
@@ -53,7 +61,7 @@ public class StatusEffects implements ContentList{
|
||||
|
||||
init(() -> {
|
||||
trans(shocked, ((unit, time, newTime, result) -> {
|
||||
unit.damagePierce(20f);
|
||||
unit.damagePierce(14f);
|
||||
if(unit.team() == state.rules.waveTeam){
|
||||
Events.fire(Trigger.shock);
|
||||
}
|
||||
@@ -62,6 +70,13 @@ public class StatusEffects implements ContentList{
|
||||
opposite(burning);
|
||||
});
|
||||
}};
|
||||
|
||||
muddy = new StatusEffect("muddy"){{
|
||||
color = Color.valueOf("46382a");
|
||||
speedMultiplier = 0.94f;
|
||||
effect = Fx.muddy;
|
||||
effectChance = 0.09f;
|
||||
}};
|
||||
|
||||
melting = new StatusEffect("melting"){{
|
||||
speedMultiplier = 0.8f;
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
package mindustry.content;
|
||||
|
||||
import arc.*;
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import mindustry.core.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.game.Objectives.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.content.Blocks.*;
|
||||
import static mindustry.content.SectorPresets.*;
|
||||
import static mindustry.content.SectorPresets.craters;
|
||||
import static mindustry.content.SectorPresets.*;
|
||||
import static mindustry.content.UnitTypes.*;
|
||||
import static mindustry.type.ItemStack.*;
|
||||
|
||||
@@ -208,11 +205,15 @@ public class TechTree implements ContentList{
|
||||
node(switchBlock, () -> {
|
||||
node(message, () -> {
|
||||
node(logicDisplay, () -> {
|
||||
node(largeLogicDisplay, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(memoryCell, () -> {
|
||||
node(memoryBank, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -264,7 +265,7 @@ public class TechTree implements ContentList{
|
||||
node(steamGenerator, () -> {
|
||||
node(thermalGenerator, () -> {
|
||||
node(differentialGenerator, () -> {
|
||||
node(thoriumReactor, () -> {
|
||||
node(thoriumReactor, Seq.with(new Research(Liquids.cryofluid)), () -> {
|
||||
node(impactReactor, () -> {
|
||||
|
||||
});
|
||||
@@ -377,7 +378,11 @@ public class TechTree implements ContentList{
|
||||
node(nova, () -> {
|
||||
node(pulsar, () -> {
|
||||
node(quasar, () -> {
|
||||
node(vela, () -> {
|
||||
node(corvus, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -410,7 +415,11 @@ public class TechTree implements ContentList{
|
||||
node(mono, () -> {
|
||||
node(poly, () -> {
|
||||
node(mega, () -> {
|
||||
node(quad, () -> {
|
||||
node(oct, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -420,7 +429,11 @@ public class TechTree implements ContentList{
|
||||
node(risso, () -> {
|
||||
node(minke, () -> {
|
||||
node(bryde, () -> {
|
||||
node(sei, () -> {
|
||||
node(omura, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -520,42 +533,27 @@ public class TechTree implements ContentList{
|
||||
});
|
||||
}
|
||||
|
||||
private static void setup(){
|
||||
public static void setup(){
|
||||
TechNode.context = null;
|
||||
map = new ObjectMap<>();
|
||||
all = new Seq<>();
|
||||
}
|
||||
|
||||
private static TechNode node(UnlockableContent content, Runnable children){
|
||||
ItemStack[] requirements;
|
||||
|
||||
if(content instanceof Block){
|
||||
Block block = (Block)content;
|
||||
|
||||
requirements = new ItemStack[block.requirements.length];
|
||||
for(int i = 0; i < requirements.length; i++){
|
||||
int quantity = 40 + Mathf.round(Mathf.pow(block.requirements[i].amount, 1.25f) * 20, 10);
|
||||
|
||||
requirements[i] = new ItemStack(block.requirements[i].item, UI.roundAmount(quantity));
|
||||
}
|
||||
}else{
|
||||
requirements = ItemStack.empty;
|
||||
}
|
||||
|
||||
return node(content, requirements, children);
|
||||
public static TechNode node(UnlockableContent content, Runnable children){
|
||||
return node(content, content.researchRequirements(), children);
|
||||
}
|
||||
|
||||
private static TechNode node(UnlockableContent content, ItemStack[] requirements, Runnable children){
|
||||
public static TechNode node(UnlockableContent content, ItemStack[] requirements, Runnable children){
|
||||
return new TechNode(content, requirements, children);
|
||||
}
|
||||
|
||||
private static TechNode node(UnlockableContent content, Seq<Objective> objectives, Runnable children){
|
||||
TechNode node = new TechNode(content, empty, children);
|
||||
public static TechNode node(UnlockableContent content, Seq<Objective> objectives, Runnable children){
|
||||
TechNode node = new TechNode(content, content.researchRequirements(), children);
|
||||
node.objectives = objectives;
|
||||
return node;
|
||||
}
|
||||
|
||||
private static TechNode node(UnlockableContent block){
|
||||
public static TechNode node(UnlockableContent block){
|
||||
return node(block, () -> {});
|
||||
}
|
||||
|
||||
|
||||
@@ -11,15 +11,23 @@ import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class UnitTypes implements ContentList{
|
||||
//region definitions
|
||||
|
||||
//ground
|
||||
//mech
|
||||
public static @EntityDef({Unitc.class, Mechc.class}) UnitType mace, dagger, crawler, fortress, scepter, reign;
|
||||
|
||||
//ground + builder + miner + commander
|
||||
//mech + builder + miner + commander
|
||||
public static @EntityDef({Unitc.class, Mechc.class, Builderc.class, Minerc.class, Commanderc.class}) UnitType nova, pulsar, quasar;
|
||||
|
||||
//mech + commander
|
||||
public static @EntityDef({Unitc.class, Mechc.class, Commanderc.class}) UnitType vela;
|
||||
|
||||
//legs + commander
|
||||
public static @EntityDef({Unitc.class, Legsc.class, Commanderc.class}) UnitType corvus;
|
||||
|
||||
//legs
|
||||
public static @EntityDef({Unitc.class, Legsc.class}) UnitType atrax;
|
||||
|
||||
@@ -38,11 +46,17 @@ public class UnitTypes implements ContentList{
|
||||
//air + building + mining + payload
|
||||
public static @EntityDef({Unitc.class, Builderc.class, Minerc.class, Payloadc.class}) UnitType mega;
|
||||
|
||||
//air + building + payload
|
||||
public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class}) UnitType quad;
|
||||
|
||||
//air + building + payload + command
|
||||
public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class, Commanderc.class}) UnitType oct;
|
||||
|
||||
//air + building + mining
|
||||
public static @EntityDef({Unitc.class, Builderc.class, Minerc.class}) UnitType alpha, beta, gamma;
|
||||
|
||||
//water
|
||||
public static @EntityDef({Unitc.class, WaterMovec.class, Commanderc.class}) UnitType risso, minke, bryde;
|
||||
//water + commander
|
||||
public static @EntityDef({Unitc.class, WaterMovec.class, Commanderc.class}) UnitType risso, minke, bryde, sei, omura;
|
||||
|
||||
//special block unit type
|
||||
public static @EntityDef({Unitc.class, BlockUnitc.class}) UnitType block;
|
||||
@@ -55,12 +69,13 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
dagger = new UnitType("dagger"){{
|
||||
speed = 0.5f;
|
||||
hitsize = 8f;
|
||||
hitSize = 8f;
|
||||
health = 140;
|
||||
weapons.add(new Weapon("large-weapon"){{
|
||||
reload = 14f;
|
||||
x = 4f;
|
||||
y = 2f;
|
||||
top = false;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
bullet = Bullets.standardCopper;
|
||||
}});
|
||||
@@ -68,13 +83,14 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
mace = new UnitType("mace"){{
|
||||
speed = 0.4f;
|
||||
hitsize = 9f;
|
||||
hitSize = 9f;
|
||||
health = 500;
|
||||
armor = 4f;
|
||||
|
||||
immunities.add(StatusEffects.burning);
|
||||
|
||||
weapons.add(new Weapon("flamethrower"){{
|
||||
top = false;
|
||||
shootSound = Sounds.flame;
|
||||
shootY = 2f;
|
||||
reload = 14f;
|
||||
@@ -98,13 +114,15 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
fortress = new UnitType("fortress"){{
|
||||
speed = 0.38f;
|
||||
hitsize = 13f;
|
||||
hitSize = 13f;
|
||||
rotateSpeed = 3f;
|
||||
targetAir = false;
|
||||
health = 790;
|
||||
armor = 9f;
|
||||
mechFrontSway = 0.55f;
|
||||
|
||||
weapons.add(new Weapon("artillery"){{
|
||||
top = false;
|
||||
y = 1f;
|
||||
x = 9f;
|
||||
reload = 60f;
|
||||
@@ -129,16 +147,19 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
scepter = new UnitType("scepter"){{
|
||||
speed = 0.35f;
|
||||
hitsize = 20f;
|
||||
hitSize = 20f;
|
||||
rotateSpeed = 2.1f;
|
||||
targetAir = false;
|
||||
health = 9000;
|
||||
armor = 11f;
|
||||
mechLegMoveScl = 1.3f;
|
||||
canDrown = false;
|
||||
mechFrontSway = 1f;
|
||||
|
||||
mechStepParticles = true;
|
||||
mechStepShake = 0.15f;
|
||||
|
||||
weapons.add(
|
||||
new Weapon("scepter-weapon"){{
|
||||
top = false;
|
||||
y = 1f;
|
||||
x = 16f;
|
||||
shootY = 8f;
|
||||
@@ -186,22 +207,25 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
reign = new UnitType("reign"){{
|
||||
speed = 0.35f;
|
||||
hitsize = 26f;
|
||||
hitSize = 26f;
|
||||
rotateSpeed = 1.65f;
|
||||
targetAir = false;
|
||||
health = 24000;
|
||||
armor = 14f;
|
||||
mechLegMoveScl = 1.75f;
|
||||
mechStepParticles = true;
|
||||
mechStepShake = 0.75f;
|
||||
canDrown = false;
|
||||
mechFrontSway = 1.9f;
|
||||
mechSideSway = 0.6f;
|
||||
|
||||
weapons.add(
|
||||
new Weapon("reign-weapon"){{
|
||||
top = false;
|
||||
y = 1f;
|
||||
x = 21.5f;
|
||||
shootY = 11f;
|
||||
reload = 9f;
|
||||
recoil = 5f;
|
||||
shake = 4f;
|
||||
shake = 2f;
|
||||
ejectEffect = Fx.shellEjectBig;
|
||||
shootSound = Sounds.artillery;
|
||||
|
||||
@@ -244,16 +268,18 @@ public class UnitTypes implements ContentList{
|
||||
itemCapacity = 60;
|
||||
canBoost = true;
|
||||
boostMultiplier = 1.5f;
|
||||
speed = 0.52f;
|
||||
hitsize = 8f;
|
||||
speed = 0.55f;
|
||||
hitSize = 8f;
|
||||
health = 110f;
|
||||
buildSpeed = 0.8f;
|
||||
armor = 1f;
|
||||
commandLimit = 8;
|
||||
|
||||
abilities.add(new HealFieldAbility(10f, 60f * 4, 60f));
|
||||
ammoType = AmmoTypes.power;
|
||||
|
||||
weapons.add(new Weapon("heal-weapon"){{
|
||||
top = false;
|
||||
shootY = 2f;
|
||||
reload = 24f;
|
||||
x = 4.5f;
|
||||
@@ -269,8 +295,8 @@ public class UnitTypes implements ContentList{
|
||||
itemCapacity = 60;
|
||||
canBoost = true;
|
||||
boostMultiplier = 1.5f;
|
||||
speed = 0.48f;
|
||||
hitsize = 10f;
|
||||
speed = 0.65f;
|
||||
hitSize = 10f;
|
||||
health = 320f;
|
||||
buildSpeed = 0.9f;
|
||||
armor = 4f;
|
||||
@@ -280,8 +306,10 @@ public class UnitTypes implements ContentList{
|
||||
commandLimit = 15;
|
||||
|
||||
abilities.add(new ShieldFieldAbility(20f, 40f, 60f * 5, 60f));
|
||||
ammoType = AmmoTypes.power;
|
||||
|
||||
weapons.add(new Weapon("heal-shotgun-weapon"){{
|
||||
top = false;
|
||||
x = 5f;
|
||||
shake = 2.2f;
|
||||
y = 0.5f;
|
||||
@@ -309,7 +337,7 @@ public class UnitTypes implements ContentList{
|
||||
|
||||
quasar = new UnitType("quasar"){{
|
||||
mineTier = 1;
|
||||
hitsize = 12f;
|
||||
hitSize = 12f;
|
||||
boostMultiplier = 2f;
|
||||
itemCapacity = 80;
|
||||
health = 650f;
|
||||
@@ -318,10 +346,12 @@ public class UnitTypes implements ContentList{
|
||||
armor = 9f;
|
||||
landShake = 2f;
|
||||
|
||||
commandLimit = 24;
|
||||
commandLimit = 18;
|
||||
mechFrontSway = 0.55f;
|
||||
ammoType = AmmoTypes.power;
|
||||
|
||||
speed = 0.4f;
|
||||
hitsize = 10f;
|
||||
hitSize = 10f;
|
||||
|
||||
mineTier = 2;
|
||||
mineSpeed = 7f;
|
||||
@@ -330,6 +360,7 @@ public class UnitTypes implements ContentList{
|
||||
abilities.add(new ForceFieldAbility(60f, 0.3f, 400f, 60f * 6));
|
||||
|
||||
weapons.add(new Weapon("beam-weapon"){{
|
||||
top = false;
|
||||
shake = 2f;
|
||||
shootY = 4f;
|
||||
x = 6.5f;
|
||||
@@ -348,6 +379,138 @@ public class UnitTypes implements ContentList{
|
||||
}});
|
||||
}};
|
||||
|
||||
vela = new UnitType("vela"){{
|
||||
hitSize = 23f;
|
||||
|
||||
rotateSpeed = 1.6f;
|
||||
canDrown = false;
|
||||
mechFrontSway = 1f;
|
||||
|
||||
mechStepParticles = true;
|
||||
mechStepShake = 0.15f;
|
||||
ammoType = AmmoTypes.powerHigh;
|
||||
|
||||
speed = 0.35f;
|
||||
boostMultiplier = 2.1f;
|
||||
engineOffset = 12f;
|
||||
engineSize = 6f;
|
||||
lowAltitude = true;
|
||||
|
||||
health = 6500f;
|
||||
armor = 7f;
|
||||
canBoost = true;
|
||||
landShake = 4f;
|
||||
|
||||
commandLimit = 20;
|
||||
|
||||
weapons.add(new Weapon("vela-weapon"){{
|
||||
mirror = false;
|
||||
top = false;
|
||||
shake = 4f;
|
||||
shootY = 13f;
|
||||
x = y = 0f;
|
||||
|
||||
firstShotDelay = Fx.greenLaserChargeSmall.lifetime - 1f;
|
||||
|
||||
reload = 320f;
|
||||
recoil = 0f;
|
||||
shootSound = Sounds.laser;
|
||||
continuous = true;
|
||||
cooldownTime = 200f;
|
||||
|
||||
bullet = new ContinuousLaserBulletType(17){{
|
||||
length = 150f;
|
||||
hitEffect = Fx.hitMeltHeal;
|
||||
drawSize = 420f;
|
||||
lifetime = 160f;
|
||||
shake = 1f;
|
||||
despawnEffect = Fx.smokeCloud;
|
||||
smokeEffect = Fx.none;
|
||||
|
||||
shootEffect = Fx.greenLaserChargeSmall;
|
||||
|
||||
incendChance = 0.02f;
|
||||
incendSpread = 5f;
|
||||
incendAmount = 1;
|
||||
|
||||
colors = new Color[]{Pal.heal.cpy().a(.2f), Pal.heal.cpy().a(.5f), Pal.heal.cpy().mul(1.2f), Color.white};
|
||||
}};
|
||||
|
||||
shootStatus = StatusEffects.slow;
|
||||
shootStatusDuration = bullet.lifetime + firstShotDelay;
|
||||
}});
|
||||
}};
|
||||
|
||||
corvus = new UnitType("corvus"){{
|
||||
mineTier = 1;
|
||||
hitSize = 29f;
|
||||
itemCapacity = 80;
|
||||
health = 19000f;
|
||||
buildSpeed = 1.7f;
|
||||
armor = 9f;
|
||||
landShake = 1.5f;
|
||||
rotateSpeed = 1.5f;
|
||||
|
||||
commandLimit = 20;
|
||||
|
||||
legCount = 4;
|
||||
legLength = 14f;
|
||||
legBaseOffset = 11f;
|
||||
legMoveSpace = 1.5f;
|
||||
legTrns = 0.58f;
|
||||
hovering = true;
|
||||
visualElevation = 0.2f;
|
||||
allowLegStep = true;
|
||||
ammoType = AmmoTypes.powerHigh;
|
||||
|
||||
speed = 0.3f;
|
||||
|
||||
mineTier = 2;
|
||||
mineSpeed = 7f;
|
||||
drawShields = false;
|
||||
|
||||
weapons.add(new Weapon("corvus-weapon"){{
|
||||
top = false;
|
||||
mirror = false;
|
||||
shake = 14f;
|
||||
shootY = 5f;
|
||||
x = y = 0;
|
||||
reload = 350f;
|
||||
recoil = 0f;
|
||||
shootSound = Sounds.laser;
|
||||
|
||||
cooldownTime = 350f;
|
||||
|
||||
shootStatusDuration = 60f * 2f;
|
||||
shootStatus = StatusEffects.unmoving;
|
||||
firstShotDelay = Fx.greenLaserCharge.lifetime;
|
||||
|
||||
bullet = new LaserBulletType(){{
|
||||
length = 500f;
|
||||
damage = 520f;
|
||||
width = 75f;
|
||||
|
||||
lifetime = 65f;
|
||||
|
||||
lightningSpacing = 35f;
|
||||
lightningLength = 5;
|
||||
lightningDelay = 1.1f;
|
||||
lightningLengthRand = 15;
|
||||
lightningDamage = 50;
|
||||
lightningAngleRand = 40f;
|
||||
largeHit = true;
|
||||
lightColor = lightningColor = Pal.heal;
|
||||
|
||||
shootEffect = Fx.greenLaserCharge;
|
||||
|
||||
sideAngle = 15f;
|
||||
sideWidth = 0f;
|
||||
sideLength = 0f;
|
||||
colors = new Color[]{Pal.heal.cpy().a(0.4f), Pal.heal, Color.white};
|
||||
}};
|
||||
}});
|
||||
}};
|
||||
|
||||
//endregion
|
||||
//region ground legs
|
||||
|
||||
@@ -355,9 +518,9 @@ public class UnitTypes implements ContentList{
|
||||
defaultController = SuicideAI::new;
|
||||
|
||||
speed = 0.85f;
|
||||
hitsize = 8f;
|
||||
health = 170;
|
||||
sway = 0.25f;
|
||||
hitSize = 8f;
|
||||
health = 180;
|
||||
mechSideSway = 0.25f;
|
||||
range = 40f;
|
||||
|
||||
weapons.add(new Weapon(){{
|
||||
@@ -371,7 +534,7 @@ public class UnitTypes implements ContentList{
|
||||
speed = 1f;
|
||||
splashDamageRadius = 55f;
|
||||
instantDisappear = true;
|
||||
splashDamage = 45f;
|
||||
splashDamage = 55f;
|
||||
killShooter = true;
|
||||
hittable = false;
|
||||
collidesAir = true;
|
||||
@@ -383,11 +546,12 @@ public class UnitTypes implements ContentList{
|
||||
itemCapacity = 80;
|
||||
speed = 0.5f;
|
||||
drag = 0.4f;
|
||||
hitsize = 10f;
|
||||
hitSize = 10f;
|
||||
rotateSpeed = 3f;
|
||||
targetAir = false;
|
||||
health = 600;
|
||||
immunities = ObjectSet.with(StatusEffects.burning, StatusEffects.melting);
|
||||
|
||||
legCount = 4;
|
||||
legLength = 9f;
|
||||
legTrns = 0.6f;
|
||||
@@ -400,6 +564,7 @@ public class UnitTypes implements ContentList{
|
||||
groundLayer = Layer.legUnit - 1f;
|
||||
|
||||
weapons.add(new Weapon("eruption"){{
|
||||
top = false;
|
||||
shootY = 3f;
|
||||
reload = 10f;
|
||||
ejectEffect = Fx.none;
|
||||
@@ -421,7 +586,7 @@ public class UnitTypes implements ContentList{
|
||||
spiroct = new UnitType("spiroct"){{
|
||||
speed = 0.4f;
|
||||
drag = 0.4f;
|
||||
hitsize = 12f;
|
||||
hitSize = 12f;
|
||||
rotateSpeed = 3f;
|
||||
health = 760;
|
||||
immunities = ObjectSet.with(StatusEffects.burning, StatusEffects.melting);
|
||||
@@ -432,6 +597,7 @@ public class UnitTypes implements ContentList{
|
||||
legBaseOffset = 2f;
|
||||
hovering = true;
|
||||
armor = 5f;
|
||||
ammoType = AmmoTypes.power;
|
||||
|
||||
buildSpeed = 0.75f;
|
||||
|
||||
@@ -486,7 +652,7 @@ public class UnitTypes implements ContentList{
|
||||
arkyid = new UnitType("arkyid"){{
|
||||
drag = 0.1f;
|
||||
speed = 0.5f;
|
||||
hitsize = 21f;
|
||||
hitSize = 21f;
|
||||
health = 8000;
|
||||
armor = 6f;
|
||||
|
||||
@@ -503,6 +669,7 @@ public class UnitTypes implements ContentList{
|
||||
legLengthScl = 0.96f;
|
||||
rippleScale = 2f;
|
||||
legSpeed = 0.2f;
|
||||
ammoType = AmmoTypes.power;
|
||||
|
||||
legSplashDamage = 32;
|
||||
legSplashRange = 30;
|
||||
@@ -584,9 +751,9 @@ public class UnitTypes implements ContentList{
|
||||
toxopid = new UnitType("toxopid"){{
|
||||
drag = 0.1f;
|
||||
speed = 0.5f;
|
||||
hitsize = 21f;
|
||||
health = 23000;
|
||||
armor = 14f;
|
||||
hitSize = 21f;
|
||||
health = 22000;
|
||||
armor = 13f;
|
||||
|
||||
rotateSpeed = 1.9f;
|
||||
|
||||
@@ -601,6 +768,7 @@ public class UnitTypes implements ContentList{
|
||||
legLengthScl = 0.93f;
|
||||
rippleScale = 3f;
|
||||
legSpeed = 0.19f;
|
||||
ammoType = AmmoTypes.powerHigh;
|
||||
|
||||
legSplashDamage = 80;
|
||||
legSplashRange = 60;
|
||||
@@ -662,8 +830,8 @@ public class UnitTypes implements ContentList{
|
||||
width = height = 25f;
|
||||
collidesTiles = collides = true;
|
||||
ammoMultiplier = 4f;
|
||||
splashDamageRadius = 95f;
|
||||
splashDamage = 90f;
|
||||
splashDamageRadius = 90f;
|
||||
splashDamage = 75f;
|
||||
backColor = Pal.sapBulletBack;
|
||||
frontColor = lightningColor = Pal.sapBullet;
|
||||
lightning = 5;
|
||||
@@ -684,7 +852,7 @@ public class UnitTypes implements ContentList{
|
||||
width = height = 20f;
|
||||
collidesTiles = false;
|
||||
splashDamageRadius = 80f;
|
||||
splashDamage = 45f;
|
||||
splashDamage = 40f;
|
||||
backColor = Pal.sapBulletBack;
|
||||
frontColor = lightningColor = Pal.sapBullet;
|
||||
lightning = 2;
|
||||
@@ -711,7 +879,6 @@ public class UnitTypes implements ContentList{
|
||||
faceTarget = false;
|
||||
engineOffset = 5.5f;
|
||||
range = 140f;
|
||||
crashDamageMultiplier = 4f;
|
||||
|
||||
weapons.add(new Weapon(){{
|
||||
y = 0f;
|
||||
@@ -729,6 +896,7 @@ public class UnitTypes implements ContentList{
|
||||
accel = 0.08f;
|
||||
drag = 0.016f;
|
||||
flying = true;
|
||||
hitSize = 9f;
|
||||
targetAir = false;
|
||||
engineOffset = 7.8f;
|
||||
range = 140f;
|
||||
@@ -765,7 +933,7 @@ public class UnitTypes implements ContentList{
|
||||
drag = 0.016f;
|
||||
flying = true;
|
||||
range = 140f;
|
||||
hitsize = 18f;
|
||||
hitSize = 18f;
|
||||
lowAltitude = true;
|
||||
armor = 5f;
|
||||
|
||||
@@ -813,7 +981,7 @@ public class UnitTypes implements ContentList{
|
||||
armor = 9f;
|
||||
engineOffset = 21;
|
||||
engineSize = 5.3f;
|
||||
hitsize = 56f;
|
||||
hitSize = 56f;
|
||||
|
||||
BulletType missiles = new MissileBulletType(2.7f, 10){{
|
||||
width = 8f;
|
||||
@@ -885,7 +1053,7 @@ public class UnitTypes implements ContentList{
|
||||
health = 20000;
|
||||
engineOffset = 38;
|
||||
engineSize = 7.3f;
|
||||
hitsize = 58f;
|
||||
hitSize = 58f;
|
||||
destructibleWreck = false;
|
||||
armor = 13f;
|
||||
|
||||
@@ -968,6 +1136,8 @@ public class UnitTypes implements ContentList{
|
||||
range = 50f;
|
||||
isCounted = false;
|
||||
|
||||
ammoType = AmmoTypes.powerLow;
|
||||
|
||||
mineTier = 1;
|
||||
mineSpeed = 2.5f;
|
||||
}};
|
||||
@@ -985,16 +1155,19 @@ public class UnitTypes implements ContentList{
|
||||
health = 400;
|
||||
buildSpeed = 0.5f;
|
||||
engineOffset = 6.5f;
|
||||
hitsize = 8f;
|
||||
hitSize = 8f;
|
||||
lowAltitude = true;
|
||||
isCounted = false;
|
||||
|
||||
ammoType = AmmoTypes.power;
|
||||
|
||||
mineTier = 2;
|
||||
mineSpeed = 3.5f;
|
||||
|
||||
abilities.add(new HealFieldAbility(5f, 60f * 5, 50f));
|
||||
|
||||
weapons.add(new Weapon("heal-weapon-mount"){{
|
||||
top = false;
|
||||
y = -2.5f;
|
||||
x = 3.5f;
|
||||
reload = 30f;
|
||||
@@ -1023,8 +1196,12 @@ public class UnitTypes implements ContentList{
|
||||
}};
|
||||
|
||||
mega = new UnitType("mega"){{
|
||||
defaultController = RepairAI::new;
|
||||
|
||||
mineTier = 2;
|
||||
health = 500;
|
||||
armor = 2f;
|
||||
armor = 5f;
|
||||
speed = 1.8f;
|
||||
accel = 0.06f;
|
||||
drag = 0.017f;
|
||||
@@ -1032,11 +1209,13 @@ public class UnitTypes implements ContentList{
|
||||
flying = true;
|
||||
engineOffset = 10.5f;
|
||||
rotateShooting = false;
|
||||
hitsize = 15f;
|
||||
hitSize = 15f;
|
||||
engineSize = 3f;
|
||||
payloadCapacity = 4 * (8 * 8);
|
||||
payloadCapacity = (2 * 2) * tilePayload;
|
||||
buildSpeed = 2.5f;
|
||||
|
||||
ammoType = AmmoTypes.power;
|
||||
|
||||
weapons.add(
|
||||
new Weapon("heal-weapon-mount"){{
|
||||
reload = 25f;
|
||||
@@ -1054,17 +1233,99 @@ public class UnitTypes implements ContentList{
|
||||
}});
|
||||
}};
|
||||
|
||||
quad = new UnitType("quad"){{
|
||||
armor = 4f;
|
||||
health = 6000;
|
||||
speed = 1.2f;
|
||||
rotateSpeed = 2f;
|
||||
accel = 0.05f;
|
||||
drag = 0.017f;
|
||||
lowAltitude = false;
|
||||
flying = true;
|
||||
engineOffset = 12f;
|
||||
engineSize = 6f;
|
||||
rotateShooting = false;
|
||||
hitSize = 32f;
|
||||
payloadCapacity = (3 * 3) * tilePayload;
|
||||
buildSpeed = 2.5f;
|
||||
range = 140f;
|
||||
targetAir = false;
|
||||
|
||||
ammoType = AmmoTypes.powerHigh;
|
||||
|
||||
weapons.add(
|
||||
new Weapon(){{
|
||||
x = y = 0f;
|
||||
mirror = false;
|
||||
reload = 60f;
|
||||
minShootVelocity = 0.01f;
|
||||
|
||||
bullet = new BasicBulletType(){{
|
||||
sprite = "large-bomb";
|
||||
width = height = 120/4f;
|
||||
|
||||
range = 30f;
|
||||
ignoreRotation = true;
|
||||
|
||||
backColor = Pal.heal;
|
||||
frontColor = Color.white;
|
||||
mixColorTo = Color.white;
|
||||
|
||||
shootCone = 180f;
|
||||
ejectEffect = Fx.none;
|
||||
shootSound = Sounds.none;
|
||||
despawnShake = 4f;
|
||||
|
||||
collidesAir = false;
|
||||
|
||||
lifetime = 70f;
|
||||
|
||||
despawnEffect = Fx.greenBomb;
|
||||
hitEffect = Fx.massiveExplosion;
|
||||
keepVelocity = false;
|
||||
spin = 2f;
|
||||
|
||||
shrinkX = shrinkY = 0.7f;
|
||||
|
||||
speed = 0.001f;
|
||||
collides = false;
|
||||
|
||||
splashDamage = 240f;
|
||||
splashDamageRadius = 115f;
|
||||
}};
|
||||
}});
|
||||
}};
|
||||
|
||||
oct = new UnitType("oct"){{
|
||||
armor = 16f;
|
||||
health = 24000;
|
||||
speed = 0.6f;
|
||||
rotateSpeed = 1f;
|
||||
accel = 0.04f;
|
||||
drag = 0.018f;
|
||||
flying = true;
|
||||
engineOffset = 46f;
|
||||
engineSize = 7.8f;
|
||||
rotateShooting = false;
|
||||
hitSize = 60f;
|
||||
payloadCapacity = (5.3f * 5.3f) * tilePayload;
|
||||
buildSpeed = 4f;
|
||||
drawShields = false;
|
||||
commandLimit = 25;
|
||||
|
||||
abilities.add(new ForceFieldAbility(140f, 4f, 7000f, 60f * 8), new HealFieldAbility(130f, 60f * 2, 140f));
|
||||
}};
|
||||
|
||||
//endregion
|
||||
//region naval attack
|
||||
|
||||
risso = new UnitType("risso"){{
|
||||
speed = 1.1f;
|
||||
drag = 0.13f;
|
||||
hitsize = 9f;
|
||||
hitSize = 9f;
|
||||
health = 280;
|
||||
accel = 0.4f;
|
||||
rotateSpeed = 3.3f;
|
||||
immunities = ObjectSet.with(StatusEffects.wet);
|
||||
trailLength = 20;
|
||||
rotateShooting = false;
|
||||
|
||||
@@ -1112,17 +1373,16 @@ public class UnitTypes implements ContentList{
|
||||
health = 600;
|
||||
speed = 0.9f;
|
||||
drag = 0.15f;
|
||||
hitsize = 11f;
|
||||
hitSize = 11f;
|
||||
armor = 4f;
|
||||
accel = 0.3f;
|
||||
rotateSpeed = 2.6f;
|
||||
immunities = ObjectSet.with(StatusEffects.wet);
|
||||
rotateShooting = false;
|
||||
|
||||
trailLength = 20;
|
||||
trailX = 5.5f;
|
||||
trailY = -4f;
|
||||
trailScl = 1.9f;
|
||||
rotateShooting = false;
|
||||
|
||||
abilities.add(new StatusFieldAbility(StatusEffects.overclock, 60f * 6, 60f * 6f, 60f));
|
||||
|
||||
@@ -1156,9 +1416,8 @@ public class UnitTypes implements ContentList{
|
||||
accel = 0.2f;
|
||||
rotateSpeed = 1.8f;
|
||||
drag = 0.17f;
|
||||
hitsize = 14f;
|
||||
armor = 6f;
|
||||
immunities = ObjectSet.with(StatusEffects.wet);
|
||||
hitSize = 16f;
|
||||
armor = 7f;
|
||||
rotateShooting = false;
|
||||
|
||||
trailLength = 22;
|
||||
@@ -1166,7 +1425,7 @@ public class UnitTypes implements ContentList{
|
||||
trailY = -9f;
|
||||
trailScl = 1.5f;
|
||||
|
||||
abilities.add(new HealFieldAbility(22f, 60f * 4, 70f), new ShieldFieldAbility(20f, 40f, 60f * 4, 60f));
|
||||
abilities.add(new ShieldFieldAbility(20f, 40f, 60f * 4, 60f));
|
||||
|
||||
weapons.add(new Weapon("large-artillery"){{
|
||||
reload = 65f;
|
||||
@@ -1178,7 +1437,7 @@ public class UnitTypes implements ContentList{
|
||||
shootY = 7f;
|
||||
shake = 5f;
|
||||
recoil = 4f;
|
||||
occlusion = 17f;
|
||||
occlusion = 12f;
|
||||
|
||||
shots = 1;
|
||||
inaccuracy = 3f;
|
||||
@@ -1244,6 +1503,140 @@ public class UnitTypes implements ContentList{
|
||||
}});
|
||||
}};
|
||||
|
||||
sei = new UnitType("sei"){{
|
||||
health = 10000;
|
||||
armor = 12f;
|
||||
|
||||
speed = 0.73f;
|
||||
drag = 0.17f;
|
||||
hitSize = 39f;
|
||||
accel = 0.2f;
|
||||
rotateSpeed = 1.3f;
|
||||
rotateShooting = false;
|
||||
|
||||
trailLength = 50;
|
||||
trailX = 18f;
|
||||
trailY = -21f;
|
||||
trailScl = 3f;
|
||||
|
||||
weapons.add(new Weapon("sei-launcher"){{
|
||||
|
||||
x = 0f;
|
||||
y = 0f;
|
||||
rotate = true;
|
||||
rotateSpeed = 4f;
|
||||
mirror = false;
|
||||
|
||||
occlusion = 20f;
|
||||
|
||||
shootY = 2f;
|
||||
recoil = 4f;
|
||||
reload = 45f;
|
||||
shots = 6;
|
||||
spacing = 10f;
|
||||
velocityRnd = 0.4f;
|
||||
inaccuracy = 7f;
|
||||
ejectEffect = Fx.none;
|
||||
shake = 3f;
|
||||
shootSound = Sounds.shootBig;
|
||||
xRand = 8f;
|
||||
shotDelay = 1f;
|
||||
|
||||
bullet = new MissileBulletType(4.2f, 25){{
|
||||
homingPower = 0.12f;
|
||||
width = 8f;
|
||||
height = 8f;
|
||||
shrinkX = shrinkY = 0f;
|
||||
drag = -0.003f;
|
||||
homingRange = 80f;
|
||||
keepVelocity = false;
|
||||
splashDamageRadius = 25f;
|
||||
splashDamage = 25f;
|
||||
lifetime = 56f;
|
||||
trailColor = Pal.bulletYellowBack;
|
||||
backColor = Pal.bulletYellowBack;
|
||||
frontColor = Pal.bulletYellow;
|
||||
hitEffect = Fx.blastExplosion;
|
||||
despawnEffect = Fx.blastExplosion;
|
||||
weaveScale = 8f;
|
||||
weaveMag = 2f;
|
||||
}};
|
||||
}});
|
||||
|
||||
weapons.add(new Weapon("large-bullet-mount"){{
|
||||
reload = 80f;
|
||||
cooldownTime = 90f;
|
||||
x = 70f/4f;
|
||||
y = -66f/4f;
|
||||
rotateSpeed = 4f;
|
||||
rotate = true;
|
||||
shootY = 7f;
|
||||
shake = 2f;
|
||||
recoil = 3f;
|
||||
occlusion = 12f;
|
||||
ejectEffect = Fx.shellEjectBig;
|
||||
|
||||
shots = 3;
|
||||
shotDelay = 4f;
|
||||
inaccuracy = 1f;
|
||||
bullet = new BasicBulletType(7f, 50){{
|
||||
width = 13f;
|
||||
height = 19f;
|
||||
shootEffect = Fx.shootBig;
|
||||
lifetime = 30f;
|
||||
}};
|
||||
}});
|
||||
}};
|
||||
|
||||
omura = new UnitType("omura"){{
|
||||
health = 22000;
|
||||
speed = 0.62f;
|
||||
drag = 0.18f;
|
||||
hitSize = 50f;
|
||||
armor = 16f;
|
||||
accel = 0.19f;
|
||||
rotateSpeed = 0.9f;
|
||||
rotateShooting = false;
|
||||
|
||||
float spawnTime = 60f * 15f;
|
||||
|
||||
abilities.add(new UnitSpawnAbility(flare, spawnTime, 19.25f, -31.75f), new UnitSpawnAbility(flare, spawnTime, -19.25f, -31.75f));
|
||||
|
||||
trailLength = 70;
|
||||
trailX = 23f;
|
||||
trailY = -32f;
|
||||
trailScl = 3.5f;
|
||||
|
||||
weapons.add(new Weapon("omura-cannon"){{
|
||||
reload = 110f;
|
||||
cooldownTime = 90f;
|
||||
mirror = false;
|
||||
x = 0f;
|
||||
y = -3.5f;
|
||||
rotateSpeed = 1.4f;
|
||||
rotate = true;
|
||||
shootY = 23f;
|
||||
shake = 6f;
|
||||
recoil = 10.5f;
|
||||
occlusion = 50f;
|
||||
|
||||
shots = 1;
|
||||
ejectEffect = Fx.none;
|
||||
|
||||
bullet = new RailBulletType(){{
|
||||
shootEffect = Fx.railShoot;
|
||||
speed = 67f;
|
||||
lifetime = 8f;
|
||||
pierceEffect = Fx.railHit;
|
||||
updateEffect = Fx.railTrail;
|
||||
hitEffect = Fx.massiveExplosion;
|
||||
smokeEffect = Fx.shootBig2;
|
||||
damage = 1250;
|
||||
pierceDamageFactor = 0.5f;
|
||||
}};
|
||||
}});
|
||||
}};
|
||||
|
||||
//endregion
|
||||
//region core
|
||||
|
||||
@@ -1256,18 +1649,19 @@ public class UnitTypes implements ContentList{
|
||||
mineTier = 1;
|
||||
buildSpeed = 0.5f;
|
||||
drag = 0.05f;
|
||||
speed = 2.6f;
|
||||
speed = 2.8f;
|
||||
rotateSpeed = 15f;
|
||||
accel = 0.1f;
|
||||
itemCapacity = 30;
|
||||
health = 120f;
|
||||
engineOffset = 6f;
|
||||
hitsize = 8f;
|
||||
hitSize = 8f;
|
||||
|
||||
weapons.add(new Weapon("small-basic-weapon"){{
|
||||
reload = 17f;
|
||||
x = 2.75f;
|
||||
y = 1f;
|
||||
top = false;
|
||||
|
||||
bullet = new BasicBulletType(2.5f, 9){{
|
||||
width = 7f;
|
||||
@@ -1289,17 +1683,18 @@ public class UnitTypes implements ContentList{
|
||||
mineTier = 1;
|
||||
buildSpeed = 0.75f;
|
||||
drag = 0.05f;
|
||||
speed = 2.9f;
|
||||
speed = 3f;
|
||||
rotateSpeed = 17f;
|
||||
accel = 0.1f;
|
||||
itemCapacity = 50;
|
||||
health = 150f;
|
||||
engineOffset = 6f;
|
||||
hitsize = 9f;
|
||||
hitSize = 9f;
|
||||
rotateShooting = false;
|
||||
lowAltitude = true;
|
||||
|
||||
weapons.add(new Weapon("small-mount-weapon"){{
|
||||
top = false;
|
||||
reload = 20f;
|
||||
x = 3f;
|
||||
y = 0.5f;
|
||||
@@ -1328,15 +1723,16 @@ public class UnitTypes implements ContentList{
|
||||
mineTier = 2;
|
||||
buildSpeed = 1f;
|
||||
drag = 0.05f;
|
||||
speed = 3.4f;
|
||||
speed = 3.5f;
|
||||
rotateSpeed = 19f;
|
||||
accel = 0.11f;
|
||||
itemCapacity = 70;
|
||||
health = 190f;
|
||||
engineOffset = 6f;
|
||||
hitsize = 10f;
|
||||
hitSize = 10f;
|
||||
|
||||
weapons.add(new Weapon("small-mount-weapon"){{
|
||||
top = false;
|
||||
reload = 15f;
|
||||
x = 1f;
|
||||
y = 2f;
|
||||
@@ -1363,7 +1759,7 @@ public class UnitTypes implements ContentList{
|
||||
block = new UnitType("block"){
|
||||
{
|
||||
speed = 0f;
|
||||
hitsize = 0f;
|
||||
hitSize = 0f;
|
||||
health = 1;
|
||||
rotateSpeed = 360f;
|
||||
itemCapacity = 0;
|
||||
|
||||
@@ -5,7 +5,6 @@ import arc.graphics.*;
|
||||
import arc.graphics.Texture.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.gen.*;
|
||||
@@ -170,8 +169,8 @@ public class Weathers implements ContentList{
|
||||
|
||||
sandstorm = new Weather("sandstorm"){
|
||||
TextureRegion region;
|
||||
float yspeed = 0.3f, xspeed = 6f, size = 140f, padding = size, invDensity = 1500f;
|
||||
Vec2 force = new Vec2(0.45f, 0.01f);
|
||||
float size = 140f, padding = size, invDensity = 1500f, baseSpeed = 6.1f;
|
||||
float force = 0.45f;
|
||||
Color color = Color.valueOf("f7cba4");
|
||||
Texture noise;
|
||||
|
||||
@@ -194,22 +193,26 @@ public class Weathers implements ContentList{
|
||||
|
||||
@Override
|
||||
public void update(WeatherState state){
|
||||
float speed = force * state.intensity;
|
||||
float windx = state.windVector.x * speed, windy = state.windVector.y * speed;
|
||||
|
||||
for(Unit unit : Groups.unit){
|
||||
unit.impulse(force.x * state.intensity(), force.y * state.intensity());
|
||||
unit.impulse(windx, windy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawOver(WeatherState state){
|
||||
Draw.tint(color);
|
||||
float speed = baseSpeed * state.intensity;
|
||||
float windx = state.windVector.x * speed, windy = state.windVector.y * speed;
|
||||
|
||||
float scale = 1f / 2000f;
|
||||
float scroll = Time.time() * scale;
|
||||
Tmp.tr1.setTexture(noise);
|
||||
Tmp.tr1.texture = noise;
|
||||
Core.camera.bounds(Tmp.r1);
|
||||
Tmp.tr1.set(Tmp.r1.x*scale, Tmp.r1.y*scale, (Tmp.r1.x + Tmp.r1.width)*scale, (Tmp.r1.y + Tmp.r1.height)*scale);
|
||||
Tmp.tr1.scroll(-xspeed * scroll, -yspeed * scroll);
|
||||
Tmp.tr1.scroll(-windx * scroll, windy * scroll);
|
||||
Draw.rect(Tmp.tr1, Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height);
|
||||
|
||||
rand.setSeed(0);
|
||||
@@ -224,8 +227,8 @@ public class Weathers implements ContentList{
|
||||
float scl = rand.random(0.5f, 1f);
|
||||
float scl2 = rand.random(0.5f, 1f);
|
||||
float sscl = rand.random(0.5f, 1f);
|
||||
float x = (rand.random(0f, world.unitWidth()) + Time.time() * xspeed * scl2);
|
||||
float y = (rand.random(0f, world.unitHeight()) - Time.time() * yspeed * scl);
|
||||
float x = (rand.random(0f, world.unitWidth()) + Time.time() * windx * scl2);
|
||||
float y = (rand.random(0f, world.unitHeight()) + Time.time() * windy * scl);
|
||||
float alpha = rand.random(0.2f);
|
||||
|
||||
x += Mathf.sin(y, rand.random(30f, 80f), rand.random(1f, 7f));
|
||||
@@ -247,14 +250,13 @@ public class Weathers implements ContentList{
|
||||
|
||||
sporestorm = new Weather("sporestorm"){
|
||||
TextureRegion region;
|
||||
float yspeed = 1f, xspeed = 4f, size = 5f, padding = size, invDensity = 2000f;
|
||||
float size = 5f, padding = size, invDensity = 2000f, baseSpeed = 4.3f, force = 0.28f;
|
||||
Color color = Color.valueOf("7457ce");
|
||||
Vec2 force = new Vec2(0.25f, 0.01f);
|
||||
Texture noise;
|
||||
|
||||
{
|
||||
attrs.set(Attribute.spores, 0.5f);
|
||||
attrs.set(Attribute.light, -0.1f);
|
||||
attrs.set(Attribute.spores, 1f);
|
||||
attrs.set(Attribute.light, -0.15f);
|
||||
status = StatusEffects.sporeSlowed;
|
||||
statusGround = false;
|
||||
}
|
||||
@@ -269,9 +271,11 @@ public class Weathers implements ContentList{
|
||||
|
||||
@Override
|
||||
public void update(WeatherState state){
|
||||
float speed = force * state.intensity;
|
||||
float windx = state.windVector.x * speed, windy = state.windVector.y * speed;
|
||||
|
||||
for(Unit unit : Groups.unit){
|
||||
unit.impulse(force.x * state.intensity(), force.y * state.intensity());
|
||||
unit.impulse(windx, windy);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,12 +289,15 @@ public class Weathers implements ContentList{
|
||||
Draw.alpha(state.opacity * 0.8f);
|
||||
Draw.tint(color);
|
||||
|
||||
float speed = baseSpeed * state.intensity;
|
||||
float windx = state.windVector.x * speed, windy = state.windVector.y * speed;
|
||||
|
||||
float scale = 1f / 2000f;
|
||||
float scroll = Time.time() * scale;
|
||||
Tmp.tr1.setTexture(noise);
|
||||
Tmp.tr1.texture = noise;
|
||||
Core.camera.bounds(Tmp.r1);
|
||||
Tmp.tr1.set(Tmp.r1.x*scale, Tmp.r1.y*scale, (Tmp.r1.x + Tmp.r1.width)*scale, (Tmp.r1.y + Tmp.r1.height)*scale);
|
||||
Tmp.tr1.scroll(-xspeed * scroll, -yspeed * scroll);
|
||||
Tmp.tr1.scroll(-windx * scroll, windy * scroll);
|
||||
Draw.rect(Tmp.tr1, Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height);
|
||||
|
||||
rand.setSeed(0);
|
||||
@@ -306,8 +313,8 @@ public class Weathers implements ContentList{
|
||||
float scl = rand.random(0.5f, 1f);
|
||||
float scl2 = rand.random(0.5f, 1f);
|
||||
float sscl = rand.random(0.5f, 1f);
|
||||
float x = (rand.random(0f, world.unitWidth()) + Time.time() * xspeed * scl2);
|
||||
float y = (rand.random(0f, world.unitHeight()) - Time.time() * yspeed * scl);
|
||||
float x = (rand.random(0f, world.unitWidth()) + Time.time() * windx * scl2);
|
||||
float y = (rand.random(0f, world.unitHeight()) + Time.time() * windy * scl);
|
||||
float alpha = rand.random(0.1f, 0.8f);
|
||||
|
||||
x += Mathf.sin(y, rand.random(30f, 80f), rand.random(1f, 7f));
|
||||
|
||||
@@ -33,6 +33,7 @@ public class ContentLoader{
|
||||
new StatusEffects(),
|
||||
new Liquids(),
|
||||
new Bullets(),
|
||||
new AmmoTypes(),
|
||||
new UnitTypes(),
|
||||
new Blocks(),
|
||||
new Loadouts(),
|
||||
|
||||
@@ -191,9 +191,13 @@ public class Control implements ApplicationListener, Loadable{
|
||||
|
||||
}
|
||||
|
||||
void resetCamera(){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadAsync(){
|
||||
Draw.scl = 1f / Core.atlas.find("scale_marker").getWidth();
|
||||
Draw.scl = 1f / Core.atlas.find("scale_marker").width;
|
||||
|
||||
Core.input.setCatch(KeyCode.back, true);
|
||||
|
||||
@@ -280,6 +284,7 @@ public class Control implements ApplicationListener, Loadable{
|
||||
try{
|
||||
net.reset();
|
||||
slot.load();
|
||||
slot.setAutosave(true);
|
||||
state.rules.sector = sector;
|
||||
|
||||
//if there is no base, simulate a new game and place the right loadout at the spawn position
|
||||
@@ -321,6 +326,7 @@ public class Control implements ApplicationListener, Loadable{
|
||||
state.rules.sector = sector;
|
||||
//assign origin when launching
|
||||
state.secinfo.origin = origin;
|
||||
state.secinfo.destination = origin;
|
||||
logic.play();
|
||||
control.saves.saveSector(sector);
|
||||
Events.fire(Trigger.newGame);
|
||||
@@ -329,6 +335,7 @@ public class Control implements ApplicationListener, Loadable{
|
||||
}
|
||||
|
||||
public void playTutorial(){
|
||||
ui.showInfo("@indev.notready");
|
||||
//TODO implement
|
||||
//ui.showInfo("death");
|
||||
/*
|
||||
@@ -428,7 +435,7 @@ public class Control implements ApplicationListener, Loadable{
|
||||
//just a regular reminder
|
||||
if(!OS.prop("user.name").equals("anuke") && !OS.hasEnv("iknowwhatimdoing")){
|
||||
app.post(() -> app.post(() -> {
|
||||
ui.showStartupInfo("@indevpopup");
|
||||
ui.showStartupInfo("@indev.popup");
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ public class GameState{
|
||||
/** Wave countdown in ticks. */
|
||||
public float wavetime;
|
||||
/** Whether the game is in game over state. */
|
||||
public boolean gameOver = false, launched = false, serverPaused = false;
|
||||
public boolean gameOver = false, launched = false, serverPaused = false, wasTimeout;
|
||||
/** Map that is currently being played on. */
|
||||
public @NonNull Map map = emptyMap;
|
||||
/** The current game rules. */
|
||||
|
||||
@@ -245,7 +245,8 @@ public class Logic implements ApplicationListener{
|
||||
if(entry.cooldown < 0 && !entry.weather.isActive()){
|
||||
float duration = Mathf.random(entry.minDuration, entry.maxDuration);
|
||||
entry.cooldown = duration + Mathf.random(entry.minFrequency, entry.maxFrequency);
|
||||
Call.createWeather(entry.weather, entry.intensity, duration);
|
||||
Tmp.v1.setToRandomDirection();
|
||||
Call.createWeather(entry.weather, entry.intensity, duration, Tmp.v1.x, Tmp.v1.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -336,7 +337,14 @@ public class Logic implements ApplicationListener{
|
||||
|
||||
//force pausing when the player is out of sector time
|
||||
if(state.isOutOfTime()){
|
||||
state.set(State.paused);
|
||||
if(!state.wasTimeout){
|
||||
universe.displayTimeEnd();
|
||||
state.wasTimeout = true;
|
||||
}
|
||||
//if no turn was run.
|
||||
if(state.isOutOfTime()){
|
||||
state.set(State.paused);
|
||||
}
|
||||
}
|
||||
|
||||
if(!state.isPaused()){
|
||||
|
||||
@@ -440,7 +440,7 @@ public class NetClient implements ApplicationListener{
|
||||
}
|
||||
|
||||
@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{
|
||||
if(wave > state.wave){
|
||||
state.wave = wave;
|
||||
@@ -453,6 +453,8 @@ public class NetClient implements ApplicationListener{
|
||||
state.enemies = enemies;
|
||||
state.serverPaused = paused;
|
||||
|
||||
universe.updateNetSeconds(timeData);
|
||||
|
||||
netClient.byteStream.setBytes(net.decompressSnapshot(coreData, coreDataLen));
|
||||
DataInputStream input = netClient.dataStream;
|
||||
|
||||
@@ -547,6 +549,10 @@ public class NetClient implements ApplicationListener{
|
||||
quiet = true;
|
||||
}
|
||||
|
||||
public void clearRemovedEntity(int id){
|
||||
removed.remove(id);
|
||||
}
|
||||
|
||||
public void addRemovedEntity(int id){
|
||||
removed.add(id);
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ public class NetServer implements ApplicationListener{
|
||||
return;
|
||||
}
|
||||
|
||||
if(Time.millis() < info.lastKicked){
|
||||
if(Time.millis() < admins.getKickTime(uuid, con.address)){
|
||||
con.kick(KickReason.recentKick);
|
||||
return;
|
||||
}
|
||||
@@ -593,38 +593,38 @@ public class NetServer implements ApplicationListener{
|
||||
if(player.isBuilder()){
|
||||
player.builder().clearBuilding();
|
||||
player.builder().updateBuilding(building);
|
||||
|
||||
if(requests != null){
|
||||
for(BuildPlan req : requests){
|
||||
if(req == null) continue;
|
||||
Tile tile = world.tile(req.x, req.y);
|
||||
if(tile == null || (!req.breaking && req.block == null)) continue;
|
||||
//auto-skip done requests
|
||||
if(req.breaking && tile.block() == Blocks.air){
|
||||
continue;
|
||||
}else if(!req.breaking && tile.block() == req.block && (!req.block.rotate || (tile.build != null && tile.build.rotation == req.rotation))){
|
||||
continue;
|
||||
}else if(con.rejectedRequests.contains(r -> r.breaking == req.breaking && r.x == req.x && r.y == req.y)){ //check if request was recently rejected, and skip it if so
|
||||
continue;
|
||||
}else if(!netServer.admins.allowAction(player, req.breaking ? ActionType.breakBlock : ActionType.placeBlock, tile, action -> { //make sure request is allowed by the server
|
||||
action.block = req.block;
|
||||
action.rotation = req.rotation;
|
||||
action.config = req.config;
|
||||
})){
|
||||
//force the player to remove this request if that's not the case
|
||||
Call.removeQueueBlock(player.con, req.x, req.y, req.breaking);
|
||||
con.rejectedRequests.add(req);
|
||||
continue;
|
||||
}
|
||||
player.builder().plans().addLast(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(player.isMiner()){
|
||||
player.miner().mineTile(mining);
|
||||
}
|
||||
|
||||
if(requests != null){
|
||||
for(BuildPlan req : requests){
|
||||
if(req == null) continue;
|
||||
Tile tile = world.tile(req.x, req.y);
|
||||
if(tile == null || (!req.breaking && req.block == null)) continue;
|
||||
//auto-skip done requests
|
||||
if(req.breaking && tile.block() == Blocks.air){
|
||||
continue;
|
||||
}else if(!req.breaking && tile.block() == req.block && (!req.block.rotate || (tile.build != null && tile.build.rotation == req.rotation))){
|
||||
continue;
|
||||
}else if(con.rejectedRequests.contains(r -> r.breaking == req.breaking && r.x == req.x && r.y == req.y)){ //check if request was recently rejected, and skip it if so
|
||||
continue;
|
||||
}else if(!netServer.admins.allowAction(player, req.breaking ? ActionType.breakBlock : ActionType.placeBlock, tile, action -> { //make sure request is allowed by the server
|
||||
action.block = req.block;
|
||||
action.rotation = req.rotation;
|
||||
action.config = req.config;
|
||||
})){
|
||||
//force the player to remove this request if that's not the case
|
||||
Call.removeQueueBlock(player.con, req.x, req.y, req.breaking);
|
||||
con.rejectedRequests.add(req);
|
||||
continue;
|
||||
}
|
||||
player.builder().plans().addLast(req);
|
||||
}
|
||||
}
|
||||
|
||||
con.rejectedRequests.clear();
|
||||
|
||||
if(!player.dead()){
|
||||
@@ -846,7 +846,7 @@ public class NetServer implements ApplicationListener{
|
||||
byte[] stateBytes = syncStream.toByteArray();
|
||||
|
||||
//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);
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ public class Renderer implements ApplicationListener{
|
||||
public PlanetRenderer planets;
|
||||
|
||||
public FrameBuffer effectBuffer = new FrameBuffer();
|
||||
public float laserOpacity = 1f;
|
||||
|
||||
private Bloom bloom;
|
||||
private FxProcessor fx = new FxProcessor();
|
||||
private Color clearColor = new Color(0f, 0f, 0f, 1f);
|
||||
@@ -59,8 +61,10 @@ public class Renderer implements ApplicationListener{
|
||||
@Override
|
||||
public void update(){
|
||||
Color.white.set(1f, 1f, 1f, 1f);
|
||||
Gl.clear(Gl.stencilBufferBit);
|
||||
|
||||
camerascale = Mathf.lerpDelta(camerascale, targetscale, 0.1f);
|
||||
laserOpacity = Core.settings.getInt("lasersopacity") / 100f;
|
||||
|
||||
if(landTime > 0){
|
||||
landTime -= Time.delta;
|
||||
@@ -273,7 +277,7 @@ public class Renderer implements ApplicationListener{
|
||||
|
||||
TextureRegion reg = entity.block.icon(Cicon.full);
|
||||
float scl = Scl.scl(4f) / camerascale;
|
||||
float s = reg.getWidth() * Draw.scl * scl * 4f * fract;
|
||||
float s = reg.width * Draw.scl * scl * 4f * fract;
|
||||
|
||||
Draw.color(Pal.lightTrail);
|
||||
Draw.rect("circle-shadow", entity.getX(), entity.getY(), s, s);
|
||||
@@ -285,7 +289,7 @@ public class Renderer implements ApplicationListener{
|
||||
|
||||
Draw.color();
|
||||
Draw.mixcol(Color.white, fract);
|
||||
Draw.rect(reg, entity.getX(), entity.getY(), reg.getWidth() * Draw.scl * scl, reg.getHeight() * Draw.scl * scl, fract * 135f);
|
||||
Draw.rect(reg, entity.getX(), entity.getY(), reg.width * Draw.scl * scl, reg.height * Draw.scl * scl, fract * 135f);
|
||||
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
@@ -491,7 +491,7 @@ public class UI implements ApplicationListener, Loadable{
|
||||
Table t = new Table();
|
||||
t.touchable = Touchable.disabled;
|
||||
t.background(Styles.black3).margin(8f)
|
||||
.add(text).style(Styles.outlineLabel);
|
||||
.add(text).style(Styles.outlineLabel).labelAlign(Align.center);
|
||||
t.update(() -> t.setPosition(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f, Align.center));
|
||||
t.actions(Actions.fadeOut(3, Interp.pow4In), Actions.remove());
|
||||
Core.scene.add(t);
|
||||
|
||||
@@ -45,4 +45,12 @@ public class Version{
|
||||
build = Strings.canParseInt(map.get("build")) ? Integer.parseInt(map.get("build")) : -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** get menu version without colors */
|
||||
public static String combined(){
|
||||
if(build == -1){
|
||||
return "custom build";
|
||||
}
|
||||
return (type.equals("official") ? modifier : type) + " build " + build + (revision == 0 ? "" : "." + revision);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,13 @@ import arc.func.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import arc.struct.ObjectIntMap.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import arc.util.*;
|
||||
import arc.util.noise.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.core.GameState.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.game.Teams.*;
|
||||
@@ -19,7 +21,6 @@ import mindustry.maps.*;
|
||||
import mindustry.maps.filters.*;
|
||||
import mindustry.maps.filters.GenerateFilter.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.type.Sector.*;
|
||||
import mindustry.type.Weather.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
@@ -33,11 +34,17 @@ public class World{
|
||||
public @NonNull Tiles tiles = new Tiles(0, 0);
|
||||
|
||||
private boolean generating, invalidMap;
|
||||
private ObjectMap<Map, Runnable> customMapLoaders = new ObjectMap<>();
|
||||
|
||||
public World(){
|
||||
|
||||
}
|
||||
|
||||
/** Adds a custom handler function for loading a custom map - usually a generated one. */
|
||||
public void addMapLoader(Map map, Runnable loader){
|
||||
customMapLoaders.put(map, loader);
|
||||
}
|
||||
|
||||
public boolean isInvalidMap(){
|
||||
return invalidMap;
|
||||
}
|
||||
@@ -255,9 +262,71 @@ public class World{
|
||||
|
||||
state.rules.weather.clear();
|
||||
|
||||
if(sector.is(SectorAttribute.rainy)) state.rules.weather.add(new WeatherEntry(Weathers.rain));
|
||||
if(sector.is(SectorAttribute.snowy)) state.rules.weather.add(new WeatherEntry(Weathers.snow));
|
||||
if(sector.is(SectorAttribute.desert)) state.rules.weather.add(new WeatherEntry(Weathers.sandstorm));
|
||||
//apply weather based on terrain
|
||||
ObjectIntMap<Block> floorc = new ObjectIntMap<>();
|
||||
ObjectSet<UnlockableContent> content = new ObjectSet<>();
|
||||
|
||||
float waterFloors = 0, totalFloors = 0;
|
||||
|
||||
for(Tile tile : world.tiles){
|
||||
if(world.getDarkness(tile.x, tile.y) >= 3){
|
||||
continue;
|
||||
}
|
||||
|
||||
Liquid liquid = tile.floor().liquidDrop;
|
||||
if(tile.floor().itemDrop != null) content.add(tile.floor().itemDrop);
|
||||
if(tile.overlay().itemDrop != null) content.add(tile.overlay().itemDrop);
|
||||
if(liquid != null) content.add(liquid);
|
||||
|
||||
if(!tile.block().isStatic()){
|
||||
totalFloors ++;
|
||||
if(liquid == Liquids.water){
|
||||
waterFloors += tile.floor().isDeep() ? 1f : 0.7f;
|
||||
}
|
||||
floorc.increment(tile.floor());
|
||||
if(tile.overlay() != Blocks.air){
|
||||
floorc.increment(tile.overlay());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//sort counts in descending order
|
||||
Seq<Entry<Block>> entries = floorc.entries().toArray();
|
||||
entries.sort(e -> -e.value);
|
||||
//remove all blocks occuring < 30 times - unimportant
|
||||
entries.removeAll(e -> e.value < 30);
|
||||
|
||||
Block[] floors = new Block[entries.size];
|
||||
int[] floorCounts = new int[entries.size];
|
||||
for(int i = 0; i < entries.size; i++){
|
||||
floorCounts[i] = entries.get(i).value;
|
||||
floors[i] = entries.get(i).key;
|
||||
}
|
||||
|
||||
//TODO bad code
|
||||
boolean hasSnow = floors[0].name.contains("ice") || floors[0].name.contains("snow");
|
||||
boolean hasRain = !hasSnow && floors[0].name.contains("water");
|
||||
boolean hasDesert = !hasSnow && !hasRain && floors[0].name.contains("sand");
|
||||
boolean hasSpores = floors[0].name.contains("spore") || floors[0].name.contains("moss") || floors[0].name.contains("tainted");
|
||||
|
||||
if(hasSnow){
|
||||
state.rules.weather.add(new WeatherEntry(Weathers.snow));
|
||||
}
|
||||
|
||||
if(hasRain){
|
||||
state.rules.weather.add(new WeatherEntry(Weathers.rain));
|
||||
}
|
||||
|
||||
if(hasDesert){
|
||||
state.rules.weather.add(new WeatherEntry(Weathers.sandstorm));
|
||||
}
|
||||
|
||||
if(hasSpores){
|
||||
state.rules.weather.add(new WeatherEntry(Weathers.sporestorm));
|
||||
}
|
||||
|
||||
state.secinfo.resources = content.asArray();
|
||||
state.secinfo.resources.sort(Structs.comps(Structs.comparing(Content::getContentType), Structs.comparingInt(c -> c.id)));
|
||||
|
||||
}
|
||||
|
||||
@@ -270,6 +339,12 @@ public class World{
|
||||
}
|
||||
|
||||
public void loadMap(Map map, Rules checkRules){
|
||||
//load using custom loader if possible
|
||||
if(customMapLoaders.containsKey(map)){
|
||||
customMapLoaders.get(map).run();
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
SaveIO.load(map.file, new FilterContext(map));
|
||||
}catch(Throwable e){
|
||||
@@ -444,7 +519,7 @@ public class World{
|
||||
dark = Math.max((edgeBlend - edgeDst) * (4f / edgeBlend), dark);
|
||||
}
|
||||
|
||||
if(state.hasSector()){
|
||||
if(state.hasSector() && state.getSector().preset == null){
|
||||
int circleBlend = 14;
|
||||
//quantized angle
|
||||
float offset = state.getSector().rect.rotation + 90;
|
||||
|
||||
@@ -15,7 +15,8 @@ public enum ContentType{
|
||||
loadout_UNUSED,
|
||||
typeid_UNUSED,
|
||||
error,
|
||||
planet;
|
||||
planet,
|
||||
ammo;
|
||||
|
||||
public static final ContentType[] all = values();
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import arc.util.ArcAnnotate.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
@@ -30,7 +31,7 @@ public abstract class UnlockableContent extends MappableContent{
|
||||
|
||||
this.localizedName = Core.bundle.get(getContentType() + "." + this.name + ".name", this.name);
|
||||
this.description = Core.bundle.getOrNull(getContentType() + "." + this.name + ".description");
|
||||
this.unlocked = Core.settings != null && Core.settings.getBool(name + "-unlocked", false);
|
||||
this.unlocked = Core.settings != null && Core.settings.getBool(this.name + "-unlocked", false);
|
||||
}
|
||||
|
||||
public String displayDescription(){
|
||||
@@ -43,6 +44,11 @@ public abstract class UnlockableContent extends MappableContent{
|
||||
|
||||
}
|
||||
|
||||
/** @return items needed to research this content */
|
||||
public ItemStack[] researchRequirements(){
|
||||
return ItemStack.empty;
|
||||
}
|
||||
|
||||
public String emoji(){
|
||||
return Fonts.getUnicodeStr(name);
|
||||
}
|
||||
|
||||
@@ -64,8 +64,12 @@ public class DrawOperation{
|
||||
if(type == OpType.floor.ordinal()){
|
||||
tile.setFloor((Floor)content.block(to));
|
||||
}else if(type == OpType.block.ordinal()){
|
||||
tile.getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y));
|
||||
|
||||
Block block = content.block(to);
|
||||
tile.setBlock(block, tile.team(), tile.build == null ? 0 : tile.build.rotation);
|
||||
|
||||
tile.getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y));
|
||||
}else if(type == OpType.rotation.ordinal()){
|
||||
if(tile.build != null) tile.build.rotation = to;
|
||||
}else if(type == OpType.team.ordinal()){
|
||||
@@ -74,7 +78,7 @@ public class DrawOperation{
|
||||
tile.setOverlayID(to);
|
||||
}
|
||||
});
|
||||
editor.renderer().updatePoint(tile.x, tile.y);
|
||||
editor.renderer.updatePoint(tile.x, tile.y);
|
||||
}
|
||||
|
||||
@Struct
|
||||
|
||||
@@ -20,7 +20,7 @@ public class EditorTile extends Tile{
|
||||
|
||||
@Override
|
||||
public void setFloor(@NonNull Floor type){
|
||||
if(state.isGame()){
|
||||
if(skip()){
|
||||
super.setFloor(type);
|
||||
return;
|
||||
}
|
||||
@@ -41,20 +41,25 @@ public class EditorTile extends Tile{
|
||||
|
||||
@Override
|
||||
public void setBlock(Block type, Team team, int rotation){
|
||||
if(state.isGame()){
|
||||
if(skip()){
|
||||
super.setBlock(type, team, rotation);
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.block == type && (build == null || build.rotation == rotation)){
|
||||
update();
|
||||
return;
|
||||
}
|
||||
|
||||
op(OpType.block, block.id);
|
||||
if(rotation != 0) op(OpType.rotation, (byte)rotation);
|
||||
if(team() != Team.derelict) op(OpType.team, (byte)team().id);
|
||||
if(team != Team.derelict) op(OpType.team, (byte)team.id);
|
||||
super.setBlock(type, team, rotation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTeam(Team team){
|
||||
if(state.isGame()){
|
||||
if(skip()){
|
||||
super.setTeam(team);
|
||||
return;
|
||||
}
|
||||
@@ -66,7 +71,7 @@ public class EditorTile extends Tile{
|
||||
|
||||
@Override
|
||||
public void setOverlay(Block overlay){
|
||||
if(state.isGame()){
|
||||
if(skip()){
|
||||
super.setOverlay(overlay);
|
||||
return;
|
||||
}
|
||||
@@ -79,23 +84,23 @@ public class EditorTile extends Tile{
|
||||
|
||||
@Override
|
||||
protected void fireChanged(){
|
||||
if(state.isGame()){
|
||||
if(skip()){
|
||||
super.fireChanged();
|
||||
}else{
|
||||
ui.editor.editor.renderer().updatePoint(x, y);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recache(){
|
||||
if(state.isGame()){
|
||||
if(skip()){
|
||||
super.recache();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void changeEntity(Team team, Prov<Building> entityprov, int rotation){
|
||||
if(state.isGame()){
|
||||
if(skip()){
|
||||
super.changeEntity(team, entityprov, rotation);
|
||||
return;
|
||||
}
|
||||
@@ -109,13 +114,21 @@ public class EditorTile extends Tile{
|
||||
|
||||
if(block.hasEntity()){
|
||||
build = entityprov.get().init(this, team, false, rotation);
|
||||
build.cons(new ConsumeModule(build));
|
||||
build.cons = new ConsumeModule(build);
|
||||
if(block.hasItems) build.items = new ItemModule();
|
||||
if(block.hasLiquids) build.liquids(new LiquidModule());
|
||||
if(block.hasPower) build.power(new PowerModule());
|
||||
}
|
||||
}
|
||||
|
||||
private void update(){
|
||||
ui.editor.editor.renderer.updatePoint(x, y);
|
||||
}
|
||||
|
||||
private boolean skip(){
|
||||
return state.isGame() || ui.editor.editor.isLoading();
|
||||
}
|
||||
|
||||
private void op(OpType type, short value){
|
||||
ui.editor.editor.addTileOp(TileOp.get(x, y, (byte)type.ordinal(), value));
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public enum EditorTool{
|
||||
if(!Structs.inBounds(x, y, editor.width(), editor.height())) return;
|
||||
|
||||
Tile tile = editor.tile(x, y);
|
||||
editor.drawBlock = tile.block() == Blocks.air ? tile.overlay() == Blocks.air ? tile.floor() : tile.overlay() : tile.block();
|
||||
editor.drawBlock = tile.block() == Blocks.air || !tile.block().inEditor ? tile.overlay() == Blocks.air ? tile.floor() : tile.overlay() : tile.block();
|
||||
}
|
||||
},
|
||||
line(KeyCode.l, "replace", "orthogonal"){
|
||||
|
||||
@@ -18,10 +18,10 @@ import static mindustry.Vars.*;
|
||||
public class MapEditor{
|
||||
public static final int[] brushSizes = {1, 2, 3, 4, 5, 9, 15, 20};
|
||||
|
||||
private final Context context = new Context();
|
||||
private StringMap tags = new StringMap();
|
||||
private MapRenderer renderer = new MapRenderer(this);
|
||||
public StringMap tags = new StringMap();
|
||||
public MapRenderer renderer = new MapRenderer(this);
|
||||
|
||||
private final Context context = new Context();
|
||||
private OperationStack stack = new OperationStack();
|
||||
private DrawOperation currentOp;
|
||||
private boolean loading;
|
||||
@@ -31,8 +31,8 @@ public class MapEditor{
|
||||
public Block drawBlock = Blocks.stone;
|
||||
public Team drawTeam = Team.sharded;
|
||||
|
||||
public StringMap getTags(){
|
||||
return tags;
|
||||
public boolean isLoading(){
|
||||
return loading;
|
||||
}
|
||||
|
||||
public void beginEdit(int width, int height){
|
||||
@@ -52,7 +52,7 @@ public class MapEditor{
|
||||
if(map.file.parent().parent().name().equals("1127400") && steam){
|
||||
tags.put("steamid", map.file.parent().name());
|
||||
}
|
||||
MapIO.loadMap(map, context);
|
||||
load(() -> MapIO.loadMap(map, context));
|
||||
renderer.resize(width(), height());
|
||||
loading = false;
|
||||
}
|
||||
@@ -210,10 +210,6 @@ public class MapEditor{
|
||||
}
|
||||
}
|
||||
|
||||
public MapRenderer renderer(){
|
||||
return renderer;
|
||||
}
|
||||
|
||||
public void resize(int width, int height){
|
||||
clearOp();
|
||||
|
||||
@@ -227,8 +223,14 @@ public class MapEditor{
|
||||
int px = offsetX + x, py = offsetY + y;
|
||||
if(previous.in(px, py)){
|
||||
tiles.set(x, y, previous.getn(px, py));
|
||||
tiles.getn(x, y).x = (short)x;
|
||||
tiles.getn(x, y).y = (short)y;
|
||||
Tile tile = tiles.getn(x, y);
|
||||
tile.x = (short)x;
|
||||
tile.y = (short)y;
|
||||
|
||||
if(tile.build != null && tile.isCenter()){
|
||||
tile.build.x = x * tilesize + tile.block().offset;
|
||||
tile.build.y = y * tilesize + tile.block().offset;
|
||||
}
|
||||
}else{
|
||||
tiles.set(x, y, new EditorTile(x, y, Blocks.stone.id, (short)0, (short)0));
|
||||
}
|
||||
|
||||
@@ -116,9 +116,9 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
|
||||
t.button("@editor.export", Icon.upload, () -> createDialog("@editor.export",
|
||||
"@editor.exportfile", "@editor.exportfile.description", Icon.file,
|
||||
(Runnable)() -> platform.export(editor.getTags().get("name", "unknown"), mapExtension, file -> MapIO.writeMap(file, editor.createMap(file))),
|
||||
(Runnable)() -> platform.export(editor.tags.get("name", "unknown"), mapExtension, file -> MapIO.writeMap(file, editor.createMap(file))),
|
||||
"@editor.exportimage", "@editor.exportimage.description", Icon.fileImage,
|
||||
(Runnable)() -> platform.export(editor.getTags().get("name", "unknown"), "png", file -> {
|
||||
(Runnable)() -> platform.export(editor.tags.get("name", "unknown"), "png", file -> {
|
||||
Pixmap out = MapIO.writeImage(editor.tiles());
|
||||
file.writePNG(out);
|
||||
out.dispose();
|
||||
@@ -129,16 +129,16 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
|
||||
if(steam){
|
||||
menu.cont.button("@editor.publish.workshop", Icon.link, () -> {
|
||||
Map builtin = maps.all().find(m -> m.name().equals(editor.getTags().get("name", "").trim()));
|
||||
Map builtin = maps.all().find(m -> m.name().equals(editor.tags.get("name", "").trim()));
|
||||
|
||||
if(editor.getTags().containsKey("steamid") && builtin != null && !builtin.custom){
|
||||
platform.viewListingID(editor.getTags().get("steamid"));
|
||||
if(editor.tags.containsKey("steamid") && builtin != null && !builtin.custom){
|
||||
platform.viewListingID(editor.tags.get("steamid"));
|
||||
return;
|
||||
}
|
||||
|
||||
Map map = save();
|
||||
|
||||
if(editor.getTags().containsKey("steamid") && map != null){
|
||||
if(editor.tags.containsKey("steamid") && map != null){
|
||||
platform.viewListing(map);
|
||||
return;
|
||||
}
|
||||
@@ -156,7 +156,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
}
|
||||
|
||||
platform.publish(map);
|
||||
}).padTop(-3).size(swidth * 2f + 10, 60f).update(b -> b.setText(editor.getTags().containsKey("steamid") ? editor.getTags().get("author").equals(player.name) ? "@workshop.listing" : "@view.workshop" : "@editor.publish.workshop"));
|
||||
}).padTop(-3).size(swidth * 2f + 10, 60f).update(b -> b.setText(editor.tags.containsKey("steamid") ? editor.tags.get("author").equals(player.name) ? "@workshop.listing" : "@view.workshop" : "@editor.publish.workshop"));
|
||||
|
||||
menu.cont.row();
|
||||
}
|
||||
@@ -235,7 +235,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
state.rules = (lastSavedRules == null ? new Rules() : lastSavedRules);
|
||||
lastSavedRules = null;
|
||||
saved = false;
|
||||
editor.renderer().updateAll();
|
||||
editor.renderer.updateAll();
|
||||
}
|
||||
|
||||
private void playtest(){
|
||||
@@ -254,14 +254,9 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
"height", editor.height()
|
||||
));
|
||||
world.endMapLoad();
|
||||
//add entities so they update. is this really needed?
|
||||
for(Tile tile : world.tiles){
|
||||
if(tile.build != null){
|
||||
tile.build.add();
|
||||
}
|
||||
}
|
||||
player.set(world.width() * tilesize/2f, world.height() * tilesize/2f);
|
||||
player.clearUnit();
|
||||
Groups.unit.clear();
|
||||
logic.play();
|
||||
});
|
||||
}
|
||||
@@ -269,10 +264,10 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
public @Nullable Map save(){
|
||||
boolean isEditor = state.rules.editor;
|
||||
state.rules.editor = false;
|
||||
String name = editor.getTags().get("name", "").trim();
|
||||
editor.getTags().put("rules", JsonIO.write(state.rules));
|
||||
editor.getTags().remove("width");
|
||||
editor.getTags().remove("height");
|
||||
String name = editor.tags.get("name", "").trim();
|
||||
editor.tags.put("rules", JsonIO.write(state.rules));
|
||||
editor.tags.remove("width");
|
||||
editor.tags.remove("height");
|
||||
|
||||
player.clearUnit();
|
||||
|
||||
@@ -286,7 +281,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
if(map != null && !map.custom){
|
||||
handleSaveBuiltin(map);
|
||||
}else{
|
||||
returned = maps.saveMap(editor.getTags());
|
||||
returned = maps.saveMap(editor.tags);
|
||||
ui.showInfoFade("@editor.saved");
|
||||
}
|
||||
}
|
||||
@@ -357,7 +352,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
editor.renderer().dispose();
|
||||
editor.renderer.dispose();
|
||||
}
|
||||
|
||||
public void beginEditMap(Fi file){
|
||||
@@ -619,12 +614,12 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
Tile tile = editor.tile(x, y);
|
||||
if(tile.block().breakable && tile.block() instanceof Boulder){
|
||||
tile.setBlock(Blocks.air);
|
||||
editor.renderer().updatePoint(x, y);
|
||||
editor.renderer.updatePoint(x, y);
|
||||
}
|
||||
|
||||
if(tile.overlay() != Blocks.air && tile.overlay() != Blocks.spawn){
|
||||
tile.setOverlay(Blocks.air);
|
||||
editor.renderer().updatePoint(x, y);
|
||||
editor.renderer.updatePoint(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ public class MapGenerateDialog extends BaseDialog{
|
||||
}
|
||||
|
||||
//reset undo stack as generation... messes things up
|
||||
editor.renderer().updateAll();
|
||||
editor.renderer.updateAll();
|
||||
editor.clearOp();
|
||||
}
|
||||
|
||||
@@ -275,6 +275,8 @@ public class MapGenerateDialog extends BaseDialog{
|
||||
}
|
||||
}).grow().left().pad(6).top();
|
||||
}).width(280f).pad(3).top().left().fillY();
|
||||
|
||||
|
||||
if(++i % cols == 0){
|
||||
filterTable.row();
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ public class MapInfoDialog extends BaseDialog{
|
||||
private void setup(){
|
||||
cont.clear();
|
||||
|
||||
ObjectMap<String, String> tags = editor.getTags();
|
||||
ObjectMap<String, String> tags = editor.tags;
|
||||
|
||||
cont.pane(t -> {
|
||||
t.add("@editor.mapname").padRight(8).left();
|
||||
@@ -73,8 +73,8 @@ public class MapInfoDialog extends BaseDialog{
|
||||
t.row();
|
||||
t.add("@editor.generation").padRight(8).left();
|
||||
t.button("@edit", () -> {
|
||||
generate.show(Vars.maps.readFilters(editor.getTags().get("genfilters", "")),
|
||||
filters -> editor.getTags().put("genfilters", JsonIO.write(filters)));
|
||||
generate.show(Vars.maps.readFilters(editor.tags.get("genfilters", "")),
|
||||
filters -> editor.tags.put("genfilters", JsonIO.write(filters)));
|
||||
hide();
|
||||
}).left().width(200f);
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ public class MapRenderer implements Disposable{
|
||||
|
||||
public MapRenderer(MapEditor editor){
|
||||
this.editor = editor;
|
||||
this.texture = Core.atlas.find("clear-editor").getTexture();
|
||||
this.texture = Core.atlas.find("clear-editor").texture;
|
||||
}
|
||||
|
||||
public void resize(int width, int height){
|
||||
@@ -110,13 +110,13 @@ public class MapRenderer implements Disposable{
|
||||
if(wall != Blocks.air && wall.synthetic()){
|
||||
region = !Core.atlas.isFound(wall.editorIcon()) || !center ? Core.atlas.find("clear-editor") : wall.editorIcon();
|
||||
|
||||
float width = region.getWidth() * Draw.scl, height = region.getHeight() * Draw.scl;
|
||||
float width = region.width * Draw.scl, height = region.height * Draw.scl;
|
||||
|
||||
mesh.draw(idxWall, region,
|
||||
wx * tilesize + wall.offset + (tilesize - width) / 2f,
|
||||
wy * tilesize + wall.offset + (tilesize - height) / 2f,
|
||||
width, height,
|
||||
tile.build == null || !wall.rotate ? 0 : tile.build.rotdeg() - 90);
|
||||
tile.build == null || !wall.rotate ? 0 : tile.build.rotdeg());
|
||||
}else{
|
||||
region = floor.editorVariantRegions()[Mathf.randomSeed(idxWall, 0, floor.editorVariantRegions().length - 1)];
|
||||
|
||||
@@ -130,15 +130,15 @@ public class MapRenderer implements Disposable{
|
||||
region = Core.atlas.find("block-border-editor");
|
||||
}else if(!wall.synthetic() && wall != Blocks.air && center){
|
||||
region = !Core.atlas.isFound(wall.editorIcon()) ? Core.atlas.find("clear-editor") : wall.editorIcon();
|
||||
offsetX = tilesize / 2f - region.getWidth() / 2f * Draw.scl;
|
||||
offsetY = tilesize / 2f - region.getHeight() / 2f * Draw.scl;
|
||||
offsetX = tilesize / 2f - region.width / 2f * Draw.scl;
|
||||
offsetY = tilesize / 2f - region.height / 2f * Draw.scl;
|
||||
}else if(wall == Blocks.air && !tile.overlay().isAir()){
|
||||
region = tile.overlay().editorVariantRegions()[Mathf.randomSeed(idxWall, 0, tile.overlay().editorVariantRegions().length - 1)];
|
||||
}else{
|
||||
region = Core.atlas.find("clear-editor");
|
||||
}
|
||||
|
||||
float width = region.getWidth() * Draw.scl, height = region.getHeight() * Draw.scl;
|
||||
float width = region.width * Draw.scl, height = region.height * Draw.scl;
|
||||
if(!wall.synthetic() && wall != Blocks.air && !wall.isMultiblock()){
|
||||
offsetX = 0;
|
||||
offsetY = 0;
|
||||
|
||||
@@ -248,14 +248,20 @@ public class MapView extends Element implements GestureListener{
|
||||
Draw.color(Pal.remove);
|
||||
Lines.stroke(2f);
|
||||
Lines.rect(centerx - sclwidth / 2 - 1, centery - sclheight / 2 - 1, sclwidth + 2, sclheight + 2);
|
||||
editor.renderer().draw(centerx - sclwidth / 2, centery - sclheight / 2, sclwidth, sclheight);
|
||||
editor.renderer.draw(centerx - sclwidth / 2, centery - sclheight / 2, sclwidth, sclheight);
|
||||
Draw.reset();
|
||||
|
||||
if(grid){
|
||||
Draw.color(Color.gray);
|
||||
image.setBounds(centerx - sclwidth / 2, centery - sclheight / 2, sclwidth, sclheight);
|
||||
image.draw();
|
||||
Draw.color();
|
||||
|
||||
Lines.stroke(3f);
|
||||
Draw.color(Pal.accent);
|
||||
Lines.line(centerx - sclwidth/2f, centery, centerx + sclwidth/2f, centery);
|
||||
Lines.line(centerx, centery - sclheight/2f, centerx, centery + sclheight/2f);
|
||||
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
|
||||
@@ -32,7 +32,6 @@ public class WaveGraph extends Table{
|
||||
|
||||
rect((x, y, width, height) -> {
|
||||
Lines.stroke(Scl.scl(3f));
|
||||
Lines.precise(true);
|
||||
|
||||
GlyphLayout lay = Pools.obtain(GlyphLayout.class, GlyphLayout::new);
|
||||
Font font = Fonts.outline;
|
||||
@@ -122,7 +121,6 @@ public class WaveGraph extends Table{
|
||||
|
||||
Pools.free(lay);
|
||||
|
||||
Lines.precise(false);
|
||||
Draw.reset();
|
||||
}).pad(4).padBottom(10).grow();
|
||||
|
||||
|
||||
@@ -77,19 +77,24 @@ public class Damage{
|
||||
}
|
||||
}
|
||||
|
||||
/** Collides a bullet with blocks in a laser, taking into account absorption blocks. Resulting length is stored in the bullet's fdata. */
|
||||
public static float collideLaser(Bullet b, float length){
|
||||
public static float findLaserLength(Bullet b, float length){
|
||||
Tmp.v1.trns(b.rotation(), length);
|
||||
|
||||
furthest = null;
|
||||
|
||||
world.raycast(b.tileX(), b.tileY(), world.toTile(b.x + Tmp.v1.x), world.toTile(b.y + Tmp.v1.y),
|
||||
boolean found = world.raycast(b.tileX(), b.tileY(), world.toTile(b.x + Tmp.v1.x), world.toTile(b.y + Tmp.v1.y),
|
||||
(x, y) -> (furthest = world.tile(x, y)) != null && furthest.team() != b.team && furthest.block().absorbLasers);
|
||||
|
||||
float resultLength = furthest != null ? Math.max(6f, b.dst(furthest.worldx(), furthest.worldy())) : length;
|
||||
return found && furthest != null ? Math.max(6f, b.dst(furthest.worldx(), furthest.worldy())) : length;
|
||||
}
|
||||
|
||||
Damage.collideLine(b, b.team, b.type.hitEffect, b.x, b.y, b.rotation(), resultLength);
|
||||
b.fdata = furthest != null ? resultLength : length;
|
||||
/** Collides a bullet with blocks in a laser, taking into account absorption blocks. Resulting length is stored in the bullet's fdata. */
|
||||
public static float collideLaser(Bullet b, float length, boolean large){
|
||||
float resultLength = findLaserLength(b, length);
|
||||
|
||||
collideLine(b, b.team, b.type.hitEffect, b.x, b.y, b.rotation(), resultLength, large);
|
||||
|
||||
b.fdata = resultLength;
|
||||
|
||||
return resultLength;
|
||||
}
|
||||
@@ -103,6 +108,8 @@ public class Damage{
|
||||
* Only enemies of the specified team are damaged.
|
||||
*/
|
||||
public static void collideLine(Bullet hitter, Team team, Effect effect, float x, float y, float angle, float length, boolean large){
|
||||
length = findLaserLength(hitter, length);
|
||||
|
||||
collidedBlocks.clear();
|
||||
tr.trns(angle, length);
|
||||
Intc2 collider = (cx, cy) -> {
|
||||
@@ -150,13 +157,8 @@ public class Damage{
|
||||
if(!e.checkTarget(hitter.type.collidesAir, hitter.type.collidesGround)) return;
|
||||
|
||||
e.hitbox(hitrect);
|
||||
Rect other = hitrect;
|
||||
other.y -= expand;
|
||||
other.x -= expand;
|
||||
other.width += expand * 2;
|
||||
other.height += expand * 2;
|
||||
|
||||
Vec2 vec = Geometry.raycastRect(x, y, x2, y2, other);
|
||||
Vec2 vec = Geometry.raycastRect(x, y, x2, y2, hitrect.grow(expand * 2));
|
||||
|
||||
if(vec != null){
|
||||
effect.at(vec.x, vec.y);
|
||||
|
||||
@@ -40,7 +40,7 @@ public class Effect{
|
||||
}
|
||||
|
||||
public Effect(float life, Cons<EffectContainer> renderer){
|
||||
this(life, 32f, renderer);
|
||||
this(life,50f, renderer);
|
||||
}
|
||||
|
||||
public Effect ground(){
|
||||
@@ -86,12 +86,14 @@ public class Effect{
|
||||
create(this, x, y, rotation, Color.white, data);
|
||||
}
|
||||
|
||||
public void render(int id, Color color, float life, float rotation, float x, float y, Object data){
|
||||
public float render(int id, Color color, float life, float lifetime, float rotation, float x, float y, Object data){
|
||||
container.set(id, color, life, lifetime, rotation, x, y, data);
|
||||
Draw.z(ground ? Layer.debris : Layer.effect);
|
||||
Draw.reset();
|
||||
renderer.get(container);
|
||||
Draw.reset();
|
||||
|
||||
return container.lifetime;
|
||||
}
|
||||
|
||||
public static @Nullable Effect get(int id){
|
||||
@@ -125,13 +127,13 @@ public class Effect{
|
||||
|
||||
if(view.overlaps(pos)){
|
||||
EffectState entity = EffectState.create();
|
||||
entity.effect(effect);
|
||||
entity.rotation(rotation);
|
||||
entity.data(data);
|
||||
entity.lifetime(effect.lifetime);
|
||||
entity.effect = effect;
|
||||
entity.rotation = rotation;
|
||||
entity.data = (data);
|
||||
entity.lifetime = (effect.lifetime);
|
||||
entity.set(x, y);
|
||||
entity.color().set(color);
|
||||
if(data instanceof Posc) entity.parent((Posc)data);
|
||||
entity.color.set(color);
|
||||
if(data instanceof Posc) entity.parent = ((Posc)data);
|
||||
entity.add();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public class EntityGroup<T extends Entityc> implements Iterable<T>{
|
||||
each(Entityc::update);
|
||||
}
|
||||
|
||||
public void copy(Seq arr){
|
||||
public void copy(Seq<T> arr){
|
||||
arr.addAll(array);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package mindustry.entities;
|
||||
|
||||
import arc.*;
|
||||
import arc.func.*;
|
||||
import arc.math.geom.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
@@ -18,6 +19,15 @@ public class Units{
|
||||
private static float cdist;
|
||||
private static boolean boolResult;
|
||||
|
||||
@Remote(called = Loc.server)
|
||||
public static void unitCapDeath(Unit unit){
|
||||
if(unit != null){
|
||||
unit.dead = true;
|
||||
Fx.unitCapKill.at(unit);
|
||||
Core.app.post(() -> Call.unitDestroy(unit.id));
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server)
|
||||
public static void unitDeath(int uid){
|
||||
Unit unit = Groups.unit.getByID(uid);
|
||||
@@ -32,6 +42,21 @@ public class Units{
|
||||
}
|
||||
}
|
||||
|
||||
//destroys immediately
|
||||
@Remote(called = Loc.server)
|
||||
public static void unitDestroy(int uid){
|
||||
Unit unit = Groups.unit.getByID(uid);
|
||||
|
||||
//if there's no unit don't add it later and get it stuck as a ghost
|
||||
if(netClient != null){
|
||||
netClient.addRemovedEntity(uid);
|
||||
}
|
||||
|
||||
if(unit != null){
|
||||
unit.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server)
|
||||
public static void unitDespawn(Unit unit){
|
||||
Fx.unitDespawn.at(unit.x, unit.y, 0, unit);
|
||||
|
||||
@@ -2,7 +2,16 @@ package mindustry.entities.abilities;
|
||||
|
||||
import mindustry.gen.*;
|
||||
|
||||
public interface Ability{
|
||||
default void update(Unit unit){}
|
||||
default void draw(Unit unit){}
|
||||
public abstract class Ability implements Cloneable{
|
||||
public void update(Unit unit){}
|
||||
public void draw(Unit unit){}
|
||||
|
||||
public Ability copy(){
|
||||
try{
|
||||
return (Ability)clone();
|
||||
}catch(CloneNotSupportedException e){
|
||||
//I am disgusted
|
||||
throw new RuntimeException("java sucks", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ import mindustry.content.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
|
||||
public class ForceFieldAbility implements Ability{
|
||||
public class ForceFieldAbility extends Ability{
|
||||
/** Shield radius. */
|
||||
public float radius = 60f;
|
||||
/** Shield regen speed in damage/tick. */
|
||||
@@ -21,22 +21,26 @@ public class ForceFieldAbility implements Ability{
|
||||
/** Cooldown after the shield is broken, in ticks. */
|
||||
public float cooldown = 60f * 5;
|
||||
|
||||
private float realRad;
|
||||
private Unit paramUnit;
|
||||
private final Cons<Shielderc> shieldConsumer = trait -> {
|
||||
/** State. */
|
||||
protected float radiusScale, alpha;
|
||||
|
||||
private static float realRad;
|
||||
private static Unit paramUnit;
|
||||
private static ForceFieldAbility paramField;
|
||||
private static final Cons<Shielderc> shieldConsumer = trait -> {
|
||||
if(trait.team() != paramUnit.team && Intersector.isInsideHexagon(paramUnit.x, paramUnit.y, realRad * 2f, trait.x(), trait.y()) && paramUnit.shield > 0){
|
||||
trait.absorb();
|
||||
Fx.absorb.at(trait);
|
||||
|
||||
//break shield
|
||||
if(paramUnit.shield <= trait.damage()){
|
||||
paramUnit.shield -= cooldown * regen;
|
||||
paramUnit.shield -= paramField.cooldown * paramField.regen;
|
||||
|
||||
Fx.shieldBreak.at(paramUnit.x, paramUnit.y, radius, paramUnit.team.color);
|
||||
Fx.shieldBreak.at(paramUnit.x, paramUnit.y, paramField.radius, paramUnit.team.color);
|
||||
}
|
||||
|
||||
paramUnit.shield -= trait.damage();
|
||||
paramUnit.shieldAlpha = 1f;
|
||||
paramField.alpha = 1f;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -55,14 +59,17 @@ public class ForceFieldAbility implements Ability{
|
||||
unit.shield += Time.delta * regen;
|
||||
}
|
||||
|
||||
alpha = Math.max(alpha - Time.delta/10f, 0f);
|
||||
|
||||
if(unit.shield > 0){
|
||||
unit.timer2 = Mathf.lerpDelta(unit.timer2, 1f, 0.06f);
|
||||
radiusScale = Mathf.lerpDelta(radiusScale, 1f, 0.06f);
|
||||
paramUnit = unit;
|
||||
paramField = this;
|
||||
checkRadius(unit);
|
||||
|
||||
Groups.bullet.intersect(unit.x - realRad, unit.y - realRad, realRad * 2f, realRad * 2f, shieldConsumer);
|
||||
}else{
|
||||
unit.timer2 = 0f;
|
||||
radiusScale = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +80,7 @@ public class ForceFieldAbility implements Ability{
|
||||
if(unit.shield > 0){
|
||||
Draw.z(Layer.shields);
|
||||
|
||||
Draw.color(unit.team.color, Color.white, Mathf.clamp(unit.shieldAlpha));
|
||||
Draw.color(unit.team.color, Color.white, Mathf.clamp(alpha));
|
||||
|
||||
if(Core.settings.getBool("animatedshields")){
|
||||
Fill.poly(unit.x, unit.y, 6, realRad);
|
||||
@@ -89,6 +96,6 @@ public class ForceFieldAbility implements Ability{
|
||||
|
||||
private void checkRadius(Unit unit){
|
||||
//timer2 is used to store radius scale as an effect
|
||||
realRad = unit.timer2 * radius;
|
||||
realRad = radiusScale * radius;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,13 @@ import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.gen.*;
|
||||
|
||||
public class HealFieldAbility implements Ability{
|
||||
public class HealFieldAbility extends Ability{
|
||||
public float amount = 1, reload = 100, range = 60;
|
||||
public Effect healEffect = Fx.heal;
|
||||
public Effect activeEffect = Fx.healWave;
|
||||
public Effect activeEffect = Fx.healWaveDynamic;
|
||||
|
||||
private boolean wasHealed = false;
|
||||
protected float timer;
|
||||
protected boolean wasHealed = false;
|
||||
|
||||
HealFieldAbility(){}
|
||||
|
||||
@@ -22,9 +23,9 @@ public class HealFieldAbility implements Ability{
|
||||
|
||||
@Override
|
||||
public void update(Unit unit){
|
||||
unit.timer1 += Time.delta;
|
||||
timer += Time.delta;
|
||||
|
||||
if(unit.timer1 >= reload){
|
||||
if(timer >= reload){
|
||||
wasHealed = false;
|
||||
|
||||
Units.nearby(unit.team, unit.x, unit.y, range, other -> {
|
||||
@@ -36,10 +37,10 @@ public class HealFieldAbility implements Ability{
|
||||
});
|
||||
|
||||
if(wasHealed){
|
||||
activeEffect.at(unit);
|
||||
activeEffect.at(unit, range);
|
||||
}
|
||||
|
||||
unit.timer1 = 0f;
|
||||
timer = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,13 @@ import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.gen.*;
|
||||
|
||||
public class ShieldFieldAbility implements Ability{
|
||||
public class ShieldFieldAbility extends Ability{
|
||||
public float amount = 1, max = 100f, reload = 100, range = 60;
|
||||
public Effect applyEffect = Fx.shieldApply;
|
||||
public Effect activeEffect = Fx.shieldWave;
|
||||
|
||||
private boolean applied = false;
|
||||
protected float timer;
|
||||
protected boolean applied = false;
|
||||
|
||||
ShieldFieldAbility(){}
|
||||
|
||||
@@ -23,9 +24,9 @@ public class ShieldFieldAbility implements Ability{
|
||||
|
||||
@Override
|
||||
public void update(Unit unit){
|
||||
unit.timer1 += Time.delta;
|
||||
timer += Time.delta;
|
||||
|
||||
if(unit.timer1 >= reload){
|
||||
if(timer >= reload){
|
||||
applied = false;
|
||||
|
||||
Units.nearby(unit.team, unit.x, unit.y, range, other -> {
|
||||
@@ -41,7 +42,7 @@ public class ShieldFieldAbility implements Ability{
|
||||
activeEffect.at(unit);
|
||||
}
|
||||
|
||||
unit.timer1 = 0f;
|
||||
timer = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,14 @@ import mindustry.entities.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
|
||||
public class StatusFieldAbility implements Ability{
|
||||
public class StatusFieldAbility extends Ability{
|
||||
public @NonNull StatusEffect effect;
|
||||
public float duration = 60, reload = 100, range = 20;
|
||||
public Effect applyEffect = Fx.heal;
|
||||
public Effect activeEffect = Fx.overdriveWave;
|
||||
|
||||
protected float timer;
|
||||
|
||||
StatusFieldAbility(){}
|
||||
|
||||
public StatusFieldAbility(@NonNull StatusEffect effect, float duration, float reload, float range){
|
||||
@@ -24,9 +26,9 @@ public class StatusFieldAbility implements Ability{
|
||||
|
||||
@Override
|
||||
public void update(Unit unit){
|
||||
unit.timer2 += Time.delta;
|
||||
timer += Time.delta;
|
||||
|
||||
if(unit.timer2 >= reload){
|
||||
if(timer >= reload){
|
||||
|
||||
Units.nearby(unit.team, unit.x, unit.y, range, other -> {
|
||||
other.apply(effect, duration);
|
||||
@@ -34,7 +36,7 @@ public class StatusFieldAbility implements Ability{
|
||||
|
||||
activeEffect.at(unit);
|
||||
|
||||
unit.timer2 = 0f;
|
||||
timer = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
60
core/src/mindustry/entities/abilities/UnitSpawnAbility.java
Normal file
60
core/src/mindustry/entities/abilities/UnitSpawnAbility.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package mindustry.entities.abilities;
|
||||
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
|
||||
public class UnitSpawnAbility extends Ability{
|
||||
public @NonNull UnitType type;
|
||||
public float spawnTime = 60f, spawnX, spawnY;
|
||||
public Effect spawnEffect = Fx.spawn;
|
||||
|
||||
protected float timer;
|
||||
|
||||
public UnitSpawnAbility(@NonNull UnitType type, float spawnTime, float spawnX, float spawnY){
|
||||
this.type = type;
|
||||
this.spawnTime = spawnTime;
|
||||
this.spawnX = spawnX;
|
||||
this.spawnY = spawnY;
|
||||
}
|
||||
|
||||
public UnitSpawnAbility(){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Unit unit){
|
||||
timer += Time.delta;
|
||||
|
||||
if(timer >= spawnTime && Units.canCreate(unit.team, type)){
|
||||
|
||||
float x = unit.x + Angles.trnsx(unit.rotation, spawnY, spawnX), y = unit.y + Angles.trnsy(unit.rotation, spawnY, spawnX);
|
||||
spawnEffect.at(x, y);
|
||||
Unit u = type.create(unit.team);
|
||||
u.set(x, y);
|
||||
u.rotation = unit.rotation;
|
||||
if(!Vars.net.client()){
|
||||
u.add();
|
||||
}
|
||||
|
||||
timer = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Unit unit){
|
||||
if(Units.canCreate(unit.team, type)){
|
||||
Draw.draw(Draw.z(), () -> {
|
||||
float x = unit.x + Angles.trnsx(unit.rotation, spawnY, spawnX), y = unit.y + Angles.trnsy(unit.rotation, spawnY, spawnX);
|
||||
Drawf.construct(x, y, type.icon(Cicon.full), unit.rotation - 90, timer / spawnTime, 1f, timer);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,17 @@
|
||||
package mindustry.entities.bullet;
|
||||
|
||||
import arc.Core;
|
||||
import arc.graphics.Color;
|
||||
import arc.graphics.g2d.Draw;
|
||||
import arc.graphics.g2d.TextureRegion;
|
||||
import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.Pal;
|
||||
import mindustry.graphics.*;
|
||||
|
||||
/** An extended BulletType for most ammo-based bullets shot from turrets and units. */
|
||||
public class BasicBulletType extends BulletType{
|
||||
public Color backColor = Pal.bulletYellowBack, frontColor = Pal.bulletYellow;
|
||||
public Color mixColorFrom = new Color(1f, 1f, 1f, 0f), mixColorTo = new Color(1f, 1f, 1f, 0f);
|
||||
public float width = 5f, height = 7f;
|
||||
public float shrinkX = 0f, shrinkY = 0.5f;
|
||||
public float spin = 0;
|
||||
@@ -45,10 +46,15 @@ public class BasicBulletType extends BulletType{
|
||||
float width = this.width * ((1f - shrinkX) + shrinkX * b.fout());
|
||||
float offset = -90 + (spin != 0 ? Mathf.randomSeed(b.id, 360f) + b.time * spin : 0f);
|
||||
|
||||
Color mix = Tmp.c1.set(mixColorFrom).lerp(mixColorTo, b.fin());
|
||||
|
||||
Draw.mixcol(mix, mix.a);
|
||||
|
||||
Draw.color(backColor);
|
||||
Draw.rect(backRegion, b.x, b.y, width, height, b.rotation() + offset);
|
||||
Draw.color(frontColor);
|
||||
Draw.rect(frontRegion, b.x, b.y, width, height, b.rotation() + offset);
|
||||
Draw.color();
|
||||
|
||||
Draw.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public abstract class BulletType extends Content{
|
||||
public float hitSize = 4;
|
||||
public float drawSize = 40f;
|
||||
public float drag = 0f;
|
||||
public boolean pierce;
|
||||
public boolean pierce, pierceBuilding;
|
||||
public Effect hitEffect, despawnEffect;
|
||||
|
||||
/** Effect created when shooting. */
|
||||
@@ -69,6 +69,10 @@ public abstract class BulletType extends Content{
|
||||
public boolean scaleVelocity;
|
||||
/** Whether this bullet can be hit by point defense. */
|
||||
public boolean hittable = true;
|
||||
/** Whether this bullet can be reflected. */
|
||||
public boolean reflectable = true;
|
||||
/** Bullet range override. */
|
||||
public float range = -1f;
|
||||
|
||||
//additional effects
|
||||
|
||||
@@ -94,13 +98,13 @@ public abstract class BulletType extends Content{
|
||||
|
||||
public Color lightningColor = Pal.surge;
|
||||
public int lightning;
|
||||
public int lightningLength = 5;
|
||||
public int lightningLength = 5, lightningLengthRand = 0;
|
||||
/** Use a negative value to use default bullet damage. */
|
||||
public float lightningDamage = -1;
|
||||
|
||||
public float weaveScale = 1f;
|
||||
public float weaveMag = -1f;
|
||||
public float hitShake = 0f;
|
||||
public float hitShake = 0f, despawnShake = 0f;
|
||||
|
||||
public int puddles;
|
||||
public float puddleRange;
|
||||
@@ -124,17 +128,21 @@ public abstract class BulletType extends Content{
|
||||
|
||||
/** Returns maximum distance the bullet this bullet type has can travel. */
|
||||
public float range(){
|
||||
return speed * lifetime * (1f - drag);
|
||||
return Math.max(speed * lifetime * (1f - drag), range);
|
||||
}
|
||||
|
||||
public boolean collides(Bullet bullet, Building tile){
|
||||
return true;
|
||||
}
|
||||
|
||||
public void hitTile(Bullet b, Building tile){
|
||||
public void hitTile(Bullet b, Building tile, float initialHealth){
|
||||
hit(b);
|
||||
}
|
||||
|
||||
public void hitEntity(Bullet b, Hitboxc other, float initialHealth){
|
||||
|
||||
}
|
||||
|
||||
public void hit(Bullet b){
|
||||
hit(b, b.x, b.y);
|
||||
}
|
||||
@@ -173,7 +181,7 @@ public abstract class BulletType extends Content{
|
||||
}
|
||||
|
||||
for(int i = 0; i < lightning; i++){
|
||||
Lightning.create(b, lightningColor, lightningDamage < 0 ? damage : lightningDamage, b.x, b.y, Mathf.random(360f), lightningLength);
|
||||
Lightning.create(b, lightningColor, lightningDamage < 0 ? damage : lightningDamage, b.x, b.y, Mathf.random(360f), lightningLength + Mathf.random(lightningLengthRand));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,6 +189,8 @@ public abstract class BulletType extends Content{
|
||||
despawnEffect.at(b.x, b.y, b.rotation(), hitColor);
|
||||
hitSound.at(b);
|
||||
|
||||
Effect.shake(despawnShake, despawnShake, b);
|
||||
|
||||
if(fragBullet != null || splashDamageRadius > 0 || lightning > 0){
|
||||
hit(b);
|
||||
}
|
||||
@@ -269,9 +279,8 @@ public abstract class BulletType extends Content{
|
||||
bullet.damage = damage < 0 ? this.damage : damage;
|
||||
bullet.add();
|
||||
|
||||
if(keepVelocity && owner instanceof Hitboxc) bullet.vel.add(((Hitboxc)owner).deltaX() / Time.delta, ((Hitboxc)owner).deltaY() / Time.delta);
|
||||
if(keepVelocity && owner instanceof Velc) bullet.vel.add(((Velc)owner).vel().x, ((Velc)owner).vel().y);
|
||||
return bullet;
|
||||
|
||||
}
|
||||
|
||||
public void createNet(Team team, float x, float y, float angle, float damage, float velocityScl, float lifetimeScl){
|
||||
|
||||
@@ -12,10 +12,13 @@ import mindustry.graphics.*;
|
||||
public class ContinuousLaserBulletType extends BulletType{
|
||||
public float length = 220f;
|
||||
public float shake = 1f;
|
||||
public float fadeTime = 16f;
|
||||
public Color[] colors = {Color.valueOf("ec745855"), Color.valueOf("ec7458aa"), Color.valueOf("ff9c5a"), Color.white};
|
||||
public float[] tscales = {1f, 0.7f, 0.5f, 0.2f};
|
||||
public float[] strokes = {2f, 1.5f, 1f, 0.3f};
|
||||
public float[] lenscales = {1f, 1.12f, 1.15f, 1.17f};
|
||||
public float width = 9f, oscScl = 0.8f, oscMag = 1.5f;
|
||||
public boolean largeHit = true;
|
||||
|
||||
public ContinuousLaserBulletType(float damage){
|
||||
super(0.001f, damage);
|
||||
@@ -25,6 +28,7 @@ public class ContinuousLaserBulletType extends BulletType{
|
||||
hitSize = 4;
|
||||
drawSize = 420f;
|
||||
lifetime = 16f;
|
||||
keepVelocity = false;
|
||||
pierce = true;
|
||||
hittable = false;
|
||||
hitColor = colors[2];
|
||||
@@ -32,6 +36,7 @@ public class ContinuousLaserBulletType extends BulletType{
|
||||
incendAmount = 1;
|
||||
incendSpread = 5;
|
||||
incendChance = 0.4f;
|
||||
lightColor = Color.orange;
|
||||
}
|
||||
|
||||
protected ContinuousLaserBulletType(){
|
||||
@@ -43,13 +48,20 @@ public class ContinuousLaserBulletType extends BulletType{
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
super.init();
|
||||
|
||||
drawSize = Math.max(drawSize, length*2f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Bullet b){
|
||||
//TODO possible laser absorption from blocks
|
||||
|
||||
//damage every 5 ticks
|
||||
if(b.timer(1, 5f)){
|
||||
Damage.collideLine(b, b.team, hitEffect, b.x, b.y, b.rotation(), length, true);
|
||||
Damage.collideLine(b, b.team, hitEffect, b.x, b.y, b.rotation(), length, largeHit);
|
||||
}
|
||||
|
||||
if(shake > 0){
|
||||
@@ -59,21 +71,23 @@ public class ContinuousLaserBulletType extends BulletType{
|
||||
|
||||
@Override
|
||||
public void draw(Bullet b){
|
||||
float baseLen = length * b.fout();
|
||||
float realLength = Damage.findLaserLength(b, length);
|
||||
float fout = Mathf.clamp(b.time > b.lifetime - fadeTime ? 1f - (b.time - (lifetime - fadeTime)) / fadeTime : 1f);
|
||||
float baseLen = realLength * fout;
|
||||
|
||||
Lines.lineAngle(b.x, b.y, b.rotation(), baseLen);
|
||||
for(int s = 0; s < colors.length; s++){
|
||||
Draw.color(Tmp.c1.set(colors[s]).mul(1f + Mathf.absin(Time.time(), 1f, 0.1f)));
|
||||
for(int i = 0; i < tscales.length; i++){
|
||||
Tmp.v1.trns(b.rotation() + 180f, (lenscales[i] - 1f) * 35f);
|
||||
Lines.stroke((9f + Mathf.absin(Time.time(), 0.8f, 1.5f)) * b.fout() * strokes[s] * tscales[i]);
|
||||
Lines.stroke((width + Mathf.absin(Time.time(), oscScl, oscMag)) * fout * strokes[s] * tscales[i]);
|
||||
Lines.lineAngle(b.x + Tmp.v1.x, b.y + Tmp.v1.y, b.rotation(), baseLen * lenscales[i], false);
|
||||
}
|
||||
}
|
||||
|
||||
Tmp.v1.trns(b.rotation(), baseLen * 1.1f);
|
||||
|
||||
Drawf.light(b.team, b.x, b.y, b.x + Tmp.v1.x, b.y + Tmp.v1.y, 40, Color.orange, 0.7f);
|
||||
Drawf.light(b.team, b.x, b.y, b.x + Tmp.v1.x, b.y + Tmp.v1.y, 40, lightColor, 0.7f);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public class HealBulletType extends BulletType{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hitTile(Bullet b, Building tile){
|
||||
public void hitTile(Bullet b, Building tile, float initialHealth){
|
||||
super.hit(b);
|
||||
|
||||
if(tile.team == b.team && !(tile.block instanceof ConstructBlock)){
|
||||
|
||||
@@ -8,18 +8,17 @@ import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
public class LaserBulletType extends BulletType{
|
||||
protected static Tile furthest;
|
||||
|
||||
protected Color[] colors = {Pal.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Pal.lancerLaser, Color.white};
|
||||
protected Effect laserEffect = Fx.lancerLaserShootSmoke;
|
||||
protected float length = 160f;
|
||||
protected float width = 15f;
|
||||
protected float lengthFalloff = 0.5f;
|
||||
protected float sideLength = 29f, sideWidth = 0.7f;
|
||||
protected float sideAngle = 90f;
|
||||
public Color[] colors = {Pal.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Pal.lancerLaser, Color.white};
|
||||
public Effect laserEffect = Fx.lancerLaserShootSmoke;
|
||||
public float length = 160f;
|
||||
public float width = 15f;
|
||||
public float lengthFalloff = 0.5f;
|
||||
public float sideLength = 29f, sideWidth = 0.7f;
|
||||
public float sideAngle = 90f;
|
||||
public float lightningSpacing = -1, lightningDelay = 0.1f, lightningAngleRand;
|
||||
public boolean largeHit = false;
|
||||
|
||||
public LaserBulletType(float damage){
|
||||
super(0.01f, damage);
|
||||
@@ -40,6 +39,13 @@ public class LaserBulletType extends BulletType{
|
||||
this(1f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
super.init();
|
||||
|
||||
drawSize = Math.max(drawSize, length*2f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float range(){
|
||||
return length;
|
||||
@@ -47,8 +53,30 @@ public class LaserBulletType extends BulletType{
|
||||
|
||||
@Override
|
||||
public void init(Bullet b){
|
||||
float resultLength = Damage.collideLaser(b, length);
|
||||
laserEffect.at(b.x, b.y, b.rotation(), resultLength * 0.75f);
|
||||
float resultLength = Damage.collideLaser(b, length, largeHit), rot = b.rotation();
|
||||
|
||||
laserEffect.at(b.x, b.y, rot, resultLength * 0.75f);
|
||||
|
||||
if(lightningSpacing > 0){
|
||||
int idx = 0;
|
||||
for(float i = 0; i <= resultLength; i += lightningSpacing){
|
||||
float cx = b.x + Angles.trnsx(rot, i),
|
||||
cy = b.y + Angles.trnsy(rot, i);
|
||||
|
||||
int f = idx++;
|
||||
|
||||
for(int s : Mathf.signs){
|
||||
Time.run(f * lightningDelay, () -> {
|
||||
if(b.isAdded() && b.type == this){
|
||||
Lightning.create(b, lightningColor,
|
||||
lightningDamage < 0 ? damage : lightningDamage,
|
||||
cx, cy, rot + 90*s + Mathf.range(lightningAngleRand),
|
||||
lightningLength + Mathf.random(lightningLengthRand));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -61,7 +89,6 @@ public class LaserBulletType extends BulletType{
|
||||
float compound = 1f;
|
||||
|
||||
Lines.lineAngle(b.x, b.y, b.rotation(), baseLen);
|
||||
Lines.precise(true);
|
||||
for(Color color : colors){
|
||||
Draw.color(color);
|
||||
Lines.stroke((cwidth *= lengthFalloff) * b.fout());
|
||||
@@ -76,7 +103,6 @@ public class LaserBulletType extends BulletType{
|
||||
|
||||
compound *= lengthFalloff;
|
||||
}
|
||||
Lines.precise(false);
|
||||
Draw.reset();
|
||||
|
||||
Tmp.v1.trns(b.rotation(), baseLen * 1.1f);
|
||||
|
||||
60
core/src/mindustry/entities/bullet/RailBulletType.java
Normal file
60
core/src/mindustry/entities/bullet/RailBulletType.java
Normal file
@@ -0,0 +1,60 @@
|
||||
package mindustry.entities.bullet;
|
||||
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.gen.*;
|
||||
|
||||
//TODO this class is bad for multiple reasons, remove/replace it.
|
||||
//- effects unreliable
|
||||
//- not really hitscan but works like it
|
||||
//- buggy trails
|
||||
//- looks bad
|
||||
//- generally unreliable
|
||||
public class RailBulletType extends BulletType{
|
||||
public Effect pierceEffect = Fx.hitBulletSmall, updateEffect = Fx.none;
|
||||
/** Multiplier of damage decreased per health pierced. */
|
||||
public float pierceDamageFactor = 1f;
|
||||
|
||||
public RailBulletType(){
|
||||
pierceBuilding = true;
|
||||
pierce = true;
|
||||
reflectable = false;
|
||||
hitEffect = Fx.none;
|
||||
despawnEffect = Fx.none;
|
||||
}
|
||||
|
||||
void handle(Bullet b, Posc pos, float initialHealth){
|
||||
float sub = initialHealth*pierceDamageFactor;
|
||||
|
||||
if(sub >= b.damage){
|
||||
//cause a despawn
|
||||
b.remove();
|
||||
}
|
||||
|
||||
//subtract health from each consecutive pierce
|
||||
b.damage -= Math.min(b.damage, sub);
|
||||
|
||||
if(b.damage > 0){
|
||||
pierceEffect.at(pos.getX(), pos.getY(), b.rotation());
|
||||
}
|
||||
|
||||
hitEffect.at(pos.getX(), pos.getY());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Bullet b){
|
||||
if(b.timer(1, 0.9f)){
|
||||
updateEffect.at(b.x, b.y, b.rotation());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hitEntity(Bullet b, Hitboxc entity, float initialHealth){
|
||||
handle(b, entity, initialHealth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hitTile(Bullet b, Building tile, float initialHealth){
|
||||
handle(b, tile, initialHealth);
|
||||
}
|
||||
}
|
||||
@@ -39,10 +39,15 @@ public class SapBulletType extends BulletType{
|
||||
|
||||
Draw.reset();
|
||||
|
||||
Drawf.light(b.team, b.x, b.y, b.x + Tmp.v1.x, b.y + Tmp.v1.y, 15f * b.fout(), lightColor, 0.6f);
|
||||
Drawf.light(b.team, b.x, b.y, Tmp.v1.x, Tmp.v1.y, 15f * b.fout(), lightColor, 0.6f);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawLight(Bullet b){
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public float range(){
|
||||
return length;
|
||||
|
||||
@@ -13,6 +13,7 @@ public class ShrapnelBulletType extends BulletType{
|
||||
public float length = 100f;
|
||||
public float width = 20f;
|
||||
public Color fromColor = Color.white, toColor = Pal.lancerLaser;
|
||||
public boolean hitLarge = false;
|
||||
|
||||
public int serrations = 7;
|
||||
public float serrationLenScl = 10f, serrationWidth = 4f, serrationSpacing = 8f, serrationSpaceOffset = 80f, serrationFadeOffset = 0.5f;
|
||||
@@ -25,11 +26,19 @@ public class ShrapnelBulletType extends BulletType{
|
||||
despawnEffect = Fx.none;
|
||||
pierce = true;
|
||||
keepVelocity = false;
|
||||
hittable = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Bullet b){
|
||||
Damage.collideLaser(b, length);
|
||||
Damage.collideLaser(b, length, hitLarge);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
super.init();
|
||||
|
||||
drawSize = Math.max(drawSize, length*2f);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -71,7 +71,7 @@ abstract class BuilderComp implements Unitc{
|
||||
Tile tile = world.tile(current.x, current.y);
|
||||
|
||||
if(within(tile, finalPlaceDst)){
|
||||
rotation = Mathf.slerpDelta(rotation, angleTo(tile), 0.4f);
|
||||
lookAt(angleTo(tile));
|
||||
}
|
||||
|
||||
if(!(tile.block() instanceof ConstructBlock)){
|
||||
@@ -108,9 +108,9 @@ abstract class BuilderComp implements Unitc{
|
||||
ConstructBuild entity = tile.bc();
|
||||
|
||||
if(current.breaking){
|
||||
entity.deconstruct(base(), core, 1f / entity.buildCost * Time.delta * type().buildSpeed * state.rules.buildSpeedMultiplier);
|
||||
entity.deconstruct(self(), core, 1f / entity.buildCost * Time.delta * type().buildSpeed * state.rules.buildSpeedMultiplier);
|
||||
}else{
|
||||
entity.construct(base(), core, 1f / entity.buildCost * Time.delta * type().buildSpeed * state.rules.buildSpeedMultiplier, current.config);
|
||||
entity.construct(self(), core, 1f / entity.buildCost * Time.delta * type().buildSpeed * state.rules.buildSpeedMultiplier, current.config);
|
||||
}
|
||||
|
||||
current.stuck = Mathf.equal(current.progress, entity.progress);
|
||||
|
||||
@@ -80,7 +80,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
if(block.hasPower){
|
||||
//reinit power graph
|
||||
power.graph = new PowerGraph();
|
||||
power.graph.add(base());
|
||||
power.graph.add(self());
|
||||
}
|
||||
}
|
||||
this.rotation = rotation;
|
||||
@@ -94,7 +94,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
|
||||
created();
|
||||
|
||||
return base();
|
||||
return self();
|
||||
}
|
||||
|
||||
/** Sets up all the necessary variables, but does not add this entity anywhere. */
|
||||
@@ -111,17 +111,17 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
maxHealth(block.health);
|
||||
timer(new Interval(block.timers));
|
||||
|
||||
cons = new ConsumeModule(base());
|
||||
cons = new ConsumeModule(self());
|
||||
if(block.hasItems) items = new ItemModule();
|
||||
if(block.hasLiquids) liquids = new LiquidModule();
|
||||
if(block.hasPower){
|
||||
power = new PowerModule();
|
||||
power.graph.add(base());
|
||||
power.graph.add(self());
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
|
||||
return base();
|
||||
return self();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -195,17 +195,17 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
public void configure(Object value){
|
||||
//save last used config
|
||||
block.lastConfig = value;
|
||||
Call.tileConfig(player, base(), value);
|
||||
Call.tileConfig(player, self(), value);
|
||||
}
|
||||
|
||||
/** Configure from a server. */
|
||||
public void configureAny(Object value){
|
||||
Call.tileConfig(null, base(), value);
|
||||
Call.tileConfig(null, self(), value);
|
||||
}
|
||||
|
||||
/** Deselect this tile from configuration. */
|
||||
public void deselect(){
|
||||
if(!headless && control.input.frag.config.getSelectedTile() == base()){
|
||||
if(!headless && control.input.frag.config.getSelectedTile() == self()){
|
||||
control.input.frag.config.hideConfig();
|
||||
}
|
||||
}
|
||||
@@ -372,7 +372,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
|
||||
/** Returns the amount of items this block can accept. */
|
||||
public int acceptStack(Item item, int amount, Teamc source){
|
||||
if(acceptItem(base(), item) && block.hasItems && (source == null || source.team() == team)){
|
||||
if(acceptItem(self(), item) && block.hasItems && (source == null || source.team() == team)){
|
||||
return Math.min(getMaximumAccepted(item) - items.get(item), amount);
|
||||
}else{
|
||||
return 0;
|
||||
@@ -425,8 +425,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
int trns = block.size/2 + 1;
|
||||
Tile next = tile.getNearby(Geometry.d4(rotation).x * trns, Geometry.d4(rotation).y * trns);
|
||||
|
||||
if(next != null && next.build != null && next.build.team == team && next.build.acceptPayload(base(), todump)){
|
||||
next.build.handlePayload(base(), todump);
|
||||
if(next != null && next.build != null && next.build.team == team && next.build.acceptPayload(self(), todump)){
|
||||
next.build.handlePayload(self(), todump);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -446,8 +446,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
for(int i = 0; i < proximity.size; i++){
|
||||
Building other = proximity.get((i + dump) % proximity.size);
|
||||
|
||||
if(other.team == team && other.acceptPayload(base(), todump)){
|
||||
other.handlePayload(base(), todump);
|
||||
if(other.team == team && other.acceptPayload(self(), todump)){
|
||||
other.handlePayload(self(), todump);
|
||||
incrementDump(proximity.size);
|
||||
return true;
|
||||
}
|
||||
@@ -480,7 +480,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
for(int i = 0; i < proximity.size; i++){
|
||||
incrementDump(proximity.size);
|
||||
Building other = proximity.get((i + dump) % proximity.size);
|
||||
other = other.getLiquidDestination(base(), liquid);
|
||||
other = other.getLiquidDestination(self(), liquid);
|
||||
|
||||
if(other != null && other.team == team && other.block.hasLiquids && canDumpLiquid(other, liquid) && other.liquids != null){
|
||||
float ofract = other.liquids.get(liquid) / other.block.liquidCapacity;
|
||||
@@ -499,8 +499,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
public void transferLiquid(Building next, float amount, Liquid liquid){
|
||||
float flow = Math.min(next.block.liquidCapacity - next.liquids.get(liquid) - 0.001f, amount);
|
||||
|
||||
if(next.acceptLiquid(base(), liquid, flow)){
|
||||
next.handleLiquid(base(), liquid, flow);
|
||||
if(next.acceptLiquid(self(), liquid, flow)){
|
||||
next.handleLiquid(self(), liquid, flow);
|
||||
liquids.remove(liquid, flow);
|
||||
}
|
||||
}
|
||||
@@ -523,7 +523,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
public float moveLiquid(Building next, Liquid liquid){
|
||||
if(next == null) return 0;
|
||||
|
||||
next = next.getLiquidDestination(base(), liquid);
|
||||
next = next.getLiquidDestination(self(), liquid);
|
||||
|
||||
if(next.team == team && next.block.hasLiquids && liquids.get(liquid) > 0f){
|
||||
float ofract = next.liquids.get(liquid) / next.block.liquidCapacity;
|
||||
@@ -531,8 +531,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
float flow = Math.min(Mathf.clamp((fract - ofract) * (1f)) * (block.liquidCapacity), liquids.get(liquid));
|
||||
flow = Math.min(flow, next.block.liquidCapacity - next.liquids.get(liquid) - 0.001f);
|
||||
|
||||
if(flow > 0f && ofract <= fract && next.acceptLiquid(base(), liquid, flow)){
|
||||
next.handleLiquid(base(), liquid, flow);
|
||||
if(flow > 0f && ofract <= fract && next.acceptLiquid(self(), liquid, flow)){
|
||||
next.handleLiquid(self(), liquid, flow);
|
||||
liquids.remove(liquid, flow);
|
||||
return flow;
|
||||
}else if(next.liquids.currentAmount() / next.block.liquidCapacity > 0.1f && fract > 0.1f){
|
||||
@@ -558,7 +558,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
}
|
||||
|
||||
public Building getLiquidDestination(Building from, Liquid liquid){
|
||||
return base();
|
||||
return self();
|
||||
}
|
||||
|
||||
public @Nullable Payload getPayload(){
|
||||
@@ -580,13 +580,13 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
for(int i = 0; i < proximity.size; i++){
|
||||
incrementDump(proximity.size);
|
||||
Building other = proximity.get((i + dump) % proximity.size);
|
||||
if(other.team == team && other.acceptItem(base(), item) && canDump(other, item)){
|
||||
other.handleItem(base(), item);
|
||||
if(other.team == team && other.acceptItem(self(), item) && canDump(other, item)){
|
||||
other.handleItem(self(), item);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
handleItem(base(), item);
|
||||
handleItem(self(), item);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -598,8 +598,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
for(int i = 0; i < proximity.size; i++){
|
||||
incrementDump(proximity.size);
|
||||
Building other = proximity.get((i + dump) % proximity.size);
|
||||
if(other.team == team && other.acceptItem(base(), item) && canDump(other, item)){
|
||||
other.handleItem(base(), item);
|
||||
if(other.team == team && other.acceptItem(self(), item) && canDump(other, item)){
|
||||
other.handleItem(self(), item);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -631,16 +631,16 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
for(int ii = 0; ii < content.items().size; ii++){
|
||||
Item item = content.item(ii);
|
||||
|
||||
if(other.team == team && items.has(item) && other.acceptItem(base(), item) && canDump(other, item)){
|
||||
other.handleItem(base(), item);
|
||||
if(other.team == team && items.has(item) && other.acceptItem(self(), item) && canDump(other, item)){
|
||||
other.handleItem(self(), item);
|
||||
items.remove(item, 1);
|
||||
incrementDump(proximity.size);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
if(other.team == team && other.acceptItem(base(), todump) && canDump(other, todump)){
|
||||
other.handleItem(base(), todump);
|
||||
if(other.team == team && other.acceptItem(self(), todump) && canDump(other, todump)){
|
||||
other.handleItem(self(), todump);
|
||||
items.remove(todump, 1);
|
||||
incrementDump(proximity.size);
|
||||
return true;
|
||||
@@ -665,8 +665,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
/** Try offloading an item to a nearby container in its facing direction. Returns true if success. */
|
||||
public boolean moveForward(Item item){
|
||||
Building other = front();
|
||||
if(other != null && other.team == team && other.acceptItem(base(), item)){
|
||||
other.handleItem(base(), item);
|
||||
if(other != null && other.team == team && other.acceptItem(self(), item)){
|
||||
other.handleItem(self(), item);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -696,7 +696,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
return;
|
||||
}
|
||||
|
||||
power.graph.remove(base());
|
||||
power.graph.remove(self());
|
||||
for(int i = 0; i < power.links.size; i++){
|
||||
Tile other = world.tile(power.links.get(i));
|
||||
if(other != null && other.build != null && other.build.power != null){
|
||||
@@ -833,8 +833,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
tempTiles.clear();
|
||||
Geometry.circle(tileX(), tileY(), range, (x, y) -> {
|
||||
Building other = world.build(x, y);
|
||||
if(other != null && other.block instanceof PowerNode && ((PowerNode)other.block).linkValid(other, base()) && !PowerNode.insulated(other, base())
|
||||
&& !other.proximity().contains(this.<Building>base()) &&
|
||||
if(other != null && other.block instanceof PowerNode && ((PowerNode)other.block).linkValid(other, self()) && !PowerNode.insulated(other, self())
|
||||
&& !other.proximity().contains(this.<Building>self()) &&
|
||||
!(block.outputsPower && proximity.contains(p -> p.power != null && p.power.graph == other.power.graph))){
|
||||
tempTiles.add(other.tile);
|
||||
}
|
||||
@@ -1037,13 +1037,13 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
table.left();
|
||||
for(Consume cons : block.consumes.all()){
|
||||
if(cons.isOptional() && cons.isBoost()) continue;
|
||||
cons.build(base(), table);
|
||||
cons.build(self(), table);
|
||||
}
|
||||
}
|
||||
|
||||
public void displayBars(Table table){
|
||||
for(Func<Building, Bar> bar : block.bars.list()){
|
||||
table.add(bar.get(base())).growX();
|
||||
table.add(bar.get(self())).growX();
|
||||
table.row();
|
||||
}
|
||||
}
|
||||
@@ -1069,7 +1069,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
* @return whether or not this block should be deselected.
|
||||
*/
|
||||
public boolean onConfigureTileTapped(Building other){
|
||||
return base() != other;
|
||||
return self() != other;
|
||||
}
|
||||
|
||||
/** Returns whether this config menu should show when the specified player taps it. */
|
||||
@@ -1128,7 +1128,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
}
|
||||
|
||||
for(Building other : tmpTiles){
|
||||
other.proximity.remove(base(), true);
|
||||
other.proximity.remove(self(), true);
|
||||
other.onProximityUpdate();
|
||||
}
|
||||
}
|
||||
@@ -1144,8 +1144,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
if(other == null || !(other.tile.interactable(team))) continue;
|
||||
|
||||
//add this tile to proximity of nearby tiles
|
||||
if(!other.proximity.contains(base(), true)){
|
||||
other.proximity.add(base());
|
||||
if(!other.proximity.contains(self(), true)){
|
||||
other.proximity.add(self());
|
||||
}
|
||||
|
||||
tmpTiles.add(other);
|
||||
@@ -1184,13 +1184,13 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
@Replace
|
||||
@Override
|
||||
public boolean isValid(){
|
||||
return tile.build == base() && !dead();
|
||||
return tile.build == self() && !dead();
|
||||
}
|
||||
|
||||
@Replace
|
||||
@Override
|
||||
public void kill(){
|
||||
Call.tileDestroyed(base());
|
||||
Call.tileDestroyed(self());
|
||||
}
|
||||
|
||||
@Replace
|
||||
@@ -1204,10 +1204,10 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
damage /= state.rules.blockHealthMultiplier;
|
||||
}
|
||||
|
||||
Call.tileDamage(base(), health - handleDamage(damage));
|
||||
Call.tileDamage(self(), health - handleDamage(damage));
|
||||
|
||||
if(health <= 0){
|
||||
Call.tileDestroyed(base());
|
||||
Call.tileDestroyed(self());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1292,7 +1292,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
|
||||
}
|
||||
|
||||
if(block.idleSound != Sounds.none && shouldIdleSound()){
|
||||
loops.play(block.idleSound, base(), block.idleSoundVolume);
|
||||
loops.play(block.idleSound, self(), block.idleSoundVolume);
|
||||
}
|
||||
|
||||
if(enabled || !block.noUpdateDisabled){
|
||||
|
||||
@@ -44,17 +44,17 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
|
||||
|
||||
@Override
|
||||
public void drawBullets(){
|
||||
type.draw(base());
|
||||
type.draw(self());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(){
|
||||
type.init(base());
|
||||
type.init(self());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(){
|
||||
type.despawned(base());
|
||||
type.despawned(self());
|
||||
collided.clear();
|
||||
}
|
||||
|
||||
@@ -92,10 +92,12 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
|
||||
@MethodPriority(100)
|
||||
@Override
|
||||
public void collision(Hitboxc other, float x, float y){
|
||||
type.hit(base(), x, y);
|
||||
type.hit(self(), x, y);
|
||||
float health = 0f;
|
||||
|
||||
if(other instanceof Healthc){
|
||||
Healthc h = (Healthc)other;
|
||||
health = h.health();
|
||||
h.damage(damage);
|
||||
}
|
||||
|
||||
@@ -111,30 +113,40 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
|
||||
}else{
|
||||
collided.add(other.id());
|
||||
}
|
||||
|
||||
type.hitEntity(self(), other, health);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
type.update(base());
|
||||
type.update(self());
|
||||
|
||||
if(type.collidesTiles && type.collides && type.collidesGround){
|
||||
world.raycastEach(world.toTile(lastX()), world.toTile(lastY()), tileX(), tileY(), (x, y) -> {
|
||||
|
||||
Building tile = world.build(x, y);
|
||||
if(tile == null) return false;
|
||||
if(tile == null || !isAdded()) return false;
|
||||
|
||||
if(tile.collide(base()) && type.collides(base(), tile) && !tile.dead() && (type.collidesTeam || tile.team != team)){
|
||||
if(tile.collide(self()) && type.collides(self(), tile) && !tile.dead() && (type.collidesTeam || tile.team != team) && !(type.pierceBuilding && collided.contains(tile.id))){
|
||||
boolean remove = false;
|
||||
|
||||
float health = tile.health;
|
||||
|
||||
if(tile.team != team){
|
||||
remove = tile.collision(base());
|
||||
remove = tile.collision(self());
|
||||
}
|
||||
|
||||
if(remove || type.collidesTeam){
|
||||
type.hitTile(base(), tile);
|
||||
remove();
|
||||
if(!type.pierceBuilding){
|
||||
remove();
|
||||
}else{
|
||||
collided.add(tile.id);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
type.hitTile(self(), tile, health);
|
||||
|
||||
return !type.pierceBuilding;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -146,8 +158,8 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
|
||||
public void draw(){
|
||||
Draw.z(Layer.bullet);
|
||||
|
||||
type.draw(base());
|
||||
type.drawLight(base());
|
||||
type.draw(self());
|
||||
type.drawLight(self());
|
||||
}
|
||||
|
||||
/** Sets the bullet's rotation in degrees. */
|
||||
|
||||
@@ -27,7 +27,7 @@ abstract class CommanderComp implements Unitc{
|
||||
@Override
|
||||
public void update(){
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -59,7 +59,7 @@ abstract class CommanderComp implements Unitc{
|
||||
units.clear();
|
||||
|
||||
Units.nearby(team(), x, y, 200f, u -> {
|
||||
if(u.isAI() && include.get(u) && u != base()){
|
||||
if(u.isAI() && include.get(u) && u != self()){
|
||||
units.add(u);
|
||||
}
|
||||
});
|
||||
@@ -73,13 +73,13 @@ abstract class CommanderComp implements Unitc{
|
||||
void command(Formation formation, Seq<Unit> units){
|
||||
clearCommand();
|
||||
|
||||
float spacing = hitSize() * 1.7f;
|
||||
float spacing = hitSize() * 1f;
|
||||
minFormationSpeed = type().speed;
|
||||
|
||||
controlling.addAll(units);
|
||||
for(Unit unit : units){
|
||||
FormationAI ai;
|
||||
unit.controller(ai = new FormationAI(base(), formation));
|
||||
unit.controller(ai = new FormationAI(self(), formation));
|
||||
spacing = Math.max(spacing, ai.formationSize());
|
||||
minFormationSpeed = Math.min(minFormationSpeed, unit.type().speed);
|
||||
}
|
||||
@@ -104,7 +104,7 @@ abstract class CommanderComp implements Unitc{
|
||||
void clearCommand(){
|
||||
//reset controlled units
|
||||
for(Unit unit : controlling){
|
||||
if(unit.controller().isBeingControlled(base())){
|
||||
if(unit.controller().isBeingControlled(self())){
|
||||
unit.controller(unit.type().createController());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ abstract class DecalComp implements Drawc, Timedc, Rotc, Posc{
|
||||
|
||||
@Replace
|
||||
public float clipSize(){
|
||||
return region.getWidth()*2;
|
||||
return region.width *2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,13 +8,16 @@ import mindustry.gen.*;
|
||||
@EntityDef(value = {EffectStatec.class, Childc.class}, pooled = true, serialize = false)
|
||||
@Component(base = true)
|
||||
abstract class EffectStateComp implements Posc, Drawc, Timedc, Rotc, Childc{
|
||||
@Import float time, lifetime, rotation, x, y;
|
||||
@Import int id;
|
||||
|
||||
Color color = new Color(Color.white);
|
||||
Effect effect;
|
||||
Object data;
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
effect.render(id(), color, time(), rotation(), x(), y(), data);
|
||||
lifetime = effect.render(id, color, time, lifetime, rotation, x, y, data);
|
||||
}
|
||||
|
||||
@Replace
|
||||
|
||||
@@ -1,23 +1,18 @@
|
||||
package mindustry.entities.comp;
|
||||
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.EntityCollisions.*;
|
||||
import mindustry.gen.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@Component
|
||||
abstract class ElevationMoveComp implements Velc, Posc, Flyingc, Hitboxc{
|
||||
@Import float x, y;
|
||||
|
||||
@Replace
|
||||
@Override
|
||||
public void move(float cx, float cy){
|
||||
if(isFlying()){
|
||||
x += cx;
|
||||
y += cy;
|
||||
}else{
|
||||
collisions.move(this, cx, cy);
|
||||
}
|
||||
public SolidPred solidity(){
|
||||
return isFlying() ? null : EntityCollisions::solid;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ abstract class EntityComp{
|
||||
return false;
|
||||
}
|
||||
|
||||
<T extends Entityc> T base(){
|
||||
<T extends Entityc> T self(){
|
||||
return (T)this;
|
||||
}
|
||||
|
||||
|
||||
@@ -97,11 +97,11 @@ abstract class FireComp implements Timedc, Posc, Firec, Syncc{
|
||||
|
||||
@Override
|
||||
public void afterRead(){
|
||||
Fires.register(base());
|
||||
Fires.register(self());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSync(){
|
||||
Fires.register(base());
|
||||
Fires.register(self());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
|
||||
}
|
||||
|
||||
if(!hovering && isGrounded() && floor.isLiquid){
|
||||
if((splashTimer += Mathf.dst(deltaX(), deltaY())) >= 7f){
|
||||
if((splashTimer += Mathf.dst(deltaX(), deltaY())) >= (7f + hitSize()/8f)){
|
||||
floor.walkEffect.at(x, y, hitSize() / 8f, floor.mapColor);
|
||||
splashTimer = 0f;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,8 @@ abstract class HitboxComp implements Posc, QuadTreeObject{
|
||||
}
|
||||
|
||||
public void hitboxTile(Rect rect){
|
||||
float scale = 0.66f;
|
||||
rect.setCentered(x, y, hitSize * scale, hitSize * scale);
|
||||
//tile hitboxes are never bigger than a tile, otherwise units get stuck
|
||||
float size = Math.min(hitSize * 0.66f, 7.9f);
|
||||
rect.setCentered(x, y, size, size);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ abstract class LaunchCoreComp implements Drawc, Timedc{
|
||||
Draw.z(Layer.weather - 1);
|
||||
|
||||
TextureRegion region = block.icon(Cicon.full);
|
||||
float rw = region.getWidth() * Draw.scl * scale, rh = region.getHeight() * Draw.scl * scale;
|
||||
float rw = region.width * Draw.scl * scale, rh = region.height * Draw.scl * scale;
|
||||
|
||||
Draw.alpha(alpha);
|
||||
Draw.rect(region, cx, cy, rw, rh, rotation - 45);
|
||||
|
||||
@@ -4,16 +4,16 @@ import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.ai.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.EntityCollisions.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@Component
|
||||
abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
|
||||
@Import float x, y;
|
||||
@@ -26,8 +26,14 @@ abstract class LegsComp implements Posc, Rotc, Hitboxc, Flyingc, Unitc{
|
||||
|
||||
@Replace
|
||||
@Override
|
||||
public void move(float cx, float cy){
|
||||
collisions.moveCheck(this, cx, cy, !type.allowLegStep ? EntityCollisions::solid : EntityCollisions::legsSolid);
|
||||
public SolidPred solidity(){
|
||||
return !type.allowLegStep ? EntityCollisions::solid : EntityCollisions::legsSolid;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Replace
|
||||
public int pathType(){
|
||||
return Pathfinder.costLegs;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,19 +1,86 @@
|
||||
package mindustry.entities.comp;
|
||||
|
||||
import arc.graphics.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@Component
|
||||
abstract class MechComp implements Posc, Flyingc, Hitboxc, Unitc, Mechc, ElevationMovec{
|
||||
@Import float x, y, hitSize;
|
||||
@Import UnitType type;
|
||||
|
||||
@SyncField(false) @SyncLocal float baseRotation;
|
||||
transient float walkTime;
|
||||
transient float walkTime, walkExtension;
|
||||
transient private boolean walked;
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
float len = deltaLen();
|
||||
baseRotation = Angles.moveToward(baseRotation, deltaAngle(), type().baseRotateSpeed * Mathf.clamp(len / type().speed / Time.delta) * Time.delta);
|
||||
walkTime += len;
|
||||
//trigger animation only when walking manually
|
||||
if(walked){
|
||||
float len = deltaLen();
|
||||
baseRotation = Angles.moveToward(baseRotation, deltaAngle(), type().baseRotateSpeed * Mathf.clamp(len / type().speed / Time.delta) * Time.delta);
|
||||
walkTime += len;
|
||||
walked = false;
|
||||
}
|
||||
|
||||
//update mech effects
|
||||
float extend = walkExtend(false);
|
||||
float base = walkExtend(true);
|
||||
float extendScl = base % 1f;
|
||||
|
||||
float lastExtend = walkExtension;
|
||||
|
||||
if(extendScl < lastExtend && base % 2f > 1f){
|
||||
int side = -Mathf.sign(extend);
|
||||
float width = hitSize / 2f * side, length = type.mechStride * 1.35f;
|
||||
|
||||
float cx = x + Angles.trnsx(baseRotation, length, width),
|
||||
cy = y + Angles.trnsy(baseRotation, length, width);
|
||||
|
||||
if(type.mechStepShake > 0){
|
||||
Effect.shake(type.mechStepShake, type.mechStepShake, cx, cy);
|
||||
}
|
||||
|
||||
if(type.mechStepParticles){
|
||||
Tile tile = world.tileWorld(cx, cy);
|
||||
if(tile != null){
|
||||
Color color = tile.floor().mapColor;
|
||||
Fx.unitLand.at(cx, cy, hitSize/8f, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
walkExtension = extendScl;
|
||||
}
|
||||
|
||||
public float walkExtend(boolean scaled){
|
||||
|
||||
//now ranges from -maxExtension to maxExtension*3
|
||||
float raw = walkTime % (type.mechStride * 4);
|
||||
|
||||
if(scaled) return raw / type.mechStride;
|
||||
|
||||
if(raw > type.mechStride*3) raw = raw - type.mechStride * 4;
|
||||
else if(raw > type.mechStride*2) raw = type.mechStride * 2 - raw;
|
||||
else if(raw > type.mechStride) raw = type.mechStride * 2 - raw;
|
||||
|
||||
return raw;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveAt(Vec2 vector, float acceleration){
|
||||
if(!vector.isZero()){
|
||||
//mark walking state when moving in a controlled manner
|
||||
walked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{
|
||||
}
|
||||
|
||||
boolean mining(){
|
||||
return mineTile != null;
|
||||
return mineTile != null && !(((Object)this) instanceof Builderc && ((Builderc)(Object)this).activelyBuilding());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,13 +51,12 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{
|
||||
}
|
||||
|
||||
if(mineTile == null || core == null || mineTile.block() != Blocks.air || dst(mineTile.worldx(), mineTile.worldy()) > miningRange
|
||||
|| (((Object)this) instanceof Builderc && ((Builderc)(Object)this).activelyBuilding())
|
||||
|| mineTile.drop() == null || !canMine(mineTile.drop())){
|
||||
mineTile = null;
|
||||
mineTimer = 0f;
|
||||
}else{
|
||||
}else if(mining()){
|
||||
Item item = mineTile.drop();
|
||||
rotation(Mathf.slerpDelta(rotation(), angleTo(mineTile.worldx(), mineTile.worldy()), 0.4f));
|
||||
lookAt(angleTo(mineTile.worldx(), mineTile.worldy()));
|
||||
mineTimer += Time.delta *type.mineSpeed;
|
||||
|
||||
if(Mathf.chance(0.06 * Time.delta)){
|
||||
|
||||
@@ -25,15 +25,15 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{
|
||||
}
|
||||
|
||||
boolean canPickup(Unit unit){
|
||||
return payloadUsed() + unit.hitSize * unit.hitSize <= type.payloadCapacity;
|
||||
return payloadUsed() + unit.hitSize * unit.hitSize <= type.payloadCapacity + 0.001f;
|
||||
}
|
||||
|
||||
boolean canPickup(Building build){
|
||||
return payloadUsed() + build.block.size * build.block.size * Vars.tilesize * Vars.tilesize <= type.payloadCapacity;
|
||||
return payloadUsed() + build.block.size * build.block.size * Vars.tilesize * Vars.tilesize <= type.payloadCapacity + 0.001f;
|
||||
}
|
||||
|
||||
boolean canPickupPayload(Payload pay){
|
||||
return payloadUsed() + pay.size()*pay.size() <= type.payloadCapacity;
|
||||
return payloadUsed() + pay.size()*pay.size() <= type.payloadCapacity + 0.001f;
|
||||
}
|
||||
|
||||
boolean hasPayload(){
|
||||
@@ -48,6 +48,9 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{
|
||||
unit.remove();
|
||||
payloads.add(new UnitPayload(unit));
|
||||
Fx.unitPickup.at(unit);
|
||||
if(Vars.net.client()){
|
||||
Vars.netClient.clearRemovedEntity(unit.id);
|
||||
}
|
||||
}
|
||||
|
||||
void pickup(Building tile){
|
||||
@@ -71,6 +74,11 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{
|
||||
boolean tryDropPayload(Payload payload){
|
||||
Tile on = tileOn();
|
||||
|
||||
//clear removed state of unit so it can be synced
|
||||
if(Vars.net.client() && payload instanceof UnitPayload){
|
||||
Vars.netClient.clearRemovedEntity(((UnitPayload)payload).unit.id);
|
||||
}
|
||||
|
||||
//drop off payload on an acceptor if possible
|
||||
if(on != null && on.build != null && on.build.acceptPayload(on.build, payload)){
|
||||
Fx.unitDrop.at(on.build);
|
||||
@@ -90,7 +98,7 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{
|
||||
Unit u = payload.unit;
|
||||
|
||||
//can't drop ground units
|
||||
if(((tileOn() == null || tileOn().solid()) && u.elevation < 0.1f) || (!floorOn().isLiquid && u instanceof WaterMovec)){
|
||||
if(!u.canPass(tileX(), tileY())){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,10 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
||||
return unit.icon();
|
||||
}
|
||||
|
||||
public boolean displayAmmo(){
|
||||
return unit instanceof BlockUnitc || state.rules.unitAmmo;
|
||||
}
|
||||
|
||||
public void reset(){
|
||||
team = state.rules.defaultTeam;
|
||||
admin = typing = false;
|
||||
@@ -88,7 +92,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
||||
|
||||
@Replace
|
||||
public float clipSize(){
|
||||
return unit.isNull() ? 20 : unit.type().hitsize * 2f;
|
||||
return unit.isNull() ? 20 : unit.type().hitSize * 2f;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -130,7 +134,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
||||
deathTimer += Time.delta;
|
||||
if(deathTimer >= deathDelay){
|
||||
//request spawn - this happens serverside only
|
||||
core.requestSpawn(base());
|
||||
core.requestSpawn(self());
|
||||
deathTimer = 0;
|
||||
}
|
||||
}
|
||||
@@ -187,7 +191,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
|
||||
}
|
||||
}
|
||||
|
||||
Events.fire(new UnitChangeEvent(base(), unit));
|
||||
Events.fire(new UnitChangeEvent(self(), unit));
|
||||
}
|
||||
|
||||
boolean dead(){
|
||||
|
||||
@@ -128,6 +128,6 @@ abstract class PuddleComp implements Posc, Puddlec, Drawc{
|
||||
|
||||
@Override
|
||||
public void afterRead(){
|
||||
Puddles.register(base());
|
||||
Puddles.register(self());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package mindustry.entities.comp;
|
||||
|
||||
import arc.graphics.*;
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.pooling.*;
|
||||
@@ -24,11 +23,6 @@ abstract class StatusComp implements Posc, Flyingc{
|
||||
|
||||
@Import UnitType type;
|
||||
|
||||
/** @return damage taken based on status armor multipliers */
|
||||
float getShieldDamage(float amount){
|
||||
return amount * Mathf.clamp(1f - armorMultiplier / 100f);
|
||||
}
|
||||
|
||||
/** Apply a status effect for 1 tick (for permanent effects) **/
|
||||
void apply(StatusEffect effect){
|
||||
apply(effect, 1);
|
||||
@@ -48,7 +42,7 @@ abstract class StatusComp implements Posc, Flyingc{
|
||||
return;
|
||||
}else if(entry.effect.reactsWith(effect)){ //find opposite
|
||||
StatusEntry.tmp.effect = entry.effect;
|
||||
entry.effect.getTransition(base(), effect, entry.time, duration, StatusEntry.tmp);
|
||||
entry.effect.getTransition(self(), effect, entry.time, duration, StatusEntry.tmp);
|
||||
entry.time = StatusEntry.tmp.time;
|
||||
|
||||
if(StatusEntry.tmp.effect != entry.effect){
|
||||
@@ -131,14 +125,14 @@ abstract class StatusComp implements Posc, Flyingc{
|
||||
armorMultiplier *= entry.effect.armorMultiplier;
|
||||
damageMultiplier *= entry.effect.damageMultiplier;
|
||||
reloadMultiplier *= entry.effect.reloadMultiplier;
|
||||
entry.effect.update(base(), entry.time);
|
||||
entry.effect.update(self(), entry.time);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void draw(){
|
||||
for(StatusEntry e : statuses){
|
||||
e.effect.draw(base());
|
||||
e.effect.draw(self());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,15 @@ import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import arc.util.*;
|
||||
import mindustry.ai.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.abilities.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
@@ -27,17 +30,17 @@ import static mindustry.Vars.*;
|
||||
@Component(base = true)
|
||||
abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Displayable, Senseable{
|
||||
|
||||
@Import boolean hovering;
|
||||
@Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health;
|
||||
@Import boolean dead;
|
||||
@Import boolean hovering, dead;
|
||||
@Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo;
|
||||
@Import Team team;
|
||||
@Import int id;
|
||||
|
||||
private UnitController controller;
|
||||
private UnitType type;
|
||||
boolean spawnedByCore, deactivated;
|
||||
boolean spawnedByCore;
|
||||
|
||||
transient float timer1, timer2;
|
||||
transient Seq<Ability> abilities = new Seq<>(0);
|
||||
private transient float resupplyTime = Mathf.random(10f);
|
||||
|
||||
public void moveAt(Vec2 vector){
|
||||
moveAt(vector, type.accel);
|
||||
@@ -67,7 +70,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
|
||||
@Replace
|
||||
public float clipSize(){
|
||||
return type.region.getWidth() * 2f;
|
||||
return Math.max(type.region.width * 2f, type.clipSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -101,7 +104,14 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
@Override
|
||||
@Replace
|
||||
public boolean canDrown(){
|
||||
return isGrounded() && !hovering && type.canDrown && !(this instanceof WaterMovec);
|
||||
return isGrounded() && !hovering && type.canDrown;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Replace
|
||||
public boolean canShoot(){
|
||||
//cannot shoot while boosting
|
||||
return !(type.canBoost && isFlying());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -117,7 +127,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
@Override
|
||||
public void controller(UnitController next){
|
||||
this.controller = next;
|
||||
if(controller.unit() != base()) controller.unit(base());
|
||||
if(controller.unit() != self()) controller.unit(self());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -147,8 +157,13 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
return type;
|
||||
}
|
||||
|
||||
/** @return pathfinder path type for calculating costs */
|
||||
public int pathType(){
|
||||
return Pathfinder.costGround;
|
||||
}
|
||||
|
||||
public void lookAt(float angle){
|
||||
rotation = Angles.moveToward(rotation, angle, type.rotateSpeed * Time.delta);
|
||||
rotation = Angles.moveToward(rotation, angle, type.rotateSpeed * Time.delta * speedMultiplier());
|
||||
}
|
||||
|
||||
public void lookAt(Position pos){
|
||||
@@ -171,23 +186,26 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
return Units.getCap(team);
|
||||
}
|
||||
|
||||
private void setStats(UnitType type){
|
||||
public void setStats(UnitType type){
|
||||
this.type = type;
|
||||
this.maxHealth = type.health;
|
||||
this.drag = type.drag;
|
||||
this.armor = type.armor;
|
||||
this.hitSize = type.hitsize;
|
||||
this.hitSize = type.hitSize;
|
||||
this.hovering = type.hovering;
|
||||
|
||||
if(controller == null) controller(type.createController());
|
||||
if(mounts().length != type.weapons.size) setupWeapons(type);
|
||||
if(abilities.size != type.abilities.size){
|
||||
abilities = type.abilities.map(Ability::copy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterSync(){
|
||||
//set up type info after reading
|
||||
setStats(this.type);
|
||||
controller.unit(base());
|
||||
controller.unit(self());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -199,20 +217,18 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
|
||||
@Override
|
||||
public void add(){
|
||||
teamIndex.updateCount(team, type, 1);
|
||||
|
||||
//check if over unit cap
|
||||
if(count() > cap() && !spawnedByCore){
|
||||
deactivated = true;
|
||||
}else{
|
||||
teamIndex.updateActiveCount(team, type, 1);
|
||||
if(count() > cap() && !spawnedByCore && !dead){
|
||||
Call.unitCapDeath(self());
|
||||
teamIndex.updateCount(team, type, -1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(){
|
||||
teamIndex.updateCount(team, type, -1);
|
||||
controller.removed(base());
|
||||
controller.removed(self());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -221,18 +237,29 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
Effect.shake(type.landShake, type.landShake, this);
|
||||
}
|
||||
|
||||
type.landed(base());
|
||||
type.landed(self());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
//activate the unit when possible
|
||||
if(!net.client() && deactivated && teamIndex.countActive(team, type) < Units.getCap(team)){
|
||||
teamIndex.updateActiveCount(team, type, 1);
|
||||
deactivated = false;
|
||||
|
||||
type.update(self());
|
||||
|
||||
if(state.rules.unitAmmo && ammo < type.ammoCapacity - 0.0001f){
|
||||
resupplyTime += Time.delta;
|
||||
|
||||
//resupply only at a fixed interval to prevent lag
|
||||
if(resupplyTime > 10f){
|
||||
type.ammoType.resupply(self());
|
||||
resupplyTime = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
if(!deactivated) type.update(base());
|
||||
if(abilities.size > 0){
|
||||
for(Ability a : abilities){
|
||||
a.update(self());
|
||||
}
|
||||
}
|
||||
|
||||
drag = type.drag * (isGrounded() ? (floorOn().dragMultiplier) : 1f);
|
||||
|
||||
@@ -282,25 +309,27 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
if(tile != null && isGrounded() && !type.hovering){
|
||||
//unit block update
|
||||
if(tile.build != null){
|
||||
tile.build.unitOn(base());
|
||||
tile.build.unitOn(self());
|
||||
}
|
||||
|
||||
//apply damage
|
||||
if(floor.damageTaken > 0f){
|
||||
damageContinuous(floor.damageTaken);
|
||||
}
|
||||
}
|
||||
|
||||
if(tile.solid()){
|
||||
if(type.canBoost){
|
||||
elevation = 1f;
|
||||
}else if(!net.client()){
|
||||
kill();
|
||||
}
|
||||
//kill entities on tiles that are solid to them
|
||||
if(tile != null && !canPassOn()){
|
||||
//boost if possible
|
||||
if(type.canBoost){
|
||||
elevation = 1f;
|
||||
}else if(!net.client()){
|
||||
kill();
|
||||
}
|
||||
}
|
||||
|
||||
//AI only updates on the server
|
||||
if(!net.client() && !dead && !deactivated){
|
||||
if(!net.client() && !dead){
|
||||
controller.updateUnit();
|
||||
}
|
||||
|
||||
@@ -309,14 +338,9 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
resetController();
|
||||
}
|
||||
|
||||
//do not control anything when deactivated
|
||||
if(deactivated){
|
||||
controlWeapons(false, false);
|
||||
}
|
||||
|
||||
//remove units spawned by the core
|
||||
if(spawnedByCore && !isPlayer()){
|
||||
Call.unitDespawn(base());
|
||||
Call.unitDespawn(self());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,8 +351,8 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
|
||||
/** Actually destroys the unit, removing it and creating explosions. **/
|
||||
public void destroy(){
|
||||
float explosiveness = 2f + item().explosiveness * stack().amount;
|
||||
float flammability = item().flammability * stack().amount;
|
||||
float explosiveness = 2f + item().explosiveness * stack().amount / 2f;
|
||||
float flammability = item().flammability * stack().amount / 2f;
|
||||
Damage.dynamicExplosion(x, y, flammability, explosiveness, 0f, bounds() / 2f, Pal.darkFlame, state.rules.damageExplosions);
|
||||
|
||||
float shake = hitSize / 3f;
|
||||
@@ -338,7 +362,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
Effect.shake(shake, shake, this);
|
||||
type.deathSound.at(this);
|
||||
|
||||
Events.fire(new UnitDestroyEvent(base()));
|
||||
Events.fire(new UnitDestroyEvent(self()));
|
||||
|
||||
if(explosiveness > 7f && isLocal()){
|
||||
Events.fire(Trigger.suicideBomb);
|
||||
@@ -346,13 +370,13 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
|
||||
//if this unit crash landed (was flying), damage stuff in a radius
|
||||
if(type.flying){
|
||||
Damage.damage(team,x, y, hitSize * 1.1f, hitSize * type.crashDamageMultiplier, true, false, true);
|
||||
Damage.damage(team,x, y, Mathf.pow(hitSize, 0.94f) * 1.25f, Mathf.pow(hitSize, 0.75f) * type.crashDamageMultiplier * 5f, true, false, true);
|
||||
}
|
||||
|
||||
if(!headless){
|
||||
for(int i = 0; i < type.wreckRegions.length; i++){
|
||||
if(type.wreckRegions[i].found()){
|
||||
float range = type.hitsize/4f;
|
||||
float range = type.hitSize /4f;
|
||||
Tmp.v1.rnd(range);
|
||||
Effect.decal(type.wreckRegions[i], x + Tmp.v1.x, y + Tmp.v1.y, rotation - 90);
|
||||
}
|
||||
@@ -364,7 +388,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
|
||||
@Override
|
||||
public void display(Table table){
|
||||
type.display(base(), table);
|
||||
type.display(self(), table);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -374,7 +398,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
type.draw(base());
|
||||
type.draw(self());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,9 +3,13 @@ package mindustry.entities.comp;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.entities.EntityCollisions.*;
|
||||
import mindustry.gen.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@Component
|
||||
abstract class VelComp implements Posc{
|
||||
@Import float x, y;
|
||||
@@ -22,12 +26,35 @@ abstract class VelComp implements Posc{
|
||||
vel.scl(Mathf.clamp(1f - drag * Time.delta));
|
||||
}
|
||||
|
||||
/** @return function to use for check solid state. if null, no checking is done. */
|
||||
@Nullable
|
||||
SolidPred solidity(){
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return whether this entity can move through a location*/
|
||||
boolean canPass(int tileX, int tileY){
|
||||
SolidPred s = solidity();
|
||||
return s == null || !s.solid(tileX, tileY);
|
||||
}
|
||||
|
||||
/** @return whether this entity can exist on its current location*/
|
||||
boolean canPassOn(){
|
||||
return canPass(tileX(), tileY());
|
||||
}
|
||||
|
||||
boolean moving(){
|
||||
return !vel.isZero(0.01f);
|
||||
}
|
||||
|
||||
void move(float cx, float cy){
|
||||
x += cx;
|
||||
y += cy;
|
||||
SolidPred check = solidity();
|
||||
|
||||
if(check != null){
|
||||
collisions.move(self(), cx, cy, check);
|
||||
}else{
|
||||
x += cx;
|
||||
y += cy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,17 +4,17 @@ import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.util.*;
|
||||
import mindustry.ai.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.entities.EntityCollisions.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.environment.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
//just a proof of concept
|
||||
@Component
|
||||
abstract class WaterMoveComp implements Posc, Velc, Hitboxc, Flyingc, Unitc{
|
||||
@@ -38,16 +38,8 @@ abstract class WaterMoveComp implements Posc, Velc, Hitboxc, Flyingc, Unitc{
|
||||
|
||||
@Override
|
||||
@Replace
|
||||
public void lookAt(float angle){
|
||||
if(onLiquid()){
|
||||
rotation = Angles.moveToward(rotation, angle, type.rotateSpeed * Time.delta);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Replace
|
||||
public boolean canShoot(){
|
||||
return onLiquid();
|
||||
public int pathType(){
|
||||
return Pathfinder.costWater;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -74,13 +66,8 @@ abstract class WaterMoveComp implements Posc, Velc, Hitboxc, Flyingc, Unitc{
|
||||
|
||||
@Replace
|
||||
@Override
|
||||
public void move(float cx, float cy){
|
||||
if(isGrounded()){
|
||||
collisions.moveCheck(this, cx, cy, EntityCollisions::waterSolid);
|
||||
}else{
|
||||
x += cx;
|
||||
y += cy;
|
||||
}
|
||||
public SolidPred solidity(){
|
||||
return isFlying() ? null : EntityCollisions::waterSolid;
|
||||
}
|
||||
|
||||
@Replace
|
||||
|
||||
@@ -13,9 +13,10 @@ import mindustry.type.*;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
@Component
|
||||
abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc{
|
||||
abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{
|
||||
@Import float x, y, rotation, reloadMultiplier;
|
||||
@Import Vec2 vel;
|
||||
@Import UnitType type;
|
||||
|
||||
/** minimum cursor distance from unit, fixes 'cross-eyed' shooting */
|
||||
static final float minAimDst = 18f;
|
||||
@@ -29,6 +30,10 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc{
|
||||
boolean isShooting;
|
||||
float ammo;
|
||||
|
||||
float ammof(){
|
||||
return ammo / type.ammoCapacity;
|
||||
}
|
||||
|
||||
void setWeaponRotation(float rotation){
|
||||
for(WeaponMount mount : mounts){
|
||||
mount.rotation = rotation;
|
||||
@@ -80,6 +85,16 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(){
|
||||
for(WeaponMount mount : mounts){
|
||||
if(mount.bullet != null){
|
||||
mount.bullet.time = mount.bullet.lifetime - 10f;
|
||||
mount.bullet = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Update shooting and rotation for this unit. */
|
||||
@Override
|
||||
public void update(){
|
||||
@@ -89,6 +104,27 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc{
|
||||
Weapon weapon = mount.weapon;
|
||||
mount.reload = Math.max(mount.reload - Time.delta * reloadMultiplier, 0);
|
||||
|
||||
float weaponRotation = this.rotation - 90 + (weapon.rotate ? mount.rotation : 0);
|
||||
float mountX = this.x + Angles.trnsx(this.rotation - 90, weapon.x, weapon.y),
|
||||
mountY = this.y + Angles.trnsy(this.rotation - 90, weapon.x, weapon.y);
|
||||
float shootX = mountX + Angles.trnsx(weaponRotation, weapon.shootX, weapon.shootY),
|
||||
shootY = mountY + Angles.trnsy(weaponRotation, weapon.shootX, weapon.shootY);
|
||||
float shootAngle = weapon.rotate ? weaponRotation + 90 : Angles.angle(shootX, shootY, mount.aimX, mount.aimY) + (this.rotation - angleTo(mount.aimX, mount.aimY));
|
||||
|
||||
//update continuous state
|
||||
if(weapon.continuous && mount.bullet != null){
|
||||
if(!mount.bullet.isAdded() || mount.bullet.time >= mount.bullet.lifetime){
|
||||
mount.bullet = null;
|
||||
}else{
|
||||
mount.bullet.rotation(weaponRotation + 90);
|
||||
mount.bullet.set(shootX, shootY);
|
||||
vel.add(Tmp.v1.trns(rotation + 180f, mount.bullet.type.recoil));
|
||||
}
|
||||
}else{
|
||||
//heat decreases when not firing
|
||||
mount.heat = Math.max(mount.heat - Time.delta * reloadMultiplier / mount.weapon.cooldownTime, 0);
|
||||
}
|
||||
|
||||
//flip weapon shoot side for alternating weapons at half reload
|
||||
if(weapon.otherSide != -1 && weapon.alternate && mount.side == weapon.flipSprite &&
|
||||
mount.reload + Time.delta > weapon.reload/2f && mount.reload <= weapon.reload/2f){
|
||||
@@ -98,10 +134,10 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc{
|
||||
|
||||
//rotate if applicable
|
||||
if(weapon.rotate && (mount.rotate || mount.shoot) && can){
|
||||
float axisX = this.x + Angles.trnsx(rotation - 90, weapon.x, weapon.y),
|
||||
axisY = this.y + Angles.trnsy(rotation - 90, weapon.x, weapon.y);
|
||||
float axisX = this.x + Angles.trnsx(this.rotation - 90, weapon.x, weapon.y),
|
||||
axisY = this.y + Angles.trnsy(this.rotation - 90, weapon.x, weapon.y);
|
||||
|
||||
mount.targetRotation = Angles.angle(axisX, axisY, mount.aimX, mount.aimY) - rotation;
|
||||
mount.targetRotation = Angles.angle(axisX, axisY, mount.aimX, mount.aimY) - this.rotation;
|
||||
mount.rotation = Angles.moveToward(mount.rotation, mount.targetRotation, weapon.rotateSpeed * Time.delta);
|
||||
}else if(!weapon.rotate){
|
||||
mount.rotation = 0;
|
||||
@@ -118,19 +154,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc{
|
||||
mount.reload <= 0.0001f && //reload has to be 0
|
||||
Angles.within(weapon.rotate ? mount.rotation : this.rotation, mount.targetRotation, mount.weapon.shootCone) //has to be within the cone
|
||||
){
|
||||
|
||||
float rotation = this.rotation - 90;
|
||||
float weaponRotation = rotation + (weapon.rotate ? mount.rotation : 0);
|
||||
|
||||
//m a t h
|
||||
|
||||
float mountX = this.x + Angles.trnsx(rotation, weapon.x, weapon.y),
|
||||
mountY = this.y + Angles.trnsy(rotation, weapon.x, weapon.y);
|
||||
float shootX = mountX + Angles.trnsx(weaponRotation, weapon.shootX, weapon.shootY),
|
||||
shootY = mountY + Angles.trnsy(weaponRotation, weapon.shootX, weapon.shootY);
|
||||
float shootAngle = weapon.rotate ? weaponRotation + 90 : Angles.angle(shootX, shootY, mount.aimX, mount.aimY) + (this.rotation - angleTo(mount.aimX, mount.aimY));
|
||||
|
||||
shoot(weapon, shootX, shootY, mount.aimX, mount.aimY, shootAngle, Mathf.sign(weapon.x));
|
||||
shoot(mount, shootX, shootY, mount.aimX, mount.aimY, shootAngle, Mathf.sign(weapon.x));
|
||||
|
||||
mount.reload = weapon.reload;
|
||||
|
||||
@@ -140,7 +164,8 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc{
|
||||
}
|
||||
}
|
||||
|
||||
private void shoot(Weapon weapon, float x, float y, float aimX, float aimY, float rotation, int side){
|
||||
private void shoot(WeaponMount mount, float x, float y, float aimX, float aimY, float rotation, int side){
|
||||
Weapon weapon = mount.weapon;
|
||||
|
||||
float baseX = this.x, baseY = this.y;
|
||||
|
||||
@@ -150,27 +175,46 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc{
|
||||
float lifeScl = ammo.scaleVelocity ? Mathf.clamp(Mathf.dst(x, y, aimX, aimY) / ammo.range()) : 1f;
|
||||
|
||||
sequenceNum = 0;
|
||||
if(weapon.shotDelay > 0.01f){
|
||||
if(weapon.shotDelay + weapon.firstShotDelay > 0.01f){
|
||||
Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> {
|
||||
Time.run(sequenceNum * weapon.shotDelay, () -> bullet(weapon, x + this.x - baseX, y + this.y - baseY, f + Mathf.range(weapon.inaccuracy), lifeScl));
|
||||
Time.run(sequenceNum * weapon.shotDelay + weapon.firstShotDelay, () -> {
|
||||
if(!isAdded()) return;
|
||||
mount.bullet = bullet(weapon, x + this.x - baseX, y + this.y - baseY, f + Mathf.range(weapon.inaccuracy), lifeScl);
|
||||
});
|
||||
sequenceNum++;
|
||||
});
|
||||
}else{
|
||||
Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> bullet(weapon, x, y, f + Mathf.range(weapon.inaccuracy), lifeScl));
|
||||
Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> mount.bullet = bullet(weapon, x, y, f + Mathf.range(weapon.inaccuracy), lifeScl));
|
||||
}
|
||||
|
||||
if(this instanceof Velc){
|
||||
((Velc)this).vel().add(Tmp.v1.trns(rotation + 180f, ammo.recoil));
|
||||
}
|
||||
boolean parentize = ammo.keepVelocity;
|
||||
|
||||
Effect.shake(weapon.shake, weapon.shake, x, y);
|
||||
if(weapon.firstShotDelay > 0){
|
||||
Time.run(weapon.firstShotDelay, () -> {
|
||||
if(!isAdded()) return;
|
||||
|
||||
vel.add(Tmp.v1.trns(rotation + 180f, ammo.recoil));
|
||||
Effect.shake(weapon.shake, weapon.shake, x, y);
|
||||
mount.heat = 1f;
|
||||
});
|
||||
}else{
|
||||
vel.add(Tmp.v1.trns(rotation + 180f, ammo.recoil));
|
||||
Effect.shake(weapon.shake, weapon.shake, x, y);
|
||||
mount.heat = 1f;
|
||||
}
|
||||
|
||||
weapon.ejectEffect.at(x, y, rotation * side);
|
||||
ammo.shootEffect.at(x, y, rotation, parentize ? this : null);
|
||||
ammo.smokeEffect.at(x, y, rotation, parentize ? this : null);
|
||||
apply(weapon.shootStatus, weapon.shootStatusDuration);
|
||||
}
|
||||
|
||||
private void bullet(Weapon weapon, float x, float y, float angle, float lifescl){
|
||||
weapon.bullet.create(this, team(), x, y, angle, (1f - weapon.velocityRnd) + Mathf.random(weapon.velocityRnd), lifescl);
|
||||
private Bullet bullet(Weapon weapon, float x, float y, float angle, float lifescl){
|
||||
float xr = Mathf.range(weapon.xRand);
|
||||
|
||||
return weapon.bullet.create(this, team(),
|
||||
x + Angles.trnsx(angle, 0, xr),
|
||||
y + Angles.trnsy(angle, 0, xr),
|
||||
angle, (1f - weapon.velocityRnd) + Mathf.random(weapon.velocityRnd), lifescl);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ public class AIController implements UnitController{
|
||||
protected static final Vec2 vec = new Vec2();
|
||||
protected static final int timerTarget = 0;
|
||||
protected static final int timerTarget2 = 1;
|
||||
protected static final int timerTarget3 = 2;
|
||||
|
||||
protected Unit unit;
|
||||
protected Interval timer = new Interval(4);
|
||||
@@ -33,6 +34,7 @@ public class AIController implements UnitController{
|
||||
|
||||
@Override
|
||||
public void updateUnit(){
|
||||
updateVisuals();
|
||||
updateTargeting();
|
||||
updateMovement();
|
||||
}
|
||||
@@ -41,13 +43,23 @@ public class AIController implements UnitController{
|
||||
return unit.team.data().command;
|
||||
}
|
||||
|
||||
protected void updateVisuals(){
|
||||
|
||||
if(unit.isFlying()){
|
||||
unit.wobble();
|
||||
|
||||
if(unit.moving()){
|
||||
unit.lookAt(unit.vel.angle());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateMovement(){
|
||||
|
||||
}
|
||||
|
||||
protected void updateTargeting(){
|
||||
if(unit.hasWeapons()){
|
||||
|
||||
updateWeapons();
|
||||
}
|
||||
}
|
||||
@@ -140,7 +152,7 @@ public class AIController implements UnitController{
|
||||
vec.rotate((circleLength - vec.len()) / circleLength * 180f);
|
||||
}
|
||||
|
||||
vec.setLength(speed * Time.delta);
|
||||
vec.setLength(speed);
|
||||
|
||||
unit.moveAt(vec);
|
||||
}
|
||||
@@ -152,7 +164,7 @@ public class AIController implements UnitController{
|
||||
|
||||
float length = circleLength <= 0.001f ? 1f : Mathf.clamp((unit.dst(target) - circleLength) / 100f, -1f, 1f);
|
||||
|
||||
vec.setLength(unit.type().speed * Time.delta * length);
|
||||
vec.setLength(unit.type().speed * length);
|
||||
if(length < -0.5f){
|
||||
vec.rotate(180f);
|
||||
}else if(length < 0){
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package mindustry.entities.units;
|
||||
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
|
||||
public class WeaponMount{
|
||||
@@ -11,6 +13,8 @@ public class WeaponMount{
|
||||
public float rotation;
|
||||
/** destination rotation; do not modify! */
|
||||
public float targetRotation;
|
||||
/** current heat, 0 to 1*/
|
||||
public float heat;
|
||||
/** aiming position in world coordinates */
|
||||
public float aimX, aimY;
|
||||
/** whether to shoot right now */
|
||||
@@ -19,6 +23,8 @@ public class WeaponMount{
|
||||
public boolean rotate = false;
|
||||
/** extra state for alternating weapons */
|
||||
public boolean side;
|
||||
/** current bullet for continuous weapons */
|
||||
public @Nullable Bullet bullet;
|
||||
|
||||
public WeaponMount(Weapon weapon){
|
||||
this.weapon = weapon;
|
||||
|
||||
@@ -38,6 +38,8 @@ public class Rules{
|
||||
public boolean canGameOver = true;
|
||||
/** Whether reactors can explode and damage other blocks. */
|
||||
public boolean reactorExplosions = true;
|
||||
/** Whether schematics are allowed */
|
||||
public boolean schematicsAllowed = true;
|
||||
/** Whether friendly explosions can occur and set fire/damage other blocks. */
|
||||
public boolean damageExplosions = true;
|
||||
/** Whether fire is enabled. */
|
||||
|
||||
@@ -61,6 +61,9 @@ public class Saves{
|
||||
//automatically assign sector save slots
|
||||
for(SaveSlot slot : saves){
|
||||
if(slot.getSector() != null){
|
||||
if(slot.getSector().save != null){
|
||||
Log.warn("Sector @ has two corresponding saves: @ and @", slot.getSector(), slot.getSector().save.file, slot.file);
|
||||
}
|
||||
slot.getSector().save = slot;
|
||||
}
|
||||
}
|
||||
@@ -75,7 +78,6 @@ public class Saves{
|
||||
}
|
||||
|
||||
public void update(){
|
||||
SaveSlot current = this.current;
|
||||
|
||||
if(current != null && state.isGame()
|
||||
&& !(state.isPaused() && Core.scene.hasDialog())){
|
||||
@@ -90,14 +92,13 @@ public class Saves{
|
||||
if(time > Core.settings.getInt("saveinterval") * 60){
|
||||
saving = true;
|
||||
|
||||
Time.runTask(2f, () -> {
|
||||
try{
|
||||
current.save();
|
||||
}catch(Throwable e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
saving = false;
|
||||
});
|
||||
try{
|
||||
current.save();
|
||||
}catch(Throwable e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Time.runTask(3f, () -> saving = false);
|
||||
|
||||
time = 0;
|
||||
}
|
||||
@@ -128,6 +129,7 @@ public class Saves{
|
||||
sector.save.setName(sector.save.file.nameWithoutExtension());
|
||||
saves.add(sector.save);
|
||||
}
|
||||
sector.save.setAutosave(true);
|
||||
sector.save.save();
|
||||
lastSectorSave = sector.save;
|
||||
Core.settings.put("last-sector-save", sector.save.getName());
|
||||
|
||||
@@ -2,9 +2,7 @@ package mindustry.game;
|
||||
|
||||
import arc.files.*;
|
||||
import arc.struct.*;
|
||||
import arc.struct.IntIntMap.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import mindustry.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.mod.Mods.*;
|
||||
import mindustry.type.*;
|
||||
@@ -38,20 +36,16 @@ public class Schematic implements Publishable, Comparable<Schematic>{
|
||||
return tiles.sumf(s -> s.block.consumes.has(ConsumeType.power) ? s.block.consumes.getPower().usage : 0f);
|
||||
}
|
||||
|
||||
public Seq<ItemStack> requirements(){
|
||||
IntIntMap amounts = new IntIntMap();
|
||||
public ItemSeq requirements(){
|
||||
ItemSeq requirements = new ItemSeq();
|
||||
|
||||
tiles.each(t -> {
|
||||
for(ItemStack stack : t.block.requirements){
|
||||
amounts.increment(stack.item.id, stack.amount);
|
||||
requirements.add(stack.item, stack.amount);
|
||||
}
|
||||
});
|
||||
Seq<ItemStack> stacks = new Seq<>();
|
||||
for(Entry ent : amounts.entries()){
|
||||
stacks.add(new ItemStack(Vars.content.item(ent.key), ent.value));
|
||||
}
|
||||
stacks.sort();
|
||||
return stacks;
|
||||
|
||||
return requirements;
|
||||
}
|
||||
|
||||
public boolean hasCore(){
|
||||
|
||||
@@ -2,9 +2,10 @@ package mindustry.game;
|
||||
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import arc.util.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||
@@ -32,6 +33,10 @@ public class SectorInfo{
|
||||
public boolean hasCore = true;
|
||||
/** Sector that was launched from. */
|
||||
public @Nullable Sector origin;
|
||||
/** Launch destination. */
|
||||
public @Nullable Sector destination;
|
||||
/** Resources known to occur at this sector. */
|
||||
public Seq<UnlockableContent> resources = new Seq<>();
|
||||
/** Time spent at this sector. Do not use unless you know what you're doing. */
|
||||
public transient float internalTimeSpent;
|
||||
|
||||
@@ -40,6 +45,12 @@ public class SectorInfo{
|
||||
/** Core item storage to prevent spoofing. */
|
||||
private transient int[] lastCoreItems;
|
||||
|
||||
/** @return the real location items go when launched on this sector */
|
||||
public Sector getRealDestination(){
|
||||
//on multiplayer the destination is, by default, the first captured sector (basically random)
|
||||
return !net.client() || destination != null ? destination : state.rules.sector.planet.sectors.find(Sector::hasBase);
|
||||
}
|
||||
|
||||
/** Updates export statistics. */
|
||||
public void handleItemExport(ItemStack stack){
|
||||
handleItemExport(stack.item, stack.amount);
|
||||
@@ -84,12 +95,10 @@ public class SectorInfo{
|
||||
/** Update averages of various stats, updates some special sector logic.
|
||||
* Called every frame. */
|
||||
public void update(){
|
||||
internalTimeSpent += Time.delta;
|
||||
//updating in multiplayer as a client doesn't make sense
|
||||
if(net.client()) return;
|
||||
|
||||
//time spent exceeds turn duration!
|
||||
if(internalTimeSpent >= turnDuration && internalTimeSpent - Time.delta < turnDuration){
|
||||
universe.displayTimeEnd();
|
||||
}
|
||||
internalTimeSpent += Time.delta;
|
||||
|
||||
//create last stored core items
|
||||
if(lastCoreItems == null){
|
||||
|
||||
@@ -39,7 +39,7 @@ public class Stats{
|
||||
|
||||
//weigh used fractions
|
||||
float frac = 0f;
|
||||
Seq<Item> obtainable = Seq.select(zone.data.resources, i -> i instanceof Item).as();
|
||||
Seq<Item> obtainable = zone.save == null ? new Seq<>() : zone.save.meta.secinfo.resources.select(i -> i instanceof Item).as();
|
||||
for(Item item : obtainable){
|
||||
frac += Mathf.clamp((float)itemsDelivered.get(item, 0) / capacity) / (float)obtainable.size;
|
||||
}
|
||||
|
||||
@@ -14,12 +14,13 @@ import static mindustry.Vars.*;
|
||||
|
||||
/** Updates and handles state of the campaign universe. Has no relevance to other gamemodes. */
|
||||
public class Universe{
|
||||
private long seconds;
|
||||
private int seconds;
|
||||
private int netSeconds;
|
||||
private float secondCounter;
|
||||
private int turn;
|
||||
|
||||
private Schematic lastLoadout;
|
||||
private Seq<ItemStack> lastLaunchResources = new Seq<>();
|
||||
private ItemSeq lastLaunchResources = new ItemSeq();
|
||||
|
||||
public Universe(){
|
||||
load();
|
||||
@@ -55,23 +56,40 @@ public class Universe{
|
||||
|
||||
public void displayTimeEnd(){
|
||||
if(!headless){
|
||||
state.set(State.paused);
|
||||
//check if any sectors are under attack to display this
|
||||
Seq<Sector> attacked = state.getSector().planet.sectors.select(s -> s.hasWaves() && s.hasBase() && !s.isBeingPlayed() && s.getSecondsPassed() > 1);
|
||||
|
||||
ui.announce("Next turn incoming.");
|
||||
if(attacked.any()){
|
||||
state.set(State.paused);
|
||||
|
||||
//TODO localize
|
||||
String text = attacked.size > 1 ? attacked.size + " sectors attacked." : "Sector " + attacked.first().id + " under attack.";
|
||||
|
||||
ui.hudfrag.sectorText = text;
|
||||
ui.hudfrag.attackedSectors = attacked;
|
||||
ui.announce(text);
|
||||
}else{
|
||||
//autorun next turn
|
||||
universe.runTurn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Update planet rotations, global time and relevant state. */
|
||||
public void update(){
|
||||
secondCounter += Time.delta / 60f;
|
||||
|
||||
if(secondCounter >= 1){
|
||||
seconds += (int)secondCounter;
|
||||
secondCounter %= 1f;
|
||||
//only update time when not in multiplayer
|
||||
if(!net.client()){
|
||||
secondCounter += Time.delta / 60f;
|
||||
|
||||
//save every few seconds
|
||||
if(seconds % 10 == 1){
|
||||
save();
|
||||
if(secondCounter >= 1){
|
||||
seconds += (int)secondCounter;
|
||||
secondCounter %= 1f;
|
||||
|
||||
//save every few seconds
|
||||
if(seconds % 10 == 1){
|
||||
save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,14 +104,14 @@ public class Universe{
|
||||
}
|
||||
}
|
||||
|
||||
public Seq<ItemStack> getLaunchResources(){
|
||||
lastLaunchResources = Core.settings.getJson("launch-resources", Seq.class, ItemStack.class, Seq::new);
|
||||
public ItemSeq getLaunchResources(){
|
||||
lastLaunchResources = Core.settings.getJson("launch-resources-seq", ItemSeq.class, ItemSeq::new);
|
||||
return lastLaunchResources;
|
||||
}
|
||||
|
||||
public void updateLaunchResources(Seq<ItemStack> stacks){
|
||||
public void updateLaunchResources(ItemSeq stacks){
|
||||
this.lastLaunchResources = stacks;
|
||||
Core.settings.putJson("launch-resources", ItemStack.class, lastLaunchResources);
|
||||
Core.settings.putJson("launch-resources-seq", lastLaunchResources);
|
||||
}
|
||||
|
||||
/** Updates selected loadout for future deployment. */
|
||||
@@ -147,10 +165,23 @@ public class Universe{
|
||||
//if so, just delete the save for now. it's lost.
|
||||
//TODO don't delete it later maybe
|
||||
sector.save.delete();
|
||||
//clear recieved
|
||||
sector.setExtraItems(new ItemSeq());
|
||||
sector.save = null;
|
||||
}
|
||||
}
|
||||
|
||||
//export to another sector
|
||||
if(sector.save != null && sector.save.meta != null && sector.save.meta.secinfo != null && sector.save.meta.secinfo.destination != null){
|
||||
Sector to = sector.save.meta.secinfo.destination;
|
||||
if(to.save != null){
|
||||
ItemSeq items = to.getExtraItems();
|
||||
//calculated exported items to this sector
|
||||
sector.save.meta.secinfo.export.each((item, stat) -> items.add(item, (int)(stat.mean * newSecondsPassed)));
|
||||
to.setExtraItems(items);
|
||||
}
|
||||
}
|
||||
|
||||
//reset time spent to 0
|
||||
sector.setTimeSpent(0f);
|
||||
}
|
||||
@@ -178,25 +209,30 @@ public class Universe{
|
||||
return count;
|
||||
}
|
||||
|
||||
public float secondsMod(float mod, float scale){
|
||||
return (seconds / scale) % mod;
|
||||
public void updateNetSeconds(int value){
|
||||
netSeconds = value;
|
||||
}
|
||||
|
||||
public long seconds(){
|
||||
return seconds;
|
||||
public float secondsMod(float mod, float scale){
|
||||
return (seconds() / scale) % mod;
|
||||
}
|
||||
|
||||
public int seconds(){
|
||||
//use networked seconds when playing as client
|
||||
return net.client() ? netSeconds : seconds;
|
||||
}
|
||||
|
||||
public float secondsf(){
|
||||
return seconds + secondCounter;
|
||||
return seconds() + secondCounter;
|
||||
}
|
||||
|
||||
private void save(){
|
||||
Core.settings.put("utime", seconds);
|
||||
Core.settings.put("utimei", seconds);
|
||||
Core.settings.put("turn", turn);
|
||||
}
|
||||
|
||||
private void load(){
|
||||
seconds = Core.settings.getLong("utime");
|
||||
seconds = Core.settings.getInt("utimei");
|
||||
turn = Core.settings.getInt("turn");
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,17 @@ public enum CacheLayer{
|
||||
endShader(Shaders.water);
|
||||
}
|
||||
},
|
||||
mud{
|
||||
@Override
|
||||
public void begin(){
|
||||
beginShader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void end(){
|
||||
endShader(Shaders.mud);
|
||||
}
|
||||
},
|
||||
tar{
|
||||
@Override
|
||||
public void begin(){
|
||||
@@ -41,7 +52,7 @@ public enum CacheLayer{
|
||||
}
|
||||
},
|
||||
normal(5),
|
||||
walls;
|
||||
walls(3);
|
||||
|
||||
public static final CacheLayer[] all = values();
|
||||
/** Capacity multiplier. */
|
||||
|
||||
@@ -150,15 +150,14 @@ public class Drawf{
|
||||
}
|
||||
|
||||
public static void laser(Team team, TextureRegion line, TextureRegion edge, float x, float y, float x2, float y2, float rotation, float scale){
|
||||
Tmp.v1.trns(rotation, 8f * scale * Draw.scl);
|
||||
float scl = 8f * scale * Draw.scl;
|
||||
float vx = Mathf.cosDeg(rotation) * scl, vy = Mathf.sinDeg(rotation) * scl;
|
||||
|
||||
Draw.rect(edge, x, y, edge.getWidth() * scale * Draw.scl, edge.getHeight() * scale * Draw.scl, rotation + 180);
|
||||
Draw.rect(edge, x2, y2, edge.getWidth() * scale * Draw.scl, edge.getHeight() * scale * Draw.scl, rotation);
|
||||
Draw.rect(edge, x, y, edge.width * scale * Draw.scl, edge.height * scale * Draw.scl, rotation + 180);
|
||||
Draw.rect(edge, x2, y2, edge.width * scale * Draw.scl, edge.height * scale * Draw.scl, rotation);
|
||||
|
||||
Lines.stroke(12f * scale);
|
||||
Lines.precise(true);
|
||||
Lines.line(line, x + Tmp.v1.x, y + Tmp.v1.y, x2 - Tmp.v1.x, y2 - Tmp.v1.y, false, 0f);
|
||||
Lines.precise(false);
|
||||
Lines.line(line, x + vx, y + vy, x2 - vx, y2 - vy, false);
|
||||
Lines.stroke(1f);
|
||||
|
||||
light(team, x, y, x2, y2);
|
||||
@@ -173,6 +172,20 @@ public class Drawf{
|
||||
construct(t, content.icon(Cicon.full), rotation, progress, speed, time);
|
||||
}
|
||||
|
||||
public static void construct(float x, float y, TextureRegion region, float rotation, float progress, float speed, float time){
|
||||
Shaders.build.region = region;
|
||||
Shaders.build.progress = progress;
|
||||
Shaders.build.color.set(Pal.accent);
|
||||
Shaders.build.color.a = speed;
|
||||
Shaders.build.time = -time / 20f;
|
||||
|
||||
Draw.shader(Shaders.build);
|
||||
Draw.rect(region, x, y, rotation);
|
||||
Draw.shader();
|
||||
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
public static void construct(Building t, TextureRegion region, float rotation, float progress, float speed, float time){
|
||||
Shaders.build.region = region;
|
||||
Shaders.build.progress = progress;
|
||||
|
||||
@@ -210,8 +210,8 @@ public class FloorRenderer implements Disposable{
|
||||
tile.block().drawBase(tile);
|
||||
}else if(floor.cacheLayer == layer && (world.isAccessible(tile.x, tile.y) || tile.block().cacheLayer != CacheLayer.walls || !tile.block().fillsTile)){
|
||||
floor.drawBase(tile);
|
||||
}else if(floor.cacheLayer.ordinal() < layer.ordinal() && layer != CacheLayer.walls){
|
||||
floor.drawNonLayer(tile);
|
||||
}else if(floor.cacheLayer != layer && layer != CacheLayer.walls){
|
||||
floor.drawNonLayer(tile, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -228,7 +228,7 @@ public class FloorRenderer implements Disposable{
|
||||
int chunksx = Mathf.ceil((float)(world.width()) / chunksize),
|
||||
chunksy = Mathf.ceil((float)(world.height()) / chunksize);
|
||||
cache = new Chunk[chunksx][chunksy];
|
||||
cbatch = new MultiCacheBatch(chunksize * chunksize * 6);
|
||||
cbatch = new MultiCacheBatch(chunksize * chunksize * 8);
|
||||
|
||||
Time.mark();
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import arc.util.*;
|
||||
public class IndexedRenderer implements Disposable{
|
||||
private static final int vsize = 5;
|
||||
|
||||
private Shader program = new Shader(
|
||||
private final Shader program = new Shader(
|
||||
"attribute vec4 a_position;\n" +
|
||||
"attribute vec4 a_color;\n" +
|
||||
"attribute vec2 a_texCoord0;\n" +
|
||||
@@ -68,10 +68,10 @@ public class IndexedRenderer implements Disposable{
|
||||
public void draw(int index, TextureRegion region, float x, float y, float w, float h){
|
||||
float fx2 = x + w;
|
||||
float fy2 = y + h;
|
||||
float u = region.getU();
|
||||
float v = region.getV2();
|
||||
float u2 = region.getU2();
|
||||
float v2 = region.getV();
|
||||
float u = region.u;
|
||||
float v = region.v2;
|
||||
float u2 = region.u2;
|
||||
float v2 = region.v;
|
||||
|
||||
float[] vertices = tmpVerts;
|
||||
float color = this.color;
|
||||
@@ -96,32 +96,32 @@ public class IndexedRenderer implements Disposable{
|
||||
vertices[idx++] = v2;
|
||||
|
||||
//tri2
|
||||
vertices[idx++] = x;
|
||||
vertices[idx++] = y;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u;
|
||||
vertices[idx++] = v;
|
||||
|
||||
vertices[idx++] = fx2;
|
||||
vertices[idx++] = y;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u2;
|
||||
vertices[idx++] = v;
|
||||
|
||||
vertices[idx++] = fx2;
|
||||
vertices[idx++] = fy2;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u2;
|
||||
vertices[idx++] = v2;
|
||||
|
||||
vertices[idx++] = fx2;
|
||||
vertices[idx++] = y;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u2;
|
||||
vertices[idx++] = v;
|
||||
|
||||
vertices[idx++] = x;
|
||||
vertices[idx++] = y;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u;
|
||||
vertices[idx++] = v;
|
||||
|
||||
mesh.updateVertices(index * vsize * 6, vertices);
|
||||
}
|
||||
|
||||
public void draw(int index, TextureRegion region, float x, float y, float w, float h, float rotation){
|
||||
float u = region.getU();
|
||||
float v = region.getV2();
|
||||
float u2 = region.getU2();
|
||||
float v2 = region.getV();
|
||||
float u = region.u;
|
||||
float v = region.v2;
|
||||
float u2 = region.u2;
|
||||
float v2 = region.v;
|
||||
|
||||
float originX = w / 2, originY = h / 2;
|
||||
|
||||
@@ -155,6 +155,19 @@ public class IndexedRenderer implements Disposable{
|
||||
vertices[idx++] = u;
|
||||
vertices[idx++] = v;
|
||||
|
||||
vertices[idx++] = x2;
|
||||
vertices[idx++] = y2;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u;
|
||||
vertices[idx++] = v2;
|
||||
|
||||
vertices[idx++] = x3;
|
||||
vertices[idx++] = y3;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u2;
|
||||
vertices[idx++] = v2;
|
||||
|
||||
//tri2
|
||||
vertices[idx++] = x3;
|
||||
vertices[idx++] = y3;
|
||||
vertices[idx++] = color;
|
||||
@@ -164,28 +177,15 @@ public class IndexedRenderer implements Disposable{
|
||||
vertices[idx++] = x4;
|
||||
vertices[idx++] = y4;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u;
|
||||
vertices[idx++] = v2;
|
||||
vertices[idx++] = u2;
|
||||
vertices[idx++] = v;
|
||||
|
||||
//tri2
|
||||
vertices[idx++] = x1;
|
||||
vertices[idx++] = y1;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u;
|
||||
vertices[idx++] = v;
|
||||
|
||||
vertices[idx++] = x2;
|
||||
vertices[idx++] = y2;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u2;
|
||||
vertices[idx++] = v;
|
||||
|
||||
vertices[idx++] = x3;
|
||||
vertices[idx++] = y3;
|
||||
vertices[idx++] = color;
|
||||
vertices[idx++] = u2;
|
||||
vertices[idx++] = v2;
|
||||
|
||||
mesh.updateVertices(index * vsize * 6, vertices);
|
||||
}
|
||||
|
||||
|
||||
@@ -58,10 +58,10 @@ public class LightRenderer{
|
||||
TextureRegion ledge = Core.atlas.find("circle-end"), lmid = Core.atlas.find("circle-mid");
|
||||
|
||||
float color = Draw.getColor().toFloatBits();
|
||||
float u = lmid.getU();
|
||||
float v = lmid.getV2();
|
||||
float u2 = lmid.getU2();
|
||||
float v2 = lmid.getV();
|
||||
float u = lmid.u;
|
||||
float v = lmid.v2;
|
||||
float u2 = lmid.u2;
|
||||
float v2 = lmid.v;
|
||||
|
||||
|
||||
Vec2 v1 = Tmp.v1.trnsExact(rot + 90f, stroke);
|
||||
@@ -98,15 +98,15 @@ public class LightRenderer{
|
||||
vertices[22] = v;
|
||||
vertices[23] = 0;
|
||||
|
||||
Draw.vert(ledge.getTexture(), vertices, 0, vertices.length);
|
||||
Draw.vert(ledge.texture, vertices, 0, vertices.length);
|
||||
|
||||
|
||||
Vec2 v3 = Tmp.v2.trnsExact(rot, stroke);
|
||||
|
||||
u = ledge.getU();
|
||||
v = ledge.getV2();
|
||||
u2 = ledge.getU2();
|
||||
v2 = ledge.getV();
|
||||
u = ledge.u;
|
||||
v = ledge.v2;
|
||||
u2 = ledge.u2;
|
||||
v2 = ledge.v;
|
||||
|
||||
vertices[0] = lx4;
|
||||
vertices[1] = ly4;
|
||||
@@ -136,7 +136,7 @@ public class LightRenderer{
|
||||
vertices[22] = v;
|
||||
vertices[23] = 0;
|
||||
|
||||
Draw.vert(ledge.getTexture(), vertices, 0, vertices.length);
|
||||
Draw.vert(ledge.texture, vertices, 0, vertices.length);
|
||||
|
||||
vertices[0] = lx2;
|
||||
vertices[1] = ly2;
|
||||
@@ -166,7 +166,7 @@ public class LightRenderer{
|
||||
vertices[22] = v;
|
||||
vertices[23] = 0;
|
||||
|
||||
Draw.vert(ledge.getTexture(), vertices, 0, vertices.length);
|
||||
Draw.vert(ledge.texture, vertices, 0, vertices.length);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,6 @@ public class LoadRenderer implements Disposable{
|
||||
|
||||
float w = Core.graphics.getWidth(), h = Core.graphics.getHeight(), s = Scl.scl();
|
||||
//s = 2f;
|
||||
Lines.precise(true);
|
||||
|
||||
Draw.proj().setOrtho(0, 0, Core.graphics.getWidth(), Core.graphics.getHeight());
|
||||
|
||||
@@ -467,7 +466,6 @@ public class LoadRenderer implements Disposable{
|
||||
font.draw(red + "[[[[ " + key + " ]]\n"+orange+"<" + Version.modifier + " " + (Version.build == 0 ? " [init]" : Version.build == -1 ? " custom" : " " + Version.build) + ">", w/2f, h/2f + 110*s, Align.center);
|
||||
}
|
||||
|
||||
Lines.precise(false);
|
||||
Draw.flush();
|
||||
|
||||
fx.end();
|
||||
|
||||
@@ -243,7 +243,7 @@ public class MenuRenderer implements Disposable{
|
||||
|
||||
TextureRegion icon = flyerType.icon(Cicon.full);
|
||||
|
||||
float size = Math.max(icon.getWidth(), icon.getHeight()) * Draw.scl * 1.6f;
|
||||
float size = Math.max(icon.width, icon.height) * Draw.scl * 1.6f;
|
||||
|
||||
flyers((x, y) -> {
|
||||
Draw.rect(flyerType.region, x - 12f, y - 13f, flyerRot - 90);
|
||||
|
||||
@@ -123,7 +123,7 @@ public class MinimapRenderer implements Disposable{
|
||||
dx = Mathf.clamp(dx, sz, world.width() - sz);
|
||||
dy = Mathf.clamp(dy, sz, world.height() - sz);
|
||||
float invTexWidth = 1f / texture.getWidth();
|
||||
float invTexHeight = 1f / texture.getHeight();
|
||||
float invTexHeight = 1f / texture.height;
|
||||
float x = dx - sz, y = world.height() - dy - sz, width = sz * 2, height = sz * 2;
|
||||
region.set(x * invTexWidth, y * invTexHeight, (x + width) * invTexWidth, (y + height) * invTexHeight);
|
||||
return region;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user