Merge remote-tracking branch 'origin/4.0' into 4.0
# Conflicts: # core/src/io/anuke/mindustry/Vars.java
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
package io.anuke.mindustry;
|
||||
|
||||
import com.badlogic.gdx.utils.async.AsyncExecutor;
|
||||
import io.anuke.mindustry.core.*;
|
||||
import io.anuke.mindustry.io.BundleLoader;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
@@ -9,36 +8,35 @@ import io.anuke.ucore.util.Log;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Mindustry extends ModuleCore {
|
||||
private AsyncExecutor exec = new AsyncExecutor(1);
|
||||
public class Mindustry extends ModuleCore{
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
Timers.mark();
|
||||
@Override
|
||||
public void init(){
|
||||
Timers.mark();
|
||||
|
||||
Vars.init();
|
||||
Vars.init();
|
||||
|
||||
debug = Platform.instance.isDebug();
|
||||
debug = Platform.instance.isDebug();
|
||||
|
||||
Log.setUseColors(false);
|
||||
BundleLoader.load();
|
||||
ContentLoader.load();
|
||||
Log.setUseColors(false);
|
||||
BundleLoader.load();
|
||||
ContentLoader.load();
|
||||
|
||||
module(logic = new Logic());
|
||||
module(world = new World());
|
||||
module(control = new Control());
|
||||
module(renderer = new Renderer());
|
||||
module(ui = new UI());
|
||||
module(netServer = new NetServer());
|
||||
module(netClient = new NetClient());
|
||||
module(logic = new Logic());
|
||||
module(world = new World());
|
||||
module(control = new Control());
|
||||
module(renderer = new Renderer());
|
||||
module(ui = new UI());
|
||||
module(netServer = new NetServer());
|
||||
module(netClient = new NetClient());
|
||||
|
||||
Log.info("Time to load [total]: {0}", Timers.elapsed());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(){
|
||||
super.render();
|
||||
threads.handleRender();
|
||||
}
|
||||
@Override
|
||||
public void render(){
|
||||
super.render();
|
||||
threads.handleRender();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,8 +19,8 @@ import io.anuke.mindustry.io.Version;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.ucore.entities.Entities;
|
||||
import io.anuke.ucore.entities.EntityGroup;
|
||||
import io.anuke.ucore.entities.trait.DrawTrait;
|
||||
import io.anuke.ucore.entities.impl.EffectEntity;
|
||||
import io.anuke.ucore.entities.trait.DrawTrait;
|
||||
import io.anuke.ucore.scene.ui.layout.Unit;
|
||||
import io.anuke.ucore.util.OS;
|
||||
import io.anuke.ucore.util.Translator;
|
||||
@@ -28,167 +28,150 @@ import io.anuke.ucore.util.Translator;
|
||||
import java.util.Locale;
|
||||
|
||||
public class Vars{
|
||||
public static boolean testMobile;
|
||||
//shorthand for whether or not this is running on android or ios
|
||||
public static boolean mobile;
|
||||
public static boolean ios;
|
||||
public static boolean android;
|
||||
//shorthand for whether or not this is running on GWT
|
||||
public static boolean gwt;
|
||||
|
||||
//respawn time in frames
|
||||
public static final float respawnduration = 60*4;
|
||||
//time between waves in frames (on normal mode)
|
||||
public static final float wavespace = 60*60*2f;
|
||||
//waves can last no longer than 3 minutes, otherwise the next one spawns
|
||||
public static final float maxwavespace = 60*60*4f;
|
||||
|
||||
//set ridiculously high for now
|
||||
public static final float coreBuildRange = 800999f;
|
||||
//discord group URL
|
||||
public static final String discordURL = "https://discord.gg/BKADYds";
|
||||
|
||||
public static final String releasesURL = "https://api.github.com/repos/Anuken/Mindustry/releases";
|
||||
|
||||
//directory for user-created map data
|
||||
public static FileHandle customMapDirectory;
|
||||
//save file directory
|
||||
public static FileHandle saveDirectory;
|
||||
public static String mapExtension = "mmap";
|
||||
public static String saveExtension = "msav";
|
||||
//scale of the font
|
||||
public static float fontScale;
|
||||
//camera zoom displayed on startup
|
||||
public static int baseCameraScale;
|
||||
//if true, player speed will be increased, massive amounts of resources will be given on start, and other debug options will be available
|
||||
public static boolean debug = false;
|
||||
public static boolean console = false;
|
||||
//whether the player can clip through walls
|
||||
public static boolean noclip = false;
|
||||
//whether turrets have infinite ammo (only with debug)
|
||||
public static boolean infiniteAmmo = true;
|
||||
//whether to show paths of enemies
|
||||
public static boolean showPaths = false;
|
||||
//if false, player is always hidden
|
||||
public static boolean showPlayer = true;
|
||||
//whether to hide ui, only on debug
|
||||
public static boolean showUI = true;
|
||||
//whether to show block debug
|
||||
public static boolean showBlockDebug = false;
|
||||
|
||||
public static boolean showFog = true;
|
||||
|
||||
//respawn time in frames
|
||||
public static final float respawnduration = 60 * 4;
|
||||
//time between waves in frames (on normal mode)
|
||||
public static final float wavespace = 60 * 60 * 2f;
|
||||
//waves can last no longer than 3 minutes, otherwise the next one spawns
|
||||
public static final float maxwavespace = 60 * 60 * 4f;
|
||||
//set ridiculously high for now
|
||||
public static final float coreBuildRange = 800999f;
|
||||
//discord group URL
|
||||
public static final String discordURL = "https://discord.gg/BKADYds";
|
||||
public static final String releasesURL = "https://api.github.com/repos/Anuken/Mindustry/releases";
|
||||
public static final int maxTextLength = 150;
|
||||
public static final int maxNameLength = 40;
|
||||
public static final int maxCharNameLength = 20;
|
||||
public static final int saveSlots = 64;
|
||||
public static final float itemSize = 5f;
|
||||
public static final int tilesize = 8;
|
||||
public static final Locale[] locales = {new Locale("en"), new Locale("fr"), new Locale("ru"), new Locale("uk", "UA"), new Locale("pl"),
|
||||
new Locale("de"), new Locale("pt", "BR"), new Locale("ko"), new Locale("in", "ID"), new Locale("ita"), new Locale("es")};
|
||||
public static final Color[] playerColors = {
|
||||
Color.valueOf("82759a"),
|
||||
Color.valueOf("c0c1c5"),
|
||||
Color.valueOf("fff0e7"),
|
||||
Color.valueOf("7d2953"),
|
||||
Color.valueOf("ff074e"),
|
||||
Color.valueOf("ff072a"),
|
||||
Color.valueOf("ff76a6"),
|
||||
Color.valueOf("a95238"),
|
||||
Color.valueOf("ffa108"),
|
||||
Color.valueOf("feeb2c"),
|
||||
Color.valueOf("ffcaa8"),
|
||||
Color.valueOf("008551"),
|
||||
Color.valueOf("00e339"),
|
||||
Color.valueOf("423c7b"),
|
||||
Color.valueOf("4b5ef1"),
|
||||
Color.valueOf("2cabfe"),
|
||||
};
|
||||
//server port
|
||||
public static final int port = 6567;
|
||||
public static final int webPort = 6568;
|
||||
public static boolean testMobile;
|
||||
//shorthand for whether or not this is running on android or ios
|
||||
public static boolean mobile;
|
||||
public static boolean ios;
|
||||
public static boolean android;
|
||||
//shorthand for whether or not this is running on GWT
|
||||
public static boolean gwt;
|
||||
//directory for user-created map data
|
||||
public static FileHandle customMapDirectory;
|
||||
//save file directory
|
||||
public static FileHandle saveDirectory;
|
||||
public static String mapExtension = "mmap";
|
||||
public static String saveExtension = "msav";
|
||||
//scale of the font
|
||||
public static float fontScale;
|
||||
//camera zoom displayed on startup
|
||||
public static int baseCameraScale;
|
||||
//if true, player speed will be increased, massive amounts of resources will be given on start, and other debug options will be available
|
||||
public static boolean debug = false;
|
||||
public static boolean console = false;
|
||||
//whether the player can clip through walls
|
||||
public static boolean noclip = false;
|
||||
//whether turrets have infinite ammo (only with debug)
|
||||
public static boolean infiniteAmmo = true;
|
||||
//whether to show paths of enemies
|
||||
public static boolean showPaths = false;
|
||||
//if false, player is always hidden
|
||||
public static boolean showPlayer = true;
|
||||
//whether to hide ui, only on debug
|
||||
public static boolean showUI = true;
|
||||
//whether to show block debug
|
||||
public static boolean showBlockDebug = false;
|
||||
public static boolean showFog = true;
|
||||
public static boolean headless = false;
|
||||
public static float controllerMin = 0.25f;
|
||||
public static float baseControllerSpeed = 11f;
|
||||
//only if smoothCamera
|
||||
public static boolean snapCamera = true;
|
||||
public static GameState state;
|
||||
public static ThreadHandler threads;
|
||||
|
||||
public static boolean headless = false;
|
||||
public static Control control;
|
||||
public static Logic logic;
|
||||
public static Renderer renderer;
|
||||
public static UI ui;
|
||||
public static World world;
|
||||
public static NetServer netServer;
|
||||
public static NetClient netClient;
|
||||
|
||||
public static float controllerMin = 0.25f;
|
||||
public static Player[] players = {};
|
||||
|
||||
public static float baseControllerSpeed = 11f;
|
||||
public static EntityGroup<Player> playerGroup;
|
||||
public static EntityGroup<TileEntity> tileGroup;
|
||||
public static EntityGroup<Bullet> bulletGroup;
|
||||
public static EntityGroup<Shield> shieldGroup;
|
||||
public static EntityGroup<EffectEntity> effectGroup;
|
||||
public static EntityGroup<DrawTrait> groundEffectGroup;
|
||||
public static EntityGroup<ItemDrop> itemGroup;
|
||||
|
||||
public static final int saveSlots = 64;
|
||||
public static EntityGroup<Puddle> puddleGroup;
|
||||
public static EntityGroup<Fire> fireGroup;
|
||||
public static EntityGroup<BaseUnit>[] unitGroups;
|
||||
|
||||
public static final float itemSize = 5f;
|
||||
public static final Translator[] tmptr = new Translator[]{new Translator(), new Translator(), new Translator(), new Translator()};
|
||||
|
||||
//only if smoothCamera
|
||||
public static boolean snapCamera = true;
|
||||
|
||||
public static final int tilesize = 8;
|
||||
public static void init(){
|
||||
Version.init();
|
||||
|
||||
public static final Translator[] tmptr = new Translator[]{new Translator(), new Translator(), new Translator(), new Translator()};
|
||||
playerGroup = Entities.addGroup(Player.class).enableMapping();
|
||||
tileGroup = Entities.addGroup(TileEntity.class, false);
|
||||
bulletGroup = Entities.addGroup(Bullet.class).enableMapping();
|
||||
shieldGroup = Entities.addGroup(Shield.class, false);
|
||||
effectGroup = Entities.addGroup(EffectEntity.class, false);
|
||||
groundEffectGroup = Entities.addGroup(DrawTrait.class, false);
|
||||
puddleGroup = Entities.addGroup(Puddle.class, false).enableMapping();
|
||||
itemGroup = Entities.addGroup(ItemDrop.class).enableMapping();
|
||||
fireGroup = Entities.addGroup(Fire.class, false).enableMapping();
|
||||
unitGroups = new EntityGroup[Team.all.length];
|
||||
|
||||
public static final Locale[] locales = {new Locale("en"), new Locale("fr"), new Locale("ru"), new Locale("uk", "UA"), new Locale("pl"),
|
||||
new Locale("de"), new Locale("pt", "BR"), new Locale("ko"), new Locale("in", "ID"), new Locale("ita"), new Locale("es")};
|
||||
for(Team team : Team.all){
|
||||
unitGroups[team.ordinal()] = Entities.addGroup(BaseUnit.class).enableMapping();
|
||||
}
|
||||
|
||||
public static final Color[] playerColors = {
|
||||
Color.valueOf("82759a"),
|
||||
Color.valueOf("c0c1c5"),
|
||||
Color.valueOf("fff0e7"),
|
||||
Color.valueOf("7d2953"),
|
||||
Color.valueOf("ff074e"),
|
||||
Color.valueOf("ff072a"),
|
||||
Color.valueOf("ff76a6"),
|
||||
Color.valueOf("a95238"),
|
||||
Color.valueOf("ffa108"),
|
||||
Color.valueOf("feeb2c"),
|
||||
Color.valueOf("ffcaa8"),
|
||||
Color.valueOf("008551"),
|
||||
Color.valueOf("00e339"),
|
||||
Color.valueOf("423c7b"),
|
||||
Color.valueOf("4b5ef1"),
|
||||
Color.valueOf("2cabfe"),
|
||||
};
|
||||
for(EntityGroup<?> group : Entities.getAllGroups()){
|
||||
group.setRemoveListener(entity -> {
|
||||
if(entity instanceof SyncTrait && Net.client()){
|
||||
netClient.addRemovedEntity((entity).getID());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//server port
|
||||
public static final int port = 6567;
|
||||
public static final int webPort = 6568;
|
||||
threads = new ThreadHandler(Platform.instance.getThreadProvider());
|
||||
|
||||
public static GameState state;
|
||||
public static ThreadHandler threads;
|
||||
mobile = Gdx.app.getType() == ApplicationType.Android || Gdx.app.getType() == ApplicationType.iOS || testMobile;
|
||||
ios = Gdx.app.getType() == ApplicationType.iOS;
|
||||
android = Gdx.app.getType() == ApplicationType.Android;
|
||||
gwt = Gdx.app.getType() == ApplicationType.WebGL;
|
||||
|
||||
public static Control control;
|
||||
public static Logic logic;
|
||||
public static Renderer renderer;
|
||||
public static UI ui;
|
||||
public static World world;
|
||||
public static NetServer netServer;
|
||||
public static NetClient netClient;
|
||||
|
||||
public static Player[] players = {};
|
||||
if(!gwt){
|
||||
customMapDirectory = OS.getAppDataDirectory("Mindustry").child("maps/");
|
||||
saveDirectory = OS.getAppDataDirectory("Mindustry").child("saves/");
|
||||
}
|
||||
|
||||
public static EntityGroup<Player> playerGroup;
|
||||
public static EntityGroup<TileEntity> tileGroup;
|
||||
public static EntityGroup<Bullet> bulletGroup;
|
||||
public static EntityGroup<Shield> shieldGroup;
|
||||
public static EntityGroup<EffectEntity> effectGroup;
|
||||
public static EntityGroup<DrawTrait> groundEffectGroup;
|
||||
public static EntityGroup<ItemDrop> itemGroup;
|
||||
|
||||
public static EntityGroup<Puddle> puddleGroup;
|
||||
public static EntityGroup<Fire> fireGroup;
|
||||
public static EntityGroup<BaseUnit>[] unitGroups;
|
||||
|
||||
public static void init(){
|
||||
Version.init();
|
||||
|
||||
playerGroup = Entities.addGroup(Player.class).enableMapping();
|
||||
tileGroup = Entities.addGroup(TileEntity.class, false);
|
||||
bulletGroup = Entities.addGroup(Bullet.class).enableMapping();
|
||||
shieldGroup = Entities.addGroup(Shield.class, false);
|
||||
effectGroup = Entities.addGroup(EffectEntity.class, false);
|
||||
groundEffectGroup = Entities.addGroup(DrawTrait.class, false);
|
||||
puddleGroup = Entities.addGroup(Puddle.class, false).enableMapping();
|
||||
itemGroup = Entities.addGroup(ItemDrop.class).enableMapping();
|
||||
fireGroup = Entities.addGroup(Fire.class, false).enableMapping();
|
||||
unitGroups = new EntityGroup[Team.all.length];
|
||||
|
||||
for(Team team : Team.all){
|
||||
unitGroups[team.ordinal()] = Entities.addGroup(BaseUnit.class).enableMapping();
|
||||
}
|
||||
|
||||
for(EntityGroup<?> group : Entities.getAllGroups()){
|
||||
group.setRemoveListener(entity -> {
|
||||
if(entity instanceof SyncTrait && Net.client()){
|
||||
netClient.addRemovedEntity(((SyncTrait) entity).getID());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
threads = new ThreadHandler(Platform.instance.getThreadProvider());
|
||||
|
||||
mobile = Gdx.app.getType() == ApplicationType.Android || Gdx.app.getType() == ApplicationType.iOS || testMobile;
|
||||
ios = Gdx.app.getType() == ApplicationType.iOS;
|
||||
android = Gdx.app.getType() == ApplicationType.Android;
|
||||
gwt = Gdx.app.getType() == ApplicationType.WebGL;
|
||||
|
||||
if(!gwt) {
|
||||
customMapDirectory = OS.getAppDataDirectory("Mindustry").child("maps/");
|
||||
saveDirectory = OS.getAppDataDirectory("Mindustry").child("saves/");
|
||||
}
|
||||
|
||||
fontScale = Math.max(Unit.dp.scl(1f)/2f, 0.5f);
|
||||
baseCameraScale = Math.round(Unit.dp.scl(4));
|
||||
}
|
||||
fontScale = Math.max(Unit.dp.scl(1f) / 2f, 0.5f);
|
||||
baseCameraScale = Math.round(Unit.dp.scl(4));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,32 +26,53 @@ import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
//TODO consider using quadtrees for finding specific types of blocks within an area
|
||||
//TODO maybe use Arrays instead of ObjectSets?
|
||||
/**Class used for indexing special target blocks for AI.*/
|
||||
public class BlockIndexer {
|
||||
/**Size of one ore quadrant.*/
|
||||
|
||||
/**
|
||||
* Class used for indexing special target blocks for AI.
|
||||
*/
|
||||
public class BlockIndexer{
|
||||
/**
|
||||
* Size of one ore quadrant.
|
||||
*/
|
||||
private final static int oreQuadrantSize = 20;
|
||||
/**Size of one structure quadrant.*/
|
||||
/**
|
||||
* Size of one structure quadrant.
|
||||
*/
|
||||
private final static int structQuadrantSize = 12;
|
||||
|
||||
/**Set of all ores that are being scanned.*/
|
||||
/**
|
||||
* Set of all ores that are being scanned.
|
||||
*/
|
||||
private final ObjectSet<Item> scanOres = ObjectSet.with(Items.tungsten, Items.coal, Items.lead, Items.thorium, Items.titanium);
|
||||
/**Stores all ore quadtrants on the map.*/
|
||||
private ObjectMap<Item, ObjectSet<Tile>> ores;
|
||||
|
||||
private final ObjectSet<Item> itemSet = new ObjectSet<>();
|
||||
|
||||
/**Tags all quadrants.*/
|
||||
/**
|
||||
* Stores all ore quadtrants on the map.
|
||||
*/
|
||||
private ObjectMap<Item, ObjectSet<Tile>> ores;
|
||||
/**
|
||||
* Tags all quadrants.
|
||||
*/
|
||||
private Bits[] structQuadrants;
|
||||
|
||||
/**Maps teams to a map of flagged tiles by type.*/
|
||||
/**
|
||||
* Maps teams to a map of flagged tiles by type.
|
||||
*/
|
||||
private ObjectMap<BlockFlag, ObjectSet<Tile>> enemyMap = new ObjectMap<>();
|
||||
/**Maps teams to a map of flagged tiles by type.*/
|
||||
/**
|
||||
* Maps teams to a map of flagged tiles by type.
|
||||
*/
|
||||
private ObjectMap<BlockFlag, ObjectSet<Tile>> allyMap = new ObjectMap<>();
|
||||
/**Empty map for invalid teams.*/
|
||||
/**
|
||||
* Empty map for invalid teams.
|
||||
*/
|
||||
private ObjectMap<BlockFlag, ObjectSet<Tile>> emptyMap = new ObjectMap<>();
|
||||
/**Maps tile positions to their last known tile index data.*/
|
||||
/**
|
||||
* Maps tile positions to their last known tile index data.
|
||||
*/
|
||||
private IntMap<TileIndex> typeMap = new IntMap<>();
|
||||
/**Empty array used for returning.*/
|
||||
/**
|
||||
* Empty array used for returning.
|
||||
*/
|
||||
private ObjectSet<Tile> emptyArray = new ObjectSet<>();
|
||||
|
||||
public BlockIndexer(){
|
||||
@@ -74,18 +95,18 @@ public class BlockIndexer {
|
||||
|
||||
//create bitset for each team type that contains each quadrant
|
||||
structQuadrants = new Bits[Team.all.length];
|
||||
for(int i = 0; i < Team.all.length; i ++){
|
||||
structQuadrants[i] = new Bits(Mathf.ceil(world.width() / (float)structQuadrantSize) * Mathf.ceil(world.height() / (float)structQuadrantSize));
|
||||
for(int i = 0; i < Team.all.length; i++){
|
||||
structQuadrants[i] = new Bits(Mathf.ceil(world.width() / (float) structQuadrantSize) * Mathf.ceil(world.height() / (float) structQuadrantSize));
|
||||
}
|
||||
|
||||
for(int x = 0; x < world.width(); x ++){
|
||||
for (int y = 0; y < world.height(); y++) {
|
||||
for(int x = 0; x < world.width(); x++){
|
||||
for(int y = 0; y < world.height(); y++){
|
||||
process(world.tile(x, y));
|
||||
}
|
||||
}
|
||||
|
||||
for (int x = 0; x < quadWidth(); x++) {
|
||||
for (int y = 0; y < quadHeight(); y++) {
|
||||
for(int x = 0; x < quadWidth(); x++){
|
||||
for(int y = 0; y < quadHeight(); y++){
|
||||
updateQuadrant(world.tile(x * structQuadrantSize, y * structQuadrantSize));
|
||||
}
|
||||
}
|
||||
@@ -94,12 +115,16 @@ public class BlockIndexer {
|
||||
});
|
||||
}
|
||||
|
||||
/**Get all allied blocks with a flag.*/
|
||||
/**
|
||||
* Get all allied blocks with a flag.
|
||||
*/
|
||||
public ObjectSet<Tile> getAllied(Team team, BlockFlag type){
|
||||
return (state.teams.get(team).ally ? allyMap : enemyMap).get(type, emptyArray);
|
||||
}
|
||||
|
||||
/**Get all enemy blocks with a flag.*/
|
||||
/**
|
||||
* Get all enemy blocks with a flag.
|
||||
*/
|
||||
public ObjectSet<Tile> getEnemy(Team team, BlockFlag type){
|
||||
return (!state.teams.get(team).ally ? allyMap : enemyMap).get(type, emptyArray);
|
||||
}
|
||||
@@ -108,13 +133,13 @@ public class BlockIndexer {
|
||||
Entity closest = null;
|
||||
float dst = 0;
|
||||
|
||||
for(int rx = Math.max((int)((x-range)/tilesize/structQuadrantSize), 0); rx <= (int)((x+range)/tilesize/structQuadrantSize) && rx < quadWidth(); rx ++){
|
||||
for(int ry = Math.max((int)((y-range)/tilesize/structQuadrantSize), 0); ry <= (int)((y+range)/tilesize/structQuadrantSize) && ry < quadHeight(); ry ++){
|
||||
for(int rx = Math.max((int) ((x - range) / tilesize / structQuadrantSize), 0); rx <= (int) ((x + range) / tilesize / structQuadrantSize) && rx < quadWidth(); rx++){
|
||||
for(int ry = Math.max((int) ((y - range) / tilesize / structQuadrantSize), 0); ry <= (int) ((y + range) / tilesize / structQuadrantSize) && ry < quadHeight(); ry++){
|
||||
|
||||
if(!getQuad(team, rx, ry)) continue;
|
||||
|
||||
for(int tx = rx * structQuadrantSize; tx < (rx + 1) * structQuadrantSize && tx < world.width(); tx ++){
|
||||
for(int ty = ry * structQuadrantSize; ty < (ry + 1) * structQuadrantSize && ty < world.height(); ty ++ ){
|
||||
for(int tx = rx * structQuadrantSize; tx < (rx + 1) * structQuadrantSize && tx < world.width(); tx++){
|
||||
for(int ty = ry * structQuadrantSize; ty < (ry + 1) * structQuadrantSize && ty < world.height(); ty++){
|
||||
Tile other = world.tile(tx, ty);
|
||||
|
||||
if(other == null || other.entity == null || !pred.test(other)) continue;
|
||||
@@ -134,22 +159,26 @@ public class BlockIndexer {
|
||||
return (TileEntity) closest;
|
||||
}
|
||||
|
||||
/**Returns a set of tiles that have ores of the specified type nearby.
|
||||
/**
|
||||
* Returns a set of tiles that have ores of the specified type nearby.
|
||||
* While each tile in the set is not guaranteed to have an ore directly on it,
|
||||
* each tile will at least have an ore within {@link #oreQuadrantSize} / 2 blocks of it.
|
||||
* Only specific ore types are scanned. See {@link #scanOres}.*/
|
||||
* Only specific ore types are scanned. See {@link #scanOres}.
|
||||
*/
|
||||
public ObjectSet<Tile> getOrePositions(Item item){
|
||||
return ores.get(item, emptyArray);
|
||||
}
|
||||
|
||||
/**Find the closest ore block relative to a position.*/
|
||||
/**
|
||||
* Find the closest ore block relative to a position.
|
||||
*/
|
||||
public Tile findClosestOre(float xp, float yp, Item item){
|
||||
Tile tile = Geometry.findClosest(xp, yp, world.indexer().getOrePositions(item));
|
||||
Tile tile = Geometry.findClosest(xp, yp, world.indexer().getOrePositions(item));
|
||||
|
||||
if(tile == null) return null;
|
||||
|
||||
for (int x = Math.max(0, tile.x - oreQuadrantSize/2); x < tile.x + oreQuadrantSize/2 && x < world.width(); x++) {
|
||||
for (int y = Math.max(0, tile.y - oreQuadrantSize/2); y < tile.y + oreQuadrantSize/2 && y < world.height(); y++) {
|
||||
for(int x = Math.max(0, tile.x - oreQuadrantSize / 2); x < tile.x + oreQuadrantSize / 2 && x < world.width(); x++){
|
||||
for(int y = Math.max(0, tile.y - oreQuadrantSize / 2); y < tile.y + oreQuadrantSize / 2 && y < world.height(); y++){
|
||||
Tile res = world.tile(x, y);
|
||||
if(res.block() == Blocks.air && res.floor().drops != null && res.floor().drops.item == item){
|
||||
return res;
|
||||
@@ -186,12 +215,12 @@ public class BlockIndexer {
|
||||
int quadrantY = tile.y / oreQuadrantSize;
|
||||
itemSet.clear();
|
||||
|
||||
Tile rounded = world.tile(Mathf.clamp(quadrantX * oreQuadrantSize + oreQuadrantSize /2, 0, world.width() - 1),
|
||||
Mathf.clamp(quadrantY * oreQuadrantSize + oreQuadrantSize /2, 0, world.height() - 1));
|
||||
Tile rounded = world.tile(Mathf.clamp(quadrantX * oreQuadrantSize + oreQuadrantSize / 2, 0, world.width() - 1),
|
||||
Mathf.clamp(quadrantY * oreQuadrantSize + oreQuadrantSize / 2, 0, world.height() - 1));
|
||||
|
||||
//find all items that this quadrant contains
|
||||
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++) {
|
||||
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);
|
||||
if(result.block().drops == null || !scanOres.contains(result.block().drops.item)) continue;
|
||||
|
||||
@@ -200,7 +229,7 @@ public class BlockIndexer {
|
||||
}
|
||||
|
||||
//update quadrant at this position
|
||||
for (Item item : scanOres){
|
||||
for(Item item : scanOres){
|
||||
ObjectSet<Tile> set = ores.get(item);
|
||||
|
||||
//update quadrant status depending on whether the item is in it
|
||||
@@ -219,7 +248,7 @@ public class BlockIndexer {
|
||||
int index = quadrantX + quadrantY * quadWidth();
|
||||
//Log.info("Updating quadrant: {0} {1}", quadrantX, quadrantY);
|
||||
|
||||
for(TeamData data : state.teams.getTeams()) {
|
||||
for(TeamData data : state.teams.getTeams()){
|
||||
|
||||
//fast-set this quadrant to 'occupied' if the tile just placed is already of this team
|
||||
if(tile.getTeam() == data.team && tile.entity != null){
|
||||
@@ -230,8 +259,8 @@ public class BlockIndexer {
|
||||
structQuadrants[data.team.ordinal()].clear(index);
|
||||
|
||||
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++) {
|
||||
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);
|
||||
//when a targetable block is found, mark this quadrant as occupied and stop searching
|
||||
if(result.entity != null && result.getTeam() == data.team){
|
||||
@@ -244,16 +273,16 @@ public class BlockIndexer {
|
||||
}
|
||||
|
||||
private boolean getQuad(Team team, int quadrantX, int quadrantY){
|
||||
int index = quadrantX + quadrantY * Mathf.ceil(world.width() / (float)structQuadrantSize);
|
||||
int index = quadrantX + quadrantY * Mathf.ceil(world.width() / (float) structQuadrantSize);
|
||||
return structQuadrants[team.ordinal()].get(index);
|
||||
}
|
||||
|
||||
private int quadWidth(){
|
||||
return Mathf.ceil(world.width() / (float)structQuadrantSize);
|
||||
return Mathf.ceil(world.width() / (float) structQuadrantSize);
|
||||
}
|
||||
|
||||
private int quadHeight(){
|
||||
return Mathf.ceil(world.height() / (float)structQuadrantSize);
|
||||
return Mathf.ceil(world.height() / (float) structQuadrantSize);
|
||||
}
|
||||
|
||||
private ObjectMap<BlockFlag, ObjectSet<Tile>> getMap(Team team){
|
||||
@@ -269,10 +298,10 @@ public class BlockIndexer {
|
||||
ores.put(item, new ObjectSet<>());
|
||||
}
|
||||
|
||||
for(int x = 0; x < world.width(); x ++){
|
||||
for (int y = 0; y < world.height(); y++) {
|
||||
int qx = (x/ oreQuadrantSize);
|
||||
int qy = (y/ oreQuadrantSize);
|
||||
for(int x = 0; x < world.width(); x++){
|
||||
for(int y = 0; y < world.height(); y++){
|
||||
int qx = (x / oreQuadrantSize);
|
||||
int qy = (y / oreQuadrantSize);
|
||||
|
||||
Tile tile = world.tile(x, y);
|
||||
|
||||
@@ -280,8 +309,8 @@ public class BlockIndexer {
|
||||
if(tile.floor().drops != null && scanOres.contains(tile.floor().drops.item) && tile.block() == Blocks.air){
|
||||
ores.get(tile.floor().drops.item).add(world.tile(
|
||||
//make sure to clamp quadrant middle position, since it might go off bounds
|
||||
Mathf.clamp(qx * oreQuadrantSize + oreQuadrantSize /2, 0, world.width() - 1),
|
||||
Mathf.clamp(qy * oreQuadrantSize + oreQuadrantSize /2, 0, world.height() - 1)));
|
||||
Mathf.clamp(qx * oreQuadrantSize + oreQuadrantSize / 2, 0, world.width() - 1),
|
||||
Mathf.clamp(qy * oreQuadrantSize + oreQuadrantSize / 2, 0, world.height() - 1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -291,7 +320,7 @@ public class BlockIndexer {
|
||||
public final EnumSet<BlockFlag> flags;
|
||||
public final Team team;
|
||||
|
||||
public TileIndex(EnumSet<BlockFlag> flags, Team team) {
|
||||
public TileIndex(EnumSet<BlockFlag> flags, Team team){
|
||||
this.flags = flags;
|
||||
this.team = team;
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import io.anuke.ucore.util.Log;
|
||||
import static io.anuke.mindustry.Vars.state;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class Pathfinder {
|
||||
public class Pathfinder{
|
||||
private long maxUpdate = TimeUtils.millisToNanos(4);
|
||||
private PathData[] paths;
|
||||
private IntArray blocked = new IntArray();
|
||||
@@ -56,7 +56,7 @@ public class Pathfinder {
|
||||
|
||||
Tile target = null;
|
||||
float tl = 0f;
|
||||
for(GridPoint2 point : Geometry.d8) {
|
||||
for(GridPoint2 point : Geometry.d8){
|
||||
int dx = tile.x + point.x, dy = tile.y + point.y;
|
||||
|
||||
Tile other = world.tile(dx, dy);
|
||||
@@ -89,16 +89,16 @@ public class Pathfinder {
|
||||
}
|
||||
|
||||
private void update(Tile tile, Team team){
|
||||
if(paths[team.ordinal()] != null) {
|
||||
if(paths[team.ordinal()] != null){
|
||||
PathData path = paths[team.ordinal()];
|
||||
|
||||
if(!passable(tile, team)){
|
||||
path.weights[tile.x][tile.y] = Float.MAX_VALUE;
|
||||
}
|
||||
|
||||
path.search ++;
|
||||
path.search++;
|
||||
|
||||
if(path.lastSearchTime + 1000/60*3 > TimeUtils.millis()){
|
||||
if(path.lastSearchTime + 1000 / 60 * 3 > TimeUtils.millis()){
|
||||
path.frontier.clear();
|
||||
}
|
||||
|
||||
@@ -115,17 +115,17 @@ public class Pathfinder {
|
||||
|
||||
private void createFor(Team team){
|
||||
PathData path = new PathData();
|
||||
path.search ++;
|
||||
path.search++;
|
||||
path.frontier.ensureCapacity((world.width() + world.height()) * 3);
|
||||
|
||||
paths[team.ordinal()] = path;
|
||||
|
||||
for (int x = 0; x < world.width(); x++) {
|
||||
for (int y = 0; y < world.height(); y++) {
|
||||
for(int x = 0; x < world.width(); x++){
|
||||
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)
|
||||
&& tile.block().flags.contains(BlockFlag.target)) {
|
||||
if(tile.block().flags != null && state.teams.areEnemies(tile.getTeam(), team)
|
||||
&& tile.block().flags.contains(BlockFlag.target)){
|
||||
path.frontier.addFirst(tile);
|
||||
path.weights[x][y] = 0;
|
||||
path.searches[x][y] = path.search;
|
||||
@@ -143,20 +143,20 @@ public class Pathfinder {
|
||||
|
||||
long start = TimeUtils.nanoTime();
|
||||
|
||||
while (path.frontier.size > 0 && (nsToRun < 0 || TimeUtils.timeSinceNanos(start) <= nsToRun)) {
|
||||
while(path.frontier.size > 0 && (nsToRun < 0 || TimeUtils.timeSinceNanos(start) <= nsToRun)){
|
||||
Tile tile = path.frontier.removeLast();
|
||||
float cost = path.weights[tile.x][tile.y];
|
||||
|
||||
if (cost < Float.MAX_VALUE) {
|
||||
for (GridPoint2 point : Geometry.d4) {
|
||||
if(cost < Float.MAX_VALUE){
|
||||
for(GridPoint2 point : Geometry.d4){
|
||||
|
||||
int dx = tile.x + point.x, dy = tile.y + point.y;
|
||||
Tile other = world.tile(dx, dy);
|
||||
|
||||
if (other != null && (path.weights[dx][dy] > cost + 1 || path.searches[dx][dy] < path.search)
|
||||
if(other != null && (path.weights[dx][dy] > cost + 1 || path.searches[dx][dy] < path.search)
|
||||
&& passable(other, team)){
|
||||
path.frontier.addFirst(world.tile(dx, dy));
|
||||
path.weights[dx][dy] = cost + other.cost/2f;
|
||||
path.weights[dx][dy] = cost + other.cost / 2f;
|
||||
path.searches[dx][dy] = path.search;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import java.io.IOException;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class WaveSpawner {
|
||||
public class WaveSpawner{
|
||||
private static final int quadsize = 4;
|
||||
|
||||
private Bits quadrants;
|
||||
@@ -34,28 +34,28 @@ public class WaveSpawner {
|
||||
|
||||
public void write(DataOutput output) throws IOException{
|
||||
output.writeShort(flySpawns.size);
|
||||
for (FlyerSpawn spawn : flySpawns){
|
||||
for(FlyerSpawn spawn : flySpawns){
|
||||
output.writeFloat(spawn.angle);
|
||||
}
|
||||
|
||||
output.writeShort(groundSpawns.size);
|
||||
for (GroundSpawn spawn : groundSpawns){
|
||||
output.writeShort((short)spawn.x);
|
||||
output.writeShort((short)spawn.y);
|
||||
for(GroundSpawn spawn : groundSpawns){
|
||||
output.writeShort((short) spawn.x);
|
||||
output.writeShort((short) spawn.y);
|
||||
}
|
||||
}
|
||||
|
||||
public void read(DataInput input) throws IOException{
|
||||
short flya = input.readShort();
|
||||
|
||||
for (int i = 0; i < flya; i++) {
|
||||
|
||||
for(int i = 0; i < flya; i++){
|
||||
FlyerSpawn spawn = new FlyerSpawn();
|
||||
spawn.angle = input.readFloat();
|
||||
flySpawns.add(spawn);
|
||||
}
|
||||
|
||||
|
||||
short grounda = input.readShort();
|
||||
for (int i = 0; i < grounda; i++) {
|
||||
for(int i = 0; i < grounda; i++){
|
||||
GroundSpawn spawn = new GroundSpawn();
|
||||
spawn.x = input.readShort();
|
||||
spawn.y = input.readShort();
|
||||
@@ -80,13 +80,13 @@ public class WaveSpawner {
|
||||
int addGround = groundGroups - groundSpawns.size, addFly = flyGroups - flySpawns.size;
|
||||
|
||||
//add extra groups if the total exceeds it
|
||||
for (int i = 0; i < addGround; i++) {
|
||||
for(int i = 0; i < addGround; i++){
|
||||
GroundSpawn spawn = new GroundSpawn();
|
||||
findLocation(spawn);
|
||||
groundSpawns.add(spawn);
|
||||
}
|
||||
|
||||
for (int i = 0; i < addFly; i++) {
|
||||
for(int i = 0; i < addFly; i++){
|
||||
FlyerSpawn spawn = new FlyerSpawn();
|
||||
findLocation(spawn);
|
||||
flySpawns.add(spawn);
|
||||
@@ -99,7 +99,7 @@ public class WaveSpawner {
|
||||
int groups = group.getGroupsSpawned(state.wave);
|
||||
int spawned = group.getUnitsSpawned(state.wave);
|
||||
|
||||
for (int i = 0; i < groups; i++) {
|
||||
for(int i = 0; i < groups; i++){
|
||||
Squad squad = new Squad();
|
||||
float spawnX, spawnY;
|
||||
float spread;
|
||||
@@ -109,11 +109,11 @@ public class WaveSpawner {
|
||||
//TODO verify flyer spawn
|
||||
|
||||
float margin = 40f; //how far away from the edge flying units spawn
|
||||
spawnX = world.width() *tilesize/2f + Mathf.sqrwavex(spawn.angle) * (world.width()/2f*tilesize + margin);
|
||||
spawnY = world.height() * tilesize/2f + Mathf.sqrwavey(spawn.angle) * (world.height()/2f*tilesize + margin);
|
||||
spawnX = world.width() * tilesize / 2f + Mathf.sqrwavex(spawn.angle) * (world.width() / 2f * tilesize + margin);
|
||||
spawnY = world.height() * tilesize / 2f + Mathf.sqrwavey(spawn.angle) * (world.height() / 2f * tilesize + margin);
|
||||
spread = margin / 1.5f;
|
||||
|
||||
flyCount ++;
|
||||
flyCount++;
|
||||
}else{
|
||||
GroundSpawn spawn = groundSpawns.get(groundCount);
|
||||
checkQuadrant(spawn.x, spawn.y);
|
||||
@@ -121,14 +121,14 @@ public class WaveSpawner {
|
||||
findLocation(spawn);
|
||||
}
|
||||
|
||||
spawnX = spawn.x * quadsize * tilesize + quadsize * tilesize/2f;
|
||||
spawnY = spawn.y * quadsize * tilesize + quadsize * tilesize/2f;
|
||||
spread = quadsize*tilesize/3f;
|
||||
spawnX = spawn.x * quadsize * tilesize + quadsize * tilesize / 2f;
|
||||
spawnY = spawn.y * quadsize * tilesize + quadsize * tilesize / 2f;
|
||||
spread = quadsize * tilesize / 3f;
|
||||
|
||||
groundCount ++;
|
||||
groundCount++;
|
||||
}
|
||||
|
||||
for (int j = 0; j < spawned; j++) {
|
||||
for(int j = 0; j < spawned; j++){
|
||||
BaseUnit unit = group.createUnit(Team.red);
|
||||
unit.setWave();
|
||||
unit.setSquad(squad);
|
||||
@@ -140,19 +140,19 @@ public class WaveSpawner {
|
||||
}
|
||||
|
||||
public void checkAllQuadrants(){
|
||||
for(int x = 0; x < quadWidth(); x ++){
|
||||
for(int y = 0; y < quadHeight(); y ++){
|
||||
for(int x = 0; x < quadWidth(); x++){
|
||||
for(int y = 0; y < quadHeight(); y++){
|
||||
checkQuadrant(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void checkQuadrant(int quadx, int quady){
|
||||
setQuad(quadx, quady, true);
|
||||
|
||||
outer:
|
||||
for (int x = quadx * quadsize; x < world.width() && x < (quadx + 1)*quadsize; x++) {
|
||||
for (int y = quady * quadsize; y < world.height() && y < (quady + 1)*quadsize; y++) {
|
||||
for(int x = quadx * quadsize; x < world.width() && x < (quadx + 1) * quadsize; x++){
|
||||
for(int y = quady * quadsize; y < world.height() && y < (quady + 1) * quadsize; y++){
|
||||
Tile tile = world.tile(x, y);
|
||||
|
||||
if(tile == null || tile.solid() || world.pathfinder().getValueforTeam(Team.red, x, y) == Float.MAX_VALUE){
|
||||
@@ -190,7 +190,7 @@ public class WaveSpawner {
|
||||
spawn.x = -1;
|
||||
spawn.y = -1;
|
||||
|
||||
int shellWidth = quadWidth()*2 + quadHeight() * 2 * 6;
|
||||
int shellWidth = quadWidth() * 2 + quadHeight() * 2 * 6;
|
||||
shellWidth = Math.min(quadWidth() * quadHeight() / 4, shellWidth);
|
||||
|
||||
Mathf.traverseSpiral(quadWidth(), quadHeight(), Mathf.random(shellWidth), (x, y) -> {
|
||||
@@ -210,11 +210,11 @@ public class WaveSpawner {
|
||||
}
|
||||
|
||||
private int quadWidth(){
|
||||
return Mathf.ceil(world.width() / (float)quadsize);
|
||||
return Mathf.ceil(world.width() / (float) quadsize);
|
||||
}
|
||||
|
||||
private int quadHeight(){
|
||||
return Mathf.ceil(world.height() / (float)quadsize);
|
||||
return Mathf.ceil(world.height() / (float) quadsize);
|
||||
}
|
||||
|
||||
private class FlyerSpawn{
|
||||
|
||||
@@ -9,7 +9,7 @@ import io.anuke.mindustry.game.Content;
|
||||
import io.anuke.mindustry.type.AmmoType;
|
||||
import io.anuke.mindustry.type.ContentList;
|
||||
|
||||
public class AmmoTypes implements ContentList {
|
||||
public class AmmoTypes implements ContentList{
|
||||
public static AmmoType bulletTungsten, bulletLead, bulletCarbide, bulletThorium, bulletSilicon, bulletPyratite,
|
||||
shotgunTungsten, bombExplosive, bombIncendiary, bombOil, shellCarbide, flamerThermite, weaponMissile,
|
||||
flakLead, flakExplosive, flakPlastic, flakSurge, missileExplosive, missileIncindiary, missileSurge,
|
||||
@@ -17,41 +17,41 @@ public class AmmoTypes implements ContentList {
|
||||
basicFlame, lancerLaser, lightning, spectreLaser, meltdownLaser, fuseShotgun, oil, water, lava, cryofluid;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
//weapon specific
|
||||
|
||||
shotgunTungsten = new AmmoType(Items.tungsten, WeaponBullets.tungstenShotgun, 2) {{
|
||||
shotgunTungsten = new AmmoType(Items.tungsten, WeaponBullets.tungstenShotgun, 2){{
|
||||
shootEffect = ShootFx.shootBig;
|
||||
smokeEffect = ShootFx.shootBigSmoke;
|
||||
recoil = 1f;
|
||||
}};
|
||||
|
||||
shellCarbide = new AmmoType(Items.carbide, WeaponBullets.shellCarbide, 2) {{
|
||||
shellCarbide = new AmmoType(Items.carbide, WeaponBullets.shellCarbide, 2){{
|
||||
shootEffect = ShootFx.shootBig;
|
||||
smokeEffect = ShootFx.shootBigSmoke;
|
||||
}};
|
||||
|
||||
bombExplosive = new AmmoType(Items.blastCompound, WeaponBullets.bombExplosive, 3) {{
|
||||
bombExplosive = new AmmoType(Items.blastCompound, WeaponBullets.bombExplosive, 3){{
|
||||
shootEffect = Fx.none;
|
||||
smokeEffect = Fx.none;
|
||||
}};
|
||||
|
||||
bombIncendiary = new AmmoType(Items.pyratite, WeaponBullets.bombIncendiary, 3) {{
|
||||
bombIncendiary = new AmmoType(Items.pyratite, WeaponBullets.bombIncendiary, 3){{
|
||||
shootEffect = Fx.none;
|
||||
smokeEffect = Fx.none;
|
||||
}};
|
||||
|
||||
bombOil = new AmmoType(Items.coal, WeaponBullets.bombOil, 3) {{
|
||||
bombOil = new AmmoType(Items.coal, WeaponBullets.bombOil, 3){{
|
||||
shootEffect = Fx.none;
|
||||
smokeEffect = Fx.none;
|
||||
}};
|
||||
|
||||
flamerThermite = new AmmoType(Items.pyratite, TurretBullets.basicFlame, 3) {{
|
||||
flamerThermite = new AmmoType(Items.pyratite, TurretBullets.basicFlame, 3){{
|
||||
shootEffect = ShootFx.shootSmallFlame;
|
||||
}};
|
||||
|
||||
weaponMissile = new AmmoType(Items.carbide, MissileBullets.javelin, 2) {{
|
||||
weaponMissile = new AmmoType(Items.carbide, MissileBullets.javelin, 2){{
|
||||
shootEffect = BulletFx.hitBulletSmall;
|
||||
smokeEffect = Fx.none;
|
||||
reloadMultiplier = 1.2f;
|
||||
@@ -59,37 +59,37 @@ public class AmmoTypes implements ContentList {
|
||||
|
||||
//bullets
|
||||
|
||||
bulletLead = new AmmoType(Items.lead, StandardBullets.lead, 5) {{
|
||||
bulletLead = new AmmoType(Items.lead, StandardBullets.lead, 5){{
|
||||
shootEffect = ShootFx.shootSmall;
|
||||
smokeEffect = ShootFx.shootSmallSmoke;
|
||||
reloadMultiplier = 1.6f;
|
||||
inaccuracy = 5f;
|
||||
}};
|
||||
|
||||
bulletTungsten = new AmmoType(Items.tungsten, StandardBullets.tungsten, 2) {{
|
||||
bulletTungsten = new AmmoType(Items.tungsten, StandardBullets.tungsten, 2){{
|
||||
shootEffect = ShootFx.shootSmall;
|
||||
smokeEffect = ShootFx.shootSmallSmoke;
|
||||
reloadMultiplier = 0.8f;
|
||||
}};
|
||||
|
||||
bulletCarbide = new AmmoType(Items.carbide, StandardBullets.carbide, 2) {{
|
||||
bulletCarbide = new AmmoType(Items.carbide, StandardBullets.carbide, 2){{
|
||||
shootEffect = ShootFx.shootSmall;
|
||||
smokeEffect = ShootFx.shootSmallSmoke;
|
||||
reloadMultiplier = 0.6f;
|
||||
}};
|
||||
|
||||
bulletThorium = new AmmoType(Items.thorium, StandardBullets.thorium, 2) {{
|
||||
bulletThorium = new AmmoType(Items.thorium, StandardBullets.thorium, 2){{
|
||||
shootEffect = ShootFx.shootBig;
|
||||
smokeEffect = ShootFx.shootBigSmoke;
|
||||
}};
|
||||
|
||||
bulletSilicon = new AmmoType(Items.silicon, StandardBullets.homing, 5) {{
|
||||
bulletSilicon = new AmmoType(Items.silicon, StandardBullets.homing, 5){{
|
||||
shootEffect = ShootFx.shootSmall;
|
||||
smokeEffect = ShootFx.shootSmallSmoke;
|
||||
reloadMultiplier = 1.4f;
|
||||
}};
|
||||
|
||||
bulletPyratite = new AmmoType(Items.pyratite, StandardBullets.tracer, 3) {{
|
||||
bulletPyratite = new AmmoType(Items.pyratite, StandardBullets.tracer, 3){{
|
||||
shootEffect = ShootFx.shootSmall;
|
||||
smokeEffect = ShootFx.shootSmallSmoke;
|
||||
inaccuracy = 3f;
|
||||
@@ -97,71 +97,71 @@ public class AmmoTypes implements ContentList {
|
||||
|
||||
//flak
|
||||
|
||||
flakLead = new AmmoType(Items.lead, FlakBullets.lead, 5) {{
|
||||
flakLead = new AmmoType(Items.lead, FlakBullets.lead, 5){{
|
||||
shootEffect = ShootFx.shootSmall;
|
||||
smokeEffect = ShootFx.shootSmallSmoke;
|
||||
}};
|
||||
|
||||
flakExplosive = new AmmoType(Items.blastCompound, FlakBullets.explosive, 5) {{
|
||||
flakExplosive = new AmmoType(Items.blastCompound, FlakBullets.explosive, 5){{
|
||||
shootEffect = ShootFx.shootSmall;
|
||||
smokeEffect = ShootFx.shootSmallSmoke;
|
||||
}};
|
||||
|
||||
flakPlastic = new AmmoType(Items.plastanium, FlakBullets.plastic, 5) {{
|
||||
flakPlastic = new AmmoType(Items.plastanium, FlakBullets.plastic, 5){{
|
||||
shootEffect = ShootFx.shootSmall;
|
||||
smokeEffect = ShootFx.shootSmallSmoke;
|
||||
}};
|
||||
|
||||
flakSurge = new AmmoType(Items.surgealloy, FlakBullets.surge, 5) {{
|
||||
flakSurge = new AmmoType(Items.surgealloy, FlakBullets.surge, 5){{
|
||||
shootEffect = ShootFx.shootSmall;
|
||||
smokeEffect = ShootFx.shootSmallSmoke;
|
||||
}};
|
||||
|
||||
//missiles
|
||||
|
||||
missileExplosive = new AmmoType(Items.blastCompound, MissileBullets.explosive, 1) {{
|
||||
missileExplosive = new AmmoType(Items.blastCompound, MissileBullets.explosive, 1){{
|
||||
shootEffect = ShootFx.shootBig2;
|
||||
smokeEffect = ShootFx.shootBigSmoke2;
|
||||
reloadMultiplier = 1.2f;
|
||||
}};
|
||||
|
||||
missileIncindiary = new AmmoType(Items.pyratite, MissileBullets.incindiary, 1) {{
|
||||
missileIncindiary = new AmmoType(Items.pyratite, MissileBullets.incindiary, 1){{
|
||||
shootEffect = ShootFx.shootBig2;
|
||||
smokeEffect = ShootFx.shootBigSmoke2;
|
||||
reloadMultiplier = 1.0f;
|
||||
}};
|
||||
|
||||
missileSurge = new AmmoType(Items.surgealloy, MissileBullets.surge, 1) {{
|
||||
missileSurge = new AmmoType(Items.surgealloy, MissileBullets.surge, 1){{
|
||||
shootEffect = ShootFx.shootBig2;
|
||||
smokeEffect = ShootFx.shootBigSmoke2;
|
||||
}};
|
||||
|
||||
//artillery
|
||||
|
||||
artilleryCarbide = new AmmoType(Items.carbide, ArtilleryBullets.carbide, 2) {{
|
||||
artilleryCarbide = new AmmoType(Items.carbide, ArtilleryBullets.carbide, 2){{
|
||||
shootEffect = ShootFx.shootBig2;
|
||||
smokeEffect = ShootFx.shootBigSmoke2;
|
||||
}};
|
||||
|
||||
artilleryPlastic = new AmmoType(Items.plastanium, ArtilleryBullets.plastic, 2) {{
|
||||
artilleryPlastic = new AmmoType(Items.plastanium, ArtilleryBullets.plastic, 2){{
|
||||
shootEffect = ShootFx.shootBig2;
|
||||
smokeEffect = ShootFx.shootBigSmoke2;
|
||||
reloadMultiplier = 1.4f;
|
||||
}};
|
||||
|
||||
artilleryHoming = new AmmoType(Items.silicon, ArtilleryBullets.homing, 1) {{
|
||||
artilleryHoming = new AmmoType(Items.silicon, ArtilleryBullets.homing, 1){{
|
||||
shootEffect = ShootFx.shootBig2;
|
||||
smokeEffect = ShootFx.shootBigSmoke2;
|
||||
reloadMultiplier = 0.9f;
|
||||
}};
|
||||
|
||||
artilleryIncindiary = new AmmoType(Items.pyratite, ArtilleryBullets.incindiary, 2) {{
|
||||
artilleryIncindiary = new AmmoType(Items.pyratite, ArtilleryBullets.incindiary, 2){{
|
||||
shootEffect = ShootFx.shootBig2;
|
||||
smokeEffect = ShootFx.shootBigSmoke2;
|
||||
reloadMultiplier = 1.2f;
|
||||
}};
|
||||
|
||||
artilleryExplosive = new AmmoType(Items.blastCompound, ArtilleryBullets.explosive, 1) {{
|
||||
artilleryExplosive = new AmmoType(Items.blastCompound, ArtilleryBullets.explosive, 1){{
|
||||
shootEffect = ShootFx.shootBig2;
|
||||
smokeEffect = ShootFx.shootBigSmoke2;
|
||||
reloadMultiplier = 1.6f;
|
||||
@@ -169,7 +169,7 @@ public class AmmoTypes implements ContentList {
|
||||
|
||||
//flame
|
||||
|
||||
basicFlame = new AmmoType(Liquids.oil, TurretBullets.basicFlame, 0.3f) {{
|
||||
basicFlame = new AmmoType(Liquids.oil, TurretBullets.basicFlame, 0.3f){{
|
||||
shootEffect = ShootFx.shootSmallFlame;
|
||||
}};
|
||||
|
||||
@@ -198,7 +198,7 @@ public class AmmoTypes implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array<? extends Content> getAll() {
|
||||
public Array<? extends Content> getAll(){
|
||||
return AmmoType.all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,41 +12,41 @@ public class Items implements ContentList{
|
||||
biomatter, sand, blastCompound, pyratite;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
stone = new Item("stone", Color.valueOf("777777")) {{
|
||||
stone = new Item("stone", Color.valueOf("777777")){{
|
||||
hardness = 3;
|
||||
}};
|
||||
|
||||
tungsten = new Item("tungsten", Color.valueOf("a0b0c8")) {{
|
||||
tungsten = new Item("tungsten", Color.valueOf("a0b0c8")){{
|
||||
type = ItemType.material;
|
||||
hardness = 1;
|
||||
cost = 0.75f;
|
||||
}};
|
||||
|
||||
lead = new Item("lead", Color.valueOf("8e85a2")) {{
|
||||
lead = new Item("lead", Color.valueOf("8e85a2")){{
|
||||
type = ItemType.material;
|
||||
hardness = 1;
|
||||
cost = 0.6f;
|
||||
}};
|
||||
|
||||
coal = new Item("coal", Color.valueOf("272727")) {{
|
||||
coal = new Item("coal", Color.valueOf("272727")){{
|
||||
explosiveness = 0.2f;
|
||||
flammability = 0.5f;
|
||||
hardness = 2;
|
||||
}};
|
||||
|
||||
carbide = new Item("carbide", Color.valueOf("e2e2e2")) {{
|
||||
carbide = new Item("carbide", Color.valueOf("e2e2e2")){{
|
||||
type = ItemType.material;
|
||||
}};
|
||||
|
||||
titanium = new Item("titanium", Color.valueOf("8da1e3")) {{
|
||||
titanium = new Item("titanium", Color.valueOf("8da1e3")){{
|
||||
type = ItemType.material;
|
||||
hardness = 3;
|
||||
cost = 1.1f;
|
||||
}};
|
||||
|
||||
thorium = new Item("thorium", Color.valueOf("f9a3c7")) {{
|
||||
thorium = new Item("thorium", Color.valueOf("f9a3c7")){{
|
||||
type = ItemType.material;
|
||||
explosiveness = 0.1f;
|
||||
hardness = 4;
|
||||
@@ -54,49 +54,49 @@ public class Items implements ContentList{
|
||||
cost = 1.2f;
|
||||
}};
|
||||
|
||||
silicon = new Item("silicon", Color.valueOf("53565c")) {{
|
||||
silicon = new Item("silicon", Color.valueOf("53565c")){{
|
||||
type = ItemType.material;
|
||||
cost = 0.9f;
|
||||
}};
|
||||
|
||||
plastanium = new Item("plastanium", Color.valueOf("e9ead3")) {{
|
||||
plastanium = new Item("plastanium", Color.valueOf("e9ead3")){{
|
||||
type = ItemType.material;
|
||||
flammability = 0.1f;
|
||||
explosiveness = 0.1f;
|
||||
cost = 1.5f;
|
||||
}};
|
||||
|
||||
phasematter = new Item("phase-matter", Color.valueOf("f4ba6e")) {{
|
||||
phasematter = new Item("phase-matter", Color.valueOf("f4ba6e")){{
|
||||
type = ItemType.material;
|
||||
cost = 1.5f;
|
||||
}};
|
||||
|
||||
surgealloy = new Item("surge-alloy", Color.valueOf("b4d5c7")) {{
|
||||
surgealloy = new Item("surge-alloy", Color.valueOf("b4d5c7")){{
|
||||
type = ItemType.material;
|
||||
}};
|
||||
|
||||
biomatter = new Item("biomatter", Color.valueOf("648b55")) {{
|
||||
biomatter = new Item("biomatter", Color.valueOf("648b55")){{
|
||||
flammability = 0.4f;
|
||||
fluxiness = 0.2f;
|
||||
}};
|
||||
|
||||
sand = new Item("sand", Color.valueOf("e3d39e")) {{
|
||||
sand = new Item("sand", Color.valueOf("e3d39e")){{
|
||||
fluxiness = 0.5f;
|
||||
}};
|
||||
|
||||
blastCompound = new Item("blast-compound", Color.valueOf("ff795e")) {{
|
||||
blastCompound = new Item("blast-compound", Color.valueOf("ff795e")){{
|
||||
flammability = 0.2f;
|
||||
explosiveness = 0.6f;
|
||||
}};
|
||||
|
||||
pyratite = new Item("pyratite", Color.valueOf("ffaa5f")) {{
|
||||
pyratite = new Item("pyratite", Color.valueOf("ffaa5f")){{
|
||||
flammability = 0.7f;
|
||||
explosiveness = 0.2f;
|
||||
}};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array<? extends Content> getAll() {
|
||||
public Array<? extends Content> getAll(){
|
||||
return Item.all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,20 +6,13 @@ import io.anuke.mindustry.game.Content;
|
||||
import io.anuke.mindustry.type.ContentList;
|
||||
import io.anuke.mindustry.type.Liquid;
|
||||
|
||||
public class Liquids implements ContentList {
|
||||
public static Liquid none, water, lava, oil, cryofluid;
|
||||
public class Liquids implements ContentList{
|
||||
public static Liquid water, lava, oil, cryofluid;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
none = new Liquid("none", Color.CLEAR){
|
||||
@Override
|
||||
public boolean isHidden(){
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
water = new Liquid("water", Color.valueOf("486acd")) {
|
||||
water = new Liquid("water", Color.valueOf("486acd")){
|
||||
{
|
||||
heatCapacity = 0.4f;
|
||||
tier = 0;
|
||||
@@ -27,7 +20,7 @@ public class Liquids implements ContentList {
|
||||
}
|
||||
};
|
||||
|
||||
lava = new Liquid("lava", Color.valueOf("e37341")) {
|
||||
lava = new Liquid("lava", Color.valueOf("e37341")){
|
||||
{
|
||||
temperature = 0.8f;
|
||||
viscosity = 0.8f;
|
||||
@@ -36,7 +29,7 @@ public class Liquids implements ContentList {
|
||||
}
|
||||
};
|
||||
|
||||
oil = new Liquid("oil", Color.valueOf("313131")) {
|
||||
oil = new Liquid("oil", Color.valueOf("313131")){
|
||||
{
|
||||
viscosity = 0.7f;
|
||||
flammability = 0.6f;
|
||||
@@ -46,10 +39,10 @@ public class Liquids implements ContentList {
|
||||
}
|
||||
};
|
||||
|
||||
cryofluid = new Liquid("cryofluid", Color.SKY) {
|
||||
cryofluid = new Liquid("cryofluid", Color.SKY){
|
||||
{
|
||||
heatCapacity = 0.75f;
|
||||
temperature = 0.4f;
|
||||
heatCapacity = 0.9f;
|
||||
temperature = 0.25f;
|
||||
tier = 1;
|
||||
effect = StatusEffects.freezing;
|
||||
}
|
||||
@@ -57,7 +50,7 @@ public class Liquids implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array<? extends Content> getAll() {
|
||||
public Array<? extends Content> getAll(){
|
||||
return Liquid.all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,16 @@ import io.anuke.mindustry.type.ContentList;
|
||||
import io.anuke.mindustry.type.Mech;
|
||||
import io.anuke.mindustry.type.Upgrade;
|
||||
|
||||
public class Mechs implements ContentList {
|
||||
public class Mechs implements ContentList{
|
||||
public static Mech alpha, delta, tau, omega, dart, javelin, trident, halberd;
|
||||
|
||||
/**These are not new mechs, just re-assignments for convenience.*/
|
||||
/**
|
||||
* These are not new mechs, just re-assignments for convenience.
|
||||
*/
|
||||
public static Mech starterDesktop, starterMobile;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
alpha = new Mech("alpha-mech", false){{
|
||||
drillPower = 1;
|
||||
@@ -48,7 +50,7 @@ public class Mechs implements ContentList {
|
||||
}};
|
||||
|
||||
dart = new Mech("dart-ship", true){{
|
||||
drillPower = -1;
|
||||
drillPower = 1;
|
||||
speed = 0.4f;
|
||||
maxSpeed = 3f;
|
||||
drag = 0.1f;
|
||||
@@ -85,7 +87,7 @@ public class Mechs implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array<? extends Content> getAll() {
|
||||
public Array<? extends Content> getAll(){
|
||||
return Upgrade.all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,19 +12,19 @@ import static io.anuke.mindustry.type.Category.*;
|
||||
public class Recipes implements ContentList{
|
||||
|
||||
@Override
|
||||
public void load (){
|
||||
public void load(){
|
||||
//WALLS
|
||||
new Recipe(defense, DefenseBlocks.tungstenWall, new ItemStack(Items.tungsten, 12));
|
||||
new Recipe(defense, DefenseBlocks.tungstenWallLarge, new ItemStack(Items.tungsten, 12*4));
|
||||
new Recipe(defense, DefenseBlocks.tungstenWallLarge, new ItemStack(Items.tungsten, 12 * 4));
|
||||
|
||||
new Recipe(defense, DefenseBlocks.carbideWall, new ItemStack(Items.carbide, 12));
|
||||
new Recipe(defense, DefenseBlocks.carbideWallLarge, new ItemStack(Items.carbide, 12*4));
|
||||
new Recipe(defense, DefenseBlocks.carbideWallLarge, new ItemStack(Items.carbide, 12 * 4));
|
||||
|
||||
new Recipe(defense, DefenseBlocks.thoriumWall, new ItemStack(Items.thorium, 12));
|
||||
new Recipe(defense, DefenseBlocks.thoriumWallLarge, new ItemStack(Items.thorium, 12*4));
|
||||
new Recipe(defense, DefenseBlocks.thoriumWallLarge, new ItemStack(Items.thorium, 12 * 4));
|
||||
|
||||
new Recipe(defense, DefenseBlocks.door, new ItemStack(Items.carbide, 12), new ItemStack(Items.silicon, 8));
|
||||
new Recipe(defense, DefenseBlocks.doorLarge, new ItemStack(Items.carbide, 12*4), new ItemStack(Items.silicon, 8*4));
|
||||
new Recipe(defense, DefenseBlocks.doorLarge, new ItemStack(Items.carbide, 12 * 4), new ItemStack(Items.silicon, 8 * 4));
|
||||
|
||||
//TURRETS
|
||||
new Recipe(weapon, TurretBlocks.duo, new ItemStack(Items.tungsten, 40));
|
||||
@@ -44,11 +44,11 @@ public class Recipes implements ContentList{
|
||||
|
||||
//starter lead transporation
|
||||
new Recipe(distribution, DistributionBlocks.junction, new ItemStack(Items.lead, 2));
|
||||
new Recipe(distribution, DistributionBlocks.router, new ItemStack(Items.lead, 6));
|
||||
new Recipe(distribution, DistributionBlocks.splitter, new ItemStack(Items.lead, 6));
|
||||
|
||||
//advanced carbide transporation
|
||||
new Recipe(distribution, DistributionBlocks.splitter, new ItemStack(Items.carbide, 2), new ItemStack(Items.tungsten, 2));
|
||||
new Recipe(distribution, DistributionBlocks.multiplexer, new ItemStack(Items.carbide, 8), new ItemStack(Items.tungsten, 8));
|
||||
//new Recipe(distribution, DistributionBlocks.splitter, new ItemStack(Items.carbide, 2), new ItemStack(Items.tungsten, 2));
|
||||
new Recipe(distribution, DistributionBlocks.distributor, new ItemStack(Items.carbide, 8), new ItemStack(Items.tungsten, 8));
|
||||
new Recipe(distribution, DistributionBlocks.sorter, new ItemStack(Items.carbide, 4), new ItemStack(Items.tungsten, 4));
|
||||
new Recipe(distribution, DistributionBlocks.overflowGate, new ItemStack(Items.carbide, 4), new ItemStack(Items.tungsten, 8));
|
||||
new Recipe(distribution, DistributionBlocks.bridgeConveyor, new ItemStack(Items.carbide, 8), new ItemStack(Items.tungsten, 8));
|
||||
@@ -171,7 +171,6 @@ public class Recipes implements ContentList{
|
||||
new Recipe(production, ProductionBlocks.oilextractor, new ItemStack(Items.titanium, 40), new ItemStack(Items.surgealloy, 40));*/
|
||||
|
||||
|
||||
|
||||
//new Recipe(distribution, DistributionBlocks.massDriver, new ItemStack(Items.carbide, 1));
|
||||
|
||||
|
||||
@@ -282,7 +281,7 @@ public class Recipes implements ContentList{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array<? extends Content> getAll() {
|
||||
public Array<? extends Content> getAll(){
|
||||
return Recipe.all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,30 +3,30 @@ package io.anuke.mindustry.content;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import io.anuke.mindustry.content.fx.EnvironmentFx;
|
||||
import io.anuke.mindustry.entities.StatusController.StatusEntry;
|
||||
import io.anuke.mindustry.game.Content;
|
||||
import io.anuke.mindustry.type.StatusEffect;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.game.Content;
|
||||
import io.anuke.mindustry.type.ContentList;
|
||||
import io.anuke.mindustry.type.StatusEffect;
|
||||
import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class StatusEffects implements ContentList {
|
||||
public class StatusEffects implements ContentList{
|
||||
public static StatusEffect none, burning, freezing, wet, melting, tarred, overdrive, shielded;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
none = new StatusEffect(0);
|
||||
|
||||
burning = new StatusEffect(4 * 60f) {
|
||||
burning = new StatusEffect(4 * 60f){
|
||||
{
|
||||
oppositeScale = 0.5f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result) {
|
||||
if (to == tarred) {
|
||||
public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result){
|
||||
if(to == tarred){
|
||||
unit.damage(1f);
|
||||
Effects.effect(EnvironmentFx.burning, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f));
|
||||
return result.set(this, Math.min(time + newTime, baseDuration + tarred.baseDuration));
|
||||
@@ -36,45 +36,45 @@ public class StatusEffects implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Unit unit, float time) {
|
||||
public void update(Unit unit, float time){
|
||||
unit.damagePeriodic(0.04f);
|
||||
|
||||
if (Mathf.chance(Timers.delta() * 0.2f)) {
|
||||
if(Mathf.chance(Timers.delta() * 0.2f)){
|
||||
Effects.effect(EnvironmentFx.burning, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
freezing = new StatusEffect(5 * 60f) {
|
||||
freezing = new StatusEffect(5 * 60f){
|
||||
{
|
||||
oppositeScale = 0.4f;
|
||||
speedMultiplier = 0.7f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Unit unit, float time) {
|
||||
public void update(Unit unit, float time){
|
||||
|
||||
if (Mathf.chance(Timers.delta() * 0.15f)) {
|
||||
if(Mathf.chance(Timers.delta() * 0.15f)){
|
||||
Effects.effect(EnvironmentFx.freezing, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
wet = new StatusEffect(3 * 60f) {
|
||||
wet = new StatusEffect(3 * 60f){
|
||||
{
|
||||
oppositeScale = 0.5f;
|
||||
speedMultiplier = 0.999f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Unit unit, float time) {
|
||||
if (Mathf.chance(Timers.delta() * 0.15f)) {
|
||||
public void update(Unit unit, float time){
|
||||
if(Mathf.chance(Timers.delta() * 0.15f)){
|
||||
Effects.effect(EnvironmentFx.wet, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
melting = new StatusEffect(5 * 60f) {
|
||||
melting = new StatusEffect(5 * 60f){
|
||||
{
|
||||
oppositeScale = 0.2f;
|
||||
speedMultiplier = 0.8f;
|
||||
@@ -82,8 +82,8 @@ public class StatusEffects implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result) {
|
||||
if (to == tarred) {
|
||||
public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result){
|
||||
if(to == tarred){
|
||||
return result.set(this, Math.min(time + newTime / 2f, baseDuration));
|
||||
}
|
||||
|
||||
@@ -91,30 +91,30 @@ public class StatusEffects implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Unit unit, float time) {
|
||||
public void update(Unit unit, float time){
|
||||
unit.damagePeriodic(0.3f);
|
||||
|
||||
if (Mathf.chance(Timers.delta() * 0.2f)) {
|
||||
if(Mathf.chance(Timers.delta() * 0.2f)){
|
||||
Effects.effect(EnvironmentFx.melting, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
tarred = new StatusEffect(4 * 60f) {
|
||||
tarred = new StatusEffect(4 * 60f){
|
||||
{
|
||||
speedMultiplier = 0.6f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Unit unit, float time) {
|
||||
if (Mathf.chance(Timers.delta() * 0.15f)) {
|
||||
public void update(Unit unit, float time){
|
||||
if(Mathf.chance(Timers.delta() * 0.15f)){
|
||||
Effects.effect(EnvironmentFx.oily, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result) {
|
||||
if (to == melting || to == burning) {
|
||||
public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result){
|
||||
if(to == melting || to == burning){
|
||||
return result.set(to, newTime + time);
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ public class StatusEffects implements ContentList {
|
||||
}
|
||||
};
|
||||
|
||||
overdrive = new StatusEffect(6f) {
|
||||
overdrive = new StatusEffect(6f){
|
||||
{
|
||||
armorMultiplier = 0.95f;
|
||||
speedMultiplier = 1.05f;
|
||||
@@ -130,13 +130,13 @@ public class StatusEffects implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Unit unit, float time) {
|
||||
public void update(Unit unit, float time){
|
||||
//idle regen boosted
|
||||
unit.health += 0.01f * Timers.delta();
|
||||
}
|
||||
};
|
||||
|
||||
shielded = new StatusEffect(6f) {
|
||||
shielded = new StatusEffect(6f){
|
||||
{
|
||||
armorMultiplier = 3f;
|
||||
}
|
||||
@@ -149,7 +149,7 @@ public class StatusEffects implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array<? extends Content> getAll() {
|
||||
public Array<? extends Content> getAll(){
|
||||
return StatusEffect.all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ import io.anuke.mindustry.entities.units.types.*;
|
||||
import io.anuke.mindustry.game.Content;
|
||||
import io.anuke.mindustry.type.ContentList;
|
||||
|
||||
public class UnitTypes implements ContentList {
|
||||
public class UnitTypes implements ContentList{
|
||||
public static UnitType drone, scout, vtol, monsoon, titan, fabricator;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
drone = new UnitType("drone", Drone.class, Drone::new){{
|
||||
isFlying = true;
|
||||
drag = 0.01f;
|
||||
@@ -73,7 +73,7 @@ public class UnitTypes implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array<? extends Content> getAll() {
|
||||
public Array<? extends Content> getAll(){
|
||||
return UnitType.all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,13 @@ import io.anuke.mindustry.type.ContentList;
|
||||
import io.anuke.mindustry.type.Upgrade;
|
||||
import io.anuke.mindustry.type.Weapon;
|
||||
|
||||
public class Weapons implements ContentList {
|
||||
public class Weapons implements ContentList{
|
||||
public static Weapon blaster, chainBlaster, shockgun, sapper, swarmer, bomber, flakgun, flamethrower, missiles;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
blaster = new Weapon("blaster") {{
|
||||
blaster = new Weapon("blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 15f;
|
||||
roundrobin = true;
|
||||
@@ -22,7 +22,7 @@ public class Weapons implements ContentList {
|
||||
setAmmo(AmmoTypes.bulletLead);
|
||||
}};
|
||||
|
||||
missiles = new Weapon("missiles") {{
|
||||
missiles = new Weapon("missiles"){{
|
||||
length = 1.5f;
|
||||
reload = 40f;
|
||||
shots = 2;
|
||||
@@ -33,7 +33,7 @@ public class Weapons implements ContentList {
|
||||
setAmmo(AmmoTypes.weaponMissile);
|
||||
}};
|
||||
|
||||
chainBlaster = new Weapon("chain-blaster") {{
|
||||
chainBlaster = new Weapon("chain-blaster"){{
|
||||
length = 1.5f;
|
||||
reload = 30f;
|
||||
roundrobin = true;
|
||||
@@ -41,7 +41,7 @@ public class Weapons implements ContentList {
|
||||
setAmmo(AmmoTypes.bulletLead, AmmoTypes.bulletCarbide, AmmoTypes.bulletTungsten, AmmoTypes.bulletSilicon, AmmoTypes.bulletThorium);
|
||||
}};
|
||||
|
||||
shockgun = new Weapon("shockgun") {{
|
||||
shockgun = new Weapon("shockgun"){{
|
||||
length = 1f;
|
||||
reload = 50f;
|
||||
roundrobin = true;
|
||||
@@ -53,7 +53,7 @@ public class Weapons implements ContentList {
|
||||
setAmmo(AmmoTypes.shotgunTungsten);
|
||||
}};
|
||||
|
||||
flakgun = new Weapon("flakgun") {{
|
||||
flakgun = new Weapon("flakgun"){{
|
||||
length = 1f;
|
||||
reload = 70f;
|
||||
roundrobin = true;
|
||||
@@ -65,7 +65,7 @@ public class Weapons implements ContentList {
|
||||
setAmmo(AmmoTypes.shellCarbide);
|
||||
}};
|
||||
|
||||
flamethrower = new Weapon("flamethrower") {{
|
||||
flamethrower = new Weapon("flamethrower"){{
|
||||
length = 1f;
|
||||
reload = 14f;
|
||||
roundrobin = true;
|
||||
@@ -74,7 +74,7 @@ public class Weapons implements ContentList {
|
||||
setAmmo(AmmoTypes.flamerThermite);
|
||||
}};
|
||||
|
||||
sapper = new Weapon("sapper") {{
|
||||
sapper = new Weapon("sapper"){{
|
||||
length = 1.5f;
|
||||
reload = 12f;
|
||||
roundrobin = true;
|
||||
@@ -82,7 +82,7 @@ public class Weapons implements ContentList {
|
||||
setAmmo(AmmoTypes.bulletCarbide);
|
||||
}};
|
||||
|
||||
swarmer = new Weapon("swarmer") {{
|
||||
swarmer = new Weapon("swarmer"){{
|
||||
length = 1.5f;
|
||||
reload = 10f;
|
||||
roundrobin = true;
|
||||
@@ -90,7 +90,7 @@ public class Weapons implements ContentList {
|
||||
setAmmo(AmmoTypes.bulletPyratite);
|
||||
}};
|
||||
|
||||
bomber = new Weapon("bomber") {{
|
||||
bomber = new Weapon("bomber"){{
|
||||
length = 0f;
|
||||
width = 2f;
|
||||
reload = 5f;
|
||||
@@ -103,7 +103,7 @@ public class Weapons implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array<? extends Content> getAll() {
|
||||
public Array<? extends Content> getAll(){
|
||||
return Upgrade.all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@ import io.anuke.mindustry.game.Content;
|
||||
import io.anuke.mindustry.type.ContentList;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
|
||||
public abstract class BlockList implements ContentList {
|
||||
public abstract class BlockList implements ContentList{
|
||||
|
||||
@Override
|
||||
public Array<? extends Content> getAll() {
|
||||
public Array<? extends Content> getAll(){
|
||||
return Block.all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,26 +15,31 @@ public class Blocks extends BlockList implements ContentList{
|
||||
public static Block air, spawn, blockpart, space, metalfloor, deepwater, water, lava, oil, stone, blackstone, dirt, sand, ice, snow, grass, shrub, rock, icerock, blackrock;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
air = new Floor("air") {
|
||||
public void load(){
|
||||
air = new Floor("air"){
|
||||
{
|
||||
blend = false;
|
||||
}
|
||||
|
||||
//don't draw
|
||||
public void draw(Tile tile) {}
|
||||
public void load() {}
|
||||
public void init() {}
|
||||
public void draw(Tile tile){
|
||||
}
|
||||
|
||||
public void load(){
|
||||
}
|
||||
|
||||
public void init(){
|
||||
}
|
||||
};
|
||||
|
||||
blockpart = new BlockPart();
|
||||
|
||||
for(int i = 1; i <= 6; i ++){
|
||||
for(int i = 1; i <= 6; i++){
|
||||
new BuildBlock("build" + i);
|
||||
}
|
||||
|
||||
space = new Floor("space") {{
|
||||
space = new Floor("space"){{
|
||||
placeableOn = false;
|
||||
variants = 0;
|
||||
cacheLayer = CacheLayer.space;
|
||||
@@ -43,11 +48,11 @@ public class Blocks extends BlockList implements ContentList{
|
||||
minimapColor = Color.valueOf("000001");
|
||||
}};
|
||||
|
||||
metalfloor = new Floor("metalfloor") {{
|
||||
metalfloor = new Floor("metalfloor"){{
|
||||
variants = 6;
|
||||
}};
|
||||
|
||||
deepwater = new Floor("deepwater") {{
|
||||
deepwater = new Floor("deepwater"){{
|
||||
liquidColor = Color.valueOf("546bb3");
|
||||
speedMultiplier = 0.2f;
|
||||
variants = 0;
|
||||
@@ -60,7 +65,7 @@ public class Blocks extends BlockList implements ContentList{
|
||||
minimapColor = Color.valueOf("465a96");
|
||||
}};
|
||||
|
||||
water = new Floor("water") {{
|
||||
water = new Floor("water"){{
|
||||
liquidColor = Color.valueOf("546bb3");
|
||||
speedMultiplier = 0.5f;
|
||||
variants = 0;
|
||||
@@ -72,7 +77,7 @@ public class Blocks extends BlockList implements ContentList{
|
||||
minimapColor = Color.valueOf("506eb4");
|
||||
}};
|
||||
|
||||
lava = new Floor("lava") {{
|
||||
lava = new Floor("lava"){{
|
||||
liquidColor = Color.valueOf("ed5334");
|
||||
speedMultiplier = 0.2f;
|
||||
damageTaken = 0.5f;
|
||||
@@ -85,7 +90,7 @@ public class Blocks extends BlockList implements ContentList{
|
||||
minimapColor = Color.valueOf("ed5334");
|
||||
}};
|
||||
|
||||
oil = new Floor("oil") {{
|
||||
oil = new Floor("oil"){{
|
||||
liquidColor = Color.valueOf("292929");
|
||||
status = StatusEffects.tarred;
|
||||
statusIntensity = 1f;
|
||||
@@ -97,7 +102,7 @@ public class Blocks extends BlockList implements ContentList{
|
||||
minimapColor = Color.valueOf("292929");
|
||||
}};
|
||||
|
||||
stone = new Floor("stone") {{
|
||||
stone = new Floor("stone"){{
|
||||
hasOres = true;
|
||||
drops = new ItemStack(Items.stone, 1);
|
||||
blends = block -> block != this && !(block instanceof Ore);
|
||||
@@ -105,7 +110,7 @@ public class Blocks extends BlockList implements ContentList{
|
||||
playerUnmineable = true;
|
||||
}};
|
||||
|
||||
blackstone = new Floor("blackstone") {{
|
||||
blackstone = new Floor("blackstone"){{
|
||||
drops = new ItemStack(Items.stone, 1);
|
||||
minimapColor = Color.valueOf("252525");
|
||||
playerUnmineable = true;
|
||||
@@ -115,14 +120,14 @@ public class Blocks extends BlockList implements ContentList{
|
||||
minimapColor = Color.valueOf("6e501e");
|
||||
}};
|
||||
|
||||
sand = new Floor("sand") {{
|
||||
sand = new Floor("sand"){{
|
||||
drops = new ItemStack(Items.sand, 1);
|
||||
minimapColor = Color.valueOf("988a67");
|
||||
hasOres = true;
|
||||
playerUnmineable = true;
|
||||
}};
|
||||
|
||||
ice = new Floor("ice") {{
|
||||
ice = new Floor("ice"){{
|
||||
dragMultiplier = 0.3f;
|
||||
speedMultiplier = 0.4f;
|
||||
minimapColor = Color.valueOf("c4e3e7");
|
||||
@@ -143,19 +148,16 @@ public class Blocks extends BlockList implements ContentList{
|
||||
shadow = "shrubshadow";
|
||||
}};
|
||||
|
||||
rock = new Rock("rock") {{
|
||||
rock = new Rock("rock"){{
|
||||
variants = 2;
|
||||
varyShadow = true;
|
||||
}};
|
||||
|
||||
icerock = new Rock("icerock") {{
|
||||
icerock = new Rock("icerock"){{
|
||||
variants = 2;
|
||||
varyShadow = true;
|
||||
}};
|
||||
|
||||
blackrock = new Rock("blackrock") {{
|
||||
blackrock = new Rock("blackrock"){{
|
||||
variants = 1;
|
||||
varyShadow = true;
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,55 +10,54 @@ import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.blocks.production.*;
|
||||
|
||||
public class CraftingBlocks extends BlockList implements ContentList {
|
||||
public class CraftingBlocks extends BlockList implements ContentList{
|
||||
public static Block smelter, arcsmelter, siliconsmelter, plastaniumCompressor, phaseWeaver, alloysmelter, alloyfuser,
|
||||
pyratiteMixer, blastMixer,
|
||||
cryofluidmixer, melter, separator, centrifuge, biomatterCompressor, pulverizer, oilRefinery, solidifier, incinerator;
|
||||
cryofluidmixer, melter, separator, centrifuge, biomatterCompressor, pulverizer, solidifier, incinerator;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
smelter = new Smelter("smelter") {{
|
||||
public void load(){
|
||||
smelter = new Smelter("smelter"){{
|
||||
health = 70;
|
||||
inputs = new ItemStack[]{new ItemStack(Items.tungsten, 3)};
|
||||
fuel = Items.coal;
|
||||
result = Items.carbide;
|
||||
craftTime = 45f;
|
||||
burnDuration = 35f;
|
||||
useFlux = true;
|
||||
|
||||
consumes.items(new ItemStack[]{new ItemStack(Items.tungsten, 3)});
|
||||
consumes.item(Items.coal);
|
||||
}};
|
||||
|
||||
arcsmelter = new PowerSmelter("arc-smelter") {{
|
||||
arcsmelter = new PowerSmelter("arc-smelter"){{
|
||||
health = 90;
|
||||
craftEffect = BlockFx.smeltsmoke;
|
||||
inputs = new ItemStack[]{new ItemStack(Items.coal, 1), new ItemStack(Items.tungsten, 2)};
|
||||
result = Items.carbide;
|
||||
powerUse = 0.1f;
|
||||
craftTime = 30f;
|
||||
size = 2;
|
||||
|
||||
useFlux = true;
|
||||
fluxNeeded = 2;
|
||||
|
||||
consumes.items(new ItemStack[]{new ItemStack(Items.coal, 1), new ItemStack(Items.tungsten, 2)});
|
||||
consumes.power(0.1f);
|
||||
}};
|
||||
|
||||
siliconsmelter = new PowerSmelter("silicon-smelter") {{
|
||||
siliconsmelter = new PowerSmelter("silicon-smelter"){{
|
||||
health = 90;
|
||||
craftEffect = BlockFx.smeltsmoke;
|
||||
inputs = new ItemStack[]{new ItemStack(Items.coal, 1), new ItemStack(Items.sand, 2)};
|
||||
result = Items.silicon;
|
||||
powerUse = 0.05f;
|
||||
craftTime = 40f;
|
||||
size = 2;
|
||||
hasLiquids = false;
|
||||
flameColor = Color.valueOf("ffef99");
|
||||
|
||||
consumes.items(new ItemStack[]{new ItemStack(Items.coal, 1), new ItemStack(Items.sand, 2)});
|
||||
consumes.power(0.05f);
|
||||
}};
|
||||
|
||||
plastaniumCompressor = new PlastaniumCompressor("plastanium-compressor") {{
|
||||
inputLiquid = Liquids.oil;
|
||||
inputItem = new ItemStack(Items.titanium, 2);
|
||||
plastaniumCompressor = new PlastaniumCompressor("plastanium-compressor"){{
|
||||
hasItems = true;
|
||||
liquidUse = 0.3f;
|
||||
liquidCapacity = 60f;
|
||||
powerUse = 0.5f;
|
||||
craftTime = 80f;
|
||||
output = Items.plastanium;
|
||||
itemCapacity = 30;
|
||||
@@ -67,94 +66,103 @@ public class CraftingBlocks extends BlockList implements ContentList {
|
||||
hasPower = hasLiquids = true;
|
||||
craftEffect = BlockFx.formsmoke;
|
||||
updateEffect = BlockFx.plasticburn;
|
||||
|
||||
consumes.liquid(Liquids.oil, 0.3f);
|
||||
consumes.power(0.4f);
|
||||
consumes.item(Items.titanium, 2);
|
||||
}};
|
||||
|
||||
phaseWeaver = new PhaseWeaver("phase-weaver") {{
|
||||
phaseWeaver = new PhaseWeaver("phase-weaver"){{
|
||||
health = 90;
|
||||
craftEffect = BlockFx.smeltsmoke;
|
||||
inputs = new ItemStack[]{new ItemStack(Items.thorium, 4), new ItemStack(Items.sand, 10)};
|
||||
result = Items.phasematter;
|
||||
powerUse = 0.4f;
|
||||
craftTime = 120f;
|
||||
size = 2;
|
||||
|
||||
consumes.items(new ItemStack[]{new ItemStack(Items.thorium, 4), new ItemStack(Items.sand, 10)});
|
||||
consumes.power(0.5f);
|
||||
}};
|
||||
|
||||
alloysmelter = new PowerSmelter("alloy-smelter") {{
|
||||
alloysmelter = new PowerSmelter("alloy-smelter"){{
|
||||
health = 90;
|
||||
craftEffect = BlockFx.smeltsmoke;
|
||||
inputs = new ItemStack[]{new ItemStack(Items.titanium, 2), new ItemStack(Items.lead, 4), new ItemStack(Items.silicon, 3), new ItemStack(Items.plastanium, 2)};
|
||||
result = Items.surgealloy;
|
||||
powerUse = 0.3f;
|
||||
craftTime = 50f;
|
||||
size = 2;
|
||||
|
||||
useFlux = true;
|
||||
fluxNeeded = 4;
|
||||
|
||||
consumes.power(0.3f);
|
||||
consumes.items(new ItemStack[]{new ItemStack(Items.titanium, 2), new ItemStack(Items.lead, 4), new ItemStack(Items.silicon, 3), new ItemStack(Items.plastanium, 2)});
|
||||
}};
|
||||
|
||||
alloyfuser = new PowerSmelter("alloy-fuser") {{
|
||||
alloyfuser = new PowerSmelter("alloy-fuser"){{
|
||||
health = 90;
|
||||
craftEffect = BlockFx.smeltsmoke;
|
||||
inputs = new ItemStack[]{new ItemStack(Items.titanium, 3), new ItemStack(Items.lead, 4), new ItemStack(Items.silicon, 3), new ItemStack(Items.plastanium, 2)};
|
||||
result = Items.surgealloy;
|
||||
powerUse = 0.4f;
|
||||
craftTime = 30f;
|
||||
size = 3;
|
||||
|
||||
useFlux = true;
|
||||
fluxNeeded = 4;
|
||||
|
||||
consumes.items(new ItemStack[]{new ItemStack(Items.titanium, 3), new ItemStack(Items.lead, 4), new ItemStack(Items.silicon, 3), new ItemStack(Items.plastanium, 2)});
|
||||
consumes.power(0.4f);
|
||||
}};
|
||||
|
||||
cryofluidmixer = new LiquidMixer("cryofluidmixer") {{
|
||||
cryofluidmixer = new LiquidMixer("cryofluidmixer"){{
|
||||
health = 200;
|
||||
inputLiquid = Liquids.water;
|
||||
outputLiquid = Liquids.cryofluid;
|
||||
inputItem = Items.titanium;
|
||||
liquidPerItem = 50f;
|
||||
itemCapacity = 50;
|
||||
powerUse = 0.1f;
|
||||
size = 2;
|
||||
hasPower = true;
|
||||
|
||||
consumes.power(0.1f);
|
||||
consumes.item(Items.titanium);
|
||||
consumes.liquid(Liquids.water, 0.3f);
|
||||
}};
|
||||
|
||||
blastMixer = new GenericCrafter("blast-mixer") {{
|
||||
blastMixer = new GenericCrafter("blast-mixer"){{
|
||||
itemCapacity = 20;
|
||||
hasItems = true;
|
||||
hasPower = true;
|
||||
inputLiquid = Liquids.oil;
|
||||
liquidUse = 0.05f;
|
||||
inputItem = new ItemStack(Items.pyratite, 1);
|
||||
hasLiquids = true;
|
||||
output = Items.blastCompound;
|
||||
powerUse = 0.04f;
|
||||
|
||||
size = 2;
|
||||
|
||||
consumes.liquid(Liquids.oil, 0.05f);
|
||||
consumes.item(Items.pyratite, 1);
|
||||
consumes.power(0.04f);
|
||||
}};
|
||||
|
||||
pyratiteMixer = new PowerSmelter("pyratite-mixer") {{
|
||||
pyratiteMixer = new PowerSmelter("pyratite-mixer"){{
|
||||
flameColor = Color.CLEAR;
|
||||
itemCapacity = 20;
|
||||
hasItems = true;
|
||||
hasPower = true;
|
||||
inputs = new ItemStack[]{new ItemStack(Items.coal, 1), new ItemStack(Items.lead, 2), new ItemStack(Items.sand, 2)};
|
||||
result = Items.pyratite;
|
||||
powerUse = 0.02f;
|
||||
|
||||
size = 2;
|
||||
|
||||
consumes.power(0.02f);
|
||||
consumes.items(new ItemStack[]{new ItemStack(Items.coal, 1), new ItemStack(Items.lead, 2), new ItemStack(Items.sand, 2)});
|
||||
}};
|
||||
|
||||
melter = new PowerCrafter("melter") {{
|
||||
melter = new PowerCrafter("melter"){{
|
||||
health = 200;
|
||||
outputLiquid = Liquids.lava;
|
||||
outputLiquidAmount = 0.05f;
|
||||
input = new ItemStack(Items.stone, 1);
|
||||
outputLiquidAmount = 0.75f;
|
||||
itemCapacity = 50;
|
||||
craftTime = 10f;
|
||||
powerUse = 0.1f;
|
||||
hasLiquids = hasPower = true;
|
||||
|
||||
consumes.power(0.1f);
|
||||
consumes.item(Items.stone, 2);
|
||||
}};
|
||||
|
||||
separator = new Separator("separator") {{
|
||||
liquid = Liquids.water;
|
||||
item = Items.stone;
|
||||
separator = new Separator("separator"){{
|
||||
results = new Item[]{
|
||||
null, null, null, null, null, null, null, null, null, null,
|
||||
Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand,
|
||||
@@ -164,15 +172,15 @@ public class CraftingBlocks extends BlockList implements ContentList {
|
||||
Items.coal, Items.coal,
|
||||
Items.titanium
|
||||
};
|
||||
liquidUse = 0.2f;
|
||||
filterTime = 40f;
|
||||
itemCapacity = 40;
|
||||
health = 50;
|
||||
|
||||
consumes.item(Items.stone, 2);
|
||||
consumes.liquid(Liquids.water, 0.3f);
|
||||
}};
|
||||
|
||||
centrifuge = new Separator("centrifuge") {{
|
||||
liquid = Liquids.water;
|
||||
item = Items.stone;
|
||||
centrifuge = new Separator("centrifuge"){{
|
||||
results = new Item[]{
|
||||
null, null, null, null, null, null, null, null, null, null, null, null, null,
|
||||
Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand, Items.sand,
|
||||
@@ -184,9 +192,7 @@ public class CraftingBlocks extends BlockList implements ContentList {
|
||||
Items.thorium,
|
||||
};
|
||||
|
||||
liquidUse = 0.3f;
|
||||
hasPower = true;
|
||||
powerUse = 0.2f;
|
||||
filterTime = 15f;
|
||||
itemCapacity = 60;
|
||||
health = 50 * 4;
|
||||
@@ -195,56 +201,52 @@ public class CraftingBlocks extends BlockList implements ContentList {
|
||||
spinnerThickness = 1.5f;
|
||||
spinnerSpeed = 3f;
|
||||
size = 2;
|
||||
|
||||
consumes.item(Items.stone, 2);
|
||||
consumes.power(0.2f);
|
||||
consumes.liquid(Liquids.water, 0.5f);
|
||||
}};
|
||||
|
||||
biomatterCompressor = new Compressor("biomattercompressor") {{
|
||||
input = new ItemStack(Items.biomatter, 1);
|
||||
biomatterCompressor = new Compressor("biomattercompressor"){{
|
||||
liquidCapacity = 60f;
|
||||
itemCapacity = 50;
|
||||
powerUse = 0.06f;
|
||||
craftTime = 25f;
|
||||
outputLiquid = Liquids.oil;
|
||||
outputLiquidAmount = 0.1f;
|
||||
outputLiquidAmount = 0.14f;
|
||||
size = 2;
|
||||
health = 320;
|
||||
hasLiquids = true;
|
||||
|
||||
consumes.item(Items.biomatter, 1);
|
||||
consumes.power(0.06f);
|
||||
}};
|
||||
|
||||
pulverizer = new Pulverizer("pulverizer") {{
|
||||
inputItem = new ItemStack(Items.stone, 2);
|
||||
pulverizer = new Pulverizer("pulverizer"){{
|
||||
itemCapacity = 40;
|
||||
powerUse = 0.2f;
|
||||
output = Items.sand;
|
||||
health = 80;
|
||||
craftEffect = BlockFx.pulverize;
|
||||
craftTime = 60f;
|
||||
updateEffect = BlockFx.pulverizeSmall;
|
||||
hasItems = hasPower = true;
|
||||
|
||||
consumes.item(Items.stone, 2);
|
||||
consumes.power(0.2f);
|
||||
}};
|
||||
|
||||
oilRefinery = new GenericCrafter("oilrefinery") {{
|
||||
inputLiquid = Liquids.oil;
|
||||
powerUse = 0.05f;
|
||||
liquidUse = 0.1f;
|
||||
liquidCapacity = 56f;
|
||||
output = Items.coal;
|
||||
health = 80;
|
||||
craftEffect = BlockFx.purifyoil;
|
||||
hasItems = hasLiquids = hasPower = true;
|
||||
}};
|
||||
|
||||
solidifier = new GenericCrafter("solidifer") {{
|
||||
inputLiquid = Liquids.lava;
|
||||
liquidUse = 1f;
|
||||
solidifier = new GenericCrafter("solidifer"){{
|
||||
liquidCapacity = 21f;
|
||||
craftTime = 14;
|
||||
output = Items.stone;
|
||||
itemCapacity = 20;
|
||||
health = 80;
|
||||
craftEffect = BlockFx.purifystone;
|
||||
hasLiquids = hasItems = true;
|
||||
|
||||
consumes.liquid(Liquids.lava, 1f);
|
||||
}};
|
||||
|
||||
incinerator = new Incinerator("incinerator") {{
|
||||
incinerator = new Incinerator("incinerator"){{
|
||||
health = 90;
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -28,45 +28,52 @@ import java.io.IOException;
|
||||
public class DebugBlocks extends BlockList implements ContentList{
|
||||
public static Block powerVoid, powerInfinite, itemSource, liquidSource, itemVoid;
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.both, in = In.blocks, forward = true)
|
||||
public static void setLiquidSourceLiquid(Player player, Tile tile, Liquid liquid){
|
||||
LiquidSourceEntity entity = tile.entity();
|
||||
entity.source = liquid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
powerVoid = new PowerBlock("powervoid") {
|
||||
public void load(){
|
||||
powerVoid = new PowerBlock("powervoid"){
|
||||
{
|
||||
powerCapacity = Float.MAX_VALUE;
|
||||
}
|
||||
};
|
||||
|
||||
powerInfinite = new PowerNode("powerinfinite") {
|
||||
powerInfinite = new PowerNode("powerinfinite"){
|
||||
{
|
||||
powerCapacity = 10000f;
|
||||
powerSpeed = 100f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Tile tile) {
|
||||
public void update(Tile tile){
|
||||
super.update(tile);
|
||||
tile.entity.power.amount = powerCapacity;
|
||||
}
|
||||
};
|
||||
|
||||
itemSource = new Sorter("itemsource") {
|
||||
itemSource = new Sorter("itemsource"){
|
||||
{
|
||||
hasItems = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Tile tile) {
|
||||
public void update(Tile tile){
|
||||
SorterEntity entity = tile.entity();
|
||||
entity.items.items[entity.sortItem.id] = 1;
|
||||
entity.items.set(entity.sortItem, 1);
|
||||
tryDump(tile, entity.sortItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptItem(Item item, Tile tile, Tile source) {
|
||||
public boolean acceptItem(Item item, Tile tile, Tile source){
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
liquidSource = new Block("liquidsource") {
|
||||
liquidSource = new Block("liquidsource"){
|
||||
{
|
||||
update = true;
|
||||
solid = true;
|
||||
@@ -76,16 +83,15 @@ public class DebugBlocks extends BlockList implements ContentList{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Tile tile) {
|
||||
public void update(Tile tile){
|
||||
LiquidSourceEntity entity = tile.entity();
|
||||
|
||||
tile.entity.liquids.amount = liquidCapacity;
|
||||
tile.entity.liquids.liquid = entity.source;
|
||||
tryDumpLiquid(tile);
|
||||
tile.entity.liquids.add(entity.source, liquidCapacity);
|
||||
tryDumpLiquid(tile, entity.source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Tile tile) {
|
||||
public void draw(Tile tile){
|
||||
super.draw(tile);
|
||||
|
||||
LiquidSourceEntity entity = tile.entity();
|
||||
@@ -96,7 +102,7 @@ public class DebugBlocks extends BlockList implements ContentList{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildTable(Tile tile, Table table) {
|
||||
public void buildTable(Tile tile, Table table){
|
||||
LiquidSourceEntity entity = tile.entity();
|
||||
|
||||
Array<Liquid> items = Liquid.all();
|
||||
@@ -104,8 +110,8 @@ public class DebugBlocks extends BlockList implements ContentList{
|
||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||
Table cont = new Table();
|
||||
|
||||
for (int i = 0; i < items.size; i++) {
|
||||
if (i == 0) continue;
|
||||
for(int i = 0; i < items.size; i++){
|
||||
if(i == 0) continue;
|
||||
final int f = i;
|
||||
ImageButton button = cont.addImageButton("white", "toggle", 24, () -> {
|
||||
CallBlocks.setLiquidSourceLiquid(null, tile, items.get(f));
|
||||
@@ -113,7 +119,7 @@ public class DebugBlocks extends BlockList implements ContentList{
|
||||
button.getStyle().imageUpColor = items.get(i).color;
|
||||
button.setChecked(entity.source.id == f);
|
||||
|
||||
if (i % 4 == 3) {
|
||||
if(i % 4 == 3){
|
||||
cont.row();
|
||||
}
|
||||
}
|
||||
@@ -122,43 +128,37 @@ public class DebugBlocks extends BlockList implements ContentList{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity getEntity() {
|
||||
public TileEntity getEntity(){
|
||||
return new LiquidSourceEntity();
|
||||
}
|
||||
};
|
||||
|
||||
itemVoid = new Block("itemvoid") {
|
||||
itemVoid = new Block("itemvoid"){
|
||||
{
|
||||
update = solid = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleItem(Item item, Tile tile, Tile source) {
|
||||
public void handleItem(Item item, Tile tile, Tile source){
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptItem(Item item, Tile tile, Tile source) {
|
||||
public boolean acceptItem(Item item, Tile tile, Tile source){
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.both, in = In.blocks, forward = true)
|
||||
public static void setLiquidSourceLiquid(Player player, Tile tile, Liquid liquid){
|
||||
LiquidSourceEntity entity = tile.entity();
|
||||
entity.source = liquid;
|
||||
}
|
||||
|
||||
class LiquidSourceEntity extends TileEntity {
|
||||
class LiquidSourceEntity extends TileEntity{
|
||||
public Liquid source = Liquids.water;
|
||||
|
||||
@Override
|
||||
public void write(DataOutputStream stream) throws IOException {
|
||||
public void write(DataOutputStream stream) throws IOException{
|
||||
stream.writeByte(source.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInputStream stream) throws IOException {
|
||||
public void read(DataInputStream stream) throws IOException{
|
||||
source = Liquid.getByID(stream.readByte());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,65 +8,65 @@ import io.anuke.mindustry.world.blocks.defense.DeflectorWall;
|
||||
import io.anuke.mindustry.world.blocks.defense.Door;
|
||||
import io.anuke.mindustry.world.blocks.defense.PhaseWall;
|
||||
|
||||
public class DefenseBlocks extends BlockList implements ContentList {
|
||||
public class DefenseBlocks extends BlockList implements ContentList{
|
||||
public static Block tungstenWall, tungstenWallLarge, carbideWall, carbideWallLarge, thoriumWall, thoriumWallLarge, door, doorLarge, deflectorwall, deflectorwalllarge,
|
||||
phasewall, phasewalllarge;
|
||||
phasewall, phasewalllarge;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
int wallHealthMultiplier = 4;
|
||||
|
||||
tungstenWall = new Wall("tungsten-wall") {{
|
||||
tungstenWall = new Wall("tungsten-wall"){{
|
||||
health = 80 * wallHealthMultiplier;
|
||||
}};
|
||||
|
||||
tungstenWallLarge = new Wall("tungsten-wall-large") {{
|
||||
tungstenWallLarge = new Wall("tungsten-wall-large"){{
|
||||
health = 80 * 4 * wallHealthMultiplier;
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
carbideWall = new Wall("carbide-wall") {{
|
||||
carbideWall = new Wall("carbide-wall"){{
|
||||
health = 110 * wallHealthMultiplier;
|
||||
}};
|
||||
|
||||
carbideWallLarge = new Wall("carbide-wall-large") {{
|
||||
health = 110 * wallHealthMultiplier*4;
|
||||
carbideWallLarge = new Wall("carbide-wall-large"){{
|
||||
health = 110 * wallHealthMultiplier * 4;
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
thoriumWall = new Wall("thorium-wall") {{
|
||||
health = 110 * wallHealthMultiplier;
|
||||
thoriumWall = new Wall("thorium-wall"){{
|
||||
health = 200 * wallHealthMultiplier;
|
||||
}};
|
||||
|
||||
thoriumWallLarge = new Wall("thorium-wall-large") {{
|
||||
health = 110 * wallHealthMultiplier*4;
|
||||
thoriumWallLarge = new Wall("thorium-wall-large"){{
|
||||
health = 200 * wallHealthMultiplier * 4;
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
deflectorwall = new DeflectorWall("deflector-wall") {{
|
||||
deflectorwall = new DeflectorWall("deflector-wall"){{
|
||||
health = 150 * wallHealthMultiplier;
|
||||
}};
|
||||
|
||||
deflectorwalllarge = new DeflectorWall("deflector-wall-large") {{
|
||||
deflectorwalllarge = new DeflectorWall("deflector-wall-large"){{
|
||||
health = 150 * 4 * wallHealthMultiplier;
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
phasewall = new PhaseWall("phase-wall") {{
|
||||
phasewall = new PhaseWall("phase-wall"){{
|
||||
health = 150 * wallHealthMultiplier;
|
||||
}};
|
||||
|
||||
phasewalllarge = new PhaseWall("phase-wall-large") {{
|
||||
phasewalllarge = new PhaseWall("phase-wall-large"){{
|
||||
health = 150 * 4 * wallHealthMultiplier;
|
||||
size = 2;
|
||||
regenSpeed = 0.5f;
|
||||
}};
|
||||
|
||||
door = new Door("door") {{
|
||||
door = new Door("door"){{
|
||||
health = 100 * wallHealthMultiplier;
|
||||
}};
|
||||
|
||||
doorLarge = new Door("door-large") {{
|
||||
doorLarge = new Door("door-large"){{
|
||||
openfx = BlockFx.dooropenlarge;
|
||||
closefx = BlockFx.doorcloselarge;
|
||||
health = 100 * 4 * wallHealthMultiplier;
|
||||
|
||||
@@ -5,53 +5,51 @@ import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.blocks.distribution.*;
|
||||
|
||||
public class DistributionBlocks extends BlockList implements ContentList{
|
||||
public static Block conveyor, titaniumconveyor, router, multiplexer, junction,
|
||||
bridgeConveyor, phaseConveyor, sorter, splitter, overflowGate, massDriver;
|
||||
public static Block conveyor, titaniumconveyor, distributor, junction,
|
||||
bridgeConveyor, phaseConveyor, sorter, splitter, overflowGate, massDriver;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
@Override
|
||||
public void load(){
|
||||
|
||||
conveyor = new Conveyor("conveyor") {{
|
||||
health = 45;
|
||||
speed = 0.03f;
|
||||
}};
|
||||
conveyor = new Conveyor("conveyor"){{
|
||||
health = 45;
|
||||
speed = 0.03f;
|
||||
}};
|
||||
|
||||
titaniumconveyor = new Conveyor("titanium-conveyor") {{
|
||||
health = 65;
|
||||
speed = 0.07f;
|
||||
}};
|
||||
titaniumconveyor = new Conveyor("titanium-conveyor"){{
|
||||
health = 65;
|
||||
speed = 0.07f;
|
||||
}};
|
||||
|
||||
router = new Router("router");
|
||||
junction = new Junction("junction"){{
|
||||
speed = 26;
|
||||
capacity = 32;
|
||||
}};
|
||||
|
||||
multiplexer = new Router("multiplexer") {{
|
||||
size = 2;
|
||||
itemCapacity = 80;
|
||||
}};
|
||||
bridgeConveyor = new BufferedItemBridge("bridge-conveyor"){{
|
||||
range = 3;
|
||||
}};
|
||||
|
||||
junction = new Junction("junction") {{
|
||||
speed = 26;
|
||||
capacity = 32;
|
||||
}};
|
||||
phaseConveyor = new ItemBridge("phase-conveyor"){{
|
||||
range = 7;
|
||||
hasPower = false;
|
||||
consumes.power(0.05f);
|
||||
}};
|
||||
|
||||
bridgeConveyor = new BufferedItemBridge("bridge-conveyor") {{
|
||||
range = 3;
|
||||
hasPower = false;
|
||||
}};
|
||||
sorter = new Sorter("sorter");
|
||||
|
||||
phaseConveyor = new ItemBridge("phase-conveyor") {{
|
||||
range = 7;
|
||||
}};
|
||||
splitter = new Splitter("splitter");
|
||||
|
||||
sorter = new Sorter("sorter");
|
||||
distributor = new Splitter("distributor"){{
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
splitter = new Splitter("splitter");
|
||||
overflowGate = new OverflowGate("overflow-gate");
|
||||
|
||||
overflowGate = new OverflowGate("overflow-gate");
|
||||
|
||||
massDriver = new MassDriver("mass-driver"){{
|
||||
size = 3;
|
||||
itemCapacity = 80;
|
||||
range = 300f;
|
||||
}};
|
||||
}
|
||||
massDriver = new MassDriver("mass-driver"){{
|
||||
size = 3;
|
||||
itemCapacity = 80;
|
||||
range = 300f;
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,46 +9,47 @@ public class LiquidBlocks extends BlockList implements ContentList{
|
||||
public static Block mechanicalPump, rotaryPump, thermalPump, conduit, pulseConduit, liquidRouter, liquidtank, liquidJunction, bridgeConduit, phaseConduit;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
mechanicalPump = new Pump("mechanical-pump") {{
|
||||
mechanicalPump = new Pump("mechanical-pump"){{
|
||||
shadow = "shadow-round-1";
|
||||
pumpAmount = 0.1f;
|
||||
tier = 0;
|
||||
}};
|
||||
|
||||
rotaryPump = new Pump("rotary-pump") {{
|
||||
rotaryPump = new Pump("rotary-pump"){{
|
||||
shadow = "shadow-rounded-2";
|
||||
pumpAmount = 0.25f;
|
||||
powerUse = 0.015f;
|
||||
consumes.power(0.015f);
|
||||
liquidCapacity = 30f;
|
||||
hasPower = true;
|
||||
size = 2;
|
||||
tier = 1;
|
||||
}};
|
||||
|
||||
thermalPump = new Pump("thermal-pump") {{
|
||||
thermalPump = new Pump("thermal-pump"){{
|
||||
pumpAmount = 0.3f;
|
||||
powerUse = 0.02f;
|
||||
consumes.power(0.05f);
|
||||
liquidCapacity = 40f;
|
||||
size = 2;
|
||||
tier = 2;
|
||||
}};
|
||||
|
||||
conduit = new Conduit("conduit") {{
|
||||
conduit = new Conduit("conduit"){{
|
||||
health = 45;
|
||||
}};
|
||||
|
||||
pulseConduit = new Conduit("pulse-conduit") {{
|
||||
pulseConduit = new Conduit("pulse-conduit"){{
|
||||
liquidCapacity = 16f;
|
||||
liquidFlowFactor = 4.9f;
|
||||
health = 90;
|
||||
}};
|
||||
|
||||
liquidRouter = new LiquidRouter("liquid-router") {{
|
||||
liquidRouter = new LiquidRouter("liquid-router"){{
|
||||
liquidCapacity = 40f;
|
||||
}};
|
||||
|
||||
liquidtank = new LiquidRouter("liquid-tank") {{
|
||||
liquidtank = new LiquidRouter("liquid-tank"){{
|
||||
size = 3;
|
||||
liquidCapacity = 1500f;
|
||||
health = 500;
|
||||
@@ -56,13 +57,15 @@ public class LiquidBlocks extends BlockList implements ContentList{
|
||||
|
||||
liquidJunction = new LiquidJunction("liquid-junction");
|
||||
|
||||
bridgeConduit = new LiquidExtendingBridge("bridge-conduit") {{
|
||||
bridgeConduit = new LiquidExtendingBridge("bridge-conduit"){{
|
||||
range = 3;
|
||||
hasPower = false;
|
||||
}};
|
||||
|
||||
phaseConduit = new LiquidBridge("phase-conduit") {{
|
||||
phaseConduit = new LiquidBridge("phase-conduit"){{
|
||||
range = 7;
|
||||
hasPower = false;
|
||||
consumes.power(0.05f);
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,11 +7,18 @@ import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.blocks.Floor;
|
||||
import io.anuke.mindustry.world.blocks.OreBlock;
|
||||
|
||||
public class OreBlocks extends BlockList {
|
||||
public class OreBlocks extends BlockList{
|
||||
private static final ObjectMap<Item, ObjectMap<Block, Block>> oreBlockMap = new ObjectMap<>();
|
||||
|
||||
public static Block get(Block floor, Item item){
|
||||
if(!oreBlockMap.containsKey(item)) throw new IllegalArgumentException("Item '" + item + "' is not an ore!");
|
||||
if(!oreBlockMap.get(item).containsKey(floor))
|
||||
throw new IllegalArgumentException("Block '" + floor.name + "' does not support ores!");
|
||||
return oreBlockMap.get(item).get(floor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
Item[] ores = {Items.tungsten, Items.lead, Items.coal, Items.titanium, Items.thorium};
|
||||
|
||||
for(Item item : ores){
|
||||
@@ -25,10 +32,4 @@ public class OreBlocks extends BlockList {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Block get(Block floor, Item item){
|
||||
if(!oreBlockMap.containsKey(item)) throw new IllegalArgumentException("Item '" + item + "' is not an ore!");
|
||||
if(!oreBlockMap.get(item).containsKey(floor)) throw new IllegalArgumentException("Block '" + floor.name + "' does not support ores!");
|
||||
return oreBlockMap.get(item).get(floor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
package io.anuke.mindustry.content.blocks;
|
||||
|
||||
import io.anuke.mindustry.content.Liquids;
|
||||
import io.anuke.mindustry.content.fx.BlockFx;
|
||||
import io.anuke.mindustry.type.ContentList;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.blocks.distribution.WarpGate;
|
||||
import io.anuke.mindustry.world.blocks.power.*;
|
||||
|
||||
public class PowerBlocks extends BlockList implements ContentList {
|
||||
public class PowerBlocks extends BlockList implements ContentList{
|
||||
public static Block combustionGenerator, thermalGenerator, turbineGenerator, rtgGenerator, solarPanel, largeSolarPanel,
|
||||
nuclearReactor, fusionReactor, battery, batteryLarge, powerNode, powerNodeLarge, warpGate;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
combustionGenerator = new BurnerGenerator("combustion-generator") {{
|
||||
public void load(){
|
||||
combustionGenerator = new BurnerGenerator("combustion-generator"){{
|
||||
powerOutput = 0.09f;
|
||||
powerCapacity = 40f;
|
||||
itemDuration = 40f;
|
||||
}};
|
||||
|
||||
thermalGenerator = new LiquidHeatGenerator("thermal-generator") {{
|
||||
thermalGenerator = new LiquidHeatGenerator("thermal-generator"){{
|
||||
maxLiquidGenerate = 0.5f;
|
||||
powerPerLiquid = 0.08f;
|
||||
powerCapacity = 40f;
|
||||
@@ -27,55 +28,55 @@ public class PowerBlocks extends BlockList implements ContentList {
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
turbineGenerator = new TurbineGenerator("turbine-generator") {{
|
||||
turbineGenerator = new TurbineGenerator("turbine-generator"){{
|
||||
powerOutput = 0.28f;
|
||||
powerCapacity = 40f;
|
||||
itemDuration = 30f;
|
||||
powerPerLiquid = 0.7f;
|
||||
auxLiquidUse = 0.05f;
|
||||
consumes.liquid(Liquids.water, 0.05f);
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
rtgGenerator = new DecayGenerator("rtg-generator") {{
|
||||
rtgGenerator = new DecayGenerator("rtg-generator"){{
|
||||
powerCapacity = 40f;
|
||||
powerOutput = 0.02f;
|
||||
itemDuration = 500f;
|
||||
}};
|
||||
|
||||
solarPanel = new SolarGenerator("solar-panel") {{
|
||||
solarPanel = new SolarGenerator("solar-panel"){{
|
||||
generation = 0.0045f;
|
||||
}};
|
||||
|
||||
largeSolarPanel = new SolarGenerator("solar-panel-large") {{
|
||||
largeSolarPanel = new SolarGenerator("solar-panel-large"){{
|
||||
size = 3;
|
||||
generation = 0.055f;
|
||||
}};
|
||||
|
||||
nuclearReactor = new NuclearReactor("nuclear-reactor") {{
|
||||
nuclearReactor = new NuclearReactor("nuclear-reactor"){{
|
||||
size = 3;
|
||||
health = 700;
|
||||
powerMultiplier = 0.8f;
|
||||
}};
|
||||
|
||||
fusionReactor = new FusionReactor("fusion-reactor") {{
|
||||
fusionReactor = new FusionReactor("fusion-reactor"){{
|
||||
size = 4;
|
||||
health = 600;
|
||||
}};
|
||||
|
||||
battery = new PowerDistributor("battery") {{
|
||||
battery = new PowerDistributor("battery"){{
|
||||
powerCapacity = 320f;
|
||||
}};
|
||||
|
||||
batteryLarge = new PowerDistributor("battery-large") {{
|
||||
batteryLarge = new PowerDistributor("battery-large"){{
|
||||
size = 3;
|
||||
powerCapacity = 2000f;
|
||||
}};
|
||||
|
||||
powerNode = new PowerNode("power-node") {{
|
||||
powerNode = new PowerNode("power-node"){{
|
||||
shadow = "shadow-round-1";
|
||||
}};
|
||||
|
||||
powerNodeLarge = new PowerNode("power-node-large") {{
|
||||
powerNodeLarge = new PowerNode("power-node-large"){{
|
||||
size = 2;
|
||||
powerSpeed = 1f;
|
||||
maxNodes = 5;
|
||||
|
||||
@@ -11,35 +11,35 @@ import io.anuke.mindustry.world.blocks.production.Drill;
|
||||
import io.anuke.mindustry.world.blocks.production.Fracker;
|
||||
import io.anuke.mindustry.world.blocks.production.SolidPump;
|
||||
|
||||
public class ProductionBlocks extends BlockList implements ContentList {
|
||||
public class ProductionBlocks extends BlockList implements ContentList{
|
||||
public static Block tungstenDrill, carbideDrill, laserdrill, blastdrill, plasmadrill, waterextractor, oilextractor, cultivator;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
tungstenDrill = new Drill("tungsten-drill") {{
|
||||
public void load(){
|
||||
tungstenDrill = new Drill("tungsten-drill"){{
|
||||
tier = 2;
|
||||
drillTime = 340;
|
||||
}};
|
||||
|
||||
carbideDrill = new Drill("carbide-drill") {{
|
||||
carbideDrill = new Drill("carbide-drill"){{
|
||||
tier = 3;
|
||||
drillTime = 280;
|
||||
}};
|
||||
|
||||
laserdrill = new Drill("laser-drill") {{
|
||||
laserdrill = new Drill("laser-drill"){{
|
||||
drillTime = 180;
|
||||
size = 2;
|
||||
powerUse = 0.2f;
|
||||
hasPower = true;
|
||||
tier = 4;
|
||||
updateEffect = BlockFx.pulverizeMedium;
|
||||
drillEffect = BlockFx.mineBig;
|
||||
|
||||
consumes.power(0.2f);
|
||||
}};
|
||||
|
||||
blastdrill = new Drill("blast-drill") {{
|
||||
blastdrill = new Drill("blast-drill"){{
|
||||
drillTime = 120;
|
||||
size = 3;
|
||||
powerUse = 0.5f;
|
||||
drawRim = true;
|
||||
hasPower = true;
|
||||
tier = 5;
|
||||
@@ -48,13 +48,14 @@ public class ProductionBlocks extends BlockList implements ContentList {
|
||||
drillEffect = BlockFx.mineHuge;
|
||||
rotateSpeed = 6f;
|
||||
warmupSpeed = 0.01f;
|
||||
|
||||
consumes.power(0.5f);
|
||||
}};
|
||||
|
||||
plasmadrill = new Drill("plasma-drill") {{
|
||||
plasmadrill = new Drill("plasma-drill"){{
|
||||
heatColor = Color.valueOf("ff461b");
|
||||
drillTime = 90;
|
||||
size = 4;
|
||||
powerUse = 0.7f;
|
||||
hasLiquids = true;
|
||||
hasPower = true;
|
||||
tier = 5;
|
||||
@@ -64,38 +65,43 @@ public class ProductionBlocks extends BlockList implements ContentList {
|
||||
updateEffectChance = 0.04f;
|
||||
drillEffect = BlockFx.mineHuge;
|
||||
warmupSpeed = 0.005f;
|
||||
|
||||
consumes.power(0.7f);
|
||||
}};
|
||||
|
||||
waterextractor = new SolidPump("water-extractor") {{
|
||||
waterextractor = new SolidPump("water-extractor"){{
|
||||
result = Liquids.water;
|
||||
powerUse = 0.2f;
|
||||
pumpAmount = 0.1f;
|
||||
size = 2;
|
||||
liquidCapacity = 30f;
|
||||
rotateSpeed = 1.4f;
|
||||
|
||||
consumes.power(0.2f);
|
||||
}};
|
||||
|
||||
oilextractor = new Fracker("oil-extractor") {{
|
||||
oilextractor = new Fracker("oil-extractor"){{
|
||||
result = Liquids.oil;
|
||||
inputLiquid = Liquids.water;
|
||||
updateEffect = BlockFx.pulverize;
|
||||
liquidCapacity = 50f;
|
||||
updateEffectChance = 0.05f;
|
||||
inputLiquidUse = 0.3f;
|
||||
powerUse = 0.6f;
|
||||
pumpAmount = 0.06f;
|
||||
pumpAmount = 0.08f;
|
||||
size = 3;
|
||||
liquidCapacity = 30f;
|
||||
|
||||
consumes.item(Items.sand);
|
||||
consumes.power(0.5f);
|
||||
consumes.liquid(Liquids.water, 0.3f);
|
||||
}};
|
||||
|
||||
cultivator = new Cultivator("cultivator") {{
|
||||
cultivator = new Cultivator("cultivator"){{
|
||||
result = Items.biomatter;
|
||||
inputLiquid = Liquids.water;
|
||||
liquidUse = 0.2f;
|
||||
drillTime = 260;
|
||||
size = 2;
|
||||
hasLiquids = true;
|
||||
hasPower = true;
|
||||
|
||||
consumes.power(0.08f);
|
||||
consumes.liquid(Liquids.water, 0.2f);
|
||||
}};
|
||||
|
||||
}
|
||||
|
||||
@@ -7,25 +7,26 @@ import io.anuke.mindustry.world.blocks.storage.SortedUnloader;
|
||||
import io.anuke.mindustry.world.blocks.storage.Unloader;
|
||||
import io.anuke.mindustry.world.blocks.storage.Vault;
|
||||
|
||||
public class StorageBlocks extends BlockList implements ContentList {
|
||||
public class StorageBlocks extends BlockList implements ContentList{
|
||||
public static Block core, vault, unloader, sortedunloader;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
core = new CoreBlock("core") {{
|
||||
public void load(){
|
||||
core = new CoreBlock("core"){{
|
||||
health = 800;
|
||||
}};
|
||||
|
||||
vault = new Vault("vault") {{
|
||||
vault = new Vault("vault"){{
|
||||
size = 3;
|
||||
health = 600;
|
||||
itemCapacity = 2000;
|
||||
}};
|
||||
|
||||
unloader = new Unloader("unloader") {{
|
||||
unloader = new Unloader("unloader"){{
|
||||
speed = 5;
|
||||
}};
|
||||
|
||||
sortedunloader = new SortedUnloader("sortedunloader") {{
|
||||
sortedunloader = new SortedUnloader("sortedunloader"){{
|
||||
speed = 5;
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -12,22 +12,23 @@ import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
import io.anuke.ucore.util.Strings;
|
||||
|
||||
public class TurretBlocks extends BlockList implements ContentList {
|
||||
public static Block duo, /*scatter,*/ scorch, hail, wave, lancer, arc, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown;
|
||||
public class TurretBlocks extends BlockList implements ContentList{
|
||||
public static Block duo, /*scatter,*/
|
||||
scorch, hail, wave, lancer, arc, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
duo = new DoubleTurret("duo") {{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.bulletTungsten, AmmoTypes.bulletLead, AmmoTypes.bulletCarbide, AmmoTypes.bulletPyratite, AmmoTypes.bulletSilicon};
|
||||
reload = 25f;
|
||||
restitution = 0.03f;
|
||||
range = 90f;
|
||||
shootCone = 15f;
|
||||
ammoUseEffect = ShootFx.shellEjectSmall;
|
||||
health = 80;
|
||||
inaccuracy = 2f;
|
||||
rotatespeed = 10f;
|
||||
}};
|
||||
@Override
|
||||
public void load(){
|
||||
duo = new DoubleTurret("duo"){{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.bulletTungsten, AmmoTypes.bulletLead, AmmoTypes.bulletCarbide, AmmoTypes.bulletPyratite, AmmoTypes.bulletSilicon};
|
||||
reload = 25f;
|
||||
restitution = 0.03f;
|
||||
range = 90f;
|
||||
shootCone = 15f;
|
||||
ammoUseEffect = ShootFx.shellEjectSmall;
|
||||
health = 80;
|
||||
inaccuracy = 2f;
|
||||
rotatespeed = 10f;
|
||||
}};
|
||||
/*
|
||||
scatter = new BurstTurret("scatter") {{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.flakLead, AmmoTypes.flakExplosive, AmmoTypes.flakPlastic};
|
||||
@@ -41,165 +42,165 @@ public class TurretBlocks extends BlockList implements ContentList {
|
||||
ammoUseEffect = ShootFx.shellEjectSmall;
|
||||
}};*/
|
||||
|
||||
hail = new ArtilleryTurret("hail") {{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.artilleryCarbide, AmmoTypes.artilleryHoming, AmmoTypes.artilleryIncindiary};
|
||||
reload = 100f;
|
||||
recoil = 2f;
|
||||
range = 200f;
|
||||
inaccuracy = 5f;
|
||||
health = 120;
|
||||
}};
|
||||
hail = new ArtilleryTurret("hail"){{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.artilleryCarbide, AmmoTypes.artilleryHoming, AmmoTypes.artilleryIncindiary};
|
||||
reload = 100f;
|
||||
recoil = 2f;
|
||||
range = 200f;
|
||||
inaccuracy = 5f;
|
||||
health = 120;
|
||||
}};
|
||||
|
||||
scorch = new LiquidTurret("scorch") {{
|
||||
scorch = new LiquidTurret("scorch"){{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.basicFlame};
|
||||
recoil = 0f;
|
||||
reload = 4f;
|
||||
shootCone = 50f;
|
||||
ammoUseEffect = ShootFx.shellEjectSmall;
|
||||
health = 160;
|
||||
health = 160;
|
||||
|
||||
drawer = (tile, entity) -> Draw.rect(entity.target != null ? name + "-shoot" : name, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90);
|
||||
}};
|
||||
|
||||
wave = new LiquidTurret("wave") {{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.water, AmmoTypes.lava, AmmoTypes.cryofluid, AmmoTypes.oil};
|
||||
size = 2;
|
||||
recoil = 0f;
|
||||
reload = 4f;
|
||||
inaccuracy = 5f;
|
||||
shootCone = 50f;
|
||||
shootEffect = ShootFx.shootLiquid;
|
||||
range = 70f;
|
||||
health = 360;
|
||||
wave = new LiquidTurret("wave"){{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.water, AmmoTypes.lava, AmmoTypes.cryofluid, AmmoTypes.oil};
|
||||
size = 2;
|
||||
recoil = 0f;
|
||||
reload = 4f;
|
||||
inaccuracy = 5f;
|
||||
shootCone = 50f;
|
||||
shootEffect = ShootFx.shootLiquid;
|
||||
range = 70f;
|
||||
health = 360;
|
||||
|
||||
drawer = (tile, entity) -> {
|
||||
Draw.rect(name, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90);
|
||||
drawer = (tile, entity) -> {
|
||||
Draw.rect(region, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90);
|
||||
|
||||
Draw.color(entity.liquids.liquid.color);
|
||||
Draw.alpha(entity.liquids.amount / liquidCapacity);
|
||||
Draw.rect(name + "-liquid", tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90);
|
||||
Draw.color();
|
||||
};
|
||||
}};
|
||||
Draw.color(entity.liquids.current().color);
|
||||
Draw.alpha(entity.liquids.total() / liquidCapacity);
|
||||
Draw.rect(name + "-liquid", tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90);
|
||||
Draw.color();
|
||||
};
|
||||
}};
|
||||
|
||||
lancer = new LaserTurret("lancer") {{
|
||||
range = 90f;
|
||||
chargeTime = 60f;
|
||||
chargeMaxDelay = 30f;
|
||||
chargeEffects = 7;
|
||||
shootType = AmmoTypes.lancerLaser;
|
||||
recoil = 2f;
|
||||
reload = 100f;
|
||||
cooldown = 0.03f;
|
||||
powerUsed = 20f;
|
||||
powerCapacity = 60f;
|
||||
shootShake = 2f;
|
||||
shootEffect = ShootFx.lancerLaserShoot;
|
||||
smokeEffect = ShootFx.lancerLaserShootSmoke;
|
||||
chargeEffect = ShootFx.lancerLaserCharge;
|
||||
chargeBeginEffect = ShootFx.lancerLaserChargeBegin;
|
||||
heatColor = Color.RED;
|
||||
size = 2;
|
||||
health = 320;
|
||||
}};
|
||||
lancer = new LaserTurret("lancer"){{
|
||||
range = 90f;
|
||||
chargeTime = 60f;
|
||||
chargeMaxDelay = 30f;
|
||||
chargeEffects = 7;
|
||||
shootType = AmmoTypes.lancerLaser;
|
||||
recoil = 2f;
|
||||
reload = 100f;
|
||||
cooldown = 0.03f;
|
||||
powerUsed = 20f;
|
||||
powerCapacity = 60f;
|
||||
shootShake = 2f;
|
||||
shootEffect = ShootFx.lancerLaserShoot;
|
||||
smokeEffect = ShootFx.lancerLaserShootSmoke;
|
||||
chargeEffect = ShootFx.lancerLaserCharge;
|
||||
chargeBeginEffect = ShootFx.lancerLaserChargeBegin;
|
||||
heatColor = Color.RED;
|
||||
size = 2;
|
||||
health = 320;
|
||||
}};
|
||||
|
||||
arc = new LaserTurret("arc") {{
|
||||
shootType = AmmoTypes.lightning;
|
||||
reload = 100f;
|
||||
chargeTime = 70f;
|
||||
shootShake = 1f;
|
||||
chargeMaxDelay = 30f;
|
||||
chargeEffects = 7;
|
||||
shootEffect = ShootFx.lightningShoot;
|
||||
chargeEffect = ShootFx.lightningCharge;
|
||||
chargeBeginEffect = ShootFx.lancerLaserChargeBegin;
|
||||
heatColor = Color.RED;
|
||||
recoil = 3f;
|
||||
size = 2;
|
||||
}};
|
||||
arc = new LaserTurret("arc"){{
|
||||
shootType = AmmoTypes.lightning;
|
||||
reload = 100f;
|
||||
chargeTime = 70f;
|
||||
shootShake = 1f;
|
||||
chargeMaxDelay = 30f;
|
||||
chargeEffects = 7;
|
||||
shootEffect = ShootFx.lightningShoot;
|
||||
chargeEffect = ShootFx.lightningCharge;
|
||||
chargeBeginEffect = ShootFx.lancerLaserChargeBegin;
|
||||
heatColor = Color.RED;
|
||||
recoil = 3f;
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
swarmer = new BurstTurret("swarmer") {{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.missileExplosive, AmmoTypes.missileIncindiary/*, AmmoTypes.missileSurge*/};
|
||||
reload = 60f;
|
||||
shots = 4;
|
||||
burstSpacing = 5;
|
||||
inaccuracy = 10f;
|
||||
range = 140f;
|
||||
xRand = 6f;
|
||||
size = 2;
|
||||
health = 380;
|
||||
}};
|
||||
swarmer = new BurstTurret("swarmer"){{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.missileExplosive, AmmoTypes.missileIncindiary/*, AmmoTypes.missileSurge*/};
|
||||
reload = 60f;
|
||||
shots = 4;
|
||||
burstSpacing = 5;
|
||||
inaccuracy = 10f;
|
||||
range = 140f;
|
||||
xRand = 6f;
|
||||
size = 2;
|
||||
health = 380;
|
||||
}};
|
||||
|
||||
salvo = new BurstTurret("salvo") {{
|
||||
size = 2;
|
||||
range = 120f;
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.bulletTungsten, AmmoTypes.bulletCarbide, AmmoTypes.bulletPyratite, AmmoTypes.bulletThorium, AmmoTypes.bulletSilicon};
|
||||
reload = 40f;
|
||||
restitution = 0.03f;
|
||||
ammoEjectBack = 3f;
|
||||
cooldown = 0.03f;
|
||||
recoil = 3f;
|
||||
shootShake = 2f;
|
||||
burstSpacing = 4;
|
||||
shots = 3;
|
||||
ammoUseEffect = ShootFx.shellEjectBig;
|
||||
salvo = new BurstTurret("salvo"){{
|
||||
size = 2;
|
||||
range = 120f;
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.bulletTungsten, AmmoTypes.bulletCarbide, AmmoTypes.bulletPyratite, AmmoTypes.bulletThorium, AmmoTypes.bulletSilicon};
|
||||
reload = 40f;
|
||||
restitution = 0.03f;
|
||||
ammoEjectBack = 3f;
|
||||
cooldown = 0.03f;
|
||||
recoil = 3f;
|
||||
shootShake = 2f;
|
||||
burstSpacing = 4;
|
||||
shots = 3;
|
||||
ammoUseEffect = ShootFx.shellEjectBig;
|
||||
|
||||
drawer = (tile, entity) -> {
|
||||
Draw.rect(name, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90);
|
||||
float offsetx = (int) (Mathf.abscurve(Mathf.curve(entity.reload / reload, 0.3f, 0.2f)) * 3f);
|
||||
float offsety = -(int) (Mathf.abscurve(Mathf.curve(entity.reload / reload, 0.3f, 0.2f)) * 2f);
|
||||
drawer = (tile, entity) -> {
|
||||
Draw.rect(region, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90);
|
||||
float offsetx = (int) (Mathf.abscurve(Mathf.curve(entity.reload / reload, 0.3f, 0.2f)) * 3f);
|
||||
float offsety = -(int) (Mathf.abscurve(Mathf.curve(entity.reload / reload, 0.3f, 0.2f)) * 2f);
|
||||
|
||||
for (int i : Mathf.signs) {
|
||||
float rot = entity.rotation + 90 * i;
|
||||
Draw.rect(name + "-panel-" + Strings.dir(i),
|
||||
tile.drawx() + tr2.x + Angles.trnsx(rot, offsetx, offsety),
|
||||
tile.drawy() + tr2.y + Angles.trnsy(rot, -offsetx, offsety), entity.rotation - 90);
|
||||
}
|
||||
};
|
||||
for(int i : Mathf.signs){
|
||||
float rot = entity.rotation + 90 * i;
|
||||
Draw.rect(name + "-panel-" + Strings.dir(i),
|
||||
tile.drawx() + tr2.x + Angles.trnsx(rot, offsetx, offsety),
|
||||
tile.drawy() + tr2.y + Angles.trnsy(rot, -offsetx, offsety), entity.rotation - 90);
|
||||
}
|
||||
};
|
||||
|
||||
health = 360;
|
||||
}};
|
||||
health = 360;
|
||||
}};
|
||||
|
||||
ripple = new ArtilleryTurret("ripple") {{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.artilleryCarbide, AmmoTypes.artilleryHoming, AmmoTypes.artilleryIncindiary, AmmoTypes.artilleryExplosive, AmmoTypes.artilleryPlastic};
|
||||
size = 3;
|
||||
shots = 4;
|
||||
inaccuracy = 12f;
|
||||
reload = 60f;
|
||||
ammoEjectBack = 5f;
|
||||
ripple = new ArtilleryTurret("ripple"){{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.artilleryCarbide, AmmoTypes.artilleryHoming, AmmoTypes.artilleryIncindiary, AmmoTypes.artilleryExplosive, AmmoTypes.artilleryPlastic};
|
||||
size = 3;
|
||||
shots = 4;
|
||||
inaccuracy = 12f;
|
||||
reload = 60f;
|
||||
ammoEjectBack = 5f;
|
||||
ammoUseEffect = ShootFx.shellEjectBig;
|
||||
cooldown = 0.03f;
|
||||
velocityInaccuracy = 0.2f;
|
||||
velocityInaccuracy = 0.2f;
|
||||
restitution = 0.02f;
|
||||
recoil = 6f;
|
||||
shootShake = 2f;
|
||||
range = 300f;
|
||||
|
||||
health = 550;
|
||||
}};
|
||||
health = 550;
|
||||
}};
|
||||
|
||||
cyclone = new ItemTurret("cyclone") {{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.flakLead, AmmoTypes.flakExplosive, AmmoTypes.flakPlastic, AmmoTypes.flakSurge};
|
||||
size = 3;
|
||||
}};
|
||||
cyclone = new ItemTurret("cyclone"){{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.flakLead, AmmoTypes.flakExplosive, AmmoTypes.flakPlastic, AmmoTypes.flakSurge};
|
||||
size = 3;
|
||||
}};
|
||||
|
||||
fuse = new ItemTurret("fuse") {{
|
||||
//TODO make it use power
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.fuseShotgun};
|
||||
size = 3;
|
||||
}};
|
||||
fuse = new ItemTurret("fuse"){{
|
||||
//TODO make it use power
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.fuseShotgun};
|
||||
size = 3;
|
||||
}};
|
||||
|
||||
spectre = new ItemTurret("spectre") {{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.bulletTungsten, AmmoTypes.bulletLead, AmmoTypes.bulletCarbide, AmmoTypes.bulletPyratite, AmmoTypes.bulletThorium, AmmoTypes.bulletSilicon};
|
||||
reload = 25f;
|
||||
restitution = 0.03f;
|
||||
ammoUseEffect = ShootFx.shellEjectSmall;
|
||||
size = 4;
|
||||
}};
|
||||
spectre = new ItemTurret("spectre"){{
|
||||
ammoTypes = new AmmoType[]{AmmoTypes.bulletTungsten, AmmoTypes.bulletLead, AmmoTypes.bulletCarbide, AmmoTypes.bulletPyratite, AmmoTypes.bulletThorium, AmmoTypes.bulletSilicon};
|
||||
reload = 25f;
|
||||
restitution = 0.03f;
|
||||
ammoUseEffect = ShootFx.shellEjectSmall;
|
||||
size = 4;
|
||||
}};
|
||||
|
||||
meltdown = new PowerTurret("meltdown") {{
|
||||
shootType = AmmoTypes.meltdownLaser;
|
||||
size = 4;
|
||||
}};
|
||||
}
|
||||
meltdown = new PowerTurret("meltdown"){{
|
||||
shootType = AmmoTypes.meltdownLaser;
|
||||
size = 4;
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,54 +7,51 @@ import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.blocks.units.*;
|
||||
|
||||
public class UnitBlocks extends BlockList implements ContentList {
|
||||
public class UnitBlocks extends BlockList implements ContentList{
|
||||
public static Block resupplyPoint, repairPoint, droneFactory, fabricatorFactory, dropPoint, reconstructor, overdriveProjector, shieldProjector;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
droneFactory = new UnitFactory("drone-factory") {{
|
||||
public void load(){
|
||||
droneFactory = new UnitFactory("drone-factory"){{
|
||||
type = UnitTypes.drone;
|
||||
produceTime = 800;
|
||||
size = 2;
|
||||
requirements = new ItemStack[]{
|
||||
new ItemStack(Items.silicon, 30), new ItemStack(Items.lead, 30)
|
||||
};
|
||||
consumes.power(0.08f);
|
||||
consumes.items(new ItemStack[]{new ItemStack(Items.silicon, 30), new ItemStack(Items.lead, 30)});
|
||||
}};
|
||||
|
||||
fabricatorFactory = new UnitFactory("fabricator-factory") {{
|
||||
fabricatorFactory = new UnitFactory("fabricator-factory"){{
|
||||
type = UnitTypes.fabricator;
|
||||
produceTime = 1600;
|
||||
size = 2;
|
||||
powerUse = 0.2f;
|
||||
requirements = new ItemStack[]{
|
||||
new ItemStack(Items.silicon, 70), new ItemStack(Items.lead, 80), new ItemStack(Items.titanium, 80)
|
||||
};
|
||||
consumes.power(0.2f);
|
||||
consumes.items(new ItemStack[]{new ItemStack(Items.silicon, 70), new ItemStack(Items.lead, 80), new ItemStack(Items.titanium, 80)});
|
||||
}};
|
||||
|
||||
resupplyPoint = new ResupplyPoint("resupply-point") {{
|
||||
resupplyPoint = new ResupplyPoint("resupply-point"){{
|
||||
shadow = "shadow-round-1";
|
||||
itemCapacity = 30;
|
||||
}};
|
||||
|
||||
dropPoint = new DropPoint("drop-point") {{
|
||||
dropPoint = new DropPoint("drop-point"){{
|
||||
shadow = "shadow-round-1";
|
||||
itemCapacity = 40;
|
||||
}};
|
||||
|
||||
repairPoint = new RepairPoint("repair-point") {{
|
||||
repairPoint = new RepairPoint("repair-point"){{
|
||||
shadow = "shadow-round-1";
|
||||
repairSpeed = 0.1f;
|
||||
}};
|
||||
|
||||
reconstructor = new Reconstructor("reconstructor") {{
|
||||
reconstructor = new Reconstructor("reconstructor"){{
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
overdriveProjector = new OverdriveProjector("overdrive-projector") {{
|
||||
overdriveProjector = new OverdriveProjector("overdrive-projector"){{
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
shieldProjector = new ShieldProjector("shieldprojector") {{
|
||||
shieldProjector = new ShieldProjector("shieldprojector"){{
|
||||
size = 2;
|
||||
}};
|
||||
}
|
||||
|
||||
@@ -4,11 +4,11 @@ import io.anuke.mindustry.content.Mechs;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.blocks.units.MechFactory;
|
||||
|
||||
public class UpgradeBlocks extends BlockList {
|
||||
public class UpgradeBlocks extends BlockList{
|
||||
public static Block deltaFactory, tauFactory, omegaFactory, dartFactory, javelinFactory, tridentFactory, halberdFactory;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
deltaFactory = new MechFactory("delta-mech-factory"){{
|
||||
mech = Mechs.delta;
|
||||
size = 2;
|
||||
|
||||
@@ -11,9 +11,9 @@ public class ArtilleryBullets extends BulletList implements ContentList{
|
||||
public static BulletType carbide, plastic, plasticFrag, homing, incindiary, explosive, surge;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
carbide = new ArtilleryBulletType(3f, 0, "shell") {
|
||||
carbide = new ArtilleryBulletType(3f, 0, "shell"){
|
||||
{
|
||||
hiteffect = BulletFx.flakExplosion;
|
||||
knockback = 0.8f;
|
||||
@@ -25,7 +25,7 @@ public class ArtilleryBullets extends BulletList implements ContentList{
|
||||
}
|
||||
};
|
||||
|
||||
plasticFrag = new BasicBulletType(2.5f, 6, "bullet") {
|
||||
plasticFrag = new BasicBulletType(2.5f, 6, "bullet"){
|
||||
{
|
||||
bulletWidth = 10f;
|
||||
bulletHeight = 12f;
|
||||
@@ -36,7 +36,7 @@ public class ArtilleryBullets extends BulletList implements ContentList{
|
||||
}
|
||||
};
|
||||
|
||||
plastic = new ArtilleryBulletType(3.3f, 0, "shell") {
|
||||
plastic = new ArtilleryBulletType(3.3f, 0, "shell"){
|
||||
{
|
||||
hiteffect = BulletFx.plasticExplosion;
|
||||
knockback = 1f;
|
||||
@@ -52,7 +52,7 @@ public class ArtilleryBullets extends BulletList implements ContentList{
|
||||
}
|
||||
};
|
||||
|
||||
homing = new ArtilleryBulletType(3f, 0, "shell") {
|
||||
homing = new ArtilleryBulletType(3f, 0, "shell"){
|
||||
{
|
||||
hiteffect = BulletFx.flakExplosion;
|
||||
knockback = 0.8f;
|
||||
@@ -66,7 +66,7 @@ public class ArtilleryBullets extends BulletList implements ContentList{
|
||||
}
|
||||
};
|
||||
|
||||
incindiary = new ArtilleryBulletType(3f, 0, "shell") {
|
||||
incindiary = new ArtilleryBulletType(3f, 0, "shell"){
|
||||
{
|
||||
hiteffect = BulletFx.blastExplosion;
|
||||
knockback = 0.8f;
|
||||
@@ -83,7 +83,7 @@ public class ArtilleryBullets extends BulletList implements ContentList{
|
||||
}
|
||||
};
|
||||
|
||||
explosive = new ArtilleryBulletType(2f, 0, "shell") {
|
||||
explosive = new ArtilleryBulletType(2f, 0, "shell"){
|
||||
{
|
||||
hiteffect = BulletFx.blastExplosion;
|
||||
knockback = 0.8f;
|
||||
@@ -97,7 +97,7 @@ public class ArtilleryBullets extends BulletList implements ContentList{
|
||||
}
|
||||
};
|
||||
|
||||
surge = new ArtilleryBulletType(3f, 0, "shell") {
|
||||
surge = new ArtilleryBulletType(3f, 0, "shell"){
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
@@ -5,10 +5,10 @@ import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
import io.anuke.mindustry.game.Content;
|
||||
import io.anuke.mindustry.type.ContentList;
|
||||
|
||||
public abstract class BulletList implements ContentList {
|
||||
public abstract class BulletList implements ContentList{
|
||||
|
||||
@Override
|
||||
public Array<? extends Content> getAll() {
|
||||
public Array<? extends Content> getAll(){
|
||||
return BulletType.all();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,34 +4,34 @@ import io.anuke.mindustry.entities.bullet.BasicBulletType;
|
||||
import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
import io.anuke.mindustry.type.ContentList;
|
||||
|
||||
public class FlakBullets extends BulletList implements ContentList {
|
||||
public class FlakBullets extends BulletList implements ContentList{
|
||||
public static BulletType lead, plastic, explosive, surge;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
lead = new BasicBulletType(3f, 5, "bullet") {
|
||||
lead = new BasicBulletType(3f, 5, "bullet"){
|
||||
{
|
||||
bulletWidth = 7f;
|
||||
bulletHeight = 9f;
|
||||
}
|
||||
};
|
||||
|
||||
plastic = new BasicBulletType(3f, 5, "bullet") {
|
||||
plastic = new BasicBulletType(3f, 5, "bullet"){
|
||||
{
|
||||
bulletWidth = 7f;
|
||||
bulletHeight = 9f;
|
||||
}
|
||||
};
|
||||
|
||||
explosive = new BasicBulletType(3f, 5, "bullet") {
|
||||
explosive = new BasicBulletType(3f, 5, "bullet"){
|
||||
{
|
||||
bulletWidth = 7f;
|
||||
bulletHeight = 9f;
|
||||
}
|
||||
};
|
||||
|
||||
surge = new BasicBulletType(3f, 5, "bullet") {
|
||||
surge = new BasicBulletType(3f, 5, "bullet"){
|
||||
{
|
||||
bulletWidth = 7f;
|
||||
bulletHeight = 9f;
|
||||
|
||||
@@ -6,13 +6,13 @@ import io.anuke.mindustry.entities.bullet.MissileBulletType;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.type.ContentList;
|
||||
|
||||
public class MissileBullets extends BulletList implements ContentList {
|
||||
public class MissileBullets extends BulletList implements ContentList{
|
||||
public static BulletType explosive, incindiary, surge, javelin;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
explosive = new MissileBulletType(1.8f, 10, "missile") {
|
||||
explosive = new MissileBulletType(1.8f, 10, "missile"){
|
||||
{
|
||||
bulletWidth = 8f;
|
||||
bulletHeight = 8f;
|
||||
@@ -26,7 +26,7 @@ public class MissileBullets extends BulletList implements ContentList {
|
||||
}
|
||||
};
|
||||
|
||||
incindiary = new MissileBulletType(2f, 12, "missile") {
|
||||
incindiary = new MissileBulletType(2f, 12, "missile"){
|
||||
{
|
||||
frontColor = Palette.lightishOrange;
|
||||
backColor = Palette.lightOrange;
|
||||
@@ -44,14 +44,14 @@ public class MissileBullets extends BulletList implements ContentList {
|
||||
}
|
||||
};
|
||||
|
||||
surge = new MissileBulletType(3f, 5, "bullet") {
|
||||
surge = new MissileBulletType(3f, 5, "bullet"){
|
||||
{
|
||||
bulletWidth = 7f;
|
||||
bulletHeight = 9f;
|
||||
}
|
||||
};
|
||||
|
||||
javelin = new MissileBulletType(2.5f, 10, "missile") {
|
||||
javelin = new MissileBulletType(2.5f, 10, "missile"){
|
||||
{
|
||||
bulletWidth = 8f;
|
||||
bulletHeight = 8f;
|
||||
|
||||
@@ -5,27 +5,27 @@ import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.type.ContentList;
|
||||
|
||||
public class StandardBullets extends BulletList implements ContentList {
|
||||
public class StandardBullets extends BulletList implements ContentList{
|
||||
public static BulletType tungsten, lead, carbide, thorium, homing, tracer;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
tungsten = new BasicBulletType(3.2f, 10, "bullet") {
|
||||
tungsten = new BasicBulletType(3.2f, 10, "bullet"){
|
||||
{
|
||||
bulletWidth = 9f;
|
||||
bulletHeight = 11f;
|
||||
}
|
||||
};
|
||||
|
||||
lead = new BasicBulletType(2.5f, 5, "bullet") {
|
||||
lead = new BasicBulletType(2.5f, 5, "bullet"){
|
||||
{
|
||||
bulletWidth = 7f;
|
||||
bulletHeight = 9f;
|
||||
}
|
||||
};
|
||||
|
||||
carbide = new BasicBulletType(3.5f, 18, "bullet") {
|
||||
carbide = new BasicBulletType(3.5f, 18, "bullet"){
|
||||
{
|
||||
bulletWidth = 9f;
|
||||
bulletHeight = 12f;
|
||||
@@ -33,7 +33,7 @@ public class StandardBullets extends BulletList implements ContentList {
|
||||
}
|
||||
};
|
||||
|
||||
thorium = new BasicBulletType(4f, 29, "bullet") {
|
||||
thorium = new BasicBulletType(4f, 29, "bullet"){
|
||||
{
|
||||
bulletWidth = 10f;
|
||||
bulletHeight = 13f;
|
||||
@@ -41,7 +41,7 @@ public class StandardBullets extends BulletList implements ContentList {
|
||||
}
|
||||
};
|
||||
|
||||
homing = new BasicBulletType(3f, 9, "bullet") {
|
||||
homing = new BasicBulletType(3f, 9, "bullet"){
|
||||
{
|
||||
bulletWidth = 7f;
|
||||
bulletHeight = 9f;
|
||||
@@ -49,7 +49,7 @@ public class StandardBullets extends BulletList implements ContentList {
|
||||
}
|
||||
};
|
||||
|
||||
tracer = new BasicBulletType(3.2f, 11, "bullet") {
|
||||
tracer = new BasicBulletType(3.2f, 11, "bullet"){
|
||||
{
|
||||
bulletWidth = 10f;
|
||||
bulletHeight = 12f;
|
||||
|
||||
@@ -29,13 +29,13 @@ import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class TurretBullets extends BulletList implements ContentList {
|
||||
public class TurretBullets extends BulletList implements ContentList{
|
||||
public static BulletType fireball, basicFlame, lancerLaser, fuseShot, waterShot, cryoShot, lavaShot, oilShot, lightning, driverBolt;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
fireball = new BulletType(1f, 4) {
|
||||
fireball = new BulletType(1f, 4){
|
||||
{
|
||||
pierce = true;
|
||||
hitTiles = false;
|
||||
@@ -45,12 +45,12 @@ public class TurretBullets extends BulletList implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Bullet b) {
|
||||
public void init(Bullet b){
|
||||
b.getVelocity().setLength(0.6f + Mathf.random(2f));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Bullet b) {
|
||||
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());
|
||||
Fill.circle(b.x, b.y, 3f * b.fout());
|
||||
@@ -58,25 +58,25 @@ public class TurretBullets extends BulletList implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Bullet b) {
|
||||
if (Mathf.chance(0.04 * Timers.delta())) {
|
||||
public void update(Bullet b){
|
||||
if(Mathf.chance(0.04 * Timers.delta())){
|
||||
Tile tile = world.tileWorld(b.x, b.y);
|
||||
if (tile != null) {
|
||||
if(tile != null){
|
||||
Fire.create(tile);
|
||||
}
|
||||
}
|
||||
|
||||
if (Mathf.chance(0.1 * Timers.delta())) {
|
||||
if(Mathf.chance(0.1 * Timers.delta())){
|
||||
Effects.effect(EnvironmentFx.fireballsmoke, b.x, b.y);
|
||||
}
|
||||
|
||||
if (Mathf.chance(0.1 * Timers.delta())) {
|
||||
if(Mathf.chance(0.1 * Timers.delta())){
|
||||
Effects.effect(EnvironmentFx.ballfire, b.x, b.y);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
basicFlame = new BulletType(2f, 5) {
|
||||
basicFlame = new BulletType(2f, 5){
|
||||
{
|
||||
hitsize = 7f;
|
||||
lifetime = 30f;
|
||||
@@ -88,11 +88,11 @@ public class TurretBullets extends BulletList implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Bullet b) {
|
||||
public void draw(Bullet b){
|
||||
}
|
||||
};
|
||||
|
||||
lancerLaser = new BulletType(0.001f, 110) {
|
||||
lancerLaser = new BulletType(0.001f, 110){
|
||||
Color[] colors = {Palette.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Palette.lancerLaser, Color.WHITE};
|
||||
float[] tscales = {1f, 0.7f, 0.5f, 0.2f};
|
||||
float[] lenscales = {1f, 1.1f, 1.13f, 1.14f};
|
||||
@@ -107,19 +107,19 @@ public class TurretBullets extends BulletList implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Bullet b) {
|
||||
public void init(Bullet b){
|
||||
Damage.collideLine(b, b.getTeam(), hiteffect, b.x, b.y, b.angle(), length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Bullet b) {
|
||||
public void draw(Bullet b){
|
||||
float f = Mathf.curve(b.fin(), 0f, 0.2f);
|
||||
float baseLen = length * f;
|
||||
|
||||
Lines.lineAngle(b.x, b.y, b.angle(), baseLen);
|
||||
for (int s = 0; s < 3; s++) {
|
||||
for(int s = 0; s < 3; s++){
|
||||
Draw.color(colors[s]);
|
||||
for (int i = 0; i < tscales.length; i++) {
|
||||
for(int i = 0; i < tscales.length; i++){
|
||||
Lines.stroke(7f * b.fout() * (s == 0 ? 1.5f : s == 1 ? 1f : 0.3f) * tscales[i]);
|
||||
Lines.lineAngle(b.x, b.y, b.angle(), baseLen * lenscales[i]);
|
||||
}
|
||||
@@ -128,24 +128,24 @@ public class TurretBullets extends BulletList implements ContentList {
|
||||
}
|
||||
};
|
||||
|
||||
fuseShot = new BulletType(0.01f, 100) {
|
||||
fuseShot = new BulletType(0.01f, 100){
|
||||
//TODO
|
||||
};
|
||||
|
||||
waterShot = new LiquidBulletType(Liquids.water) {
|
||||
waterShot = new LiquidBulletType(Liquids.water){
|
||||
{
|
||||
status = StatusEffects.wet;
|
||||
statusIntensity = 0.5f;
|
||||
knockback = 0.65f;
|
||||
}
|
||||
};
|
||||
cryoShot = new LiquidBulletType(Liquids.cryofluid) {
|
||||
cryoShot = new LiquidBulletType(Liquids.cryofluid){
|
||||
{
|
||||
status = StatusEffects.freezing;
|
||||
statusIntensity = 0.5f;
|
||||
}
|
||||
};
|
||||
lavaShot = new LiquidBulletType(Liquids.lava) {
|
||||
lavaShot = new LiquidBulletType(Liquids.lava){
|
||||
{
|
||||
damage = 4;
|
||||
speed = 1.9f;
|
||||
@@ -154,7 +154,7 @@ public class TurretBullets extends BulletList implements ContentList {
|
||||
statusIntensity = 0.5f;
|
||||
}
|
||||
};
|
||||
oilShot = new LiquidBulletType(Liquids.oil) {
|
||||
oilShot = new LiquidBulletType(Liquids.oil){
|
||||
{
|
||||
speed = 2f;
|
||||
drag = 0.03f;
|
||||
@@ -162,7 +162,7 @@ public class TurretBullets extends BulletList implements ContentList {
|
||||
statusIntensity = 0.5f;
|
||||
}
|
||||
};
|
||||
lightning = new BulletType(0.001f, 10) {
|
||||
lightning = new BulletType(0.001f, 10){
|
||||
{
|
||||
lifetime = 1;
|
||||
despawneffect = Fx.none;
|
||||
@@ -170,16 +170,16 @@ public class TurretBullets extends BulletList implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Bullet b) {
|
||||
public void draw(Bullet b){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Bullet b) {
|
||||
public void init(Bullet b){
|
||||
Lightning.create(b.getTeam(), hiteffect, Palette.lancerLaser, damage, b.x, b.y, b.angle(), 30);
|
||||
}
|
||||
};
|
||||
|
||||
driverBolt = new BulletType(5f, 20) {
|
||||
driverBolt = new BulletType(5f, 20){
|
||||
{
|
||||
collidesTiles = false;
|
||||
lifetime = 200f;
|
||||
@@ -189,7 +189,7 @@ public class TurretBullets extends BulletList implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Bullet b) {
|
||||
public void draw(Bullet b){
|
||||
Draw.color(Color.LIGHT_GRAY);
|
||||
Fill.square(b.x, b.y, 3f, b.angle());
|
||||
|
||||
@@ -199,7 +199,7 @@ public class TurretBullets extends BulletList implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Bullet b) {
|
||||
public void update(Bullet b){
|
||||
//data MUST be an instance of DriverBulletData
|
||||
if(!(b.getData() instanceof DriverBulletData)){
|
||||
hit(b);
|
||||
@@ -208,7 +208,7 @@ public class TurretBullets extends BulletList implements ContentList {
|
||||
|
||||
float hitDst = 7f;
|
||||
|
||||
DriverBulletData data = (DriverBulletData)b.getData();
|
||||
DriverBulletData data = (DriverBulletData) b.getData();
|
||||
|
||||
//if the target is dead, just keep flying until the bullet explodes
|
||||
if(data.to.isDead()){
|
||||
@@ -245,15 +245,15 @@ public class TurretBullets extends BulletList implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void despawned(Bullet b) {
|
||||
public void despawned(Bullet b){
|
||||
super.despawned(b);
|
||||
|
||||
if(!(b.getData() instanceof DriverBulletData)) return;
|
||||
|
||||
DriverBulletData data = (DriverBulletData)b.getData();
|
||||
DriverBulletData data = (DriverBulletData) b.getData();
|
||||
data.to.isRecieving = false;
|
||||
|
||||
for(int i = 0; i < data.items.length; i ++){
|
||||
for(int i = 0; i < data.items.length; i++){
|
||||
int amountDropped = Mathf.random(0, data.items[i]);
|
||||
if(amountDropped > 0){
|
||||
float angle = b.angle() + Mathf.range(100f);
|
||||
@@ -264,7 +264,7 @@ public class TurretBullets extends BulletList implements ContentList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hit(Bullet b, float hitx, float hity) {
|
||||
public void hit(Bullet b, float hitx, float hity){
|
||||
super.hit(b, hitx, hity);
|
||||
despawned(b);
|
||||
}
|
||||
|
||||
@@ -16,12 +16,12 @@ import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class WeaponBullets extends BulletList {
|
||||
public class WeaponBullets extends BulletList{
|
||||
public static BulletType tungstenShotgun, bombExplosive, bombIncendiary, bombOil, shellCarbide;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
tungstenShotgun = new BasicBulletType(5f, 8, "bullet") {
|
||||
public void load(){
|
||||
tungstenShotgun = new BasicBulletType(5f, 8, "bullet"){
|
||||
{
|
||||
bulletWidth = 8f;
|
||||
bulletHeight = 9f;
|
||||
@@ -49,10 +49,10 @@ public class WeaponBullets extends BulletList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hit(Bullet b, float x, float y) {
|
||||
public void hit(Bullet b, float x, float y){
|
||||
super.hit(b, x, y);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for(int i = 0; i < 3; i++){
|
||||
float cx = x + Mathf.range(10f);
|
||||
float cy = y + Mathf.range(10f);
|
||||
Tile tile = world.tileWorld(cx, cy);
|
||||
@@ -73,17 +73,17 @@ public class WeaponBullets extends BulletList {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hit(Bullet b, float x, float y) {
|
||||
public void hit(Bullet b, float x, float y){
|
||||
super.hit(b, x, y);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for(int i = 0; i < 3; i++){
|
||||
Tile tile = world.tileWorld(x + Mathf.range(8f), y + Mathf.range(8f));
|
||||
Puddle.deposit(tile, Liquids.oil, 5f);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
shellCarbide = new BasicBulletType(3.4f, 20, "bullet") {
|
||||
shellCarbide = new BasicBulletType(3.4f, 20, "bullet"){
|
||||
{
|
||||
bulletWidth = 10f;
|
||||
bulletHeight = 12f;
|
||||
|
||||
@@ -19,7 +19,7 @@ public class BlockFx extends FxList implements ContentList{
|
||||
public static Effect reactorsmoke, nuclearsmoke, nuclearcloud, redgeneratespark, generatespark, fuelburn, plasticburn, pulverize, pulverizeRed, pulverizeRedder, pulverizeSmall, pulverizeMedium, producesmoke, smeltsmoke, formsmoke, blastsmoke, lava, dooropen, doorclose, dooropenlarge, doorcloselarge, purify, purifyoil, purifystone, generate, mine, mineBig, mineHuge, smelt, teleportActivate, teleport, teleportOut, ripple, bubble;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
reactorsmoke = new Effect(17, e -> {
|
||||
Angles.randLenVectors(e.id, 4, e.fin() * 8f, (x, y) -> {
|
||||
|
||||
@@ -10,12 +10,12 @@ import io.anuke.ucore.graphics.Lines;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class BulletFx extends FxList implements ContentList {
|
||||
public class BulletFx extends FxList implements ContentList{
|
||||
public static Effect hitBulletSmall, hitBulletBig, hitFlameSmall, hitLiquid, hitLancer, despawn, flakExplosion, blastExplosion, plasticExplosion,
|
||||
artilleryTrail, incendTrail, missileTrail;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
hitBulletSmall = new Effect(14, e -> {
|
||||
Draw.color(Color.WHITE, Palette.lightOrange, e.fin());
|
||||
|
||||
@@ -10,11 +10,11 @@ import io.anuke.ucore.graphics.Fill;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class EnvironmentFx extends FxList implements ContentList {
|
||||
public class EnvironmentFx extends FxList implements ContentList{
|
||||
public static Effect burning, fire, smoke, steam, fireballsmoke, ballfire, freezing, melting, wet, oily;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
burning = new Effect(35f, e -> {
|
||||
Draw.color(Palette.lightFlame, Palette.darkFlame, e.fin());
|
||||
|
||||
@@ -10,11 +10,11 @@ import io.anuke.ucore.graphics.Lines;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class ExplosionFx extends FxList implements ContentList {
|
||||
public class ExplosionFx extends FxList implements ContentList{
|
||||
public static Effect shockwave, bigShockwave, nuclearShockwave, explosion, blockExplosion, blockExplosionSmoke;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
shockwave = new Effect(10f, 80f, e -> {
|
||||
Draw.color(Color.WHITE, Color.LIGHT_GRAY, e.fin());
|
||||
|
||||
@@ -11,59 +11,59 @@ import io.anuke.ucore.util.Angles;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
|
||||
public class Fx extends FxList implements ContentList {
|
||||
public static Effect none, placeBlock, breakBlock, smoke, spawn, tapBlock, select;
|
||||
public class Fx extends FxList implements ContentList{
|
||||
public static Effect none, placeBlock, breakBlock, smoke, spawn, tapBlock, select;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
@Override
|
||||
public void load(){
|
||||
|
||||
none = new Effect(0, 0f, e -> {
|
||||
});
|
||||
none = new Effect(0, 0f, e -> {
|
||||
});
|
||||
|
||||
placeBlock = new Effect(16, e -> {
|
||||
Draw.color(Palette.accent);
|
||||
Lines.stroke(3f - e.fin() * 2f);
|
||||
Lines.square(e.x, e.y, tilesize / 2f * e.rotation + e.fin() * 3f);
|
||||
Draw.reset();
|
||||
});
|
||||
placeBlock = new Effect(16, e -> {
|
||||
Draw.color(Palette.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);
|
||||
Lines.stroke(3f - e.fin() * 2f);
|
||||
Lines.circle(e.x, e.y, 4f + (tilesize/1.5f * e.rotation) * e.fin());
|
||||
Draw.reset();
|
||||
});
|
||||
tapBlock = new Effect(12, e -> {
|
||||
Draw.color(Palette.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);
|
||||
Lines.stroke(3f - e.fin() * 2f);
|
||||
Lines.square(e.x, e.y, tilesize / 2f * e.rotation + e.fin() * 3f);
|
||||
breakBlock = new Effect(12, e -> {
|
||||
Draw.color(Palette.remove);
|
||||
Lines.stroke(3f - e.fin() * 2f);
|
||||
Lines.square(e.x, e.y, tilesize / 2f * e.rotation + e.fin() * 3f);
|
||||
|
||||
Angles.randLenVectors(e.id, 3 + (int) (e.rotation * 3), e.rotation * 2f + (tilesize * e.rotation) * e.finpow(), (x, y) -> {
|
||||
Fill.square(e.x + x, e.y + y, 1f + e.fout() * (3f + e.rotation));
|
||||
});
|
||||
Draw.reset();
|
||||
});
|
||||
Angles.randLenVectors(e.id, 3 + (int) (e.rotation * 3), e.rotation * 2f + (tilesize * e.rotation) * e.finpow(), (x, y) -> {
|
||||
Fill.square(e.x + x, e.y + y, 1f + e.fout() * (3f + e.rotation));
|
||||
});
|
||||
Draw.reset();
|
||||
});
|
||||
|
||||
select = new Effect(23, e -> {
|
||||
Draw.color(Palette.accent);
|
||||
Lines.stroke(e.fout() * 3f);
|
||||
Lines.circle(e.x, e.y, 3f + e.fin() * 14f);
|
||||
Draw.reset();
|
||||
});
|
||||
select = new Effect(23, e -> {
|
||||
Draw.color(Palette.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());
|
||||
float size = 7f - e.fin() * 7f;
|
||||
Draw.rect("circle", e.x, e.y, size, size);
|
||||
Draw.reset();
|
||||
});
|
||||
smoke = new Effect(100, e -> {
|
||||
Draw.color(Color.GRAY, Palette.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 -> {
|
||||
Lines.stroke(2f * e.fout());
|
||||
Draw.color(Palette.accent);
|
||||
Lines.poly(e.x, e.y, 4, 3f + e.fin() * 8f);
|
||||
Draw.reset();
|
||||
});
|
||||
}
|
||||
spawn = new Effect(23, e -> {
|
||||
Lines.stroke(2f * e.fout());
|
||||
Draw.color(Palette.accent);
|
||||
Lines.poly(e.x, e.y, 4, 3f + e.fin() * 8f);
|
||||
Draw.reset();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import io.anuke.mindustry.type.ContentList;
|
||||
public abstract class FxList implements ContentList{
|
||||
|
||||
@Override
|
||||
public Array<? extends Content> getAll() {
|
||||
public Array<? extends Content> getAll(){
|
||||
return Array.with();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,11 +12,11 @@ import io.anuke.ucore.graphics.Shapes;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class ShootFx extends FxList implements ContentList {
|
||||
public class ShootFx extends FxList implements ContentList{
|
||||
public static Effect shootSmall, shootSmallSmoke, shootBig, shootBig2, shootBigSmoke, shootBigSmoke2, shootSmallFlame, shootLiquid, shellEjectSmall, shellEjectMedium, shellEjectBig, lancerLaserShoot, lancerLaserShootSmoke, lancerLaserCharge, lancerLaserChargeBegin, lightningCharge, lightningShoot;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
shootSmall = new Effect(8, e -> {
|
||||
Draw.color(Palette.lighterOrange, Palette.lightOrange, e.fin());
|
||||
@@ -111,7 +111,7 @@ public class ShootFx extends FxList implements ContentList {
|
||||
shellEjectMedium = new GroundEffect(34f, 400f, e -> {
|
||||
Draw.color(Palette.lightOrange, Color.LIGHT_GRAY, Palette.lightishGray, e.fin());
|
||||
float rot = e.rotation + 90f;
|
||||
for (int i : Mathf.signs) {
|
||||
for(int i : Mathf.signs){
|
||||
float len = (2f + e.finpow() * 10f) * i;
|
||||
float lr = rot + e.fin() * 20f * i;
|
||||
Draw.rect("casing",
|
||||
@@ -122,7 +122,7 @@ public class ShootFx extends FxList implements ContentList {
|
||||
|
||||
Draw.color(Color.LIGHT_GRAY, Color.GRAY, e.fin());
|
||||
|
||||
for (int i : Mathf.signs) {
|
||||
for(int i : Mathf.signs){
|
||||
Angles.randLenVectors(e.id, 4, 1f + e.finpow() * 11f, e.rotation + 90f * i, 20f, (x, y) -> {
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 1.5f);
|
||||
});
|
||||
@@ -134,7 +134,7 @@ public class ShootFx extends FxList implements ContentList {
|
||||
shellEjectBig = new GroundEffect(22f, 400f, e -> {
|
||||
Draw.color(Palette.lightOrange, Color.LIGHT_GRAY, Palette.lightishGray, e.fin());
|
||||
float rot = e.rotation + 90f;
|
||||
for (int i : Mathf.signs) {
|
||||
for(int i : Mathf.signs){
|
||||
float len = (4f + e.finpow() * 8f) * i;
|
||||
float lr = rot + Mathf.randomSeedRange(e.id + i + 6, 20f * e.fin()) * i;
|
||||
Draw.rect("casing",
|
||||
@@ -146,7 +146,7 @@ public class ShootFx extends FxList implements ContentList {
|
||||
|
||||
Draw.color(Color.LIGHT_GRAY);
|
||||
|
||||
for (int i : Mathf.signs) {
|
||||
for(int i : Mathf.signs){
|
||||
Angles.randLenVectors(e.id, 4, -e.finpow() * 15f, e.rotation + 90f * i, 25f, (x, y) -> {
|
||||
Fill.circle(e.x + x, e.y + y, e.fout() * 2f);
|
||||
});
|
||||
@@ -158,7 +158,7 @@ public class ShootFx extends FxList implements ContentList {
|
||||
lancerLaserShoot = new Effect(21f, e -> {
|
||||
Draw.color(Palette.lancerLaser);
|
||||
|
||||
for (int i : Mathf.signs) {
|
||||
for(int i : Mathf.signs){
|
||||
Shapes.tri(e.x, e.y, 4f * e.fout(), 29f, e.rotation + 90f * i);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,11 +10,11 @@ import io.anuke.ucore.graphics.Lines;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class UnitFx extends FxList implements ContentList {
|
||||
public class UnitFx extends FxList implements ContentList{
|
||||
public static Effect vtolHover, unitDrop, unitPickup, pickup;
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
|
||||
vtolHover = new Effect(40f, e -> {
|
||||
float len = e.finpow() * 10f;
|
||||
|
||||
@@ -25,76 +25,80 @@ import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.function.Consumer;
|
||||
import io.anuke.ucore.util.Log;
|
||||
|
||||
/**Loads all game content.
|
||||
* Call load() before doing anything with content.*/
|
||||
public class ContentLoader {
|
||||
/**
|
||||
* Loads all game content.
|
||||
* Call load() before doing anything with content.
|
||||
*/
|
||||
public class ContentLoader{
|
||||
private static boolean loaded = false;
|
||||
private static ObjectSet<Array<? extends Content>> contentSet = new OrderedSet<>();
|
||||
private static OrderedMap<String, Array<Content>> contentMap = new OrderedMap<>();
|
||||
private static ObjectSet<Consumer<Content>> initialization = new ObjectSet<>();
|
||||
private static ContentList[] content = {
|
||||
//effects
|
||||
new BlockFx(),
|
||||
new BulletFx(),
|
||||
new EnvironmentFx(),
|
||||
new ExplosionFx(),
|
||||
new Fx(),
|
||||
new ShootFx(),
|
||||
new UnitFx(),
|
||||
//effects
|
||||
new BlockFx(),
|
||||
new BulletFx(),
|
||||
new EnvironmentFx(),
|
||||
new ExplosionFx(),
|
||||
new Fx(),
|
||||
new ShootFx(),
|
||||
new UnitFx(),
|
||||
|
||||
//items
|
||||
new Items(),
|
||||
//items
|
||||
new Items(),
|
||||
|
||||
//status effects
|
||||
new StatusEffects(),
|
||||
//status effects
|
||||
new StatusEffects(),
|
||||
|
||||
//liquids
|
||||
new Liquids(),
|
||||
//liquids
|
||||
new Liquids(),
|
||||
|
||||
//bullets
|
||||
new ArtilleryBullets(),
|
||||
new FlakBullets(),
|
||||
new MissileBullets(),
|
||||
new StandardBullets(),
|
||||
new TurretBullets(),
|
||||
new WeaponBullets(),
|
||||
//bullets
|
||||
new ArtilleryBullets(),
|
||||
new FlakBullets(),
|
||||
new MissileBullets(),
|
||||
new StandardBullets(),
|
||||
new TurretBullets(),
|
||||
new WeaponBullets(),
|
||||
|
||||
|
||||
//ammotypes
|
||||
new AmmoTypes(),
|
||||
//ammotypes
|
||||
new AmmoTypes(),
|
||||
|
||||
//weapons
|
||||
new Weapons(),
|
||||
//weapons
|
||||
new Weapons(),
|
||||
|
||||
//mechs
|
||||
new Mechs(),
|
||||
//mechs
|
||||
new Mechs(),
|
||||
|
||||
//units
|
||||
new UnitTypes(),
|
||||
//units
|
||||
new UnitTypes(),
|
||||
|
||||
//blocks
|
||||
new Blocks(),
|
||||
new DefenseBlocks(),
|
||||
new DistributionBlocks(),
|
||||
new ProductionBlocks(),
|
||||
new TurretBlocks(),
|
||||
new DebugBlocks(),
|
||||
new LiquidBlocks(),
|
||||
new StorageBlocks(),
|
||||
new UnitBlocks(),
|
||||
new PowerBlocks(),
|
||||
new CraftingBlocks(),
|
||||
new UpgradeBlocks(),
|
||||
new OreBlocks(),
|
||||
//blocks
|
||||
new Blocks(),
|
||||
new DefenseBlocks(),
|
||||
new DistributionBlocks(),
|
||||
new ProductionBlocks(),
|
||||
new TurretBlocks(),
|
||||
new DebugBlocks(),
|
||||
new LiquidBlocks(),
|
||||
new StorageBlocks(),
|
||||
new UnitBlocks(),
|
||||
new PowerBlocks(),
|
||||
new CraftingBlocks(),
|
||||
new UpgradeBlocks(),
|
||||
new OreBlocks(),
|
||||
|
||||
//not really a content class, but this makes initialization easier
|
||||
new ColorMapper(),
|
||||
//not really a content class, but this makes initialization easier
|
||||
new ColorMapper(),
|
||||
|
||||
//recipes
|
||||
new Recipes(),
|
||||
//recipes
|
||||
new Recipes(),
|
||||
};
|
||||
|
||||
/**Creates all content types.*/
|
||||
/**
|
||||
* Creates all content types.
|
||||
*/
|
||||
public static void load(){
|
||||
if(loaded){
|
||||
Log.info("Content already loaded, skipping.");
|
||||
@@ -103,11 +107,11 @@ public class ContentLoader {
|
||||
|
||||
registerTypes();
|
||||
|
||||
for (ContentList list : content){
|
||||
for(ContentList list : content){
|
||||
list.load();
|
||||
}
|
||||
|
||||
for (ContentList list : content){
|
||||
for(ContentList list : content){
|
||||
if(list.getAll().size != 0){
|
||||
String type = list.getAll().first().getContentTypeName();
|
||||
|
||||
@@ -134,7 +138,9 @@ public class ContentLoader {
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
/**Initializes all content with the specified function.*/
|
||||
/**
|
||||
* Initializes all content with the specified function.
|
||||
*/
|
||||
public static void initialize(Consumer<Content> callable){
|
||||
if(initialization.contains(callable)) return;
|
||||
|
||||
@@ -155,8 +161,10 @@ public class ContentLoader {
|
||||
return contentMap;
|
||||
}
|
||||
|
||||
/**Registers sync IDs for all types of sync entities.
|
||||
* Do not register units here!*/
|
||||
/**
|
||||
* Registers sync IDs for all types of sync entities.
|
||||
* Do not register units here!
|
||||
*/
|
||||
private static void registerTypes(){
|
||||
TypeTrait.registerType(Player.class, Player::new);
|
||||
TypeTrait.registerType(ItemDrop.class, ItemDrop::new);
|
||||
|
||||
@@ -20,7 +20,6 @@ import io.anuke.mindustry.input.MobileInput;
|
||||
import io.anuke.mindustry.io.Map;
|
||||
import io.anuke.mindustry.io.Saves;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.ucore.core.*;
|
||||
@@ -31,142 +30,146 @@ import io.anuke.ucore.util.Atlas;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
/**Control module.
|
||||
/**
|
||||
* Control module.
|
||||
* Handles all input, saving, keybinds and keybinds.
|
||||
* Should <i>not</i> handle any logic-critical state.
|
||||
* This class is not created in the headless server.*/
|
||||
* This class is not created in the headless server.
|
||||
*/
|
||||
public class Control extends Module{
|
||||
/**Minimum period of time between the same sound being played.*/
|
||||
private static final long minSoundPeriod = 100;
|
||||
/** Minimum period of time between the same sound being played.*/
|
||||
private static final long minSoundPeriod = 100;
|
||||
|
||||
private boolean hiscore = false;
|
||||
private boolean wasPaused = false;
|
||||
private Saves saves;
|
||||
private ContentDatabase db;
|
||||
private InputHandler[] inputs = {};
|
||||
private ObjectMap<Sound, Long> soundMap = new ObjectMap<>();
|
||||
private boolean hiscore = false;
|
||||
private boolean wasPaused = false;
|
||||
private Saves saves;
|
||||
private ContentDatabase db;
|
||||
private InputHandler[] inputs = {};
|
||||
private ObjectMap<Sound, Long> soundMap = new ObjectMap<>();
|
||||
|
||||
private Throwable error;
|
||||
private Input gdxInput;
|
||||
|
||||
public Control(){
|
||||
public Control(){
|
||||
|
||||
saves = new Saves();
|
||||
db = new ContentDatabase();
|
||||
saves = new Saves();
|
||||
db = new ContentDatabase();
|
||||
|
||||
Inputs.useControllers(!gwt);
|
||||
Inputs.useControllers(!gwt);
|
||||
|
||||
Gdx.input.setCatchBackKey(true);
|
||||
Gdx.input.setCatchBackKey(true);
|
||||
|
||||
Effects.setShakeFalloff(10000f);
|
||||
Effects.setShakeFalloff(10000f);
|
||||
|
||||
ContentLoader.initialize(Content::init);
|
||||
Core.atlas = new Atlas("sprites.atlas");
|
||||
Core.atlas.setErrorRegion("error");
|
||||
ContentLoader.initialize(Content::load);
|
||||
ContentLoader.initialize(Content::init);
|
||||
Core.atlas = new Atlas("sprites.atlas");
|
||||
Core.atlas.setErrorRegion("error");
|
||||
ContentLoader.initialize(Content::load);
|
||||
|
||||
db.load();
|
||||
db.load();
|
||||
|
||||
gdxInput = Gdx.input;
|
||||
gdxInput = Gdx.input;
|
||||
|
||||
Sounds.load("shoot.mp3", "place.mp3", "explosion.mp3", "enemyshoot.mp3",
|
||||
"corexplode.mp3", "break.mp3", "spawn.mp3", "flame.mp3", "die.mp3",
|
||||
"respawn.mp3", "purchase.mp3", "flame2.mp3", "bigshot.mp3", "laser.mp3", "lasershot.mp3",
|
||||
"ping.mp3", "tesla.mp3", "waveend.mp3", "railgun.mp3", "blast.mp3", "bang2.mp3");
|
||||
Sounds.load("shoot.mp3", "place.mp3", "explosion.mp3", "enemyshoot.mp3",
|
||||
"corexplode.mp3", "break.mp3", "spawn.mp3", "flame.mp3", "die.mp3",
|
||||
"respawn.mp3", "purchase.mp3", "flame2.mp3", "bigshot.mp3", "laser.mp3", "lasershot.mp3",
|
||||
"ping.mp3", "tesla.mp3", "waveend.mp3", "railgun.mp3", "blast.mp3", "bang2.mp3");
|
||||
|
||||
Sounds.setFalloff(9000f);
|
||||
Sounds.setPlayer((sound, volume) -> {
|
||||
long time = TimeUtils.millis();
|
||||
long value = soundMap.get(sound, 0L);
|
||||
Sounds.setFalloff(9000f);
|
||||
Sounds.setPlayer((sound, volume) -> {
|
||||
long time = TimeUtils.millis();
|
||||
long value = soundMap.get(sound, 0L);
|
||||
|
||||
if(TimeUtils.timeSinceMillis(value) >= minSoundPeriod){
|
||||
threads.run(() -> sound.play(volume));
|
||||
soundMap.put(sound, time);
|
||||
}
|
||||
});
|
||||
if(TimeUtils.timeSinceMillis(value) >= minSoundPeriod){
|
||||
threads.run(() -> sound.play(volume));
|
||||
soundMap.put(sound, time);
|
||||
}
|
||||
});
|
||||
|
||||
Musics.load("1.mp3", "2.mp3", "3.mp3", "4.mp3", "5.mp3", "6.mp3");
|
||||
|
||||
DefaultKeybinds.load();
|
||||
|
||||
Settings.defaultList(
|
||||
"ip", "localhost",
|
||||
"port", port+"",
|
||||
"color-0", Color.rgba8888(playerColors[8]),
|
||||
"color-1", Color.rgba8888(playerColors[11]),
|
||||
"color-2", Color.rgba8888(playerColors[13]),
|
||||
"color-3", Color.rgba8888(playerColors[9]),
|
||||
"name", "player",
|
||||
"lastBuild", 0
|
||||
);
|
||||
Settings.defaultList(
|
||||
"ip", "localhost",
|
||||
"port", port + "",
|
||||
"color-0", Color.rgba8888(playerColors[8]),
|
||||
"color-1", Color.rgba8888(playerColors[11]),
|
||||
"color-2", Color.rgba8888(playerColors[13]),
|
||||
"color-3", Color.rgba8888(playerColors[9]),
|
||||
"name", "player",
|
||||
"lastBuild", 0
|
||||
);
|
||||
|
||||
KeyBinds.load();
|
||||
KeyBinds.load();
|
||||
|
||||
addPlayer(0);
|
||||
addPlayer(0);
|
||||
|
||||
saves.load();
|
||||
saves.load();
|
||||
|
||||
Events.on(StateChangeEvent.class, (from, to) -> {
|
||||
if((from == State.playing && to == State.menu) || (from == State.menu && to != State.menu)){
|
||||
Timers.runTask(5f, Platform.instance::updateRPC);
|
||||
}
|
||||
});
|
||||
Events.on(StateChangeEvent.class, (from, to) -> {
|
||||
if((from == State.playing && to == State.menu) || (from == State.menu && to != State.menu)){
|
||||
Timers.runTask(5f, Platform.instance::updateRPC);
|
||||
}
|
||||
});
|
||||
|
||||
Events.on(PlayEvent.class, () -> {
|
||||
for(Player player : players){
|
||||
Events.on(PlayEvent.class, () -> {
|
||||
for(Player player : players){
|
||||
player.add();
|
||||
}
|
||||
|
||||
state.set(State.playing);
|
||||
});
|
||||
state.set(State.playing);
|
||||
});
|
||||
|
||||
Events.on(WorldLoadGraphicsEvent.class, () -> {
|
||||
if(mobile){
|
||||
Core.camera.position.set(players[0].x, players[0].y, 0);
|
||||
}
|
||||
});
|
||||
Events.on(WorldLoadGraphicsEvent.class, () -> {
|
||||
if(mobile){
|
||||
Core.camera.position.set(players[0].x, players[0].y, 0);
|
||||
}
|
||||
});
|
||||
|
||||
Events.on(ResetEvent.class, () -> {
|
||||
for(Player player : players){
|
||||
player.reset();
|
||||
Events.on(ResetEvent.class, () -> {
|
||||
for(Player player : players){
|
||||
player.reset();
|
||||
}
|
||||
|
||||
hiscore = false;
|
||||
hiscore = false;
|
||||
|
||||
saves.resetSave();
|
||||
});
|
||||
saves.resetSave();
|
||||
});
|
||||
|
||||
Events.on(WaveEvent.class, () -> {
|
||||
Events.on(WaveEvent.class, () -> {
|
||||
|
||||
int last = Settings.getInt("hiscore" + world.getMap().name, 0);
|
||||
int last = Settings.getInt("hiscore" + world.getMap().name, 0);
|
||||
|
||||
if(state.wave > last && !state.mode.infiniteResources && !state.mode.disableWaveTimer){
|
||||
Settings.putInt("hiscore" + world.getMap().name, state.wave);
|
||||
Settings.save();
|
||||
hiscore = true;
|
||||
}
|
||||
if(state.wave > last && !state.mode.infiniteResources && !state.mode.disableWaveTimer){
|
||||
Settings.putInt("hiscore" + world.getMap().name, state.wave);
|
||||
Settings.save();
|
||||
hiscore = true;
|
||||
}
|
||||
|
||||
Platform.instance.updateRPC();
|
||||
});
|
||||
Platform.instance.updateRPC();
|
||||
});
|
||||
|
||||
Events.on(GameOverEvent.class, () -> {
|
||||
Effects.shake(5, 6, Core.camera.position.x, Core.camera.position.y);
|
||||
Events.on(GameOverEvent.class, () -> {
|
||||
Effects.shake(5, 6, Core.camera.position.x, Core.camera.position.y);
|
||||
|
||||
//TODO game over effect
|
||||
ui.restart.show();
|
||||
//TODO game over effect
|
||||
ui.restart.show();
|
||||
|
||||
Timers.runTask(30f, () -> state.set(State.menu));
|
||||
});
|
||||
Timers.runTask(30f, () -> state.set(State.menu));
|
||||
});
|
||||
|
||||
Events.on(WorldLoadEvent.class, () -> threads.runGraphics(() -> Events.fire(WorldLoadGraphicsEvent.class)));
|
||||
}
|
||||
Events.on(WorldLoadEvent.class, () -> threads.runGraphics(() -> Events.fire(WorldLoadGraphicsEvent.class)));
|
||||
}
|
||||
|
||||
public void addPlayer(int index){
|
||||
if(players.length != index + 1){
|
||||
Player[] old = players;
|
||||
players = new Player[index + 1];
|
||||
public void addPlayer(int index){
|
||||
if(players.length != index + 1){
|
||||
Player[] old = players;
|
||||
players = new Player[index + 1];
|
||||
System.arraycopy(old, 0, players, 0, old.length);
|
||||
}
|
||||
|
||||
if(inputs.length != index + 1){
|
||||
InputHandler[] oldi = inputs;
|
||||
inputs = new InputHandler[index + 1];
|
||||
System.arraycopy(oldi, 0, inputs, 0, oldi.length);
|
||||
@@ -204,8 +207,8 @@ public class Control extends Module{
|
||||
}
|
||||
|
||||
public void removePlayer(){
|
||||
players[players.length-1].remove();
|
||||
inputs[inputs.length-1].remove();
|
||||
players[players.length - 1].remove();
|
||||
inputs[inputs.length - 1].remove();
|
||||
|
||||
Player[] old = players;
|
||||
players = new Player[players.length - 1];
|
||||
@@ -216,195 +219,191 @@ public class Control extends Module{
|
||||
System.arraycopy(oldi, 0, inputs, 0, inputs.length);
|
||||
}
|
||||
|
||||
public ContentDatabase database() {
|
||||
return db;
|
||||
}
|
||||
|
||||
public Input gdxInput(){
|
||||
return gdxInput;
|
||||
public ContentDatabase database(){
|
||||
return db;
|
||||
}
|
||||
|
||||
public void setError(Throwable error){
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public Saves getSaves(){
|
||||
return saves;
|
||||
}
|
||||
|
||||
public InputHandler input(int index){
|
||||
return inputs[index];
|
||||
}
|
||||
|
||||
public void triggerUpdateInput(){
|
||||
//Gdx.input = proxy;
|
||||
public Input gdxInput(){
|
||||
return gdxInput;
|
||||
}
|
||||
|
||||
public void playMap(Map map){
|
||||
ui.loadfrag.show();
|
||||
public void setError(Throwable error){
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
Timers.run(5f, () ->
|
||||
threads.run(() -> {
|
||||
logic.reset();
|
||||
world.loadMap(map);
|
||||
logic.play();
|
||||
public Saves getSaves(){
|
||||
return saves;
|
||||
}
|
||||
|
||||
Gdx.app.postRunnable(ui.loadfrag::hide);
|
||||
}));
|
||||
}
|
||||
public InputHandler input(int index){
|
||||
return inputs[index];
|
||||
}
|
||||
|
||||
public boolean isHighScore(){
|
||||
return hiscore;
|
||||
}
|
||||
public void triggerUpdateInput(){
|
||||
//Gdx.input = proxy;
|
||||
}
|
||||
|
||||
private void checkUnlockableBlocks(){
|
||||
TileEntity entity = players[0].getClosestCore();
|
||||
public void playMap(Map map){
|
||||
ui.loadfrag.show();
|
||||
|
||||
if(entity == null) return;
|
||||
Timers.run(5f, () ->
|
||||
threads.run(() -> {
|
||||
logic.reset();
|
||||
world.loadMap(map);
|
||||
logic.play();
|
||||
|
||||
for (int i = 0; i < entity.items.items.length; i++) {
|
||||
if(entity.items.items[i] <= 0) continue;
|
||||
Item item = Item.getByID(i);
|
||||
control.database().unlockContent(item);
|
||||
}
|
||||
Gdx.app.postRunnable(ui.loadfrag::hide);
|
||||
}));
|
||||
}
|
||||
|
||||
if(players[0].inventory.hasItem()){
|
||||
control.database().unlockContent(players[0].inventory.getItem().item);
|
||||
}
|
||||
public boolean isHighScore(){
|
||||
return hiscore;
|
||||
}
|
||||
|
||||
for(int i = 0 ; i < Recipe.all().size; i ++){
|
||||
Recipe recipe = Recipe.all().get(i);
|
||||
if(!recipe.debugOnly && entity.items.hasItems(recipe.requirements, 1.4f)){
|
||||
if(control.database().unlockContent(recipe)){
|
||||
ui.hudfrag.showUnlock(recipe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private void checkUnlockableBlocks(){
|
||||
TileEntity entity = players[0].getClosestCore();
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
Platform.instance.onGameExit();
|
||||
ContentLoader.dispose();
|
||||
Net.dispose();
|
||||
ui.editor.dispose();
|
||||
inputs = new InputHandler[]{};
|
||||
players = new Player[]{};
|
||||
}
|
||||
if(entity == null) return;
|
||||
|
||||
@Override
|
||||
public void pause(){
|
||||
wasPaused = state.is(State.paused);
|
||||
if(state.is(State.playing)) state.set(State.paused);
|
||||
}
|
||||
entity.items.forEach((item, amount) -> control.database().unlockContent(item));
|
||||
|
||||
@Override
|
||||
public void resume(){
|
||||
if(state.is(State.paused) && !wasPaused){
|
||||
if(players[0].inventory.hasItem()){
|
||||
control.database().unlockContent(players[0].inventory.getItem().item);
|
||||
}
|
||||
|
||||
for(int i = 0; i < Recipe.all().size; i++){
|
||||
Recipe recipe = Recipe.all().get(i);
|
||||
if(!recipe.debugOnly && entity.items.has(recipe.requirements, 1.4f)){
|
||||
if(control.database().unlockContent(recipe)){
|
||||
ui.hudfrag.showUnlock(recipe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
Platform.instance.onGameExit();
|
||||
ContentLoader.dispose();
|
||||
Net.dispose();
|
||||
ui.editor.dispose();
|
||||
inputs = new InputHandler[]{};
|
||||
players = new Player[]{};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pause(){
|
||||
wasPaused = state.is(State.paused);
|
||||
if(state.is(State.playing)) state.set(State.paused);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume(){
|
||||
if(state.is(State.paused) && !wasPaused){
|
||||
state.set(State.playing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
EntityPhysics.initPhysics();
|
||||
@Override
|
||||
public void init(){
|
||||
EntityPhysics.initPhysics();
|
||||
|
||||
Platform.instance.updateRPC();
|
||||
Platform.instance.updateRPC();
|
||||
|
||||
if(!Settings.has("4.0-warning")){
|
||||
Settings.putBool("4.0-warning", true);
|
||||
if(!Settings.has("4.0-warning")){
|
||||
Settings.putBool("4.0-warning", true);
|
||||
|
||||
Timers.run(5f, () -> {
|
||||
FloatingDialog dialog = new FloatingDialog("[orange]WARNING![]");
|
||||
dialog.buttons().addButton("$text.ok", dialog::hide).size(100f, 60f);
|
||||
dialog.content().add("The beta version you are about to play should be considered very unstable, and is [accent]not representative of the final 4.0 release.[]\n\n " +
|
||||
"A large portion of content is still unimplemented. \nAll 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.[] You have been warned!").wrap().width(500f);
|
||||
dialog.show();
|
||||
Timers.run(5f, () -> {
|
||||
FloatingDialog dialog = new FloatingDialog("[orange]WARNING![]");
|
||||
dialog.buttons().addButton("$text.ok", dialog::hide).size(100f, 60f);
|
||||
dialog.content().add("The beta version you are about to play should be considered very unstable, and is [accent]not representative of the final 4.0 release.[]\n\n " +
|
||||
"A large portion of content is still unimplemented. \nAll 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.[] You have been warned!").wrap().width(500f);
|
||||
dialog.show();
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if(!Settings.has("4.0-no-sound")){
|
||||
Settings.putBool("4.0-no-sound", true);
|
||||
if(!Settings.has("4.0-no-sound")){
|
||||
Settings.putBool("4.0-no-sound", true);
|
||||
|
||||
Timers.run(4f, () -> {
|
||||
FloatingDialog dialog = new FloatingDialog("[orange]Attention![]");
|
||||
dialog.buttons().addButton("$text.ok", dialog::hide).size(100f, 60f);
|
||||
dialog.content().add("You might have noticed that 4.0 does not have any sound.\nThis is [orange]intentional![] Sound will be added in a later update.\n\n[LIGHT_GRAY](now stop reporting this as a bug)").wrap().width(500f);
|
||||
dialog.show();
|
||||
Timers.run(4f, () -> {
|
||||
FloatingDialog dialog = new FloatingDialog("[orange]Attention![]");
|
||||
dialog.buttons().addButton("$text.ok", dialog::hide).size(100f, 60f);
|
||||
dialog.content().add("You might have noticed that 4.0 does not have any sound.\nThis is [orange]intentional![] Sound will be added in a later update.\n\n[LIGHT_GRAY](now stop reporting this as a bug)").wrap().width(500f);
|
||||
dialog.show();
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**Called from main logic thread.*/
|
||||
public void runUpdateLogic(){
|
||||
if(!state.is(State.menu)) {
|
||||
renderer.minimap().updateUnitArray();
|
||||
}
|
||||
}
|
||||
/** Called from main logic thread.*/
|
||||
public void runUpdateLogic(){
|
||||
if(!state.is(State.menu)){
|
||||
renderer.minimap().updateUnitArray();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
@Override
|
||||
public void update(){
|
||||
|
||||
if(error != null){
|
||||
throw new RuntimeException(error);
|
||||
}
|
||||
if(error != null){
|
||||
throw new RuntimeException(error);
|
||||
}
|
||||
|
||||
if(Inputs.keyTap("console")){
|
||||
console = !console;
|
||||
}
|
||||
console = !console;
|
||||
}
|
||||
|
||||
saves.update();
|
||||
|
||||
triggerUpdateInput();
|
||||
triggerUpdateInput();
|
||||
|
||||
for(InputHandler inputHandler : inputs){
|
||||
inputHandler.updateController();
|
||||
}
|
||||
for(InputHandler inputHandler : inputs){
|
||||
inputHandler.updateController();
|
||||
}
|
||||
|
||||
if(!state.is(State.menu)){
|
||||
for(InputHandler input : inputs){
|
||||
input.update();
|
||||
if(!state.is(State.menu)){
|
||||
for(InputHandler input : inputs){
|
||||
input.update();
|
||||
}
|
||||
|
||||
//check unlocks every 2 seconds
|
||||
if(!state.mode.infiniteResources && Timers.get("timerCheckUnlock", 120)){
|
||||
checkUnlockableBlocks();
|
||||
if(!state.mode.infiniteResources && Timers.get("timerCheckUnlock", 120)){
|
||||
checkUnlockableBlocks();
|
||||
|
||||
//save if the db changed, but don't save unlocks
|
||||
if(db.isDirty() && !debug){
|
||||
db.save();
|
||||
}
|
||||
}
|
||||
//save if the db changed, but don't save unlocks
|
||||
if(db.isDirty() && !debug){
|
||||
db.save();
|
||||
}
|
||||
}
|
||||
|
||||
if(Inputs.keyTap("pause") && !ui.restart.isShown() && (state.is(State.paused) || state.is(State.playing))){
|
||||
if(Inputs.keyTap("pause") && !ui.restart.isShown() && (state.is(State.paused) || state.is(State.playing))){
|
||||
state.set(state.is(State.playing) ? State.paused : State.playing);
|
||||
}
|
||||
}
|
||||
|
||||
if(Inputs.keyTap("menu")){
|
||||
if(state.is(State.paused)){
|
||||
ui.paused.hide();
|
||||
if(Inputs.keyTap("menu")){
|
||||
if(state.is(State.paused)){
|
||||
ui.paused.hide();
|
||||
state.set(State.playing);
|
||||
}else if (!ui.restart.isShown()){
|
||||
if(ui.chatfrag.chatOpen()) {
|
||||
ui.chatfrag.hide();
|
||||
}else{
|
||||
ui.paused.show();
|
||||
}else if(!ui.restart.isShown()){
|
||||
if(ui.chatfrag.chatOpen()){
|
||||
ui.chatfrag.hide();
|
||||
}else{
|
||||
ui.paused.show();
|
||||
state.set(State.paused);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!state.is(State.paused) || Net.active()){
|
||||
Entities.update(effectGroup);
|
||||
Entities.update(groundEffectGroup);
|
||||
}
|
||||
}else{
|
||||
if(!state.is(State.paused) || Net.active()){
|
||||
Timers.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!state.is(State.paused) || Net.active()){
|
||||
Entities.update(effectGroup);
|
||||
Entities.update(groundEffectGroup);
|
||||
}
|
||||
}else{
|
||||
if(!state.is(State.paused) || Net.active()){
|
||||
Timers.update();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,31 +8,30 @@ import io.anuke.mindustry.game.TeamInfo;
|
||||
import io.anuke.ucore.core.Events;
|
||||
|
||||
public class GameState{
|
||||
private State state = State.menu;
|
||||
public int wave = 1;
|
||||
public float wavetime;
|
||||
public boolean gameOver = false;
|
||||
public GameMode mode = GameMode.waves;
|
||||
public Difficulty difficulty = Difficulty.normal;
|
||||
public boolean friendlyFire;
|
||||
public WaveSpawner spawner = new WaveSpawner();
|
||||
public TeamInfo teams = new TeamInfo();
|
||||
private State state = State.menu;
|
||||
|
||||
public int wave = 1;
|
||||
public float wavetime;
|
||||
public boolean gameOver = false;
|
||||
public GameMode mode = GameMode.waves;
|
||||
public Difficulty difficulty = Difficulty.normal;
|
||||
public boolean friendlyFire;
|
||||
public WaveSpawner spawner = new WaveSpawner();
|
||||
public TeamInfo teams = new TeamInfo();
|
||||
|
||||
public void set(State astate){
|
||||
Events.fire(StateChangeEvent.class, state, astate);
|
||||
state = astate;
|
||||
}
|
||||
|
||||
public boolean is(State astate){
|
||||
return state == astate;
|
||||
}
|
||||
public void set(State astate){
|
||||
Events.fire(StateChangeEvent.class, state, astate);
|
||||
state = astate;
|
||||
}
|
||||
|
||||
public State getState(){
|
||||
return state;
|
||||
}
|
||||
|
||||
public enum State{
|
||||
paused, playing, menu
|
||||
}
|
||||
public boolean is(State astate){
|
||||
return state == astate;
|
||||
}
|
||||
|
||||
public State getState(){
|
||||
return state;
|
||||
}
|
||||
|
||||
public enum State{
|
||||
paused, playing, menu
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,13 +24,15 @@ import io.anuke.ucore.modules.Module;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
/**Logic module.
|
||||
/**
|
||||
* Logic module.
|
||||
* Handles all logic for entities and waves.
|
||||
* Handles game state events.
|
||||
* Does not store any game state itself.
|
||||
*
|
||||
* This class should <i>not</i> call any outside methods to change state of modules, but instead fire events.*/
|
||||
public class Logic extends Module {
|
||||
* <p>
|
||||
* This class should <i>not</i> call any outside methods to change state of modules, but instead fire events.
|
||||
*/
|
||||
public class Logic extends Module{
|
||||
public boolean doUpdate = true;
|
||||
|
||||
public Logic(){
|
||||
@@ -49,17 +51,17 @@ public class Logic extends Module {
|
||||
|
||||
//fill inventory with items for debugging
|
||||
|
||||
for (TeamData team : state.teams.getTeams()) {
|
||||
for (Tile tile : team.cores) {
|
||||
if(debug) {
|
||||
for (Item item : Item.all()) {
|
||||
if (item.type == ItemType.material) {
|
||||
tile.entity.items.addItem(item, 1000);
|
||||
for(TeamData team : state.teams.getTeams()){
|
||||
for(Tile tile : team.cores){
|
||||
if(debug){
|
||||
for(Item item : Item.all()){
|
||||
if(item.type == ItemType.material){
|
||||
tile.entity.items.add(item, 1000);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
tile.entity.items.addItem(Items.tungsten, 50);
|
||||
tile.entity.items.addItem(Items.lead, 20);
|
||||
tile.entity.items.add(Items.tungsten, 50);
|
||||
tile.entity.items.add(Items.lead, 20);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,7 +87,7 @@ public class Logic extends Module {
|
||||
|
||||
public void runWave(){
|
||||
state.spawner.spawnEnemies();
|
||||
state.wave ++;
|
||||
state.wave++;
|
||||
state.wavetime = wavespace * state.difficulty.timeScaling;
|
||||
|
||||
Events.fire(WaveEvent.class);
|
||||
@@ -137,7 +139,8 @@ public class Logic extends Module {
|
||||
runWave();
|
||||
}
|
||||
|
||||
if(!Entities.defaultGroup().isEmpty()) throw new RuntimeException("Do not add anything to the default group!");
|
||||
if(!Entities.defaultGroup().isEmpty())
|
||||
throw new RuntimeException("Do not add anything to the default group!");
|
||||
|
||||
Entities.update(bulletGroup);
|
||||
for(EntityGroup group : unitGroups){
|
||||
@@ -158,13 +161,6 @@ public class Logic extends Module {
|
||||
for(EntityGroup group : unitGroups){
|
||||
if(!group.isEmpty()){
|
||||
EntityPhysics.collideGroups(bulletGroup, group);
|
||||
|
||||
/*
|
||||
for(EntityGroup other : unitGroups){
|
||||
if(!other.isEmpty()){
|
||||
EntityPhysics.collideGroups(group, other);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package io.anuke.mindustry.core;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.Base64Coder;
|
||||
import com.badlogic.gdx.utils.IntSet;
|
||||
@@ -35,38 +36,64 @@ import java.util.Random;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class NetClient extends Module {
|
||||
private final static float dataTimeout = 60*18;
|
||||
public class NetClient extends Module{
|
||||
private final static float dataTimeout = 60 * 18;
|
||||
private final static float playerSyncTime = 2;
|
||||
|
||||
private Timer timer = new Timer(5);
|
||||
/**Whether the client is currently connecting.*/
|
||||
/**
|
||||
* Whether the client is currently connecting.
|
||||
*/
|
||||
private boolean connecting = false;
|
||||
/**If true, no message will be shown on disconnect.*/
|
||||
/**
|
||||
* If true, no message will be shown on disconnect.
|
||||
*/
|
||||
private boolean quiet = false;
|
||||
/**Counter for data timeout.*/
|
||||
/**
|
||||
* Counter for data timeout.
|
||||
*/
|
||||
private float timeoutTime = 0f;
|
||||
/**Last sent client snapshot ID.*/
|
||||
/**
|
||||
* Last sent client snapshot ID.
|
||||
*/
|
||||
private int lastSent;
|
||||
|
||||
/**Last snapshot ID recieved.*/
|
||||
/**
|
||||
* Last snapshot ID recieved.
|
||||
*/
|
||||
private int lastSnapshotBaseID = -1;
|
||||
/**Last snapshot recieved.*/
|
||||
/**
|
||||
* Last snapshot recieved.
|
||||
*/
|
||||
private byte[] lastSnapshotBase;
|
||||
/**Current snapshot that is being built from chinks.*/
|
||||
/**
|
||||
* Current snapshot that is being built from chinks.
|
||||
*/
|
||||
private byte[] currentSnapshot;
|
||||
/**Array of recieved chunk statuses.*/
|
||||
/**
|
||||
* Array of recieved chunk statuses.
|
||||
*/
|
||||
private boolean[] recievedChunks;
|
||||
/**Counter of how many chunks have been recieved.*/
|
||||
/**
|
||||
* Counter of how many chunks have been recieved.
|
||||
*/
|
||||
private int recievedChunkCounter;
|
||||
/**ID of snapshot that is currently being constructed.*/
|
||||
/**
|
||||
* ID of snapshot that is currently being constructed.
|
||||
*/
|
||||
private int currentSnapshotID = -1;
|
||||
|
||||
/**Decoder for uncompressing snapshots.*/
|
||||
/**
|
||||
* Decoder for uncompressing snapshots.
|
||||
*/
|
||||
private DEZDecoder decoder = new DEZDecoder();
|
||||
/**List of entities that were removed, and need not be added while syncing.*/
|
||||
/**
|
||||
* List of entities that were removed, and need not be added while syncing.
|
||||
*/
|
||||
private IntSet removed = new IntSet();
|
||||
/**Byte stream for reading in snapshots.*/
|
||||
/**
|
||||
* Byte stream for reading in snapshots.
|
||||
*/
|
||||
private ReusableByteArrayInputStream byteStream = new ReusableByteArrayInputStream();
|
||||
private DataInputStream dataStream = new DataInputStream(byteStream);
|
||||
|
||||
@@ -119,7 +146,7 @@ public class NetClient extends Module {
|
||||
});
|
||||
|
||||
Net.handleClient(Disconnect.class, packet -> {
|
||||
if (quiet) return;
|
||||
if(quiet) return;
|
||||
|
||||
Timers.runTask(3f, ui.loadfrag::hide);
|
||||
|
||||
@@ -144,6 +171,166 @@ public class NetClient extends Module {
|
||||
});
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.one, priority = PacketPriority.high)
|
||||
public static void onKick(KickReason reason){
|
||||
netClient.disconnectQuietly();
|
||||
state.set(State.menu);
|
||||
if(!reason.quiet) ui.showError("$text.server.kicked." + reason.name());
|
||||
ui.loadfrag.hide();
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.one)
|
||||
public static void onPositionSet(float x, float y){
|
||||
players[0].x = x;
|
||||
players[0].y = y;
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.one)
|
||||
public static void onTraceInfo(TraceInfo info){
|
||||
Player player = playerGroup.getByID(info.playerid);
|
||||
ui.traces.show(player, info);
|
||||
}
|
||||
|
||||
@Remote
|
||||
public static void onPlayerDisconnect(int playerid){
|
||||
playerGroup.removeByID(playerid);
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true)
|
||||
public static void onSnapshot(byte[] chunk, int snapshotID, short chunkID, int totalLength, int base){
|
||||
if(NetServer.showSnapshotSize)
|
||||
Log.info("Recieved snapshot: len {0} ID {1} chunkID {2} totalLength {3} base {4} client-base {5}", chunk.length, snapshotID, chunkID, totalLength, base, netClient.lastSnapshotBaseID);
|
||||
|
||||
//skip snapshot IDs that have already been recieved OR snapshots that are too far in front
|
||||
if(snapshotID < netClient.lastSnapshotBaseID || base != netClient.lastSnapshotBaseID){
|
||||
if(NetServer.showSnapshotSize) Log.info("//SKIP SNAPSHOT");
|
||||
return;
|
||||
}
|
||||
|
||||
try{
|
||||
byte[] snapshot;
|
||||
|
||||
//total length exceeds that needed to hold one snapshot, therefore, it is split into chunks
|
||||
if(totalLength > NetServer.maxSnapshotSize){
|
||||
//total amount of chunks to recieve
|
||||
int totalChunks = Mathf.ceil((float) totalLength / NetServer.maxSnapshotSize);
|
||||
|
||||
//reset status when a new snapshot sending begins
|
||||
if(netClient.currentSnapshotID != snapshotID){
|
||||
netClient.currentSnapshotID = snapshotID;
|
||||
netClient.currentSnapshot = new byte[totalLength];
|
||||
netClient.recievedChunkCounter = 0;
|
||||
netClient.recievedChunks = new boolean[totalChunks];
|
||||
}
|
||||
|
||||
//if this chunk hasn't been recieved yet...
|
||||
if(!netClient.recievedChunks[chunkID]){
|
||||
netClient.recievedChunks[chunkID] = true;
|
||||
netClient.recievedChunkCounter++; //update recieved status
|
||||
//copy the recieved bytes into the holding array
|
||||
System.arraycopy(chunk, 0, netClient.currentSnapshot, chunkID * NetServer.maxSnapshotSize,
|
||||
Math.min(NetServer.maxSnapshotSize, totalLength - chunkID * NetServer.maxSnapshotSize));
|
||||
}
|
||||
|
||||
//when all chunks have been recieved, begin
|
||||
if(netClient.recievedChunkCounter >= totalChunks){
|
||||
snapshot = netClient.currentSnapshot;
|
||||
}else{
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
snapshot = chunk;
|
||||
}
|
||||
|
||||
if(NetServer.showSnapshotSize)
|
||||
Log.info("Finished recieving snapshot ID {0} length {1}", snapshotID, chunk.length);
|
||||
|
||||
byte[] result;
|
||||
int length;
|
||||
if(base == -1){ //fresh snapshot
|
||||
result = snapshot;
|
||||
length = snapshot.length;
|
||||
netClient.lastSnapshotBase = Arrays.copyOf(snapshot, snapshot.length);
|
||||
}else{ //otherwise, last snapshot must not be null, decode it
|
||||
if(NetServer.showSnapshotSize)
|
||||
Log.info("Base size: {0} Patch size: {1}", netClient.lastSnapshotBase.length, snapshot.length);
|
||||
netClient.decoder.init(netClient.lastSnapshotBase, snapshot);
|
||||
result = netClient.decoder.decode();
|
||||
length = netClient.decoder.getDecodedLength();
|
||||
//set last snapshot to a copy to prevent issues
|
||||
netClient.lastSnapshotBase = Arrays.copyOf(result, length);
|
||||
}
|
||||
|
||||
netClient.lastSnapshotBaseID = snapshotID;
|
||||
|
||||
//set stream bytes to begin snapshot reaeding
|
||||
netClient.byteStream.setBytes(result, 0, length);
|
||||
|
||||
//get data input for reading from the stream
|
||||
DataInputStream input = netClient.dataStream;
|
||||
|
||||
//read wave info
|
||||
state.wavetime = input.readFloat();
|
||||
state.wave = input.readInt();
|
||||
|
||||
byte cores = input.readByte();
|
||||
for(int i = 0; i < cores; i++){
|
||||
int pos = input.readInt();
|
||||
world.tile(pos).entity.items.read(input);
|
||||
}
|
||||
|
||||
long timestamp = input.readLong();
|
||||
|
||||
byte totalGroups = input.readByte();
|
||||
//for each group...
|
||||
for(int i = 0; i < totalGroups; i++){
|
||||
//read group info
|
||||
byte groupID = input.readByte();
|
||||
short amount = input.readShort();
|
||||
|
||||
EntityGroup group = Entities.getGroup(groupID);
|
||||
|
||||
//go through each entity
|
||||
for(int j = 0; j < amount; j++){
|
||||
int position = netClient.byteStream.position(); //save position to check read/write correctness
|
||||
int id = input.readInt();
|
||||
byte typeID = input.readByte();
|
||||
|
||||
SyncTrait entity = (SyncTrait) group.getByID(id);
|
||||
boolean add = false;
|
||||
|
||||
//entity must not be added yet, so create it
|
||||
if(entity == null){
|
||||
entity = (SyncTrait) TypeTrait.getTypeByID(typeID).get(); //create entity from supplier
|
||||
entity.resetID(id);
|
||||
if(!netClient.isEntityUsed(entity.getID())){
|
||||
add = true;
|
||||
}
|
||||
}
|
||||
|
||||
//read the entity
|
||||
entity.read(input, timestamp);
|
||||
|
||||
byte readLength = input.readByte();
|
||||
if(netClient.byteStream.position() - position - 1 != readLength){
|
||||
throw new RuntimeException("Error reading entity of type '" + group.getType() + "': Read length mismatch [write=" + readLength + ", read=" + (netClient.byteStream.position() - position - 1) + "]");
|
||||
}
|
||||
|
||||
if(add){
|
||||
entity.add();
|
||||
netClient.addRemovedEntity(entity.getID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//confirm that snapshot has been recieved
|
||||
netClient.lastSnapshotBaseID = snapshotID;
|
||||
|
||||
}catch(Exception e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
if(!Net.client()) return;
|
||||
@@ -175,7 +362,7 @@ public class NetClient extends Module {
|
||||
ui.loadfrag.hide();
|
||||
ui.join.hide();
|
||||
Net.setClientLoaded(true);
|
||||
Call.connectConfirm();
|
||||
Gdx.app.postRunnable(Call::connectConfirm);
|
||||
Timers.runTask(40f, Platform.instance::updateRPC);
|
||||
}
|
||||
|
||||
@@ -223,161 +410,4 @@ public class NetClient extends Module {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.one, priority = PacketPriority.high)
|
||||
public static void onKick(KickReason reason){
|
||||
netClient.disconnectQuietly();
|
||||
state.set(State.menu);
|
||||
if(!reason.quiet) ui.showError("$text.server.kicked." + reason.name());
|
||||
ui.loadfrag.hide();
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.one)
|
||||
public static void onPositionSet(float x, float y){
|
||||
players[0].x = x;
|
||||
players[0].y = y;
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.one)
|
||||
public static void onTraceInfo(TraceInfo info){
|
||||
Player player = playerGroup.getByID(info.playerid);
|
||||
ui.traces.show(player, info);
|
||||
}
|
||||
|
||||
@Remote
|
||||
public static void onPlayerDisconnect(int playerid){
|
||||
playerGroup.removeByID(playerid);
|
||||
}
|
||||
|
||||
@Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true)
|
||||
public static void onSnapshot(byte[] chunk, int snapshotID, short chunkID, short totalLength, int base){
|
||||
if(NetServer.showSnapshotSize) Log.info("Recieved snapshot: len {0} ID {1} chunkID {2} totalLength {3} base {4} client-base {5}", chunk.length, snapshotID, chunkID, totalLength, base, netClient.lastSnapshotBaseID);
|
||||
|
||||
//skip snapshot IDs that have already been recieved OR snapshots that are too far in front
|
||||
if(snapshotID < netClient.lastSnapshotBaseID || base != netClient.lastSnapshotBaseID){
|
||||
if(NetServer.showSnapshotSize) Log.info("//SKIP SNAPSHOT");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
byte[] snapshot;
|
||||
|
||||
//total length exceeds that needed to hold one snapshot, therefore, it is split into chunks
|
||||
if(totalLength > NetServer.maxSnapshotSize) {
|
||||
//total amount of chunks to recieve
|
||||
int totalChunks = Mathf.ceil((float) totalLength / NetServer.maxSnapshotSize);
|
||||
|
||||
//reset status when a new snapshot sending begins
|
||||
if (netClient.currentSnapshotID != snapshotID) {
|
||||
netClient.currentSnapshotID = snapshotID;
|
||||
netClient.currentSnapshot = new byte[totalLength];
|
||||
netClient.recievedChunkCounter = 0;
|
||||
netClient.recievedChunks = new boolean[totalChunks];
|
||||
}
|
||||
|
||||
//if this chunk hasn't been recieved yet...
|
||||
if (!netClient.recievedChunks[chunkID]) {
|
||||
netClient.recievedChunks[chunkID] = true;
|
||||
netClient.recievedChunkCounter ++; //update recieved status
|
||||
//copy the recieved bytes into the holding array
|
||||
System.arraycopy(chunk, 0, netClient.currentSnapshot, chunkID * NetServer.maxSnapshotSize,
|
||||
Math.min(NetServer.maxSnapshotSize, totalLength - chunkID * NetServer.maxSnapshotSize));
|
||||
}
|
||||
|
||||
//when all chunks have been recieved, begin
|
||||
if(netClient.recievedChunkCounter >= totalChunks){
|
||||
snapshot = netClient.currentSnapshot;
|
||||
}else{
|
||||
return;
|
||||
}
|
||||
}else{
|
||||
snapshot = chunk;
|
||||
}
|
||||
|
||||
if(NetServer.showSnapshotSize) Log.info("Finished recieving snapshot ID {0} length {1}", snapshotID, chunk.length);
|
||||
|
||||
byte[] result;
|
||||
int length;
|
||||
if (base == -1) { //fresh snapshot
|
||||
result = snapshot;
|
||||
length = snapshot.length;
|
||||
netClient.lastSnapshotBase = Arrays.copyOf(snapshot, snapshot.length);
|
||||
} else { //otherwise, last snapshot must not be null, decode it
|
||||
if(NetServer.showSnapshotSize) Log.info("Base size: {0} Patch size: {1}", netClient.lastSnapshotBase.length, snapshot.length);
|
||||
netClient.decoder.init(netClient.lastSnapshotBase, snapshot);
|
||||
result = netClient.decoder.decode();
|
||||
length = netClient.decoder.getDecodedLength();
|
||||
//set last snapshot to a copy to prevent issues
|
||||
netClient.lastSnapshotBase = Arrays.copyOf(result, length);
|
||||
}
|
||||
|
||||
netClient.lastSnapshotBaseID = snapshotID;
|
||||
|
||||
//set stream bytes to begin snapshot reaeding
|
||||
netClient.byteStream.setBytes(result, 0, length);
|
||||
|
||||
//get data input for reading from the stream
|
||||
DataInputStream input = netClient.dataStream;
|
||||
|
||||
//read wave info
|
||||
state.wavetime = input.readFloat();
|
||||
state.wave = input.readInt();
|
||||
|
||||
byte cores = input.readByte();
|
||||
for (int i = 0; i < cores; i++) {
|
||||
int pos = input.readInt();
|
||||
world.tile(pos).entity.items.read(input);
|
||||
}
|
||||
|
||||
long timestamp = input.readLong();
|
||||
|
||||
byte totalGroups = input.readByte();
|
||||
//for each group...
|
||||
for (int i = 0; i < totalGroups; i++) {
|
||||
//read group info
|
||||
byte groupID = input.readByte();
|
||||
short amount = input.readShort();
|
||||
|
||||
EntityGroup group = Entities.getGroup(groupID);
|
||||
|
||||
//go through each entity
|
||||
for (int j = 0; j < amount; j++) {
|
||||
int position = netClient.byteStream.position(); //save position to check read/write correctness
|
||||
int id = input.readInt();
|
||||
byte typeID = input.readByte();
|
||||
|
||||
SyncTrait entity = (SyncTrait) group.getByID(id);
|
||||
boolean add = false;
|
||||
|
||||
//entity must not be added yet, so create it
|
||||
if(entity == null){
|
||||
entity = (SyncTrait) TypeTrait.getTypeByID(typeID).get(); //create entity from supplier
|
||||
entity.resetID(id);
|
||||
if(!netClient.isEntityUsed(entity.getID())){
|
||||
add = true;
|
||||
}
|
||||
}
|
||||
|
||||
//read the entity
|
||||
entity.read(input, timestamp);
|
||||
|
||||
byte readLength = input.readByte();
|
||||
if(netClient.byteStream.position() - position - 1 != readLength){
|
||||
throw new RuntimeException("Error reading entity of type '"+ group.getType() + "': Read length mismatch [write=" + readLength + ", read=" + (netClient.byteStream.position() - position - 1)+ "]");
|
||||
}
|
||||
|
||||
if(add){
|
||||
entity.add();
|
||||
netClient.addRemovedEntity(entity.getID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//confirm that snapshot has been recieved
|
||||
netClient.lastSnapshotBaseID = snapshotID;
|
||||
|
||||
}catch (Exception e){
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,20 +45,30 @@ public class NetServer extends Module{
|
||||
private final static byte[] reusableSnapArray = new byte[maxSnapshotSize];
|
||||
private final static float serverSyncTime = 4, kickDuration = 30 * 1000;
|
||||
private final static Vector2 vector = new Vector2();
|
||||
/**If a play goes away of their server-side coordinates by this distance, they get teleported back.*/
|
||||
/**
|
||||
* If a play goes away of their server-side coordinates by this distance, they get teleported back.
|
||||
*/
|
||||
private final static float correctDist = 16f;
|
||||
|
||||
public final Administration admins = new Administration();
|
||||
|
||||
/**Maps connection IDs to players.*/
|
||||
/**
|
||||
* Maps connection IDs to players.
|
||||
*/
|
||||
private IntMap<Player> connections = new IntMap<>();
|
||||
private boolean closing = false;
|
||||
|
||||
/**Stream for writing player sync data to.*/
|
||||
/**
|
||||
* Stream for writing player sync data to.
|
||||
*/
|
||||
private CountableByteArrayOutputStream syncStream = new CountableByteArrayOutputStream();
|
||||
/**Data stream for writing player sync data to.*/
|
||||
/**
|
||||
* Data stream for writing player sync data to.
|
||||
*/
|
||||
private DataOutputStream dataStream = new DataOutputStream(syncStream);
|
||||
/**Encoder for computing snapshot deltas.*/
|
||||
/**
|
||||
* Encoder for computing snapshot deltas.
|
||||
*/
|
||||
private DEZEncoder encoder = new DEZEncoder();
|
||||
|
||||
public NetServer(){
|
||||
@@ -105,14 +115,14 @@ public class NetServer extends Module{
|
||||
|
||||
boolean preventDuplicates = headless;
|
||||
|
||||
if(preventDuplicates) {
|
||||
for (Player player : playerGroup.all()) {
|
||||
if (player.name.equalsIgnoreCase(packet.name)) {
|
||||
if(preventDuplicates){
|
||||
for(Player player : playerGroup.all()){
|
||||
if(player.name.equalsIgnoreCase(packet.name)){
|
||||
kick(id, KickReason.nameInUse);
|
||||
return;
|
||||
}
|
||||
|
||||
if (player.uuid.equals(packet.uuid)) {
|
||||
if(player.uuid.equals(packet.uuid)){
|
||||
kick(id, KickReason.idInUse);
|
||||
return;
|
||||
}
|
||||
@@ -181,7 +191,7 @@ public class NetServer extends Module{
|
||||
|
||||
long elapsed = TimeUtils.timeSinceMillis(connection.lastRecievedClientTime);
|
||||
|
||||
float maxSpeed = (packet.boosting && !player.mech.flying ? player.mech.boostSpeed : player.mech.speed)*2.5f;
|
||||
float maxSpeed = (packet.boosting && !player.mech.flying ? player.mech.boostSpeed : player.mech.speed) * 2.5f;
|
||||
|
||||
//extra 1.1x multiplicaton is added just in case
|
||||
float maxMove = elapsed / 1000f * 60f * maxSpeed * 1.1f;
|
||||
@@ -238,6 +248,86 @@ public class NetServer extends Module{
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a raw byte[] snapshot to a client, splitting up into chunks when needed.
|
||||
*/
|
||||
private static void sendSplitSnapshot(int userid, byte[] bytes, int snapshotID, int base){
|
||||
if(bytes.length < maxSnapshotSize){
|
||||
Call.onSnapshot(userid, bytes, snapshotID, (short) 0, bytes.length, base);
|
||||
}else{
|
||||
int remaining = bytes.length;
|
||||
int offset = 0;
|
||||
int chunkid = 0;
|
||||
while(remaining > 0){
|
||||
int used = Math.min(remaining, maxSnapshotSize);
|
||||
byte[] toSend;
|
||||
//re-use sent byte arrays when possible
|
||||
if(used == maxSnapshotSize){
|
||||
toSend = reusableSnapArray;
|
||||
System.arraycopy(bytes, offset, toSend, 0, Math.min(offset + maxSnapshotSize, bytes.length) - offset);
|
||||
}else{
|
||||
toSend = Arrays.copyOfRange(bytes, offset, Math.min(offset + maxSnapshotSize, bytes.length));
|
||||
}
|
||||
Call.onSnapshot(userid, toSend, snapshotID, (short) chunkid, bytes.length, base);
|
||||
|
||||
remaining -= used;
|
||||
offset += used;
|
||||
chunkid++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void onDisconnect(Player player){
|
||||
Call.sendMessage("[accent]" + player.name + " has disconnected.");
|
||||
Call.onPlayerDisconnect(player.id);
|
||||
player.remove();
|
||||
netServer.connections.remove(player.con.id);
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.client, called = Loc.server)
|
||||
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.",
|
||||
player.name, player.con.address);
|
||||
return;
|
||||
}
|
||||
|
||||
if(other == null || (other.isAdmin && other != player)){ //fun fact: this means you can ban yourself
|
||||
Log.err("{0} attempted to perform admin action on nonexistant or admin player.", player.name);
|
||||
return;
|
||||
}
|
||||
|
||||
if(action == AdminAction.wave){
|
||||
//no verification is done, so admins can hypothetically spam waves
|
||||
//not a real issue, because server owners may want to do just that
|
||||
state.wavetime = 0f;
|
||||
}else if(action == AdminAction.ban){
|
||||
netServer.admins.banPlayerIP(other.con.address);
|
||||
netServer.kick(other.con.id, KickReason.banned);
|
||||
Log.info("&lc{0} has banned {1}.", player.name, other.name);
|
||||
}else if(action == AdminAction.kick){
|
||||
netServer.kick(other.con.id, KickReason.kick);
|
||||
Log.info("&lc{0} has kicked {1}.", player.name, other.name);
|
||||
}else if(action == AdminAction.trace){
|
||||
//TODO
|
||||
if(player.con != null){
|
||||
Call.onTraceInfo(player.con.id, netServer.admins.getTraceByID(other.uuid));
|
||||
}else{
|
||||
NetClient.onTraceInfo(netServer.admins.getTraceByID(other.uuid));
|
||||
}
|
||||
Log.info("&lc{0} has requested trace info of {1}.", player.name, other.name);
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.client)
|
||||
public static void connectConfirm(Player player){
|
||||
player.add();
|
||||
player.con.hasConnected = true;
|
||||
Call.sendMessage("[accent]" + player.name + " has connected.");
|
||||
Log.info("&y{0} has connected.", player.name);
|
||||
}
|
||||
|
||||
public void update(){
|
||||
if(!headless && !closing && Net.server() && state.is(State.menu)){
|
||||
closing = true;
|
||||
@@ -270,7 +360,7 @@ public class NetServer extends Module{
|
||||
|
||||
if((reason == KickReason.kick || reason == KickReason.banned) && admins.getTraceByID(getUUID(con.id)).uuid != null){
|
||||
PlayerInfo info = admins.getInfo(admins.getTraceByID(getUUID(con.id)).uuid);
|
||||
info.timesKicked ++;
|
||||
info.timesKicked++;
|
||||
info.lastKicked = TimeUtils.millis();
|
||||
}
|
||||
|
||||
@@ -288,7 +378,7 @@ public class NetServer extends Module{
|
||||
|
||||
String fixName(String name){
|
||||
|
||||
for(int i = 0; i < name.length(); i ++){
|
||||
for(int i = 0; i < name.length(); i++){
|
||||
if(name.charAt(i) == '[' && i != name.length() - 1 && name.charAt(i + 1) != '[' && (i == 0 || name.charAt(i - 1) != '[')){
|
||||
String prev = name.substring(0, i);
|
||||
String next = name.substring(i);
|
||||
@@ -303,7 +393,7 @@ public class NetServer extends Module{
|
||||
|
||||
String checkColor(String str){
|
||||
|
||||
for(int i = 1; i < str.length(); i ++){
|
||||
for(int i = 1; i < str.length(); i++){
|
||||
if(str.charAt(i) == ']'){
|
||||
String color = str.substring(1, i);
|
||||
|
||||
@@ -318,7 +408,7 @@ public class NetServer extends Module{
|
||||
if(result.a <= 0.8f){
|
||||
return str.substring(i + 1);
|
||||
}
|
||||
}catch (Exception e){
|
||||
}catch(Exception e){
|
||||
return str;
|
||||
}
|
||||
}
|
||||
@@ -328,10 +418,10 @@ public class NetServer extends Module{
|
||||
}
|
||||
|
||||
void sync(){
|
||||
try {
|
||||
try{
|
||||
|
||||
//iterate through each player
|
||||
for (Player player : connections.values()) {
|
||||
for(Player player : connections.values()){
|
||||
NetConnection connection = player.con;
|
||||
|
||||
if(!connection.isConnected()){
|
||||
@@ -344,7 +434,8 @@ public class NetServer extends Module{
|
||||
|
||||
//if the player hasn't acknowledged that it has recieved the packet, send the same thing again
|
||||
if(connection.currentBaseID < connection.lastSentSnapshotID){
|
||||
if(showSnapshotSize) Log.info("Re-sending snapshot: {0} bytes, ID {1} base {2} baselength {3}", connection.lastSentSnapshot.length, connection.lastSentSnapshotID, connection.lastSentBase, connection.currentBaseSnapshot.length);
|
||||
if(showSnapshotSize)
|
||||
Log.info("Re-sending snapshot: {0} bytes, ID {1} base {2} baselength {3}", connection.lastSentSnapshot.length, connection.lastSentSnapshotID, connection.lastSentBase, connection.currentBaseSnapshot.length);
|
||||
sendSplitSnapshot(connection.id, connection.lastSentSnapshot, connection.lastSentSnapshotID, connection.lastSentBase);
|
||||
return;
|
||||
}
|
||||
@@ -371,17 +462,17 @@ public class NetServer extends Module{
|
||||
|
||||
int totalGroups = 0;
|
||||
|
||||
for (EntityGroup<?> group : Entities.getAllGroups()) {
|
||||
if (!group.isEmpty() && (group.all().get(0) instanceof SyncTrait)) totalGroups ++;
|
||||
for(EntityGroup<?> group : Entities.getAllGroups()){
|
||||
if(!group.isEmpty() && (group.all().get(0) instanceof SyncTrait)) totalGroups++;
|
||||
}
|
||||
|
||||
//write total amount of serializable groups
|
||||
dataStream.writeByte(totalGroups);
|
||||
|
||||
//check for syncable groups
|
||||
for (EntityGroup<?> group : Entities.getAllGroups()) {
|
||||
for(EntityGroup<?> group : Entities.getAllGroups()){
|
||||
//TODO range-check sync positions to optimize?
|
||||
if (group.isEmpty() || !(group.all().get(0) instanceof SyncTrait)) continue;
|
||||
if(group.isEmpty() || !(group.all().get(0) instanceof SyncTrait)) continue;
|
||||
|
||||
//make sure mapping is enabled for this group
|
||||
if(!group.mappingEnabled()){
|
||||
@@ -391,8 +482,8 @@ public class NetServer extends Module{
|
||||
int amount = 0;
|
||||
|
||||
for(Entity entity : group.all()){
|
||||
if(((SyncTrait)entity).isSyncing()){
|
||||
amount ++;
|
||||
if(((SyncTrait) entity).isSyncing()){
|
||||
amount++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,15 +492,16 @@ public class NetServer extends Module{
|
||||
dataStream.writeShort(amount);
|
||||
|
||||
for(Entity entity : group.all()){
|
||||
if(!((SyncTrait)entity).isSyncing()) continue;
|
||||
if(!((SyncTrait) entity).isSyncing()) continue;
|
||||
|
||||
int position = syncStream.position();
|
||||
//write all entities now
|
||||
dataStream.writeInt(entity.getID()); //write id
|
||||
dataStream.writeByte(((SyncTrait)entity).getTypeID()); //write type ID
|
||||
((SyncTrait)entity).write(dataStream); //write entity
|
||||
dataStream.writeByte(((SyncTrait) entity).getTypeID()); //write type ID
|
||||
((SyncTrait) entity).write(dataStream); //write entity
|
||||
int length = syncStream.position() - position; //length must always be less than 127 bytes
|
||||
if(length > 127) throw new RuntimeException("Write size for entity of type " + group.getType() + " must not exceed 127!");
|
||||
if(length > 127)
|
||||
throw new RuntimeException("Write size for entity of type " + group.getType() + " must not exceed 127!");
|
||||
dataStream.writeByte(length);
|
||||
}
|
||||
}
|
||||
@@ -433,7 +525,8 @@ public class NetServer extends Module{
|
||||
|
||||
//send diff, otherwise
|
||||
byte[] diff = ByteDeltaEncoder.toDiff(new ByteMatcherHash(connection.currentBaseSnapshot, bytes), encoder);
|
||||
if(showSnapshotSize) Log.info("Shrank snapshot: {0} -> {1}, Base {2} ID {3} base length = {4}", bytes.length, diff.length, connection.currentBaseID, connection.currentBaseID + 1, connection.currentBaseSnapshot.length);
|
||||
if(showSnapshotSize)
|
||||
Log.info("Shrank snapshot: {0} -> {1}, Base {2} ID {3} base length = {4}", bytes.length, diff.length, connection.currentBaseID, connection.currentBaseID + 1, connection.currentBaseSnapshot.length);
|
||||
sendSplitSnapshot(connection.id, diff, connection.currentBaseID + 1, connection.currentBaseID);
|
||||
connection.lastSentSnapshot = diff;
|
||||
connection.lastSentSnapshotID = connection.currentBaseID + 1;
|
||||
@@ -441,88 +534,8 @@ public class NetServer extends Module{
|
||||
}
|
||||
}
|
||||
|
||||
}catch (IOException e){
|
||||
}catch(IOException e){
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**Sends a raw byte[] snapshot to a client, splitting up into chunks when needed.*/
|
||||
private static void sendSplitSnapshot(int userid, byte[] bytes, int snapshotID, int base){
|
||||
if(bytes.length < maxSnapshotSize){
|
||||
Call.onSnapshot(userid, bytes, snapshotID, (short)0, (short)bytes.length, base);
|
||||
}else{
|
||||
int remaining = bytes.length;
|
||||
int offset = 0;
|
||||
int chunkid = 0;
|
||||
while(remaining > 0){
|
||||
int used = Math.min(remaining, maxSnapshotSize);
|
||||
byte[] toSend;
|
||||
//re-use sent byte arrays when possible
|
||||
if(used == maxSnapshotSize){
|
||||
toSend = reusableSnapArray;
|
||||
System.arraycopy(bytes, offset, toSend, 0, Math.min(offset + maxSnapshotSize, bytes.length) - offset);
|
||||
}else {
|
||||
toSend = Arrays.copyOfRange(bytes, offset, Math.min(offset + maxSnapshotSize, bytes.length));
|
||||
}
|
||||
Call.onSnapshot(userid, toSend, snapshotID, (short)chunkid, (short)bytes.length, base);
|
||||
|
||||
remaining -= used;
|
||||
offset += used;
|
||||
chunkid ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void onDisconnect(Player player){
|
||||
Call.sendMessage("[accent]" + player.name + " has disconnected.");
|
||||
Call.onPlayerDisconnect(player.id);
|
||||
player.remove();
|
||||
netServer.connections.remove(player.con.id);
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.client, called = Loc.server)
|
||||
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.",
|
||||
player.name, player.con.address);
|
||||
return;
|
||||
}
|
||||
|
||||
if(other == null || (other.isAdmin && other != player)){ //fun fact: this means you can ban yourself
|
||||
Log.err("{0} attempted to perform admin action on nonexistant or admin player.", player.name);
|
||||
return;
|
||||
}
|
||||
|
||||
String ip = player.con.address;
|
||||
|
||||
if(action == AdminAction.wave) {
|
||||
//no verification is done, so admins can hypothetically spam waves
|
||||
//not a real issue, because server owners may want to do just that
|
||||
state.wavetime = 0f;
|
||||
}else if(action == AdminAction.ban){
|
||||
netServer.admins.banPlayerIP(ip);
|
||||
netServer.kick(other.con.id, KickReason.banned);
|
||||
Log.info("&lc{0} has banned {1}.", player.name, other.name);
|
||||
}else if(action == AdminAction.kick){
|
||||
netServer.kick(other.con.id, KickReason.kick);
|
||||
Log.info("&lc{0} has kicked {1}.", player.name, other.name);
|
||||
}else if(action == AdminAction.trace){
|
||||
//TODO
|
||||
if(player.con != null) {
|
||||
Call.onTraceInfo(player.con.id, netServer.admins.getTraceByID(other.uuid));
|
||||
}else{
|
||||
NetClient.onTraceInfo(netServer.admins.getTraceByID(other.uuid));
|
||||
}
|
||||
Log.info("&lc{0} has requested trace info of {1}.", player.name, other.name);
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.client)
|
||||
public static void connectConfirm(Player player){
|
||||
player.add();
|
||||
player.con.hasConnected = true;
|
||||
Call.sendMessage("[accent]" + player.name + " has connected.");
|
||||
Log.info("&y{0} has connected.", player.name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,6 @@ import com.badlogic.gdx.files.FileHandle;
|
||||
import com.badlogic.gdx.utils.Base64Coder;
|
||||
import io.anuke.mindustry.core.ThreadHandler.ThreadProvider;
|
||||
import io.anuke.ucore.core.Settings;
|
||||
import io.anuke.ucore.entities.EntityGroup;
|
||||
import io.anuke.ucore.entities.trait.Entity;
|
||||
import io.anuke.ucore.function.Consumer;
|
||||
import io.anuke.ucore.scene.ui.TextField;
|
||||
|
||||
@@ -13,63 +11,129 @@ import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Random;
|
||||
|
||||
public abstract class Platform {
|
||||
/**Each separate game platform should set this instance to their own implementation.*/
|
||||
public static Platform instance = new Platform() {};
|
||||
public abstract class Platform{
|
||||
/**
|
||||
* Each separate game platform should set this instance to their own implementation.
|
||||
*/
|
||||
public static Platform instance = new Platform(){
|
||||
};
|
||||
|
||||
/**Format the date using the default date formatter.*/
|
||||
public String format(Date date){return "invalid";}
|
||||
/**Format a number by adding in commas or periods where needed.*/
|
||||
public String format(int number){return "invalid";}
|
||||
/**Show a native error dialog.*/
|
||||
public void showError(String text){}
|
||||
/**Add a text input dialog that should show up after the field is tapped.*/
|
||||
public void addDialog(TextField field){
|
||||
addDialog(field, 16);
|
||||
}
|
||||
/**See addDialog().*/
|
||||
public void addDialog(TextField field, int maxLength){}
|
||||
/**Update discord RPC.*/
|
||||
public void updateRPC(){}
|
||||
/**Called when the game is exited.*/
|
||||
public void onGameExit(){}
|
||||
/**Open donation dialog. Currently android only.*/
|
||||
public void openDonations(){}
|
||||
/**Whether donating is supported.*/
|
||||
public boolean canDonate(){
|
||||
return false;
|
||||
}
|
||||
/**Whether discord RPC is supported.*/
|
||||
public boolean hasDiscord(){return true;}
|
||||
/**Return the localized name for the locale. This is basically a workaround for GWT not supporting getName().*/
|
||||
public String getLocaleName(Locale locale){
|
||||
return locale.toString();
|
||||
}
|
||||
/**Whether joining games is supported.*/
|
||||
public boolean canJoinGame(){
|
||||
return true;
|
||||
}
|
||||
/**Whether debug mode is enabled.*/
|
||||
public boolean isDebug(){return false;}
|
||||
/**Must be a base64 string 8 bytes in length.*/
|
||||
public String getUUID(){
|
||||
String uuid = Settings.getString("uuid", "");
|
||||
if(uuid.isEmpty()){
|
||||
byte[] result = new byte[8];
|
||||
new Random().nextBytes(result);
|
||||
uuid = new String(Base64Coder.encode(result));
|
||||
Settings.putString("uuid", uuid);
|
||||
Settings.save();
|
||||
return uuid;
|
||||
}
|
||||
return uuid;
|
||||
}
|
||||
/**Only used for iOS or android: open the share menu for a map or save.*/
|
||||
public void shareFile(FileHandle file){}
|
||||
/**Download a file. Only used on GWT backend.*/
|
||||
public void downloadFile(String name, byte[] bytes){}
|
||||
/**
|
||||
* Format the date using the default date formatter.
|
||||
*/
|
||||
public String format(Date date){
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
/**Show a file chooser. Desktop only.
|
||||
/**
|
||||
* Format a number by adding in commas or periods where needed.
|
||||
*/
|
||||
public String format(int number){
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a native error dialog.
|
||||
*/
|
||||
public void showError(String text){
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a text input dialog that should show up after the field is tapped.
|
||||
*/
|
||||
public void addDialog(TextField field){
|
||||
addDialog(field, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* See addDialog().
|
||||
*/
|
||||
public void addDialog(TextField field, int maxLength){
|
||||
}
|
||||
|
||||
/**
|
||||
* Update discord RPC.
|
||||
*/
|
||||
public void updateRPC(){
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the game is exited.
|
||||
*/
|
||||
public void onGameExit(){
|
||||
}
|
||||
|
||||
/**
|
||||
* Open donation dialog. Currently android only.
|
||||
*/
|
||||
public void openDonations(){
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether donating is supported.
|
||||
*/
|
||||
public boolean canDonate(){
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether discord RPC is supported.
|
||||
*/
|
||||
public boolean hasDiscord(){
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the localized name for the locale. This is basically a workaround for GWT not supporting getName().
|
||||
*/
|
||||
public String getLocaleName(Locale locale){
|
||||
return locale.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether joining games is supported.
|
||||
*/
|
||||
public boolean canJoinGame(){
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether debug mode is enabled.
|
||||
*/
|
||||
public boolean isDebug(){
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be a base64 string 8 bytes in length.
|
||||
*/
|
||||
public String getUUID(){
|
||||
String uuid = Settings.getString("uuid", "");
|
||||
if(uuid.isEmpty()){
|
||||
byte[] result = new byte[8];
|
||||
new Random().nextBytes(result);
|
||||
uuid = new String(Base64Coder.encode(result));
|
||||
Settings.putString("uuid", uuid);
|
||||
Settings.save();
|
||||
return uuid;
|
||||
}
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only used for iOS or android: open the share menu for a map or save.
|
||||
*/
|
||||
public void shareFile(FileHandle file){
|
||||
}
|
||||
|
||||
/**
|
||||
* Download a file. Only used on GWT backend.
|
||||
*/
|
||||
public void downloadFile(String name, byte[] bytes){
|
||||
}
|
||||
|
||||
/**
|
||||
* Show a file chooser. Desktop only.
|
||||
*
|
||||
* @param text File chooser title text
|
||||
* @param content Description of the type of files to be loaded
|
||||
@@ -77,25 +141,54 @@ public abstract class Platform {
|
||||
* @param open Whether to open or save files
|
||||
* @param filetype File extension to filter
|
||||
*/
|
||||
public void showFileChooser(String text, String content, Consumer<FileHandle> cons, boolean open, String filetype){}
|
||||
/**Use the default thread provider from the kryonet module for this.*/
|
||||
public ThreadProvider getThreadProvider(){
|
||||
return new ThreadProvider() {
|
||||
@Override public boolean isOnThread() {return true;}
|
||||
@Override public void sleep(long ms) {}
|
||||
@Override public void start(Runnable run) {}
|
||||
@Override public void stop() {}
|
||||
@Override public void notify(Object object) {}
|
||||
@Override public void wait(Object object) {}
|
||||
@Override public <T extends Entity> void switchContainer(EntityGroup<T> group) {}
|
||||
};
|
||||
}
|
||||
public void showFileChooser(String text, String content, Consumer<FileHandle> cons, boolean open, String filetype){
|
||||
}
|
||||
|
||||
//TODO iOS implementation
|
||||
/**Forces the app into landscape mode. Currently Android only.*/
|
||||
public void beginForceLandscape(){}
|
||||
/**
|
||||
* Use the default thread provider from the kryonet module for this.
|
||||
*/
|
||||
public ThreadProvider getThreadProvider(){
|
||||
return new ThreadProvider(){
|
||||
@Override
|
||||
public boolean isOnThread(){
|
||||
return true;
|
||||
}
|
||||
|
||||
//TODO iOS implementation
|
||||
/**Stops forcing the app into landscape orientation. Currently Android only.*/
|
||||
public void endForceLandscape(){}
|
||||
@Override
|
||||
public void sleep(long ms){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(Runnable run){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop(){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notify(Object object){
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wait(Object object){
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
//TODO iOS implementation
|
||||
|
||||
/**
|
||||
* Forces the app into landscape mode. Currently Android only.
|
||||
*/
|
||||
public void beginForceLandscape(){
|
||||
}
|
||||
|
||||
//TODO iOS implementation
|
||||
|
||||
/**
|
||||
* Stops forcing the app into landscape orientation. Currently Android only.
|
||||
*/
|
||||
public void endForceLandscape(){
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,399 +47,430 @@ import static io.anuke.ucore.core.Core.batch;
|
||||
import static io.anuke.ucore.core.Core.camera;
|
||||
|
||||
public class Renderer extends RendererModule{
|
||||
public Surface effectSurface;
|
||||
|
||||
private int targetscale = baseCameraScale;
|
||||
private Texture background = new Texture("sprites/background.png");
|
||||
public Surface effectSurface;
|
||||
|
||||
private Rectangle rect = new Rectangle(), rect2 = new Rectangle();
|
||||
private Vector2 avgPosition = new Translator();
|
||||
private Vector2 tmpVector1 = new Translator();
|
||||
private Vector2 tmpVector2 = new Translator();
|
||||
private int targetscale = baseCameraScale;
|
||||
private Texture background = new Texture("sprites/background.png");
|
||||
|
||||
private BlockRenderer blocks = new BlockRenderer();
|
||||
private MinimapRenderer minimap = new MinimapRenderer();
|
||||
private OverlayRenderer overlays = new OverlayRenderer();
|
||||
private FogRenderer fog = new FogRenderer();
|
||||
private Rectangle rect = new Rectangle(), rect2 = new Rectangle();
|
||||
private Vector2 avgPosition = new Translator();
|
||||
private Vector2 tmpVector1 = new Translator();
|
||||
private Vector2 tmpVector2 = new Translator();
|
||||
|
||||
public Renderer() {
|
||||
pixelate = true;
|
||||
Lines.setCircleVertices(14);
|
||||
private BlockRenderer blocks = new BlockRenderer();
|
||||
private MinimapRenderer minimap = new MinimapRenderer();
|
||||
private OverlayRenderer overlays = new OverlayRenderer();
|
||||
private FogRenderer fog = new FogRenderer();
|
||||
|
||||
Shaders.init();
|
||||
public Renderer(){
|
||||
pixelate = true;
|
||||
Lines.setCircleVertices(14);
|
||||
|
||||
Core.cameraScale = baseCameraScale;
|
||||
Effects.setEffectProvider((effect, color, x, y, rotation, data) -> {
|
||||
if(effect == Fx.none) return;
|
||||
if(Settings.getBool("effects")){
|
||||
Rectangle view = rect.setSize(camera.viewportWidth, camera.viewportHeight)
|
||||
.setCenter(camera.position.x, camera.position.y);
|
||||
Rectangle pos = rect2.setSize(effect.size).setCenter(x, y);
|
||||
Shaders.init();
|
||||
|
||||
if(view.overlaps(pos)){
|
||||
Core.cameraScale = baseCameraScale;
|
||||
Effects.setEffectProvider((effect, color, x, y, rotation, data) -> {
|
||||
if(effect == Fx.none) return;
|
||||
if(Settings.getBool("effects")){
|
||||
Rectangle view = rect.setSize(camera.viewportWidth, camera.viewportHeight)
|
||||
.setCenter(camera.position.x, camera.position.y);
|
||||
Rectangle pos = rect2.setSize(effect.size).setCenter(x, y);
|
||||
|
||||
if(!(effect instanceof GroundEffect)) {
|
||||
EffectEntity entity = Pooling.obtain(EffectEntity.class);
|
||||
entity.effect = effect;
|
||||
entity.color = color;
|
||||
entity.rotation = rotation;
|
||||
entity.data = data;
|
||||
entity.id ++;
|
||||
entity.set(x, y);
|
||||
if(data instanceof BaseEntity){
|
||||
entity.setParent((BaseEntity)data);
|
||||
}
|
||||
threads.runGraphics(() -> effectGroup.add(entity));
|
||||
}else{
|
||||
GroundEffectEntity entity = Pooling.obtain(GroundEffectEntity.class);
|
||||
entity.effect = effect;
|
||||
entity.color = color;
|
||||
entity.rotation = rotation;
|
||||
entity.id ++;
|
||||
entity.data = data;
|
||||
entity.set(x, y);
|
||||
threads.runGraphics(() -> groundEffectGroup.add(entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if(view.overlaps(pos)){
|
||||
|
||||
Cursors.cursorScaling = 3;
|
||||
Cursors.outlineColor = Color.valueOf("444444");
|
||||
if(!(effect instanceof GroundEffect)){
|
||||
EffectEntity entity = Pooling.obtain(EffectEntity.class);
|
||||
entity.effect = effect;
|
||||
entity.color = color;
|
||||
entity.rotation = rotation;
|
||||
entity.data = data;
|
||||
entity.id++;
|
||||
entity.set(x, y);
|
||||
if(data instanceof BaseEntity){
|
||||
entity.setParent((BaseEntity) data);
|
||||
}
|
||||
threads.runGraphics(() -> effectGroup.add(entity));
|
||||
}else{
|
||||
GroundEffectEntity entity = Pooling.obtain(GroundEffectEntity.class);
|
||||
entity.effect = effect;
|
||||
entity.color = color;
|
||||
entity.rotation = rotation;
|
||||
entity.id++;
|
||||
entity.data = data;
|
||||
entity.set(x, y);
|
||||
threads.runGraphics(() -> groundEffectGroup.add(entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Cursors.arrow = Cursors.loadCursor("cursor");
|
||||
Cursors.hand = Cursors.loadCursor("hand");
|
||||
Cursors.ibeam = Cursors.loadCursor("ibar");
|
||||
Cursors.loadCustom("drill");
|
||||
Cursors.loadCustom("unload");
|
||||
Cursors.cursorScaling = 3;
|
||||
Cursors.outlineColor = Color.valueOf("444444");
|
||||
|
||||
clearColor = Hue.lightness(0.4f);
|
||||
clearColor.a = 1f;
|
||||
Cursors.arrow = Cursors.loadCursor("cursor");
|
||||
Cursors.hand = Cursors.loadCursor("hand");
|
||||
Cursors.ibeam = Cursors.loadCursor("ibar");
|
||||
Cursors.restoreCursor();
|
||||
Cursors.loadCustom("drill");
|
||||
Cursors.loadCustom("unload");
|
||||
|
||||
background.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
|
||||
}
|
||||
clearColor = Hue.lightness(0.4f);
|
||||
clearColor.a = 1f;
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
int scale = Core.cameraScale;
|
||||
background.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
int scale = Core.cameraScale;
|
||||
|
||||
effectSurface = Graphics.createSurface(scale);
|
||||
pixelSurface = Graphics.createSurface(scale);
|
||||
}
|
||||
pixelSurface = Graphics.createSurface(scale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
@Override
|
||||
public void update(){
|
||||
|
||||
if(Core.cameraScale != targetscale){
|
||||
float targetzoom = (float) Core.cameraScale / targetscale;
|
||||
camera.zoom = Mathf.lerpDelta(camera.zoom, targetzoom, 0.2f);
|
||||
if(Core.cameraScale != targetscale){
|
||||
float targetzoom = (float) Core.cameraScale / targetscale;
|
||||
camera.zoom = Mathf.lerpDelta(camera.zoom, targetzoom, 0.2f);
|
||||
|
||||
if(Mathf.in(camera.zoom, targetzoom, 0.005f)){
|
||||
camera.zoom = 1f;
|
||||
Graphics.setCameraScale(targetscale);
|
||||
for(Player player : players) {
|
||||
if(Mathf.in(camera.zoom, targetzoom, 0.005f)){
|
||||
camera.zoom = 1f;
|
||||
Graphics.setCameraScale(targetscale);
|
||||
for(Player player : players){
|
||||
control.input(player.playerIndex).resetCursor();
|
||||
}
|
||||
}
|
||||
}else{
|
||||
camera.zoom = Mathf.lerpDelta(camera.zoom, 1f, 0.2f);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
camera.zoom = Mathf.lerpDelta(camera.zoom, 1f, 0.2f);
|
||||
}
|
||||
|
||||
if(state.is(State.menu)){
|
||||
Graphics.clear(Color.BLACK);
|
||||
}else{
|
||||
if(state.is(State.menu)){
|
||||
Graphics.clear(Color.BLACK);
|
||||
}else{
|
||||
Vector2 position = averagePosition();
|
||||
|
||||
if(!mobile){
|
||||
setCamera(position.x + 0.0001f, position.y + 0.0001f);
|
||||
}
|
||||
setCamera(position.x + 0.0001f, position.y + 0.0001f);
|
||||
}
|
||||
|
||||
clampCamera(-tilesize / 2f, -tilesize / 2f + 1, world.width() * tilesize - tilesize / 2f, world.height() * tilesize - tilesize / 2f);
|
||||
clampCamera(-tilesize / 2f, -tilesize / 2f + 1, world.width() * tilesize - tilesize / 2f, world.height() * tilesize - tilesize / 2f);
|
||||
|
||||
float prex = camera.position.x, prey = camera.position.y;
|
||||
updateShake(0.75f);
|
||||
float prex = camera.position.x, prey = camera.position.y;
|
||||
updateShake(0.75f);
|
||||
|
||||
float deltax = camera.position.x - prex, deltay = camera.position.y - prey;
|
||||
float lastx = camera.position.x, lasty = camera.position.y;
|
||||
|
||||
if(snapCamera){
|
||||
camera.position.set((int) camera.position.x, (int) camera.position.y, 0);
|
||||
}
|
||||
|
||||
if(Gdx.graphics.getHeight() / Core.cameraScale % 2 == 1){
|
||||
camera.position.add(0, -0.5f, 0);
|
||||
}
|
||||
float deltax = camera.position.x - prex, deltay = camera.position.y - prey;
|
||||
float lastx = camera.position.x, lasty = camera.position.y;
|
||||
|
||||
if(Gdx.graphics.getWidth() / Core.cameraScale % 2 == 1){
|
||||
camera.position.add(-0.5f, 0, 0);
|
||||
}
|
||||
|
||||
draw();
|
||||
if(snapCamera){
|
||||
camera.position.set((int) camera.position.x, (int) camera.position.y, 0);
|
||||
}
|
||||
|
||||
camera.position.set(lastx - deltax, lasty - deltay, 0);
|
||||
}
|
||||
if(Gdx.graphics.getHeight() / Core.cameraScale % 2 == 1){
|
||||
camera.position.add(0, -0.5f, 0);
|
||||
}
|
||||
|
||||
if(debug && !ui.chatfrag.chatOpen()) {
|
||||
renderer.record(); //this only does something if GdxGifRecorder is on the class path, which it usually isn't
|
||||
}
|
||||
}
|
||||
if(Gdx.graphics.getWidth() / Core.cameraScale % 2 == 1){
|
||||
camera.position.add(-0.5f, 0, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
camera.update();
|
||||
draw();
|
||||
|
||||
Graphics.clear(clearColor);
|
||||
|
||||
batch.setProjectionMatrix(camera.combined);
|
||||
camera.position.set(lastx - deltax, lasty - deltay, 0);
|
||||
}
|
||||
|
||||
Graphics.surface(pixelSurface, false);
|
||||
if(debug && !ui.chatfrag.chatOpen()){
|
||||
renderer.record(); //this only does something if GdxGifRecorder is on the class path, which it usually isn't
|
||||
}
|
||||
}
|
||||
|
||||
drawPadding();
|
||||
|
||||
blocks.drawFloor();
|
||||
@Override
|
||||
public void draw(){
|
||||
camera.update();
|
||||
|
||||
drawAndInterpolate(groundEffectGroup, e -> e instanceof BelowLiquidTrait);
|
||||
drawAndInterpolate(puddleGroup);
|
||||
drawAndInterpolate(groundEffectGroup, e -> !(e instanceof BelowLiquidTrait));
|
||||
Graphics.clear(clearColor);
|
||||
|
||||
blocks.processBlocks();
|
||||
blocks.drawBlocks(Layer.block);
|
||||
batch.setProjectionMatrix(camera.combined);
|
||||
|
||||
Graphics.shader(Shaders.blockbuild, false);
|
||||
Graphics.surface(pixelSurface, false);
|
||||
|
||||
drawPadding();
|
||||
|
||||
blocks.drawFloor();
|
||||
|
||||
drawAndInterpolate(groundEffectGroup, e -> e instanceof BelowLiquidTrait);
|
||||
drawAndInterpolate(puddleGroup);
|
||||
drawAndInterpolate(groundEffectGroup, e -> !(e instanceof BelowLiquidTrait));
|
||||
|
||||
blocks.processBlocks();
|
||||
blocks.drawBlocks(Layer.block);
|
||||
|
||||
Graphics.shader(Shaders.blockbuild, false);
|
||||
blocks.drawBlocks(Layer.placement);
|
||||
Graphics.shader();
|
||||
|
||||
blocks.drawBlocks(Layer.overlay);
|
||||
|
||||
if(itemGroup.size() > 0){
|
||||
Shaders.outline.color.set(Team.none.color);
|
||||
|
||||
Graphics.beginShaders(Shaders.outline);
|
||||
drawAndInterpolate(itemGroup);
|
||||
Graphics.endShaders();
|
||||
}
|
||||
Shaders.outline.color.set(Team.none.color);
|
||||
|
||||
Graphics.beginShaders(Shaders.outline);
|
||||
drawAndInterpolate(itemGroup);
|
||||
Graphics.endShaders();
|
||||
}
|
||||
|
||||
drawAllTeams(false);
|
||||
|
||||
blocks.skipLayer(Layer.turret);
|
||||
blocks.drawBlocks(Layer.laser);
|
||||
blocks.skipLayer(Layer.turret);
|
||||
blocks.drawBlocks(Layer.laser);
|
||||
|
||||
drawAllTeams(true);
|
||||
drawFlyerShadows();
|
||||
|
||||
drawAndInterpolate(bulletGroup);
|
||||
drawAndInterpolate(effectGroup);
|
||||
drawAllTeams(true);
|
||||
|
||||
overlays.drawBottom();
|
||||
drawAndInterpolate(playerGroup, p -> true, Player::drawBuildRequests);
|
||||
overlays.drawTop();
|
||||
drawAndInterpolate(bulletGroup);
|
||||
drawAndInterpolate(effectGroup);
|
||||
|
||||
Graphics.flushSurface();
|
||||
overlays.drawBottom();
|
||||
drawAndInterpolate(playerGroup, p -> true, Player::drawBuildRequests);
|
||||
overlays.drawTop();
|
||||
|
||||
if(showPaths && debug) drawDebug();
|
||||
Graphics.flushSurface();
|
||||
|
||||
batch.end();
|
||||
if(showPaths && debug) drawDebug();
|
||||
|
||||
if(showFog){
|
||||
fog.draw();
|
||||
}
|
||||
batch.end();
|
||||
|
||||
batch.begin();
|
||||
EntityDraw.setClip(false);
|
||||
drawAndInterpolate(playerGroup, p -> !p.isDead() && !p.isLocal, Player::drawName);
|
||||
EntityDraw.setClip(true);
|
||||
batch.end();
|
||||
}
|
||||
if(showFog){
|
||||
fog.draw();
|
||||
}
|
||||
|
||||
private void drawAllTeams(boolean flying){
|
||||
for(Team team : Team.all){
|
||||
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
|
||||
Graphics.beginCam();
|
||||
EntityDraw.setClip(false);
|
||||
drawAndInterpolate(playerGroup, p -> !p.isDead() && !p.isLocal, Player::drawName);
|
||||
EntityDraw.setClip(true);
|
||||
Graphics.end();
|
||||
}
|
||||
|
||||
if(group.count(p -> p.isFlying() == flying) +
|
||||
playerGroup.count(p -> p.isFlying() == flying && p.getTeam() == team) == 0 && flying) continue;
|
||||
private void drawFlyerShadows(){
|
||||
Graphics.surface(effectSurface, true, false);
|
||||
|
||||
drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder);
|
||||
drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawUnder);
|
||||
float trnsX = 12, trnsY = -13;
|
||||
|
||||
Shaders.outline.color.set(team.color);
|
||||
Shaders.mix.color.set(Color.WHITE);
|
||||
Graphics.end();
|
||||
Core.batch.getTransformMatrix().translate(trnsX, trnsY, 0);
|
||||
Graphics.begin();
|
||||
|
||||
Graphics.beginShaders(Shaders.outline);
|
||||
Graphics.shader(Shaders.mix, true);
|
||||
drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead());
|
||||
drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team);
|
||||
Graphics.shader();
|
||||
blocks.drawTeamBlocks(Layer.turret, team);
|
||||
Graphics.endShaders();
|
||||
for(EntityGroup<? extends BaseUnit> group : unitGroups){
|
||||
if(!group.isEmpty()){
|
||||
drawAndInterpolate(group, unit -> unit.isFlying() && !unit.isDead(), Unit::drawShadow);
|
||||
}
|
||||
}
|
||||
|
||||
drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver);
|
||||
drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawOver);
|
||||
}
|
||||
}
|
||||
if(!playerGroup.isEmpty()){
|
||||
drawAndInterpolate(playerGroup, unit -> unit.isFlying() && !unit.isDead(), Unit::drawShadow);
|
||||
}
|
||||
|
||||
public <T extends DrawTrait> void drawAndInterpolate(EntityGroup<T> group){
|
||||
drawAndInterpolate(group, t -> true, DrawTrait::draw);
|
||||
}
|
||||
Graphics.end();
|
||||
Core.batch.getTransformMatrix().translate(-trnsX, -trnsY, 0);
|
||||
Graphics.begin();
|
||||
|
||||
public <T extends DrawTrait> void drawAndInterpolate(EntityGroup<T> group, Predicate<T> toDraw){
|
||||
drawAndInterpolate(group, toDraw, DrawTrait::draw);
|
||||
}
|
||||
//TODO this actually isn't necessary
|
||||
Draw.color(0, 0, 0, 0.15f);
|
||||
Graphics.flushSurface();
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
public <T extends DrawTrait> void drawAndInterpolate(EntityGroup<T> group, Predicate<T> toDraw, Consumer<T> drawer){
|
||||
EntityDraw.drawWith(group, toDraw, t -> {
|
||||
float lastx = t.getX(), lasty = t.getY(), lastrot = 0f;
|
||||
private void drawAllTeams(boolean flying){
|
||||
for(Team team : Team.all){
|
||||
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
|
||||
|
||||
if(threads.doInterpolate() && threads.isEnabled() && t instanceof SolidTrait){
|
||||
SolidTrait s = (SolidTrait)t;
|
||||
if(group.count(p -> p.isFlying() == flying) +
|
||||
playerGroup.count(p -> p.isFlying() == flying && p.getTeam() == team) == 0 && flying) continue;
|
||||
|
||||
lastrot = s.getRotation();
|
||||
drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder);
|
||||
drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawUnder);
|
||||
|
||||
if(s.lastUpdated() != 0){
|
||||
float timeSinceUpdate = TimeUtils.timeSinceMillis(s.lastUpdated());
|
||||
float alpha = Math.min(timeSinceUpdate / s.updateSpacing(), 1f);
|
||||
Shaders.outline.color.set(team.color);
|
||||
Shaders.mix.color.set(Color.WHITE);
|
||||
|
||||
tmpVector1.set(s.lastPosition().x, s.lastPosition().y)
|
||||
.lerp(tmpVector2.set(lastx, lasty), alpha);
|
||||
s.setRotation(Mathf.slerp(s.lastPosition().z, lastrot, alpha));
|
||||
Graphics.beginShaders(Shaders.outline);
|
||||
Graphics.shader(Shaders.mix, true);
|
||||
drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead());
|
||||
drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team);
|
||||
Graphics.shader();
|
||||
blocks.drawTeamBlocks(Layer.turret, team);
|
||||
Graphics.endShaders();
|
||||
|
||||
s.setX(tmpVector1.x);
|
||||
s.setY(tmpVector1.y);
|
||||
}
|
||||
}
|
||||
drawAndInterpolate(unitGroups[team.ordinal()], u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver);
|
||||
drawAndInterpolate(playerGroup, p -> p.isFlying() == flying && p.getTeam() == team, Unit::drawOver);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO extremely hacky
|
||||
if(t instanceof Player && ((Player) t).getCarry() != null && ((Player) t).getCarry() instanceof Player && ((Player) ((Player) t).getCarry()).isLocal){
|
||||
((Player) t).x = ((Player) t).getCarry().getX();
|
||||
((Player) t).y = ((Player) t).getCarry().getY();
|
||||
}
|
||||
public <T extends DrawTrait> void drawAndInterpolate(EntityGroup<T> group){
|
||||
drawAndInterpolate(group, t -> true, DrawTrait::draw);
|
||||
}
|
||||
|
||||
drawer.accept(t);
|
||||
public <T extends DrawTrait> void drawAndInterpolate(EntityGroup<T> group, Predicate<T> toDraw){
|
||||
drawAndInterpolate(group, toDraw, DrawTrait::draw);
|
||||
}
|
||||
|
||||
t.setX(lastx);
|
||||
t.setY(lasty);
|
||||
public <T extends DrawTrait> void drawAndInterpolate(EntityGroup<T> group, Predicate<T> toDraw, Consumer<T> drawer){
|
||||
EntityDraw.drawWith(group, toDraw, t -> {
|
||||
float lastx = t.getX(), lasty = t.getY(), lastrot = 0f;
|
||||
|
||||
if(threads.doInterpolate() && threads.isEnabled()) {
|
||||
if(threads.doInterpolate() && threads.isEnabled() && t instanceof SolidTrait){
|
||||
SolidTrait s = (SolidTrait) t;
|
||||
|
||||
if (t instanceof SolidTrait) {
|
||||
((SolidTrait) t).setRotation(lastrot);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
lastrot = s.getRotation();
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height){
|
||||
super.resize(width, height);
|
||||
for(Player player : players) {
|
||||
if(s.lastUpdated() != 0){
|
||||
float timeSinceUpdate = TimeUtils.timeSinceMillis(s.lastUpdated());
|
||||
float alpha = Math.min(timeSinceUpdate / s.updateSpacing(), 1f);
|
||||
|
||||
tmpVector1.set(s.lastPosition().x, s.lastPosition().y)
|
||||
.lerp(tmpVector2.set(lastx, lasty), alpha);
|
||||
s.setRotation(Mathf.slerp(s.lastPosition().z, lastrot, alpha));
|
||||
|
||||
s.setX(tmpVector1.x);
|
||||
s.setY(tmpVector1.y);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO extremely hacky
|
||||
if(t instanceof Player && ((Player) t).getCarry() != null && ((Player) t).getCarry() instanceof Player && ((Player) ((Player) t).getCarry()).isLocal){
|
||||
((Player) t).x = ((Player) t).getCarry().getX();
|
||||
((Player) t).y = ((Player) t).getCarry().getY();
|
||||
}
|
||||
|
||||
drawer.accept(t);
|
||||
|
||||
t.setX(lastx);
|
||||
t.setY(lasty);
|
||||
|
||||
if(threads.doInterpolate() && threads.isEnabled()){
|
||||
|
||||
if(t instanceof SolidTrait){
|
||||
((SolidTrait) t).setRotation(lastrot);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height){
|
||||
super.resize(width, height);
|
||||
for(Player player : players){
|
||||
control.input(player.playerIndex).resetCursor();
|
||||
}
|
||||
camera.position.set(players[0].x, players[0].y, 0);
|
||||
}
|
||||
camera.position.set(players[0].x, players[0].y, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
background.dispose();
|
||||
fog.dispose();
|
||||
}
|
||||
@Override
|
||||
public void dispose(){
|
||||
background.dispose();
|
||||
fog.dispose();
|
||||
}
|
||||
|
||||
public Vector2 averagePosition(){
|
||||
avgPosition.setZero();
|
||||
public Vector2 averagePosition(){
|
||||
avgPosition.setZero();
|
||||
|
||||
drawAndInterpolate(playerGroup, p -> p.isLocal, p -> {
|
||||
avgPosition.add(p.x, p.y);
|
||||
});
|
||||
drawAndInterpolate(playerGroup, p -> p.isLocal, p -> {
|
||||
avgPosition.add(p.x, p.y);
|
||||
});
|
||||
|
||||
avgPosition.scl(1f / players.length);
|
||||
return avgPosition;
|
||||
}
|
||||
|
||||
public FogRenderer fog() {
|
||||
return fog;
|
||||
}
|
||||
public FogRenderer fog(){
|
||||
return fog;
|
||||
}
|
||||
|
||||
public MinimapRenderer minimap() {
|
||||
return minimap;
|
||||
}
|
||||
public MinimapRenderer minimap(){
|
||||
return minimap;
|
||||
}
|
||||
|
||||
void drawPadding(){
|
||||
float vw = world.width() * tilesize;
|
||||
float cw = camera.viewportWidth * camera.zoom;
|
||||
float ch = camera.viewportHeight * camera.zoom;
|
||||
if(vw < cw){
|
||||
batch.draw(background,
|
||||
camera.position.x + vw/2,
|
||||
Mathf.round(camera.position.y - ch/2, tilesize),
|
||||
(cw - vw) /2,
|
||||
ch + tilesize,
|
||||
0, 0,
|
||||
((cw - vw) / 2 / tilesize), -ch / tilesize + 1);
|
||||
void drawPadding(){
|
||||
float vw = world.width() * tilesize;
|
||||
float cw = camera.viewportWidth * camera.zoom;
|
||||
float ch = camera.viewportHeight * camera.zoom;
|
||||
if(vw < cw){
|
||||
batch.draw(background,
|
||||
camera.position.x + vw / 2,
|
||||
Mathf.round(camera.position.y - ch / 2, tilesize),
|
||||
(cw - vw) / 2,
|
||||
ch + tilesize,
|
||||
0, 0,
|
||||
((cw - vw) / 2 / tilesize), -ch / tilesize + 1);
|
||||
|
||||
batch.draw(background,
|
||||
camera.position.x - vw/2,
|
||||
Mathf.round(camera.position.y - ch/2, tilesize),
|
||||
-(cw - vw) /2,
|
||||
ch + tilesize,
|
||||
0, 0,
|
||||
-((cw - vw) / 2 / tilesize), -ch / tilesize + 1);
|
||||
}
|
||||
}
|
||||
batch.draw(background,
|
||||
camera.position.x - vw / 2,
|
||||
Mathf.round(camera.position.y - ch / 2, tilesize),
|
||||
-(cw - vw) / 2,
|
||||
ch + tilesize,
|
||||
0, 0,
|
||||
-((cw - vw) / 2 / tilesize), -ch / tilesize + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void drawDebug(){
|
||||
int rangex = (int)(Core.camera.viewportWidth/tilesize/2), rangey = (int)(Core.camera.viewportHeight/tilesize/2);
|
||||
void drawDebug(){
|
||||
int rangex = (int) (Core.camera.viewportWidth / tilesize / 2), rangey = (int) (Core.camera.viewportHeight / tilesize / 2);
|
||||
|
||||
for(int x = -rangex; x <= rangex; x++) {
|
||||
for (int y = -rangey; y <= rangey; y++) {
|
||||
int worldx = Mathf.scl(camera.position.x, tilesize) + x;
|
||||
int worldy = Mathf.scl(camera.position.y, tilesize) + y;
|
||||
for(int x = -rangex; x <= rangex; x++){
|
||||
for(int y = -rangey; y <= rangey; y++){
|
||||
int worldx = Mathf.scl(camera.position.x, tilesize) + x;
|
||||
int worldy = Mathf.scl(camera.position.y, tilesize) + y;
|
||||
|
||||
if(world.tile(worldx, worldy) == null) continue;
|
||||
if(world.tile(worldx, worldy) == null) continue;
|
||||
|
||||
float value = world.pathfinder().getDebugValue(worldx, worldy);
|
||||
Draw.color(Color.PURPLE);
|
||||
Draw.alpha((value % 10f) / 10f);
|
||||
Lines.square(worldx * tilesize, worldy*tilesize, 4f);
|
||||
}
|
||||
}
|
||||
float value = world.pathfinder().getDebugValue(worldx, worldy);
|
||||
Draw.color(Color.PURPLE);
|
||||
Draw.alpha((value % 10f) / 10f);
|
||||
Lines.square(worldx * tilesize, worldy * tilesize, 4f);
|
||||
}
|
||||
}
|
||||
|
||||
Draw.color(Color.ORANGE);
|
||||
Draw.tcolor(Color.ORANGE);
|
||||
Draw.color(Color.ORANGE);
|
||||
Draw.tcolor(Color.ORANGE);
|
||||
|
||||
ObjectIntMap<Tile> seen = new ObjectIntMap<>();
|
||||
ObjectIntMap<Tile> seen = new ObjectIntMap<>();
|
||||
|
||||
for(BlockFlag flag : BlockFlag.values()){
|
||||
for(Tile tile : world.indexer().getEnemy(Team.blue, flag)){
|
||||
int index = seen.getAndIncrement(tile, 0, 1);
|
||||
Draw.tscl(0.125f);
|
||||
Draw.text(flag.name(), tile.drawx(), tile.drawy() + tile.block().size * tilesize/2f + 4 + index * 3);
|
||||
Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize/2f);
|
||||
}
|
||||
}
|
||||
Draw.tscl(fontScale);
|
||||
Draw.tcolor();
|
||||
for(BlockFlag flag : BlockFlag.values()){
|
||||
for(Tile tile : world.indexer().getEnemy(Team.blue, flag)){
|
||||
int index = seen.getAndIncrement(tile, 0, 1);
|
||||
Draw.tscl(0.125f);
|
||||
Draw.text(flag.name(), tile.drawx(), tile.drawy() + tile.block().size * tilesize / 2f + 4 + index * 3);
|
||||
Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize / 2f);
|
||||
}
|
||||
}
|
||||
Draw.tscl(fontScale);
|
||||
Draw.tcolor();
|
||||
|
||||
Draw.color();
|
||||
}
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
public BlockRenderer getBlocks() {
|
||||
return blocks;
|
||||
}
|
||||
public BlockRenderer getBlocks(){
|
||||
return blocks;
|
||||
}
|
||||
|
||||
public void setCameraScale(int amount){
|
||||
targetscale = amount;
|
||||
clampScale();
|
||||
//scale up all surfaces in preparation for the zoom
|
||||
for(Surface surface : Graphics.getSurfaces()){
|
||||
surface.setScale(targetscale);
|
||||
}
|
||||
}
|
||||
public void setCameraScale(int amount){
|
||||
targetscale = amount;
|
||||
clampScale();
|
||||
//scale up all surfaces in preparation for the zoom
|
||||
for(Surface surface : Graphics.getSurfaces()){
|
||||
surface.setScale(targetscale);
|
||||
}
|
||||
}
|
||||
|
||||
public void scaleCamera(int amount){
|
||||
setCameraScale(targetscale + amount);
|
||||
}
|
||||
public void scaleCamera(int amount){
|
||||
setCameraScale(targetscale + amount);
|
||||
}
|
||||
|
||||
public void clampScale(){
|
||||
float s = io.anuke.ucore.scene.ui.layout.Unit.dp.scl(1f);
|
||||
targetscale = Mathf.clamp(targetscale, Math.round(s*2), Math.round(s*5));
|
||||
}
|
||||
public void clampScale(){
|
||||
float s = io.anuke.ucore.scene.ui.layout.Unit.dp.scl(1f);
|
||||
targetscale = Mathf.clamp(targetscale, Math.round(s * 2), Math.round(s * 5));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,43 +1,38 @@
|
||||
package io.anuke.mindustry.core;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Queue;
|
||||
import com.badlogic.gdx.utils.TimeUtils;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.entities.Entities;
|
||||
import io.anuke.ucore.entities.EntityGroup;
|
||||
import io.anuke.ucore.entities.EntityGroup.ArrayContainer;
|
||||
import io.anuke.ucore.entities.trait.Entity;
|
||||
import io.anuke.ucore.util.Log;
|
||||
|
||||
import static io.anuke.mindustry.Vars.control;
|
||||
import static io.anuke.mindustry.Vars.logic;
|
||||
|
||||
public class ThreadHandler {
|
||||
private final Array<Runnable> toRun = new Array<>();
|
||||
public class ThreadHandler{
|
||||
private final Queue<Runnable> toRun = new Queue<>();
|
||||
private final ThreadProvider impl;
|
||||
private final Object updateLock = new Object();
|
||||
private float delta = 1f;
|
||||
private float smoothDelta = 1f;
|
||||
private long frame = 0, lastDeltaUpdate;
|
||||
private float framesSinceUpdate;
|
||||
private boolean enabled;
|
||||
|
||||
private final Object updateLock = new Object();
|
||||
private boolean rendered = true;
|
||||
|
||||
public ThreadHandler(ThreadProvider impl){
|
||||
this.impl = impl;
|
||||
|
||||
Timers.setDeltaProvider(() -> {
|
||||
float result = impl.isOnThread() ? delta : Gdx.graphics.getDeltaTime()*60f;
|
||||
float result = impl.isOnThread() ? delta : Gdx.graphics.getDeltaTime() * 60f;
|
||||
return Math.min(Float.isNaN(result) ? 1f : result, 15f);
|
||||
});
|
||||
}
|
||||
|
||||
public void run(Runnable r){
|
||||
if(enabled) {
|
||||
synchronized (toRun) {
|
||||
toRun.add(r);
|
||||
if(enabled){
|
||||
synchronized(toRun){
|
||||
toRun.addLast(r);
|
||||
}
|
||||
}else{
|
||||
r.run();
|
||||
@@ -45,7 +40,7 @@ public class ThreadHandler {
|
||||
}
|
||||
|
||||
public void runGraphics(Runnable r){
|
||||
if(enabled) {
|
||||
if(enabled){
|
||||
Gdx.app.postRunnable(r);
|
||||
}else{
|
||||
r.run();
|
||||
@@ -53,9 +48,9 @@ public class ThreadHandler {
|
||||
}
|
||||
|
||||
public void runDelay(Runnable r){
|
||||
if(enabled) {
|
||||
synchronized (toRun) {
|
||||
toRun.add(r);
|
||||
if(enabled){
|
||||
synchronized(toRun){
|
||||
toRun.addLast(r);
|
||||
}
|
||||
}else{
|
||||
Gdx.app.postRunnable(r);
|
||||
@@ -63,7 +58,7 @@ public class ThreadHandler {
|
||||
}
|
||||
|
||||
public int getTPS(){
|
||||
return (int)(60/smoothDelta);
|
||||
return (int) (60 / smoothDelta);
|
||||
}
|
||||
|
||||
public long getFrameID(){
|
||||
@@ -80,40 +75,34 @@ public class ThreadHandler {
|
||||
|
||||
framesSinceUpdate += Timers.delta();
|
||||
|
||||
synchronized (updateLock) {
|
||||
synchronized(updateLock){
|
||||
rendered = true;
|
||||
impl.notify(updateLock);
|
||||
}
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled){
|
||||
if(enabled){
|
||||
logic.doUpdate = false;
|
||||
for(EntityGroup<?> group : Entities.getAllGroups()){
|
||||
impl.switchContainer(group);
|
||||
}
|
||||
Timers.runTask(2f, () -> {
|
||||
impl.start(this::runLogic);
|
||||
this.enabled = true;
|
||||
});
|
||||
}else{
|
||||
this.enabled = false;
|
||||
impl.stop();
|
||||
for(EntityGroup<?> group : Entities.getAllGroups()){
|
||||
group.setContainer(new ArrayContainer<>());
|
||||
}
|
||||
Timers.runTask(2f, () -> {
|
||||
logic.doUpdate = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled(){
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled){
|
||||
if(enabled){
|
||||
logic.doUpdate = false;
|
||||
Timers.runTask(2f, () -> {
|
||||
impl.start(this::runLogic);
|
||||
this.enabled = true;
|
||||
});
|
||||
}else{
|
||||
this.enabled = false;
|
||||
impl.stop();
|
||||
Timers.runTask(2f, () -> {
|
||||
logic.doUpdate = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public boolean doInterpolate(){
|
||||
return enabled && Math.abs(Gdx.graphics.getFramesPerSecond() - getTPS()) > 15;
|
||||
return enabled && Gdx.graphics.getFramesPerSecond() - getTPS() > 20 && getTPS() < 30;
|
||||
}
|
||||
|
||||
public boolean isOnThread(){
|
||||
@@ -121,15 +110,21 @@ public class ThreadHandler {
|
||||
}
|
||||
|
||||
private void runLogic(){
|
||||
try {
|
||||
while (true) {
|
||||
try{
|
||||
while(true){
|
||||
long time = TimeUtils.nanoTime();
|
||||
|
||||
synchronized (toRun) {
|
||||
for(Runnable r : toRun){
|
||||
r.run();
|
||||
while(true){
|
||||
Runnable r;
|
||||
synchronized(toRun){
|
||||
if(toRun.size > 0){
|
||||
r = toRun.removeFirst();
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
toRun.clear();
|
||||
|
||||
r.run();
|
||||
}
|
||||
|
||||
logic.doUpdate = true;
|
||||
@@ -139,12 +134,12 @@ public class ThreadHandler {
|
||||
long elapsed = TimeUtils.nanosToMillis(TimeUtils.timeSinceNanos(time));
|
||||
long target = (long) ((1000) / 60f);
|
||||
|
||||
if (elapsed < target) {
|
||||
if(elapsed < target){
|
||||
impl.sleep(target - elapsed);
|
||||
}
|
||||
|
||||
synchronized(updateLock) {
|
||||
while(!rendered) {
|
||||
synchronized(updateLock){
|
||||
while(!rendered){
|
||||
impl.wait(updateLock);
|
||||
}
|
||||
rendered = false;
|
||||
@@ -158,23 +153,27 @@ public class ThreadHandler {
|
||||
smoothDelta = delta;
|
||||
}
|
||||
|
||||
frame ++;
|
||||
frame++;
|
||||
framesSinceUpdate = 0;
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
}catch(InterruptedException ex){
|
||||
Log.info("Stopping logic thread.");
|
||||
} catch (Throwable ex) {
|
||||
}catch(Throwable ex){
|
||||
control.setError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public interface ThreadProvider {
|
||||
public interface ThreadProvider{
|
||||
boolean isOnThread();
|
||||
|
||||
void sleep(long ms) throws InterruptedException;
|
||||
|
||||
void start(Runnable run);
|
||||
|
||||
void stop();
|
||||
|
||||
void wait(Object object) throws InterruptedException;
|
||||
|
||||
void notify(Object object);
|
||||
<T extends Entity> void switchContainer(EntityGroup<T> group);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,32 +34,11 @@ import java.util.Locale;
|
||||
|
||||
import static io.anuke.mindustry.Vars.control;
|
||||
import static io.anuke.mindustry.Vars.players;
|
||||
import static io.anuke.mindustry.Vars.threads;
|
||||
import static io.anuke.ucore.scene.actions.Actions.*;
|
||||
|
||||
public class UI extends SceneModule{
|
||||
public AboutDialog about;
|
||||
public RestartDialog restart;
|
||||
public LevelDialog levels;
|
||||
public MapsDialog maps;
|
||||
public LoadDialog load;
|
||||
public DiscordDialog discord;
|
||||
public JoinDialog join;
|
||||
public HostDialog host;
|
||||
public PausedDialog paused;
|
||||
public SettingsMenuDialog settings;
|
||||
public ControlsDialog controls;
|
||||
public MapEditorDialog editor;
|
||||
public LanguageDialog language;
|
||||
public BansDialog bans;
|
||||
public AdminsDialog admins;
|
||||
public TraceDialog traces;
|
||||
public RollbackDialog rollback;
|
||||
public ChangelogDialog changelog;
|
||||
public LocalPlayerDialog localplayers;
|
||||
public UnlocksDialog unlocks;
|
||||
public ContentInfoDialog content;
|
||||
|
||||
public final MenuFragment menufrag = new MenuFragment();
|
||||
public final MenuFragment menufrag = new MenuFragment();
|
||||
public final HudFragment hudfrag = new HudFragment();
|
||||
public final ChatFragment chatfrag = new ChatFragment();
|
||||
public final PlayerListFragment listfrag = new PlayerListFragment();
|
||||
@@ -67,239 +46,260 @@ public class UI extends SceneModule{
|
||||
public final LoadingFragment loadfrag = new LoadingFragment();
|
||||
public final DebugFragment debugfrag = new DebugFragment();
|
||||
|
||||
public AboutDialog about;
|
||||
public RestartDialog restart;
|
||||
public LevelDialog levels;
|
||||
public MapsDialog maps;
|
||||
public LoadDialog load;
|
||||
public DiscordDialog discord;
|
||||
public JoinDialog join;
|
||||
public HostDialog host;
|
||||
public PausedDialog paused;
|
||||
public SettingsMenuDialog settings;
|
||||
public ControlsDialog controls;
|
||||
public MapEditorDialog editor;
|
||||
public LanguageDialog language;
|
||||
public BansDialog bans;
|
||||
public AdminsDialog admins;
|
||||
public TraceDialog traces;
|
||||
public RollbackDialog rollback;
|
||||
public ChangelogDialog changelog;
|
||||
public LocalPlayerDialog localplayers;
|
||||
public UnlocksDialog unlocks;
|
||||
public ContentInfoDialog content;
|
||||
|
||||
private Locale lastLocale;
|
||||
|
||||
public UI() {
|
||||
Dialog.setShowAction(()-> sequence(
|
||||
alpha(0f),
|
||||
originCenter(),
|
||||
moveToAligned(Gdx.graphics.getWidth()/2, Gdx.graphics.getHeight()/2, Align.center),
|
||||
scaleTo(0.0f, 1f),
|
||||
parallel(
|
||||
scaleTo(1f, 1f, 0.1f, Interpolation.fade),
|
||||
fadeIn(0.1f, Interpolation.fade)
|
||||
)
|
||||
));
|
||||
|
||||
Dialog.setHideAction(()-> sequence(
|
||||
parallel(
|
||||
scaleTo(0.01f, 0.01f, 0.1f, Interpolation.fade),
|
||||
fadeOut(0.1f, Interpolation.fade)
|
||||
)
|
||||
));
|
||||
|
||||
TooltipManager.getInstance().animations = false;
|
||||
|
||||
Settings.setErrorHandler(()-> Timers.run(1f, ()-> showError("[crimson]Failed to access local storage.\nSettings will not be saved.")));
|
||||
|
||||
Dialog.closePadR = -1;
|
||||
Dialog.closePadT = 5;
|
||||
|
||||
Colors.put("description", Palette.description);
|
||||
Colors.put("turretinfo", Palette.turretinfo);
|
||||
Colors.put("iteminfo", Palette.iteminfo);
|
||||
Colors.put("powerinfo", Palette.powerinfo);
|
||||
Colors.put("liquidinfo", Palette.liquidinfo);
|
||||
Colors.put("craftinfo", Palette.craftinfo);
|
||||
Colors.put("missingitems", Palette.missingitems);
|
||||
Colors.put("health", Palette.health);
|
||||
Colors.put("healthstats", Palette.healthstats);
|
||||
Colors.put("interact", Palette.interact);
|
||||
Colors.put("accent", Palette.accent);
|
||||
Colors.put("place", Palette.place);
|
||||
Colors.put("remove", Palette.remove);
|
||||
Colors.put("placeRotate", Palette.placeRotate);
|
||||
Colors.put("range", Palette.range);
|
||||
Colors.put("power", Palette.power);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadSkin(){
|
||||
skin = new Skin(Gdx.files.internal("ui/uiskin.json"), Core.atlas);
|
||||
Mathf.each(font -> {
|
||||
font.setUseIntegerPositions(false);
|
||||
font.getData().setScale(Vars.fontScale);
|
||||
font.getData().down += Unit.dp.scl(4f);
|
||||
font.getData().lineHeight -= Unit.dp.scl(2f);
|
||||
}, skin.font(), skin.getFont("default-font-chat"), skin.getFont("korean"));
|
||||
}
|
||||
public UI(){
|
||||
Dialog.setShowAction(() -> sequence(
|
||||
alpha(0f),
|
||||
originCenter(),
|
||||
moveToAligned(Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() / 2, Align.center),
|
||||
scaleTo(0.0f, 1f),
|
||||
parallel(
|
||||
scaleTo(1f, 1f, 0.1f, Interpolation.fade),
|
||||
fadeIn(0.1f, Interpolation.fade)
|
||||
)
|
||||
));
|
||||
|
||||
@Override
|
||||
public synchronized void update(){
|
||||
if(Vars.debug && !Vars.showUI) return;
|
||||
Dialog.setHideAction(() -> sequence(
|
||||
parallel(
|
||||
scaleTo(0.01f, 0.01f, 0.1f, Interpolation.fade),
|
||||
fadeOut(0.1f, Interpolation.fade)
|
||||
)
|
||||
));
|
||||
|
||||
if(Graphics.drawing()) Graphics.end();
|
||||
|
||||
act();
|
||||
TooltipManager.getInstance().animations = false;
|
||||
|
||||
Graphics.begin();
|
||||
Settings.setErrorHandler(() -> Timers.run(1f, () -> showError("[crimson]Failed to access local storage.\nSettings will not be saved.")));
|
||||
|
||||
for(int i = 0; i < players.length; i ++){
|
||||
InputHandler input = control.input(i);
|
||||
Dialog.closePadR = -1;
|
||||
Dialog.closePadT = 5;
|
||||
|
||||
if(input.isCursorVisible()) {
|
||||
Colors.put("description", Palette.description);
|
||||
Colors.put("turretinfo", Palette.turretinfo);
|
||||
Colors.put("iteminfo", Palette.iteminfo);
|
||||
Colors.put("powerinfo", Palette.powerinfo);
|
||||
Colors.put("liquidinfo", Palette.liquidinfo);
|
||||
Colors.put("craftinfo", Palette.craftinfo);
|
||||
Colors.put("missingitems", Palette.missingitems);
|
||||
Colors.put("health", Palette.health);
|
||||
Colors.put("healthstats", Palette.healthstats);
|
||||
Colors.put("interact", Palette.interact);
|
||||
Colors.put("accent", Palette.accent);
|
||||
Colors.put("place", Palette.place);
|
||||
Colors.put("remove", Palette.remove);
|
||||
Colors.put("placeRotate", Palette.placeRotate);
|
||||
Colors.put("range", Palette.range);
|
||||
Colors.put("power", Palette.power);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void loadSkin(){
|
||||
skin = new Skin(Gdx.files.internal("ui/uiskin.json"), Core.atlas);
|
||||
Mathf.each(font -> {
|
||||
font.setUseIntegerPositions(false);
|
||||
font.getData().setScale(Vars.fontScale);
|
||||
font.getData().down += Unit.dp.scl(4f);
|
||||
font.getData().lineHeight -= Unit.dp.scl(2f);
|
||||
}, skin.font(), skin.getFont("default-font-chat"), skin.getFont("korean"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void update(){
|
||||
if(Vars.debug && !Vars.showUI) return;
|
||||
|
||||
if(Graphics.drawing()) Graphics.end();
|
||||
|
||||
act();
|
||||
|
||||
Graphics.begin();
|
||||
|
||||
for(int i = 0; i < players.length; i++){
|
||||
InputHandler input = control.input(i);
|
||||
|
||||
if(input.isCursorVisible()){
|
||||
Draw.color();
|
||||
|
||||
float scl = Unit.dp.scl(3f);
|
||||
|
||||
Draw.rect("controller-cursor", input.getMouseX(), Gdx.graphics.getHeight() - input.getMouseY(), 16*scl, 16*scl);
|
||||
Draw.rect("controller-cursor", input.getMouseX(), Gdx.graphics.getHeight() - input.getMouseY(), 16 * scl, 16 * scl);
|
||||
}
|
||||
}
|
||||
|
||||
Graphics.end();
|
||||
Graphics.end();
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void init(){
|
||||
editor = new MapEditorDialog();
|
||||
controls = new ControlsDialog();
|
||||
restart = new RestartDialog();
|
||||
join = new JoinDialog();
|
||||
discord = new DiscordDialog();
|
||||
load = new LoadDialog();
|
||||
levels = new LevelDialog();
|
||||
language = new LanguageDialog();
|
||||
settings = new SettingsMenuDialog();
|
||||
paused = new PausedDialog();
|
||||
changelog = new ChangelogDialog();
|
||||
about = new AboutDialog();
|
||||
host = new HostDialog();
|
||||
bans = new BansDialog();
|
||||
admins = new AdminsDialog();
|
||||
traces = new TraceDialog();
|
||||
rollback = new RollbackDialog();
|
||||
maps = new MapsDialog();
|
||||
localplayers = new LocalPlayerDialog();
|
||||
unlocks = new UnlocksDialog();
|
||||
content = new ContentInfoDialog();
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
editor = new MapEditorDialog();
|
||||
controls = new ControlsDialog();
|
||||
restart = new RestartDialog();
|
||||
join = new JoinDialog();
|
||||
discord = new DiscordDialog();
|
||||
load = new LoadDialog();
|
||||
levels = new LevelDialog();
|
||||
language = new LanguageDialog();
|
||||
settings = new SettingsMenuDialog();
|
||||
paused = new PausedDialog();
|
||||
changelog = new ChangelogDialog();
|
||||
about = new AboutDialog();
|
||||
host = new HostDialog();
|
||||
bans = new BansDialog();
|
||||
admins = new AdminsDialog();
|
||||
traces = new TraceDialog();
|
||||
rollback = new RollbackDialog();
|
||||
maps = new MapsDialog();
|
||||
localplayers = new LocalPlayerDialog();
|
||||
unlocks = new UnlocksDialog();
|
||||
content = new ContentInfoDialog();
|
||||
build.begin(scene);
|
||||
|
||||
build.begin(scene);
|
||||
Group group = Core.scene.getRoot();
|
||||
|
||||
Group group = Core.scene.getRoot();
|
||||
backfrag.build(group);
|
||||
hudfrag.build(group);
|
||||
menufrag.build(group);
|
||||
chatfrag.container().build(group);
|
||||
listfrag.build(group);
|
||||
debugfrag.build(group);
|
||||
loadfrag.build(group);
|
||||
|
||||
backfrag.build(group);
|
||||
hudfrag.build(group);
|
||||
menufrag.build(group);
|
||||
chatfrag.container().build(group);
|
||||
listfrag.build(group);
|
||||
debugfrag.build(group);
|
||||
loadfrag.build(group);
|
||||
build.end();
|
||||
}
|
||||
|
||||
build.end();
|
||||
}
|
||||
@Override
|
||||
public boolean hasMouse(){
|
||||
return super.hasMouse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMouse() {
|
||||
return super.hasMouse();
|
||||
}
|
||||
@Override
|
||||
public void resize(int width, int height){
|
||||
super.resize(width, height);
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height) {
|
||||
super.resize(width, height);
|
||||
Events.fire(ResizeEvent.class);
|
||||
}
|
||||
|
||||
Events.fire(ResizeEvent.class);
|
||||
}
|
||||
public Locale getLocale(){
|
||||
String loc = Settings.getString("locale");
|
||||
if(loc.equals("default")){
|
||||
return Locale.getDefault();
|
||||
}else{
|
||||
if(lastLocale == null || !lastLocale.toString().equals(loc)){
|
||||
if(loc.contains("_")){
|
||||
String[] split = loc.split("_");
|
||||
lastLocale = new Locale(split[0], split[1]);
|
||||
}else{
|
||||
lastLocale = new Locale(loc);
|
||||
}
|
||||
}
|
||||
|
||||
public Locale getLocale(){
|
||||
String loc = Settings.getString("locale");
|
||||
if(loc.equals("default")){
|
||||
return Locale.getDefault();
|
||||
}else{
|
||||
if(lastLocale == null || !lastLocale.toString().equals(loc)){
|
||||
if(loc.contains("_")){
|
||||
String[] split = loc.split("_");
|
||||
lastLocale = new Locale(split[0], split[1]);
|
||||
}else{
|
||||
lastLocale = new Locale(loc);
|
||||
}
|
||||
}
|
||||
return lastLocale;
|
||||
}
|
||||
}
|
||||
|
||||
return lastLocale;
|
||||
}
|
||||
}
|
||||
public void loadAnd(Callable call){
|
||||
loadAnd("$text.loading", call);
|
||||
}
|
||||
|
||||
public void loadAnd(Callable call){
|
||||
loadAnd("$text.loading", call);
|
||||
}
|
||||
public void loadAnd(String text, Callable call){
|
||||
loadfrag.show(text);
|
||||
Timers.runTask(7f, () -> {
|
||||
call.run();
|
||||
loadfrag.hide();
|
||||
});
|
||||
}
|
||||
|
||||
public void loadAnd(String text, Callable call){
|
||||
loadfrag.show(text);
|
||||
Timers.runTask(6f, () -> {
|
||||
call.run();
|
||||
loadfrag.hide();
|
||||
});
|
||||
}
|
||||
public void loadLogic(Callable call){
|
||||
loadLogic("$text.loading", call);
|
||||
}
|
||||
|
||||
public void showTextInput(String title, String text, String def, TextFieldFilter filter, Consumer<String> confirmed){
|
||||
new Dialog(title, "dialog"){{
|
||||
content().margin(30).add(text).padRight(6f);
|
||||
TextField field = content().addField(def, t->{}).size(170f, 50f).get();
|
||||
field.setTextFieldFilter((f, c) -> field.getText().length() < 12 && filter.acceptChar(f, c));
|
||||
Platform.instance.addDialog(field);
|
||||
buttons().defaults().size(120, 54).pad(4);
|
||||
buttons().addButton("$text.ok", () -> {
|
||||
confirmed.accept(field.getText());
|
||||
hide();
|
||||
}).disabled(b -> field.getText().isEmpty());
|
||||
buttons().addButton("$text.cancel", this::hide);
|
||||
}}.show();
|
||||
}
|
||||
public void loadLogic(String text, Callable call){
|
||||
loadfrag.show();
|
||||
Timers.runTask(7f, () -> {
|
||||
threads.run(() -> {
|
||||
call.run();
|
||||
threads.runGraphics(loadfrag::hide);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public void showTextInput(String title, String text, String def, Consumer<String> confirmed){
|
||||
showTextInput(title, text, def, (field, c) -> true, confirmed);
|
||||
}
|
||||
public void showTextInput(String title, String text, String def, TextFieldFilter filter, Consumer<String> confirmed){
|
||||
new Dialog(title, "dialog"){{
|
||||
content().margin(30).add(text).padRight(6f);
|
||||
TextField field = content().addField(def, t -> {
|
||||
}).size(170f, 50f).get();
|
||||
field.setTextFieldFilter((f, c) -> field.getText().length() < 12 && filter.acceptChar(f, c));
|
||||
Platform.instance.addDialog(field);
|
||||
buttons().defaults().size(120, 54).pad(4);
|
||||
buttons().addButton("$text.ok", () -> {
|
||||
confirmed.accept(field.getText());
|
||||
hide();
|
||||
}).disabled(b -> field.getText().isEmpty());
|
||||
buttons().addButton("$text.cancel", this::hide);
|
||||
}}.show();
|
||||
}
|
||||
|
||||
public void showInfoFade(String info){
|
||||
Table table = new Table();
|
||||
table.setFillParent(true);
|
||||
table.actions(Actions.fadeOut(7f, Interpolation.fade), Actions.removeActor());
|
||||
table.top().add(info).padTop(8);
|
||||
Core.scene.add(table);
|
||||
}
|
||||
public void showTextInput(String title, String text, String def, Consumer<String> confirmed){
|
||||
showTextInput(title, text, def, (field, c) -> true, confirmed);
|
||||
}
|
||||
|
||||
public void showInfo(String info){
|
||||
new Dialog("$text.info.title", "dialog"){{
|
||||
getCell(content()).growX();
|
||||
content().margin(15).add(info).width(400f).wrap().get().setAlignment(Align.center, Align.center);
|
||||
buttons().addButton("$text.ok", this::hide).size(90, 50).pad(4);
|
||||
}}.show();
|
||||
}
|
||||
public void showInfoFade(String info){
|
||||
Table table = new Table();
|
||||
table.setFillParent(true);
|
||||
table.actions(Actions.fadeOut(7f, Interpolation.fade), Actions.removeActor());
|
||||
table.top().add(info).padTop(8);
|
||||
Core.scene.add(table);
|
||||
}
|
||||
|
||||
public void showError(String text){
|
||||
new Dialog("$text.error.title", "dialog"){{
|
||||
content().margin(15).add(text).width(400f).wrap().get().setAlignment(Align.center, Align.center);
|
||||
buttons().addButton("$text.ok", this::hide).size(90, 50).pad(4);
|
||||
}}.show();
|
||||
}
|
||||
public void showInfo(String info){
|
||||
new Dialog("$text.info.title", "dialog"){{
|
||||
getCell(content()).growX();
|
||||
content().margin(15).add(info).width(400f).wrap().get().setAlignment(Align.center, Align.center);
|
||||
buttons().addButton("$text.ok", this::hide).size(90, 50).pad(4);
|
||||
}}.show();
|
||||
}
|
||||
|
||||
public void showConfirm(String title, String text, Listenable confirmed){
|
||||
FloatingDialog dialog = new FloatingDialog(title);
|
||||
dialog.content().add(text).width(400f).wrap().pad(4f).get().setAlignment(Align.center, Align.center);
|
||||
dialog.buttons().defaults().size(200f, 54f).pad(2f);
|
||||
dialog.buttons().addButton("$text.cancel", dialog::hide);
|
||||
dialog.buttons().addButton("$text.ok", () -> {
|
||||
dialog.hide();
|
||||
confirmed.listen();
|
||||
});
|
||||
dialog.keyDown(Keys.ESCAPE, dialog::hide);
|
||||
dialog.keyDown(Keys.BACK, dialog::hide);
|
||||
dialog.show();
|
||||
}
|
||||
public void showError(String text){
|
||||
new Dialog("$text.error.title", "dialog"){{
|
||||
content().margin(15).add(text).width(400f).wrap().get().setAlignment(Align.center, Align.center);
|
||||
buttons().addButton("$text.ok", this::hide).size(90, 50).pad(4);
|
||||
}}.show();
|
||||
}
|
||||
|
||||
public void showConfirmListen(String title, String text, Consumer<Boolean> listener){
|
||||
FloatingDialog dialog = new FloatingDialog(title);
|
||||
dialog.content().add(text).pad(4f);
|
||||
dialog.buttons().defaults().size(200f, 54f).pad(2f);
|
||||
dialog.buttons().addButton("$text.cancel", () -> {
|
||||
dialog.hide();
|
||||
listener.accept(true);
|
||||
});
|
||||
dialog.buttons().addButton("$text.ok", () -> {
|
||||
dialog.hide();
|
||||
listener.accept(true);
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
public void showConfirm(String title, String text, Listenable confirmed){
|
||||
FloatingDialog dialog = new FloatingDialog(title);
|
||||
dialog.content().add(text).width(400f).wrap().pad(4f).get().setAlignment(Align.center, Align.center);
|
||||
dialog.buttons().defaults().size(200f, 54f).pad(2f);
|
||||
dialog.buttons().addButton("$text.cancel", dialog::hide);
|
||||
dialog.buttons().addButton("$text.ok", () -> {
|
||||
dialog.hide();
|
||||
confirmed.listen();
|
||||
});
|
||||
dialog.keyDown(Keys.ESCAPE, dialog::hide);
|
||||
dialog.keyDown(Keys.BACK, dialog::hide);
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,11 @@ import io.anuke.mindustry.content.blocks.Blocks;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.game.EventType.TileChangeEvent;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.io.*;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.io.Map;
|
||||
import io.anuke.mindustry.io.MapIO;
|
||||
import io.anuke.mindustry.io.MapMeta;
|
||||
import io.anuke.mindustry.io.Maps;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.mapgen.WorldGenerator;
|
||||
@@ -26,124 +30,130 @@ import io.anuke.ucore.util.Tmp;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class World extends Module{
|
||||
private int seed;
|
||||
|
||||
private Map currentMap;
|
||||
private Tile[][] tiles;
|
||||
private Pathfinder pathfinder = new Pathfinder();
|
||||
private BlockIndexer indexer = new BlockIndexer();
|
||||
private Maps maps = new Maps();
|
||||
private int seed;
|
||||
|
||||
private Array<Tile> tempTiles = new ThreadArray<>();
|
||||
private boolean generating, invalidMap;
|
||||
|
||||
public World(){
|
||||
maps.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
maps.dispose();
|
||||
}
|
||||
|
||||
public Maps maps(){
|
||||
return maps;
|
||||
}
|
||||
private Map currentMap;
|
||||
private Tile[][] tiles;
|
||||
private Pathfinder pathfinder = new Pathfinder();
|
||||
private BlockIndexer indexer = new BlockIndexer();
|
||||
private Maps maps = new Maps();
|
||||
|
||||
public BlockIndexer indexer() {
|
||||
return indexer;
|
||||
}
|
||||
private Array<Tile> tempTiles = new ThreadArray<>();
|
||||
private boolean generating, invalidMap;
|
||||
|
||||
public Pathfinder pathfinder(){
|
||||
return pathfinder;
|
||||
}
|
||||
public World(){
|
||||
maps.load();
|
||||
}
|
||||
|
||||
public boolean isInvalidMap() {
|
||||
return invalidMap;
|
||||
}
|
||||
@Override
|
||||
public void dispose(){
|
||||
maps.dispose();
|
||||
}
|
||||
|
||||
public boolean solid(int x, int y){
|
||||
Tile tile = tile(x, y);
|
||||
|
||||
return tile == null || tile.solid();
|
||||
}
|
||||
|
||||
public boolean passable(int x, int y){
|
||||
Tile tile = tile(x, y);
|
||||
|
||||
return tile != null && tile.passable();
|
||||
}
|
||||
|
||||
public boolean wallSolid(int x, int y){
|
||||
Tile tile = tile(x, y);
|
||||
return tile == null || tile.block().solid;
|
||||
}
|
||||
|
||||
public boolean isAccessible(int x, int y){
|
||||
return !wallSolid(x, y-1) || !wallSolid(x, y+1) || !wallSolid(x-1, y) ||!wallSolid(x+1, y);
|
||||
}
|
||||
|
||||
public boolean floorBlends(int x, int y, Block block){
|
||||
Tile tile = tile(x, y);
|
||||
return tile == null || tile.floor().id <= block.id;
|
||||
}
|
||||
|
||||
public Map getMap(){
|
||||
return currentMap;
|
||||
}
|
||||
|
||||
public int width(){
|
||||
return tiles.length;
|
||||
}
|
||||
|
||||
public int height(){
|
||||
return tiles[0].length;
|
||||
}
|
||||
public Maps maps(){
|
||||
return maps;
|
||||
}
|
||||
|
||||
public int toPacked(int x, int y){
|
||||
return x + y *width();
|
||||
}
|
||||
public BlockIndexer indexer(){
|
||||
return indexer;
|
||||
}
|
||||
|
||||
public Tile tile(int packed){
|
||||
return tiles == null ? null : tile(packed % width(), packed / width());
|
||||
}
|
||||
|
||||
public Tile tile(int x, int y){
|
||||
if(tiles == null){
|
||||
return null;
|
||||
}
|
||||
if(!Mathf.inBounds(x, y, tiles)) return null;
|
||||
return tiles[x][y];
|
||||
}
|
||||
public Pathfinder pathfinder(){
|
||||
return pathfinder;
|
||||
}
|
||||
|
||||
public Tile rawTile(int x, int y){
|
||||
return tiles[x][y];
|
||||
}
|
||||
|
||||
public Tile tileWorld(float x, float y){
|
||||
return tile(Mathf.scl2(x, tilesize), Mathf.scl2(y, tilesize));
|
||||
}
|
||||
public boolean isInvalidMap(){
|
||||
return invalidMap;
|
||||
}
|
||||
|
||||
public int toTile(float coord){
|
||||
return Mathf.scl2(coord, tilesize);
|
||||
}
|
||||
|
||||
public Tile[][] getTiles(){
|
||||
return tiles;
|
||||
}
|
||||
|
||||
private void clearTileEntities(){
|
||||
for(int x = 0; x < tiles.length; x ++){
|
||||
for(int y = 0; y < tiles[0].length; y ++){
|
||||
if(tiles[x][y] != null && tiles[x][y].entity != null){
|
||||
tiles[x][y].entity.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public boolean solid(int x, int y){
|
||||
Tile tile = tile(x, y);
|
||||
|
||||
/**Resizes the tile array to the specified size and returns the resulting tile array.
|
||||
* Only use for loading saves!*/
|
||||
return tile == null || tile.solid();
|
||||
}
|
||||
|
||||
public boolean passable(int x, int y){
|
||||
Tile tile = tile(x, y);
|
||||
|
||||
return tile != null && tile.passable();
|
||||
}
|
||||
|
||||
public boolean wallSolid(int x, int y){
|
||||
Tile tile = tile(x, y);
|
||||
return tile == null || tile.block().solid;
|
||||
}
|
||||
|
||||
public boolean isAccessible(int x, int y){
|
||||
return !wallSolid(x, y - 1) || !wallSolid(x, y + 1) || !wallSolid(x - 1, y) || !wallSolid(x + 1, y);
|
||||
}
|
||||
|
||||
public boolean floorBlends(int x, int y, Block block){
|
||||
Tile tile = tile(x, y);
|
||||
return tile == null || tile.floor().id <= block.id;
|
||||
}
|
||||
|
||||
public Map getMap(){
|
||||
return currentMap;
|
||||
}
|
||||
|
||||
public void setMap(Map map){
|
||||
this.currentMap = map;
|
||||
}
|
||||
|
||||
public int width(){
|
||||
return tiles == null ? 0 : tiles.length;
|
||||
}
|
||||
|
||||
public int height(){
|
||||
return tiles == null ? 0 : tiles[0].length;
|
||||
}
|
||||
|
||||
public int toPacked(int x, int y){
|
||||
return x + y * width();
|
||||
}
|
||||
|
||||
public Tile tile(int packed){
|
||||
return tiles == null ? null : tile(packed % width(), packed / width());
|
||||
}
|
||||
|
||||
public Tile tile(int x, int y){
|
||||
if(tiles == null){
|
||||
return null;
|
||||
}
|
||||
if(!Mathf.inBounds(x, y, tiles)) return null;
|
||||
return tiles[x][y];
|
||||
}
|
||||
|
||||
public Tile rawTile(int x, int y){
|
||||
return tiles[x][y];
|
||||
}
|
||||
|
||||
public Tile tileWorld(float x, float y){
|
||||
return tile(Mathf.scl2(x, tilesize), Mathf.scl2(y, tilesize));
|
||||
}
|
||||
|
||||
public int toTile(float coord){
|
||||
return Mathf.scl2(coord, tilesize);
|
||||
}
|
||||
|
||||
public Tile[][] getTiles(){
|
||||
return tiles;
|
||||
}
|
||||
|
||||
private void clearTileEntities(){
|
||||
for(int x = 0; x < tiles.length; x++){
|
||||
for(int y = 0; y < tiles[0].length; y++){
|
||||
if(tiles[x][y] != null && tiles[x][y].entity != null){
|
||||
tiles[x][y].entity.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes the tile array to the specified size and returns the resulting tile array.
|
||||
* Only use for loading saves!
|
||||
*/
|
||||
public Tile[][] createTiles(int width, int height){
|
||||
if(tiles != null){
|
||||
clearTileEntities();
|
||||
@@ -158,181 +168,214 @@ public class World extends Module{
|
||||
return tiles;
|
||||
}
|
||||
|
||||
/**Call to signify the beginning of map loading.
|
||||
* TileChangeEvents will not be fired until endMapLoad().*/
|
||||
public void beginMapLoad(){
|
||||
generating = true;
|
||||
}
|
||||
/**
|
||||
* Call to signify the beginning of map loading.
|
||||
* TileChangeEvents will not be fired until endMapLoad().
|
||||
*/
|
||||
public void beginMapLoad(){
|
||||
generating = true;
|
||||
}
|
||||
|
||||
/**Call to signify the end of map loading. Updates tile occlusions and sets up physics for the world.
|
||||
* A WorldLoadEvent will be fire.*/
|
||||
public void endMapLoad(){
|
||||
for(int x = 0; x < tiles.length; x ++) {
|
||||
for (int y = 0; y < tiles[0].length; y++) {
|
||||
tiles[x][y].updateOcclusion();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Call to signify the end of map loading. Updates tile occlusions and sets up physics for the world.
|
||||
* A WorldLoadEvent will be fire.
|
||||
*/
|
||||
public void endMapLoad(){
|
||||
for(int x = 0; x < tiles.length; x++){
|
||||
for(int y = 0; y < tiles[0].length; y++){
|
||||
tiles[x][y].updateOcclusion();
|
||||
|
||||
EntityPhysics.resizeTree(0, 0, tiles.length * tilesize, tiles[0].length * tilesize);
|
||||
if(tiles[x][y].entity != null){
|
||||
tiles[x][y].entity.updateProximity();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generating = false;
|
||||
Events.fire(WorldLoadEvent.class);
|
||||
}
|
||||
EntityPhysics.resizeTree(0, 0, tiles.length * tilesize, tiles[0].length * tilesize);
|
||||
|
||||
/**Loads up a procedural map. This does not call play(), but calls reset().*/
|
||||
public void loadProceduralMap(){
|
||||
Timers.mark();
|
||||
Timers.mark();
|
||||
generating = false;
|
||||
Events.fire(WorldLoadEvent.class);
|
||||
}
|
||||
|
||||
logic.reset();
|
||||
/**
|
||||
* Loads up a procedural map. This does not call play(), but calls reset().
|
||||
*/
|
||||
public void loadProceduralMap(){
|
||||
Timers.mark();
|
||||
Timers.mark();
|
||||
|
||||
beginMapLoad();
|
||||
logic.reset();
|
||||
|
||||
int width = 400, height = 400;
|
||||
beginMapLoad();
|
||||
|
||||
Tile[][] tiles = createTiles(width, height);
|
||||
int width = 400, height = 400;
|
||||
|
||||
Map map = new Map("Generated Map", new MapMeta(0, new ObjectMap<>(), width, height, null), true, () -> null);
|
||||
setMap(map);
|
||||
Tile[][] tiles = createTiles(width, height);
|
||||
|
||||
EntityPhysics.resizeTree(0, 0, width * tilesize, height * tilesize);
|
||||
Map map = new Map("Generated Map", new MapMeta(0, new ObjectMap<>(), width, height, null), true, () -> null);
|
||||
setMap(map);
|
||||
|
||||
Timers.mark();
|
||||
WorldGenerator.generateMap(tiles, Mathf.random(9999999));
|
||||
Log.info("Time to generate base map: {0}", Timers.elapsed());
|
||||
EntityPhysics.resizeTree(0, 0, width * tilesize, height * tilesize);
|
||||
|
||||
Log.info("Time to generate fully without additional events: {0}", Timers.elapsed());
|
||||
Timers.mark();
|
||||
WorldGenerator.generateMap(tiles, Mathf.random(9999999));
|
||||
Log.info("Time to generate base map: {0}", Timers.elapsed());
|
||||
|
||||
endMapLoad();
|
||||
Log.info("Time to generate fully without additional events: {0}", Timers.elapsed());
|
||||
|
||||
Log.info("Full time to generate: {0}", Timers.elapsed());
|
||||
}
|
||||
endMapLoad();
|
||||
|
||||
public void setMap(Map map){
|
||||
this.currentMap = map;
|
||||
}
|
||||
|
||||
public void loadMap(Map map){
|
||||
loadMap(map, MathUtils.random(0, 999999));
|
||||
}
|
||||
|
||||
public void loadMap(Map map, int seed){
|
||||
beginMapLoad();
|
||||
this.currentMap = map;
|
||||
this.seed = seed;
|
||||
Log.info("Full time to generate: {0}", Timers.elapsed());
|
||||
}
|
||||
|
||||
int width = map.meta.width, height = map.meta.height;
|
||||
public void loadMap(Map map){
|
||||
loadMap(map, MathUtils.random(0, 999999));
|
||||
}
|
||||
|
||||
createTiles(width, height);
|
||||
|
||||
EntityPhysics.resizeTree(0, 0, width * tilesize, height * tilesize);
|
||||
public void loadMap(Map map, int seed){
|
||||
beginMapLoad();
|
||||
this.currentMap = map;
|
||||
this.seed = seed;
|
||||
|
||||
WorldGenerator.loadTileData(tiles, MapIO.readTileData(map, true), map.meta.hasOreGen(), seed);
|
||||
int width = map.meta.width, height = map.meta.height;
|
||||
|
||||
if(!headless && state.teams.get(players[0].getTeam()).cores.size == 0){
|
||||
ui.showError("$text.map.nospawn");
|
||||
threads.runDelay(() -> state.set(State.menu));
|
||||
invalidMap = true;
|
||||
}else{
|
||||
invalidMap = false;
|
||||
}
|
||||
createTiles(width, height);
|
||||
|
||||
endMapLoad();
|
||||
}
|
||||
EntityPhysics.resizeTree(0, 0, width * tilesize, height * tilesize);
|
||||
|
||||
public int getSeed(){
|
||||
return seed;
|
||||
}
|
||||
WorldGenerator.loadTileData(tiles, MapIO.readTileData(map, true), map.meta.hasOreGen(), seed);
|
||||
|
||||
public void notifyChanged(Tile tile){
|
||||
if(!generating){
|
||||
threads.runDelay(() -> Events.fire(TileChangeEvent.class, tile));
|
||||
}
|
||||
}
|
||||
if(!headless && state.teams.get(players[0].getTeam()).cores.size == 0){
|
||||
ui.showError("$text.map.nospawn");
|
||||
threads.runDelay(() -> state.set(State.menu));
|
||||
invalidMap = true;
|
||||
}else{
|
||||
invalidMap = false;
|
||||
}
|
||||
|
||||
public void removeBlock(Tile tile){
|
||||
if(!tile.block().isMultiblock() && !tile.isLinked()){
|
||||
tile.setBlock(Blocks.air);
|
||||
}else{
|
||||
Tile target = tile.target();
|
||||
Array<Tile> removals = target.getLinkedTiles(tempTiles);
|
||||
for(Tile toremove : removals){
|
||||
//note that setting a new block automatically unlinks it
|
||||
if(toremove != null) toremove.setBlock(Blocks.air);
|
||||
}
|
||||
}
|
||||
}
|
||||
endMapLoad();
|
||||
}
|
||||
|
||||
/**Raycast, but with world coordinates.*/
|
||||
public GridPoint2 raycastWorld(float x, float y, float x2, float y2){
|
||||
return raycast(Mathf.scl2(x, tilesize), Mathf.scl2(y, tilesize),
|
||||
Mathf.scl2(x2, tilesize), Mathf.scl2(y2, tilesize));
|
||||
}
|
||||
|
||||
/**Input is in block coordinates, not world coordinates.
|
||||
* @return null if no collisions found, block position otherwise.*/
|
||||
public GridPoint2 raycast(int x0f, int y0f, int x1, int y1){
|
||||
int x0 = x0f;
|
||||
int y0 = y0f;
|
||||
int dx = Math.abs(x1 - x0);
|
||||
int dy = Math.abs(y1 - y0);
|
||||
public int getSeed(){
|
||||
return seed;
|
||||
}
|
||||
|
||||
int sx = x0 < x1 ? 1 : -1;
|
||||
int sy = y0 < y1 ? 1 : -1;
|
||||
public void notifyChanged(Tile tile){
|
||||
if(!generating){
|
||||
threads.runDelay(() -> Events.fire(TileChangeEvent.class, tile));
|
||||
}
|
||||
}
|
||||
|
||||
int err = dx - dy;
|
||||
int e2;
|
||||
while(true){
|
||||
public void removeBlock(Tile tile){
|
||||
if(!tile.block().isMultiblock() && !tile.isLinked()){
|
||||
tile.setBlock(Blocks.air);
|
||||
}else{
|
||||
Tile target = tile.target();
|
||||
Array<Tile> removals = target.getLinkedTiles(tempTiles);
|
||||
for(Tile toremove : removals){
|
||||
//note that setting a new block automatically unlinks it
|
||||
if(toremove != null) toremove.setBlock(Blocks.air);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!passable(x0, y0)){
|
||||
return Tmp.g1.set(x0, y0);
|
||||
}
|
||||
if(x0 == x1 && y0 == y1) break;
|
||||
public void setBlock(Tile tile, Block block, Team team){
|
||||
tile.setBlock(block);
|
||||
if(block.isMultiblock()){
|
||||
int offsetx = -(block.size - 1) / 2;
|
||||
int offsety = -(block.size - 1) / 2;
|
||||
|
||||
e2 = 2 * err;
|
||||
if(e2 > -dy){
|
||||
err = err - dy;
|
||||
x0 = x0 + sx;
|
||||
}
|
||||
for(int dx = 0; dx < block.size; dx++){
|
||||
for(int dy = 0; dy < block.size; dy++){
|
||||
int worldx = dx + offsetx + tile.x;
|
||||
int worldy = dy + offsety + tile.y;
|
||||
if(!(worldx == tile.x && worldy == tile.y)){
|
||||
Tile toplace = world.tile(worldx, worldy);
|
||||
if(toplace != null){
|
||||
toplace.setLinked((byte) (dx + offsetx), (byte) (dy + offsety));
|
||||
toplace.setTeam(team);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(e2 < dx){
|
||||
err = err + dx;
|
||||
y0 = y0 + sy;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Raycast, but with world coordinates.
|
||||
*/
|
||||
public GridPoint2 raycastWorld(float x, float y, float x2, float y2){
|
||||
return raycast(Mathf.scl2(x, tilesize), Mathf.scl2(y, tilesize),
|
||||
Mathf.scl2(x2, tilesize), Mathf.scl2(y2, tilesize));
|
||||
}
|
||||
|
||||
public void raycastEach(int x0f, int y0f, int x1, int y1, Raycaster cons){
|
||||
int x0 = x0f;
|
||||
int y0 = y0f;
|
||||
int dx = Math.abs(x1 - x0);
|
||||
int dy = Math.abs(y1 - y0);
|
||||
/**
|
||||
* Input is in block coordinates, not world coordinates.
|
||||
*
|
||||
* @return null if no collisions found, block position otherwise.
|
||||
*/
|
||||
public GridPoint2 raycast(int x0f, int y0f, int x1, int y1){
|
||||
int x0 = x0f;
|
||||
int y0 = y0f;
|
||||
int dx = Math.abs(x1 - x0);
|
||||
int dy = Math.abs(y1 - y0);
|
||||
|
||||
int sx = x0 < x1 ? 1 : -1;
|
||||
int sy = y0 < y1 ? 1 : -1;
|
||||
int sx = x0 < x1 ? 1 : -1;
|
||||
int sy = y0 < y1 ? 1 : -1;
|
||||
|
||||
int err = dx - dy;
|
||||
int e2;
|
||||
while(true){
|
||||
int err = dx - dy;
|
||||
int e2;
|
||||
while(true){
|
||||
|
||||
if(cons.accept(x0, y0)) break;
|
||||
if(x0 == x1 && y0 == y1) break;
|
||||
if(!passable(x0, y0)){
|
||||
return Tmp.g1.set(x0, y0);
|
||||
}
|
||||
if(x0 == x1 && y0 == y1) break;
|
||||
|
||||
e2 = 2 * err;
|
||||
if(e2 > -dy){
|
||||
err = err - dy;
|
||||
x0 = x0 + sx;
|
||||
}
|
||||
e2 = 2 * err;
|
||||
if(e2 > -dy){
|
||||
err = err - dy;
|
||||
x0 = x0 + sx;
|
||||
}
|
||||
|
||||
if(e2 < dx){
|
||||
err = err + dx;
|
||||
y0 = y0 + sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(e2 < dx){
|
||||
err = err + dx;
|
||||
y0 = y0 + sy;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public interface Raycaster{
|
||||
boolean accept(int x, int y);
|
||||
}
|
||||
public void raycastEach(int x0f, int y0f, int x1, int y1, Raycaster cons){
|
||||
int x0 = x0f;
|
||||
int y0 = y0f;
|
||||
int dx = Math.abs(x1 - x0);
|
||||
int dy = Math.abs(y1 - y0);
|
||||
|
||||
int sx = x0 < x1 ? 1 : -1;
|
||||
int sy = y0 < y1 ? 1 : -1;
|
||||
|
||||
int err = dx - dy;
|
||||
int e2;
|
||||
while(true){
|
||||
|
||||
if(cons.accept(x0, y0)) break;
|
||||
if(x0 == x1 && y0 == y1) break;
|
||||
|
||||
e2 = 2 * err;
|
||||
if(e2 > -dy){
|
||||
err = err - dy;
|
||||
x0 = x0 + sx;
|
||||
}
|
||||
|
||||
if(e2 < dx){
|
||||
err = err + dx;
|
||||
y0 = y0 + sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface Raycaster{
|
||||
boolean accept(int x, int y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,60 +7,66 @@ import io.anuke.mindustry.io.MapTileData.TileDataMarker;
|
||||
import io.anuke.ucore.util.Bits;
|
||||
|
||||
public class DrawOperation{
|
||||
/**Data to apply operation to.*/
|
||||
private MapTileData data;
|
||||
/**List of per-tile operations that occurred.*/
|
||||
private Array<TileOperation> operations = new Array<>();
|
||||
/**Checks for duplicate operations, useful for brushes.*/
|
||||
private IntSet checks = new IntSet();
|
||||
/**
|
||||
* Data to apply operation to.
|
||||
*/
|
||||
private MapTileData data;
|
||||
/**
|
||||
* List of per-tile operations that occurred.
|
||||
*/
|
||||
private Array<TileOperation> operations = new Array<>();
|
||||
/**
|
||||
* Checks for duplicate operations, useful for brushes.
|
||||
*/
|
||||
private IntSet checks = new IntSet();
|
||||
|
||||
public DrawOperation(MapTileData data){
|
||||
this.data = data;
|
||||
}
|
||||
public DrawOperation(MapTileData data){
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public boolean isEmpty(){
|
||||
return operations.size == 0;
|
||||
}
|
||||
public boolean isEmpty(){
|
||||
return operations.size == 0;
|
||||
}
|
||||
|
||||
public boolean checkDuplicate(short x, short y){
|
||||
int i = Bits.packInt(x, y);
|
||||
if(checks.contains(i)) return true;
|
||||
public boolean checkDuplicate(short x, short y){
|
||||
int i = Bits.packInt(x, y);
|
||||
if(checks.contains(i)) return true;
|
||||
|
||||
checks.add(i);
|
||||
return false;
|
||||
}
|
||||
checks.add(i);
|
||||
return false;
|
||||
}
|
||||
|
||||
public void addOperation(TileOperation op){
|
||||
operations.add(op);
|
||||
}
|
||||
public void addOperation(TileOperation op){
|
||||
operations.add(op);
|
||||
}
|
||||
|
||||
public void undo(MapEditor editor) {
|
||||
for(int i = operations.size - 1; i >= 0; i --){
|
||||
TileOperation op = operations.get(i);
|
||||
data.position(op.x, op.y);
|
||||
data.write(op.from);
|
||||
editor.renderer().updatePoint(op.x, op.y);
|
||||
}
|
||||
}
|
||||
public void undo(MapEditor editor){
|
||||
for(int i = operations.size - 1; i >= 0; i--){
|
||||
TileOperation op = operations.get(i);
|
||||
data.position(op.x, op.y);
|
||||
data.write(op.from);
|
||||
editor.renderer().updatePoint(op.x, op.y);
|
||||
}
|
||||
}
|
||||
|
||||
public void redo(MapEditor editor) {
|
||||
for(TileOperation op : operations){
|
||||
data.position(op.x, op.y);
|
||||
data.write(op.to);
|
||||
editor.renderer().updatePoint(op.x, op.y);
|
||||
}
|
||||
}
|
||||
public void redo(MapEditor editor){
|
||||
for(TileOperation op : operations){
|
||||
data.position(op.x, op.y);
|
||||
data.write(op.to);
|
||||
editor.renderer().updatePoint(op.x, op.y);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TileOperation{
|
||||
public short x, y;
|
||||
public TileDataMarker from;
|
||||
public TileDataMarker to;
|
||||
public static class TileOperation{
|
||||
public short x, y;
|
||||
public TileDataMarker from;
|
||||
public TileDataMarker to;
|
||||
|
||||
public TileOperation(short x, short y, TileDataMarker from, TileDataMarker to) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
}
|
||||
public TileOperation(short x, short y, TileDataMarker from, TileDataMarker to){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,132 +12,132 @@ import io.anuke.ucore.util.Bits;
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
|
||||
public enum EditorTool{
|
||||
pick{
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
byte bf = editor.getMap().read(x, y, DataPosition.floor);
|
||||
byte bw = editor.getMap().read(x, y, DataPosition.wall);
|
||||
byte link = editor.getMap().read(x, y, DataPosition.link);
|
||||
pick{
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
byte bf = editor.getMap().read(x, y, DataPosition.floor);
|
||||
byte bw = editor.getMap().read(x, y, DataPosition.wall);
|
||||
byte link = editor.getMap().read(x, y, DataPosition.link);
|
||||
|
||||
if(link != 0){
|
||||
x -= (Bits.getLeftByte(link) - 8);
|
||||
y -= (Bits.getRightByte(link) - 8);
|
||||
bf = editor.getMap().read(x, y, DataPosition.floor);
|
||||
bw = editor.getMap().read(x, y, DataPosition.wall);
|
||||
}
|
||||
if(link != 0){
|
||||
x -= (Bits.getLeftByte(link) - 8);
|
||||
y -= (Bits.getRightByte(link) - 8);
|
||||
bf = editor.getMap().read(x, y, DataPosition.floor);
|
||||
bw = editor.getMap().read(x, y, DataPosition.wall);
|
||||
}
|
||||
|
||||
Block block = Block.getByID(bw == 0 ? bf : bw);
|
||||
editor.setDrawBlock(block);
|
||||
ui.editor.updateSelectedBlock();
|
||||
}
|
||||
},
|
||||
pencil{
|
||||
{
|
||||
edit = true;
|
||||
draggable = true;
|
||||
}
|
||||
Block block = Block.getByID(bw == 0 ? bf : bw);
|
||||
editor.setDrawBlock(block);
|
||||
ui.editor.updateSelectedBlock();
|
||||
}
|
||||
},
|
||||
pencil{
|
||||
{
|
||||
edit = true;
|
||||
draggable = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
editor.draw(x, y);
|
||||
}
|
||||
},
|
||||
eraser{
|
||||
{
|
||||
edit = true;
|
||||
draggable = true;
|
||||
}
|
||||
@Override
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
editor.draw(x, y);
|
||||
}
|
||||
},
|
||||
eraser{
|
||||
{
|
||||
edit = true;
|
||||
draggable = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
editor.draw(x, y, Blocks.air);
|
||||
}
|
||||
},
|
||||
elevation{
|
||||
{
|
||||
edit = true;
|
||||
draggable = true;
|
||||
}
|
||||
@Override
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
editor.draw(x, y, Blocks.air);
|
||||
}
|
||||
},
|
||||
elevation{
|
||||
{
|
||||
edit = true;
|
||||
draggable = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
editor.elevate(x, y);
|
||||
}
|
||||
},
|
||||
line{
|
||||
{
|
||||
@Override
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
editor.elevate(x, y);
|
||||
}
|
||||
},
|
||||
line{
|
||||
{
|
||||
|
||||
}
|
||||
},
|
||||
fill{
|
||||
{
|
||||
edit = true;
|
||||
}
|
||||
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
if(editor.getDrawBlock().isMultiblock()){
|
||||
//don't fill multiblocks, thanks
|
||||
pencil.touched(editor, x, y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
fill{
|
||||
{
|
||||
edit = true;
|
||||
}
|
||||
|
||||
boolean floor = editor.getDrawBlock() instanceof Floor;
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
if(editor.getDrawBlock().isMultiblock()){
|
||||
//don't fill multiblocks, thanks
|
||||
pencil.touched(editor, x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
byte bf = editor.getMap().read(x, y, DataPosition.floor);
|
||||
byte bw = editor.getMap().read(x, y, DataPosition.wall);
|
||||
boolean synth = editor.getDrawBlock().synthetic();
|
||||
byte brt = Bits.packByte((byte)editor.getDrawRotation(), (byte)editor.getDrawTeam().ordinal());
|
||||
boolean floor = editor.getDrawBlock() instanceof Floor;
|
||||
|
||||
byte dest = floor ? bf: bw;
|
||||
byte draw = (byte)editor.getDrawBlock().id;
|
||||
byte bf = editor.getMap().read(x, y, DataPosition.floor);
|
||||
byte bw = editor.getMap().read(x, y, DataPosition.wall);
|
||||
boolean synth = editor.getDrawBlock().synthetic();
|
||||
byte brt = Bits.packByte((byte) editor.getDrawRotation(), (byte) editor.getDrawTeam().ordinal());
|
||||
|
||||
int width = editor.getMap().width();
|
||||
int height = editor.getMap().height();
|
||||
byte dest = floor ? bf : bw;
|
||||
byte draw = (byte) editor.getDrawBlock().id;
|
||||
|
||||
IntSet set = new IntSet();
|
||||
IntArray points = new IntArray();
|
||||
points.add(asInt(x, y, editor.getMap().width()));
|
||||
int width = editor.getMap().width();
|
||||
int height = editor.getMap().height();
|
||||
|
||||
while(points.size != 0){
|
||||
int pos = points.pop();
|
||||
int px = pos % width;
|
||||
int py = pos / width;
|
||||
set.add(pos);
|
||||
IntSet set = new IntSet();
|
||||
IntArray points = new IntArray();
|
||||
points.add(asInt(x, y, editor.getMap().width()));
|
||||
|
||||
byte nbf = editor.getMap().read(px, py, DataPosition.floor);
|
||||
byte nbw = editor.getMap().read(px, py, DataPosition.wall);
|
||||
while(points.size != 0){
|
||||
int pos = points.pop();
|
||||
int px = pos % width;
|
||||
int py = pos / width;
|
||||
set.add(pos);
|
||||
|
||||
if((floor ? nbf : nbw) == dest){
|
||||
TileDataMarker prev = editor.getPrev(px, py, false);
|
||||
byte nbf = editor.getMap().read(px, py, DataPosition.floor);
|
||||
byte nbw = editor.getMap().read(px, py, DataPosition.wall);
|
||||
|
||||
if(floor) {
|
||||
editor.getMap().write(px, py, DataPosition.floor, draw);
|
||||
}else {
|
||||
editor.getMap().write(px, py, DataPosition.wall, draw);
|
||||
}
|
||||
if((floor ? nbf : nbw) == dest){
|
||||
TileDataMarker prev = editor.getPrev(px, py, false);
|
||||
|
||||
if(synth){
|
||||
editor.getMap().write(px, py, DataPosition.rotationTeam, brt);
|
||||
}
|
||||
if(floor){
|
||||
editor.getMap().write(px, py, DataPosition.floor, draw);
|
||||
}else{
|
||||
editor.getMap().write(px, py, DataPosition.wall, draw);
|
||||
}
|
||||
|
||||
if(px > 0 && !set.contains(asInt(px - 1, py, width))) points.add(asInt(px - 1, py, width));
|
||||
if(py > 0 && !set.contains(asInt(px, py - 1, width))) points.add(asInt(px, py - 1, width));
|
||||
if(px < width - 1 && !set.contains(asInt(px + 1, py, width))) points.add(asInt(px + 1, py, width));
|
||||
if(py < height - 1 && !set.contains(asInt(px, py + 1, width))) points.add(asInt(px, py + 1, width));
|
||||
if(synth){
|
||||
editor.getMap().write(px, py, DataPosition.rotationTeam, brt);
|
||||
}
|
||||
|
||||
editor.onWrite(px, py, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int asInt(int x, int y, int width){
|
||||
return x+y*width;
|
||||
}
|
||||
},
|
||||
zoom;
|
||||
if(px > 0 && !set.contains(asInt(px - 1, py, width))) points.add(asInt(px - 1, py, width));
|
||||
if(py > 0 && !set.contains(asInt(px, py - 1, width))) points.add(asInt(px, py - 1, width));
|
||||
if(px < width - 1 && !set.contains(asInt(px + 1, py, width))) points.add(asInt(px + 1, py, width));
|
||||
if(py < height - 1 && !set.contains(asInt(px, py + 1, width))) points.add(asInt(px, py + 1, width));
|
||||
|
||||
boolean edit, draggable;
|
||||
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
|
||||
}
|
||||
editor.onWrite(px, py, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int asInt(int x, int y, int width){
|
||||
return x + y * width;
|
||||
}
|
||||
},
|
||||
zoom;
|
||||
|
||||
boolean edit, draggable;
|
||||
|
||||
public void touched(MapEditor editor, int x, int y){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,265 +14,267 @@ import io.anuke.ucore.util.Bits;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class MapEditor{
|
||||
public static final int minMapSize = 128, maxMapSize = 512;
|
||||
public static final int[] brushSizes = {1, 2, 3, 4, 5, 9, 15};
|
||||
|
||||
private MapTileData map;
|
||||
private ObjectMap<String, String> tags = new ObjectMap<>();
|
||||
private MapRenderer renderer = new MapRenderer(this);
|
||||
public static final int minMapSize = 128, maxMapSize = 512;
|
||||
public static final int[] brushSizes = {1, 2, 3, 4, 5, 9, 15};
|
||||
|
||||
private int brushSize = 1;
|
||||
private byte elevation;
|
||||
private int rotation;
|
||||
private Block drawBlock = Blocks.stone;
|
||||
private Team drawTeam = Team.none;
|
||||
|
||||
public MapEditor(){
|
||||
private MapTileData map;
|
||||
private ObjectMap<String, String> tags = new ObjectMap<>();
|
||||
private MapRenderer renderer = new MapRenderer(this);
|
||||
|
||||
}
|
||||
|
||||
public MapTileData getMap(){
|
||||
return map;
|
||||
}
|
||||
private int brushSize = 1;
|
||||
private byte elevation;
|
||||
private int rotation;
|
||||
private Block drawBlock = Blocks.stone;
|
||||
private Team drawTeam = Team.none;
|
||||
|
||||
public ObjectMap<String, String> getTags() {
|
||||
return tags;
|
||||
}
|
||||
public MapEditor(){
|
||||
|
||||
public void beginEdit(MapTileData map, ObjectMap<String, String> tags){
|
||||
this.map = map;
|
||||
this.brushSize = 1;
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
for (int x = 0; x < map.width(); x++) {
|
||||
for (int y = 0; y < map.height(); y++) {
|
||||
map.write(x, y, DataPosition.floor, (byte)Blocks.stone.id);
|
||||
}
|
||||
}
|
||||
public MapTileData getMap(){
|
||||
return map;
|
||||
}
|
||||
|
||||
drawBlock = Blocks.stone;
|
||||
renderer.resize(map.width(), map.height());
|
||||
}
|
||||
public ObjectMap<String, String> getTags(){
|
||||
return tags;
|
||||
}
|
||||
|
||||
public void setDrawElevation(int elevation){
|
||||
this.elevation = (byte)elevation;
|
||||
}
|
||||
public void beginEdit(MapTileData map, ObjectMap<String, String> tags, boolean clear){
|
||||
this.map = map;
|
||||
this.brushSize = 1;
|
||||
this.tags = tags;
|
||||
|
||||
public byte getDrawElevation(){
|
||||
return elevation;
|
||||
}
|
||||
if(clear){
|
||||
for(int x = 0; x < map.width(); x++){
|
||||
for(int y = 0; y < map.height(); y++){
|
||||
map.write(x, y, DataPosition.floor, (byte) Blocks.stone.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getDrawRotation(){
|
||||
return rotation;
|
||||
}
|
||||
drawBlock = Blocks.stone;
|
||||
renderer.resize(map.width(), map.height());
|
||||
}
|
||||
|
||||
public void setDrawRotation(int rotation){
|
||||
this.rotation = rotation;
|
||||
}
|
||||
public byte getDrawElevation(){
|
||||
return elevation;
|
||||
}
|
||||
|
||||
public void setDrawTeam(Team team){
|
||||
this.drawTeam = team;
|
||||
}
|
||||
public void setDrawElevation(int elevation){
|
||||
this.elevation = (byte) elevation;
|
||||
}
|
||||
|
||||
public Team getDrawTeam() {
|
||||
return drawTeam;
|
||||
}
|
||||
public int getDrawRotation(){
|
||||
return rotation;
|
||||
}
|
||||
|
||||
public Block getDrawBlock(){
|
||||
return drawBlock;
|
||||
}
|
||||
|
||||
public void setDrawBlock(Block block){
|
||||
this.drawBlock = block;
|
||||
}
|
||||
|
||||
public void setBrushSize(int size){
|
||||
this.brushSize = size;
|
||||
}
|
||||
public void setDrawRotation(int rotation){
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
public int getBrushSize() {
|
||||
return brushSize;
|
||||
}
|
||||
public Team getDrawTeam(){
|
||||
return drawTeam;
|
||||
}
|
||||
|
||||
public void draw(int x, int y){
|
||||
draw(x, y, drawBlock);
|
||||
}
|
||||
public void setDrawTeam(Team team){
|
||||
this.drawTeam = team;
|
||||
}
|
||||
|
||||
public void draw(int x, int y, Block drawBlock){
|
||||
if(x < 0 || y < 0 || x >= map.width() || y >= map.height()){
|
||||
return;
|
||||
}
|
||||
public Block getDrawBlock(){
|
||||
return drawBlock;
|
||||
}
|
||||
|
||||
byte writeID = (byte)drawBlock.id;
|
||||
byte partID = (byte)Blocks.blockpart.id;
|
||||
byte rotationTeam = Bits.packByte(drawBlock.rotate ? (byte)rotation : 0, drawBlock.synthetic() ? (byte)drawTeam.ordinal() : 0);
|
||||
public void setDrawBlock(Block block){
|
||||
this.drawBlock = block;
|
||||
}
|
||||
|
||||
boolean isfloor = drawBlock instanceof Floor && drawBlock != Blocks.air;
|
||||
public int getBrushSize(){
|
||||
return brushSize;
|
||||
}
|
||||
|
||||
if(drawBlock.isMultiblock()) {
|
||||
public void setBrushSize(int size){
|
||||
this.brushSize = size;
|
||||
}
|
||||
|
||||
int offsetx = -(drawBlock.size - 1) / 2;
|
||||
int offsety = -(drawBlock.size - 1) / 2;
|
||||
public void draw(int x, int y){
|
||||
draw(x, y, drawBlock);
|
||||
}
|
||||
|
||||
for(int i = 0; i < 2; i ++){
|
||||
for (int dx = 0; dx < drawBlock.size; dx++) {
|
||||
for (int dy = 0; dy < drawBlock.size; dy++) {
|
||||
int worldx = dx + offsetx + x;
|
||||
int worldy = dy + offsety + y;
|
||||
public void draw(int x, int y, Block drawBlock){
|
||||
if(x < 0 || y < 0 || x >= map.width() || y >= map.height()){
|
||||
return;
|
||||
}
|
||||
|
||||
if (Mathf.inBounds(worldx, worldy, map.width(), map.height())) {
|
||||
TileDataMarker prev = getPrev(worldx, worldy, false);
|
||||
byte writeID = (byte) drawBlock.id;
|
||||
byte partID = (byte) Blocks.blockpart.id;
|
||||
byte rotationTeam = Bits.packByte(drawBlock.rotate ? (byte) rotation : 0, drawBlock.synthetic() ? (byte) drawTeam.ordinal() : 0);
|
||||
|
||||
if(i == 1) {
|
||||
map.write(worldx, worldy, DataPosition.wall, partID);
|
||||
map.write(worldx, worldy, DataPosition.rotationTeam, rotationTeam);
|
||||
map.write(worldx, worldy, DataPosition.link, Bits.packByte((byte) (dx + offsetx + 8), (byte) (dy + offsety + 8)));
|
||||
}else{
|
||||
byte link = map.read(worldx, worldy, DataPosition.link);
|
||||
byte block = map.read(worldx, worldy, DataPosition.wall);
|
||||
boolean isfloor = drawBlock instanceof Floor && drawBlock != Blocks.air;
|
||||
|
||||
if (link != 0) {
|
||||
removeLinked(worldx - (Bits.getLeftByte(link) - 8), worldy - (Bits.getRightByte(link) - 8));
|
||||
}else if(Block.getByID(block).isMultiblock()){
|
||||
removeLinked(worldx, worldy);
|
||||
}
|
||||
}
|
||||
if(drawBlock.isMultiblock()){
|
||||
|
||||
onWrite(worldx, worldy, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
int offsetx = -(drawBlock.size - 1) / 2;
|
||||
int offsety = -(drawBlock.size - 1) / 2;
|
||||
|
||||
TileDataMarker prev = getPrev(x, y, false);
|
||||
for(int i = 0; i < 2; i++){
|
||||
for(int dx = 0; dx < drawBlock.size; dx++){
|
||||
for(int dy = 0; dy < drawBlock.size; dy++){
|
||||
int worldx = dx + offsetx + x;
|
||||
int worldy = dy + offsety + y;
|
||||
|
||||
map.write(x, y, DataPosition.wall, writeID);
|
||||
map.write(x, y, DataPosition.link, (byte)0);
|
||||
map.write(x, y, DataPosition.rotationTeam, rotationTeam);
|
||||
if(Mathf.inBounds(worldx, worldy, map.width(), map.height())){
|
||||
TileDataMarker prev = getPrev(worldx, worldy, false);
|
||||
|
||||
onWrite(x, y, prev);
|
||||
}else{
|
||||
if(i == 1){
|
||||
map.write(worldx, worldy, DataPosition.wall, partID);
|
||||
map.write(worldx, worldy, DataPosition.rotationTeam, rotationTeam);
|
||||
map.write(worldx, worldy, DataPosition.link, Bits.packByte((byte) (dx + offsetx + 8), (byte) (dy + offsety + 8)));
|
||||
}else{
|
||||
byte link = map.read(worldx, worldy, DataPosition.link);
|
||||
byte block = map.read(worldx, worldy, DataPosition.wall);
|
||||
|
||||
for (int rx = -brushSize; rx <= brushSize; rx++) {
|
||||
for (int ry = -brushSize; ry <= brushSize; ry++) {
|
||||
if (Mathf.dst(rx, ry) <= brushSize - 0.5f) {
|
||||
int wx = x + rx, wy = y + ry;
|
||||
if(link != 0){
|
||||
removeLinked(worldx - (Bits.getLeftByte(link) - 8), worldy - (Bits.getRightByte(link) - 8));
|
||||
}else if(Block.getByID(block).isMultiblock()){
|
||||
removeLinked(worldx, worldy);
|
||||
}
|
||||
}
|
||||
|
||||
if (wx < 0 || wy < 0 || wx >= map.width() || wy >= map.height()) {
|
||||
continue;
|
||||
}
|
||||
onWrite(worldx, worldy, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TileDataMarker prev = getPrev(wx, wy, true);
|
||||
TileDataMarker prev = getPrev(x, y, false);
|
||||
|
||||
if(!isfloor) {
|
||||
byte link = map.read(wx, wy, DataPosition.link);
|
||||
map.write(x, y, DataPosition.wall, writeID);
|
||||
map.write(x, y, DataPosition.link, (byte) 0);
|
||||
map.write(x, y, DataPosition.rotationTeam, rotationTeam);
|
||||
|
||||
if (link != 0) {
|
||||
removeLinked(wx - (Bits.getLeftByte(link) - 8), wy - (Bits.getRightByte(link) - 8));
|
||||
}
|
||||
}
|
||||
onWrite(x, y, prev);
|
||||
}else{
|
||||
|
||||
if(isfloor){
|
||||
map.write(wx, wy, DataPosition.floor, writeID);
|
||||
map.write(wx, wy, DataPosition.elevation, elevation);
|
||||
}else{
|
||||
map.write(wx, wy, DataPosition.wall, writeID);
|
||||
map.write(wx, wy, DataPosition.link, (byte)0);
|
||||
map.write(wx, wy, DataPosition.rotationTeam, rotationTeam);
|
||||
}
|
||||
for(int rx = -brushSize; rx <= brushSize; rx++){
|
||||
for(int ry = -brushSize; ry <= brushSize; ry++){
|
||||
if(Mathf.dst(rx, ry) <= brushSize - 0.5f){
|
||||
int wx = x + rx, wy = y + ry;
|
||||
|
||||
onWrite(x + rx, y + ry, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(wx < 0 || wy < 0 || wx >= map.width() || wy >= map.height()){
|
||||
continue;
|
||||
}
|
||||
|
||||
public void elevate(int x, int y){
|
||||
if(x < 0 || y < 0 || x >= map.width() || y >= map.height()){
|
||||
return;
|
||||
}
|
||||
TileDataMarker prev = getPrev(wx, wy, true);
|
||||
|
||||
for (int rx = -brushSize; rx <= brushSize; rx++) {
|
||||
for (int ry = -brushSize; ry <= brushSize; ry++) {
|
||||
if (Mathf.dst(rx, ry) <= brushSize - 0.5f) {
|
||||
int wx = x + rx, wy = y + ry;
|
||||
if(!isfloor){
|
||||
byte link = map.read(wx, wy, DataPosition.link);
|
||||
|
||||
if (wx < 0 || wy < 0 || wx >= map.width() || wy >= map.height()) {
|
||||
continue;
|
||||
}
|
||||
if(link != 0){
|
||||
removeLinked(wx - (Bits.getLeftByte(link) - 8), wy - (Bits.getRightByte(link) - 8));
|
||||
}
|
||||
}
|
||||
|
||||
TileDataMarker prev = getPrev(wx, wy, true);
|
||||
if(isfloor){
|
||||
map.write(wx, wy, DataPosition.floor, writeID);
|
||||
map.write(wx, wy, DataPosition.elevation, elevation);
|
||||
}else{
|
||||
map.write(wx, wy, DataPosition.wall, writeID);
|
||||
map.write(wx, wy, DataPosition.link, (byte) 0);
|
||||
map.write(wx, wy, DataPosition.rotationTeam, rotationTeam);
|
||||
}
|
||||
|
||||
map.write(wx, wy, DataPosition.elevation, elevation);
|
||||
onWrite(x + rx, y + ry, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onWrite(x + rx, y + ry, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void elevate(int x, int y){
|
||||
if(x < 0 || y < 0 || x >= map.width() || y >= map.height()){
|
||||
return;
|
||||
}
|
||||
|
||||
private void removeLinked(int x, int y){
|
||||
Block block = Block.getByID(map.read(x, y, DataPosition.wall));
|
||||
for(int rx = -brushSize; rx <= brushSize; rx++){
|
||||
for(int ry = -brushSize; ry <= brushSize; ry++){
|
||||
if(Mathf.dst(rx, ry) <= brushSize - 0.5f){
|
||||
int wx = x + rx, wy = y + ry;
|
||||
|
||||
int offsetx = -(block.size-1)/2;
|
||||
int offsety = -(block.size-1)/2;
|
||||
for(int dx = 0; dx < block.size; dx ++){
|
||||
for(int dy = 0; dy < block.size; dy ++){
|
||||
int worldx = x + dx + offsetx, worldy = y + dy + offsety;
|
||||
if(Mathf.inBounds(worldx, worldy, map.width(), map.height())){
|
||||
TileDataMarker prev = getPrev(worldx, worldy, false);
|
||||
if(wx < 0 || wy < 0 || wx >= map.width() || wy >= map.height()){
|
||||
continue;
|
||||
}
|
||||
|
||||
map.write(worldx, worldy, DataPosition.link, (byte)0);
|
||||
map.write(worldx, worldy, DataPosition.rotationTeam, (byte)0);
|
||||
map.write(worldx, worldy, DataPosition.wall, (byte)0);
|
||||
TileDataMarker prev = getPrev(wx, wy, true);
|
||||
|
||||
onWrite(worldx, worldy, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
map.write(wx, wy, DataPosition.elevation, elevation);
|
||||
|
||||
boolean checkDupes(int x, int y){
|
||||
return Vars.ui.editor.getView().checkForDuplicates((short) x, (short) y);
|
||||
}
|
||||
onWrite(x + rx, y + ry, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void onWrite(int x, int y, TileDataMarker previous){
|
||||
if(previous == null){
|
||||
renderer.updatePoint(x, y);
|
||||
return;
|
||||
}
|
||||
private void removeLinked(int x, int y){
|
||||
Block block = Block.getByID(map.read(x, y, DataPosition.wall));
|
||||
|
||||
TileDataMarker current = map.new TileDataMarker();
|
||||
map.position(x, y);
|
||||
map.read(current);
|
||||
int offsetx = -(block.size - 1) / 2;
|
||||
int offsety = -(block.size - 1) / 2;
|
||||
for(int dx = 0; dx < block.size; dx++){
|
||||
for(int dy = 0; dy < block.size; dy++){
|
||||
int worldx = x + dx + offsetx, worldy = y + dy + offsety;
|
||||
if(Mathf.inBounds(worldx, worldy, map.width(), map.height())){
|
||||
TileDataMarker prev = getPrev(worldx, worldy, false);
|
||||
|
||||
Vars.ui.editor.getView().addTileOp(new TileOperation((short) x, (short) y, previous, current));
|
||||
renderer.updatePoint(x, y);
|
||||
}
|
||||
map.write(worldx, worldy, DataPosition.link, (byte) 0);
|
||||
map.write(worldx, worldy, DataPosition.rotationTeam, (byte) 0);
|
||||
map.write(worldx, worldy, DataPosition.wall, (byte) 0);
|
||||
|
||||
TileDataMarker getPrev(int x, int y, boolean checkDupes){
|
||||
if(checkDupes && checkDupes(x, y)){
|
||||
return null;
|
||||
}else{
|
||||
TileDataMarker marker = map.newDataMarker();
|
||||
map.position(x, y);
|
||||
map.read(marker);
|
||||
return marker;
|
||||
}
|
||||
}
|
||||
onWrite(worldx, worldy, prev);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MapRenderer renderer() {
|
||||
return renderer;
|
||||
}
|
||||
boolean checkDupes(int x, int y){
|
||||
return Vars.ui.editor.getView().checkForDuplicates((short) x, (short) y);
|
||||
}
|
||||
|
||||
public void resize(int width, int height){
|
||||
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, (byte)Blocks.stone.id);
|
||||
}
|
||||
}
|
||||
renderer.resize(width, height);
|
||||
}
|
||||
void onWrite(int x, int y, TileDataMarker previous){
|
||||
if(previous == null){
|
||||
renderer.updatePoint(x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
TileDataMarker current = map.new TileDataMarker();
|
||||
map.position(x, y);
|
||||
map.read(current);
|
||||
|
||||
Vars.ui.editor.getView().addTileOp(new TileOperation((short) x, (short) y, previous, current));
|
||||
renderer.updatePoint(x, y);
|
||||
}
|
||||
|
||||
TileDataMarker getPrev(int x, int y, boolean checkDupes){
|
||||
if(checkDupes && checkDupes(x, y)){
|
||||
return null;
|
||||
}else{
|
||||
TileDataMarker marker = map.newDataMarker();
|
||||
map.position(x, y);
|
||||
map.read(marker);
|
||||
return marker;
|
||||
}
|
||||
}
|
||||
|
||||
public MapRenderer renderer(){
|
||||
return renderer;
|
||||
}
|
||||
|
||||
public void resize(int width, int height){
|
||||
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, (byte) Blocks.stone.id);
|
||||
}
|
||||
}
|
||||
renderer.resize(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -14,68 +14,68 @@ import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class MapLoadDialog extends FloatingDialog{
|
||||
private Map selected = null;
|
||||
private Map selected = null;
|
||||
|
||||
public MapLoadDialog(Consumer<Map> loader) {
|
||||
super("$text.editor.loadmap");
|
||||
public MapLoadDialog(Consumer<Map> loader){
|
||||
super("$text.editor.loadmap");
|
||||
|
||||
shown(this::rebuild);
|
||||
rebuild();
|
||||
shown(this::rebuild);
|
||||
rebuild();
|
||||
|
||||
TextButton button = new TextButton("$text.load");
|
||||
button.setDisabled(() -> selected == null);
|
||||
button.clicked(() -> {
|
||||
if (selected != null) {
|
||||
loader.accept(selected);
|
||||
hide();
|
||||
}
|
||||
});
|
||||
TextButton button = new TextButton("$text.load");
|
||||
button.setDisabled(() -> selected == null);
|
||||
button.clicked(() -> {
|
||||
if(selected != null){
|
||||
loader.accept(selected);
|
||||
hide();
|
||||
}
|
||||
});
|
||||
|
||||
buttons().defaults().size(200f, 50f);
|
||||
buttons().addButton("$text.cancel", this::hide);
|
||||
buttons().add(button);
|
||||
}
|
||||
buttons().defaults().size(200f, 50f);
|
||||
buttons().addButton("$text.cancel", this::hide);
|
||||
buttons().add(button);
|
||||
}
|
||||
|
||||
public void rebuild(){
|
||||
content().clear();
|
||||
if(world.maps().all().size > 0){
|
||||
selected = world.maps().all().first();
|
||||
}
|
||||
public void rebuild(){
|
||||
content().clear();
|
||||
if(world.maps().all().size > 0){
|
||||
selected = world.maps().all().first();
|
||||
}
|
||||
|
||||
ButtonGroup<TextButton> group = new ButtonGroup<>();
|
||||
ButtonGroup<TextButton> group = new ButtonGroup<>();
|
||||
|
||||
int maxcol = 3;
|
||||
int maxcol = 3;
|
||||
|
||||
int i = 0;
|
||||
int i = 0;
|
||||
|
||||
Table table = new Table();
|
||||
table.defaults().size(200f, 90f).pad(4f);
|
||||
table.margin(10f);
|
||||
Table table = new Table();
|
||||
table.defaults().size(200f, 90f).pad(4f);
|
||||
table.margin(10f);
|
||||
|
||||
ScrollPane pane = new ScrollPane(table, "horizontal");
|
||||
pane.setFadeScrollBars(false);
|
||||
ScrollPane pane = new ScrollPane(table, "horizontal");
|
||||
pane.setFadeScrollBars(false);
|
||||
|
||||
for (Map map : world.maps().all()) {
|
||||
for(Map map : world.maps().all()){
|
||||
|
||||
TextButton button = new TextButton(map.getDisplayName(), "toggle");
|
||||
button.add(new BorderImage(map.texture, 2f)).size(16 * 4f);
|
||||
button.getCells().reverse();
|
||||
button.clicked(() -> selected = map);
|
||||
button.getLabelCell().grow().left().padLeft(5f);
|
||||
group.add(button);
|
||||
table.add(button);
|
||||
if (++i % maxcol == 0) table.row();
|
||||
}
|
||||
TextButton button = new TextButton(map.getDisplayName(), "toggle");
|
||||
button.add(new BorderImage(map.texture, 2f)).size(16 * 4f);
|
||||
button.getCells().reverse();
|
||||
button.clicked(() -> selected = map);
|
||||
button.getLabelCell().grow().left().padLeft(5f);
|
||||
group.add(button);
|
||||
table.add(button);
|
||||
if(++i % maxcol == 0) table.row();
|
||||
}
|
||||
|
||||
if(world.maps().all().size == 0){
|
||||
pane.setStyle(Core.skin.get("clear", ScrollPaneStyle.class));
|
||||
table.add("$text.maps.none").center();
|
||||
}else {
|
||||
content().add("$text.editor.loadmap");
|
||||
}
|
||||
if(world.maps().all().size == 0){
|
||||
pane.setStyle(Core.skin.get("clear", ScrollPaneStyle.class));
|
||||
table.add("$text.maps.none").center();
|
||||
}else{
|
||||
content().add("$text.editor.loadmap");
|
||||
}
|
||||
|
||||
content().row();
|
||||
content().add(pane);
|
||||
}
|
||||
content().row();
|
||||
content().add(pane);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,18 +34,18 @@ public class MapRenderer implements Disposable{
|
||||
|
||||
public void resize(int width, int height){
|
||||
if(chunks != null){
|
||||
for(int x = 0; x < chunks.length; x ++){
|
||||
for(int y = 0; y < chunks[0].length; y ++){
|
||||
for(int x = 0; x < chunks.length; x++){
|
||||
for(int y = 0; y < chunks[0].length; y++){
|
||||
chunks[x][y].dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
chunks = new IndexedRenderer[(int)Math.ceil((float)width/chunksize)][(int)Math.ceil((float)height/chunksize )];
|
||||
chunks = new IndexedRenderer[(int) Math.ceil((float) width / chunksize)][(int) Math.ceil((float) height / chunksize)];
|
||||
|
||||
for(int x = 0; x < chunks.length; x ++){
|
||||
for(int y = 0; y < chunks[0].length; y ++){
|
||||
chunks[x][y] = new IndexedRenderer(chunksize*chunksize*2);
|
||||
for(int x = 0; x < chunks.length; x++){
|
||||
for(int y = 0; y < chunks[0].length; y++){
|
||||
chunks[x][y] = new IndexedRenderer(chunksize * chunksize * 2);
|
||||
}
|
||||
}
|
||||
this.width = width;
|
||||
@@ -69,8 +69,8 @@ public class MapRenderer implements Disposable{
|
||||
updates.addAll(delayedUpdates);
|
||||
delayedUpdates.clear();
|
||||
|
||||
for(int x = 0; x < chunks.length; x ++){
|
||||
for(int y = 0; y < chunks[0].length; y ++){
|
||||
for(int x = 0; x < chunks.length; x++){
|
||||
for(int y = 0; y < chunks[0].length; y++){
|
||||
IndexedRenderer mesh = chunks[x][y];
|
||||
|
||||
mesh.getTransformMatrix().setToTranslation(tx, ty, 0).scl(tw / (width * tilesize),
|
||||
@@ -86,19 +86,19 @@ public class MapRenderer implements Disposable{
|
||||
|
||||
public void updatePoint(int x, int y){
|
||||
//TODO spread out over multiple frames?
|
||||
updates.add(x + y*width);
|
||||
updates.add(x + y * width);
|
||||
}
|
||||
|
||||
public void updateAll(){
|
||||
for(int x = 0; x < width; x ++){
|
||||
for(int y = 0; y < height; y ++){
|
||||
for(int x = 0; x < width; x++){
|
||||
for(int y = 0; y < height; y++){
|
||||
render(x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void render(int wx, int wy){
|
||||
int x = wx/chunksize, y = wy/chunksize;
|
||||
int x = wx / chunksize, y = wy / chunksize;
|
||||
IndexedRenderer mesh = chunks[x][y];
|
||||
//TileDataMarker data = editor.getMap().readAt(wx, wy);
|
||||
byte bf = editor.getMap().read(wx, wy, DataPosition.floor);
|
||||
@@ -111,19 +111,19 @@ public class MapRenderer implements Disposable{
|
||||
Block floor = Block.getByID(bf);
|
||||
Block wall = Block.getByID(bw);
|
||||
|
||||
int offsetx = -(wall.size-1)/2;
|
||||
int offsety = -(wall.size-1)/2;
|
||||
int offsetx = -(wall.size - 1) / 2;
|
||||
int offsety = -(wall.size - 1) / 2;
|
||||
|
||||
TextureRegion region;
|
||||
|
||||
if(bw != 0) {
|
||||
if(bw != 0){
|
||||
region = wall.getEditorIcon();
|
||||
|
||||
if (wall.rotate) {
|
||||
if(wall.rotate){
|
||||
mesh.draw((wx % chunksize) + (wy % chunksize) * chunksize, region,
|
||||
wx * tilesize + offsetx * tilesize, wy * tilesize + offsety * tilesize,
|
||||
region.getRegionWidth(), region.getRegionHeight(), rotation * 90 - 90);
|
||||
} else {
|
||||
}else{
|
||||
mesh.draw((wx % chunksize) + (wy % chunksize) * chunksize, region,
|
||||
wx * tilesize + offsetx * tilesize, wy * tilesize + offsety * tilesize,
|
||||
region.getRegionWidth(), region.getRegionHeight());
|
||||
@@ -131,16 +131,16 @@ public class MapRenderer implements Disposable{
|
||||
}else{
|
||||
region = floor.getEditorIcon();
|
||||
|
||||
mesh.draw((wx % chunksize) + (wy % chunksize)*chunksize, region, wx * tilesize, wy * tilesize, 8, 8);
|
||||
mesh.draw((wx % chunksize) + (wy % chunksize) * chunksize, region, wx * tilesize, wy * tilesize, 8, 8);
|
||||
}
|
||||
|
||||
boolean check = checkElevation(elev, wx, wy);
|
||||
|
||||
if(wall.update || wall.destructible) {
|
||||
if(wall.update || wall.destructible){
|
||||
mesh.setColor(team.color);
|
||||
region = Draw.region("block-border");
|
||||
}else if(elev > 0 && check){
|
||||
mesh.setColor(tmpColor.fromHsv((360f * elev/127f * 4f) % 360f, 0.5f + (elev / 4f) % 0.5f, 1f));
|
||||
mesh.setColor(tmpColor.fromHsv((360f * elev / 127f * 4f) % 360f, 0.5f + (elev / 4f) % 0.5f, 1f));
|
||||
region = Draw.region("block-elevation");
|
||||
}else if(elev == -1){
|
||||
region = Draw.region("block-slope");
|
||||
@@ -148,8 +148,8 @@ public class MapRenderer implements Disposable{
|
||||
region = Draw.region("clear");
|
||||
}
|
||||
|
||||
mesh.draw((wx % chunksize) + (wy % chunksize)*chunksize + chunksize*chunksize, region,
|
||||
wx * tilesize + offsetx*tilesize, wy * tilesize + offsety * tilesize,
|
||||
mesh.draw((wx % chunksize) + (wy % chunksize) * chunksize + chunksize * chunksize, region,
|
||||
wx * tilesize + offsetx * tilesize, wy * tilesize + offsety * tilesize,
|
||||
region.getRegionWidth(), region.getRegionHeight());
|
||||
mesh.setColor(Color.WHITE);
|
||||
}
|
||||
@@ -165,19 +165,19 @@ public class MapRenderer implements Disposable{
|
||||
if(value < elev){
|
||||
return true;
|
||||
}else if(value > elev){
|
||||
delayedUpdates.add(wx + wy*width);
|
||||
delayedUpdates.add(wx + wy * width);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
public void dispose(){
|
||||
if(chunks == null){
|
||||
return;
|
||||
}
|
||||
for(int x = 0; x < chunks.length; x ++){
|
||||
for(int y = 0; y < chunks[0].length; y ++){
|
||||
for(int x = 0; x < chunks.length; x++){
|
||||
for(int y = 0; y < chunks[0].length; y++){
|
||||
if(chunks[x][y] != null){
|
||||
chunks[x][y].dispose();
|
||||
}
|
||||
|
||||
@@ -9,55 +9,55 @@ import io.anuke.ucore.scene.ui.layout.Table;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class MapResizeDialog extends FloatingDialog{
|
||||
int[] validMapSizes = {200, 300, 400, 500};
|
||||
int width, height;
|
||||
|
||||
public MapResizeDialog(MapEditor editor, BiConsumer<Integer, Integer> cons){
|
||||
super("$text.editor.resizemap");
|
||||
shown(() -> {
|
||||
content().clear();
|
||||
MapTileData data = editor.getMap();
|
||||
width = data.width();
|
||||
height = data.height();
|
||||
|
||||
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 ? "$text.width": "$text.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.row();
|
||||
}
|
||||
content().row();
|
||||
content().add(table);
|
||||
|
||||
});
|
||||
|
||||
buttons().defaults().size(200f, 50f);
|
||||
buttons().addButton("$text.cancel", this::hide);
|
||||
buttons().addButton("$text.editor.resize", () -> {
|
||||
cons.accept(width, height);
|
||||
hide();
|
||||
});
|
||||
|
||||
}
|
||||
int[] validMapSizes = {200, 300, 400, 500};
|
||||
int width, height;
|
||||
|
||||
public MapResizeDialog(MapEditor editor, BiConsumer<Integer, Integer> cons){
|
||||
super("$text.editor.resizemap");
|
||||
shown(() -> {
|
||||
content().clear();
|
||||
MapTileData data = editor.getMap();
|
||||
width = data.width();
|
||||
height = data.height();
|
||||
|
||||
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 ? "$text.width" : "$text.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.row();
|
||||
}
|
||||
content().row();
|
||||
content().add(table);
|
||||
|
||||
});
|
||||
|
||||
buttons().defaults().size(200f, 50f);
|
||||
buttons().addButton("$text.cancel", this::hide);
|
||||
buttons().addButton("$text.editor.resize", () -> {
|
||||
cons.accept(width, height);
|
||||
hide();
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.anuke.mindustry.editor;
|
||||
|
||||
import io.anuke.mindustry.io.Map;
|
||||
import io.anuke.mindustry.core.Platform;
|
||||
import io.anuke.mindustry.io.Map;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.ucore.function.Consumer;
|
||||
import io.anuke.ucore.scene.ui.TextButton;
|
||||
@@ -11,65 +11,65 @@ import static io.anuke.mindustry.Vars.ui;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class MapSaveDialog extends FloatingDialog{
|
||||
private TextField field;
|
||||
private Consumer<String> listener;
|
||||
|
||||
public MapSaveDialog(Consumer<String> cons){
|
||||
super("$text.editor.savemap");
|
||||
field = new TextField();
|
||||
listener = cons;
|
||||
|
||||
Platform.instance.addDialog(field);
|
||||
|
||||
shown(() -> {
|
||||
content().clear();
|
||||
content().label(() ->{
|
||||
Map map = world.maps().getByName(field.getText());
|
||||
if(map != null){
|
||||
if(map.custom){
|
||||
return "$text.editor.overwrite";
|
||||
}else{
|
||||
return "$text.editor.failoverwrite";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}).colspan(2);
|
||||
content().row();
|
||||
content().add("$text.editor.mapname").padRight(14f);
|
||||
content().add(field).size(220f, 48f);
|
||||
});
|
||||
|
||||
buttons().defaults().size(200f, 50f).pad(2f);
|
||||
buttons().addButton("$text.cancel", this::hide);
|
||||
|
||||
TextButton button = new TextButton("$text.save");
|
||||
button.clicked(() -> {
|
||||
if(!invalid()){
|
||||
cons.accept(field.getText());
|
||||
hide();
|
||||
}
|
||||
});
|
||||
button.setDisabled(this::invalid);
|
||||
buttons().add(button);
|
||||
}
|
||||
private TextField field;
|
||||
private Consumer<String> listener;
|
||||
|
||||
public void save(){
|
||||
if(!invalid()){
|
||||
listener.accept(field.getText());
|
||||
}else{
|
||||
ui.showError("$text.editor.failoverwrite");
|
||||
}
|
||||
}
|
||||
|
||||
public void setFieldText(String text){
|
||||
field.setText(text);
|
||||
}
|
||||
|
||||
private boolean invalid(){
|
||||
if(field.getText().isEmpty()){
|
||||
return true;
|
||||
}
|
||||
Map map = world.maps().getByName(field.getText());
|
||||
return map != null && !map.custom;
|
||||
}
|
||||
public MapSaveDialog(Consumer<String> cons){
|
||||
super("$text.editor.savemap");
|
||||
field = new TextField();
|
||||
listener = cons;
|
||||
|
||||
Platform.instance.addDialog(field);
|
||||
|
||||
shown(() -> {
|
||||
content().clear();
|
||||
content().label(() -> {
|
||||
Map map = world.maps().getByName(field.getText());
|
||||
if(map != null){
|
||||
if(map.custom){
|
||||
return "$text.editor.overwrite";
|
||||
}else{
|
||||
return "$text.editor.failoverwrite";
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}).colspan(2);
|
||||
content().row();
|
||||
content().add("$text.editor.mapname").padRight(14f);
|
||||
content().add(field).size(220f, 48f);
|
||||
});
|
||||
|
||||
buttons().defaults().size(200f, 50f).pad(2f);
|
||||
buttons().addButton("$text.cancel", this::hide);
|
||||
|
||||
TextButton button = new TextButton("$text.save");
|
||||
button.clicked(() -> {
|
||||
if(!invalid()){
|
||||
cons.accept(field.getText());
|
||||
hide();
|
||||
}
|
||||
});
|
||||
button.setDisabled(this::invalid);
|
||||
buttons().add(button);
|
||||
}
|
||||
|
||||
public void save(){
|
||||
if(!invalid()){
|
||||
listener.accept(field.getText());
|
||||
}else{
|
||||
ui.showError("$text.editor.failoverwrite");
|
||||
}
|
||||
}
|
||||
|
||||
public void setFieldText(String text){
|
||||
field.setText(text);
|
||||
}
|
||||
|
||||
private boolean invalid(){
|
||||
if(field.getText().isEmpty()){
|
||||
return true;
|
||||
}
|
||||
Map map = world.maps().getByName(field.getText());
|
||||
return map != null && !map.custom;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,261 +33,261 @@ import static io.anuke.mindustry.Vars.mobile;
|
||||
import static io.anuke.mindustry.Vars.ui;
|
||||
|
||||
public class MapView extends Element implements GestureListener{
|
||||
private MapEditor editor;
|
||||
private EditorTool tool = EditorTool.pencil;
|
||||
private OperationStack stack = new OperationStack();
|
||||
private DrawOperation op;
|
||||
private Bresenham2 br = new Bresenham2();
|
||||
private boolean updated = false;
|
||||
private float offsetx, offsety;
|
||||
private float zoom = 1f;
|
||||
private boolean grid = false;
|
||||
private GridImage image = new GridImage(0, 0);
|
||||
private Vector2 vec = new Vector2();
|
||||
private Rectangle rect = new Rectangle();
|
||||
private Vector2[][] brushPolygons = new Vector2[MapEditor.brushSizes.length][0];
|
||||
private MapEditor editor;
|
||||
private EditorTool tool = EditorTool.pencil;
|
||||
private OperationStack stack = new OperationStack();
|
||||
private DrawOperation op;
|
||||
private Bresenham2 br = new Bresenham2();
|
||||
private boolean updated = false;
|
||||
private float offsetx, offsety;
|
||||
private float zoom = 1f;
|
||||
private boolean grid = false;
|
||||
private GridImage image = new GridImage(0, 0);
|
||||
private Vector2 vec = new Vector2();
|
||||
private Rectangle rect = new Rectangle();
|
||||
private Vector2[][] brushPolygons = new Vector2[MapEditor.brushSizes.length][0];
|
||||
|
||||
private boolean drawing;
|
||||
private int lastx, lasty;
|
||||
private int startx, starty;
|
||||
private float mousex, mousey;
|
||||
private EditorTool lastTool;
|
||||
private boolean drawing;
|
||||
private int lastx, lasty;
|
||||
private int startx, starty;
|
||||
private float mousex, mousey;
|
||||
private EditorTool lastTool;
|
||||
|
||||
public void setTool(EditorTool tool){
|
||||
this.tool = tool;
|
||||
}
|
||||
public MapView(MapEditor editor){
|
||||
this.editor = editor;
|
||||
|
||||
public EditorTool getTool() {
|
||||
return tool;
|
||||
}
|
||||
|
||||
public void clearStack(){
|
||||
stack.clear();
|
||||
//TODO clear und obuffer
|
||||
}
|
||||
|
||||
public OperationStack getStack() {
|
||||
return stack;
|
||||
}
|
||||
|
||||
public void setGrid(boolean grid) {
|
||||
this.grid = grid;
|
||||
}
|
||||
|
||||
public boolean isGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
public void undo(){
|
||||
if(stack.canUndo()){
|
||||
stack.undo(editor);
|
||||
}
|
||||
}
|
||||
|
||||
public void redo(){
|
||||
if(stack.canRedo()){
|
||||
stack.redo(editor);
|
||||
}
|
||||
}
|
||||
|
||||
public void addTileOp(TileOperation t){
|
||||
op.addOperation(t);
|
||||
}
|
||||
|
||||
public boolean checkForDuplicates(short x, short y){
|
||||
return op.checkDuplicate(x, y);
|
||||
}
|
||||
|
||||
public MapView(MapEditor editor){
|
||||
this.editor = editor;
|
||||
|
||||
for(int i = 0; i < MapEditor.brushSizes.length; i ++){
|
||||
for(int i = 0; i < MapEditor.brushSizes.length; i++){
|
||||
float size = MapEditor.brushSizes[i];
|
||||
brushPolygons[i] = Geometry.pixelCircle(size, (index, x, y) -> Vector2.dst(x, y, index, index) <= index - 0.5f);
|
||||
}
|
||||
|
||||
Inputs.addProcessor(0, new GestureDetector(20, 0.5f, 2, 0.15f, this));
|
||||
setTouchable(Touchable.enabled);
|
||||
|
||||
addListener(new InputListener(){
|
||||
|
||||
@Override
|
||||
public boolean mouseMoved (InputEvent event, float x, float y) {
|
||||
mousex = x;
|
||||
mousey = y;
|
||||
Inputs.addProcessor(0, new GestureDetector(20, 0.5f, 2, 0.15f, this));
|
||||
setTouchable(Touchable.enabled);
|
||||
|
||||
return false;
|
||||
addListener(new InputListener(){
|
||||
|
||||
@Override
|
||||
public boolean mouseMoved(InputEvent event, float x, float y){
|
||||
mousex = x;
|
||||
mousey = y;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
|
||||
if(pointer != 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!mobile && button != Buttons.LEFT && button != Buttons.MIDDLE){
|
||||
return true;
|
||||
}
|
||||
@Override
|
||||
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button){
|
||||
if(pointer != 0){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(button == Buttons.MIDDLE){
|
||||
lastTool = tool;
|
||||
tool = EditorTool.zoom;
|
||||
}
|
||||
if(!mobile && button != Buttons.LEFT && button != Buttons.MIDDLE){
|
||||
return true;
|
||||
}
|
||||
|
||||
mousex = x;
|
||||
mousey = y;
|
||||
if(button == Buttons.MIDDLE){
|
||||
lastTool = tool;
|
||||
tool = EditorTool.zoom;
|
||||
}
|
||||
|
||||
op = new DrawOperation(editor.getMap());
|
||||
mousex = x;
|
||||
mousey = y;
|
||||
|
||||
updated = false;
|
||||
op = new DrawOperation(editor.getMap());
|
||||
|
||||
GridPoint2 p = project(x, y);
|
||||
lastx = p.x;
|
||||
lasty = p.y;
|
||||
startx = p.x;
|
||||
starty = p.y;
|
||||
tool.touched(editor, p.x, p.y);
|
||||
|
||||
if(tool.edit){
|
||||
updated = true;
|
||||
ui.editor.resetSaved();
|
||||
}
|
||||
updated = false;
|
||||
|
||||
drawing = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
|
||||
if(!mobile && button != Buttons.LEFT && button != Buttons.MIDDLE){
|
||||
return;
|
||||
}
|
||||
GridPoint2 p = project(x, y);
|
||||
lastx = p.x;
|
||||
lasty = p.y;
|
||||
startx = p.x;
|
||||
starty = p.y;
|
||||
tool.touched(editor, p.x, p.y);
|
||||
|
||||
drawing = false;
|
||||
if(tool.edit){
|
||||
updated = true;
|
||||
ui.editor.resetSaved();
|
||||
}
|
||||
|
||||
GridPoint2 p = project(x, y);
|
||||
drawing = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(tool == EditorTool.line){
|
||||
ui.editor.resetSaved();
|
||||
Array<GridPoint2> points = br.line(startx, starty, p.x, p.y);
|
||||
for(GridPoint2 point : points){
|
||||
editor.draw(point.x, point.y);
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
@Override
|
||||
public void touchUp(InputEvent event, float x, float y, int pointer, int button){
|
||||
if(!mobile && button != Buttons.LEFT && button != Buttons.MIDDLE){
|
||||
return;
|
||||
}
|
||||
|
||||
if(op != null && updated){
|
||||
if(!op.isEmpty()){
|
||||
stack.add(op);
|
||||
}
|
||||
op = null;
|
||||
}
|
||||
drawing = false;
|
||||
|
||||
if(lastTool != null){
|
||||
tool = lastTool;
|
||||
lastTool = null;
|
||||
}
|
||||
GridPoint2 p = project(x, y);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void touchDragged (InputEvent event, float x, float y, int pointer) {
|
||||
mousex = x;
|
||||
mousey = y;
|
||||
if(tool == EditorTool.line){
|
||||
ui.editor.resetSaved();
|
||||
Array<GridPoint2> points = br.line(startx, starty, p.x, p.y);
|
||||
for(GridPoint2 point : points){
|
||||
editor.draw(point.x, point.y);
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
|
||||
GridPoint2 p = project(x, y);
|
||||
|
||||
if(drawing && tool.draggable){
|
||||
ui.editor.resetSaved();
|
||||
Array<GridPoint2> points = br.line(lastx, lasty, p.x, p.y);
|
||||
for(GridPoint2 point : points){
|
||||
tool.touched(editor, point.x, point.y);
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
lastx = p.x;
|
||||
lasty = p.y;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void act(float delta){
|
||||
super.act(delta);
|
||||
if(op != null && updated){
|
||||
if(!op.isEmpty()){
|
||||
stack.add(op);
|
||||
}
|
||||
op = null;
|
||||
}
|
||||
|
||||
if(Core.scene.getKeyboardFocus() == null || !(Core.scene.getKeyboardFocus() instanceof TextField) &&
|
||||
!Inputs.keyDown(io.anuke.ucore.input.Input.CONTROL_LEFT)) {
|
||||
float ax = Inputs.getAxis("move_x");
|
||||
float ay = Inputs.getAxis("move_y");
|
||||
offsetx -= ax * 15f / zoom;
|
||||
offsety -= ay * 15f / zoom;
|
||||
}
|
||||
if(lastTool != null){
|
||||
tool = lastTool;
|
||||
lastTool = null;
|
||||
}
|
||||
|
||||
if(ui.editor.hasPane()) return;
|
||||
|
||||
zoom += Inputs.scroll()/10f * zoom;
|
||||
clampZoom();
|
||||
}
|
||||
|
||||
private void clampZoom(){
|
||||
zoom = Mathf.clamp(zoom, 0.2f, 12f);
|
||||
}
|
||||
|
||||
private GridPoint2 project(float x, float y){
|
||||
float ratio = 1f / ((float)editor.getMap().width() / editor.getMap().height());
|
||||
float size = Math.min(width, height);
|
||||
float sclwidth = size * zoom;
|
||||
float sclheight = size * zoom * ratio;
|
||||
x = (x - getWidth()/2 + sclwidth/2 - offsetx*zoom) / sclwidth * editor.getMap().width();
|
||||
y = (y - getHeight()/2 + sclheight/2 - offsety*zoom) / sclheight * editor.getMap().height();
|
||||
}
|
||||
|
||||
if(editor.getDrawBlock().size % 2 == 0 && tool != EditorTool.eraser){
|
||||
return Tmp.g1.set((int)(x - 0.5f), (int)(y - 0.5f));
|
||||
}else{
|
||||
return Tmp.g1.set((int)x, (int)y);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void touchDragged(InputEvent event, float x, float y, int pointer){
|
||||
mousex = x;
|
||||
mousey = y;
|
||||
|
||||
private Vector2 unproject(int x, int y){
|
||||
float ratio = 1f / ((float)editor.getMap().width() / editor.getMap().height());
|
||||
float size = Math.min(width, height);
|
||||
float sclwidth = size * zoom;
|
||||
float sclheight = size * zoom * ratio;
|
||||
float px = ((float)x / editor.getMap().width()) * sclwidth + offsetx*zoom - sclwidth/2 + getWidth()/2;
|
||||
float py = ((float)(y) / editor.getMap().height()) * sclheight
|
||||
+ offsety*zoom - sclheight/2 + getHeight()/2;
|
||||
return vec.set(px, py);
|
||||
}
|
||||
GridPoint2 p = project(x, y);
|
||||
|
||||
@Override
|
||||
public void draw(Batch batch, float alpha){
|
||||
float ratio = 1f / ((float)editor.getMap().width() / editor.getMap().height());
|
||||
float size = Math.min(width, height);
|
||||
float sclwidth = size * zoom;
|
||||
float sclheight = size * zoom * ratio;
|
||||
float centerx = x + width/2 + offsetx * zoom;
|
||||
float centery = y + height/2 + offsety * zoom;
|
||||
if(drawing && tool.draggable){
|
||||
ui.editor.resetSaved();
|
||||
Array<GridPoint2> points = br.line(lastx, lasty, p.x, p.y);
|
||||
for(GridPoint2 point : points){
|
||||
tool.touched(editor, point.x, point.y);
|
||||
}
|
||||
updated = true;
|
||||
}
|
||||
lastx = p.x;
|
||||
lasty = p.y;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
image.setImageSize(editor.getMap().width(), editor.getMap().height());
|
||||
|
||||
batch.flush();
|
||||
boolean pop = ScissorStack.pushScissors(rect.set(x, y, width, height));
|
||||
public EditorTool getTool(){
|
||||
return tool;
|
||||
}
|
||||
|
||||
Draw.color(Color.LIGHT_GRAY);
|
||||
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);
|
||||
Draw.reset();
|
||||
public void setTool(EditorTool tool){
|
||||
this.tool = tool;
|
||||
}
|
||||
|
||||
if(grid){
|
||||
Draw.color(Color.GRAY);
|
||||
image.setBounds(centerx - sclwidth/2, centery - sclheight/2, sclwidth, sclheight);
|
||||
image.draw(batch, alpha);
|
||||
Draw.color();
|
||||
}
|
||||
public void clearStack(){
|
||||
stack.clear();
|
||||
//TODO clear und obuffer
|
||||
}
|
||||
|
||||
public OperationStack getStack(){
|
||||
return stack;
|
||||
}
|
||||
|
||||
public boolean isGrid(){
|
||||
return grid;
|
||||
}
|
||||
|
||||
public void setGrid(boolean grid){
|
||||
this.grid = grid;
|
||||
}
|
||||
|
||||
public void undo(){
|
||||
if(stack.canUndo()){
|
||||
stack.undo(editor);
|
||||
}
|
||||
}
|
||||
|
||||
public void redo(){
|
||||
if(stack.canRedo()){
|
||||
stack.redo(editor);
|
||||
}
|
||||
}
|
||||
|
||||
public void addTileOp(TileOperation t){
|
||||
op.addOperation(t);
|
||||
}
|
||||
|
||||
public boolean checkForDuplicates(short x, short y){
|
||||
return op.checkDuplicate(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void act(float delta){
|
||||
super.act(delta);
|
||||
|
||||
if(Core.scene.getKeyboardFocus() == null || !(Core.scene.getKeyboardFocus() instanceof TextField) &&
|
||||
!Inputs.keyDown(io.anuke.ucore.input.Input.CONTROL_LEFT)){
|
||||
float ax = Inputs.getAxis("move_x");
|
||||
float ay = Inputs.getAxis("move_y");
|
||||
offsetx -= ax * 15f / zoom;
|
||||
offsety -= ay * 15f / zoom;
|
||||
}
|
||||
|
||||
if(ui.editor.hasPane()) return;
|
||||
|
||||
zoom += Inputs.scroll() / 10f * zoom;
|
||||
clampZoom();
|
||||
}
|
||||
|
||||
private void clampZoom(){
|
||||
zoom = Mathf.clamp(zoom, 0.2f, 12f);
|
||||
}
|
||||
|
||||
private GridPoint2 project(float x, float y){
|
||||
float ratio = 1f / ((float) editor.getMap().width() / editor.getMap().height());
|
||||
float size = Math.min(width, height);
|
||||
float sclwidth = size * zoom;
|
||||
float sclheight = size * zoom * ratio;
|
||||
x = (x - getWidth() / 2 + sclwidth / 2 - offsetx * zoom) / sclwidth * editor.getMap().width();
|
||||
y = (y - getHeight() / 2 + sclheight / 2 - offsety * zoom) / sclheight * editor.getMap().height();
|
||||
|
||||
if(editor.getDrawBlock().size % 2 == 0 && tool != EditorTool.eraser){
|
||||
return Tmp.g1.set((int) (x - 0.5f), (int) (y - 0.5f));
|
||||
}else{
|
||||
return Tmp.g1.set((int) x, (int) y);
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 unproject(int x, int y){
|
||||
float ratio = 1f / ((float) editor.getMap().width() / editor.getMap().height());
|
||||
float size = Math.min(width, height);
|
||||
float sclwidth = size * zoom;
|
||||
float sclheight = size * zoom * ratio;
|
||||
float px = ((float) x / editor.getMap().width()) * sclwidth + offsetx * zoom - sclwidth / 2 + getWidth() / 2;
|
||||
float py = ((float) (y) / editor.getMap().height()) * sclheight
|
||||
+ offsety * zoom - sclheight / 2 + getHeight() / 2;
|
||||
return vec.set(px, py);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Batch batch, float alpha){
|
||||
float ratio = 1f / ((float) editor.getMap().width() / editor.getMap().height());
|
||||
float size = Math.min(width, height);
|
||||
float sclwidth = size * zoom;
|
||||
float sclheight = size * zoom * ratio;
|
||||
float centerx = x + width / 2 + offsetx * zoom;
|
||||
float centery = y + height / 2 + offsety * zoom;
|
||||
|
||||
image.setImageSize(editor.getMap().width(), editor.getMap().height());
|
||||
|
||||
batch.flush();
|
||||
boolean pop = ScissorStack.pushScissors(rect.set(x, y, width, height));
|
||||
|
||||
Draw.color(Color.LIGHT_GRAY);
|
||||
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);
|
||||
Draw.reset();
|
||||
|
||||
if(grid){
|
||||
Draw.color(Color.GRAY);
|
||||
image.setBounds(centerx - sclwidth / 2, centery - sclheight / 2, sclwidth, sclheight);
|
||||
image.draw(batch, alpha);
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for(int i = 0; i < MapEditor.brushSizes.length; i ++){
|
||||
for(int i = 0; i < MapEditor.brushSizes.length; i++){
|
||||
if(editor.getBrushSize() == MapEditor.brushSizes[i]){
|
||||
index = i;
|
||||
break;
|
||||
@@ -297,102 +297,102 @@ public class MapView extends Element implements GestureListener{
|
||||
//todo is it really math.max?
|
||||
float scaling = zoom * Math.min(width, height) / Math.max(editor.getMap().width(), editor.getMap().height());
|
||||
|
||||
Draw.color(Palette.accent);
|
||||
Lines.stroke(Unit.dp.scl(1f * zoom));
|
||||
Draw.color(Palette.accent);
|
||||
Lines.stroke(Unit.dp.scl(1f * zoom));
|
||||
|
||||
if(!editor.getDrawBlock().isMultiblock() || tool == EditorTool.eraser) {
|
||||
if (tool == EditorTool.line && drawing) {
|
||||
Vector2 v1 = unproject(startx, starty).add(x, y);
|
||||
float sx = v1.x, sy = v1.y;
|
||||
Vector2 v2 = unproject(lastx, lasty).add(x, y);
|
||||
if(!editor.getDrawBlock().isMultiblock() || tool == EditorTool.eraser){
|
||||
if(tool == EditorTool.line && drawing){
|
||||
Vector2 v1 = unproject(startx, starty).add(x, y);
|
||||
float sx = v1.x, sy = v1.y;
|
||||
Vector2 v2 = unproject(lastx, lasty).add(x, y);
|
||||
|
||||
Lines.poly(brushPolygons[index], sx, sy, scaling);
|
||||
Lines.poly(brushPolygons[index], v2.x, v2.y, scaling);
|
||||
}
|
||||
Lines.poly(brushPolygons[index], sx, sy, scaling);
|
||||
Lines.poly(brushPolygons[index], v2.x, v2.y, scaling);
|
||||
}
|
||||
|
||||
if (tool.edit && (!mobile || drawing)) {
|
||||
GridPoint2 p = project(mousex, mousey);
|
||||
Vector2 v = unproject(p.x, p.y).add(x, y);
|
||||
Lines.poly(brushPolygons[index], v.x, v.y, scaling);
|
||||
}
|
||||
}else{
|
||||
if((tool.edit || tool == EditorTool.line) && (!mobile || drawing)){
|
||||
GridPoint2 p = project(mousex, mousey);
|
||||
Vector2 v = unproject(p.x, p.y).add(x, y);
|
||||
float offset = (editor.getDrawBlock().size % 2 == 0 ? scaling/2f : 0f);
|
||||
Lines.square(
|
||||
v.x + scaling/2f + offset,
|
||||
v.y + scaling/2f + offset,
|
||||
scaling * editor.getDrawBlock().size /2f);
|
||||
}
|
||||
}
|
||||
if(tool.edit && (!mobile || drawing)){
|
||||
GridPoint2 p = project(mousex, mousey);
|
||||
Vector2 v = unproject(p.x, p.y).add(x, y);
|
||||
Lines.poly(brushPolygons[index], v.x, v.y, scaling);
|
||||
}
|
||||
}else{
|
||||
if((tool.edit || tool == EditorTool.line) && (!mobile || drawing)){
|
||||
GridPoint2 p = project(mousex, mousey);
|
||||
Vector2 v = unproject(p.x, p.y).add(x, y);
|
||||
float offset = (editor.getDrawBlock().size % 2 == 0 ? scaling / 2f : 0f);
|
||||
Lines.square(
|
||||
v.x + scaling / 2f + offset,
|
||||
v.y + scaling / 2f + offset,
|
||||
scaling * editor.getDrawBlock().size / 2f);
|
||||
}
|
||||
}
|
||||
|
||||
batch.flush();
|
||||
|
||||
if(pop) ScissorStack.popScissors();
|
||||
|
||||
Draw.color(Palette.accent);
|
||||
Lines.stroke(Unit.dp.scl(3f));
|
||||
Lines.rect(x, y, width, height);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
private boolean active(){
|
||||
return Core.scene.getKeyboardFocus() != null
|
||||
&& Core.scene.getKeyboardFocus().isDescendantOf(ui.editor)
|
||||
&& ui.editor.isShown() && tool == EditorTool.zoom &&
|
||||
Core.scene.hit(Graphics.mouse().x, Graphics.mouse().y, true) == this;
|
||||
}
|
||||
batch.flush();
|
||||
|
||||
@Override
|
||||
public boolean touchDown(float x, float y, int pointer, int button){
|
||||
return false;
|
||||
}
|
||||
if(pop) ScissorStack.popScissors();
|
||||
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count, int button){
|
||||
return false;
|
||||
}
|
||||
Draw.color(Palette.accent);
|
||||
Lines.stroke(Unit.dp.scl(3f));
|
||||
Lines.rect(x, y, width, height);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean longPress(float x, float y){
|
||||
return false;
|
||||
}
|
||||
private boolean active(){
|
||||
return Core.scene.getKeyboardFocus() != null
|
||||
&& Core.scene.getKeyboardFocus().isDescendantOf(ui.editor)
|
||||
&& ui.editor.isShown() && tool == EditorTool.zoom &&
|
||||
Core.scene.hit(Graphics.mouse().x, Graphics.mouse().y, true) == this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean fling(float velocityX, float velocityY, int button){
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean touchDown(float x, float y, int pointer, int button){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pan(float x, float y, float deltaX, float deltaY){
|
||||
if(!active()) return false;
|
||||
offsetx += deltaX / zoom;
|
||||
offsety -= deltaY / zoom;
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean tap(float x, float y, int count, int button){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean panStop(float x, float y, int pointer, int button){
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean longPress(float x, float y){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean zoom(float initialDistance, float distance){
|
||||
if(!active()) return false;
|
||||
float nzoom = distance - initialDistance;
|
||||
zoom += nzoom / 10000f / Unit.dp.scl(1f) * zoom;
|
||||
clampZoom();
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean fling(float velocityX, float velocityY, int button){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2){
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public boolean pan(float x, float y, float deltaX, float deltaY){
|
||||
if(!active()) return false;
|
||||
offsetx += deltaX / zoom;
|
||||
offsety -= deltaY / zoom;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pinchStop(){
|
||||
@Override
|
||||
public boolean panStop(float x, float y, int pointer, int button){
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@Override
|
||||
public boolean zoom(float initialDistance, float distance){
|
||||
if(!active()) return false;
|
||||
float nzoom = distance - initialDistance;
|
||||
zoom += nzoom / 10000f / Unit.dp.scl(1f) * zoom;
|
||||
clampZoom();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pinchStop(){
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,49 +3,49 @@ package io.anuke.mindustry.editor;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
public class OperationStack{
|
||||
private final static int maxSize = 10;
|
||||
private Array<DrawOperation> stack = new Array<>();
|
||||
private int index = 0;
|
||||
|
||||
public OperationStack(){
|
||||
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
stack.clear();
|
||||
index = 0;
|
||||
}
|
||||
|
||||
public void add(DrawOperation action){
|
||||
stack.truncate(stack.size + index);
|
||||
index = 0;
|
||||
stack.add(action);
|
||||
private final static int maxSize = 10;
|
||||
private Array<DrawOperation> stack = new Array<>();
|
||||
private int index = 0;
|
||||
|
||||
if(stack.size > maxSize){
|
||||
public OperationStack(){
|
||||
|
||||
}
|
||||
|
||||
public void clear(){
|
||||
stack.clear();
|
||||
index = 0;
|
||||
}
|
||||
|
||||
public void add(DrawOperation action){
|
||||
stack.truncate(stack.size + index);
|
||||
index = 0;
|
||||
stack.add(action);
|
||||
|
||||
if(stack.size > maxSize){
|
||||
stack.removeIndex(0);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean canUndo(){
|
||||
return !(stack.size - 1 + index < 0);
|
||||
}
|
||||
|
||||
public boolean canRedo(){
|
||||
return !(index > -1 || stack.size + index < 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void undo(MapEditor editor){
|
||||
if(!canUndo()) return;
|
||||
public boolean canUndo(){
|
||||
return !(stack.size - 1 + index < 0);
|
||||
}
|
||||
|
||||
stack.get(stack.size - 1 + index).undo(editor);
|
||||
index --;
|
||||
}
|
||||
public boolean canRedo(){
|
||||
return !(index > -1 || stack.size + index < 0);
|
||||
}
|
||||
|
||||
public void redo(MapEditor editor){
|
||||
if(!canRedo()) return;
|
||||
|
||||
index ++;
|
||||
stack.get(stack.size - 1 + index).redo(editor);
|
||||
|
||||
}
|
||||
public void undo(MapEditor editor){
|
||||
if(!canUndo()) return;
|
||||
|
||||
stack.get(stack.size - 1 + index).undo(editor);
|
||||
index--;
|
||||
}
|
||||
|
||||
public void redo(MapEditor editor){
|
||||
if(!canRedo()) return;
|
||||
|
||||
index++;
|
||||
stack.get(stack.size - 1 + index).redo(editor);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,84 +24,90 @@ import io.anuke.ucore.util.Translator;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
/**Utility class for damaging in an area.*/
|
||||
public class Damage {
|
||||
private static Rectangle rect = new Rectangle();
|
||||
private static Rectangle hitrect = new Rectangle();
|
||||
private static Translator tr = new Translator();
|
||||
/**
|
||||
* Utility class for damaging in an area.
|
||||
*/
|
||||
public class Damage{
|
||||
private static Rectangle rect = new Rectangle();
|
||||
private static Rectangle hitrect = new Rectangle();
|
||||
private static Translator tr = new Translator();
|
||||
|
||||
/**Creates a dynamic explosion based on specified parameters.*/
|
||||
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);
|
||||
Timers.run(i*2f + Mathf.random(4f), () -> Lightning.create(Team.none, Fx.none, Palette.power, 3,
|
||||
x, y, Mathf.random(360f), branches + Mathf.range(2)));
|
||||
}
|
||||
/**
|
||||
* Creates a dynamic explosion based on specified parameters.
|
||||
*/
|
||||
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);
|
||||
Timers.run(i * 2f + Mathf.random(4f), () -> Lightning.create(Team.none, Fx.none, Palette.power, 3,
|
||||
x, y, Mathf.random(360f), branches + Mathf.range(2)));
|
||||
}
|
||||
|
||||
for(int i = 0; i < Mathf.clamp(flammability / 4, 0, 30); i ++){
|
||||
Timers.run(i/2, () -> CallEntity.createBullet(TurretBullets.fireball, x, y, Mathf.random(360f)));
|
||||
}
|
||||
for(int i = 0; i < Mathf.clamp(flammability / 4, 0, 30); i++){
|
||||
Timers.run(i / 2, () -> CallEntity.createBullet(TurretBullets.fireball, x, y, Mathf.random(360f)));
|
||||
}
|
||||
|
||||
int waves = Mathf.clamp((int)(explosiveness / 4), 0, 30);
|
||||
int waves = Mathf.clamp((int) (explosiveness / 4), 0, 30);
|
||||
|
||||
for(int i = 0; i < waves; i ++){
|
||||
int f = i;
|
||||
Timers.run(i*2f, () -> {
|
||||
Damage.damage(x, y, Mathf.clamp(radius + explosiveness, 0, 50f) * ((f + 1f)/waves), explosiveness/2f);
|
||||
Effects.effect(ExplosionFx.blockExplosionSmoke, x + Mathf.range(radius), y + Mathf.range(radius));
|
||||
});
|
||||
}
|
||||
for(int i = 0; i < waves; i++){
|
||||
int f = i;
|
||||
Timers.run(i * 2f, () -> {
|
||||
Damage.damage(x, y, Mathf.clamp(radius + explosiveness, 0, 50f) * ((f + 1f) / waves), explosiveness / 2f);
|
||||
Effects.effect(ExplosionFx.blockExplosionSmoke, x + Mathf.range(radius), y + Mathf.range(radius));
|
||||
});
|
||||
}
|
||||
|
||||
if(explosiveness > 15f){
|
||||
Effects.effect(ExplosionFx.shockwave, x, y);
|
||||
}
|
||||
if(explosiveness > 15f){
|
||||
Effects.effect(ExplosionFx.shockwave, x, y);
|
||||
}
|
||||
|
||||
if(explosiveness > 30f){
|
||||
Effects.effect(ExplosionFx.bigShockwave, x, y);
|
||||
}
|
||||
if(explosiveness > 30f){
|
||||
Effects.effect(ExplosionFx.bigShockwave, x, y);
|
||||
}
|
||||
|
||||
float shake = Math.min(explosiveness/4f + 3f, 9f);
|
||||
Effects.shake(shake, shake, x, y);
|
||||
Effects.effect(ExplosionFx.blockExplosion, x, y);
|
||||
}
|
||||
float shake = Math.min(explosiveness / 4f + 3f, 9f);
|
||||
Effects.shake(shake, shake, x, y);
|
||||
Effects.effect(ExplosionFx.blockExplosion, x, y);
|
||||
}
|
||||
|
||||
public static void createIncend(float x, float y, float range, int amount){
|
||||
for (int i = 0; i < amount; i++) {
|
||||
float cx = x + Mathf.range(range);
|
||||
float cy = y + Mathf.range(range);
|
||||
Tile tile = world.tileWorld(cx, cy);
|
||||
if(tile != null){
|
||||
Fire.create(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void createIncend(float x, float y, float range, int amount){
|
||||
for(int i = 0; i < amount; i++){
|
||||
float cx = x + Mathf.range(range);
|
||||
float cy = y + Mathf.range(range);
|
||||
Tile tile = world.tileWorld(cx, cy);
|
||||
if(tile != null){
|
||||
Fire.create(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**Damages entities in a line.
|
||||
* Only enemies of the specified team are damaged.*/
|
||||
public static void collideLine(SolidEntity hitter, Team team, Effect effect, float x, float y, float angle, float length){
|
||||
tr.trns(angle, length);
|
||||
rect.setPosition(x, y).setSize(tr.x, tr.y);
|
||||
float x2 = tr.x + x, y2 = tr.y + y;
|
||||
/**
|
||||
* Damages entities in a line.
|
||||
* Only enemies of the specified team are damaged.
|
||||
*/
|
||||
public static void collideLine(SolidEntity hitter, Team team, Effect effect, float x, float y, float angle, float length){
|
||||
tr.trns(angle, length);
|
||||
rect.setPosition(x, y).setSize(tr.x, tr.y);
|
||||
float x2 = tr.x + x, y2 = tr.y + y;
|
||||
|
||||
if(rect.width < 0){
|
||||
rect.x += rect.width;
|
||||
rect.width *= -1;
|
||||
}
|
||||
if(rect.width < 0){
|
||||
rect.x += rect.width;
|
||||
rect.width *= -1;
|
||||
}
|
||||
|
||||
if(rect.height < 0){
|
||||
rect.y += rect.height;
|
||||
rect.height *= -1;
|
||||
}
|
||||
if(rect.height < 0){
|
||||
rect.y += rect.height;
|
||||
rect.height *= -1;
|
||||
}
|
||||
|
||||
float expand = 3f;
|
||||
float expand = 3f;
|
||||
|
||||
rect.y -= expand;
|
||||
rect.x -= expand;
|
||||
rect.width += expand*2;
|
||||
rect.height += expand*2;
|
||||
rect.y -= expand;
|
||||
rect.x -= expand;
|
||||
rect.width += expand * 2;
|
||||
rect.height += expand * 2;
|
||||
|
||||
Consumer<Unit> cons = e -> {
|
||||
e.getHitbox(hitrect);
|
||||
e.getHitbox(hitrect);
|
||||
Rectangle other = hitrect;
|
||||
other.y -= expand;
|
||||
other.x -= expand;
|
||||
@@ -110,79 +116,85 @@ public class Damage {
|
||||
|
||||
Vector2 vec = Physics.raycastRect(x, y, x2, y2, other);
|
||||
|
||||
if (vec != null) {
|
||||
if(vec != null){
|
||||
Effects.effect(effect, vec.x, vec.y);
|
||||
e.collision(hitter, vec.x, vec.y);
|
||||
hitter.collision(e, vec.x, vec.y);
|
||||
}
|
||||
};
|
||||
|
||||
Units.getNearbyEnemies(team, rect, cons);
|
||||
}
|
||||
Units.getNearbyEnemies(team, rect, cons);
|
||||
}
|
||||
|
||||
/**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 -> {
|
||||
if(!predicate.test(entity)) return;
|
||||
/**
|
||||
* 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 -> {
|
||||
if(!predicate.test(entity)) return;
|
||||
|
||||
entity.getHitbox(hitrect);
|
||||
if (!hitrect.overlaps(rect)) {
|
||||
return;
|
||||
}
|
||||
entity.damage(damage);
|
||||
acceptor.accept(entity);
|
||||
};
|
||||
entity.getHitbox(hitrect);
|
||||
if(!hitrect.overlaps(rect)){
|
||||
return;
|
||||
}
|
||||
entity.damage(damage);
|
||||
acceptor.accept(entity);
|
||||
};
|
||||
|
||||
rect.setSize(size * 2).setCenter(x, y);
|
||||
if (team != null) {
|
||||
Units.getNearbyEnemies(team, rect, cons);
|
||||
} else {
|
||||
Units.getNearby(rect, cons);
|
||||
}
|
||||
}
|
||||
rect.setSize(size * 2).setCenter(x, y);
|
||||
if(team != null){
|
||||
Units.getNearbyEnemies(team, rect, cons);
|
||||
}else{
|
||||
Units.getNearby(rect, cons);
|
||||
}
|
||||
}
|
||||
|
||||
/**Damages everything in a radius.*/
|
||||
public static void damage(float x, float y, float radius, float damage){
|
||||
damage(null, x, y, radius, damage);
|
||||
}
|
||||
/**
|
||||
* Damages everything in a radius.
|
||||
*/
|
||||
public static void damage(float x, float y, float radius, float damage){
|
||||
damage(null, x, y, radius, 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.distanceTo(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.getVelocity().add(tr.setLength((1f-dst/radius) * 2f));
|
||||
};
|
||||
/**
|
||||
* 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.distanceTo(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.getVelocity().add(tr.setLength((1f - dst / radius) * 2f));
|
||||
};
|
||||
|
||||
rect.setSize(radius *2).setCenter(x, y);
|
||||
if(team != null) {
|
||||
Units.getNearbyEnemies(team, rect, cons);
|
||||
}else{
|
||||
Units.getNearby(rect, cons);
|
||||
}
|
||||
rect.setSize(radius * 2).setCenter(x, y);
|
||||
if(team != null){
|
||||
Units.getNearbyEnemies(team, rect, cons);
|
||||
}else{
|
||||
Units.getNearby(rect, cons);
|
||||
}
|
||||
|
||||
int trad = (int)(radius / tilesize);
|
||||
for(int dx = -trad; dx <= trad; dx ++){
|
||||
for(int dy= -trad; dy <= trad; dy ++){
|
||||
Tile tile = world.tile(Mathf.scl2(x, tilesize) + dx, Mathf.scl2(y, tilesize) + dy);
|
||||
if(tile != null && tile.entity != null && (team == null || state.teams.areEnemies(team, tile.getTeam())) && Vector2.dst(dx, dy, 0, 0) <= trad){
|
||||
float amount = calculateDamage(x, y, tile.worldx(), tile.worldy(), radius, damage);
|
||||
tile.entity.damage(amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
int trad = (int) (radius / tilesize);
|
||||
for(int dx = -trad; dx <= trad; dx++){
|
||||
for(int dy = -trad; dy <= trad; dy++){
|
||||
Tile tile = world.tile(Mathf.scl2(x, tilesize) + dx, Mathf.scl2(y, tilesize) + dy);
|
||||
if(tile != null && tile.entity != null && (team == null || state.teams.areEnemies(team, tile.getTeam())) && Vector2.dst(dx, dy, 0, 0) <= trad){
|
||||
float amount = calculateDamage(x, y, tile.worldx(), tile.worldy(), radius, damage);
|
||||
tile.entity.damage(amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static float calculateDamage(float x, float y, float tx, float ty, float radius, float damage){
|
||||
float dist = Vector2.dst(x, y, tx, ty);
|
||||
float falloff = 0.4f;
|
||||
float scaled = Mathf.lerp(1f - dist/radius, 1f, falloff);
|
||||
return damage * scaled;
|
||||
}
|
||||
}
|
||||
|
||||
private static float calculateDamage(float x, float y, float tx, float ty, float radius, float damage){
|
||||
float dist = Vector2.dst(x, y, tx, ty);
|
||||
float falloff = 0.4f;
|
||||
float scaled = Mathf.lerp(1f - dist / radius, 1f, falloff);
|
||||
return damage * scaled;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,12 +4,16 @@ import com.badlogic.gdx.math.Vector2;
|
||||
import io.anuke.mindustry.entities.traits.TargetTrait;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
/**Class for predicting shoot angles based on velocities of targets.*/
|
||||
public class Predict {
|
||||
/**
|
||||
* Class for predicting shoot angles based on velocities of targets.
|
||||
*/
|
||||
public class Predict{
|
||||
private static Vector2 vec = new Vector2();
|
||||
private static Vector2 vresult = new Vector2();
|
||||
|
||||
/**Calculates of intercept of a stationary and moving target. Do not call from multiple threads!
|
||||
/**
|
||||
* Calculates of intercept of a stationary and moving target. Do not call from multiple threads!
|
||||
*
|
||||
* @param srcx X of shooter
|
||||
* @param srcy Y of shooter
|
||||
* @param dstx X of target
|
||||
@@ -17,52 +21,55 @@ public class Predict {
|
||||
* @param dstvx X velocity of target (subtract shooter X velocity if needed)
|
||||
* @param dstvy Y velocity of target (subtract shooter Y velocity if needed)
|
||||
* @param v speed of bullet
|
||||
* @return the intercept location*/
|
||||
public static Vector2 intercept(float srcx, float srcy, float dstx, float dsty, float dstvx, float dstvy, float v) {
|
||||
* @return the intercept location
|
||||
*/
|
||||
public static Vector2 intercept(float srcx, float srcy, float dstx, float dsty, float dstvx, float dstvy, float v){
|
||||
float tx = dstx - srcx,
|
||||
ty = dsty - srcy;
|
||||
|
||||
// Get quadratic equation components
|
||||
float a = dstvx * dstvx + dstvy * dstvy - v*v;
|
||||
float a = dstvx * dstvx + dstvy * dstvy - v * v;
|
||||
float b = 2 * (dstvx * tx + dstvy * ty);
|
||||
float c = tx*tx + ty*ty;
|
||||
float c = tx * tx + ty * ty;
|
||||
|
||||
// Solve quadratic
|
||||
Vector2 ts = quad(a, b, c);
|
||||
|
||||
// Find smallest positive solution
|
||||
Vector2 sol = vresult.set(0, 0);
|
||||
if (ts != null) {
|
||||
if(ts != null){
|
||||
float t0 = ts.x, t1 = ts.y;
|
||||
float t = Math.min(t0, t1);
|
||||
if (t < 0) t = Math.max(t0, t1);
|
||||
if (t > 0) {
|
||||
sol.set(dstx + dstvx*t, dsty + dstvy*t);
|
||||
if(t < 0) t = Math.max(t0, t1);
|
||||
if(t > 0){
|
||||
sol.set(dstx + dstvx * t, dsty + dstvy * t);
|
||||
}
|
||||
}
|
||||
|
||||
return sol;
|
||||
}
|
||||
|
||||
/**See {@link #intercept(float, float, float, float, float, float, float)}.*/
|
||||
public static Vector2 intercept(TargetTrait src, TargetTrait dst, float v) {
|
||||
/**
|
||||
* See {@link #intercept(float, float, float, float, float, float, float)}.
|
||||
*/
|
||||
public static Vector2 intercept(TargetTrait src, TargetTrait dst, float v){
|
||||
return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getVelocity().x - src.getVelocity().x, dst.getVelocity().x - src.getVelocity().y, v);
|
||||
}
|
||||
|
||||
private static Vector2 quad(float a, float b, float c) {
|
||||
private static Vector2 quad(float a, float b, float c){
|
||||
Vector2 sol = null;
|
||||
if (Math.abs(a) < 1e-6) {
|
||||
if (Math.abs(b) < 1e-6) {
|
||||
sol = Math.abs(c) < 1e-6 ? vec.set(0,0) : null;
|
||||
} else {
|
||||
vec.set(-c/b, -c/b);
|
||||
if(Math.abs(a) < 1e-6){
|
||||
if(Math.abs(b) < 1e-6){
|
||||
sol = Math.abs(c) < 1e-6 ? vec.set(0, 0) : null;
|
||||
}else{
|
||||
vec.set(-c / b, -c / b);
|
||||
}
|
||||
} else {
|
||||
float disc = b*b - 4*a*c;
|
||||
if (disc >= 0) {
|
||||
}else{
|
||||
float disc = b * b - 4 * a * c;
|
||||
if(disc >= 0){
|
||||
disc = Mathf.sqrt(disc);
|
||||
a = 2*a;
|
||||
sol = vec.set((-b-disc)/a, (-b+disc)/a);
|
||||
a = 2 * a;
|
||||
sol = vec.set((-b - disc) / a, (-b + disc) / a);
|
||||
}
|
||||
}
|
||||
return sol;
|
||||
|
||||
@@ -12,7 +12,9 @@ import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/**Class for controlling status effects on an entity.*/
|
||||
/**
|
||||
* Class for controlling status effects on an entity.
|
||||
*/
|
||||
public class StatusController implements Saveable{
|
||||
private static final StatusEntry globalResult = new StatusEntry();
|
||||
private static final Array<StatusEntry> removals = new ThreadArray<>();
|
||||
@@ -26,20 +28,20 @@ public class StatusController implements Saveable{
|
||||
public void handleApply(Unit unit, StatusEffect effect, float intensity){
|
||||
if(effect == StatusEffects.none) return; //don't apply empty effects
|
||||
|
||||
float newTime = effect.baseDuration*intensity;
|
||||
float newTime = effect.baseDuration * intensity;
|
||||
|
||||
if(statuses.size > 0){
|
||||
//check for opposite effects
|
||||
for(StatusEntry entry : statuses){
|
||||
//extend effect
|
||||
if(entry.effect == effect) {
|
||||
if(entry.effect == effect){
|
||||
entry.time = Math.max(entry.time, newTime);
|
||||
return;
|
||||
}else if(entry.effect.isOpposite(effect)){ //find opposite
|
||||
entry.effect.getTransition(unit, effect, entry.time, newTime, globalResult);
|
||||
entry.time = globalResult.time;
|
||||
|
||||
if (globalResult.effect != entry.effect) {
|
||||
if(globalResult.effect != entry.effect){
|
||||
entry.effect.onTransition(unit, globalResult.effect);
|
||||
entry.effect = globalResult.effect;
|
||||
}
|
||||
@@ -94,7 +96,7 @@ public class StatusController implements Saveable{
|
||||
return damageMultiplier;
|
||||
}
|
||||
|
||||
public float getArmorMultiplier() {
|
||||
public float getArmorMultiplier(){
|
||||
return armorMultiplier;
|
||||
}
|
||||
|
||||
@@ -106,24 +108,24 @@ public class StatusController implements Saveable{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSave(DataOutput stream) throws IOException {
|
||||
public void writeSave(DataOutput stream) throws IOException{
|
||||
stream.writeByte(statuses.size);
|
||||
for(StatusEntry entry : statuses){
|
||||
stream.writeByte(entry.effect.id);
|
||||
stream.writeShort((short)(entry.time * 2));
|
||||
stream.writeShort((short) (entry.time * 2));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSave(DataInput stream) throws IOException {
|
||||
for (StatusEntry effect : statuses){
|
||||
public void readSave(DataInput stream) throws IOException{
|
||||
for(StatusEntry effect : statuses){
|
||||
Pooling.free(effect);
|
||||
}
|
||||
|
||||
statuses.clear();
|
||||
|
||||
byte amount = stream.readByte();
|
||||
for (int i = 0; i < amount; i++) {
|
||||
for(int i = 0; i < amount; i++){
|
||||
byte id = stream.readByte();
|
||||
float time = stream.readShort() / 2f;
|
||||
StatusEntry entry = Pooling.obtain(StatusEntry.class);
|
||||
@@ -132,7 +134,7 @@ public class StatusController implements Saveable{
|
||||
}
|
||||
}
|
||||
|
||||
public static class StatusEntry {
|
||||
public static class StatusEntry{
|
||||
public StatusEffect effect;
|
||||
public float time;
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package io.anuke.mindustry.entities;
|
||||
|
||||
import com.badlogic.gdx.math.GridPoint2;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.ObjectSet;
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.mindustry.content.fx.Fx;
|
||||
@@ -10,11 +13,14 @@ import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.gen.CallBlocks;
|
||||
import io.anuke.mindustry.net.In;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Edges;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.Wall;
|
||||
import io.anuke.mindustry.world.blocks.modules.InventoryModule;
|
||||
import io.anuke.mindustry.world.blocks.modules.LiquidModule;
|
||||
import io.anuke.mindustry.world.blocks.modules.PowerModule;
|
||||
import io.anuke.mindustry.world.consumers.Consume;
|
||||
import io.anuke.mindustry.world.modules.ConsumeModule;
|
||||
import io.anuke.mindustry.world.modules.InventoryModule;
|
||||
import io.anuke.mindustry.world.modules.LiquidModule;
|
||||
import io.anuke.mindustry.world.modules.PowerModule;
|
||||
import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.entities.EntityGroup;
|
||||
@@ -29,153 +35,219 @@ import java.io.IOException;
|
||||
import static io.anuke.mindustry.Vars.tileGroup;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class TileEntity extends BaseEntity implements TargetTrait {
|
||||
public static final float timeToSleep = 60f*4; //4 seconds to fall asleep
|
||||
/**This value is only used for debugging.*/
|
||||
public static int sleepingEntities = 0;
|
||||
public class TileEntity extends BaseEntity implements TargetTrait{
|
||||
public static final float timeToSleep = 60f * 4; //4 seconds to fall asleep
|
||||
private static final ObjectSet<Tile> tmpTiles = new ObjectSet<>();
|
||||
/**
|
||||
* This value is only used for debugging.
|
||||
*/
|
||||
public static int sleepingEntities = 0;
|
||||
public Tile tile;
|
||||
public Timer timer;
|
||||
public float health;
|
||||
|
||||
public Tile tile;
|
||||
public Timer timer;
|
||||
public float health;
|
||||
public PowerModule power;
|
||||
public InventoryModule items;
|
||||
public LiquidModule liquids;
|
||||
public ConsumeModule cons;
|
||||
|
||||
public PowerModule power;
|
||||
public InventoryModule items;
|
||||
public LiquidModule liquids;
|
||||
/**List of (cached) tiles with entities in proximity, used for outputting to*/
|
||||
private Array<Tile> proximity = new Array<>(8);
|
||||
private boolean dead = false;
|
||||
private boolean sleeping;
|
||||
private float sleepTime;
|
||||
|
||||
private boolean dead = false;
|
||||
private boolean sleeping;
|
||||
private float sleepTime;
|
||||
|
||||
/**Sets this tile entity data to this tile, and adds it if necessary.*/
|
||||
public TileEntity init(Tile tile, boolean added){
|
||||
this.tile = tile;
|
||||
x = tile.drawx();
|
||||
y = tile.drawy();
|
||||
@Remote(called = Loc.server, in = In.blocks)
|
||||
public static void onTileDamage(Tile tile, float health){
|
||||
if(tile.entity != null){
|
||||
tile.entity.health = health;
|
||||
}
|
||||
}
|
||||
|
||||
health = tile.block().health;
|
||||
|
||||
timer = new Timer(tile.block().timers);
|
||||
|
||||
if(added){
|
||||
//if(!tile.block().autoSleep) { //TODO only autosleep when creating a fresh block!
|
||||
add();
|
||||
/*}else{
|
||||
sleeping = true;
|
||||
sleepingEntities ++;
|
||||
}*/
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
@Remote(called = Loc.server, in = In.blocks)
|
||||
public static void onTileDestroyed(Tile tile){
|
||||
if(tile.entity == null) return;
|
||||
tile.entity.onDeath();
|
||||
}
|
||||
|
||||
/**Call when nothing is happening to the entity.
|
||||
* This increments the internal sleep timer.*/
|
||||
public void sleep(){
|
||||
sleepTime += Timers.delta();
|
||||
if(!sleeping && sleepTime >= timeToSleep){
|
||||
remove();
|
||||
sleeping = true;
|
||||
sleepingEntities ++;
|
||||
}
|
||||
}
|
||||
/**Sets this tile entity data to this tile, and adds it if necessary.*/
|
||||
public TileEntity init(Tile tile, boolean added){
|
||||
this.tile = tile;
|
||||
x = tile.drawx();
|
||||
y = tile.drawy();
|
||||
|
||||
/**Call when something just happened to the entity.
|
||||
* If the entity was sleeping, this enables it. This also resets the sleep timer.*/
|
||||
public void wakeUp(){
|
||||
sleepTime = 0f;
|
||||
if(sleeping){
|
||||
add();
|
||||
sleeping = false;
|
||||
sleepingEntities --;
|
||||
}
|
||||
}
|
||||
health = tile.block().health;
|
||||
|
||||
public boolean isSleeping(){
|
||||
return sleeping;
|
||||
}
|
||||
timer = new Timer(tile.block().timers);
|
||||
|
||||
public boolean isDead() {
|
||||
return dead;
|
||||
}
|
||||
if(added){
|
||||
add();
|
||||
}
|
||||
|
||||
public void write(DataOutputStream stream) throws IOException{}
|
||||
public void read(DataInputStream stream) throws IOException{}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void onDeath(){
|
||||
if(!dead) {
|
||||
dead = true;
|
||||
Block block = tile.block();
|
||||
/**
|
||||
* Call when nothing is happening to the entity.
|
||||
* This increments the internal sleep timer.
|
||||
*/
|
||||
public void sleep(){
|
||||
sleepTime += Timers.delta();
|
||||
if(!sleeping && sleepTime >= timeToSleep){
|
||||
remove();
|
||||
sleeping = true;
|
||||
sleepingEntities++;
|
||||
}
|
||||
}
|
||||
|
||||
block.onDestroyed(tile);
|
||||
world.removeBlock(tile);
|
||||
block.afterDestroyed(tile, this);
|
||||
remove();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Call when something just happened to the entity.
|
||||
* If the entity was sleeping, this enables it. This also resets the sleep timer.
|
||||
*/
|
||||
public void wakeUp(){
|
||||
sleepTime = 0f;
|
||||
if(sleeping){
|
||||
add();
|
||||
sleeping = false;
|
||||
sleepingEntities--;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean collide(Bullet other){
|
||||
return true;
|
||||
}
|
||||
|
||||
public void collision(Bullet other){
|
||||
tile.block().handleBulletHit(this, other);
|
||||
}
|
||||
|
||||
public void damage(float damage){
|
||||
if(dead) return;
|
||||
public boolean isSleeping(){
|
||||
return sleeping;
|
||||
}
|
||||
|
||||
CallBlocks.onTileDamage(tile, health - tile.block().handleDamage(tile, damage));
|
||||
public boolean isDead(){
|
||||
return dead;
|
||||
}
|
||||
|
||||
if(health <= 0){
|
||||
CallBlocks.onTileDestroyed(tile);
|
||||
}
|
||||
}
|
||||
public void write(DataOutputStream stream) throws IOException{
|
||||
}
|
||||
|
||||
public Tile getTile(){
|
||||
return tile;
|
||||
}
|
||||
public void read(DataInputStream stream) throws IOException{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Team getTeam() {
|
||||
return tile.getTeam();
|
||||
}
|
||||
private void onDeath(){
|
||||
if(!dead){
|
||||
dead = true;
|
||||
Block block = tile.block();
|
||||
|
||||
@Override
|
||||
public Vector2 getVelocity() {
|
||||
return Vector2.Zero;
|
||||
}
|
||||
block.onDestroyed(tile);
|
||||
world.removeBlock(tile);
|
||||
block.afterDestroyed(tile, this);
|
||||
remove();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
synchronized (Tile.tileSetLock) {
|
||||
//TODO better smoke effect, this one is awful
|
||||
if (health != 0 && health < tile.block().health && !(tile.block() instanceof Wall) &&
|
||||
Mathf.chance(0.009f * Timers.delta() * (1f - health / tile.block().health))) {
|
||||
public boolean collide(Bullet other){
|
||||
return true;
|
||||
}
|
||||
|
||||
Effects.effect(Fx.smoke, x + Mathf.range(4), y + Mathf.range(4));
|
||||
}
|
||||
public void collision(Bullet other){
|
||||
tile.block().handleBulletHit(this, other);
|
||||
}
|
||||
|
||||
if (health <= 0) {
|
||||
onDeath();
|
||||
}
|
||||
public void damage(float damage){
|
||||
if(dead) return;
|
||||
|
||||
tile.block().update(tile);
|
||||
}
|
||||
}
|
||||
CallBlocks.onTileDamage(tile, health - tile.block().handleDamage(tile, damage));
|
||||
|
||||
@Override
|
||||
public EntityGroup targetGroup() {
|
||||
return tileGroup;
|
||||
}
|
||||
if(health <= 0){
|
||||
CallBlocks.onTileDestroyed(tile);
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, in = In.blocks)
|
||||
public static void onTileDamage(Tile tile, float health){
|
||||
tile.entity.health = health;
|
||||
}
|
||||
public Tile getTile(){
|
||||
return tile;
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, in = In.blocks)
|
||||
public static void onTileDestroyed(Tile tile){
|
||||
if(tile.entity == null) return;
|
||||
tile.entity.onDeath();
|
||||
}
|
||||
public boolean consumed(Class<? extends Consume> type){
|
||||
return tile.block().consumes.get(type).valid(tile.block(), this);
|
||||
}
|
||||
|
||||
public void removeFromProximity(){
|
||||
GridPoint2[] nearby = Edges.getEdges(tile.block().size);
|
||||
for(GridPoint2 point : nearby){
|
||||
Tile other = world.tile(tile.x + point.x, tile.y + point.y);
|
||||
//remove this tile from all nearby tile's proximities
|
||||
if(other != null){
|
||||
other = other.target();
|
||||
other.block().onProximityUpdate(other);
|
||||
}
|
||||
if(other != null && other.entity != null){
|
||||
other.entity.proximity.removeValue(tile, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateProximity(){
|
||||
tmpTiles.clear();
|
||||
proximity.clear();
|
||||
|
||||
GridPoint2[] nearby = Edges.getEdges(tile.block().size);
|
||||
for(GridPoint2 point : nearby){
|
||||
Tile other = world.tile(tile.x + point.x, tile.y + point.y);
|
||||
|
||||
if(other != null){
|
||||
other.block().onProximityUpdate(other);
|
||||
other = other.target();
|
||||
}
|
||||
|
||||
if(other != null && other.entity != null){
|
||||
tmpTiles.add(other);
|
||||
|
||||
//add this tile to proximity of nearby tiles
|
||||
if(!other.entity.proximity.contains(tile, true)){
|
||||
other.entity.proximity.add(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//using a set to prevent duplicates
|
||||
for(Tile tile : tmpTiles){
|
||||
proximity.add(tile);
|
||||
}
|
||||
|
||||
tile.block().onProximityUpdate(tile);
|
||||
}
|
||||
|
||||
public Array<Tile> proximity(){
|
||||
return proximity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Team getTeam(){
|
||||
return tile.getTeam();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector2 getVelocity(){
|
||||
return Vector2.Zero;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
synchronized(Tile.tileSetLock){
|
||||
//TODO better smoke effect, this one is awful
|
||||
if(health != 0 && health < tile.block().health && !(tile.block() instanceof Wall) &&
|
||||
Mathf.chance(0.009f * Timers.delta() * (1f - health / tile.block().health))){
|
||||
|
||||
Effects.effect(Fx.smoke, x + Mathf.range(4), y + Mathf.range(4));
|
||||
}
|
||||
|
||||
if(health <= 0){
|
||||
onDeath();
|
||||
}
|
||||
|
||||
tile.block().update(tile);
|
||||
if(cons != null){
|
||||
cons.update(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityGroup targetGroup(){
|
||||
return tileGroup;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,13 +31,20 @@ import java.io.IOException;
|
||||
import static io.anuke.mindustry.Vars.state;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait, CarriableTrait, InventoryTrait {
|
||||
/**total duration of hit flash effect*/
|
||||
public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait, CarriableTrait, InventoryTrait{
|
||||
/**
|
||||
* 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.*/
|
||||
/**
|
||||
* Percision divisor of velocity, used when writing. For example a value of '2' would mean the percision is 1/2 = 0.5-size chunks.
|
||||
*/
|
||||
public static final float velocityPercision = 8f;
|
||||
/**Maximum absolute value of a velocity vector component.*/
|
||||
public static final float maxAbsVelocity = 127f/velocityPercision;
|
||||
/**
|
||||
* Maximum absolute value of a velocity vector component.
|
||||
*/
|
||||
public static final float maxAbsVelocity = 127f / velocityPercision;
|
||||
public static final float elevationScale = 4f;
|
||||
|
||||
private static final Vector2 moveVector = new Vector2();
|
||||
|
||||
@@ -52,30 +59,31 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
protected Vector2 velocity = new Translator(0f, 0.0001f);
|
||||
protected float hitTime;
|
||||
protected float drownTime;
|
||||
protected float elevation;
|
||||
|
||||
@Override
|
||||
public UnitInventory getInventory() {
|
||||
public UnitInventory getInventory(){
|
||||
return inventory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getRotation() {
|
||||
public float getRotation(){
|
||||
return rotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRotation(float rotation) {
|
||||
public void setRotation(float rotation){
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCarrier(CarryTrait carrier) {
|
||||
this.carrier = carrier;
|
||||
public CarryTrait getCarrier(){
|
||||
return carrier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CarryTrait getCarrier() {
|
||||
return carrier;
|
||||
public void setCarrier(CarryTrait carrier){
|
||||
this.carrier = carrier;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,7 +92,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interpolate() {
|
||||
public void interpolate(){
|
||||
interpolator.update();
|
||||
|
||||
x = interpolator.pos.x;
|
||||
@@ -96,7 +104,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
}
|
||||
|
||||
@Override
|
||||
public Interpolator getInterpolator() {
|
||||
public Interpolator getInterpolator(){
|
||||
return interpolator;
|
||||
}
|
||||
|
||||
@@ -113,31 +121,31 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeath() {
|
||||
public void onDeath(){
|
||||
inventory.clear();
|
||||
drownTime = 0f;
|
||||
status.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector2 getVelocity() {
|
||||
public Vector2 getVelocity(){
|
||||
return velocity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSave(DataOutput stream) throws IOException {
|
||||
public void writeSave(DataOutput stream) throws IOException{
|
||||
writeSave(stream, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSave(DataInput stream) throws IOException {
|
||||
public void readSave(DataInput stream) throws IOException{
|
||||
byte team = stream.readByte();
|
||||
boolean dead = stream.readBoolean();
|
||||
float x = stream.readFloat();
|
||||
float y = stream.readFloat();
|
||||
byte xv = stream.readByte();
|
||||
byte yv = stream.readByte();
|
||||
float rotation = stream.readShort()/2f;
|
||||
float rotation = stream.readShort() / 2f;
|
||||
int health = stream.readShort();
|
||||
|
||||
this.status.readSave(stream);
|
||||
@@ -151,21 +159,21 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
public void writeSave(DataOutput stream, boolean net) throws IOException {
|
||||
public void writeSave(DataOutput stream, boolean net) throws IOException{
|
||||
stream.writeByte(team.ordinal());
|
||||
stream.writeBoolean(isDead());
|
||||
stream.writeFloat(net ? interpolator.target.x : x);
|
||||
stream.writeFloat(net ? interpolator.target.y : y);
|
||||
stream.writeByte((byte)(Mathf.clamp(velocity.x, -maxAbsVelocity, maxAbsVelocity) * velocityPercision));
|
||||
stream.writeByte((byte)(Mathf.clamp(velocity.y, -maxAbsVelocity, maxAbsVelocity) * velocityPercision));
|
||||
stream.writeShort((short)(rotation*2));
|
||||
stream.writeShort((short)health);
|
||||
stream.writeByte((byte) (Mathf.clamp(velocity.x, -maxAbsVelocity, maxAbsVelocity) * velocityPercision));
|
||||
stream.writeByte((byte) (Mathf.clamp(velocity.y, -maxAbsVelocity, maxAbsVelocity) * velocityPercision));
|
||||
stream.writeShort((short) (rotation * 2));
|
||||
stream.writeShort((short) health);
|
||||
status.writeSave(stream);
|
||||
inventory.writeSave(stream);
|
||||
}
|
||||
|
||||
public float calculateDamage(float amount){
|
||||
return amount * Mathf.clamp(1f-getArmor()/100f*status.getArmorMultiplier());
|
||||
return amount * Mathf.clamp(1f - getArmor() / 100f * status.getArmorMultiplier());
|
||||
}
|
||||
|
||||
public float getDamageMultipler(){
|
||||
@@ -180,7 +188,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
if(state.teams.has(team)){
|
||||
TeamData data = state.teams.get(team);
|
||||
|
||||
Tile tile = Geometry.findClosest(x, y, data.cores);
|
||||
Tile tile = Geometry.findClosest(x, y, data.cores);
|
||||
if(tile == null){
|
||||
return null;
|
||||
}else{
|
||||
@@ -198,15 +206,18 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
|
||||
public void avoidOthers(float avoidRange){
|
||||
|
||||
EntityPhysics.getNearby(getGroup(), x, y, avoidRange*2f, t -> {
|
||||
if(t == this || (t instanceof Unit && (((Unit) t).isDead() || (((Unit) t).isFlying() != isFlying()) || ((Unit) t).getCarrier() == this) || getCarrier() == t)) return;
|
||||
EntityPhysics.getNearby(getGroup(), x, y, avoidRange * 2f, t -> {
|
||||
if(t == this || (t instanceof Unit && (((Unit) t).isDead() || (((Unit) t).isFlying() != isFlying()) || ((Unit) t).getCarrier() == this) || getCarrier() == t))
|
||||
return;
|
||||
float dst = distanceTo(t);
|
||||
if(dst > avoidRange) return;
|
||||
velocity.add(moveVector.set(x, y).sub(t.getX(), t.getY()).setLength(1f * (1f - (dst / avoidRange))));
|
||||
});
|
||||
}
|
||||
|
||||
/**Updates velocity and status effects.*/
|
||||
/**
|
||||
* Updates velocity and status effects.
|
||||
*/
|
||||
public void updateVelocityStatus(float drag, float maxVelocity){
|
||||
if(isCarried()){ //carried units do not take into account velocity normally
|
||||
set(carrier.getX(), carrier.getY());
|
||||
@@ -221,9 +232,13 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
|
||||
velocity.limit(maxVelocity).scl(status.getSpeedMultiplier());
|
||||
|
||||
if(isFlying()) {
|
||||
if(isFlying()){
|
||||
x += velocity.x / getMass() * Timers.delta();
|
||||
y += velocity.y / getMass() * Timers.delta();
|
||||
|
||||
if(tile != null){
|
||||
elevation = Mathf.lerpDelta(elevation, tile.elevation, 0.04f);
|
||||
}
|
||||
}else{
|
||||
boolean onLiquid = floor.isLiquid;
|
||||
|
||||
@@ -239,7 +254,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
}
|
||||
}
|
||||
|
||||
if(onLiquid && velocity.len() > 0.4f && Timers.get(this, "flooreffect", 14 - (velocity.len() * floor.speedMultiplier)*2f)){
|
||||
if(onLiquid && velocity.len() > 0.4f && Timers.get(this, "flooreffect", 14 - (velocity.len() * floor.speedMultiplier) * 2f)){
|
||||
Effects.effect(floor.walkEffect, floor.liquidColor, x, y);
|
||||
}
|
||||
|
||||
@@ -250,7 +265,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
}
|
||||
|
||||
if(onLiquid && floor.drownTime > 0){
|
||||
drownTime += Timers.delta() * 1f/floor.drownTime;
|
||||
drownTime += Timers.delta() * 1f / floor.drownTime;
|
||||
if(Timers.get(this, "drowneffect", 15)){
|
||||
Effects.effect(floor.drownUpdateEffect, floor.liquidColor, x, y);
|
||||
}
|
||||
@@ -270,7 +285,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
if(Math.abs(py - y) <= 0.0001f) velocity.y = 0f;
|
||||
}
|
||||
|
||||
velocity.scl(Mathf.clamp(1f-drag* floor.dragMultiplier* Timers.delta()));
|
||||
velocity.scl(Mathf.clamp(1f - drag * floor.dragMultiplier * Timers.delta()));
|
||||
}
|
||||
|
||||
public void applyEffect(StatusEffect effect, float intensity){
|
||||
@@ -293,11 +308,17 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
}
|
||||
|
||||
public float getAmmoFraction(){
|
||||
return inventory.totalAmmo() / (float)inventory.ammoCapacity();
|
||||
return inventory.totalAmmo() / (float) inventory.ammoCapacity();
|
||||
}
|
||||
|
||||
public void drawUnder(){}
|
||||
public void drawOver(){}
|
||||
public void drawUnder(){
|
||||
}
|
||||
|
||||
public void drawOver(){
|
||||
}
|
||||
|
||||
public void drawShadow(){
|
||||
}
|
||||
|
||||
public void drawView(){
|
||||
Fill.circle(x, y, getViewDistance());
|
||||
@@ -312,12 +333,20 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
}
|
||||
|
||||
public abstract TextureRegion getIconRegion();
|
||||
|
||||
public abstract int getItemCapacity();
|
||||
|
||||
public abstract int getAmmoCapacity();
|
||||
|
||||
public abstract float getArmor();
|
||||
|
||||
public abstract boolean acceptsAmmo(Item item);
|
||||
|
||||
public abstract void addAmmo(Item item);
|
||||
|
||||
public abstract float getMass();
|
||||
|
||||
public abstract boolean isFlying();
|
||||
|
||||
public abstract float getSize();
|
||||
}
|
||||
|
||||
@@ -8,16 +8,17 @@ import io.anuke.mindustry.type.AmmoType;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
public class UnitInventory implements Saveable{
|
||||
private final Unit unit;
|
||||
private Array<AmmoEntry> ammos = new Array<>();
|
||||
private int totalAmmo;
|
||||
private ItemStack item = new ItemStack(Items.stone, 0);
|
||||
|
||||
private final Unit unit;
|
||||
|
||||
public UnitInventory(Unit unit) {
|
||||
public UnitInventory(Unit unit){
|
||||
this.unit = unit;
|
||||
}
|
||||
|
||||
@@ -26,24 +27,24 @@ public class UnitInventory implements Saveable{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSave(DataOutput stream) throws IOException {
|
||||
public void writeSave(DataOutput stream) throws IOException{
|
||||
stream.writeShort(item.amount);
|
||||
stream.writeByte(item.item.id);
|
||||
stream.writeShort(totalAmmo);
|
||||
stream.writeByte(ammos.size);
|
||||
for(int i = 0; i < ammos.size; i ++){
|
||||
for(int i = 0; i < ammos.size; i++){
|
||||
stream.writeByte(ammos.get(i).type.id);
|
||||
stream.writeShort(ammos.get(i).amount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSave(DataInput stream) throws IOException {
|
||||
public void readSave(DataInput stream) throws IOException{
|
||||
short iamount = stream.readShort();
|
||||
byte iid = stream.readByte();
|
||||
this.totalAmmo = stream.readShort();
|
||||
byte ammoa = stream.readByte();
|
||||
for(int i = 0; i < ammoa; i ++){
|
||||
for(int i = 0; i < ammoa; i++){
|
||||
byte aid = stream.readByte();
|
||||
int am = stream.readShort();
|
||||
ammos.add(new AmmoEntry(AmmoType.getByID(aid), am));
|
||||
@@ -53,12 +54,14 @@ public class UnitInventory implements Saveable{
|
||||
item.amount = iamount;
|
||||
}
|
||||
|
||||
/**Returns ammo range, or MAX_VALUE if this inventory has no ammo.*/
|
||||
/**
|
||||
* Returns ammo range, or MAX_VALUE if this inventory has no ammo.
|
||||
*/
|
||||
public float getAmmoRange(){
|
||||
return hasAmmo() ? getAmmo().getRange() : Float.MAX_VALUE;
|
||||
}
|
||||
|
||||
public AmmoType getAmmo() {
|
||||
public AmmoType getAmmo(){
|
||||
return ammos.size == 0 ? null : ammos.peek().type;
|
||||
}
|
||||
|
||||
@@ -69,9 +72,9 @@ public class UnitInventory implements Saveable{
|
||||
public void useAmmo(){
|
||||
if(unit.isInfiniteAmmo()) return;
|
||||
AmmoEntry entry = ammos.peek();
|
||||
entry.amount --;
|
||||
entry.amount--;
|
||||
if(entry.amount == 0) ammos.pop();
|
||||
totalAmmo --;
|
||||
totalAmmo--;
|
||||
}
|
||||
|
||||
public int totalAmmo(){
|
||||
@@ -87,22 +90,23 @@ public class UnitInventory implements Saveable{
|
||||
}
|
||||
|
||||
public void addAmmo(AmmoType type){
|
||||
if(type == null) return;
|
||||
totalAmmo += type.quantityMultiplier;
|
||||
|
||||
//find ammo entry by type
|
||||
for(int i = ammos.size - 1; i >= 0; i --){
|
||||
for(int i = ammos.size - 1; i >= 0; i--){
|
||||
AmmoEntry entry = ammos.get(i);
|
||||
|
||||
//if found, put it to the right
|
||||
if(entry.type == type){
|
||||
entry.amount += type.quantityMultiplier;
|
||||
ammos.swap(i, ammos.size-1);
|
||||
ammos.swap(i, ammos.size - 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//must not be found
|
||||
AmmoEntry entry = new AmmoEntry(type, (int)type.quantityMultiplier);
|
||||
AmmoEntry entry = new AmmoEntry(type, (int) type.quantityMultiplier);
|
||||
ammos.add(entry);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,12 +15,19 @@ import io.anuke.ucore.function.Predicate;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
/**Utility class for unit and team interactions.*/
|
||||
public class Units {
|
||||
/**
|
||||
* Utility class for unit and team interactions.
|
||||
*/
|
||||
public class Units{
|
||||
private static Rectangle rect = new Rectangle();
|
||||
private static Rectangle hitrect = new Rectangle();
|
||||
private static Unit result;
|
||||
private static float cdist;
|
||||
private static boolean boolResult;
|
||||
|
||||
/**Validates a target.
|
||||
/**
|
||||
* Validates a target.
|
||||
*
|
||||
* @param target The target to validate
|
||||
* @param team The team of the thing doing tha targeting
|
||||
* @param x The X position of the thing doign the targeting
|
||||
@@ -28,44 +35,52 @@ public class Units {
|
||||
* @param range The maximum distance from the target X/Y the targeter can be for it to be valid
|
||||
* @return whether the target is invalid
|
||||
*/
|
||||
public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y, float range) {
|
||||
public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y, float range){
|
||||
return target == null || (range != Float.MAX_VALUE && target.distanceTo(x, y) > range) || target.getTeam() == team || !target.isValid();
|
||||
|
||||
}
|
||||
|
||||
/**See {@link #invalidateTarget(TargetTrait, Team, float, float, float)}*/
|
||||
/**
|
||||
* See {@link #invalidateTarget(TargetTrait, Team, float, float, float)}
|
||||
*/
|
||||
public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y){
|
||||
return invalidateTarget(target, team, x, y, Float.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**See {@link #invalidateTarget(TargetTrait, Team, float, float, float)}*/
|
||||
/**
|
||||
* 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.inventory.getAmmoRange());
|
||||
}
|
||||
|
||||
/**Returns whether there are any entities on this tile.*/
|
||||
/**
|
||||
* Returns whether there are any entities on this tile.
|
||||
*/
|
||||
public static boolean anyEntities(Tile tile){
|
||||
Block type = tile.block();
|
||||
rect.setSize(type.size * tilesize, type.size * tilesize);
|
||||
rect.setCenter(tile.drawx(), tile.drawy());
|
||||
|
||||
boolean[] value = new boolean[1];
|
||||
boolResult = false;
|
||||
|
||||
Units.getNearby(rect, unit -> {
|
||||
if (value[0]) return;
|
||||
if (!unit.isFlying()) {
|
||||
if(boolResult) return;
|
||||
if(!unit.isFlying()){
|
||||
unit.getHitbox(hitrect);
|
||||
|
||||
if (hitrect.overlaps(rect)) {
|
||||
value[0] = true;
|
||||
if(hitrect.overlaps(rect)){
|
||||
boolResult = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return value[0];
|
||||
return boolResult;
|
||||
}
|
||||
|
||||
/**Returns whether there are any entities on this tile, with the hitbox expanded.*/
|
||||
/**
|
||||
* Returns whether there are any entities on this tile, with the hitbox expanded.
|
||||
*/
|
||||
public static boolean anyEntities(Tile tile, float expansion, Predicate<Unit> pred){
|
||||
Block type = tile.block();
|
||||
rect.setSize(type.size * tilesize + expansion, type.size * tilesize + expansion);
|
||||
@@ -78,7 +93,7 @@ public class Units {
|
||||
if(!unit.isFlying()){
|
||||
unit.getHitbox(hitrect);
|
||||
|
||||
if(hitrect.overlaps(rect)) {
|
||||
if(hitrect.overlaps(rect)){
|
||||
value[0] = true;
|
||||
}
|
||||
}
|
||||
@@ -87,7 +102,9 @@ public class Units {
|
||||
return value[0];
|
||||
}
|
||||
|
||||
/**Returns the neareset ally tile in a range.*/
|
||||
/**
|
||||
* Returns the neareset ally tile in a range.
|
||||
*/
|
||||
public static TileEntity findAllyTile(Team team, float x, float y, float range, Predicate<Tile> pred){
|
||||
for(Team enemy : state.teams.alliesOf(team)){
|
||||
TileEntity entity = world.indexer().findTile(enemy, x, y, range, pred);
|
||||
@@ -98,7 +115,9 @@ public class Units {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**Returns the neareset enemy tile in a range.*/
|
||||
/**
|
||||
* Returns the neareset enemy tile in a range.
|
||||
*/
|
||||
public static TileEntity findEnemyTile(Team team, float x, float y, float range, Predicate<Tile> pred){
|
||||
for(Team enemy : state.teams.enemiesOf(team)){
|
||||
TileEntity entity = world.indexer().findTile(enemy, x, y, range, pred);
|
||||
@@ -109,7 +128,9 @@ public class Units {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**Iterates over all units on all teams, including players.*/
|
||||
/**
|
||||
* Iterates over all units on all teams, including players.
|
||||
*/
|
||||
public static void allUnits(Consumer<Unit> cons){
|
||||
//check all unit groups first
|
||||
for(EntityGroup<BaseUnit> group : unitGroups){
|
||||
@@ -126,7 +147,9 @@ public class Units {
|
||||
}
|
||||
}
|
||||
|
||||
/**Returns the closest target enemy. First, units are checked, then tile entities.*/
|
||||
/**
|
||||
* Returns the closest target enemy. First, units are checked, then tile entities.
|
||||
*/
|
||||
public static TargetTrait getClosestTarget(Team team, float x, float y, float range){
|
||||
Unit unit = getClosestEnemy(team, x, y, range, u -> true);
|
||||
if(unit != null){
|
||||
@@ -136,74 +159,82 @@ public class Units {
|
||||
}
|
||||
}
|
||||
|
||||
/**Returns the closest enemy of this team. Filter by predicate.*/
|
||||
/**
|
||||
* 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){
|
||||
Unit[] result = {null};
|
||||
float[] cdist = {0};
|
||||
result = null;
|
||||
cdist = 0f;
|
||||
|
||||
rect.setSize(range*2f).setCenter(x, y);
|
||||
rect.setSize(range * 2f).setCenter(x, y);
|
||||
|
||||
getNearbyEnemies(team, rect, e -> {
|
||||
if (e.isDead() || !predicate.test(e))
|
||||
if(e.isDead() || !predicate.test(e))
|
||||
return;
|
||||
|
||||
float dist = Vector2.dst(e.x, e.y, x, y);
|
||||
if (dist < range) {
|
||||
if (result[0] == null || dist < cdist[0]) {
|
||||
result[0] = e;
|
||||
cdist[0] = dist;
|
||||
if(dist < range){
|
||||
if(result == null || dist < cdist){
|
||||
result = e;
|
||||
cdist = dist;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return result[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
/**Returns the closest ally of this team. Filter by predicate.*/
|
||||
/**
|
||||
* Returns the closest ally of this team. Filter by predicate.
|
||||
*/
|
||||
public static Unit getClosest(Team team, float x, float y, float range, Predicate<Unit> predicate){
|
||||
Unit[] result = {null};
|
||||
float[] cdist = {0};
|
||||
result = null;
|
||||
cdist = 0f;
|
||||
|
||||
rect.setSize(range*2f).setCenter(x, y);
|
||||
rect.setSize(range * 2f).setCenter(x, y);
|
||||
|
||||
getNearby(team, rect, e -> {
|
||||
if (!predicate.test(e))
|
||||
if(!predicate.test(e))
|
||||
return;
|
||||
|
||||
float dist = Vector2.dst(e.x, e.y, x, y);
|
||||
if (dist < range) {
|
||||
if (result[0] == null || dist < cdist[0]) {
|
||||
result[0] = e;
|
||||
cdist[0] = dist;
|
||||
if(dist < range){
|
||||
if(result == null || dist < cdist){
|
||||
result = e;
|
||||
cdist = dist;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return result[0];
|
||||
return result;
|
||||
}
|
||||
|
||||
/**Iterates over all units in a rectangle.*/
|
||||
/**
|
||||
* Iterates over all units in a rectangle.
|
||||
*/
|
||||
public static void getNearby(Team team, Rectangle rect, Consumer<Unit> cons){
|
||||
|
||||
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
|
||||
if(!group.isEmpty()){
|
||||
EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit)entity));
|
||||
EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit) entity));
|
||||
}
|
||||
|
||||
//now check all players
|
||||
EntityPhysics.getNearby(playerGroup, rect, player -> {
|
||||
if(((Unit)player).team == team) cons.accept((Unit)player);
|
||||
if(((Unit) player).team == team) cons.accept((Unit) player);
|
||||
});
|
||||
}
|
||||
|
||||
/**Iterates over all units in a circle around this position.*/
|
||||
/**
|
||||
* Iterates over all units in a circle around this position.
|
||||
*/
|
||||
public static void getNearby(Team team, float x, float y, float radius, Consumer<Unit> cons){
|
||||
rect.setSize(radius * 2).setCenter(x, y);
|
||||
|
||||
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
|
||||
if(!group.isEmpty()){
|
||||
EntityPhysics.getNearby(group, rect, entity -> {
|
||||
if(entity.distanceTo(x, y) <= radius) {
|
||||
if(entity.distanceTo(x, y) <= radius){
|
||||
cons.accept((Unit) entity);
|
||||
}
|
||||
});
|
||||
@@ -211,46 +242,52 @@ public class Units {
|
||||
|
||||
//now check all players
|
||||
EntityPhysics.getNearby(playerGroup, rect, player -> {
|
||||
if(((Unit)player).team == team && player.distanceTo(x, y) <= radius){
|
||||
cons.accept((Unit)player);
|
||||
if(((Unit) player).team == team && player.distanceTo(x, y) <= radius){
|
||||
cons.accept((Unit) player);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**Iterates over all units in a rectangle.*/
|
||||
/**
|
||||
* Iterates over all units in a rectangle.
|
||||
*/
|
||||
public static void getNearby(Rectangle rect, Consumer<Unit> cons){
|
||||
|
||||
for(Team team : Team.all){
|
||||
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
|
||||
if(!group.isEmpty()){
|
||||
EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit)entity));
|
||||
EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit) entity));
|
||||
}
|
||||
}
|
||||
|
||||
//now check all enemy players
|
||||
EntityPhysics.getNearby(playerGroup, rect, player -> cons.accept((Unit)player));
|
||||
EntityPhysics.getNearby(playerGroup, rect, player -> cons.accept((Unit) player));
|
||||
}
|
||||
|
||||
/**Iterates over all units that are enemies of this team.*/
|
||||
/**
|
||||
* Iterates over all units that are enemies of this team.
|
||||
*/
|
||||
public static void getNearbyEnemies(Team team, Rectangle rect, Consumer<Unit> cons){
|
||||
ObjectSet<Team> targets = state.teams.enemiesOf(team);
|
||||
|
||||
for(Team other : targets){
|
||||
EntityGroup<BaseUnit> group = unitGroups[other.ordinal()];
|
||||
if(!group.isEmpty()){
|
||||
EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit)entity));
|
||||
EntityPhysics.getNearby(group, rect, entity -> cons.accept((Unit) entity));
|
||||
}
|
||||
}
|
||||
|
||||
//now check all enemy players
|
||||
EntityPhysics.getNearby(playerGroup, rect, player -> {
|
||||
if(targets.contains(((Player)player).team)){
|
||||
cons.accept((Unit)player);
|
||||
if(targets.contains(((Player) player).team)){
|
||||
cons.accept((Unit) player);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**Iterates over all units.*/
|
||||
/**
|
||||
* Iterates over all units.
|
||||
*/
|
||||
public static void getAllUnits(Consumer<Unit> cons){
|
||||
|
||||
for(Team team : Team.all){
|
||||
|
||||
@@ -6,10 +6,10 @@ import io.anuke.ucore.core.Effects.Effect;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
|
||||
//TODO scale velocity depending on fslope()
|
||||
public class ArtilleryBulletType extends BasicBulletType {
|
||||
public class ArtilleryBulletType extends BasicBulletType{
|
||||
protected Effect trailEffect = BulletFx.artilleryTrail;
|
||||
|
||||
public ArtilleryBulletType(float speed, float damage, String bulletSprite) {
|
||||
public ArtilleryBulletType(float speed, float damage, String bulletSprite){
|
||||
super(speed, damage, bulletSprite);
|
||||
collidesTiles = false;
|
||||
collides = false;
|
||||
@@ -17,18 +17,18 @@ public class ArtilleryBulletType extends BasicBulletType {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Bullet b) {
|
||||
public void update(Bullet b){
|
||||
super.update(b);
|
||||
|
||||
if(b.timer.get(0, 3 + b.fslope()*2f)){
|
||||
if(b.timer.get(0, 3 + b.fslope() * 2f)){
|
||||
Effects.effect(trailEffect, backColor, b.x, b.y, b.fslope() * 4f);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Bullet b) {
|
||||
public void draw(Bullet b){
|
||||
float baseScale = 0.7f;
|
||||
float scale = (baseScale + b.fslope()*(1f-baseScale));
|
||||
float scale = (baseScale + b.fslope() * (1f - baseScale));
|
||||
|
||||
float height = bulletHeight * ((1f - bulletShrink) + bulletShrink * b.fout());
|
||||
|
||||
|
||||
@@ -12,8 +12,10 @@ import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
/**A BulletType for most ammo-based bullets shot from turrets and units.*/
|
||||
public class BasicBulletType extends BulletType {
|
||||
/**
|
||||
* A 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 float bulletWidth = 5f, bulletHeight = 7f;
|
||||
public float bulletShrink = 0.5f;
|
||||
@@ -23,7 +25,9 @@ public class BasicBulletType extends BulletType {
|
||||
public float fragVelocityMin = 0.2f, fragVelocityMax = 1f;
|
||||
public BulletType fragBullet = null;
|
||||
|
||||
/**Use a negative value to disable splash damage.*/
|
||||
/**
|
||||
* Use a negative value to disable splash damage.
|
||||
*/
|
||||
public float splashDamageRadius = -1f;
|
||||
public float splashDamage = 6f;
|
||||
|
||||
@@ -39,19 +43,19 @@ public class BasicBulletType extends BulletType {
|
||||
|
||||
public float hitShake = 0f;
|
||||
|
||||
public BasicBulletType(float speed, float damage, String bulletSprite) {
|
||||
public BasicBulletType(float speed, float damage, String bulletSprite){
|
||||
super(speed, damage);
|
||||
this.bulletSprite = bulletSprite;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
public void load(){
|
||||
backRegion = Draw.region(bulletSprite + "-back");
|
||||
frontRegion = Draw.region(bulletSprite);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Bullet b) {
|
||||
public void draw(Bullet b){
|
||||
float height = bulletHeight * ((1f - bulletShrink) + bulletShrink * b.fout());
|
||||
|
||||
Draw.color(backColor);
|
||||
@@ -62,7 +66,7 @@ public class BasicBulletType extends BulletType {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Bullet b) {
|
||||
public void update(Bullet b){
|
||||
super.update(b);
|
||||
|
||||
if(homingPower > 0.0001f){
|
||||
@@ -74,20 +78,20 @@ public class BasicBulletType extends BulletType {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hit(Bullet b, float x, float y) {
|
||||
public void hit(Bullet b, float x, float y){
|
||||
super.hit(b, x, y);
|
||||
|
||||
Effects.shake(hitShake, hitShake, b);
|
||||
|
||||
if(fragBullet != null) {
|
||||
for (int i = 0; i < fragBullets; i++) {
|
||||
if(fragBullet != null){
|
||||
for(int i = 0; i < fragBullets; i++){
|
||||
float len = Mathf.random(1f, 7f);
|
||||
float a = Mathf.random(360f);
|
||||
Bullet.create(fragBullet, b, x + Angles.trnsx(a, len), y + Angles.trnsy(a, len), a, Mathf.random(fragVelocityMin, fragVelocityMax));
|
||||
}
|
||||
}
|
||||
|
||||
if(Mathf.chance(incendChance)) {
|
||||
if(Mathf.chance(incendChance)){
|
||||
Damage.createIncend(x, y, incendSpread, incendAmount);
|
||||
}
|
||||
|
||||
@@ -97,7 +101,7 @@ public class BasicBulletType extends BulletType {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void despawned(Bullet b) {
|
||||
public void despawned(Bullet b){
|
||||
if(fragBullet != null || splashDamageRadius > 0){
|
||||
hit(b);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package io.anuke.mindustry.entities.bullet;
|
||||
|
||||
public class BombBulletType extends BasicBulletType {
|
||||
public class BombBulletType extends BasicBulletType{
|
||||
|
||||
public BombBulletType(float damage, float radius, String sprite) {
|
||||
public BombBulletType(float damage, float radius, String sprite){
|
||||
super(0.7f, 0, sprite);
|
||||
splashDamageRadius = radius;
|
||||
splashDamage = damage;
|
||||
|
||||
@@ -27,198 +27,199 @@ import static io.anuke.mindustry.Vars.bulletGroup;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class Bullet extends BulletEntity<BulletType> implements TeamTrait, SyncTrait{
|
||||
private static Vector2 vector = new Vector2();
|
||||
private static Vector2 vector = new Vector2();
|
||||
public Timer timer = new Timer(3);
|
||||
private Team team;
|
||||
private Object data;
|
||||
private boolean supressCollision;
|
||||
|
||||
private Team team;
|
||||
private Object data;
|
||||
private boolean supressCollision;
|
||||
/**
|
||||
* Internal use only!
|
||||
*/
|
||||
public Bullet(){
|
||||
}
|
||||
|
||||
public Timer timer = new Timer(3);
|
||||
public static void create(BulletType type, TeamTrait owner, float x, float y, float angle){
|
||||
create(type, owner, owner.getTeam(), x, y, angle);
|
||||
}
|
||||
|
||||
public static void create (BulletType type, TeamTrait owner, float x, float y, float angle){
|
||||
create(type, owner, owner.getTeam(), x, y, angle);
|
||||
}
|
||||
public static void create(BulletType type, Entity owner, Team team, float x, float y, float angle){
|
||||
create(type, owner, team, x, y, angle, 1f);
|
||||
}
|
||||
|
||||
public static void create (BulletType type, Entity owner, Team team, float x, float y, float angle){
|
||||
create(type, owner, team, x, y, angle, 1f);
|
||||
}
|
||||
public static void create(BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl){
|
||||
create(type, owner, team, x, y, angle, velocityScl, null);
|
||||
}
|
||||
|
||||
public static void create (BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl){
|
||||
create(type, owner, team, x, y, angle, velocityScl, null);
|
||||
}
|
||||
public static void create(BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl, Object data){
|
||||
Bullet bullet = Pooling.obtain(Bullet.class);
|
||||
bullet.type = type;
|
||||
bullet.owner = owner;
|
||||
bullet.data = data;
|
||||
|
||||
public static void create (BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl, Object data){
|
||||
Bullet bullet = Pooling.obtain(Bullet.class);
|
||||
bullet.type = type;
|
||||
bullet.owner = owner;
|
||||
bullet.data = data;
|
||||
bullet.velocity.set(0, type.speed).setAngle(angle).scl(velocityScl);
|
||||
if(type.keepVelocity){
|
||||
bullet.velocity.add(owner instanceof VelocityTrait ? ((VelocityTrait) owner).getVelocity() : Vector2.Zero);
|
||||
}
|
||||
bullet.hitbox.setSize(type.hitsize);
|
||||
|
||||
bullet.velocity.set(0, type.speed).setAngle(angle).scl(velocityScl);
|
||||
if(type.keepVelocity){
|
||||
bullet.velocity.add(owner instanceof VelocityTrait ? ((VelocityTrait)owner).getVelocity() : Vector2.Zero);
|
||||
}
|
||||
bullet.hitbox.setSize(type.hitsize);
|
||||
bullet.team = team;
|
||||
bullet.type = type;
|
||||
|
||||
bullet.team = team;
|
||||
bullet.type = type;
|
||||
//translate bullets backwards, purely for visual reasons
|
||||
float backDelta = Timers.delta();
|
||||
|
||||
//translate bullets backwards, purely for visual reasons
|
||||
float backDelta = Timers.delta();
|
||||
bullet.lastPosition().set(x - bullet.velocity.x * backDelta, y - bullet.velocity.y * backDelta, bullet.angle());
|
||||
bullet.setLastUpdated(TimeUtils.millis());
|
||||
bullet.setUpdateSpacing((long) ((Timers.delta() / 60f) * 1000));
|
||||
bullet.set(x - bullet.velocity.x * backDelta, y - bullet.velocity.y * backDelta);
|
||||
|
||||
bullet.lastPosition().set(x-bullet.velocity.x * backDelta, y-bullet.velocity.y * backDelta, bullet.angle());
|
||||
bullet.setLastUpdated(TimeUtils.millis());
|
||||
bullet.setUpdateSpacing((long)((Timers.delta() / 60f) * 1000));
|
||||
bullet.set(x-bullet.velocity.x * backDelta, y-bullet.velocity.y * backDelta);
|
||||
bullet.add();
|
||||
}
|
||||
|
||||
bullet.add();
|
||||
}
|
||||
public static void create(BulletType type, Bullet parent, float x, float y, float angle){
|
||||
create(type, parent.owner, parent.team, x, y, angle);
|
||||
}
|
||||
|
||||
public static void create(BulletType type, Bullet parent, float x, float y, float angle){
|
||||
create(type, parent.owner, parent.team, x, y, angle);
|
||||
}
|
||||
public static void create(BulletType type, Bullet parent, float x, float y, float angle, float velocityScl){
|
||||
create(type, parent.owner, parent.team, x, y, angle, velocityScl);
|
||||
}
|
||||
|
||||
public static void create(BulletType type, Bullet parent, float x, float y, float angle, float velocityScl){
|
||||
create(type, parent.owner, parent.team, x, y, angle, velocityScl);
|
||||
}
|
||||
@Remote(called = Loc.server, in = In.entities)
|
||||
public static void createBullet(BulletType type, float x, float y, float angle){
|
||||
create(type, null, Team.none, x, y, angle);
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, in = In.entities)
|
||||
public static void createBullet(BulletType type, float x, float y, float angle){
|
||||
create(type, null, Team.none, x, y, angle);
|
||||
}
|
||||
public boolean collidesTiles(){
|
||||
return type.collidesTiles;
|
||||
}
|
||||
|
||||
/**Internal use only!*/
|
||||
public Bullet(){}
|
||||
public void supressCollision(){
|
||||
supressCollision = true;
|
||||
}
|
||||
|
||||
public boolean collidesTiles(){
|
||||
return type.collidesTiles;
|
||||
}
|
||||
public void resetOwner(Entity entity, Team team){
|
||||
this.owner = entity;
|
||||
this.team = team;
|
||||
}
|
||||
|
||||
public void supressCollision(){
|
||||
supressCollision = true;
|
||||
}
|
||||
public void scaleTime(float add){
|
||||
time += add;
|
||||
}
|
||||
|
||||
public void resetOwner(Entity entity, Team team){
|
||||
this.owner = entity;
|
||||
this.team = team;
|
||||
}
|
||||
public Object getData(){
|
||||
return data;
|
||||
}
|
||||
|
||||
public void scaleTime(float add){
|
||||
time += add;
|
||||
}
|
||||
@Override
|
||||
public float getDamage(){
|
||||
if(owner instanceof Unit){
|
||||
return super.getDamage() * ((Unit) owner).getDamageMultipler();
|
||||
}
|
||||
|
||||
public Object getData() {
|
||||
return data;
|
||||
}
|
||||
return super.getDamage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getDamage(){
|
||||
if(owner instanceof Unit){
|
||||
return super.getDamage() * ((Unit) owner).getDamageMultipler();
|
||||
}
|
||||
@Override
|
||||
public boolean isSyncing(){
|
||||
return type.syncable;
|
||||
}
|
||||
|
||||
return super.getDamage();
|
||||
}
|
||||
@Override
|
||||
public void write(DataOutput data) throws IOException{
|
||||
data.writeFloat(x);
|
||||
data.writeFloat(y);
|
||||
data.writeFloat(velocity.x);
|
||||
data.writeFloat(velocity.y);
|
||||
data.writeByte(team.ordinal());
|
||||
data.writeByte(type.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSyncing(){
|
||||
return type.syncable;
|
||||
}
|
||||
@Override
|
||||
public void read(DataInput data, long time) throws IOException{
|
||||
x = data.readFloat();
|
||||
y = data.readFloat();
|
||||
velocity.x = data.readFloat();
|
||||
velocity.y = data.readFloat();
|
||||
team = Team.all[data.readByte()];
|
||||
type = BulletType.getByID(data.readByte());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput data) throws IOException {
|
||||
data.writeFloat(x);
|
||||
data.writeFloat(y);
|
||||
data.writeFloat(velocity.x);
|
||||
data.writeFloat(velocity.y);
|
||||
data.writeByte(team.ordinal());
|
||||
data.writeByte(type.id);
|
||||
}
|
||||
@Override
|
||||
public Team getTeam(){
|
||||
return team;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput data, long time) throws IOException{
|
||||
x = data.readFloat();
|
||||
y = data.readFloat();
|
||||
velocity.x = data.readFloat();
|
||||
velocity.y = data.readFloat();
|
||||
team = Team.all[data.readByte()];
|
||||
type = BulletType.getByID(data.readByte());
|
||||
}
|
||||
@Override
|
||||
public void draw(){
|
||||
type.draw(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Team getTeam() {
|
||||
return team;
|
||||
}
|
||||
@Override
|
||||
public float drawSize(){
|
||||
return 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
type.draw(this);
|
||||
}
|
||||
@Override
|
||||
public boolean collides(SolidTrait other){
|
||||
return type.collides && super.collides(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float drawSize(){
|
||||
return 8;
|
||||
}
|
||||
@Override
|
||||
public void collision(SolidTrait other, float x, float y){
|
||||
super.collision(other, x, y);
|
||||
|
||||
@Override
|
||||
public boolean collides(SolidTrait other){
|
||||
return type.collides && super.collides(other);
|
||||
}
|
||||
if(other instanceof Unit){
|
||||
Unit unit = (Unit) other;
|
||||
unit.getVelocity().add(vector.set(other.getX(), other.getY()).sub(x, y).setLength(type.knockback / unit.getMass()));
|
||||
unit.applyEffect(type.status, type.statusIntensity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collision(SolidTrait other, float x, float y){
|
||||
super.collision(other, x, y);
|
||||
@Override
|
||||
public void update(){
|
||||
super.update();
|
||||
|
||||
if(other instanceof Unit){
|
||||
Unit unit = (Unit)other;
|
||||
unit.getVelocity().add(vector.set(other.getX(), other.getY()).sub(x, y).setLength(type.knockback / unit.getMass()));
|
||||
unit.applyEffect(type.status, type.statusIntensity);
|
||||
}
|
||||
}
|
||||
if(type.hitTiles && collidesTiles() && !supressCollision){
|
||||
world.raycastEach(world.toTile(lastPosition().x), world.toTile(lastPosition().y), world.toTile(x), world.toTile(y), (x, y) -> {
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
super.update();
|
||||
Tile tile = world.tile(x, y);
|
||||
if(tile == null) return false;
|
||||
tile = tile.target();
|
||||
|
||||
if (type.hitTiles && collidesTiles() && !supressCollision) {
|
||||
world.raycastEach(world.toTile(lastPosition().x), world.toTile(lastPosition().y), world.toTile(x), world.toTile(y), (x, y) -> {
|
||||
if(tile.entity != null && tile.entity.collide(this) && !tile.entity.isDead() && tile.entity.tile.getTeam() != team){
|
||||
tile.entity.collision(this);
|
||||
|
||||
Tile tile = world.tile(x, y);
|
||||
if (tile == null) return false;
|
||||
tile = tile.target();
|
||||
if(!supressCollision){
|
||||
type.hit(this);
|
||||
remove();
|
||||
}
|
||||
|
||||
if (tile.entity != null && tile.entity.collide(this) && !tile.entity.isDead() && tile.entity.tile.getTeam() != team) {
|
||||
tile.entity.collision(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(!supressCollision){
|
||||
type.hit(this);
|
||||
remove();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
supressCollision = false;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
@Override
|
||||
public void reset(){
|
||||
super.reset();
|
||||
timer.clear();
|
||||
team = null;
|
||||
data = null;
|
||||
}
|
||||
|
||||
supressCollision = false;
|
||||
}
|
||||
@Override
|
||||
public void removed(){
|
||||
Pooling.free(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
timer.clear();
|
||||
team = null;
|
||||
data = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed() {
|
||||
Pooling.free(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityGroup targetGroup() {
|
||||
return bulletGroup;
|
||||
}
|
||||
@Override
|
||||
public EntityGroup targetGroup(){
|
||||
return bulletGroup;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,65 +9,83 @@ import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.entities.impl.BaseBulletType;
|
||||
|
||||
public abstract class BulletType extends BaseBulletType<Bullet> implements Content{
|
||||
private static int lastid = 0;
|
||||
private static Array<BulletType> types = new Array<>();
|
||||
private static int lastid = 0;
|
||||
private static Array<BulletType> types = new Array<>();
|
||||
|
||||
public final int id;
|
||||
/**Knockback in velocity.*/
|
||||
public float knockback;
|
||||
/**Whether this bullet hits tiles.*/
|
||||
public boolean hitTiles = true;
|
||||
/**Status effect applied on hit.*/
|
||||
public StatusEffect status = StatusEffects.none;
|
||||
/**Intensity of applied status effect in terms of duration.*/
|
||||
public float statusIntensity = 0.5f;
|
||||
/**What fraction of armor is pierced, 0-1*/
|
||||
public float armorPierce = 0f;
|
||||
/**Whether to sync this bullet to clients.*/
|
||||
public boolean syncable;
|
||||
/**Whether this bullet type collides with tiles.*/
|
||||
public boolean collidesTiles = true;
|
||||
/**Whether this bullet types collides with anything at all.*/
|
||||
public boolean collides = true;
|
||||
/**Whether velocity is inherited from the shooter.*/
|
||||
public boolean keepVelocity = true;
|
||||
public final int id;
|
||||
/**
|
||||
* Knockback in velocity.
|
||||
*/
|
||||
public float knockback;
|
||||
/**
|
||||
* Whether this bullet hits tiles.
|
||||
*/
|
||||
public boolean hitTiles = true;
|
||||
/**
|
||||
* Status effect applied on hit.
|
||||
*/
|
||||
public StatusEffect status = StatusEffects.none;
|
||||
/**
|
||||
* Intensity of applied status effect in terms of duration.
|
||||
*/
|
||||
public float statusIntensity = 0.5f;
|
||||
/**
|
||||
* What fraction of armor is pierced, 0-1
|
||||
*/
|
||||
public float armorPierce = 0f;
|
||||
/**
|
||||
* Whether to sync this bullet to clients.
|
||||
*/
|
||||
public boolean syncable;
|
||||
/**
|
||||
* Whether this bullet type collides with tiles.
|
||||
*/
|
||||
public boolean collidesTiles = true;
|
||||
/**
|
||||
* Whether this bullet types collides with anything at all.
|
||||
*/
|
||||
public boolean collides = true;
|
||||
/**
|
||||
* Whether velocity is inherited from the shooter.
|
||||
*/
|
||||
public boolean keepVelocity = true;
|
||||
|
||||
public BulletType(float speed, float damage){
|
||||
this.id = lastid ++;
|
||||
this.speed = speed;
|
||||
this.damage = damage;
|
||||
lifetime = 40f;
|
||||
hiteffect = BulletFx.hitBulletSmall;
|
||||
despawneffect = BulletFx.despawn;
|
||||
public BulletType(float speed, float damage){
|
||||
this.id = lastid++;
|
||||
this.speed = speed;
|
||||
this.damage = damage;
|
||||
lifetime = 40f;
|
||||
hiteffect = BulletFx.hitBulletSmall;
|
||||
despawneffect = BulletFx.despawn;
|
||||
|
||||
types.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hit(Bullet b, float hitx, float hity){
|
||||
Effects.effect(hiteffect, hitx, hity, b.angle());
|
||||
}
|
||||
types.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void despawned(Bullet b){
|
||||
Effects.effect(despawneffect, b.x, b.y, b.angle());
|
||||
}
|
||||
public static BulletType getByID(int id){
|
||||
return types.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentTypeName() {
|
||||
return "bullettype";
|
||||
}
|
||||
public static Array<BulletType> all(){
|
||||
return types;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array<? extends Content> getAll() {
|
||||
return types;
|
||||
}
|
||||
@Override
|
||||
public void hit(Bullet b, float hitx, float hity){
|
||||
Effects.effect(hiteffect, hitx, hity, b.angle());
|
||||
}
|
||||
|
||||
public static BulletType getByID(int id){
|
||||
return types.get(id);
|
||||
}
|
||||
@Override
|
||||
public void despawned(Bullet b){
|
||||
Effects.effect(despawneffect, b.x, b.y, b.angle());
|
||||
}
|
||||
|
||||
public static Array<BulletType> all(){
|
||||
return types;
|
||||
}
|
||||
@Override
|
||||
public String getContentTypeName(){
|
||||
return "bullettype";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Array<? extends Content> getAll(){
|
||||
return types;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,10 +16,10 @@ import io.anuke.ucore.util.Mathf;
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class LiquidBulletType extends BulletType {
|
||||
public class LiquidBulletType extends BulletType{
|
||||
Liquid liquid;
|
||||
|
||||
public LiquidBulletType(Liquid liquid) {
|
||||
public LiquidBulletType(Liquid liquid){
|
||||
super(2.5f, 0);
|
||||
this.liquid = liquid;
|
||||
|
||||
@@ -31,14 +31,14 @@ public class LiquidBulletType extends BulletType {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Bullet b) {
|
||||
public void draw(Bullet b){
|
||||
Draw.color(liquid.color, Color.WHITE, b.fout() / 100f + Mathf.randomSeedRange(b.id, 0.1f));
|
||||
|
||||
Fill.circle(b.x, b.y, 0.5f + b.fout()*2.5f);
|
||||
Fill.circle(b.x, b.y, 0.5f + b.fout() * 2.5f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hit(Bullet b, float hitx, float hity) {
|
||||
public void hit(Bullet b, float hitx, float hity){
|
||||
Effects.effect(hiteffect, liquid.color, hitx, hity);
|
||||
Puddle.deposit(world.tileWorld(hitx, hity), liquid, 5f);
|
||||
|
||||
@@ -46,7 +46,7 @@ public class LiquidBulletType extends BulletType {
|
||||
float intensity = 400f;
|
||||
Fire.extinguish(world.tileWorld(hitx, hity), intensity);
|
||||
for(GridPoint2 p : Geometry.d4){
|
||||
Fire.extinguish(world.tileWorld(hitx + p.x*tilesize, hity + p.y*tilesize), intensity);
|
||||
Fire.extinguish(world.tileWorld(hitx + p.x * tilesize, hity + p.y * tilesize), intensity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,9 @@ import io.anuke.mindustry.content.fx.BulletFx;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.ucore.core.Effects;
|
||||
|
||||
public class MissileBulletType extends BasicBulletType {
|
||||
public class MissileBulletType extends BasicBulletType{
|
||||
|
||||
public MissileBulletType(float speed, float damage, String bulletSprite) {
|
||||
public MissileBulletType(float speed, float damage, String bulletSprite){
|
||||
super(speed, damage, bulletSprite);
|
||||
backColor = Palette.missileYellowBack;
|
||||
frontColor = Palette.missileYellow;
|
||||
@@ -14,7 +14,7 @@ public class MissileBulletType extends BasicBulletType {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Bullet b) {
|
||||
public void update(Bullet b){
|
||||
super.update(b);
|
||||
|
||||
if(b.timer.get(0, 4f)){
|
||||
|
||||
@@ -10,24 +10,26 @@ import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import static io.anuke.mindustry.Vars.groundEffectGroup;
|
||||
|
||||
/**Class for creating block rubble on the ground.*/
|
||||
public abstract class Decal extends TimedEntity implements BelowLiquidTrait, DrawTrait {
|
||||
/**
|
||||
* Class for creating block rubble on the ground.
|
||||
*/
|
||||
public abstract class Decal extends TimedEntity implements BelowLiquidTrait, DrawTrait{
|
||||
private static final Color color = Color.valueOf("52504e");
|
||||
|
||||
@Override
|
||||
public float lifetime() {
|
||||
public float lifetime(){
|
||||
return 8200f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
Draw.color(color.r, color.g, color.b, 1f-Mathf.curve(fin(), 0.98f));
|
||||
Draw.color(color.r, color.g, color.b, 1f - Mathf.curve(fin(), 0.98f));
|
||||
drawDecal();
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityGroup targetGroup() {
|
||||
public EntityGroup targetGroup(){
|
||||
return groundEffectGroup;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.io.IOException;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable {
|
||||
public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
|
||||
private static final IntMap<Fire> map = new IntMap<>();
|
||||
private static final float baseLifetime = 1000f;
|
||||
|
||||
@@ -41,7 +41,15 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
||||
private float baseFlammability = -1, puddleFlammability;
|
||||
private float lifetime;
|
||||
|
||||
/**Start a fire on the tile. If there already is a file there, refreshes its lifetime.*/
|
||||
/**
|
||||
* Deserialization use only!
|
||||
*/
|
||||
public Fire(){
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a fire on the tile. If there already is a file there, refreshes its lifetime.
|
||||
*/
|
||||
public static void create(Tile tile){
|
||||
if(Net.client() || tile == null) return; //not clientside.
|
||||
|
||||
@@ -60,24 +68,28 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
||||
}
|
||||
}
|
||||
|
||||
/**Attempts to extinguish a fire by shortening its life. If there is no fire here, does nothing.*/
|
||||
public static void extinguish(Tile tile, float intensity) {
|
||||
if (tile != null && map.containsKey(tile.packedPosition())) {
|
||||
/**
|
||||
* Attempts to extinguish a fire by shortening its life. If there is no fire here, does nothing.
|
||||
*/
|
||||
public static void extinguish(Tile tile, float intensity){
|
||||
if(tile != null && map.containsKey(tile.packedPosition())){
|
||||
map.get(tile.packedPosition()).time += intensity * Timers.delta();
|
||||
}
|
||||
}
|
||||
|
||||
/**Deserialization use only!*/
|
||||
public Fire(){}
|
||||
@Remote(called = Loc.server, in = In.entities)
|
||||
public static void onFireRemoved(int fireid){
|
||||
fireGroup.removeByID(fireid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float lifetime() {
|
||||
public float lifetime(){
|
||||
return lifetime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
if(Mathf.chance(0.1 * Timers.delta())) {
|
||||
public void update(){
|
||||
if(Mathf.chance(0.1 * Timers.delta())){
|
||||
Effects.effect(EnvironmentFx.fire, x + Mathf.range(4f), y + Mathf.range(4f));
|
||||
}
|
||||
|
||||
@@ -91,9 +103,10 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
||||
|
||||
time = Mathf.clamp(time + Timers.delta(), 0, lifetime());
|
||||
|
||||
if(time >= lifetime()){
|
||||
if(time >= lifetime() || tile == null){
|
||||
CallEntity.onFireRemoved(getID());
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
|
||||
TileEntity entity = tile.target().entity;
|
||||
@@ -102,19 +115,19 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
||||
float flammability = baseFlammability + puddleFlammability;
|
||||
|
||||
if(!damage && flammability <= 0){
|
||||
time += Timers.delta()*8;
|
||||
time += Timers.delta() * 8;
|
||||
}
|
||||
|
||||
if (baseFlammability < 0 || block != tile.block()){
|
||||
if(baseFlammability < 0 || block != tile.block()){
|
||||
baseFlammability = tile.block().getFlammability(tile);
|
||||
block = tile.block();
|
||||
}
|
||||
|
||||
if(damage) {
|
||||
if(damage){
|
||||
lifetime += Mathf.clamp(flammability / 8f, 0f, 0.6f) * Timers.delta();
|
||||
}
|
||||
|
||||
if (flammability > 1f && Mathf.chance(0.03 * Timers.delta() * Mathf.clamp(flammability/5f, 0.3f, 2f))) {
|
||||
if(flammability > 1f && Mathf.chance(0.03 * Timers.delta() * Mathf.clamp(flammability / 5f, 0.3f, 2f))){
|
||||
GridPoint2 p = Mathf.select(Geometry.d4);
|
||||
Tile other = world.tile(tile.x + p.x, tile.y + p.y);
|
||||
create(other);
|
||||
@@ -127,7 +140,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
||||
if(Mathf.chance(0.1 * Timers.delta())){
|
||||
Puddle p = Puddle.getPuddle(tile);
|
||||
if(p != null){
|
||||
puddleFlammability = p.getFlammability()/3f;
|
||||
puddleFlammability = p.getFlammability() / 3f;
|
||||
}else{
|
||||
puddleFlammability = 0;
|
||||
}
|
||||
@@ -140,14 +153,14 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSave(DataOutput stream) throws IOException {
|
||||
public void writeSave(DataOutput stream) throws IOException{
|
||||
stream.writeInt(tile.packedPosition());
|
||||
stream.writeFloat(lifetime);
|
||||
stream.writeFloat(time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSave(DataInput stream) throws IOException {
|
||||
public void readSave(DataInput stream) throws IOException{
|
||||
this.loadedPosition = stream.readInt();
|
||||
this.lifetime = stream.readFloat();
|
||||
this.time = stream.readFloat();
|
||||
@@ -155,19 +168,19 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput data) throws IOException {
|
||||
public void write(DataOutput data) throws IOException{
|
||||
data.writeFloat(x);
|
||||
data.writeFloat(y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput data, long time) throws IOException {
|
||||
public void read(DataInput data, long time) throws IOException{
|
||||
x = data.readFloat();
|
||||
y = data.readFloat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
public void reset(){
|
||||
loadedPosition = -1;
|
||||
tile = null;
|
||||
baseFlammability = -1;
|
||||
@@ -175,7 +188,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
||||
}
|
||||
|
||||
@Override
|
||||
public void added() {
|
||||
public void added(){
|
||||
if(loadedPosition != -1){
|
||||
map.put(loadedPosition, this);
|
||||
tile = world.tile(loadedPosition);
|
||||
@@ -184,7 +197,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed() {
|
||||
public void removed(){
|
||||
if(tile != null){
|
||||
map.remove(tile.packedPosition());
|
||||
}
|
||||
@@ -192,12 +205,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityGroup targetGroup() {
|
||||
public EntityGroup targetGroup(){
|
||||
return fireGroup;
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, in = In.entities)
|
||||
public static void onFireRemoved(int fireid){
|
||||
fireGroup.removeByID(fireid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,27 +9,29 @@ import io.anuke.ucore.entities.impl.EffectEntity;
|
||||
import io.anuke.ucore.function.EffectRenderer;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
/**A ground effect contains an effect that is rendered on the ground layer as opposed to the top layer.*/
|
||||
public class GroundEffectEntity extends EffectEntity {
|
||||
/**
|
||||
* A ground effect contains an effect that is rendered on the ground layer as opposed to the top layer.
|
||||
*/
|
||||
public class GroundEffectEntity extends EffectEntity{
|
||||
private boolean once;
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
GroundEffect effect = (GroundEffect)this.effect;
|
||||
GroundEffect effect = (GroundEffect) this.effect;
|
||||
|
||||
if(effect.isStatic) {
|
||||
if(effect.isStatic){
|
||||
time += Timers.delta();
|
||||
|
||||
time = Mathf.clamp(time, 0, effect.staticLife);
|
||||
|
||||
if (!once && time >= lifetime()) {
|
||||
if(!once && time >= lifetime()){
|
||||
once = true;
|
||||
time = 0f;
|
||||
Tile tile = Vars.world.tileWorld(x, y);
|
||||
if(tile != null && tile.floor().isLiquid){
|
||||
remove();
|
||||
}
|
||||
} else if (once && time >= effect.staticLife) {
|
||||
}else if(once && time >= effect.staticLife){
|
||||
remove();
|
||||
}
|
||||
}else{
|
||||
@@ -39,7 +41,7 @@ public class GroundEffectEntity extends EffectEntity {
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
GroundEffect effect = (GroundEffect)this.effect;
|
||||
GroundEffect effect = (GroundEffect) this.effect;
|
||||
|
||||
if(once && effect.isStatic)
|
||||
Effects.renderEffect(id, effect, color, lifetime(), rotation, x, y, data);
|
||||
@@ -48,32 +50,38 @@ public class GroundEffectEntity extends EffectEntity {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
public void reset(){
|
||||
super.reset();
|
||||
once = false;
|
||||
}
|
||||
|
||||
/**An effect that is rendered on the ground layer as opposed to the top layer.*/
|
||||
/**
|
||||
* An effect that is rendered on the ground layer as opposed to the top layer.
|
||||
*/
|
||||
public static class GroundEffect extends Effect{
|
||||
/**How long this effect stays on the ground when static.*/
|
||||
/**
|
||||
* How long this effect stays on the ground when static.
|
||||
*/
|
||||
public final float staticLife;
|
||||
/**If true, this effect will stop and lie on the ground for a specific duration,
|
||||
* after its initial lifetime is over.*/
|
||||
/**
|
||||
* If true, this effect will stop and lie on the ground for a specific duration,
|
||||
* after its initial lifetime is over.
|
||||
*/
|
||||
public final boolean isStatic;
|
||||
|
||||
public GroundEffect(float life, float staticLife, EffectRenderer draw) {
|
||||
public GroundEffect(float life, float staticLife, EffectRenderer draw){
|
||||
super(life, draw);
|
||||
this.staticLife = staticLife;
|
||||
this.isStatic = true;
|
||||
}
|
||||
|
||||
public GroundEffect(boolean isStatic, float life, EffectRenderer draw) {
|
||||
public GroundEffect(boolean isStatic, float life, EffectRenderer draw){
|
||||
super(life, draw);
|
||||
this.staticLife = 0f;
|
||||
this.isStatic = isStatic;
|
||||
}
|
||||
|
||||
public GroundEffect(float life, EffectRenderer draw) {
|
||||
public GroundEffect(float life, EffectRenderer draw){
|
||||
super(life, draw);
|
||||
this.staticLife = 0f;
|
||||
this.isStatic = false;
|
||||
|
||||
@@ -35,7 +35,7 @@ import java.io.IOException;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawTrait, VelocityTrait, TimeTrait, TargetTrait, Poolable {
|
||||
public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawTrait, VelocityTrait, TimeTrait, TargetTrait, Poolable{
|
||||
private static final float sinkLifetime = 80f;
|
||||
|
||||
private Interpolator interpolator = new Interpolator();
|
||||
@@ -46,6 +46,14 @@ public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawT
|
||||
private float time;
|
||||
private float sinktime;
|
||||
|
||||
/**
|
||||
* Internal use only!
|
||||
*/
|
||||
public ItemDrop(){
|
||||
hitbox.setSize(5f);
|
||||
hitboxTile.setSize(5f);
|
||||
}
|
||||
|
||||
public static ItemDrop create(Item item, int amount, float x, float y, float angle){
|
||||
ItemDrop drop = new ItemDrop();
|
||||
drop.item = item;
|
||||
@@ -73,13 +81,7 @@ public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawT
|
||||
}
|
||||
}
|
||||
|
||||
/**Internal use only!*/
|
||||
public ItemDrop(){
|
||||
hitbox.setSize(5f);
|
||||
hitboxTile.setSize(5f);
|
||||
}
|
||||
|
||||
public Item getItem() {
|
||||
public Item getItem(){
|
||||
return item;
|
||||
}
|
||||
|
||||
@@ -88,66 +90,66 @@ public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawT
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDead() {
|
||||
public boolean isDead(){
|
||||
return !isAdded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Team getTeam() {
|
||||
public Team getTeam(){
|
||||
return Team.none;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float lifetime() {
|
||||
return 60*60;
|
||||
public float lifetime(){
|
||||
return 60 * 60;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void time(float time) {
|
||||
public void time(float time){
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float time() {
|
||||
public float time(){
|
||||
return time;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector2 getVelocity() {
|
||||
public Vector2 getVelocity(){
|
||||
return velocity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collides(SolidTrait other) {
|
||||
public boolean collides(SolidTrait other){
|
||||
return other instanceof Player && time > 20f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void collision(SolidTrait other, float x, float y) {
|
||||
Unit player = (Unit)other;
|
||||
public void collision(SolidTrait other, float x, float y){
|
||||
Unit player = (Unit) other;
|
||||
if(player.inventory.canAcceptItem(item, 1)){
|
||||
int used = Math.min(amount, player.inventory.capacity() - player.inventory.getItem().amount);
|
||||
player.inventory.addItem(item, used);
|
||||
amount -= used;
|
||||
|
||||
if(amount <= 0) {
|
||||
if(amount <= 0){
|
||||
CallEntity.onPickup(getID());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw() {
|
||||
float size = itemSize * (1f - sinktime/sinkLifetime) * (1f-Mathf.curve(fin(), 0.98f));
|
||||
public void draw(){
|
||||
float size = itemSize * (1f - sinktime / sinkLifetime) * (1f - Mathf.curve(fin(), 0.98f));
|
||||
|
||||
Tile tile = world.tileWorld(x, y);
|
||||
|
||||
Draw.color(Color.WHITE, tile == null || !tile.floor().isLiquid ? Color.WHITE : tile.floor().liquidColor, sinktime/sinkLifetime);
|
||||
Draw.color(Color.WHITE, tile == null || !tile.floor().isLiquid ? Color.WHITE : tile.floor().liquidColor, sinktime / sinkLifetime);
|
||||
Draw.rect(item.region, x, y, size, size);
|
||||
|
||||
int stored = Mathf.clamp(amount / 6, 1, 8);
|
||||
|
||||
for(int i = 0; i < stored; i ++) {
|
||||
for(int i = 0; i < stored; i++){
|
||||
float px = stored == 1 ? 0 : Mathf.randomSeedRange(i + 1, 4f);
|
||||
float py = stored == 1 ? 0 : Mathf.randomSeedRange(i + 2, 4f);
|
||||
Draw.rect(item.region, x + px, y + py, size, size);
|
||||
@@ -157,8 +159,8 @@ public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawT
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
if(Net.client()) {
|
||||
public void update(){
|
||||
if(Net.client()){
|
||||
interpolate();
|
||||
}else{
|
||||
updateVelocity(0.2f);
|
||||
@@ -190,28 +192,28 @@ public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawT
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
public void reset(){
|
||||
time = 0f;
|
||||
interpolator.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Interpolator getInterpolator() {
|
||||
public Interpolator getInterpolator(){
|
||||
return interpolator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float drawSize() {
|
||||
public float drawSize(){
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityGroup targetGroup() {
|
||||
public EntityGroup targetGroup(){
|
||||
return itemGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSave(DataOutput data) throws IOException {
|
||||
public void writeSave(DataOutput data) throws IOException{
|
||||
data.writeFloat(x);
|
||||
data.writeFloat(y);
|
||||
data.writeByte(item.id);
|
||||
@@ -219,7 +221,7 @@ public class ItemDrop extends SolidEntity implements SaveTrait, SyncTrait, DrawT
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSave(DataInput data) throws IOException {
|
||||
public void readSave(DataInput data) throws IOException{
|
||||
x = data.readFloat();
|
||||
y = data.readFloat();
|
||||
item = Item.getByID(data.readByte());
|
||||
|
||||
@@ -32,17 +32,22 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
|
||||
private PosTrait to;
|
||||
private Runnable done;
|
||||
|
||||
public ItemTransfer(){
|
||||
}
|
||||
|
||||
@Remote(in = In.entities, called = Loc.server, unreliable = true)
|
||||
public static void transferAmmo(Item item, float x, float y, Unit to){
|
||||
if(to == null) return;
|
||||
to.addAmmo(item);
|
||||
create(item, x, y, to, () -> {});
|
||||
create(item, x, y, to, () -> {
|
||||
});
|
||||
}
|
||||
|
||||
@Remote(in = In.entities, called = Loc.server, unreliable = true)
|
||||
public static void transferItemEffect(Item item, float x, float y, Unit to){
|
||||
if(to == null) return;
|
||||
create(item, x, y, to, () -> {});
|
||||
create(item, x, y, to, () -> {
|
||||
});
|
||||
}
|
||||
|
||||
@Remote(in = In.entities, called = Loc.server, unreliable = true)
|
||||
@@ -54,10 +59,11 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
|
||||
@Remote(in = In.entities, called = Loc.server)
|
||||
public static void transferItemTo(Item item, int amount, float x, float y, Tile tile){
|
||||
if(tile == null) return;
|
||||
for (int i = 0; i < Mathf.clamp(amount/3, 1, 8); i++) {
|
||||
Timers.run(i*3, () -> create(item, x, y, tile, () -> {}));
|
||||
for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){
|
||||
Timers.run(i * 3, () -> create(item, x, y, tile, () -> {
|
||||
}));
|
||||
}
|
||||
tile.entity.items.addItem(item, amount);
|
||||
tile.entity.items.add(item, amount);
|
||||
}
|
||||
|
||||
public static void create(Item item, float fromx, float fromy, PosTrait to, Runnable done){
|
||||
@@ -70,15 +76,13 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
|
||||
tr.add();
|
||||
}
|
||||
|
||||
public ItemTransfer(){}
|
||||
|
||||
@Override
|
||||
public float lifetime() {
|
||||
public float lifetime(){
|
||||
return 60;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
public void reset(){
|
||||
super.reset();
|
||||
item = null;
|
||||
to = null;
|
||||
@@ -89,7 +93,7 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed() {
|
||||
public void removed(){
|
||||
if(done != null){
|
||||
threads.run(done);
|
||||
}
|
||||
@@ -97,7 +101,7 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
public void update(){
|
||||
if(to == null){
|
||||
remove();
|
||||
return;
|
||||
@@ -110,24 +114,24 @@ public class ItemTransfer extends TimedEntity implements DrawTrait{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw() {
|
||||
float length = fslope()*6f;
|
||||
public void draw(){
|
||||
float length = fslope() * 6f;
|
||||
float angle = current.set(x, y).sub(from).angle();
|
||||
Draw.color(Palette.accent);
|
||||
Lines.stroke(fslope()*2f);
|
||||
Lines.stroke(fslope() * 2f);
|
||||
|
||||
Lines.circle(x, y, fslope()*2f);
|
||||
Lines.circle(x, y, fslope() * 2f);
|
||||
Lines.lineAngleCenter(x, y, angle, length);
|
||||
Lines.lineAngle(x, y, angle, fout()*6f);
|
||||
Lines.lineAngle(x, y, angle, fout() * 6f);
|
||||
|
||||
Draw.color(item.color);
|
||||
Fill.circle(x, y, fslope()*1.5f);
|
||||
Fill.circle(x, y, fslope() * 1.5f);
|
||||
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityGroup targetGroup() {
|
||||
public EntityGroup targetGroup(){
|
||||
return effectGroup;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,15 @@ public class Lightning extends TimedEntity implements Poolable, DrawTrait, SyncT
|
||||
private Color color = Palette.lancerLaser;
|
||||
private SeedRandom random = new SeedRandom();
|
||||
|
||||
/**Create a lighting branch at a location. Use Team.none to damage everyone.*/
|
||||
/**
|
||||
* For pooling use only. Do not call directly!
|
||||
*/
|
||||
public Lightning(){
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a lighting branch at a location. Use Team.none to damage everyone.
|
||||
*/
|
||||
public static void create(Team team, Effect effect, Color color, float damage, float x, float y, float targetAngle, int length){
|
||||
CallEntity.createLighting(lastSeed++, team, effect, color, damage, x, y, targetAngle, length);
|
||||
}
|
||||
@@ -69,7 +77,7 @@ public class Lightning extends TimedEntity implements Poolable, DrawTrait, SyncT
|
||||
|
||||
Units.getNearbyEnemies(team, rect, entities::add);
|
||||
|
||||
for(int i = 0; i < length; i ++){
|
||||
for(int i = 0; i < length; i++){
|
||||
l.lines.add(new Vector2(x, y));
|
||||
|
||||
float fx = x, fy = y;
|
||||
@@ -82,15 +90,15 @@ public class Lightning extends TimedEntity implements Poolable, DrawTrait, SyncT
|
||||
|
||||
Units.getNearbyEnemies(team, rect, entity -> {
|
||||
float dst = entity.distanceTo(x2, y2);
|
||||
if(dst < attractRange) {
|
||||
if(dst < attractRange){
|
||||
angle = Mathf.slerp(angle, Angles.angle(x2, y2, entity.x, entity.y), (attractRange - dst) / attractRange / 4f);
|
||||
}
|
||||
|
||||
entity.getHitbox(hitrect);
|
||||
hitrect.x -= range/2f;
|
||||
hitrect.y -= range/2f;
|
||||
hitrect.width += range/2f;
|
||||
hitrect.height += range/2f;
|
||||
hitrect.x -= range / 2f;
|
||||
hitrect.y -= range / 2f;
|
||||
hitrect.width += range / 2f;
|
||||
hitrect.height += range / 2f;
|
||||
|
||||
if(hitrect.contains(x2, y2) || hitrect.contains(fx, fy)){
|
||||
float result = damage;
|
||||
@@ -104,7 +112,7 @@ public class Lightning extends TimedEntity implements Poolable, DrawTrait, SyncT
|
||||
});
|
||||
|
||||
if(l.random.chance(0.1f)){
|
||||
createLighting(l.random.nextInt(), team, effect, color, damage, x2, y2, angle + l.random.range(100f), length/3);
|
||||
createLighting(l.random.nextInt(), team, effect, color, damage, x2, y2, angle + l.random.range(100f), length / 3);
|
||||
}
|
||||
|
||||
x = x2;
|
||||
@@ -115,47 +123,44 @@ public class Lightning extends TimedEntity implements Poolable, DrawTrait, SyncT
|
||||
l.add();
|
||||
}
|
||||
|
||||
/**For pooling use only. Do not call directly!*/
|
||||
public Lightning(){}
|
||||
|
||||
@Override
|
||||
public boolean isSyncing() {
|
||||
public boolean isSyncing(){
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput data) throws IOException {
|
||||
public void write(DataOutput data) throws IOException{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput data, long time) throws IOException {
|
||||
public void read(DataInput data, long time) throws IOException{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public float lifetime() {
|
||||
public float lifetime(){
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
public void reset(){
|
||||
color = Palette.lancerLaser;
|
||||
lines.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed() {
|
||||
public void removed(){
|
||||
Pooling.free(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw() {
|
||||
public void draw(){
|
||||
float lx = x, ly = y;
|
||||
Draw.color(color, Color.WHITE, fin());
|
||||
for(int i = 0; i < lines.size; i ++){
|
||||
for(int i = 0; i < lines.size; i++){
|
||||
Vector2 v = lines.get(i);
|
||||
Lines.stroke(fout() * 3f + 1f-(float)i/lines.size);
|
||||
Lines.stroke(fout() * 3f + 1f - (float) i / lines.size);
|
||||
Lines.line(lx, ly, v.x, v.y);
|
||||
lx = v.x;
|
||||
ly = v.y;
|
||||
@@ -164,7 +169,7 @@ public class Lightning extends TimedEntity implements Poolable, DrawTrait, SyncT
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityGroup targetGroup() {
|
||||
public EntityGroup targetGroup(){
|
||||
return bulletGroup;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ import java.io.IOException;
|
||||
import static io.anuke.mindustry.Vars.puddleGroup;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait, SyncTrait {
|
||||
public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait, SyncTrait{
|
||||
private static final IntMap<Puddle> map = new IntMap<>();
|
||||
private static final float maxLiquid = 70f;
|
||||
private static final int maxGeneration = 2;
|
||||
@@ -58,17 +58,29 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
private float accepting;
|
||||
private byte generation;
|
||||
|
||||
/**Deposists a puddle between tile and source.*/
|
||||
/**
|
||||
* Deserialization use only!
|
||||
*/
|
||||
public Puddle(){
|
||||
}
|
||||
|
||||
/**
|
||||
* Deposists a puddle between tile and source.
|
||||
*/
|
||||
public static void deposit(Tile tile, Tile source, Liquid liquid, float amount){
|
||||
deposit(tile, source, liquid, amount, 0);
|
||||
}
|
||||
|
||||
/**Deposists a puddle at a tile.*/
|
||||
/**
|
||||
* Deposists a puddle at a tile.
|
||||
*/
|
||||
public static void deposit(Tile tile, Liquid liquid, float amount){
|
||||
deposit(tile, tile, liquid, amount, 0);
|
||||
}
|
||||
|
||||
/**Returns the puddle on the specified tile. May return null.*/
|
||||
/**
|
||||
* Returns the puddle on the specified tile. May return null.
|
||||
*/
|
||||
public static Puddle getPuddle(Tile tile){
|
||||
return map.get(tile.packedPosition());
|
||||
}
|
||||
@@ -76,11 +88,11 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
private static void deposit(Tile tile, Tile source, Liquid liquid, float amount, int generation){
|
||||
if(tile.floor().isLiquid && !canStayOn(liquid, tile.floor().liquidDrop)){
|
||||
reactPuddle(tile.floor().liquidDrop, liquid, amount, tile,
|
||||
(tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f);
|
||||
(tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f);
|
||||
|
||||
if(generation == 0 && Timers.get(tile, "ripple", 50)){
|
||||
Effects.effect(BlockFx.ripple, tile.floor().liquidDrop.color,
|
||||
(tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f);
|
||||
(tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -93,28 +105,32 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
puddle.tile = tile;
|
||||
puddle.liquid = liquid;
|
||||
puddle.amount = amount;
|
||||
puddle.generation = (byte)generation;
|
||||
puddle.set((tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f);
|
||||
puddle.generation = (byte) generation;
|
||||
puddle.set((tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f);
|
||||
puddle.add();
|
||||
map.put(tile.packedPosition(), puddle);
|
||||
}else if(p.liquid == liquid){
|
||||
p.accepting = Math.max(amount, p.accepting);
|
||||
|
||||
if(generation == 0 && Timers.get(p, "ripple2", 50) && p.amount >= maxLiquid/2f){
|
||||
Effects.effect(BlockFx.ripple, p.liquid.color, (tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f);
|
||||
if(generation == 0 && Timers.get(p, "ripple2", 50) && p.amount >= maxLiquid / 2f){
|
||||
Effects.effect(BlockFx.ripple, p.liquid.color, (tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f);
|
||||
}
|
||||
}else{
|
||||
p.amount -= reactPuddle(p.liquid, liquid, amount, p.tile, p.x, p.y);
|
||||
}
|
||||
}
|
||||
|
||||
/**Returns whether the first liquid can 'stay' on the second one.
|
||||
* Currently, the only place where this can happen is oil on water.*/
|
||||
/**
|
||||
* Returns whether the first liquid can 'stay' on the second one.
|
||||
* Currently, the only place where this can happen is oil on water.
|
||||
*/
|
||||
private static boolean canStayOn(Liquid liquid, Liquid other){
|
||||
return liquid == Liquids.oil && other == Liquids.water;
|
||||
}
|
||||
|
||||
/**Reacts two liquids together at a location.*/
|
||||
/**
|
||||
* Reacts two liquids together at a location.
|
||||
*/
|
||||
private static float reactPuddle(Liquid dest, Liquid liquid, float amount, Tile tile, float x, float y){
|
||||
if((dest.flammability > 0.3f && liquid.temperature > 0.7f) ||
|
||||
(liquid.flammability > 0.3f && dest.temperature > 0.7f)){ //flammable liquid + hot liquid
|
||||
@@ -126,25 +142,27 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
if(Mathf.chance(0.5f * amount)){
|
||||
Effects.effect(EnvironmentFx.steam, x, y);
|
||||
}
|
||||
return - 0.1f * amount;
|
||||
return -0.1f * amount;
|
||||
}else if(liquid.temperature > 0.7f && dest.temperature < 0.55f){ //hot liquid poured onto cold puddle
|
||||
if(Mathf.chance(0.8f * amount)){
|
||||
Effects.effect(EnvironmentFx.steam, x, y);
|
||||
}
|
||||
return - 0.4f * amount;
|
||||
return -0.4f * amount;
|
||||
}
|
||||
return 0f;
|
||||
}
|
||||
|
||||
/**Deserialization use only!*/
|
||||
public Puddle(){}
|
||||
@Remote(called = Loc.server, in = In.entities)
|
||||
public static void onPuddleRemoved(int puddleid){
|
||||
puddleGroup.removeByID(puddleid);
|
||||
}
|
||||
|
||||
public float getFlammability(){
|
||||
return liquid.flammability * amount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update() {
|
||||
public void update(){
|
||||
|
||||
//no updating happens clientside
|
||||
if(Net.client()){
|
||||
@@ -158,11 +176,11 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
amount += accepting;
|
||||
accepting = 0f;
|
||||
|
||||
if (amount >= maxLiquid / 1.5f && generation < maxGeneration) {
|
||||
if(amount >= maxLiquid / 1.5f && generation < maxGeneration){
|
||||
float deposited = Math.min((amount - maxLiquid / 1.5f) / 4f, 0.3f) * Timers.delta();
|
||||
for (GridPoint2 point : Geometry.d4) {
|
||||
for(GridPoint2 point : Geometry.d4){
|
||||
Tile other = world.tile(tile.x + point.x, tile.y + point.y);
|
||||
if (other.block() == Blocks.air && other.cliffs == 0) {
|
||||
if(other.block() == Blocks.air && other.cliffs == 0){
|
||||
deposit(other, tile, liquid, deposited, generation + 1);
|
||||
amount -= deposited / 2f; //tweak to speed up/slow down puddle propagation
|
||||
}
|
||||
@@ -171,14 +189,14 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
|
||||
amount = Mathf.clamp(amount, 0, maxLiquid);
|
||||
|
||||
if (amount <= 0f) {
|
||||
if(amount <= 0f){
|
||||
CallEntity.onPuddleRemoved(getID());
|
||||
}
|
||||
}
|
||||
|
||||
//effects-only code
|
||||
if(amount >= maxLiquid/2f && updateTime <= 0f){
|
||||
Units.getNearby(rect.setSize(Mathf.clamp(amount/(maxLiquid/1.5f))*10f).setCenter(x, y), unit -> {
|
||||
if(amount >= maxLiquid / 2f && updateTime <= 0f){
|
||||
Units.getNearby(rect.setSize(Mathf.clamp(amount / (maxLiquid / 1.5f)) * 10f).setCenter(x, y), unit -> {
|
||||
if(unit.isFlying()) return;
|
||||
|
||||
unit.getHitbox(rect2);
|
||||
@@ -186,7 +204,7 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
|
||||
unit.applyEffect(liquid.effect, 0.5f);
|
||||
|
||||
if(unit.getVelocity().len() > 0.1) {
|
||||
if(unit.getVelocity().len() > 0.1){
|
||||
Effects.effect(BlockFx.ripple, liquid.color, unit.x, unit.y);
|
||||
}
|
||||
});
|
||||
@@ -202,30 +220,30 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw() {
|
||||
public void draw(){
|
||||
seeds = id;
|
||||
boolean onLiquid = tile.floor().isLiquid;
|
||||
float f = Mathf.clamp(amount/(maxLiquid/1.5f));
|
||||
float f = Mathf.clamp(amount / (maxLiquid / 1.5f));
|
||||
float smag = onLiquid ? 0.8f : 0f;
|
||||
float sscl = 20f;
|
||||
|
||||
Draw.color(Hue.shift(tmp.set(liquid.color), 2, -0.05f));
|
||||
Fill.circle(x + Mathf.sin(Timers.time() + seeds*532, sscl, smag), y + Mathf.sin(Timers.time() + seeds*53, sscl, smag), f * 8f);
|
||||
Fill.circle(x + Mathf.sin(Timers.time() + seeds * 532, sscl, smag), y + Mathf.sin(Timers.time() + seeds * 53, sscl, smag), f * 8f);
|
||||
Angles.randLenVectors(id, 3, f * 6f, (ex, ey) -> {
|
||||
Fill.circle(x + ex + Mathf.sin(Timers.time() + seeds*532, sscl, smag),
|
||||
y + ey + Mathf.sin(Timers.time() + seeds*53, sscl, smag), f * 5f);
|
||||
seeds ++;
|
||||
Fill.circle(x + ex + Mathf.sin(Timers.time() + seeds * 532, sscl, smag),
|
||||
y + ey + Mathf.sin(Timers.time() + seeds * 53, sscl, smag), f * 5f);
|
||||
seeds++;
|
||||
});
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float drawSize() {
|
||||
public float drawSize(){
|
||||
return 20;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSave(DataOutput stream) throws IOException {
|
||||
public void writeSave(DataOutput stream) throws IOException{
|
||||
stream.writeInt(tile.packedPosition());
|
||||
stream.writeFloat(x);
|
||||
stream.writeFloat(y);
|
||||
@@ -235,7 +253,7 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSave(DataInput stream) throws IOException {
|
||||
public void readSave(DataInput stream) throws IOException{
|
||||
this.loadedPosition = stream.readInt();
|
||||
this.x = stream.readFloat();
|
||||
this.y = stream.readFloat();
|
||||
@@ -246,7 +264,7 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
public void reset(){
|
||||
loadedPosition = -1;
|
||||
tile = null;
|
||||
liquid = null;
|
||||
@@ -256,7 +274,7 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
}
|
||||
|
||||
@Override
|
||||
public void added() {
|
||||
public void added(){
|
||||
if(loadedPosition != -1){
|
||||
map.put(loadedPosition, this);
|
||||
tile = world.tile(loadedPosition);
|
||||
@@ -264,38 +282,33 @@ public class Puddle extends BaseEntity implements SaveTrait, Poolable, DrawTrait
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed() {
|
||||
public void removed(){
|
||||
map.remove(tile.packedPosition());
|
||||
reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput data) throws IOException {
|
||||
public void write(DataOutput data) throws IOException{
|
||||
data.writeFloat(x);
|
||||
data.writeFloat(y);
|
||||
data.writeByte(liquid.id);
|
||||
data.writeShort((short)(amount * 4));
|
||||
data.writeShort((short) (amount * 4));
|
||||
data.writeInt(tile.packedPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput data, long time) throws IOException {
|
||||
public void read(DataInput data, long time) throws IOException{
|
||||
x = data.readFloat();
|
||||
y = data.readFloat();
|
||||
liquid = Liquid.getByID(data.readByte());
|
||||
targetAmount = data.readShort()/4f;
|
||||
targetAmount = data.readShort() / 4f;
|
||||
tile = world.tile(data.readInt());
|
||||
|
||||
map.put(tile.packedPosition(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityGroup targetGroup() {
|
||||
public EntityGroup targetGroup(){
|
||||
return puddleGroup;
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, in = In.entities)
|
||||
public static void onPuddleRemoved(int puddleid){
|
||||
puddleGroup.removeByID(puddleid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@ package io.anuke.mindustry.entities.effect;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
public class RubbleDecal extends Decal {
|
||||
public class RubbleDecal extends Decal{
|
||||
private int size;
|
||||
|
||||
/**Creates a rubble effect at a position. Provide a block size to use.*/
|
||||
/**
|
||||
* Creates a rubble effect at a position. Provide a block size to use.
|
||||
*/
|
||||
public static void create(float x, float y, int size){
|
||||
RubbleDecal decal = new RubbleDecal();
|
||||
decal.size = size;
|
||||
|
||||
@@ -8,21 +8,21 @@ import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class ScorchDecal extends Decal {
|
||||
public class ScorchDecal extends Decal{
|
||||
private static final int scorches = 5;
|
||||
private static final TextureRegion[] regions = new TextureRegion[scorches];
|
||||
|
||||
public static void create(float x, float y){
|
||||
if(regions[0] == null){
|
||||
for (int i = 0; i < regions.length; i++) {
|
||||
regions[i] = Draw.region("scorch" + (i+1));
|
||||
for(int i = 0; i < regions.length; i++){
|
||||
regions[i] = Draw.region("scorch" + (i + 1));
|
||||
}
|
||||
}
|
||||
|
||||
Tile tile = world.tileWorld(x, y);
|
||||
|
||||
if(tile == null || tile.floor().liquidDrop != null) return;
|
||||
|
||||
|
||||
ScorchDecal decal = new ScorchDecal();
|
||||
decal.set(x, y);
|
||||
decal.add();
|
||||
@@ -31,10 +31,10 @@ public class ScorchDecal extends Decal {
|
||||
@Override
|
||||
public void drawDecal(){
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
TextureRegion region = regions[Mathf.randomSeed(id - i, 0, scorches-1)];
|
||||
for(int i = 0; i < 5; i++){
|
||||
TextureRegion region = regions[Mathf.randomSeed(id - i, 0, scorches - 1)];
|
||||
float rotation = Mathf.randomSeed(id + i, 0, 360);
|
||||
float space = 1.5f + Mathf.randomSeed(id + i + 1, 0, 20)/10f;
|
||||
float space = 1.5f + Mathf.randomSeed(id + i + 1, 0, 20) / 10f;
|
||||
Draw.grect(region, x + Angles.trnsx(rotation, space), y + Angles.trnsy(rotation, space), rotation - 90);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,44 +13,43 @@ import io.anuke.ucore.util.Mathf;
|
||||
import static io.anuke.mindustry.Vars.shieldGroup;
|
||||
|
||||
//todo re-implement
|
||||
public class Shield extends BaseEntity implements DrawTrait {
|
||||
public boolean active;
|
||||
public boolean hitPlayers = false;
|
||||
public float radius = 0f;
|
||||
|
||||
private float uptime = 0f;
|
||||
private final Tile tile;
|
||||
|
||||
public Shield(Tile tile){
|
||||
this.tile = tile;
|
||||
this.x = tile.worldx();
|
||||
this.y = tile.worldy();
|
||||
}
|
||||
|
||||
public float drawSize(){
|
||||
return 150;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
float alpha = 0.1f;
|
||||
Interpolation interp = Interpolation.fade;
|
||||
|
||||
if(active){
|
||||
uptime = interp.apply(uptime, 1f, alpha * Timers.delta());
|
||||
}else{
|
||||
uptime = interp.apply(uptime, 0f, alpha * Timers.delta());
|
||||
if(uptime <= 0.05f)
|
||||
remove();
|
||||
}
|
||||
uptime = Mathf.clamp(uptime);
|
||||
|
||||
if(!(tile.block() instanceof ShieldBlock)){
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
|
||||
ShieldBlock block = (ShieldBlock)tile.block();
|
||||
public class Shield extends BaseEntity implements DrawTrait{
|
||||
private final Tile tile;
|
||||
public boolean active;
|
||||
public boolean hitPlayers = false;
|
||||
public float radius = 0f;
|
||||
private float uptime = 0f;
|
||||
|
||||
public Shield(Tile tile){
|
||||
this.tile = tile;
|
||||
this.x = tile.worldx();
|
||||
this.y = tile.worldy();
|
||||
}
|
||||
|
||||
public float drawSize(){
|
||||
return 150;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(){
|
||||
float alpha = 0.1f;
|
||||
Interpolation interp = Interpolation.fade;
|
||||
|
||||
if(active){
|
||||
uptime = interp.apply(uptime, 1f, alpha * Timers.delta());
|
||||
}else{
|
||||
uptime = interp.apply(uptime, 0f, alpha * Timers.delta());
|
||||
if(uptime <= 0.05f)
|
||||
remove();
|
||||
}
|
||||
uptime = Mathf.clamp(uptime);
|
||||
|
||||
if(!(tile.block() instanceof ShieldBlock)){
|
||||
remove();
|
||||
return;
|
||||
}
|
||||
|
||||
ShieldBlock block = (ShieldBlock) tile.block();
|
||||
|
||||
/*
|
||||
Entities.getNearby(bulletGroup, x, y, block.shieldRadius * 2*uptime + 10, entity->{
|
||||
@@ -64,39 +63,39 @@ public class Shield extends BaseEntity implements DrawTrait {
|
||||
}
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
if(!(tile.block() instanceof ShieldBlock) || radius <= 1f){
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Fill.circle(x, y, drawRadius());
|
||||
}
|
||||
|
||||
float drawRadius(){
|
||||
return (radius + Mathf.sin(Timers.time(), 25f, 1f));
|
||||
}
|
||||
|
||||
public void removeDelay(){
|
||||
active = false;
|
||||
}
|
||||
@Override
|
||||
public void draw(){
|
||||
if(!(tile.block() instanceof ShieldBlock) || radius <= 1f){
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityGroup targetGroup() {
|
||||
return shieldGroup;
|
||||
}
|
||||
Fill.circle(x, y, drawRadius());
|
||||
}
|
||||
|
||||
float drawRadius(){
|
||||
return (radius + Mathf.sin(Timers.time(), 25f, 1f));
|
||||
}
|
||||
|
||||
public void removeDelay(){
|
||||
active = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityGroup targetGroup(){
|
||||
return shieldGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void added(){
|
||||
active = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed(){
|
||||
active = false;
|
||||
uptime = 0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void added(){
|
||||
active = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed(){
|
||||
active = false;
|
||||
uptime = 0f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
/**A flag interface for marking an effect as appearing below liquids.*/
|
||||
public interface BelowLiquidTrait {
|
||||
/**
|
||||
* A flag interface for marking an effect as appearing below liquids.
|
||||
*/
|
||||
public interface BelowLiquidTrait{
|
||||
}
|
||||
|
||||
@@ -37,27 +37,46 @@ import static io.anuke.mindustry.Vars.tilesize;
|
||||
import static io.anuke.mindustry.Vars.tmptr;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
/**Interface for units that build, break or mine things.*/
|
||||
/**
|
||||
* Interface for units that build, break or mine things.
|
||||
*/
|
||||
public interface BuilderTrait extends Entity{
|
||||
//these are not instance variables!
|
||||
float placeDistance = 140f;
|
||||
float mineDistance = 70f;
|
||||
|
||||
/**Returns the queue for storing build requests.*/
|
||||
/**
|
||||
* Returns the queue for storing build requests.
|
||||
*/
|
||||
Queue<BuildRequest> getPlaceQueue();
|
||||
|
||||
/**Returns the tile this builder is currently mining.*/
|
||||
/**
|
||||
* Returns the tile this builder is currently mining.
|
||||
*/
|
||||
Tile getMineTile();
|
||||
|
||||
/**Sets the tile this builder is currently mining.*/
|
||||
/**
|
||||
* Sets the tile this builder is currently mining.
|
||||
*/
|
||||
void setMineTile(Tile tile);
|
||||
|
||||
/**Returns the minining speed of this miner. 1 = standard, 0.5 = half speed, 2 = double speed, etc.*/
|
||||
/**
|
||||
* Returns the minining speed of this miner. 1 = standard, 0.5 = half speed, 2 = double speed, etc.
|
||||
*/
|
||||
float getMinePower();
|
||||
|
||||
/**Build power, can be any float. 1 = builds recipes in normal time, 0 = doesn't build at all.*/
|
||||
/**
|
||||
* Build power, can be any float. 1 = builds recipes in normal time, 0 = doesn't build at all.
|
||||
*/
|
||||
float getBuildPower(Tile tile);
|
||||
|
||||
/**
|
||||
* Whether this type of builder can begin creating new blocks.
|
||||
*/
|
||||
default boolean canCreateBlocks(){
|
||||
return true;
|
||||
}
|
||||
|
||||
default void writeBuilding(DataOutput output) throws IOException{
|
||||
BuildRequest request = getCurrentRequest();
|
||||
|
||||
@@ -78,17 +97,17 @@ public interface BuilderTrait extends Entity{
|
||||
}
|
||||
|
||||
default void readBuilding(DataInput input, boolean applyChanges) throws IOException{
|
||||
synchronized (getPlaceQueue()) {
|
||||
synchronized(getPlaceQueue()){
|
||||
if(applyChanges) getPlaceQueue().clear();
|
||||
|
||||
byte type = input.readByte();
|
||||
if (type != -1) {
|
||||
if(type != -1){
|
||||
int position = input.readInt();
|
||||
BuildRequest request;
|
||||
|
||||
if (type == 1) { //remove
|
||||
if(type == 1){ //remove
|
||||
request = new BuildRequest(position % world.width(), position / world.width());
|
||||
} else { //place
|
||||
}else{ //place
|
||||
byte recipe = input.readByte();
|
||||
byte rotation = input.readByte();
|
||||
request = new BuildRequest(position % world.width(), position / world.width(), rotation, Recipe.getByID(recipe));
|
||||
@@ -101,17 +120,21 @@ public interface BuilderTrait extends Entity{
|
||||
}
|
||||
}
|
||||
|
||||
/**Return whether this builder's place queue contains items.*/
|
||||
/**
|
||||
* Return whether this builder's place queue contains items.
|
||||
*/
|
||||
default boolean isBuilding(){
|
||||
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.*/
|
||||
/**
|
||||
* 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, Recipe recipe){
|
||||
synchronized (getPlaceQueue()) {
|
||||
for (BuildRequest request : getPlaceQueue()) {
|
||||
if (request.x == x && request.y == y) {
|
||||
synchronized(getPlaceQueue()){
|
||||
for(BuildRequest request : getPlaceQueue()){
|
||||
if(request.x == x && request.y == y){
|
||||
clearBuilding();
|
||||
addBuildRequest(request);
|
||||
return;
|
||||
@@ -122,16 +145,20 @@ public interface BuilderTrait extends Entity{
|
||||
addBuildRequest(new BuildRequest(x, y, rotation, recipe));
|
||||
}
|
||||
|
||||
/**Clears the placement queue.*/
|
||||
/**
|
||||
* Clears the placement queue.
|
||||
*/
|
||||
default void clearBuilding(){
|
||||
getPlaceQueue().clear();
|
||||
}
|
||||
|
||||
/**Add another build requests to the tail of the queue, if it doesn't exist there yet.*/
|
||||
/**
|
||||
* Add another build requests to the tail of the queue, if it doesn't exist there yet.
|
||||
*/
|
||||
default void addBuildRequest(BuildRequest place){
|
||||
synchronized (getPlaceQueue()) {
|
||||
for (BuildRequest request : getPlaceQueue()) {
|
||||
if (request.x == place.x && request.y == place.y) {
|
||||
synchronized(getPlaceQueue()){
|
||||
for(BuildRequest request : getPlaceQueue()){
|
||||
if(request.x == place.x && request.y == place.y){
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -139,16 +166,20 @@ public interface BuilderTrait extends Entity{
|
||||
}
|
||||
}
|
||||
|
||||
/**Return the build requests currently active, or the one at the top of the queue.
|
||||
* May return null.*/
|
||||
/**
|
||||
* Return the build requests currently active, or the one at the top of the queue.
|
||||
* May return null.
|
||||
*/
|
||||
default BuildRequest getCurrentRequest(){
|
||||
synchronized (getPlaceQueue()) {
|
||||
synchronized(getPlaceQueue()){
|
||||
return getPlaceQueue().size == 0 ? null : getPlaceQueue().first();
|
||||
}
|
||||
}
|
||||
|
||||
/**Update building mechanism for this unit.
|
||||
* This includes mining.*/
|
||||
/**
|
||||
* Update building mechanism for this unit.
|
||||
* This includes mining.
|
||||
*/
|
||||
default void updateBuilding(Unit unit){
|
||||
BuildRequest current = getCurrentRequest();
|
||||
|
||||
@@ -171,10 +202,10 @@ public interface BuilderTrait extends Entity{
|
||||
|
||||
Tile tile = world.tile(current.x, current.y);
|
||||
|
||||
if (!(tile.block() instanceof BuildBlock)) {
|
||||
if(!current.remove && Build.validPlace(unit.getTeam(), current.x, current.y, current.recipe.result, current.rotation)) {
|
||||
if(!(tile.block() instanceof BuildBlock)){
|
||||
if(canCreateBlocks() && !current.remove && Build.validPlace(unit.getTeam(), current.x, current.y, current.recipe.result, current.rotation)){
|
||||
Build.beginPlace(unit.getTeam(), current.x, current.y, current.recipe, current.rotation);
|
||||
}else if(current.remove && Build.validBreak(unit.getTeam(), current.x, current.y)){
|
||||
}else if(canCreateBlocks() && current.remove && Build.validBreak(unit.getTeam(), current.x, current.y)){
|
||||
Build.beginBreak(unit.getTeam(), current.x, current.y);
|
||||
}else{
|
||||
getPlaceQueue().removeFirst();
|
||||
@@ -198,7 +229,9 @@ public interface BuilderTrait extends Entity{
|
||||
current.progress = entity.progress();
|
||||
}
|
||||
|
||||
/**Do not call directly.*/
|
||||
/**
|
||||
* Do not call directly.
|
||||
*/
|
||||
default void updateMining(Unit unit){
|
||||
Tile tile = getMineTile();
|
||||
|
||||
@@ -211,26 +244,28 @@ public interface BuilderTrait extends Entity{
|
||||
if(unit.inventory.canAcceptItem(item) &&
|
||||
Mathf.chance(Timers.delta() * (0.06 - item.hardness * 0.01) * getMinePower())){
|
||||
CallEntity.transferItemToUnit(item,
|
||||
tile.worldx() + Mathf.range(tilesize/2f),
|
||||
tile.worldy() + Mathf.range(tilesize/2f),
|
||||
tile.worldx() + Mathf.range(tilesize / 2f),
|
||||
tile.worldy() + Mathf.range(tilesize / 2f),
|
||||
unit);
|
||||
}
|
||||
|
||||
if(Mathf.chance(0.06 * Timers.delta())){
|
||||
Effects.effect(BlockFx.pulverizeSmall,
|
||||
tile.worldx() + Mathf.range(tilesize/2f),
|
||||
tile.worldy() + Mathf.range(tilesize/2f), 0f, item.color);
|
||||
tile.worldx() + Mathf.range(tilesize / 2f),
|
||||
tile.worldy() + Mathf.range(tilesize / 2f), 0f, item.color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**Draw placement effects for an entity. This includes mining*/
|
||||
/**
|
||||
* Draw placement effects for an entity. This includes mining
|
||||
*/
|
||||
default void drawBuilding(Unit unit){
|
||||
BuildRequest request;
|
||||
|
||||
synchronized (getPlaceQueue()) {
|
||||
if (!isBuilding()) {
|
||||
if (getMineTile() != null) {
|
||||
synchronized(getPlaceQueue()){
|
||||
if(!isBuilding()){
|
||||
if(getMineTile() != null){
|
||||
drawMining(unit);
|
||||
}
|
||||
return;
|
||||
@@ -250,7 +285,7 @@ public interface BuilderTrait extends Entity{
|
||||
float px = unit.x + Angles.trnsx(unit.rotation, focusLen);
|
||||
float py = unit.y + Angles.trnsy(unit.rotation, focusLen);
|
||||
|
||||
float sz = Vars.tilesize*tile.block().size/2f;
|
||||
float sz = Vars.tilesize * tile.block().size / 2f;
|
||||
float ang = unit.angleTo(tile);
|
||||
|
||||
tmptr[0].set(tile.drawx() - sz, tile.drawy() - sz);
|
||||
@@ -281,14 +316,16 @@ public interface BuilderTrait extends Entity{
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
/**Internal use only.*/
|
||||
/**
|
||||
* Internal use only.
|
||||
*/
|
||||
default void drawMining(Unit unit){
|
||||
Tile tile = getMineTile();
|
||||
|
||||
if(tile == null) return;
|
||||
|
||||
float focusLen = 4f + Mathf.absin(Timers.time(), 1.1f, 0.5f);
|
||||
float swingScl = 12f, swingMag = tilesize/8f;
|
||||
float swingScl = 12f, swingMag = tilesize / 8f;
|
||||
float flashScl = 0.3f;
|
||||
|
||||
float px = unit.x + Angles.trnsx(unit.rotation, focusLen);
|
||||
@@ -297,10 +334,10 @@ public interface BuilderTrait extends Entity{
|
||||
float ex = tile.worldx() + Mathf.sin(Timers.time() + 48, swingScl, swingMag);
|
||||
float ey = tile.worldy() + Mathf.sin(Timers.time() + 48, swingScl + 2f, swingMag);
|
||||
|
||||
Draw.color(Color.LIGHT_GRAY, Color.WHITE, 1f-flashScl + Mathf.absin(Timers.time(), 0.5f, flashScl));
|
||||
Draw.color(Color.LIGHT_GRAY, Color.WHITE, 1f - flashScl + Mathf.absin(Timers.time(), 0.5f, flashScl));
|
||||
Shapes.laser("minelaser", "minelaser-end", px, py, ex, ey);
|
||||
|
||||
if(unit instanceof Player && ((Player) unit).isLocal) {
|
||||
if(unit instanceof Player && ((Player) unit).isLocal){
|
||||
Draw.color(Palette.accent);
|
||||
Lines.poly(tile.worldx(), tile.worldy(), 4, tilesize / 2f * Mathf.sqrt2, Timers.time());
|
||||
}
|
||||
@@ -308,16 +345,20 @@ public interface BuilderTrait extends Entity{
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
/**Class for storing build requests. Can be either a place or remove request.*/
|
||||
class BuildRequest {
|
||||
/**
|
||||
* Class for storing build requests. Can be either a place or remove request.
|
||||
*/
|
||||
class BuildRequest{
|
||||
public final int x, y, rotation;
|
||||
public final Recipe recipe;
|
||||
public final boolean remove;
|
||||
|
||||
public float progress;
|
||||
|
||||
/**This creates a build request.*/
|
||||
public BuildRequest(int x, int y, int rotation, Recipe recipe) {
|
||||
/**
|
||||
* This creates a build request.
|
||||
*/
|
||||
public BuildRequest(int x, int y, int rotation, Recipe recipe){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.rotation = rotation;
|
||||
@@ -325,8 +366,10 @@ public interface BuilderTrait extends Entity{
|
||||
this.remove = false;
|
||||
}
|
||||
|
||||
/**This creates a remove request.*/
|
||||
public BuildRequest(int x, int y) {
|
||||
/**
|
||||
* This creates a remove request.
|
||||
*/
|
||||
public BuildRequest(int x, int y){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.rotation = -1;
|
||||
|
||||
@@ -8,6 +8,7 @@ public interface CarriableTrait extends TeamTrait, TargetTrait, SolidTrait{
|
||||
return getCarrier() != null;
|
||||
}
|
||||
|
||||
void setCarrier(CarryTrait carrier);
|
||||
CarryTrait getCarrier();
|
||||
|
||||
void setCarrier(CarryTrait carrier);
|
||||
}
|
||||
|
||||
@@ -10,28 +10,6 @@ import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.entities.trait.SolidTrait;
|
||||
|
||||
public interface CarryTrait extends TeamTrait, SolidTrait, TargetTrait{
|
||||
/**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){
|
||||
CallEntity.setCarryOf(this instanceof Player ? (Player)this : null, this, unit);
|
||||
}
|
||||
|
||||
@Remote(called = Loc.both, targets = Loc.both, forward = true, in = In.entities)
|
||||
static void dropSelf(Player player){
|
||||
if(player.getCarrier() != null){
|
||||
@@ -41,6 +19,7 @@ public interface CarryTrait extends TeamTrait, SolidTrait, TargetTrait{
|
||||
|
||||
@Remote(called = Loc.both, targets = Loc.both, forward = true, in = In.entities)
|
||||
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;
|
||||
}
|
||||
@@ -61,4 +40,38 @@ public interface CarryTrait extends TeamTrait, SolidTrait, TargetTrait{
|
||||
Effects.effect(UnitFx.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){
|
||||
CallEntity.setCarryOf(this instanceof Player ? (Player) this : null, this, unit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,6 @@ package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.mindustry.entities.UnitInventory;
|
||||
|
||||
public interface InventoryTrait {
|
||||
public interface InventoryTrait{
|
||||
UnitInventory getInventory();
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package io.anuke.mindustry.entities.traits;
|
||||
import io.anuke.ucore.entities.trait.HealthTrait;
|
||||
|
||||
//TODO implement
|
||||
public interface RepairTrait extends TeamTrait {
|
||||
public interface RepairTrait extends TeamTrait{
|
||||
|
||||
HealthTrait getRepairing();
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.ucore.entities.trait.Entity;
|
||||
|
||||
/**Marks an entity as serializable.*/
|
||||
/**
|
||||
* Marks an entity as serializable.
|
||||
*/
|
||||
public interface SaveTrait extends Entity, TypeTrait, Saveable{
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@ import java.io.DataInput;
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
public interface Saveable {
|
||||
public interface Saveable{
|
||||
void writeSave(DataOutput stream) throws IOException;
|
||||
|
||||
void readSave(DataInput stream) throws IOException;
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import io.anuke.ucore.util.Timer;
|
||||
public interface ShooterTrait extends VelocityTrait, TeamTrait, InventoryTrait{
|
||||
|
||||
Timer getTimer();
|
||||
|
||||
int getShootTimer(boolean left);
|
||||
|
||||
Weapon getWeapon();
|
||||
}
|
||||
|
||||
@@ -3,8 +3,10 @@ package io.anuke.mindustry.entities.traits;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
public interface SpawnerTrait {
|
||||
public interface SpawnerTrait{
|
||||
Tile getTile();
|
||||
|
||||
void updateSpawning(Unit unit);
|
||||
|
||||
float getSpawnProgress();
|
||||
}
|
||||
|
||||
@@ -10,18 +10,22 @@ import java.io.IOException;
|
||||
|
||||
import static io.anuke.mindustry.Vars.threads;
|
||||
|
||||
public interface SyncTrait extends Entity, TypeTrait {
|
||||
public interface SyncTrait extends Entity, TypeTrait{
|
||||
|
||||
/**Whether smoothing of entities is enabled when using multithreading; not yet implemented.*/
|
||||
/**
|
||||
* Whether smoothing of entities is enabled when using multithreading; not yet implemented.
|
||||
*/
|
||||
static boolean isSmoothing(){
|
||||
return threads.isEnabled() && threads.getTPS() <= Gdx.graphics.getFramesPerSecond() / 2f;
|
||||
}
|
||||
|
||||
/**Sets the position of this entity and updated the interpolator.*/
|
||||
/**
|
||||
* Sets the position of this entity and updated the interpolator.
|
||||
*/
|
||||
default void setNet(float x, float y){
|
||||
set(x, y);
|
||||
|
||||
if(getInterpolator() != null) {
|
||||
if(getInterpolator() != null){
|
||||
getInterpolator().target.set(x, y);
|
||||
getInterpolator().last.set(x, y);
|
||||
getInterpolator().pos.set(0, 0);
|
||||
@@ -30,9 +34,12 @@ public interface SyncTrait extends Entity, TypeTrait {
|
||||
}
|
||||
}
|
||||
|
||||
/**Interpolate entity position only. Override if you need to interpolate rotations or other values.*/
|
||||
/**
|
||||
* Interpolate entity position only. Override if you need to interpolate rotations or other values.
|
||||
*/
|
||||
default void interpolate(){
|
||||
if(getInterpolator() == null) throw new RuntimeException("This entity must have an interpolator to interpolate()!");
|
||||
if(getInterpolator() == null)
|
||||
throw new RuntimeException("This entity must have an interpolator to interpolate()!");
|
||||
|
||||
getInterpolator().update();
|
||||
|
||||
@@ -40,17 +47,22 @@ public interface SyncTrait extends Entity, TypeTrait {
|
||||
setY(getInterpolator().pos.y);
|
||||
}
|
||||
|
||||
/**Return the interpolator used for smoothing the position. Optional.*/
|
||||
/**
|
||||
* Return the interpolator used for smoothing the position. Optional.
|
||||
*/
|
||||
default Interpolator getInterpolator(){
|
||||
return null;
|
||||
}
|
||||
|
||||
/**Whether syncing is enabled for this entity; true by default.*/
|
||||
/**
|
||||
* Whether syncing is enabled for this entity; true by default.
|
||||
*/
|
||||
default boolean isSyncing(){
|
||||
return true;
|
||||
}
|
||||
|
||||
//Read and write sync data, usually position
|
||||
void write(DataOutput data) throws IOException;
|
||||
|
||||
void read(DataInput data, long time) throws IOException;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.ucore.entities.trait.VelocityTrait;
|
||||
import io.anuke.ucore.entities.trait.PosTrait;
|
||||
import io.anuke.ucore.entities.trait.VelocityTrait;
|
||||
|
||||
/**Base interface for targetable entities.*/
|
||||
public interface TargetTrait extends PosTrait, VelocityTrait {
|
||||
/**
|
||||
* Base interface for targetable entities.
|
||||
*/
|
||||
public interface TargetTrait extends PosTrait, VelocityTrait{
|
||||
|
||||
boolean isDead();
|
||||
|
||||
Team getTeam();
|
||||
|
||||
/**Whether this entity is a valid target.*/
|
||||
/**
|
||||
* Whether this entity is a valid target.
|
||||
*/
|
||||
default boolean isValid(){
|
||||
return !isDead();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user