Merge branch 'master' into patch-1

This commit is contained in:
Anuken
2019-08-23 18:12:20 -04:00
committed by GitHub
118 changed files with 1372 additions and 1226 deletions

View File

@@ -75,6 +75,7 @@ server.kicked.nameEmpty = Your chosen name is invalid.
server.kicked.idInUse = You are already on this server! Connecting with two accounts is not permitted.
server.kicked.customClient = This server does not support custom builds. Download an official version.
server.kicked.gameover = Game over!
server.versions = Your version:[accent] {0}[]\nServer version:[accent] {1}[]
host.info = The [accent]host[] button hosts a server on port [scarlet]6567[]. \nAnybody on the same [lightgray]wifi or local network[] should be able to see your server in their server list.\n\nIf you want people to be able to connect from anywhere by IP, [accent]port forwarding[] is required.\n\n[lightgray]Note: If someone is experiencing trouble connecting to your LAN game, make sure you have allowed Mindustry access to your local network in your firewall settings. Note that public networks sometimes do not allow server discovery.
join.info = Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[lightgray]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP.
hostserver = Host Multiplayer Game
@@ -124,7 +125,7 @@ save.new = New Save
save.overwrite = Are you sure you want to overwrite\nthis save slot?
overwrite = Overwrite
save.none = No saves found!
saveload = [accent]Saving...
saveload = Saving...
savefail = Failed to save game!
save.delete.confirm = Are you sure you want to delete this save?
save.delete = Delete
@@ -371,7 +372,7 @@ zone.crags.name = Crags
zone.fungalPass.name = Fungal Pass
zone.groundZero.description = The optimal location to begin once more. Low enemy threat. Few resources.\nGather as much lead and copper as possible.\nMove on.
zone.frozenForest.description = Even here, closer to mountains, the spores have spread. The fridgid temperatures cannot contain them forever.\n\nBegin the venture into power. Build combustion generators. Learn to use menders.
zone.frozenForest.description = Even here, closer to mountains, the spores have spread. The frigid temperatures cannot contain them forever.\n\nBegin the venture into power. Build combustion generators. Learn to use menders.
zone.desertWastes.description = These wastes are vast, unpredictable, and criss-crossed with derelict sector structures.\nCoal is present in the region. Burn it for power, or synthesize graphite.\n\n[lightgray]This landing location cannot be guaranteed.
zone.saltFlats.description = On the outskirts of the desert lie the Salt Flats. Few resources can be found in this location.\n\nThe enemy has erected a resource storage complex here. Eradicate their core. Leave nothing standing.
zone.craters.description = Water has accumulated in this crater, relic of the old wars. Reclaim the area. Collect sand. Smelt metaglass. Pump water to cool turrets and drills.

File diff suppressed because it is too large Load Diff

View File

@@ -46,6 +46,7 @@ newgame = 새 게임
none = <없음>
minimap = 미니맵
close = 닫기
website = 웹사이트
quit = 나가기
maps =
continue = 계속하기
@@ -514,6 +515,7 @@ setting.lasers.name = 전력 노드 레이저 표시
setting.pixelate.name = 픽셀화[LIGHT_GRAY] (애니메이션 효과가 꺼집니다)
setting.minimap.name = 미니맵 보기
setting.musicvol.name = 음악 크기
setting.ambientvol.name = 배경음 크기
setting.mutemusic.name = 음소거
setting.sfxvol.name = 효과음 크기
setting.mutesound.name = 소리 끄기

View File

@@ -172,7 +172,7 @@ saveimage = 保存图片
unknown = 未知
custom = 自定义
builtin = 内建的
map.delete.confirm = 你确定你想要删除这张地图吗?这个操作无法取消
map.delete.confirm = 你确定你想要删除这张地图吗?这个操作无法撤销
map.random = [accent]随机地图
map.nospawn = 这个地图没有核心!请在编辑器中添加一个[ROYAL]蓝色[]的核心。
map.nospawn.pvp = 这个地图没有敌人的核心!请在编辑器中添加一个[ROYAL]红色[]的核心。
@@ -349,13 +349,13 @@ error.any = 未知网络错误。
error.bloom = 未能初始化特效。\n您的设备可能不支持它。
zone.groundZero.name = 零号地区
zone.desertWastes.name = 沙漠废物
zone.desertWastes.name = 荒芜沙漠
zone.craters.name = 陨石带
zone.frozenForest.name = 冰冻森林
zone.ruinousShores.name = 毁灭海岸
zone.ruinousShores.name = 遗迹海岸
zone.stainedMountains.name = 绵延群山
zone.desolateRift.name = 荒芜裂谷
zone.nuclearComplex.name = 核裂
zone.nuclearComplex.name = 核裂
zone.overgrowth.name = 增生区
zone.tarFields.name = 石油田
zone.saltFlats.name = 盐碱荒滩
@@ -498,9 +498,9 @@ setting.sensitivity.name = 控制器灵敏度
setting.saveinterval.name = 自动保存间隔
setting.seconds = {0} 秒
setting.fullscreen.name = 全屏
setting.borderlesswindow.name = 全屏化[LIGHT_GRAY] (可能需要重启)
setting.borderlesswindow.name = 无边框窗口[LIGHT_GRAY] (可能需要重启)
setting.fps.name = 显示 FPS
setting.vsync.name = 同步
setting.vsync.name = 垂直同步
setting.lasers.name = 显示能量射线
setting.pixelate.name = 像素画面 [LIGHT_GRAY](可能会降低性能)
setting.minimap.name = 显示小地图
@@ -736,7 +736,7 @@ block.duo.name = 双管炮
block.scorch.name = 火焰炮
block.scatter.name = 分裂炮
block.hail.name = 冰雹炮
block.lancer.name = 蓝瑟炮
block.lancer.name = 激光矛
block.conveyor.name = 传送带
block.titanium-conveyor.name = 钛传送带
block.junction.name = 连接点
@@ -825,7 +825,7 @@ block.surge-wall.name = 波动墙
block.surge-wall-large.name = 大型波动墙
block.cyclone.name = 气旋炮
block.fuse.name = 融合炮
block.shock-mine.name = 休克地雷
block.shock-mine.name = 脉冲地雷
block.overdrive-projector.name = 超速投影器
block.force-projector.name = 力墙投影器
block.arc.name = 电弧
@@ -955,7 +955,7 @@ block.surge-wall-large.description = 强大的防御区块。\n有很小的机
block.door.description = 一扇小门,可以通过点击打开和关闭。\n如果打开敌人可以射击并穿过。
block.door-large.description = 一扇大门,可以通过点击打开和关闭。\n如果打开敌人可以射击并穿过。\n跨越多个区块。
block.mender.description = 定期修理附近的方块,使防御系统在波与波之间得到修复。\n通常使用硅来提高范围和效率。
block.mend-projector.description = 定期修复附近的建筑物。
block.mend-projector.description = 修理者的升级。定期修复附近的建筑物。
block.overdrive-projector.description = 提高附近建筑物的速度,如钻头和传送带。
block.force-projector.description = 自身周围创建一个六边形力场,使建筑物和内部单位免受子弹的伤害。
block.shock-mine.description = 伤害踩到它的敌人。敌人几乎看不到它。
@@ -1008,20 +1008,20 @@ block.container.description = 存储少量物品。当存在非恒定的材料
block.vault.description = 存储大量物品。当存在非恒定的材料需求时,使用它来创建缓冲区。 [LIGHT_GRAY]卸载器[]可用于从仓库中获取物品。
block.launch-pad.description = 不通过核心发射物体。
block.launch-pad-large.description = 发射台的改进版。存储更多物体。启动频率更高。
block.duo.description = 小而便宜的炮塔。
block.scatter.description = 中型防空炮塔,向空中单位发射铅或废料。
block.scorch.description = 小型炮塔,燃烧任何靠近它的地面敌人。近距离效。
block.duo.description = 小而便宜的炮塔。对地高效。
block.scatter.description = 不可或缺的防空炮塔,向空中单位发射铅或废料。
block.scorch.description = 小型炮塔,燃烧任何靠近它的地面敌人。近距离非常有效。
block.arc.description = 小型炮塔,发射电弧。
block.hail.description = 小型炮兵炮台。
block.lancer.description = 中型炮塔,发射带电的电子束。
block.wave.description = 中型快速炮塔,射出液体泡泡。
block.salvo.description = 中型炮塔,齐射射击。
block.swarmer.description = 中型炮塔,发射爆炸导弹。
block.ripple.description = 大型炮兵炮塔,可同时向多个目标开火
block.cyclone.description = 大型快速炮塔。
block.fuse.description = 大型炮塔,发射强大的短程光束。
block.spectre.description = 大型炮塔,一次射出两颗强大的子弹。
block.meltdown.description = 发射强大的远程光束的大型炮塔
block.hail.description = 小型,远程炮台。
block.lancer.description = 中型对地炮塔。遇敌时会充能并发射强有力的的能量束。
block.wave.description = 中型快速炮塔,射出液体泡泡。有液体输入时自动灭火。
block.salvo.description = 双管炮的升级。中型,齐射射击。
block.swarmer.description = 中型炮塔,对空对地,发射跟踪爆炸导弹。
block.ripple.description = 大型远程炮台,非常强力,向远处的敌人投射一簇弹药
block.cyclone.description = 大型快速炮塔,对空对地,向周围敌人发射爆炸弹
block.fuse.description = 大型炮塔,发射三道刺穿敌人的短程光束。
block.spectre.description = 大型炮塔,对空对地,一次射出两颗强大的穿甲子弹。
block.meltdown.description = 超大型激光炮塔,充能之后持续发射光束,需要冷却剂
block.crawler-factory.description = 生产快速自毁单元。
block.draug-factory.description = 生产德鲁格釆矿机。
block.spirit-factory.description = 生产幽灵修理机。
@@ -1039,4 +1039,4 @@ block.javelin-ship-pad.description = 离开你当前的装置,换成一个强
block.glaive-ship-pad.description = 离开现有的装置,换成装甲良好的大型武装直升机。\n站在上面时双击切换。
block.tau-mech-pad.description = 离开你当前的装置并换成一个可以治愈友方建筑物和单位的支撑机械。\n站在上面时双击切换。
block.delta-mech-pad.description = 离开你当前的装置并换成一个快速,轻装甲的机械装置,用于快速攻击。\n站在上面时双击切换。
block.omega-mech-pad.description = 离开你当前的装置并换成一个笨重且装甲良好的机甲,用于前线攻击。\n站在上面时双击切换。
block.omega-mech-pad.description = 离开你当前的装置并换成一个笨重且装甲良好的机甲,用于前线攻击。\n站在上面时双击切换。

View File

@@ -26,7 +26,7 @@ beito
BeefEX
Lorex
laohuaji233
CrazyBearTR
Spico The Spirit Guy
Zachary
Fenr1r
Jaiun Lee
@@ -71,3 +71,4 @@ Paul T
Dominik
Arkanic
Potion
Markus G

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -188,7 +188,8 @@
up: button,
over: button-over,
imageDisabledColor: gray,
imageUpColor: white
imageUpColor: white,
disabled: button-disabled
},
node: {
up: button-over,

View File

@@ -67,6 +67,6 @@ public class Mindustry extends ApplicationCore{
super.init();
Log.info("Time to load [total]: {0}", Time.elapsed());
Events.fire(new GameLoadEvent());
Events.fire(new ClientLoadEvent());
}
}

View File

@@ -1,7 +1,7 @@
package io.anuke.mindustry;
import io.anuke.arc.*;
import io.anuke.arc.Application.ApplicationType;
import io.anuke.arc.Core;
import io.anuke.arc.files.FileHandle;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.util.Structs;
@@ -15,6 +15,7 @@ import io.anuke.mindustry.entities.traits.DrawTrait;
import io.anuke.mindustry.entities.traits.SyncTrait;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.gen.Serialization;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.world.blocks.defense.ForceProjector.ShieldEntity;
@@ -222,5 +223,7 @@ public class Vars{
customMapDirectory = dataDirectory.child("maps/");
saveDirectory = dataDirectory.child("saves/");
tmpDirectory = dataDirectory.child("tmp/");
Events.fire(new AppLoadEvent());
}
}

View File

@@ -119,7 +119,7 @@ public class BlockIndexer{
ObjectSet<Tile> set = damagedTiles[team.ordinal()];
for(Tile tile : set){
if((tile.entity == null || tile.entity.getTeam() != team || !tile.entity.damaged()) && !(tile.block() instanceof BuildBlock)){
if((tile.entity == null || tile.entity.getTeam() != team || !tile.entity.damaged()) || tile.block() instanceof BuildBlock){
returnArray.add(tile);
}
}

View File

@@ -267,7 +267,7 @@ public class Bullets implements ContentList{
keepVelocity = false;
splashDamageRadius = 25f;
splashDamage = 10f;
lifetime = 50f;
lifetime = 60f;
trailColor = Pal.unitBack;
backColor = Pal.unitBack;
frontColor = Pal.unitFront;

View File

@@ -227,12 +227,14 @@ public class TechTree implements ContentList{
node(turbineGenerator, () -> {
node(thermalGenerator, () -> {
node(rtgGenerator, () -> {
node(differentialGenerator, () -> {
node(thoriumReactor, () -> {
node(impactReactor, () -> {
node(differentialGenerator, () -> {
node(thoriumReactor, () -> {
node(impactReactor, () -> {
});
node(rtgGenerator, () -> {
});
});
});
});

View File

@@ -330,9 +330,9 @@ public class UnitTypes implements ContentList{
baseRotateSpeed = 0.04f;
weapon = new Weapon("lich-missiles"){{
length = 4f;
reload = 180f;
reload = 160f;
width = 22f;
shots = 22;
shots = 16;
shootCone = 100f;
shotDelay = 2;
inaccuracy = 10f;
@@ -341,7 +341,7 @@ public class UnitTypes implements ContentList{
velocityRnd = 0.2f;
spacing = 1f;
bullet = Bullets.missileRevenant;
shootSound = Sounds.missile;
shootSound = Sounds.artillery;
}};
}};
@@ -371,7 +371,18 @@ public class UnitTypes implements ContentList{
inaccuracy = 3f;
roundrobin = true;
ejectEffect = Fx.none;
bullet = Bullets.standardDenseBig;
bullet = new BasicBulletType(7f, 42, "bullet"){
{
bulletWidth = 15f;
bulletHeight = 21f;
shootEffect = Fx.shootBig;
}
@Override
public float range(){
return 165f;
}
};
shootSound = Sounds.shootBig;
}};
}};

View File

@@ -84,7 +84,7 @@ public class Control implements ApplicationListener{
});
Events.on(PlayEvent.class, event -> {
player.setTeam(defaultTeam);
player.setTeam(state.rules.pvp ? netServer.assignTeam(player, playerGroup.all()) : defaultTeam);
player.setDead(true);
player.add();
@@ -237,7 +237,7 @@ public class Control implements ApplicationListener{
public void playMap(Map map, Rules rules){
ui.loadAnd(() -> {
logic.reset();
world.loadMap(map);
world.loadMap(map, rules);
state.rules = rules;
logic.play();
});
@@ -350,35 +350,37 @@ public class Control implements ApplicationListener{
//display UI scale changed dialog
if(Core.settings.getBool("uiscalechanged", false)){
FloatingDialog dialog = new FloatingDialog("$confirm");
Core.app.post(() -> Core.app.post(() -> {
FloatingDialog dialog = new FloatingDialog("$confirm");
dialog.setFillParent(true);
float[] countdown = {60 * 11};
Runnable exit = () -> {
Core.settings.put("uiscale", 100);
Core.settings.put("uiscalechanged", false);
settings.save();
dialog.hide();
Core.app.exit();
};
float[] countdown = {60 * 11};
Runnable exit = () -> {
Core.settings.put("uiscale", 100);
Core.settings.put("uiscalechanged", false);
settings.save();
dialog.hide();
Core.app.exit();
};
dialog.setFillParent(false);
dialog.cont.label(() -> {
if(countdown[0] <= 0){
exit.run();
}
return Core.bundle.format("uiscale.reset", (int)((countdown[0] -= Time.delta()) / 60f));
}).pad(10f).expand().left();
dialog.cont.label(() -> {
if(countdown[0] <= 0){
exit.run();
}
return Core.bundle.format("uiscale.reset", (int)((countdown[0] -= Time.delta()) / 60f));
}).pad(10f).expand().center();
dialog.buttons.defaults().size(200f, 60f);
dialog.buttons.addButton("$uiscale.cancel", exit);
dialog.buttons.defaults().size(200f, 60f);
dialog.buttons.addButton("$uiscale.cancel", exit);
dialog.buttons.addButton("$ok", () -> {
Core.settings.put("uiscalechanged", false);
settings.save();
dialog.hide();
});
dialog.buttons.addButton("$ok", () -> {
Core.settings.put("uiscalechanged", false);
settings.save();
dialog.hide();
});
Core.app.post(dialog::show);
dialog.show();
}));
}
}

View File

@@ -40,7 +40,7 @@ import static io.anuke.mindustry.Vars.*;
public class NetServer implements ApplicationListener{
public final static int maxSnapshotSize = 430;
private final static float serverSyncTime = 15, kickDuration = 30 * 1000;
private final static float serverSyncTime = 12, kickDuration = 30 * 1000;
private final static Vector2 vector = new Vector2();
private final static Rectangle viewport = new Rectangle();
/** If a player goes away of their server-side coordinates by this distance, they get teleported back. */
@@ -176,7 +176,7 @@ public class NetServer implements ApplicationListener{
//playing in pvp mode automatically assigns players to teams
if(state.rules.pvp){
player.setTeam(assignTeam(playerGroup.all()));
player.setTeam(assignTeam(player, playerGroup.all()));
Log.info("Auto-assigned player {0} to team {1}.", player.name, player.getTeam());
}
@@ -194,13 +194,13 @@ public class NetServer implements ApplicationListener{
});
}
public Team assignTeam(Iterable<Player> players){
public Team assignTeam(Player current, Iterable<Player> players){
//find team with minimum amount of players and auto-assign player to that.
return Structs.findMin(Team.all, team -> {
if(state.teams.isActive(team) && !state.teams.get(team).cores.isEmpty()){
int count = 0;
for(Player other : players){
if(other.getTeam() == team){
if(other.getTeam() == team && other != current){
count++;
}
}

View File

@@ -256,7 +256,7 @@ public class Renderer implements ApplicationListener{
draw(playerGroup, p -> true, Player::drawBuildRequests);
if(Entities.countInBounds(shieldGroup) > 0){
if(settings.getBool("animatedshields")){
if(settings.getBool("animatedshields") && Shaders.shield != null){
Draw.flush();
shieldBuffer.begin();
graphics.clear(Color.CLEAR);

View File

@@ -220,6 +220,10 @@ public class World implements ApplicationListener{
}
public void loadMap(Map map){
loadMap(map, new Rules());
}
public void loadMap(Map map, Rules checkRules){
try{
SaveIO.load(map.file, new FilterContext(map));
}catch(Exception e){
@@ -238,20 +242,21 @@ public class World implements ApplicationListener{
invalidMap = false;
if(!headless){
if(state.teams.get(defaultTeam).cores.size == 0){
if(state.teams.get(defaultTeam).cores.size == 0 && !checkRules.pvp){
ui.showError("$map.nospawn");
invalidMap = true;
}else if(state.rules.pvp){ //pvp maps need two cores to be valid
invalidMap = true;
}else if(checkRules.pvp){ //pvp maps need two cores to be valid
int teams = 0;
for(Team team : Team.all){
if(state.teams.get(team).cores.size != 0 && team != defaultTeam){
invalidMap = false;
if(state.teams.get(team).cores.size != 0){
teams ++;
}
}
if(invalidMap){
if(teams < 2){
invalidMap = true;
ui.showError("$map.nospawn.pvp");
}
}else if(state.rules.attackMode){ //pvp maps need two cores to be valid
}else if(checkRules.attackMode){ //attack maps need two cores to be valid
invalidMap = state.teams.get(waveTeam).cores.isEmpty();
if(invalidMap){
ui.showError("$map.nospawn.attack");

View File

@@ -55,7 +55,7 @@ public class Predict{
* See {@link #intercept(float, float, float, float, float, float, float)}.
*/
public static Vector2 intercept(TargetTrait src, TargetTrait dst, float v){
return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getTargetVelocityX() - src.getTargetVelocityX(), dst.getTargetVelocityY() - src.getTargetVelocityY(), v);
return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getTargetVelocityX() - src.getTargetVelocityX()/2f, dst.getTargetVelocityY() - src.getTargetVelocityY()/2f, v);
}
private static Vector2 quad(float a, float b, float c){

View File

@@ -5,6 +5,7 @@ import io.anuke.arc.math.Mathf;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.content.Fx;
import io.anuke.mindustry.entities.Effects;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.Pal;
public class MissileBulletType extends BasicBulletType{
@@ -18,6 +19,7 @@ public class MissileBulletType extends BasicBulletType{
backColor = Pal.missileYellowBack;
frontColor = Pal.missileYellow;
homingPower = 7f;
hitSound = Sounds.explosion;
}
@Override

View File

@@ -1,33 +1,28 @@
package io.anuke.mindustry.entities.traits;
import io.anuke.annotations.Annotations.*;
import io.anuke.arc.Core;
import io.anuke.arc.Events;
import io.anuke.arc.collection.Array;
import io.anuke.arc.*;
import io.anuke.arc.collection.Queue;
import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.Angles;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Vector2;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.entities.type.TileEntity;
import io.anuke.mindustry.entities.type.Unit;
import io.anuke.mindustry.game.EventType.BuildSelectEvent;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.graphics.Pal;
import io.anuke.mindustry.net.Net;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.*;
import io.anuke.mindustry.content.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.BuildBlock;
import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity;
import io.anuke.mindustry.world.blocks.*;
import io.anuke.mindustry.world.blocks.BuildBlock.*;
import java.io.*;
import java.util.Arrays;
import java.util.*;
import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.entities.traits.BuilderTrait.BuildDataStatic.removal;
import static io.anuke.mindustry.entities.traits.BuilderTrait.BuildDataStatic.tmptr;
import static io.anuke.mindustry.entities.traits.BuilderTrait.BuildDataStatic.*;
/** Interface for units that build things.*/
public interface BuilderTrait extends Entity, TeamTrait{
@@ -106,19 +101,14 @@ public interface BuilderTrait extends Entity, TeamTrait{
unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(entity), 0.4f);
}
//progress is synced, thus not updated clientside
if(!Net.client()){
//deconstructing is 2x as fast
if(current.breaking){
entity.deconstruct(unit, core, 2f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
}else{
entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
}
current.progress = entity.progress();
//deconstructing is 2x as fast
if(current.breaking){
entity.deconstruct(unit, core, 2f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
}else{
entity.progress = current.progress;
entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier);
}
current.progress = entity.progress;
}
/** Returns the queue for storing build requests. */
@@ -135,7 +125,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
default void writeBuilding(DataOutput output) throws IOException{
BuildRequest request = buildRequest();
if(request != null){
if(request != null && (request.block != null || request.breaking)){
output.writeByte(request.breaking ? 1 : 0);
output.writeInt(Pos.get(request.x, request.y));
output.writeFloat(request.progress);
@@ -174,7 +164,11 @@ public interface BuilderTrait extends Entity, TeamTrait{
if(applyChanges){
buildQueue().addLast(request);
}else if(isBuilding()){
buildRequest().progress = progress;
BuildRequest last = buildRequest();
last.progress = progress;
if(last.tile() != null && last.tile().entity instanceof BuildEntity){
((BuildEntity)last.tile().entity).progress = progress;
}
}
}
}
@@ -285,6 +279,10 @@ public interface BuilderTrait extends Entity, TeamTrait{
this.breaking = true;
}
public Tile tile(){
return world.tile(x, y);
}
@Override
public String toString(){
return "BuildRequest{" +

View File

@@ -70,7 +70,6 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
private Tile mining;
private Vector2 movement = new Vector2();
private boolean moved;
private SoundLoop buildSound = new SoundLoop(Sounds.build, 0.75f);
//endregion
@@ -131,11 +130,6 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
}
}
@Override
public void removed(){
buildSound.stop();
}
@Override
public float drag(){
return mech.drag;
@@ -514,11 +508,13 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
}
if(!isDead() && isFlying()){
loops.play(Sounds.thruster, this, Mathf.clamp(velocity.len() * 2f) * 0.4f);
loops.play(Sounds.thruster, this, Mathf.clamp(velocity.len() * 2f) * 0.3f);
}
BuildRequest request = buildRequest();
buildSound.update(request == null ? x : request.x * tilesize, request == null ? y : request.y * tilesize, isBuilding() && (Mathf.within(request.x * tilesize, request.y * tilesize, x, y, placeDistance) || state.isEditor()));
if(isBuilding() && request.tile() != null && (request.tile().withinDst(x, y, placeDistance) || state.isEditor())){
loops.play(Sounds.build, request.tile(), 0.75f);
}
if(isDead()){
isBoosting = false;
@@ -531,7 +527,9 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
spawner = null;
}
avoidOthers();
if(isLocal || Net.server()){
avoidOthers();
}
Tile tile = world.tileWorld(x, y);

View File

@@ -5,6 +5,7 @@ import io.anuke.mindustry.entities.type.TileEntity;
import io.anuke.mindustry.entities.units.UnitState;
import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.*;
import java.io.*;
@@ -23,6 +24,10 @@ public class RepairDrone extends BaseDrone{
target = Units.findDamagedTile(team, x, y);
}
if(target instanceof TileEntity && ((TileEntity)target).block instanceof BuildBlock){
target = null;
}
if(target != null){
if(target.dst(RepairDrone.this) > type.range){
circle(type.range * 0.9f);

View File

@@ -27,8 +27,13 @@ public class EventType{
}
}
/** Called when the game is first loaded. */
public static class GameLoadEvent{
/** Called when the client game is first loaded. */
public static class ClientLoadEvent{
}
/** Called when the core app is first loaded. */
public static class AppLoadEvent{
}

View File

@@ -14,7 +14,7 @@ import static io.anuke.mindustry.Vars.*;
/** Controls playback of multiple music tracks.*/
public class MusicControl{
private static final float finTime = 120f, foutTime = 120f, musicInterval = 60 * 60 * 3f, musicChance = 0.3f, musicWaveChance = 0.24f;
private static final float finTime = 120f, foutTime = 120f, musicInterval = 60 * 60 * 3f, musicChance = 0.45f, musicWaveChance = 0.35f;
/** normal, ambient music, plays at any time */
public final Array<Music> ambientMusic = Array.with(Musics.game1, Musics.game3, Musics.game4, Musics.game6);

View File

@@ -26,8 +26,10 @@ public class Stats{
public RankResult calculateRank(Zone zone, boolean launched){
float score = 0;
//each new launch period adds onto the rank 'points'
if(wavesLasted >= zone.conditionWave){
if(launched && zone.getRules().attackMode){
score += 3f;
}else if(wavesLasted >= zone.conditionWave){
//each new launch period adds onto the rank 'points'
score += (float)((wavesLasted - zone.conditionWave) / zone.launchPeriod + 1) * 1.2f;
}

View File

@@ -1,5 +1,6 @@
package io.anuke.mindustry.graphics;
import io.anuke.annotations.Annotations.*;
import io.anuke.arc.Core;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.graphics.g2d.TextureRegion;
@@ -10,7 +11,7 @@ import io.anuke.arc.util.Time;
public class Shaders{
public static Shadow shadow;
public static BlockBuild blockbuild;
public static Shield shield;
public static @Nullable Shield shield;
public static UnitBuild build;
public static FogShader fog;
public static MenuShader menu;
@@ -19,7 +20,13 @@ public class Shaders{
public static void init(){
shadow = new Shadow();
blockbuild = new BlockBuild();
shield = new Shield();
try{
shield = new Shield();
}catch(Throwable t){
//don't load shield shader
shield = null;
t.printStackTrace();
}
build = new UnitBuild();
fog = new FogShader();
menu = new MenuShader();

View File

@@ -131,7 +131,7 @@ public class DesktopInput extends InputHandler{
player.isShooting = false;
}
if(!state.is(State.menu) && Core.input.keyTap(Binding.minimap) && !ui.chatfrag.chatOpen() && !(scene.getKeyboardFocus() instanceof TextField)){
if(!state.is(State.menu) && Core.input.keyTap(Binding.minimap) && (scene.getKeyboardFocus() == ui.minimap || !scene.hasDialog()) && !ui.chatfrag.chatOpen() && !(scene.getKeyboardFocus() instanceof TextField)){
if(!ui.minimap.isShown()){
ui.minimap.show();
}else{

View File

@@ -214,7 +214,12 @@ public class Maps implements Disposable{
return filters;
}else{
return JsonIO.read(Array.class, str);
try{
return JsonIO.read(Array.class, str.replace("mindustrz", "mindustry"));
}catch(Exception e){
e.printStackTrace();
return readFilters("");
}
}
}

View File

@@ -17,7 +17,6 @@ public class MirrorFilter extends GenerateFilter{
{
options(new SliderOption("angle", () -> angle, f -> angle = (int)f, 0, 360, 45));
buffered = true;
}
@Override

View File

@@ -1,14 +1,15 @@
package io.anuke.mindustry.net;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Vector2;
import io.anuke.arc.util.Time;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.*;
public class Interpolator{
//used for movement
public Vector2 target = new Vector2();
public Vector2 last = new Vector2();
public float[] targets = {};
public float[] lasts = {};
public long lastUpdated, updateSpacing;
//current state
@@ -21,6 +22,12 @@ public class Interpolator{
lastUpdated = Time.millis();
targets = target1ds;
if(lasts.length != values.length){
lasts = new float[values.length];
}
for(int i = 0; i < values.length; i++){
lasts[i] = values[i];
}
last.set(cx, cy);
target.set(x, y);
}
@@ -46,8 +53,12 @@ public class Interpolator{
values = new float[targets.length];
}
if(lasts.length != targets.length){
lasts = new float[targets.length];
}
for(int i = 0; i < values.length; i++){
values[i] = Mathf.slerp(values[i], targets[i], alpha);
values[i] = Mathf.slerp(lasts[i], targets[i], alpha);
}
}else{
pos.set(target);

View File

@@ -1,19 +1,18 @@
package io.anuke.mindustry.net;
import io.anuke.arc.Core;
import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.function.BiConsumer;
import io.anuke.arc.function.Consumer;
import io.anuke.arc.function.*;
import io.anuke.arc.util.*;
import io.anuke.arc.util.pooling.Pools;
import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.gen.Call;
import io.anuke.arc.util.pooling.*;
import io.anuke.mindustry.core.*;
import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.net.Packets.*;
import io.anuke.mindustry.net.Streamable.StreamBuilder;
import io.anuke.mindustry.net.Streamable.*;
import net.jpountz.lz4.*;
import java.io.IOException;
import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.io.*;
import java.nio.*;
import static io.anuke.mindustry.Vars.*;
@@ -28,6 +27,8 @@ public class Net{
private static ClientProvider clientProvider;
private static ServerProvider serverProvider;
private static IntMap<StreamBuilder> streams = new IntMap<>();
private static final LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor();
private static final LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor();
/** Display a network error. Call on the graphics thread. */
public static void showError(Throwable e){
@@ -144,11 +145,11 @@ public class Net{
}
public static byte[] compressSnapshot(byte[] input){
return serverProvider.compressSnapshot(input);
return compressor.compress(input);
}
public static byte[] decompressSnapshot(byte[] input, int size){
return clientProvider.decompressSnapshot(input, size);
return decompressor.decompress(input, size);
}
/**
@@ -162,8 +163,8 @@ public class Net{
/**
* Returns a list of all connections IDs.
*/
public static Array<NetConnection> getConnections(){
return (Array<NetConnection>)serverProvider.getConnections();
public static Iterable<NetConnection> getConnections(){
return (Iterable<NetConnection>)serverProvider.getConnections();
}
/**
@@ -326,7 +327,7 @@ public class Net{
public static void dispose(){
if(clientProvider != null) clientProvider.dispose();
if(serverProvider != null) serverProvider.dispose();
if(serverProvider != null) serverProvider.close();
clientProvider = null;
serverProvider = null;
server = false;
@@ -354,9 +355,6 @@ public class Net{
/** Disconnect from the server. */
void disconnect();
/** Decompress an input snapshot byte array. */
byte[] decompressSnapshot(byte[] input, int size);
/**
* Discover servers. This should run the callback regardless of whether any servers are found. Should not block.
* Callback should be run on libGDX main thread.
@@ -377,30 +375,61 @@ public class Net{
void host(int port) throws IOException;
/** Sends a large stream of data to a specific client. */
void sendStream(int id, Streamable stream);
default void sendStream(int id, Streamable stream){
NetConnection connection = getByID(id);
if(connection == null) return;
try{
int cid;
StreamBegin begin = new StreamBegin();
begin.total = stream.stream.available();
begin.type = Registrator.getID(stream.getClass());
connection.send(begin, SendMode.tcp);
cid = begin.id;
/** Send an object to everyone connected. */
void send(Object object, SendMode mode);
while(stream.stream.available() > 0){
byte[] bytes = new byte[Math.min(512, stream.stream.available())];
stream.stream.read(bytes);
/** Send an object to a specific client ID. */
void sendTo(int id, Object object, SendMode mode);
StreamChunk chunk = new StreamChunk();
chunk.id = cid;
chunk.data = bytes;
connection.send(chunk, SendMode.tcp);
}
}catch(IOException e){
throw new RuntimeException(e);
}
}
/** Send an object to everyone <i>except</i> a client ID. */
void sendExcept(int id, Object object, SendMode mode);
default void send(Object object, SendMode mode){
for(NetConnection con : getConnections()){
con.send(object, mode);
}
}
default void sendTo(int id, Object object, SendMode mode){
NetConnection conn = getByID(id);
if(conn == null){
Log.err("Failed to find connection with ID {0}.", id);
return;
}
conn.send(object, mode);
}
default void sendExcept(int id, Object object, SendMode mode){
for(NetConnection con : getConnections()){
if(con.id != id){
con.send(object, mode);
}
}
}
/** Close the server connection. */
void close();
/** Compress an input snapshot byte array. */
byte[] compressSnapshot(byte[] input);
/** Return all connected users. */
Array<? extends NetConnection> getConnections();
Iterable<? extends NetConnection> getConnections();
/** Returns a connection by ID. */
NetConnection getByID(int id);
/** Close all connections. */
void dispose();
}
}

View File

@@ -3,6 +3,8 @@ package io.anuke.mindustry.net;
import io.anuke.mindustry.net.Net.SendMode;
public abstract class NetConnection{
private static int lastID;
public final int id;
public final String address;
@@ -18,8 +20,9 @@ public abstract class NetConnection{
public boolean hasBegunConnecting = false;
public float viewWidth, viewHeight, viewX, viewY;
public NetConnection(int id, String address){
this.id = id;
/** Assigns this connection a unique ID. No two connections will ever have the same ID.*/
public NetConnection(String address){
this.id = lastID++;
this.address = address;
}

View File

@@ -31,7 +31,6 @@ public class FileChooser extends FloatingDialog{
private Predicate<FileHandle> filter;
private Consumer<FileHandle> selectListener;
private boolean open;
private int lastWidth = Core.graphics.getWidth(), lastHeight = Core.graphics.getHeight();
public static final Predicate<String> pngFiles = str -> str.equals("png");
public static final Predicate<String> anyMapFiles = str -> str.equals(oldMapExtension) || str.equals(mapExtension);
@@ -44,12 +43,14 @@ public class FileChooser extends FloatingDialog{
this.filter = filter;
this.selectListener = result;
update(() -> {
if(Core.graphics.getWidth() != lastWidth || Core.graphics.getHeight() != lastHeight){
updateFiles(false);
lastHeight = Core.graphics.getHeight();
lastWidth = Core.graphics.getWidth();
}
onResize(() -> {
cont.clear();
setupWidgets();
});
shown(() -> {
cont.clear();
setupWidgets();
});
}
@@ -121,8 +122,9 @@ public class FileChooser extends FloatingDialog{
forward.resizeImage(isize);
forward.clicked(() -> stack.forward());
back.clicked(() -> stack.back());
forward.setDisabled(() -> !stack.canForward());
back.setDisabled(() -> !stack.canBack());
ImageButton home = new ImageButton("icon-home");
home.resizeImage(isize);
@@ -206,7 +208,7 @@ public class FileChooser extends FloatingDialog{
//macs are confined to the Downloads/ directory
if(!OS.isMac){
Image upimage = new Image("icon-folder-parent");
Image upimage = new Image("icon-folder-parent-small");
TextButton upbutton = new TextButton(".." + directory.toString(), "clear-toggle");
upbutton.clicked(() -> {
directory = directory.parent();
@@ -214,7 +216,7 @@ public class FileChooser extends FloatingDialog{
updateFiles(true);
});
upbutton.left().add(upimage).padRight(4f).size(iconsize);
upbutton.left().add(upimage).padRight(4f).size(iconsizesmall).padLeft(4);
upbutton.getLabel().setAlignment(Align.left);
upbutton.getCells().reverse();
@@ -248,9 +250,9 @@ public class FileChooser extends FloatingDialog{
button.setChecked(filename.equals(filefield.getText()));
});
Image image = new Image(file.isDirectory() ? "icon-folder" : "icon-file-text");
Image image = new Image(file.isDirectory() ? "icon-folder-small" : "icon-file-text-small");
button.add(image).padRight(4f).size(iconsize);
button.add(image).padRight(4f).padLeft(4).size(iconsizesmall);
button.getCells().reverse();
files.top().left().add(button).align(Align.topLeft).fillX().expandX()
.height(50).pad(2).padTop(0).padBottom(0).colspan(2);
@@ -273,17 +275,6 @@ public class FileChooser extends FloatingDialog{
}
}
@Override
public Dialog show(){
Time.runTask(2f, () -> {
cont.clear();
setupWidgets();
super.show();
Core.scene.setScrollFocus(pane);
});
return this;
}
public class FileHistory{
private Array<FileHandle> history = new Array<>();
private int index;

View File

@@ -39,18 +39,6 @@ public class FloatingDialog extends Dialog{
state.set(State.paused);
}
});
boolean[] done = {false};
shown(() -> Core.app.post(() ->
forEach(child -> {
if(done[0]) return;
if(child instanceof ScrollPane){
Core.scene.setScrollFocus(child);
done[0] = true;
}
})));
}
public FloatingDialog(String title){
@@ -59,8 +47,9 @@ public class FloatingDialog extends Dialog{
protected void onResize(Runnable run){
Events.on(ResizeEvent.class, event -> {
if(isShown()){
if(isShown() && Core.scene.getDialog() == this){
run.run();
updateScrollFocus();
}
});
}

View File

@@ -1,11 +1,11 @@
package io.anuke.mindustry.ui.dialogs;
import io.anuke.arc.Core;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.game.Stats.RankResult;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.Item.Icon;
import io.anuke.arc.*;
import io.anuke.mindustry.core.GameState.*;
import io.anuke.mindustry.game.Stats.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.type.Item.*;
import static io.anuke.mindustry.Vars.*;

View File

@@ -1,21 +1,20 @@
package io.anuke.mindustry.ui.dialogs;
import io.anuke.annotations.Annotations.Serialize;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.scene.style.Drawable;
import io.anuke.annotations.Annotations.*;
import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.*;
import io.anuke.arc.math.*;
import io.anuke.arc.scene.style.*;
import io.anuke.arc.scene.ui.*;
import io.anuke.arc.scene.ui.layout.Cell;
import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.arc.util.Strings;
import io.anuke.arc.util.Time;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.core.Platform;
import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.net.Host;
import io.anuke.arc.scene.ui.layout.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.*;
import io.anuke.mindustry.core.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.*;
import io.anuke.mindustry.net.Packets.*;
import static io.anuke.mindustry.Vars.*;
@@ -97,9 +96,14 @@ public class JoinDialog extends FloatingDialog{
TextButton button = buttons[0] = remote.addButton("[accent]" + server.displayIP(), "clear", () -> {
if(!buttons[0].childrenPressed()){
connect(server.ip, server.port);
if(server.lastHost != null && server.lastHost.version != Version.build && Version.build != -1 && server.lastHost.version != -1){
ui.showInfo("[scarlet]" + (server.lastHost.version > Version.build ? KickReason.clientOutdated : KickReason.serverOutdated).toString() + "\n[]" +
Core.bundle.format("server.versions", Version.build, server.lastHost.version));
}else{
connect(server.ip, server.port);
}
}
}).width(targetWidth()).height(130f).pad(4f).get();
}).width(targetWidth()).pad(4f).get();
button.getLabel().setWrap(true);

View File

@@ -106,7 +106,7 @@ public class PausedDialog extends FloatingDialog{
return;
}
if(control.saves.getCurrent() == null || !control.saves.getCurrent().isAutosave() || state.rules.tutorial){
if(control.saves.getCurrent() == null || !control.saves.getCurrent().isAutosave() || state.rules.tutorial || wasClient){
state.set(State.menu);
logic.reset();
return;

View File

@@ -241,7 +241,9 @@ public class SettingsMenuDialog extends SettingsDialog{
graphics.checkPref("fps", false);
graphics.checkPref("indicators", true);
graphics.checkPref("animatedwater", false);
graphics.checkPref("animatedshields", !mobile);
if(Shaders.shield != null){
graphics.checkPref("animatedshields", !mobile);
}
graphics.checkPref("bloom", false, val -> renderer.toggleBloom(val));
graphics.checkPref("lasers", true);
graphics.checkPref("pixelate", false);

View File

@@ -113,9 +113,16 @@ public class ZoneInfoDialog extends FloatingDialog{
t.add("$zone.resources").padRight(6);
if(zone.resources.length > 0){
for(Item item : zone.resources){
t.addImage(item.icon(Item.Icon.medium)).size(8 * 3);
}
t.table(r -> {
t.left();
int i = 0;
for(Item item : zone.resources){
r.addImage(item.icon(Item.Icon.medium)).size(8 * 3);
if(++i % 4 == 0){
r.row();
}
}
});
}else{
t.add("$none");
}

View File

@@ -242,9 +242,9 @@ public class HudFragment extends Fragment{
IntFormat fps = new IntFormat("fps");
IntFormat ping = new IntFormat("ping");
info.label(() -> fps.get(Core.graphics.getFramesPerSecond())).left();
info.label(() -> fps.get(Core.graphics.getFramesPerSecond())).left().style("outline");
info.row();
info.label(() -> ping.get(Net.getPing())).visible(Net::client).left();
info.label(() -> ping.get(Net.getPing())).visible(Net::client).left().style("outline");
}).top().left();
});

View File

@@ -294,9 +294,7 @@ public class Block extends BlockStorage{
/** Called after the block is placed by this client. */
@CallSuper
public void playerPlaced(Tile tile){
if(outputsPower && !consumesPower){
PowerNode.lastPlaced = tile.pos();
}
}
/** Called after the block is placed by anyone. */

View File

@@ -2,6 +2,7 @@ package io.anuke.mindustry.world.blocks.power;
import io.anuke.annotations.Annotations.*;
import io.anuke.arc.*;
import io.anuke.arc.collection.*;
import io.anuke.arc.function.*;
import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*;
@@ -20,9 +21,7 @@ import io.anuke.mindustry.world.meta.*;
import static io.anuke.mindustry.Vars.*;
public class PowerNode extends PowerBlock{
//last distribution block placed
public static int lastPlaced = -1;
protected ObjectSet<PowerGraph> graphs = new ObjectSet<>();
protected Vector2 t1 = new Vector2(), t2 = new Vector2();
protected TextureRegion laser, laserEnd;
@@ -99,23 +98,11 @@ public class PowerNode extends PowerBlock{
() -> Mathf.clamp(entity.power.graph.getPowerProduced() / entity.power.graph.getPowerNeeded())));
}
@Override
public void playerPlaced(Tile tile){
Tile before = world.tile(lastPlaced);
if(linkValid(tile, before) && !before.entity.proximity().contains(tile)){
Call.linkPowerNodes(null, tile, before);
}
lastPlaced = tile.pos();
super.playerPlaced(tile);
}
@Override
public void placed(Tile tile){
if(Net.client()) return;
Predicate<Tile> valid = other -> other != null && other != tile && ((!other.block().outputsPower && other.block().consumesPower) || (other.block().outputsPower && !other.block().consumesPower)) && linkValid(tile, other)
Predicate<Tile> valid = other -> other != null && other != tile && ((!other.block().outputsPower && other.block().consumesPower) || (other.block().outputsPower && !other.block().consumesPower) || other.block() instanceof PowerNode) && linkValid(tile, other)
&& !other.entity.proximity().contains(tile) && other.entity.power.graph != tile.entity.power.graph;
tempTiles.clear();
@@ -132,6 +119,28 @@ public class PowerNode extends PowerBlock{
super.placed(tile);
}
private void getPotentialLinks(Tile tile, Consumer<Tile> others){
Predicate<Tile> valid = other -> other != null && other != tile && other.entity != null && other.entity.power != null &&
((!other.block().outputsPower && other.block().consumesPower) || (other.block().outputsPower && !other.block().consumesPower) || other.block() instanceof PowerNode) &&
overlaps(tile.x * tilesize + offset(), tile.y *tilesize + offset(), other, laserRange * tilesize)
&& !other.entity.proximity().contains(tile) && !graphs.contains(other.entity.power.graph);
tempTiles.clear();
graphs.clear();
Geometry.circle(tile.x, tile.y, (int)(laserRange + 1), (x, y) -> {
Tile other = world.ltile(x, y);
if(valid.test(other)){
tempTiles.add(other);
}
});
tempTiles.sort(Structs.comparingFloat(t -> t.dst2(tile)));
tempTiles.each(valid, t -> {
graphs.add(t.entity.power.graph);
others.accept(t);
});
}
@Override
public void setStats(){
super.setStats();
@@ -213,6 +222,11 @@ public class PowerNode extends PowerBlock{
Draw.color(Pal.placing);
Drawf.circles(x * tilesize + offset(), y * tilesize + offset(), laserRange * tilesize);
getPotentialLinks(tile, other -> {
Drawf.square(other.drawx(), other.drawy(), other.block().size * tilesize / 2f + 2f, Pal.place);
});
/*
for(int cx = (int)(x - laserRange - 1); cx <= x + laserRange + 1; cx++){
for(int cy = (int)(y - laserRange - 1); cy <= y + laserRange + 1; cy++){
Tile link = world.ltile(cx, cy);
@@ -221,7 +235,7 @@ public class PowerNode extends PowerBlock{
Drawf.square(link.drawx(), link.drawy(), link.block().size * tilesize / 2f + 2f, link.pos() == lastPlaced ? Pal.place : Pal.accent);
}
}
}
}*/
Draw.reset();
}

View File

@@ -67,7 +67,7 @@ public class Drill extends Block{
hasItems = true;
idleSound = Sounds.drill;
idleSoundVolume = 0.002f;
idleSoundVolume = 0.003f;
}
@Override

View File

@@ -12,6 +12,11 @@ public class LiquidConverter extends GenericCrafter{
hasLiquids = true;
}
@Override
public boolean outputsItems(){
return false;
}
@Override
public void init(){
ConsumeLiquidBase cl = consumes.get(ConsumeType.liquid);