Merge
This commit is contained in:
@@ -84,10 +84,12 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
||||
|
||||
@Override
|
||||
public void resize(int width, int height){
|
||||
super.resize(width, height);
|
||||
if(assets == null) return;
|
||||
|
||||
if(!assets.isFinished()){
|
||||
Draw.proj().setOrtho(0, 0, width, height);
|
||||
}else{
|
||||
super.resize(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,6 +102,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
||||
for(ApplicationListener listener : modules){
|
||||
listener.init();
|
||||
}
|
||||
super.resize(graphics.getWidth(), graphics.getHeight());
|
||||
finished = true;
|
||||
Events.fire(new ClientLoadEvent());
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.anuke.mindustry;
|
||||
import io.anuke.arc.Application.*;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.assets.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.files.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
@@ -43,6 +44,8 @@ public class Vars implements Loadable{
|
||||
public static final String discordURL = "https://discord.gg/mindustry";
|
||||
/** URL for sending crash reports to */
|
||||
public static final String crashReportURL = "http://mins.us.to/report";
|
||||
/** list of built-in servers.*/
|
||||
public static final Array<String> defaultServers = Array.with(/*"mins.us.to"*/);
|
||||
/** maximum distance between mine and core that supports automatic transferring */
|
||||
public static final float mineTransferRange = 220f;
|
||||
/** team of the player by default */
|
||||
|
||||
@@ -242,14 +242,13 @@ public class BlockIndexer{
|
||||
int quadrantY = tile.y / quadrantSize;
|
||||
itemSet.clear();
|
||||
|
||||
Tile rounded = world.tile(Mathf.clamp(quadrantX * quadrantSize + quadrantSize / 2, 0, world.width() - 1),
|
||||
Mathf.clamp(quadrantY * quadrantSize + quadrantSize / 2, 0, world.height() - 1));
|
||||
Tile rounded = world.tile(Mathf.clamp(quadrantX * quadrantSize + quadrantSize / 2, 0, world.width() - 1), Mathf.clamp(quadrantY * quadrantSize + quadrantSize / 2, 0, world.height() - 1));
|
||||
|
||||
//find all items that this quadrant contains
|
||||
for(int x = quadrantX * quadrantSize; x < world.width() && x < (quadrantX + 1) * quadrantSize; x++){
|
||||
for(int y = quadrantY * quadrantSize; y < world.height() && y < (quadrantY + 1) * quadrantSize; y++){
|
||||
for(int x = Math.max(0, rounded.x - quadrantSize / 2); x < rounded.x + quadrantSize / 2 && x < world.width(); x++){
|
||||
for(int y = Math.max(0, rounded.y - quadrantSize / 2); y < rounded.y + quadrantSize / 2 && y < world.height(); y++){
|
||||
Tile result = world.tile(x, y);
|
||||
if(result == null || result.drop() == null || !scanOres.contains(result.drop())) continue;
|
||||
if(result == null || result.drop() == null || !scanOres.contains(result.drop()) || result.block() != Blocks.air) continue;
|
||||
|
||||
itemSet.add(result.drop());
|
||||
}
|
||||
|
||||
@@ -500,6 +500,7 @@ public class Blocks implements ContentList{
|
||||
|
||||
consumes.items(new ItemStack(Items.thorium, 4), new ItemStack(Items.sand, 10));
|
||||
consumes.power(5f);
|
||||
itemCapacity = 20;
|
||||
|
||||
int bottomRegion = reg("-bottom"), weaveRegion = reg("-weave");
|
||||
|
||||
@@ -982,7 +983,6 @@ public class Blocks implements ContentList{
|
||||
pulseConduit = new Conduit("pulse-conduit"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.titanium, 1, Items.metaglass, 1));
|
||||
liquidCapacity = 16f;
|
||||
liquidFlowFactor = 4.9f;
|
||||
health = 90;
|
||||
}};
|
||||
|
||||
@@ -1405,14 +1405,14 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
arc = new PowerTurret("arc"){{
|
||||
requirements(Category.turret, ItemStack.with(Items.copper, 35, Items.lead, 35));
|
||||
requirements(Category.turret, ItemStack.with(Items.copper, 35, Items.lead, 50));
|
||||
shootType = Bullets.arc;
|
||||
reload = 24f;
|
||||
reload = 35f;
|
||||
shootCone = 40f;
|
||||
rotatespeed = 8f;
|
||||
powerUse = 0.9f;
|
||||
powerUse = 1.5f;
|
||||
targetAir = false;
|
||||
range = 95f;
|
||||
range = 90f;
|
||||
shootEffect = Fx.lightningShoot;
|
||||
heatColor = Color.RED;
|
||||
recoil = 1f;
|
||||
@@ -1775,4 +1775,4 @@ public class Blocks implements ContentList{
|
||||
|
||||
//endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,13 @@ import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.bullet.*;
|
||||
import io.anuke.mindustry.entities.effect.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Bullets implements ContentList{
|
||||
public static BulletType
|
||||
@@ -631,7 +632,7 @@ public class Bullets implements ContentList{
|
||||
|
||||
@Override
|
||||
public void init(Bullet b){
|
||||
Lightning.create(b.getTeam(), Pal.lancerLaser, damage, b.x, b.y, b.rot(), 30);
|
||||
Lightning.create(b.getTeam(), Pal.lancerLaser, damage * (b.getOwner() instanceof Player ? state.rules.playerDamageMultiplier : 1f), b.x, b.y, b.rot(), 30);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -48,6 +48,10 @@ public class Control implements ApplicationListener, Loadable{
|
||||
private boolean wasPaused = false;
|
||||
|
||||
public Control(){
|
||||
saves = new Saves();
|
||||
tutorial = new Tutorial();
|
||||
music = new MusicControl();
|
||||
|
||||
Events.on(StateChangeEvent.class, event -> {
|
||||
if((event.from == State.playing && event.to == State.menu) || (event.from == State.menu && event.to != State.menu)){
|
||||
Time.runTask(5f, platform::updateRPC);
|
||||
@@ -152,10 +156,6 @@ public class Control implements ApplicationListener, Loadable{
|
||||
|
||||
@Override
|
||||
public void loadAsync(){
|
||||
saves = new Saves();
|
||||
tutorial = new Tutorial();
|
||||
music = new MusicControl();
|
||||
|
||||
Draw.scl = 1f / Core.atlas.find("scale_marker").getWidth();
|
||||
|
||||
Core.input.setCatch(KeyCode.BACK, true);
|
||||
|
||||
@@ -107,7 +107,17 @@ public class NetClient implements ApplicationListener{
|
||||
|
||||
Time.runTask(3f, ui.loadfrag::hide);
|
||||
|
||||
ui.showError("$disconnect");
|
||||
if(packet.reason != null){
|
||||
if(packet.reason.equals("closed")){
|
||||
ui.showSmall("$disconnect", "$disconnect.closed");
|
||||
}else if(packet.reason.equals("timeout")){
|
||||
ui.showSmall("$disconnect", "$disconnect.timeout");
|
||||
}else if(packet.reason.equals("error")){
|
||||
ui.showSmall("$disconnect", "$disconnect.error");
|
||||
}
|
||||
}else{
|
||||
ui.showError("$disconnect");
|
||||
}
|
||||
});
|
||||
|
||||
Net.handleClient(WorldStream.class, data -> {
|
||||
|
||||
@@ -1,39 +1,32 @@
|
||||
package io.anuke.mindustry.core;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.ApplicationListener;
|
||||
import io.anuke.arc.Events;
|
||||
import io.anuke.annotations.Annotations.*;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.Colors;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.math.geom.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.CommandHandler.*;
|
||||
import io.anuke.arc.util.io.*;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.core.GameState.State;
|
||||
import io.anuke.mindustry.entities.EntityGroup;
|
||||
import io.anuke.mindustry.entities.traits.BuilderTrait.BuildRequest;
|
||||
import io.anuke.mindustry.entities.traits.Entity;
|
||||
import io.anuke.mindustry.entities.traits.SyncTrait;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.game.Version;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.gen.RemoteReadServer;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.core.GameState.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.net.Administration.PlayerInfo;
|
||||
import io.anuke.mindustry.net.Administration.TraceInfo;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.Administration.*;
|
||||
import io.anuke.mindustry.net.Packets.*;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.zip.DeflaterOutputStream;
|
||||
import java.nio.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
@@ -76,7 +69,7 @@ public class NetServer implements ApplicationListener{
|
||||
Net.handleServer(Disconnect.class, (id, packet) -> {
|
||||
Player player = connections.get(id);
|
||||
if(player != null){
|
||||
onDisconnect(player);
|
||||
onDisconnect(player, packet.reason);
|
||||
}
|
||||
connections.remove(id);
|
||||
});
|
||||
@@ -111,6 +104,27 @@ public class NetServer implements ApplicationListener{
|
||||
return;
|
||||
}
|
||||
|
||||
if(admins.isIDBanned(uuid)){
|
||||
kick(id, KickReason.banned);
|
||||
return;
|
||||
}
|
||||
|
||||
if(admins.getPlayerLimit() > 0 && playerGroup.size() >= admins.getPlayerLimit()){
|
||||
kick(id, KickReason.playerLimit);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!admins.isWhitelisted(packet.uuid, packet.usid)){
|
||||
info.adminUsid = packet.usid;
|
||||
info.lastName = packet.name;
|
||||
info.id = packet.uuid;
|
||||
admins.save();
|
||||
Call.onInfoMessage(id, "You are not whitelisted here.");
|
||||
Log.info("&lcDo &lywhitelist-add {0}&lc to whitelist the player &lb'{1}'", packet.uuid, packet.name);
|
||||
kick(id, KickReason.whitelist);
|
||||
return;
|
||||
}
|
||||
|
||||
if(packet.versionType == null || ((packet.version == -1 || !packet.versionType.equals(Version.type)) && Version.build != -1 && !admins.allowsCustomClients())){
|
||||
kick(id, !Version.type.equals(packet.versionType) ? KickReason.typeMismatch : KickReason.customClient);
|
||||
return;
|
||||
@@ -184,6 +198,8 @@ public class NetServer implements ApplicationListener{
|
||||
sendWorldData(player, id);
|
||||
|
||||
platform.updateRPC();
|
||||
|
||||
Events.fire(new PlayerJoin(player));
|
||||
});
|
||||
|
||||
Net.handleServer(InvokePacket.class, (id, packet) -> {
|
||||
@@ -227,25 +243,34 @@ public class NetServer implements ApplicationListener{
|
||||
});
|
||||
|
||||
//duration of a a kick in seconds
|
||||
int kickDuration = 10 * 60;
|
||||
int kickDuration = 15 * 60;
|
||||
|
||||
class VoteSession{
|
||||
Player target;
|
||||
ObjectSet<String> voted = new ObjectSet<>();
|
||||
ObjectMap<Player, VoteSession> map;
|
||||
VoteSession[] map;
|
||||
Timer.Task task;
|
||||
int votes;
|
||||
|
||||
public VoteSession(ObjectMap<Player, VoteSession> map, Player target){
|
||||
public VoteSession(VoteSession[] map, Player target){
|
||||
this.target = target;
|
||||
this.map = map;
|
||||
this.task = Timer.schedule(() -> {
|
||||
if(!checkPass()){
|
||||
Call.sendMessage(Strings.format("[lightgray]Vote failed. Not enough votes to kick[orange] {0}[lightgray].", target.name));
|
||||
map[0] = null;
|
||||
task.cancel();
|
||||
}
|
||||
map.remove(target);
|
||||
task.cancel();
|
||||
}, 60 * 1.5f);
|
||||
}, 60 * 1);
|
||||
}
|
||||
|
||||
void vote(Player player, int d){
|
||||
votes += d;
|
||||
voted.addAll(player.uuid, admins.getInfo(player.uuid).lastIP);
|
||||
|
||||
Call.sendMessage(Strings.format("[orange]{0}[lightgray] has voted to kick[orange] {1}[].[accent] ({2}/{3})\n[lightgray]Type[orange] /vote <y/n>[] to agree.",
|
||||
player.name, target.name, votes, votesRequired()));
|
||||
//checkPass();
|
||||
}
|
||||
|
||||
boolean checkPass(){
|
||||
@@ -253,6 +278,8 @@ public class NetServer implements ApplicationListener{
|
||||
Call.sendMessage(Strings.format("[orange]Vote passed.[scarlet] {0}[orange] will be kicked from the server.", target.name));
|
||||
admins.getInfo(target.uuid).lastKicked = Time.millis() + kickDuration*1000;
|
||||
kick(target.con.id, KickReason.vote);
|
||||
map[0] = null;
|
||||
task.cancel();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -260,10 +287,10 @@ public class NetServer implements ApplicationListener{
|
||||
}
|
||||
|
||||
//cooldown between votes
|
||||
int voteTime = 60 * 10;
|
||||
int voteTime = 60 * 5;
|
||||
Timekeeper vtime = new Timekeeper(voteTime);
|
||||
//current kick sessions
|
||||
ObjectMap<Player, VoteSession> currentlyKicking = new ObjectMap<>();
|
||||
VoteSession[] currentlyKicking = {null};
|
||||
|
||||
clientCommands.<Player>register("votekick", "[player...]", "Vote to kick a player, with a cooldown.", (args, player) -> {
|
||||
if(playerGroup.size() < 3){
|
||||
@@ -271,8 +298,8 @@ public class NetServer implements ApplicationListener{
|
||||
return;
|
||||
}
|
||||
|
||||
if(currentlyKicking.values().toArray().contains(v -> v.voted.contains(player.uuid) || v.voted.contains(admins.getInfo(player.uuid).lastIP))){
|
||||
player.sendMessage("[scarlet]You've already voted. Sit down.");
|
||||
if(player.isLocal){
|
||||
player.sendMessage("[scarlet]Just kick them yourself if you're the host.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -295,24 +322,20 @@ public class NetServer implements ApplicationListener{
|
||||
}
|
||||
|
||||
if(found != null){
|
||||
if(player == found){
|
||||
player.sendMessage("[scarlet]If you're interested in kicking yourself, just leave.");
|
||||
}else if(found.isAdmin){
|
||||
if(found.isAdmin){
|
||||
player.sendMessage("[scarlet]Did you really expect to be able to kick an admin?");
|
||||
}else if(found.isLocal){
|
||||
player.sendMessage("[scarlet]Local players cannot be kicked.");
|
||||
}else{
|
||||
if(!currentlyKicking.containsKey(found) && !vtime.get()){
|
||||
if(!vtime.get()){
|
||||
player.sendMessage("[scarlet]You must wait " + voteTime/60 + " minutes between votekicks.");
|
||||
return;
|
||||
}
|
||||
|
||||
VoteSession session = currentlyKicking.getOr(found, () -> new VoteSession(currentlyKicking, found));
|
||||
session.votes ++;
|
||||
session.voted.addAll(player.uuid, admins.getInfo(player.uuid).lastIP);
|
||||
|
||||
Call.sendMessage(Strings.format("[orange]{0}[lightgray] has voted to kick[orange] {1}[].[accent] ({2}/{3})\n[lightgray]Type[orange] /votekick #{4}[] to agree.",
|
||||
player.name, found.name, session.votes, votesRequired(), found.con.id));
|
||||
session.checkPass();
|
||||
vtime.reset();
|
||||
VoteSession session = new VoteSession(currentlyKicking, found);
|
||||
session.vote(player, 1);
|
||||
vtime.reset();
|
||||
currentlyKicking[0] = session;
|
||||
}
|
||||
}else{
|
||||
player.sendMessage("[scarlet]No player[orange]'" + args[0] + "'[scarlet] found.");
|
||||
@@ -320,6 +343,31 @@ public class NetServer implements ApplicationListener{
|
||||
}
|
||||
});
|
||||
|
||||
clientCommands.<Player>register("vote", "<y/n>", "Vote to kick the current player.", (arg, player) -> {
|
||||
if(currentlyKicking[0] == null){
|
||||
player.sendMessage("[scarlet]Nobody is being voted on.");
|
||||
}else{
|
||||
if(currentlyKicking[0].voted.contains(player.uuid) || currentlyKicking[0].voted.contains(admins.getInfo(player.uuid).lastIP)){
|
||||
player.sendMessage("[scarlet]You've already voted. Sit down.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(currentlyKicking[0].target == player){
|
||||
player.sendMessage("[scarlet]You can't vote on your own trial.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!arg[0].toLowerCase().equals("y") && !arg[0].toLowerCase().equals("n")){
|
||||
player.sendMessage("[scarlet]Vote either 'y' (yes) or 'n' (no).");
|
||||
return;
|
||||
}
|
||||
|
||||
int sign = arg[0].toLowerCase().equals("y") ? 1 : -1;
|
||||
currentlyKicking[0].vote(player, sign);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
clientCommands.<Player>register("sync", "Re-synchronize world state.", (args, player) -> {
|
||||
if(player.isLocal){
|
||||
player.sendMessage("[scarlet]Re-synchronizing as the host is pointless.");
|
||||
@@ -331,7 +379,7 @@ public class NetServer implements ApplicationListener{
|
||||
}
|
||||
|
||||
public int votesRequired(){
|
||||
return playerGroup.size() * 2 / 3;
|
||||
return 2 + (playerGroup.size() > 4 ? 1 : 0);
|
||||
}
|
||||
|
||||
public Team assignTeam(Player current, Iterable<Player> players){
|
||||
@@ -361,7 +409,7 @@ public class NetServer implements ApplicationListener{
|
||||
Log.debug("Packed {0} compressed bytes of world data.", stream.size());
|
||||
}
|
||||
|
||||
public static void onDisconnect(Player player){
|
||||
public static void onDisconnect(Player player, String reason){
|
||||
//singleplayer multiplayer wierdness
|
||||
if(player.con == null){
|
||||
player.remove();
|
||||
@@ -369,12 +417,13 @@ public class NetServer implements ApplicationListener{
|
||||
}
|
||||
|
||||
if(player.con.hasConnected){
|
||||
Events.fire(new PlayerLeave(player));
|
||||
Call.sendMessage("[accent]" + player.name + "[accent] has disconnected.");
|
||||
Call.onPlayerDisconnect(player.id);
|
||||
}
|
||||
player.remove();
|
||||
netServer.connections.remove(player.con.id);
|
||||
Log.info("&lm[{1}] &lc{0} has disconnected.", player.name, player.uuid);
|
||||
Log.info("&lm[{1}] &lc{0} has disconnected. &lg&fi({2})", player.name, player.uuid, reason);
|
||||
}
|
||||
|
||||
private static float compound(float speed, float drag){
|
||||
@@ -700,7 +749,7 @@ public class NetServer implements ApplicationListener{
|
||||
|
||||
if(connection == null || !connection.isConnected() || !connections.containsKey(connection.id)){
|
||||
//player disconnected, call d/c event
|
||||
onDisconnect(player);
|
||||
onDisconnect(player, "disappeared");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -360,6 +360,15 @@ public class UI implements ApplicationListener, Loadable{
|
||||
}}.show();
|
||||
}
|
||||
|
||||
public void showSmall(String titleText, String text){
|
||||
new Dialog(titleText, "dialog"){{
|
||||
cont.margin(10).add(text);
|
||||
titleTable.row();
|
||||
titleTable.addImage("whiteui").color(Pal.accent).height(3f).growX().pad(2f);
|
||||
buttons.addButton("$ok", this::hide).size(90, 50).pad(4);
|
||||
}}.show();
|
||||
}
|
||||
|
||||
public void showConfirm(String title, String text, Runnable confirmed){
|
||||
showConfirm(title, text, null, confirmed);
|
||||
}
|
||||
|
||||
@@ -186,7 +186,6 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
|
||||
clearChildren();
|
||||
margin(0);
|
||||
shown(this::build);
|
||||
|
||||
update(() -> {
|
||||
if(Core.scene.getKeyboardFocus() instanceof Dialog && Core.scene.getKeyboardFocus() != this){
|
||||
@@ -228,6 +227,8 @@ public class MapEditorDialog extends Dialog implements Disposable{
|
||||
platform.updateRPC();
|
||||
if(!Core.settings.getBool("landscape")) platform.endForceLandscape();
|
||||
});
|
||||
|
||||
shown(this::build);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import io.anuke.arc.math.geom.Position;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
public interface SpawnerTrait extends TargetTrait, Position{
|
||||
@@ -9,6 +9,8 @@ public interface SpawnerTrait extends TargetTrait, Position{
|
||||
|
||||
void updateSpawning(Player unit);
|
||||
|
||||
boolean hasUnit(Unit unit);
|
||||
|
||||
@Override
|
||||
default boolean isValid(){
|
||||
return getTile().entity instanceof SpawnerTrait;
|
||||
|
||||
@@ -58,7 +58,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
|
||||
//visual only.
|
||||
if(Net.client()){
|
||||
Tile tile = world.tile(unit.spawner);
|
||||
if(tile != null && !Net.client()){
|
||||
if(tile != null){
|
||||
tile.block().unitRemoved(tile, unit);
|
||||
}
|
||||
|
||||
|
||||
@@ -125,8 +125,8 @@ public abstract class FlyingUnit extends BaseUnit{
|
||||
|
||||
if(!Net.client()){
|
||||
updateRotation();
|
||||
wobble();
|
||||
}
|
||||
wobble();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,6 +23,7 @@ import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.input.*;
|
||||
import io.anuke.mindustry.input.InputHandler.PlaceDraw;
|
||||
import io.anuke.mindustry.io.TypeIO;
|
||||
import io.anuke.mindustry.net.Administration.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.NetConnection;
|
||||
import io.anuke.mindustry.type.*;
|
||||
@@ -37,6 +38,7 @@ import static io.anuke.mindustry.Vars.*;
|
||||
public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
public static final int timerSync = 2;
|
||||
public static final int timerAbility = 3;
|
||||
public static final int timerTransfer = 4;
|
||||
private static final int timerShootLeft = 0;
|
||||
private static final int timerShootRight = 1;
|
||||
private static final float liftoffBoost = 0.2f;
|
||||
@@ -59,7 +61,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
|
||||
public NetConnection con;
|
||||
public boolean isLocal = false;
|
||||
public Interval timer = new Interval(4);
|
||||
public Interval timer = new Interval(6);
|
||||
public TargetTrait target;
|
||||
public TargetTrait moveTarget;
|
||||
|
||||
@@ -800,6 +802,14 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerInfo getInfo(){
|
||||
if(uuid == null){
|
||||
throw new IllegalArgumentException("Local players cannot be traced and do not have info.");
|
||||
}else{
|
||||
return netServer.admins.getInfo(uuid);
|
||||
}
|
||||
}
|
||||
|
||||
/** Resets all values of the player. */
|
||||
public void reset(){
|
||||
resetNoAdd();
|
||||
@@ -909,7 +919,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
buffer.writeInt(Color.rgba8888(color));
|
||||
buffer.writeByte(mech.id);
|
||||
buffer.writeInt(mining == null ? noSpawner : mining.pos());
|
||||
buffer.writeInt(spawner == null ? noSpawner : spawner.getTile().pos());
|
||||
buffer.writeInt(spawner == null || !spawner.hasUnit(this) ? noSpawner : spawner.getTile().pos());
|
||||
buffer.writeShort((short)(baseRotation * 2));
|
||||
|
||||
writeBuilding(buffer);
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.anuke.mindustry.entities.traits.BuilderTrait;
|
||||
import io.anuke.mindustry.entities.type.Unit;
|
||||
import io.anuke.mindustry.type.Zone;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
|
||||
public class EventType{
|
||||
|
||||
@@ -184,5 +185,22 @@ public class EventType{
|
||||
public static class ResizeEvent{
|
||||
|
||||
}
|
||||
|
||||
public static class PlayerJoin{
|
||||
public final Player player;
|
||||
|
||||
public PlayerJoin(Player player){
|
||||
this.player = player;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlayerLeave{
|
||||
public final Player player;
|
||||
|
||||
public PlayerLeave(Player player){
|
||||
this.player = player;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,20 @@ public enum Gamemode{
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
public static Gamemode bestFit(Rules rules){
|
||||
if(rules.pvp){
|
||||
return pvp;
|
||||
}else if(rules.editor){
|
||||
return editor;
|
||||
}else if(rules.attackMode){
|
||||
return attack;
|
||||
}else if(rules.infiniteResources){
|
||||
return sandbox;
|
||||
}else{
|
||||
return survival;
|
||||
}
|
||||
}
|
||||
|
||||
/** Applies this preset to this ruleset. */
|
||||
public Rules apply(Rules in){
|
||||
rules.accept(in);
|
||||
|
||||
@@ -14,7 +14,7 @@ import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
/** Controls playback of multiple music tracks.*/
|
||||
public class MusicControl{
|
||||
private static final float finTime = 120f, foutTime = 120f, musicInterval = 60 * 60 * 3f, musicChance = 0.5f, musicWaveChance = 0.4f;
|
||||
private static final float finTime = 120f, foutTime = 120f, musicInterval = 60 * 60 * 3f, musicChance = 0.6f, musicWaveChance = 0.5f;
|
||||
|
||||
/** normal, ambient music, plays at any time */
|
||||
public final Array<Music> ambientMusic = Array.with(Musics.game1, Musics.game3, Musics.game4, Musics.game6);
|
||||
|
||||
@@ -266,6 +266,10 @@ public class Saves{
|
||||
return meta == null || meta.rules == null ? null : meta.rules.zone;
|
||||
}
|
||||
|
||||
public Gamemode mode(){
|
||||
return Gamemode.bestFit(meta.rules);
|
||||
}
|
||||
|
||||
public int getBuild(){
|
||||
return meta.build;
|
||||
}
|
||||
|
||||
@@ -115,9 +115,7 @@ public class Tutorial{
|
||||
outline("blockinfo");
|
||||
}
|
||||
},
|
||||
conveyor(
|
||||
line -> Strings.format(line, Math.min(placed(Blocks.conveyor), 2), 2),
|
||||
() -> placed(Blocks.conveyor, 2) && event("lineconfirm") && event("coreitem")){
|
||||
conveyor(() -> placed(Blocks.conveyor, 2) && event("lineconfirm") && event("coreitem")){
|
||||
void draw(){
|
||||
outline("category-distribution");
|
||||
outline("block-conveyor");
|
||||
@@ -190,13 +188,12 @@ public class Tutorial{
|
||||
|
||||
protected final String line = Core.bundle.has("tutorial." + name() + ".mobile") && mobile ? "tutorial." + name() + ".mobile" : "tutorial." + name();
|
||||
protected final Function<String, String> text;
|
||||
protected final Array<String> sentences;
|
||||
protected Array<String> sentences;
|
||||
protected final BooleanProvider done;
|
||||
|
||||
TutorialStage(Function<String, String> text, BooleanProvider done){
|
||||
this.text = text;
|
||||
this.done = done;
|
||||
this.sentences = Array.select(Core.bundle.get(line).split("\n"), s -> !s.isEmpty());
|
||||
}
|
||||
|
||||
TutorialStage(BooleanProvider done){
|
||||
@@ -205,6 +202,7 @@ public class Tutorial{
|
||||
|
||||
/** displayed tutorial stage text.*/
|
||||
public String text(){
|
||||
if(sentences == null) this.sentences = Array.select(Core.bundle.get(line).split("\n"), s -> !s.isEmpty());
|
||||
String line = sentences.get(control.tutorial.sentence);
|
||||
return line.contains("{") ? text.get(line) : line;
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ public abstract class InputHandler implements InputProcessor{
|
||||
|
||||
@Remote(targets = Loc.both, forward = true, called = Loc.server)
|
||||
public static void transferInventory(Player player, Tile tile){
|
||||
if(!player.timer.get(Player.timerTransfer, 40)) return;
|
||||
if(Net.server() && (player.item().amount <= 0 || player.isTransferring)){
|
||||
throw new ValidateException(player, "Player cannot transfer an item.");
|
||||
}
|
||||
@@ -288,7 +289,7 @@ public abstract class InputHandler implements InputProcessor{
|
||||
}
|
||||
|
||||
public void tryDropItems(Tile tile, float x, float y){
|
||||
if(!droppingItem || player.item().amount <= 0 || canTapPlayer(x, y) || state.isPaused()){
|
||||
if(!droppingItem || player.item().amount <= 0 || canTapPlayer(x, y) || state.isPaused() || !player.timer.check(Player.timerTransfer, 40)){
|
||||
droppingItem = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ public class Maps{
|
||||
FileHandle dest = findFile();
|
||||
file.copyTo(dest);
|
||||
|
||||
loadMap(dest, true);
|
||||
createNewPreview(loadMap(dest, true));
|
||||
}
|
||||
|
||||
/** Attempts to run the following code;
|
||||
@@ -356,7 +356,7 @@ public class Maps{
|
||||
//if it's here, then the preview failed to load or doesn't exist, make it
|
||||
//this has to be done synchronously!
|
||||
Pixmap pix = MapIO.generatePreview(map);
|
||||
Core.app.post(() -> map.texture = new Texture(pix));
|
||||
map.texture = new Texture(pix);
|
||||
executor.submit(() -> {
|
||||
try{
|
||||
map.previewFile().writePNG(pix);
|
||||
@@ -404,7 +404,7 @@ public class Maps{
|
||||
return customMapDirectory.child("map_" + i + "." + mapExtension);
|
||||
}
|
||||
|
||||
private void loadMap(FileHandle file, boolean custom) throws IOException{
|
||||
private Map loadMap(FileHandle file, boolean custom) throws IOException{
|
||||
Map map = MapIO.createMap(file, custom);
|
||||
|
||||
if(map.name() == null){
|
||||
@@ -413,6 +413,7 @@ public class Maps{
|
||||
|
||||
maps.add(map);
|
||||
maps.sort();
|
||||
return map;
|
||||
}
|
||||
|
||||
private void loadCustomMaps(){
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package io.anuke.mindustry.net;
|
||||
|
||||
import io.anuke.annotations.Annotations.Serialize;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.annotations.Annotations.*;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.headless;
|
||||
@@ -10,6 +10,7 @@ public class Administration{
|
||||
/** All player info. Maps UUIDs to info. This persists throughout restarts. */
|
||||
private ObjectMap<String, PlayerInfo> playerInfo = new ObjectMap<>();
|
||||
private Array<String> bannedIPs = new Array<>();
|
||||
private Array<String> whitelist = new Array<>();
|
||||
|
||||
public Administration(){
|
||||
Core.settings.defaults(
|
||||
@@ -20,9 +21,16 @@ public class Administration{
|
||||
load();
|
||||
}
|
||||
|
||||
public int getPlayerLimit(){
|
||||
return Core.settings.getInt("playerlimit", 0);
|
||||
}
|
||||
|
||||
public void setPlayerLimit(int limit){
|
||||
Core.settings.putSave("playerlimit", limit);
|
||||
}
|
||||
|
||||
public void setStrict(boolean on){
|
||||
Core.settings.put("strict", on);
|
||||
Core.settings.save();
|
||||
Core.settings.putSave("strict", on);
|
||||
}
|
||||
|
||||
public boolean getStrict(){
|
||||
@@ -186,6 +194,36 @@ public class Administration{
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isWhitelistEnabled(){
|
||||
return Core.settings.getBool("whitelist", false);
|
||||
}
|
||||
|
||||
public void setWhitelist(boolean enabled){
|
||||
Core.settings.putSave("whitelist", enabled);
|
||||
}
|
||||
|
||||
public boolean isWhitelisted(String id, String usid){
|
||||
return !isWhitelistEnabled() || whitelist.contains(usid + id);
|
||||
}
|
||||
|
||||
public boolean whitelist(String id){
|
||||
PlayerInfo info = getCreateInfo(id);
|
||||
if(whitelist.contains(info.adminUsid + id)) return false;
|
||||
whitelist.add(info.adminUsid + id);
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean unwhitelist(String id){
|
||||
PlayerInfo info = getCreateInfo(id);
|
||||
if(whitelist.contains(info.adminUsid + id)){
|
||||
whitelist.remove(info.adminUsid + id);
|
||||
save();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isIPBanned(String ip){
|
||||
return bannedIPs.contains(ip, false) || (findByIP(ip) != null && findByIP(ip).banned);
|
||||
}
|
||||
@@ -242,6 +280,10 @@ public class Administration{
|
||||
return null;
|
||||
}
|
||||
|
||||
public Array<PlayerInfo> getWhitelisted(){
|
||||
return playerInfo.values().toArray().select(p -> isWhitelisted(p.id, p.adminUsid));
|
||||
}
|
||||
|
||||
private PlayerInfo getCreateInfo(String id){
|
||||
if(playerInfo.containsKey(id)){
|
||||
return playerInfo.get(id);
|
||||
@@ -256,6 +298,7 @@ public class Administration{
|
||||
public void save(){
|
||||
Core.settings.putObject("player-info", playerInfo);
|
||||
Core.settings.putObject("banned-ips", bannedIPs);
|
||||
Core.settings.putObject("whitelisted", whitelist);
|
||||
Core.settings.save();
|
||||
}
|
||||
|
||||
@@ -263,6 +306,7 @@ public class Administration{
|
||||
private void load(){
|
||||
playerInfo = Core.settings.getObject("player-info", ObjectMap.class, ObjectMap::new);
|
||||
bannedIPs = Core.settings.getObject("banned-ips", Array.class, Array::new);
|
||||
whitelist = Core.settings.getObject("whitelisted", Array.class, Array::new);
|
||||
}
|
||||
|
||||
@Serialize
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
package io.anuke.mindustry.net;
|
||||
|
||||
import io.anuke.mindustry.game.*;
|
||||
|
||||
public class Host{
|
||||
public final String name;
|
||||
public final String address;
|
||||
public final String mapname;
|
||||
public final int wave;
|
||||
public final int players;
|
||||
public final int players, playerLimit;
|
||||
public final int version;
|
||||
public final String versionType;
|
||||
public final Gamemode mode;
|
||||
|
||||
public Host(String name, String address, String mapname, int wave, int players, int version, String versionType){
|
||||
public Host(String name, String address, String mapname, int wave, int players, int version, String versionType, Gamemode mode, int playerLimit){
|
||||
this.name = name;
|
||||
this.address = address;
|
||||
this.players = players;
|
||||
@@ -17,5 +20,7 @@ public class Host{
|
||||
this.wave = wave;
|
||||
this.version = version;
|
||||
this.versionType = versionType;
|
||||
this.playerLimit = playerLimit;
|
||||
this.mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
package io.anuke.mindustry.net;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.entities.Entities;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.io.JsonIO;
|
||||
import io.anuke.mindustry.io.SaveIO;
|
||||
import io.anuke.mindustry.io.*;
|
||||
import io.anuke.mindustry.maps.Map;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
@@ -71,8 +69,9 @@ public class NetworkIO{
|
||||
buffer.putInt(state.wave);
|
||||
buffer.putInt(Version.build);
|
||||
writeString(buffer, Version.type);
|
||||
//TODO additional information:
|
||||
// - gamemode ID/name (just pick the closest one?)
|
||||
|
||||
buffer.put((byte)Gamemode.bestFit(state.rules).ordinal());
|
||||
buffer.putInt(netServer.admins.getPlayerLimit());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -83,13 +82,15 @@ public class NetworkIO{
|
||||
int wave = buffer.getInt();
|
||||
int version = buffer.getInt();
|
||||
String vertype = readString(buffer);
|
||||
Gamemode gamemode = Gamemode.all[buffer.get()];
|
||||
int limit = buffer.getInt();
|
||||
|
||||
return new Host(host, hostAddress, map, wave, players, version, vertype);
|
||||
return new Host(host, hostAddress, map, wave, players, version, vertype, gamemode, limit);
|
||||
}
|
||||
|
||||
private static void writeString(ByteBuffer buffer, String string, int maxlen){
|
||||
byte[] bytes = string.getBytes(charset);
|
||||
//truncating this way may lead to wierd encoding errors at the ends of strings...
|
||||
//todo truncating this way may lead to wierd encoding errors at the ends of strings...
|
||||
if(bytes.length > maxlen){
|
||||
bytes = Arrays.copyOfRange(bytes, 0, maxlen);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ public class Packets{
|
||||
|
||||
public enum KickReason{
|
||||
kick, clientOutdated, serverOutdated, banned, gameover(true), recentKick,
|
||||
nameInUse, idInUse, nameEmpty, customClient, serverClose, vote, typeMismatch;
|
||||
nameInUse, idInUse, nameEmpty, customClient, serverClose, vote, typeMismatch, whitelist, playerLimit;
|
||||
|
||||
public final boolean quiet;
|
||||
|
||||
@@ -52,6 +52,7 @@ public class Packets{
|
||||
|
||||
public static class Disconnect implements Packet{
|
||||
public int id;
|
||||
public String reason;
|
||||
|
||||
@Override
|
||||
public boolean isImportant(){
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
package io.anuke.mindustry.plugin;
|
||||
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.files.*;
|
||||
import io.anuke.arc.function.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.io.*;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.net.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.pluginDirectory;
|
||||
@@ -50,12 +49,9 @@ public class Plugins{
|
||||
|
||||
PluginMeta meta = JsonIO.read(PluginMeta.class, metaf.readString());
|
||||
|
||||
URLClassLoader classLoader = (URLClassLoader)ClassLoader.getSystemClassLoader();
|
||||
Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
|
||||
method.setAccessible(true);
|
||||
method.invoke(classLoader, jar.file().toURI().toURL());
|
||||
|
||||
Class<?> main = Class.forName(meta.main);
|
||||
URLClassLoader classLoader = new URLClassLoader(new URL[]{jar.file().toURI().toURL()}, ClassLoader.getSystemClassLoader());
|
||||
Class<?> main = classLoader.loadClass(meta.main);
|
||||
return new LoadedPlugin(jar, zip, (Plugin)main.newInstance(), meta);
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ public class Zone extends UnlockableContent{
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
preview = Core.atlas.find(name);
|
||||
preview = Core.atlas.find("zone-" + name);
|
||||
}
|
||||
|
||||
public Rules getRules(){
|
||||
|
||||
@@ -13,11 +13,15 @@ public class ItemDisplay extends Table{
|
||||
this(item, 0);
|
||||
}
|
||||
|
||||
public ItemDisplay(Item item, int amount){
|
||||
add(new ItemImage(new ItemStack(item, amount))).size(8 * 4);
|
||||
add(item.localizedName()).padLeft(4);
|
||||
public ItemDisplay(Item item, int amount, boolean showName){
|
||||
add(new ItemImage(new ItemStack(item, amount))).size(8 * 4).padRight(amount > 99 ? 12 : 0);
|
||||
if(showName) add(item.localizedName()).padLeft(4 + amount > 99 ? 4 : 0);
|
||||
|
||||
this.item = item;
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public ItemDisplay(Item item, int amount){
|
||||
this(item, amount, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public class LiquidDisplay extends Table{
|
||||
t.add(Strings.autoFixed(amount, 1));
|
||||
add(t);
|
||||
}
|
||||
}}).size(8 * 4).padRight(3);
|
||||
}}).size(8 * 4).padRight(3 + (amount != 0 && Strings.autoFixed(amount, 1).length() > 2 ? 8 : 0));
|
||||
|
||||
if(perSecond){
|
||||
add(StatUnit.perSecond.localized()).padLeft(2).padRight(5).color(Color.LIGHT_GRAY);
|
||||
|
||||
@@ -182,10 +182,10 @@ public class JoinDialog extends FloatingDialog{
|
||||
void setupServer(Server server, Host host){
|
||||
server.lastHost = host;
|
||||
server.content.clear();
|
||||
server.content.table(t -> setupHostTable(t, host)).expand().left().bottom().padLeft(12f).padBottom(8);
|
||||
buildServer(host, server.content);
|
||||
}
|
||||
|
||||
void setupHostTable(Table content, Host host){
|
||||
void buildServer(Host host, Table content){
|
||||
String versionString;
|
||||
|
||||
if(host.version == -1){
|
||||
@@ -202,12 +202,14 @@ public class JoinDialog extends FloatingDialog{
|
||||
versionString = Core.bundle.format("server.version", host.version, host.versionType);
|
||||
}
|
||||
|
||||
content.add("[lightgray]" + host.name + " " + versionString).width(targetWidth() - 10f).left().get().setEllipsis(true);
|
||||
content.row();
|
||||
content.add("[lightgray]" + (host.players != 1 ? Core.bundle.format("players", host.players == 0 ? host.players : "[accent]" + host.players + "[lightgray]") : Core.bundle.format("players.single", "[accent]" + host.players + "[lightgray]"))).left();
|
||||
content.row();
|
||||
content.add("[lightgray]" + Core.bundle.format("save.map", host.mapname) + "[lightgray] / " + Core.bundle.format("save.wave", host.wave)).width(targetWidth() - 10f).left().get().setEllipsis(true);
|
||||
|
||||
content.table(t -> {
|
||||
t.add("[lightgray]" + host.name + " " + versionString).width(targetWidth() - 10f).left().get().setEllipsis(true);
|
||||
t.row();
|
||||
t.add("[lightgray]" + (Core.bundle.format("players" + (host.players == 1 ? ".single" : ""), (host.players == 0 ? "[lightgray]" : "[accent]") + host.players + (host.playerLimit > 0 ? "[lightgray]/[accent]" + host.playerLimit : "")+ "[lightgray]"))).left();
|
||||
t.row();
|
||||
t.add("[lightgray]" + Core.bundle.format("save.map", host.mapname) + "[lightgray] / " + host.mode.toString()).width(targetWidth() - 10f).left().get().setEllipsis(true);
|
||||
}).expand().left().bottom().padLeft(12f).padBottom(8);
|
||||
}
|
||||
|
||||
void setup(){
|
||||
@@ -275,6 +277,9 @@ public class JoinDialog extends FloatingDialog{
|
||||
local.background((Drawable)null);
|
||||
local.table("button", t -> t.label(() -> "[accent]" + Core.bundle.get("hosts.discovering.any") + Strings.animated(Time.time(), 4, 10f, ".")).pad(10f)).growX();
|
||||
Net.discoverServers(this::addLocalHost, this::finishLocalHosts);
|
||||
for(String host : defaultServers){
|
||||
Net.pingHost(host, port, this::addLocalHost, e -> {});
|
||||
}
|
||||
}
|
||||
|
||||
void finishLocalHosts(){
|
||||
@@ -299,11 +304,10 @@ public class JoinDialog extends FloatingDialog{
|
||||
|
||||
local.row();
|
||||
|
||||
local.addButton(b -> {
|
||||
b.margin(5f);
|
||||
b.left();
|
||||
setupHostTable(b, host);
|
||||
}, "clear", () -> connect(host.address, port)).width(w).pad(4f).get();
|
||||
TextButton button = local.addButton("", "clear", () -> connect(host.address, port))
|
||||
.width(w).pad(5f).get();
|
||||
button.clearChildren();
|
||||
buildServer(host, button);
|
||||
}
|
||||
|
||||
void connect(String ip, int port){
|
||||
|
||||
@@ -137,13 +137,13 @@ public class LoadDialog extends FloatingDialog{
|
||||
meta.row();
|
||||
meta.labelWrap(Core.bundle.format("save.map", color + (slot.getMap() == null ? Core.bundle.get("unknown") : slot.getMap().name())));
|
||||
meta.row();
|
||||
meta.labelWrap(Core.bundle.format("save.wave", color + slot.getWave()));
|
||||
meta.labelWrap(slot.mode().toString() + " /" + color + " " + Core.bundle.format("save.wave", color + slot.getWave()));
|
||||
meta.row();
|
||||
meta.labelWrap(() -> Core.bundle.format("save.autosave", color + Core.bundle.get(slot.isAutosave() ? "on" : "off")));
|
||||
meta.row();
|
||||
meta.labelWrap(() -> Core.bundle.format("save.playtime", color + slot.getPlayTime()));
|
||||
meta.row();
|
||||
meta.labelWrap(Core.bundle.format("save.date", color + slot.getDate()));
|
||||
meta.labelWrap(color + slot.getDate());
|
||||
meta.row();
|
||||
}).left().growX().width(250f);
|
||||
|
||||
|
||||
@@ -62,49 +62,52 @@ public class MapsDialog extends FloatingDialog{
|
||||
if(!ios){
|
||||
buttons.addImageTextButton("$editor.importmap", "icon-load", iconsize, () -> {
|
||||
platform.showFileChooser("$editor.importmap", "Map File", file -> {
|
||||
maps.tryCatchMapError(() -> {
|
||||
if(MapIO.isImage(file)){
|
||||
ui.showError("$editor.errorimage");
|
||||
return;
|
||||
}
|
||||
ui.loadAnd(() -> {
|
||||
maps.tryCatchMapError(() -> {
|
||||
if(MapIO.isImage(file)){
|
||||
ui.showError("$editor.errorimage");
|
||||
return;
|
||||
}
|
||||
|
||||
Map map;
|
||||
if(file.extension().equalsIgnoreCase(mapExtension)){
|
||||
map = MapIO.createMap(file, true);
|
||||
}else{
|
||||
map = maps.makeLegacyMap(file);
|
||||
}
|
||||
Map map;
|
||||
if(file.extension().equalsIgnoreCase(mapExtension)){
|
||||
map = MapIO.createMap(file, true);
|
||||
}else{
|
||||
map = maps.makeLegacyMap(file);
|
||||
}
|
||||
|
||||
//when you attempt to import a save, it will have no name, so generate one
|
||||
String name = map.tags.getOr("name", () -> {
|
||||
String result = "unknown";
|
||||
int number = 0;
|
||||
while(maps.byName(result + number++) != null) ;
|
||||
return result + number;
|
||||
});
|
||||
|
||||
//this will never actually get called, but it remains just in case
|
||||
if(name == null){
|
||||
ui.showError("$editor.errorname");
|
||||
return;
|
||||
}
|
||||
|
||||
Map conflict = maps.all().find(m -> m.name().equals(name));
|
||||
|
||||
if(conflict != null && !conflict.custom){
|
||||
ui.showInfo(Core.bundle.format("editor.import.exists", name));
|
||||
}else if(conflict != null){
|
||||
ui.showConfirm("$confirm", "$editor.overwrite.confirm", () -> {
|
||||
maps.tryCatchMapError(() -> {
|
||||
maps.importMap(file);
|
||||
setup();
|
||||
});
|
||||
//when you attempt to import a save, it will have no name, so generate one
|
||||
String name = map.tags.getOr("name", () -> {
|
||||
String result = "unknown";
|
||||
int number = 0;
|
||||
while(maps.byName(result + number++) != null);
|
||||
return result + number;
|
||||
});
|
||||
}else{
|
||||
maps.importMap(map.file);
|
||||
setup();
|
||||
}
|
||||
|
||||
//this will never actually get called, but it remains just in case
|
||||
if(name == null){
|
||||
ui.showError("$editor.errorname");
|
||||
return;
|
||||
}
|
||||
|
||||
Map conflict = maps.all().find(m -> m.name().equals(name));
|
||||
|
||||
if(conflict != null && !conflict.custom){
|
||||
ui.showInfo(Core.bundle.format("editor.import.exists", name));
|
||||
}else if(conflict != null){
|
||||
ui.showConfirm("$confirm", "$editor.overwrite.confirm", () -> {
|
||||
maps.tryCatchMapError(() -> {
|
||||
maps.removeMap(conflict);
|
||||
maps.importMap(map.file);
|
||||
setup();
|
||||
});
|
||||
});
|
||||
}else{
|
||||
maps.importMap(map.file);
|
||||
setup();
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}, true, FileChooser.anyMapFiles);
|
||||
}).size(210f, 64f);
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.input.*;
|
||||
import io.anuke.arc.scene.event.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.renderer;
|
||||
|
||||
@@ -40,7 +41,7 @@ public class MinimapDialog extends FloatingDialog{
|
||||
renderer.minimap.drawEntities(x, y, width, height);
|
||||
}
|
||||
}).grow();
|
||||
}).size(Math.min(Core.graphics.getWidth() / 1.1f, Core.graphics.getHeight() / 1.3f)).padTop(-20f);
|
||||
}).size(Math.min(Core.graphics.getWidth() / 1.1f, Core.graphics.getHeight() / 1.3f) / UnitScl.dp.scl(1f)).padTop(-20f);
|
||||
|
||||
cont.addListener(new InputListener(){
|
||||
@Override
|
||||
|
||||
@@ -139,7 +139,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
t.row();
|
||||
|
||||
//iOS doesn't have a file chooser.
|
||||
if(!ios){
|
||||
//if(!ios){
|
||||
t.addButton("$data.import", style, () -> ui.showConfirm("$confirm", "$data.import.confirm", () -> platform.showFileChooser("$data.import", "Zip Files", file -> {
|
||||
try{
|
||||
data.importData(file);
|
||||
@@ -151,7 +151,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
ui.showError(Strings.parseException(e, true));
|
||||
}
|
||||
}, true, f -> f.equalsIgnoreCase("zip"))));
|
||||
}
|
||||
//}
|
||||
});
|
||||
|
||||
ScrollPane pane = new ScrollPane(prefs);
|
||||
|
||||
@@ -40,7 +40,7 @@ public class BlockInventoryFragment extends Fragment{
|
||||
|
||||
@Remote(called = Loc.server, targets = Loc.both, forward = true)
|
||||
public static void requestItem(Player player, Tile tile, Item item, int amount){
|
||||
if(player == null || tile == null) return;
|
||||
if(player == null || tile == null || !player.timer.get(Player.timerTransfer, 20)) return;
|
||||
|
||||
int removed = tile.block().removeStack(tile, item, amount);
|
||||
|
||||
@@ -71,6 +71,8 @@ public class BlockInventoryFragment extends Fragment{
|
||||
}
|
||||
|
||||
public void hide(){
|
||||
if(table == null) return;
|
||||
|
||||
table.actions(Actions.scaleTo(0f, 1f, 0.06f, Interpolation.pow3Out), Actions.run(() -> {
|
||||
table.clearChildren();
|
||||
table.clearListeners();
|
||||
|
||||
@@ -19,7 +19,6 @@ import io.anuke.arc.util.pooling.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.bullet.*;
|
||||
import io.anuke.mindustry.entities.effect.*;
|
||||
import io.anuke.mindustry.entities.type.Unit;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
@@ -32,6 +31,7 @@ import io.anuke.mindustry.world.blocks.*;
|
||||
import io.anuke.mindustry.world.blocks.power.*;
|
||||
import io.anuke.mindustry.world.consumers.*;
|
||||
import io.anuke.mindustry.world.meta.*;
|
||||
import io.anuke.mindustry.world.meta.values.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -251,7 +251,7 @@ public class Block extends BlockStorage{
|
||||
public void drawPlace(int x, int y, int rotation, boolean valid){
|
||||
}
|
||||
|
||||
protected float drawPlaceText(String text, int x, int y, boolean valid){
|
||||
public float drawPlaceText(String text, int x, int y, boolean valid){
|
||||
if(renderer.pixelator.enabled()) return 0;
|
||||
|
||||
Color color = valid ? Pal.accent : Pal.remove;
|
||||
@@ -476,7 +476,10 @@ public class Block extends BlockStorage{
|
||||
public void setStats(){
|
||||
stats.add(BlockStat.size, "{0}x{0}", size);
|
||||
stats.add(BlockStat.health, health, StatUnit.none);
|
||||
stats.add(BlockStat.buildTime, buildCost / 60, StatUnit.seconds);
|
||||
if(isBuildable()){
|
||||
stats.add(BlockStat.buildTime, buildCost / 60, StatUnit.seconds);
|
||||
stats.add(BlockStat.buildCost, new ItemListValue(false, buildRequirements));
|
||||
}
|
||||
|
||||
consumes.display(stats);
|
||||
|
||||
@@ -581,7 +584,7 @@ public class Block extends BlockStorage{
|
||||
});
|
||||
}
|
||||
|
||||
Damage.dynamicExplosion(x, y, flammability, explosiveness, power, tilesize * size / 2f, Pal.darkFlame);
|
||||
Damage.dynamicExplosion(x, y, flammability, explosiveness * 3.5f, power, tilesize * size / 2f, Pal.darkFlame);
|
||||
if(!tile.floor().solid && !tile.floor().isLiquid){
|
||||
RubbleDecal.create(tile.drawx(), tile.drawy(), size);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,6 @@ public abstract class BlockStorage extends UnlockableContent{
|
||||
|
||||
public int itemCapacity = 10;
|
||||
public float liquidCapacity = 10f;
|
||||
public float liquidFlowFactor = 4.9f;
|
||||
|
||||
public final BlockStats stats = new BlockStats();
|
||||
public final BlockBars bars = new BlockBars();
|
||||
|
||||
71
core/src/io/anuke/mindustry/world/blocks/RespawnBlock.java
Normal file
71
core/src/io/anuke/mindustry/world/blocks/RespawnBlock.java
Normal file
@@ -0,0 +1,71 @@
|
||||
package io.anuke.mindustry.world.blocks;
|
||||
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
public class RespawnBlock{
|
||||
|
||||
public static void drawRespawn(Tile tile, float heat, float progress, float time, Player player, Mech to){
|
||||
progress = Mathf.clamp(progress);
|
||||
|
||||
Draw.color(Pal.darkMetal);
|
||||
Lines.stroke(2f * heat);
|
||||
Fill.poly(tile.drawx(), tile.drawy(), 4, 10f * heat);
|
||||
|
||||
Draw.reset();
|
||||
if(player != null){
|
||||
TextureRegion region = to.iconRegion;
|
||||
|
||||
Draw.color(0f, 0f, 0f, 0.4f * progress);
|
||||
Draw.rect("circle-shadow", tile.drawx(), tile.drawy(), region.getWidth() / 3f, region.getWidth() / 3f);
|
||||
Draw.color();
|
||||
|
||||
Shaders.build.region = region;
|
||||
Shaders.build.progress = progress;
|
||||
Shaders.build.color.set(Pal.accent);
|
||||
Shaders.build.time = -time / 10f;
|
||||
|
||||
Draw.shader(Shaders.build, true);
|
||||
Draw.rect(region, tile.drawx(), tile.drawy());
|
||||
Draw.shader();
|
||||
|
||||
Draw.color(Pal.accentBack);
|
||||
|
||||
float pos = Mathf.sin(time, 6f, 8f);
|
||||
|
||||
Lines.lineAngleCenter(tile.drawx() + pos, tile.drawy(), 90, 16f - Math.abs(pos) * 2f);
|
||||
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
Lines.stroke(2f * heat);
|
||||
|
||||
Draw.color(Pal.accentBack);
|
||||
Lines.poly(tile.drawx(), tile.drawy(), 4, 8f * heat);
|
||||
|
||||
float oy = -7f, len = 6f * heat;
|
||||
Lines.stroke(5f);
|
||||
Draw.color(Pal.darkMetal);
|
||||
Lines.line(tile.drawx() - len, tile.drawy() + oy, tile.drawx() + len, tile.drawy() + oy, CapStyle.none);
|
||||
for(int i : Mathf.signs){
|
||||
Fill.tri(tile.drawx() + len * i, tile.drawy() + oy - Lines.getStroke()/2f, tile.drawx() + len * i, tile.drawy() + oy + Lines.getStroke()/2f, tile.drawx() + (len + Lines.getStroke() * heat) * i, tile.drawy() + oy);
|
||||
}
|
||||
|
||||
Lines.stroke(3f);
|
||||
Draw.color(Pal.accent);
|
||||
Lines.line(tile.drawx() - len, tile.drawy() + oy, tile.drawx() - len + len*2 * progress, tile.drawy() + oy, CapStyle.none);
|
||||
for(int i : Mathf.signs){
|
||||
Fill.tri(tile.drawx() + len * i, tile.drawy() + oy - Lines.getStroke()/2f, tile.drawx() + len * i, tile.drawy() + oy + Lines.getStroke()/2f, tile.drawx() + (len + Lines.getStroke() * heat) * i, tile.drawy() + oy);
|
||||
}
|
||||
Draw.reset();
|
||||
|
||||
if(Net.active() && player != null){
|
||||
tile.block().drawPlaceText(player.name, tile.x, tile.y - (Math.max((tile.block().size-1)/2, 0)), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ public class CooledTurret extends Turret{
|
||||
TurretEntity entity = tile.entity();
|
||||
Liquid liquid = entity.liquids.current();
|
||||
|
||||
float used = Math.min(Math.min(entity.liquids.get(liquid), maxUsed * Time.delta()), Math.max(0, ((reload - entity.reload) / coolantMultiplier) / liquid.heatCapacity));
|
||||
float used = Math.min(Math.min(entity.liquids.get(liquid), maxUsed * Time.delta()), Math.max(0, ((reload - entity.reload) / coolantMultiplier) / liquid.heatCapacity)) * baseReloadSpeed(tile);
|
||||
entity.reload += (used * liquid.heatCapacity) / liquid.heatCapacity;
|
||||
entity.liquids.remove(liquid, used);
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ public abstract class Turret extends Block{
|
||||
protected void turnToTarget(Tile tile, float targetRot){
|
||||
TurretEntity entity = tile.entity();
|
||||
|
||||
entity.rotation = Angles.moveToward(entity.rotation, targetRot, rotatespeed * entity.delta());
|
||||
entity.rotation = Angles.moveToward(entity.rotation, targetRot, rotatespeed * entity.delta() * baseReloadSpeed(tile));
|
||||
}
|
||||
|
||||
public boolean shouldTurn(Tile tile){
|
||||
|
||||
@@ -37,7 +37,7 @@ public class ItemLiquidGenerator extends PowerGenerator{
|
||||
protected Effects.Effect explodeEffect = Fx.generatespark;
|
||||
protected Color heatColor = Color.valueOf("ff9b59");
|
||||
protected TextureRegion topRegion, liquidRegion;
|
||||
protected boolean randomlyExplode = false;
|
||||
protected boolean randomlyExplode = true;
|
||||
|
||||
public ItemLiquidGenerator(boolean hasItems, boolean hasLiquids, String name){
|
||||
super(name);
|
||||
@@ -127,8 +127,10 @@ public class ItemLiquidGenerator extends PowerGenerator{
|
||||
|
||||
if(randomlyExplode && Mathf.chance(entity.delta() * 0.06 * Mathf.clamp(entity.explosiveness - 0.5f))){
|
||||
//this block is run last so that in the event of a block destruction, no code relies on the block type
|
||||
entity.damage(Mathf.random(11f));
|
||||
Effects.effect(explodeEffect, tile.worldx() + Mathf.range(size * tilesize / 2f), tile.worldy() + Mathf.range(size * tilesize / 2f));
|
||||
Core.app.post(() -> {
|
||||
entity.damage(Mathf.random(11f));
|
||||
Effects.effect(explodeEffect, tile.worldx() + Mathf.range(size * tilesize / 2f), tile.worldy() + Mathf.range(size * tilesize / 2f));
|
||||
});
|
||||
}
|
||||
}else{
|
||||
entity.productionEfficiency = 0.0f;
|
||||
|
||||
@@ -22,7 +22,6 @@ public class Pump extends LiquidBlock{
|
||||
public Pump(String name){
|
||||
super(name);
|
||||
layer = Layer.overlay;
|
||||
liquidFlowFactor = 3f;
|
||||
group = BlockGroup.liquids;
|
||||
floating = true;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,7 @@ package io.anuke.mindustry.world.blocks.storage;
|
||||
import io.anuke.annotations.Annotations.*;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
@@ -16,6 +14,7 @@ import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
import io.anuke.mindustry.world.meta.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@@ -32,6 +31,7 @@ public class CoreBlock extends StorageBlock{
|
||||
flags = EnumSet.of(BlockFlag.target, BlockFlag.producer);
|
||||
activeSound = Sounds.respawning;
|
||||
activeSoundVolume = 1f;
|
||||
layer = Layer.overlay;
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server)
|
||||
@@ -84,41 +84,11 @@ public class CoreBlock extends StorageBlock{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Tile tile){
|
||||
public void drawLayer(Tile tile){
|
||||
CoreEntity entity = tile.entity();
|
||||
|
||||
Draw.rect(region, tile.drawx(), tile.drawy());
|
||||
|
||||
if(entity.heat > 0){
|
||||
Draw.color(Pal.darkMetal);
|
||||
Lines.stroke(2f * entity.heat);
|
||||
Lines.poly(tile.drawx(), tile.drawy(), 4, 8f * entity.heat);
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
if(entity.spawnPlayer != null){
|
||||
Unit player = entity.spawnPlayer;
|
||||
|
||||
TextureRegion region = player.getIconRegion();
|
||||
|
||||
Shaders.build.region = region;
|
||||
Shaders.build.progress = entity.progress;
|
||||
Shaders.build.color.set(Pal.accent);
|
||||
Shaders.build.time = -entity.time / 10f;
|
||||
|
||||
Draw.shader(Shaders.build, true);
|
||||
Draw.rect(region, tile.drawx(), tile.drawy());
|
||||
Draw.shader();
|
||||
|
||||
Draw.color(Pal.accent);
|
||||
|
||||
Lines.lineAngleCenter(
|
||||
tile.drawx() + Mathf.sin(entity.time, 6f, Vars.tilesize / 3f * size),
|
||||
tile.drawy(),
|
||||
90,
|
||||
size * Vars.tilesize / 2f);
|
||||
|
||||
Draw.reset();
|
||||
if(entity.heat > 0.001f){
|
||||
RespawnBlock.drawRespawn(tile, entity.heat, entity.progress, entity.time, entity.spawnPlayer, mech);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,6 +143,11 @@ public class CoreBlock extends StorageBlock{
|
||||
float time;
|
||||
float heat;
|
||||
|
||||
@Override
|
||||
public boolean hasUnit(Unit unit){
|
||||
return unit == spawnPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSpawning(Player player){
|
||||
if(!netServer.isWaitingForPlayers() && spawnPlayer == null){
|
||||
|
||||
@@ -1,32 +1,24 @@
|
||||
package io.anuke.mindustry.world.blocks.units;
|
||||
|
||||
import io.anuke.annotations.Annotations.Loc;
|
||||
import io.anuke.annotations.Annotations.Remote;
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.annotations.Annotations.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Geometry;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.content.Mechs;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.traits.SpawnerTrait;
|
||||
import io.anuke.mindustry.entities.type.Player;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.gen.Call;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.graphics.Shaders;
|
||||
import io.anuke.mindustry.type.Mech;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.meta.BlockStat;
|
||||
import io.anuke.mindustry.world.meta.StatUnit;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.math.geom.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
import io.anuke.mindustry.world.meta.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.mobile;
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class MechPad extends Block{
|
||||
protected Mech mech;
|
||||
@@ -37,6 +29,7 @@ public class MechPad extends Block{
|
||||
update = true;
|
||||
solid = false;
|
||||
hasPower = true;
|
||||
layer = Layer.overlay;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -110,32 +103,11 @@ public class MechPad extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Tile tile){
|
||||
public void drawLayer(Tile tile){
|
||||
MechFactoryEntity entity = tile.entity();
|
||||
|
||||
Draw.rect(Core.atlas.find(name), tile.drawx(), tile.drawy());
|
||||
|
||||
if(entity.player != null){
|
||||
TextureRegion region = (!entity.sameMech && entity.player.mech == mech ? Mechs.starter.iconRegion : mech.iconRegion);
|
||||
|
||||
Shaders.build.region = region;
|
||||
Shaders.build.progress = entity.progress;
|
||||
Shaders.build.time = -entity.time / 5f;
|
||||
Shaders.build.color.set(Pal.accent);
|
||||
|
||||
Draw.shader(Shaders.build);
|
||||
Draw.rect(region, tile.drawx(), tile.drawy());
|
||||
Draw.shader();
|
||||
|
||||
Draw.color(Pal.accent);
|
||||
|
||||
Lines.lineAngleCenter(
|
||||
tile.drawx() + Mathf.sin(entity.time, 6f, Vars.tilesize / 3f * size),
|
||||
tile.drawy(),
|
||||
90,
|
||||
size * Vars.tilesize / 2f + 1f);
|
||||
|
||||
Draw.reset();
|
||||
RespawnBlock.drawRespawn(tile, entity.heat, entity.progress, entity.time, entity.player, (!entity.sameMech && entity.player.mech == mech ? Mechs.starter : mech));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,6 +142,11 @@ public class MechPad extends Block{
|
||||
float time;
|
||||
float heat;
|
||||
|
||||
@Override
|
||||
public boolean hasUnit(Unit unit){
|
||||
return unit == player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateSpawning(Player unit){
|
||||
if(player == null){
|
||||
|
||||
@@ -9,6 +9,7 @@ public enum BlockStat{
|
||||
health(StatCategory.general),
|
||||
size(StatCategory.general),
|
||||
buildTime(StatCategory.general),
|
||||
buildCost(StatCategory.general),
|
||||
|
||||
itemCapacity(StatCategory.items),
|
||||
itemsMoved(StatCategory.items),
|
||||
|
||||
@@ -7,15 +7,21 @@ import io.anuke.mindustry.world.meta.StatValue;
|
||||
|
||||
public class ItemListValue implements StatValue{
|
||||
private final ItemStack[] stacks;
|
||||
private final boolean displayName;
|
||||
|
||||
public ItemListValue(ItemStack... stacks){
|
||||
this(true, stacks);
|
||||
}
|
||||
|
||||
public ItemListValue(boolean displayName, ItemStack... stacks){
|
||||
this.stacks = stacks;
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void display(Table table){
|
||||
for(ItemStack stack : stacks){
|
||||
table.add(new ItemDisplay(stack.item, stack.amount)).padRight(5);
|
||||
table.add(new ItemDisplay(stack.item, stack.amount, displayName)).padRight(5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user