Removed shadow/world padding

This commit is contained in:
Anuken
2018-11-12 13:17:43 -05:00
83 changed files with 1375 additions and 1454 deletions

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module>
<source path="io/anuke/mindustry"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.world.Tile"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.game.Content"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.type.ItemStack"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.maps.Maps"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.world.Map"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.game.SpawnGroup"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.core.GameState"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.io.SaveFileVersion"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.ucore.entities.impl.EffectEntity"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.entities.effect"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.entities.bullet.Bullet"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.game.Team"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.maps.missions.Mission"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.type.Item"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.world.meta.BlockBar"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.maps.generation.WorldGenerator"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.entities.StatusController"/>
<extend-configuration-property name="gdx.reflect.include" value="io.anuke.mindustry.maps.Sector"/>
<extend-configuration-property name="gdx.reflect.include" value="com.badlogic.gdx.utils.Predicate"/>
</module>

View File

@@ -94,6 +94,7 @@ public class Vars{
public static float controllerMin = 0.25f;
public static float baseControllerSpeed = 11f;
public static boolean snapCamera = true;
public static ContentLoader content;
public static GameState state;
public static ThreadHandler threads;
@@ -162,6 +163,7 @@ public class Vars{
});
}
state = new GameState();
threads = new ThreadHandler();
mobile = Gdx.app.getType() == ApplicationType.Android || Gdx.app.getType() == ApplicationType.iOS || testMobile;

View File

@@ -71,6 +71,7 @@ public class BlockIndexer{
flagMap[i][j] = new ObjectSet<>();
}
}
typeMap.clear();
ores = null;
@@ -246,7 +247,7 @@ public class BlockIndexer{
for(int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++){
for(int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++){
Tile result = world.tile(x, y);
if(result.block().drops == null || !scanOres.contains(result.block().drops.item)) continue;
if( result == null || result.block().drops == null || !scanOres.contains(result.block().drops.item)) continue;
itemSet.add(result.block().drops.item);
}

View File

@@ -37,7 +37,7 @@ public class Mechs implements ContentList{
alpha = new Mech("alpha-mech", false){
int maxDrones = 3;
float buildTime = 200f;
float buildTime = 20f;
{
drillPower = 1;
@@ -53,14 +53,19 @@ public class Mechs implements ContentList{
@Override
public void updateAlt(Player player){
if(getDrones(player) < maxDrones && !TutorialSector.supressDrone() && player.timer.get(Player.timerAbility, buildTime)){
if(!Net.client()) {
AlphaDrone drone = (AlphaDrone) UnitTypes.alphaDrone.create(player.getTeam());
drone.leader = player;
drone.set(player.x, player.y);
drone.add();
if(player.isShooting && getDrones(player) < maxDrones && !TutorialSector.supressDrone()){
player.timer.get(Player.timerAbility, buildTime);
if(player.timer.getTime(Player.timerAbility) > buildTime/2f){
if(!Net.client()){
AlphaDrone drone = (AlphaDrone) UnitTypes.alphaDrone.create(player.getTeam());
drone.leader = player;
drone.set(player.x, player.y);
drone.add();
Effects.effect(UnitFx.unitLand, player);
}
}
Effects.effect(UnitFx.unitLand, player);
}
}

View File

@@ -139,7 +139,7 @@ public class Blocks extends BlockList implements ContentList{
}};
ice = new Floor("ice"){{
dragMultiplier = 0.3f;
dragMultiplier = 0.2f;
speedMultiplier = 0.4f;
minimapColor = Color.valueOf("b8eef8");
hasOres = true;

View File

@@ -30,7 +30,7 @@ public class LiquidBlocks extends BlockList implements ContentList{
thermalPump = new Pump("thermal-pump"){{
shadow = "shadow-rounded-2";
pumpAmount = 0.3f;
pumpAmount = 0.275f;
consumes.power(0.03f);
liquidCapacity = 40f;
hasPower = true;

View File

@@ -20,9 +20,9 @@ public class PowerBlocks extends BlockList implements ContentList{
}};
thermalGenerator = new LiquidHeatGenerator("thermal-generator"){{
maxLiquidGenerate = 0.5f;
maxLiquidGenerate = 4f;
powerCapacity = 40f;
powerPerLiquid = 1f;
powerPerLiquid = 0.1f;
generateEffect = BlockFx.redgeneratespark;
size = 2;
}};

View File

@@ -179,12 +179,6 @@ public class Control extends Module{
});
Events.on(WorldLoadEvent.class, event -> threads.runGraphics(() -> Events.fire(new WorldLoadGraphicsEvent())));
Events.on(TileChangeEvent.class, event -> {
if(event.tile.getTeam() == players[0].getTeam() && Recipe.getByResult(event.tile.block()) != null){
unlocks.handleContentUsed(Recipe.getByResult(event.tile.block()));
}
});
}
public void addPlayer(int index){
@@ -278,7 +272,7 @@ public class Control extends Module{
outer:
for(int i = 0; i < content.recipes().size; i ++){
Recipe recipe = content.recipes().get(i);
if(!recipe.hidden && recipe.requirements != null){
if(!recipe.isHidden() && recipe.requirements != null){
for(ItemStack stack : recipe.requirements){
if(!entity.items.has(stack.item, Math.min((int) (stack.amount * unlockResourceScaling), 2000))) continue outer;
}

View File

@@ -10,9 +10,11 @@ import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.Teams;
import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Events;
import io.anuke.ucore.core.Timers;
@@ -35,13 +37,31 @@ public class Logic extends Module{
public boolean doUpdate = true;
public Logic(){
state = new GameState();
Events.on(TileChangeEvent.class, event -> {
if(event.tile.getTeam() == defaultTeam && Recipe.getByResult(event.tile.block()) != null){
handleContent(Recipe.getByResult(event.tile.block()));
}
});
}
@Override
public void init(){
EntityQuery.init();
EntityQuery.collisions().setCollider(tilesize, world::solid);
EntityQuery.collisions().setCollider(tilesize, (x, y) -> {
Tile tile = world.tile(x, y);
return tile != null && tile.solid();
});
}
/**Handles the event of content being used by either the player or some block.*/
public void handleContent(UnlockableContent content){
if(world.getSector() != null){
world.getSector().currentMission().onContentUsed(content);
}
if(!headless){
control.unlocks.unlockContent(content);
}
}
public void play(){
@@ -142,7 +162,8 @@ public class Logic extends Module{
world.sectors.completeSector(world.getSector().x, world.getSector().y);
world.sectors.save();
if(!headless){
if(!headless && !Net.client()){
ui.missions.show(world.getSector());
}
@@ -151,7 +172,6 @@ public class Logic extends Module{
@Override
public void update(){
if(threads.isEnabled() && !threads.isOnThread()) return;
if(Vars.control != null){
control.runUpdateLogic();
@@ -159,15 +179,10 @@ public class Logic extends Module{
if(!state.is(State.menu)){
if(!Net.client() && !world.isInvalidMap()){
updateSectors();
checkGameOver();
}
if(!state.isPaused()){
Timers.update();
if(!state.mode.disableWaveTimer && !state.mode.disableWaves){
if(!state.mode.disableWaveTimer && !state.mode.disableWaves && !state.gameOver){
state.wavetime -= Timers.delta();
}
@@ -216,10 +231,11 @@ public class Logic extends Module{
world.pathfinder.update();
}
}
if(threads.isEnabled()){
netServer.update();
if(!Net.client() && !world.isInvalidMap()){
updateSectors();
checkGameOver();
}
}
}
}

View File

@@ -165,14 +165,17 @@ public class NetClient extends Module{
public static void onKick(KickReason reason){
netClient.disconnectQuietly();
state.set(State.menu);
if(!reason.quiet){
if(reason.extraText() != null){
ui.showText(reason.toString(), reason.extraText());
}else{
ui.showText("$text.disconnect", reason.toString());
threads.runGraphics(() -> {
if(!reason.quiet){
if(reason.extraText() != null){
ui.showText(reason.toString(), reason.extraText());
}else{
ui.showText("$text.disconnect", reason.toString());
}
}
}
ui.loadfrag.hide();
ui.loadfrag.hide();
});
}
@Remote(variants = Variant.both)
@@ -396,11 +399,11 @@ public class NetClient extends Module{
quiet = true;
}
public synchronized void addRemovedEntity(int id){
public void addRemovedEntity(int id){
removed.add(id);
}
public synchronized boolean isEntityUsed(int id){
public boolean isEntityUsed(int id){
return removed.contains(id);
}
@@ -411,11 +414,9 @@ public class NetClient extends Module{
BuildRequest[] requests;
synchronized(player.getPlaceQueue()){
requests = new BuildRequest[player.getPlaceQueue().size];
for(int i = 0; i < requests.length; i++){
requests[i] = player.getPlaceQueue().get(i);
}
requests = new BuildRequest[player.getPlaceQueue().size];
for(int i = 0; i < requests.length; i++){
requests[i] = player.getPlaceQueue().get(i);
}
Call.onClientShapshot(lastSent++, TimeUtils.millis(), player.x, player.y,

View File

@@ -416,7 +416,6 @@ public class NetServer extends Module{
}
public void update(){
if(threads.isEnabled() && !threads.isOnThread()) return;
if(!headless && !closing && Net.server() && state.is(State.menu)){
closing = true;

View File

@@ -248,11 +248,12 @@ public class Renderer extends RendererModule{
overlays.drawBottom();
drawAndInterpolate(playerGroup, p -> true, Player::drawBuildRequests);
Shaders.shield.color.set(Palette.accent);
Graphics.beginShaders(Shaders.shield);
EntityDraw.draw(shieldGroup);
EntityDraw.drawWith(shieldGroup, shield -> true, shield -> ((ShieldEntity)shield).drawOver());
Draw.color(Palette.accent);
Graphics.endShaders();
Draw.color();
overlays.drawTop();

View File

@@ -1,80 +1,35 @@
package io.anuke.mindustry.core;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.utils.Queue;
import com.badlogic.gdx.utils.TimeUtils;
import io.anuke.ucore.core.Settings;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.util.Log;
import io.anuke.ucore.util.Threads;
import io.anuke.ucore.util.Threads.ThreadInfoProvider;
import static io.anuke.mindustry.Vars.control;
import static io.anuke.mindustry.Vars.logic;
public class ThreadHandler implements ThreadInfoProvider{
private final Queue<Runnable> toRun = new Queue<>();
private Thread thread, graphicsThread;
private final Object updateLock = new Object();
private float delta = 1f;
private float smoothDelta = 1f;
private long frame = 0, lastDeltaUpdate;
private float framesSinceUpdate;
private boolean enabled;
private boolean rendered = true;
private long lastFrameTime;
public ThreadHandler(){
Threads.setThreadInfoProvider(this);
graphicsThread = Thread.currentThread();
Timers.setDeltaProvider(() -> {
float result = isOnThread() ? delta : Gdx.graphics.getDeltaTime() * 60f;
return Math.min(Float.isNaN(result) ? 1f : result, 15f);
float result = Gdx.graphics.getDeltaTime() * 60f;
return Math.min(Float.isNaN(result) || Float.isInfinite(result) ? 1f : result, 15f);
});
}
public void run(Runnable r){
if(enabled){
synchronized(toRun){
toRun.addLast(r);
}
}else{
r.run();
}
r.run();
}
public void runGraphics(Runnable r){
if(enabled){
Gdx.app.postRunnable(r);
}else{
r.run();
}
r.run();
}
public void runDelay(Runnable r){
if(enabled){
synchronized(toRun){
toRun.addLast(r);
}
}else{
Gdx.app.postRunnable(r);
}
}
public int getTPS(){
if(smoothDelta == 0f){
return 60;
}
return (int) (60 / smoothDelta);
Gdx.app.postRunnable(r);
}
public long getFrameID(){
return enabled ? frame : Gdx.graphics.getFrameId();
}
public float getFramesSinceUpdate(){
return framesSinceUpdate;
return Gdx.graphics.getFrameId();
}
public void handleBeginRender(){
@@ -95,119 +50,16 @@ public class ThreadHandler implements ThreadInfoProvider{
}
}
}
if(!enabled) return;
framesSinceUpdate += Timers.delta();
synchronized(updateLock){
rendered = true;
updateLock.notify();
}
}
public boolean isEnabled(){
return enabled;
}
public void setEnabled(boolean enabled){
if(enabled){
logic.doUpdate = false;
Timers.runTask(2f, () -> {
if(thread != null){
thread.interrupt();
thread = null;
}
thread = new Thread(this::runLogic);
thread.setDaemon(true);
thread.setName("Update Thread");
thread.start();
Log.info("Starting logic thread.");
this.enabled = true;
});
}else{
this.enabled = false;
if(thread != null){
thread.interrupt();
thread = null;
}
Timers.runTask(2f, () -> {
logic.doUpdate = true;
});
}
}
public boolean doInterpolate(){
return enabled && Gdx.graphics.getFramesPerSecond() - getTPS() > 20 && getTPS() < 30;
}
public boolean isOnThread(){
return Thread.currentThread() == thread;
}
@Override
public boolean isOnLogicThread() {
return !enabled || Thread.currentThread() == thread;
return true;
}
@Override
public boolean isOnGraphicsThread() {
return !enabled || Thread.currentThread() == graphicsThread;
return true;
}
private void runLogic(){
try{
while(true){
long time = TimeUtils.nanoTime();
while(true){
Runnable r;
synchronized(toRun){
if(toRun.size > 0){
r = toRun.removeFirst();
}else{
break;
}
}
r.run();
}
logic.doUpdate = true;
logic.update();
logic.doUpdate = false;
long elapsed = TimeUtils.nanosToMillis(TimeUtils.timeSinceNanos(time));
long target = (long) ((1000) / 60f);
if(elapsed < target){
Thread.sleep(target - elapsed);
}
synchronized(updateLock){
while(!rendered){
updateLock.wait();
}
rendered = false;
}
long actuallyElapsed = TimeUtils.nanosToMillis(TimeUtils.timeSinceNanos(time));
delta = Math.max(actuallyElapsed, target) / 1000f * 60f;
if(TimeUtils.timeSinceMillis(lastDeltaUpdate) > 1000){
lastDeltaUpdate = TimeUtils.millis();
smoothDelta = delta;
}
frame++;
framesSinceUpdate = 0;
}
}catch(InterruptedException ex){
Log.info("Stopping logic thread.");
}catch(Throwable ex){
control.setError(ex);
}
}
}

View File

@@ -28,6 +28,7 @@ import io.anuke.ucore.scene.ui.TextField.TextFieldFilter;
import io.anuke.ucore.scene.ui.TooltipManager;
import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.scene.ui.layout.Unit;
import io.anuke.ucore.util.Threads;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.ucore.scene.actions.Actions.*;
@@ -154,6 +155,7 @@ public class UI extends SceneModule{
load = new LoadDialog();
levels = new CustomGameDialog();
language = new LanguageDialog();
unlocks = new UnlocksDialog();
settings = new SettingsMenuDialog();
host = new HostDialog();
paused = new PausedDialog();
@@ -164,7 +166,6 @@ public class UI extends SceneModule{
traces = new TraceDialog();
maps = new MapsDialog();
localplayers = new LocalPlayerDialog();
unlocks = new UnlocksDialog();
content = new ContentInfoDialog();
sectors = new SectorsDialog();
missions = new MissionDialog();
@@ -239,6 +240,8 @@ public class UI extends SceneModule{
}
public void showInfoFade(String info){
Threads.assertGraphics();
Table table = new Table();
table.setFillParent(true);
table.actions(Actions.fadeOut(7f, Interpolation.fade), Actions.removeActor());
@@ -247,6 +250,8 @@ public class UI extends SceneModule{
}
public void showInfo(String info){
Threads.assertGraphics();
new Dialog("$text.info.title", "dialog"){{
getCell(content()).growX();
content().margin(15).add(info).width(400f).wrap().get().setAlignment(Align.center, Align.center);
@@ -255,6 +260,8 @@ public class UI extends SceneModule{
}
public void showInfo(String info, Runnable clicked){
Threads.assertGraphics();
new Dialog("$text.info.title", "dialog"){{
getCell(content()).growX();
content().margin(15).add(info).width(400f).wrap().get().setAlignment(Align.center, Align.center);

View File

@@ -70,7 +70,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
public TargetTrait moveTarget;
private float walktime;
private Queue<BuildRequest> placeQueue = new ThreadQueue<>();
private Queue<BuildRequest> placeQueue = new Queue<>();
private Tile mining;
private CarriableTrait carrying;
private Trail trail = new Trail(12);
@@ -323,7 +323,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
}
if(floor.isLiquid){
Draw.tint(Color.WHITE, floor.liquidColor, Mathf.clamp(drownTime));
Draw.tint(Color.WHITE, floor.liquidColor, drownTime);
}else{
Draw.tint(Color.WHITE);
}
@@ -421,55 +421,53 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
/**Draw all current build requests. Does not draw the beam effect, only the positions.*/
public void drawBuildRequests(){
synchronized(getPlaceQueue()){
for(BuildRequest request : getPlaceQueue()){
if(getCurrentRequest() == request) continue;
for(BuildRequest request : getPlaceQueue()){
if(getCurrentRequest() == request) continue;
if(request.breaking){
Block block = world.tile(request.x, request.y).target().block();
if(request.breaking){
Block block = world.tile(request.x, request.y).target().block();
//draw removal request
Lines.stroke(2f);
//draw removal request
Lines.stroke(2f);
Draw.color(Palette.removeBack);
Draw.color(Palette.removeBack);
float rad = Mathf.absin(Timers.time(), 7f, 1f) + block.size * tilesize / 2f - 1;
float rad = Mathf.absin(Timers.time(), 7f, 1f) + block.size * tilesize / 2f - 1;
Lines.square(
request.x * tilesize + block.offset(),
request.y * tilesize + block.offset() - 1,
rad);
Lines.square(
request.x * tilesize + block.offset(),
request.y * tilesize + block.offset() - 1,
rad);
Draw.color(Palette.remove);
Draw.color(Palette.remove);
Lines.square(
request.x * tilesize + block.offset(),
request.y * tilesize + block.offset(),
rad);
}else{
//draw place request
Lines.stroke(2f);
Lines.square(
request.x * tilesize + block.offset(),
request.y * tilesize + block.offset(),
rad);
}else{
//draw place request
Lines.stroke(2f);
Draw.color(Palette.accentBack);
Draw.color(Palette.accentBack);
float rad = Mathf.absin(Timers.time(), 7f, 1f) - 2f + request.recipe.result.size * tilesize / 2f;
float rad = Mathf.absin(Timers.time(), 7f, 1f) - 2f + request.recipe.result.size * tilesize / 2f;
Lines.square(
request.x * tilesize + request.recipe.result.offset(),
request.y * tilesize + request.recipe.result.offset() - 1,
rad);
Lines.square(
request.x * tilesize + request.recipe.result.offset(),
request.y * tilesize + request.recipe.result.offset() - 1,
rad);
Draw.color(Palette.accent);
Draw.color(Palette.accent);
Lines.square(
request.x * tilesize + request.recipe.result.offset(),
request.y * tilesize + request.recipe.result.offset(),
rad);
}
Lines.square(
request.x * tilesize + request.recipe.result.offset(),
request.y * tilesize + request.recipe.result.offset(),
rad);
}
Draw.reset();
}
Draw.reset();
}
//endregion
@@ -512,14 +510,14 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
achievedFlight = true;
}
if(boostHeat <= liftoffBoost + 0.05f && achievedFlight){
if(boostHeat <= liftoffBoost + 0.05f && achievedFlight && !mech.flying){
if(tile != null){
if(mech.shake > 1f){
Effects.shake(mech.shake, mech.shake, this);
}
Effects.effect(UnitFx.unitLand, tile.floor().minimapColor, x, y, tile.floor().isLiquid ? 1f : 0.5f);
}
if(!mech.flying) mech.onLand(this);
mech.onLand(this);
achievedFlight = false;
}

View File

@@ -259,27 +259,25 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
@Override
public void update(){
synchronized(Tile.tileSetLock){
//TODO better smoke effect, this one is awful
if(health != 0 && health < tile.block().health && !(tile.block() instanceof Wall) &&
Mathf.chance(0.009f * Timers.delta() * (1f - health / tile.block().health))){
//TODO better smoke effect, this one is awful
if(health != 0 && health < tile.block().health && !(tile.block() instanceof Wall) &&
Mathf.chance(0.009f * Timers.delta() * (1f - health / tile.block().health))){
Effects.effect(Fx.smoke, x + Mathf.range(4), y + Mathf.range(4));
}
Effects.effect(Fx.smoke, x + Mathf.range(4), y + Mathf.range(4));
}
timeScaleDuration -= Timers.delta();
if(timeScaleDuration <= 0f || !tile.block().canOverdrive){
timeScale = 1f;
}
timeScaleDuration -= Timers.delta();
if(timeScaleDuration <= 0f || !tile.block().canOverdrive){
timeScale = 1f;
}
if(health <= 0){
onDeath();
}
Block previous = tile.block();
tile.block().update(tile);
if(tile.block() == previous && cons != null){
cons.update(this);
}
if(health <= 0){
onDeath();
}
Block previous = tile.block();
tile.block().update(tile);
if(tile.block() == previous && cons != null){
cons.update(this);
}
}

View File

@@ -278,7 +278,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
drownTime = Mathf.clamp(drownTime);
if(drownTime >= 0.999f){
if(drownTime >= 0.999f && !Net.client()){
damage(health + 1);
}

View File

@@ -88,14 +88,13 @@ public interface BuilderTrait extends Entity{
}
default void readBuilding(DataInput input, boolean applyChanges) throws IOException{
synchronized(getPlaceQueue()){
if(applyChanges) getPlaceQueue().clear();
if(applyChanges) getPlaceQueue().clear();
byte type = input.readByte();
if(type != -1){
int position = input.readInt();
float progress = input.readFloat();
BuildRequest request;
byte type = input.readByte();
if(type != -1){
int position = input.readInt();
float progress = input.readFloat();
BuildRequest request;
if(type == 1){ //remove
request = new BuildRequest(Pos.x(position), Pos.y(position));
@@ -105,13 +104,12 @@ public interface BuilderTrait extends Entity{
request = new BuildRequest(Pos.x(position), Pos.y(position), rotation, content.recipe(recipe));
}
request.progress = progress;
request.progress = progress;
if(applyChanges){
getPlaceQueue().addLast(request);
}else if(isBuilding()){
getCurrentRequest().progress = progress;
}
if(applyChanges){
getPlaceQueue().addLast(request);
}else if(isBuilding()){
getCurrentRequest().progress = progress;
}
}
}
@@ -126,13 +124,11 @@ public interface BuilderTrait extends Entity{
* Otherwise, a new place request is added to the queue.
*/
default void replaceBuilding(int x, int y, int rotation, Recipe recipe){
synchronized(getPlaceQueue()){
for(BuildRequest request : getPlaceQueue()){
if(request.x == x && request.y == y){
clearBuilding();
addBuildRequest(request);
return;
}
for(BuildRequest request : getPlaceQueue()){
if(request.x == x && request.y == y){
clearBuilding();
addBuildRequest(request);
return;
}
}
@@ -146,18 +142,16 @@ public interface BuilderTrait extends Entity{
/**Add another build requests to the tail of the queue, if it doesn't exist there yet.*/
default void addBuildRequest(BuildRequest place){
synchronized(getPlaceQueue()){
for(BuildRequest request : getPlaceQueue()){
if(request.x == place.x && request.y == place.y){
return;
}
for(BuildRequest request : getPlaceQueue()){
if(request.x == place.x && request.y == place.y){
return;
}
Tile tile = world.tile(place.x, place.y);
if(tile != null && tile.entity instanceof BuildEntity){
place.progress = tile.<BuildEntity>entity().progress;
}
getPlaceQueue().addLast(place);
}
Tile tile = world.tile(place.x, place.y);
if(tile != null && tile.entity instanceof BuildEntity){
place.progress = tile.<BuildEntity>entity().progress;
}
getPlaceQueue().addLast(place);
}
/**
@@ -165,9 +159,7 @@ public interface BuilderTrait extends Entity{
* May return null.
*/
default BuildRequest getCurrentRequest(){
synchronized(getPlaceQueue()){
return getPlaceQueue().size == 0 ? null : getPlaceQueue().first();
}
return getPlaceQueue().size == 0 ? null : getPlaceQueue().first();
}
/**
@@ -279,18 +271,15 @@ public interface BuilderTrait extends Entity{
/**Draw placement effects for an entity. This includes mining*/
default void drawBuilding(Unit unit){
BuildRequest request;
synchronized(getPlaceQueue()){
if(!isBuilding()){
if(getMineTile() != null){
drawMining(unit);
}
return;
if(!isBuilding()){
if(getMineTile() != null){
drawMining(unit);
}
request = getCurrentRequest();
return;
}
request = getCurrentRequest();
Tile tile = world.tile(request.x, request.y);
if(unit.distanceTo(tile) > placeDistance){

View File

@@ -28,10 +28,7 @@ import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Timer;
import io.anuke.ucore.util.*;
import java.io.DataInput;
import java.io.DataOutput;
@@ -316,8 +313,8 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
if(target != null) behavior();
if(!isWave && !isFlying()){
x = Mathf.clamp(x, 0, world.width() * tilesize);
y = Mathf.clamp(y, 0, world.height() * tilesize);
x = Mathf.clamp(x, tilesize/2f, world.width() * tilesize - tilesize/2f);
y = Mathf.clamp(y, tilesize/2f, world.height() * tilesize - tilesize/2f);
}
}

View File

@@ -1,15 +1,21 @@
package io.anuke.mindustry.entities.units.types;
import com.badlogic.gdx.math.Vector2;
import io.anuke.annotations.Annotations.Loc;
import io.anuke.annotations.Annotations.Remote;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.fx.UnitFx;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.Predict;
import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.entities.units.FlyingUnit;
import io.anuke.mindustry.entities.units.UnitCommand;
import io.anuke.mindustry.entities.units.UnitState;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.AmmoType;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.util.Mathf;
import java.io.DataInput;
@@ -22,7 +28,8 @@ import static io.anuke.mindustry.Vars.players;
public class AlphaDrone extends FlyingUnit {
static final float followDistance = 80f;
public Unit leader;
public Player leader;
public final UnitState attack = new UnitState() {
@Override
public void update() {
@@ -32,15 +39,18 @@ public class AlphaDrone extends FlyingUnit {
}
TargetTrait last = target;
target = leader;
if(last == null){
circle(50f);
circle(leader.isShooting ? 60f : 0f);
}
target = last;
if(distanceTo(leader) < followDistance){
targetClosest();
}else{
target = null;
}
if(target != null){
attack(50f);
@@ -51,9 +61,20 @@ public class AlphaDrone extends FlyingUnit {
getWeapon().update(AlphaDrone.this, to.x, to.y);
}
}
if(!leader.isShooting && distanceTo(leader) < 8f){
Call.onAlphaDroneFade(AlphaDrone.this);
}
}
};
@Remote(called = Loc.server)
public static void onAlphaDroneFade(BaseUnit drone){
if(drone == null) return;
drone.remove();
Effects.effect(UnitFx.pickup, drone);
}
@Override
public void onCommand(UnitCommand command){
//nuh

View File

@@ -40,12 +40,11 @@ import static io.anuke.mindustry.Vars.unitGroups;
import static io.anuke.mindustry.Vars.world;
public class Drone extends FlyingUnit implements BuilderTrait{
protected static float discoverRange = 120f;
protected static int timerRepairEffect = timerIndex++;
protected Item targetItem;
protected Tile mineTile;
protected Queue<BuildRequest> placeQueue = new ThreadQueue<>();
protected Queue<BuildRequest> placeQueue = new Queue<>();
protected boolean isBreaking;
public final UnitState
@@ -250,14 +249,12 @@ public class Drone extends FlyingUnit implements BuilderTrait{
for(BaseUnit unit : group.all()){
if(unit instanceof Drone){
Drone drone = (Drone)unit;
synchronized(drone.getPlaceQueue()){
if(drone.isBuilding()){
//stop building if opposite building begins.
BuildRequest req = drone.getCurrentRequest();
if(req.breaking != event.breaking && req.x == event.tile.x && req.y == event.tile.y){
drone.clearBuilding();
drone.setState(drone.repair);
}
if(drone.isBuilding()){
//stop building if opposite building begins.
BuildRequest req = drone.getCurrentRequest();
if(req.breaking != event.breaking && req.x == event.tile.x && req.y == event.tile.y){
drone.clearBuilding();
drone.setState(drone.repair);
}
}
@@ -319,6 +316,10 @@ public class Drone extends FlyingUnit implements BuilderTrait{
TileEntity entity = (TileEntity) target;
entity.health += type.healSpeed * Timers.delta();
entity.health = Mathf.clamp(entity.health, 0, entity.tile.block().health);
if(timer.get(timerRepairEffect, 30)){
Effects.effect(BlockFx.healBlockFull, Palette.heal, entity.x, entity.y, entity.tile.block().size);
}
}
updateBuilding(this);

View File

@@ -19,14 +19,6 @@ public class Unlocks{
Settings.setSerializer(ContentType.class, (stream, t) -> stream.writeInt(t.ordinal()), stream -> ContentType.values()[stream.readInt()]);
}
/**Handles the event of content being used by either the player or some block.*/
public void handleContentUsed(UnlockableContent content){
if(world.getSector() != null){
world.getSector().currentMission().onContentUsed(content);
}
unlockContent(content);
}
/** Returns whether or not this piece of content is unlocked yet.*/
public boolean isUnlocked(UnlockableContent content){
return rootSet().isUnlocked(content) || currentSet().isUnlocked(content);

View File

@@ -106,32 +106,29 @@ public class BlockRenderer{
for(int x = minx; x <= maxx; x++){
for(int y = miny; y <= maxy; y++){
boolean expanded = (Math.abs(x - avgx) > rangex || Math.abs(y - avgy) > rangey);
Tile tile = world.rawTile(x, y);
synchronized(Tile.tileSetLock){
Tile tile = world.rawTile(x, y);
if(tile != null){
Block block = tile.block();
Team team = tile.getTeam();
if(tile != null){
Block block = tile.block();
Team team = tile.getTeam();
if(!expanded && block != Blocks.air && world.isAccessible(x, y)){
tile.block().drawShadow(tile);
}
if(!expanded && block != Blocks.air && world.isAccessible(x, y)){
tile.block().drawShadow(tile);
if(block != Blocks.air){
if(!expanded){
addRequest(tile, Layer.block);
teamChecks.add(team.ordinal());
}
if(block != Blocks.air){
if(!expanded){
addRequest(tile, Layer.block);
teamChecks.add(team.ordinal());
if(block.expanded || !expanded){
if(block.layer != null && block.isLayer(tile)){
addRequest(tile, block.layer);
}
if(block.expanded || !expanded){
if(block.layer != null && block.isLayer(tile)){
addRequest(tile, block.layer);
}
if(block.layer2 != null && block.isLayer2(tile)){
addRequest(tile, block.layer2);
}
if(block.layer2 != null && block.isLayer2(tile)){
addRequest(tile, block.layer2);
}
}
}
@@ -171,16 +168,14 @@ public class BlockRenderer{
layerBegins(req.layer);
}
synchronized(Tile.tileSetLock){
Block block = req.tile.block();
Block block = req.tile.block();
if(req.layer == Layer.block){
block.draw(req.tile);
}else if(req.layer == block.layer){
block.drawLayer(req.tile);
}else if(req.layer == block.layer2){
block.drawLayer2(req.tile);
}
if(req.layer == Layer.block){
block.draw(req.tile);
}else if(req.layer == block.layer){
block.drawLayer(req.tile);
}else if(req.layer == block.layer2){
block.drawLayer2(req.tile);
}
lastLayer = req.layer;
@@ -199,17 +194,16 @@ public class BlockRenderer{
BlockRequest req = requests.get(index);
if(req.tile.getTeam() != team) continue;
synchronized(Tile.tileSetLock){
Block block = req.tile.block();
Block block = req.tile.block();
if(req.layer == Layer.block){
block.draw(req.tile);
}else if(req.layer == block.layer){
block.drawLayer(req.tile);
}else if(req.layer == block.layer2){
block.drawLayer2(req.tile);
}
if(req.layer == Layer.block){
block.draw(req.tile);
}else if(req.layer == block.layer){
block.drawLayer(req.tile);
}else if(req.layer == block.layer2){
block.drawLayer2(req.tile);
}
}
}

View File

@@ -74,20 +74,18 @@ public class MinimapRenderer implements Disposable{
dx = Mathf.clamp(dx, sz, world.width() - sz);
dy = Mathf.clamp(dy, sz, world.height() - sz);
synchronized(units){
rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize);
Graphics.beginClip(x, y, w, h);
rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize);
Graphics.beginClip(x, y, w, h);
for(Unit unit : units){
float rx = (unit.x - rect.x) / rect.width * w, ry = (unit.y - rect.y) / rect.width * h;
Draw.color(unit.getTeam().color);
Draw.rect("white", x + rx, y + ry, w / (sz * 2), h / (sz * 2));
}
Draw.color();
Graphics.endClip();
for(Unit unit : units){
float rx = (unit.x - rect.x) / rect.width * w, ry = (unit.y - rect.y) / rect.width * h;
Draw.color(unit.getTeam().color);
Draw.rect("white", x + rx, y + ry, w / (sz * 2), h / (sz * 2));
}
Draw.color();
Graphics.endClip();
}
public TextureRegion getRegion(){
@@ -128,11 +126,9 @@ public class MinimapRenderer implements Disposable{
dx = Mathf.clamp(dx, sz, world.width() - sz);
dy = Mathf.clamp(dy, sz, world.height() - sz);
synchronized(units){
rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize);
units.clear();
Units.getNearby(rect, units::add);
}
rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize);
units.clear();
Units.getNearby(rect, units::add);
}
private int colorFor(Tile tile){

View File

@@ -53,10 +53,7 @@ public class OverlayRenderer{
//draw config selected block
if(input.frag.config.isShown()){
Tile tile = input.frag.config.getSelectedTile();
synchronized(Tile.tileSetLock){
tile.block().drawConfigure(tile);
}
tile.block().drawConfigure(tile);
}
input.drawTop();
@@ -113,53 +110,52 @@ public class OverlayRenderer{
Draw.reset();
}
synchronized(Tile.tileSetLock){
Block block = target.block();
TileEntity entity = target.entity;
Block block = target.block();
TileEntity entity = target.entity;
if(entity != null){
int[] values = {0, 0};
boolean[] doDraw = {false};
if(entity != null){
int[] values = {0, 0};
boolean[] doDraw = {false};
Runnable drawbars = () -> {
for(BlockBar bar : block.bars.list()){
float offset = Mathf.sign(bar.top) * (block.size / 2f * tilesize + 2f + (bar.top ? values[0] : values[1]));
Runnable drawbars = () -> {
for(BlockBar bar : block.bars.list()){
float offset = Mathf.sign(bar.top) * (block.size / 2f * tilesize + 2f + (bar.top ? values[0] : values[1]));
float value = bar.value.get(target);
float value = bar.value.get(target);
if(MathUtils.isEqual(value, -1f)) continue;
if(MathUtils.isEqual(value, -1f)) continue;
if(doDraw[0]){
drawBar(bar.type.color, target.drawx(), target.drawy() + offset, value);
}
if(bar.top)
values[0]++;
else
values[1]++;
if(doDraw[0]){
drawBar(bar.type.color, target.drawx(), target.drawy() + offset, value);
}
};
drawbars.run();
if(values[0] > 0){
drawEncloser(target.drawx(), target.drawy() + block.size * tilesize / 2f + 2f, values[0]);
if(bar.top)
values[0]++;
else
values[1]++;
}
};
if(values[1] > 0){
drawEncloser(target.drawx(), target.drawy() - block.size * tilesize / 2f - 2f - values[1], values[1]);
}
drawbars.run();
doDraw[0] = true;
values[0] = 0;
values[1] = 1;
drawbars.run();
if(values[0] > 0){
drawEncloser(target.drawx(), target.drawy() + block.size * tilesize / 2f + 2f, values[0]);
}
if(values[1] > 0){
drawEncloser(target.drawx(), target.drawy() - block.size * tilesize / 2f - 2f - values[1], values[1]);
}
target.block().drawSelect(target);
doDraw[0] = true;
values[0] = 0;
values[1] = 1;
drawbars.run();
}
target.block().drawSelect(target);
}
}

View File

@@ -3,7 +3,6 @@ package io.anuke.mindustry.graphics;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.FloatArray;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.graphics.Draw;
@@ -168,9 +167,7 @@ public class Shaders{
}
public static class Shield extends Shader{
public static final int MAX_HITS = 3 * 64;
public Color color = new Color();
public FloatArray hits = new FloatArray();
//public Color color = new Color();
public Shield(){
super("shield", "default");
@@ -179,12 +176,9 @@ public class Shaders{
@Override
public void apply(){
float scaling = Core.cameraScale / 4f / Core.camera.zoom;
if(hits.size > 0){
shader.setUniform3fv("u_hits[0]", hits.items, 0, Math.min(hits.size, MAX_HITS));
shader.setUniformi("u_hitamount", Math.min(hits.size, MAX_HITS) / 3);
}
shader.setUniformf("u_dp", Unit.dp.scl(1f));
shader.setUniformf("u_color", color);
//shader.setUniformf("u_color", color);
shader.setUniformf("u_time", Timers.time() / Unit.dp.scl(1f));
shader.setUniformf("u_scaling", scaling);
shader.setUniformf("u_offset",

View File

@@ -22,7 +22,7 @@ public class Trail{
this.length = length;
}
public synchronized void update(float curx, float cury){
public void update(float curx, float cury){
if(Vector2.dst(curx, cury, lastX, lastY) >= maxJump){
points.clear();
}
@@ -39,11 +39,11 @@ public class Trail{
lastY = cury;
}
public synchronized void clear(){
public void clear(){
points.clear();
}
public synchronized void draw(Color color, float stroke){
public void draw(Color color, float stroke){
Draw.color(color);
for(int i = 0; i < points.size - 2; i += 2){

View File

@@ -430,7 +430,7 @@ public class MobileInput extends InputHandler implements GestureListener{
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button){
if(state.is(State.menu)) return false;
if(state.is(State.menu) || player.isDead()) return false;
//get tile on cursor
Tile cursor = tileAt(screenX, screenY);
@@ -519,7 +519,7 @@ public class MobileInput extends InputHandler implements GestureListener{
@Override
public boolean longPress(float x, float y){
if(state.is(State.menu) || mode == none) return false;
if(state.is(State.menu) || mode == none || player.isDead()) return false;
//get tile on cursor
Tile cursor = tileAt(x, y);
@@ -535,7 +535,7 @@ public class MobileInput extends InputHandler implements GestureListener{
if(mode == breaking){
Effects.effect(Fx.tapBlock, cursor.worldx(), cursor.worldy(), 1f);
}else{
}else if(recipe != null){
Effects.effect(Fx.tapBlock, cursor.worldx() + recipe.result.offset(), cursor.worldy() + recipe.result.offset(), recipe.result.size);
}
@@ -595,7 +595,7 @@ public class MobileInput extends InputHandler implements GestureListener{
@Override
public void update(){
if(state.is(State.menu)){
if(state.is(State.menu) || player.isDead()){
selection.clear();
removals.clear();
mode = none;

View File

@@ -47,23 +47,15 @@ public class MapIO{
data.position(0, 0);
TileDataMarker marker = data.newDataMarker();
Color color = new Color();
for(int y = 0; y < data.height(); y++){
for(int x = 0; x < data.width(); x++){
data.read(marker);
byte elev = y >= data.height() - 1 ? 0 : data.read(x, y + 1, DataPosition.elevation);
Block floor = content.block(marker.floor);
Block wall = content.block(marker.wall);
int wallc = ColorMapper.getBlockColor(wall);
if(wallc == 0 && (wall.update || wall.solid || wall.breakable)) wallc = Team.all[marker.team].intColor;
wallc = wallc == 0 ? ColorMapper.getBlockColor(floor) : wallc;
if(marker.elevation > 0){
float scaling = 1f + marker.elevation / 8f;
color.set(wallc);
color.mul(scaling, scaling, scaling, 1f);
wallc = Color.rgba8888(color);
}
pixmap.drawPixel(x, pixmap.getHeight() - 1 - y, wallc);
int color = ColorMapper.colorFor(floor, wall, Team.all[marker.team], marker.elevation + 1, elev > marker.elevation ? (byte)(1 << 6) : (byte)0);
pixmap.drawPixel(x, pixmap.getHeight() - 1 - y, color);
}
}

View File

@@ -2,6 +2,7 @@ package io.anuke.mindustry.maps;
import com.badlogic.gdx.utils.IntIntMap;
import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.ucore.util.Bundles;
public class MapMeta{
public final int version;
@@ -18,15 +19,19 @@ public class MapMeta{
}
public String author(){
return tags.get("author", "unknown");
return tag("author");
}
public String description(){
return tags.get("description", "unknown");
return tag("description");
}
public String name(){
return tags.get("name", "unknown");
return tag("name");
}
public String tag(String name){
return tags.containsKey(name) && !tags.get(name).trim().isEmpty() ? tags.get(name): Bundles.get("text.unknown");
}
public boolean hasOreGen(){

View File

@@ -23,10 +23,10 @@ public class SectorPresets{
public SectorPresets(){
//base tutorial mission (disabled)
/*add(new SectorPreset(0, 0,
//base tutorial mission
add(new SectorPreset(0, 0,
TutorialSector.getMissions(),
Array.with(Items.copper, Items.coal, Items.lead)));*/
Array.with(Items.copper, Items.coal, Items.lead)));
//command center mission
add(new SectorPreset(0, 1,
@@ -56,7 +56,8 @@ public class SectorPresets{
Missions.blockRecipe(ProductionBlocks.waterExtractor),
new ContentMission(Items.biomatter),
Missions.blockRecipe(CraftingBlocks.biomatterCompressor),
new ContentMission(Liquids.oil)
new ContentMission(Liquids.oil),
new BattleMission()
),
Array.with(Items.copper, Items.lead, Items.coal, Items.titanium)));
}
@@ -69,6 +70,8 @@ public class SectorPresets{
return presets.get(x, y);
}
public GridMap<SectorPreset> getPresets() { return presets; }
private void add(SectorPreset preset){
presets.put(preset.x, preset.y, preset);
orePresets.put(preset.x, preset.y, preset.ores);

View File

@@ -41,7 +41,7 @@ public class Sectors{
private final AsyncExecutor executor = new AsyncExecutor(6);
public void playSector(Sector sector){
if(sector.hasSave() && SaveIO.breakingVersions.contains(sector.getSave().getBuild())){
if(!headless && sector.hasSave() && SaveIO.breakingVersions.contains(sector.getSave().getBuild())){
sector.getSave().delete();
ui.showInfo("$text.save.old");
}
@@ -88,8 +88,6 @@ public class Sectors{
public Difficulty getDifficulty(Sector sector){
if(sector.difficulty == 0){
//yes, this means hard tutorial difficulty
//(((have fun)))
return Difficulty.hard;
}else if(sector.difficulty < 4){
return Difficulty.normal;
@@ -158,7 +156,7 @@ public class Sectors{
}
grid.clear();
Array<Sector> out = Settings.getObject("sectors", Array.class, Array::new);
Array<Sector> out = Settings.getObject("sector-data-2", Array.class, Array::new);
for(Sector sector : out){
@@ -187,7 +185,7 @@ public class Sectors{
}
}
Settings.putObject("sectors", out);
Settings.putObject("sector-data-2", out);
Settings.save();
}
@@ -229,7 +227,7 @@ public class Sectors{
private void generate(Sector sector){
//50% chance to get a wave mission
if(Mathf.randomSeed(sector.getSeed() + 6) < 0.5){
if(Mathf.randomSeed(sector.getSeed() + 7) < 0.5){
//recipe mission (maybe)
addRecipeMission(sector, 3);
sector.missions.add(new WaveMission(sector.difficulty*5 + Mathf.randomSeed(sector.getSeed(), 1, 4)*5));

View File

@@ -2,12 +2,15 @@ package io.anuke.mindustry.maps;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.content.Items;
import io.anuke.mindustry.content.UnitTypes;
import io.anuke.mindustry.content.blocks.*;
import io.anuke.mindustry.maps.generation.Generation;
import io.anuke.mindustry.maps.missions.*;
import io.anuke.mindustry.content.blocks.CraftingBlocks;
import io.anuke.mindustry.content.blocks.ProductionBlocks;
import io.anuke.mindustry.content.blocks.StorageBlocks;
import io.anuke.mindustry.content.blocks.UnitBlocks;
import io.anuke.mindustry.maps.missions.BlockMission;
import io.anuke.mindustry.maps.missions.ItemMission;
import io.anuke.mindustry.maps.missions.Mission;
import io.anuke.mindustry.maps.missions.WaveMission;
import io.anuke.mindustry.world.Block;
import io.anuke.ucore.util.Bundles;
import static io.anuke.mindustry.Vars.*;
@@ -16,7 +19,7 @@ public class TutorialSector{
private static int droneIndex;
public static Array<Mission> getMissions(){
/*
Array<Mission> missions = Array.with(
new ItemMission(Items.copper, 60).setMessage("$tutorial.begin"),
@@ -30,7 +33,8 @@ public class TutorialSector{
//TODO fill turret with items mission
//new BlockMission(ProductionBlocks.mechanicalDrill).setMessage("$tutorial.drillturret"),
new WaveMission(2).setMessage("$tutorial.waves"),
// Create a wave mission which spawns the core at 60, 60 rather than in the center of the map
new WaveMission(2, 60, 60).setMessage("$tutorial.waves"),
new ItemMission(Items.lead, 150).setMessage("$tutorial.lead"),
new ItemMission(Items.copper, 250).setMessage("$tutorial.morecopper"),
@@ -82,9 +86,21 @@ public class TutorialSector{
droneIndex = i;
break;
}
}
}*/
return missions;
return Array.with(
//intentionally unlocalized
new ItemMission(Items.copper, 50).setMessage("An updated tutorial will return next build.\nFor now, you'll have to deal with... this."),
new BlockMission(ProductionBlocks.mechanicalDrill),
new ItemMission(Items.copper, 100),
new ItemMission(Items.lead, 50),
new BlockMission(CraftingBlocks.smelter),
new ItemMission(Items.densealloy, 10),
new WaveMission(5)
);
}
public static boolean supressDrone(){

View File

@@ -57,6 +57,7 @@ public class FortressGenerator{
void gen(){
gen.setBlock(enemyX, enemyY, StorageBlocks.core, team);
gen.random.nextBoolean();
float difficultyScl = Mathf.clamp(gen.sector.difficulty / 20f + gen.random.range(0.25f), 0f, 0.9999f);
float dscl2 = Mathf.clamp(0.5f + gen.sector.difficulty / 20f + gen.random.range(0.1f), 0f, 1.5f);

View File

@@ -312,7 +312,7 @@ public class WorldGenerator{
+ sim3.octaveNoise2D(detailed ? 12 : 9, 0.6, 1f / 1100f, x - 120, y);
double lake = sim2.octaveNoise2D(1, 1, 1f / 110f, x, y);
elevation -= lake/3f;
elevation -= Math.pow(lake + 0.15, 5);
int lerpDst = 20;
lerpDst *= lerpDst;
@@ -330,9 +330,9 @@ public class WorldGenerator{
}
}
if(elevation < 0.7 || lake > 0.96){
if(elevation < 0.7){
floor = Blocks.deepwater;
}else if(elevation < 0.79 || lake > 0.948){
}else if(elevation < 0.79){
floor = Blocks.water;
}else if(elevation < 0.85){
floor = Blocks.sand;

View File

@@ -12,8 +12,24 @@ import io.anuke.ucore.util.Bundles;
import static io.anuke.mindustry.Vars.*;
public class BattleMission extends Mission{
public class BattleMission extends MissionWithStartingCore{
final int spacing = 30;
public static final int defaultXCorePos = 50;
public static final int defaultYCorePos = 50;
/** Creates a battle mission with the player core being at (@defaultXCorePos, @defaultYCorePos) */
public BattleMission(){
this(defaultXCorePos, defaultYCorePos);
}
/**
* Creates a wave survival with the player core being at a custom location.
* @param xCorePos The X coordinate of the custom core position.
* @param yCorePos The Y coordinate of the custom core position.
*/
public BattleMission(int xCorePos, int yCorePos){
super(xCorePos, yCorePos);
}
@Override
public String getIcon(){
@@ -37,7 +53,7 @@ public class BattleMission extends Mission{
@Override
public void generate(Generation gen){
generateCoreAt(gen, 50, 50, defaultTeam);
generateCoreAtFirstSpawnPoint(gen, defaultTeam);
if(state.teams.get(defaultTeam).cores.size == 0){
return;

View File

@@ -1,15 +0,0 @@
package io.anuke.mindustry.maps.missions;
import io.anuke.mindustry.Vars;
/**A mission that just displays some text.*/
public class MessageMission extends ActionMission{
public MessageMission(String text){
super(() -> {
if(!Vars.headless){
Vars.ui.showInfo(text);
}
});
}
}

View File

@@ -100,10 +100,4 @@ public abstract class Mission{
}
public void generate(Generation gen){}
public void generateCoreAt(Generation gen, int coreX, int coreY, Team team){
gen.tiles[coreX][coreY].setBlock(StorageBlocks.core);
gen.tiles[coreX][coreY].setTeam(team);
state.teams.get(team).cores.add(gen.tiles[coreX][coreY]);
}
}

View File

@@ -0,0 +1,61 @@
package io.anuke.mindustry.maps.missions;
import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.content.blocks.StorageBlocks;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.maps.generation.Generation;
import io.anuke.mindustry.world.Tile;
import static io.anuke.mindustry.Vars.state;
public abstract class MissionWithStartingCore extends Mission{
/** Stores a custom starting location for the core, or null if the default calculation (map center) shall be used. */
private final GridPoint2 customStartingPoint;
/** Default constructor. Missions created this way will have a player starting core in the center of the map. */
MissionWithStartingCore(){
this.customStartingPoint = null;
}
/**
* Creates a mission with a core on a non-default location.
* @param xCorePos The x coordinate of the custom core position.
* @param yCorePos The y coordinate of the custom core position.
*/
MissionWithStartingCore(int xCorePos, int yCorePos){
this.customStartingPoint = new GridPoint2(xCorePos, yCorePos);
}
/**
* Generates a player core based on generation parameters.
* @param gen The generation parameters which provide the map size.
* @param team The team to generate the core for.
*/
public void generateCoreAtFirstSpawnPoint(Generation gen, Team team){
Array<GridPoint2> spawnPoints = getSpawnPoints(gen);
if(spawnPoints == null || spawnPoints.size == 0){
throw new IllegalArgumentException("A MissionWithStartingCore subclass did not provide a spawn point in getSpawnPoints(). However, at least one point must always be provided.");
}
Tile startingCoreTile = gen.tiles[spawnPoints.first().x][spawnPoints.first().y];
startingCoreTile.setBlock(StorageBlocks.core);
startingCoreTile.setTeam(team);
state.teams.get(team).cores.add(startingCoreTile);
}
/**
* Retrieves the spawn point in the center of the map or at a custom location which was provided through the constructor.
* @param gen The generation parameters which provide the map size.
* @return The center of the map or a custom location.
* @implNote Must return an array with at least one entry.
*/
@Override
public Array<GridPoint2> getSpawnPoints(Generation gen){
if(this.customStartingPoint == null){
return Array.with(new GridPoint2(gen.width / 2, gen.height / 2));
}else{
return Array.with(this.customStartingPoint);
}
}
}

View File

@@ -1,6 +1,5 @@
package io.anuke.mindustry.maps.missions;
import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.game.GameMode;
@@ -9,16 +8,31 @@ import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.Waves;
import io.anuke.mindustry.maps.Sector;
import io.anuke.mindustry.maps.generation.Generation;
import io.anuke.mindustry.net.Net;
import io.anuke.ucore.util.Bundles;
import static io.anuke.mindustry.Vars.state;
import static io.anuke.mindustry.Vars.waveTeam;
import static io.anuke.mindustry.Vars.world;
import static io.anuke.mindustry.Vars.*;
public class WaveMission extends Mission{
public class WaveMission extends MissionWithStartingCore{
private final int target;
/**
* Creates a wave survival mission with the player core being in the center of the map.
* @param target The number of waves to be survived.
*/
public WaveMission(int target){
super();
this.target = target;
}
/**
* Creates a wave survival with the player core being at a custom location.
* @param target The number of waves to be survived.
* @param xCorePos The X coordinate of the custom core position.
* @param yCorePos The Y coordinate of the custom core position.
*/
public WaveMission(int target, int xCorePos, int yCorePos){
super(xCorePos, yCorePos);
this.target = target;
}
@@ -29,8 +43,7 @@ public class WaveMission extends Mission{
@Override
public void generate(Generation gen){
int coreX = gen.width/2, coreY = gen.height/2;
generateCoreAt(gen, coreX, coreY, Team.blue);
generateCoreAtFirstSpawnPoint(gen, Team.blue);
}
@Override
@@ -49,7 +62,7 @@ public class WaveMission extends Mission{
public String displayString(){
return state.wave > target ?
Bundles.format(
Vars.unitGroups[Vars.waveTeam.ordinal()].size() > 1 ?
Vars.unitGroups[Vars.waveTeam.ordinal()].size() > 1 && !Net.client() ?
"text.mission.wave.enemies" :
"text.mission.wave.enemy", target, target, Vars.unitGroups[Vars.waveTeam.ordinal()].size()) :
Bundles.format("text.mission.wave", state.wave, target, (int)(state.wavetime/60));
@@ -71,9 +84,4 @@ public class WaveMission extends Mission{
public boolean isComplete(){
return state.wave > target && Vars.unitGroups[Vars.waveTeam.ordinal()].size() == 0;
}
@Override
public Array<GridPoint2> getSpawnPoints(Generation gen){
return Array.with(new GridPoint2(gen.width/2, gen.height/2));
}
}

View File

@@ -59,7 +59,7 @@ public class Net{
}
String error = t.getMessage() == null ? "" : t.getMessage().toLowerCase();
String type = error.getClass().toString().toLowerCase();
String type = t.getClass().toString().toLowerCase();
if(error.equals("mismatch")){
error = Bundles.get("text.error.mismatch");

View File

@@ -1,21 +1,17 @@
package io.anuke.mindustry.ui;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import io.anuke.mindustry.graphics.Shaders;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.scene.Element;
import io.anuke.ucore.scene.event.InputEvent;
import io.anuke.ucore.scene.event.InputListener;
import io.anuke.ucore.scene.style.TextureRegionDrawable;
import io.anuke.ucore.scene.ui.Image;
import io.anuke.ucore.scene.ui.layout.Table;
import static io.anuke.mindustry.Vars.renderer;
import static io.anuke.mindustry.Vars.showFog;
import static io.anuke.mindustry.Vars.world;
import static io.anuke.mindustry.Vars.*;
public class Minimap extends Table{
@@ -25,14 +21,15 @@ public class Minimap extends Table{
margin(5);
marginBottom(10);
Image image = new Image(new TextureRegionDrawable(new TextureRegion())){
TextureRegion r = new TextureRegion();
Element elem = new Element(){
@Override
public void draw(Batch batch, float parentAlpha){
public void draw(){
if(renderer.minimap.getRegion() == null) return;
TextureRegionDrawable draw = (TextureRegionDrawable) getDrawable();
draw.getRegion().setRegion(renderer.minimap.getRegion());
super.draw(batch, parentAlpha);
Draw.crect(renderer.minimap.getRegion(), x, y, width, height);
if(renderer.minimap.getTexture() != null){
renderer.minimap.drawEntities(x, y, width, height);
}
@@ -40,7 +37,7 @@ public class Minimap extends Table{
if(showFog){
renderer.fog.getTexture().setFilter(TextureFilter.Nearest, TextureFilter.Nearest);
TextureRegion r = draw.getRegion();
r.setRegion(renderer.minimap.getRegion());
float pad = renderer.fog.getPadding();
float px = r.getU() * world.width() + pad;
@@ -55,7 +52,7 @@ public class Minimap extends Table{
r.setV2(1f - py2 / (world.height() + pad*2f));
Graphics.shader(Shaders.fog);
super.draw(batch, parentAlpha);
Draw.crect(r, x, y, width, height);
Graphics.shader();
renderer.fog.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear);
@@ -70,7 +67,7 @@ public class Minimap extends Table{
}
});
image.update(() -> {
elem.update(() -> {
Element e = Core.scene.hit(Graphics.mouse().x, Graphics.mouse().y, true);
if(e != null && e.isDescendantOf(this)){
@@ -79,6 +76,7 @@ public class Minimap extends Table{
Core.scene.setScrollFocus(null);
}
});
add(image).size(140f, 140f);
add(elem).size(140f, 140f);
}
}

View File

@@ -57,6 +57,9 @@ public class PausedDialog extends FloatingDialog{
hide();
});
content().row();
content().addButton("$text.unlocks", ui.unlocks::show);
content().row();
content().addButton("$text.settings", ui.settings::show);

View File

@@ -60,7 +60,7 @@ public class SectorsDialog extends FloatingDialog{
margin(0);
getTitleTable().clear();
clear();
stack(content(), buttons(), container).grow();
stack(content(), container, buttons()).grow();
shown(this::setup);
}
@@ -128,7 +128,7 @@ public class SectorsDialog extends FloatingDialog{
class SectorView extends Element{
float lastX, lastY;
boolean clicked = false;
float panX = 0, panY = -sectorSize/2f;
float panX = sectorSize/2f, panY = sectorSize/2f;
SectorView(){
addListener(new InputListener(){

View File

@@ -130,13 +130,16 @@ public class SettingsMenuDialog extends SettingsDialog{
sound.volumePrefs();
game.screenshakePref();
//game.checkPref("smoothcam", true);
game.checkPref("effects", true);
if(mobile){
game.checkPref("autotarget", true);
}
//game.sliderPref("sensitivity", 100, 10, 300, i -> i + "%");
game.sliderPref("saveinterval", 60, 10, 5 * 120, i -> Bundles.format("setting.seconds", i));
game.sliderPref("saveinterval", 120, 10, 5 * 120, i -> Bundles.format("setting.seconds", i));
if(!mobile){
game.checkPref("crashreport", true);
}
game.pref(new Setting(){
@Override
public void add(SettingsTable table){
@@ -187,12 +190,6 @@ public class SettingsMenuDialog extends SettingsDialog{
});
graphics.sliderPref("fpscap", 125, 5, 125, 5, s -> (s > 120 ? Bundles.get("setting.fpscap.none") : Bundles.format("setting.fpscap.text", s)));
graphics.checkPref("multithread", mobile, threads::setEnabled);
if(Settings.getBool("multithread")){
threads.setEnabled(true);
}
if(!mobile){
graphics.checkPref("vsync", true, b -> Gdx.graphics.setVSync(b));

View File

@@ -107,7 +107,7 @@ public class HudFragment extends Fragment{
Stack stack = new Stack();
TextButton waves = new TextButton("");
Table btable = new Table().margin(14);
Table btable = new Table().margin(0);
stack.add(waves);
stack.add(btable);
@@ -126,7 +126,6 @@ public class HudFragment extends Fragment{
IntFormat tps = new IntFormat("text.tps");
IntFormat ping = new IntFormat("text.ping");
t.label(() -> fps.get(Gdx.graphics.getFramesPerSecond())).padRight(10);
t.label(() -> tps.get(threads.getTPS())).visible(() -> threads.isEnabled());
t.row();
if(Net.hasClient()){
t.label(() -> ping.get(Net.getPing())).visible(Net::client).colspan(2);
@@ -375,7 +374,7 @@ public class HudFragment extends Fragment{
(!state.mode.disableWaveTimer ?
Bundles.format("text.wave.waiting", (int)(state.wavetime/60)) :
Bundles.get("text.waiting"))) :
Bundles.format("text.mission.display", world.getSector().currentMission().displayString())).growX();
Bundles.format("text.mission.display", world.getSector().currentMission().displayString())).growX().pad(8f);
table.clicked(() -> {
if(world.getSector() != null && world.getSector().currentMission().hasMessage()){

View File

@@ -230,7 +230,7 @@ public class Block extends BaseBlock {
/**Call when some content is produced. This unlocks the content if it is applicable.*/
public void useContent(Tile tile, UnlockableContent content){
if(!headless && tile.getTeam() == players[0].getTeam()){
control.unlocks.handleContentUsed(content);
logic.handleContent(content);
}
}

View File

@@ -14,11 +14,7 @@ public class ColorMapper implements ContentList{
private static ObjectIntMap<Block> colorMap = new ObjectIntMap<>();
private static ThreadLocal<Color> tmpColors = new ThreadLocal<>();
public static Block getByColor(int color){
return blockMap.get(color);
}
public static int getBlockColor(Block block){
private static int getBlockColor(Block block){
return colorMap.get(block, 0);
}

View File

@@ -22,7 +22,6 @@ import static io.anuke.mindustry.Vars.*;
public class Tile implements PosTrait, TargetTrait{
public static final Object tileSetLock = new Object();
/**
* The coordinates of the core tile this is linked to, in the form of two bytes packed into one.
* This is relative to the block it is linked to; negate coords to find the link.
@@ -130,8 +129,9 @@ public class Tile implements PosTrait, TargetTrait{
return wall;
}
@Override
public Team getTeam(){
return Team.all[team];
return Team.all[target().team];
}
public void setTeam(Team team){
@@ -143,33 +143,27 @@ public class Tile implements PosTrait, TargetTrait{
}
public void setBlock(Block type, int rotation){
synchronized(tileSetLock){
preChanged();
if(rotation < 0) rotation = (-rotation + 2);
this.wall = type;
this.link = 0;
setRotation((byte) (rotation % 4));
changed();
}
preChanged();
if(rotation < 0) rotation = (-rotation + 2);
this.wall = type;
this.link = 0;
setRotation((byte) (rotation % 4));
changed();
}
public void setBlock(Block type, Team team){
synchronized(tileSetLock){
preChanged();
this.wall = type;
this.team = (byte)team.ordinal();
this.link = 0;
changed();
}
preChanged();
this.wall = type;
this.team = (byte)team.ordinal();
this.link = 0;
changed();
}
public void setBlock(Block type){
synchronized(tileSetLock){
preChanged();
this.wall = type;
this.link = 0;
changed();
}
preChanged();
this.wall = type;
this.link = 0;
changed();
}
public void setFloor(Floor type){
@@ -266,7 +260,7 @@ public class Tile implements PosTrait, TargetTrait{
* Returns the list of all tiles linked to this multiblock, or an empty array if it's not a multiblock.
* This array contains all linked tiles, including this tile itself.
*/
public synchronized Array<Tile> getLinkedTiles(Array<Tile> tmpArray){
public Array<Tile> getLinkedTiles(Array<Tile> tmpArray){
Block block = block();
tmpArray.clear();
if(block.isMultiblock()){
@@ -288,7 +282,7 @@ public class Tile implements PosTrait, TargetTrait{
* Returns the list of all tiles linked to this multiblock if it were this block, or an empty array if it's not a multiblock.
* This array contains all linked tiles, including this tile itself.
*/
public synchronized Array<Tile> getLinkedTilesAs(Block block, Array<Tile> tmpArray){
public Array<Tile> getLinkedTilesAs(Block block, Array<Tile> tmpArray){
tmpArray.clear();
if(block.isMultiblock()){
int offsetx = -(block.size - 1) / 2;
@@ -390,52 +384,47 @@ public class Tile implements PosTrait, TargetTrait{
}
private void preChanged(){
synchronized(tileSetLock){
block().removed(this);
if(entity != null){
entity.removeFromProximity();
}
team = 0;
block().removed(this);
if(entity != null){
entity.removeFromProximity();
}
team = 0;
}
private void changed(){
synchronized(tileSetLock){
if(entity != null){
entity.remove();
entity = null;
}
Block block = block();
if(block.hasEntity()){
entity = block.newEntity().init(this, block.update);
entity.cons = new ConsumeModule();
if(block.hasItems) entity.items = new ItemModule();
if(block.hasLiquids) entity.liquids = new LiquidModule();
if(block.hasPower){
entity.power = new PowerModule();
entity.power.graph.add(this);
}
if(!world.isGenerating()){
entity.updateProximity();
}
}else if(!(block instanceof BlockPart) && !world.isGenerating()){
//since the entity won't update proximity for us, update proximity for all nearby tiles manually
for(GridPoint2 p : Geometry.d4){
Tile tile = world.tile(x + p.x, y + p.y);
if(tile != null){
tile = tile.target();
tile.block().onProximityUpdate(tile);
}
}
}
updateOcclusion();
if(entity != null){
entity.remove();
entity = null;
}
Block block = block();
if(block.hasEntity()){
entity = block.newEntity().init(this, block.update);
entity.cons = new ConsumeModule();
if(block.hasItems) entity.items = new ItemModule();
if(block.hasLiquids) entity.liquids = new LiquidModule();
if(block.hasPower){
entity.power = new PowerModule();
entity.power.graph.add(this);
}
if(!world.isGenerating()){
entity.updateProximity();
}
}else if(!(block instanceof BlockPart) && !world.isGenerating()){
//since the entity won't update proximity for us, update proximity for all nearby tiles manually
for(GridPoint2 p : Geometry.d4){
Tile tile = world.tile(x + p.x, y + p.y);
if(tile != null){
tile = tile.target();
tile.block().onProximityUpdate(tile);
}
}
}
updateOcclusion();
world.notifyChanged(this);
}

View File

@@ -5,6 +5,7 @@ import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.consumers.ConsumeLiquidFilter;
import io.anuke.mindustry.world.meta.BlockStat;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.util.Mathf;
@@ -15,9 +16,7 @@ import static io.anuke.mindustry.Vars.tilesize;
public abstract class ItemLiquidGenerator extends ItemGenerator{
protected float minLiquidEfficiency = 0.2f;
protected float powerPerLiquid = 0.13f;
/**
* Maximum liquid used per frame.
*/
/**Maximum liquid used per frame.*/
protected float maxLiquidGenerate = 0.4f;
public ItemLiquidGenerator(String name){
@@ -28,6 +27,12 @@ public abstract class ItemLiquidGenerator extends ItemGenerator{
consumes.add(new ConsumeLiquidFilter(liquid -> getLiquidEfficiency(liquid) >= minLiquidEfficiency, 0.001f, true)).update(false).optional(true);
}
@Override
public void init(){
super.init();
stats.remove(BlockStat.liquidFuelUse);
}
@Override
public void update(Tile tile){
ItemGeneratorEntity entity = tile.entity();

View File

@@ -13,19 +13,21 @@ import io.anuke.ucore.util.Mathf;
public abstract class LiquidGenerator extends PowerGenerator{
protected float minEfficiency = 0.2f;
protected float powerPerLiquid = 0.13f;
/**
* Maximum liquid used per frame.
*/
protected float maxLiquidGenerate = 0.4f;
protected float powerPerLiquid;
/**Maximum liquid used per frame.*/
protected float maxLiquidGenerate;
protected Effect generateEffect = BlockFx.generatespark;
public LiquidGenerator(String name){
super(name);
liquidCapacity = 30f;
hasLiquids = true;
}
consumes.add(new ConsumeLiquidFilter(liquid -> getEfficiency(liquid) >= minEfficiency, 0.001f)).update(false);
@Override
public void setStats(){
consumes.add(new ConsumeLiquidFilter(liquid -> getEfficiency(liquid) >= minEfficiency, maxLiquidGenerate)).update(false);
super.setStats();
}
@Override

View File

@@ -14,7 +14,7 @@ public class LiquidHeatGenerator extends LiquidGenerator{
public void setStats(){
super.setStats();
stats.add(BlockStat.basePowerGeneration, maxLiquidGenerate * powerPerLiquid * 60f * 0.4f, StatUnit.powerSecond);
stats.add(BlockStat.basePowerGeneration, maxLiquidGenerate * powerPerLiquid * 60f, StatUnit.powerSecond);
}
@Override

View File

@@ -5,6 +5,7 @@ import com.badlogic.gdx.utils.IntSet;
import com.badlogic.gdx.utils.ObjectSet;
import com.badlogic.gdx.utils.Queue;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Timers;
import static io.anuke.mindustry.Vars.threads;
@@ -37,63 +38,38 @@ public class PowerGraph{
lastFrameUpdated = threads.getFrameID();
boolean charge = false;
float totalInput = 0f;
float bufferInput = 0f;
for(Tile producer : producers){
if (producer.block().consumesPower) {
bufferInput += producer.entity.power.amount;
} else {
totalInput += producer.entity.power.amount;
}
totalInput += producer.entity.power.amount;
}
float maxOutput = 0f;
float bufferOutput = 0f;
for(Tile consumer : consumers){
if (consumer.block().outputsPower) {
bufferOutput += consumer.block().powerCapacity - consumer.entity.power.amount;
} else {
maxOutput += consumer.block().powerCapacity - consumer.entity.power.amount;
}
}
if (maxOutput < totalInput) {
charge = true;
}
if (totalInput + bufferInput <= 0.0001f || maxOutput + bufferOutput <= 0.0001f) {
return;
}
float bufferUsed = 0;
if (charge) {
bufferUsed = Math.min((totalInput - maxOutput) / bufferOutput, 1f);
} else {
bufferUsed = Math.min((maxOutput - totalInput) / bufferInput, 1f);
}
float inputUsed = charge ? Math.min((maxOutput + bufferOutput) / totalInput, 1f) : 1f;
for(Tile producer : producers){
if (producer.block().consumesPower) {
if (!charge) {
producer.entity.power.amount -= producer.entity.power.amount * bufferUsed;
}
float accumulator = producer.entity.power.amount;
if(accumulator <= 0.0001f) continue;
float toEach = accumulator / consumers.size;
float outputs = 0f;
for(Tile tile : consumers){
outputs += Math.min(tile.block().powerCapacity - tile.entity.power.amount, toEach) / toEach;
}
float finalEach = toEach / outputs * Timers.delta();
float buffer = 0f;
if(Float.isNaN(finalEach) || Float.isInfinite(finalEach)){
continue;
}
producer.entity.power.amount -= producer.entity.power.amount * inputUsed;
}
float outputSatisfied = charge ? 1f : Math.min((totalInput + bufferInput) / maxOutput, 1f);
for(Tile consumer : consumers){
if (consumer.block().outputsPower) {
if (charge) {
consumer.entity.power.amount += (consumer.block().powerCapacity - consumer.entity.power.amount) * bufferUsed;
}
continue;
for(Tile tile : consumers){
float used = Math.min(tile.block().powerCapacity - tile.entity.power.amount, finalEach) * accumulator / totalInput;
buffer += used;
tile.entity.power.amount += used;
}
consumer.entity.power.amount += (consumer.block().powerCapacity - consumer.entity.power.amount) * outputSatisfied;
producer.entity.power.amount -= buffer;
}
}

View File

@@ -127,7 +127,7 @@ public class MechPad extends Block{
if(checkValidTap(tile, player)){
Call.onMechFactoryTap(player, tile);
}else if(player.isLocal && mobile){
}else if(player.isLocal && mobile && !player.isDead()){
player.moveTarget = tile.entity;
}
}