1
0
mirror of https://github.com/Anuken/Mindustry.git synced 2024-11-13 07:15:28 +03:00

Major refactoring of building, sound, inventory

This commit is contained in:
Anuken 2018-05-20 17:59:52 -04:00
parent de40df7f7b
commit c1a5482ad2
40 changed files with 348 additions and 991 deletions

View File

@ -4,6 +4,7 @@ import com.squareup.javapoet.*;
import io.anuke.annotations.Annotations.Local;
import io.anuke.annotations.Annotations.RemoteClient;
import io.anuke.annotations.Annotations.RemoteServer;
import io.anuke.annotations.Annotations.Unreliable;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
@ -22,7 +23,8 @@ import java.util.Set;
@SupportedAnnotationTypes({
"io.anuke.annotations.Annotations.RemoteClient",
"io.anuke.annotations.Annotations.RemoteServer",
"io.anuke.annotations.Annotations.Local"
"io.anuke.annotations.Annotations.Local",
"io.anuke.annotations.Annotations.Unreliable"
})
public class AnnotationProcessor extends AbstractProcessor {
private static final int maxPacketSize = 128;
@ -39,6 +41,19 @@ public class AnnotationProcessor extends AbstractProcessor {
"rtype rvalue = io.anuke.mindustry.Vars.playerGroup.getByID(rbuffer.getInt())"
}
});
put("String", new String[][]{
{
"rbuffer.putShort((short)rvalue.getBytes().length)",
"rbuffer.put(rvalue.getBytes())"
},
{
"short __rvalue_length = rbuffer.getShort()",
"byte[] __rvalue_bytes = new byte[__rvalue_length]",
"rbuffer.get(__rvalue_bytes)",
"rtype rvalue = new rtype(__rvalue_bytes)"
}
});
}};
private Types typeUtils;
@ -109,6 +124,7 @@ public class AnnotationProcessor extends AbstractProcessor {
if(e.getAnnotation(annotation) == null) continue;
boolean local = e.getAnnotation(Local.class) != null;
boolean unreliable = e.getAnnotation(Unreliable.class) != null;
ExecutableElement exec = (ExecutableElement)e;
@ -211,7 +227,8 @@ public class AnnotationProcessor extends AbstractProcessor {
}
}
method.addStatement("packet.writeLength = TEMP_BUFFER.position()");
method.addStatement("io.anuke.mindustry.net.Net.send(packet, io.anuke.mindustry.net.Net.SendMode.tcp)");
method.addStatement("io.anuke.mindustry.net.Net.send(packet, "+
(unreliable ? "io.anuke.mindustry.net.Net.SendMode.udp" : "io.anuke.mindustry.net.Net.SendMode.tcp")+")");
classBuilder.addMethod(method.build());

View File

@ -14,7 +14,8 @@ import java.lang.annotation.Target;
* {@link RemoteServer}: Marks a method as able to be invoked remotely on a server from a client.<br>
* {@link Local}: Makes this method get invoked locally as well as remotely.<br>
*<br>
* All RemoteClient methods are put in the class CallClient, and all RemoteServer methods are put in the class CallServer.<br>
* All RemoteClient methods are put in the class io.anuke.mindustry.gen.CallClient.<br>
* All RemoteServer methods are put in the class io.anuke.mindustry.gen.CallServer.<br>
*/
public class Annotations {
@ -35,4 +36,10 @@ public class Annotations {
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface Local{}
/**Marks a method to be invoked unreliably, e.g. with UDP instead of TCP.
* This is faster, but is prone to packet loss and duplication.*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface Unreliable{}
}

View File

@ -46,13 +46,11 @@ public class PowerBlocks {
nuclearReactor = new NuclearReactor("nuclearreactor") {{
size = 3;
health = 600;
breaktime *= 2.3f;
}},
fusionReactor = new FusionReactor("fusionreactor") {{
size = 4;
health = 600;
breaktime *= 4f;
}},
repairturret = new RepairTurret("repairturret") {{

View File

@ -60,7 +60,7 @@ public class ContentLoader {
Log.info("--- CONTENT INFO ---");
Log.info("Blocks loaded: {0}\nItems loaded: {1}\nLiquids loaded: {2}\nUpgrades loaded: {3}\nUnits loaded: {4}\nAmmo types loaded: {5}\nStatus effects loaded: {6}\nRecipes loaded: {7}\nTotal content classes: {8}",
Block.getAllBlocks().size, Item.getAllItems().size, Liquid.getAllLiquids().size,
Mech.getAllUpgrades().size, UnitType.getAllTypes().size, AmmoType.getAllTypes().size, StatusEffect.getAllEffects().size, Recipe.all().size, content.length);
Mech.getAllUpgrades().size, UnitType.getAllTypes().size, AmmoType.getAllTypes().size, StatusEffect.getAllEffects().size, Recipe.getAllRecipes().size, content.length);
Log.info("-------------------");
}

View File

@ -2,7 +2,10 @@ package io.anuke.mindustry.core;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.TimeUtils;
import io.anuke.mindustry.content.Mechs;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.Player;
@ -20,7 +23,7 @@ import io.anuke.ucore.core.*;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.input.InputProxy;
import io.anuke.ucore.modules.Module;
import io.anuke.ucore.util.*;
import io.anuke.ucore.util.Atlas;
import static io.anuke.mindustry.Vars.*;
@ -29,10 +32,14 @@ import static io.anuke.mindustry.Vars.*;
* Should <i>not</i> handle any logic-critical state.
* 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 = 30;
private boolean hiscore = false;
private boolean wasPaused = false;
private Saves saves;
private InputHandler[] inputs = {};
private ObjectMap<Sound, Long> soundMap = new ObjectMap<>();
private Throwable error;
private InputProxy proxy;
@ -85,6 +92,15 @@ public class Control extends Module{
"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);
if(TimeUtils.timeSinceMillis(value) >= minSoundPeriod){
threads.run(() -> sound.play(volume));
soundMap.put(sound, time);
}
}));
Musics.load("1.mp3", "2.mp3", "3.mp3", "4.mp3");

View File

@ -3,15 +3,12 @@ package io.anuke.mindustry.core;
import io.anuke.mindustry.game.Difficulty;
import io.anuke.mindustry.game.EventType.StateChangeEvent;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.game.Inventory;
import io.anuke.mindustry.game.TeamInfo;
import io.anuke.ucore.core.Events;
public class GameState{
private State state = State.menu;
public final Inventory inventory = new Inventory();
public int wave = 1;
public float wavetime;
public float extrawavetime;

View File

@ -17,8 +17,6 @@ import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.modules.Module;
import java.sql.Time;
import static io.anuke.mindustry.Vars.*;
/**Logic module.
@ -44,12 +42,6 @@ public class Logic extends Module {
public void play(){
state.wavetime = wavespace * state.difficulty.timeScaling * 2;
if(state.mode.infiniteResources){
state.inventory.fill();
}else{
state.inventory.clearItems();
}
Events.fire(PlayEvent.class);
}

View File

@ -3,7 +3,6 @@ package io.anuke.mindustry.core;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.IntSet;
import io.anuke.mindustry.content.UpgradeRecipes;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.BulletType;
import io.anuke.mindustry.entities.Player;
@ -17,7 +16,7 @@ import io.anuke.mindustry.net.Packets.*;
import io.anuke.mindustry.resource.Recipe;
import io.anuke.mindustry.resource.Upgrade;
import io.anuke.mindustry.resource.Weapon;
import io.anuke.mindustry.world.Placement;
import io.anuke.mindustry.world.Build;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Timers;
@ -153,8 +152,6 @@ public class NetClient extends Module {
});
Net.handleClient(StateSyncPacket.class, packet -> {
System.arraycopy(packet.items, 0, state.inventory.writeItems(), 0, packet.items.length);
state.enemies = packet.enemies;
state.wavetime = packet.countdown;
state.wave = packet.wave;
@ -178,7 +175,7 @@ public class NetClient extends Module {
Net.handleClient(BreakPacket.class, (packet) -> {
Player placer = playerGroup.getByID(packet.playerid);
Placement.breakBlock(placer.team, packet.x, packet.y, true, Timers.get("breakblocksound", 10));
Build.breakBlock(placer.team, packet.x, packet.y, true, Timers.get("breakblocksound", 10));
});
Net.handleClient(EntitySpawnPacket.class, packet -> {
@ -271,7 +268,6 @@ public class NetClient extends Module {
Net.handleClient(UpgradePacket.class, packet -> {
Weapon weapon = Upgrade.getByID(packet.upgradeid);
state.inventory.removeItems(UpgradeRecipes.get(weapon));
for(Player player : players) {
player.upgrades.add(weapon);
}

View File

@ -5,7 +5,6 @@ import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.TimeUtils;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.Mechs;
import io.anuke.mindustry.content.UpgradeRecipes;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.BulletType;
import io.anuke.mindustry.entities.Player;
@ -21,7 +20,7 @@ import io.anuke.mindustry.resource.Recipe;
import io.anuke.mindustry.resource.Upgrade;
import io.anuke.mindustry.resource.Weapon;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Placement;
import io.anuke.mindustry.world.Build;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.BaseBulletType;
@ -203,7 +202,7 @@ public class NetServer extends Module{
Recipe recipe = Recipe.getByID(packet.recipe);
Block block = recipe.result;
if(!Placement.validPlace(placer.team, packet.x, packet.y, block, packet.rotation)) return;
if(!Build.validPlace(placer.team, packet.x, packet.y, block, packet.rotation)) return;
if(recipe == null || recipe.debugOnly != debug) return;
@ -215,8 +214,6 @@ public class NetServer extends Module{
return;
}
state.inventory.removeItems(recipe.requirements);
//todo implement placing
//Placement.placeBlock(placer, packet.x, packet.y, recipe, packet.rotation, true, false);
@ -233,7 +230,7 @@ public class NetServer extends Module{
Player placer = connections.get(id);
packet.playerid = placer.id;
if(!Placement.validBreak(placer.team, packet.x, packet.y)) return;
if(!Build.validBreak(placer.team, packet.x, packet.y)) return;
Tile tile = world.tile(packet.x, packet.y);
@ -244,7 +241,7 @@ public class NetServer extends Module{
return;
}
Block block = Placement.breakBlock(placer.team, packet.x, packet.y, true, false);
Block block = Build.breakBlock(placer.team, packet.x, packet.y, true, false);
if(block != null) {
TraceInfo trace = admins.getTraceByID(getUUID(id));
@ -283,9 +280,7 @@ public class NetServer extends Module{
Weapon weapon = Upgrade.getByID(packet.upgradeid);
if(!state.inventory.hasItems(UpgradeRecipes.get(weapon))){
return;
}
//todo verify upgrades with item requirements
if (!player.upgrades.contains(weapon, true)){
player.upgrades.add(weapon);
@ -293,7 +288,6 @@ public class NetServer extends Module{
return;
}
state.inventory.removeItems(UpgradeRecipes.get(weapon));
Net.send(packet, SendMode.tcp);
});
@ -493,7 +487,6 @@ public class NetServer extends Module{
if(timer.get(timerStateSync, itemSyncTime)){
StateSyncPacket packet = new StateSyncPacket();
packet.items = state.inventory.readItems();
packet.countdown = state.wavetime;
packet.enemies = state.enemies;
packet.wave = state.wave;

View File

@ -4,7 +4,6 @@ import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureWrap;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
@ -12,7 +11,6 @@ import com.badlogic.gdx.utils.FloatArray;
import com.badlogic.gdx.utils.Pools;
import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.BlockPlacer.PlaceRequest;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.effect.BelowLiquidEffect;
@ -22,14 +20,16 @@ import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Placement;
import io.anuke.ucore.core.*;
import io.anuke.ucore.entities.EffectEntity;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.function.Callable;
import io.anuke.ucore.graphics.*;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Hue;
import io.anuke.ucore.graphics.Lines;
import io.anuke.ucore.graphics.Surface;
import io.anuke.ucore.modules.RendererModule;
import io.anuke.ucore.scene.utils.Cursors;
import io.anuke.ucore.util.Mathf;
@ -206,13 +206,11 @@ public class Renderer extends RendererModule{
blocks.processBlocks();
blocks.drawBlocks(Layer.block);
//Graphics.surface(effectSurface, true);
Graphics.shader(Shaders.blockbuild, false);
blocks.drawBlocks(Layer.placement);
Graphics.shader();
//Graphics.flushSurface();
drawPlaceRequests();
Entities.drawWith(playerGroup, p -> true, Player::drawBuildRequests);
blocks.drawBlocks(Layer.overlay);
@ -227,35 +225,18 @@ public class Renderer extends RendererModule{
Entities.draw(airItemGroup);
Entities.draw(effectGroup);
//drawShield();
overlays.draw();
if(pixelate)
Graphics.flushSurface();
if(showPaths) drawDebug();
drawPlayerNames();
Entities.drawWith(playerGroup, p -> !p.isLocal && !p.isDead(), Player::drawName);
batch.end();
}
private void drawPlaceRequests(){
Draw.color("accent");
for(Player player : playerGroup.all()) {
for (PlaceRequest request : player.getPlaceQueue()) {
if(Placement.validPlace(player.team, request.x, request.y, request.recipe.result, request.rotation)){
Lines.poly(request.x * tilesize + request.recipe.result.getPlaceOffset().x,
request.y * tilesize + request.recipe.result.getPlaceOffset().y,
4, request.recipe.result.size * tilesize /2f + Mathf.absin(Timers.time(), 3f, 1f));
}
}
}
Draw.color();
}
private void drawAllTeams(boolean flying){
for(Team team : Team.values()){
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
@ -351,31 +332,6 @@ public class Renderer extends RendererModule{
Draw.color();
}
void drawPlayerNames(){
GlyphLayout layout = Pools.obtain(GlyphLayout.class);
Draw.tscl(0.25f/2);
for(Player player : playerGroup.all()){
if(!player.isLocal && !player.isDead()){
layout.setText(Core.font, player.name);
Draw.color(0f, 0f, 0f, 0.3f);
Draw.rect("blank", player.getDrawPosition().x, player.getDrawPosition().y + 8 - layout.height/2, layout.width + 2, layout.height + 2);
Draw.color();
Draw.tcolor(player.getColor());
Draw.text(player.name, player.getDrawPosition().x, player.getDrawPosition().y + 8);
if(player.isAdmin){
Draw.color(player.getColor());
float s = 3f;
Draw.rect("icon-admin-small", player.getDrawPosition().x + layout.width/2f + 2 + 1, player.getDrawPosition().y + 7f, s, s);
}
Draw.reset();
}
}
Pools.free(layout);
Draw.tscl(fontscale);
}
void drawShield(){
if(shieldGroup.size() == 0 && shieldDraws.size == 0) return;

View File

@ -0,0 +1,154 @@
package io.anuke.mindustry.entities;
import com.badlogic.gdx.utils.Queue;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.resource.Recipe;
import io.anuke.mindustry.world.Build;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.BuildBlock;
import io.anuke.mindustry.world.blocks.types.BuildBlock.BuildEntity;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Fill;
import io.anuke.ucore.graphics.Lines;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Translator;
import java.util.Arrays;
import static io.anuke.mindustry.Vars.world;
/**Interface for units that build thing.*/
public interface BlockBuilder {
//temporary static final values
Translator[] tmptr = {new Translator(), new Translator(), new Translator(), new Translator()};
float placeDistance = 80f;
/**Returns the queue for storing build requests.*/
Queue<BuildRequest> getPlaceQueue();
/**Clears the placement queue.*/
default void clearBuilding(){
getPlaceQueue().clear();
}
/**Add another build requests to the tail of the queue.*/
default void addBuildRequest(BuildRequest place){
getPlaceQueue().addLast(place);
}
/**Return the build requests currently active, or the one at the top of the queue.
* May return null.*/
default BuildRequest getCurrentRequest(){
return getPlaceQueue().size == 0 ? null : getPlaceQueue().first();
}
/**Update building mechanism for this unit.*/
default void updateBuilding(Unit unit){
BuildRequest current = getCurrentRequest();
if(current == null) return; //nothing to do here
Tile tile = world.tile(current.x, current.y);
if(unit.distanceTo(tile) > placeDistance) { //out of range, skip it.
getPlaceQueue().removeFirst();
}else if(current.remove){
if(Build.validBreak(unit.team, current.x, current.y)){ //if it's valid, break it
current.removeProgress += 1f / tile.getBreakTime();
if(current.removeProgress >= 1f){
Build.breakBlock(unit.team, current.x, current.y, true, true);
}
}else{
//otherwise, skip it
getPlaceQueue().removeFirst();
}
}else{
if (!(tile.block() instanceof BuildBlock)) { //check if haven't started placing
if(Build.validPlace(unit.team, current.x, current.y, current.recipe.result, current.rotation)){
//if it's valid, place it
Build.placeBlock(unit.team, current.x, current.y, current.recipe, current.rotation);
}else{
//otherwise, skip it
getPlaceQueue().removeFirst();
}
}else{
//otherwise, update it.
BuildEntity entity = tile.entity();
entity.progress += 1f / entity.recipe.cost;
unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(entity), 0.4f);
}
}
}
/**Draw placement effects for an entity.*/
default void drawBuilding(Unit unit){
Tile tile = world.tile(getCurrentRequest().x, getCurrentRequest().y);
Draw.color(unit.distanceTo(tile) > placeDistance ? "placeInvalid" : "accent");
float focusLen = 3.8f + Mathf.absin(Timers.time(), 1.1f, 0.6f);
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 ang = unit.angleTo(tile);
tmptr[0].set(tile.drawx() - sz, tile.drawy() - sz);
tmptr[1].set(tile.drawx() + sz, tile.drawy() - sz);
tmptr[2].set(tile.drawx() - sz, tile.drawy() + sz);
tmptr[3].set(tile.drawx() + sz, tile.drawy() + sz);
Arrays.sort(tmptr, (a, b) -> -Float.compare(Angles.angleDist(Angles.angle(unit.x, unit.y, a.x, a.y), ang),
Angles.angleDist(Angles.angle(unit.x, unit.y, b.x, b.y), ang)));
float x1 = tmptr[0].x, y1 = tmptr[0].y,
x3 = tmptr[1].x, y3 = tmptr[1].y;
Translator close = Geometry.findClosest(unit.x, unit.y, tmptr);
float x2 = close.x, y2 = close.y;
Draw.alpha(0.3f + Mathf.absin(Timers.time(), 0.9f, 0.2f));
Fill.tri(px, py, x2, y2, x1, y1);
Fill.tri(px, py, x2, y2, x3, y3);
Draw.alpha(1f);
Lines.line(px, py, x1, y1);
Lines.line(px, py, x3, y3);
Fill.circle(px, py, 1.5f + Mathf.absin(Timers.time(), 1f, 1.8f));
Draw.color();
}
/**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;
float removeProgress;
/**This creates a build request.*/
public BuildRequest(int x, int y, int rotation, Recipe recipe) {
this.x = x;
this.y = y;
this.rotation = rotation;
this.recipe = recipe;
this.remove = false;
}
/**This creates a remove request.*/
public BuildRequest(int x, int y) {
this.x = x;
this.y = y;
this.rotation = -1;
this.recipe = null;
this.remove = true;
}
}
}

View File

@ -1,21 +0,0 @@
package io.anuke.mindustry.entities;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.resource.Recipe;
public interface BlockPlacer {
void addPlaceBlock(PlaceRequest place);
Team getTeam();
class PlaceRequest{
public final int x, y, rotation;
public final Recipe recipe;
public PlaceRequest(int x, int y, int rotation, Recipe recipe) {
this.x = x;
this.y = y;
this.rotation = rotation;
this.recipe = recipe;
}
}
}

View File

@ -10,6 +10,8 @@ import io.anuke.ucore.function.Callable;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.util.Mathf;
/**This class should not be used anymore, as the animation does not fit the style well.*/
@Deprecated
public class ItemAnimationEffect extends TimedEntity {
private static final float size = 5f;

View File

@ -1,10 +1,11 @@
package io.anuke.mindustry.entities;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.GlyphLayout;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Pools;
import com.badlogic.gdx.utils.Queue;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.Mechs;
import io.anuke.mindustry.content.Weapons;
import io.anuke.mindustry.content.fx.ExplosionFx;
@ -14,18 +15,11 @@ import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.mindustry.resource.*;
import io.anuke.mindustry.world.Placement;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.BuildBlock;
import io.anuke.mindustry.world.blocks.types.BuildBlock.BuildEntity;
import io.anuke.mindustry.world.blocks.types.Floor;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Inputs;
import io.anuke.ucore.core.Settings;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.core.*;
import io.anuke.ucore.entities.SolidEntity;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Fill;
import io.anuke.ucore.graphics.Lines;
import io.anuke.ucore.util.*;
@ -33,17 +27,13 @@ import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import static io.anuke.mindustry.Vars.*;
public class Player extends Unit implements BlockPlacer{
static final float speed = 1.1f;
static final float dashSpeed = 1.8f;
public static final float placeDistance = 80f;
static final int timerRegen = 3;
static final Translator[] tmptr = {new Translator(), new Translator(), new Translator(), new Translator()};
public class Player extends Unit implements BlockBuilder {
private static final float speed = 1.1f;
private static final float dashSpeed = 1.8f;
private static final Vector2 movement = new Vector2();
public String name = "name";
public String uuid;
@ -61,12 +51,10 @@ public class Player extends Unit implements BlockPlacer{
public int playerIndex = 0;
public boolean isLocal = false;
public Timer timer = new Timer(4);
public float walktime;
public float respawntime;
private Queue<PlaceRequest> placeQueue = new Queue<>();
private Tile currentPlace;
private Vector2 movement = new Vector2();
private float walktime;
private float respawntime;
private Queue<BuildRequest> placeQueue = new Queue<>();
public Player(){
hitbox.setSize(5);
@ -110,11 +98,6 @@ public class Player extends Unit implements BlockPlacer{
}
}
@Override
public void addPlaceBlock(PlaceRequest req){
placeQueue.addFirst(req);
}
@Override
public boolean collides(SolidEntity other){
return !isDead() && super.collides(other) && !mech.flying;
@ -227,45 +210,49 @@ public class Player extends Unit implements BlockPlacer{
@Override
public void drawOver(){
if(!isShooting() && currentPlace != null) {
Draw.color(distanceTo(currentPlace) > placeDistance ? "placeInvalid" : "accent");
float focusLen = 3.8f + Mathf.absin(Timers.time(), 1.1f, 0.6f);
float px = x + Angles.trnsx(rotation, focusLen);
float py = y + Angles.trnsy(rotation, focusLen);
Tile tile = currentPlace;
float sz = Vars.tilesize*tile.block().size/2f;
float ang = angleTo(tile);
tmptr[0].set(tile.drawx() - sz, tile.drawy() - sz);
tmptr[1].set(tile.drawx() + sz, tile.drawy() - sz);
tmptr[2].set(tile.drawx() - sz, tile.drawy() + sz);
tmptr[3].set(tile.drawx() + sz, tile.drawy() + sz);
Arrays.sort(tmptr, (a, b) -> -Float.compare(Angles.angleDist(Angles.angle(x, y, a.x, a.y), ang),
Angles.angleDist(Angles.angle(x, y, b.x, b.y), ang)));
float x1 = tmptr[0].x, y1 = tmptr[0].y,
x3 = tmptr[1].x, y3 = tmptr[1].y;
Translator close = Geometry.findClosest(x, y, tmptr);
float x2 = close.x, y2 = close.y;
Draw.alpha(0.3f + Mathf.absin(Timers.time(), 0.9f, 0.2f));
Fill.tri(px, py, x2, y2, x1, y1);
Fill.tri(px, py, x2, y2, x3, y3);
Draw.alpha(1f);
Lines.line(px, py, x1, y1);
Lines.line(px, py, x3, y3);
Fill.circle(px, py, 1.5f + Mathf.absin(Timers.time(), 1f, 1.8f));
Draw.color();
if(!isShooting() && getCurrentRequest() != null) {
drawBuilding(this);
}
}
public void drawName(){
GlyphLayout layout = Pools.obtain(GlyphLayout.class);
Draw.tscl(0.25f/2);
layout.setText(Core.font, name);
Draw.color(0f, 0f, 0f, 0.3f);
Draw.rect("blank", getDrawPosition().x, getDrawPosition().y + 8 - layout.height/2, layout.width + 2, layout.height + 2);
Draw.color();
Draw.tcolor(color);
Draw.text(name, getDrawPosition().x, getDrawPosition().y + 8);
if(isAdmin){
Draw.color(color);
float s = 3f;
Draw.rect("icon-admin-small", getDrawPosition().x + layout.width/2f + 2 + 1, getDrawPosition().y + 7f, s, s);
}
Draw.reset();
Pools.free(layout);
Draw.tscl(fontscale);
}
public void drawBuildRequests(){
for (BuildRequest request : getPlaceQueue()) {
if(request.remove){
Draw.color("placeInvalid");
Tile tile = world.tile(request.x, request.y);
Lines.poly(tile.drawx(), tile.drawy(),
4, tile.block().size * tilesize /2f + Mathf.absin(Timers.time(), 3f, 1f));
}else{
Draw.color("accent");
Lines.poly(request.x * tilesize + request.recipe.result.getPlaceOffset().x,
request.y * tilesize + request.recipe.result.getPlaceOffset().y,
4, request.recipe.result.size * tilesize /2f + Mathf.absin(Timers.time(), 3f, 1f));
}
}
}
@Override
public void update(){
@ -300,6 +287,7 @@ public class Player extends Unit implements BlockPlacer{
y = Mathf.clamp(y, 0, world.height() * tilesize);
}
/**Resets all values of the player.*/
public void reset(){
weapon = Weapons.blaster;
team = Team.blue;
@ -316,12 +304,11 @@ public class Player extends Unit implements BlockPlacer{
return control.input(playerIndex).canShoot() && control.input(playerIndex).isShooting() && inventory.hasAmmo();
}
public Queue<PlaceRequest> getPlaceQueue(){
public Queue<BuildRequest> getPlaceQueue(){
return placeQueue;
}
protected void updateMech(){
Tile tile = world.tileWorld(x, y);
//if player is in solid block
@ -330,29 +317,7 @@ public class Player extends Unit implements BlockPlacer{
}
if(!isShooting()) {
//update placing queue
if(currentPlace != null) {
Tile check = currentPlace;
if (!(check.block() instanceof BuildBlock)) {
currentPlace = null;
}else if(distanceTo(check) <= placeDistance){
BuildEntity entity = check.entity();
entity.progress += 1f / entity.recipe.cost;
rotation = Mathf.slerpDelta(rotation, angleTo(entity), 0.4f);
}
}else if(placeQueue.size > 0){
PlaceRequest check = placeQueue.last();
if(distanceTo(world.tile(check.x, check.y)) <= placeDistance &&
Placement.validPlace(team, check.x, check.y, check.recipe.result, check.rotation)){
placeQueue.removeLast();
Placement.placeBlock(team, check.x, check.y, check.recipe, check.rotation, true, true);
currentPlace = world.tile(check.x, check.y);
}
}
updateBuilding(this);
}
if(ui.chatfrag.chatOpen()) return;
@ -365,11 +330,6 @@ public class Player extends Unit implements BlockPlacer{
speed *= ((1f-carrySlowdown) + (inventory.hasItem() ? (float)inventory.getItem().amount/inventory.capacity(): 1f) * carrySlowdown);
if(health < maxhealth && timer.get(timerRegen, 20))
health ++;
health = Mathf.clamp(health, -1, maxhealth);
movement.set(0, 0);
String section = "player_" + (playerIndex + 1);
@ -524,18 +484,4 @@ public class Player extends Unit implements BlockPlacer{
interpolator.read(this.x, this.y, x, y, rot, baseRot, time);
}
@Override
public void interpolate() {
super.interpolate();
Interpolator i = interpolator;
float tx = x + Angles.trnsx(rotation + 180f, 4f);
float ty = y + Angles.trnsy(rotation + 180f, 4f);
}
public Color getColor(){
return color;
}
}

View File

@ -3,12 +3,13 @@ package io.anuke.mindustry.entities;
import com.badlogic.gdx.math.Vector2;
import io.anuke.ucore.util.Mathf;
/**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();
/**Returns resulting predicted vector.
* Don't call from multiple threads, ever.*/
* Don't call from multiple threads.*/
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,
@ -37,7 +38,6 @@ public class Predict {
return sol;
}
private static Vector2 quad(float a, float b, float c) {
Vector2 sol = null;
if (Math.abs(a) < 1e-6) {

View File

@ -3,6 +3,7 @@ package io.anuke.mindustry.entities;
import io.anuke.mindustry.content.StatusEffects;
import io.anuke.ucore.core.Timers;
/**Class for controlling status effects on an entity.*/
public class StatusController {
private static final TransitionResult globalResult = new TransitionResult();

View File

@ -1,578 +0,0 @@
package io.anuke.mindustry.game;
import com.badlogic.gdx.math.GridPoint2;
import io.anuke.mindustry.content.Items;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.content.blocks.DistributionBlocks;
import io.anuke.mindustry.content.blocks.WeaponBlocks;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.world.Block;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.scene.builders.button;
import io.anuke.ucore.scene.builders.label;
import io.anuke.ucore.scene.builders.table;
import io.anuke.ucore.scene.ui.ImageButton;
import io.anuke.ucore.scene.ui.Label;
import io.anuke.ucore.scene.ui.TextButton;
import io.anuke.ucore.util.Bundles;
import io.anuke.ucore.util.Tmp;
import static io.anuke.mindustry.Vars.*;
public class Tutorial{
private Stage stage;
private Label info;
private TextButton next, prev;
public Tutorial(){
reset();
}
public boolean active(){
return world.getMap() != null && world.getMap().name.equals("tutorial") && !state.is(State.menu);
}
public void buildUI(table table){
table.atop();
new table("pane"){{
atop();
margin(12);
info = new label(()->stage.text).pad(10f).padBottom(5f).width(340f).colspan(2).get();
info.setWrap(true);
row();
prev = new button("$text.tutorial.back", ()->{
if(!prev.isDisabled())
move(false);
}).left().get();
next = new button("$text.tutorial.next", ()->{
if(!next.isDisabled())
move(true);
}).right().get();
}}.end();
prev.margin(16);
next.margin(16);
prev.setDisabled(()->!canMove(false) || !stage.canBack);
next.setDisabled(()->!stage.canForward);
}
public void update(){
stage.update(this);
//info.setText(stage.text);
if(stage.showBlock){
/*
Tile tile = world.tile(world.getCore().x + stage.blockPlaceX, world.getCore().y + stage.blockPlaceY);
if(tile.block() == stage.targetBlock && (tile.getRotation() == stage.blockRotation || stage.blockRotation == -1)){
move(true);
}*/
}
}
public void reset(){
stage = Stage.values()[0];
stage.onSwitch();
}
public void complete(){
//new TextDialog("Congratulations!", "You have completed the tutorial!").padText(Unit.dp.inPixels(10f)).show();
state.set(State.menu);
reset();
}
void move(boolean forward){
//TODO
}
boolean canMove(boolean forward){
return true;
}
public boolean showTarget(){
return stage == Stage.shoot;
}
public boolean canPlace(){
return stage.canPlace;
}
public boolean showBlock(){
return stage.showBlock;
}
public Block getPlaceBlock(){
return stage.targetBlock;
}
public GridPoint2 getPlacePoint(){
return Tmp.g1.set(stage.blockPlaceX, stage.blockPlaceY);
}
public int getPlaceRotation(){
return stage.blockRotation;
}
public void setDefaultBlocks(int corex, int corey){
world.tile(corex, corey - 2).setBlock(Blocks.air);
world.tile(corex, corey - 3).setBlock(Blocks.air);
world.tile(corex, corey - 3).setFloor(Blocks.stone);
world.tile(corex + 1, corey - 8).setFloor(Blocks.iron);
world.tile(corex - 1, corey - 8).setFloor(Blocks.coal);
int r = 10;
for(int x = -r; x <= r; x ++){
for(int y = -r; y <= r; y ++){
if(world.tile(corex + x, corey + y).block() == Blocks.rock){
world.tile(corex + x, corey + y).setBlock(Blocks.air);
}
}
}
}
public enum Stage{
intro{
{
}
},
moveDesktop{
{
desktopOnly = true;
}
},
shoot{
{
desktopOnly = true;
}
},
moveAndroid{
{
androidOnly = true;
}
},
placeSelect{
{
canBack = false;
canPlace = true;
}
void onSwitch(){
ui.<ImageButton>find("sectionbuttondistribution").fireClick();
}
},
placeConveyorDesktop{
{
desktopOnly = true;
canPlace = true;
showBlock = true;
canForward = false;
blockRotation = 1;
blockPlaceX = 0;
blockPlaceY = -2;
targetBlock = DistributionBlocks.conveyor;
}
},
placeConveyorAndroid{
{
androidOnly = true;
canPlace = true;
showBlock = true;
canForward = false;
blockRotation = 1;
blockPlaceX = 0;
blockPlaceY = -2;
targetBlock = DistributionBlocks.conveyor;
}
},
placeConveyorAndroidInfo{
{
androidOnly = true;
canBack = false;
}
void onSwitch(){
//player.recipe = null;
}
},
placeDrill{
{
canPlace = true;
canBack = false;
showBlock = true;
canForward = false;
blockPlaceX = 0;
blockPlaceY = -3;
//targetBlock = ProductionBlocks.stonedrill;
}
void onSwitch(){
ui.<ImageButton>find("sectionbuttonproduction").fireClick();
}
},
blockInfo{
{
canBack = true;
}
},
deselectDesktop{
{
desktopOnly = true;
canBack = false;
}
},
deselectAndroid{
{
androidOnly = true;
canBack = false;
}
},
drillPlaced{
{
canBack = false;
}
void onSwitch(){
}
},
drillInfo{
{
}
},
drillPlaced2{
{
}
},
moreDrills{
{
canBack = false;
}
void onSwitch(){
/*
for(int flip : new int[]{1, -1}){
world.tile(world.getCore().x + flip, world.getCore().y - 2).setBlock(DistributionBlocks.conveyor, 2 * flip);
world.tile(world.getCore().x + flip*2, world.getCore().y - 2).setBlock(DistributionBlocks.conveyor, 2 * flip);
world.tile(world.getCore().x + flip*2, world.getCore().y - 3).setBlock(DistributionBlocks.conveyor, 2 * flip);
world.tile(world.getCore().x + flip*2, world.getCore().y - 3).setBlock(DistributionBlocks.conveyor, 1);
world.tile(world.getCore().x + flip*2, world.getCore().y - 4).setFloor(Blocks.stone);
world.tile(world.getCore().x + flip*2, world.getCore().y - 4).setBlock(ProductionBlocks.stonedrill);
}*/
}
},
deleteBlock{
{
canBack = false;
canForward = false;
showBlock = true;
targetBlock = Blocks.air;
blockPlaceX = 2;
blockPlaceY = -2;
desktopOnly = true;
}
},
deleteBlockAndroid{
{
canBack = false;
canForward = false;
showBlock = true;
targetBlock = Blocks.air;
blockPlaceX = 2;
blockPlaceY = -2;
androidOnly = true;
}
},
placeTurret{
{
canBack = false;
canForward = false;
showBlock = true;
canPlace = true;
targetBlock = WeaponBlocks.doubleturret;
blockPlaceX = 2;
blockPlaceY = 2;
}
void onSwitch(){
ui.<ImageButton>find("sectionbuttonweapon").fireClick();
}
},
placedTurretAmmo{
{
canBack = false;
}
void onSwitch(){
for(int i = 0; i < 4; i ++){
//world.tile(world.getCore().x + 2, world.getCore().y - 2 + i).setBlock(DistributionBlocks.conveyor, 1);
}
}
},
turretExplanation{
{
canBack = false;
}
},
waves{
{
}
},
coreDestruction{
{
}
},
pausingDesktop{
{
desktopOnly = true;
}
},
pausingAndroid{
{
androidOnly = true;
}
},
//TODO re-add tutorial on weapons
spawnWave{
float warmup = 0f;
{
canBack = false;
canForward = false;
}
void update(Tutorial t){
warmup += Timers.delta();
if(state.enemies == 0 && warmup > 60f){
t.move(true);
}
}
void onSwitch(){
warmup = 0f;
logic.runWave();
}
},
pumpDesc{
{
canBack = false;
}
},
pumpPlace{
{
canBack = false;
canForward = false;
showBlock = true;
canPlace = true;
//targetBlock = ProductionBlocks.pump;
blockPlaceX = 6;
blockPlaceY = -2;
}
void onSwitch(){
ui.<ImageButton>find("sectionbuttonproduction").fireClick();
state.inventory.addItem(Items.steel, 60);
state.inventory.addItem(Items.iron, 60);
}
},
conduitUse{
{
canBack = false;
canForward = false;
showBlock = true;
canPlace = true;
//targetBlock = DistributionBlocks.conduit;
blockPlaceX = 5;
blockPlaceY = -2;
blockRotation = 2;
}
void onSwitch(){
ui.<ImageButton>find("sectionbuttondistribution").fireClick();
//world.tile(blockPlaceX + world.getCore().x, blockPlaceY + world.getCore().y).setBlock(Blocks.air);
}
},
conduitUse2{
{
canBack = false;
canForward = false;
showBlock = true;
canPlace = true;
//targetBlock = DistributionBlocks.conduit;
//blockPlaceX = 4;
blockPlaceY = -2;
blockRotation = 1;
}
void onSwitch(){
//world.tile(blockPlaceX + world.getCore().x, blockPlaceY + world.getCore().y).setBlock(Blocks.air);
}
},
conduitUse3{
{
canBack = false;
canForward = false;
showBlock = true;
canPlace = true;
//targetBlock = DistributionBlocks.conduit;
blockPlaceX = 4;
blockPlaceY = -1;
blockRotation = 1;
}
void onSwitch(){
//world.tile(blockPlaceX + world.getCore().x, blockPlaceY + world.getCore().y).setBlock(Blocks.air);
}
},
generator{
{
canBack = false;
canForward = false;
showBlock = true;
canPlace = true;
//targetBlock = ProductionBlocks.combustiongenerator;
blockPlaceX = 4;
blockPlaceY = 0;
}
void onSwitch(){
//world.tile(blockPlaceX + world.getCore().x, blockPlaceY + world.getCore().y).setBlock(Blocks.air);
ui.<ImageButton>find("sectionbuttonpower").fireClick();
state.inventory.addItem(Items.steel, 60);
state.inventory.addItem(Items.iron, 60);
}
},
generatorExplain{
{
canBack = false;
}
},
lasers{
{
canBack = false;
canForward = false;
showBlock = true;
canPlace = true;
blockPlaceX = 4;
blockPlaceY = 4;
blockRotation = 2;
//targetBlock = DistributionBlocks.powerlaser;
}
void onSwitch(){
ui.<ImageButton>find("sectionbuttonpower").fireClick();
}
},
laserExplain{
{
canBack = false;
}
},
laserMore{
{
canBack = false;
}
},
healingTurret{
{
canBack = false;
canForward = false;
showBlock = true;
canPlace = true;
canBack = false;
blockPlaceX = 1;
blockPlaceY = 4;
//targetBlock = DefenseBlocks.repairturret;
}
void onSwitch(){
ui.<ImageButton>find("sectionbuttonpower").fireClick();
}
},
healingTurretExplain{
{
canBack = false;
}
},
smeltery{
{
canBack = false;
canForward = false;
showBlock = true;
canPlace = true;
canBack = false;
blockPlaceX = 0;
blockPlaceY = -7;
//targetBlock = ProductionBlocks.smelter;
}
void onSwitch(){
state.inventory.addItem(Items.stone, 40);
state.inventory.addItem(Items.iron, 40);
ui.<ImageButton>find("sectionbuttoncrafting").fireClick();
}
},
smelterySetup{
{
canBack = false;
}
void onSwitch(){
/*
for(int i = 0; i < 5; i ++){
world.tile(world.getCore().x, world.getCore().y - 6 + i).setBlock(DistributionBlocks.conveyor, 1);
}
world.tile(world.getCore().x, world.getCore().y - 6 + 1).setBlock(DistributionBlocks.tunnel, 3);
world.tile(world.getCore().x, world.getCore().y - 6 + 2).setBlock(DefenseBlocks.stonewall, 0);
world.tile(world.getCore().x, world.getCore().y - 6 + 3).setBlock(DistributionBlocks.tunnel, 1);
world.tile(world.getCore().x+1, world.getCore().y - 8).setBlock(ProductionBlocks.irondrill);
world.tile(world.getCore().x-1, world.getCore().y - 8).setBlock(ProductionBlocks.coaldrill);
world.tile(world.getCore().x+1, world.getCore().y - 7).setBlock(DistributionBlocks.conveyor, 2);
world.tile(world.getCore().x-1, world.getCore().y - 7).setBlock(DistributionBlocks.conveyor, 0);*/
}
},
tunnelExplain{
{
canBack = false;
}
},
end{
{
canBack = false;
}
};
public final String text = Bundles.getNotNull("tutorial."+name()+".text");
boolean androidOnly;
boolean desktopOnly;
boolean canBack = true;
boolean canForward = true;
boolean canPlace = false;
boolean showBlock = false;
int blockPlaceX = 0;
int blockPlaceY = 0;
int blockRotation = -1;
Block targetBlock = null;
void update(Tutorial t){};
void onSwitch(){}
}
}

View File

@ -45,7 +45,7 @@ public class OverlayRenderer {
int tiley = input.getBlockY();
//draw placement box
if ((input.recipe != null && state.inventory.hasItems(input.recipe.requirements) && (!ui.hasMouse() || mobile)
if ((input.recipe != null && (!ui.hasMouse() || mobile)
&& input.drawPlace())) {
input.placeMode.draw(input, input.getBlockX(),
@ -55,7 +55,7 @@ public class OverlayRenderer {
input.breakMode.draw(input, tilex, tiley, 0, 0);
} else if (input.breakMode.delete && input.drawPlace()
&& (input.recipe == null || !state.inventory.hasItems(input.recipe.requirements))
&& (input.recipe == null)
&& (input.placeMode.delete || input.breakMode.both || !mobile)) {
if (input.breakMode == PlaceMode.holdDelete)

View File

@ -7,7 +7,6 @@ import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.mindustry.resource.ItemStack;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.core.Inputs;
@ -98,28 +97,12 @@ public class AndroidInput extends InputHandler{
mousex = Gdx.graphics.getWidth()/2;
mousey = Gdx.graphics.getHeight()/2;
}
@Override
public boolean cursorNear(){
return true;
}
public Tile selected(){
Vector2 vec = Graphics.world(mousex, mousey);
return world.tile(Mathf.scl2(vec.x, tilesize), Mathf.scl2(vec.y, tilesize));
}
public void breakBlock(){
Tile tile = selected();
breaktime += Timers.delta();
if(breaktime >= tile.block().breaktime){
brokeBlock = true;
breakBlock(tile.x, tile.y, true);
breaktime = 0f;
}
}
@Override
public void update(){
enableHold = breakMode == PlaceMode.holdDelete;
@ -150,15 +133,6 @@ public class AndroidInput extends InputHandler{
if(sel == null)
return;
if(warmup > warmupDelay && validBreak(sel.x, sel.y)){
breaktime += Timers.delta();
if(breaktime > selected().block().breaktime){
breakBlock();
breaktime = 0;
}
}
mousex = lx;
mousey = ly;
}else{
@ -169,23 +143,6 @@ public class AndroidInput extends InputHandler{
mousey = Mathf.clamp(mousey, 0, Gdx.graphics.getHeight());
}
}
@Override
public boolean tryPlaceBlock(int x, int y, boolean sound){
if(recipe != null &&
validPlace(x, y, recipe.result) && cursorNear() &&
state.inventory.hasItems(recipe.requirements)){
placeBlock(x, y, recipe, rotation, true, sound);
for(ItemStack stack : recipe.requirements){
state.inventory.removeItem(stack);
}
return true;
}
return false;
}
public boolean breaking(){
return recipe == null;

View File

@ -21,7 +21,6 @@ public class DesktopInput extends InputHandler{
float mousex, mousey;
float endx, endy;
private float controlx, controly;
private boolean enableHold = false;
private boolean beganBreak;
private boolean controlling;
private final int index;
@ -178,17 +177,6 @@ public class DesktopInput extends InputHandler{
recipe = null;
}
//block breaking
if(enableHold && Inputs.keyDown(section,"break") && cursor != null && validBreak(tilex(), tiley())){
breaktime += Timers.delta();
if(breaktime >= cursor.getBreakTime()){
breakBlock(cursor.x, cursor.y, true);
breaktime = 0f;
}
}else{
breaktime = 0f;
}
if(recipe != null){
showCursor = validPlace(tilex(), tiley(), recipe.result) && cursorNear();
}

View File

@ -47,7 +47,7 @@ public class GestureHandler extends GestureAdapter{
if(input.isCursorVisible() && !Inputs.keyDown("select")) return false;
if(!input.isCursorVisible() && !(input.recipe != null
&& input.placeMode.lockCamera && state.inventory.hasItems(input.recipe.requirements)) &&
&& input.placeMode.lockCamera) &&
!(input.recipe == null && input.breakMode.lockCamera)){
float dx = deltaX*Core.camera.zoom/Core.cameraScale, dy = deltaY*Core.camera.zoom/Core.cameraScale;
input.player.x -= dx;

View File

@ -4,16 +4,14 @@ import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.math.Interpolation;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.entities.BlockPlacer.PlaceRequest;
import io.anuke.mindustry.entities.BlockBuilder.BuildRequest;
import io.anuke.mindustry.entities.ItemAnimationEffect;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetEvents;
import io.anuke.mindustry.resource.ItemStack;
import io.anuke.mindustry.resource.Recipe;
import io.anuke.mindustry.ui.fragments.OverlayFragment;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Placement;
import io.anuke.mindustry.world.Build;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Graphics;
@ -158,25 +156,20 @@ public abstract class InputHandler extends InputAdapter{
return true;
}
public boolean tryPlaceBlock(int x, int y, boolean sound){
public boolean tryPlaceBlock(int x, int y){
if(recipe != null &&
validPlace(x, y, recipe.result) && !ui.hasMouse() && cursorNear() &&
state.inventory.hasItems(recipe.requirements)){
validPlace(x, y, recipe.result) && !ui.hasMouse() && cursorNear()){
placeBlock(x, y, recipe, rotation, true, sound);
for(ItemStack stack : recipe.requirements){
state.inventory.removeItem(stack);
}
placeBlock(x, y, recipe, rotation);
return true;
}
return false;
}
public boolean tryDeleteBlock(int x, int y, boolean sound){
public boolean tryDeleteBlock(int x, int y){
if(cursorNear() && validBreak(x, y)){
breakBlock(x, y, sound);
breakBlock(x, y);
return true;
}
return false;
@ -189,7 +182,7 @@ public abstract class InputHandler extends InputAdapter{
public boolean validPlace(int x, int y, Block type){
for(Tile tile : state.teams.get(player.team).cores){
if(tile.distanceTo(x * tilesize, y * tilesize) < coreBuildRange){
return Placement.validPlace(player.team, x, y, type, rotation) &&
return Build.validPlace(player.team, x, y, type, rotation) &&
Vector2.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance;
}
}
@ -198,35 +191,16 @@ public abstract class InputHandler extends InputAdapter{
}
public boolean validBreak(int x, int y){
return Placement.validBreak(player.team, x, y);
return Build.validBreak(player.team, x, y);
}
public void placeBlock(int x, int y, Recipe recipe, int rotation, boolean effects, boolean sound){
public void placeBlock(int x, int y, Recipe recipe, int rotation){
//todo multiplayer support
player.addPlaceBlock(new PlaceRequest(x, y, rotation, recipe));
/*
if(!Net.client()){ //is server or singleplayer
threads.run(() -> Placement.placeBlock(player.team, x, y, recipe, rotation, effects, sound));
}
if(Net.active()){
NetEvents.handlePlace(player, x, y, recipe, rotation);
}
//todo fix this, call placed()
if(!Net.client()){
//Tile tile = world.tile(x, y);
//if(tile != null) threads.run(() -> result.placed(tile));
}*/
player.addBuildRequest(new BuildRequest(x, y, rotation, recipe));
}
public void breakBlock(int x, int y, boolean sound){
if(!Net.client()){
threads.run(() -> Placement.breakBlock(player.team, x, y, true, sound));
}
if(Net.active()){
NetEvents.handleBreak(x, y);
}
public void breakBlock(int x, int y){
//todo multiplayer support
player.addBuildRequest(new BuildRequest(x, y));
}
}

View File

@ -8,7 +8,7 @@ import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.graphics.Shaders;
import io.anuke.mindustry.ui.fragments.ToolFragment;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Placement;
import io.anuke.mindustry.world.Build;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.core.Timers;
@ -55,7 +55,7 @@ public enum PlaceMode{
}
public void tapped(InputHandler input, int tilex, int tiley){
input.tryPlaceBlock(tilex, tiley, true);
input.tryPlaceBlock(tilex, tiley);
}
},
touch{
@ -67,7 +67,7 @@ public enum PlaceMode{
}
public void tapped(InputHandler input, int x, int y){
input.tryPlaceBlock(x, y, true);
input.tryPlaceBlock(x, y);
}
},
none{
@ -110,7 +110,7 @@ public enum PlaceMode{
}
public void tapped(InputHandler input, int x, int y){
input.tryDeleteBlock(x, y, true);
input.tryDeleteBlock(x, y);
}
},
areaDelete{
@ -172,7 +172,7 @@ public enum PlaceMode{
tilex = this.rtilex; tiley = this.rtiley;
endx = this.rendx; endy = this.rendy;
input.player.getPlaceQueue().clear();
input.player.clearBuilding();
if(mobile){
ToolFragment t = input.frag.tool;
@ -186,13 +186,10 @@ public enum PlaceMode{
}
}
boolean first = true;
for(int cx = tilex; cx <= endx; cx ++){
for(int cy = tiley; cy <= endy; cy ++){
if(input.tryDeleteBlock(cx, cy, first)){
first = false;
}
input.tryDeleteBlock(cx, cy);
}
}
}
@ -283,7 +280,7 @@ public enum PlaceMode{
int wx = tilex + px * Mathf.sign(endx - tilex),
wy = tiley + py * Mathf.sign(endy - tiley);
if(!Placement.validPlace(input.player.team, wx, wy, block, rotation)){
if(!Build.validPlace(input.player.team, wx, wy, block, rotation)){
Draw.color("placeInvalid");
}else{
Draw.color("accent");
@ -315,22 +312,21 @@ public enum PlaceMode{
process(input, tilex, tiley, endx, endy);
input.rotation = this.rotation;
input.player.getPlaceQueue().clear();
input.player.clearBuilding();
boolean first = true;
for(int x = 0; x <= Math.abs(this.rendx - this.rtilex); x += input.recipe.result.size){
for(int y = 0; y <= Math.abs(this.rendy - this.rtiley); y += input.recipe.result.size){
if(input.tryPlaceBlock(
input.tryPlaceBlock(
tilex + x * Mathf.sign(endx - tilex),
tiley + y * Mathf.sign(endy - tiley), first)){
first = false;
}
tiley + y * Mathf.sign(endy - tiley));
}
}
}
void process(InputHandler input, int tilex, int tiley, int endx, int endy){
//todo hold shift to snap
/*
if(Math.abs(tilex - endx) > Math.abs(tiley - endy)){
endy = tiley;

View File

@ -27,7 +27,7 @@ public class NetEvents {
}
@RemoteServer
public static void notifySomethingFromClient(Player player, int x, float y){
public static void notifySomethingFromClient(Player player, int x, float y, String asdsad, long l){
}

View File

@ -11,7 +11,6 @@ import io.anuke.mindustry.gen.CallClient;
import io.anuke.mindustry.io.Version;
import io.anuke.mindustry.net.Packet.ImportantPacket;
import io.anuke.mindustry.net.Packet.UnimportantPacket;
import io.anuke.mindustry.resource.Item;
import io.anuke.mindustry.world.Block;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.EntityGroup;
@ -136,17 +135,13 @@ public class Packets {
}
public static class StateSyncPacket implements Packet, UnimportantPacket{
public int[] items;
//todo fix item syncing
public float countdown, time;
public int enemies, wave;
public long timestamp;
@Override
public void write(ByteBuffer buffer) {
for(int i = 0; i < items.length; i ++){
buffer.putInt(items[i]);
}
buffer.putFloat(countdown);
buffer.putFloat(time);
buffer.putShort((short)enemies);
@ -156,12 +151,6 @@ public class Packets {
@Override
public void read(ByteBuffer buffer) {
items = new int[Item.getAllItems().size];
for(int i = 0; i < items.length; i ++){
items[i] = buffer.getInt();
}
countdown = buffer.getFloat();
time = buffer.getFloat();
enemies = buffer.getShort();

View File

@ -1,4 +0,0 @@
package io.anuke.mindustry.resource;
public interface CarryItem {
}

View File

@ -1,6 +1,6 @@
package io.anuke.mindustry.resource;
public class ItemStack implements CarryItem{
public class ItemStack{
public Item item;
public int amount;

View File

@ -1,15 +0,0 @@
package io.anuke.mindustry.resource;
public class LiquidStack implements CarryItem{
public Liquid liquid;
public float amount;
public LiquidStack(Liquid liquid, float amount){
this.liquid = liquid;
this.amount = amount;
}
public boolean equals(LiquidStack other){
return other != null && other.liquid == liquid && other.amount == amount;
}
}

View File

@ -54,7 +54,7 @@ public class Recipe {
return r;
}
public static Array<Recipe> all(){
public static Array<Recipe> getAllRecipes(){
return allRecipes;
}

View File

@ -29,7 +29,7 @@ public class ColorPickDialog extends Dialog{
cons.accept(color);
hide();
}).size(44, 48).pad(0).padBottom(-5.1f).get();
button.setChecked(players[0].getColor().equals(color));
button.setChecked(players[0].color.equals(color));
button.getStyle().imageUpColor = color;
if(i%4 == 3){

View File

@ -42,7 +42,7 @@ public class HostDialog extends FloatingDialog{
Settings.save();
});
}).size(50f, 54f).get();
button.update(() -> button.getStyle().imageUpColor = player.getColor());
button.update(() -> button.getStyle().imageUpColor = player.color);
}).width(w).height(70f).pad(4).colspan(3);
content().row();

View File

@ -222,7 +222,7 @@ public class JoinDialog extends FloatingDialog {
Settings.save();
});
}).size(50f, 54f).get();
button.update(() -> button.getStyle().imageUpColor = player.getColor());
button.update(() -> button.getStyle().imageUpColor = player.color);
}).width(w).height(70f).pad(4);
content().row();
content().add(pane).width(w + 34).pad(0);

View File

@ -17,7 +17,6 @@ import io.anuke.mindustry.ui.dialogs.FloatingDialog;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.BlockStats;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Hue;
import io.anuke.ucore.scene.Element;
import io.anuke.ucore.scene.Group;
import io.anuke.ucore.scene.actions.Actions;
@ -40,6 +39,16 @@ public class BlocksFragment implements Fragment{
private boolean shown = true;
private Recipe hoveredDescriptionRecipe;
private IntSet itemset = new IntSet();
private int[] tmpItems;
{
int size = 0;
for(Item ignored : Item.getAllItems()){
size ++;
}
tmpItems = new int[size];
}
public void build(Group parent){
InputHandler input = control.input(0);
@ -55,7 +64,7 @@ public class BlocksFragment implements Fragment{
itemtable = new Table("button");
itemtable.setVisible(() -> input.recipe == null && !state.mode.infiniteResources);
itemtable.update(() -> {
int[] items = state.inventory.readItems();
int[] items = tmpItems;
for(int i = 0; i < items.length; i ++){
if(itemset.contains(items[i]) != (items[i] > 0)){
updateItems();
@ -186,10 +195,9 @@ public class BlocksFragment implements Fragment{
table.add(image).size(size + 8);
image.update(() -> {
boolean has = (state.inventory.hasItems(r.requirements));
image.setTouchable(Touchable.enabled);
for(Element e : istack.getChildren()){
e.setColor(has ? Color.WHITE : Hue.lightness(0.33f));
e.setColor(Color.WHITE);
}
for(Player player : players){
@ -287,7 +295,7 @@ public class BlocksFragment implements Fragment{
Label reqlabel = new Label("");
reqlabel.update(()->{
int current = state.inventory.getAmount(stack.item);
int current = stack.amount;
String text = Mathf.clamp(current, 0, stack.amount) + "/" + stack.amount;
reqlabel.setColor(current < stack.amount ? Colors.get("missingitems") : Color.WHITE);
@ -364,7 +372,7 @@ public class BlocksFragment implements Fragment{
};
int index = 0;
int[] items = state.inventory.readItems();
int[] items = tmpItems;
for(int i = 0; i < items.length; i ++){
int amount = items[i];

View File

@ -118,7 +118,7 @@ public class PlayerListFragment implements Fragment{
});
button.add(stack).size(h);
button.labelWrap("[#" + player.getColor().toString().toUpperCase() + "]" + player.name).width(170f).pad(10);
button.labelWrap("[#" + player.color.toString().toUpperCase() + "]" + player.name).width(170f).pad(10);
button.add().grow();
button.addImage("icon-admin").size(14*2).visible(() -> player.isAdmin && !(!player.isLocal && Net.server())).padRight(5);

View File

@ -3,7 +3,6 @@ package io.anuke.mindustry.ui.fragments;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Align;
import static io.anuke.mindustry.Vars.*;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.input.InputHandler;
import io.anuke.mindustry.input.PlaceMode;
@ -12,6 +11,8 @@ import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.scene.Group;
import io.anuke.ucore.scene.ui.layout.Table;
import static io.anuke.mindustry.Vars.*;
public class ToolFragment implements Fragment{
private Table tools;
private InputHandler input;
@ -52,7 +53,7 @@ public class ToolFragment implements Fragment{
});
tools.setVisible(() ->
!state.is(State.menu) && mobile && ((input.recipe != null && state.inventory.hasItems(input.recipe.requirements) &&
!state.is(State.menu) && mobile && ((input.recipe != null &&
input.placeMode == PlaceMode.cursor) || confirming)
);

View File

@ -68,8 +68,6 @@ public class Block extends BaseBlock {
public boolean liquid;
/**whether this floor can be placed on.*/
public boolean placeableOn = true;
/**time it takes to break*/
public float breaktime = 18;
/**tile entity health*/
public int health = 40;
/**base block explosiveness*/

View File

@ -7,15 +7,15 @@ import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.content.fx.Fx;
import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.resource.ItemStack;
import io.anuke.mindustry.resource.Recipe;
import io.anuke.mindustry.world.blocks.types.BuildBlock.BuildEntity;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.entities.Entities;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.Vars.tilesize;
import static io.anuke.mindustry.Vars.world;
public class Placement {
public class Build {
private static final Rectangle rect = new Rectangle();
private static Array<Tile> tempTiles = new Array<>();
@ -28,17 +28,9 @@ public class Placement {
Block block = tile.isLinked() ? tile.getLinked().block() : tile.block();
Recipe result = Recipe.getByResult(block);
if(result != null){
for(ItemStack stack : result.requirements){
state.inventory.addItem(stack.item, (int)(stack.amount * breakDropAmount));
}
}
//todo add break results to core inventory
if(tile.block().drops != null){
state.inventory.addItem(tile.block().drops.item, tile.block().drops.amount);
}
if(sound) threads.run(() -> Effects.sound("break", x * tilesize, y * tilesize));
if(sound) Effects.sound("break", x * tilesize, y * tilesize);
if(!tile.block().isMultiblock() && !tile.isLinked()){
tile.setBlock(Blocks.air);
@ -56,7 +48,8 @@ public class Placement {
return block;
}
public static void placeBlock(Team team, int x, int y, Recipe recipe, int rotation, boolean effects, boolean sound){
/**Places a BuildBlock at this location. Call validPlace first.*/
public static void placeBlock(Team team, int x, int y, Recipe recipe, int rotation){
Tile tile = world.tile(x, y);
Block result = recipe.result;
@ -86,23 +79,16 @@ public class Placement {
toplace.setTeam(team);
}
}
if(effects) Effects.effect(Fx.none, worldx * tilesize, worldy * tilesize);
}
}
}else if(effects){
Effects.effect(Fx.none, x * tilesize, y * tilesize);
}
if(effects && sound){
threads.run(() -> Effects.sound("place", x * tilesize, y * tilesize));
}
}
/**Returns whether a tile can be placed at this location by this team.*/
public static boolean validPlace(Team team, int x, int y, Block type, int rotation){
Recipe recipe = Recipe.getByResult(type);
if(recipe == null || !state.inventory.hasItems(recipe.requirements)){
if(recipe == null){
return false;
}
@ -121,7 +107,7 @@ public class Placement {
if (e == null) return; //not sure why this happens?
Rectangle rect = e.hitbox.getRect(e.x, e.y);
if (Placement.rect.overlaps(rect) && !e.isFlying()) {
if (Build.rect.overlaps(rect) && !e.isFlying()) {
result[0] = true;
}
});
@ -160,13 +146,12 @@ public class Placement {
return false;
}
/**Returns whether the tile at this position is breakable by this team*/
public static boolean validBreak(Team team, int x, int y) {
Tile tile = world.tile(x, y);
if (tile == null || tile.block().unbreakable) return false;
return (!tile.isLinked() || !tile.getLinked().block().unbreakable) && tile.breakable()
&& (tile.getTeam() == Team.none || tile.getTeam() == team);
return tile != null && !tile.block().unbreakable
&& (!tile.isLinked() || !tile.getLinked().block().unbreakable) && tile.breakable() && (tile.getTeam() == Team.none || tile.getTeam() == team);
}
}

View File

@ -6,6 +6,7 @@ import com.badlogic.gdx.utils.reflect.ClassReflection;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.resource.Recipe;
import io.anuke.mindustry.world.blocks.types.Floor;
import io.anuke.mindustry.world.blocks.types.modules.InventoryModule;
import io.anuke.mindustry.world.blocks.types.modules.LiquidModule;
@ -132,10 +133,14 @@ public class Tile implements Position{
this.team = (byte)team.ordinal();
}
/**Returns the breaktime of the block, <i>or</i> the breaktime of the linked block, if this tile is linked.*/
/**Returns the break time of the block, <i>or</i> the breaktime of the linked block, if this tile is linked.*/
public float getBreakTime(){
Block block = block();
return link == 0 ? block.breaktime : getLinked().block().breaktime;
Block block = target().block();
if(Recipe.getByResult(block) != null){
return Recipe.getByResult(block).cost;
}else{
return 15f;
}
}
public void setBlock(Block type, int rotation){

View File

@ -8,7 +8,6 @@ public class Rock extends Block {
super(name);
shadow = name+"shadow";
breakable = true;
breaktime = 10;
alwaysReplace = true;
}
}