Merge remote-tracking branch 'upstream/master'

This commit is contained in:
beito123
2019-04-29 17:18:16 +09:00
182 changed files with 9317 additions and 8885 deletions

View File

@@ -8,7 +8,7 @@ buildscript{
} }
dependencies{ dependencies{
classpath 'com.android.tools.build:gradle:3.3.2' classpath 'com.android.tools.build:gradle:3.4.0'
} }
} }

View File

@@ -23,8 +23,8 @@ import io.anuke.mindustry.game.Saves.SaveSlot;
import io.anuke.mindustry.io.SaveIO; import io.anuke.mindustry.io.SaveIO;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.ui.dialogs.FileChooser; import io.anuke.mindustry.ui.dialogs.FileChooser;
import io.anuke.net.KryoClient; import io.anuke.mindustry.net.ArcNetClient;
import io.anuke.net.KryoServer; import io.anuke.mindustry.net.ArcNetServer;
import java.io.*; import java.io.*;
import java.util.ArrayList; import java.util.ArrayList;
@@ -111,8 +111,8 @@ public class AndroidLauncher extends AndroidApplication{
} }
config.hideStatusBar = true; config.hideStatusBar = true;
Net.setClientProvider(new KryoClient()); Net.setClientProvider(new ArcNetClient());
Net.setServerProvider(new KryoServer()); Net.setServerProvider(new ArcNetServer());
initialize(new Mindustry(), config); initialize(new Mindustry(), config);
checkFiles(getIntent()); checkFiles(getIntent());
} }

View File

@@ -187,7 +187,7 @@ project(":core"){
task copyGen{ task copyGen{
doLast{ doLast{
copy{ copy{
from("../core/build/classes/java/main/io/anuke/mindustry/gen/"){ from("../core/build/generated/sources/annotationProcessor/java/main/io/anuke/mindustry/gen"){
include "**/*.java" include "**/*.java"
} }
@@ -202,7 +202,7 @@ project(":core"){
compile arcModule("arc-core") compile arcModule("arc-core")
compile arcModule("extensions:freetype") compile arcModule("extensions:freetype")
//compile arcModule("extensions:postprocessing") compile arcModule("extensions:arcnet")
if(localArc() && debugged()) compile arcModule("extensions:recorder") if(localArc() && debugged()) compile arcModule("extensions:recorder")
compileOnly project(":annotations") compileOnly project(":annotations")
@@ -259,7 +259,6 @@ project(":net"){
dependencies{ dependencies{
compile project(":core") compile project(":core")
compile "org.lz4:lz4-java:1.4.1" compile "org.lz4:lz4-java:1.4.1"
compile 'com.github.Anuken:kryonet:a64d2280880e80566ca1bdaffa55de43e51cad38'
compile 'com.github.Anuken:WaifUPnP:05eb46bc577fd7674596946ba288c96c0cedd893' compile 'com.github.Anuken:WaifUPnP:05eb46bc577fd7674596946ba288c96c0cedd893'
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 115 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 B

View File

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@@ -158,6 +158,7 @@ confirm = Confirm
delete = Delete delete = Delete
ok = OK ok = OK
open = Open open = Open
customize = Customize
cancel = Cancel cancel = Cancel
openlink = Open Link openlink = Open Link
copylink = Copy Link copylink = Copy Link
@@ -174,6 +175,7 @@ loading = [accent]Loading...
saving = [accent]Saving... saving = [accent]Saving...
wave = [accent]Wave {0} wave = [accent]Wave {0}
wave.waiting = [LIGHT_GRAY]Wave in {0} wave.waiting = [LIGHT_GRAY]Wave in {0}
wave.waveInProgress = [LIGHT_GRAY]Wave in progress
waiting = [LIGHT_GRAY]Waiting... waiting = [LIGHT_GRAY]Waiting...
waiting.players = Waiting for players... waiting.players = Waiting for players...
wave.enemies = [LIGHT_GRAY]{0} Enemies Remaining wave.enemies = [LIGHT_GRAY]{0} Enemies Remaining
@@ -326,6 +328,8 @@ zone.ruinousShores.name = Ruinous Shores
zone.stainedMountains.name = Stained Mountains zone.stainedMountains.name = Stained Mountains
zone.desolateRift.name = Desolate Rift zone.desolateRift.name = Desolate Rift
zone.nuclearComplex.name = Nuclear Production Complex zone.nuclearComplex.name = Nuclear Production Complex
zone.overgrowth.name = Overgrowth
zone.tarFields.name = Tar Fields
settings.language = Language settings.language = Language
settings.reset = Reset to Defaults settings.reset = Reset to Defaults
@@ -440,14 +444,14 @@ setting.difficulty.name = Difficulty:
setting.screenshake.name = Screen Shake setting.screenshake.name = Screen Shake
setting.effects.name = Display Effects setting.effects.name = Display Effects
setting.sensitivity.name = Controller Sensitivity setting.sensitivity.name = Controller Sensitivity
setting.saveinterval.name = Autosave Interval setting.saveinterval.name = Save Interval
setting.seconds = {0} Seconds setting.seconds = {0} Seconds
setting.fullscreen.name = Fullscreen setting.fullscreen.name = Fullscreen
setting.borderless.name = Borderless Window setting.borderless.name = Borderless Window
setting.fps.name = Show FPS setting.fps.name = Show FPS
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Show Power Lasers setting.lasers.name = Show Power Lasers
setting.pixelate.name = Pixelate [LIGHT_GRAY](may decrease performance, disables animations) setting.pixelate.name = Pixelate[LIGHT_GRAY] (disables animations)
setting.minimap.name = Show Minimap setting.minimap.name = Show Minimap
setting.musicvol.name = Music Volume setting.musicvol.name = Music Volume
setting.mutemusic.name = Mute Music setting.mutemusic.name = Mute Music
@@ -480,6 +484,7 @@ keybind.zoom_hold.name = Zoom Hold
keybind.zoom.name = Zoom keybind.zoom.name = Zoom
keybind.menu.name = Menu keybind.menu.name = Menu
keybind.pause.name = Pause keybind.pause.name = Pause
keybind.minimap.name = Minimap
keybind.dash.name = Dash keybind.dash.name = Dash
keybind.chat.name = Chat keybind.chat.name = Chat
keybind.player_list.name = Player list keybind.player_list.name = Player list
@@ -496,21 +501,18 @@ mode.survival.name = Survival
mode.survival.description = The normal mode. Limited resources and automatic incoming waves. mode.survival.description = The normal mode. Limited resources and automatic incoming waves.
mode.sandbox.name = Sandbox mode.sandbox.name = Sandbox
mode.sandbox.description = Infinite resources and no timer for waves. mode.sandbox.description = Infinite resources and no timer for waves.
mode.freebuild.name = Freebuild
mode.freebuild.description = Limited resources and no timer for waves.
mode.pvp.name = PvP mode.pvp.name = PvP
mode.pvp.description = Fight against other players locally. mode.pvp.description = Fight against other players locally.
mode.attack.name = Attack mode.attack.name = Attack
mode.attack.description = No waves, with the goal to destroy the enemy base. mode.attack.description = Destroy the enemy's base. No waves.
mode.custom = Custom Rules mode.custom = Custom Rules
rules.infiniteresources = Infinite Resources rules.infiniteresources = Infinite Resources
rules.wavetimer = Wave Timer rules.wavetimer = Wave Timer
rules.waves = Waves rules.waves = Waves
rules.enemyCheat = Infinite AI (Red Team) Resources rules.enemyCheat = Infinite AI (Red Team) Resources
rules.pvp = PvP
rules.unitdrops = Unit Drops rules.unitdrops = Unit Drops
rules.unitbuildspeedmultiplier = Unit Creation Speed Multiplier rules.unitbuildspeedmultiplier = Unit Production Speed Multiplier
rules.unithealthmultiplier = Unit Health Multiplier rules.unithealthmultiplier = Unit Health Multiplier
rules.playerhealthmultiplier = Player Health Multiplier rules.playerhealthmultiplier = Player Health Multiplier
rules.playerdamagemultiplier = Player Damage Multiplier rules.playerdamagemultiplier = Player Damage Multiplier
@@ -520,6 +522,16 @@ rules.respawntime = Respawn Time:[LIGHT_GRAY] (sec)
rules.wavespacing = Wave Spacing:[LIGHT_GRAY] (sec) rules.wavespacing = Wave Spacing:[LIGHT_GRAY] (sec)
rules.buildcostmultiplier = Build Cost Multiplier rules.buildcostmultiplier = Build Cost Multiplier
rules.buildspeedmultiplier = Build Speed Multiplier rules.buildspeedmultiplier = Build Speed Multiplier
rules.waitForWaveToEnd = Waves wait for enemies
rules.dropzoneradius = Drop Zone Radius:[LIGHT_GRAY] (tiles)
rules.respawns = Max respawns per wave
rules.limitedRespawns = Limit Respawns
rules.title.waves = Waves
rules.title.respawns = Respawns
rules.title.resourcesbuilding = Resources & Building
rules.title.player = Players
rules.title.enemy = Enemies
rules.title.unit = Units
content.item.name = Items content.item.name = Items
content.liquid.name = Liquids content.liquid.name = Liquids
@@ -610,6 +622,7 @@ block.grass.name = Grass
block.salt.name = Salt block.salt.name = Salt
block.saltrocks.name = Salt Rocks block.saltrocks.name = Salt Rocks
block.pebbles.name = Pebbles block.pebbles.name = Pebbles
block.tendrils.name = Tendrils
block.sandrocks.name = Sand Rocks block.sandrocks.name = Sand Rocks
block.spore-pine.name = Spore Pine block.spore-pine.name = Spore Pine
block.sporerocks.name = Spore Rocks block.sporerocks.name = Spore Rocks
@@ -618,6 +631,7 @@ block.snowrock.name = Snow Rock
block.shale.name = Shale block.shale.name = Shale
block.shale-boulder.name = Shale Boulder block.shale-boulder.name = Shale Boulder
block.moss.name = Moss block.moss.name = Moss
block.shrubs.name = Shrubs
block.spore-moss.name = Spore Moss block.spore-moss.name = Spore Moss
block.shalerocks.name = Shale Rocks block.shalerocks.name = Shale Rocks
block.scrap-wall.name = Scrap Wall block.scrap-wall.name = Scrap Wall
@@ -722,7 +736,7 @@ block.pneumatic-drill.name = Pneumatic Drill
block.laser-drill.name = Laser Drill block.laser-drill.name = Laser Drill
block.water-extractor.name = Water Extractor block.water-extractor.name = Water Extractor
block.cultivator.name = Cultivator block.cultivator.name = Cultivator
block.alpha-dart-mech-pad.name = Alpha-Dart Mech Pad block.dart-mech-pad.name = Dart Mech Pad
block.delta-mech-pad.name = Delta Mech Pad block.delta-mech-pad.name = Delta Mech Pad
block.javelin-ship-pad.name = Javelin Ship Pad block.javelin-ship-pad.name = Javelin Ship Pad
block.trident-ship-pad.name = Trident Ship Pad block.trident-ship-pad.name = Trident Ship Pad

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 501 B

After

Width:  |  Height:  |  Size: 501 B

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

After

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 143 KiB

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 KiB

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 274 KiB

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 522 KiB

After

Width:  |  Height:  |  Size: 401 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 338 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 704 KiB

After

Width:  |  Height:  |  Size: 685 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 KiB

After

Width:  |  Height:  |  Size: 373 KiB

View File

@@ -281,6 +281,7 @@
font: default-font-chat, font: default-font-chat,
fontColor: white, fontColor: white,
disabledFontColor: gray, disabledFontColor: gray,
disabledBackground: underline-disabled,
selection: selection, selection: selection,
background: underline, background: underline,
invalidBackground: underline-red, invalidBackground: underline-red,
@@ -305,9 +306,12 @@
checkboxOff: check-off, checkboxOff: check-off,
checkboxOnOver: check-on-over, checkboxOnOver: check-on-over,
checkboxOver: check-over, checkboxOver: check-over,
checkboxOnDisabled: check-on-disabled,
checkboxOffDisabled: check-disabled,
font: default-font, font: default-font,
fontColor: white, fontColor: white,
disabledFontColor: gray disabledFontColor: gray,
} }
} }
} }

View File

@@ -6,8 +6,7 @@ import io.anuke.arc.files.FileHandle;
import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.Color;
import io.anuke.arc.util.Structs; import io.anuke.arc.util.Structs;
import io.anuke.mindustry.core.*; import io.anuke.mindustry.core.*;
import io.anuke.mindustry.entities.Entities; import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.EntityGroup;
import io.anuke.mindustry.entities.bullet.Bullet; import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.effect.Fire; import io.anuke.mindustry.entities.effect.Fire;
import io.anuke.mindustry.entities.effect.Puddle; import io.anuke.mindustry.entities.effect.Puddle;
@@ -48,10 +47,6 @@ public class Vars{
public static final Team defaultTeam = Team.blue; public static final Team defaultTeam = Team.blue;
/** team of the enemy in waves/sectors */ /** team of the enemy in waves/sectors */
public static final Team waveTeam = Team.red; public static final Team waveTeam = Team.red;
/** how many times longer a boss wave takes */
public static final float bossWaveMultiplier = 3f;
/** how many times longer a launch wave takes */
public static final float launchWaveMultiplier = 2f;
/** max chat message length */ /** max chat message length */
public static final int maxTextLength = 150; public static final int maxTextLength = 150;
/** max player name length in bytes */ /** max player name length in bytes */
@@ -70,22 +65,22 @@ public class Vars{
public static final int tilesize = 8; public static final int tilesize = 8;
/** all choosable player colors in join/host dialog */ /** all choosable player colors in join/host dialog */
public static final Color[] playerColors = { public static final Color[] playerColors = {
Color.valueOf("82759a"), Color.valueOf("82759a"),
Color.valueOf("c0c1c5"), Color.valueOf("c0c1c5"),
Color.valueOf("fff0e7"), Color.valueOf("fff0e7"),
Color.valueOf("7d2953"), Color.valueOf("7d2953"),
Color.valueOf("ff074e"), Color.valueOf("ff074e"),
Color.valueOf("ff072a"), Color.valueOf("ff072a"),
Color.valueOf("ff76a6"), Color.valueOf("ff76a6"),
Color.valueOf("a95238"), Color.valueOf("a95238"),
Color.valueOf("ffa108"), Color.valueOf("ffa108"),
Color.valueOf("feeb2c"), Color.valueOf("feeb2c"),
Color.valueOf("ffcaa8"), Color.valueOf("ffcaa8"),
Color.valueOf("008551"), Color.valueOf("008551"),
Color.valueOf("00e339"), Color.valueOf("00e339"),
Color.valueOf("423c7b"), Color.valueOf("423c7b"),
Color.valueOf("4b5ef1"), Color.valueOf("4b5ef1"),
Color.valueOf("2cabfe"), Color.valueOf("2cabfe"),
}; };
/** default server port */ /** default server port */
public static final int port = 6567; public static final int port = 6567;
@@ -120,6 +115,7 @@ public class Vars{
public static ContentLoader content; public static ContentLoader content;
public static GameState state; public static GameState state;
public static GlobalData data; public static GlobalData data;
public static EntityCollisions collisions;
public static Control control; public static Control control;
public static Logic logic; public static Logic logic;
@@ -165,6 +161,8 @@ public class Vars{
content.setVerbose(); content.setVerbose();
} }
collisions = new EntityCollisions();
playerGroup = Entities.addGroup(Player.class).enableMapping(); playerGroup = Entities.addGroup(Player.class).enableMapping();
tileGroup = Entities.addGroup(TileEntity.class, false); tileGroup = Entities.addGroup(TileEntity.class, false);
bulletGroup = Entities.addGroup(Bullet.class).enableMapping(); bulletGroup = Entities.addGroup(Bullet.class).enableMapping();

View File

@@ -21,7 +21,6 @@ import java.io.*;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
public class WaveSpawner{ public class WaveSpawner{
private static final float shockwaveBase = 380f, shockwaveRand = 0f, maxShockwaveDst = shockwaveBase + shockwaveRand;
private Array<FlyerSpawn> flySpawns = new Array<>(); private Array<FlyerSpawn> flySpawns = new Array<>();
private Array<GroundSpawn> groundSpawns = new Array<>(); private Array<GroundSpawn> groundSpawns = new Array<>();
private IntArray loadedSpawns = new IntArray(); private IntArray loadedSpawns = new IntArray();
@@ -56,7 +55,7 @@ public class WaveSpawner{
/** @return true if the player is near a ground spawn point. */ /** @return true if the player is near a ground spawn point. */
public boolean playerNear(){ public boolean playerNear(){
return groundSpawns.count(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, player.x, player.y) < maxShockwaveDst) > 0; return groundSpawns.count(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, player.x, player.y) < state.rules.dropZoneRadius) > 0;
} }
public void spawnEnemies(){ public void spawnEnemies(){
@@ -98,7 +97,7 @@ public class WaveSpawner{
} }
Time.run(20f, () -> Effects.effect(Fx.spawnShockwave, spawn.x * tilesize, spawn.y * tilesize)); Time.run(20f, () -> Effects.effect(Fx.spawnShockwave, spawn.x * tilesize, spawn.y * tilesize));
//would be interesting to see player structures survive this without hacks //would be interesting to see player structures survive this without hacks
Time.run(40f, () -> Damage.damage(waveTeam, spawn.x * tilesize, spawn.y * tilesize, shockwaveBase + Mathf.random(shockwaveRand), 99999999f, true)); Time.run(40f, () -> Damage.damage(waveTeam, spawn.x * tilesize, spawn.y * tilesize, state.rules.dropZoneRadius, 99999999f, true));
} }
} }
} }

View File

@@ -36,7 +36,7 @@ public class Blocks implements ContentList{
metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, ignarock, magmarock, hotrock, snowrocks, rock, snowrock, saltRocks, metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, ignarock, magmarock, hotrock, snowrocks, rock, snowrock, saltRocks,
creeptree, creeptree,
darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal,
pebbles, pebbles, tendrils,
//ores //ores
oreCopper, oreLead, oreScrap, oreCoal, oreTitanium, oreThorium, oreCopper, oreLead, oreScrap, oreCoal, oreTitanium, oreThorium,
@@ -77,7 +77,7 @@ public class Blocks implements ContentList{
fortressFactory, repairPoint, fortressFactory, repairPoint,
//upgrades //upgrades
alphaDartPad, deltaPad, tauPad, omegaPad, javelinPad, tridentPad, glaivePad; dartPad, deltaPad, tauPad, omegaPad, javelinPad, tridentPad, glaivePad;
@Override @Override
public void load(){ public void load(){
@@ -112,10 +112,7 @@ public class Blocks implements ContentList{
part = new BlockPart(); part = new BlockPart();
spawn = new Block("spawn"){ spawn = new Block("spawn");
public void drawShadow(Tile tile){
}
};
//Registers build blocks from size 1-6 //Registers build blocks from size 1-6
//no reference is needed here since they can be looked up by name later //no reference is needed here since they can be looked up by name later
@@ -255,13 +252,11 @@ public class Blocks implements ContentList{
dragMultiplier = 1f; dragMultiplier = 1f;
speedMultiplier = 1f; speedMultiplier = 1f;
attributes.set(Attribute.water, 0.4f); attributes.set(Attribute.water, 0.4f);
edgeStyle = "blocky";
}}; }};
iceSnow = new Floor("ice-snow"){{ iceSnow = new Floor("ice-snow"){{
variants = 3; variants = 3;
attributes.set(Attribute.water, 0.3f); attributes.set(Attribute.water, 0.3f);
edgeStyle = "blocky";
}}; }};
cliffs = new StaticWall("cliffs"){{ cliffs = new StaticWall("cliffs"){{
@@ -351,7 +346,6 @@ public class Blocks implements ContentList{
sporeMoss = new Floor("spore-moss"){{ sporeMoss = new Floor("spore-moss"){{
variants = 3; variants = 3;
attributes.set(Attribute.spores, 0.3f); attributes.set(Attribute.spores, 0.3f);
edgeStyle = "blocky";
}}; }};
metalFloor = new Floor("metal-floor"){{ metalFloor = new Floor("metal-floor"){{
@@ -359,7 +353,7 @@ public class Blocks implements ContentList{
}}; }};
metalFloorDamaged = new Floor("metal-floor-damaged"){{ metalFloorDamaged = new Floor("metal-floor-damaged"){{
variants = 6; variants = 3;
}}; }};
metalFloor2 = new Floor("metal-floor-2"){{ metalFloor2 = new Floor("metal-floor-2"){{
@@ -381,11 +375,12 @@ public class Blocks implements ContentList{
darkPanel5 = new Floor("dark-panel-5"){{ variants = 0; }}; darkPanel5 = new Floor("dark-panel-5"){{ variants = 0; }};
darkPanel6 = new Floor("dark-panel-6"){{ variants = 0; }}; darkPanel6 = new Floor("dark-panel-6"){{ variants = 0; }};
darkMetal = new StaticWall("dark-metal"){{ darkMetal = new StaticWall("dark-metal");
}};
pebbles = new OverlayFloor("pebbles"); pebbles = new OverlayFloor("pebbles");
tendrils = new OverlayFloor("tendrils");
//endregion //endregion
//region ore //region ore
@@ -902,8 +897,8 @@ public class Blocks implements ContentList{
junction = new Junction("junction"){{ junction = new Junction("junction"){{
requirements(Category.distribution, ItemStack.with(Items.copper, 3), true); requirements(Category.distribution, ItemStack.with(Items.copper, 3), true);
speed = 26; speed = 26;
capacity = 32; capacity = 15;
health = 25; health = 30;
}}; }};
itemBridge = new BufferedItemBridge("bridge-conveyor"){{ itemBridge = new BufferedItemBridge("bridge-conveyor"){{
@@ -1117,7 +1112,7 @@ public class Blocks implements ContentList{
itemDuration = 40f; itemDuration = 40f;
consumes.power(25f); consumes.power(25f);
consumes.item(Items.blastCompound); consumes.item(Items.blastCompound);
consumes.liquid(Liquids.cryofluid, 0.3f); consumes.liquid(Liquids.cryofluid, 0.26f);
}}; }};
//endregion power //endregion power
@@ -1652,9 +1647,9 @@ public class Blocks implements ContentList{
//endregion //endregion
//region upgrades //region upgrades
alphaDartPad = new MechPad("alpha-dart-mech-pad"){{ dartPad = new MechPad("dart-mech-pad"){{
requirements(Category.upgrade, ItemStack.with(Items.lead, 200, Items.graphite, 100, Items.copper, 150)); requirements(Category.upgrade, ItemStack.with(Items.lead, 200, Items.graphite, 100, Items.copper, 150));
mech = Mechs.alpha; mech = Mechs.dart;
size = 2; size = 2;
consumes.powerBuffered(50f); consumes.powerBuffered(50f);
}}; }};

View File

@@ -730,7 +730,7 @@ public class Bullets implements ContentList{
explode = new BombBulletType(2f, 3f, "clear"){ explode = new BombBulletType(2f, 3f, "clear"){
{ {
hitEffect = Fx.pulverize; hitEffect = Fx.pulverize;
lifetime = 23f; lifetime = 30f;
speed = 1f; speed = 1f;
splashDamageRadius = 50f; splashDamageRadius = 50f;
splashDamage = 28f; splashDamage = 28f;

View File

@@ -6,7 +6,6 @@ import io.anuke.arc.graphics.Color;
import io.anuke.arc.graphics.g2d.Draw; import io.anuke.arc.graphics.g2d.Draw;
import io.anuke.arc.graphics.g2d.TextureRegion; import io.anuke.arc.graphics.g2d.TextureRegion;
import io.anuke.arc.math.Mathf; import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Rectangle;
import io.anuke.arc.util.Time; import io.anuke.arc.util.Time;
import io.anuke.mindustry.entities.Effects; import io.anuke.mindustry.entities.Effects;
import io.anuke.mindustry.entities.Units; import io.anuke.mindustry.entities.Units;
@@ -21,20 +20,18 @@ import io.anuke.mindustry.type.Weapon;
public class Mechs implements ContentList{ public class Mechs implements ContentList{
public static Mech alpha, delta, tau, omega, dart, javelin, trident, glaive; public static Mech alpha, delta, tau, omega, dart, javelin, trident, glaive;
/** These are not new mechs, just re-assignments for convenience. */ public static Mech starter;
public static Mech starterDesktop, starterMobile;
@Override @Override
public void load(){ public void load(){
alpha = new Mech("alpha-mech", false){ alpha = new Mech("alpha-mech", false){
{ {
drillPower = 1; drillPower = 1;
mineSpeed = 1.5f; mineSpeed = 1.5f;
mass = 1.2f; mass = 1.2f;
speed = 0.5f; speed = 0.5f;
boostSpeed = 0.85f; boostSpeed = 0.95f;
buildPower = 1.2f; buildPower = 1.2f;
engineColor = Color.valueOf("ffd37f"); engineColor = Color.valueOf("ffd37f");
health = 300f; health = 300f;
@@ -103,7 +100,6 @@ public class Mechs implements ContentList{
float healRange = 60f; float healRange = 60f;
float healAmount = 10f; float healAmount = 10f;
float healReload = 160f; float healReload = 160f;
Rectangle rect = new Rectangle();
boolean wasHealed; boolean wasHealed;
{ {
@@ -137,15 +133,12 @@ public class Mechs implements ContentList{
if(player.timer.get(Player.timerAbility, healReload)){ if(player.timer.get(Player.timerAbility, healReload)){
wasHealed = false; wasHealed = false;
rect.setSize(healRange * 2f).setCenter(player.x, player.y); Units.nearby(player.getTeam(), player.x, player.y, healRange, unit -> {
Units.getNearby(player.getTeam(), rect, unit -> { if(unit.health < unit.maxHealth()){
if(unit.dst(player) <= healRange){ Effects.effect(Fx.heal, unit);
if(unit.health < unit.maxHealth()){ wasHealed = true;
Effects.effect(Fx.heal, unit);
wasHealed = true;
}
unit.healBy(healAmount);
} }
unit.healBy(healAmount);
}); });
if(wasHealed){ if(wasHealed){
@@ -230,9 +223,9 @@ public class Mechs implements ContentList{
{ {
drillPower = 1; drillPower = 1;
mineSpeed = 0.9f; mineSpeed = 0.9f;
speed = 0.4f; speed = 0.5f;
drag = 0.1f; drag = 0.09f;
health = 180f; health = 200f;
weaponOffsetX = -1; weaponOffsetX = -1;
weaponOffsetY = -1; weaponOffsetY = -1;
engineColor = Pal.lightTrail; engineColor = Pal.lightTrail;
@@ -240,17 +233,12 @@ public class Mechs implements ContentList{
buildPower = 1.1f; buildPower = 1.1f;
weapon = new Weapon("blaster"){{ weapon = new Weapon("blaster"){{
length = 1.5f; length = 1.5f;
reload = 20f; reload = 15f;
roundrobin = true; roundrobin = true;
ejectEffect = Fx.shellEjectSmall; ejectEffect = Fx.shellEjectSmall;
bullet = Bullets.standardCopper; bullet = Bullets.standardCopper;
}}; }};
} }
@Override
public boolean alwaysUnlocked(){
return true;
}
}; };
javelin = new Mech("javelin-ship", true){ javelin = new Mech("javelin-ship", true){
@@ -371,7 +359,6 @@ public class Mechs implements ContentList{
} }
}; };
starterDesktop = alpha; starter = alpha;
starterMobile = dart;
} }
} }

View File

@@ -250,7 +250,7 @@ public class TechTree implements ContentList{
node(phantomFactory); node(phantomFactory);
}); });
node(alphaDartPad, () -> { node(dartPad, () -> {
node(deltaPad, () -> { node(deltaPad, () -> {
node(javelinPad, () -> { node(javelinPad, () -> {
@@ -281,8 +281,7 @@ public class TechTree implements ContentList{
} }
private TechNode node(Block block){ private TechNode node(Block block){
return node(block, () -> { return node(block, () -> {});
});
} }
public static class TechNode{ public static class TechNode{

View File

@@ -1,18 +1,17 @@
package io.anuke.mindustry.content; package io.anuke.mindustry.content;
import io.anuke.mindustry.game.ContentList; import io.anuke.arc.collection.Array;
import io.anuke.mindustry.game.Rules; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.maps.zonegen.DesertWastesGenerator;
import io.anuke.mindustry.maps.generators.MapGenerator; import io.anuke.mindustry.maps.generators.MapGenerator;
import io.anuke.mindustry.maps.generators.MapGenerator.Decoration; import io.anuke.mindustry.maps.generators.MapGenerator.Decoration;
import io.anuke.mindustry.maps.zonegen.OvergrowthGenerator; import io.anuke.mindustry.maps.zonegen.DesertWastesGenerator;
import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Block;
public class Zones implements ContentList{ public class Zones implements ContentList{
public static Zone public static Zone
groundZero, desertWastes, groundZero, desertWastes,
craters, frozenForest, ruinousShores, stainedMountains, craters, frozenForest, ruinousShores, stainedMountains, tarFields,
saltFlats, overgrowth, infestedIslands, saltFlats, overgrowth, infestedIslands,
desolateRift, nuclearComplex; desolateRift, nuclearComplex;
@@ -35,21 +34,58 @@ public class Zones implements ContentList{
desertWastes = new Zone("desertWastes", new DesertWastesGenerator(260, 260)){{ desertWastes = new Zone("desertWastes", new DesertWastesGenerator(260, 260)){{
startingItems = ItemStack.list(Items.copper, 200); startingItems = ItemStack.list(Items.copper, 200);
conditionWave = 10; conditionWave = 20;
zoneRequirements = ZoneRequirement.with(groundZero, 10); launchPeriod = 10;
blockRequirements = new Block[]{Blocks.router}; loadout = Loadouts.advancedShard;
zoneRequirements = ZoneRequirement.with(groundZero, 20);
resources = new Item[]{Items.copper, Items.lead, Items.coal, Items.sand}; resources = new Item[]{Items.copper, Items.lead, Items.coal, Items.sand};
rules = () -> new Rules(){{ rules = () -> new Rules(){{
waves = true; waves = true;
waveTimer = true; waveTimer = true;
waveSpacing = 60 * 60 * 1.5f; launchWaveMultiplier = 3f;
waveSpacing = 60 * 50f;
spawns = Array.with(
new SpawnGroup(UnitTypes.crawler){{
unitScaling = 3f;
}},
new SpawnGroup(UnitTypes.dagger){{
unitScaling = 4f;
begin = 2;
spacing = 2;
}},
new SpawnGroup(UnitTypes.wraith){{
unitScaling = 3f;
begin = 11;
spacing = 3;
}},
new SpawnGroup(UnitTypes.eruptor){{
unitScaling = 3f;
begin = 22;
unitAmount = 1;
spacing = 4;
}},
new SpawnGroup(UnitTypes.titan){{
unitScaling = 3f;
begin = 37;
unitAmount = 2;
spacing = 4;
}},
new SpawnGroup(UnitTypes.fortress){{
unitScaling = 2f;
effect = StatusEffects.boss;
begin = 41;
spacing = 20;
}}
);
}}; }};
}}; }};
//to be implemented as an attack map
/*
saltFlats = new Zone("saltFlats", new DesertWastesGenerator(260, 260)){{ saltFlats = new Zone("saltFlats", new DesertWastesGenerator(260, 260)){{
startingItems = ItemStack.list(Items.copper, 200); startingItems = ItemStack.list(Items.copper, 200);
conditionWave = 10; conditionWave = 10;
zoneRequirements = ZoneRequirement.with(groundZero, 10); zoneRequirements = ZoneRequirement.with(desertWastes, 25);
blockRequirements = new Block[]{Blocks.router}; blockRequirements = new Block[]{Blocks.router};
resources = new Item[]{Items.copper, Items.lead, Items.coal, Items.sand}; resources = new Item[]{Items.copper, Items.lead, Items.coal, Items.sand};
rules = () -> new Rules(){{ rules = () -> new Rules(){{
@@ -57,20 +93,7 @@ public class Zones implements ContentList{
waveTimer = true; waveTimer = true;
waveSpacing = 60 * 60 * 1.5f; waveSpacing = 60 * 60 * 1.5f;
}}; }};
}}; }};*/
overgrowth = new Zone("overgrowth", new OvergrowthGenerator(320, 320)){{
startingItems = ItemStack.list(Items.copper, 200);
conditionWave = 10;
zoneRequirements = ZoneRequirement.with(groundZero, 10);
blockRequirements = new Block[]{Blocks.router};
resources = new Item[]{Items.copper, Items.lead, Items.coal};
rules = () -> new Rules(){{
waves = true;
waveTimer = true;
waveSpacing = 60 * 60 * 1.5f;
}};
}};
craters = new Zone("craters", new MapGenerator("craters", 1).dist(0).decor(new Decoration(Blocks.snow, Blocks.sporeCluster, 0.01))){{ craters = new Zone("craters", new MapGenerator("craters", 1).dist(0).decor(new Decoration(Blocks.snow, Blocks.sporeCluster, 0.01))){{
startingItems = ItemStack.list(Items.copper, 200); startingItems = ItemStack.list(Items.copper, 200);
@@ -100,13 +123,28 @@ public class Zones implements ContentList{
}}; }};
}}; }};
overgrowth = new Zone("overgrowth", new MapGenerator("overgrowth")){{
startingItems = ItemStack.list(Items.copper, 3000, Items.lead, 2000, Items.silicon, 1000, Items.metaglass, 500);
conditionWave = 12;
launchPeriod = 4;
loadout = Loadouts.basicNucleus;
zoneRequirements = ZoneRequirement.with(frozenForest, 40);
blockRequirements = new Block[]{Blocks.router};
resources = new Item[]{Items.copper, Items.lead, Items.coal, Items.titanium, Items.sand, Items.thorium, Items.scrap};
rules = () -> new Rules(){{
waves = true;
waveTimer = true;
waveSpacing = 60 * 100f;
}};
}};
ruinousShores = new Zone("ruinousShores", new MapGenerator("ruinousShores", 1).dist(3f, true)){{ ruinousShores = new Zone("ruinousShores", new MapGenerator("ruinousShores", 1).dist(3f, true)){{
loadout = Loadouts.basicFoundation; loadout = Loadouts.basicFoundation;
baseLaunchCost = ItemStack.with(); baseLaunchCost = ItemStack.with();
startingItems = ItemStack.list(Items.copper, 400); startingItems = ItemStack.list(Items.copper, 400);
conditionWave = 20; conditionWave = 20;
launchPeriod = 20; launchPeriod = 20;
zoneRequirements = ZoneRequirement.with(frozenForest, 10, craters, 15); zoneRequirements = ZoneRequirement.with(desertWastes, 20, craters, 15);
blockRequirements = new Block[]{Blocks.graphitePress, Blocks.combustionGenerator}; blockRequirements = new Block[]{Blocks.graphitePress, Blocks.combustionGenerator};
resources = new Item[]{Items.copper, Items.scrap, Items.lead, Items.coal, Items.sand}; resources = new Item[]{Items.copper, Items.scrap, Items.lead, Items.coal, Items.sand};
rules = () -> new Rules(){{ rules = () -> new Rules(){{
@@ -124,7 +162,7 @@ public class Zones implements ContentList{
zoneRequirements = new Zone[]{frozenForest}; zoneRequirements = new Zone[]{frozenForest};
blockRequirements = new Block[]{Blocks.copperWall}; blockRequirements = new Block[]{Blocks.copperWall};
rules = () -> new Rules(){{ rules = () -> new Rules(){{
waves = true; waves = true;]
waveTimer = true; waveTimer = true;
waveSpacing = 60 * 80; waveSpacing = 60 * 80;
}}; }};
@@ -132,9 +170,8 @@ public class Zones implements ContentList{
stainedMountains = new Zone("stainedMountains", new MapGenerator("stainedMountains", 2) stainedMountains = new Zone("stainedMountains", new MapGenerator("stainedMountains", 2)
.dist(0f, false) .dist(0f, false)
.decor(new Decoration(Blocks.moss, Blocks.shaleBoulder, 0.02))){{ .decor(new Decoration(Blocks.shale, Blocks.shaleBoulder, 0.02))){{
loadout = Loadouts.basicFoundation; loadout = Loadouts.basicFoundation;
baseLaunchCost = ItemStack.with();
startingItems = ItemStack.list(Items.copper, 400, Items.lead, 100); startingItems = ItemStack.list(Items.copper, 400, Items.lead, 100);
conditionWave = 10; conditionWave = 10;
launchPeriod = 10; launchPeriod = 10;
@@ -148,31 +185,47 @@ public class Zones implements ContentList{
}}; }};
}}; }};
desolateRift = new Zone("desolateRift", new MapGenerator("desolateRift").dist(2f)){{ tarFields = new Zone("tarFields", new MapGenerator("tarFields")
loadout = Loadouts.basicNucleus; .dist(0f, false)
baseLaunchCost = ItemStack.with(); .decor(new Decoration(Blocks.shale, Blocks.shaleBoulder, 0.02))){{
startingItems = ItemStack.list(Items.copper, 1500); loadout = Loadouts.basicFoundation;
conditionWave = 10; startingItems = ItemStack.list(Items.copper, 500, Items.lead, 200);
launchPeriod = 20; conditionWave = 15;
zoneRequirements = ZoneRequirement.with(stainedMountains, 20); launchPeriod = 10;
blockRequirements = new Block[]{Blocks.thermalGenerator}; zoneRequirements = ZoneRequirement.with(ruinousShores, 20);
blockRequirements = new Block[]{Blocks.coalCentrifuge};
resources = new Item[]{Items.copper, Items.scrap, Items.lead, Items.coal, Items.titanium, Items.sand}; resources = new Item[]{Items.copper, Items.scrap, Items.lead, Items.coal, Items.titanium, Items.sand};
rules = () -> new Rules(){{ rules = () -> new Rules(){{
waves = true; waves = true;
waveTimer = true; waveTimer = true;
waveSpacing = 60 * 60 * 1.3f; waveSpacing = 60 * 60 * 2;
}};
}};
desolateRift = new Zone("desolateRift", new MapGenerator("desolateRift").dist(2f)){{
loadout = Loadouts.basicNucleus;
baseLaunchCost = ItemStack.with();
startingItems = ItemStack.list(Items.copper, 1500);
conditionWave = 3;
launchPeriod = 1;
zoneRequirements = ZoneRequirement.with(tarFields, 20);
blockRequirements = new Block[]{Blocks.thermalGenerator};
resources = new Item[]{Items.copper, Items.scrap, Items.lead, Items.coal, Items.titanium, Items.sand, Items.thorium};
rules = () -> new Rules(){{
waves = true;
waveTimer = true;
waveSpacing = 60 * 60 * 2.5f;
}}; }};
}}; }};
nuclearComplex = new Zone("nuclearComplex", new MapGenerator("nuclearProductionComplex", 1) nuclearComplex = new Zone("nuclearComplex", new MapGenerator("nuclearProductionComplex", 1)
.drops(ItemStack.with(Items.copper, 2000, Items.lead, 1500, Items.silicon, 1000, Items.graphite, 1000, Items.thorium, 200, Items.titanium, 2000, Items.metaglass, 1000))
.decor(new Decoration(Blocks.snow, Blocks.sporeCluster, 0.01))){{ .decor(new Decoration(Blocks.snow, Blocks.sporeCluster, 0.01))){{
loadout = Loadouts.basicNucleus; loadout = Loadouts.basicNucleus;
baseLaunchCost = ItemStack.with(); baseLaunchCost = ItemStack.with();
startingItems = ItemStack.list(Items.copper, 2500, Items.lead, 3000, Items.silicon, 800, Items.metaglass, 400); startingItems = ItemStack.list(Items.copper, 2500, Items.lead, 3000, Items.silicon, 800, Items.metaglass, 400);
conditionWave = 30; conditionWave = 30;
launchPeriod = 15; launchPeriod = 15;
zoneRequirements = ZoneRequirement.with(desolateRift, 20); zoneRequirements = ZoneRequirement.with(stainedMountains, 20);
blockRequirements = new Block[]{Blocks.thermalGenerator}; blockRequirements = new Block[]{Blocks.thermalGenerator};
resources = new Item[]{Items.copper, Items.scrap, Items.lead, Items.coal, Items.titanium, Items.thorium, Items.sand}; resources = new Item[]{Items.copper, Items.scrap, Items.lead, Items.coal, Items.titanium, Items.thorium, Items.sand};
rules = () -> new Rules(){{ rules = () -> new Rules(){{

View File

@@ -9,10 +9,8 @@ import io.anuke.arc.input.KeyCode;
import io.anuke.arc.scene.ui.Dialog; import io.anuke.arc.scene.ui.Dialog;
import io.anuke.arc.scene.ui.TextField; import io.anuke.arc.scene.ui.TextField;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.mindustry.content.Mechs;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.Effects; import io.anuke.mindustry.entities.Effects;
import io.anuke.mindustry.entities.EntityQuery;
import io.anuke.mindustry.entities.type.Player; import io.anuke.mindustry.entities.type.Player;
import io.anuke.mindustry.game.*; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.EventType.*;
@@ -91,7 +89,15 @@ public class Control implements ApplicationListener{
}); });
Events.on(WorldLoadEvent.class, event -> { Events.on(WorldLoadEvent.class, event -> {
Core.app.post(() -> Core.app.post(() -> Core.camera.position.set(player))); Core.app.post(() -> Core.app.post(() -> {
if(Net.active() && player.getClosestCore() != null){
//set to closest core since that's where the player will probably respawn; prevents camera jumps
Core.camera.position.set(player.getClosestCore());
}else{
//locally, set to player position since respawning occurs immediately
Core.camera.position.set(player);
}
}));
}); });
Events.on(ResetEvent.class, event -> { Events.on(ResetEvent.class, event -> {
@@ -124,7 +130,7 @@ public class Control implements ApplicationListener{
} }
}); });
//autohost for pvp sectors //autohost for pvp maps
Events.on(WorldLoadEvent.class, event -> { Events.on(WorldLoadEvent.class, event -> {
if(state.rules.pvp && !Net.active()){ if(state.rules.pvp && !Net.active()){
try{ try{
@@ -173,7 +179,6 @@ public class Control implements ApplicationListener{
void createPlayer(){ void createPlayer(){
player = new Player(); player = new Player();
player.name = Core.settings.getString("name"); player.name = Core.settings.getString("name");
player.mech = mobile ? Mechs.starterMobile : Mechs.starterDesktop;
player.color.set(Core.settings.getInt("color-0")); player.color.set(Core.settings.getInt("color-0"));
player.isLocal = true; player.isLocal = true;
player.isMobile = mobile; player.isMobile = mobile;
@@ -230,8 +235,6 @@ public class Control implements ApplicationListener{
@Override @Override
public void init(){ public void init(){
EntityQuery.init();
Platform.instance.updateRPC(); Platform.instance.updateRPC();
if(!Core.settings.getBool("4.0-warning-2", false)){ if(!Core.settings.getBool("4.0-warning-2", false)){

View File

@@ -9,6 +9,7 @@ import io.anuke.arc.util.Time;
import io.anuke.mindustry.content.Fx; import io.anuke.mindustry.content.Fx;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.type.Player;
import io.anuke.mindustry.entities.type.TileEntity; import io.anuke.mindustry.entities.type.TileEntity;
import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.*; import io.anuke.mindustry.game.*;
@@ -33,13 +34,15 @@ public class Logic implements ApplicationListener{
if(world.isZone()){ if(world.isZone()){
world.getZone().updateWave(state.wave); world.getZone().updateWave(state.wave);
} }
for (Player p : playerGroup.all()) {
p.respawns = state.rules.respawns;
}
}); });
} }
@Override @Override
public void init(){ public void init(){
EntityQuery.init(); collisions.setCollider(tilesize, (x, y) -> {
EntityQuery.collisions().setCollider(tilesize, (x, y) -> {
Tile tile = world.tile(x, y); Tile tile = world.tile(x, y);
return tile != null && tile.solid(); return tile != null && tile.solid();
}); });
@@ -55,7 +58,11 @@ public class Logic implements ApplicationListener{
public void play(){ public void play(){
state.set(State.playing); state.set(State.playing);
state.wavetime = state.rules.waveSpacing * 2; //grace period of 2x wave time before game starts state.wavetime = state.rules.waveSpacing * 2; //grace period of 2x wave time before game starts
state.rules.spawns = world.getMap().getWaves();
//sometimes a map has no waves defined, they're defined in the zone rules
if(world.getMap().getWaves() != DefaultWaves.get() || !world.isZone()){
state.rules.spawns = world.getMap().getWaves();
}
Events.fire(new PlayEvent()); Events.fire(new PlayEvent());
} }
@@ -78,8 +85,8 @@ public class Logic implements ApplicationListener{
public void runWave(){ public void runWave(){
world.spawner.spawnEnemies(); world.spawner.spawnEnemies();
state.wave++; state.wave++;
state.wavetime = world.isZone() && world.getZone().isBossWave(state.wave) ? state.rules.waveSpacing * bossWaveMultiplier : state.wavetime = world.isZone() && world.getZone().isBossWave(state.wave) ? state.rules.waveSpacing * state.rules.bossWaveMultiplier :
world.isZone() && world.getZone().isLaunchWave(state.wave) ? state.rules.waveSpacing * launchWaveMultiplier : state.rules.waveSpacing; world.isZone() && world.getZone().isLaunchWave(state.wave) ? state.rules.waveSpacing * state.rules.launchWaveMultiplier : state.rules.waveSpacing;
Events.fire(new WaveEvent()); Events.fire(new WaveEvent());
} }
@@ -88,7 +95,7 @@ public class Logic implements ApplicationListener{
if(state.rules.waves && state.teams.get(defaultTeam).cores.size == 0 && !state.gameOver){ if(state.rules.waves && state.teams.get(defaultTeam).cores.size == 0 && !state.gameOver){
state.gameOver = true; state.gameOver = true;
Events.fire(new GameOverEvent(waveTeam)); Events.fire(new GameOverEvent(waveTeam));
}else if(!state.rules.waves){ }else if(state.rules.attackMode){
Team alive = null; Team alive = null;
for(Team team : Team.all){ for(Team team : Team.all){
@@ -144,17 +151,15 @@ public class Logic implements ApplicationListener{
Time.update(); Time.update();
if(state.rules.waves && state.rules.waveTimer && !state.gameOver){ if(state.rules.waves && state.rules.waveTimer && !state.gameOver){
state.wavetime = Math.max(state.wavetime - Time.delta(), 0); if(!state.rules.waitForWaveToEnd || unitGroups[waveTeam.ordinal()].size() == 0){
state.wavetime = Math.max(state.wavetime - Time.delta(), 0);
}
} }
if(!Net.client() && state.wavetime <= 0 && state.rules.waves){ if(!Net.client() && state.wavetime <= 0 && state.rules.waves){
runWave(); runWave();
} }
if(!Entities.defaultGroup().isEmpty()){
throw new IllegalArgumentException("Do not add anything to the default group!");
}
if(!headless){ if(!headless){
Entities.update(effectGroup); Entities.update(effectGroup);
Entities.update(groundEffectGroup); Entities.update(groundEffectGroup);
@@ -179,11 +184,11 @@ public class Logic implements ApplicationListener{
for(EntityGroup group : unitGroups){ for(EntityGroup group : unitGroups){
if(group.isEmpty()) continue; if(group.isEmpty()) continue;
EntityQuery.collideGroups(bulletGroup, group); collisions.collideGroups(bulletGroup, group);
} }
EntityQuery.collideGroups(bulletGroup, playerGroup); collisions.collideGroups(bulletGroup, playerGroup);
EntityQuery.collideGroups(playerGroup, playerGroup); collisions.collideGroups(playerGroup, playerGroup);
world.pathfinder.update(); world.pathfinder.update();
} }

View File

@@ -4,7 +4,8 @@ import io.anuke.annotations.Annotations.Loc;
import io.anuke.annotations.Annotations.Remote; import io.anuke.annotations.Annotations.Remote;
import io.anuke.arc.ApplicationListener; import io.anuke.arc.ApplicationListener;
import io.anuke.arc.Events; import io.anuke.arc.Events;
import io.anuke.arc.collection.*; import io.anuke.arc.collection.IntMap;
import io.anuke.arc.collection.ObjectSet;
import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.Color;
import io.anuke.arc.graphics.Colors; import io.anuke.arc.graphics.Colors;
import io.anuke.arc.math.Mathf; import io.anuke.arc.math.Mathf;
@@ -14,7 +15,6 @@ import io.anuke.arc.util.*;
import io.anuke.arc.util.io.ByteBufferOutput; import io.anuke.arc.util.io.ByteBufferOutput;
import io.anuke.arc.util.io.CountableByteArrayOutputStream; import io.anuke.arc.util.io.CountableByteArrayOutputStream;
import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.content.Mechs;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.Entities; import io.anuke.mindustry.entities.Entities;
import io.anuke.mindustry.entities.EntityGroup; import io.anuke.mindustry.entities.EntityGroup;
@@ -33,7 +33,6 @@ import io.anuke.mindustry.net.Packets.*;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import java.io.*; import java.io.*;
import java.lang.StringBuilder;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.zip.DeflaterOutputStream; import java.util.zip.DeflaterOutputStream;
@@ -161,7 +160,6 @@ public class NetServer implements ApplicationListener{
player.name = packet.name; player.name = packet.name;
player.uuid = uuid; player.uuid = uuid;
player.isMobile = packet.mobile; player.isMobile = packet.mobile;
player.mech = packet.mobile ? Mechs.starterMobile : Mechs.starterDesktop;
player.dead = true; player.dead = true;
player.setNet(player.x, player.y); player.setNet(player.x, player.y);
player.color.set(packet.color); player.color.set(packet.color);

View File

@@ -126,6 +126,13 @@ public class Renderer implements ApplicationListener{
} }
} }
@Override
public void dispose(){
minimap.dispose();
shieldBuffer.dispose();
blocks.dispose();
}
void updateShake(float scale){ void updateShake(float scale){
if(shaketime > 0){ if(shaketime > 0){
float intensity = shakeIntensity * (settings.getInt("screenshake", 4) / 4f) * scale; float intensity = shakeIntensity * (settings.getInt("screenshake", 4) / 4f) * scale;
@@ -195,13 +202,13 @@ public class Renderer implements ApplicationListener{
overlays.drawBottom(); overlays.drawBottom();
drawAndInterpolate(playerGroup, p -> true, Player::drawBuildRequests); drawAndInterpolate(playerGroup, p -> true, Player::drawBuildRequests);
if(EntityDraw.countInBounds(shieldGroup) > 0){ if(Entities.countInBounds(shieldGroup) > 0){
if(settings.getBool("animatedshields")){ if(settings.getBool("animatedshields")){
Draw.flush(); Draw.flush();
shieldBuffer.begin(); shieldBuffer.begin();
graphics.clear(Color.CLEAR); graphics.clear(Color.CLEAR);
EntityDraw.draw(shieldGroup); Entities.draw(shieldGroup);
EntityDraw.drawWith(shieldGroup, shield -> true, shield -> ((ShieldEntity)shield).drawOver()); Entities.draw(shieldGroup, shield -> true, shield -> ((ShieldEntity)shield).drawOver());
Draw.flush(); Draw.flush();
shieldBuffer.end(); shieldBuffer.end();
Draw.shader(Shaders.shield); Draw.shader(Shaders.shield);
@@ -210,7 +217,7 @@ public class Renderer implements ApplicationListener{
Draw.color(); Draw.color();
Draw.shader(); Draw.shader();
}else{ }else{
EntityDraw.drawWith(shieldGroup, shield -> true, shield -> ((ShieldEntity)shield).drawSimple()); Entities.draw(shieldGroup, shield -> true, shield -> ((ShieldEntity)shield).drawSimple());
} }
} }
@@ -289,7 +296,7 @@ public class Renderer implements ApplicationListener{
} }
public <T extends DrawTrait> void drawAndInterpolate(EntityGroup<T> group, Predicate<T> toDraw, Consumer<T> drawer){ public <T extends DrawTrait> void drawAndInterpolate(EntityGroup<T> group, Predicate<T> toDraw, Consumer<T> drawer){
EntityDraw.drawWith(group, toDraw, drawer); Entities.draw(group, toDraw, drawer);
} }
public void scaleCamera(float amount){ public void scaleCamera(float amount){

View File

@@ -76,21 +76,21 @@ public class UI implements ApplicationListener{
Core.input.addProcessor(Core.scene); Core.input.addProcessor(Core.scene);
Dialog.setShowAction(() -> sequence( Dialog.setShowAction(() -> sequence(
alpha(0f), alpha(0f),
originCenter(), originCenter(),
moveToAligned(Core.graphics.getWidth() / 2f, Core.graphics.getHeight() / 2f, Align.center), moveToAligned(Core.graphics.getWidth() / 2f, Core.graphics.getHeight() / 2f, Align.center),
scaleTo(0.0f, 1f), scaleTo(0.0f, 1f),
parallel( parallel(
scaleTo(1f, 1f, 0.1f, Interpolation.fade), scaleTo(1f, 1f, 0.1f, Interpolation.fade),
fadeIn(0.1f, Interpolation.fade) fadeIn(0.1f, Interpolation.fade)
) )
)); ));
Dialog.setHideAction(() -> sequence( Dialog.setHideAction(() -> sequence(
parallel( parallel(
scaleTo(0.01f, 0.01f, 0.1f, Interpolation.fade), scaleTo(0.01f, 0.01f, 0.1f, Interpolation.fade),
fadeOut(0.1f, Interpolation.fade) fadeOut(0.1f, Interpolation.fade)
) )
)); ));
TooltipManager.getInstance().animations = false; TooltipManager.getInstance().animations = false;

View File

@@ -11,7 +11,7 @@ import io.anuke.arc.util.*;
import io.anuke.mindustry.ai.*; import io.anuke.mindustry.ai.*;
import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.EntityQuery; import io.anuke.mindustry.entities.Entities;
import io.anuke.mindustry.game.EventType.TileChangeEvent; import io.anuke.mindustry.game.EventType.TileChangeEvent;
import io.anuke.mindustry.game.EventType.WorldLoadEvent; import io.anuke.mindustry.game.EventType.WorldLoadEvent;
import io.anuke.mindustry.game.Team; import io.anuke.mindustry.game.Team;
@@ -85,13 +85,11 @@ public class World implements ApplicationListener{
return tiles == null ? 0 : tiles[0].length; return tiles == null ? 0 : tiles[0].length;
} }
public @Nullable public @Nullable Tile tile(int pos){
Tile tile(int pos){
return tiles == null ? null : tile(Pos.x(pos), Pos.y(pos)); return tiles == null ? null : tile(Pos.x(pos), Pos.y(pos));
} }
public @Nullable public @Nullable Tile tile(int x, int y){
Tile tile(int x, int y){
if(tiles == null){ if(tiles == null){
return null; return null;
} }
@@ -103,8 +101,7 @@ public class World implements ApplicationListener{
return tiles[x][y]; return tiles[x][y];
} }
public @Nullable public @Nullable Tile tileWorld(float x, float y){
Tile tileWorld(float x, float y){
return tile(Math.round(x / tilesize), Math.round(y / tilesize)); return tile(Math.round(x / tilesize), Math.round(y / tilesize));
} }
@@ -176,7 +173,7 @@ public class World implements ApplicationListener{
addDarkness(tiles); addDarkness(tiles);
EntityQuery.resizeTree(-finalWorldBounds, -finalWorldBounds, tiles.length * tilesize + finalWorldBounds * 2, tiles[0].length * tilesize + finalWorldBounds * 2); Entities.getAllGroups().each(group -> group.resize(-finalWorldBounds, -finalWorldBounds, tiles.length * tilesize + finalWorldBounds * 2, tiles[0].length * tilesize + finalWorldBounds * 2));
generating = false; generating = false;
Events.fire(new WorldLoadEvent()); Events.fire(new WorldLoadEvent());
@@ -263,7 +260,7 @@ public class World implements ApplicationListener{
if(invalidMap){ if(invalidMap){
ui.showError("$map.nospawn.pvp"); ui.showError("$map.nospawn.pvp");
} }
}else if(!state.rules.waves){ //pvp maps need two cores to be valid }else if(state.rules.attackMode){ //pvp maps need two cores to be valid
invalidMap = state.teams.get(waveTeam).cores.isEmpty(); invalidMap = state.teams.get(waveTeam).cores.isEmpty();
if(invalidMap){ if(invalidMap){
ui.showError("$map.nospawn.attack"); ui.showError("$map.nospawn.attack");

View File

@@ -26,7 +26,9 @@ public class EditorTile extends Tile{
public void setFloor(Floor type){ public void setFloor(Floor type){
if(type instanceof OverlayFloor){ if(type instanceof OverlayFloor){
//don't place on liquids //don't place on liquids
setOverlayID(type.id); if(!floor.isLiquid){
setOverlayID(type.id);
}
return; return;
} }

View File

@@ -4,13 +4,13 @@ import io.anuke.arc.Core;
import io.anuke.arc.collection.IntArray; import io.anuke.arc.collection.IntArray;
import io.anuke.arc.function.IntPositionConsumer; import io.anuke.arc.function.IntPositionConsumer;
import io.anuke.arc.input.KeyCode; import io.anuke.arc.input.KeyCode;
import io.anuke.arc.util.Pack; import io.anuke.arc.util.*;
import io.anuke.arc.util.Structs;
import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.content.Blocks;
import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.*; import io.anuke.mindustry.world.blocks.*;
public enum EditorTool{ public enum EditorTool{
zoom,
pick{ pick{
public void touched(MapEditor editor, int x, int y){ public void touched(MapEditor editor, int x, int y){
if(!Structs.inBounds(x, y, editor.width(), editor.height())) return; if(!Structs.inBounds(x, y, editor.width(), editor.height())) return;
@@ -34,6 +34,7 @@ public enum EditorTool{
editor.drawBlock = tile.block() == Blocks.air ? tile.overlay() == Blocks.air ? tile.floor() : tile.overlay() : tile.block(); editor.drawBlock = tile.block() == Blocks.air ? tile.overlay() == Blocks.air ? tile.floor() : tile.overlay() : tile.block();
} }
}, },
line,
pencil{ pencil{
{ {
edit = true; edit = true;
@@ -56,22 +57,6 @@ public enum EditorTool{
editor.draw(x, y, isPaint(), Blocks.air); editor.draw(x, y, isPaint(), Blocks.air);
} }
}, },
spray{
{
edit = true;
draggable = true;
}
@Override
public void touched(MapEditor editor, int x, int y){
editor.draw(x, y, isPaint(), editor.drawBlock, 0.012);
}
},
line{
{
}
},
fill{ fill{
{ {
edit = true; edit = true;
@@ -157,7 +142,6 @@ public enum EditorTool{
}else{ }else{
//normal fill //normal fill
int x1; int x1;
boolean spanAbove, spanBelow;
stack.clear(); stack.clear();
@@ -171,21 +155,21 @@ public enum EditorTool{
x1 = x; x1 = x;
while(x1 >= 0 && eq(x1, y)) x1--; while(x1 >= 0 && eq(x1, y)) x1--;
x1++; x1++;
spanAbove = spanBelow = false; boolean spanAbove = false, spanBelow = false;
while(x1 < width && eq(x1, y)){ while(x1 < width && eq(x1, y)){
writer.accept(x1, y); writer.accept(x1, y);
if(!spanAbove && y > 0 && eq(x1, y - 1)){ if(!spanAbove && y > 0 && eq(x1, y - 1)){
stack.add(Pos.get(x1, y - 1)); stack.add(Pos.get(x1, y - 1));
spanAbove = true; spanAbove = true;
}else if(spanAbove && eq(x1, y - 1)){ }else if(spanAbove && !eq(x1, y - 1)){
spanAbove = false; spanAbove = false;
} }
if(!spanBelow && y < height - 1 && eq(x1, y + 1)){ if(!spanBelow && y < height - 1 && eq(x1, y + 1)){
stack.add(Pos.get(x1, y + 1)); stack.add(Pos.get(x1, y + 1));
spanBelow = true; spanBelow = true;
}else if(spanBelow && y < height - 1 && eq(x1, y + 1)){ }else if(spanBelow && y < height - 1 && !eq(x1, y + 1)){
spanBelow = false; spanBelow = false;
} }
x1++; x1++;
@@ -200,7 +184,17 @@ public enum EditorTool{
return (data.drawBlock instanceof OverlayFloor ? tile.overlay() : isfloor ? tile.floor() : tile.block()) == dest && !(data.drawBlock instanceof OverlayFloor && tile.floor().isLiquid); return (data.drawBlock instanceof OverlayFloor ? tile.overlay() : isfloor ? tile.floor() : tile.block()) == dest && !(data.drawBlock instanceof OverlayFloor && tile.floor().isLiquid);
} }
}, },
zoom; spray{
{
edit = true;
draggable = true;
}
@Override
public void touched(MapEditor editor, int x, int y){
editor.draw(x, y, isPaint(), editor.drawBlock, 0.012);
}
};
boolean edit, draggable; boolean edit, draggable;

View File

@@ -33,6 +33,7 @@ import static io.anuke.mindustry.Vars.*;
public class MapEditorDialog extends Dialog implements Disposable{ public class MapEditorDialog extends Dialog implements Disposable{
public final MapEditor editor; public final MapEditor editor;
private MapView view; private MapView view;
private MapInfoDialog infoDialog; private MapInfoDialog infoDialog;
private MapLoadDialog loadDialog; private MapLoadDialog loadDialog;
@@ -85,49 +86,50 @@ public class MapEditorDialog extends Dialog implements Disposable{
t.row(); t.row();
t.addImageTextButton("$editor.import", "icon-load-map", isize, () -> t.addImageTextButton("$editor.import", "icon-load-map", isize, () ->
createDialog("$editor.import", createDialog("$editor.import",
"$editor.importmap", "$editor.importmap.description", "icon-load-map", (Runnable)loadDialog::show, "$editor.importmap", "$editor.importmap.description", "icon-load-map", (Runnable)loadDialog::show,
"$editor.importfile", "$editor.importfile.description", "icon-file", (Runnable)() -> "$editor.importfile", "$editor.importfile.description", "icon-file", (Runnable)() ->
Platform.instance.showFileChooser("$editor.loadmap", "Map Files", file -> ui.loadAnd(() -> { Platform.instance.showFileChooser("$editor.loadmap", "Map Files", file -> ui.loadAnd(() -> {
try{
//TODO what if it's an image? users should be warned for their stupidity
editor.beginEdit(MapIO.readMap(file, true));
}catch(Exception e){
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
Log.err(e);
}
}), true, mapExtension),
"$editor.importimage", "$editor.importimage.description", "icon-file-image", (Runnable)() ->
Platform.instance.showFileChooser("$loadimage", "Image Files", file ->
ui.loadAnd(() -> {
try{
Pixmap pixmap = new Pixmap(file);
Tile[][] tiles = editor.createTiles(pixmap.getWidth(), pixmap.getHeight());
editor.load(() -> MapIO.readLegacyPixmap(pixmap, tiles));
editor.beginEdit(tiles);
}catch(Exception e){
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
Log.err(e);
}
}), true, "png")));
t.addImageTextButton("$editor.export", "icon-save-map", isize, () ->
Platform.instance.showFileChooser("$editor.savemap", "Map Files", file -> {
file = file.parent().child(file.nameWithoutExtension() + "." + mapExtension);
FileHandle result = file;
ui.loadAnd(() -> {
try{ try{
if(!editor.getTags().containsKey("name")){ //TODO what if it's an image? users should be warned for their stupidity
editor.getTags().put("name", result.nameWithoutExtension()); editor.beginEdit(MapIO.readMap(file, true));
}
MapIO.writeMap(result, editor.createMap(result), editor.tiles());
}catch(Exception e){ }catch(Exception e){
ui.showError(Core.bundle.format("editor.errorsave", Strings.parseException(e, false))); ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
Log.err(e); Log.err(e);
} }
}); }), true, mapExtension),
}, false, mapExtension));
"$editor.importimage", "$editor.importimage.description", "icon-file-image", (Runnable)() ->
Platform.instance.showFileChooser("$loadimage", "Image Files", file ->
ui.loadAnd(() -> {
try{
Pixmap pixmap = new Pixmap(file);
Tile[][] tiles = editor.createTiles(pixmap.getWidth(), pixmap.getHeight());
editor.load(() -> MapIO.readLegacyPixmap(pixmap, tiles));
editor.beginEdit(tiles);
}catch(Exception e){
ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, false)));
Log.err(e);
}
}), true, "png"))
);
t.addImageTextButton("$editor.export", "icon-save-map", isize, () ->
Platform.instance.showFileChooser("$editor.savemap", "Map Files", file -> {
file = file.parent().child(file.nameWithoutExtension() + "." + mapExtension);
FileHandle result = file;
ui.loadAnd(() -> {
try{
if(!editor.getTags().containsKey("name")){
editor.getTags().put("name", result.nameWithoutExtension());
}
MapIO.writeMap(result, editor.createMap(result), editor.tiles());
}catch(Exception e){
ui.showError(Core.bundle.format("editor.errorsave", Strings.parseException(e, false)));
Log.err(e);
}
});
}, false, mapExtension));
}); });
menu.cont.row(); menu.cont.row();

View File

@@ -79,7 +79,9 @@ public class MapGenerateDialog extends FloatingDialog{
cont.clear(); cont.clear();
cont.table("flat", t -> { cont.table("flat", t -> {
t.margin(8f); t.margin(8f);
t.stack(new BorderImage(texture), new Stack(){{ t.stack(new BorderImage(texture){{
setScaling(Scaling.fit);
}}, new Stack(){{
add(new Image("loadDim")); add(new Image("loadDim"));
add(new Image("icon-refresh"){{ add(new Image("icon-refresh"){{
setScaling(Scaling.none); setScaling(Scaling.none);

View File

@@ -24,11 +24,7 @@ import static io.anuke.mindustry.Vars.ui;
public class MapView extends Element implements GestureListener{ public class MapView extends Element implements GestureListener{
private MapEditor editor; private MapEditor editor;
private EditorTool tool = EditorTool.pencil; private EditorTool tool = EditorTool.pencil;
//private OperationStack stack = new OperationStack();
//private DrawOperation op;
//private GridBits used;
private Bresenham2 br = new Bresenham2(); private Bresenham2 br = new Bresenham2();
private boolean updated = false;
private float offsetx, offsety; private float offsetx, offsety;
private float zoom = 1f; private float zoom = 1f;
private boolean grid = false; private boolean grid = false;
@@ -84,8 +80,6 @@ public class MapView extends Element implements GestureListener{
mousex = x; mousex = x;
mousey = y; mousey = y;
updated = false;
Point2 p = project(x, y); Point2 p = project(x, y);
lastx = p.x; lastx = p.x;
lasty = p.y; lasty = p.y;
@@ -95,7 +89,6 @@ public class MapView extends Element implements GestureListener{
firstTouch.set(p); firstTouch.set(p);
if(tool.edit){ if(tool.edit){
updated = true;
ui.editor.resetSaved(); ui.editor.resetSaved();
} }
@@ -127,7 +120,6 @@ public class MapView extends Element implements GestureListener{
for(Point2 point : points){ for(Point2 point : points){
editor.draw(point.x, point.y, EditorTool.isPaint()); editor.draw(point.x, point.y, EditorTool.isPaint());
} }
updated = true;
} }
editor.flushOp(); editor.flushOp();
@@ -153,7 +145,6 @@ public class MapView extends Element implements GestureListener{
for(Point2 point : points){ for(Point2 point : points){
tool.touched(editor, point.x, point.y); tool.touched(editor, point.x, point.y);
} }
updated = true;
} }
if(tool == EditorTool.line && Core.input.keyDown(KeyCode.TAB)){ if(tool == EditorTool.line && Core.input.keyDown(KeyCode.TAB)){

View File

@@ -86,6 +86,7 @@ public class Damage{
tr.trns(angle, length); tr.trns(angle, length);
world.raycastEachWorld(x, y, x + tr.x, y + tr.y, (cx, cy) -> { world.raycastEachWorld(x, y, x + tr.x, y + tr.y, (cx, cy) -> {
Tile tile = world.tile(cx, cy); Tile tile = world.tile(cx, cy);
if(tile != null) tile = tile.target();
if(tile != null && tile.entity != null && tile.target().getTeamID() != team.ordinal() && tile.entity.collide(hitter)){ if(tile != null && tile.entity != null && tile.target().getTeamID() != team.ordinal() && tile.entity.collide(hitter)){
tile.entity.collision(hitter); tile.entity.collision(hitter);
hitter.getBulletType().hit(hitter, tile.worldx(), tile.worldy()); hitter.getBulletType().hit(hitter, tile.worldx(), tile.worldy());
@@ -113,7 +114,7 @@ public class Damage{
rect.width += expand * 2; rect.width += expand * 2;
rect.height += expand * 2; rect.height += expand * 2;
Consumer<io.anuke.mindustry.entities.type.Unit> cons = e -> { Consumer<Unit> cons = e -> {
e.hitbox(hitrect); e.hitbox(hitrect);
Rectangle other = hitrect; Rectangle other = hitrect;
other.y -= expand; other.y -= expand;
@@ -130,12 +131,12 @@ public class Damage{
} }
}; };
Units.getNearbyEnemies(team, rect, cons); Units.nearbyEnemies(team, rect, cons);
} }
/** Damages all entities and blocks in a radius that are enemies of the team. */ /** Damages all entities and blocks in a radius that are enemies of the team. */
public static void damageUnits(Team team, float x, float y, float size, float damage, Predicate<io.anuke.mindustry.entities.type.Unit> predicate, Consumer<io.anuke.mindustry.entities.type.Unit> acceptor){ public static void damageUnits(Team team, float x, float y, float size, float damage, Predicate<Unit> predicate, Consumer<Unit> acceptor){
Consumer<io.anuke.mindustry.entities.type.Unit> cons = entity -> { Consumer<Unit> cons = entity -> {
if(!predicate.test(entity)) return; if(!predicate.test(entity)) return;
entity.hitbox(hitrect); entity.hitbox(hitrect);
@@ -148,9 +149,9 @@ public class Damage{
rect.setSize(size * 2).setCenter(x, y); rect.setSize(size * 2).setCenter(x, y);
if(team != null){ if(team != null){
Units.getNearbyEnemies(team, rect, cons); Units.nearbyEnemies(team, rect, cons);
}else{ }else{
Units.getNearby(rect, cons); Units.nearby(rect, cons);
} }
} }
@@ -179,9 +180,9 @@ public class Damage{
rect.setSize(radius * 2).setCenter(x, y); rect.setSize(radius * 2).setCenter(x, y);
if(team != null){ if(team != null){
Units.getNearbyEnemies(team, rect, cons); Units.nearbyEnemies(team, rect, cons);
}else{ }else{
Units.getNearby(rect, cons); Units.nearby(rect, cons);
} }
if(!complete){ if(!complete){

View File

@@ -1,18 +1,23 @@
package io.anuke.mindustry.entities; package io.anuke.mindustry.entities;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array; import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.IntMap; import io.anuke.arc.collection.IntMap;
import io.anuke.arc.function.Consumer;
import io.anuke.arc.function.Predicate;
import io.anuke.arc.graphics.Camera;
import io.anuke.arc.math.geom.Rectangle;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.traits.DrawTrait;
import io.anuke.mindustry.entities.traits.Entity; import io.anuke.mindustry.entities.traits.Entity;
public class Entities{ public class Entities{
public static final int maxLeafObjects = 5; public static final int maxLeafObjects = 4;
private static final EntityGroup<Entity> defaultGroup;
private static final Array<EntityGroup<?>> groupArray = new Array<>(); private static final Array<EntityGroup<?>> groupArray = new Array<>();
private static final IntMap<EntityGroup<?>> groups = new IntMap<>(); private static final IntMap<EntityGroup<?>> groups = new IntMap<>();
private static final Rectangle viewport = new Rectangle();
static{ private static final boolean clip = true;
defaultGroup = addGroup(Entity.class); private static int count = 0;
}
public static void clear(){ public static void clear(){
for(EntityGroup group : groupArray){ for(EntityGroup group : groupArray){
@@ -20,20 +25,12 @@ public class Entities{
} }
} }
public static Iterable<Entity> all(){
return defaultGroup.all();
}
public static EntityGroup<?> getGroup(int id){ public static EntityGroup<?> getGroup(int id){
return groups.get(id); return groups.get(id);
} }
public static Iterable<EntityGroup<?>> getAllGroups(){ public static Array<EntityGroup<?>> getAllGroups(){
return groups.values(); return groupArray;
}
public static EntityGroup<Entity> defaultGroup(){
return defaultGroup;
} }
public static <T extends Entity> EntityGroup<T> addGroup(Class<T> type){ public static <T extends Entity> EntityGroup<T> addGroup(Class<T> type){
@@ -47,20 +44,46 @@ public class Entities{
return group; return group;
} }
public static void update(){
update(defaultGroup());
EntityQuery.collideGroups(defaultGroup(), defaultGroup());
}
public static void update(EntityGroup<?> group){ public static void update(EntityGroup<?> group){
group.updateEvents(); group.updateEvents();
if(group.useTree()){ if(group.useTree()){
EntityQuery.collisions().updatePhysics(group); Vars.collisions.updatePhysics(group);
} }
for(Entity e : group.all()){ for(Entity e : group.all()){
e.update(); e.update();
} }
} }
public static int countInBounds(EntityGroup<?> group){
count = 0;
draw(group, e -> true, e -> count++);
return count;
}
public static void draw(EntityGroup<?> group){
draw(group, e -> true);
}
public static <T extends DrawTrait> void draw(EntityGroup<?> group, Predicate<T> toDraw){
draw(group, toDraw, DrawTrait::draw);
}
@SuppressWarnings("unchecked")
public static <T extends DrawTrait> void draw(EntityGroup<?> group, Predicate<T> toDraw, Consumer<T> cons){
if(clip){
Camera cam = Core.camera;
viewport.set(cam.position.x - cam.width / 2, cam.position.y - cam.height / 2, cam.width, cam.height);
}
for(Entity e : group.all()){
if(!(e instanceof DrawTrait) || !toDraw.test((T)e) || !e.isAdded()) continue;
DrawTrait draw = (DrawTrait)e;
if(!clip || viewport.overlaps(draw.getX() - draw.drawSize()/2f, draw.getY() - draw.drawSize()/2f, draw.drawSize(), draw.drawSize())){
cons.accept((T)e);
}
}
}
} }

View File

@@ -43,7 +43,7 @@ public class EntityCollisions{
while(Math.abs(deltax) > 0 || !movedx){ while(Math.abs(deltax) > 0 || !movedx){
movedx = true; movedx = true;
moveInternal(entity, Math.min(Math.abs(deltax), seg) * Mathf.sign(deltax), 0, true); moveDelta(entity, Math.min(Math.abs(deltax), seg) * Mathf.sign(deltax), 0, true);
if(Math.abs(deltax) >= seg){ if(Math.abs(deltax) >= seg){
deltax -= seg * Mathf.sign(deltax); deltax -= seg * Mathf.sign(deltax);
@@ -56,7 +56,7 @@ public class EntityCollisions{
while(Math.abs(deltay) > 0 || !movedy){ while(Math.abs(deltay) > 0 || !movedy){
movedy = true; movedy = true;
moveInternal(entity, 0, Math.min(Math.abs(deltay), seg) * Mathf.sign(deltay), false); moveDelta(entity, 0, Math.min(Math.abs(deltay), seg) * Mathf.sign(deltay), false);
if(Math.abs(deltay) >= seg){ if(Math.abs(deltay) >= seg){
deltay -= seg * Mathf.sign(deltay); deltay -= seg * Mathf.sign(deltay);
@@ -66,7 +66,7 @@ public class EntityCollisions{
} }
} }
public void moveInternal(SolidTrait entity, float deltax, float deltay, boolean x){ public void moveDelta(SolidTrait entity, float deltax, float deltay, boolean x){
if(collider == null) if(collider == null)
throw new IllegalArgumentException("No tile collider specified! Call setCollider() first."); throw new IllegalArgumentException("No tile collider specified! Call setCollider() first.");
@@ -124,6 +124,7 @@ public class EntityCollisions{
return false; return false;
} }
@SuppressWarnings("unchecked")
public <T extends Entity> void updatePhysics(EntityGroup<T> group){ public <T extends Entity> void updatePhysics(EntityGroup<T> group){
collided.clear(); collided.clear();
@@ -218,6 +219,7 @@ public class EntityCollisions{
} }
} }
@SuppressWarnings("unchecked")
public void collideGroups(EntityGroup<?> groupa, EntityGroup<?> groupb){ public void collideGroups(EntityGroup<?> groupa, EntityGroup<?> groupb){
collided.clear(); collided.clear();

View File

@@ -1,54 +0,0 @@
package io.anuke.mindustry.entities;
import io.anuke.arc.Core;
import io.anuke.arc.function.Consumer;
import io.anuke.arc.function.Predicate;
import io.anuke.arc.graphics.Camera;
import io.anuke.arc.math.geom.Rectangle;
import io.anuke.mindustry.entities.traits.DrawTrait;
import io.anuke.mindustry.entities.traits.Entity;
public class EntityDraw{
private static final Rectangle viewport = new Rectangle();
private static final Rectangle rect = new Rectangle();
private static boolean clip = true;
private static int count = 0;
public static void setClip(boolean clip){
EntityDraw.clip = clip;
}
public static int countInBounds(EntityGroup<?> group){
count = 0;
drawWith(group, e -> true, e -> count++);
return count;
}
public static void draw(){
draw(Entities.defaultGroup());
}
public static void draw(EntityGroup<?> group){
draw(group, e -> true);
}
public static <T extends DrawTrait> void draw(EntityGroup<?> group, Predicate<T> toDraw){
drawWith(group, toDraw, DrawTrait::draw);
}
@SuppressWarnings("unchecked")
public static <T extends DrawTrait> void drawWith(EntityGroup<?> group, Predicate<T> toDraw, Consumer<T> cons){
if(clip){
Camera cam = Core.camera;
viewport.set(cam.position.x - cam.width / 2, cam.position.y - cam.height / 2, cam.width, cam.height);
}
for(Entity e : group.all()){
if(!(e instanceof DrawTrait) || !toDraw.test((T)e) || !e.isAdded()) continue;
if(!clip || rect.setSize(((DrawTrait)e).drawSize()).setCenter(e.getX(), e.getY()).overlaps(viewport)){
cons.accept((T)e);
}
}
}
}

View File

@@ -25,6 +25,10 @@ public class EntityGroup<T extends Entity>{
this.useTree = useTree; this.useTree = useTree;
this.id = lastid++; this.id = lastid++;
this.type = type; this.type = type;
if(useTree){
tree = new QuadTree<>(Entities.maxLeafObjects, new Rectangle(0, 0, 0, 0));
}
} }
public boolean useTree(){ public boolean useTree(){
@@ -105,12 +109,23 @@ public class EntityGroup<T extends Entity>{
} }
} }
@SuppressWarnings("unchecked")
public void intersect(float x, float y, float width, float height, Consumer<? super T> out){
//don't waste time for empty groups
if(isEmpty()) return;
tree().getIntersect(out, x, y, width, height);
}
public QuadTree tree(){ public QuadTree tree(){
if(!useTree) throw new RuntimeException("This group does not support quadtrees! Enable quadtrees when creating it.");
return tree; return tree;
} }
public void setTree(float x, float y, float w, float h){ /** Resizes the internal quadtree, if it is enabled.*/
tree = new QuadTree<>(Entities.maxLeafObjects, new Rectangle(x, y, w, h)); public void resize(float x, float y, float w, float h){
if(useTree){
tree = new QuadTree<>(Entities.maxLeafObjects, new Rectangle(x, y, w, h));
}
} }
public boolean isEmpty(){ public boolean isEmpty(){
@@ -184,11 +199,4 @@ public class EntityGroup<T extends Entity>{
public Array<T> all(){ public Array<T> all(){
return entityArray; return entityArray;
} }
public void forEach(Consumer<T> cons){
for(T t : entityArray){
cons.accept(t);
}
}
} }

View File

@@ -1,95 +0,0 @@
package io.anuke.mindustry.entities;
import io.anuke.arc.collection.Array;
import io.anuke.arc.function.Consumer;
import io.anuke.arc.function.Predicate;
import io.anuke.arc.math.Mathf;
import io.anuke.arc.math.geom.Rectangle;
import io.anuke.mindustry.entities.traits.Entity;
import io.anuke.mindustry.entities.traits.SolidTrait;
import static io.anuke.mindustry.entities.Entities.defaultGroup;
public class EntityQuery{
private static final EntityCollisions collisions = new EntityCollisions();
private static final Array<SolidTrait> array = new Array<>();
private static final Rectangle r1 = new Rectangle();
public static EntityCollisions collisions(){
return collisions;
}
public static void init(float x, float y, float w, float h){
for(EntityGroup group : Entities.getAllGroups()){
if(group.useTree()){
group.setTree(x, y, w, h);
}
}
}
public static void init(){
init(0, 0, 0, 0);
}
public static void resizeTree(float x, float y, float w, float h){
init(x, y, w, h);
}
public static void getNearby(EntityGroup<?> group, Rectangle rect, Consumer<SolidTrait> out){
if(!group.useTree())
throw new RuntimeException("This group does not support quadtrees! Enable quadtrees when creating it.");
group.tree().getIntersect(out, rect);
}
public static Array<SolidTrait> getNearby(EntityGroup<?> group, Rectangle rect){
array.clear();
if(!group.useTree())
throw new RuntimeException("This group does not support quadtrees! Enable quadtrees when creating it.");
group.tree().getIntersect(array, rect);
return array;
}
public static void getNearby(float x, float y, float size, Consumer<SolidTrait> out){
getNearby(defaultGroup(), r1.setSize(size).setCenter(x, y), out);
}
public static void getNearby(EntityGroup<?> group, float x, float y, float size, Consumer<SolidTrait> out){
getNearby(group, r1.setSize(size).setCenter(x, y), out);
}
public static Array<SolidTrait> getNearby(float x, float y, float size){
return getNearby(defaultGroup(), r1.setSize(size).setCenter(x, y));
}
public static Array<SolidTrait> getNearby(EntityGroup<?> group, float x, float y, float size){
return getNearby(group, r1.setSize(size).setCenter(x, y));
}
public static <T extends Entity> T getClosest(EntityGroup<T> group, float x, float y, float range, Predicate<T> pred){
T closest = null;
float cdist = 0f;
Array<SolidTrait> entities = getNearby(group, x, y, range * 2f);
for(int i = 0; i < entities.size; i++){
T e = (T)entities.get(i);
if(!pred.test(e))
continue;
float dist = Mathf.dst(e.getX(), e.getY(), x, y);
if(dist < range)
if(closest == null || dist < cdist){
closest = e;
cdist = dist;
}
}
return closest;
}
public static void collideGroups(EntityGroup<?> groupa, EntityGroup<?> groupb){
collisions().collideGroups(groupa, groupb);
}
}

View File

@@ -9,16 +9,12 @@ import io.anuke.arc.math.geom.Rectangle;
import io.anuke.mindustry.entities.traits.TargetTrait; import io.anuke.mindustry.entities.traits.TargetTrait;
import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.Team; import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
/** /** Utility class for unit and team interactions.*/
* Utility class for unit and team interactions.
*/
public class Units{ public class Units{
private static Rectangle rect = new Rectangle();
private static Rectangle hitrect = new Rectangle(); private static Rectangle hitrect = new Rectangle();
private static Unit result; private static Unit result;
private static float cdist; private static float cdist;
@@ -34,7 +30,7 @@ public class Units{
* @return whether the target is invalid * @return whether the target is invalid
*/ */
public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y, float range){ public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y, float range){
return target == null || (range != Float.MAX_VALUE && target.dst(x, y) > range) || target.getTeam() == team || !target.isValid(); return target == null || (range != Float.MAX_VALUE && !target.withinDst(x, y, range)) || target.getTeam() == team || !target.isValid();
} }
/** See {@link #invalidateTarget(TargetTrait, Team, float, float, float)} */ /** See {@link #invalidateTarget(TargetTrait, Team, float, float, float)} */
@@ -49,23 +45,19 @@ public class Units{
/** Returns whether there are any entities on this tile. */ /** Returns whether there are any entities on this tile. */
public static boolean anyEntities(Tile tile){ public static boolean anyEntities(Tile tile){
Block type = tile.block(); float size = tile.block().size * tilesize;
rect.setSize(type.size * tilesize, type.size * tilesize); return anyEntities(tile.drawx() - size/2f, tile.drawy() - size/2f, size, size);
rect.setCenter(tile.drawx(), tile.drawy());
return anyEntities(rect);
} }
/** Can be called from any thread. */ public static boolean anyEntities(float x, float y, float width, float height){
public static boolean anyEntities(Rectangle rect){
boolResult = false; boolResult = false;
Units.getNearby(rect, unit -> { nearby(x, y, width, height, unit -> {
if(boolResult) return; if(boolResult) return;
if(!unit.isFlying()){ if(!unit.isFlying()){
unit.hitbox(hitrect); unit.hitbox(hitrect);
if(hitrect.overlaps(rect)){ if(hitrect.overlaps(x, y, width, height)){
boolResult = true; boolResult = true;
} }
} }
@@ -74,28 +66,6 @@ public class Units{
return boolResult; return boolResult;
} }
/** Returns whether there are any entities on this tile, with the hitbox expanded. */
public static boolean anyEntities(Tile tile, float expansion, Predicate<Unit> pred){
Block type = tile.block();
rect.setSize(type.size * tilesize + expansion, type.size * tilesize + expansion);
rect.setCenter(tile.drawx(), tile.drawy());
boolean[] value = new boolean[1];
Units.getNearby(rect, unit -> {
if(value[0] || !pred.test(unit) || unit.isDead()) return;
if(!unit.isFlying()){
unit.hitbox(hitrect);
if(hitrect.overlaps(rect)){
value[0] = true;
}
}
});
return value[0];
}
/** Returns the neareset damaged tile. */ /** Returns the neareset damaged tile. */
public static TileEntity findDamagedTile(Team team, float x, float y){ public static TileEntity findDamagedTile(Team team, float x, float y){
Tile tile = Geometry.findClosest(x, y, world.indexer.getDamaged(team)); Tile tile = Geometry.findClosest(x, y, world.indexer.getDamaged(team));
@@ -120,36 +90,19 @@ public class Units{
return null; return null;
} }
/** Iterates over all units on all teams, including players. */ /** Returns the closest target enemy. First, units are checked, then tile entities. */
public static void allUnits(Consumer<Unit> cons){ public static TargetTrait closestTarget(Team team, float x, float y, float range){
//check all unit groups first return closestTarget(team, x, y, range, Unit::isValid);
for(EntityGroup<BaseUnit> group : unitGroups){
if(!group.isEmpty()){
for(BaseUnit unit : group.all()){
cons.accept(unit);
}
}
}
//then check all player groups
for(Player player : playerGroup.all()){
cons.accept(player);
}
} }
/** Returns the closest target enemy. First, units are checked, then tile entities. */ /** Returns the closest target enemy. First, units are checked, then tile entities. */
public static TargetTrait getClosestTarget(Team team, float x, float y, float range){ public static TargetTrait closestTarget(Team team, float x, float y, float range, Predicate<Unit> unitPred){
return getClosestTarget(team, x, y, range, Unit::isValid); return closestTarget(team, x, y, range, unitPred, t -> true);
} }
/** Returns the closest target enemy. First, units are checked, then tile entities. */ /** Returns the closest target enemy. First, units are checked, then tile entities. */
public static TargetTrait getClosestTarget(Team team, float x, float y, float range, Predicate<Unit> unitPred){ public static TargetTrait closestTarget(Team team, float x, float y, float range, Predicate<Unit> unitPred, Predicate<Tile> tilePred){
return getClosestTarget(team, x, y, range, unitPred, t -> true); Unit unit = closestEnemy(team, x, y, range, unitPred);
}
/** Returns the closest target enemy. First, units are checked, then tile entities. */
public static TargetTrait getClosestTarget(Team team, float x, float y, float range, Predicate<Unit> unitPred, Predicate<Tile> tilePred){
Unit unit = getClosestEnemy(team, x, y, range, unitPred);
if(unit != null){ if(unit != null){
return unit; return unit;
}else{ }else{
@@ -158,24 +111,19 @@ public class Units{
} }
/** Returns the closest enemy of this team. Filter by predicate. */ /** Returns the closest enemy of this team. Filter by predicate. */
public static Unit getClosestEnemy(Team team, float x, float y, float range, Predicate<Unit> predicate){ public static Unit closestEnemy(Team team, float x, float y, float range, Predicate<Unit> predicate){
if(team == Team.none) return null; if(team == Team.none) return null;
result = null; result = null;
cdist = 0f; cdist = 0f;
rect.setSize(range * 2f).setCenter(x, y); nearbyEnemies(team, x - range, y - range, range*2f, range*2f, e -> {
if(e.isDead() || !predicate.test(e)) return;
getNearbyEnemies(team, rect, e -> { float dst2 = Mathf.dst2(e.x, e.y, x, y);
if(e.isDead() || !predicate.test(e)) if(dst2 < range*range && (result == null || dst2 < cdist)){
return; result = e;
cdist = dst2;
float dist = Mathf.dst(e.x, e.y, x, y);
if(dist < range){
if(result == null || dist < cdist){
result = e;
cdist = dist;
}
} }
}); });
@@ -183,22 +131,17 @@ public class Units{
} }
/** Returns the closest ally of this team. Filter by predicate. */ /** Returns the closest ally of this team. Filter by predicate. */
public static Unit getClosest(Team team, float x, float y, float range, Predicate<Unit> predicate){ public static Unit closest(Team team, float x, float y, float range, Predicate<Unit> predicate){
result = null; result = null;
cdist = 0f; cdist = 0f;
rect.setSize(range * 2f).setCenter(x, y); nearby(team, x, y, range, e -> {
if(!predicate.test(e)) return;
getNearby(team, rect, e -> { float dist = Mathf.dst2(e.x, e.y, x, y);
if(!predicate.test(e)) if(result == null || dist < cdist){
return; result = e;
cdist = dist;
float dist = Mathf.dst(e.x, e.y, x, y);
if(dist < range){
if(result == null || dist < cdist){
result = e;
cdist = dist;
}
} }
}); });
@@ -206,87 +149,71 @@ public class Units{
} }
/** Iterates over all units in a rectangle. */ /** Iterates over all units in a rectangle. */
public static void getNearby(Team team, Rectangle rect, Consumer<Unit> cons){ public static void nearby(Team team, float x, float y, float width, float height, Consumer<Unit> cons){
unitGroups[team.ordinal()].intersect(x, y, width, height, cons);
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()]; playerGroup.intersect(x, y, width, height, player -> {
if(!group.isEmpty()){ if(player.getTeam() == team){
EntityQuery.getNearby(group, rect, entity -> cons.accept((Unit)entity)); cons.accept(player);
} }
//now check all players
EntityQuery.getNearby(playerGroup, rect, player -> {
if(((Unit)player).getTeam() == team) cons.accept((Unit)player);
}); });
} }
/** Iterates over all units in a circle around this position. */ /** Iterates over all units in a circle around this position. */
public static void getNearby(Team team, float x, float y, float radius, Consumer<Unit> cons){ public static void nearby(Team team, float x, float y, float radius, Consumer<Unit> cons){
rect.setSize(radius * 2).setCenter(x, y); unitGroups[team.ordinal()].intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> {
if(unit.withinDst(x, y, radius)){
cons.accept(unit);
}
});
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()]; playerGroup.intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> {
if(!group.isEmpty()){ if(unit.getTeam() == team && unit.withinDst(x, y, radius)){
EntityQuery.getNearby(group, rect, entity -> { cons.accept(unit);
if(entity.dst(x, y) <= radius){
cons.accept((Unit)entity);
}
});
}
//now check all players
EntityQuery.getNearby(playerGroup, rect, player -> {
if(((Unit)player).getTeam() == team && player.dst(x, y) <= radius){
cons.accept((Unit)player);
} }
}); });
} }
/** Iterates over all units in a rectangle. */ /** Iterates over all units in a rectangle. */
public static void getNearby(Rectangle rect, Consumer<Unit> cons){ public static void nearby(float x, float y, float width, float height, Consumer<Unit> cons){
for(Team team : Team.all){ for(Team team : Team.all){
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()]; unitGroups[team.ordinal()].intersect(x, y, width, height, cons);
if(!group.isEmpty()){
EntityQuery.getNearby(group, rect, entity -> cons.accept((Unit)entity));
}
} }
//now check all enemy players playerGroup.intersect(x, y, width, height, cons);
EntityQuery.getNearby(playerGroup, rect, player -> cons.accept((Unit)player)); }
/** Iterates over all units in a rectangle. */
public static void nearby(Rectangle rect, Consumer<Unit> cons){
nearby(rect.x, rect.y, rect.width, rect.height, cons);
} }
/** Iterates over all units that are enemies of this team. */ /** Iterates over all units that are enemies of this team. */
public static void getNearbyEnemies(Team team, Rectangle rect, Consumer<Unit> cons){ public static void nearbyEnemies(Team team, float x, float y, float width, float height, Consumer<Unit> cons){
EnumSet<Team> targets = state.teams.enemiesOf(team); EnumSet<Team> targets = state.teams.enemiesOf(team);
for(Team other : targets){ for(Team other : targets){
EntityGroup<BaseUnit> group = unitGroups[other.ordinal()]; unitGroups[other.ordinal()].intersect(x, y, width, height, cons);
if(!group.isEmpty()){
EntityQuery.getNearby(group, rect, entity -> cons.accept((Unit)entity));
}
} }
//now check all enemy players playerGroup.intersect(x, y, width, height, player -> {
EntityQuery.getNearby(playerGroup, rect, player -> { if(targets.contains(player.getTeam())){
if(targets.contains(((Player)player).getTeam())){ cons.accept(player);
cons.accept((Unit)player);
} }
}); });
} }
/** Iterates over all units that are enemies of this team. */
public static void nearbyEnemies(Team team, Rectangle rect, Consumer<Unit> cons){
nearbyEnemies(team, rect.x, rect.y, rect.width, rect.height, cons);
}
/** Iterates over all units. */ /** Iterates over all units. */
public static void getAllUnits(Consumer<Unit> cons){ public static void all(Consumer<Unit> cons){
for(Team team : Team.all){ for(Team team : Team.all){
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()]; unitGroups[team.ordinal()].all().each(cons);
for(Unit unit : group.all()){
cons.accept(unit);
}
} }
//now check all enemy players playerGroup.all().each(cons);
for(Unit unit : playerGroup.all()){
cons.accept(unit);
}
} }
} }

View File

@@ -148,7 +148,7 @@ public abstract class BulletType extends Content{
public void update(Bullet b){ public void update(Bullet b){
if(homingPower > 0.0001f){ if(homingPower > 0.0001f){
TargetTrait target = Units.getClosestTarget(b.getTeam(), b.x, b.y, homingRange); TargetTrait target = Units.closestTarget(b.getTeam(), b.x, b.y, homingRange);
if(target != null){ if(target != null){
b.velocity().setAngle(Mathf.slerpDelta(b.velocity().angle(), b.angleTo(target), 0.08f)); b.velocity().setAngle(Mathf.slerpDelta(b.velocity().angle(), b.angleTo(target), 0.08f));
} }

View File

@@ -24,7 +24,7 @@ public abstract class FlakBulletType extends BasicBulletType{
if(b.getData() instanceof Integer) return; if(b.getData() instanceof Integer) return;
if(b.timer.get(2, 6)){ if(b.timer.get(2, 6)){
Units.getNearbyEnemies(b.getTeam(), rect.setSize(explodeRange * 2f).setCenter(b.x, b.y), unit -> { Units.nearbyEnemies(b.getTeam(), rect.setSize(explodeRange * 2f).setCenter(b.x, b.y), unit -> {
if(b.getData() instanceof Float) return; if(b.getData() instanceof Float) return;
if(unit.dst(b) < explodeRange){ if(unit.dst(b) < explodeRange){

View File

@@ -88,7 +88,6 @@ public class MassDriverBolt extends BulletType{
if(!(b.getData() instanceof DriverBulletData)) return; if(!(b.getData() instanceof DriverBulletData)) return;
DriverBulletData data = (DriverBulletData)b.getData(); DriverBulletData data = (DriverBulletData)b.getData();
data.to.isRecieving = false;
for(int i = 0; i < data.items.length; i++){ for(int i = 0; i < data.items.length; i++){
int amountDropped = Mathf.random(0, data.items[i]); int amountDropped = Mathf.random(0, data.items[i]);

View File

@@ -70,7 +70,7 @@ public class Lightning extends TimedEntity implements DrawTrait, SyncTrait, Time
rect.setSize(hitRange).setCenter(x, y); rect.setSize(hitRange).setCenter(x, y);
entities.clear(); entities.clear();
if(hit.size < maxChain){ if(hit.size < maxChain){
Units.getNearbyEnemies(team, rect, u -> { Units.nearbyEnemies(team, rect, u -> {
if(!hit.contains(u.getID())){ if(!hit.contains(u.getID())){
entities.add(u); entities.add(u);
} }

View File

@@ -188,7 +188,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
//effects-only code //effects-only code
if(amount >= maxLiquid / 2f && updateTime <= 0f){ if(amount >= maxLiquid / 2f && updateTime <= 0f){
Units.getNearby(rect.setSize(Mathf.clamp(amount / (maxLiquid / 1.5f)) * 10f).setCenter(x, y), unit -> { Units.nearby(rect.setSize(Mathf.clamp(amount / (maxLiquid / 1.5f)) * 10f).setCenter(x, y), unit -> {
if(unit.isFlying()) return; if(unit.isFlying()) return;
unit.hitbox(rect2); unit.hitbox(rect2);

View File

@@ -5,9 +5,12 @@ import io.anuke.arc.util.pooling.Pool.Poolable;
import io.anuke.arc.util.pooling.Pools; import io.anuke.arc.util.pooling.Pools;
import io.anuke.mindustry.entities.Effects; import io.anuke.mindustry.entities.Effects;
import io.anuke.mindustry.entities.Effects.Effect; import io.anuke.mindustry.entities.Effects.Effect;
import io.anuke.mindustry.entities.EntityGroup;
import io.anuke.mindustry.entities.traits.DrawTrait; import io.anuke.mindustry.entities.traits.DrawTrait;
import io.anuke.mindustry.entities.traits.Entity; import io.anuke.mindustry.entities.traits.Entity;
import static io.anuke.mindustry.Vars.effectGroup;
public class EffectEntity extends TimedEntity implements Poolable, DrawTrait{ public class EffectEntity extends TimedEntity implements Poolable, DrawTrait{
public Effect effect; public Effect effect;
public Color color = new Color(Color.WHITE); public Color color = new Color(Color.WHITE);
@@ -27,6 +30,12 @@ public class EffectEntity extends TimedEntity implements Poolable, DrawTrait{
this.poffsety = y - parent.getY(); this.poffsety = y - parent.getY();
} }
@Override
public EntityGroup targetGroup(){
//this should never actually be called
return effectGroup;
}
@Override @Override
public float lifetime(){ public float lifetime(){
return effect.lifetime; return effect.lifetime;

View File

@@ -1,6 +1,5 @@
package io.anuke.mindustry.entities.traits; package io.anuke.mindustry.entities.traits;
import io.anuke.mindustry.entities.Entities;
import io.anuke.mindustry.entities.EntityGroup; import io.anuke.mindustry.entities.EntityGroup;
public interface Entity extends MoveTrait{ public interface Entity extends MoveTrait{
@@ -18,13 +17,13 @@ public interface Entity extends MoveTrait{
default void added(){ default void added(){
} }
default EntityGroup targetGroup(){ EntityGroup targetGroup();
return Entities.defaultGroup();
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
default void add(){ default void add(){
targetGroup().add(this); if(targetGroup() != null){
targetGroup().add(this);
}
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@@ -3,7 +3,7 @@ package io.anuke.mindustry.entities.traits;
import io.anuke.arc.math.geom.*; import io.anuke.arc.math.geom.*;
import io.anuke.arc.math.geom.QuadTree.QuadTreeObject; import io.anuke.arc.math.geom.QuadTree.QuadTreeObject;
import io.anuke.mindustry.entities.EntityQuery; import io.anuke.mindustry.Vars;
public interface SolidTrait extends QuadTreeObject, MoveTrait, VelocityTrait, Entity, Position{ public interface SolidTrait extends QuadTreeObject, MoveTrait, VelocityTrait, Entity, Position{
@@ -25,10 +25,6 @@ public interface SolidTrait extends QuadTreeObject, MoveTrait, VelocityTrait, En
return getY() - lastPosition().y; return getY() - lastPosition().y;
} }
default boolean movable(){
return false;
}
default boolean collides(SolidTrait other){ default boolean collides(SolidTrait other){
return true; return true;
} }
@@ -37,6 +33,6 @@ public interface SolidTrait extends QuadTreeObject, MoveTrait, VelocityTrait, En
} }
default void move(float x, float y){ default void move(float x, float y){
EntityQuery.collisions().move(this, x, y); Vars.collisions.move(this, x, y);
} }
} }

View File

@@ -136,7 +136,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
} }
public void targetClosest(){ public void targetClosest(){
TargetTrait newTarget = Units.getClosestTarget(team, x, y, Math.max(getWeapon().bullet.range(), type.range), u -> type.targetAir || !u.isFlying()); TargetTrait newTarget = Units.closestTarget(team, x, y, Math.max(getWeapon().bullet.range(), type.range), u -> type.targetAir || !u.isFlying());
if(newTarget != null){ if(newTarget != null){
target = newTarget; target = newTarget;
} }
@@ -260,7 +260,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
kill(); kill();
} }
avoidOthers(1.25f); avoidOthers();
if(spawner != noSpawner && (world.tile(spawner) == null || world.tile(spawner).entity == null)){ if(spawner != noSpawner && (world.tile(spawner) == null || world.tile(spawner).entity == null)){
kill(); kill();

Some files were not shown because too many files have changed in this diff Show More