Merge
This commit is contained in:
@@ -17,7 +17,7 @@ public class Mindustry extends ApplicationCore{
|
||||
public void setup(){
|
||||
Time.setDeltaProvider(() -> {
|
||||
float result = Core.graphics.getDeltaTime() * 60f;
|
||||
return Float.isNaN(result) || Float.isInfinite(result) ? 1f : Math.min(result, 60f / 10f);
|
||||
return (Float.isNaN(result) || Float.isInfinite(result)) ? 1f : Math.min(result, 60f / 10f);
|
||||
});
|
||||
|
||||
Time.mark();
|
||||
@@ -27,6 +27,7 @@ public class Mindustry extends ApplicationCore{
|
||||
Log.setUseColors(false);
|
||||
BundleLoader.load();
|
||||
content.load();
|
||||
content.loadColors();
|
||||
|
||||
add(logic = new Logic());
|
||||
add(world = new World());
|
||||
@@ -47,18 +48,18 @@ public class Mindustry extends ApplicationCore{
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
long lastFrameTime = Time.millis();
|
||||
long lastFrameTime = Time.nanos();
|
||||
|
||||
super.update();
|
||||
|
||||
int fpsCap = Core.settings.getInt("fpscap", 125);
|
||||
|
||||
if(fpsCap <= 120){
|
||||
long target = 1000/fpsCap;
|
||||
long elapsed = Time.timeSinceMillis(lastFrameTime);
|
||||
long target = (1000 * 1000000)/fpsCap; //target in nanos
|
||||
long elapsed = Time.timeSinceNanos(lastFrameTime);
|
||||
if(elapsed < target){
|
||||
try{
|
||||
Thread.sleep(target - elapsed);
|
||||
Thread.sleep((target - elapsed) / 1000000, (int)((target - elapsed) % 1000000));
|
||||
}catch(InterruptedException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -2,21 +2,21 @@ package io.anuke.mindustry;
|
||||
|
||||
import io.anuke.arc.Application.ApplicationType;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.entities.Entities;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.entities.impl.EffectEntity;
|
||||
import io.anuke.arc.entities.trait.DrawTrait;
|
||||
import io.anuke.arc.files.FileHandle;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.util.Structs;
|
||||
import io.anuke.mindustry.core.*;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.Entities;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
||||
import io.anuke.mindustry.entities.effect.Fire;
|
||||
import io.anuke.mindustry.entities.effect.Puddle;
|
||||
import io.anuke.mindustry.entities.impl.EffectEntity;
|
||||
import io.anuke.mindustry.entities.traits.DrawTrait;
|
||||
import io.anuke.mindustry.entities.traits.SyncTrait;
|
||||
import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.entities.type.BaseUnit;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.game.GlobalData;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.game.Version;
|
||||
@@ -24,11 +24,14 @@ import io.anuke.mindustry.gen.Serialization;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.world.blocks.defense.ForceProjector.ShieldEntity;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class Vars{
|
||||
/**global charset*/
|
||||
public static final Charset charset = Charset.forName("UTF-8");
|
||||
/**main application name, capitalized*/
|
||||
public static final String appName = "Mindustry";
|
||||
/**URL for discord invite.*/
|
||||
@@ -45,12 +48,22 @@ public class Vars{
|
||||
public static final Team defaultTeam = Team.blue;
|
||||
/**team of the enemy in waves/sectors*/
|
||||
public static final Team waveTeam = Team.red;
|
||||
/**how many times longer a boss wave takes*/
|
||||
public static final float bossWaveMultiplier = 3f;
|
||||
/**how many times longer a launch wave takes*/
|
||||
public static final float launchWaveMultiplier = 2f;
|
||||
/**max chat message length*/
|
||||
public static final int maxTextLength = 150;
|
||||
/**max player name length in bytes*/
|
||||
public static final int maxNameLength = 40;
|
||||
/**displayed item size when ingame, TODO remove.*/
|
||||
public static final float itemSize = 5f;
|
||||
/**extra padding around the world; units outside this bound will begin to self-destruct.*/
|
||||
public static final float worldBounds = 100f;
|
||||
/**units outside of this bound will simply die instantly*/
|
||||
public static final float finalWorldBounds = worldBounds + 500;
|
||||
/**ticks spent out of bound until self destruct.*/
|
||||
public static final float boundsCountdown = 60*7;
|
||||
/**size of tiles in units*/
|
||||
public static final int tilesize = 8;
|
||||
/**all choosable player colors in join/host dialog*/
|
||||
@@ -146,6 +159,9 @@ public class Vars{
|
||||
Version.init();
|
||||
|
||||
content = new ContentLoader();
|
||||
if(!headless){
|
||||
content.setVerbose();
|
||||
}
|
||||
|
||||
playerGroup = Entities.addGroup(Player.class).enableMapping();
|
||||
tileGroup = Entities.addGroup(TileEntity.class, false);
|
||||
|
||||
@@ -6,7 +6,7 @@ import io.anuke.arc.function.Predicate;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.game.EventType.TileChangeEvent;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
@@ -17,8 +17,6 @@ import io.anuke.mindustry.world.meta.BlockFlag;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
//TODO consider using quadtrees for finding specific types of blocks within an area
|
||||
|
||||
/**Class used for indexing special target blocks for AI.*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class BlockIndexer{
|
||||
@@ -28,7 +26,7 @@ public class BlockIndexer{
|
||||
private final static int structQuadrantSize = 12;
|
||||
|
||||
/**Set of all ores that are being scanned.*/
|
||||
private final ObjectSet<Item> scanOres = new ObjectSet<Item>(){{addAll(Item.getAllOres());}};
|
||||
private final ObjectSet<Item> scanOres = ObjectSet.with(Item.getAllOres().toArray(Item.class));
|
||||
private final ObjectSet<Item> itemSet = new ObjectSet<>();
|
||||
/**Stores all ore quadtrants on the map.*/
|
||||
private ObjectMap<Item, ObjectSet<Tile>> ores;
|
||||
@@ -215,7 +213,7 @@ public class BlockIndexer{
|
||||
}
|
||||
|
||||
private void process(Tile tile){
|
||||
if(tile.block().flags != null &&
|
||||
if(tile.block().flags.size() > 0 &&
|
||||
tile.getTeam() != Team.none){
|
||||
ObjectSet<Tile>[] map = getFlagged(tile.getTeam());
|
||||
|
||||
@@ -282,7 +280,7 @@ public class BlockIndexer{
|
||||
outer:
|
||||
for(int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++){
|
||||
for(int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++){
|
||||
Tile result = world.tile(x, y);
|
||||
Tile result = world.tile(x, y).target();
|
||||
//when a targetable block is found, mark this quadrant as occupied and stop searching
|
||||
if(result.entity != null && result.getTeam() == data.team){
|
||||
structQuadrants[data.team.ordinal()].set(index);
|
||||
|
||||
@@ -2,7 +2,7 @@ package io.anuke.mindustry.ai;
|
||||
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.collection.IntArray;
|
||||
import io.anuke.arc.collection.Queue;
|
||||
import io.anuke.arc.collection.IntQueue;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.arc.math.geom.Point2;
|
||||
import io.anuke.arc.util.Structs;
|
||||
@@ -12,6 +12,7 @@ import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.game.Teams.TeamData;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.world.Pos;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.meta.BlockFlag;
|
||||
|
||||
@@ -19,7 +20,7 @@ import static io.anuke.mindustry.Vars.state;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class Pathfinder{
|
||||
private long maxUpdate = Time.millisToNanos(4);
|
||||
private static final long maxUpdate = Time.millisToNanos(4);
|
||||
private PathData[] paths;
|
||||
private IntArray blocked = new IntArray();
|
||||
|
||||
@@ -39,10 +40,6 @@ public class Pathfinder{
|
||||
});
|
||||
}
|
||||
|
||||
public void activateTeamPath(Team team){
|
||||
createFor(team);
|
||||
}
|
||||
|
||||
public void update(){
|
||||
if(Net.client() || paths == null) return;
|
||||
|
||||
@@ -110,7 +107,7 @@ public class Pathfinder{
|
||||
for(Tile other : world.indexer.getEnemy(team, BlockFlag.target)){
|
||||
path.weights[other.x][other.y] = 0;
|
||||
path.searches[other.x][other.y] = (short)path.search;
|
||||
path.frontier.addFirst(other);
|
||||
path.frontier.addFirst(other.pos());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,9 +125,9 @@ public class Pathfinder{
|
||||
for(int y = 0; y < world.height(); y++){
|
||||
Tile tile = world.tile(x, y);
|
||||
|
||||
if(tile.block().flags != null && state.teams.areEnemies(tile.getTeam(), team)
|
||||
if(state.teams.areEnemies(tile.getTeam(), team)
|
||||
&& tile.block().flags.contains(BlockFlag.target)){
|
||||
path.frontier.addFirst(tile);
|
||||
path.frontier.addFirst(tile.pos());
|
||||
path.weights[x][y] = 0;
|
||||
path.searches[x][y] = (short)path.search;
|
||||
}else{
|
||||
@@ -145,12 +142,19 @@ public class Pathfinder{
|
||||
private void updateFrontier(Team team, long nsToRun){
|
||||
PathData path = paths[team.ordinal()];
|
||||
|
||||
long start = Time.nanoTime();
|
||||
long start = Time.nanos();
|
||||
|
||||
while(path.frontier.size > 0 && (nsToRun < 0 || Time.timeSinceNanos(start) <= nsToRun)){
|
||||
Tile tile = path.frontier.removeLast();
|
||||
Tile tile = world.tile(path.frontier.removeLast());
|
||||
if(tile == null || path.weights == null) return; //something went horribly wrong, bail
|
||||
float cost = path.weights[tile.x][tile.y];
|
||||
|
||||
//pathfinding overflowed for some reason, time to bail. the next block update will handle this, hopefully
|
||||
if(path.frontier.size >= world.width() * world.height()){
|
||||
path.frontier.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
if(cost < Float.MAX_VALUE){
|
||||
for(Point2 point : Geometry.d4){
|
||||
|
||||
@@ -159,7 +163,8 @@ public class Pathfinder{
|
||||
|
||||
if(other != null && (path.weights[dx][dy] > cost + other.cost || path.searches[dx][dy] < path.search)
|
||||
&& passable(other, team)){
|
||||
path.frontier.addFirst(world.tile(dx, dy));
|
||||
if(other.cost < 0) throw new IllegalArgumentException("Tile cost cannot be negative! " + other);
|
||||
path.frontier.addFirst(Pos.get(dx, dy));
|
||||
path.weights[dx][dy] = cost + other.cost;
|
||||
path.searches[dx][dy] = (short)path.search;
|
||||
}
|
||||
@@ -189,6 +194,6 @@ public class Pathfinder{
|
||||
short[][] searches;
|
||||
int search = 0;
|
||||
long lastSearchTime;
|
||||
Queue<Tile> frontier = new Queue<>();
|
||||
IntQueue frontier = new IntQueue();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,25 +2,61 @@ package io.anuke.mindustry.ai;
|
||||
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.IntArray;
|
||||
import io.anuke.arc.math.Angles;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.entities.units.Squad;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.Damage;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.type.BaseUnit;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.SpawnGroup;
|
||||
import io.anuke.mindustry.world.Pos;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class WaveSpawner{
|
||||
private static final float shockwaveBase = 380f, shockwaveRand = 50f, maxShockwaveDst = shockwaveBase + shockwaveRand;
|
||||
private Array<SpawnGroup> groups;
|
||||
private Array<FlyerSpawn> flySpawns = new Array<>();
|
||||
private Array<GroundSpawn> groundSpawns = new Array<>();
|
||||
private IntArray loadedSpawns = new IntArray();
|
||||
|
||||
public WaveSpawner(){
|
||||
Events.on(WorldLoadEvent.class, e -> reset());
|
||||
}
|
||||
|
||||
public void write(DataOutput stream) throws IOException{
|
||||
stream.writeInt(groundSpawns.size);
|
||||
for(GroundSpawn spawn : groundSpawns){
|
||||
stream.writeInt(Pos.get(spawn.x, spawn.y));
|
||||
}
|
||||
}
|
||||
|
||||
public void read(DataInput stream) throws IOException{
|
||||
flySpawns.clear();
|
||||
groundSpawns.clear();
|
||||
loadedSpawns.clear();
|
||||
|
||||
int amount = stream.readInt();
|
||||
|
||||
for(int i = 0; i < amount; i++){
|
||||
loadedSpawns.add(stream.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
/**@return true if the player is near a ground spawn point.*/
|
||||
public boolean playerNear(){
|
||||
return groundSpawns.count(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, players[0].x, players[0].y) < maxShockwaveDst) > 0;
|
||||
}
|
||||
|
||||
public void spawnEnemies(){
|
||||
|
||||
for(SpawnGroup group : groups){
|
||||
@@ -31,7 +67,6 @@ public class WaveSpawner{
|
||||
|
||||
if(group.type.isFlying){
|
||||
for(FlyerSpawn spawn : flySpawns){
|
||||
Squad squad = new Squad();
|
||||
float margin = 40f; //how far away from the edge flying units spawn
|
||||
float trns = (world.width() + world.height()) * tilesize;
|
||||
spawnX = Mathf.clamp(world.width() * tilesize / 2f + Angles.trnsx(spawn.angle, trns), -margin, world.width() * tilesize + margin);
|
||||
@@ -40,32 +75,34 @@ public class WaveSpawner{
|
||||
|
||||
for(int i = 0; i < spawned; i++){
|
||||
BaseUnit unit = group.createUnit(waveTeam);
|
||||
unit.setWave();
|
||||
unit.setSquad(squad);
|
||||
unit.set(spawnX + Mathf.range(spread), spawnY + Mathf.range(spread));
|
||||
unit.add();
|
||||
}
|
||||
}
|
||||
}else{
|
||||
for(GroundSpawn spawn : groundSpawns){
|
||||
Squad squad = new Squad();
|
||||
spawnX = spawn.x * tilesize;
|
||||
spawnY = spawn.y * tilesize;
|
||||
spread = tilesize;
|
||||
spread = tilesize*2;
|
||||
|
||||
for(int i = 0; i < spawned; i++){
|
||||
Tmp.v1.rnd(spread);
|
||||
|
||||
BaseUnit unit = group.createUnit(waveTeam);
|
||||
unit.setWave();
|
||||
unit.setSquad(squad);
|
||||
unit.set(spawnX + Mathf.range(spread), spawnY + Mathf.range(spread));
|
||||
unit.add();
|
||||
unit.set(spawnX + Tmp.v1.x, spawnY + Tmp.v1.y);
|
||||
|
||||
Time.run(i*5, () -> shockwave(unit));
|
||||
}
|
||||
Time.run(20f, () -> Effects.effect(Fx.spawnShockwave, spawn.x * tilesize, spawn.y * tilesize));
|
||||
//would be interesting to see player structures survive this without hacks
|
||||
Time.run(40f, () -> Damage.damage(waveTeam, spawn.x * tilesize, spawn.y * tilesize, shockwaveBase + Mathf.random(shockwaveRand), 99999999f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void reset(){
|
||||
|
||||
flySpawns.clear();
|
||||
groundSpawns.clear();
|
||||
groups = state.rules.spawns;
|
||||
@@ -73,17 +110,39 @@ public class WaveSpawner{
|
||||
for(int x = 0; x < world.width(); x++){
|
||||
for(int y = 0; y < world.height(); y++){
|
||||
if(world.tile(x, y).block() == Blocks.spawn){
|
||||
GroundSpawn spawn = new GroundSpawn();
|
||||
spawn.x = x;
|
||||
spawn.y = y;
|
||||
groundSpawns.add(spawn);
|
||||
addSpawns(x, y);
|
||||
|
||||
FlyerSpawn fspawn = new FlyerSpawn();
|
||||
fspawn.angle = Angles.angle(world.width()/2f, world.height()/2f, x, y);
|
||||
flySpawns.add(fspawn);
|
||||
//hide spawnpoints, they have served their purpose
|
||||
world.tile(x, y).setBlock(Blocks.air);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < loadedSpawns.size; i++){
|
||||
int pos = loadedSpawns.get(i);
|
||||
addSpawns(Pos.x(pos), Pos.y(pos));
|
||||
}
|
||||
|
||||
loadedSpawns.clear();
|
||||
}
|
||||
|
||||
private void addSpawns(int x, int y){
|
||||
GroundSpawn spawn = new GroundSpawn();
|
||||
spawn.x = x;
|
||||
spawn.y = y;
|
||||
groundSpawns.add(spawn);
|
||||
|
||||
FlyerSpawn fspawn = new FlyerSpawn();
|
||||
fspawn.angle = Angles.angle(world.width()/2f, world.height()/2f, x, y);
|
||||
flySpawns.add(fspawn);
|
||||
}
|
||||
|
||||
private void shockwave(BaseUnit unit){
|
||||
Effects.effect(Fx.unitSpawn, unit.x, unit.y, 0f, unit);
|
||||
Time.run(30f, () -> {
|
||||
unit.add();
|
||||
Effects.effect(Fx.spawn, unit);
|
||||
});
|
||||
}
|
||||
|
||||
private class FlyerSpawn{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
package io.anuke.mindustry.content;
|
||||
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.CapStyle;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
@@ -10,12 +10,13 @@ import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.mindustry.entities.Damage;
|
||||
import io.anuke.mindustry.entities.type.Unit;
|
||||
import io.anuke.mindustry.entities.bullet.*;
|
||||
import io.anuke.mindustry.entities.effect.Fire;
|
||||
import io.anuke.mindustry.entities.effect.Lightning;
|
||||
import io.anuke.mindustry.entities.effect.Puddle;
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.graphics.Shapes;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.BuildBlock;
|
||||
@@ -32,7 +33,7 @@ public class Bullets implements ContentList{
|
||||
flakPlastic, flakExplosive, flakSurge,
|
||||
|
||||
//missiles
|
||||
missileExplosive, missileIncendiary, missileSurge, missileJavelin, missileSwarm,
|
||||
missileExplosive, missileIncendiary, missileSurge, missileJavelin, missileSwarm, missileRevenant,
|
||||
|
||||
//standard
|
||||
standardCopper, standardDense, standardThorium, standardHoming, standardIncendiary, standardMechSmall,
|
||||
@@ -45,10 +46,10 @@ public class Bullets implements ContentList{
|
||||
waterShot, cryoShot, slagShot, oilShot,
|
||||
|
||||
//environment, misc.
|
||||
fireball, basicFlame, fuseShot, driverBolt, healBullet, frag,
|
||||
fireball, basicFlame, fuseShot, driverBolt, healBullet, frag, eruptorShot,
|
||||
|
||||
//bombs
|
||||
bombExplosive, bombIncendiary, bombOil;
|
||||
bombExplosive, bombIncendiary, bombOil, explode;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
@@ -63,28 +64,28 @@ public class Bullets implements ContentList{
|
||||
splashDamage = 33f;
|
||||
}};
|
||||
|
||||
artilleryPlasticFrag = new BasicBulletType(2.5f, 6, "bullet"){{
|
||||
artilleryPlasticFrag = new BasicBulletType(2.5f, 7, "bullet"){{
|
||||
bulletWidth = 10f;
|
||||
bulletHeight = 12f;
|
||||
bulletShrink = 1f;
|
||||
lifetime = 15f;
|
||||
backColor = Palette.plastaniumBack;
|
||||
frontColor = Palette.plastaniumFront;
|
||||
backColor = Pal.plastaniumBack;
|
||||
frontColor = Pal.plastaniumFront;
|
||||
despawnEffect = Fx.none;
|
||||
}};
|
||||
|
||||
arilleryPlastic = new ArtilleryBulletType(3.3f, 0, "shell"){{
|
||||
arilleryPlastic = new ArtilleryBulletType(3.4f, 0, "shell"){{
|
||||
hitEffect = Fx.plasticExplosion;
|
||||
knockback = 1f;
|
||||
lifetime = 55f;
|
||||
bulletWidth = bulletHeight = 13f;
|
||||
collidesTiles = false;
|
||||
splashDamageRadius = 35f;
|
||||
splashDamage = 35f;
|
||||
splashDamage = 45f;
|
||||
fragBullet = artilleryPlasticFrag;
|
||||
fragBullets = 9;
|
||||
backColor = Palette.plastaniumBack;
|
||||
frontColor = Palette.plastaniumFront;
|
||||
fragBullets = 10;
|
||||
backColor = Pal.plastaniumBack;
|
||||
frontColor = Pal.plastaniumFront;
|
||||
}};
|
||||
|
||||
artilleryHoming = new ArtilleryBulletType(3f, 0, "shell"){{
|
||||
@@ -109,8 +110,8 @@ public class Bullets implements ContentList{
|
||||
splashDamage = 30f;
|
||||
incendAmount = 4;
|
||||
incendSpread = 11f;
|
||||
frontColor = Palette.lightishOrange;
|
||||
backColor = Palette.lightOrange;
|
||||
frontColor = Pal.lightishOrange;
|
||||
backColor = Pal.lightOrange;
|
||||
trailEffect = Fx.incendTrail;
|
||||
}};
|
||||
|
||||
@@ -122,8 +123,8 @@ public class Bullets implements ContentList{
|
||||
collidesTiles = false;
|
||||
splashDamageRadius = 45f;
|
||||
splashDamage = 50f;
|
||||
backColor = Palette.missileYellowBack;
|
||||
frontColor = Palette.missileYellow;
|
||||
backColor = Pal.missileYellowBack;
|
||||
frontColor = Pal.missileYellow;
|
||||
}};
|
||||
|
||||
artilleryUnit = new ArtilleryBulletType(2f, 0, "shell"){{
|
||||
@@ -135,27 +136,30 @@ public class Bullets implements ContentList{
|
||||
collidesTiles = true;
|
||||
splashDamageRadius = 45f;
|
||||
splashDamage = 50f;
|
||||
backColor = Palette.bulletYellowBack;
|
||||
frontColor = Palette.bulletYellow;
|
||||
backColor = Pal.bulletYellowBack;
|
||||
frontColor = Pal.bulletYellow;
|
||||
}};
|
||||
|
||||
flakPlastic = new FlakBulletType(4f, 5){{
|
||||
splashDamageRadius = 40f;
|
||||
flakPlastic = new FlakBulletType(4f, 6){{
|
||||
splashDamageRadius = 50f;
|
||||
fragBullet = artilleryPlasticFrag;
|
||||
fragBullets = 4;
|
||||
fragBullets = 6;
|
||||
hitEffect = Fx.plasticExplosion;
|
||||
frontColor = Palette.plastaniumFront;
|
||||
backColor = Palette.plastaniumBack;
|
||||
frontColor = Pal.plastaniumFront;
|
||||
backColor = Pal.plastaniumBack;
|
||||
shootEffect = Fx.shootBig;
|
||||
}};
|
||||
|
||||
flakExplosive = new FlakBulletType(4f, 5){{
|
||||
//default bullet type, no changes
|
||||
shootEffect = Fx.shootBig;
|
||||
}};
|
||||
|
||||
flakSurge = new FlakBulletType(4f, 7){{
|
||||
splashDamage = 33f;
|
||||
lightining = 2;
|
||||
lightningLength = 12;
|
||||
shootEffect = Fx.shootBig;
|
||||
}};
|
||||
|
||||
missileExplosive = new MissileBulletType(1.8f, 10, "missile"){{
|
||||
@@ -171,8 +175,8 @@ public class Bullets implements ContentList{
|
||||
}};
|
||||
|
||||
missileIncendiary = new MissileBulletType(2f, 12, "missile"){{
|
||||
frontColor = Palette.lightishOrange;
|
||||
backColor = Palette.lightOrange;
|
||||
frontColor = Pal.lightishOrange;
|
||||
backColor = Pal.lightOrange;
|
||||
bulletWidth = 7f;
|
||||
bulletHeight = 8f;
|
||||
bulletShrink = 0f;
|
||||
@@ -212,8 +216,8 @@ public class Bullets implements ContentList{
|
||||
trailColor = Color.valueOf("b6c6fd");
|
||||
hitEffect = Fx.blastExplosion;
|
||||
despawnEffect = Fx.blastExplosion;
|
||||
backColor = Palette.bulletYellowBack;
|
||||
frontColor = Palette.bulletYellow;
|
||||
backColor = Pal.bulletYellowBack;
|
||||
frontColor = Pal.bulletYellow;
|
||||
weaveScale = 8f;
|
||||
weaveMag = 2f;
|
||||
}};
|
||||
@@ -229,20 +233,39 @@ public class Bullets implements ContentList{
|
||||
splashDamage = 10f;
|
||||
lifetime = 120f;
|
||||
trailColor = Color.GRAY;
|
||||
backColor = Palette.bulletYellowBack;
|
||||
frontColor = Palette.bulletYellow;
|
||||
backColor = Pal.bulletYellowBack;
|
||||
frontColor = Pal.bulletYellow;
|
||||
hitEffect = Fx.blastExplosion;
|
||||
despawnEffect = Fx.blastExplosion;
|
||||
weaveScale = 8f;
|
||||
weaveMag = 2f;
|
||||
}};
|
||||
|
||||
standardCopper = new BasicBulletType(2.5f, 7, "bullet"){{
|
||||
missileRevenant = new MissileBulletType(2.7f, 12, "missile"){{
|
||||
bulletWidth = 8f;
|
||||
bulletHeight = 8f;
|
||||
bulletShrink = 0f;
|
||||
drag = -0.003f;
|
||||
homingRange = 60f;
|
||||
keepVelocity = false;
|
||||
splashDamageRadius = 25f;
|
||||
splashDamage = 10f;
|
||||
lifetime = 80f;
|
||||
trailColor = Pal.unitBack;
|
||||
backColor = Pal.unitBack;
|
||||
frontColor = Pal.unitFront;
|
||||
hitEffect = Fx.blastExplosion;
|
||||
despawnEffect = Fx.blastExplosion;
|
||||
weaveScale = 6f;
|
||||
weaveMag = 1f;
|
||||
}};
|
||||
|
||||
standardCopper = new BasicBulletType(2.5f, 9, "bullet"){{
|
||||
bulletWidth = 7f;
|
||||
bulletHeight = 9f;
|
||||
shootEffect = Fx.shootSmall;
|
||||
smokeEffect = Fx.shootSmallSmoke;
|
||||
ammoMultiplier = 2;
|
||||
ammoMultiplier = 1;
|
||||
}};
|
||||
|
||||
standardDense = new BasicBulletType(3.5f, 18, "bullet"){{
|
||||
@@ -273,8 +296,8 @@ public class Bullets implements ContentList{
|
||||
standardIncendiary = new BasicBulletType(3.2f, 11, "bullet"){{
|
||||
bulletWidth = 10f;
|
||||
bulletHeight = 12f;
|
||||
frontColor = Palette.lightishOrange;
|
||||
backColor = Palette.lightOrange;
|
||||
frontColor = Pal.lightishOrange;
|
||||
backColor = Pal.lightOrange;
|
||||
incendSpread = 3f;
|
||||
incendAmount = 1;
|
||||
incendChance = 0.3f;
|
||||
@@ -303,22 +326,25 @@ public class Bullets implements ContentList{
|
||||
bulletWidth = 15f;
|
||||
bulletHeight = 21f;
|
||||
armorPierce = 0.2f;
|
||||
shootEffect = Fx.shootBig;
|
||||
}};
|
||||
|
||||
standardThoriumBig = new BasicBulletType(8f, 65, "bullet"){{
|
||||
bulletWidth = 16f;
|
||||
bulletHeight = 23f;
|
||||
armorPierce = 0.5f;
|
||||
shootEffect = Fx.shootBig;
|
||||
}};
|
||||
|
||||
standardIncendiaryBig = new BasicBulletType(7f, 38, "bullet"){{
|
||||
bulletWidth = 16f;
|
||||
bulletHeight = 21f;
|
||||
frontColor = Palette.lightishOrange;
|
||||
backColor = Palette.lightOrange;
|
||||
frontColor = Pal.lightishOrange;
|
||||
backColor = Pal.lightOrange;
|
||||
incendSpread = 3f;
|
||||
incendAmount = 2;
|
||||
incendChance = 0.3f;
|
||||
shootEffect = Fx.shootBig;
|
||||
}};
|
||||
|
||||
damageLightning = new BulletType(0.0001f, 0f){{
|
||||
@@ -333,6 +359,7 @@ public class Bullets implements ContentList{
|
||||
float healPercent = 3f;
|
||||
|
||||
{
|
||||
shootEffect = Fx.shootHeal;
|
||||
hitEffect = Fx.hitLaser;
|
||||
despawnEffect = Fx.hitLaser;
|
||||
collidesTeam = true;
|
||||
@@ -345,7 +372,7 @@ public class Bullets implements ContentList{
|
||||
|
||||
@Override
|
||||
public void draw(Bullet b){
|
||||
Draw.color(Palette.heal);
|
||||
Draw.color(Pal.heal);
|
||||
Lines.stroke(2f);
|
||||
Lines.lineAngleCenter(b.x, b.y, b.rot(), 7f);
|
||||
Draw.color(Color.WHITE);
|
||||
@@ -359,7 +386,7 @@ public class Bullets implements ContentList{
|
||||
tile = tile.target();
|
||||
|
||||
if(tile != null && tile.getTeam() == b.getTeam() && !(tile.block() instanceof BuildBlock)){
|
||||
Effects.effect(Fx.healBlockFull, Palette.heal, tile.drawx(), tile.drawy(), tile.block().size);
|
||||
Effects.effect(Fx.healBlockFull, Pal.heal, tile.drawx(), tile.drawy(), tile.block().size);
|
||||
tile.entity.healBy(healPercent / 100f * tile.entity.maxHealth());
|
||||
}
|
||||
}
|
||||
@@ -383,7 +410,7 @@ public class Bullets implements ContentList{
|
||||
@Override
|
||||
public void draw(Bullet b){
|
||||
//TODO add color to the bullet depending on the color of the flame it came from
|
||||
Draw.color(Palette.lightFlame, Palette.darkFlame, Color.GRAY, b.fin());
|
||||
Draw.color(Pal.lightFlame, Pal.darkFlame, Color.GRAY, b.fin());
|
||||
Fill.circle(b.x, b.y, 3f * b.fout());
|
||||
Draw.reset();
|
||||
}
|
||||
@@ -413,6 +440,8 @@ public class Bullets implements ContentList{
|
||||
lifetime = 35f;
|
||||
pierce = true;
|
||||
drag = 0.05f;
|
||||
statusDuration = 60f * 4;
|
||||
shootEffect = Fx.shootSmallFlame;
|
||||
hitEffect = Fx.hitFlameSmall;
|
||||
despawnEffect = Fx.none;
|
||||
status = StatusEffects.burning;
|
||||
@@ -424,10 +453,10 @@ public class Bullets implements ContentList{
|
||||
};
|
||||
|
||||
lancerLaser = new BulletType(0.001f, 140){
|
||||
Color[] colors = {Palette.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Palette.lancerLaser, Color.WHITE};
|
||||
Color[] colors = {Pal.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Pal.lancerLaser, Color.WHITE};
|
||||
float[] tscales = {1f, 0.7f, 0.5f, 0.2f};
|
||||
float[] lenscales = {1f, 1.1f, 1.13f, 1.14f};
|
||||
float length = 100f;
|
||||
float length = 160f;
|
||||
|
||||
{
|
||||
hitEffect = Fx.hitLancer;
|
||||
@@ -437,6 +466,11 @@ public class Bullets implements ContentList{
|
||||
pierce = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float range(){
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Bullet b){
|
||||
Damage.collideLine(b, b.getTeam(), hitEffect, b.x, b.y, b.rot(), length);
|
||||
@@ -459,7 +493,7 @@ public class Bullets implements ContentList{
|
||||
}
|
||||
};
|
||||
|
||||
meltdownLaser = new BulletType(0.001f, 26){
|
||||
meltdownLaser = new BulletType(0.001f, 35){
|
||||
Color tmpColor = new Color();
|
||||
Color[] colors = {Color.valueOf("ec745855"), Color.valueOf("ec7458aa"), Color.valueOf("ff9c5a"), Color.WHITE};
|
||||
float[] tscales = {1f, 0.7f, 0.5f, 0.2f};
|
||||
@@ -529,7 +563,7 @@ public class Bullets implements ContentList{
|
||||
@Override
|
||||
public void draw(Bullet b) {
|
||||
super.draw(b);
|
||||
Draw.color(Color.WHITE, Palette.surge, b.fin());
|
||||
Draw.color(Color.WHITE, Pal.surge, b.fin());
|
||||
for(int i = 0; i < 7; i++){
|
||||
Tmp.v1.trns(b.rot(), i * 8f);
|
||||
float sl = Mathf.clamp(b.fout()-0.5f) * (80f - i *10);
|
||||
@@ -543,7 +577,7 @@ public class Bullets implements ContentList{
|
||||
};
|
||||
|
||||
waterShot = new LiquidBulletType(Liquids.water){{
|
||||
knockback = 0.65f;
|
||||
knockback = 0.7f;
|
||||
}};
|
||||
|
||||
cryoShot = new LiquidBulletType(Liquids.cryofluid){{
|
||||
@@ -556,6 +590,12 @@ public class Bullets implements ContentList{
|
||||
drag = 0.03f;
|
||||
}};
|
||||
|
||||
eruptorShot = new LiquidBulletType(Liquids.slag){{
|
||||
damage = 2;
|
||||
speed = 2.1f;
|
||||
drag = 0.02f;
|
||||
}};
|
||||
|
||||
oilShot = new LiquidBulletType(Liquids.oil){{
|
||||
speed = 2f;
|
||||
drag = 0.03f;
|
||||
@@ -569,17 +609,22 @@ public class Bullets implements ContentList{
|
||||
keepVelocity = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float range(){
|
||||
return 70f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Bullet b){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Bullet b){
|
||||
Lightning.create(b.getTeam(), Palette.lancerLaser, damage, b.x, b.y, b.rot(), 30);
|
||||
Lightning.create(b.getTeam(), Pal.lancerLaser, damage, b.x, b.y, b.rot(), 30);
|
||||
}
|
||||
};
|
||||
|
||||
arc = new BulletType(0.001f, 26){{
|
||||
arc = new BulletType(0.001f, 20){{
|
||||
lifetime = 1;
|
||||
despawnEffect = Fx.none;
|
||||
hitEffect = Fx.hitLancer;
|
||||
@@ -590,7 +635,7 @@ public class Bullets implements ContentList{
|
||||
|
||||
@Override
|
||||
public void init(Bullet b){
|
||||
Lightning.create(b.getTeam(), Palette.lancerLaser, damage, b.x, b.y, b.rot(), 36);
|
||||
Lightning.create(b.getTeam(), Pal.lancerLaser, damage, b.x, b.y, b.rot(), 14);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -614,8 +659,8 @@ public class Bullets implements ContentList{
|
||||
bulletWidth = 8f;
|
||||
bulletHeight = 12f;
|
||||
hitEffect = Fx.flakExplosion;
|
||||
backColor = Palette.lightOrange;
|
||||
frontColor = Palette.lightishOrange;
|
||||
backColor = Pal.lightOrange;
|
||||
frontColor = Pal.lightishOrange;
|
||||
incendChance = 1f;
|
||||
incendAmount = 3;
|
||||
incendSpread = 10f;
|
||||
@@ -639,5 +684,22 @@ public class Bullets implements ContentList{
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
explode = new BombBulletType(2f, 3f, "clear"){{
|
||||
hitEffect = Fx.pulverize;
|
||||
lifetime = 23f;
|
||||
speed = 1f;
|
||||
splashDamageRadius = 50f;
|
||||
splashDamage = 20f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Bullet b){
|
||||
if(b.getOwner() instanceof Unit){
|
||||
((Unit)b.getOwner()).kill();
|
||||
}
|
||||
b.time(b.lifetime());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.anuke.mindustry.content;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.entities.Effects.Effect;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Fill;
|
||||
@@ -9,11 +8,14 @@ import io.anuke.arc.graphics.g2d.Lines;
|
||||
import io.anuke.arc.math.Angles;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.mindustry.entities.Effects.Effect;
|
||||
import io.anuke.mindustry.entities.effect.GroundEffectEntity.GroundEffect;
|
||||
import io.anuke.mindustry.entities.type.BaseUnit;
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.graphics.Shapes;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Item.Icon;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
|
||||
@@ -32,29 +34,43 @@ public class Fx implements ContentList{
|
||||
bigShockwave, nuclearShockwave, explosion, blockExplosion, blockExplosionSmoke, shootSmall, shootHeal, shootSmallSmoke, shootBig, shootBig2, shootBigSmoke,
|
||||
shootBigSmoke2, shootSmallFlame, shootLiquid, shellEjectSmall, shellEjectMedium,
|
||||
shellEjectBig, lancerLaserShoot, lancerLaserShootSmoke, lancerLaserCharge, lancerLaserChargeBegin, lightningCharge, lightningShoot,
|
||||
launchFull;
|
||||
unitSpawn, spawnShockwave, magmasmoke, impactShockwave, impactcloud, impactsmoke, dynamicExplosion;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
|
||||
none = new Effect(0, 0f, e -> {});
|
||||
|
||||
unitSpawn = new Effect(30f, e -> {
|
||||
if(!(e.data instanceof BaseUnit)) return;
|
||||
|
||||
Draw.alpha(e.fin());
|
||||
|
||||
float scl = 1f + e.fout()*2f;
|
||||
|
||||
BaseUnit unit = (BaseUnit)e.data;
|
||||
Draw.rect(unit.getIconRegion(), e.x, e.y,
|
||||
unit.getIconRegion().getWidth() * Draw.scl * scl, unit.getIconRegion().getWidth() * Draw.scl * scl, 180f);
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
placeBlock = new Effect(16, e -> {
|
||||
Draw.color(Palette.accent);
|
||||
Draw.color(Pal.accent);
|
||||
Lines.stroke(3f - e.fin() * 2f);
|
||||
Lines.square(e.x, e.y, tilesize / 2f * e.rotation + e.fin() * 3f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
tapBlock = new Effect(12, e -> {
|
||||
Draw.color(Palette.accent);
|
||||
Draw.color(Pal.accent);
|
||||
Lines.stroke(3f - e.fin() * 2f);
|
||||
Lines.circle(e.x, e.y, 4f + (tilesize / 1.5f * e.rotation) * e.fin());
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
breakBlock = new Effect(12, e -> {
|
||||
Draw.color(Palette.remove);
|
||||
Draw.color(Pal.remove);
|
||||
Lines.stroke(3f - e.fin() * 2f);
|
||||
Lines.square(e.x, e.y, tilesize / 2f * e.rotation + e.fin() * 3f);
|
||||
|
||||
@@ -65,36 +81,42 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
select = new Effect(23, e -> {
|
||||
Draw.color(Palette.accent);
|
||||
Draw.color(Pal.accent);
|
||||
Lines.stroke(e.fout() * 3f);
|
||||
Lines.circle(e.x, e.y, 3f + e.fin() * 14f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
smoke = new Effect(100, e -> {
|
||||
Draw.color(Color.GRAY, Palette.darkishGray, e.fin());
|
||||
Draw.color(Color.GRAY, Pal.darkishGray, e.fin());
|
||||
float size = 7f - e.fin() * 7f;
|
||||
Draw.rect("circle", e.x, e.y, size, size);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
spawn = new Effect(23, e -> {
|
||||
magmasmoke = new Effect(110, e -> {
|
||||
Draw.color(Color.GRAY);
|
||||
Fill.circle(e.x, e.y, e.fslope() * 6f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
spawn = new Effect(30, e -> {
|
||||
Lines.stroke(2f * e.fout());
|
||||
Draw.color(Palette.accent);
|
||||
Lines.poly(e.x, e.y, 4, 3f + e.fin() * 8f);
|
||||
Draw.color(Pal.accent);
|
||||
Lines.poly(e.x, e.y, 4, 5f + e.fin() * 12f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
vtolHover = new Effect(40f, e -> {
|
||||
float len = e.finpow() * 10f;
|
||||
float ang = e.rotation + Mathf.randomSeedRange(e.id, 30f);
|
||||
Draw.color(Palette.lightFlame, Palette.lightOrange, e.fin());
|
||||
Draw.color(Pal.lightFlame, Pal.lightOrange, e.fin());
|
||||
Fill.circle(e.x + Angles.trnsx(ang, len), e.y + Angles.trnsy(ang, len), 2f * e.fout());
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
unitDrop = new GroundEffect(30, e -> {
|
||||
Draw.color(Palette.lightishGray);
|
||||
Draw.color(Pal.lightishGray);
|
||||
Angles.randLenVectors(e.id, 9, 3 + 20f * e.finpow(), (x, y) -> {
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.4f);
|
||||
});
|
||||
@@ -102,7 +124,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
unitLand = new GroundEffect(30, e -> {
|
||||
Draw.color(Palette.lightishGray, e.color, e.rotation);
|
||||
Draw.color(Tmp.c1.set(e.color).mul(1.1f));
|
||||
Angles.randLenVectors(e.id, 6, 17f * e.finpow(), (x, y) -> {
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.3f);
|
||||
});
|
||||
@@ -110,35 +132,35 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
unitPickup = new GroundEffect(18, e -> {
|
||||
Draw.color(Palette.lightishGray);
|
||||
Draw.color(Pal.lightishGray);
|
||||
Lines.stroke(e.fin() * 2f);
|
||||
Lines.poly(e.x, e.y, 4, 13f * e.fout());
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
landShock = new GroundEffect(12, e -> {
|
||||
Draw.color(Palette.lancerLaser);
|
||||
Draw.color(Pal.lancerLaser);
|
||||
Lines.stroke(e.fout() * 3f);
|
||||
Lines.poly(e.x, e.y, 12, 20f * e.fout());
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
pickup = new Effect(18, e -> {
|
||||
Draw.color(Palette.lightishGray);
|
||||
Draw.color(Pal.lightishGray);
|
||||
Lines.stroke(e.fout() * 2f);
|
||||
Lines.spikes(e.x, e.y, 1f + e.fin() * 6f, e.fout() * 4f, 6);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
healWave = new Effect(22, e -> {
|
||||
Draw.color(Palette.heal);
|
||||
Draw.color(Pal.heal);
|
||||
Lines.stroke(e.fout() * 2f);
|
||||
Lines.poly(e.x, e.y, 30, 4f + e.finpow() * 60f);
|
||||
Draw.color();
|
||||
});
|
||||
|
||||
heal = new Effect(11, e -> {
|
||||
Draw.color(Palette.heal);
|
||||
Draw.color(Pal.heal);
|
||||
Lines.stroke(e.fout() * 2f);
|
||||
Lines.poly(e.x, e.y, 10, 2f + e.finpow() * 7f);
|
||||
Draw.color();
|
||||
@@ -146,7 +168,7 @@ public class Fx implements ContentList{
|
||||
|
||||
|
||||
hitBulletSmall = new Effect(14, e -> {
|
||||
Draw.color(Color.WHITE, Palette.lightOrange, e.fin());
|
||||
Draw.color(Color.WHITE, Pal.lightOrange, e.fin());
|
||||
|
||||
e.scaled(7f, s -> {
|
||||
Lines.stroke(0.5f + s.fout());
|
||||
@@ -165,7 +187,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
hitFuse = new Effect(14, e -> {
|
||||
Draw.color(Color.WHITE, Palette.surge, e.fin());
|
||||
Draw.color(Color.WHITE, Pal.surge, e.fin());
|
||||
|
||||
e.scaled(7f, s -> {
|
||||
Lines.stroke(0.5f + s.fout());
|
||||
@@ -184,7 +206,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
hitBulletBig = new Effect(13, e -> {
|
||||
Draw.color(Color.WHITE, Palette.lightOrange, e.fin());
|
||||
Draw.color(Color.WHITE, Pal.lightOrange, e.fin());
|
||||
Lines.stroke(0.5f + e.fout() * 1.5f);
|
||||
|
||||
Angles.randLenVectors(e.id, 8, e.finpow() * 30f, e.rotation, 50f, (x, y) -> {
|
||||
@@ -196,7 +218,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
hitFlameSmall = new Effect(14, e -> {
|
||||
Draw.color(Palette.lightFlame, Palette.darkFlame, e.fin());
|
||||
Draw.color(Pal.lightFlame, Pal.darkFlame, e.fin());
|
||||
Lines.stroke(0.5f + e.fout());
|
||||
|
||||
Angles.randLenVectors(e.id, 5, e.fin() * 15f, e.rotation, 50f, (x, y) -> {
|
||||
@@ -230,7 +252,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
hitMeltdown = new Effect(12, e -> {
|
||||
Draw.color(Palette.meltdownHit);
|
||||
Draw.color(Pal.meltdownHit);
|
||||
Lines.stroke(e.fout() * 2f);
|
||||
|
||||
Angles.randLenVectors(e.id, 6, e.finpow() * 18f, e.rotation, 360f, (x, y) -> {
|
||||
@@ -242,14 +264,14 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
hitLaser = new Effect(8, e -> {
|
||||
Draw.color(Color.WHITE, Palette.heal, e.fin());
|
||||
Draw.color(Color.WHITE, Pal.heal, e.fin());
|
||||
Lines.stroke(0.5f + e.fout());
|
||||
Lines.circle(e.x, e.y, e.fin()*5f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
despawn = new Effect(12, e -> {
|
||||
Draw.color(Palette.lighterOrange, Color.GRAY, e.fin());
|
||||
Draw.color(Pal.lighterOrange, Color.GRAY, e.fin());
|
||||
Lines.stroke(e.fout());
|
||||
|
||||
Angles.randLenVectors(e.id, 7, e.fin() * 7f, e.rotation, 40f, (x, y) -> {
|
||||
@@ -262,7 +284,7 @@ public class Fx implements ContentList{
|
||||
|
||||
flakExplosion = new Effect(20, e -> {
|
||||
|
||||
Draw.color(Palette.bulletYellow);
|
||||
Draw.color(Pal.bulletYellow);
|
||||
e.scaled(6, i -> {
|
||||
Lines.stroke(3f * i.fout());
|
||||
Lines.circle(e.x, e.y, 3f + i.fin() * 10f);
|
||||
@@ -274,7 +296,7 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 3f + 0.5f);
|
||||
});
|
||||
|
||||
Draw.color(Palette.lighterOrange);
|
||||
Draw.color(Pal.lighterOrange);
|
||||
Lines.stroke(1f * e.fout());
|
||||
|
||||
Angles.randLenVectors(e.id + 1, 4, 1f + 23f * e.finpow(), (x, y) -> {
|
||||
@@ -286,7 +308,7 @@ public class Fx implements ContentList{
|
||||
|
||||
plasticExplosion = new Effect(24, e -> {
|
||||
|
||||
Draw.color(Palette.plastaniumFront);
|
||||
Draw.color(Pal.plastaniumFront);
|
||||
e.scaled(7, i -> {
|
||||
Lines.stroke(3f * i.fout());
|
||||
Lines.circle(e.x, e.y, 3f + i.fin() * 24f);
|
||||
@@ -298,7 +320,7 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f);
|
||||
});
|
||||
|
||||
Draw.color(Palette.plastaniumBack);
|
||||
Draw.color(Pal.plastaniumBack);
|
||||
Lines.stroke(1f * e.fout());
|
||||
|
||||
Angles.randLenVectors(e.id + 1, 4, 1f + 25f * e.finpow(), (x, y) -> {
|
||||
@@ -310,7 +332,7 @@ public class Fx implements ContentList{
|
||||
|
||||
plasticExplosionFlak = new Effect(28, e -> {
|
||||
|
||||
Draw.color(Palette.plastaniumFront);
|
||||
Draw.color(Pal.plastaniumFront);
|
||||
e.scaled(7, i -> {
|
||||
Lines.stroke(3f * i.fout());
|
||||
Lines.circle(e.x, e.y, 3f + i.fin() * 34f);
|
||||
@@ -322,7 +344,7 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f);
|
||||
});
|
||||
|
||||
Draw.color(Palette.plastaniumBack);
|
||||
Draw.color(Pal.plastaniumBack);
|
||||
Lines.stroke(1f * e.fout());
|
||||
|
||||
Angles.randLenVectors(e.id + 1, 4, 1f + 30f * e.finpow(), (x, y) -> {
|
||||
@@ -334,7 +356,7 @@ public class Fx implements ContentList{
|
||||
|
||||
blastExplosion = new Effect(22, e -> {
|
||||
|
||||
Draw.color(Palette.missileYellow);
|
||||
Draw.color(Pal.missileYellow);
|
||||
e.scaled(6, i -> {
|
||||
Lines.stroke(3f * i.fout());
|
||||
Lines.circle(e.x, e.y, 3f + i.fin() * 15f);
|
||||
@@ -346,7 +368,7 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f);
|
||||
});
|
||||
|
||||
Draw.color(Palette.missileYellowBack);
|
||||
Draw.color(Pal.missileYellowBack);
|
||||
Lines.stroke(1f * e.fout());
|
||||
|
||||
Angles.randLenVectors(e.id + 1, 4, 1f + 23f * e.finpow(), (x, y) -> {
|
||||
@@ -363,7 +385,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
incendTrail = new Effect(50, e -> {
|
||||
Draw.color(Palette.lightOrange);
|
||||
Draw.color(Pal.lightOrange);
|
||||
Fill.circle(e.x, e.y, e.rotation * e.fout());
|
||||
Draw.reset();
|
||||
});
|
||||
@@ -375,7 +397,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
absorb = new Effect(12, e -> {
|
||||
Draw.color(Palette.accent);
|
||||
Draw.color(Pal.accent);
|
||||
Lines.stroke(2f * e.fout());
|
||||
Lines.circle(e.x, e.y, 5f * e.fout());
|
||||
Draw.reset();
|
||||
@@ -383,7 +405,7 @@ public class Fx implements ContentList{
|
||||
|
||||
flakExplosionBig = new Effect(30, e -> {
|
||||
|
||||
Draw.color(Palette.bulletYellowBack);
|
||||
Draw.color(Pal.bulletYellowBack);
|
||||
e.scaled(6, i -> {
|
||||
Lines.stroke(3f * i.fout());
|
||||
Lines.circle(e.x, e.y, 3f + i.fin() * 25f);
|
||||
@@ -395,7 +417,7 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f);
|
||||
});
|
||||
|
||||
Draw.color(Palette.bulletYellow);
|
||||
Draw.color(Pal.bulletYellow);
|
||||
Lines.stroke(1f * e.fout());
|
||||
|
||||
Angles.randLenVectors(e.id + 1, 4, 1f + 23f * e.finpow(), (x, y) -> {
|
||||
@@ -407,7 +429,7 @@ public class Fx implements ContentList{
|
||||
|
||||
|
||||
burning = new Effect(35f, e -> {
|
||||
Draw.color(Palette.lightFlame, Palette.darkFlame, e.fin());
|
||||
Draw.color(Pal.lightFlame, Pal.darkFlame, e.fin());
|
||||
|
||||
Angles.randLenVectors(e.id, 3, 2f + e.fin() * 7f, (x, y) -> {
|
||||
Fill.circle(e.x + x, e.y + y, 0.1f + e.fout() * 1.4f);
|
||||
@@ -417,7 +439,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
fire = new Effect(35f, e -> {
|
||||
Draw.color(Palette.lightFlame, Palette.darkFlame, e.fin());
|
||||
Draw.color(Pal.lightFlame, Pal.darkFlame, e.fin());
|
||||
|
||||
Angles.randLenVectors(e.id, 2, 2f + e.fin() * 7f, (x, y) -> {
|
||||
Fill.circle(e.x + x, e.y + y, 0.2f + e.fslope() * 1.5f);
|
||||
@@ -457,7 +479,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
ballfire = new Effect(25f, e -> {
|
||||
Draw.color(Palette.lightFlame, Palette.darkFlame, e.fin());
|
||||
Draw.color(Pal.lightFlame, Pal.darkFlame, e.fin());
|
||||
|
||||
Angles.randLenVectors(e.id, 2, 2f + e.fin() * 7f, (x, y) -> {
|
||||
Fill.circle(e.x + x, e.y + y, 0.2f + e.fout() * 1.5f);
|
||||
@@ -507,7 +529,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
overdriven = new Effect(20f, e -> {
|
||||
Draw.color(Palette.accent);
|
||||
Draw.color(Pal.accent);
|
||||
|
||||
Angles.randLenVectors(e.id, 2, 1f + e.fin() * 2f, (x, y) -> {
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 2.3f+0.5f);
|
||||
@@ -520,7 +542,7 @@ public class Fx implements ContentList{
|
||||
float length = 20f * e.finpow();
|
||||
float size = 7f * e.fout();
|
||||
|
||||
Draw.rect(((Item) e.data).region, e.x + Angles.trnsx(e.rotation, length), e.y + Angles.trnsy(e.rotation, length), size, size);
|
||||
Draw.rect(((Item) e.data).icon(Icon.large), e.x + Angles.trnsx(e.rotation, length), e.y + Angles.trnsy(e.rotation, length), size, size);
|
||||
});
|
||||
|
||||
|
||||
@@ -545,6 +567,20 @@ public class Fx implements ContentList{
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
impactShockwave = new Effect(13f, 300f, e -> {
|
||||
Draw.color(Pal.lighterOrange, Color.LIGHT_GRAY, e.fin());
|
||||
Lines.stroke(e.fout() * 4f + 0.2f);
|
||||
Lines.poly(e.x, e.y, 60, e.fin() * 200f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
spawnShockwave = new Effect(20f, 400f, e -> {
|
||||
Draw.color(Color.WHITE, Color.LIGHT_GRAY, e.fin());
|
||||
Lines.stroke(e.fout() * 3f + 0.5f);
|
||||
Lines.poly(e.x, e.y, 60, e.fin() * 450f);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
explosion = new Effect(30, e -> {
|
||||
e.scaled(7, i -> {
|
||||
Lines.stroke(3f * i.fout());
|
||||
@@ -558,7 +594,7 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x / 2f, e.y + y / 2f, e.fout() * 1f);
|
||||
});
|
||||
|
||||
Draw.color(Palette.lighterOrange, Palette.lightOrange, Color.GRAY, e.fin());
|
||||
Draw.color(Pal.lighterOrange, Pal.lightOrange, Color.GRAY, e.fin());
|
||||
Lines.stroke(1.5f * e.fout());
|
||||
|
||||
Angles.randLenVectors(e.id + 1, 8, 1f + 23f * e.finpow(), (x, y) -> {
|
||||
@@ -568,6 +604,31 @@ public class Fx implements ContentList{
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
dynamicExplosion = new Effect(30, e -> {
|
||||
float intensity = e.rotation;
|
||||
|
||||
e.scaled(5 + intensity*2, i -> {
|
||||
Lines.stroke(3.1f * i.fout());
|
||||
Lines.poly(e.x, e.y, (int)(20 * intensity), (3f + i.fin() * 14f) * intensity);
|
||||
});
|
||||
|
||||
Draw.color(Color.GRAY);
|
||||
|
||||
Angles.randLenVectors(e.id, e.finpow(), (int)(6 * intensity), 21f*intensity, (x, y, in, out) -> {
|
||||
Fill.circle(e.x + x, e.y + y, out * (2f+intensity) * 3 + 0.5f);
|
||||
Fill.circle(e.x + x / 2f, e.y + y / 2f, out * (intensity) * 3);
|
||||
});
|
||||
|
||||
Draw.color(Pal.lighterOrange, Pal.lightOrange, Color.GRAY, e.fin());
|
||||
Lines.stroke((1.7f * e.fout()) * (1f + (intensity - 1f) / 2f));
|
||||
|
||||
Angles.randLenVectors(e.id + 1, e.finpow(), (int)(9*intensity), 40f*intensity, (x, y, in, out) -> {
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + out * 4 * (3f+intensity));
|
||||
});
|
||||
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
blockExplosion = new Effect(30, e -> {
|
||||
e.scaled(7, i -> {
|
||||
Lines.stroke(3.1f * i.fout());
|
||||
@@ -581,7 +642,7 @@ public class Fx implements ContentList{
|
||||
Fill.circle(e.x + x / 2f, e.y + y / 2f, e.fout() * 1f);
|
||||
});
|
||||
|
||||
Draw.color(Palette.lighterOrange, Palette.lightOrange, Color.GRAY, e.fin());
|
||||
Draw.color(Pal.lighterOrange, Pal.lightOrange, Color.GRAY, e.fin());
|
||||
Lines.stroke(1.7f * e.fout());
|
||||
|
||||
Angles.randLenVectors(e.id + 1, 9, 1f + 23f * e.finpow(), (x, y) -> {
|
||||
@@ -604,7 +665,7 @@ public class Fx implements ContentList{
|
||||
|
||||
|
||||
shootSmall = new Effect(8, e -> {
|
||||
Draw.color(Palette.lighterOrange, Palette.lightOrange, e.fin());
|
||||
Draw.color(Pal.lighterOrange, Pal.lightOrange, e.fin());
|
||||
float w = 1f + 5 * e.fout();
|
||||
Shapes.tri(e.x, e.y, w, 15f * e.fout(), e.rotation);
|
||||
Shapes.tri(e.x, e.y, w, 3f * e.fout(), e.rotation + 180f);
|
||||
@@ -612,7 +673,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
shootHeal = new Effect(8, e -> {
|
||||
Draw.color(Palette.heal);
|
||||
Draw.color(Pal.heal);
|
||||
float w = 1f + 5 * e.fout();
|
||||
Shapes.tri(e.x, e.y, w, 17f * e.fout(), e.rotation);
|
||||
Shapes.tri(e.x, e.y, w, 4f * e.fout(), e.rotation + 180f);
|
||||
@@ -620,7 +681,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
shootSmallSmoke = new Effect(20f, e -> {
|
||||
Draw.color(Palette.lighterOrange, Color.LIGHT_GRAY, Color.GRAY, e.fin());
|
||||
Draw.color(Pal.lighterOrange, Color.LIGHT_GRAY, Color.GRAY, e.fin());
|
||||
|
||||
Angles.randLenVectors(e.id, 5, e.finpow() * 6f, e.rotation, 20f, (x, y) -> {
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 1.5f);
|
||||
@@ -630,7 +691,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
shootBig = new Effect(9, e -> {
|
||||
Draw.color(Palette.lighterOrange, Palette.lightOrange, e.fin());
|
||||
Draw.color(Pal.lighterOrange, Pal.lightOrange, e.fin());
|
||||
float w = 1.2f + 7 * e.fout();
|
||||
Shapes.tri(e.x, e.y, w, 25f * e.fout(), e.rotation);
|
||||
Shapes.tri(e.x, e.y, w, 4f * e.fout(), e.rotation + 180f);
|
||||
@@ -638,7 +699,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
shootBig2 = new Effect(10, e -> {
|
||||
Draw.color(Palette.lightOrange, Color.GRAY, e.fin());
|
||||
Draw.color(Pal.lightOrange, Color.GRAY, e.fin());
|
||||
float w = 1.2f + 8 * e.fout();
|
||||
Shapes.tri(e.x, e.y, w, 29f * e.fout(), e.rotation);
|
||||
Shapes.tri(e.x, e.y, w, 5f * e.fout(), e.rotation + 180f);
|
||||
@@ -646,7 +707,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
shootBigSmoke = new Effect(17f, e -> {
|
||||
Draw.color(Palette.lighterOrange, Color.LIGHT_GRAY, Color.GRAY, e.fin());
|
||||
Draw.color(Pal.lighterOrange, Color.LIGHT_GRAY, Color.GRAY, e.fin());
|
||||
|
||||
Angles.randLenVectors(e.id, 8, e.finpow() * 19f, e.rotation, 10f, (x, y) -> {
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 2f + 0.2f);
|
||||
@@ -656,7 +717,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
shootBigSmoke2 = new Effect(18f, e -> {
|
||||
Draw.color(Palette.lightOrange, Color.LIGHT_GRAY, Color.GRAY, e.fin());
|
||||
Draw.color(Pal.lightOrange, Color.LIGHT_GRAY, Color.GRAY, e.fin());
|
||||
|
||||
Angles.randLenVectors(e.id, 9, e.finpow() * 23f, e.rotation, 20f, (x, y) -> {
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 2.4f + 0.2f);
|
||||
@@ -665,10 +726,10 @@ public class Fx implements ContentList{
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
shootSmallFlame = new Effect(30f, e -> {
|
||||
Draw.color(Palette.lightFlame, Palette.darkFlame, Color.GRAY, e.fin());
|
||||
shootSmallFlame = new Effect(32f, e -> {
|
||||
Draw.color(Pal.lightFlame, Pal.darkFlame, Color.GRAY, e.fin());
|
||||
|
||||
Angles.randLenVectors(e.id, 8, e.finpow() * 36f, e.rotation, 10f, (x, y) -> {
|
||||
Angles.randLenVectors(e.id, 8, e.finpow() * 44f, e.rotation, 10f, (x, y) -> {
|
||||
Fill.circle(e.x + x, e.y + y, 0.65f + e.fout() * 1.5f);
|
||||
});
|
||||
|
||||
@@ -686,7 +747,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
shellEjectSmall = new GroundEffect(30f, 400f, e -> {
|
||||
Draw.color(Palette.lightOrange, Color.LIGHT_GRAY, Palette.lightishGray, e.fin());
|
||||
Draw.color(Pal.lightOrange, Color.LIGHT_GRAY, Pal.lightishGray, e.fin());
|
||||
float rot = Math.abs(e.rotation) + 90f;
|
||||
|
||||
int i = Mathf.sign(e.rotation);
|
||||
@@ -701,7 +762,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
shellEjectMedium = new GroundEffect(34f, 400f, e -> {
|
||||
Draw.color(Palette.lightOrange, Color.LIGHT_GRAY, Palette.lightishGray, e.fin());
|
||||
Draw.color(Pal.lightOrange, Color.LIGHT_GRAY, Pal.lightishGray, e.fin());
|
||||
float rot = e.rotation + 90f;
|
||||
for(int i : Mathf.signs){
|
||||
float len = (2f + e.finpow() * 10f) * i;
|
||||
@@ -724,7 +785,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
shellEjectBig = new GroundEffect(22f, 400f, e -> {
|
||||
Draw.color(Palette.lightOrange, Color.LIGHT_GRAY, Palette.lightishGray, e.fin());
|
||||
Draw.color(Pal.lightOrange, Color.LIGHT_GRAY, Pal.lightishGray, e.fin());
|
||||
float rot = e.rotation + 90f;
|
||||
for(int i : Mathf.signs){
|
||||
float len = (4f + e.finpow() * 8f) * i;
|
||||
@@ -748,7 +809,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
lancerLaserShoot = new Effect(21f, e -> {
|
||||
Draw.color(Palette.lancerLaser);
|
||||
Draw.color(Pal.lancerLaser);
|
||||
|
||||
for(int i : Mathf.signs){
|
||||
Shapes.tri(e.x, e.y, 4f * e.fout(), 29f, e.rotation + 90f * i);
|
||||
@@ -758,7 +819,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
lancerLaserShootSmoke = new Effect(26f, e -> {
|
||||
Draw.color(Palette.lancerLaser);
|
||||
Draw.color(Pal.lancerLaser);
|
||||
|
||||
Angles.randLenVectors(e.id, 7, 80f, e.rotation, 0f, (x, y) -> {
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fout() * 9f);
|
||||
@@ -768,7 +829,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
lancerLaserCharge = new Effect(38f, e -> {
|
||||
Draw.color(Palette.lancerLaser);
|
||||
Draw.color(Pal.lancerLaser);
|
||||
|
||||
Angles.randLenVectors(e.id, 2, 1f + 20f * e.fout(), e.rotation, 120f, (x, y) -> {
|
||||
Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fslope() * 3f + 1f);
|
||||
@@ -778,7 +839,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
lancerLaserChargeBegin = new Effect(71f, e -> {
|
||||
Draw.color(Palette.lancerLaser);
|
||||
Draw.color(Pal.lancerLaser);
|
||||
Fill.circle(e.x, e.y, e.fin() * 3f);
|
||||
|
||||
Draw.color();
|
||||
@@ -786,7 +847,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
lightningCharge = new Effect(38f, e -> {
|
||||
Draw.color(Palette.lancerLaser);
|
||||
Draw.color(Pal.lancerLaser);
|
||||
|
||||
Angles.randLenVectors(e.id, 2, 1f + 20f * e.fout(), e.rotation, 120f, (x, y) -> {
|
||||
Shapes.tri(e.x + x, e.y + y, e.fslope() * 3f + 1, e.fslope() * 3f + 1, Mathf.angle(x, y));
|
||||
@@ -796,7 +857,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
lightningShoot = new Effect(12f, e -> {
|
||||
Draw.color(Color.WHITE, Palette.lancerLaser, e.fin());
|
||||
Draw.color(Color.WHITE, Pal.lancerLaser, e.fin());
|
||||
Lines.stroke(e.fout() * 1.2f + 0.5f);
|
||||
|
||||
Angles.randLenVectors(e.id, 7, 25f * e.finpow(), e.rotation, 50f, (x, y) -> {
|
||||
@@ -831,11 +892,26 @@ public class Fx implements ContentList{
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
impactsmoke = new Effect(60, e -> {
|
||||
Angles.randLenVectors(e.id, 7, e.fin() * 20f, (x, y) -> {
|
||||
float size = e.fslope() * 4f;
|
||||
Draw.color(Color.LIGHT_GRAY, Color.GRAY, e.fin());
|
||||
Draw.rect("circle", e.x + x, e.y + y, size, size);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
impactcloud = new Effect(140, 400f, e -> {
|
||||
Angles.randLenVectors(e.id, 20, e.finpow() * 160f, (x, y) -> {
|
||||
float size = e.fout() * 15f;
|
||||
Draw.color(Pal.lighterOrange, Color.LIGHT_GRAY, e.fin());
|
||||
Draw.rect("circle", e.x + x, e.y + y, size, size);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
redgeneratespark = new Effect(18, e -> {
|
||||
Angles.randLenVectors(e.id, 5, e.fin() * 8f, (x, y) -> {
|
||||
float len = e.fout() * 4f;
|
||||
Draw.color(Palette.redSpark, Color.GRAY, e.fin());
|
||||
//Draw.alpha(e.fout());
|
||||
Draw.color(Pal.redSpark, Color.GRAY, e.fin());
|
||||
Draw.rect("circle", e.x + x, e.y + y, len, len);
|
||||
Draw.reset();
|
||||
});
|
||||
@@ -843,7 +919,7 @@ public class Fx implements ContentList{
|
||||
generatespark = new Effect(18, e -> {
|
||||
Angles.randLenVectors(e.id, 5, e.fin() * 8f, (x, y) -> {
|
||||
float len = e.fout() * 4f;
|
||||
Draw.color(Palette.orangeSpark, Color.GRAY, e.fin());
|
||||
Draw.color(Pal.orangeSpark, Color.GRAY, e.fin());
|
||||
Draw.rect("circle", e.x + x, e.y + y, len, len);
|
||||
Draw.reset();
|
||||
});
|
||||
@@ -865,42 +941,42 @@ public class Fx implements ContentList{
|
||||
});
|
||||
pulverize = new Effect(40, e -> {
|
||||
Angles.randLenVectors(e.id, 5, 3f + e.fin() * 8f, (x, y) -> {
|
||||
Draw.color(Palette.stoneGray);
|
||||
Draw.color(Pal.stoneGray);
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.5f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
pulverizeRed = new Effect(40, e -> {
|
||||
Angles.randLenVectors(e.id, 5, 3f + e.fin() * 8f, (x, y) -> {
|
||||
Draw.color(Palette.redDust, Palette.stoneGray, e.fin());
|
||||
Draw.color(Pal.redDust, Pal.stoneGray, e.fin());
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.5f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
pulverizeRedder = new Effect(40, e -> {
|
||||
Angles.randLenVectors(e.id, 5, 3f + e.fin() * 9f, (x, y) -> {
|
||||
Draw.color(Palette.redderDust, Palette.stoneGray, e.fin());
|
||||
Draw.color(Pal.redderDust, Pal.stoneGray, e.fin());
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 2.5f + 0.5f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
pulverizeSmall = new Effect(30, e -> {
|
||||
Angles.randLenVectors(e.id, 3, e.fin() * 5f, (x, y) -> {
|
||||
Draw.color(Palette.stoneGray);
|
||||
Draw.color(Pal.stoneGray);
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 1f + 0.5f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
pulverizeMedium = new Effect(30, e -> {
|
||||
Angles.randLenVectors(e.id, 5, 3f + e.fin() * 8f, (x, y) -> {
|
||||
Draw.color(Palette.stoneGray);
|
||||
Draw.color(Pal.stoneGray);
|
||||
Fill.square(e.x + x, e.y + y, e.fout() * 1f + 0.5f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
});
|
||||
producesmoke = new Effect(12, e -> {
|
||||
Angles.randLenVectors(e.id, 8, 4f + e.fin() * 18f, (x, y) -> {
|
||||
Draw.color(Color.WHITE, Palette.accent, e.fin());
|
||||
Draw.color(Color.WHITE, Pal.accent, e.fin());
|
||||
Fill.square(e.x + x, e.y + y, 1f + e.fout() * 3f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
@@ -914,7 +990,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
formsmoke = new Effect(40, e -> {
|
||||
Angles.randLenVectors(e.id, 6, 5f + e.fin() * 8f, (x, y) -> {
|
||||
Draw.color(Palette.plasticSmoke, Color.LIGHT_GRAY, e.fin());
|
||||
Draw.color(Pal.plasticSmoke, Color.LIGHT_GRAY, e.fin());
|
||||
Fill.square(e.x + x, e.y + y, 0.2f + e.fout() * 2f, 45);
|
||||
Draw.reset();
|
||||
});
|
||||
@@ -1046,7 +1122,7 @@ public class Fx implements ContentList{
|
||||
Draw.reset();
|
||||
});
|
||||
ripple = new GroundEffect(false, 30, e -> {
|
||||
Draw.color(Tmp.c1.set(e.color).shiftValue(0.1f));
|
||||
Draw.color(Tmp.c1.set(e.color).mul(1.2f));
|
||||
Lines.stroke(e.fout() + 0.4f);
|
||||
Lines.circle(e.x, e.y, 2f + e.fin() * 4f);
|
||||
Draw.reset();
|
||||
@@ -1062,7 +1138,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
launch = new Effect(28, e -> {
|
||||
Draw.color(Palette.command);
|
||||
Draw.color(Pal.command);
|
||||
Lines.stroke(e.fout() * 2f);
|
||||
Lines.poly(e.x, e.y, 40, 4f + e.finpow() * 120f);
|
||||
Draw.color();
|
||||
@@ -1083,7 +1159,7 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
healBlock = new Effect(20, e -> {
|
||||
Draw.color(Palette.heal);
|
||||
Draw.color(Pal.heal);
|
||||
Lines.stroke(2f * e.fout() + 0.5f);
|
||||
Lines.square(e.x, e.y, 1f + (e.fin() * e.rotation * tilesize/2f-1f));
|
||||
Draw.color();
|
||||
@@ -1104,17 +1180,10 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
shieldBreak = new Effect(40, e -> {
|
||||
Draw.color(Palette.accent);
|
||||
Draw.color(Pal.accent);
|
||||
Lines.stroke(3f * e.fout());
|
||||
Lines.poly(e.x, e.y, 6, e.rotation + e.fin(), 90);
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
launchFull = new Effect(60, 9999999999f, e -> {
|
||||
Draw.color();
|
||||
Draw.alpha(e.fslope());
|
||||
Fill.rect(Core.camera.position.x, Core.camera.position.y, Core.camera.width + 10, Core.camera.height + 10);
|
||||
Draw.reset();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import io.anuke.mindustry.type.ItemType;
|
||||
|
||||
public class Items implements ContentList{
|
||||
public static Item scrap, copper, lead, graphite, coal, titanium, thorium, silicon, plastanium, phasefabric, surgealloy,
|
||||
biomatter, sand, blastCompound, pyratite, metaglass;
|
||||
sporePod, sand, blastCompound, pyratite, metaglass;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
@@ -26,7 +26,7 @@ public class Items implements ContentList{
|
||||
genOre = true;
|
||||
}};
|
||||
|
||||
metaglass = new Item("metaglass", Color.valueOf("648b55")){{
|
||||
metaglass = new Item("metaglass", Color.valueOf("ebeef5")){{
|
||||
type = ItemType.material;
|
||||
cost = 2f;
|
||||
}};
|
||||
@@ -37,8 +37,8 @@ public class Items implements ContentList{
|
||||
}};
|
||||
|
||||
coal = new Item("coal", Color.valueOf("272727")){{
|
||||
explosiveness = 0.2f;
|
||||
flammability = 0.5f;
|
||||
explosiveness = 0.4f;
|
||||
flammability = 1f;
|
||||
hardness = 2;
|
||||
genOre = true;
|
||||
}};
|
||||
@@ -52,9 +52,9 @@ public class Items implements ContentList{
|
||||
|
||||
thorium = new Item("thorium", Color.valueOf("f9a3c7")){{
|
||||
type = ItemType.material;
|
||||
explosiveness = 0.1f;
|
||||
explosiveness = 0.2f;
|
||||
hardness = 4;
|
||||
radioactivity = 0.5f;
|
||||
radioactivity = 1f;
|
||||
cost = 1.4f;
|
||||
genOre = true;
|
||||
}};
|
||||
@@ -70,39 +70,37 @@ public class Items implements ContentList{
|
||||
|
||||
plastanium = new Item("plastanium", Color.valueOf("cbd97f")){{
|
||||
type = ItemType.material;
|
||||
flammability = 0.1f;
|
||||
explosiveness = 0.1f;
|
||||
flammability = 0.2f;
|
||||
explosiveness = 0.2f;
|
||||
cost = 1.6f;
|
||||
}};
|
||||
|
||||
phasefabric = new Item("phase-fabric", Color.valueOf("f4ba6e")){{
|
||||
type = ItemType.material;
|
||||
cost = 1.5f;
|
||||
fluxiness = 0.9f;
|
||||
radioactivity = 0.3f;
|
||||
radioactivity = 0.6f;
|
||||
}};
|
||||
|
||||
surgealloy = new Item("surge-alloy", Color.valueOf("f3e979")){{
|
||||
type = ItemType.material;
|
||||
}};
|
||||
|
||||
biomatter = new Item("biomatter", Color.valueOf("648b55")){{
|
||||
flammability = 0.55f;
|
||||
fluxiness = 0.3f;
|
||||
sporePod = new Item("spore-pod", Color.valueOf("7457ce")){{
|
||||
flammability = 1.05f;
|
||||
}};
|
||||
|
||||
sand = new Item("sand", Color.valueOf("e3d39e")){{
|
||||
fluxiness = 0.5f;
|
||||
sand = new Item("sand", Color.valueOf("f7cba4")){{
|
||||
|
||||
}};
|
||||
|
||||
blastCompound = new Item("blast-compound", Color.valueOf("ff795e")){{
|
||||
flammability = 0.2f;
|
||||
explosiveness = 0.6f;
|
||||
flammability = 0.4f;
|
||||
explosiveness = 1.2f;
|
||||
}};
|
||||
|
||||
pyratite = new Item("pyratite", Color.valueOf("ffaa5f")){{
|
||||
flammability = 0.7f;
|
||||
explosiveness = 0.2f;
|
||||
flammability = 1.4f;
|
||||
explosiveness = 0.4f;
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,32 +10,28 @@ public class Liquids implements ContentList{
|
||||
@Override
|
||||
public void load(){
|
||||
|
||||
water = new Liquid("water", Color.valueOf("486acd")){{
|
||||
water = new Liquid("water", Color.valueOf("596ab8")){{
|
||||
heatCapacity = 0.4f;
|
||||
tier = 0;
|
||||
effect = StatusEffects.wet;
|
||||
}};
|
||||
|
||||
slag = new Liquid("slag", Color.valueOf("ffcd66")){{
|
||||
slag = new Liquid("slag", Color.valueOf("ffa166")){{
|
||||
temperature = 1f;
|
||||
viscosity = 0.8f;
|
||||
tier = 2;
|
||||
effect = StatusEffects.melting;
|
||||
}};
|
||||
|
||||
oil = new Liquid("oil", Color.valueOf("313131")){{
|
||||
viscosity = 0.7f;
|
||||
flammability = 0.6f;
|
||||
explosiveness = 0.6f;
|
||||
flammability = 1.2f;
|
||||
explosiveness = 1.2f;
|
||||
heatCapacity = 0.7f;
|
||||
tier = 1;
|
||||
effect = StatusEffects.tarred;
|
||||
}};
|
||||
|
||||
cryofluid = new Liquid("cryofluid", Color.valueOf("6ecdec")){{
|
||||
heatCapacity = 0.9f;
|
||||
temperature = 0.25f;
|
||||
tier = 1;
|
||||
effect = StatusEffects.freezing;
|
||||
}};
|
||||
}
|
||||
|
||||
54
core/src/io/anuke/mindustry/content/Loadouts.java
Normal file
54
core/src/io/anuke/mindustry/content/Loadouts.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package io.anuke.mindustry.content;
|
||||
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.type.Loadout;
|
||||
|
||||
public class Loadouts implements ContentList{
|
||||
public static Loadout
|
||||
basicShard,
|
||||
advancedShard,
|
||||
basicFoundation,
|
||||
basicNucleus;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
basicShard = new Loadout(
|
||||
" ### ",
|
||||
" #1# ",
|
||||
" ### ",
|
||||
" ^ ^ ",
|
||||
" ## ## ",
|
||||
" C# C# "
|
||||
);
|
||||
|
||||
advancedShard = new Loadout(
|
||||
" ### ",
|
||||
" #1# ",
|
||||
"#######",
|
||||
"C#^ ^C#",
|
||||
" ## ## ",
|
||||
" C# C# "
|
||||
);
|
||||
|
||||
basicFoundation = new Loadout(
|
||||
" #### ",
|
||||
" #### ",
|
||||
" #2## ",
|
||||
" #### ",
|
||||
" ^^^^ ",
|
||||
" ###### ",
|
||||
" C#C#C# "
|
||||
);
|
||||
|
||||
basicNucleus = new Loadout(
|
||||
" ##### ",
|
||||
" ##### ",
|
||||
" ##3## ",
|
||||
" ##### ",
|
||||
" >#####< ",
|
||||
" ^ ^ ^ ^ ",
|
||||
"#### ####",
|
||||
"C#C# C#C#"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.anuke.mindustry.content;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.graphics.Blending;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
@@ -9,13 +8,15 @@ import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.effect.Lightning;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.graphics.Shaders;
|
||||
import io.anuke.mindustry.type.Mech;
|
||||
import io.anuke.mindustry.type.Weapon;
|
||||
|
||||
public class Mechs implements ContentList{
|
||||
public static Mech alpha, delta, tau, omega, dart, javelin, trident, glaive;
|
||||
@@ -34,9 +35,16 @@ public class Mechs implements ContentList{
|
||||
mass = 1.2f;
|
||||
speed = 0.5f;
|
||||
boostSpeed = 0.85f;
|
||||
weapon = Weapons.blaster;
|
||||
trailColorTo = Color.valueOf("ffd37f");
|
||||
armor = 20f;
|
||||
engineColor = Color.valueOf("ffd37f");
|
||||
health = 250f;
|
||||
|
||||
weapon = new Weapon("blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 14f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
bullet = Bullets.standardMechSmall;
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -54,11 +62,21 @@ public class Mechs implements ContentList{
|
||||
boostSpeed = 0.95f;
|
||||
itemCapacity = 15;
|
||||
mass = 0.9f;
|
||||
armor = 30f;
|
||||
health = 220f;
|
||||
weaponOffsetX = -1;
|
||||
weaponOffsetY = -1;
|
||||
weapon = Weapons.shockgun;
|
||||
trailColorTo = Color.valueOf("d3ddff");
|
||||
engineColor = Color.valueOf("d3ddff");
|
||||
|
||||
weapon = new Weapon("shockgun"){{
|
||||
length = 1f;
|
||||
reload = 40f;
|
||||
roundrobin = true;
|
||||
shots = 1;
|
||||
inaccuracy = 0f;
|
||||
velocityRnd = 0.2f;
|
||||
ejectEffect = Fx.none;
|
||||
bullet = Bullets.lightning;
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -67,7 +85,7 @@ public class Mechs implements ContentList{
|
||||
Effects.shake(1f, 1f, player);
|
||||
Effects.effect(Fx.landShock, player);
|
||||
for(int i = 0; i < 8; i++){
|
||||
Time.run(Mathf.random(8f), () -> Lightning.create(player.getTeam(), Palette.lancerLaser, 17f, player.x, player.y, Mathf.random(360f), 14));
|
||||
Time.run(Mathf.random(8f), () -> Lightning.create(player.getTeam(), Pal.lancerLaser, 17f, player.x, player.y, Mathf.random(360f), 14));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,9 +109,17 @@ public class Mechs implements ContentList{
|
||||
drag = 0.35f;
|
||||
boostSpeed = 0.8f;
|
||||
canHeal = true;
|
||||
weapon = Weapons.healBlaster;
|
||||
armor = 15f;
|
||||
trailColorTo = Palette.heal;
|
||||
health = 200f;
|
||||
engineColor = Pal.heal;
|
||||
|
||||
weapon = new Weapon("heal-blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 24f;
|
||||
roundrobin = false;
|
||||
ejectEffect = Fx.none;
|
||||
recoil = 2f;
|
||||
bullet = Bullets.healBullet;
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -133,9 +159,20 @@ public class Mechs implements ContentList{
|
||||
shake = 4f;
|
||||
weaponOffsetX = 1;
|
||||
weaponOffsetY = 0;
|
||||
weapon = Weapons.swarmer;
|
||||
trailColorTo = Color.valueOf("feb380");
|
||||
armor = 45f;
|
||||
engineColor = Color.valueOf("feb380");
|
||||
health = 300f;
|
||||
weapon = new Weapon("swarmer"){{
|
||||
length = 1.5f;
|
||||
recoil = 4f;
|
||||
reload = 60f;
|
||||
shots = 4;
|
||||
spacing = 8f;
|
||||
inaccuracy = 8f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
shake = 3f;
|
||||
bullet = Bullets.missileSwarm;
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -169,16 +206,13 @@ public class Mechs implements ContentList{
|
||||
public void draw(Player player){
|
||||
if(player.shootHeat <= 0.01f) return;
|
||||
|
||||
float alpha = Draw.getColor().a;
|
||||
Shaders.build.progress = player.shootHeat;
|
||||
Shaders.build.region = armorRegion;
|
||||
Shaders.build.time = Time.time() / 10f;
|
||||
Shaders.build.color.set(Palette.accent).a = player.shootHeat;
|
||||
Shaders.build.color.set(Pal.accent).a = player.shootHeat;
|
||||
Draw.shader(Shaders.build);
|
||||
Draw.alpha(1f);
|
||||
Draw.rect(armorRegion, player.x, player.y, player.rotation);
|
||||
Draw.shader(Shaders.mix);
|
||||
Draw.color(1f, 1f, 1f, alpha);
|
||||
Draw.shader();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -188,12 +222,18 @@ public class Mechs implements ContentList{
|
||||
mineSpeed = 0.9f;
|
||||
speed = 0.4f;
|
||||
drag = 0.1f;
|
||||
armor = 10f;
|
||||
weapon = Weapons.blasterSmall;
|
||||
health = 180f;
|
||||
weaponOffsetX = -1;
|
||||
weaponOffsetY = -1;
|
||||
trailColor = Palette.lightTrail;
|
||||
engineColor = Pal.lightTrail;
|
||||
cellTrnsY = 1f;
|
||||
weapon = new Weapon("blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 20f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
bullet = Bullets.standardCopper;
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -211,10 +251,20 @@ public class Mechs implements ContentList{
|
||||
speed = 0.11f;
|
||||
drag = 0.01f;
|
||||
mass = 2f;
|
||||
armor = 5f;
|
||||
weapon = Weapons.missiles;
|
||||
trailColor = Color.valueOf("d3ddff");
|
||||
health = 170f;
|
||||
engineColor = Color.valueOf("d3ddff");
|
||||
cellTrnsY = 1f;
|
||||
weapon = new Weapon("missiles"){{
|
||||
length = 1.5f;
|
||||
reload = 70f;
|
||||
shots = 4;
|
||||
inaccuracy = 2f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
velocityRnd = 0.2f;
|
||||
spacing = 1f;
|
||||
bullet = Bullets.missileJavelin;
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -232,8 +282,8 @@ public class Mechs implements ContentList{
|
||||
public void updateAlt(Player player){
|
||||
float scl = scld(player);
|
||||
if(Mathf.chance(Time.delta() * (0.15*scl))){
|
||||
Effects.effect(Fx.hitLancer, Palette.lancerLaser, player.x, player.y);
|
||||
Lightning.create(player.getTeam(), Palette.lancerLaser, 10f,
|
||||
Effects.effect(Fx.hitLancer, Pal.lancerLaser, player.x, player.y);
|
||||
Lightning.create(player.getTeam(), Pal.lancerLaser, 10f,
|
||||
player.x + player.velocity().x, player.y + player.velocity().y, player.rotation, 14);
|
||||
}
|
||||
}
|
||||
@@ -242,16 +292,11 @@ public class Mechs implements ContentList{
|
||||
public void draw(Player player){
|
||||
float scl = scld(player);
|
||||
if(scl < 0.01f) return;
|
||||
float alpha = Draw.getColor().a;
|
||||
Draw.shader();
|
||||
Draw.color(Palette.lancerLaser);
|
||||
Draw.color(Pal.lancerLaser);
|
||||
Draw.alpha(scl/2f);
|
||||
Draw.blend(Blending.additive);
|
||||
Draw.rect(shield, player.x + Mathf.range(scl/2f), player.y + Mathf.range(scl/2f), player.rotation - 90);
|
||||
Draw.blend();
|
||||
Draw.shader(Shaders.mix);
|
||||
Draw.color();
|
||||
Draw.alpha(alpha);
|
||||
}
|
||||
|
||||
float scld(Player player){
|
||||
@@ -266,11 +311,22 @@ public class Mechs implements ContentList{
|
||||
drag = 0.034f;
|
||||
mass = 2.5f;
|
||||
turnCursor = false;
|
||||
armor = 20f;
|
||||
health = 220f;
|
||||
itemCapacity = 30;
|
||||
trailColor = Color.valueOf("84f491");
|
||||
weapon = Weapons.bomberTrident;
|
||||
engineColor = Color.valueOf("84f491");
|
||||
cellTrnsY = 1f;
|
||||
weapon = new Weapon("bomber"){{
|
||||
length = 0f;
|
||||
width = 2f;
|
||||
reload = 8f;
|
||||
shots = 2;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
velocityRnd = 1f;
|
||||
inaccuracy = 40f;
|
||||
ignoreRotation = true;
|
||||
bullet = Bullets.bombExplosive;
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -281,16 +337,23 @@ public class Mechs implements ContentList{
|
||||
|
||||
glaive = new Mech("glaive-ship", true){
|
||||
{
|
||||
weapon = Weapons.glaiveBlaster;
|
||||
drillPower = 4;
|
||||
mineSpeed = 1.3f;
|
||||
speed = 0.32f;
|
||||
drag = 0.06f;
|
||||
mass = 3f;
|
||||
armor = 30f;
|
||||
health = 240f;
|
||||
itemCapacity = 60;
|
||||
trailColor = Color.valueOf("feb380");
|
||||
engineColor = Color.valueOf("feb380");
|
||||
cellTrnsY = 1f;
|
||||
|
||||
weapon = new Weapon("bomber"){{
|
||||
length = 1.5f;
|
||||
reload = 13f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
bullet = Bullets.standardGlaive;
|
||||
}};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package io.anuke.mindustry.content;
|
||||
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.type.StatusEffect;
|
||||
|
||||
public class StatusEffects implements ContentList{
|
||||
public static StatusEffect none, burning, freezing, wet, melting, tarred, overdrive, shielded, shocked, corroded;
|
||||
public static StatusEffect none, burning, freezing, wet, melting, tarred, overdrive, shielded, shocked, corroded, boss;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
@@ -71,6 +71,14 @@ public class StatusEffects implements ContentList{
|
||||
armorMultiplier = 3f;
|
||||
}};
|
||||
|
||||
boss = new StatusEffect(){{
|
||||
armorMultiplier = 3f;
|
||||
damageMultiplier = 3f;
|
||||
speedMultiplier = 1.1f;
|
||||
//TODO custom effect
|
||||
//effect = Fx.overdriven;
|
||||
}};
|
||||
|
||||
shocked = new StatusEffect();
|
||||
|
||||
//no effects, just small amounts of damage.
|
||||
|
||||
@@ -12,12 +12,9 @@ public class TechTree implements ContentList{
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
root = node(core, () -> {
|
||||
root = node(coreShard, () -> {
|
||||
|
||||
node(conveyor, () -> {
|
||||
node(launchPad, () -> {
|
||||
|
||||
});
|
||||
|
||||
node(junction, () -> {
|
||||
node(itemBridge);
|
||||
@@ -28,14 +25,17 @@ public class TechTree implements ContentList{
|
||||
node(container, () -> {
|
||||
node(unloader);
|
||||
node(vault, () -> {
|
||||
node(launchPad, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
node(titaniumConveyor, () -> {
|
||||
node(phaseConveyor, () -> {
|
||||
node(massDriver, () -> {
|
||||
|
||||
node(titaniumConveyor, () -> {
|
||||
node(phaseConveyor, () -> {
|
||||
node(massDriver, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -99,25 +99,24 @@ public class TechTree implements ContentList{
|
||||
});
|
||||
|
||||
node(mechanicalDrill, () -> {
|
||||
node(pneumaticDrill, () -> {
|
||||
node(cultivator, () -> {
|
||||
|
||||
});
|
||||
|
||||
node(laserDrill, () -> {
|
||||
node(blastDrill, () -> {
|
||||
node(graphitePress, () -> {
|
||||
node(pneumaticDrill, () -> {
|
||||
node(cultivator, () -> {
|
||||
|
||||
});
|
||||
|
||||
node(waterExtractor, () -> {
|
||||
node(oilExtractor, () -> {
|
||||
node(laserDrill, () -> {
|
||||
node(blastDrill, () -> {
|
||||
|
||||
});
|
||||
|
||||
node(waterExtractor, () -> {
|
||||
node(oilExtractor, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(siliconSmelter, () -> {
|
||||
|
||||
node(pyratiteMixer, () -> {
|
||||
node(blastMixer, () -> {
|
||||
@@ -125,33 +124,44 @@ public class TechTree implements ContentList{
|
||||
});
|
||||
});
|
||||
|
||||
node(biomatterCompressor, () -> {
|
||||
node(plastaniumCompressor, () -> {
|
||||
node(phaseWeaver, () -> {
|
||||
node(siliconSmelter, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(incinerator, () -> {
|
||||
node(melter, () -> {
|
||||
node(surgeSmelter, () -> {
|
||||
node(sporePress, () -> {
|
||||
node(multiPress, () -> {
|
||||
|
||||
});
|
||||
|
||||
node(separator, () -> {
|
||||
node(pulverizer, () -> {
|
||||
node(plastaniumCompressor, () -> {
|
||||
node(phaseWeaver, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(cryofluidMixer, () -> {
|
||||
node(kiln, () -> {
|
||||
node(incinerator, () -> {
|
||||
node(melter, () -> {
|
||||
node(surgeSmelter, () -> {
|
||||
|
||||
});
|
||||
|
||||
node(separator, () -> {
|
||||
node(pulverizer, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(cryofluidMixer, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
node(mechanicalPump, () -> {
|
||||
node(conduit, () -> {
|
||||
node(liquidJunction, () -> {
|
||||
@@ -174,72 +184,69 @@ public class TechTree implements ContentList{
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(powerNode, () -> {
|
||||
node(combustionGenerator, () -> {
|
||||
node(powerNodeLarge, () -> {
|
||||
node(battery, () -> {
|
||||
node(batteryLarge, () -> {
|
||||
node(powerNode, () -> {
|
||||
node(powerNodeLarge, () -> {
|
||||
node(battery, () -> {
|
||||
node(batteryLarge, () -> {
|
||||
node(surgeTower, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(mendProjector, () -> {
|
||||
node(forceProjector, () -> {
|
||||
node(overdriveProjector, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(repairPoint, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(turbineGenerator, () -> {
|
||||
node(thermalGenerator, () -> {
|
||||
node(rtgGenerator, () -> {
|
||||
node(thoriumReactor, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(solarPanel, () -> {
|
||||
node(largeSolarPanel, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(alphaPad, () -> {
|
||||
node(dartPad);
|
||||
node(deltaPad, () -> {
|
||||
node(javelinPad);
|
||||
node(tauPad, () -> {
|
||||
node(tridentPad);
|
||||
node(omegaPad, () -> {
|
||||
node(glaivePad);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(spiritFactory, () -> {
|
||||
node(daggerFactory, () -> {
|
||||
node(daggerFactory, () -> {
|
||||
node(titanFactory, () -> {
|
||||
node(fortressFactory);
|
||||
});
|
||||
node(wraithFactory, () -> {
|
||||
node(phantomFactory);
|
||||
node(ghoulFactory, () -> {
|
||||
node(revenantFactory);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(mendProjector, () -> {
|
||||
node(forceProjector, () -> {
|
||||
node(overdriveProjector, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(repairPoint, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(turbineGenerator, () -> {
|
||||
node(thermalGenerator, () -> {
|
||||
node(rtgGenerator, () -> {
|
||||
node(differentialGenerator, () -> {
|
||||
node(thoriumReactor, () -> {
|
||||
node(impactReactor, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(solarPanel, () -> {
|
||||
node(largeSolarPanel, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(alphaDartPad, () -> {
|
||||
node(deltaPad, () -> {
|
||||
node(spiritFactory, () -> {
|
||||
node(phantomFactory);
|
||||
});
|
||||
|
||||
node(javelinPad, () -> {
|
||||
node(tridentPad, () -> {
|
||||
node(glaivePad);
|
||||
});
|
||||
});
|
||||
|
||||
node(tauPad, () -> {
|
||||
node(omegaPad, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -250,7 +257,7 @@ public class TechTree implements ContentList{
|
||||
private TechNode node(Block block, Runnable children){
|
||||
ItemStack[] requirements = new ItemStack[block.buildRequirements.length];
|
||||
for(int i = 0; i < requirements.length; i++){
|
||||
requirements[i] = new ItemStack(block.buildRequirements[i].item, block.buildRequirements[i].amount * 50);
|
||||
requirements[i] = new ItemStack(block.buildRequirements[i].item, block.buildRequirements[i].amount * 8);
|
||||
}
|
||||
|
||||
return new TechNode(block, requirements, children);
|
||||
@@ -272,7 +279,6 @@ public class TechTree implements ContentList{
|
||||
context.children.add(this);
|
||||
}
|
||||
|
||||
//TODO remove requirements... for now
|
||||
this.block = block;
|
||||
this.requirements = requirements;
|
||||
|
||||
|
||||
@@ -1,26 +1,37 @@
|
||||
package io.anuke.mindustry.content;
|
||||
|
||||
import io.anuke.arc.collection.ObjectSet;
|
||||
import io.anuke.mindustry.entities.units.UnitType;
|
||||
import io.anuke.mindustry.entities.units.types.*;
|
||||
import io.anuke.mindustry.entities.type.base.*;
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.type.UnitType;
|
||||
import io.anuke.mindustry.type.Weapon;
|
||||
|
||||
public class UnitTypes implements ContentList{
|
||||
public static UnitType
|
||||
spirit, phantom,
|
||||
wraith, ghoul, revenant,
|
||||
dagger, titan, fortress;
|
||||
wraith, ghoul, revenant, lich, reaper,
|
||||
dagger, crawler, titan, fortress, eruptor, chaosArray, eradicator;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
spirit = new UnitType("spirit", Spirit.class, Spirit::new){{
|
||||
weapon = Weapons.healBlasterDrone;
|
||||
isFlying = true;
|
||||
drag = 0.01f;
|
||||
speed = 0.2f;
|
||||
maxVelocity = 0.8f;
|
||||
range = 50f;
|
||||
health = 60;
|
||||
engineSize = 1.8f;
|
||||
engineOffset = 5.7f;
|
||||
weapon = new Weapon("heal-blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 40f;
|
||||
width = 0.5f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
recoil = 2f;
|
||||
bullet = Bullets.healBullet;
|
||||
}};
|
||||
}};
|
||||
|
||||
dagger = new UnitType("dagger", Dagger.class, Dagger::new){{
|
||||
@@ -29,8 +40,28 @@ public class UnitTypes implements ContentList{
|
||||
drag = 0.4f;
|
||||
hitsize = 8f;
|
||||
mass = 1.75f;
|
||||
weapon = Weapons.chainBlaster;
|
||||
health = 130;
|
||||
weapon = new Weapon("chain-blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 28f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
bullet = Bullets.standardCopper;
|
||||
}};
|
||||
}};
|
||||
|
||||
crawler = new UnitType("crawler", Crawler.class, Crawler::new){{
|
||||
maxVelocity = 1.2f;
|
||||
speed = 0.26f;
|
||||
drag = 0.4f;
|
||||
hitsize = 8f;
|
||||
mass = 1.75f;
|
||||
health = 100;
|
||||
weapon = new Weapon("bomber"){{
|
||||
reload = 12f;
|
||||
ejectEffect = Fx.none;
|
||||
bullet = Bullets.explode;
|
||||
}};
|
||||
}};
|
||||
|
||||
titan = new UnitType("titan", Titan.class, Titan::new){{
|
||||
@@ -40,21 +71,105 @@ public class UnitTypes implements ContentList{
|
||||
mass = 3.5f;
|
||||
hitsize = 9f;
|
||||
rotatespeed = 0.1f;
|
||||
weapon = Weapons.flamethrower;
|
||||
health = 440;
|
||||
immunities.add(StatusEffects.burning);
|
||||
weapon = new Weapon("flamethrower"){{
|
||||
length = 1f;
|
||||
reload = 14f;
|
||||
roundrobin = true;
|
||||
recoil = 1f;
|
||||
ejectEffect = Fx.none;
|
||||
bullet = Bullets.basicFlame;
|
||||
}};
|
||||
}};
|
||||
|
||||
fortress = new UnitType("fortress", Fortress.class, Fortress::new){{
|
||||
maxVelocity = 0.8f;
|
||||
maxVelocity = 0.78f;
|
||||
speed = 0.15f;
|
||||
drag = 0.4f;
|
||||
mass = 5f;
|
||||
hitsize = 10f;
|
||||
rotatespeed = 0.06f;
|
||||
weaponOffsetX = 1;
|
||||
targetAir = false;
|
||||
weapon = Weapons.artillery;
|
||||
health = 800;
|
||||
weapon = new Weapon("artillery"){{
|
||||
length = 1f;
|
||||
reload = 60f;
|
||||
width = 10f;
|
||||
roundrobin = true;
|
||||
recoil = 4f;
|
||||
shake = 2f;
|
||||
ejectEffect = Fx.shellEjectMedium;
|
||||
bullet = Bullets.artilleryUnit;
|
||||
}};
|
||||
}};
|
||||
|
||||
eruptor = new UnitType("eruptor", Eruptor.class, Eruptor::new){{
|
||||
maxVelocity = 0.81f;
|
||||
speed = 0.16f;
|
||||
drag = 0.4f;
|
||||
mass = 5f;
|
||||
hitsize = 9f;
|
||||
rotatespeed = 0.05f;
|
||||
targetAir = false;
|
||||
health = 600;
|
||||
immunities = ObjectSet.with(StatusEffects.burning, StatusEffects.melting);
|
||||
weapon = new Weapon("eruption"){{
|
||||
length = 3f;
|
||||
reload = 10f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
bullet = Bullets.eruptorShot;
|
||||
recoil = 1f;
|
||||
width = 7f;
|
||||
}};
|
||||
}};
|
||||
|
||||
chaosArray = new UnitType("chaos-array", Dagger.class, Dagger::new){{
|
||||
maxVelocity = 0.68f;
|
||||
speed = 0.12f;
|
||||
drag = 0.4f;
|
||||
mass = 5f;
|
||||
hitsize = 20f;
|
||||
rotatespeed = 0.06f;
|
||||
health = 4000;
|
||||
weapon = new Weapon("chaos"){{
|
||||
length = 8f;
|
||||
reload = 50f;
|
||||
width = 17f;
|
||||
roundrobin = true;
|
||||
recoil = 3f;
|
||||
shake = 2f;
|
||||
shots = 4;
|
||||
spacing = 4f;
|
||||
shotDelay = 5;
|
||||
ejectEffect = Fx.shellEjectMedium;
|
||||
bullet = Bullets.flakSurge;
|
||||
}};
|
||||
}};
|
||||
|
||||
eradicator = new UnitType("eradicator", Dagger.class, Dagger::new){{
|
||||
maxVelocity = 0.68f;
|
||||
speed = 0.12f;
|
||||
drag = 0.4f;
|
||||
mass = 5f;
|
||||
hitsize = 20f;
|
||||
rotatespeed = 0.06f;
|
||||
health = 10000;
|
||||
weapon = new Weapon("eradication"){{
|
||||
length = 13f;
|
||||
reload = 30f;
|
||||
width = 22f;
|
||||
roundrobin = true;
|
||||
recoil = 3f;
|
||||
shake = 2f;
|
||||
inaccuracy = 3f;
|
||||
shots = 4;
|
||||
spacing = 0f;
|
||||
shotDelay = 3;
|
||||
ejectEffect = Fx.shellEjectMedium;
|
||||
bullet = Bullets.standardThoriumBig;
|
||||
}};
|
||||
}};
|
||||
|
||||
wraith = new UnitType("wraith", Wraith.class, Wraith::new){{
|
||||
@@ -62,9 +177,16 @@ public class UnitTypes implements ContentList{
|
||||
maxVelocity = 1.9f;
|
||||
drag = 0.01f;
|
||||
mass = 1.5f;
|
||||
weapon = Weapons.chainBlaster;
|
||||
isFlying = true;
|
||||
health = 70;
|
||||
engineOffset = 5.5f;
|
||||
weapon = new Weapon("chain-blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 28f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
bullet = Bullets.standardCopper;
|
||||
}};
|
||||
}};
|
||||
|
||||
ghoul = new UnitType("ghoul", Ghoul.class, Ghoul::new){{
|
||||
@@ -75,23 +197,21 @@ public class UnitTypes implements ContentList{
|
||||
drag = 0.01f;
|
||||
isFlying = true;
|
||||
targetAir = false;
|
||||
weapon = Weapons.bomber;
|
||||
}};
|
||||
|
||||
revenant = new UnitType("revenant", Revenant.class, Revenant::new){{
|
||||
health = 250;
|
||||
mass = 5f;
|
||||
hitsize = 12f;
|
||||
speed = 0.14f;
|
||||
maxVelocity = 1.3f;
|
||||
drag = 0.01f;
|
||||
range = 80f;
|
||||
isFlying = true;
|
||||
weapon = Weapons.laserBurster;
|
||||
engineOffset = 7.8f;
|
||||
weapon = new Weapon("bomber"){{
|
||||
length = 0f;
|
||||
width = 2f;
|
||||
reload = 12f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
velocityRnd = 1f;
|
||||
inaccuracy = 40f;
|
||||
ignoreRotation = true;
|
||||
bullet = Bullets.bombExplosive;
|
||||
}};
|
||||
}};
|
||||
|
||||
phantom = new UnitType("phantom", Phantom.class, Phantom::new){{
|
||||
weapon = Weapons.healBlasterDrone2;
|
||||
isFlying = true;
|
||||
drag = 0.01f;
|
||||
mass = 2f;
|
||||
@@ -102,7 +222,107 @@ public class UnitTypes implements ContentList{
|
||||
health = 220;
|
||||
buildPower = 0.9f;
|
||||
minePower = 1.1f;
|
||||
engineOffset = 6.5f;
|
||||
toMine = ObjectSet.with(Items.lead, Items.copper, Items.titanium);
|
||||
weapon = new Weapon("heal-blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 20f;
|
||||
width = 0.5f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
recoil = 2f;
|
||||
bullet = Bullets.healBullet;
|
||||
}};
|
||||
}};
|
||||
|
||||
revenant = new UnitType("revenant", Revenant.class, Revenant::new){{
|
||||
health = 1000;
|
||||
mass = 5f;
|
||||
hitsize = 20f;
|
||||
speed = 0.1f;
|
||||
maxVelocity = 1f;
|
||||
drag = 0.01f;
|
||||
range = 80f;
|
||||
shootCone = 40f;
|
||||
isFlying = true;
|
||||
rotateWeapon = true;
|
||||
engineOffset = 12f;
|
||||
engineSize = 3f;
|
||||
rotatespeed = 0.01f;
|
||||
attackLength = 90f;
|
||||
baseRotateSpeed = 0.06f;
|
||||
weapon = new Weapon("revenant-missiles"){{
|
||||
length = 3f;
|
||||
reload = 70f;
|
||||
width = 10f;
|
||||
shots = 2;
|
||||
inaccuracy = 2f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
velocityRnd = 0.2f;
|
||||
spacing = 1f;
|
||||
bullet = Bullets.missileRevenant;
|
||||
}};
|
||||
}};
|
||||
|
||||
lich = new UnitType("lich", Revenant.class, Revenant::new){{
|
||||
health = 7000;
|
||||
mass = 20f;
|
||||
hitsize = 40f;
|
||||
speed = 0.01f;
|
||||
maxVelocity = 0.6f;
|
||||
drag = 0.02f;
|
||||
range = 80f;
|
||||
shootCone = 20f;
|
||||
isFlying = true;
|
||||
rotateWeapon = true;
|
||||
engineOffset = 21;
|
||||
engineSize = 5.3f;
|
||||
rotatespeed = 0.01f;
|
||||
attackLength = 90f;
|
||||
baseRotateSpeed = 0.04f;
|
||||
weapon = new Weapon("lich-missiles"){{
|
||||
length = 4f;
|
||||
reload = 180f;
|
||||
width = 22f;
|
||||
shots = 22;
|
||||
shotDelay = 2;
|
||||
inaccuracy = 10f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
velocityRnd = 0.2f;
|
||||
spacing = 1f;
|
||||
bullet = Bullets.missileRevenant;
|
||||
}};
|
||||
}};
|
||||
|
||||
reaper = new UnitType("reaper", Revenant.class, Revenant::new){{
|
||||
health = 13000;
|
||||
mass = 30f;
|
||||
hitsize = 56f;
|
||||
speed = 0.01f;
|
||||
maxVelocity = 0.6f;
|
||||
drag = 0.02f;
|
||||
range = 80f;
|
||||
shootCone = 30f;
|
||||
isFlying = true;
|
||||
rotateWeapon = true;
|
||||
engineOffset = 40;
|
||||
engineSize = 7.3f;
|
||||
rotatespeed = 0.01f;
|
||||
baseRotateSpeed = 0.04f;
|
||||
weapon = new Weapon("reaper-gun"){{
|
||||
length = 3f;
|
||||
reload = 10f;
|
||||
width = 32f;
|
||||
shots = 1;
|
||||
|
||||
shake = 1f;
|
||||
inaccuracy = 3f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
bullet = Bullets.standardDenseBig;
|
||||
}};
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
package io.anuke.mindustry.content;
|
||||
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.type.Weapon;
|
||||
|
||||
public class Weapons implements ContentList{
|
||||
public static Weapon blaster, blasterSmall, glaiveBlaster, droneBlaster, healBlaster, healBlasterDrone, chainBlaster, shockgun,
|
||||
swarmer, bomber, bomberTrident, flakgun, flamethrower, missiles, artillery, laserBurster, healBlasterDrone2;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
|
||||
blaster = new Weapon("blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 14f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
ammo = Bullets.standardMechSmall;
|
||||
}};
|
||||
|
||||
blasterSmall = new Weapon("blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 20f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
ammo = Bullets.standardCopper;
|
||||
}};
|
||||
|
||||
glaiveBlaster = new Weapon("bomber"){{
|
||||
length = 1.5f;
|
||||
reload = 13f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
ammo = Bullets.standardGlaive;
|
||||
}};
|
||||
|
||||
droneBlaster = new Weapon("blaster"){{
|
||||
length = 2f;
|
||||
reload = 25f;
|
||||
width = 1f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
ammo = Bullets.standardCopper;
|
||||
}};
|
||||
|
||||
healBlaster = new Weapon("heal-blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 24f;
|
||||
roundrobin = false;
|
||||
ejectEffect = Fx.none;
|
||||
recoil = 2f;
|
||||
ammo = Bullets.healBullet;
|
||||
}};
|
||||
|
||||
missiles = new Weapon("missiles"){{
|
||||
length = 1.5f;
|
||||
reload = 70f;
|
||||
shots = 4;
|
||||
inaccuracy = 2f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
velocityRnd = 0.2f;
|
||||
spacing = 1f;
|
||||
ammo = Bullets.missileJavelin;
|
||||
}};
|
||||
|
||||
swarmer = new Weapon("swarmer"){{
|
||||
length = 1.5f;
|
||||
recoil = 4f;
|
||||
reload = 60f;
|
||||
shots = 4;
|
||||
spacing = 8f;
|
||||
inaccuracy = 8f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
shake = 3f;
|
||||
ammo = Bullets.missileSwarm;
|
||||
}};
|
||||
|
||||
chainBlaster = new Weapon("chain-blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 28f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.shellEjectSmall;
|
||||
ammo = Bullets.standardCopper;
|
||||
}};
|
||||
|
||||
shockgun = new Weapon("shockgun"){{
|
||||
length = 1f;
|
||||
reload = 40f;
|
||||
roundrobin = true;
|
||||
shots = 1;
|
||||
inaccuracy = 0f;
|
||||
velocityRnd = 0.2f;
|
||||
ejectEffect = Fx.none;
|
||||
ammo = Bullets.lightning;
|
||||
}};
|
||||
|
||||
flakgun = new Weapon("flakgun"){{
|
||||
length = 1f;
|
||||
reload = 70f;
|
||||
roundrobin = true;
|
||||
shots = 1;
|
||||
inaccuracy = 3f;
|
||||
recoil = 3f;
|
||||
velocityRnd = 0.1f;
|
||||
ejectEffect = Fx.shellEjectMedium;
|
||||
ammo = Bullets.artilleryDense;
|
||||
}};
|
||||
|
||||
flamethrower = new Weapon("flamethrower"){{
|
||||
length = 1f;
|
||||
reload = 14f;
|
||||
roundrobin = true;
|
||||
recoil = 1f;
|
||||
ejectEffect = Fx.none;
|
||||
ammo = Bullets.basicFlame;
|
||||
}};
|
||||
|
||||
artillery = new Weapon("artillery"){{
|
||||
length = 1f;
|
||||
reload = 60f;
|
||||
roundrobin = true;
|
||||
recoil = 5f;
|
||||
shake = 2f;
|
||||
ejectEffect = Fx.shellEjectMedium;
|
||||
ammo = Bullets.artilleryUnit;
|
||||
}};
|
||||
|
||||
bomber = new Weapon("bomber"){{
|
||||
length = 0f;
|
||||
width = 2f;
|
||||
reload = 12f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
velocityRnd = 1f;
|
||||
inaccuracy = 40f;
|
||||
ammo = Bullets.bombExplosive;
|
||||
}};
|
||||
|
||||
bomberTrident = new Weapon("bomber"){{
|
||||
length = 0f;
|
||||
width = 2f;
|
||||
reload = 8f;
|
||||
shots = 2;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
velocityRnd = 1f;
|
||||
inaccuracy = 40f;
|
||||
ammo = Bullets.bombExplosive;
|
||||
}};
|
||||
|
||||
laserBurster = new Weapon("bomber"){{
|
||||
reload = 80f;
|
||||
shake = 3f;
|
||||
width = 0f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
ammo = Bullets.lancerLaser;
|
||||
}};
|
||||
|
||||
healBlasterDrone = new Weapon("heal-blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 40f;
|
||||
width = 0.5f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
recoil = 2f;
|
||||
ammo = Bullets.healBullet;
|
||||
}};
|
||||
|
||||
healBlasterDrone2 = new Weapon("heal-blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 20f;
|
||||
width = 0.5f;
|
||||
roundrobin = true;
|
||||
ejectEffect = Fx.none;
|
||||
recoil = 2f;
|
||||
ammo = Bullets.healBullet;
|
||||
}};
|
||||
}
|
||||
}
|
||||
@@ -5,101 +5,267 @@ import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.game.Rules;
|
||||
import io.anuke.mindustry.game.SpawnGroup;
|
||||
import io.anuke.mindustry.maps.generators.MapGenerator;
|
||||
import io.anuke.mindustry.maps.generators.MapGenerator.Decoration;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.type.Zone;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
|
||||
public class Zones implements ContentList{
|
||||
public static Zone groundZero, craters, frozenForest, ruinousShores, crags, stainedMountains,
|
||||
impact, desolateRift, arcticDesert, dryWastes, nuclearComplex, moltenFault;
|
||||
public static Zone groundZero, craters, frozenForest, ruinousShores, stainedMountains,
|
||||
desolateRift, nuclearComplex;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
|
||||
groundZero = new Zone("groundZero", new MapGenerator("groundZero", 1)){{
|
||||
deployCost = ItemStack.with(Items.copper, 60);
|
||||
startingItems = ItemStack.with(Items.copper, 50);
|
||||
baseLaunchCost = ItemStack.with(Items.copper, -100);
|
||||
startingItems = ItemStack.list(Items.copper, 100);
|
||||
alwaysUnlocked = true;
|
||||
conditionWave = 10;
|
||||
conditionWave = 5;
|
||||
launchPeriod = 5;
|
||||
resources = new Item[]{Items.copper, Items.scrap};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 60 * 2; //2 mins
|
||||
waveSpacing = 60 * 60 * 2;
|
||||
spawns = Array.with(
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
unitScaling = 2;
|
||||
unitScaling = 1.5f;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 10;
|
||||
begin = 5;
|
||||
unitScaling = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 15;
|
||||
unitScaling = 1;
|
||||
unitScaling = 3;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 20;
|
||||
unitScaling = 1;
|
||||
unitScaling = 3;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 25;
|
||||
unitScaling = 1;
|
||||
unitScaling = 3;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 30;
|
||||
unitScaling = 1;
|
||||
}}
|
||||
unitScaling = 2;
|
||||
}},
|
||||
|
||||
|
||||
bossGroup(UnitTypes.fortress)
|
||||
);
|
||||
}};
|
||||
}};
|
||||
|
||||
craters = new Zone("craters", new MapGenerator("craters", 1){{ distortion = 1.44f; }}){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
craters = new Zone("craters", new MapGenerator("craters", 1).dist(0)){{
|
||||
startingItems = ItemStack.list(Items.copper, 200);
|
||||
conditionWave = 10;
|
||||
itemRequirements = ItemStack.with(Items.copper, 2000);
|
||||
zoneRequirements = new Zone[]{groundZero};
|
||||
blockRequirements = new Block[]{Blocks.router};
|
||||
resources = new Item[]{Items.copper, Items.lead};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
waveSpacing = 60 * 60 * 1f;
|
||||
spawns = Array.with(
|
||||
new SpawnGroup(UnitTypes.crawler){{
|
||||
unitScaling = 2f;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.crawler){{
|
||||
begin = 5;
|
||||
unitAmount = 2;
|
||||
spacing = 2;
|
||||
unitScaling = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 3;
|
||||
unitScaling = 2f;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.crawler){{
|
||||
begin = 15;
|
||||
unitScaling = 1;
|
||||
unitAmount = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 20;
|
||||
unitScaling = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.crawler){{
|
||||
begin = 25;
|
||||
unitScaling = 1;
|
||||
unitAmount = 2;
|
||||
}},
|
||||
|
||||
bossGroup(UnitTypes.revenant)
|
||||
);
|
||||
}};
|
||||
}};
|
||||
|
||||
frozenForest = new Zone("frozenForest", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
frozenForest = new Zone("frozenForest", new MapGenerator("frozenForest", 1)
|
||||
.decor(new Decoration(Blocks.snow, Blocks.sporeCluster, 0.02))){{
|
||||
loadout = Loadouts.basicFoundation;
|
||||
baseLaunchCost = ItemStack.with(Items.copper, 100);
|
||||
startingItems = ItemStack.list(Items.copper, 400);
|
||||
conditionWave = 10;
|
||||
zoneRequirements = new Zone[]{craters};
|
||||
itemRequirements = ItemStack.with(Items.copper, 4000, Items.lead, 2000);
|
||||
resources = new Item[]{Items.copper, Items.lead, Items.coal};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 60 * 1.5f;
|
||||
spawns = Array.with(
|
||||
new SpawnGroup(UnitTypes.titan){{
|
||||
unitScaling = 3;
|
||||
end = 9;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
unitScaling = 2;
|
||||
begin = 2;
|
||||
end = 9;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
unitScaling = 2;
|
||||
begin = 5;
|
||||
end = 9;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.crawler){{
|
||||
unitScaling = 0.5f;
|
||||
begin = 10;
|
||||
spacing = 10;
|
||||
unitAmount = 5;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.titan){{
|
||||
begin = 11;
|
||||
unitAmount = 2;
|
||||
unitScaling = 2;
|
||||
spacing = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 12;
|
||||
unitAmount = 2;
|
||||
unitScaling = 2;
|
||||
spacing = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.crawler){{
|
||||
unitScaling = 0.5f;
|
||||
begin = 35;
|
||||
spacing = 10;
|
||||
unitAmount = 6;
|
||||
}},
|
||||
|
||||
//boss
|
||||
new SpawnGroup(UnitTypes.revenant){{
|
||||
begin = configureWave;
|
||||
effect = StatusEffects.boss;
|
||||
unitScaling = never;
|
||||
}},
|
||||
|
||||
bossGroup(UnitTypes.eruptor)
|
||||
);
|
||||
}};
|
||||
}};
|
||||
|
||||
ruinousShores = new Zone("ruinousShores", new MapGenerator("ruinousShores", 1).dist(3f, true)){{
|
||||
loadout = Loadouts.basicFoundation;
|
||||
baseLaunchCost = ItemStack.with(Items.copper, 200, Items.graphite, 50);
|
||||
startingItems = ItemStack.list(Items.copper, 400);
|
||||
conditionWave = 20;
|
||||
launchPeriod = 20;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
ruinousShores = new Zone("ruinousShores", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
itemRequirements = ItemStack.with(Items.lead, 6000, Items.graphite, 2000);
|
||||
blockRequirements = new Block[]{Blocks.graphitePress, Blocks.combustionGenerator};
|
||||
resources = new Item[]{Items.copper, Items.scrap, Items.lead, Items.coal, Items.sand};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
spawns = Array.with(
|
||||
new SpawnGroup(UnitTypes.wraith){{
|
||||
unitScaling = 2;
|
||||
spacing = 2;
|
||||
end = 10;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 1;
|
||||
spacing = 2;
|
||||
unitScaling = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.wraith){{
|
||||
begin = 10;
|
||||
unitScaling = 0.5f;
|
||||
unitAmount = 6;
|
||||
spacing = 10;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.crawler){{
|
||||
begin = 5;
|
||||
unitScaling = 1;
|
||||
spacing = 5;
|
||||
unitAmount = 1;
|
||||
effect = StatusEffects.overdrive;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.crawler){{
|
||||
begin = 22;
|
||||
unitScaling = 1;
|
||||
spacing = 20;
|
||||
unitScaling = 0.5f;
|
||||
unitAmount = 10;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 11;
|
||||
spacing = 2;
|
||||
unitScaling = 2;
|
||||
unitAmount = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 12;
|
||||
spacing = 2;
|
||||
unitScaling = 2;
|
||||
unitAmount = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.crawler){{
|
||||
begin = 12;
|
||||
spacing = 3;
|
||||
unitScaling = 3;
|
||||
unitAmount = 2;
|
||||
}},
|
||||
|
||||
bossGroup(UnitTypes.revenant),
|
||||
bossGroup(UnitTypes.revenant)
|
||||
);
|
||||
}};
|
||||
}};
|
||||
|
||||
/*
|
||||
crags = new Zone("crags", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
baseLaunchCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
@@ -109,99 +275,245 @@ public class Zones implements ContentList{
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
}};*/
|
||||
|
||||
stainedMountains = new Zone("stainedMountains", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
stainedMountains = new Zone("stainedMountains", new MapGenerator("stainedMountains", 2)
|
||||
.dist(2.5f, true)
|
||||
.decor(new Decoration(Blocks.moss, Blocks.stainedBoulder, 0.01))){{
|
||||
loadout = Loadouts.basicFoundation;
|
||||
baseLaunchCost = ItemStack.with(Items.copper, 100, Items.lead, 200, Items.silicon, 100);
|
||||
startingItems = ItemStack.list(Items.copper, 400, Items.lead, 100);
|
||||
conditionWave = 10;
|
||||
launchPeriod = 10;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
blockRequirements = new Block[]{Blocks.pneumaticDrill};
|
||||
itemRequirements = ItemStack.with(Items.copper, 8000, Items.silicon, 2000);
|
||||
resources = new Item[]{Items.copper, Items.scrap, Items.lead, Items.coal, Items.titanium};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
waveSpacing = 60 * 60 * 2;
|
||||
spawns = Array.with(
|
||||
new SpawnGroup(UnitTypes.titan){{
|
||||
unitScaling = 2;
|
||||
spacing = 2;
|
||||
end = 10;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 1;
|
||||
unitScaling = 1;
|
||||
spacing = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 11;
|
||||
spacing = 2;
|
||||
unitScaling = 2;
|
||||
unitAmount = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.ghoul){{
|
||||
begin = 6;
|
||||
unitScaling = 0.5f;
|
||||
unitAmount = 1;
|
||||
spacing = 5;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.wraith){{
|
||||
begin = 10;
|
||||
unitScaling = 1f;
|
||||
unitAmount = 1;
|
||||
spacing = 5;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 2;
|
||||
unitScaling = 1;
|
||||
spacing = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.wraith){{
|
||||
begin = 23;
|
||||
unitScaling = 1f;
|
||||
unitAmount = 1;
|
||||
spacing = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.crawler){{
|
||||
begin = 20;
|
||||
unitScaling = 1;
|
||||
spacing = 10;
|
||||
unitScaling = 0.5f;
|
||||
unitAmount = 10;
|
||||
}},
|
||||
|
||||
bossGroup(UnitTypes.chaosArray)
|
||||
);
|
||||
}};
|
||||
}};
|
||||
|
||||
impact = new Zone("impact", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
desolateRift = new Zone("desolateRift", new MapGenerator("desolateRift").dist(2f)){{
|
||||
loadout = Loadouts.basicNucleus;
|
||||
baseLaunchCost = ItemStack.with(Items.copper, 500);
|
||||
startingItems = ItemStack.list(Items.copper, 1500);
|
||||
itemRequirements = ItemStack.with(Items.copper, 8000, Items.metaglass, 2000, Items.graphite, 3000);
|
||||
conditionWave = 10;
|
||||
launchPeriod = 20;
|
||||
zoneRequirements = new Zone[]{ruinousShores};
|
||||
blockRequirements = new Block[]{Blocks.thermalGenerator};
|
||||
resources = new Item[]{Items.copper, Items.scrap, Items.lead, Items.coal, Items.titanium, Items.sand};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
waveSpacing = 60 * 60 * 1.5f;
|
||||
spawns = Array.with(
|
||||
new SpawnGroup(UnitTypes.crawler){{
|
||||
unitScaling = 1;
|
||||
spacing = 2;
|
||||
end = 10;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.titan){{
|
||||
begin = 1;
|
||||
unitScaling = 3;
|
||||
spacing = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 2;
|
||||
spacing = 2;
|
||||
unitScaling = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.titan){{
|
||||
begin = 10;
|
||||
unitScaling = 1f;
|
||||
unitAmount = 3;
|
||||
spacing = 3;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.fortress){{
|
||||
begin = 5;
|
||||
unitScaling = 1;
|
||||
spacing = 5;
|
||||
unitAmount = 1;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.fortress){{
|
||||
begin = 13;
|
||||
unitScaling = 1;
|
||||
spacing = 4;
|
||||
unitAmount = 1;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 11;
|
||||
spacing = 2;
|
||||
unitScaling = 2;
|
||||
unitAmount = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.crawler){{
|
||||
unitScaling = 1;
|
||||
spacing = 2;
|
||||
unitAmount = 4;
|
||||
begin = 13;
|
||||
}},
|
||||
|
||||
bossGroup(UnitTypes.chaosArray)
|
||||
);
|
||||
}};
|
||||
}};
|
||||
|
||||
desolateRift = new Zone("desolateRift", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
nuclearComplex = new Zone("nuclearComplex", new MapGenerator("nuclearProductionComplex", 1)
|
||||
.drops(ItemStack.with(Items.copper, 2000, Items.lead, 1500, Items.silicon, 1000, Items.graphite, 1000, Items.thorium, 200, Items.titanium, 2000, Items.metaglass, 1000))
|
||||
.decor(new Decoration(Blocks.snow, Blocks.sporeCluster, 0.01))){{
|
||||
loadout = Loadouts.basicNucleus;
|
||||
baseLaunchCost = ItemStack.with(Items.copper, 500, Items.silicon, 200, Items.metaglass, 100);
|
||||
startingItems = ItemStack.list(Items.copper, 2500, Items.lead, 3000, Items.silicon, 800, Items.metaglass, 400);
|
||||
itemRequirements = ItemStack.with(Items.copper, 10000, Items.titanium, 8000, Items.metaglass, 6000, Items.plastanium, 2000);
|
||||
conditionWave = 30;
|
||||
launchPeriod = 15;
|
||||
zoneRequirements = new Zone[]{desolateRift};
|
||||
blockRequirements = new Block[]{Blocks.blastDrill, Blocks.thermalGenerator};
|
||||
resources = new Item[]{Items.copper, Items.scrap, Items.lead, Items.coal, Items.titanium, Items.thorium, Items.sand};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
waveSpacing = 60 * 60 * 2;
|
||||
|
||||
spawns = Array.with(
|
||||
new SpawnGroup(UnitTypes.titan){{
|
||||
unitScaling = 2;
|
||||
spacing = 2;
|
||||
end = 10;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.crawler){{
|
||||
begin = 1;
|
||||
unitScaling = 2;
|
||||
spacing = 2;
|
||||
unitAmount = 3;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 2;
|
||||
unitScaling = 1;
|
||||
spacing = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 10;
|
||||
spacing = 2;
|
||||
unitScaling = 2;
|
||||
unitAmount = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.ghoul){{
|
||||
begin = 5;
|
||||
unitScaling = 0.5f;
|
||||
unitAmount = 1;
|
||||
spacing = 5;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.fortress){{
|
||||
begin = 13;
|
||||
unitScaling = 2;
|
||||
spacing = 3;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.wraith){{
|
||||
begin = 10;
|
||||
unitScaling = 1f;
|
||||
unitAmount = 1;
|
||||
spacing = 5;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.dagger){{
|
||||
begin = 2;
|
||||
unitScaling = 1;
|
||||
spacing = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.wraith){{
|
||||
begin = 23;
|
||||
unitScaling = 1f;
|
||||
unitAmount = 1;
|
||||
spacing = 2;
|
||||
}},
|
||||
|
||||
new SpawnGroup(UnitTypes.crawler){{
|
||||
begin = 20;
|
||||
unitScaling = 1;
|
||||
spacing = 10;
|
||||
unitScaling = 0.5f;
|
||||
unitAmount = 10;
|
||||
}},
|
||||
|
||||
bossGroup(UnitTypes.reaper)
|
||||
);
|
||||
}};
|
||||
}};
|
||||
|
||||
arcticDesert = new Zone("arcticDesert", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
dryWastes = new Zone("dryWastes", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
nuclearComplex = new Zone("nuclearComplex", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
moltenFault = new Zone("moltenFault", new MapGenerator("groundZero", 1)){{ //TODO implement
|
||||
deployCost = ItemStack.with(Items.copper, 300);
|
||||
startingItems = ItemStack.with(Items.copper, 200);
|
||||
conditionWave = 15;
|
||||
zoneRequirements = new Zone[]{frozenForest};
|
||||
blockRequirements = new Block[]{Blocks.copperWall};
|
||||
rules = () -> new Rules(){{
|
||||
waves = true;
|
||||
waveTimer = true;
|
||||
waveSpacing = 60 * 80;
|
||||
}};
|
||||
}};
|
||||
|
||||
frozenForest.zoneRequirements = new Zone[]{frozenForest};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,11 @@ import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.ObjectMap;
|
||||
import io.anuke.arc.collection.ObjectSet;
|
||||
import io.anuke.arc.function.Consumer;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.Pixmap;
|
||||
import io.anuke.arc.util.Log;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
||||
import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
import io.anuke.mindustry.entities.effect.Fire;
|
||||
@@ -16,11 +18,15 @@ import io.anuke.mindustry.entities.traits.TypeTrait;
|
||||
import io.anuke.mindustry.game.Content;
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.game.MappableContent;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Liquid;
|
||||
import io.anuke.mindustry.type.Zone;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.ColorMapper;
|
||||
import io.anuke.mindustry.world.LegacyColorMapper;
|
||||
|
||||
import static io.anuke.arc.Core.files;
|
||||
|
||||
/**
|
||||
* Loads all game content.
|
||||
* Call load() before doing anything with content.
|
||||
@@ -28,7 +34,7 @@ import io.anuke.mindustry.world.LegacyColorMapper;
|
||||
@SuppressWarnings("unchecked")
|
||||
public class ContentLoader{
|
||||
private boolean loaded = false;
|
||||
private boolean verbose = true;
|
||||
private boolean verbose = false;
|
||||
|
||||
private ObjectMap<String, MappableContent>[] contentNameMap = new ObjectMap[ContentType.values().length];
|
||||
private Array<Content>[] contentMap = new Array[ContentType.values().length];
|
||||
@@ -40,18 +46,21 @@ public class ContentLoader{
|
||||
new StatusEffects(),
|
||||
new Liquids(),
|
||||
new Bullets(),
|
||||
new Weapons(),
|
||||
new Mechs(),
|
||||
new UnitTypes(),
|
||||
new Blocks(),
|
||||
new Loadouts(),
|
||||
new TechTree(),
|
||||
new Zones(),
|
||||
|
||||
//these are not really content classes, but this makes initialization easier
|
||||
new ColorMapper(),
|
||||
new LegacyColorMapper(),
|
||||
};
|
||||
|
||||
public void setVerbose(){
|
||||
verbose = true;
|
||||
}
|
||||
|
||||
/**Creates all content types.*/
|
||||
public void load(){
|
||||
if(loaded){
|
||||
@@ -76,7 +85,7 @@ public class ContentLoader{
|
||||
|
||||
for(Content c : contentMap[type.ordinal()]){
|
||||
if(c instanceof MappableContent){
|
||||
String name = ((MappableContent) c).getContentName();
|
||||
String name = ((MappableContent) c).name;
|
||||
if(contentNameMap[type.ordinal()].containsKey(name)){
|
||||
throw new IllegalArgumentException("Two content objects cannot have the same name! (issue: '" + name + "')");
|
||||
}
|
||||
@@ -126,6 +135,22 @@ public class ContentLoader{
|
||||
initialization.add(callable);
|
||||
}
|
||||
|
||||
/**Loads block colors.*/
|
||||
public void loadColors(){
|
||||
Pixmap pixmap = new Pixmap(files.internal("sprites/block_colors.png"));
|
||||
for(int i = 0; i < 256; i++){
|
||||
if(blocks().size > i){
|
||||
int color = pixmap.getPixel(i, 0);
|
||||
|
||||
if(color == 0) continue;
|
||||
|
||||
Block block = block(i);
|
||||
Color.rgba8888ToColor(block.color, color);
|
||||
}
|
||||
}
|
||||
pixmap.dispose();
|
||||
}
|
||||
|
||||
public void verbose(boolean verbose){
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
@@ -3,22 +3,22 @@ package io.anuke.mindustry.core;
|
||||
import io.anuke.arc.ApplicationListener;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.EntityQuery;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.TextureAtlas;
|
||||
import io.anuke.arc.input.KeyCode;
|
||||
import io.anuke.arc.scene.ui.TextField;
|
||||
import io.anuke.arc.util.Interval;
|
||||
import io.anuke.arc.util.Strings;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.content.Mechs;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.EntityQuery;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.game.Content;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.GlobalData;
|
||||
import io.anuke.mindustry.game.Rules;
|
||||
import io.anuke.mindustry.game.Saves;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.input.Binding;
|
||||
@@ -27,7 +27,9 @@ import io.anuke.mindustry.input.InputHandler;
|
||||
import io.anuke.mindustry.input.MobileInput;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@@ -61,10 +63,11 @@ public class Control implements ApplicationListener{
|
||||
Draw.scl = 1f / Core.atlas.find("scale_marker").getWidth();
|
||||
content.initialize(Content::load);
|
||||
|
||||
/*
|
||||
if(Core.atlas.getTextures().size != 1){
|
||||
throw new IllegalStateException("Atlas must be exactly one texture. " +
|
||||
"If more textures are used, the map editor will not display them correctly.");
|
||||
}
|
||||
}*/
|
||||
|
||||
data.load();
|
||||
|
||||
@@ -98,9 +101,7 @@ public class Control implements ApplicationListener{
|
||||
});
|
||||
|
||||
Events.on(WorldLoadEvent.class, event -> {
|
||||
if(mobile){
|
||||
Core.app.post(() -> Core.camera.position.set(players[0]));
|
||||
}
|
||||
Core.app.post(() -> Core.camera.position.set(players[0]));
|
||||
});
|
||||
|
||||
Events.on(ResetEvent.class, event -> {
|
||||
@@ -164,6 +165,14 @@ public class Control implements ApplicationListener{
|
||||
state.stats.enemyUnitsDestroyed ++;
|
||||
}
|
||||
});
|
||||
|
||||
Events.on(ZoneCompleteEvent.class, e -> {
|
||||
ui.hudfrag.showToast(Core.bundle.format("zone.complete", e.zone.conditionWave));
|
||||
});
|
||||
|
||||
Events.on(ZoneConfigureCompleteEvent.class, e -> {
|
||||
ui.hudfrag.showToast(Core.bundle.format("zone.config.complete", e.zone.configureWave));
|
||||
});
|
||||
}
|
||||
|
||||
public void addPlayer(int index){
|
||||
@@ -227,9 +236,10 @@ public class Control implements ApplicationListener{
|
||||
return inputs[index];
|
||||
}
|
||||
|
||||
public void playMap(Map map){
|
||||
public void playMap(Map map, Rules rules){
|
||||
ui.loadAnd(() -> {
|
||||
logic.reset();
|
||||
state.rules = rules;
|
||||
world.loadMap(map);
|
||||
logic.play();
|
||||
});
|
||||
@@ -270,16 +280,16 @@ public class Control implements ApplicationListener{
|
||||
if(!Core.settings.getBool("4.0-warning-2", false)){
|
||||
|
||||
Time.run(5f, () -> {
|
||||
FloatingDialog dialog = new FloatingDialog("WARNING!");
|
||||
FloatingDialog dialog = new FloatingDialog("VERY IMPORTANT");
|
||||
dialog.buttons.addButton("$ok", () -> {
|
||||
dialog.hide();
|
||||
Core.settings.put("4.0-warning-2", true);
|
||||
Core.settings.save();
|
||||
}).size(100f, 60f);
|
||||
dialog.cont.add("Reminder: The alpha version you are about to play is very unstable, and is [accent]not representative of the final 4.0 release.[]\n\n " +
|
||||
dialog.cont.add("Reminder: The alpha version you are about to play is very unstable, and is [accent]not representative of the final v4 release.[]\n\n " +
|
||||
"\nThere is currently[scarlet] no sound implemented[]; this is intentional.\n" +
|
||||
"All current art and UI is temporary, and will be re-drawn before release. " +
|
||||
"\n\n[accent]Saves and maps may be corrupted without warning between updates.").wrap().width(400f);
|
||||
"All current art and UI is unfinished, and will be changed before release. " +
|
||||
"\n\n[accent]Saves may be corrupted without warning between updates.").wrap().width(400f);
|
||||
dialog.show();
|
||||
});
|
||||
}
|
||||
@@ -287,25 +297,32 @@ public class Control implements ApplicationListener{
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
|
||||
saves.update();
|
||||
|
||||
for(InputHandler inputHandler : inputs){
|
||||
inputHandler.updateController();
|
||||
}
|
||||
|
||||
//autosave global data if it's modified
|
||||
data.checkSave();
|
||||
|
||||
if(!state.is(State.menu)){
|
||||
for(InputHandler input : inputs){
|
||||
input.update();
|
||||
}
|
||||
|
||||
//autosave global data every second if it's modified
|
||||
if(timer.get(1, 60)){
|
||||
data.checkSave();
|
||||
if(world.isZone()){
|
||||
for(Tile tile : state.teams.get(players[0].getTeam()).cores){
|
||||
for(Item item : content.items()){
|
||||
if(tile.entity.items.has(item)){
|
||||
data.unlockContent(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//auto-update rpc every 5 seconds
|
||||
if(timer.get(60 * 5)){
|
||||
if(timer.get(0, 60 * 5)){
|
||||
Platform.instance.updateRPC();
|
||||
}
|
||||
|
||||
@@ -322,10 +339,6 @@ public class Control implements ApplicationListener{
|
||||
}
|
||||
}
|
||||
|
||||
if(!mobile && Core.input.keyTap(Binding.screenshot) && !(scene.getKeyboardFocus() instanceof TextField) && !ui.chatfrag.chatOpen()){
|
||||
renderer.takeMapScreenshot();
|
||||
}
|
||||
|
||||
}else{
|
||||
if(!state.isPaused()){
|
||||
Time.update();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.anuke.mindustry.core;
|
||||
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.mindustry.entities.type.BaseUnit;
|
||||
import io.anuke.mindustry.game.EventType.StateChangeEvent;
|
||||
import io.anuke.mindustry.game.Rules;
|
||||
import io.anuke.mindustry.game.Stats;
|
||||
@@ -32,13 +33,17 @@ public class GameState{
|
||||
return Net.client() ? enemies : unitGroups[waveTeam.ordinal()].size();
|
||||
}
|
||||
|
||||
public BaseUnit boss(){
|
||||
return unitGroups[waveTeam.ordinal()].find(BaseUnit::isBoss);
|
||||
}
|
||||
|
||||
public void set(State astate){
|
||||
Events.fire(new StateChangeEvent(state, astate));
|
||||
state = astate;
|
||||
}
|
||||
|
||||
public boolean isPaused(){
|
||||
return is(State.paused) && !Net.active();
|
||||
return (is(State.paused) && !Net.active()) || (gameOver && !Net.active());
|
||||
}
|
||||
|
||||
public boolean is(State astate){
|
||||
|
||||
@@ -4,15 +4,19 @@ import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.ApplicationListener;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.entities.Entities;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.entities.EntityQuery;
|
||||
import io.anuke.arc.collection.ObjectSet.ObjectSetIterator;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Entities;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.EntityQuery;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@@ -28,15 +32,9 @@ import static io.anuke.mindustry.Vars.*;
|
||||
public class Logic implements ApplicationListener{
|
||||
|
||||
public Logic(){
|
||||
Events.on(TileChangeEvent.class, event -> {
|
||||
if(event.tile.getTeam() == defaultTeam && event.tile.block().isVisible()){
|
||||
handleContent(event.tile.block());
|
||||
}
|
||||
});
|
||||
|
||||
Events.on(WaveEvent.class, event -> {
|
||||
if(world.isZone()){
|
||||
data.updateWaveScore(world.getZone(), state.wave);
|
||||
world.getZone().updateWave(state.wave);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -70,7 +68,6 @@ public class Logic implements ApplicationListener{
|
||||
state.gameOver = state.launched = false;
|
||||
state.teams = new Teams();
|
||||
state.rules = new Rules();
|
||||
state.rules.spawns = Waves.getDefaultSpawns();
|
||||
state.stats = new Stats();
|
||||
|
||||
Time.clear();
|
||||
@@ -83,16 +80,17 @@ public class Logic implements ApplicationListener{
|
||||
public void runWave(){
|
||||
world.spawner.spawnEnemies();
|
||||
state.wave++;
|
||||
state.wavetime = state.rules.waveSpacing;
|
||||
state.wavetime = world.isZone() && world.getZone().isBossWave(state.wave) ? state.rules.waveSpacing * bossWaveMultiplier :
|
||||
world.isZone() && world.getZone().isLaunchWave(state.wave) ? state.rules.waveSpacing * launchWaveMultiplier : state.rules.waveSpacing;
|
||||
|
||||
Events.fire(new WaveEvent());
|
||||
}
|
||||
|
||||
private void checkGameOver(){
|
||||
if(!state.rules.pvp && state.teams.get(defaultTeam).cores.size == 0 && !state.gameOver){
|
||||
if(state.rules.waves && state.teams.get(defaultTeam).cores.size == 0 && !state.gameOver){
|
||||
state.gameOver = true;
|
||||
Events.fire(new GameOverEvent(waveTeam));
|
||||
}else if(state.rules.pvp){
|
||||
}else if(!state.rules.waves){
|
||||
Team alive = null;
|
||||
|
||||
for(Team team : Team.all){
|
||||
@@ -111,6 +109,27 @@ public class Logic implements ApplicationListener{
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.both)
|
||||
public static void launchZone(){
|
||||
if(!headless){
|
||||
ui.hudfrag.showLaunch();
|
||||
}
|
||||
|
||||
for(Tile tile : new ObjectSetIterator<>(state.teams.get(defaultTeam).cores)){
|
||||
Effects.effect(Fx.launch, tile);
|
||||
}
|
||||
|
||||
Time.runTask(30f, () -> {
|
||||
for(Tile tile : new ObjectSetIterator<>(state.teams.get(defaultTeam).cores)){
|
||||
for(Item item : content.items()){
|
||||
data.addItem(item, tile.entity.items.get(item));
|
||||
}
|
||||
world.removeBlock(tile);
|
||||
}
|
||||
state.launched = true;
|
||||
});
|
||||
}
|
||||
|
||||
@Remote(called = Loc.both)
|
||||
public static void onGameOver(Team winner){
|
||||
ui.restart.show(winner);
|
||||
|
||||
@@ -7,9 +7,8 @@ import io.anuke.annotations.Annotations.Variant;
|
||||
import io.anuke.arc.ApplicationListener;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.IntSet;
|
||||
import io.anuke.arc.entities.Entities;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.math.RandomXS128;
|
||||
import io.anuke.arc.util.Interval;
|
||||
import io.anuke.arc.util.Log;
|
||||
import io.anuke.arc.util.Time;
|
||||
@@ -17,10 +16,12 @@ import io.anuke.arc.util.io.ReusableByteArrayInputStream;
|
||||
import io.anuke.arc.util.serialization.Base64Coder;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.Entities;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.traits.BuilderTrait.BuildRequest;
|
||||
import io.anuke.mindustry.entities.traits.SyncTrait;
|
||||
import io.anuke.mindustry.entities.traits.TypeTrait;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.game.Version;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.gen.RemoteReadClient;
|
||||
@@ -34,7 +35,6 @@ import io.anuke.mindustry.world.modules.ItemModule;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@@ -345,7 +345,7 @@ public class NetClient implements ApplicationListener{
|
||||
requests[i] = player.getPlaceQueue().get(i);
|
||||
}
|
||||
|
||||
Call.onClientShapshot(lastSent++, Time.millis(), player.x, player.y,
|
||||
Call.onClientShapshot(lastSent++, player.x, player.y,
|
||||
player.pointerX, player.pointerY, player.rotation, player.baseRotation,
|
||||
player.velocity().x, player.velocity().y,
|
||||
player.getMineTile(),
|
||||
@@ -364,7 +364,7 @@ public class NetClient implements ApplicationListener{
|
||||
return Core.settings.getString("usid-" + ip, null);
|
||||
}else{
|
||||
byte[] bytes = new byte[8];
|
||||
new Random().nextBytes(bytes);
|
||||
new RandomXS128().nextBytes(bytes);
|
||||
String result = new String(Base64Coder.encode(bytes));
|
||||
Core.settings.put("usid-" + ip, result);
|
||||
Core.settings.save();
|
||||
|
||||
@@ -7,10 +7,6 @@ import io.anuke.arc.Events;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.IntMap;
|
||||
import io.anuke.arc.collection.ObjectSet;
|
||||
import io.anuke.arc.entities.Entities;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.entities.EntityQuery;
|
||||
import io.anuke.arc.entities.trait.Entity;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.Colors;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
@@ -19,14 +15,19 @@ import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.util.Log;
|
||||
import io.anuke.arc.util.Structs;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.arc.util.io.ByteBufferOutput;
|
||||
import io.anuke.arc.util.io.CountableByteArrayOutputStream;
|
||||
import io.anuke.mindustry.content.Mechs;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.content.Mechs;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.Entities;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.EntityQuery;
|
||||
import io.anuke.mindustry.entities.traits.BuilderTrait.BuildRequest;
|
||||
import io.anuke.mindustry.entities.traits.Entity;
|
||||
import io.anuke.mindustry.entities.traits.SyncTrait;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.game.Version;
|
||||
@@ -51,12 +52,6 @@ import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class NetServer implements ApplicationListener{
|
||||
public final static int maxSnapshotSize = 430;
|
||||
|
||||
public final static boolean debugSnapshots = false;
|
||||
public final static float maxSnapshotDelay = 200;
|
||||
public final static float snapshotDropchance = 0.01f;
|
||||
|
||||
private final static byte[] reusableSnapArray = new byte[maxSnapshotSize];
|
||||
private final static float serverSyncTime = 4, kickDuration = 30 * 1000;
|
||||
private final static Vector2 vector = new Vector2();
|
||||
private final static Rectangle viewport = new Rectangle();
|
||||
@@ -156,7 +151,7 @@ public class NetServer implements ApplicationListener{
|
||||
return;
|
||||
}
|
||||
|
||||
Log.info("Recieved connect packet for player '{0}' / UUID {1} / IP {2}", packet.name, uuid, connection.address);
|
||||
Log.debug("Recieved connect packet for player '{0}' / UUID {1} / IP {2}", packet.name, uuid, connection.address);
|
||||
|
||||
String ip = Net.getConnection(id).address;
|
||||
|
||||
@@ -234,7 +229,7 @@ public class NetServer implements ApplicationListener{
|
||||
data.stream = new ByteArrayInputStream(stream.toByteArray());
|
||||
Net.sendStream(clientID, data);
|
||||
|
||||
Log.info("Packed {0} compressed bytes of world data.", stream.size());
|
||||
Log.debug("Packed {0} compressed bytes of world data.", stream.size());
|
||||
}
|
||||
|
||||
public static void onDisconnect(Player player){
|
||||
@@ -259,7 +254,7 @@ public class NetServer implements ApplicationListener{
|
||||
@Remote(targets = Loc.client, unreliable = true)
|
||||
public static void onClientShapshot(
|
||||
Player player,
|
||||
int snapshotID, long sent,
|
||||
int snapshotID,
|
||||
float x, float y,
|
||||
float pointerX, float pointerY,
|
||||
float rotation, float baseRotation,
|
||||
@@ -272,7 +267,7 @@ public class NetServer implements ApplicationListener{
|
||||
NetConnection connection = player.con;
|
||||
if(connection == null || snapshotID < connection.lastRecievedClientSnapshot) return;
|
||||
|
||||
boolean verifyPosition = !player.isDead() && netServer.admins.getStrict() && headless && player.getCarrier() == null;
|
||||
boolean verifyPosition = !player.isDead() && netServer.admins.getStrict() && headless;
|
||||
|
||||
if(connection.lastRecievedClientTime == 0) connection.lastRecievedClientTime = Time.millis() - 16;
|
||||
|
||||
@@ -329,7 +324,7 @@ public class NetServer implements ApplicationListener{
|
||||
player.y = prevy;
|
||||
|
||||
//set interpolator target to *new* position so it moves toward it
|
||||
player.getInterpolator().read(player.x, player.y, newx, newy, sent, rotation, baseRotation);
|
||||
player.getInterpolator().read(player.x, player.y, newx, newy, rotation, baseRotation);
|
||||
player.velocity().set(xVelocity, yVelocity); //only for visual calculation purposes, doesn't actually update the player
|
||||
|
||||
connection.lastRecievedClientSnapshot = snapshotID;
|
||||
@@ -340,13 +335,13 @@ public class NetServer implements ApplicationListener{
|
||||
public static void onAdminRequest(Player player, Player other, AdminAction action){
|
||||
|
||||
if(!player.isAdmin){
|
||||
Log.err("ACCESS DENIED: Player {0} / {1} attempted to perform admin action without proper security access.",
|
||||
Log.warn("ACCESS DENIED: Player {0} / {1} attempted to perform admin action without proper security access.",
|
||||
player.name, player.con.address);
|
||||
return;
|
||||
}
|
||||
|
||||
if(other == null || ((other.isAdmin && !player.isLocal) && other != player)){
|
||||
Log.err("{0} attempted to perform admin action on nonexistant or admin player.", player.name);
|
||||
Log.warn("{0} attempted to perform admin action on nonexistant or admin player.", player.name);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -475,7 +470,7 @@ public class NetServer implements ApplicationListener{
|
||||
returnArray.clear();
|
||||
if(represent.isClipped()){
|
||||
EntityQuery.getNearby(group, viewport, entity -> {
|
||||
if(((SyncTrait) entity).isSyncing() && viewport.contains(entity.getX(), entity.getY())){
|
||||
if(((SyncTrait) entity).isSyncing() && viewport.overlaps(Tmp.r3.setSize(((SyncTrait)entity).clipSize(), ((SyncTrait)entity).clipSize()).setCenter(entity.getX(), entity.getY()))){
|
||||
returnArray.add(entity);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,11 +4,10 @@ import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Input.TextInput;
|
||||
import io.anuke.arc.files.FileHandle;
|
||||
import io.anuke.arc.function.Consumer;
|
||||
import io.anuke.arc.math.RandomXS128;
|
||||
import io.anuke.arc.scene.ui.TextField;
|
||||
import io.anuke.arc.util.serialization.Base64Coder;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import static io.anuke.mindustry.Vars.mobile;
|
||||
|
||||
public abstract class Platform {
|
||||
@@ -49,7 +48,7 @@ public abstract class Platform {
|
||||
String uuid = Core.settings.getString("uuid", "");
|
||||
if(uuid.isEmpty()){
|
||||
byte[] result = new byte[8];
|
||||
new Random().nextBytes(result);
|
||||
new RandomXS128().nextBytes(result);
|
||||
uuid = new String(Base64Coder.encode(result));
|
||||
Core.settings.put("uuid", uuid);
|
||||
Core.settings.save();
|
||||
|
||||
@@ -2,12 +2,6 @@ package io.anuke.mindustry.core;
|
||||
|
||||
import io.anuke.arc.ApplicationListener;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.EntityDraw;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.entities.impl.EffectEntity;
|
||||
import io.anuke.arc.entities.trait.DrawTrait;
|
||||
import io.anuke.arc.entities.trait.Entity;
|
||||
import io.anuke.arc.function.Consumer;
|
||||
import io.anuke.arc.function.Predicate;
|
||||
import io.anuke.arc.graphics.Camera;
|
||||
@@ -15,23 +9,32 @@ import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Lines;
|
||||
import io.anuke.arc.graphics.g2d.SpriteBatch;
|
||||
import io.anuke.arc.graphics.glutils.FrameBuffer;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.util.ScreenRecorder;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.EntityDraw;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.effect.GroundEffectEntity;
|
||||
import io.anuke.mindustry.entities.effect.GroundEffectEntity.GroundEffect;
|
||||
import io.anuke.mindustry.entities.impl.EffectEntity;
|
||||
import io.anuke.mindustry.entities.traits.BelowLiquidTrait;
|
||||
import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.entities.traits.DrawTrait;
|
||||
import io.anuke.mindustry.entities.traits.Entity;
|
||||
import io.anuke.mindustry.entities.type.BaseUnit;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.entities.type.Unit;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.world.blocks.defense.ForceProjector.ShieldEntity;
|
||||
|
||||
import static io.anuke.arc.Core.*;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@@ -41,18 +44,17 @@ public class Renderer implements ApplicationListener{
|
||||
public final MinimapRenderer minimap = new MinimapRenderer();
|
||||
public final OverlayRenderer overlays = new OverlayRenderer();
|
||||
|
||||
public FrameBuffer shieldBuffer = new FrameBuffer(2, 2);
|
||||
private Color clearColor;
|
||||
private float targetscale = io.anuke.arc.scene.ui.layout.Unit.dp.scl(4);
|
||||
private float camerascale = targetscale;
|
||||
private Rectangle rect = new Rectangle(), rect2 = new Rectangle();
|
||||
private Vector2 avgPosition = new Vector2();
|
||||
private float shakeIntensity, shaketime;
|
||||
|
||||
public Renderer(){
|
||||
batch = new SpriteBatch(4096);
|
||||
camera = new Camera();
|
||||
Lines.setCircleVertices(14);
|
||||
|
||||
Shaders.init();
|
||||
|
||||
Effects.setScreenShakeProvider((intensity, duration) -> {
|
||||
@@ -63,8 +65,7 @@ public class Renderer implements ApplicationListener{
|
||||
Effects.setEffectProvider((effect, color, x, y, rotation, data) -> {
|
||||
if(effect == Fx.none) return;
|
||||
if(Core.settings.getBool("effects")){
|
||||
Rectangle view = rect.setSize(camera.width, camera.height)
|
||||
.setCenter(camera.position.x, camera.position.y);
|
||||
Rectangle view = camera.bounds(rect);
|
||||
Rectangle pos = rect2.setSize(effect.size).setCenter(x, y);
|
||||
|
||||
if(view.overlaps(pos)){
|
||||
@@ -72,7 +73,7 @@ public class Renderer implements ApplicationListener{
|
||||
if(!(effect instanceof GroundEffect)){
|
||||
EffectEntity entity = Pools.obtain(EffectEntity.class, EffectEntity::new);
|
||||
entity.effect = effect;
|
||||
entity.color = color;
|
||||
entity.color.set(color);
|
||||
entity.rotation = rotation;
|
||||
entity.data = data;
|
||||
entity.id++;
|
||||
@@ -84,7 +85,7 @@ public class Renderer implements ApplicationListener{
|
||||
}else{
|
||||
GroundEffectEntity entity = Pools.obtain(GroundEffectEntity.class, GroundEffectEntity::new);
|
||||
entity.effect = effect;
|
||||
entity.color = color;
|
||||
entity.color.set(color);
|
||||
entity.rotation = rotation;
|
||||
entity.id++;
|
||||
entity.data = data;
|
||||
@@ -113,11 +114,11 @@ public class Renderer implements ApplicationListener{
|
||||
if(state.is(State.menu)){
|
||||
graphics.clear(Color.BLACK);
|
||||
}else{
|
||||
Vector2 position = averagePosition();
|
||||
Vector2 position = Tmp.v3.set(players[0]);
|
||||
|
||||
if(players[0].isDead()){
|
||||
TileEntity core = players[0].getClosestCore();
|
||||
if(core != null && players[0].spawner == Unit.noSpawner){
|
||||
if(core != null && players[0].spawner == null){
|
||||
camera.position.lerpDelta(core.x, core.y, 0.08f);
|
||||
}else{
|
||||
camera.position.lerpDelta(position, 0.08f);
|
||||
@@ -126,9 +127,6 @@ public class Renderer implements ApplicationListener{
|
||||
camera.position.lerpDelta(position, 0.08f);
|
||||
}
|
||||
|
||||
camera.position.x = Mathf.clamp(camera.position.x, -tilesize / 2f, world.width() * tilesize - tilesize / 2f);
|
||||
camera.position.y = Mathf.clamp(camera.position.y, -tilesize / 2f, world.height() * tilesize - tilesize / 2f);
|
||||
|
||||
updateShake(0.75f);
|
||||
|
||||
draw();
|
||||
@@ -161,6 +159,10 @@ public class Renderer implements ApplicationListener{
|
||||
|
||||
graphics.clear(clearColor);
|
||||
|
||||
if(graphics.getWidth() >= 2 && graphics.getHeight() >= 2 && (shieldBuffer.getWidth() != graphics.getWidth() || shieldBuffer.getHeight() != graphics.getHeight())){
|
||||
shieldBuffer.resize(graphics.getWidth(), graphics.getHeight());
|
||||
}
|
||||
|
||||
Draw.proj(camera.projection());
|
||||
|
||||
blocks.floor.drawFloor();
|
||||
@@ -172,7 +174,13 @@ public class Renderer implements ApplicationListener{
|
||||
blocks.processBlocks();
|
||||
|
||||
blocks.drawShadows();
|
||||
|
||||
blocks.floor.beginDraw();
|
||||
blocks.floor.drawLayer(CacheLayer.walls);
|
||||
blocks.floor.endDraw();
|
||||
|
||||
blocks.drawBlocks(Layer.block);
|
||||
blocks.drawFog();
|
||||
|
||||
Draw.shader(Shaders.blockbuild, true);
|
||||
blocks.drawBlocks(Layer.placement);
|
||||
@@ -195,17 +203,20 @@ public class Renderer implements ApplicationListener{
|
||||
overlays.drawBottom();
|
||||
drawAndInterpolate(playerGroup, p -> true, Player::drawBuildRequests);
|
||||
|
||||
//TODO shield
|
||||
/*
|
||||
if(shieldGroup.size() > 0){
|
||||
Graphics.beginShaders(Shaders.shield);
|
||||
if(EntityDraw.countInBounds(shieldGroup) > 0){
|
||||
Draw.flush();
|
||||
shieldBuffer.begin();
|
||||
graphics.clear(Color.CLEAR);
|
||||
EntityDraw.draw(shieldGroup);
|
||||
EntityDraw.drawWith(shieldGroup, shield -> true, shield -> ((ShieldEntity)shield).drawOver());
|
||||
Draw.color(Palette.accent);
|
||||
Graphics.endShaders();
|
||||
Draw.flush();
|
||||
shieldBuffer.end();
|
||||
Draw.shader(Shaders.shield);
|
||||
Draw.color(Pal.accent);
|
||||
Draw.rect(Draw.wrap(shieldBuffer.getTexture()), camera.position.x, camera.position.y, camera.width, -camera.height);
|
||||
Draw.color();
|
||||
Draw.shader();
|
||||
}
|
||||
*/
|
||||
|
||||
overlays.drawTop();
|
||||
|
||||
@@ -218,11 +229,8 @@ public class Renderer implements ApplicationListener{
|
||||
}
|
||||
|
||||
private void drawFlyerShadows(){
|
||||
//TODO fix flyer shadows
|
||||
//Graphics.surface(effectSurface, true, false);
|
||||
|
||||
float trnsX = -12, trnsY = -13;
|
||||
Draw.color(0, 0, 0, 0.15f);
|
||||
Draw.color(0, 0, 0, 0.22f);
|
||||
|
||||
for(EntityGroup<? extends BaseUnit> group : unitGroups){
|
||||
if(!group.isEmpty()){
|
||||
@@ -234,8 +242,6 @@ public class Renderer implements ApplicationListener{
|
||||
drawAndInterpolate(playerGroup, unit -> unit.isFlying() && !unit.isDead(), player -> player.drawShadow(trnsX, trnsY));
|
||||
}
|
||||
|
||||
//Draw.color(0, 0, 0, 0.15f);
|
||||
//Graphics.flushSurface();
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@@ -247,18 +253,11 @@ public class Renderer implements ApplicationListener{
|
||||
playerGroup.count(p -> p.isFlying() == flying && p.getTeam() == team) == 0 && flying) continue;
|
||||
|
||||
drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder);
|
||||
drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawUnder);
|
||||
drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team && !p.isDead(), Unit::drawUnder);
|
||||
|
||||
Shaders.outline.color.set(team.color);
|
||||
Shaders.mix.color.set(Color.WHITE);
|
||||
|
||||
//Graphics.beginShaders(Shaders.outline);
|
||||
Draw.shader(Shaders.mix, true);
|
||||
drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawAll);
|
||||
drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawAll);
|
||||
Draw.shader();
|
||||
blocks.drawTeamBlocks(Layer.turret, team);
|
||||
//Graphics.endShaders();
|
||||
|
||||
drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver);
|
||||
drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawOver);
|
||||
@@ -281,15 +280,6 @@ public class Renderer implements ApplicationListener{
|
||||
return camerascale;
|
||||
}
|
||||
|
||||
public Vector2 averagePosition(){
|
||||
avgPosition.setZero();
|
||||
|
||||
drawAndInterpolate(playerGroup, p -> p.isLocal, p -> avgPosition.add(p.x, p.y));
|
||||
|
||||
avgPosition.scl(1f / players.length);
|
||||
return avgPosition;
|
||||
}
|
||||
|
||||
public void scaleCamera(float amount){
|
||||
targetscale += amount;
|
||||
clampScale();
|
||||
@@ -297,47 +287,7 @@ public class Renderer implements ApplicationListener{
|
||||
|
||||
public void clampScale(){
|
||||
float s = io.anuke.arc.scene.ui.layout.Unit.dp.scl(1f);
|
||||
targetscale = Mathf.clamp(targetscale, s * 2.5f, Math.round(s * 7));
|
||||
}
|
||||
|
||||
public void takeMapScreenshot(){
|
||||
//TODO fix/implement
|
||||
/*
|
||||
float vpW = camera.width, vpH = camera.height;
|
||||
int w = world.width()*tilesize, h = world.height()*tilesize;
|
||||
int pw = pixelSurface.width(), ph = pixelSurface.height();
|
||||
disableUI = true;
|
||||
pixelSurface.setSize(w, h, true);
|
||||
Graphics.getEffectSurface().setSize(w, h, true);
|
||||
camera.width = w;
|
||||
camera.height = h;
|
||||
camera.position.x = w/2f + tilesize/2f;
|
||||
camera.position.y = h/2f + tilesize/2f;
|
||||
|
||||
draw();
|
||||
|
||||
disableUI = false;
|
||||
camera.width = vpW;
|
||||
camera.height = vpH;
|
||||
|
||||
pixelSurface.getBuffer().begin();
|
||||
byte[] lines = ScreenUtils.getFrameBufferPixels(0, 0, w, h, true);
|
||||
for(int i = 0; i < lines.length; i+= 4){
|
||||
lines[i + 3] = (byte)255;
|
||||
}
|
||||
pixelSurface.getBuffer().end();
|
||||
|
||||
Pixmap fullPixmap = new Pixmap(w, h, Pixmap.Format.RGBA8888);
|
||||
|
||||
BufferUtils.copy(lines, 0, fullPixmap.getPixels(), lines.length);
|
||||
FileHandle file = screenshotDirectory.child("screenshot-" + Time.millis() + ".png");
|
||||
PixmapIO.writePNG(file, fullPixmap);
|
||||
fullPixmap.dispose();
|
||||
|
||||
pixelSurface.setSize(pw, ph, false);
|
||||
Graphics.getEffectSurface().setSize(pw, ph, false);
|
||||
|
||||
ui.showInfoFade(Core.bundle.format("screenshot", file.toString()));*/
|
||||
targetscale = Mathf.clamp(targetscale, s * 1.5f, Math.round(s * 5));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import io.anuke.arc.util.Strings;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.editor.MapEditorDialog;
|
||||
import io.anuke.mindustry.game.EventType.ResizeEvent;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.ui.dialogs.*;
|
||||
import io.anuke.mindustry.ui.fragments.*;
|
||||
|
||||
@@ -48,7 +48,7 @@ public class UI implements ApplicationListener{
|
||||
|
||||
public AboutDialog about;
|
||||
public GameOverDialog restart;
|
||||
public CustomGameDialog levels;
|
||||
public CustomGameDialog custom;
|
||||
public MapsDialog maps;
|
||||
public LoadDialog load;
|
||||
public DiscordDialog discord;
|
||||
@@ -108,28 +108,28 @@ public class UI implements ApplicationListener{
|
||||
Core.app.post(() -> showError("Failed to access local storage.\nSettings will not be saved."));
|
||||
});
|
||||
|
||||
Colors.put("accent", Palette.accent);
|
||||
Colors.put("accent", Pal.accent);
|
||||
|
||||
loadCursors();
|
||||
}
|
||||
|
||||
void loadCursors(){
|
||||
int cursorScaling = 3;
|
||||
int cursorScaling = 1, outlineThickness = 3;
|
||||
Color outlineColor = Color.valueOf("444444");
|
||||
|
||||
drillCursor = Core.graphics.newCursor("drill", cursorScaling, outlineColor);
|
||||
unloadCursor = Core.graphics.newCursor("unload", cursorScaling, outlineColor);
|
||||
SystemCursor.arrow.set(Core.graphics.newCursor("cursor", cursorScaling, outlineColor));
|
||||
SystemCursor.hand.set(Core.graphics.newCursor("hand", cursorScaling, outlineColor));
|
||||
SystemCursor.ibeam.set(Core.graphics.newCursor("ibeam", cursorScaling, outlineColor));
|
||||
drillCursor = Core.graphics.newCursor("drill", cursorScaling, outlineColor, outlineThickness);
|
||||
unloadCursor = Core.graphics.newCursor("unload", cursorScaling, outlineColor, outlineThickness);
|
||||
SystemCursor.arrow.set(Core.graphics.newCursor("cursor", cursorScaling, outlineColor, outlineThickness));
|
||||
SystemCursor.hand.set(Core.graphics.newCursor("hand", cursorScaling, outlineColor, outlineThickness));
|
||||
SystemCursor.ibeam.set(Core.graphics.newCursor("ibeam", cursorScaling, outlineColor, outlineThickness));
|
||||
|
||||
Core.graphics.restoreCursor();
|
||||
}
|
||||
|
||||
void generateFonts(Skin skin){
|
||||
generator = new FreeTypeFontGenerator(Core.files.internal("fonts/pixel.ttf"));
|
||||
generator = new FreeTypeFontGenerator(Core.files.internal("fonts/font.ttf"));
|
||||
FreeTypeFontParameter param = new FreeTypeFontParameter();
|
||||
param.size = (int)(14*2 * Math.max(Unit.dp.scl(1f), 0.5f));
|
||||
param.size = (int)(9*2 * Math.max(Unit.dp.scl(1f), 0.5f));
|
||||
param.shadowColor = Color.DARK_GRAY;
|
||||
param.shadowOffsetY = 2;
|
||||
param.incremental = true;
|
||||
@@ -163,7 +163,7 @@ public class UI implements ApplicationListener{
|
||||
join = new JoinDialog();
|
||||
discord = new DiscordDialog();
|
||||
load = new LoadDialog();
|
||||
levels = new CustomGameDialog();
|
||||
custom = new CustomGameDialog();
|
||||
language = new LanguageDialog();
|
||||
database = new DatabaseDialog();
|
||||
settings = new SettingsMenuDialog();
|
||||
@@ -238,7 +238,7 @@ public class UI implements ApplicationListener{
|
||||
Table table = new Table();
|
||||
table.setFillParent(true);
|
||||
table.actions(Actions.fadeOut(7f, Interpolation.fade), Actions.removeActor());
|
||||
table.top().add(info).padTop(40);
|
||||
table.top().add(info).padTop(10);
|
||||
Core.scene.add(table);
|
||||
}
|
||||
|
||||
@@ -250,17 +250,6 @@ public class UI implements ApplicationListener{
|
||||
}}.show();
|
||||
}
|
||||
|
||||
public void showInfo(String info, Runnable clicked){
|
||||
new Dialog("", "dialog"){{
|
||||
getCell(cont).growX();
|
||||
cont.margin(15).add(info).width(400f).wrap().get().setAlignment(Align.center, Align.center);
|
||||
buttons.addButton("$ok", () -> {
|
||||
clicked.run();
|
||||
hide();
|
||||
}).size(90, 50).pad(4);
|
||||
}}.show();
|
||||
}
|
||||
|
||||
public void showError(String text){
|
||||
new Dialog("$error.title", "dialog"){{
|
||||
cont.margin(15).add(text).width(400f).wrap().get().setAlignment(Align.center, Align.center);
|
||||
@@ -275,9 +264,16 @@ public class UI implements ApplicationListener{
|
||||
}}.show();
|
||||
}
|
||||
|
||||
public void showInfoText(String titleText, String text){
|
||||
new Dialog(titleText, "dialog"){{
|
||||
cont.margin(15).add(text).width(400f).wrap().left().get().setAlignment(Align.left, Align.left);
|
||||
buttons.addButton("$ok", this::hide).size(90, 50).pad(4);
|
||||
}}.show();
|
||||
}
|
||||
|
||||
public void showConfirm(String title, String text, Runnable confirmed){
|
||||
FloatingDialog dialog = new FloatingDialog(title);
|
||||
dialog.cont.add(text).width(400f).wrap().pad(4f).get().setAlignment(Align.center, Align.center);
|
||||
dialog.cont.add(text).width(500f).wrap().pad(4f).get().setAlignment(Align.center, Align.center);
|
||||
dialog.buttons.defaults().size(200f, 54f).pad(2f);
|
||||
dialog.setFillParent(false);
|
||||
dialog.buttons.addButton("$cancel", dialog::hide);
|
||||
|
||||
@@ -5,22 +5,18 @@ import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.IntArray;
|
||||
import io.anuke.arc.collection.ObjectSet.ObjectSetIterator;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.EntityQuery;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.arc.math.geom.Point2;
|
||||
import io.anuke.arc.util.Log;
|
||||
import io.anuke.arc.util.Structs;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.mindustry.ai.BlockIndexer;
|
||||
import io.anuke.mindustry.ai.Pathfinder;
|
||||
import io.anuke.mindustry.ai.WaveSpawner;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.EntityQuery;
|
||||
import io.anuke.mindustry.game.EventType.TileChangeEvent;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
@@ -29,7 +25,6 @@ import io.anuke.mindustry.maps.Map;
|
||||
import io.anuke.mindustry.maps.Maps;
|
||||
import io.anuke.mindustry.maps.generators.Generator;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.type.Zone;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
@@ -188,7 +183,7 @@ public class World implements ApplicationListener{
|
||||
|
||||
addDarkness(tiles);
|
||||
|
||||
EntityQuery.resizeTree(0, 0, tiles.length * tilesize, tiles[0].length * tilesize);
|
||||
EntityQuery.resizeTree(-finalWorldBounds, -finalWorldBounds, tiles.length * tilesize + finalWorldBounds, tiles[0].length * tilesize + finalWorldBounds);
|
||||
|
||||
generating = false;
|
||||
Events.fire(new WorldLoadEvent());
|
||||
@@ -198,24 +193,6 @@ public class World implements ApplicationListener{
|
||||
return generating;
|
||||
}
|
||||
|
||||
public void launchZone(){
|
||||
Effects.effect(Fx.launchFull, 0, 0);
|
||||
|
||||
for(Tile tile : new ObjectSetIterator<>(state.teams.get(defaultTeam).cores)){
|
||||
Effects.effect(Fx.launch, tile);
|
||||
}
|
||||
|
||||
Time.runTask(30f, () -> {
|
||||
for(Tile tile : new ObjectSetIterator<>(state.teams.get(defaultTeam).cores)){
|
||||
for(Item item : content.items()){
|
||||
data.addItem(item, tile.entity.items.get(item));
|
||||
}
|
||||
world.removeBlock(tile);
|
||||
}
|
||||
state.launched = true;
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isZone(){
|
||||
return getZone() != null;
|
||||
}
|
||||
@@ -228,13 +205,14 @@ public class World implements ApplicationListener{
|
||||
ui.loadAnd(() -> {
|
||||
logic.reset();
|
||||
state.rules = zone.rules.get();
|
||||
state.rules.zone = zone.id;
|
||||
loadGenerator(zone.generator);
|
||||
for(Tile core : state.teams.get(defaultTeam).cores){
|
||||
for(ItemStack stack : zone.startingItems){
|
||||
for(ItemStack stack : zone.getStartingItems()){
|
||||
core.entity.items.add(stack.item, stack.amount);
|
||||
}
|
||||
}
|
||||
state.rules.zone = zone.id;
|
||||
state.set(State.playing);
|
||||
control.saves.zoneSave();
|
||||
logic.play();
|
||||
});
|
||||
@@ -290,6 +268,17 @@ public class World implements ApplicationListener{
|
||||
ui.showError("$map.nospawn.pvp");
|
||||
}
|
||||
}
|
||||
}else{
|
||||
invalidMap = true;
|
||||
for(Team team : Team.all){
|
||||
if(state.teams.get(team).cores.size != 0){
|
||||
invalidMap = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(invalidMap){
|
||||
throw new MapException(map, "Map has no cores!");
|
||||
}
|
||||
}
|
||||
|
||||
if(invalidMap) Core.app.post(() -> state.set(State.menu));
|
||||
@@ -440,7 +429,6 @@ public class World implements ApplicationListener{
|
||||
}
|
||||
|
||||
public void addDarkness(Tile[][] tiles){
|
||||
|
||||
byte[][] dark = new byte[tiles.length][tiles[0].length];
|
||||
byte[][] writeBuffer = new byte[tiles.length][tiles[0].length];
|
||||
|
||||
@@ -448,7 +436,7 @@ public class World implements ApplicationListener{
|
||||
for(int x = 0; x < tiles.length; x++){
|
||||
for(int y = 0; y < tiles[0].length; y++){
|
||||
Tile tile = tiles[x][y];
|
||||
if(tile.block().solid && !tile.block().update){
|
||||
if(tile.block().solid && !tile.block().synthetic() && tile.block().fillsTile){
|
||||
dark[x][y] = darkIterations;
|
||||
}
|
||||
}
|
||||
@@ -479,7 +467,7 @@ public class World implements ApplicationListener{
|
||||
for(int x = 0; x < tiles.length; x++){
|
||||
for(int y = 0; y < tiles[0].length; y++){
|
||||
Tile tile = tiles[x][y];
|
||||
if(tile.block().solid && !tile.block().update){
|
||||
if(tile.block().solid && !tile.block().synthetic()){
|
||||
tiles[x][y].setRotation(dark[x][y]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.IntArray;
|
||||
import io.anuke.arc.function.IntPositionConsumer;
|
||||
import io.anuke.arc.input.KeyCode;
|
||||
import io.anuke.arc.util.Pack;
|
||||
import io.anuke.arc.util.Structs;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.blocks.BlockPart;
|
||||
import io.anuke.mindustry.world.blocks.Floor;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public enum EditorTool{
|
||||
pick{
|
||||
@@ -40,7 +42,7 @@ public enum EditorTool{
|
||||
|
||||
@Override
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
editor.draw(x, y);
|
||||
editor.draw(x, y, isPaint());
|
||||
}
|
||||
},
|
||||
eraser{
|
||||
@@ -51,7 +53,7 @@ public enum EditorTool{
|
||||
|
||||
@Override
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
editor.draw(x, y, Blocks.air);
|
||||
editor.draw(x, y, isPaint(), Blocks.air);
|
||||
}
|
||||
},
|
||||
spray{
|
||||
@@ -62,7 +64,7 @@ public enum EditorTool{
|
||||
|
||||
@Override
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
editor.draw(x, y, editor.getDrawBlock(), 0.012);
|
||||
editor.draw(x, y, isPaint(), editor.getDrawBlock(), 0.012);
|
||||
}
|
||||
},
|
||||
line{
|
||||
@@ -102,20 +104,13 @@ public enum EditorTool{
|
||||
dest = floor ? bf : bw;
|
||||
byte draw = editor.getDrawBlock().id;
|
||||
|
||||
if(dest == draw){
|
||||
if(dest == draw || content.block(bw) instanceof BlockPart || content.block(bw).isMultiblock()){
|
||||
return;
|
||||
}
|
||||
|
||||
width = world.width();
|
||||
int height = world.height();
|
||||
|
||||
int x1;
|
||||
boolean spanAbove, spanBelow;
|
||||
|
||||
stack.clear();
|
||||
|
||||
stack.add(asi(x, y));
|
||||
|
||||
IntPositionConsumer writer = (px, py) -> {
|
||||
TileDataMarker prev = editor.getPrev(px, py, false);
|
||||
|
||||
@@ -132,32 +127,60 @@ public enum EditorTool{
|
||||
editor.onWrite(px, py, prev);
|
||||
};
|
||||
|
||||
while(stack.size > 0){
|
||||
int popped = stack.pop();
|
||||
x = popped % width;
|
||||
y = popped / width;
|
||||
|
||||
x1 = x;
|
||||
while(x1 >= 0 && eq(x1, y)) x1--;
|
||||
x1++;
|
||||
spanAbove = spanBelow = false;
|
||||
while(x1 < width && eq(x1, y)){
|
||||
writer.accept(x1, y);
|
||||
|
||||
if(!spanAbove && y > 0 && eq(x1, y - 1)){
|
||||
stack.add(asi(x1, y - 1));
|
||||
spanAbove = true;
|
||||
}else if(spanAbove && y > 0 && eq(x1, y - 1)){
|
||||
spanAbove = false;
|
||||
if(isAlt()){
|
||||
for(int cx = 0; cx < width; cx++){
|
||||
for(int cy = 0; cy < height; cy++){
|
||||
if(eq(cx, cy)){
|
||||
writer.accept(cx, cy);
|
||||
}
|
||||
}
|
||||
|
||||
if(!spanBelow && y < height - 1 && eq(x1, y + 1)){
|
||||
stack.add(asi(x1, y + 1));
|
||||
spanBelow = true;
|
||||
}else if(spanBelow && y < height - 1 && eq(x1, y + 1)){
|
||||
spanBelow = false;
|
||||
}
|
||||
}else if(isAlt2()){
|
||||
for(int cx = 0; cx < width; cx++){
|
||||
for(int cy = 0; cy < height; cy++){
|
||||
byte w = data.read(cx, cy, DataPosition.wall);
|
||||
if(content.block(w).synthetic()){
|
||||
TileDataMarker prev = editor.getPrev(cx, cy, false);
|
||||
data.write(cx, cy, DataPosition.rotationTeam, (byte)editor.getDrawTeam().ordinal());
|
||||
editor.onWrite(cx, cy, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
int x1;
|
||||
boolean spanAbove, spanBelow;
|
||||
|
||||
stack.clear();
|
||||
|
||||
stack.add(asi(x, y));
|
||||
|
||||
while(stack.size > 0){
|
||||
int popped = stack.pop();
|
||||
x = popped % width;
|
||||
y = popped / width;
|
||||
|
||||
x1 = x;
|
||||
while(x1 >= 0 && eq(x1, y)) x1--;
|
||||
x1++;
|
||||
spanAbove = spanBelow = false;
|
||||
while(x1 < width && eq(x1, y)){
|
||||
writer.accept(x1, y);
|
||||
|
||||
if(!spanAbove && y > 0 && eq(x1, y - 1)){
|
||||
stack.add(asi(x1, y - 1));
|
||||
spanAbove = true;
|
||||
}else if(spanAbove && y > 0 && eq(x1, y - 1)){
|
||||
spanAbove = false;
|
||||
}
|
||||
|
||||
if(!spanBelow && y < height - 1 && eq(x1, y + 1)){
|
||||
stack.add(asi(x1, y + 1));
|
||||
spanBelow = true;
|
||||
}else if(spanBelow && y < height - 1 && eq(x1, y + 1)){
|
||||
spanBelow = false;
|
||||
}
|
||||
x1++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,6 +201,18 @@ public enum EditorTool{
|
||||
|
||||
boolean edit, draggable;
|
||||
|
||||
public static boolean isPaint(){
|
||||
return Core.input.keyDown(KeyCode.CONTROL_LEFT);
|
||||
}
|
||||
|
||||
public static boolean isAlt(){
|
||||
return Core.input.keyDown(KeyCode.TAB);
|
||||
}
|
||||
|
||||
public static boolean isAlt2(){
|
||||
return Core.input.keyDown(KeyCode.GRAVE);
|
||||
}
|
||||
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
|
||||
}
|
||||
|
||||
@@ -79,15 +79,15 @@ public class MapEditor{
|
||||
this.brushSize = size;
|
||||
}
|
||||
|
||||
public void draw(int x, int y){
|
||||
draw(x, y, drawBlock);
|
||||
public void draw(int x, int y, boolean paint){
|
||||
draw(x, y, paint, drawBlock);
|
||||
}
|
||||
|
||||
public void draw(int x, int y, Block drawBlock){
|
||||
draw(x, y, drawBlock, 1.0);
|
||||
public void draw(int x, int y, boolean paint, Block drawBlock){
|
||||
draw(x, y, paint, drawBlock, 1.0);
|
||||
}
|
||||
|
||||
public void draw(int x, int y, Block drawBlock, double chance){
|
||||
public void draw(int x, int y, boolean paint, Block drawBlock, double chance){
|
||||
byte writeID = drawBlock.id;
|
||||
byte partID = Blocks.part.id;
|
||||
byte rotationTeam = Pack.byteByte(drawBlock.rotate ? (byte)rotation : 0, drawBlock.synthetic() ? (byte)drawTeam.ordinal() : 0);
|
||||
@@ -144,7 +144,7 @@ public class MapEditor{
|
||||
if(Mathf.dst(rx, ry) <= brushSize - 0.5f && (chance >= 0.999 || Mathf.chance(chance))){
|
||||
int wx = x + rx, wy = y + ry;
|
||||
|
||||
if(wx < 0 || wy < 0 || wx >= map.width() || wy >= map.height()){
|
||||
if(wx < 0 || wy < 0 || wx >= map.width() || wy >= map.height() || (paint && !isfloor && content.block(map.read(wx, wy, DataPosition.wall)) == Blocks.air)){
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -230,10 +230,21 @@ public class MapEditor{
|
||||
}
|
||||
|
||||
public void resize(int width, int height){
|
||||
MapTileData previous = map;
|
||||
int offsetX = -(width - previous.width())/2, offsetY = -(height - previous.height())/2;
|
||||
|
||||
map = new MapTileData(width, height);
|
||||
for(int x = 0; x < map.width(); x++){
|
||||
for(int y = 0; y < map.height(); y++){
|
||||
map.write(x, y, DataPosition.floor, Blocks.stone.id);
|
||||
int px = offsetX + x, py = offsetY + y;
|
||||
if(Structs.inBounds(px, py, previous.width(), previous.height())){
|
||||
map.write(x, y, DataPosition.floor, previous.read(px, py, DataPosition.floor));
|
||||
map.write(x, y, DataPosition.wall, previous.read(px, py, DataPosition.wall));
|
||||
map.write(x, y, DataPosition.link, previous.read(px, py, DataPosition.link));
|
||||
map.write(x, y, DataPosition.rotationTeam, previous.read(px, py, DataPosition.rotationTeam));
|
||||
}else{
|
||||
map.write(x, y, DataPosition.floor, Blocks.stone.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
renderer.resize(width, height);
|
||||
|
||||
@@ -27,6 +27,7 @@ import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
import io.anuke.mindustry.world.blocks.OreBlock;
|
||||
import io.anuke.mindustry.world.blocks.storage.CoreBlock;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.InputStream;
|
||||
@@ -165,7 +166,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
editor.beginEdit(data, meta.tags, false);
|
||||
view.clearStack();
|
||||
}catch(Exception e){
|
||||
ui.showError(Core.bundle.format("editor.errormapload", Strings.parseException(e, false)));
|
||||
ui.showError(Core.bundle.format("editor.errorimageload", Strings.parseException(e, false)));
|
||||
Log.err(e);
|
||||
}
|
||||
}));
|
||||
@@ -200,7 +201,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
view.clearStack();
|
||||
Core.scene.setScrollFocus(view);
|
||||
if(!shownWithMap){
|
||||
editor.beginEdit(new MapTileData(256, 256), new ObjectMap<>(), true);
|
||||
editor.beginEdit(new MapTileData(200, 200), new ObjectMap<>(), true);
|
||||
}
|
||||
shownWithMap = false;
|
||||
|
||||
@@ -501,14 +502,20 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
|
||||
blocksOut.clear();
|
||||
blocksOut.addAll(Vars.content.blocks());
|
||||
blocksOut.sort((b1, b2) -> b1.synthetic() && !b2.synthetic() ? 1 : b2.synthetic() && !b1.synthetic() ? -1 :
|
||||
b1 instanceof OreBlock && !(b2 instanceof OreBlock) ? 1 : !(b1 instanceof OreBlock) && b2 instanceof OreBlock ? -1 :
|
||||
Integer.compare(b1.id, b2.id));
|
||||
blocksOut.sort((b1, b2) -> {
|
||||
int core = -Boolean.compare(b1 instanceof CoreBlock, b2 instanceof CoreBlock);
|
||||
if(core != 0) return core;
|
||||
int synth = Boolean.compare(b1.synthetic(), b2.synthetic());
|
||||
if(synth != 0) return synth;
|
||||
int ore = Boolean.compare(b1 instanceof OreBlock, b2 instanceof OreBlock);
|
||||
if(ore != 0) return ore;
|
||||
return Integer.compare(b1.id, b2.id);
|
||||
});
|
||||
|
||||
for(Block block : blocksOut){
|
||||
TextureRegion region = block.icon(Icon.medium);
|
||||
|
||||
if(region == Core.atlas.find("jjfgj")) continue;
|
||||
if(!Core.atlas.isFound(region)) continue;
|
||||
|
||||
ImageButton button = new ImageButton("white", "clear-toggle");
|
||||
button.getStyle().imageUp = new TextureRegionDrawable(region);
|
||||
@@ -525,7 +532,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
|
||||
group.getButtons().get(2).setChecked(true);
|
||||
|
||||
table.table("underline", extra -> extra.labelWrap(() -> editor.getDrawBlock().formalName).width(200f).center()).growX();
|
||||
table.table("underline", extra -> extra.labelWrap(() -> editor.getDrawBlock().localizedName).width(200f).center()).growX();
|
||||
table.row();
|
||||
table.add(pane).growY().fillX();
|
||||
}
|
||||
|
||||
@@ -60,13 +60,6 @@ public class MapInfoDialog extends FloatingDialog{
|
||||
}).size(400, 55f).get();
|
||||
author.setMessageText("$unknown");
|
||||
|
||||
cont.row();
|
||||
|
||||
cont.add().padRight(8).left();
|
||||
cont.addCheck("$editor.oregen", enabled -> {
|
||||
tags.put("oregen", enabled ? "1" : "0");
|
||||
}).update(c -> c.setChecked(!tags.get("oregen", "0").equals("0"))).left();
|
||||
|
||||
name.change();
|
||||
description.change();
|
||||
author.change();
|
||||
|
||||
@@ -4,15 +4,16 @@ import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.IntSet;
|
||||
import io.anuke.arc.collection.IntSet.IntSetIterator;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.Texture;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.util.Disposable;
|
||||
import io.anuke.arc.util.Pack;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.graphics.IndexedRenderer;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
@@ -24,9 +25,11 @@ public class MapRenderer implements Disposable{
|
||||
private IntSet delayedUpdates = new IntSet();
|
||||
private MapEditor editor;
|
||||
private int width, height;
|
||||
private Texture texture;
|
||||
|
||||
public MapRenderer(MapEditor editor){
|
||||
this.editor = editor;
|
||||
texture = Core.atlas.find("clear-editor").getTexture();
|
||||
}
|
||||
|
||||
public void resize(int width, int height){
|
||||
@@ -50,7 +53,6 @@ public class MapRenderer implements Disposable{
|
||||
updateAll();
|
||||
}
|
||||
|
||||
|
||||
public void draw(float tx, float ty, float tw, float th){
|
||||
Draw.flush();
|
||||
|
||||
@@ -78,7 +80,7 @@ public class MapRenderer implements Disposable{
|
||||
mesh.getTransformMatrix().setToTranslation(tx, ty).scale(tw / (width * tilesize), th / (height * tilesize));
|
||||
mesh.setProjectionMatrix(Draw.proj());
|
||||
|
||||
mesh.render(Core.atlas.getTextures().first());
|
||||
mesh.render(texture);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,7 +116,7 @@ public class MapRenderer implements Disposable{
|
||||
int idxDecal = (wx % chunksize) + (wy % chunksize) * chunksize + chunksize * chunksize;
|
||||
|
||||
if(bw != 0 && (wall.synthetic() || wall == Blocks.part)){
|
||||
region = wall.icon(Icon.full) == Core.atlas.find("____") ? Core.atlas.find("clear") : wall.icon(Icon.full);
|
||||
region = !Core.atlas.isFound(wall.editorIcon()) ? Core.atlas.find("clear-editor") : wall.editorIcon();
|
||||
|
||||
if(wall.rotate){
|
||||
mesh.draw(idxWall, region,
|
||||
@@ -127,22 +129,26 @@ public class MapRenderer implements Disposable{
|
||||
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl);
|
||||
}
|
||||
}else{
|
||||
region = floor.icon(Icon.full);
|
||||
region = floor.editorVariantRegions()[Mathf.randomSeed(idxWall, 0, floor.editorVariantRegions().length-1)];
|
||||
|
||||
mesh.draw(idxWall, region, wx * tilesize, wy * tilesize, 8, 8);
|
||||
}
|
||||
|
||||
float offsetX = -(wall.size/3)*tilesize, offsetY = -(wall.size/3) * tilesize;
|
||||
|
||||
if(wall.update || wall.destructible){
|
||||
mesh.setColor(team.color);
|
||||
region = Core.atlas.find("block-border");
|
||||
region = Core.atlas.find("block-border-editor");
|
||||
}else if(!wall.synthetic() && bw != 0){
|
||||
region = wall.icon(Icon.full) == Core.atlas.find("____") ? Core.atlas.find("clear") : wall.icon(Icon.full);
|
||||
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;
|
||||
}else{
|
||||
region = Core.atlas.find("clear");
|
||||
region = Core.atlas.find("clear-editor");
|
||||
}
|
||||
|
||||
mesh.draw(idxDecal, region,
|
||||
wx * tilesize - (wall.size/3) * tilesize, wy * tilesize - (wall.size/3) * tilesize,
|
||||
wx * tilesize + offsetX, wy * tilesize + offsetY,
|
||||
region.getWidth() * Draw.scl, region.getHeight() * Draw.scl);
|
||||
mesh.setColor(Color.WHITE);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.arc.function.BiConsumer;
|
||||
import io.anuke.arc.scene.ui.ButtonGroup;
|
||||
import io.anuke.arc.scene.ui.TextButton;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.maps.MapTileData;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
|
||||
public class MapResizeDialog extends FloatingDialog{
|
||||
int[] validMapSizes = {200, 300, 400, 500};
|
||||
private static final int minSize = 50, maxSize = 500, increment = 50;
|
||||
int width, height;
|
||||
|
||||
public MapResizeDialog(MapEditor editor, BiConsumer<Integer, Integer> cons){
|
||||
@@ -22,28 +21,23 @@ public class MapResizeDialog extends FloatingDialog{
|
||||
Table table = new Table();
|
||||
|
||||
for(boolean w : Mathf.booleans){
|
||||
int curr = w ? data.width() : data.height();
|
||||
int idx = 0;
|
||||
for(int i = 0; i < validMapSizes.length; i++){
|
||||
if(validMapSizes[i] == curr) idx = i;
|
||||
}
|
||||
|
||||
table.add(w ? "$width" : "$height").padRight(8f);
|
||||
ButtonGroup<TextButton> group = new ButtonGroup<>();
|
||||
for(int i = 0; i < validMapSizes.length; i++){
|
||||
int size = validMapSizes[i];
|
||||
TextButton button = new TextButton(size + "", "toggle");
|
||||
button.clicked(() -> {
|
||||
if(w)
|
||||
width = size;
|
||||
else
|
||||
height = size;
|
||||
});
|
||||
group.add(button);
|
||||
if(i == idx) button.setChecked(true);
|
||||
table.add(button).size(100f, 54f).pad(2f);
|
||||
}
|
||||
table.defaults().height(60f).padTop(8);
|
||||
table.addButton("<", () -> {
|
||||
if(w)
|
||||
width = move(width, -1);
|
||||
else
|
||||
height = move(height, -1);
|
||||
}).size(60f);
|
||||
|
||||
table.table("button", t -> t.label(() -> (w ? width : height) + "")).width(200);
|
||||
|
||||
table.addButton(">", () -> {
|
||||
if(w)
|
||||
width = move(width, 1);
|
||||
else
|
||||
height = move(height, 1);
|
||||
}).size(60f);
|
||||
table.row();
|
||||
}
|
||||
cont.row();
|
||||
@@ -57,6 +51,9 @@ public class MapResizeDialog extends FloatingDialog{
|
||||
cons.accept(width, height);
|
||||
hide();
|
||||
});
|
||||
}
|
||||
|
||||
static int move(int value, int direction){
|
||||
return Mathf.clamp((value / increment + direction) * increment, minSize, maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import io.anuke.arc.scene.event.Touchable;
|
||||
import io.anuke.arc.scene.ui.TextField;
|
||||
import io.anuke.arc.scene.ui.layout.Unit;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.input.Binding;
|
||||
import io.anuke.mindustry.ui.GridImage;
|
||||
import io.anuke.mindustry.world.Pos;
|
||||
@@ -59,6 +58,8 @@ public class MapView extends Element implements GestureListener{
|
||||
Core.input.getInputProcessors().insert(0, new GestureDetector(20, 0.5f, 2, 0.15f, this));
|
||||
touchable(Touchable.enabled);
|
||||
|
||||
Point2 firstTouch = new Point2();
|
||||
|
||||
addListener(new InputListener(){
|
||||
|
||||
@Override
|
||||
@@ -68,7 +69,6 @@ public class MapView extends Element implements GestureListener{
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){
|
||||
if(pointer != 0){
|
||||
@@ -102,6 +102,7 @@ public class MapView extends Element implements GestureListener{
|
||||
startx = p.x;
|
||||
starty = p.y;
|
||||
tool.touched(editor, p.x, p.y);
|
||||
firstTouch.set(p);
|
||||
|
||||
if(tool.edit){
|
||||
updated = true;
|
||||
@@ -123,10 +124,18 @@ public class MapView extends Element implements GestureListener{
|
||||
Point2 p = project(x, y);
|
||||
|
||||
if(tool == EditorTool.line){
|
||||
if(Core.input.keyDown(KeyCode.TAB)){
|
||||
if(Math.abs(p.x - firstTouch.x) > Math.abs(p.y - firstTouch.y)){
|
||||
p.y = firstTouch.y;
|
||||
}else{
|
||||
p.x = firstTouch.x;
|
||||
}
|
||||
}
|
||||
|
||||
ui.editor.resetSaved();
|
||||
Array<Point2> points = br.line(startx, starty, p.x, p.y);
|
||||
for(Point2 point : points){
|
||||
editor.draw(point.x, point.y);
|
||||
editor.draw(point.x, point.y, EditorTool.isPaint());
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
@@ -138,7 +147,7 @@ public class MapView extends Element implements GestureListener{
|
||||
op = null;
|
||||
}
|
||||
|
||||
if(lastTool != null){
|
||||
if(button == KeyCode.MOUSE_MIDDLE && lastTool != null){
|
||||
tool = lastTool;
|
||||
lastTool = null;
|
||||
}
|
||||
@@ -147,6 +156,7 @@ public class MapView extends Element implements GestureListener{
|
||||
|
||||
@Override
|
||||
public void touchDragged(InputEvent event, float x, float y, int pointer){
|
||||
|
||||
mousex = x;
|
||||
mousey = y;
|
||||
|
||||
@@ -160,8 +170,19 @@ public class MapView extends Element implements GestureListener{
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
lastx = p.x;
|
||||
lasty = p.y;
|
||||
|
||||
if(tool == EditorTool.line && Core.input.keyDown(KeyCode.TAB)){
|
||||
if(Math.abs(p.x - firstTouch.x) > Math.abs(p.y - firstTouch.y)){
|
||||
lastx = p.x;
|
||||
lasty = firstTouch.y;
|
||||
}else{
|
||||
lastx = firstTouch.x;
|
||||
lasty = p.y;
|
||||
}
|
||||
}else{
|
||||
lastx = p.x;
|
||||
lasty = p.y;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -223,6 +244,16 @@ public class MapView extends Element implements GestureListener{
|
||||
offsety -= ay * 15f / zoom;
|
||||
}
|
||||
|
||||
if(Core.input.keyTap(KeyCode.SHIFT_LEFT)){
|
||||
lastTool = tool;
|
||||
tool = EditorTool.pick;
|
||||
}
|
||||
|
||||
if(Core.input.keyRelease(KeyCode.SHIFT_LEFT) && lastTool != null){
|
||||
tool = lastTool;
|
||||
lastTool = null;
|
||||
}
|
||||
|
||||
if(ui.editor.hasPane()) return;
|
||||
|
||||
zoom += Core.input.axis(KeyCode.SCROLL) / 10f * zoom;
|
||||
@@ -274,7 +305,7 @@ public class MapView extends Element implements GestureListener{
|
||||
return;
|
||||
}
|
||||
|
||||
Draw.color(Palette.remove);
|
||||
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);
|
||||
@@ -301,10 +332,10 @@ public class MapView extends Element implements GestureListener{
|
||||
|
||||
float scaling = zoom * Math.min(width, height) / world.width();
|
||||
|
||||
Draw.color(Palette.accent);
|
||||
Lines.stroke(Unit.dp.scl(1f * zoom));
|
||||
Draw.color(Pal.accent);
|
||||
Lines.stroke(Unit.dp.scl(2f));
|
||||
|
||||
if(!editor.getDrawBlock().isMultiblock() || tool == EditorTool.eraser){
|
||||
if((!editor.getDrawBlock().isMultiblock() || tool == EditorTool.eraser) && tool != EditorTool.fill){
|
||||
if(tool == EditorTool.line && drawing){
|
||||
Vector2 v1 = unproject(startx, starty).add(x, y);
|
||||
float sx = v1.x, sy = v1.y;
|
||||
@@ -314,7 +345,7 @@ public class MapView extends Element implements GestureListener{
|
||||
Lines.poly(brushPolygons[index], v2.x, v2.y, scaling);
|
||||
}
|
||||
|
||||
if(tool.edit && (!mobile || drawing)){
|
||||
if((tool.edit || (tool == EditorTool.line && !drawing)) && (!mobile || drawing)){
|
||||
Point2 p = project(mousex, mousey);
|
||||
Vector2 v = unproject(p.x, p.y).add(x, y);
|
||||
Lines.poly(brushPolygons[index], v.x, v.y, scaling);
|
||||
@@ -331,7 +362,7 @@ public class MapView extends Element implements GestureListener{
|
||||
}
|
||||
}
|
||||
|
||||
Draw.color(Palette.accent);
|
||||
Draw.color(Pal.accent);
|
||||
Lines.stroke(Unit.dp.scl(3f));
|
||||
Lines.rect(x, y, width, height);
|
||||
Draw.reset();
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.anuke.mindustry.entities;
|
||||
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.Effects.Effect;
|
||||
import io.anuke.mindustry.entities.Effects.Effect;
|
||||
import io.anuke.arc.function.Consumer;
|
||||
import io.anuke.arc.function.Predicate;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
@@ -15,9 +14,10 @@ import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
||||
import io.anuke.mindustry.entities.effect.Fire;
|
||||
import io.anuke.mindustry.entities.effect.Lightning;
|
||||
import io.anuke.mindustry.entities.type.Unit;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@@ -32,7 +32,7 @@ public class Damage{
|
||||
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, Color color){
|
||||
for(int i = 0; i < Mathf.clamp(power / 20, 0, 6); i++){
|
||||
int branches = 5 + Mathf.clamp((int) (power / 30), 1, 20);
|
||||
Time.run(i * 2f + Mathf.random(4f), () -> Lightning.create(Team.none, Palette.power, 3,
|
||||
Time.run(i * 2f + Mathf.random(4f), () -> Lightning.create(Team.none, Pal.power, 3,
|
||||
x, y, Mathf.random(360f), branches + Mathf.range(2)));
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ public class Damage{
|
||||
|
||||
float shake = Math.min(explosiveness / 4f + 3f, 9f);
|
||||
Effects.shake(shake, shake, x, y);
|
||||
Effects.effect(Fx.blockExplosion, x, y);
|
||||
Effects.effect(Fx.dynamicExplosion, x, y, radius/8f);
|
||||
}
|
||||
|
||||
public static void createIncend(float x, float y, float range, int amount){
|
||||
@@ -109,7 +109,7 @@ public class Damage{
|
||||
rect.width += expand * 2;
|
||||
rect.height += expand * 2;
|
||||
|
||||
Consumer<Unit> cons = e -> {
|
||||
Consumer<io.anuke.mindustry.entities.type.Unit> cons = e -> {
|
||||
e.hitbox(hitrect);
|
||||
Rectangle other = hitrect;
|
||||
other.y -= expand;
|
||||
@@ -130,8 +130,8 @@ public class Damage{
|
||||
}
|
||||
|
||||
/**Damages all entities and blocks in a radius that are enemies of the team.*/
|
||||
public static void damageUnits(Team team, float x, float y, float size, float damage, Predicate<Unit> predicate, Consumer<Unit> acceptor){
|
||||
Consumer<Unit> cons = entity -> {
|
||||
public static void damageUnits(Team team, float x, float y, float size, float damage, Predicate<io.anuke.mindustry.entities.type.Unit> predicate, Consumer<io.anuke.mindustry.entities.type.Unit> acceptor){
|
||||
Consumer<io.anuke.mindustry.entities.type.Unit> cons = entity -> {
|
||||
if(!predicate.test(entity)) return;
|
||||
|
||||
entity.hitbox(hitrect);
|
||||
@@ -158,14 +158,14 @@ public class Damage{
|
||||
/**Damages all entities and blocks in a radius that are enemies of the team.*/
|
||||
public static void damage(Team team, float x, float y, float radius, float damage){
|
||||
Consumer<Unit> cons = entity -> {
|
||||
if(entity.team == team || entity.dst(x, y) > radius){
|
||||
if(entity.getTeam() == team || entity.dst(x, y) > radius){
|
||||
return;
|
||||
}
|
||||
float amount = calculateDamage(x, y, entity.x, entity.y, radius, damage);
|
||||
entity.damage(amount);
|
||||
//TODO better velocity displacement
|
||||
float dst = tr.set(entity.x - x, entity.y - y).len();
|
||||
entity.velocity().add(tr.setLength((1f - dst / radius) * 2f));
|
||||
entity.velocity().add(tr.setLength((1f - dst / radius) * 2f / entity.mass()));
|
||||
};
|
||||
|
||||
rect.setSize(radius * 2).setCenter(x, y);
|
||||
|
||||
166
core/src/io/anuke/mindustry/entities/Effects.java
Normal file
166
core/src/io/anuke/mindustry/entities/Effects.java
Normal file
@@ -0,0 +1,166 @@
|
||||
package io.anuke.mindustry.entities;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.function.Consumer;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Position;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
import io.anuke.mindustry.entities.impl.EffectEntity;
|
||||
import io.anuke.mindustry.entities.traits.ScaleTrait;
|
||||
|
||||
public class Effects{
|
||||
private static final EffectContainer container = new EffectContainer();
|
||||
private static Array<Effect> effects = new Array<>();
|
||||
private static ScreenshakeProvider shakeProvider;
|
||||
private static float shakeFalloff = 1000f;
|
||||
private static EffectProvider provider = (effect, color, x, y, rotation, data) -> {
|
||||
EffectEntity entity = Pools.obtain(EffectEntity.class, EffectEntity::new);
|
||||
entity.effect = effect;
|
||||
entity.color = color;
|
||||
entity.rotation = rotation;
|
||||
entity.data = data;
|
||||
entity.set(x, y);
|
||||
entity.add();
|
||||
};
|
||||
|
||||
public static void setEffectProvider(EffectProvider prov){
|
||||
provider = prov;
|
||||
}
|
||||
|
||||
public static void setScreenShakeProvider(ScreenshakeProvider provider){
|
||||
shakeProvider = provider;
|
||||
}
|
||||
|
||||
public static void renderEffect(int id, Effect render, Color color, float life, float rotation, float x, float y, Object data){
|
||||
container.set(id, color, life, render.lifetime, rotation, x, y, data);
|
||||
render.draw.render(container);
|
||||
}
|
||||
|
||||
public static Effect getEffect(int id){
|
||||
if(id >= effects.size || id < 0)
|
||||
throw new IllegalArgumentException("The effect with ID \"" + id + "\" does not exist!");
|
||||
return effects.get(id);
|
||||
}
|
||||
|
||||
public static Array<Effect> all(){
|
||||
return effects;
|
||||
}
|
||||
|
||||
public static void effect(Effect effect, float x, float y, float rotation){
|
||||
provider.createEffect(effect, Color.WHITE, x, y, rotation, null);
|
||||
}
|
||||
|
||||
public static void effect(Effect effect, float x, float y){
|
||||
effect(effect, x, y, 0);
|
||||
}
|
||||
|
||||
public static void effect(Effect effect, Color color, float x, float y){
|
||||
provider.createEffect(effect, color, x, y, 0f, null);
|
||||
}
|
||||
|
||||
public static void effect(Effect effect, Position loc){
|
||||
provider.createEffect(effect, Color.WHITE, loc.getX(), loc.getY(), 0f, null);
|
||||
}
|
||||
|
||||
public static void effect(Effect effect, Color color, float x, float y, float rotation){
|
||||
provider.createEffect(effect, color, x, y, rotation, null);
|
||||
}
|
||||
|
||||
public static void effect(Effect effect, Color color, float x, float y, float rotation, Object data){
|
||||
provider.createEffect(effect, color, x, y, rotation, data);
|
||||
}
|
||||
|
||||
public static void effect(Effect effect, float x, float y, float rotation, Object data){
|
||||
provider.createEffect(effect, Color.WHITE, x, y, rotation, data);
|
||||
}
|
||||
|
||||
/** Default value is 1000. Higher numbers mean more powerful shake (less falloff). */
|
||||
public static void setShakeFalloff(float falloff){
|
||||
shakeFalloff = falloff;
|
||||
}
|
||||
|
||||
private static void shake(float intensity, float duration){
|
||||
if(shakeProvider == null) throw new RuntimeException("Screenshake provider is null! Set it first.");
|
||||
shakeProvider.accept(intensity, duration);
|
||||
}
|
||||
|
||||
public static void shake(float intensity, float duration, float x, float y){
|
||||
if(Core.camera == null) return;
|
||||
|
||||
float distance = Core.camera.position.dst(x, y);
|
||||
if(distance < 1) distance = 1;
|
||||
|
||||
shake(Mathf.clamp(1f / (distance * distance / shakeFalloff)) * intensity, duration);
|
||||
}
|
||||
|
||||
public static void shake(float intensity, float duration, Position loc){
|
||||
shake(intensity, duration, loc.getX(), loc.getY());
|
||||
}
|
||||
|
||||
public interface ScreenshakeProvider{
|
||||
void accept(float intensity, float duration);
|
||||
}
|
||||
|
||||
public static class Effect{
|
||||
private static int lastid = 0;
|
||||
public final int id;
|
||||
public final EffectRenderer draw;
|
||||
public final float lifetime;
|
||||
/** Clip size. */
|
||||
public float size;
|
||||
|
||||
public Effect(float life, float clipsize, EffectRenderer draw){
|
||||
this.id = lastid++;
|
||||
this.lifetime = life;
|
||||
this.draw = draw;
|
||||
this.size = clipsize;
|
||||
effects.add(this);
|
||||
}
|
||||
|
||||
public Effect(float life, EffectRenderer draw){
|
||||
this(life, 28f, draw);
|
||||
}
|
||||
}
|
||||
|
||||
public static class EffectContainer implements ScaleTrait{
|
||||
public float x, y, time, lifetime, rotation;
|
||||
public Color color;
|
||||
public int id;
|
||||
public Object data;
|
||||
private EffectContainer innerContainer;
|
||||
|
||||
public void set(int id, Color color, float life, float lifetime, float rotation, float x, float y, Object data){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.color = color;
|
||||
this.time = life;
|
||||
this.lifetime = lifetime;
|
||||
this.id = id;
|
||||
this.rotation = rotation;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public void scaled(float lifetime, Consumer<EffectContainer> cons){
|
||||
if(innerContainer == null) innerContainer = new EffectContainer();
|
||||
if(time <= lifetime){
|
||||
innerContainer.set(id, color, time, lifetime, rotation, x, y, data);
|
||||
cons.accept(innerContainer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float fin(){
|
||||
return time / lifetime;
|
||||
}
|
||||
}
|
||||
|
||||
public static interface EffectProvider{
|
||||
void createEffect(Effect effect, Color color, float x, float y, float rotation, Object data);
|
||||
}
|
||||
|
||||
public static interface EffectRenderer{
|
||||
void render(EffectContainer effect);
|
||||
}
|
||||
}
|
||||
66
core/src/io/anuke/mindustry/entities/Entities.java
Executable file
66
core/src/io/anuke/mindustry/entities/Entities.java
Executable file
@@ -0,0 +1,66 @@
|
||||
package io.anuke.mindustry.entities;
|
||||
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.IntMap;
|
||||
import io.anuke.mindustry.entities.traits.Entity;
|
||||
|
||||
public class Entities{
|
||||
public static final int maxLeafObjects = 5;
|
||||
private static final EntityGroup<Entity> defaultGroup;
|
||||
private static final Array<EntityGroup<?>> groupArray = new Array<>();
|
||||
private static final IntMap<EntityGroup<?>> groups = new IntMap<>();
|
||||
|
||||
static{
|
||||
defaultGroup = addGroup(Entity.class);
|
||||
}
|
||||
|
||||
public static void clear(){
|
||||
for(EntityGroup group : groupArray){
|
||||
group.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public static Iterable<Entity> all(){
|
||||
return defaultGroup.all();
|
||||
}
|
||||
|
||||
public static EntityGroup<?> getGroup(int id){
|
||||
return groups.get(id);
|
||||
}
|
||||
|
||||
public static Iterable<EntityGroup<?>> getAllGroups(){
|
||||
return groups.values();
|
||||
}
|
||||
|
||||
public static EntityGroup<Entity> defaultGroup(){
|
||||
return defaultGroup;
|
||||
}
|
||||
|
||||
public static <T extends Entity> EntityGroup<T> addGroup(Class<T> type){
|
||||
return addGroup(type, true);
|
||||
}
|
||||
|
||||
public static <T extends Entity> EntityGroup<T> addGroup(Class<T> type, boolean useTree){
|
||||
EntityGroup<T> group = new EntityGroup<>(type, useTree);
|
||||
groups.put(group.getID(), group);
|
||||
groupArray.add(group);
|
||||
return group;
|
||||
}
|
||||
|
||||
public static void update(){
|
||||
update(defaultGroup());
|
||||
EntityQuery.collideGroups(defaultGroup(), defaultGroup());
|
||||
}
|
||||
|
||||
public static void update(EntityGroup<?> group){
|
||||
group.updateEvents();
|
||||
|
||||
if(group.useTree()){
|
||||
EntityQuery.collisions().updatePhysics(group);
|
||||
}
|
||||
|
||||
for(Entity e : group.all()){
|
||||
e.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
261
core/src/io/anuke/mindustry/entities/EntityCollisions.java
Normal file
261
core/src/io/anuke/mindustry/entities/EntityCollisions.java
Normal file
@@ -0,0 +1,261 @@
|
||||
package io.anuke.mindustry.entities;
|
||||
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.IntSet;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.arc.math.geom.QuadTree;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.mindustry.entities.traits.Entity;
|
||||
import io.anuke.mindustry.entities.traits.SolidTrait;
|
||||
|
||||
public class EntityCollisions{
|
||||
//range for tile collision scanning
|
||||
private static final int r = 2;
|
||||
//move in 1-unit chunks
|
||||
private static final float seg = 1f;
|
||||
|
||||
//tile collisions
|
||||
private float tilesize;
|
||||
private Rectangle tmp = new Rectangle();
|
||||
private TileCollider collider;
|
||||
private TileHitboxProvider hitboxProvider;
|
||||
private Vector2 vector = new Vector2();
|
||||
private Vector2 l1 = new Vector2();
|
||||
private Rectangle r1 = new Rectangle();
|
||||
private Rectangle r2 = new Rectangle();
|
||||
|
||||
//entity collisions
|
||||
private IntSet collided = new IntSet();
|
||||
private Array<SolidTrait> arrOut = new Array<>();
|
||||
|
||||
public void setCollider(float tilesize, TileCollider collider, TileHitboxProvider hitbox){
|
||||
this.tilesize = tilesize;
|
||||
this.collider = collider;
|
||||
this.hitboxProvider = hitbox;
|
||||
}
|
||||
|
||||
public void setCollider(float tilesize, TileCollider collider){
|
||||
setCollider(tilesize, collider, (x, y, out) -> out.setSize(tilesize).setCenter(x * tilesize, y * tilesize));
|
||||
}
|
||||
|
||||
public void move(SolidTrait entity, float deltax, float deltay){
|
||||
|
||||
boolean movedx = false;
|
||||
|
||||
while(Math.abs(deltax) > 0 || !movedx){
|
||||
movedx = true;
|
||||
moveInternal(entity, Math.min(Math.abs(deltax), seg) * Mathf.sign(deltax), 0, true);
|
||||
|
||||
if(Math.abs(deltax) >= seg){
|
||||
deltax -= seg * Mathf.sign(deltax);
|
||||
}else{
|
||||
deltax = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
boolean movedy = false;
|
||||
|
||||
while(Math.abs(deltay) > 0 || !movedy){
|
||||
movedy = true;
|
||||
moveInternal(entity, 0, Math.min(Math.abs(deltay), seg) * Mathf.sign(deltay), false);
|
||||
|
||||
if(Math.abs(deltay) >= seg){
|
||||
deltay -= seg * Mathf.sign(deltay);
|
||||
}else{
|
||||
deltay = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void moveInternal(SolidTrait entity, float deltax, float deltay, boolean x){
|
||||
if(collider == null)
|
||||
throw new IllegalArgumentException("No tile collider specified! Call setCollider() first.");
|
||||
|
||||
Rectangle rect = r1;
|
||||
entity.hitboxTile(rect);
|
||||
entity.hitboxTile(r2);
|
||||
rect.x += deltax;
|
||||
rect.y += deltay;
|
||||
|
||||
int tilex = Math.round((rect.x + rect.width / 2) / tilesize), tiley = Math.round((rect.y + rect.height / 2) / tilesize);
|
||||
|
||||
for(int dx = -r; dx <= r; dx++){
|
||||
for(int dy = -r; dy <= r; dy++){
|
||||
int wx = dx + tilex, wy = dy + tiley;
|
||||
if(collider.solid(wx, wy) && entity.collidesGrid(wx, wy)){
|
||||
|
||||
hitboxProvider.getHitbox(wx, wy, tmp);
|
||||
|
||||
if(tmp.overlaps(rect)){
|
||||
Vector2 v = Geometry.overlap(rect, tmp, x);
|
||||
rect.x += v.x;
|
||||
rect.y += v.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entity.setX(entity.getX() + rect.x - r2.x);
|
||||
entity.setY(entity.getY() + rect.y - r2.y);
|
||||
}
|
||||
|
||||
public boolean overlapsTile(Rectangle rect){
|
||||
if(collider == null)
|
||||
throw new IllegalArgumentException("No tile collider specified! Call setCollider() first.");
|
||||
|
||||
rect.getCenter(vector);
|
||||
int r = 1;
|
||||
|
||||
//assumes tiles are centered
|
||||
int tilex = Math.round(vector.x / tilesize);
|
||||
int tiley = Math.round(vector.y / tilesize);
|
||||
|
||||
for(int dx = -r; dx <= r; dx++){
|
||||
for(int dy = -r; dy <= r; dy++){
|
||||
int wx = dx + tilex, wy = dy + tiley;
|
||||
if(collider.solid(wx, wy)){
|
||||
hitboxProvider.getHitbox(wx, wy, r2);
|
||||
|
||||
if(r2.overlaps(rect)){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public <T extends Entity> void updatePhysics(EntityGroup<T> group){
|
||||
collided.clear();
|
||||
|
||||
QuadTree tree = group.tree();
|
||||
tree.clear();
|
||||
|
||||
for(Entity entity : group.all()){
|
||||
if(entity instanceof SolidTrait){
|
||||
SolidTrait s = (SolidTrait) entity;
|
||||
s.lastPosition().set(s.getX(), s.getY());
|
||||
tree.insert(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCollide(Entity entity, Entity other){
|
||||
|
||||
SolidTrait a = (SolidTrait) entity;
|
||||
SolidTrait b = (SolidTrait) other;
|
||||
|
||||
a.hitbox(this.r1);
|
||||
b.hitbox(this.r2);
|
||||
|
||||
r1.x += (a.lastPosition().x - a.getX());
|
||||
r1.y += (a.lastPosition().y - a.getY());
|
||||
r2.x += (b.lastPosition().x - b.getX());
|
||||
r2.y += (b.lastPosition().y - b.getY());
|
||||
|
||||
float vax = a.getX() - a.lastPosition().x;
|
||||
float vay = a.getY() - a.lastPosition().y;
|
||||
float vbx = b.getX() - b.lastPosition().x;
|
||||
float vby = b.getY() - b.lastPosition().y;
|
||||
|
||||
if(a != b && a.collides(b) && b.collides(a)){
|
||||
l1.set(a.getX(), a.getY());
|
||||
boolean collide = r1.overlaps(r2) || collide(r1.x, r1.y, r1.width, r1.height, vax, vay,
|
||||
r2.x, r2.y, r2.width, r2.height, vbx, vby, l1);
|
||||
if(collide){
|
||||
a.collision(b, l1.x, l1.y);
|
||||
b.collision(a, l1.x, l1.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean collide(float x1, float y1, float w1, float h1, float vx1, float vy1,
|
||||
float x2, float y2, float w2, float h2, float vx2, float vy2, Vector2 out){
|
||||
float px = vx1, py = vy1;
|
||||
|
||||
vx1 -= vx2;
|
||||
vy1 -= vy2;
|
||||
|
||||
float xInvEntry, yInvEntry;
|
||||
float xInvExit, yInvExit;
|
||||
|
||||
if(vx1 > 0.0f){
|
||||
xInvEntry = x2 - (x1 + w1);
|
||||
xInvExit = (x2 + w2) - x1;
|
||||
}else{
|
||||
xInvEntry = (x2 + w2) - x1;
|
||||
xInvExit = x2 - (x1 + w1);
|
||||
}
|
||||
|
||||
if(vy1 > 0.0f){
|
||||
yInvEntry = y2 - (y1 + h1);
|
||||
yInvExit = (y2 + h2) - y1;
|
||||
}else{
|
||||
yInvEntry = (y2 + h2) - y1;
|
||||
yInvExit = y2 - (y1 + h1);
|
||||
}
|
||||
|
||||
float xEntry, yEntry;
|
||||
float xExit, yExit;
|
||||
|
||||
xEntry = xInvEntry / vx1;
|
||||
xExit = xInvExit / vx1;
|
||||
|
||||
yEntry = yInvEntry / vy1;
|
||||
yExit = yInvExit / vy1;
|
||||
|
||||
float entryTime = Math.max(xEntry, yEntry);
|
||||
float exitTime = Math.min(xExit, yExit);
|
||||
|
||||
if(entryTime > exitTime || xExit < 0.0f || yExit < 0.0f || xEntry > 1.0f || yEntry > 1.0f){
|
||||
return false;
|
||||
}else{
|
||||
float dx = x1 + w1 / 2f + px * entryTime;
|
||||
float dy = y1 + h1 / 2f + py * entryTime;
|
||||
|
||||
out.set(dx, dy);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void collideGroups(EntityGroup<?> groupa, EntityGroup<?> groupb){
|
||||
collided.clear();
|
||||
|
||||
for(Entity entity : groupa.all()){
|
||||
if(!(entity instanceof SolidTrait) || collided.contains(entity.getID()))
|
||||
continue;
|
||||
|
||||
SolidTrait solid = (SolidTrait) entity;
|
||||
|
||||
solid.hitbox(r1);
|
||||
r1.x += (solid.lastPosition().x - solid.getX());
|
||||
r1.y += (solid.lastPosition().y - solid.getY());
|
||||
|
||||
solid.hitbox(r2);
|
||||
r2.merge(r1);
|
||||
|
||||
arrOut.clear();
|
||||
groupb.tree().getIntersect(arrOut, r2);
|
||||
|
||||
for(SolidTrait sc : arrOut){
|
||||
sc.hitbox(r1);
|
||||
if(r2.overlaps(r1) && !collided.contains(sc.getID())){
|
||||
checkCollide(entity, sc);
|
||||
}
|
||||
}
|
||||
|
||||
collided.add(entity.getID());
|
||||
}
|
||||
}
|
||||
|
||||
public interface TileCollider{
|
||||
boolean solid(int x, int y);
|
||||
}
|
||||
|
||||
public interface TileHitboxProvider{
|
||||
void getHitbox(int x, int y, Rectangle out);
|
||||
}
|
||||
}
|
||||
56
core/src/io/anuke/mindustry/entities/EntityDraw.java
Normal file
56
core/src/io/anuke/mindustry/entities/EntityDraw.java
Normal file
@@ -0,0 +1,56 @@
|
||||
package io.anuke.mindustry.entities;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.function.Consumer;
|
||||
import io.anuke.arc.function.Predicate;
|
||||
import io.anuke.arc.graphics.Camera;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.mindustry.entities.traits.DrawTrait;
|
||||
|
||||
public class EntityDraw{
|
||||
private static final Rectangle viewport = new Rectangle();
|
||||
private static final Rectangle rect = new Rectangle();
|
||||
private static boolean clip = true;
|
||||
private static int count = 0;
|
||||
|
||||
public static void setClip(boolean clip){
|
||||
EntityDraw.clip = clip;
|
||||
}
|
||||
|
||||
public static int countInBounds(EntityGroup<?> group){
|
||||
count = 0;
|
||||
drawWith(group, e -> true, e -> count++);
|
||||
return count;
|
||||
}
|
||||
|
||||
public static void draw(){
|
||||
draw(Entities.defaultGroup());
|
||||
}
|
||||
|
||||
public static void draw(EntityGroup<?> group){
|
||||
draw(group, e -> true);
|
||||
}
|
||||
|
||||
public static <T extends DrawTrait> void draw(EntityGroup<?> group, Predicate<T> toDraw){
|
||||
drawWith(group, toDraw, DrawTrait::draw);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T extends DrawTrait> void drawWith(EntityGroup<?> group, Predicate<T> toDraw, Consumer<T> cons){
|
||||
if(clip){
|
||||
Camera cam = Core.camera;
|
||||
viewport.set(cam.position.x - cam.width / 2, cam.position.y - cam.height / 2, cam.width, cam.height);
|
||||
}
|
||||
|
||||
group.forEach(e -> {
|
||||
if(!(e instanceof DrawTrait)) return;
|
||||
T t = (T) e;
|
||||
|
||||
if(!toDraw.test(t) || !e.isAdded()) return;
|
||||
|
||||
if(!clip || rect.setSize(((DrawTrait) e).drawSize()).setCenter(e.getX(), e.getY()).overlaps(viewport)){
|
||||
cons.accept(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
194
core/src/io/anuke/mindustry/entities/EntityGroup.java
Normal file
194
core/src/io/anuke/mindustry/entities/EntityGroup.java
Normal file
@@ -0,0 +1,194 @@
|
||||
package io.anuke.mindustry.entities;
|
||||
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.IntMap;
|
||||
import io.anuke.arc.function.Consumer;
|
||||
import io.anuke.arc.function.Predicate;
|
||||
import io.anuke.arc.math.geom.QuadTree;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.mindustry.entities.traits.Entity;
|
||||
|
||||
public class EntityGroup<T extends Entity>{
|
||||
private static int lastid;
|
||||
private final boolean useTree;
|
||||
private final int id;
|
||||
private final Class<T> type;
|
||||
private final Array<T> entityArray = new Array<>(false, 16);
|
||||
private final Array<T> entitiesToRemove = new Array<>(false, 16);
|
||||
private final Array<T> entitiesToAdd = new Array<>(false, 16);
|
||||
private IntMap<T> map;
|
||||
private QuadTree<T> tree;
|
||||
private Consumer<T> removeListener;
|
||||
private Consumer<T> addListener;
|
||||
|
||||
public EntityGroup(Class<T> type, boolean useTree){
|
||||
this.useTree = useTree;
|
||||
this.id = lastid++;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public boolean useTree(){
|
||||
return useTree;
|
||||
}
|
||||
|
||||
public void setRemoveListener(Consumer<T> removeListener){
|
||||
this.removeListener = removeListener;
|
||||
}
|
||||
|
||||
public void setAddListener(Consumer<T> addListener){
|
||||
this.addListener = addListener;
|
||||
}
|
||||
|
||||
public EntityGroup<T> enableMapping(){
|
||||
map = new IntMap<>();
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean mappingEnabled(){
|
||||
return map != null;
|
||||
}
|
||||
|
||||
public Class<T> getType(){
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getID(){
|
||||
return id;
|
||||
}
|
||||
|
||||
public void updateEvents(){
|
||||
|
||||
for(T e : entitiesToAdd){
|
||||
if(e == null)
|
||||
continue;
|
||||
entityArray.add(e);
|
||||
e.added();
|
||||
|
||||
if(map != null){
|
||||
map.put(e.getID(), e);
|
||||
}
|
||||
}
|
||||
|
||||
entitiesToAdd.clear();
|
||||
|
||||
for(T e : entitiesToRemove){
|
||||
entityArray.removeValue(e, true);
|
||||
if(map != null){
|
||||
map.remove(e.getID());
|
||||
}
|
||||
e.removed();
|
||||
}
|
||||
|
||||
entitiesToRemove.clear();
|
||||
}
|
||||
|
||||
public T getByID(int id){
|
||||
if(map == null) throw new RuntimeException("Mapping is not enabled for group " + id + "!");
|
||||
return map.get(id);
|
||||
}
|
||||
|
||||
public void removeByID(int id){
|
||||
if(map == null) throw new RuntimeException("Mapping is not enabled for group " + id + "!");
|
||||
T t = map.get(id);
|
||||
if(t != null){ //remove if present in map already
|
||||
remove(t);
|
||||
}else{ //maybe it's being queued?
|
||||
for(T check : entitiesToAdd){
|
||||
if(check.getID() == id){ //if it is indeed queued, remove it
|
||||
entitiesToAdd.removeValue(check, true);
|
||||
if(removeListener != null){
|
||||
removeListener.accept(check);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public QuadTree tree(){
|
||||
return tree;
|
||||
}
|
||||
|
||||
public void setTree(float x, float y, float w, float h){
|
||||
tree = new QuadTree<>(Entities.maxLeafObjects, new Rectangle(x, y, w, h));
|
||||
}
|
||||
|
||||
public boolean isEmpty(){
|
||||
return entityArray.size == 0;
|
||||
}
|
||||
|
||||
public int size(){
|
||||
return entityArray.size;
|
||||
}
|
||||
|
||||
public int count(Predicate<T> pred){
|
||||
int count = 0;
|
||||
for(int i = 0; i < entityArray.size; i++){
|
||||
if(pred.test(entityArray.get(i))) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public void add(T type){
|
||||
if(type == null) throw new RuntimeException("Cannot add a null entity!");
|
||||
if(type.getGroup() != null) return;
|
||||
type.setGroup(this);
|
||||
entitiesToAdd.add(type);
|
||||
|
||||
if(mappingEnabled()){
|
||||
map.put(type.getID(), type);
|
||||
}
|
||||
|
||||
if(addListener != null){
|
||||
addListener.accept(type);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(T type){
|
||||
if(type == null) throw new RuntimeException("Cannot remove a null entity!");
|
||||
type.setGroup(null);
|
||||
entitiesToRemove.add(type);
|
||||
|
||||
if(removeListener != null){
|
||||
removeListener.accept(type);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
for(T entity : entityArray)
|
||||
entity.setGroup(null);
|
||||
|
||||
for(T entity : entitiesToAdd)
|
||||
entity.setGroup(null);
|
||||
|
||||
for(T entity : entitiesToRemove)
|
||||
entity.setGroup(null);
|
||||
|
||||
entitiesToAdd.clear();
|
||||
entitiesToRemove.clear();
|
||||
entityArray.clear();
|
||||
if(map != null)
|
||||
map.clear();
|
||||
}
|
||||
|
||||
public T find(Predicate<T> pred){
|
||||
|
||||
for(int i = 0; i < entityArray.size; i++){
|
||||
if(pred.test(entityArray.get(i))) return entityArray.get(i);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**Returns the logic-only array for iteration.*/
|
||||
public Array<T> all(){
|
||||
return entityArray;
|
||||
}
|
||||
|
||||
public void forEach(Consumer<T> cons){
|
||||
|
||||
for(T t : entityArray){
|
||||
cons.accept(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
95
core/src/io/anuke/mindustry/entities/EntityQuery.java
Normal file
95
core/src/io/anuke/mindustry/entities/EntityQuery.java
Normal file
@@ -0,0 +1,95 @@
|
||||
package io.anuke.mindustry.entities;
|
||||
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.function.Consumer;
|
||||
import io.anuke.arc.function.Predicate;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.mindustry.entities.traits.Entity;
|
||||
import io.anuke.mindustry.entities.traits.SolidTrait;
|
||||
|
||||
import static io.anuke.mindustry.entities.Entities.defaultGroup;
|
||||
|
||||
public class EntityQuery{
|
||||
private static final EntityCollisions collisions = new EntityCollisions();
|
||||
private static final Array<SolidTrait> array = new Array<>();
|
||||
private static final Rectangle r1 = new Rectangle();
|
||||
|
||||
public static EntityCollisions collisions(){
|
||||
return collisions;
|
||||
}
|
||||
|
||||
public static void init(float x, float y, float w, float h){
|
||||
|
||||
for(EntityGroup group : Entities.getAllGroups()){
|
||||
if(group.useTree()){
|
||||
group.setTree(x, y, w, h);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void init(){
|
||||
init(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
public static void resizeTree(float x, float y, float w, float h){
|
||||
init(x, y, w, h);
|
||||
}
|
||||
|
||||
public static void getNearby(EntityGroup<?> group, Rectangle rect, Consumer<SolidTrait> out){
|
||||
|
||||
if(!group.useTree())
|
||||
throw new RuntimeException("This group does not support quadtrees! Enable quadtrees when creating it.");
|
||||
group.tree().getIntersect(out, rect);
|
||||
}
|
||||
|
||||
public static Array<SolidTrait> getNearby(EntityGroup<?> group, Rectangle rect){
|
||||
|
||||
array.clear();
|
||||
if(!group.useTree())
|
||||
throw new RuntimeException("This group does not support quadtrees! Enable quadtrees when creating it.");
|
||||
group.tree().getIntersect(array, rect);
|
||||
return array;
|
||||
}
|
||||
|
||||
public static void getNearby(float x, float y, float size, Consumer<SolidTrait> out){
|
||||
getNearby(defaultGroup(), r1.setSize(size).setCenter(x, y), out);
|
||||
}
|
||||
|
||||
public static void getNearby(EntityGroup<?> group, float x, float y, float size, Consumer<SolidTrait> out){
|
||||
getNearby(group, r1.setSize(size).setCenter(x, y), out);
|
||||
}
|
||||
|
||||
public static Array<SolidTrait> getNearby(float x, float y, float size){
|
||||
return getNearby(defaultGroup(), r1.setSize(size).setCenter(x, y));
|
||||
}
|
||||
|
||||
public static Array<SolidTrait> getNearby(EntityGroup<?> group, float x, float y, float size){
|
||||
return getNearby(group, r1.setSize(size).setCenter(x, y));
|
||||
}
|
||||
|
||||
public static <T extends Entity> T getClosest(EntityGroup<T> group, float x, float y, float range, Predicate<T> pred){
|
||||
|
||||
T closest = null;
|
||||
float cdist = 0f;
|
||||
Array<SolidTrait> entities = getNearby(group, x, y, range * 2f);
|
||||
for(int i = 0; i < entities.size; i++){
|
||||
T e = (T) entities.get(i);
|
||||
if(!pred.test(e))
|
||||
continue;
|
||||
|
||||
float dist = Mathf.dst(e.getX(), e.getY(), x, y);
|
||||
if(dist < range)
|
||||
if(closest == null || dist < cdist){
|
||||
closest = e;
|
||||
cdist = dist;
|
||||
}
|
||||
}
|
||||
|
||||
return closest;
|
||||
}
|
||||
|
||||
public static void collideGroups(EntityGroup<?> groupa, EntityGroup<?> groupb){
|
||||
collisions().collideGroups(groupa, groupb);
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package io.anuke.mindustry.entities;
|
||||
|
||||
import io.anuke.mindustry.entities.traits.Saveable;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
|
||||
public class UnitInventory implements Saveable{
|
||||
private final Unit unit;
|
||||
private ItemStack item = new ItemStack(content.item(0), 0);
|
||||
|
||||
public UnitInventory(Unit unit){
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
public boolean isFull(){
|
||||
return item != null && item.amount >= unit.getItemCapacity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSave(DataOutput stream) throws IOException{
|
||||
stream.writeByte(item.amount);
|
||||
stream.writeByte(item.item.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSave(DataInput stream) throws IOException{
|
||||
int iamount = stream.readUnsignedByte();
|
||||
byte iid = stream.readByte();
|
||||
|
||||
item.item = content.item(iid);
|
||||
item.amount = iamount;
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
item.amount = 0;
|
||||
}
|
||||
|
||||
public int capacity(){
|
||||
return unit.getItemCapacity();
|
||||
}
|
||||
|
||||
public boolean isEmpty(){
|
||||
return item.amount == 0;
|
||||
}
|
||||
|
||||
public int itemCapacityUsed(Item type){
|
||||
if(canAcceptItem(type)){
|
||||
return !hasItem() ? unit.getItemCapacity() : (unit.getItemCapacity() - item.amount);
|
||||
}else{
|
||||
return unit.getItemCapacity();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canAcceptItem(Item type){
|
||||
return (!hasItem() && 1 <= unit.getItemCapacity()) || (item.item == type && unit.getItemCapacity() - item.amount > 0);
|
||||
}
|
||||
|
||||
public boolean canAcceptItem(Item type, int amount){
|
||||
return (!hasItem() && amount <= unit.getItemCapacity()) || (item.item == type && item.amount + amount <= unit.getItemCapacity());
|
||||
}
|
||||
|
||||
public void clearItem(){
|
||||
item.amount = 0;
|
||||
}
|
||||
|
||||
public boolean hasItem(){
|
||||
return item.amount > 0;
|
||||
}
|
||||
|
||||
public boolean hasItem(Item i, int amount){
|
||||
return item.item == i && item.amount >= amount;
|
||||
}
|
||||
|
||||
public void addItem(Item item, int amount){
|
||||
getItem().amount = getItem().item == item ? getItem().amount + amount : amount;
|
||||
getItem().item = item;
|
||||
}
|
||||
|
||||
public ItemStack getItem(){
|
||||
return item;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
package io.anuke.mindustry.entities;
|
||||
|
||||
import io.anuke.arc.collection.EnumSet;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.entities.EntityQuery;
|
||||
import io.anuke.arc.function.Consumer;
|
||||
import io.anuke.arc.function.Predicate;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.mindustry.entities.traits.TargetTrait;
|
||||
import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.entities.type.BaseUnit;
|
||||
import io.anuke.mindustry.entities.type.Unit;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
@@ -21,11 +22,10 @@ import static io.anuke.mindustry.Vars.*;
|
||||
*/
|
||||
public class Units{
|
||||
private static Rectangle rect = new Rectangle();
|
||||
private static Rectangle rectGraphics = new Rectangle();
|
||||
private static Rectangle hitrect = new Rectangle();
|
||||
private static Unit result;
|
||||
private static float cdist;
|
||||
private static boolean boolResult, boolResultGraphics;
|
||||
private static boolean boolResult;
|
||||
|
||||
/**
|
||||
* Validates a target.
|
||||
@@ -48,7 +48,7 @@ public class Units{
|
||||
|
||||
/**See {@link #invalidateTarget(TargetTrait, Team, float, float, float)}*/
|
||||
public static boolean invalidateTarget(TargetTrait target, Unit targeter){
|
||||
return invalidateTarget(target, targeter.team, targeter.x, targeter.y, targeter.getWeapon().getAmmo().range());
|
||||
return invalidateTarget(target, targeter.getTeam(), targeter.x, targeter.y, targeter.getWeapon().bullet.range());
|
||||
}
|
||||
|
||||
/**Returns whether there are any entities on this tile.*/
|
||||
@@ -113,6 +113,8 @@ public class Units{
|
||||
|
||||
/**Returns the neareset enemy tile in a range.*/
|
||||
public static TileEntity findEnemyTile(Team team, float x, float y, float range, Predicate<Tile> pred){
|
||||
if(team == Team.none) return null;
|
||||
|
||||
for(Team enemy : state.teams.enemiesOf(team)){
|
||||
TileEntity entity = world.indexer.findTile(enemy, x, y, range, pred);
|
||||
if(entity != null){
|
||||
@@ -141,21 +143,28 @@ public class Units{
|
||||
|
||||
/**Returns the closest target enemy. First, units are checked, then tile entities.*/
|
||||
public static TargetTrait getClosestTarget(Team team, float x, float y, float range){
|
||||
return getClosestTarget(team, x, y, range, u -> !u.isDead() && u.isAdded());
|
||||
return getClosestTarget(team, x, y, range, Unit::isValid);
|
||||
}
|
||||
|
||||
/**Returns the closest target enemy. First, units are checked, then tile entities.*/
|
||||
public static TargetTrait getClosestTarget(Team team, float x, float y, float range, Predicate<Unit> unitPred){
|
||||
return getClosestTarget(team, x, y, range, unitPred, t -> true);
|
||||
}
|
||||
|
||||
/**Returns the closest target enemy. First, units are checked, then tile entities.*/
|
||||
public static TargetTrait getClosestTarget(Team team, float x, float y, float range, Predicate<Unit> unitPred, Predicate<Tile> tilePred){
|
||||
Unit unit = getClosestEnemy(team, x, y, range, unitPred);
|
||||
if(unit != null){
|
||||
return unit;
|
||||
}else{
|
||||
return findEnemyTile(team, x, y, range, tile -> true);
|
||||
return findEnemyTile(team, x, y, range, tilePred);
|
||||
}
|
||||
}
|
||||
|
||||
/**Returns the closest enemy of this team. Filter by predicate.*/
|
||||
public static Unit getClosestEnemy(Team team, float x, float y, float range, Predicate<Unit> predicate){
|
||||
if(team == Team.none) return null;
|
||||
|
||||
result = null;
|
||||
cdist = 0f;
|
||||
|
||||
@@ -210,7 +219,7 @@ public class Units{
|
||||
|
||||
//now check all players
|
||||
EntityQuery.getNearby(playerGroup, rect, player -> {
|
||||
if(((Unit) player).team == team) cons.accept((Unit) player);
|
||||
if(((Unit) player).getTeam() == team) cons.accept((Unit) player);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -229,7 +238,7 @@ public class Units{
|
||||
|
||||
//now check all players
|
||||
EntityQuery.getNearby(playerGroup, rect, player -> {
|
||||
if(((Unit) player).team == team && player.dst(x, y) <= radius){
|
||||
if(((Unit) player).getTeam() == team && player.dst(x, y) <= radius){
|
||||
cons.accept((Unit) player);
|
||||
}
|
||||
});
|
||||
@@ -262,7 +271,7 @@ public class Units{
|
||||
|
||||
//now check all enemy players
|
||||
EntityQuery.getNearby(playerGroup, rect, player -> {
|
||||
if(targets.contains(((Player) player).team)){
|
||||
if(targets.contains(((Player) player).getTeam())){
|
||||
cons.accept((Unit) player);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.anuke.mindustry.entities.bullet;
|
||||
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.Effects.Effect;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Effects.Effect;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
package io.anuke.mindustry.entities.bullet;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.math.Angles;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.entities.Damage;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.effect.Lightning;
|
||||
import io.anuke.mindustry.entities.traits.TargetTrait;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
|
||||
/**An extended BulletType for most ammo-based bullets shot from turrets and units.*/
|
||||
public class BasicBulletType extends BulletType{
|
||||
public Color backColor = Palette.bulletYellowBack, frontColor = Palette.bulletYellow;
|
||||
public Color backColor = Pal.bulletYellowBack, frontColor = Pal.bulletYellow;
|
||||
public float bulletWidth = 5f, bulletHeight = 7f;
|
||||
public float bulletShrink = 0.5f;
|
||||
public String bulletSprite;
|
||||
@@ -72,7 +71,7 @@ public class BasicBulletType extends BulletType{
|
||||
if(homingPower > 0.0001f){
|
||||
TargetTrait target = Units.getClosestTarget(b.getTeam(), b.x, b.y, homingRange);
|
||||
if(target != null){
|
||||
b.velocity().setAngle(Angles.moveToward(b.velocity().angle(), b.angleTo(target), homingPower * Time.delta()));
|
||||
b.velocity().setAngle(Mathf.slerpDelta(b.velocity().angle(), b.angleTo(target), 0.08f));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,7 +107,7 @@ public class BasicBulletType extends BulletType{
|
||||
}
|
||||
|
||||
for (int i = 0; i < lightining; i++) {
|
||||
Lightning.create(b.getTeam(), Palette.surge, damage, b.x, b.y, Mathf.random(360f), lightningLength);
|
||||
Lightning.create(b.getTeam(), Pal.surge, damage, b.x, b.y, Mathf.random(360f), lightningLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,6 @@ package io.anuke.mindustry.entities.bullet;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.entities.impl.SolidEntity;
|
||||
import io.anuke.arc.entities.trait.*;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
@@ -13,11 +10,11 @@ import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.arc.util.pooling.Pool.Poolable;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.effect.Lightning;
|
||||
import io.anuke.mindustry.entities.traits.AbsorbTrait;
|
||||
import io.anuke.mindustry.entities.traits.SyncTrait;
|
||||
import io.anuke.mindustry.entities.traits.TeamTrait;
|
||||
import io.anuke.mindustry.entities.impl.SolidEntity;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.entities.type.Unit;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
@@ -89,11 +86,21 @@ public class Bullet extends SolidEntity implements DamageTrait, ScaleTrait, Pool
|
||||
}
|
||||
|
||||
/**Internal use only.*/
|
||||
@Remote(called = Loc.server)
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void createBullet(BulletType type, float x, float y, float angle){
|
||||
create(type, null, Team.none, x, y, angle);
|
||||
}
|
||||
|
||||
/**ok*/
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void createBullet(BulletType type, Team team, float x, float y, float angle){
|
||||
create(type, null, team, x, y, angle);
|
||||
}
|
||||
|
||||
public Entity getOwner(){
|
||||
return owner;
|
||||
}
|
||||
|
||||
public boolean collidesTiles(){
|
||||
return type.collidesTiles;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.anuke.mindustry.entities.bullet;
|
||||
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.Effects.Effect;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Effects.Effect;
|
||||
import io.anuke.mindustry.content.StatusEffects;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.game.Content;
|
||||
@@ -66,7 +66,7 @@ public abstract class BulletType extends Content{
|
||||
|
||||
/**Returns maximum distance the bullet this bullet type has can travel.*/
|
||||
public float range(){
|
||||
return speed * lifetime;
|
||||
return speed * lifetime * (1f - drag);
|
||||
}
|
||||
|
||||
public boolean collides(Bullet bullet, Tile tile){
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package io.anuke.mindustry.entities.bullet;
|
||||
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Fill;
|
||||
@@ -20,16 +20,22 @@ public class LiquidBulletType extends BulletType{
|
||||
Liquid liquid;
|
||||
|
||||
public LiquidBulletType(Liquid liquid){
|
||||
super(2.5f, 0);
|
||||
super(2.8f, 0);
|
||||
this.liquid = liquid;
|
||||
|
||||
lifetime = 70f;
|
||||
lifetime = 74f;
|
||||
status = liquid.effect;
|
||||
statusDuration = 90f;
|
||||
despawnEffect = Fx.none;
|
||||
hitEffect = Fx.hitLiquid;
|
||||
drag = 0.01f;
|
||||
knockback = 0.5f;
|
||||
shootEffect = Fx.none;
|
||||
drag = 0.009f;
|
||||
knockback = 0.55f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float range(){
|
||||
return speed * lifetime /2f;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package io.anuke.mindustry.entities.bullet;
|
||||
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.math.Angles;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.world.blocks.distribution.MassDriver.DriverBulletData;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
@@ -26,10 +26,10 @@ public class MassDriverBolt extends BulletType{
|
||||
public void draw(Bullet b){
|
||||
float w = 11f, h = 13f;
|
||||
|
||||
Draw.color(Palette.bulletYellowBack);
|
||||
Draw.color(Pal.bulletYellowBack);
|
||||
Draw.rect("shell-back", b.x, b.y, w, h, b.rot() + 90);
|
||||
|
||||
Draw.color(Palette.bulletYellow);
|
||||
Draw.color(Pal.bulletYellow);
|
||||
Draw.rect("shell", b.x, b.y, w, h, b.rot() + 90);
|
||||
|
||||
Draw.reset();
|
||||
|
||||
@@ -2,21 +2,21 @@ package io.anuke.mindustry.entities.bullet;
|
||||
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
|
||||
public class MissileBulletType extends BasicBulletType{
|
||||
protected Color trailColor = Palette.missileYellowBack;
|
||||
protected Color trailColor = Pal.missileYellowBack;
|
||||
|
||||
protected float weaveScale = 0f;
|
||||
protected float weaveMag = -1f;
|
||||
|
||||
public MissileBulletType(float speed, float damage, String bulletSprite){
|
||||
super(speed, damage, bulletSprite);
|
||||
backColor = Palette.missileYellowBack;
|
||||
frontColor = Palette.missileYellow;
|
||||
backColor = Pal.missileYellowBack;
|
||||
frontColor = Pal.missileYellow;
|
||||
homingPower = 7f;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@ package io.anuke.mindustry.entities.effect;
|
||||
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.mindustry.entities.traits.BelowLiquidTrait;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.entities.impl.TimedEntity;
|
||||
import io.anuke.arc.entities.trait.DrawTrait;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.impl.TimedEntity;
|
||||
import io.anuke.mindustry.entities.traits.DrawTrait;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ package io.anuke.mindustry.entities.effect;
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.collection.IntMap;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.entities.impl.TimedEntity;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.impl.TimedEntity;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.arc.math.geom.Point2;
|
||||
@@ -17,12 +17,13 @@ import io.anuke.mindustry.content.Bullets;
|
||||
import io.anuke.mindustry.content.StatusEffects;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.Damage;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.entities.traits.SaveTrait;
|
||||
import io.anuke.mindustry.entities.traits.SyncTrait;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Pos;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import java.io.DataInput;
|
||||
@@ -64,10 +65,10 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
|
||||
}
|
||||
|
||||
public static boolean has(int x, int y){
|
||||
if(!Structs.inBounds(x, y, world.width(), world.height()) || !map.containsKey(x + y * world.width())){
|
||||
if(!Structs.inBounds(x, y, world.width(), world.height()) || !map.containsKey(Pos.get(x, y))){
|
||||
return false;
|
||||
}
|
||||
Fire fire = map.get(x + y * world.width());
|
||||
Fire fire = map.get(Pos.get(x, y));
|
||||
return fire.isAdded() && fire.fin() < 1f && fire.tile != null && fire.tile.x == x && fire.tile.y == y;
|
||||
}
|
||||
|
||||
@@ -152,7 +153,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
|
||||
entity.damage(0.4f);
|
||||
}
|
||||
Damage.damageUnits(null, tile.worldx(), tile.worldy(), tilesize, 3f,
|
||||
unit -> !unit.isFlying(),
|
||||
unit -> !unit.isFlying() && !unit.isImmune(StatusEffects.burning),
|
||||
unit -> unit.applyEffect(StatusEffects.burning, 60 * 5));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package io.anuke.mindustry.entities.effect;
|
||||
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.Effects.Effect;
|
||||
import io.anuke.arc.entities.Effects.EffectRenderer;
|
||||
import io.anuke.arc.entities.impl.EffectEntity;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Effects.Effect;
|
||||
import io.anuke.mindustry.entities.Effects.EffectRenderer;
|
||||
import io.anuke.mindustry.entities.impl.EffectEntity;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.Vars;
|
||||
|
||||
@@ -2,9 +2,9 @@ package io.anuke.mindustry.entities.effect;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.entities.impl.TimedEntity;
|
||||
import io.anuke.arc.entities.trait.DrawTrait;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.impl.TimedEntity;
|
||||
import io.anuke.mindustry.entities.traits.DrawTrait;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Fill;
|
||||
import io.anuke.arc.graphics.g2d.Lines;
|
||||
@@ -14,8 +14,8 @@ import io.anuke.arc.math.geom.Position;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.entities.type.Unit;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
@@ -43,7 +43,7 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void transferItemToUnit(Item item, float x, float y, Unit to){
|
||||
if(to == null) return;
|
||||
create(item, x, y, to, () -> to.inventory.addItem(item, 1));
|
||||
create(item, x, y, to, () -> to.addItem(item));
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server)
|
||||
@@ -105,7 +105,7 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
Lines.stroke(fslope() * 2f, Palette.accent);
|
||||
Lines.stroke(fslope() * 2f, Pal.accent);
|
||||
|
||||
Lines.circle(x, y, fslope() * 2f);
|
||||
|
||||
|
||||
@@ -4,13 +4,14 @@ import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.IntSet;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.entities.impl.TimedEntity;
|
||||
import io.anuke.arc.entities.trait.DrawTrait;
|
||||
import io.anuke.arc.entities.trait.TimeTrait;
|
||||
import io.anuke.arc.graphics.g2d.Fill;
|
||||
import io.anuke.arc.graphics.g2d.Lines;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.impl.TimedEntity;
|
||||
import io.anuke.mindustry.entities.traits.DrawTrait;
|
||||
import io.anuke.mindustry.entities.traits.TimeTrait;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Lines;
|
||||
import io.anuke.arc.math.Angles;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.RandomXS128;
|
||||
@@ -20,13 +21,13 @@ import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
import io.anuke.mindustry.content.Bullets;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.type.Unit;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.bullet.Bullet;
|
||||
import io.anuke.mindustry.entities.traits.SyncTrait;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
@@ -45,7 +46,7 @@ public class Lightning extends TimedEntity implements DrawTrait, SyncTrait, Time
|
||||
private static int lastSeed = 0;
|
||||
|
||||
private Array<Position> lines = new Array<>();
|
||||
private Color color = Palette.lancerLaser;
|
||||
private Color color = Pal.lancerLaser;
|
||||
|
||||
/**For pooling use only. Do not call directly!*/
|
||||
public Lightning(){
|
||||
@@ -118,7 +119,7 @@ public class Lightning extends TimedEntity implements DrawTrait, SyncTrait, Time
|
||||
@Override
|
||||
public void reset(){
|
||||
super.reset();
|
||||
color = Palette.lancerLaser;
|
||||
color = Pal.lancerLaser;
|
||||
lines.clear();
|
||||
}
|
||||
|
||||
@@ -130,31 +131,22 @@ public class Lightning extends TimedEntity implements DrawTrait, SyncTrait, Time
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
float lx = x, ly = y;
|
||||
Lines.stroke(3f * fout());
|
||||
Draw.color(color, Color.WHITE, fin());
|
||||
//TODO this is really, really bad rendering
|
||||
/*
|
||||
for(int i = 0; i < lines.size; i++){
|
||||
Position v = lines.get(i);
|
||||
Lines.beginLine();
|
||||
|
||||
float f = (float) i / lines.size;
|
||||
Lines.linePoint(x, y);
|
||||
for(Position p : lines){
|
||||
Lines.linePoint(p.getX(), p.getY());
|
||||
}
|
||||
Lines.endLine();
|
||||
|
||||
Lines.stroke(fout() * 3f * (1.5f - f));
|
||||
int i = 0;
|
||||
|
||||
Lines.stroke(Lines.getStroke() * 4f);
|
||||
Draw.alpha(0.3f);
|
||||
Lines.line(lx, ly, v.getX(), v.getY());
|
||||
|
||||
Lines.stroke(Lines.getStroke()/4f);
|
||||
Draw.alpha(1f);
|
||||
Lines.line(lx, ly, v.getX(), v.getY());
|
||||
|
||||
Lines.stroke(3f * fout() * (1f - f));
|
||||
|
||||
lx = v.getX();
|
||||
ly = v.getY();
|
||||
}*/
|
||||
Draw.color();
|
||||
for(Position p : lines){
|
||||
Fill.square(p.getX(), p.getY(), (5f - (float)i++/lines.size*2f) * fout(), 45);
|
||||
}
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -3,10 +3,10 @@ package io.anuke.mindustry.entities.effect;
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.collection.IntMap;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.entities.impl.SolidEntity;
|
||||
import io.anuke.arc.entities.trait.DrawTrait;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.impl.SolidEntity;
|
||||
import io.anuke.mindustry.entities.traits.DrawTrait;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Fill;
|
||||
@@ -212,7 +212,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
|
||||
}
|
||||
});
|
||||
|
||||
if(liquid.temperature > 0.7f && tile.entity != null && Mathf.chance(0.3 * Time.delta())){
|
||||
if(liquid.temperature > 0.7f && (tile.target().entity != null) && Mathf.chance(0.3 * Time.delta())){
|
||||
Fire.create(tile);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,30 +2,43 @@ package io.anuke.mindustry.entities.effect;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
|
||||
public class RubbleDecal extends Decal{
|
||||
private int size;
|
||||
import static io.anuke.mindustry.Vars.headless;
|
||||
|
||||
/**
|
||||
* Creates a rubble effect at a position. Provide a block size to use.
|
||||
*/
|
||||
public class RubbleDecal extends Decal{
|
||||
private static final TextureRegion[][] regions = new TextureRegion[16][0];
|
||||
private TextureRegion region;
|
||||
|
||||
/**Creates a rubble effect at a position. Provide a block size to use.*/
|
||||
public static void create(float x, float y, int size){
|
||||
if(headless) return;
|
||||
|
||||
if(regions[size].length == 0){
|
||||
regions[size] = new TextureRegion[2];
|
||||
for(int j = 0; j < 2; j++){
|
||||
regions[size][j] = Core.atlas.find("rubble-" + size + "-" + j);
|
||||
}
|
||||
}
|
||||
|
||||
RubbleDecal decal = new RubbleDecal();
|
||||
decal.size = size;
|
||||
decal.region = regions[size][Mathf.clamp(Mathf.randomSeed(decal.id, 0, 1), 0, regions[size].length - 1)];
|
||||
|
||||
if(!Core.atlas.isFound(decal.region)){
|
||||
return;
|
||||
}
|
||||
|
||||
decal.set(x, y);
|
||||
decal.add();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawDecal(){
|
||||
String region = "rubble-" + size + "-" + Mathf.randomSeed(id, 0, 1);
|
||||
|
||||
if(!Core.atlas.has(region)){
|
||||
if(!Core.atlas.isFound(region)){
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
|
||||
Draw.rect(region, x, y, Mathf.randomSeed(id, 0, 4) * 90);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import io.anuke.arc.math.Angles;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
import static io.anuke.mindustry.Vars.headless;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class ScorchDecal extends Decal{
|
||||
@@ -14,6 +15,8 @@ public class ScorchDecal extends Decal{
|
||||
private static final TextureRegion[] regions = new TextureRegion[scorches];
|
||||
|
||||
public static void create(float x, float y){
|
||||
if(headless) return;
|
||||
|
||||
if(regions[0] == null){
|
||||
for(int i = 0; i < regions.length; i++){
|
||||
regions[i] = Core.atlas.find("scorch" + (i + 1));
|
||||
|
||||
61
core/src/io/anuke/mindustry/entities/impl/BaseEntity.java
Executable file
61
core/src/io/anuke/mindustry/entities/impl/BaseEntity.java
Executable file
@@ -0,0 +1,61 @@
|
||||
package io.anuke.mindustry.entities.impl;
|
||||
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.traits.Entity;
|
||||
|
||||
public abstract class BaseEntity implements Entity{
|
||||
private static int lastid;
|
||||
/** Do not modify. Used for network operations and mapping. */
|
||||
public int id;
|
||||
public float x, y;
|
||||
protected transient EntityGroup group;
|
||||
|
||||
public BaseEntity(){
|
||||
id = lastid++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getID(){
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetID(int id){
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityGroup getGroup(){
|
||||
return group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroup(EntityGroup group){
|
||||
this.group = group;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getX(){
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setX(float x){
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getY(){
|
||||
return y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setY(float y){
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return getClass() + " " + id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package io.anuke.mindustry.entities.impl;
|
||||
|
||||
|
||||
import io.anuke.mindustry.entities.traits.DamageTrait;
|
||||
import io.anuke.mindustry.entities.traits.HealthTrait;
|
||||
import io.anuke.mindustry.entities.traits.SolidTrait;
|
||||
|
||||
public abstract class DestructibleEntity extends SolidEntity implements HealthTrait{
|
||||
public transient boolean dead;
|
||||
public float health;
|
||||
|
||||
@Override
|
||||
public boolean collides(SolidTrait other){
|
||||
return other instanceof DamageTrait;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collision(SolidTrait other, float x, float y){
|
||||
if(other instanceof DamageTrait){
|
||||
onHit(other);
|
||||
damage(((DamageTrait) other).damage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void health(float health){
|
||||
this.health = health;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float health(){
|
||||
return health;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDead(){
|
||||
return dead;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDead(boolean dead){
|
||||
this.dead = dead;
|
||||
}
|
||||
|
||||
}
|
||||
72
core/src/io/anuke/mindustry/entities/impl/EffectEntity.java
Normal file
72
core/src/io/anuke/mindustry/entities/impl/EffectEntity.java
Normal file
@@ -0,0 +1,72 @@
|
||||
package io.anuke.mindustry.entities.impl;
|
||||
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.util.pooling.Pool.Poolable;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Effects.Effect;
|
||||
import io.anuke.mindustry.entities.traits.DrawTrait;
|
||||
import io.anuke.mindustry.entities.traits.Entity;
|
||||
|
||||
public class EffectEntity extends TimedEntity implements Poolable, DrawTrait{
|
||||
public Effect effect;
|
||||
public Color color = new Color(Color.WHITE);
|
||||
public Object data;
|
||||
public float rotation = 0f;
|
||||
|
||||
public Entity parent;
|
||||
public float poffsetx, poffsety;
|
||||
|
||||
/** For pooling use only! */
|
||||
public EffectEntity(){
|
||||
}
|
||||
|
||||
public void setParent(Entity parent){
|
||||
this.parent = parent;
|
||||
this.poffsetx = x - parent.getX();
|
||||
this.poffsety = y - parent.getY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float lifetime(){
|
||||
return effect.lifetime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float drawSize(){
|
||||
return effect.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
if(effect == null){
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
|
||||
super.update();
|
||||
if(parent != null){
|
||||
x = parent.getX() + poffsetx;
|
||||
y = parent.getY() + poffsety;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(){
|
||||
effect = null;
|
||||
color.set(Color.WHITE);
|
||||
rotation = time = poffsetx = poffsety = 0f;
|
||||
parent = null;
|
||||
data = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
Effects.renderEffect(id, effect, color, time, rotation, x, y, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed(){
|
||||
Pools.free(this);
|
||||
}
|
||||
}
|
||||
19
core/src/io/anuke/mindustry/entities/impl/SolidEntity.java
Normal file
19
core/src/io/anuke/mindustry/entities/impl/SolidEntity.java
Normal file
@@ -0,0 +1,19 @@
|
||||
package io.anuke.mindustry.entities.impl;
|
||||
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.mindustry.entities.traits.SolidTrait;
|
||||
|
||||
public abstract class SolidEntity extends BaseEntity implements SolidTrait{
|
||||
protected transient Vector2 velocity = new Vector2(0f, 0.0001f);
|
||||
private transient Vector2 lastPosition = new Vector2();
|
||||
|
||||
@Override
|
||||
public Vector2 lastPosition(){
|
||||
return lastPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector2 velocity(){
|
||||
return velocity;
|
||||
}
|
||||
}
|
||||
34
core/src/io/anuke/mindustry/entities/impl/TimedEntity.java
Normal file
34
core/src/io/anuke/mindustry/entities/impl/TimedEntity.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package io.anuke.mindustry.entities.impl;
|
||||
|
||||
import io.anuke.arc.util.pooling.Pool.Poolable;
|
||||
import io.anuke.mindustry.entities.traits.ScaleTrait;
|
||||
import io.anuke.mindustry.entities.traits.TimeTrait;
|
||||
|
||||
public abstract class TimedEntity extends BaseEntity implements ScaleTrait, TimeTrait, Poolable{
|
||||
public float time;
|
||||
|
||||
@Override
|
||||
public void time(float time){
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float time(){
|
||||
return time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
updateTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(){
|
||||
time = 0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float fin(){
|
||||
return time() / lifetime();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.arc.entities.trait.DamageTrait;
|
||||
import io.anuke.arc.entities.trait.Entity;
|
||||
|
||||
public interface AbsorbTrait extends Entity, TeamTrait, DamageTrait{
|
||||
void absorb();
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.Queue;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.trait.Entity;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Fill;
|
||||
@@ -17,12 +15,13 @@ import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.entities.type.Unit;
|
||||
import io.anuke.mindustry.game.EventType.BuildSelectEvent;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.graphics.Shapes;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
@@ -43,7 +42,7 @@ import static io.anuke.mindustry.Vars.*;
|
||||
/**
|
||||
* Interface for units that build, break or mine things.
|
||||
*/
|
||||
public interface BuilderTrait extends Entity{
|
||||
public interface BuilderTrait extends Entity, TeamTrait{
|
||||
//these are not instance variables!
|
||||
Vector2[] tmptr = new Vector2[]{new Vector2(), new Vector2(), new Vector2(), new Vector2()};
|
||||
float placeDistance = 150f;
|
||||
@@ -125,22 +124,6 @@ public interface BuilderTrait extends Entity{
|
||||
return getPlaceQueue().size != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a place request matching this signature is present, it is removed.
|
||||
* Otherwise, a new place request is added to the queue.
|
||||
*/
|
||||
default void replaceBuilding(int x, int y, int rotation, Block block){
|
||||
for(BuildRequest request : getPlaceQueue()){
|
||||
if(request.x == x && request.y == y){
|
||||
clearBuilding();
|
||||
addBuildRequest(request);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
addBuildRequest(new BuildRequest(x, y, rotation, block));
|
||||
}
|
||||
|
||||
/**Clears the placement queue.*/
|
||||
default void clearBuilding(){
|
||||
getPlaceQueue().clear();
|
||||
@@ -172,7 +155,8 @@ public interface BuilderTrait extends Entity{
|
||||
* Update building mechanism for this unit.
|
||||
* This includes mining.
|
||||
*/
|
||||
default void updateBuilding(Unit unit){
|
||||
default void updateBuilding(){
|
||||
Unit unit = (Unit)this;
|
||||
//remove already completed build requests
|
||||
removal.clear();
|
||||
for(BuildRequest req : getPlaceQueue()){
|
||||
@@ -183,8 +167,7 @@ public interface BuilderTrait extends Entity{
|
||||
|
||||
for(BuildRequest request : removal){
|
||||
if(!((request.breaking && world.tile(request.x, request.y).block() == Blocks.air) ||
|
||||
(!request.breaking &&
|
||||
(world.tile(request.x, request.y).getRotation() == request.rotation || !request.block.rotate)
|
||||
(!request.breaking && (world.tile(request.x, request.y).getRotation() == request.rotation || !request.block.rotate)
|
||||
&& world.tile(request.x, request.y).block() == request.block))){
|
||||
getPlaceQueue().addLast(request);
|
||||
}
|
||||
@@ -195,7 +178,7 @@ public interface BuilderTrait extends Entity{
|
||||
//update mining here
|
||||
if(current == null){
|
||||
if(getMineTile() != null){
|
||||
updateMining(unit);
|
||||
updateMining();
|
||||
}
|
||||
return;
|
||||
}else{
|
||||
@@ -204,15 +187,19 @@ public interface BuilderTrait extends Entity{
|
||||
|
||||
Tile tile = world.tile(current.x, current.y);
|
||||
|
||||
if(unit.dst(tile) > placeDistance){
|
||||
if(dst(tile) > placeDistance){
|
||||
if(getPlaceQueue().size > 1){
|
||||
getPlaceQueue().removeFirst();
|
||||
getPlaceQueue().addLast(current);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(tile.block() instanceof BuildBlock)){
|
||||
if(canCreateBlocks() && !current.breaking && Build.validPlace(unit.getTeam(), current.x, current.y, current.block, current.rotation)){
|
||||
Build.beginPlace(unit.getTeam(), current.x, current.y, current.block, current.rotation);
|
||||
}else if(canCreateBlocks() && current.breaking && Build.validBreak(unit.getTeam(), current.x, current.y)){
|
||||
Build.beginBreak(unit.getTeam(), current.x, current.y);
|
||||
if(canCreateBlocks() && !current.breaking && Build.validPlace(getTeam(), current.x, current.y, current.block, current.rotation)){
|
||||
Build.beginPlace(getTeam(), current.x, current.y, current.block, current.rotation);
|
||||
}else if(canCreateBlocks() && current.breaking && Build.validBreak(getTeam(), current.x, current.y)){
|
||||
Build.beginBreak(getTeam(), current.x, current.y);
|
||||
}else{
|
||||
getPlaceQueue().removeFirst();
|
||||
return;
|
||||
@@ -259,12 +246,13 @@ public interface BuilderTrait extends Entity{
|
||||
}
|
||||
|
||||
/**Do not call directly.*/
|
||||
default void updateMining(Unit unit){
|
||||
default void updateMining(){
|
||||
Unit unit = (Unit)this;
|
||||
Tile tile = getMineTile();
|
||||
TileEntity core = unit.getClosestCore();
|
||||
|
||||
if(core == null || tile.block() != Blocks.air || unit.dst(tile.worldx(), tile.worldy()) > mineDistance
|
||||
|| tile.floor().itemDrop == null || !unit.inventory.canAcceptItem(tile.floor().itemDrop) || !canMine(tile.floor().itemDrop)){
|
||||
if(core == null || tile.block() != Blocks.air || dst(tile.worldx(), tile.worldy()) > mineDistance
|
||||
|| tile.floor().itemDrop == null || !unit.acceptsItem(tile.floor().itemDrop) || !canMine(tile.floor().itemDrop)){
|
||||
setMineTile(null);
|
||||
}else{
|
||||
Item item = tile.floor().itemDrop;
|
||||
@@ -276,7 +264,7 @@ public interface BuilderTrait extends Entity{
|
||||
Call.transferItemTo(item, 1,
|
||||
tile.worldx() + Mathf.range(tilesize / 2f),
|
||||
tile.worldy() + Mathf.range(tilesize / 2f), core.tile);
|
||||
}else if(unit.inventory.canAcceptItem(item)){
|
||||
}else if(unit.acceptsItem(item)){
|
||||
Call.transferItemToUnit(item,
|
||||
tile.worldx() + Mathf.range(tilesize / 2f),
|
||||
tile.worldy() + Mathf.range(tilesize / 2f),
|
||||
@@ -293,11 +281,12 @@ public interface BuilderTrait extends Entity{
|
||||
}
|
||||
|
||||
/**Draw placement effects for an entity. This includes mining*/
|
||||
default void drawBuilding(Unit unit){
|
||||
default void drawBuilding(){
|
||||
Unit unit = (Unit)this;
|
||||
BuildRequest request;
|
||||
if(!isBuilding()){
|
||||
if(getMineTile() != null){
|
||||
drawMining(unit);
|
||||
drawMining();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -306,11 +295,11 @@ public interface BuilderTrait extends Entity{
|
||||
|
||||
Tile tile = world.tile(request.x, request.y);
|
||||
|
||||
if(unit.dst(tile) > placeDistance){
|
||||
if(dst(tile) > placeDistance){
|
||||
return;
|
||||
}
|
||||
|
||||
Lines.stroke(1f, Palette.accent);
|
||||
Lines.stroke(1f, Pal.accent);
|
||||
float focusLen = 3.8f + Mathf.absin(Time.time(), 1.1f, 0.6f);
|
||||
float px = unit.x + Angles.trnsx(unit.rotation, focusLen);
|
||||
float py = unit.y + Angles.trnsy(unit.rotation, focusLen);
|
||||
@@ -340,7 +329,8 @@ public interface BuilderTrait extends Entity{
|
||||
}
|
||||
|
||||
/**Internal use only.*/
|
||||
default void drawMining(Unit unit){
|
||||
default void drawMining(){
|
||||
Unit unit = (Unit)this;
|
||||
Tile tile = getMineTile();
|
||||
|
||||
if(tile == null) return;
|
||||
@@ -357,10 +347,10 @@ public interface BuilderTrait extends Entity{
|
||||
|
||||
Draw.color(Color.LIGHT_GRAY, Color.WHITE, 1f - flashScl + Mathf.absin(Time.time(), 0.5f, flashScl));
|
||||
|
||||
Shapes.laser("minelaser", "minelaser-end", px, py, ex, ey);
|
||||
Shapes.laser("minelaser", "minelaser-end", px, py, ex, ey, 0.75f);
|
||||
|
||||
if(unit instanceof Player && ((Player) unit).isLocal){
|
||||
Lines.stroke(1f, Palette.accent);
|
||||
Lines.stroke(1f, Pal.accent);
|
||||
Lines.poly(tile.worldx(), tile.worldy(), 4, tilesize / 2f * Mathf.sqrt2, Time.time());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.arc.entities.trait.SolidTrait;
|
||||
|
||||
public interface CarriableTrait extends TeamTrait, TargetTrait, SolidTrait{
|
||||
|
||||
default boolean isCarried(){
|
||||
return getCarrier() != null;
|
||||
}
|
||||
|
||||
CarryTrait getCarrier();
|
||||
|
||||
void setCarrier(CarryTrait carrier);
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.trait.SolidTrait;
|
||||
|
||||
public interface CarryTrait extends TeamTrait, SolidTrait, TargetTrait{
|
||||
|
||||
@Remote(called = Loc.both, targets = Loc.both, forward = true)
|
||||
static void dropSelf(Player player){
|
||||
if(player != null && player.getCarrier() != null){
|
||||
player.getCarrier().dropCarry();
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.both, targets = Loc.both, forward = true)
|
||||
static void setCarryOf(Player player, CarryTrait trait, CarriableTrait unit){
|
||||
if(trait == null) return;
|
||||
if(player != null){ //when a server recieves this called from a player, set the carrier to the player.
|
||||
trait = player;
|
||||
}
|
||||
|
||||
if(trait.getCarry() != null){ //already carrying something, drop it
|
||||
//drop current
|
||||
Effects.effect(Fx.unitDrop, trait.getCarry());
|
||||
trait.getCarry().setCarrier(null);
|
||||
trait.setCarry(null);
|
||||
|
||||
if(unit != null){
|
||||
trait.carry(unit); //now carry this new thing
|
||||
}
|
||||
}else if(unit != null){ //not currently carrying anything, make sure it's not null
|
||||
trait.setCarry(unit);
|
||||
unit.setCarrier(trait);
|
||||
|
||||
Effects.effect(Fx.unitPickup, trait);
|
||||
}
|
||||
}
|
||||
|
||||
/**Returns the thing this carrier is carrying.*/
|
||||
CarriableTrait getCarry();
|
||||
|
||||
/**Sets the carrying unit. Internal use only! Use {@link #carry(CarriableTrait)} to set state.*/
|
||||
void setCarry(CarriableTrait unit);
|
||||
|
||||
/**Returns maximum mass this carrier can carry.*/
|
||||
float getCarryWeight();
|
||||
|
||||
/**Drops the unit that is being carried, if applicable.*/
|
||||
default void dropCarry(){
|
||||
carry(null);
|
||||
}
|
||||
|
||||
default void dropCarryLocal(){
|
||||
setCarryOf(null, this, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not override unless absolutely necessary.
|
||||
* Carries a unit. To drop a unit, call with {@code null}.
|
||||
*/
|
||||
default void carry(CarriableTrait unit){
|
||||
Call.setCarryOf(this instanceof Player ? (Player) this : null, this, unit);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
public interface DamageTrait{
|
||||
float damage();
|
||||
}
|
||||
10
core/src/io/anuke/mindustry/entities/traits/DrawTrait.java
Normal file
10
core/src/io/anuke/mindustry/entities/traits/DrawTrait.java
Normal file
@@ -0,0 +1,10 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
public interface DrawTrait extends Entity{
|
||||
|
||||
default float drawSize(){
|
||||
return 20f;
|
||||
}
|
||||
|
||||
void draw();
|
||||
}
|
||||
46
core/src/io/anuke/mindustry/entities/traits/Entity.java
Normal file
46
core/src/io/anuke/mindustry/entities/traits/Entity.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.mindustry.entities.Entities;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
|
||||
public interface Entity extends MoveTrait{
|
||||
|
||||
int getID();
|
||||
|
||||
void resetID(int id);
|
||||
|
||||
default void update(){
|
||||
}
|
||||
|
||||
default void removed(){
|
||||
}
|
||||
|
||||
default void added(){
|
||||
}
|
||||
|
||||
default EntityGroup targetGroup(){
|
||||
return Entities.defaultGroup();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
default void add(){
|
||||
targetGroup().add(this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
default void remove(){
|
||||
if(getGroup() != null){
|
||||
getGroup().remove(this);
|
||||
}
|
||||
|
||||
setGroup(null);
|
||||
}
|
||||
|
||||
EntityGroup getGroup();
|
||||
|
||||
void setGroup(EntityGroup group);
|
||||
|
||||
default boolean isAdded(){
|
||||
return getGroup() != null;
|
||||
}
|
||||
}
|
||||
48
core/src/io/anuke/mindustry/entities/traits/HealthTrait.java
Normal file
48
core/src/io/anuke/mindustry/entities/traits/HealthTrait.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.arc.math.Mathf;
|
||||
|
||||
public interface HealthTrait{
|
||||
|
||||
void health(float health);
|
||||
|
||||
float health();
|
||||
|
||||
float maxHealth();
|
||||
|
||||
boolean isDead();
|
||||
|
||||
void setDead(boolean dead);
|
||||
|
||||
default void onHit(SolidTrait entity){
|
||||
}
|
||||
|
||||
default void onDeath(){
|
||||
}
|
||||
|
||||
default void damage(float amount){
|
||||
health(health() - amount);
|
||||
if(health() <= 0 && !isDead()){
|
||||
onDeath();
|
||||
setDead(true);
|
||||
}
|
||||
}
|
||||
|
||||
default void clampHealth(){
|
||||
health(Mathf.clamp(health(), 0, maxHealth()));
|
||||
}
|
||||
|
||||
default float healthf(){
|
||||
return health() / maxHealth();
|
||||
}
|
||||
|
||||
default void healBy(float amount){
|
||||
health(health() + amount);
|
||||
clampHealth();
|
||||
}
|
||||
|
||||
default void heal(){
|
||||
health(maxHealth());
|
||||
setDead(false);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.mindustry.entities.UnitInventory;
|
||||
|
||||
public interface InventoryTrait{
|
||||
UnitInventory getInventory();
|
||||
}
|
||||
20
core/src/io/anuke/mindustry/entities/traits/MoveTrait.java
Normal file
20
core/src/io/anuke/mindustry/entities/traits/MoveTrait.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.arc.math.geom.Position;
|
||||
|
||||
public interface MoveTrait extends Position{
|
||||
|
||||
void setX(float x);
|
||||
|
||||
void setY(float y);
|
||||
|
||||
default void moveBy(float x, float y){
|
||||
setX(getX() + x);
|
||||
setY(getY() + y);
|
||||
}
|
||||
|
||||
default void set(float x, float y){
|
||||
setX(x);
|
||||
setY(y);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.arc.entities.trait.Entity;
|
||||
|
||||
/**
|
||||
* Marks an entity as serializable.
|
||||
*/
|
||||
|
||||
43
core/src/io/anuke/mindustry/entities/traits/ScaleTrait.java
Normal file
43
core/src/io/anuke/mindustry/entities/traits/ScaleTrait.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.arc.math.Interpolation;
|
||||
|
||||
public interface ScaleTrait{
|
||||
/** 0 to 1. */
|
||||
float fin();
|
||||
|
||||
/** 1 to 0 */
|
||||
default float fout(){
|
||||
return 1f - fin();
|
||||
}
|
||||
|
||||
/** 1 to 0 */
|
||||
default float fout(Interpolation i){
|
||||
return i.apply(fout());
|
||||
}
|
||||
|
||||
/** 1 to 0, ending at the specified margin */
|
||||
default float fout(float margin){
|
||||
float f = fin();
|
||||
if(f >= 1f - margin){
|
||||
return 1f - (f - (1f - margin)) / margin;
|
||||
}else{
|
||||
return 1f;
|
||||
}
|
||||
}
|
||||
|
||||
/** 0 to 1 **/
|
||||
default float fin(Interpolation i){
|
||||
return i.apply(fin());
|
||||
}
|
||||
|
||||
/** 0 to 1 */
|
||||
default float finpow(){
|
||||
return Interpolation.pow3Out.apply(fin());
|
||||
}
|
||||
|
||||
/** 0 to 1 to 0 */
|
||||
default float fslope(){
|
||||
return (0.5f - Math.abs(fin() - 0.5f)) * 2f;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.arc.entities.trait.VelocityTrait;
|
||||
import io.anuke.arc.util.Interval;
|
||||
import io.anuke.mindustry.type.Weapon;
|
||||
|
||||
public interface ShooterTrait extends VelocityTrait, TeamTrait, InventoryTrait{
|
||||
public interface ShooterTrait extends VelocityTrait, TeamTrait{
|
||||
|
||||
Interval getTimer();
|
||||
|
||||
|
||||
43
core/src/io/anuke/mindustry/entities/traits/SolidTrait.java
Normal file
43
core/src/io/anuke/mindustry/entities/traits/SolidTrait.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
|
||||
import io.anuke.mindustry.entities.EntityQuery;
|
||||
import io.anuke.arc.math.geom.Position;
|
||||
import io.anuke.arc.math.geom.QuadTree.QuadTreeObject;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
|
||||
public interface SolidTrait extends QuadTreeObject, MoveTrait, VelocityTrait, Entity, Position{
|
||||
|
||||
void hitbox(Rectangle rectangle);
|
||||
|
||||
void hitboxTile(Rectangle rectangle);
|
||||
|
||||
Vector2 lastPosition();
|
||||
|
||||
default boolean collidesGrid(int x, int y){
|
||||
return true;
|
||||
}
|
||||
|
||||
default float getDeltaX(){
|
||||
return getX() - lastPosition().x;
|
||||
}
|
||||
|
||||
default float getDeltaY(){
|
||||
return getY() - lastPosition().y;
|
||||
}
|
||||
|
||||
default boolean movable(){
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean collides(SolidTrait other){
|
||||
return true;
|
||||
}
|
||||
|
||||
default void collision(SolidTrait other, float x, float y){}
|
||||
|
||||
default void move(float x, float y){
|
||||
EntityQuery.collisions().move(this, x, y);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,16 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.arc.math.geom.Position;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
public interface SpawnerTrait{
|
||||
public interface SpawnerTrait extends TargetTrait, Position{
|
||||
Tile getTile();
|
||||
|
||||
void updateSpawning(Unit unit);
|
||||
void updateSpawning(Player unit);
|
||||
|
||||
float getSpawnProgress();
|
||||
@Override
|
||||
default boolean isValid(){
|
||||
return getTile().entity instanceof SpawnerTrait;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package io.anuke.mindustry.entities.traits;
|
||||
import io.anuke.mindustry.core.NetClient;
|
||||
import io.anuke.mindustry.net.Interpolator;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.entities.trait.Entity;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
|
||||
import java.io.DataInput;
|
||||
@@ -63,6 +62,10 @@ public interface SyncTrait extends Entity, TypeTrait{
|
||||
return true;
|
||||
}
|
||||
|
||||
default float clipSize(){
|
||||
return (this instanceof DrawTrait ? ((DrawTrait)this).drawSize() : 8f);
|
||||
}
|
||||
|
||||
//Read and write sync data, usually position
|
||||
void write(DataOutput data) throws IOException;
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.arc.entities.trait.SolidTrait;
|
||||
import io.anuke.arc.entities.trait.VelocityTrait;
|
||||
import io.anuke.arc.math.geom.Position;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.arc.entities.trait.Entity;
|
||||
|
||||
public interface TeamTrait extends Entity{
|
||||
Team getTeam();
|
||||
|
||||
23
core/src/io/anuke/mindustry/entities/traits/TimeTrait.java
Normal file
23
core/src/io/anuke/mindustry/entities/traits/TimeTrait.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.util.Time;
|
||||
|
||||
public interface TimeTrait extends ScaleTrait, Entity{
|
||||
|
||||
float lifetime();
|
||||
|
||||
void time(float time);
|
||||
|
||||
float time();
|
||||
|
||||
default void updateTime(){
|
||||
time(Mathf.clamp(time() + Time.delta(), 0, lifetime()));
|
||||
|
||||
if(time() >= lifetime()){
|
||||
remove();
|
||||
}
|
||||
}
|
||||
|
||||
//fin() is not implemented due to compiler issues with iOS/RoboVM
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.util.Time;
|
||||
|
||||
public interface VelocityTrait extends MoveTrait{
|
||||
|
||||
Vector2 velocity();
|
||||
|
||||
default void applyImpulse(float x, float y){
|
||||
velocity().x += x / mass();
|
||||
velocity().y += y / mass();
|
||||
}
|
||||
|
||||
default float maxVelocity(){
|
||||
return Float.MAX_VALUE;
|
||||
}
|
||||
|
||||
default float mass(){
|
||||
return 1f;
|
||||
}
|
||||
|
||||
default float drag(){
|
||||
return 0f;
|
||||
}
|
||||
|
||||
default void updateVelocity(){
|
||||
velocity().scl(1f - drag() * Time.delta());
|
||||
|
||||
if(this instanceof SolidTrait){
|
||||
((SolidTrait) this).move(velocity().x * Time.delta(), velocity().y * Time.delta());
|
||||
}else{
|
||||
moveBy(velocity().x * Time.delta(), velocity().y * Time.delta());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
package io.anuke.mindustry.entities.units;
|
||||
package io.anuke.mindustry.entities.type;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.math.Angles;
|
||||
@@ -14,22 +12,18 @@ import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.arc.util.Interval;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.Damage;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.content.StatusEffects;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.effect.ScorchDecal;
|
||||
import io.anuke.mindustry.entities.traits.ShooterTrait;
|
||||
import io.anuke.mindustry.entities.traits.SpawnerTrait;
|
||||
import io.anuke.mindustry.entities.traits.TargetTrait;
|
||||
import io.anuke.mindustry.entities.units.StateMachine;
|
||||
import io.anuke.mindustry.entities.units.UnitDrops;
|
||||
import io.anuke.mindustry.entities.units.UnitState;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.type.Weapon;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.meta.BlockFlag;
|
||||
|
||||
@@ -53,8 +47,6 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
protected StateMachine state = new StateMachine();
|
||||
protected TargetTrait target;
|
||||
|
||||
protected boolean isWave;
|
||||
protected Squad squad;
|
||||
protected int spawner = noSpawner;
|
||||
|
||||
/**internal constructor used for deserialization, DO NOT USE*/
|
||||
@@ -69,16 +61,8 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
UnitDrops.dropItems(unit);
|
||||
}
|
||||
|
||||
float explosiveness = 2f + (unit.inventory.hasItem() ? unit.inventory.getItem().item.explosiveness * unit.inventory.getItem().amount : 0f);
|
||||
float flammability = (unit.inventory.hasItem() ? unit.inventory.getItem().item.flammability * unit.inventory.getItem().amount : 0f);
|
||||
Damage.dynamicExplosion(unit.x, unit.y, flammability, explosiveness, 0f, unit.getSize() / 2f, Palette.darkFlame);
|
||||
|
||||
unit.onSuperDeath();
|
||||
|
||||
ScorchDecal.create(unit.x, unit.y);
|
||||
Effects.effect(Fx.explosion, unit);
|
||||
Effects.shake(2f, 2f, unit);
|
||||
|
||||
//must run afterwards so the unit's group is not null when sending the removal packet
|
||||
Core.app.post(unit::remove);
|
||||
}
|
||||
@@ -104,36 +88,12 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
this.spawner = tile.pos();
|
||||
}
|
||||
|
||||
/**Sets this to a 'wave' unit, which means it has slightly different AI and will not run out of ammo.*/
|
||||
public void setWave(){
|
||||
isWave = true;
|
||||
}
|
||||
|
||||
public void setSquad(Squad squad){
|
||||
this.squad = squad;
|
||||
squad.units++;
|
||||
}
|
||||
|
||||
public void rotate(float angle){
|
||||
rotation = Mathf.slerpDelta(rotation, angle, type.rotatespeed);
|
||||
}
|
||||
|
||||
public boolean targetHasFlag(BlockFlag flag){
|
||||
return target instanceof TileEntity && ((TileEntity) target).tile.block().flags != null &&
|
||||
((TileEntity) target).tile.block().flags.contains(flag);
|
||||
}
|
||||
|
||||
public void updateRespawning(){
|
||||
if(spawner == noSpawner) return;
|
||||
|
||||
Tile tile = world.tile(spawner);
|
||||
if(tile != null && tile.entity != null){
|
||||
if(tile.entity instanceof SpawnerTrait){
|
||||
((SpawnerTrait) tile.entity).updateSpawning(this);
|
||||
}
|
||||
}else{
|
||||
spawner = noSpawner;
|
||||
}
|
||||
return target instanceof TileEntity && ((TileEntity) target).tile.block().flags.contains(flag);
|
||||
}
|
||||
|
||||
public void setState(UnitState state){
|
||||
@@ -169,7 +129,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
}
|
||||
|
||||
public void targetClosest(){
|
||||
target = Units.getClosestTarget(team, x, y, Math.max(getWeapon().getAmmo().range(), type.range), u -> type.targetAir || !u.isFlying());
|
||||
target = Units.getClosestTarget(team, x, y, Math.max(getWeapon().bullet.range(), type.range), u -> type.targetAir || !u.isFlying());
|
||||
}
|
||||
|
||||
public TileEntity getClosestEnemyCore(){
|
||||
@@ -189,15 +149,14 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
}
|
||||
|
||||
protected void drawItems(){
|
||||
float backTrns = 4f, itemSize = 5f;
|
||||
if(inventory.hasItem()){
|
||||
ItemStack stack = inventory.getItem();
|
||||
int stored = Mathf.clamp(stack.amount / 6, 1, 8);
|
||||
float backTrns = 4f;
|
||||
if(item.amount > 0){
|
||||
int stored = Mathf.clamp(item.amount / 6, 1, 8);
|
||||
|
||||
for(int i = 0; i < stored; i++){
|
||||
float angT = i == 0 ? 0 : Mathf.randomSeedRange(i + 2, 60f);
|
||||
float lenT = i == 0 ? 0 : Mathf.randomSeedRange(i + 3, 1f) - 1f;
|
||||
Draw.rect(stack.item.region,
|
||||
Draw.rect(item.item.icon(Item.Icon.large),
|
||||
x + Angles.trnsx(rotation + 180f + angT, backTrns + lenT),
|
||||
y + Angles.trnsy(rotation + 180f + angT, backTrns + lenT),
|
||||
itemSize, itemSize, rotation);
|
||||
@@ -205,6 +164,15 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isBoss(){
|
||||
return hasEffect(StatusEffects.boss);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isImmune(StatusEffect effect){
|
||||
return type.immunities.contains(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(){
|
||||
return super.isValid() && isAdded();
|
||||
@@ -249,16 +217,6 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
return type.health;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getArmor(){
|
||||
return type.armor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSize(){
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float mass(){
|
||||
return type.mass;
|
||||
@@ -274,7 +232,6 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
hitTime -= Time.delta();
|
||||
|
||||
if(isDead()){
|
||||
updateRespawning();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -290,10 +247,6 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
damage(health);
|
||||
}
|
||||
|
||||
if(squad != null){
|
||||
squad.update();
|
||||
}
|
||||
|
||||
updateTargeting();
|
||||
|
||||
state.update();
|
||||
@@ -301,8 +254,9 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
|
||||
if(target != null) behavior();
|
||||
|
||||
x = Mathf.clamp(x, tilesize, world.width() * tilesize - tilesize);
|
||||
y = Mathf.clamp(y, tilesize, world.height() * tilesize - tilesize);
|
||||
if(!isFlying()){
|
||||
clampPosition();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -317,12 +271,22 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
|
||||
@Override
|
||||
public void removed(){
|
||||
Tile tile = world.tile(spawner);
|
||||
if(tile != null){
|
||||
tile.block().unitRemoved(tile, this);
|
||||
}
|
||||
|
||||
spawner = noSpawner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float drawSize(){
|
||||
return 14;
|
||||
return type.hitsize * 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float clipSize(){
|
||||
return isBoss() ? 10000000000f : super.clipSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -356,7 +320,6 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
public void writeSave(DataOutput stream) throws IOException{
|
||||
super.writeSave(stream);
|
||||
stream.writeByte(type.id);
|
||||
stream.writeBoolean(isWave);
|
||||
stream.writeInt(spawner);
|
||||
}
|
||||
|
||||
@@ -364,7 +327,6 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
public void readSave(DataInput stream) throws IOException{
|
||||
super.readSave(stream);
|
||||
byte type = stream.readByte();
|
||||
this.isWave = stream.readBoolean();
|
||||
this.spawner = stream.readInt();
|
||||
|
||||
this.type = content.getByID(ContentType.unit, type);
|
||||
221
core/src/io/anuke/mindustry/entities/type/FlyingUnit.java
Normal file
221
core/src/io/anuke/mindustry/entities/type/FlyingUnit.java
Normal file
@@ -0,0 +1,221 @@
|
||||
package io.anuke.mindustry.entities.type;
|
||||
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Fill;
|
||||
import io.anuke.arc.math.Angles;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.mindustry.entities.Predict;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
import io.anuke.mindustry.entities.units.UnitState;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.world.meta.BlockFlag;
|
||||
|
||||
public abstract class FlyingUnit extends BaseUnit{
|
||||
protected float[] weaponAngles = {0, 0};
|
||||
|
||||
protected final UnitState
|
||||
|
||||
attack = new UnitState(){
|
||||
public void entered(){
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update(){
|
||||
|
||||
if(Units.invalidateTarget(target, team, x, y)){
|
||||
target = null;
|
||||
}
|
||||
|
||||
if(target == null){
|
||||
|
||||
retarget(() -> {
|
||||
targetClosest();
|
||||
|
||||
if(target == null) targetClosestEnemyFlag(BlockFlag.producer);
|
||||
if(target == null) targetClosestEnemyFlag(BlockFlag.turret);
|
||||
|
||||
if(target == null){
|
||||
setState(patrol);
|
||||
}
|
||||
});
|
||||
|
||||
}else{
|
||||
attack(type.attackLength);
|
||||
|
||||
if((Angles.near(angleTo(target), rotation, type.shootCone) || getWeapon().ignoreRotation) //bombers and such don't care about rotation
|
||||
&& dst(target) < Math.max(getWeapon().bullet.range(), type.range)){
|
||||
BulletType ammo = getWeapon().bullet;
|
||||
|
||||
if(type.rotateWeapon){
|
||||
for(boolean left : Mathf.booleans){
|
||||
int wi = Mathf.num(left);
|
||||
float wx = x + Angles.trnsx(rotation - 90, getWeapon().width * Mathf.sign(left));
|
||||
float wy = y + Angles.trnsy(rotation - 90, getWeapon().width * Mathf.sign(left));
|
||||
|
||||
weaponAngles[wi] = Mathf.slerpDelta(weaponAngles[wi], Angles.angle(wx, wy, target.getX(), target.getY()), 0.1f);
|
||||
|
||||
Tmp.v2.trns(weaponAngles[wi], getWeapon().length);
|
||||
getWeapon().update(FlyingUnit.this, wx + Tmp.v2.x, wy + Tmp.v2.y, weaponAngles[wi], left);
|
||||
}
|
||||
}else{
|
||||
Vector2 to = Predict.intercept(FlyingUnit.this, target, ammo.speed);
|
||||
getWeapon().update(FlyingUnit.this, to.x, to.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
patrol = new UnitState(){
|
||||
public void update(){
|
||||
retarget(() -> {
|
||||
targetClosest();
|
||||
targetClosestEnemyFlag(BlockFlag.target);
|
||||
|
||||
if(target != null){
|
||||
setState(attack);
|
||||
}
|
||||
|
||||
target = getClosestCore();
|
||||
});
|
||||
|
||||
if(target != null){
|
||||
circle(60f + Mathf.absin(Time.time() + id * 23525, 70f, 1200f));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void move(float x, float y){
|
||||
moveBy(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
super.update();
|
||||
|
||||
if(!Net.client()){
|
||||
updateRotation();
|
||||
wobble();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawUnder(){
|
||||
drawEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
Draw.mixcol(Color.WHITE, hitTime / hitDuration);
|
||||
Draw.rect(type.region, x, y, rotation - 90);
|
||||
|
||||
drawWeapons();
|
||||
drawItems();
|
||||
|
||||
Draw.mixcol();
|
||||
}
|
||||
|
||||
public void drawWeapons(){
|
||||
|
||||
}
|
||||
|
||||
public void drawEngine(){
|
||||
Draw.color(Pal.engine);
|
||||
Fill.circle(x + Angles.trnsx(rotation + 180, type.engineOffset), y + Angles.trnsy(rotation + 180, type.engineOffset),
|
||||
type.engineSize + Mathf.absin(Time.time(), 2f, type.engineSize/4f));
|
||||
|
||||
Draw.color(Color.WHITE);
|
||||
Fill.circle(x + Angles.trnsx(rotation + 180, type.engineOffset-1f), y + Angles.trnsy(rotation + 180, type.engineOffset-1f),
|
||||
(type.engineSize + Mathf.absin(Time.time(), 2f, type.engineSize/4f)) / 2f);
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void behavior(){
|
||||
|
||||
if(Units.invalidateTarget(target, this)){
|
||||
for(boolean left : Mathf.booleans){
|
||||
int wi = Mathf.num(left);
|
||||
weaponAngles[wi] = Mathf.slerpDelta(weaponAngles[wi],rotation, 0.1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnitState getStartState(){
|
||||
return attack;
|
||||
}
|
||||
|
||||
protected void wobble(){
|
||||
if(Net.client()) return;
|
||||
|
||||
x += Mathf.sin(Time.time() + id * 999, 25f, 0.05f)*Time.delta();
|
||||
y += Mathf.cos(Time.time() + id * 999, 25f, 0.05f)*Time.delta();
|
||||
|
||||
if(velocity.len() <= 0.05f){
|
||||
//rotation += Mathf.sin(Time.time() + id * 99, 10f, 2f * type.speed)*Time.delta();
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateRotation(){
|
||||
rotation = velocity.angle();
|
||||
}
|
||||
|
||||
protected void circle(float circleLength){
|
||||
circle(circleLength, type.speed);
|
||||
}
|
||||
|
||||
protected void circle(float circleLength, float speed){
|
||||
if(target == null) return;
|
||||
|
||||
Tmp.v1.set(target.getX() - x, target.getY() - y);
|
||||
|
||||
if(Tmp.v1.len() < circleLength){
|
||||
Tmp.v1.rotate((circleLength - Tmp.v1.len()) / circleLength * 180f);
|
||||
}
|
||||
|
||||
Tmp.v1.setLength(speed * Time.delta());
|
||||
|
||||
velocity.add(Tmp.v1);
|
||||
}
|
||||
|
||||
protected void moveTo(float circleLength){
|
||||
if(target == null) return;
|
||||
|
||||
Tmp.v1.set(target.getX() - x, target.getY() - y);
|
||||
|
||||
float length = circleLength <= 0.001f ? 1f : Mathf.clamp((dst(target) - circleLength) / 100f, -1f, 1f);
|
||||
|
||||
Tmp.v1.setLength(type.speed * Time.delta() * length);
|
||||
if(length < -0.5f){
|
||||
Tmp.v1.rotate(180f);
|
||||
}else if(length < 0){
|
||||
Tmp.v1.setZero();
|
||||
}
|
||||
|
||||
velocity.add(Tmp.v1);
|
||||
}
|
||||
|
||||
protected void attack(float circleLength){
|
||||
Tmp.v1.set(target.getX() - x, target.getY() - y);
|
||||
|
||||
float ang = angleTo(target);
|
||||
float diff = Angles.angleDist(ang, rotation);
|
||||
|
||||
if(diff > 100f && Tmp.v1.len() < circleLength){
|
||||
Tmp.v1.setAngle(velocity.angle());
|
||||
}else{
|
||||
Tmp.v1.setAngle(Mathf.slerpDelta(velocity.angle(), Tmp.v1.angle(), 0.44f));
|
||||
}
|
||||
|
||||
Tmp.v1.setLength(type.speed * Time.delta());
|
||||
|
||||
velocity.add(Tmp.v1);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.anuke.mindustry.entities.units;
|
||||
package io.anuke.mindustry.entities.type;
|
||||
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
@@ -8,21 +8,14 @@ import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.entities.Predict;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
import io.anuke.mindustry.entities.units.UnitState;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.graphics.Shaders;
|
||||
import io.anuke.mindustry.type.ContentType;
|
||||
import io.anuke.mindustry.type.Weapon;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.Floor;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public abstract class GroundUnit extends BaseUnit{
|
||||
@@ -31,7 +24,6 @@ public abstract class GroundUnit extends BaseUnit{
|
||||
protected float walkTime;
|
||||
protected float stuckTime;
|
||||
protected float baseRotation;
|
||||
protected Weapon weapon;
|
||||
|
||||
public final UnitState
|
||||
|
||||
@@ -42,13 +34,19 @@ public abstract class GroundUnit extends BaseUnit{
|
||||
|
||||
public void update(){
|
||||
TileEntity core = getClosestEnemyCore();
|
||||
float dst = core == null ? 0 : dst(core);
|
||||
|
||||
if(core != null && dst < getWeapon().getAmmo().range() / 1.1f){
|
||||
if(core == null){
|
||||
setState(patrol);
|
||||
return;
|
||||
}
|
||||
|
||||
float dst = dst(core);
|
||||
|
||||
if(dst < getWeapon().bullet.range() / 1.1f){
|
||||
target = core;
|
||||
}
|
||||
|
||||
if(dst > getWeapon().getAmmo().range() * 0.5f){
|
||||
if(dst > getWeapon().bullet.range() * 0.5f){
|
||||
moveToCore();
|
||||
}
|
||||
}
|
||||
@@ -64,27 +62,8 @@ public abstract class GroundUnit extends BaseUnit{
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
retreat = new UnitState(){
|
||||
public void entered(){
|
||||
target = null;
|
||||
}
|
||||
|
||||
public void update(){
|
||||
if(health >= maxHealth()){
|
||||
state.set(attack);
|
||||
}
|
||||
|
||||
moveAwayFromCore();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void init(UnitType type, Team team){
|
||||
super.init(type, team);
|
||||
this.weapon = type.weapon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interpolate(){
|
||||
super.interpolate();
|
||||
@@ -124,36 +103,32 @@ public abstract class GroundUnit extends BaseUnit{
|
||||
|
||||
@Override
|
||||
public Weapon getWeapon(){
|
||||
return weapon;
|
||||
}
|
||||
|
||||
public void setWeapon(Weapon weapon){
|
||||
this.weapon = weapon;
|
||||
return type.weapon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
Draw.alpha(Draw.getShader() != Shaders.mix ? 1f : hitTime / hitDuration);
|
||||
Draw.mixcol(Color.WHITE, hitTime / hitDuration);
|
||||
|
||||
float ft = Mathf.sin(walkTime * type.speed*5f, 6f, 2f);
|
||||
float ft = Mathf.sin(walkTime * type.speed*5f, 6f, 2f + type.hitsize/15f);
|
||||
|
||||
Floor floor = getFloorOn();
|
||||
|
||||
if(floor.isLiquid){
|
||||
Draw.tint(Color.WHITE, floor.liquidColor, 0.5f);
|
||||
Draw.color(Color.WHITE, floor.liquidColor, 0.5f);
|
||||
}
|
||||
|
||||
for(int i : Mathf.signs){
|
||||
Draw.rect(type.legRegion,
|
||||
x + Angles.trnsx(baseRotation, ft * i),
|
||||
y + Angles.trnsy(baseRotation, ft * i),
|
||||
12f * i, 12f - Mathf.clamp(ft * i, 0, 2), baseRotation - 90);
|
||||
type.legRegion.getWidth() * i * Draw.scl, type.legRegion.getHeight() * Draw.scl - Mathf.clamp(ft * i, 0, 2), baseRotation - 90);
|
||||
}
|
||||
|
||||
if(floor.isLiquid){
|
||||
Draw.tint(Color.WHITE, floor.liquidColor, drownTime * 0.4f);
|
||||
Draw.color(Color.WHITE, floor.liquidColor, drownTime * 0.4f);
|
||||
}else{
|
||||
Draw.tint(Color.WHITE);
|
||||
Draw.color(Color.WHITE);
|
||||
}
|
||||
|
||||
Draw.rect(type.baseRegion, x, y, baseRotation - 90);
|
||||
@@ -161,30 +136,27 @@ public abstract class GroundUnit extends BaseUnit{
|
||||
Draw.rect(type.region, x, y, rotation - 90);
|
||||
|
||||
for(int i : Mathf.signs){
|
||||
float tra = rotation - 90, trY = -weapon.getRecoil(this, i > 0) + type.weaponOffsetY;
|
||||
float w = i > 0 ? -12 : 12;
|
||||
Draw.rect(weapon.equipRegion,
|
||||
x + Angles.trnsx(tra, type.weaponOffsetX * i, trY),
|
||||
y + Angles.trnsy(tra, type.weaponOffsetX * i, trY), w, 12, rotation - 90);
|
||||
float tra = rotation - 90, trY = -type.weapon.getRecoil(this, i > 0) + type.weaponOffsetY;
|
||||
float w = - i * type.weapon.region.getWidth() * Draw.scl;
|
||||
Draw.rect(type.weapon.region,
|
||||
x + Angles.trnsx(tra, getWeapon().width * i, trY),
|
||||
y + Angles.trnsy(tra, getWeapon().width * i, trY), w, type.weapon.region.getHeight() * Draw.scl, rotation - 90);
|
||||
}
|
||||
|
||||
drawItems();
|
||||
|
||||
Draw.alpha(1f);
|
||||
Draw.mixcol();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void behavior(){
|
||||
if(health <= health * type.retreatPercent){
|
||||
setState(retreat);
|
||||
}
|
||||
|
||||
if(!Units.invalidateTarget(target, this)){
|
||||
if(dst(target) < getWeapon().getAmmo().range()){
|
||||
if(dst(target) < getWeapon().bullet.range()){
|
||||
rotate(angleTo(target));
|
||||
|
||||
if(Angles.near(angleTo(target), rotation, 13f)){
|
||||
BulletType ammo = getWeapon().getAmmo();
|
||||
BulletType ammo = getWeapon().bullet;
|
||||
|
||||
Vector2 to = Predict.intercept(GroundUnit.this, target, ammo.speed);
|
||||
|
||||
@@ -205,32 +177,8 @@ public abstract class GroundUnit extends BaseUnit{
|
||||
retarget(this::targetClosest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput data) throws IOException{
|
||||
super.write(data);
|
||||
data.writeByte(weapon.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput data) throws IOException{
|
||||
super.read(data);
|
||||
weapon = content.getByID(ContentType.weapon, data.readByte());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSave(DataOutput stream) throws IOException{
|
||||
stream.writeByte(weapon.id);
|
||||
super.writeSave(stream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSave(DataInput stream) throws IOException{
|
||||
weapon = content.getByID(ContentType.weapon, stream.readByte());
|
||||
super.readSave(stream);
|
||||
}
|
||||
|
||||
protected void patrol(){
|
||||
vec.trns(baseRotation, type.speed * Time.delta());
|
||||
vec.trns(baseRotation, type.speed * Time.delta() * 2);
|
||||
velocity.add(vec.x, vec.y);
|
||||
vec.trns(baseRotation, type.hitsizeTile);
|
||||
Tile tile = world.tileWorld(x + vec.x, y + vec.y);
|
||||
@@ -1,12 +1,9 @@
|
||||
package io.anuke.mindustry.entities;
|
||||
package io.anuke.mindustry.entities.type;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Queue;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.entities.EntityQuery;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.Angles;
|
||||
@@ -14,19 +11,18 @@ import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.util.Align;
|
||||
import io.anuke.arc.util.Interval;
|
||||
import io.anuke.arc.util.Pack;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
import io.anuke.mindustry.content.Mechs;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.effect.ScorchDecal;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.content.Mechs;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.traits.BuilderTrait;
|
||||
import io.anuke.mindustry.entities.traits.ShooterTrait;
|
||||
import io.anuke.mindustry.entities.traits.SpawnerTrait;
|
||||
import io.anuke.mindustry.entities.traits.TargetTrait;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.graphics.Shaders;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.input.Binding;
|
||||
import io.anuke.mindustry.io.TypeIO;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
@@ -36,7 +32,6 @@ import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.Floor;
|
||||
import io.anuke.mindustry.world.blocks.storage.CoreBlock.CoreEntity;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
@@ -44,7 +39,7 @@ import java.io.IOException;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTrait{
|
||||
public class Player extends Unit implements BuilderTrait, ShooterTrait{
|
||||
public static final int timerSync = 2;
|
||||
public static final int timerAbility = 3;
|
||||
private static final int timerShootLeft = 0;
|
||||
@@ -60,11 +55,11 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
public String name = "name";
|
||||
public String uuid, usid;
|
||||
public boolean isAdmin, isTransferring, isShooting, isBoosting, isMobile;
|
||||
public float boostHeat, shootHeat;
|
||||
public float boostHeat, shootHeat, destructTime;
|
||||
public boolean achievedFlight;
|
||||
public Color color = new Color();
|
||||
public Mech mech;
|
||||
public int spawner = noSpawner;
|
||||
public SpawnerTrait spawner, lastSpawner;
|
||||
|
||||
public NetConnection con;
|
||||
public int playerIndex = 0;
|
||||
@@ -76,7 +71,6 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
private float walktime;
|
||||
private Queue<BuildRequest> placeQueue = new Queue<>();
|
||||
private Tile mining;
|
||||
private CarriableTrait carrying;
|
||||
private Vector2 movement = new Vector2();
|
||||
private boolean moved;
|
||||
|
||||
@@ -90,15 +84,8 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
|
||||
player.dead = true;
|
||||
player.placeQueue.clear();
|
||||
|
||||
player.dropCarry();
|
||||
|
||||
float explosiveness = 2f + (player.inventory.hasItem() ? player.inventory.getItem().item.explosiveness * player.inventory.getItem().amount : 0f);
|
||||
float flammability = (player.inventory.hasItem() ? player.inventory.getItem().item.flammability * player.inventory.getItem().amount : 0f);
|
||||
Damage.dynamicExplosion(player.x, player.y, flammability, explosiveness, 0f, player.getSize() / 2f, Palette.darkFlame);
|
||||
|
||||
ScorchDecal.create(player.x, player.y);
|
||||
player.onDeath();
|
||||
player.mech = (player.isMobile ? Mechs.starterMobile : Mechs.starterDesktop);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -129,11 +116,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
@Override
|
||||
public boolean collidesGrid(int x, int y){
|
||||
Tile tile = world.tile(x, y);
|
||||
if(!isFlying()) return true;
|
||||
if(!mech.flying && tile != null && !tile.block().synthetic() && tile.block().solid){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return !isFlying() || (!mech.flying && tile != null && !tile.block().synthetic() && tile.block().solid);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,21 +167,6 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CarriableTrait getCarry(){
|
||||
return carrying;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCarry(CarriableTrait unit){
|
||||
this.carrying = unit;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCarryWeight(){
|
||||
return mech.carryWeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getBuildPower(Tile tile){
|
||||
return mech.buildPower;
|
||||
@@ -206,7 +174,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
|
||||
@Override
|
||||
public float maxHealth(){
|
||||
return 200;
|
||||
return mech.health;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -225,8 +193,8 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getArmor(){
|
||||
return mech.armor + mech.getExtraArmor(this);
|
||||
public float calculateDamage(float amount){
|
||||
return amount * Mathf.clamp(1f - (status.getArmorMultiplier() + mech.getExtraArmor(this)) / 100f);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -241,12 +209,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
|
||||
@Override
|
||||
public boolean isFlying(){
|
||||
return mech.flying || boostHeat > liftoffBoost || isCarried();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getSize(){
|
||||
return 8;
|
||||
return mech.flying || boostHeat > liftoffBoost;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -282,16 +245,6 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
return "Player{" + id + ", mech=" + mech.name + ", local=" + isLocal + ", " + x + ", " + y + "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed(){
|
||||
dropCarryLocal();
|
||||
|
||||
TileEntity core = getClosestCore();
|
||||
if(core != null && ((CoreEntity) core).currentUnit == this){
|
||||
((CoreEntity) core).currentUnit = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityGroup targetGroup(){
|
||||
return playerGroup;
|
||||
@@ -322,7 +275,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
if(dead) return;
|
||||
|
||||
if(!movement.isZero() && moved && !state.isPaused()){
|
||||
walktime += movement.len() / 0.7f * getFloorOn().speedMultiplier;
|
||||
walktime += movement.len() / 1f * getFloorOn().speedMultiplier;
|
||||
baseRotation = Mathf.slerpDelta(baseRotation, movement.angle(), 0.13f);
|
||||
}
|
||||
|
||||
@@ -331,11 +284,11 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
Floor floor = getFloorOn();
|
||||
|
||||
Draw.color();
|
||||
Draw.alpha(Draw.getShader() != Shaders.mix ? 1f : hitTime / hitDuration);
|
||||
Draw.mixcol(Color.WHITE, hitTime / hitDuration);
|
||||
|
||||
if(!mech.flying){
|
||||
if(floor.isLiquid){
|
||||
Draw.tint(Color.WHITE, floor.liquidColor, 0.5f);
|
||||
Draw.color(Color.WHITE, floor.liquidColor, 0.5f);
|
||||
}
|
||||
|
||||
float boostTrnsY = -boostHeat * 3f;
|
||||
@@ -355,9 +308,9 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
}
|
||||
|
||||
if(floor.isLiquid){
|
||||
Draw.tint(Color.WHITE, floor.liquidColor, drownTime);
|
||||
Draw.color(Color.WHITE, floor.liquidColor, drownTime);
|
||||
}else{
|
||||
Draw.tint(Color.WHITE);
|
||||
Draw.color(Color.WHITE);
|
||||
}
|
||||
|
||||
Draw.rect(mech.region, x, y, rotation - 90);
|
||||
@@ -366,37 +319,36 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
|
||||
for(int i : Mathf.signs){
|
||||
float tra = rotation - 90, trY = -mech.weapon.getRecoil(this, i > 0) + mech.weaponOffsetY;
|
||||
float w = i > 0 ? -mech.weapon.equipRegion.getWidth() : mech.weapon.equipRegion.getWidth();
|
||||
Draw.rect(mech.weapon.equipRegion,
|
||||
float w = i > 0 ? -mech.weapon.region.getWidth() : mech.weapon.region.getWidth();
|
||||
Draw.rect(mech.weapon.region,
|
||||
x + Angles.trnsx(tra, (mech.weaponOffsetX + mech.spreadX(this)) * i, trY),
|
||||
y + Angles.trnsy(tra, (mech.weaponOffsetX + mech.spreadX(this)) * i, trY),
|
||||
w * Draw.scl,
|
||||
mech.weapon.equipRegion.getHeight() * Draw.scl,
|
||||
mech.weapon.region.getHeight() * Draw.scl,
|
||||
rotation - 90);
|
||||
}
|
||||
|
||||
float backTrns = 4f, itemSize = 5f;
|
||||
if(inventory.hasItem()){
|
||||
ItemStack stack = inventory.getItem();
|
||||
float backTrns = 4f;
|
||||
if(item.amount > 0){
|
||||
ItemStack stack = item;
|
||||
int stored = Mathf.clamp(stack.amount / 6, 1, 8);
|
||||
|
||||
for(int i = 0; i < stored; i++){
|
||||
float angT = i == 0 ? 0 : Mathf.randomSeedRange(i + 1, 60f);
|
||||
float lenT = i == 0 ? 0 : Mathf.randomSeedRange(i + 2, 1f) - 1f;
|
||||
Draw.rect(stack.item.region,
|
||||
Draw.rect(stack.item.icon(Item.Icon.large),
|
||||
x + Angles.trnsx(rotation + 180f + angT, backTrns + lenT),
|
||||
y + Angles.trnsy(rotation + 180f + angT, backTrns + lenT),
|
||||
itemSize, itemSize, rotation);
|
||||
}
|
||||
}
|
||||
|
||||
Draw.alpha(1f);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawStats(){
|
||||
Draw.color(Color.BLACK, team.color, healthf() + Mathf.absin(Time.time(), healthf() * 5f, 1f - healthf()));
|
||||
Draw.alpha(hitTime / hitDuration);
|
||||
Draw.rect(getPowerCellRegion(), x + Angles.trnsx(rotation, mech.cellTrnsY, 0f), y + Angles.trnsy(rotation, mech.cellTrnsY, 0f), rotation - 90);
|
||||
Draw.color();
|
||||
}
|
||||
@@ -405,7 +357,22 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
public void drawOver(){
|
||||
if(dead) return;
|
||||
|
||||
drawBuilding(this);
|
||||
drawBuilding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawUnder(){
|
||||
if(dead) return;
|
||||
|
||||
float size = mech.engineSize * (mech.flying ? 1f : boostHeat);
|
||||
Draw.color(mech.engineColor);
|
||||
Fill.circle(x + Angles.trnsx(rotation + 180, mech.engineOffset), y + Angles.trnsy(rotation + 180, mech.engineOffset),
|
||||
size + Mathf.absin(Time.time(), 2f, size/4f));
|
||||
|
||||
Draw.color(Color.WHITE);
|
||||
Fill.circle(x + Angles.trnsx(rotation + 180, mech.engineOffset-1f), y + Angles.trnsy(rotation + 180, mech.engineOffset-1f),
|
||||
(size + Mathf.absin(Time.time(), 2f, size/4f)) / 2f);
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
public void drawName(){
|
||||
@@ -434,19 +401,20 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
Draw.reset();
|
||||
Pools.free(layout);
|
||||
font.getData().setScale(1f);
|
||||
font.setColor(Color.WHITE);
|
||||
font.setUseIntegerPositions(ints);
|
||||
}
|
||||
|
||||
/** Draw all current build requests. Does not draw the beam effect, only the positions. */
|
||||
public void drawBuildRequests(){
|
||||
for(BuildRequest request : getPlaceQueue()){
|
||||
if(getCurrentRequest() == request) continue;
|
||||
if(getCurrentRequest() == request && request.progress > 0.001f) continue;
|
||||
|
||||
if(request.breaking){
|
||||
Block block = world.tile(request.x, request.y).target().block();
|
||||
|
||||
//draw removal request
|
||||
Lines.stroke(2f, Palette.removeBack);
|
||||
Lines.stroke(2f, Pal.removeBack);
|
||||
|
||||
float rad = Mathf.absin(Time.time(), 7f, 1f) + block.size * tilesize / 2f - 1;
|
||||
Lines.square(
|
||||
@@ -454,7 +422,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
request.y * tilesize + block.offset() - 1,
|
||||
rad);
|
||||
|
||||
Draw.color(Palette.remove);
|
||||
Draw.color(Pal.remove);
|
||||
|
||||
Lines.square(
|
||||
request.x * tilesize + block.offset(),
|
||||
@@ -464,7 +432,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
float rad = Mathf.absin(Time.time(), 7f, 1f) - 1.5f + request.block.size * tilesize / 2f;
|
||||
|
||||
//draw place request
|
||||
Lines.stroke(1f, Palette.accentBack);
|
||||
Lines.stroke(1f, Pal.accentBack);
|
||||
|
||||
Lines.square(
|
||||
request.x * tilesize + request.block.offset(),
|
||||
@@ -475,10 +443,10 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
|
||||
Draw.rect(request.block.icon(Icon.full),
|
||||
request.x * tilesize + request.block.offset(),
|
||||
request.y * tilesize + request.block.offset(), rad*2, rad*2, request.rotation * 90);
|
||||
request.y * tilesize + request.block.offset(), rad*2, rad*2, request.block.rotate ? request.rotation * 90 : 0);
|
||||
|
||||
|
||||
Draw.color(Palette.accent);
|
||||
Draw.color(Pal.accent);
|
||||
|
||||
Lines.square(
|
||||
request.x * tilesize + request.block.offset(),
|
||||
@@ -496,6 +464,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
|
||||
hitTime -= Time.delta();
|
||||
|
||||
if(Float.isNaN(x) || Float.isNaN(y)){
|
||||
@@ -509,13 +478,23 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
setDead(true);
|
||||
}
|
||||
|
||||
if(!isDead() && isOutOfBounds()){
|
||||
destructTime += Time.delta();
|
||||
|
||||
if(destructTime >= boundsCountdown){
|
||||
kill();
|
||||
}
|
||||
}else{
|
||||
destructTime = 0f;
|
||||
}
|
||||
|
||||
if(isDead()){
|
||||
isBoosting = false;
|
||||
boostHeat = 0f;
|
||||
updateRespawning();
|
||||
return;
|
||||
}else{
|
||||
spawner = noSpawner;
|
||||
spawner = null;
|
||||
}
|
||||
|
||||
avoidOthers(1f);
|
||||
@@ -535,7 +514,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
if(mech.shake > 1f){
|
||||
Effects.shake(mech.shake, mech.shake, this);
|
||||
}
|
||||
Effects.effect(Fx.unitLand, tile.floor().minimapColor, x, y, tile.floor().isLiquid ? 1f : 0.5f);
|
||||
Effects.effect(Fx.unitLand, tile.floor().liquidColor == null ? tile.floor().color : tile.floor().color, x, y, tile.floor().isLiquid ? 1f : 0.5f);
|
||||
}
|
||||
mech.onLand(this);
|
||||
achievedFlight = false;
|
||||
@@ -543,15 +522,10 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
|
||||
if(!isLocal){
|
||||
interpolate();
|
||||
updateBuilding(this); //building happens even with non-locals
|
||||
updateBuilding(); //building happens even with non-locals
|
||||
status.update(this); //status effect updating also happens with non locals for effect purposes
|
||||
updateVelocityStatus(); //velocity too, for visual purposes
|
||||
|
||||
if(getCarrier() != null){
|
||||
x = getCarrier().getX();
|
||||
y = getCarrier().getY();
|
||||
}
|
||||
|
||||
if(Net.server()){
|
||||
updateShooting(); //server simulates player shooting
|
||||
}
|
||||
@@ -567,10 +541,11 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
updateMech();
|
||||
}
|
||||
|
||||
updateBuilding(this);
|
||||
updateBuilding();
|
||||
|
||||
x = Mathf.clamp(x, 0, world.width() * tilesize - tilesize);
|
||||
y = Mathf.clamp(y, 0, world.height() * tilesize - tilesize);
|
||||
if(!mech.flying){
|
||||
clampPosition();
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateMech(){
|
||||
@@ -584,10 +559,6 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
}
|
||||
|
||||
float speed = isBoosting && !mech.flying ? mech.boostSpeed : mech.speed;
|
||||
//fraction of speed when at max load
|
||||
float carrySlowdown = 0.7f;
|
||||
|
||||
speed *= ((inventory.hasItem() ? Mathf.lerp(1f, carrySlowdown, (float) inventory.getItem().amount / inventory.capacity()) : 1f));
|
||||
|
||||
if(mech.flying){
|
||||
//prevent strafing backwards, have a penalty for doing so
|
||||
@@ -595,23 +566,6 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
speed *= Mathf.lerp(1f, penalty, Angles.angleDist(rotation, velocity.angle()) / 180f);
|
||||
}
|
||||
|
||||
//drop from carrier on key press
|
||||
if(!ui.chatfrag.chatOpen() && Core.input.keyTap(Binding.drop_unit)){
|
||||
if(!mech.flying){
|
||||
if(getCarrier() != null){
|
||||
Call.dropSelf(this);
|
||||
}
|
||||
}else if(getCarry() != null){
|
||||
dropCarry();
|
||||
}else{
|
||||
Unit unit = Units.getClosest(team, x, y, 8f, u -> !u.isFlying() && u.mass() <= mech.carryWeight);
|
||||
|
||||
if(unit != null){
|
||||
carry(unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
movement.setZero();
|
||||
|
||||
float xa = Core.input.axis(Binding.move_x);
|
||||
@@ -628,18 +582,12 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
|
||||
movement.limit(speed).scl(Time.delta());
|
||||
|
||||
if(getCarrier() == null){
|
||||
if(!ui.chatfrag.chatOpen()){
|
||||
velocity.add(movement.x, movement.y);
|
||||
}
|
||||
float prex = x, prey = y;
|
||||
updateVelocityStatus();
|
||||
moved = dst(prex, prey) > 0.001f;
|
||||
}else{
|
||||
velocity.setZero();
|
||||
x = Mathf.lerpDelta(x, getCarrier().getX(), 0.1f);
|
||||
y = Mathf.lerpDelta(y, getCarrier().getY(), 0.1f);
|
||||
if(!ui.chatfrag.chatOpen()){
|
||||
velocity.add(movement.x, movement.y);
|
||||
}
|
||||
float prex = x, prey = y;
|
||||
updateVelocityStatus();
|
||||
moved = dst(prex, prey) > 0.001f;
|
||||
|
||||
if(!ui.chatfrag.chatOpen()){
|
||||
float baseLerp = mech.getRotationAlpha(this);
|
||||
@@ -662,7 +610,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
|
||||
protected void updateFlying(){
|
||||
if(Units.invalidateTarget(target, this) && !(target instanceof TileEntity && ((TileEntity) target).damaged() && target.getTeam() == team &&
|
||||
mech.canHeal && dst(target) < getWeapon().getAmmo().range())){
|
||||
mech.canHeal && dst(target) < getWeapon().bullet.range())){
|
||||
target = null;
|
||||
}
|
||||
|
||||
@@ -680,9 +628,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
}
|
||||
|
||||
if(dst(moveTarget) < 2f){
|
||||
if(moveTarget instanceof CarriableTrait){
|
||||
carry((CarriableTrait) moveTarget);
|
||||
}else if(tapping){
|
||||
if(tapping){
|
||||
Tile tile = ((TileEntity) moveTarget).tile;
|
||||
tile.block().tapped(tile, this);
|
||||
}
|
||||
@@ -693,12 +639,6 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
moveTarget = null;
|
||||
}
|
||||
|
||||
if(getCarrier() != null){
|
||||
velocity.setZero();
|
||||
x = Mathf.lerpDelta(x, getCarrier().getX(), 0.1f);
|
||||
y = Mathf.lerpDelta(y, getCarrier().getY(), 0.1f);
|
||||
}
|
||||
|
||||
movement.set(targetX - x, targetY - y).limit(isBoosting && !mech.flying ? mech.boostSpeed : mech.speed);
|
||||
movement.setAngle(Mathf.slerp(movement.angle(), velocity.angle(), 0.05f));
|
||||
|
||||
@@ -726,7 +666,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
|
||||
float lx = x, ly = y;
|
||||
updateVelocityStatus();
|
||||
moved = dst(lx, ly) > 0.001f && !isCarried();
|
||||
moved = dst(lx, ly) > 0.001f;
|
||||
|
||||
if(mech.flying){
|
||||
//hovering effect
|
||||
@@ -742,11 +682,11 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
if(target == null){
|
||||
isShooting = false;
|
||||
if(Core.settings.getBool("autotarget")){
|
||||
target = Units.getClosestTarget(team, x, y, getWeapon().getAmmo().range());
|
||||
target = Units.getClosestTarget(team, x, y, getWeapon().bullet.range(), u -> u.getTeam() != Team.none, u -> u.getTeam() != Team.none);
|
||||
|
||||
if(mech.canHeal && target == null){
|
||||
target = Geometry.findClosest(x, y, world.indexer.getDamaged(Team.blue));
|
||||
if(target != null && dst(target) > getWeapon().getAmmo().range()){
|
||||
if(target != null && dst(target) > getWeapon().bullet.range()){
|
||||
target = null;
|
||||
}else if(target != null){
|
||||
target = ((Tile) target).entity;
|
||||
@@ -758,14 +698,14 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
}
|
||||
}
|
||||
}else if(target.isValid() || (target instanceof TileEntity && ((TileEntity) target).damaged() && target.getTeam() == team &&
|
||||
mech.canHeal && dst(target) < getWeapon().getAmmo().range())){
|
||||
mech.canHeal && dst(target) < getWeapon().bullet.range())){
|
||||
//rotate toward and shoot the target
|
||||
if(mech.turnCursor){
|
||||
rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.2f);
|
||||
}
|
||||
|
||||
Vector2 intercept =
|
||||
Predict.intercept(x, y, target.getX(), target.getY(), target.velocity().x - velocity.x, target.velocity().y - velocity.y, getWeapon().getAmmo().speed);
|
||||
Predict.intercept(x, y, target.getX(), target.getY(), target.velocity().x - velocity.x, target.velocity().y - velocity.y, getWeapon().bullet.speed);
|
||||
|
||||
pointerX = intercept.x;
|
||||
pointerY = intercept.y;
|
||||
@@ -799,12 +739,12 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
public void resetNoAdd(){
|
||||
status.clear();
|
||||
team = Team.blue;
|
||||
inventory.clear();
|
||||
item.amount = 0;
|
||||
placeQueue.clear();
|
||||
dead = true;
|
||||
target = null;
|
||||
moveTarget = null;
|
||||
carrier = null;
|
||||
spawner = lastSpawner = null;
|
||||
health = maxHealth();
|
||||
boostHeat = drownTime = hitTime = 0f;
|
||||
mech = (isMobile ? Mechs.starterMobile : Mechs.starterDesktop);
|
||||
@@ -817,23 +757,27 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
|
||||
public void updateRespawning(){
|
||||
|
||||
if(spawner != noSpawner && world.tile(spawner) != null && world.tile(spawner).entity instanceof SpawnerTrait){
|
||||
((SpawnerTrait) world.tile(spawner).entity).updateSpawning(this);
|
||||
}else{
|
||||
CoreEntity entity = (CoreEntity) getClosestCore();
|
||||
if(entity != null && !netServer.isWaitingForPlayers()){
|
||||
this.spawner = entity.tile.pos();
|
||||
if(spawner != null && spawner.isValid()){
|
||||
spawner.updateSpawning(this);
|
||||
}else if(!netServer.isWaitingForPlayers()){
|
||||
if(lastSpawner != null && lastSpawner.isValid()){
|
||||
this.spawner = lastSpawner;
|
||||
}else if(getClosestCore() != null){
|
||||
this.spawner = (SpawnerTrait)getClosestCore();
|
||||
}
|
||||
}else if(getClosestCore() != null){
|
||||
set(getClosestCore().getX(), getClosestCore().getY());
|
||||
}
|
||||
}
|
||||
|
||||
public void beginRespawning(SpawnerTrait spawner){
|
||||
this.spawner = spawner.getTile().pos();
|
||||
this.spawner = spawner;
|
||||
this.lastSpawner = spawner;
|
||||
this.dead = true;
|
||||
}
|
||||
|
||||
public void endRespawning(){
|
||||
spawner = noSpawner;
|
||||
spawner = null;
|
||||
}
|
||||
|
||||
//endregion
|
||||
@@ -853,6 +797,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
if(isLocal){
|
||||
stream.writeByte(mech.id);
|
||||
stream.writeByte(playerIndex);
|
||||
stream.writeInt(lastSpawner == null ? noSpawner : lastSpawner.getTile().pos());
|
||||
super.writeSave(stream, false);
|
||||
}
|
||||
}
|
||||
@@ -864,12 +809,17 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
if(local && !headless){
|
||||
byte mechid = stream.readByte();
|
||||
int index = stream.readByte();
|
||||
int spawner = stream.readInt();
|
||||
if(world.tile(spawner) != null && world.tile(spawner).entity != null && world.tile(spawner).entity instanceof SpawnerTrait){
|
||||
lastSpawner = (SpawnerTrait)(world.tile(spawner).entity);
|
||||
}
|
||||
players[index].readSaveSuper(stream);
|
||||
players[index].mech = content.getByID(ContentType.mech, mechid);
|
||||
players[index].dead = false;
|
||||
}else if(local){
|
||||
byte mechid = stream.readByte();
|
||||
stream.readByte();
|
||||
stream.readInt();
|
||||
readSaveSuper(stream);
|
||||
mech = content.getByID(ContentType.mech, mechid);
|
||||
dead = false;
|
||||
@@ -889,8 +839,8 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
buffer.writeByte(Pack.byteValue(isAdmin) | (Pack.byteValue(dead) << 1) | (Pack.byteValue(isBoosting) << 2));
|
||||
buffer.writeInt(Color.rgba8888(color));
|
||||
buffer.writeByte(mech.id);
|
||||
buffer.writeInt(mining == null ? -1 : mining.pos());
|
||||
buffer.writeInt(spawner);
|
||||
buffer.writeInt(mining == null ? noSpawner : mining.pos());
|
||||
buffer.writeInt(spawner == null ? noSpawner : spawner.getTile().pos());
|
||||
buffer.writeShort((short) (baseRotation * 2));
|
||||
|
||||
writeBuilding(buffer);
|
||||
@@ -898,7 +848,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
|
||||
@Override
|
||||
public void read(DataInput buffer) throws IOException{
|
||||
float lastx = x, lasty = y, lastrot = rotation;
|
||||
float lastx = x, lasty = y, lastrot = rotation, lastvx = velocity.x, lastvy = velocity.y;
|
||||
super.readSave(buffer);
|
||||
name = TypeIO.readStringData(buffer);
|
||||
byte bools = buffer.readByte();
|
||||
@@ -919,10 +869,17 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
|
||||
if(isLocal){
|
||||
x = lastx;
|
||||
y = lasty;
|
||||
velocity.x = lastvx;
|
||||
velocity.y = lastvy;
|
||||
}else{
|
||||
mining = world.tile(mine);
|
||||
isBoosting = boosting;
|
||||
this.spawner = spawner;
|
||||
Tile tile = world.tile(spawner);
|
||||
if(tile != null && tile.entity instanceof SpawnerTrait){
|
||||
this.spawner = (SpawnerTrait)tile.entity;
|
||||
}else{
|
||||
this.spawner = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package io.anuke.mindustry.entities;
|
||||
package io.anuke.mindustry.entities.type;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.ObjectSet;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.arc.entities.impl.BaseEntity;
|
||||
import io.anuke.arc.entities.trait.HealthTrait;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.impl.BaseEntity;
|
||||
import io.anuke.mindustry.entities.traits.HealthTrait;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Point2;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
@@ -59,7 +59,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
||||
private boolean sleeping;
|
||||
private float sleepTime;
|
||||
|
||||
@Remote(called = Loc.server)
|
||||
@Remote(called = Loc.server, unreliable = true)
|
||||
public static void onTileDamage(Tile tile, float health){
|
||||
if(tile.entity != null){
|
||||
tile.entity.health = health;
|
||||
@@ -151,7 +151,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
||||
|
||||
if(health <= 0){
|
||||
Call.onTileDestroyed(tile);
|
||||
}else if(preHealth >= maxHealth() - 0.00001f && health < maxHealth()){ //when just damaged
|
||||
}else if(preHealth >= maxHealth() - 0.00001f && health < maxHealth() && world != null){ //when just damaged
|
||||
world.indexer.notifyTileDamaged(this);
|
||||
}
|
||||
}
|
||||
@@ -195,7 +195,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
||||
|
||||
if(other == null) continue;
|
||||
other = other.target();
|
||||
if(other.entity == null || other.getTeamID() != tile.getTeamID()) continue;
|
||||
if(other.entity == null || !(other.interactable(tile.getTeam()))) continue;
|
||||
|
||||
other.block().onProximityUpdate(other);
|
||||
|
||||
@@ -283,7 +283,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
||||
Block previous = tile.block();
|
||||
tile.block().update(tile);
|
||||
if(tile.block() == previous && cons != null){
|
||||
cons.update(this);
|
||||
cons.update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,4 +291,12 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
|
||||
public EntityGroup targetGroup(){
|
||||
return tileGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return "TileEntity{" +
|
||||
"tile=" + tile +
|
||||
", health=" + health +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,33 @@
|
||||
package io.anuke.mindustry.entities;
|
||||
package io.anuke.mindustry.entities.type;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.entities.Effects;
|
||||
import io.anuke.arc.entities.impl.DestructibleEntity;
|
||||
import io.anuke.arc.entities.trait.DamageTrait;
|
||||
import io.anuke.arc.entities.trait.DrawTrait;
|
||||
import io.anuke.arc.entities.trait.SolidTrait;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Fill;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.Damage;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.effect.ScorchDecal;
|
||||
import io.anuke.mindustry.entities.impl.DestructibleEntity;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.entities.units.Statuses;
|
||||
import io.anuke.mindustry.game.EventType.UnitDestroyEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.game.Teams.TeamData;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.net.Interpolator;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.type.StatusEffect;
|
||||
import io.anuke.mindustry.type.Weapon;
|
||||
import io.anuke.mindustry.world.Pos;
|
||||
@@ -33,10 +38,9 @@ import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
import static io.anuke.mindustry.Vars.state;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait, CarriableTrait, InventoryTrait{
|
||||
public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait{
|
||||
/**Total duration of hit flash effect*/
|
||||
public static final float hitDuration = 9f;
|
||||
/**Percision divisor of velocity, used when writing. For example a value of '2' would mean the percision is 1/2 = 0.5-size chunks.*/
|
||||
@@ -48,42 +52,25 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
private static final Rectangle queryRect = new Rectangle();
|
||||
private static final Vector2 moveVector = new Vector2();
|
||||
|
||||
public final UnitInventory inventory = new UnitInventory(this);
|
||||
public float rotation;
|
||||
public float hitTime;
|
||||
|
||||
protected final Interpolator interpolator = new Interpolator();
|
||||
protected final StatusController status = new StatusController();
|
||||
protected Team team = Team.blue;
|
||||
protected final Statuses status = new Statuses();
|
||||
protected final ItemStack item = new ItemStack(content.item(0), 0);
|
||||
|
||||
protected CarryTrait carrier;
|
||||
protected float drownTime;
|
||||
protected Team team = Team.blue;
|
||||
protected float drownTime, hitTime;
|
||||
|
||||
@Override
|
||||
public boolean movable(){
|
||||
return !isDead();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UnitInventory getInventory(){
|
||||
return inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CarryTrait getCarrier(){
|
||||
return carrier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collidesGrid(int x, int y){
|
||||
return !isFlying();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCarrier(CarryTrait carrier){
|
||||
this.carrier = carrier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Team getTeam(){
|
||||
return team;
|
||||
@@ -125,7 +112,15 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
|
||||
@Override
|
||||
public void onDeath(){
|
||||
inventory.clear();
|
||||
float explosiveness = 2f + item.item.explosiveness * item.amount;
|
||||
float flammability = item.item.flammability * item.amount;
|
||||
Damage.dynamicExplosion(x, y, flammability, explosiveness, 0f, getSize() / 2f, Pal.darkFlame);
|
||||
|
||||
ScorchDecal.create(x, y);
|
||||
Effects.effect(Fx.explosion, this);
|
||||
Effects.shake(2f, 2f, this);
|
||||
|
||||
item.amount = 0;
|
||||
drownTime = 0f;
|
||||
status.clear();
|
||||
Events.fire(new UnitDestroyEvent(this));
|
||||
@@ -145,6 +140,11 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(){
|
||||
return !isDead() && isAdded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSave(DataOutput stream) throws IOException{
|
||||
writeSave(stream, false);
|
||||
@@ -160,9 +160,12 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
byte yv = stream.readByte();
|
||||
float rotation = stream.readShort() / 2f;
|
||||
int health = stream.readShort();
|
||||
byte itemID = stream.readByte();
|
||||
short itemAmount = stream.readShort();
|
||||
|
||||
this.status.readSave(stream);
|
||||
this.inventory.readSave(stream);
|
||||
this.item.amount = itemAmount;
|
||||
this.item.item = content.item(itemID);
|
||||
this.dead = dead;
|
||||
this.team = Team.all[team];
|
||||
this.health = health;
|
||||
@@ -181,12 +184,31 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
stream.writeByte((byte) (Mathf.clamp(velocity.y, -maxAbsVelocity, maxAbsVelocity) * velocityPercision));
|
||||
stream.writeShort((short) (rotation * 2));
|
||||
stream.writeShort((short) health);
|
||||
stream.writeByte(item.item.id);
|
||||
stream.writeShort((short)item.amount);
|
||||
status.writeSave(stream);
|
||||
inventory.writeSave(stream);
|
||||
}
|
||||
|
||||
protected void clampPosition(){
|
||||
x = Mathf.clamp(x, tilesize, world.width() * tilesize - tilesize);
|
||||
y = Mathf.clamp(y, tilesize, world.height() * tilesize - tilesize);
|
||||
}
|
||||
|
||||
public void kill(){
|
||||
health = -1;
|
||||
damage(1);
|
||||
}
|
||||
|
||||
public boolean isImmune(StatusEffect effect){
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isOutOfBounds(){
|
||||
return x < -worldBounds || y < -worldBounds || x > world.width() * tilesize + worldBounds || y > world.height() * tilesize + worldBounds;
|
||||
}
|
||||
|
||||
public float calculateDamage(float amount){
|
||||
return amount * Mathf.clamp(1f - getArmor() / 100f * status.getArmorMultiplier());
|
||||
return amount * Mathf.clamp(1f - status.getArmorMultiplier() / 100f);
|
||||
}
|
||||
|
||||
public float getDamageMultipler(){
|
||||
@@ -197,12 +219,13 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
return status.hasEffect(effect);
|
||||
}
|
||||
|
||||
//TODO optimize
|
||||
public void avoidOthers(float scaling){
|
||||
hitbox(queryRect);
|
||||
queryRect.setSize(queryRect.getWidth() * scaling);
|
||||
|
||||
Units.getNearby(queryRect, t -> {
|
||||
if(t == this || t.getCarrier() == this || getCarrier() == t || t.isFlying() != isFlying()) return;
|
||||
if(t == this || t.isFlying() != isFlying()) return;
|
||||
float dst = dst(t);
|
||||
moveVector.set(x, y).sub(t.getX(), t.getY()).setLength(1f * (1f - (dst / queryRect.getWidth())));
|
||||
applyImpulse(moveVector.x, moveVector.y);
|
||||
@@ -227,28 +250,22 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
|
||||
public void onRespawn(Tile tile){}
|
||||
|
||||
@Override
|
||||
public boolean isValid(){
|
||||
return !isDead() && isAdded();
|
||||
}
|
||||
|
||||
/**Updates velocity and status effects.*/
|
||||
public void updateVelocityStatus(){
|
||||
Floor floor = getFloorOn();
|
||||
|
||||
if(isCarried()){ //carried units do not take into account velocity normally
|
||||
set(carrier.getX(), carrier.getY());
|
||||
velocity.set(carrier.velocity());
|
||||
return;
|
||||
}
|
||||
|
||||
Tile tile = world.tileWorld(x, y);
|
||||
|
||||
status.update(this);
|
||||
|
||||
velocity.limit(maxVelocity()).scl(1f + (status.getSpeedMultiplier()-1f) * Time.delta());
|
||||
|
||||
if(x < -finalWorldBounds || y < -finalWorldBounds || x >= world.width() * tilesize + finalWorldBounds || y >= world.height() * tilesize + finalWorldBounds){
|
||||
kill();
|
||||
}
|
||||
|
||||
if(isFlying()){
|
||||
drownTime = 0f;
|
||||
move(velocity.x * Time.delta(), velocity.y * Time.delta());
|
||||
}else{
|
||||
boolean onLiquid = floor.isLiquid;
|
||||
@@ -296,6 +313,31 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
velocity.scl(Mathf.clamp(1f - drag() * (isFlying() ? 1f : floor.dragMultiplier) * Time.delta()));
|
||||
}
|
||||
|
||||
public boolean acceptsItem(Item item){
|
||||
return this.item.amount <= 0 || (this.item.item == item && this.item.amount <= getItemCapacity());
|
||||
}
|
||||
|
||||
public void addItem(Item item){
|
||||
addItem(item, 1);
|
||||
}
|
||||
|
||||
public void addItem(Item item, int amount){
|
||||
this.item.amount = this.item.item == item ? this.item.amount + amount : amount;
|
||||
this.item.item = item;
|
||||
}
|
||||
|
||||
public void clearItem(){
|
||||
item.amount = 0;
|
||||
}
|
||||
|
||||
public ItemStack item(){
|
||||
return item;
|
||||
}
|
||||
|
||||
public int maxAccepted(Item item){
|
||||
return this.item.item != item && this.item.amount > 0 ? 0 : getItemCapacity() - this.item.amount;
|
||||
}
|
||||
|
||||
public void applyEffect(StatusEffect effect, float duration){
|
||||
if(dead || Net.client()) return; //effects are synced and thus not applied through clients
|
||||
status.handleApply(this, effect, duration);
|
||||
@@ -323,7 +365,6 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
|
||||
public void drawStats(){
|
||||
Draw.color(Color.BLACK, team.color, healthf() + Mathf.absin(Time.time(), healthf()*5f, 1f - healthf()));
|
||||
Draw.alpha(hitTime);
|
||||
Draw.rect(getPowerCellRegion(), x, y, rotation - 90);
|
||||
Draw.color();
|
||||
}
|
||||
@@ -343,12 +384,9 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
Draw.rect(getIconRegion(), x + offsetX, y + offsetY, rotation - 90);
|
||||
}
|
||||
|
||||
public void drawView(){
|
||||
Fill.circle(x, y, getViewDistance());
|
||||
}
|
||||
|
||||
public float getViewDistance(){
|
||||
return 135f;
|
||||
public float getSize(){
|
||||
hitbox(Tmp.r1);
|
||||
return Math.max(Tmp.r1.width, Tmp.r1.height) * 2f;
|
||||
}
|
||||
|
||||
public abstract TextureRegion getIconRegion();
|
||||
@@ -357,11 +395,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
|
||||
public abstract int getItemCapacity();
|
||||
|
||||
public abstract float getArmor();
|
||||
|
||||
public abstract float mass();
|
||||
|
||||
public abstract boolean isFlying();
|
||||
|
||||
public abstract float getSize();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package io.anuke.mindustry.entities.type.base;
|
||||
|
||||
import io.anuke.mindustry.entities.type.GroundUnit;
|
||||
|
||||
public class Crawler extends GroundUnit{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.anuke.mindustry.entities.type.base;
|
||||
|
||||
import io.anuke.mindustry.entities.type.GroundUnit;
|
||||
|
||||
public class Dagger extends GroundUnit{
|
||||
|
||||
}
|
||||
@@ -1,18 +1,18 @@
|
||||
package io.anuke.mindustry.entities.units.types;
|
||||
package io.anuke.mindustry.entities.type.base;
|
||||
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.arc.collection.Queue;
|
||||
import io.anuke.arc.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.arc.util.Structs;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.traits.BuilderTrait;
|
||||
import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.entities.units.FlyingUnit;
|
||||
import io.anuke.mindustry.entities.type.BaseUnit;
|
||||
import io.anuke.mindustry.entities.type.FlyingUnit;
|
||||
import io.anuke.mindustry.entities.units.UnitState;
|
||||
import io.anuke.mindustry.game.EventType.BuildSelectEvent;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
@@ -32,8 +32,6 @@ import static io.anuke.mindustry.Vars.unitGroups;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class Drone extends FlyingUnit implements BuilderTrait{
|
||||
protected static int timerRepairEffect = timerIndex++;
|
||||
|
||||
protected Item targetItem;
|
||||
protected Tile mineTile;
|
||||
protected Queue<BuildRequest> placeQueue = new Queue<>();
|
||||
@@ -135,10 +133,10 @@ public class Drone extends FlyingUnit implements BuilderTrait{
|
||||
}
|
||||
|
||||
//if inventory is full, drop it off.
|
||||
if(inventory.isFull()){
|
||||
if(item.amount >= getItemCapacity()){
|
||||
setState(drop);
|
||||
}else{
|
||||
if(targetItem != null && !inventory.canAcceptItem(targetItem)){
|
||||
if(targetItem != null && !acceptsItem(targetItem)){
|
||||
setState(drop);
|
||||
return;
|
||||
}
|
||||
@@ -177,13 +175,13 @@ public class Drone extends FlyingUnit implements BuilderTrait{
|
||||
}
|
||||
|
||||
public void update(){
|
||||
if(inventory.isEmpty()){
|
||||
if(item.amount == 0){
|
||||
setState(mine);
|
||||
return;
|
||||
}
|
||||
|
||||
if(inventory.getItem().item.type != ItemType.material){
|
||||
inventory.clearItem();
|
||||
if(item.item.type != ItemType.material){
|
||||
item.amount = 0;
|
||||
setState(mine);
|
||||
return;
|
||||
}
|
||||
@@ -195,9 +193,9 @@ public class Drone extends FlyingUnit implements BuilderTrait{
|
||||
TileEntity tile = (TileEntity) target;
|
||||
|
||||
if(dst(target) < type.range){
|
||||
if(tile.tile.block().acceptStack(inventory.getItem().item, inventory.getItem().amount, tile.tile, Drone.this) == inventory.getItem().amount){
|
||||
Call.transferItemTo(inventory.getItem().item, inventory.getItem().amount, x, y, tile.tile);
|
||||
inventory.clearItem();
|
||||
if(tile.tile.block().acceptStack(item.item, item.amount, tile.tile, Drone.this) == item.amount){
|
||||
Call.transferItemTo(item.item, item.amount, x, y, tile.tile);
|
||||
item.amount = 0;
|
||||
}
|
||||
|
||||
setState(repair);
|
||||
@@ -299,7 +297,7 @@ public class Drone extends FlyingUnit implements BuilderTrait{
|
||||
target = null;
|
||||
}
|
||||
|
||||
updateBuilding(this);
|
||||
updateBuilding();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -326,7 +324,7 @@ public class Drone extends FlyingUnit implements BuilderTrait{
|
||||
|
||||
@Override
|
||||
public void drawOver(){
|
||||
drawBuilding(this);
|
||||
drawBuilding();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +1,6 @@
|
||||
package io.anuke.mindustry.entities.type.base;
|
||||
|
||||
import io.anuke.mindustry.entities.type.GroundUnit;
|
||||
|
||||
public class Eruptor extends GroundUnit{
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.anuke.mindustry.entities.units.types;
|
||||
package io.anuke.mindustry.entities.type.base;
|
||||
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.units.GroundUnit;
|
||||
import io.anuke.mindustry.entities.type.GroundUnit;
|
||||
|
||||
public class Fortress extends GroundUnit{
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.anuke.mindustry.entities.type.base;
|
||||
|
||||
import io.anuke.mindustry.entities.type.FlyingUnit;
|
||||
|
||||
public class Ghoul extends FlyingUnit{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.anuke.mindustry.entities.type.base;
|
||||
|
||||
public class Phantom extends Drone{
|
||||
|
||||
}
|
||||
35
core/src/io/anuke/mindustry/entities/type/base/Revenant.java
Normal file
35
core/src/io/anuke/mindustry/entities/type/base/Revenant.java
Normal file
@@ -0,0 +1,35 @@
|
||||
package io.anuke.mindustry.entities.type.base;
|
||||
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.math.Angles;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.type.FlyingUnit;
|
||||
|
||||
public class Revenant extends FlyingUnit{
|
||||
|
||||
@Override
|
||||
public void drawWeapons(){
|
||||
for(int i : Mathf.signs){
|
||||
float tra = rotation - 90, trY = -getWeapon().getRecoil(this, i > 0) + type.weaponOffsetY;
|
||||
float w = i > 0 ? -12 : 12;
|
||||
float wx = x + Angles.trnsx(tra, getWeapon().width * i, trY), wy = y + Angles.trnsy(tra, getWeapon().width * i, trY);
|
||||
int wi = (i + 1)/2;
|
||||
Draw.rect(getWeapon().region, wx, wy, w, 12, weaponAngles[wi] - 90);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attack(float circleLength){
|
||||
moveTo(circleLength);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateRotation(){
|
||||
if(!Units.invalidateTarget(target, this)){
|
||||
rotation = Mathf.slerpDelta(rotation, angleTo(target), type.rotatespeed);
|
||||
}else{
|
||||
rotation = Mathf.slerpDelta(rotation, velocity.angle(), type.baseRotateSpeed);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
package io.anuke.mindustry.entities.type.base;
|
||||
|
||||
public class Spirit extends Drone{
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.anuke.mindustry.entities.type.base;
|
||||
|
||||
import io.anuke.mindustry.entities.type.GroundUnit;
|
||||
|
||||
public class Titan extends GroundUnit{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package io.anuke.mindustry.entities.type.base;
|
||||
|
||||
import io.anuke.mindustry.entities.type.FlyingUnit;
|
||||
|
||||
public class Wraith extends FlyingUnit{
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user