diff --git a/.gitignore b/.gitignore index 163c036ea1..c6c812b18e 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,10 @@ logs/ /tests/build/ /server/build/ changelog +saves/ +core/assets/saves/ +/core/assets/saves/ +steam_appid.txt /test_files/ /annotations/build/ /android/assets/mindustry-maps/ diff --git a/.travis.yml b/.travis.yml index 58473d0aaf..9df31f3301 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,14 +9,14 @@ android: script: - git clone --depth=1 --branch=master https://github.com/Anuken/MindustryBuilds ../MindustryBuilds - cd ../MindustryBuilds -- echo ${TRAVIS_BUILD_NUMBER} > version.txt -- git add . -- git commit -m "Updating to build ${TRAVIS_BUILD_NUMBER}" +- echo ${TRAVIS_TAG} +- if [ -n "$TRAVIS_TAG" ]; then echo versionName=4-fdroid-${TRAVIS_TAG:1}$'\n'versionCode=${TRAVIS_TAG:1} > version_fdroid.txt; git add .; git commit -m "Updating to build ${TRAVIS_TAG}"; fi - git tag ${TRAVIS_BUILD_NUMBER} - git config --global user.name "Build Uploader" -- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then git push https://Anuken:${GH_PUSH_TOKEN}@github.com/Anuken/MindustryBuilds ${TRAVIS_BUILD_NUMBER}; fi +- if [ "$TRAVIS_PULL_REQUEST" = "false" ]; then git push https://Anuken:${GH_PUSH_TOKEN}@github.com/Anuken/MindustryBuilds ${TRAVIS_BUILD_NUMBER}; git push https://Anuken:${GH_PUSH_TOKEN}@github.com/Anuken/MindustryBuilds; fi - cd ../Mindustry - git clone --depth=1 --branch=master https://github.com/Anuken/Arc ../Arc +- if [ -n "$TRAVIS_TAG" ]; then cd ../Arc; git tag ${TRAVIS_TAG}; git push https://Anuken:${GH_PUSH_TOKEN}@github.com/Anuken/Arc ${TRAVIS_TAG}; cd ../Mindustry; fi - "./gradlew test" - "./gradlew desktop:dist -Pbuildversion=${TRAVIS_TAG:1}" - "./gradlew server:dist -Pbuildversion=${TRAVIS_TAG:1}" diff --git a/README.md b/README.md index a2d2dda8fc..279de729a6 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,13 @@ _Building:_ `./gradlew desktop:dist` Server builds are bundled with each released build (in Releases). If you'd rather compile on your own, replace 'desktop' with 'server', e.g. `gradlew server:dist`. +#### Android + +1. Install the Android SDK [here.](https://developer.android.com/studio#downloads) Make sure you're downloading the "Command line tools only", as Android Studio is not required. +2. Create a file named `local.properties` inside the Mindustry directory, with its contents looking like this: `sdk.dir=`. For example, if you're on Windows and installed the tools to C:\\tools, your local.properties would contain `sdk.dir=C:\\tools` (*note the double backslashes are required instead of single ones!*). +3. Run `gradlew android:assembleDebug` (or `./gradlew` if on linux/mac). This will create an unsigned APK in `android/build/outputs/apk`. +4. (Optional) To debug the application on a connected phone, do `gradlew android:installDebug android:run`. It is **highly recommended** to use IntelliJ for this instead, however. + ##### Troubleshooting If the terminal returns `Permission denied` or `Command not found` on Mac/Linux, run `chmod +x ./gradlew` before running `./gradlew`. *This is a one-time procedure.* diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 6e42e10a0c..a4202d4364 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -32,32 +32,9 @@ - - - - - - - - - + - - - - - - - - - - - - - diff --git a/android/build.gradle b/android/build.gradle index 75e513de2f..0f61c32912 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -26,7 +26,6 @@ repositories{ dependencies{ implementation project(":core") - implementation project(":net") implementation arcModule("backends:backend-android") natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi" diff --git a/android/src/io/anuke/mindustry/AndroidLauncher.java b/android/src/io/anuke/mindustry/AndroidLauncher.java index f8f7552ca1..97443f0d3b 100644 --- a/android/src/io/anuke/mindustry/AndroidLauncher.java +++ b/android/src/io/anuke/mindustry/AndroidLauncher.java @@ -1,9 +1,10 @@ package io.anuke.mindustry; -import android.*; +import android.app.*; import android.content.*; import android.content.pm.*; import android.net.*; +import android.os.Build.*; import android.os.*; import android.provider.Settings.*; import android.telephony.*; @@ -16,13 +17,10 @@ import io.anuke.arc.util.*; import io.anuke.arc.util.serialization.*; import io.anuke.mindustry.game.Saves.*; import io.anuke.mindustry.io.*; -import io.anuke.mindustry.net.Net; -import io.anuke.mindustry.net.*; import io.anuke.mindustry.ui.dialogs.*; import java.io.*; import java.lang.System; -import java.util.*; import static io.anuke.mindustry.Vars.*; @@ -35,16 +33,10 @@ public class AndroidLauncher extends AndroidApplication{ @Override protected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); - AndroidApplicationConfiguration config = new AndroidApplicationConfiguration(); - config.useImmersiveMode = true; - config.depth = 0; if(doubleScaleTablets && isTablet(this.getContext())){ - UnitScl.dp.addition = 0.5f; + Scl.setAddition(0.5f); } - config.hideStatusBar = true; - Net.setClientProvider(new ArcNetClient()); - Net.setServerProvider(new ArcNetServer()); initialize(new ClientLauncher(){ @Override @@ -70,44 +62,43 @@ public class AndroidLauncher extends AndroidApplication{ } } - @Override - public void requestExternalPerms(Runnable callback){ - if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && - checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)){ - callback.run(); - }else{ - permCallback = callback; - ArrayList perms = new ArrayList<>(); - if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ - perms.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); - } - if(checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ - perms.add(Manifest.permission.READ_EXTERNAL_STORAGE); - } - requestPermissions(perms.toArray(new String[0]), PERMISSION_REQUEST_CODE); - } - } - @Override public void shareFile(FileHandle file){ } @Override - public void showFileChooser(String text, String content, Consumer cons, boolean open, Predicate filetype){ - chooser = new FileChooser(text, file -> filetype.test(file.extension().toLowerCase()), open, cons); - if(Build.VERSION.SDK_INT < Build.VERSION_CODES.M || (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && - checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)){ - chooser.show(); - chooser = null; + public void showFileChooser(boolean open, String extension, Consumer cons){ + if(VERSION.SDK_INT >= 19){ + Intent intent = new Intent(open ? Intent.ACTION_OPEN_DOCUMENT : Intent.ACTION_CREATE_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("*/*"); + addResultListener(i -> startActivityForResult(intent, i), (code, in) -> { + if(code == Activity.RESULT_OK && in != null && in.getData() != null){ + Uri uri = in.getData(); + + Core.app.post(() -> Core.app.post(() -> cons.accept(new FileHandle(uri.getPath()){ + @Override + public InputStream read(){ + try{ + return getContentResolver().openInputStream(uri); + }catch(IOException e){ + throw new ArcRuntimeException(e); + } + } + + @Override + public OutputStream write(boolean append){ + try{ + return getContentResolver().openOutputStream(uri); + }catch(IOException e){ + throw new ArcRuntimeException(e); + } + } + }))); + } + }); }else{ - ArrayList perms = new ArrayList<>(); - if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ - perms.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); - } - if(checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){ - perms.add(Manifest.permission.READ_EXTERNAL_STORAGE); - } - requestPermissions(perms.toArray(new String[0]), PERMISSION_REQUEST_CODE); + super.showFileChooser(open, extension, cons); } } @@ -125,7 +116,11 @@ public class AndroidLauncher extends AndroidApplication{ public boolean canDonate(){ return true; } - }, config); + }, new AndroidApplicationConfiguration(){{ + useImmersiveMode = true; + depth = 0; + hideStatusBar = true; + }}); checkFiles(getIntent()); } @@ -173,10 +168,10 @@ public class AndroidLauncher extends AndroidApplication{ SaveSlot slot = control.saves.importSave(file); ui.load.runLoadSave(slot); }catch(IOException e){ - ui.showError(Core.bundle.format("save.import.fail", Strings.parseException(e, true))); + ui.showException("$save.import.fail", e); } }else{ - ui.showError("$save.import.invalid"); + ui.showErrorMessage("$save.import.invalid"); } }else if(map){ //open map FileHandle file = Core.files.local("temp-map." + mapExtension); diff --git a/annotations/src/main/java/io/anuke/annotations/Annotations.java b/annotations/src/main/java/io/anuke/annotations/Annotations.java index d964f85401..e7afef4f9a 100644 --- a/annotations/src/main/java/io/anuke/annotations/Annotations.java +++ b/annotations/src/main/java/io/anuke/annotations/Annotations.java @@ -4,6 +4,11 @@ import java.lang.annotation.*; public class Annotations{ + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.SOURCE) + public @interface StyleDefaults { + } + /** Indicates that a method should always call its super version. */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) diff --git a/annotations/src/main/java/io/anuke/annotations/AssetsAnnotationProcessor.java b/annotations/src/main/java/io/anuke/annotations/AssetsAnnotationProcessor.java index 53642c7597..9dc159405d 100644 --- a/annotations/src/main/java/io/anuke/annotations/AssetsAnnotationProcessor.java +++ b/annotations/src/main/java/io/anuke/annotations/AssetsAnnotationProcessor.java @@ -1,26 +1,22 @@ package io.anuke.annotations; import com.squareup.javapoet.*; +import io.anuke.annotations.Annotations.*; -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.ProcessingEnvironment; -import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedSourceVersion; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.TypeElement; -import javax.tools.Diagnostic.Kind; -import javax.tools.StandardLocation; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.tools.Diagnostic.*; +import javax.tools.*; +import java.nio.file.*; +import java.util.*; @SupportedSourceVersion(SourceVersion.RELEASE_8) +@SupportedAnnotationTypes("io.anuke.annotations.Annotations.StyleDefaults") public class AssetsAnnotationProcessor extends AbstractProcessor{ /** Name of the base package to put all the generated classes. */ private static final String packageName = "io.anuke.mindustry.gen"; + private String path; private int round; @Override @@ -38,13 +34,13 @@ public class AssetsAnnotationProcessor extends AbstractProcessor{ if(round++ != 0) return false; //only process 1 round try{ - - String path = Paths.get(Utils.filer.createResource(StandardLocation.CLASS_OUTPUT, "no", "no") + path = Paths.get(Utils.filer.createResource(StandardLocation.CLASS_OUTPUT, "no", "no") .toUri().toURL().toString().substring(System.getProperty("os.name").contains("Windows") ? 6 : "file:".length())) .getParent().getParent().getParent().getParent().getParent().getParent().toString(); - process("Sounds", path + "/assets/sounds", "io.anuke.arc.audio.Sound", "newSound"); - process("Musics", path + "/assets/music", "io.anuke.arc.audio.Music", "newMusic"); + processSounds("Sounds", path + "/assets/sounds", "io.anuke.arc.audio.Sound"); + processSounds("Musics", path + "/assets/music", "io.anuke.arc.audio.Music"); + processUI(roundEnv.getElementsAnnotatedWith(StyleDefaults.class)); return true; }catch(Exception e){ @@ -53,19 +49,74 @@ public class AssetsAnnotationProcessor extends AbstractProcessor{ } } - @Override - public Set getSupportedAnnotationTypes() { - return Collections.singleton("*"); + void processUI(Set elements) throws Exception{ + String[] iconSizes = {"small", "smaller", "tiny"}; + + TypeSpec.Builder type = TypeSpec.classBuilder("Tex").addModifiers(Modifier.PUBLIC); + TypeSpec.Builder ictype = TypeSpec.classBuilder("Icon").addModifiers(Modifier.PUBLIC); + MethodSpec.Builder load = MethodSpec.methodBuilder("load").addModifiers(Modifier.PUBLIC, Modifier.STATIC); + MethodSpec.Builder loadStyles = MethodSpec.methodBuilder("loadStyles").addModifiers(Modifier.PUBLIC, Modifier.STATIC); + MethodSpec.Builder icload = MethodSpec.methodBuilder("load").addModifiers(Modifier.PUBLIC, Modifier.STATIC); + String resources = path + "/assets-raw/sprites/ui"; + Files.walk(Paths.get(resources)).forEach(p -> { + if(Files.isDirectory(p) || p.getFileName().toString().equals(".DS_Store")) return; + + String filename = p.getFileName().toString(); + filename = filename.substring(0, filename.indexOf(".")); + + ArrayList names = new ArrayList<>(); + names.add(""); + if(filename.contains("icon")){ + names.addAll(Arrays.asList(iconSizes)); + } + + for(String suffix : names){ + suffix = suffix.isEmpty() ? "" : "-" + suffix; + + String sfilen = filename + suffix; + String dtype = p.getFileName().toString().endsWith(".9.png") ? "io.anuke.arc.scene.style.NinePatchDrawable" : "io.anuke.arc.scene.style.TextureRegionDrawable"; + + String varname = capitalize(sfilen); + TypeSpec.Builder ttype = type; + MethodSpec.Builder tload = load; + if(varname.startsWith("icon")){ + varname = varname.substring("icon".length()); + varname = Character.toLowerCase(varname.charAt(0)) + varname.substring(1); + ttype = ictype; + tload = icload; + if(SourceVersion.isKeyword(varname)) varname += "i"; + } + + if(SourceVersion.isKeyword(varname)) varname += "s"; + + ttype.addField(ClassName.bestGuess(dtype), varname, Modifier.STATIC, Modifier.PUBLIC); + tload.addStatement(varname + " = ("+dtype+")io.anuke.arc.Core.atlas.drawable($S)", sfilen); + } + }); + + for(Element elem : elements){ + TypeElement t = (TypeElement)elem; + t.getEnclosedElements().stream().filter(e -> e.getKind() == ElementKind.FIELD).forEach(field -> { + String fname = field.getSimpleName().toString(); + if(fname.startsWith("default")){ + loadStyles.addStatement("io.anuke.arc.Core.scene.addStyle(" + field.asType().toString() + ".class, io.anuke.mindustry.ui.Styles." + fname + ")"); + } + }); + } + + ictype.addMethod(icload.build()); + JavaFile.builder(packageName, ictype.build()).build().writeTo(Utils.filer); + + type.addMethod(load.build()); + type.addMethod(loadStyles.build()); + JavaFile.builder(packageName, type.build()).build().writeTo(Utils.filer); } - void process(String classname, String path, String rtype, String loadMethod) throws Exception{ + void processSounds(String classname, String path, String rtype) throws Exception{ TypeSpec.Builder type = TypeSpec.classBuilder(classname).addModifiers(Modifier.PUBLIC); - //MethodSpec.Builder load = MethodSpec.methodBuilder("load").addModifiers(Modifier.PUBLIC, Modifier.STATIC); MethodSpec.Builder dispose = MethodSpec.methodBuilder("dispose").addModifiers(Modifier.PUBLIC, Modifier.STATIC); - MethodSpec.Builder loadBegin = MethodSpec.methodBuilder("load").addModifiers(Modifier.PUBLIC, Modifier.STATIC); - HashSet names = new HashSet<>(); Files.list(Paths.get(path)).forEach(p -> { String fname = p.getFileName().toString(); @@ -84,27 +135,38 @@ public class AssetsAnnotationProcessor extends AbstractProcessor{ String filepath = path.substring(path.lastIndexOf("/") + 1) + "/" + fname; - //load.addStatement(name + " = io.anuke.arc.Core.audio."+loadMethod+"(io.anuke.arc.Core.files.internal(io.anuke.arc.Core.app.getType() != io.anuke.arc.Application.ApplicationType.iOS ? $S : $S))", - //filepath, filepath.replace(".ogg", ".mp3")); - - loadBegin.addStatement("io.anuke.arc.Core.assets.load(io.anuke.arc.Core.app.getType() != io.anuke.arc.Application.ApplicationType.iOS ? $S : $S, "+rtype+".class, " + - "new io.anuke.arc.assets.loaders."+classname.substring(0, classname.length()-1)+"Loader."+classname.substring(0, classname.length()-1)+"Parameter((m, name, type) -> " + name + " = m.get(\"" + filepath + "\")))", - filepath, filepath.replace(".ogg", ".mp3")); + String filename = "io.anuke.arc.Core.app.getType() != io.anuke.arc.Application.ApplicationType.iOS ? \"" + filepath + "\" : \"" + filepath.replace(".ogg", ".mp3")+"\""; + loadBegin.addStatement("io.anuke.arc.Core.assets.load("+filename +", "+rtype+".class).loaded = a -> " + name + " = ("+rtype+")a", filepath, filepath.replace(".ogg", ".mp3")); dispose.addStatement(name + ".dispose()"); dispose.addStatement(name + " = null"); type.addField(FieldSpec.builder(ClassName.bestGuess(rtype), name, Modifier.STATIC, Modifier.PUBLIC).initializer("new io.anuke.arc.audio.mock.Mock" + rtype.substring(rtype.lastIndexOf(".") + 1)+ "()").build()); - //cons.consume(type, fname, name); }); if(classname.equals("Sounds")){ type.addField(FieldSpec.builder(ClassName.bestGuess(rtype), "none", Modifier.STATIC, Modifier.PUBLIC).initializer("new io.anuke.arc.audio.mock.Mock" + rtype.substring(rtype.lastIndexOf(".") + 1)+ "()").build()); } - //type.addMethod(load.build()); type.addMethod(loadBegin.build()); type.addMethod(dispose.build()); JavaFile.builder(packageName, type.build()).build().writeTo(Utils.filer); } + + static String capitalize(String s){ + StringBuilder result = new StringBuilder(s.length()); + + for(int i = 0; i < s.length(); i++){ + char c = s.charAt(i); + if(c != '_' && c != '-'){ + if(i > 0 && (s.charAt(i - 1) == '_' || s.charAt(i - 1) == '-')){ + result.append(Character.toUpperCase(c)); + }else{ + result.append(c); + } + } + } + + return result.toString(); + } } diff --git a/annotations/src/main/java/io/anuke/annotations/CodeAnalyzerTreeScanner.java b/annotations/src/main/java/io/anuke/annotations/CodeAnalyzerTreeScanner.java index c2d543e3be..8655efe155 100644 --- a/annotations/src/main/java/io/anuke/annotations/CodeAnalyzerTreeScanner.java +++ b/annotations/src/main/java/io/anuke/annotations/CodeAnalyzerTreeScanner.java @@ -54,8 +54,20 @@ class CodeAnalyzerTreeScanner extends TreePathScanner { return false; } + @SuppressWarnings("unchecked") public boolean checkScope (Scope members) { - for (Symbol s : members.getElements()) { + Iterable it; + try{ + it = (Iterable)members.getClass().getMethod("getElements").invoke(members); + }catch(Throwable t){ + try{ + it = (Iterable)members.getClass().getMethod("getSymbols").invoke(members); + }catch(Exception e){ + throw new RuntimeException(e); + } + } + + for (Symbol s : it) { if (s instanceof MethodSymbol) { MethodSymbol ms = (MethodSymbol) s; diff --git a/annotations/src/main/java/io/anuke/annotations/RemoteReadGenerator.java b/annotations/src/main/java/io/anuke/annotations/RemoteReadGenerator.java index d23bd592c9..6bbc34ed0d 100644 --- a/annotations/src/main/java/io/anuke/annotations/RemoteReadGenerator.java +++ b/annotations/src/main/java/io/anuke/annotations/RemoteReadGenerator.java @@ -118,7 +118,7 @@ public class RemoteReadGenerator{ if(entry.forward && entry.where.isServer && needsPlayer){ //call forwarded method readBlock.addStatement(packageName + "." + entry.className + "." + entry.element.getSimpleName() + - "__forward(player.con.id" + (varResult.length() == 0 ? "" : ", ") + varResult.toString() + ")"); + "__forward(player.con" + (varResult.length() == 0 ? "" : ", ") + varResult.toString() + ")"); } readBlock.nextControlFlow("catch (java.lang.Exception e)"); diff --git a/annotations/src/main/java/io/anuke/annotations/RemoteWriteGenerator.java b/annotations/src/main/java/io/anuke/annotations/RemoteWriteGenerator.java index 411f8ead86..d28ff02a2d 100644 --- a/annotations/src/main/java/io/anuke/annotations/RemoteWriteGenerator.java +++ b/annotations/src/main/java/io/anuke/annotations/RemoteWriteGenerator.java @@ -85,19 +85,19 @@ public class RemoteWriteGenerator{ //if toAll is false, it's a 'send to one player' variant, so add the player as a parameter if(!toAll){ - method.addParameter(int.class, "playerClientID"); + method.addParameter(ClassName.bestGuess("io.anuke.mindustry.net.NetConnection"), "playerConnection"); } //add sender to ignore if(forwarded){ - method.addParameter(int.class, "exceptSenderID"); + method.addParameter(ClassName.bestGuess("io.anuke.mindustry.net.NetConnection"), "exceptConnection"); } //call local method if applicable, shouldn't happen when forwarding method as that already happens by default if(!forwarded && methodEntry.local != Loc.none){ //add in local checks if(methodEntry.local != Loc.both){ - method.beginControlFlow("if(" + getCheckString(methodEntry.local) + " || !io.anuke.mindustry.net.Net.active())"); + method.beginControlFlow("if(" + getCheckString(methodEntry.local) + " || !io.anuke.mindustry.Vars.net.active())"); } //concatenate parameters @@ -159,7 +159,7 @@ public class RemoteWriteGenerator{ boolean writePlayerSkipCheck = methodEntry.where == Loc.both && i == 0; if(writePlayerSkipCheck){ //write begin check - method.beginControlFlow("if(io.anuke.mindustry.net.Net.server())"); + method.beginControlFlow("if(io.anuke.mindustry.Vars.net.server())"); } if(Utils.isPrimitive(typeName)){ //check if it's a primitive, and if so write it @@ -194,18 +194,18 @@ public class RemoteWriteGenerator{ if(forwarded){ //forward packet if(!methodEntry.local.isClient){ //if the client doesn't get it called locally, forward it back after validation - sendString = "send("; + sendString = "io.anuke.mindustry.Vars.net.send("; }else{ - sendString = "sendExcept(exceptSenderID, "; + sendString = "io.anuke.mindustry.Vars.net.sendExcept(exceptConnection, "; } }else if(toAll){ //send to all players / to server - sendString = "send("; + sendString = "io.anuke.mindustry.Vars.net.send("; }else{ //send to specific client from server - sendString = "sendTo(playerClientID, "; + sendString = "playerConnection.send("; } //send the actual packet - method.addStatement("io.anuke.mindustry.net.Net." + sendString + "packet, " + + method.addStatement(sendString + "packet, " + (methodEntry.unreliable ? "io.anuke.mindustry.net.Net.SendMode.udp" : "io.anuke.mindustry.net.Net.SendMode.tcp") + ")"); @@ -217,8 +217,8 @@ public class RemoteWriteGenerator{ } private String getCheckString(Loc loc){ - return loc.isClient && loc.isServer ? "io.anuke.mindustry.net.Net.server() || io.anuke.mindustry.net.Net.client()" : - loc.isClient ? "io.anuke.mindustry.net.Net.client()" : - loc.isServer ? "io.anuke.mindustry.net.Net.server()" : "false"; + return loc.isClient && loc.isServer ? "io.anuke.mindustry.Vars.net.server() || io.anuke.mindustry.Vars.net.client()" : + loc.isClient ? "io.anuke.mindustry.Vars.net.client()" : + loc.isServer ? "io.anuke.mindustry.Vars.net.server()" : "false"; } } diff --git a/build.gradle b/build.gradle index 578fe451c6..7bc56367ea 100644 --- a/build.gradle +++ b/build.gradle @@ -21,11 +21,12 @@ allprojects{ ext{ versionNumber = '4' - versionModifier = 'release' + if(!project.hasProperty("versionModifier")) versionModifier = 'release' if(!project.hasProperty("versionType")) versionType = 'official' appName = 'Mindustry' gdxVersion = '1.9.10' roboVMVersion = '2.3.7' + steamworksVersion = '1.8.0' arcHash = null debugged = { @@ -33,20 +34,11 @@ allprojects{ } localArc = { - return (!project.hasProperty("release")) && new File(projectDir.parent, '../Arc').exists() + return !project.hasProperty("release") && new File(projectDir.parent, '../Arc').exists() } getArcHash = { - //get latest commit hash from github since JITPack's '-snapshot' version doesn't work correctly - if(arcHash == null){ - try{ - arcHash = 'git ls-remote https://github.com/Anuken/Arc.git'.execute().text.split("\t")[0] - }catch(e){ - e.printStackTrace() - arcHash = "-SNAPSHOT" - } - } - return arcHash + return new Properties().with{ p -> p.load(new File((File)projectDir, 'gradle.properties').newReader()); return p }["archash"] } arcModule = { String name -> @@ -150,13 +142,15 @@ project(":desktop"){ dependencies{ compile project(":core") - compile project(":net") if(debugged()) compile project(":debug") compile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" compile "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop" + compile "com.code-disaster.steamworks4j:steamworks4j:$steamworksVersion" + compile "com.code-disaster.steamworks4j:steamworks4j-server:$steamworksVersion" + compile arcModule("backends:backend-sdl") compile 'com.github.MinnDevelopment:java-discord-rpc:v2.0.2' } @@ -175,7 +169,7 @@ project(":ios"){ } props['app.id'] = 'io.anuke.mindustry' - props['app.version'] = '4.0' + props['app.version'] = '4.2.1' props['app.mainclass'] = 'io.anuke.mindustry.IOSLauncher' props['app.executable'] = 'IOSLauncher' props['app.name'] = 'Mindustry' @@ -185,7 +179,6 @@ project(":ios"){ dependencies{ compile project(":core") - compile project(":net") compileOnly project(":annotations") compile arcModule("backends:backend-robovm") @@ -201,6 +194,7 @@ project(":core"){ apply plugin: "java" task preGen{ + outputs.upToDateWhen{ false } generateLocales() writeVersion() } @@ -249,7 +243,6 @@ project(":server"){ dependencies{ compile project(":core") - compile project(":net") compile arcModule("backends:backend-headless") } } @@ -294,14 +287,6 @@ project(":annotations"){ } } -project(":net"){ - apply plugin: "java" - - dependencies{ - compile project(":core") - } -} - task deployAll{ task cleanDeployOutput{ doFirst{ @@ -321,4 +306,4 @@ task deployAll{ dependsOn "desktop:packrMacOS" dependsOn "server:deploy" dependsOn "android:deploy" -} \ No newline at end of file +} diff --git a/core/assets-raw/sprites/ui/icons/icon-admin-small.png b/core/assets-raw/sprites/ui/icons/icon-admin-badge.png similarity index 100% rename from core/assets-raw/sprites/ui/icons/icon-admin-small.png rename to core/assets-raw/sprites/ui/icons/icon-admin-badge.png diff --git a/core/assets-raw/sprites/ui/icons/icon-fdroid.png b/core/assets-raw/sprites/ui/icons/icon-fdroid.png new file mode 100644 index 0000000000..24c7cb884d Binary files /dev/null and b/core/assets-raw/sprites/ui/icons/icon-fdroid.png differ diff --git a/core/assets-raw/sprites/ui/icons/icon-workshop.png b/core/assets-raw/sprites/ui/icons/icon-workshop.png new file mode 100644 index 0000000000..74e43e701f Binary files /dev/null and b/core/assets-raw/sprites/ui/icons/icon-workshop.png differ diff --git a/core/assets-raw/sprites/ui/window-empty.9.png b/core/assets-raw/sprites/ui/window-empty.9.png index cbc2915f60..5c943d42b7 100644 Binary files a/core/assets-raw/sprites/ui/window-empty.9.png and b/core/assets-raw/sprites/ui/window-empty.9.png differ diff --git a/core/assets-raw/sprites/zones/craters.png b/core/assets-raw/sprites/zones/zone-craters.png similarity index 100% rename from core/assets-raw/sprites/zones/craters.png rename to core/assets-raw/sprites/zones/zone-craters.png diff --git a/core/assets-raw/sprites/zones/desertWastes.png b/core/assets-raw/sprites/zones/zone-desertWastes.png similarity index 100% rename from core/assets-raw/sprites/zones/desertWastes.png rename to core/assets-raw/sprites/zones/zone-desertWastes.png diff --git a/core/assets-raw/sprites/zones/desolateRift.png b/core/assets-raw/sprites/zones/zone-desolateRift.png similarity index 100% rename from core/assets-raw/sprites/zones/desolateRift.png rename to core/assets-raw/sprites/zones/zone-desolateRift.png diff --git a/core/assets-raw/sprites/zones/frozenForest.png b/core/assets-raw/sprites/zones/zone-frozenForest.png similarity index 100% rename from core/assets-raw/sprites/zones/frozenForest.png rename to core/assets-raw/sprites/zones/zone-frozenForest.png diff --git a/core/assets-raw/sprites/zones/fungalPass.png b/core/assets-raw/sprites/zones/zone-fungalPass.png similarity index 100% rename from core/assets-raw/sprites/zones/fungalPass.png rename to core/assets-raw/sprites/zones/zone-fungalPass.png diff --git a/core/assets-raw/sprites/zones/groundZero.png b/core/assets-raw/sprites/zones/zone-groundZero.png similarity index 100% rename from core/assets-raw/sprites/zones/groundZero.png rename to core/assets-raw/sprites/zones/zone-groundZero.png diff --git a/core/assets-raw/sprites/zones/nuclearComplex.png b/core/assets-raw/sprites/zones/zone-nuclearComplex.png similarity index 100% rename from core/assets-raw/sprites/zones/nuclearComplex.png rename to core/assets-raw/sprites/zones/zone-nuclearComplex.png diff --git a/core/assets-raw/sprites/zones/overgrowth.png b/core/assets-raw/sprites/zones/zone-overgrowth.png similarity index 100% rename from core/assets-raw/sprites/zones/overgrowth.png rename to core/assets-raw/sprites/zones/zone-overgrowth.png diff --git a/core/assets-raw/sprites/zones/ruinousShores.png b/core/assets-raw/sprites/zones/zone-ruinousShores.png similarity index 100% rename from core/assets-raw/sprites/zones/ruinousShores.png rename to core/assets-raw/sprites/zones/zone-ruinousShores.png diff --git a/core/assets-raw/sprites/zones/saltFlats.png b/core/assets-raw/sprites/zones/zone-saltFlats.png similarity index 100% rename from core/assets-raw/sprites/zones/saltFlats.png rename to core/assets-raw/sprites/zones/zone-saltFlats.png diff --git a/core/assets-raw/sprites/zones/stainedMountains.png b/core/assets-raw/sprites/zones/zone-stainedMountains.png similarity index 100% rename from core/assets-raw/sprites/zones/stainedMountains.png rename to core/assets-raw/sprites/zones/zone-stainedMountains.png diff --git a/core/assets-raw/sprites/zones/tarFields.png b/core/assets-raw/sprites/zones/zone-tarFields.png similarity index 100% rename from core/assets-raw/sprites/zones/tarFields.png rename to core/assets-raw/sprites/zones/zone-tarFields.png diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 4d829e9eb5..d0ef17bcad 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -52,8 +52,17 @@ close = Close website = Website quit = Quit maps = Maps +maps.browse = Browse Maps continue = Continue maps.none = [lightgray]No maps found! +invalid = Invalid +preparingconfig = Preparing Config +preparingcontent = Preparing Content +uploadingcontent = Uploading Content +uploadingpreviewfile = Uploading Preview File +committingchanges = Comitting Changes +done = Done + about.button = About name = Name: noname = Pick a[accent] player name[] first. @@ -64,16 +73,18 @@ techtree = Tech Tree research.list = [lightgray]Research: research = Research researched = [lightgray]{0} researched. -players = {0} players online -players.single = {0} player online +players = {0} players +players.single = {0} player server.closing = [accent]Closing server... server.kicked.kick = You have been kicked from the server! +server.kicked.whitelist = You are not whitelisted here. server.kicked.serverClose = Server closed. server.kicked.vote = You have been vote-kicked. Goodbye. server.kicked.clientOutdated = Outdated client! Update your game! server.kicked.serverOutdated = Outdated server! Ask the host to update! server.kicked.banned = You are banned on this server. server.kicked.typeMismatch = This server is not compatible with your build type. +server.kicked.playerLimit = This server is full. Wait for an empty slot. server.kicked.recentKick = You have been kicked recently.\nWait before connecting again. server.kicked.nameInUse = There is someone with that name\nalready on this server. server.kicked.nameEmpty = Your chosen name is invalid. @@ -84,11 +95,13 @@ server.versions = Your version:[accent] {0}[]\nServer version:[accent] {1}[] host.info = The [accent]host[] button hosts a server on port [scarlet]6567[]. \nAnybody on the same [lightgray]wifi or local network[] should be able to see your server in their server list.\n\nIf you want people to be able to connect from anywhere by IP, [accent]port forwarding[] is required.\n\n[lightgray]Note: If someone is experiencing trouble connecting to your LAN game, make sure you have allowed Mindustry access to your local network in your firewall settings. Note that public networks sometimes do not allow server discovery. join.info = Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[lightgray]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP. hostserver = Host Multiplayer Game +invitefriends = Invite Friends hostserver.mobile = Host\nGame host = Host hosting = [accent]Opening server... hosts.refresh = Refresh hosts.discovering = Discovering LAN games +hosts.discovering.any = Discovering games server.refreshing = Refreshing server hosts.none = [lightgray]No local games found! host.invalid = [scarlet]Can't connect to host. @@ -109,7 +122,7 @@ server.edit = Edit Server server.outdated = [crimson]Outdated Server![] server.outdated.client = [crimson]Outdated Client![] server.version = [gray]v{0} {1} -server.custombuild = [yellow]Custom Build +server.custombuild = [accent]Custom Build confirmban = Are you sure you want to ban this player? confirmkick = Are you sure you want to kick this player? confirmunban = Are you sure you want to unban this player? @@ -118,13 +131,17 @@ confirmunadmin = Are you sure you want to remove admin status from this player? joingame.title = Join Game joingame.ip = Address: disconnect = Disconnected. +disconnect.error = Connection error. +disconnect.closed = Connection closed. +disconnect.timeout = Timed out. disconnect.data = Failed to load world data! +cantconnect = Unable to join game ([accent]{0}[]). connecting = [accent]Connecting... connecting.data = [accent]Loading world data... server.port = Port: server.addressinuse = Address already in use! server.invalidport = Invalid port number! -server.error = [crimson]Error hosting server: [accent]{0} +server.error = [crimson]Error hosting server. save.old = This save is for an older version of the game, and can no longer be used.\n\n[lightgray]Save backwards compatibility will be implemented in the full 4.0 release. save.new = New Save save.overwrite = Are you sure you want to overwrite\nthis save slot? @@ -151,7 +168,7 @@ off = Off save.autosave = Autosave: {0} save.map = Map: {0} save.wave = Wave {0} -save.difficulty = Difficulty: {0} +save.mode = Gamemode: {0} save.date = Last Saved: {0} save.playtime = Playtime: {0} warning = Warning. @@ -185,7 +202,7 @@ wave.enemy = [lightgray]{0} Enemy Remaining loadimage = Load Image saveimage = Save Image unknown = Unknown -custom = Custom +custom = Custom builtin = Built-In map.delete.confirm = Are you sure you want to delete this map? This action cannot be undone! map.random = [accent]Random Map @@ -193,6 +210,11 @@ map.nospawn = This map does not have any cores for the player to spawn in! Add a map.nospawn.pvp = This map does not have any enemy cores for player to spawn into! Add[SCARLET] non-orange[] cores to this map in the editor. map.nospawn.attack = This map does not have any enemy cores for player to attack! Add[SCARLET] red[] cores to this map in the editor. map.invalid = Error loading map: corrupted or invalid map file. +map.publish.error = Error publishing map: {0} +map.publish.confirm = Are you sure you want to publish this map?\n\n[lightgray]Make sure you agree to the Workshop EULA first, or your maps will not show up! +eula = Steam EULA +map.publish = Map published. +map.publishing = [accent]Publishing map... editor.brush = Brush editor.openin = Open In Editor editor.oregen = Ore Generation @@ -204,7 +226,9 @@ editor.waves = Waves: editor.rules = Rules: editor.generation = Generation: editor.ingame = Edit In-Game +editor.publish.workshop = Publish On Workshop editor.newmap = New Map +workshop = Workshop waves.title = Waves waves.remove = Remove waves.never = @@ -221,15 +245,17 @@ waves.invalid = Invalid waves in clipboard. waves.copied = Waves copied. waves.none = No enemies defined.\nNote that empty wave layouts will automatically be replaced with the default layout. editor.default = [lightgray] +details = Details... edit = Edit... editor.name = Name: editor.spawn = Spawn Unit editor.removeunit = Remove Unit editor.teams = Teams -editor.errorload = Error loading file:\n[accent]{0} -editor.errorsave = Error saving file:\n[accent]{0} -editor.errorimage = That's an image, not a map. Don't go around changing extensions expecting it to work.\n\nIf you want to import a legacy map, use the 'import legacy map' button in the editor. +editor.errorload = Error loading file. +editor.errorsave = Error saving file. +editor.errorimage = That's an image, not a map.\n\nIf you want to import a 3.5/build 40 map, use the 'Import Legacy Map' button in the editor. editor.errorlegacy = This map is too old, and uses a legacy map format that is no longer supported. +editor.errornot = This is not a map file. editor.errorheader = This map file is either not valid or corrupt. editor.errorname = Map has no name defined. Are you trying to load a save file? editor.update = Update @@ -248,7 +274,7 @@ editor.importmap = Import Map editor.importmap.description = Import an already existing map editor.importfile = Import File editor.importfile.description = Import an external map file -editor.importimage = Import Legacy Image +editor.importimage = Import Legacy Map editor.importimage.description = Import an external map image file editor.export = Export... editor.exportfile = Export File @@ -345,6 +371,7 @@ launch.skip.confirm = If you skip now, you will not be able to launch until late uncover = Uncover configure = Configure Loadout configure.locked = [lightgray]Unlock configuring loadout: Wave {0}. +configure.invalid = Amount must be a number between 0 and {0}. zone.unlocked = [lightgray]{0} unlocked. zone.requirement.complete = Wave {0} reached:\n{1} zone requirements met. zone.config.complete = Wave {0} reached:\nLoadout config unlocked. @@ -445,6 +472,7 @@ blocks.boosteffect = Boost Effect blocks.maxunits = Max Active Units blocks.health = Health blocks.buildtime = Build Time +blocks.buildcost = Build Cost blocks.inaccuracy = Inaccuracy blocks.shots = Shots blocks.reload = Shots/Second @@ -457,6 +485,7 @@ bar.powerbalance = Power: {0}/s bar.poweramount = Power: {0} bar.poweroutput = Power Output: {0} bar.items = Items: {0} +bar.capacity = Capacity: {0} bar.liquid = Liquid bar.heat = Heat bar.power = Power @@ -533,8 +562,9 @@ setting.sfxvol.name = SFX Volume setting.mutesound.name = Mute Sound setting.crashreport.name = Send Anonymous Crash Reports setting.savecreate.name = Auto-Create Saves +setting.publichost.name = Public Game Visibility setting.chatopacity.name = Chat Opacity -setting.playerchat.name = Display In-Game Chat +setting.playerchat.name = Display Player Bubble Chat uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] seconds... uiscale.cancel = Cancel & Exit setting.bloom.name = Bloom @@ -885,11 +915,11 @@ unit.lich.name = Lich unit.reaper.name = Reaper tutorial.next = [lightgray] tutorial.intro = You have entered the[scarlet] Mindustry Tutorial.[]\nBegin by[accent] mining copper[]. Tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper -tutorial.drill = Mining manually is inefficient.\n[accent]Drills []can mine automatically.\nClick the drill tab in the bottom right.\nSelect the[accent] mechanical drill[]. Place it on a copper vein by clicking.\n[accent]Right-click[] to stop building. +tutorial.drill = Mining manually is inefficient.\n[accent]Drills []can mine automatically.\nClick the drill tab in the bottom right.\nSelect the[accent] mechanical drill[]. Place it on a copper vein by clicking.\n[accent]Right-click[] to stop building, and[accent] Hold Ctrl while scrolling[] to zoom in and out. tutorial.drill.mobile = Mining manually is inefficient.\n[accent]Drills []can mine automatically.\nTap the drill tab in the bottom right.\nSelect the[accent] mechanical drill[].\nPlace it on a copper vein by tapping, then press the[accent] checkmark[] below to confirm your selection.\nPress the[accent] X button[] to cancel placement. tutorial.blockinfo = Each block has different stats. Each drill can only mine certain ores.\nTo check a block's info and stats,[accent] tap the "?" button while selecting it in the build menu.[]\n\n[accent]Access the Mechanical Drill's stats now.[] -tutorial.conveyor = [accent]Conveyors[] are used to transport items to the core.\nMake a line of conveyors from the drill to the core.\n[accent]Hold down the mouse to place in a line.[]\nHold[accent] CTRL[] while selecting a line to place diagonally.\n\n[accent]{0}/{1} conveyors placed in line\n[accent]0/1 items delivered -tutorial.conveyor.mobile = [accent]Conveyors[] are used to transport items to the core.\nMake a line of conveyors from the drill to the core.\n[accent] Place in a line by holding down your finger for a few seconds[] and dragging in a direction.\n\n[accent]{0}/{1} conveyors placed in line\n[accent]0/1 items delivered +tutorial.conveyor = [accent]Conveyors[] are used to transport items to the core.\nMake a line of conveyors from the drill to the core.\n[accent]Hold down the mouse to place in a line.[]\nHold[accent] CTRL[] while selecting a line to place diagonally.\n\n[accent]Place 2 conveyors with the line tool, then deliver an item into the core. +tutorial.conveyor.mobile = [accent]Conveyors[] are used to transport items to the core.\nMake a line of conveyors from the drill to the core.\n[accent] Place in a line by holding down your finger for a few seconds[] and dragging in a direction.\n\n[accent]Place 2 conveyors with the line tool, then deliver an item into the core. tutorial.turret = Once an item enters your core, it can be used for building.\nKeep in mind that not all items can be used for building.\nItems that are not used for building, such as[accent] coal[] or[accent] scrap[], cannot be put into the core.\nDefensive structures must be built to repel the[lightgray] enemy[].\nBuild a[accent] duo turret[] near your base. tutorial.drillturret = Duo turrets require[accent] copper ammo []to shoot.\nPlace a drill near the turret.\nLead conveyors into the turret to supply it with copper.\n\n[accent]Ammo delivered: 0/1 tutorial.pause = During battle, you are able to[accent] pause the game.[]\nYou may queue buildings while paused.\n\n[accent]Press space to pause. @@ -904,7 +934,6 @@ tutorial.waves = The[lightgray] enemy[] approaches.\n\nDefend the core for 2 wav tutorial.waves.mobile = The[lightgray] enemy[] approaches.\n\nDefend the core for 2 waves. Your ship will automatically fire at enemies.\nBuild more turrets and drills. Mine more copper. tutorial.launch = Once you reach a specific wave, you are able to[accent] launch the core[], leaving your defenses behind and[accent] obtaining all the resources in your core.[]\nThese resources can then be used to research new technology.\n\n[accent]Press the launch button. - item.copper.description = The most basic structural material. Used extensively in all types of blocks. item.lead.description = A basic starter material. Used extensively in electronics and liquid transportation blocks. item.metaglass.description = A super-tough glass compound. Extensively used for liquid distribution and storage. diff --git a/core/assets/bundles/bundle_cs.properties b/core/assets/bundles/bundle_cs.properties index dfee68c878..8a005b0e13 100644 --- a/core/assets/bundles/bundle_cs.properties +++ b/core/assets/bundles/bundle_cs.properties @@ -16,6 +16,11 @@ screenshot.invalid = Map too large, potentially not enough memory for screenshot gameover = Konec hry gameover.pvp = [accent] {0}[] Tým Vyhrál! highscore = [accent]Nový Rekord! +load.sound = Sounds +load.map = Maps +load.image = Images +load.content = Content +load.system = System stat.wave = Waves Defeated:[accent] {0} stat.enemiesDestroyed = Enemies Destroyed:[accent] {0} stat.built = Buildings Built:[accent] {0} @@ -23,8 +28,6 @@ stat.destroyed = Buildings Destroyed:[accent] {0} stat.deconstructed = Buildings Deconstructed:[accent] {0} stat.delivered = Resources Launched: stat.rank = Final Rank: [accent]{0} -placeline = You have selected a block.\nYou can[accent] place in a line[] by[accent] holding down your finger for a few seconds[] and dragging in a direction.\nTry it. -removearea = You have selected removal mode.\nYou can[accent] remove blocks in a rectangle[] by[accent] holding down your finger for a few seconds[] and dragging.\nTry it. launcheditems = [accent]Launched Items map.delete = Jsi si jistý že chceš smazat mapu "[accent]{0}[]"? level.highscore = Nejvyšší skóre: [accent]{0} @@ -63,9 +66,11 @@ players.single = {0} hráč online server.closing = [accent]Zavírám server... server.kicked.kick = Byl jsi vykopnut ze serveru! server.kicked.serverClose = Server je zavřený. +server.kicked.vote = You have been vote-kicked. Goodbye. server.kicked.clientOutdated = Zastaralý klient hry! Aktualizuj si hru! server.kicked.serverOutdated = Zastaralý server! Řekni hostiteli o aktualizaci! server.kicked.banned = Jsi zabanován na tomto serveru. +server.kicked.typeMismatch = This server is not compatible with your build type. server.kicked.recentKick = Před nedávnem jsi byl vykopnut.\nPočkej než se znovu připojíš. server.kicked.nameInUse = Někdo se stejným jménem\nje aktuálně na serveru. server.kicked.nameEmpty = Tvé jméno je neplatné. @@ -156,6 +161,11 @@ cancel = Zrušit openlink = Otevřít Odkaz copylink = Zkopírovat Odkaz back = Zpět +data.export = Export Data +data.import = Import Data +data.exported = Data exported. +data.invalid = This isn't valid game data. +data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. classic.export = Export Classic Data classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? quit.confirm = Jsi si jistý že chceš ukončit ? @@ -376,6 +386,7 @@ zone.fungalPass.description = A transition area between high mountains and lower zone.impact0078.description = zone.crags.description = settings.language = Jazyk +settings.data = Game Data settings.reset = nastavit výchozí settings.rebind = Přenastavit settings.controls = Ovládání @@ -507,6 +518,7 @@ setting.mutemusic.name = Ztišit hudbu setting.sfxvol.name = SFX hlasitost setting.mutesound.name = Ztišit zvuky setting.crashreport.name = Poslat anonymní spis o zhroucení hry +setting.savecreate.name = Auto-Create Saves setting.chatopacity.name = Chat Opacity setting.playerchat.name = Display In-Game Chat uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... @@ -527,6 +539,7 @@ keybind.press.axis = Stiskni osu nebo klávesu... keybind.screenshot.name = Sníměk mapy keybind.move_x.name = Pohyb na X keybind.move_y.name = Pohyb na Y +keybind.fullscreen.name = Toggle Fullscreen keybind.select.name = Vybrat/Střílet keybind.diagonal_placement.name = Diagonal Placement keybind.pick.name = Pick Block @@ -790,6 +803,7 @@ block.blast-mixer.name = Výbušninový mixér block.solar-panel.name = Solární panel block.solar-panel-large.name = Velký solární panel block.oil-extractor.name = Ropný Extraktor +block.command-center.name = Command Center block.draug-factory.name = Draug Miner Drone Factory block.spirit-factory.name = Továrna na Spirit Drony block.phantom-factory.name = Továrna na Fantom Drony @@ -1012,6 +1026,7 @@ block.ripple.description = Velká artilérní střílna, která vystřelí něko block.cyclone.description = Velká rychle pálící střílna. block.spectre.description = Velká střílna, která vystřelí dva mocné projektily naráz. block.meltdown.description = Velká střílna, která vystřelí mocný paprsek dalekého dosahu. +block.command-center.description = Issues movement commands to allied units across the map.\nCauses units to patrol, attack an enemy core or retreat to the core/factory. When no enemy core is present, units will default to patrolling under the attack command. block.draug-factory.description = Produces Draug mining drones. block.spirit-factory.description = Produkuje lehké drony, kteří teží minerály a opravují budovy block.phantom-factory.description = Produkuje pokročilé drony kteří jsou podstatně efektivnější jak spirit droni. diff --git a/core/assets/bundles/bundle_de.properties b/core/assets/bundles/bundle_de.properties index 7a671aa426..3d69c97d3b 100644 --- a/core/assets/bundles/bundle_de.properties +++ b/core/assets/bundles/bundle_de.properties @@ -16,6 +16,11 @@ screenshot.invalid = Karte zu groß! Eventuell nicht ausreichend Arbeitsspeicher gameover = Der Kern wurde zerstört. gameover.pvp = Das[accent] {0}[] Team ist siegreich! highscore = [YELLOW] Neuer Highscore! +load.sound = Sounds +load.map = Maps +load.image = Images +load.content = Content +load.system = System stat.wave = Wellen besiegt:[accent] {0} stat.enemiesDestroyed = Gegner zerstört:[accent] {0} stat.built = Gebäude gebaut:[accent] {0} @@ -23,8 +28,6 @@ stat.destroyed = Gebäude zerstört:[accent] {0} stat.deconstructed = Gebäude abgebaut:[accent] {0} stat.delivered = Übertragene Ressourcen: stat.rank = Finaler Rang: [accent]{0} -placeline = Du hast einen Block ausgewählt.\nDu kannst[accent] davon eine Reihe bauen,[] indem du[accent] wenige Sekunden mit einem Finger drückst[] und ihn in eine Richtung ziehst.\nVersuche es. -removearea = Du hast den Zerstörungsmodus ausgewählt.\nDu kannst[accent] Blöcke im Rechteck zerstören,[] indem du[accent] wenige Sekunden mit einem Finger drückst[] und ihn ziehst.\nVersuche es. launcheditems = [accent]Übertragene Items map.delete = Bist du sicher, dass du die Karte "[accent]{0}[]" löschen möchtest? level.highscore = Highscore: [accent]{0} @@ -63,9 +66,11 @@ players.single = {0} Spieler online server.closing = [accent]Schließe den Server ... server.kicked.kick = Du wurdest vom Server gekickt! server.kicked.serverClose = Server geschlossen. +server.kicked.vote = You have been vote-kicked. Goodbye. server.kicked.clientOutdated = Veralteter Client! Aktualisiere dein Spiel! server.kicked.serverOutdated = Veralteter Server! Bitte den Host um ein Update! server.kicked.banned = Du wurdest vom Server verbannt. +server.kicked.typeMismatch = This server is not compatible with your build type. server.kicked.recentKick = Du wurdest gerade gekickt.\nWarte bevor du dich wieder verbindest. server.kicked.nameInUse = Es ist bereits ein Spieler \nmit diesem Namen auf dem Server. server.kicked.nameEmpty = Dein Name muss mindestens einen Buchstaben oder eine Zahl enthalten. @@ -156,6 +161,11 @@ cancel = Abbruch openlink = Link öffnen copylink = Kopiere Link back = Zurück +data.export = Export Data +data.import = Import Data +data.exported = Data exported. +data.invalid = This isn't valid game data. +data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. classic.export = Export Classic Data classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? quit.confirm = Willst du wirklich aufhören? @@ -376,6 +386,7 @@ zone.fungalPass.description = A transition area between high mountains and lower zone.impact0078.description = zone.crags.description = settings.language = Sprache +settings.data = Game Data settings.reset = Auf Standard zurücksetzen settings.rebind = Zuweisen settings.controls = Steuerung @@ -507,6 +518,7 @@ setting.mutemusic.name = Musik stummschalten setting.sfxvol.name = Audioeffekt-Lautstärke setting.mutesound.name = Audioeffekte stummschalten setting.crashreport.name = Anonyme Absturzberichte senden +setting.savecreate.name = Auto-Create Saves setting.chatopacity.name = Chat Deckkraft setting.playerchat.name = Chat im Spiel anzeigen uiscale.reset = UI-Skalierung wurde geändert.\nDrücke "OK", um diese Skalierung zu bestätigen.\n[scarlet]Zurückkehren und Beenden in[accent] {0}[] Einstellungen... @@ -527,6 +539,7 @@ keybind.press.axis = Drücke eine Taste oder bewege eine Achse... keybind.screenshot.name = Karten Screenshot keybind.move_x.name = X-Achse keybind.move_y.name = Y-Achse +keybind.fullscreen.name = Toggle Fullscreen keybind.select.name = Auswählen/Schießen keybind.diagonal_placement.name = Diagonal platzieren keybind.pick.name = Block Auswählen @@ -790,6 +803,7 @@ block.blast-mixer.name = Sprengmixer block.solar-panel.name = Solarpanel block.solar-panel-large.name = Großes Solarpanel block.oil-extractor.name = Öl-Extraktor +block.command-center.name = Command Center block.draug-factory.name = Draug Miner-Drohnenfactory block.spirit-factory.name = Spirit-Drohnenfabrik block.phantom-factory.name = Phantom-Drohnenfabrik @@ -1012,6 +1026,7 @@ block.ripple.description = Ein großer Artillerie-Geschützturm, der mehrere Sch block.cyclone.description = Ein großer Schnellfeuer-Geschützturm. block.spectre.description = Ein großer Geschützturm, der zwei starke Schüsse gleichzeitig abfeuert. block.meltdown.description = Ein großer Geschützturm, der starke Strahlen mit großer Reichweite abfeuert. +block.command-center.description = Issues movement commands to allied units across the map.\nCauses units to patrol, attack an enemy core or retreat to the core/factory. When no enemy core is present, units will default to patrolling under the attack command. block.draug-factory.description = Produziert Draug-Mining-Drohnen. block.spirit-factory.description = Produziert leichte Drohnen, die Erz abbauen und Blöcke reparieren können. block.phantom-factory.description = Produziert erweiterte Drohnen, die deutlich effizienter sind als Spirit-Drohnen. diff --git a/core/assets/bundles/bundle_es.properties b/core/assets/bundles/bundle_es.properties index 5e82487f0e..4a0e34ce40 100644 --- a/core/assets/bundles/bundle_es.properties +++ b/core/assets/bundles/bundle_es.properties @@ -1,47 +1,50 @@ -credits.text = Created by [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[]\n\n[GRAY](In case you can't tell, this text is currently unfinished.\nTranslators, don't edit it yet!) +credits.text = Creado por [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[] credits = Créditos contributors = Traductores y Contribuidores discord = ¡Únete al Discord de Mindustry! link.discord.description = La sala oficial del Discord de Mindustry link.github.description = Código fuente del juego -link.changelog.description = Lista de cambios de actualización -link.dev-builds.description = Versiones de desarrollo inestable +link.changelog.description = Lista de actualizaciones +link.dev-builds.description = Versiones de desarrollo inestables link.trello.description = Tablero de Trello oficial para las características planificadas link.itch.io.description = itch.io es la página donde podes descargar las versiones para PC y web link.google-play.description = Ficha en la Google Play Store link.wiki.description = Wiki oficial de Mindustry linkfail = ¡Error al abrir el enlace!\nLa URL ha sido copiada a su portapapeles. screenshot = Captura de pantalla guardada en {0} -screenshot.invalid = El mapa es muy grande, potencialmente no hay suficiente memoria para una captura de pantalla. +screenshot.invalid = Mapa demasiado grande, no hay suficiente memoria para la captura de pantalla. gameover = Tu núcleo ha sido destruido. gameover.pvp = ¡El equipo[accent] {0}[] ha ganado! highscore = [accent]¡Nueva mejor puntuación! -stat.wave = Oleadas vencidas:[accent] {0} -stat.enemiesDestroyed = Enemigos destruidos:[accent] {0} -stat.built = Edificaciones hechas:[accent] {0} -stat.destroyed = Edificaciones destruidas:[accent] {0} -stat.deconstructed = Edificaciones deconstruidas:[accent] {0} -stat.delivered = Recursos lanzados: +load.sound = Sounds +load.map = Maps +load.image = Images +load.content = Content +load.system = System +stat.wave = Oleadas Derrotadas:[accent] {0} +stat.enemiesDestroyed = Enemigos Destruidos:[accent] {0} +stat.built = Estructuras Construidas:[accent] {0} +stat.destroyed = Estructuras Destruidas:[accent] {0} +stat.deconstructed = Estructuras Desconstruidas:[accent] {0} +stat.delivered = Recursos Lanzados: stat.rank = Rango final: [accent]{0} -placeline = Acabas de dejar de selecionar un bloque.\nPuedes poner en una linea[accent] por presionar y mantener tu dedo[] y moverlo hacia[accent] una dirrecion[accent].\nTry it. -removearea = Acabas de slecionar el modo de remover.\nPuedes remover bloques en un rectangulo[] por presionar y mantener tu dedo[] y moverlo hacia [accent] una direccion[accent].\nTry it. -launcheditems = [accent]Items lanzados +launcheditems = [accent]Recursos Lanzados map.delete = ¿Estás seguro que quieres borrar el mapa "[accent]{0}[]"? level.highscore = Puntuación más alta: [accent]{0} level.select = Selección de nivel level.mode = Modo de juego: showagain = No mostrar otra vez en la próxima sesión coreattack = < ¡El núcleo está bajo ataque! > -nearpoint = [[ [scarlet]ABANDONA EL PUNTO DE CAIDA INMEDIATAMENTE![] ]\naniquilación inmediata +nearpoint = [[ [scarlet]ABANDONA EL PUNTO DE APARICIÓN IMNEDIATAMENTE[] ]\naniquilación inminente database = Base de datos del núcleo savegame = Guardar Partida loadgame = Cargar Partida joingame = Unirse a la Partida addplayers = Agregar/Quitar Jugadores customgame = Partida personalizada -newgame = Nueva partida +newgame = Nueva Partida none = -minimap = Mini mapa +minimap = Minimapa close = Cerrar website = Sitio web quit = Salir @@ -50,29 +53,31 @@ continue = Continuar maps.none = [LIGHT_GRAY]¡No se han encontrado mapas! about.button = Acerca de name = Nombre: -noname = Escoje[accent] tu nombre de jugador[] primero. +noname = Elige un[accent] nombre de jugador[] primero. filename = Nombre del archivo: unlocked = ¡Nuevo Bloque Desbloqueado! completed = [accent]Completado -techtree = Árbol tecnologico -research.list = [LIGHT_GRAY]Lista de investigación: +techtree = Árbol de Tecnologías +research.list = [LIGHT_GRAY]investigación: research = Investigación -researched = [LIGHT_GRAY]{0} Investigado. -players = {0} jugadores en linea -players.single = {0} jugador en linea +researched = [LIGHT_GRAY]{0} investigado. +players = {0} jugadores online +players.single = {0} jugador online server.closing = [accent]Cerrando servidor... server.kicked.kick = ¡Has sido expulsado del servidor! server.kicked.serverClose = El servidor ha cerrado. -server.kicked.clientOutdated = ¡Cliente desactualizado! ¡Actualiza el juego! +server.kicked.vote = You have been vote-kicked. Goodbye. +server.kicked.clientOutdated = ¡Cliente desactualizado! ¡Actualiza tu juego! server.kicked.serverOutdated = ¡Servidor desactualizado! ¡Pídele al anfitrión que lo actualice! server.kicked.banned = Has sido baneado del servidor. +server.kicked.typeMismatch = This server is not compatible with your build type. server.kicked.recentKick = Has sido expulsado recientemente.\nEspera para poder conectarte de nuevo. server.kicked.nameInUse = Ya hay alguien con ese\nnombre en el servidor. server.kicked.nameEmpty = Tu nombre debe por lo menos contener un carácter o número. server.kicked.idInUse = ¡Ya estás en el servidor! Conectarse con dos cuentas no está permitido. server.kicked.customClient = Este servidor no soporta versiones personalizadas. Descarga una versión oficial. -server.kicked.gameover = Fin del juego! -server.versions = Tu versión:[accent] {0}[]\nVersión del servidor:[accent] {1}[] +server.kicked.gameover = ¡Fin del juego! +server.versions = Your version:[accent] {0}[]\nVersión del servidor:[accent] {1}[] host.info = El botón [accent]host[] hostea un servidor en el puerto [scarlet]6567[]. \nCualquier persona en la misma [LIGHT_GRAY]wifi o red local[] debería poder ver tu servidor en la lista de servidores.\n\nSi quieres que cualquier persona se pueda conectar de cualquier lugar por IP, la [accent]asignación de puertos[] es requerida.\n\n[LIGHT_GRAY]Nota: Si alguien experimenta problemas conectándose a tu partida LAN, asegúrate de permitir a Mindustry acceso a tu red local mediante la configuración de tu firewall. join.info = Aquí, puedes escribir la [accent]IP de un server[] para conectarte, o descubrir servidores de [accent]red local[] para conectarte.\nLAN y WAN es soportado para jugar en multijugador.\n\n[LIGHT_GRAY]Nota: No hay una lista automática global de servidores; si quieres conectarte por IP, tendrás que preguntarle al anfitrión por la IP. hostserver = Hostear Servidor @@ -88,10 +93,10 @@ trace = Rastrear Jugador trace.playername = Nombre de jugador: [accent]{0} trace.ip = IP: [accent]{0} trace.id = ID Única: [accent]{0} -trace.mobile = Cliente movíl: [accent]{0} +trace.mobile = Mobile Client: [accent]{0} trace.modclient = Cliente Personalizado: [accent]{0} invalidid = ¡ID de cliente inválida! Envía un informe del error. -server.bans = Expulsiones +server.bans = Baneos server.bans.none = ¡Ningún usuario ha sido baneado! server.admins = Administradores server.admins.none = ¡Ningún administrador ha sido encontrado! @@ -142,28 +147,33 @@ on = Encendido off = Apagado save.autosave = Autoguardado: {0} save.map = Mapa: {0} -save.wave = Horda {0} +save.wave = Oleada {0} save.difficulty = Dificultad: {0} save.date = Última vez guardado: {0} save.playtime = Tiempo de juego: {0} -warning = Advertencia. +warning = Aviso. confirm = Confirmar delete = Borrar ok = OK open = Abrir -customize = Customizar +customize = Personalizar cancel = Cancelar openlink = Abrir Enlace copylink = Copiar Enlace back = Atrás -classic.export = Exportar data clásica -classic.export.text = [accent]Mindustry[] acaba de tener una actualización importante.\nClásico (v3.5 build 40) data de mapa or guardado se han detectados. ¿Desea exportar estos archivos guardados a la carpeta de inicio de su teléfono?, para usar en la aplicación de Mindustry? +data.export = Export Data +data.import = Import Data +data.exported = Data exported. +data.invalid = This isn't valid game data. +data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. +classic.export = Export Classic Data +classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? quit.confirm = ¿Estás seguro de querer salir de la partida? -quit.confirm.tutorial = Are you sure you know what you're doing?\nThe tutorial can be re-taken in[accent] Settings->Game->Re-Take Tutorial.[] +quit.confirm.tutorial = ¿Estás seguro de que sabes qué estas haciendo?\nSe puede hacer el tutorial de nuevo in[accent] Ajustes->Juego->Volver a hacer tutorial.[] loading = [accent]Cargando... saving = [accent]Guardando... -wave = [accent]Horda {0} -wave.waiting = Horda en {0} +wave = [accent]Oleada {0} +wave.waiting = Oleada en {0} wave.waveInProgress = [LIGHT_GRAY]Oleada en progreso waiting = Esperando... waiting.players = Esperando jugadores... @@ -174,53 +184,53 @@ saveimage = Guardar Imagen unknown = Desconocido custom = Personalizado builtin = Incorporado -map.delete.confirm = ¿Estás seguro de querer borrar este mapa? ¡Recuerda que está acción no puede deshacerse! +map.delete.confirm = ¿Estás seguro de querer borrar este mapa? ¡Recuerda que está acción no se puede deshacer! map.random = [accent]Mapa Aleatorio -map.nospawn = ¡Este mapa no tiene ningún núcleo en el cual pueda aparecer el jugador! Agrega un núcleo[ROYAL] blue[] al mapa con el editor. +map.nospawn = ¡Este mapa no tiene ningún núcleo en el cual pueda aparecer el jugador! Agrega un núcleo[accent] orange[] [white]al mapa con el editor. map.nospawn.pvp = ¡Este mapa no tiene ningún núcleo enemigo para que aparezca el jugador! Añade un núcleo[SCARLET] red[] a este mapa en el editor. -map.nospawn.attack = ¡Este mapa no contiene ningún núcleo enemigo para que el jugador pueda atacar! Añade un núcleo[SCARLET] red[] a este mapa con el editor. +map.nospawn.attack = ¡Este mapa no tiene núcleos para que el jugador ataque! Añade núcleos[SCARLET] red[] a este mapa en el editor. map.invalid = Error cargando el mapa: archivo corrupto o inválido. editor.brush = Pincel editor.openin = Abrir en el Editor editor.oregen = Generación de Minerales editor.oregen.info = Generación de Minerales: -editor.mapinfo = Información del Mapa +editor.mapinfo = Info del Mapa editor.author = Autor: editor.description = Descripción: editor.waves = Oleadas: -editor.rules = Reglas: +editor.rules = Normas: editor.generation = Generación: -editor.ingame = Editor en el juego -editor.newmap = Nuevo mapa +editor.ingame = Editar dentro del juego +editor.newmap = Nuevo Mapa waves.title = Oleadas -waves.remove = Remover +waves.remove = Borrar waves.never = -waves.every = siempre +waves.every = cada waves.waves = oleada(s) -waves.perspawn = por punto de aparición -waves.to = a +waves.perspawn = por lugar de aparición +waves.to = hasta waves.boss = Jefe waves.preview = Vista previa waves.edit = Editar... -waves.copy = Copiar al portapapeles -waves.load = Pegar al portapapeles -waves.invalid = Oleadas invalidas en el portapapeles. +waves.copy = Copiar al Portapapeles +waves.load = Cargar del Portapapeles +waves.invalid = Oleadas inválidaas en el portapapeles. waves.copied = Oleadas copiadas. -waves.none = No hay enemigos definidos.\nTenga en cuenta que los diseños de oleada vacíos se reemplazarán automáticamente con el diseño predeterminado. +waves.none = No hay enemigos definidos.\nNótese que las listas de oleadas vacías se sustituirán por la lista por defecto. editor.default = [LIGHT_GRAY] edit = Editar... editor.name = Nombre: -editor.spawn = Unidad de aparición -editor.removeunit = Remover unidad +editor.spawn = Spawn Unit +editor.removeunit = Borrar Unidad editor.teams = Equipos -editor.errorload = Error cargando archivo:\n[accent]{0} -editor.errorsave = Error guardando archivo:\n[accent]{0} -editor.errorimage = Esa es una imagen, no un mapa. No vallas alrededor cambiando extensiones esperando a que funcionen.\n\nSi quieres importar un mapa de legado, use el botón 'importar mapa de legado' en el editor. -editor.errorlegacy = Este mapa es muy viejo, y usa un formato de mapa de legado que ya no es actualmente recuperable. -editor.errorheader = Este archivo de mapa o no es válido o esta corrupto. -editor.errorname = Este mapa no tiene nombre definido. -editor.update = Actializar -editor.randomize = Al azar +editor.errorload = Error cargando el archivo:\n[accent]{0} +editor.errorsave = Error guardando el archivo:\n[accent]{0} +editor.errorimage = Eso es una imagen, no un mapa. No cambies las extensiones del archivo esperando que funcione.\nSi quieres importar un mapa viejo, usa el botón de 'import legacy map' en el editor. +editor.errorlegacy = Este mapa es demasiado viejo y usa un formato de mapa que ya no es soportado. +editor.errorheader = Este mapa es inválido o está corrupto. +editor.errorname = El mapa no tiene un nombre definido. +editor.update = Actualizar +editor.randomize = Aleatorio editor.apply = Aplicar editor.generate = Generar editor.resize = Cambiar Tamaño @@ -250,54 +260,54 @@ editor.mapname = Nombre del Mapa: editor.overwrite = [accent]¡Advertencia!\nEsto sobrescribe un mapa ya existente. editor.overwrite.confirm = [scarlet]¡Advertencia![] Un mapa con ese nombre ya existe. ¿Estás seguro de querer sobrescribirlo? editor.selectmap = Selecciona un mapa para cargar: -toolmode.replace = Reemplazar -toolmode.replace.description = Dibuja solo en bloques sólidos. -toolmode.replaceall = Reemplazar todo -toolmode.replaceall.description = Reemplazar todos los bloques en este mapa. +toolmode.replace = Sustituir +toolmode.replace.description = Solo dibuja en bloques sólidos. +toolmode.replaceall = Sustituir Todo +toolmode.replaceall.description = Sustituye todos los bloques del mapa. toolmode.orthogonal = Ortogonal -toolmode.orthogonal.description = Dibuja solo líneas ortogonales. +toolmode.orthogonal.description = Solo dibuja líneas ortogonales. toolmode.square = Cuadrado -toolmode.square.description = Pincél en cuadrado. -toolmode.eraseores = Borrar minerales -toolmode.eraseores.description = Borrar solo minerales. -toolmode.fillteams = Llenar equipos -toolmode.fillteams.description = Llenar equipos en vez de bloques. -toolmode.drawteams = Dibuja equipos +toolmode.square.description = Pincel cuadrado. +toolmode.eraseores = Borrar Vetas +toolmode.eraseores.description = Solo borra vetas. +toolmode.fillteams = Llenar Equipos +toolmode.fillteams.description = Llena equipos en vez de bloques. +toolmode.drawteams = Dibujar Equipos toolmode.drawteams.description = Dibuja equipos en vez de bloques. -filters.empty = [LIGHT_GRAY]No hay filtros! Añade uno con el botón de abajo. +filters.empty = [LIGHT_GRAY]¡No hay filtros! Añade uno con el botón de abajo. filter.distort = Distorsionar filter.noise = Ruido -filter.median = Mediano -filter.oremedian = Mineral mediano -filter.blend = Mezclar -filter.defaultores = Mineral por defecto -filter.ore = Mineral -filter.rivernoise = Rio ruidoso +filter.median = Median +filter.oremedian = Ore Median +filter.blend = Mezcla +filter.defaultores = Vetas por defecto +filter.ore = Vetas +filter.rivernoise = River Noise filter.mirror = Espejo -filter.clear = Limpiar +filter.clear = Despejar filter.option.ignore = Ignorar filter.scatter = Dispersar filter.terrain = Terreno filter.option.scale = Escala filter.option.chance = Chance filter.option.mag = Magnitud -filter.option.threshold = Límite -filter.option.circle-scale = Escala circular -filter.option.octaves = Octavos -filter.option.falloff = Caída -filter.option.angle = Angúlo +filter.option.threshold = Umbral +filter.option.circle-scale = Escala del círculo +filter.option.octaves = Octaves +filter.option.falloff = Falloff +filter.option.angle = Ángulo filter.option.block = Bloque filter.option.floor = Suelo -filter.option.flooronto = Suelo objetivo +filter.option.flooronto = Target Floor filter.option.wall = Muro -filter.option.ore = Mineral -filter.option.floor2 = Suelo secundario -filter.option.threshold2 = Límite secundario +filter.option.ore = Veta +filter.option.floor2 = Secondary Floor +filter.option.threshold2 = Secondary Threshold filter.option.radius = Radio -filter.option.percentile = Percentil +filter.option.percentile = Porcentaje width = Ancho: height = Alto: -menu = Menu +menu = Menú play = Jugar campaign = Campaña load = Cargar @@ -308,35 +318,35 @@ ping = Ping: {0} ms language.restart = Por favor reinicie el juego para que los cambios del lenguaje surjan efecto. settings = Ajustes tutorial = Tutorial -tutorial.retake = Re-tomar Tutorial +tutorial.retake = Volver a hacer tutorial editor = Editor mapeditor = Editor de Mapa donate = Donar abandon = Abandonar -abandon.text = Esta zona y sus recursos se perderan al enemigo. +abandon.text = Esta zona y sus recursos se perderán ante el enemigo. locked = Bloqueado -complete = [LIGHT_GRAY]Complete: +complete = [LIGHT_GRAY]Completado: zone.requirement = Oleada {0} en la zona {1} -resume = Resumir la zona:\n[LIGHT_GRAY]{0} -bestwave = [LIGHT_GRAY]Mejor: {0} +resume = Continuar Zona:\n[LIGHT_GRAY]{0} +bestwave = [LIGHT_GRAY]Récord: {0} launch = Lanzar -launch.title = Lanzamiento exitoso -launch.next = [LIGHT_GRAY]proxima oportunidad a la oleada {0} -launch.unable2 = [scarlet]incapaz de LANZAR.[] -launch.confirm = Esto lanzara todos los recursos de tu base.\nYa no seras capaz de regresar aqui. -launch.skip.confirm = Si salteas ahora, no volveras a lanzarte hasta oleadas proximas. +launch.title = Lanzamiento Exitoso +launch.next = [LIGHT_GRAY]próxima oportunidad en la oleada {0} +launch.unable2 = [scarlet]No se puede LANZAR.[] +launch.confirm = Esto lanzará todos los recursos al núcleo.\nNo podrás volver a esta base. +launch.skip.confirm = Si saltas la oleada ahora, no podrás lanzar recursos hasta unas oleadas después. uncover = Descubrir -configure = Configurar cargado -configure.locked = [LIGHT_GRAY]Alcanza la oleada {0}\npara configurar tu cargado. +configure = Configurar carga inicial +configure.locked = [LIGHT_GRAY]Alcanza la oleada {0}\npara configurar la carga inicial. zone.unlocked = [LIGHT_GRAY]{0} desbloqueado. -zone.requirement.complete = Oleada {0} alcanzada:\n{1} requerimientos de la zona reunídos. -zone.config.complete = Oleada {0} alcanzada:\nConfiguración de cargado desbloqueado. -zone.resources = Recursos detectados: +zone.requirement.complete = Oleada {0} alcanzada:\nrequerimientos de la zona {1} cumplidos. +zone.config.complete = Oleada {0} alcanzada:\nconfiguración de carga inicial desbloqueada. +zone.resources = Recursos Detectados: zone.objective = [lightgray]Objetivo: [accent]{0} -zone.objective.survival = Sobrevive -zone.objective.attack = Destruye al núcleo enemigo +zone.objective.survival = Sobrevivir +zone.objective.attack = Destruir Núcleo Enemigo add = Añadir... -boss.health = Salud del jefe +boss.health = Salud del Jefe connectfail = [crimson]Ha fallado la conexión con el servidor: [accent]{0} error.unreachable = Servidor inaccesible. error.invalidaddress = Dirección inválida. @@ -344,38 +354,39 @@ error.timedout = ¡Se acabó el tiempo!\n¡Asegúrate que el host ha hecho el po error.mismatch = Error de paquete:\nposible versión no válida del servidor/cliente.\nAsegúrate de que tú y el host tenéis la última versión de Mindustry. error.alreadyconnected = Ya estás conectado. error.mapnotfound = ¡Archivo de mapa no encontrado! -error.io = Error de red I/O. +error.io = Error I/O de conexión. error.any = Error de red desconocido. -error.bloom = Falló al iniziar resplandor.\nTu dispositivo no trabaja con esto al parecer. -zone.groundZero.name = Zona de impacto -zone.desertWastes.name = Desechos del desierto -zone.craters.name = Los crateres -zone.frozenForest.name = Bosque congelado -zone.ruinousShores.name = Costas arruinadas -zone.stainedMountains.name = Montañas manchadas -zone.desolateRift.name = Grieta desolada -zone.nuclearComplex.name = Complejo de producción nuclear -zone.overgrowth.name = Crecimiento excesivo -zone.tarFields.name = Campos petroliferos +error.bloom = Failed to initialize bloom.\nYour device may not support it. +zone.groundZero.name = Terreno Cero +zone.desertWastes.name = Ruinas del Desierto +zone.craters.name = Los Cráteres +zone.frozenForest.name = Bosque Congelado +zone.ruinousShores.name = Costas Ruinosas +zone.stainedMountains.name = Stained Mountains +zone.desolateRift.name = Grieta Desolada +zone.nuclearComplex.name = Complejo de Producción Nuclear +zone.overgrowth.name = Overgrowth +zone.tarFields.name = Campos de Alquitrán zone.saltFlats.name = Salinas zone.impact0078.name = Impacto 0078 zone.crags.name = Riscos -zone.fungalPass.name = Pase fúngico -zone.groundZero.description = La localizacíon optima para comenzar denuevo. Amenazas enemigas muy bajas. Algunos recursos.\nRecoje mucho cobre y plomo como sean posibles.\nMarchando!. -zone.frozenForest.description = Incluso aqui, cerca de las montañas, las esporas se esparcieron. Las temperaturas frigidas ya no los puede contener por mucho.\n\nComienza la aventura con poder. Cream generadores termicos. Aprende a usar a los reparadores. -zone.desertWastes.description = Estos desechos son vastos, impredecibles y entrecruzados con estructuras sectoriales abandonadas..\nCarbon presente en la región. Quemalo por poder o sintetiza grafito.\n\n[lightgray]Esta localizacion de aterrizaje no esta asegurada. -zone.saltFlats.description = En las afueras del desierto se encuentran las salinas. Se pueden encontrar pocos recursos en esta ubicación.\n\nEl enemigo ha dirigido un complejo de almacenamiento de recursos aquí. Erradicar su núcleo. No dejes nada en pie aqui. -zone.craters.description = El agua se ha acumulado en este cráter, reliquia de las viejas guerras. Recuperar el área. Recoge arena. Fundir cristal meta. Bombea agua para enfriar torretas y taladros. -zone.ruinousShores.description = Más allá de los desechos, es la costa. Una vez, esta ubicación albergó una matriz de defensa costera. No queda mucho de eso. Solo las estructuras de defensa más básicas han permanecido indemnes, todo lo demás reducido a chatarra.\nContinue the expansion outwards. Rediscover the technology. -zone.stainedMountains.description = Más hacia el interior se encuentran las montañas, pero sin estar contaminadas por esporas.\nExtraiga el abundante titanio en esta área. Aprenda a usarlo.\n\nLa presencia del enemigo es mayor aquí. No les des tiempo para enviar sus unidades más fuertes.. -zone.overgrowth.description = This area is overgrown, closer to the source of the spores.\nThe enemy has established an outpost here. Build dagger units. Destroy it. Reclaim that which was lost. -zone.tarFields.description = Las afueras de una zona de producción de petróleo, entre las montañas y el desierto. Una de las pocas áreas con reservas de alquitrán utilizables.\nAunque abandonada, esta área tiene algunas fuerzas enemigas peligrosas cerca. No los subestimes.\n\n[lightgray]Investigue la tecnología de procesamiento de aceite si es posible. -zone.desolateRift.description = Una zona extremadamente peligrosa. Abundantes recursos, pero poco espacio. Alto riesgo de destrucción. Vete lo antes posible. No te dejes engañar por el largo espacio entre los ataques enemigos. -zone.nuclearComplex.description = Una antigua instalación para la producción y procesamiento de torio, reducida a ruinas.\n[lightgray]Investigue el torio y sus múltiples usos.\n\nEl enemigo está presente aquí en grandes cantidades, constantemente buscando atacantes. -zone.fungalPass.description = Un área de transición entre altas montañas y tierras bajas y esporas. Aquí se encuentra una pequeña base de reconocimiento enemiga.\nDestruyela.\nUsa unidades de dagas y rastreadoras. Elimina los dos núcleos. -zone.impact0078.description = -zone.crags.description = -settings.language = Lenguaje +zone.fungalPass.name = Fungal Pass +zone.groundZero.description = La zona óptima para empear una vez más. Riesgo bajo de los enemigos. Pocos recursos.\nConsigue tanto plomo y cobre como puedas.\nSigue avanzando. +zone.frozenForest.description = Incluso aquí, cerca de las montañas, las esporas se han expandido. Las temperaturas gélidas no pueden contenerlas para siempre.\n\nEmpieza a investigar sobre energía. Cnstruye generadores de combustión. Aprende a usar reparadores. +zone.desertWastes.description = Estas ruinas son vastas, impredecibles y entrecruzadas con sectores de estructuras abandonadas.\nHay carbñon presente en la región. Quémalo para energía, o sintetiza grafito.\n\n[lightgray]La zona de aparición no puede ser garantizada. +zone.saltFlats.description = A las afueras del desierto se encuentran las Salinas. Pocos recursos pueden ser encontrados en esta ubicación.\n\nEl enemigo ha erigido un complejo de almacén de recursos aquí. Erradica su núcleo. No dejes nada. +zone.craters.description = Se ha acumulado agua en este cráter, reliquia de las guerraas antiguas. Reconquista la zona. Obtén arena. Funde metacristal. Bombea agua para refrigerar torres y taladros. +zone.ruinousShores.description = Después de las ruinas viene la costa. Una vez este lugar hospedaba a una defensa de cosa. No queda mucho de ella. Solo las estructuras defensivas más básicas se han mantenido intactas, tolo lo demás ha sido reducido a chatarra. Continúa la expansión hacia fuera. Redescubre la tecnología. +zone.stainedMountains.description = Más hacia dentro están las montañas, todavía sin esporas. Extrae el abundante titanio en esta zona. Aprende cómo usarlo.\n\nLa presencia de enemigos es mayor aquí. No les dejes tiempo a que envíen sus unidades más fuertes. +zone.overgrowth.description = Este área está cubierta, más cerca de la fuente de esporas.\nEl enemigo ha establecido un puesto aquí. Construye unidades daga. Destrúyelo. Reconquista lo que se perdió. +zone.tarFields.description = Las afueras de una zona de producción de petróleo, entre las montañas y el desierto. Una de las pocas zonas con reservas utilizables de alquitrán natural.\nAunque abandonada, esta zona tiene esta zona tiene algunas fuerzas enemigas peligrosas. No las subestimes.\n\n[lightgray]Investiga tecnología de procesamiento de petróleo si es posible. +zone.desolateRift.description = Una zona extremadamente peligrosa. Tiene muchos recursos pero poco espacio. Riesgo alto de destrucción. Abandona lo antes posible. No te dejes engañar por la gran separación de tiempo entre oleadas enemigas. +zone.nuclearComplex.description = Una antigua facilidad para la producción y el procesamiento del torio reducido a ruinas.\n[lightgray]Investiga el torio y sus diversos usos.\n\nEl enemigo está presente en números grandes, constantemente buscando atacantes. +zone.fungalPass.description = Una zona transitoria entre alta montaña y zonas más bajas con esporas. Una base enemiga pequeña de reconocimiento se ubica aquí.\nDestrúyela.nUsa Dagas y Orugas. Destruye los dos núcleos. +zone.impact0078.description = +zone.crags.description = +settings.language = Idioma +settings.data = Game Data settings.reset = Reiniciar por los de defecto settings.rebind = Reasignar settings.controls = Controles @@ -393,19 +404,19 @@ no = No info.title = [accent]Información error.title = [crimson]Un error ha ocurrido. error.crashtitle = Un error ha ocurrido. -attackpvponly = [scarlet]Solo disponibles en modos JcJ o Ataque +attackpvponly = [scarlet]Solo disponible en los modos de Ataque/PvP blocks.input = Entrada blocks.output = Salida -blocks.booster = Bonificador +blocks.booster = Potenciador block.unknown = [LIGHT_GRAY]??? blocks.powercapacity = Capacidad de Energía blocks.powershot = Energía/Disparo -blocks.damage = Damage +blocks.damage = Daño blocks.targetsair = Apunta al Aire -blocks.targetsground = Apunta al suelo +blocks.targetsground = Apunta a Tierra blocks.itemsmoved = Velocidad de movimiento blocks.launchtime = Tiempo entre lanzamientos -blocks.shootrange = Rango +blocks.shootrange = Rango de Disparo blocks.size = Tamaño blocks.liquidcapacity = Capacidad de Líquidos blocks.powerrange = Rango de Energía @@ -414,41 +425,41 @@ blocks.powerdamage = Energía/Daño blocks.itemcapacity = Capacidad de Objetos blocks.basepowergeneration = Generación de energía base blocks.productiontime = Tiempo de producción -blocks.repairtime = Tiempo de reparación completa del bloque -blocks.speedincrease = Incremento de velocidad +blocks.repairtime = Tiempo para Reparar Bloque Completamente +blocks.speedincrease = Aumento de Velocidad blocks.range = Rango blocks.drilltier = Taladrables blocks.drillspeed = Velocidad Base del Taladro -blocks.boosteffect = Efecto bonificador -blocks.maxunits = Unidades activas máximas +blocks.boosteffect = Efecto del Potenciador +blocks.maxunits = Máximo de Unidades Activas blocks.health = Vida blocks.buildtime = Tiempo de construcción blocks.inaccuracy = Imprecisión blocks.shots = Disparos blocks.reload = Recarga blocks.ammo = Munición -bar.drilltierreq = Se requiere mejor taladro -bar.drillspeed = Melocidad de minado: {0}/s +bar.drilltierreq = Se requiere un mejor taladro. +bar.drillspeed = Velocidad del Taladro: {0}/s bar.efficiency = Eficiencia: {0}% -bar.powerbalance = Poder: {0} -bar.poweramount = Poder: {0} -bar.poweroutput = Poder de salida: {0} -bar.items = Objetos: {0} -bar.liquid = Liquido +bar.powerbalance = Energía: {0} +bar.poweramount = Energía: {0} +bar.poweroutput = Salida de Energía: {0} +bar.items = Items: {0} +bar.liquid = Líquido bar.heat = Calor -bar.power = Poder +bar.power = Energía bar.progress = Progreso de construcción bar.spawned = Unidades: {0}/{1} -bullet.damage = [stat]{0}[lightgray] Daño -bullet.splashdamage = [stat]{0}[lightgray] Daño en area ~[stat] {1}[lightgray] casillas -bullet.incendiary = [stat]incendiario -bullet.homing = [stat]rastreo -bullet.shock = [stat]electrizante -bullet.frag = [stat]exparcimiento -bullet.knockback = [stat]{0}[lightgray] empuje -bullet.freezing = [stat]congelado -bullet.tarred = [stat]embarrado -bullet.multiplier = [stat]{0}[lightgray]x multiplicador de armadura +bullet.damage = [stat]{0}[lightgray] daño +bullet.splashdamage = [stat]{0}[lightgray] daño de área ~[stat] {1}[lightgray] casillas +bullet.incendiary = [stat]incendiaria +bullet.homing = [stat]homing +bullet.shock = [stat]shock +bullet.frag = [stat]frag +bullet.knockback = [stat]{0}[lightgray] knockback +bullet.freezing = [stat]freezing +bullet.tarred = [stat]tarred +bullet.multiplier = [stat]{0}[lightgray]x multiplicador de munición bullet.reload = [stat]{0}[lightgray]x recarga unit.blocks = bloques unit.powersecond = unidades de energía/segundo @@ -458,7 +469,7 @@ unit.liquidunits = unidades de líquido unit.powerunits = unidades de energía unit.degrees = grados unit.seconds = segundos -unit.persecond = /segundos +unit.persecond = /sec unit.timesspeed = x velocidad unit.percent = % unit.items = objetos @@ -469,119 +480,121 @@ category.items = Objetos category.crafting = Fabricación category.shooting = Disparo category.optional = Mejoras Opcionales -setting.landscape.name = Bloquear portaretrato +setting.landscape.name = Lock Landscape setting.shadows.name = Sombras -setting.linear.name = Filtro linear -setting.animatedwater.name = Agua animada -setting.animatedshields.name = Escudos animados -setting.antialias.name = Antialias[LIGHT_GRAY] (requiere reinicio)[] -setting.indicators.name = Indicador aliado +setting.linear.name = Linear Filtering +setting.animatedwater.name = Agua Animada +setting.animatedshields.name = Escudos Animados +setting.antialias.name = Antialias[LIGHT_GRAY] (requires restart)[] +setting.indicators.name = Indicadores de Aliados setting.autotarget.name = Auto apuntado setting.keyboard.name = Controles de Ratón+Teclado setting.fpscap.name = Máx FPS setting.fpscap.none = Nada setting.fpscap.text = {0} FPS -setting.uiscale.name = Escalamiento de UI[lightgray] (require reinicio)[] -setting.swapdiagonal.name = Siempre poner en diagonal +setting.uiscale.name = Escala de IU[lightgray] (necesita reinicio)[] +setting.swapdiagonal.name = Siempre Colocar Diagonalmente setting.difficulty.training = entrenamiento setting.difficulty.easy = fácil setting.difficulty.normal = normal setting.difficulty.hard = difícil -setting.difficulty.insane = enfermizo +setting.difficulty.insane = locura setting.difficulty.name = Dificultad: setting.screenshake.name = Movimiento de la Pantalla setting.effects.name = Mostrar Efectos setting.sensitivity.name = Sensibilidad del Control -setting.saveinterval.name = Intervalo del Auto-guardado +setting.saveinterval.name = Intervalo del Autoguardado setting.seconds = {0} Segundos setting.fullscreen.name = Pantalla Completa -setting.borderlesswindow.name = Bordeado de ventana[LIGHT_GRAY] (requeire reiniciado) +setting.borderlesswindow.name = Ventana sin Bordes[LIGHT_GRAY] (podría requerir un reinicio) setting.fps.name = Mostrar FPS setting.vsync.name = VSync setting.lasers.name = Mostrar Energía de los Láseres -setting.pixelate.name = Pixelar [LIGHT_GRAY](quisas disminuya el improvisamiento) +setting.pixelate.name = Pixelar [LIGHT_GRAY](podría reducir el rendimiento) setting.minimap.name = Mostrar Minimapa setting.musicvol.name = Volumen de la Música -setting.ambientvol.name = Volumen Ambiental +setting.ambientvol.name = Volumen del Ambiente setting.mutemusic.name = Silenciar Musica setting.sfxvol.name = Volumen de los efectos de sonido setting.mutesound.name = Silenciar Sonido setting.crashreport.name = Enviar informes de fallos anónimos -setting.chatopacity.name = Opacidad del chat -setting.playerchat.name = Mostrar chat durante el juego -uiscale.reset = La escala del UI cambió.\nPresiona "OK" para confirmar estos cambios.\n[scarlet]Revertir y salir en[accent] {0}[] opciones... -uiscale.cancel = Cancelar y salir -setting.bloom.name = Destello -keybind.title = Reasignar Teclas -keybinds.mobile = [scarlet]Muchos atajos de tecla no funcionan en movíl. Solo el movimiento basico es funcional. +setting.savecreate.name = Auto-Create Saves +setting.chatopacity.name = Opacidad del Chat +setting.playerchat.name = Display In-Game Chat +uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] seconds... +uiscale.cancel = Cancel & Exit +setting.bloom.name = Bloom +keybind.title = Rebind Keys +keybinds.mobile = [scarlet]Most keybinds here are not functional on mobile. Only basic movement is supported. category.general.name = General category.view.name = Visión category.multiplayer.name = Multijugador command.attack = Atacar command.retreat = Retirarse command.patrol = Patrullar -keybind.gridMode.name = Selecionar bloque -keybind.gridModeShift.name = Selecionar categoria +keybind.gridMode.name = Selección de Bloque +keybind.gridModeShift.name = Selección de Categoría keybind.press = Presiona una tecla... keybind.press.axis = Pulsa un eje o botón... -keybind.screenshot.name = Fotografiar mapa +keybind.screenshot.name = Captura de pantalla de Mapa keybind.move_x.name = Mover x keybind.move_y.name = Mover y +keybind.fullscreen.name = Toggle Fullscreen keybind.select.name = Seleccionar -keybind.diagonal_placement.name = Poner en diagonal -keybind.pick.name = Escojer bloque -keybind.break_block.name = Romper bloque +keybind.diagonal_placement.name = Construcción Diagonal +keybind.pick.name = Pick Block +keybind.break_block.name = Destruir Bloque keybind.deselect.name = Deseleccionar keybind.shoot.name = Disparar keybind.zoom_hold.name = Mantener Zoom keybind.zoom.name = Zoom -keybind.menu.name = Menu +keybind.menu.name = Menú keybind.pause.name = Pausa keybind.minimap.name = Minimapa keybind.dash.name = Correr keybind.chat.name = Chat keybind.player_list.name = Lista de jugadores -keybind.console.name = consola +keybind.console.name = Consola keybind.rotate.name = Rotar keybind.toggle_menus.name = Alternar menús keybind.chat_history_prev.name = Historial de chat anterior keybind.chat_history_next.name = Historial de chat siguiente -keybind.chat_scroll.name = Arrastre del chat -keybind.drop_unit.name = Lanzar unidad +keybind.chat_scroll.name = Chat scroll +keybind.drop_unit.name = drop unit keybind.zoom_minimap.name = Zoom minimapa mode.help.title = Descripción de modos mode.survival.name = Supervivencia -mode.survival.description = El modo común. Recursos limitados y oleadas entrantes automáticas. -mode.sandbox.name = Caja de arena -mode.sandbox.description = Recursos ilimitados y sin temporizador para las hordas. +mode.survival.description = El modo normal. Recursos limitados y oleadas automáticas. +mode.sandbox.name = Sandbox +mode.sandbox.description = Recursos ilimitados y sin temporizador para las oleadas. mode.pvp.name = PvP mode.pvp.description = Pelea contra otros jugadores localmente. mode.attack.name = Attack -mode.attack.description = No hay oleadas, solo la meta de destruir la base. -mode.custom = Reglas por defecto -rules.infiniteresources = Recursos infinitos -rules.wavetimer = Tiempo de oleadas -rules.waves = oleadas -rules.attack = Modo de ataque -rules.enemyCheat = Infinitos recursos de la inteligencia artificial -rules.unitdrops = Lanzamientos de unidades -rules.unitbuildspeedmultiplier = Multiplicador de la velocidad de creacion de unidades. -rules.unithealthmultiplier = Multiplicador de salud de unidades -rules.playerhealthmultiplier = Multiplicador de la salud del jugador +mode.attack.description = No hay oleadas, el objetivo es destruir la base enemiga. +mode.custom = Normas personalizadas +rules.infiniteresources = Recursos Infinitos +rules.wavetimer = Temportzador de Oleadas +rules.waves = Oleadas +rules.attack = Modo de Ataque +rules.enemyCheat = Recursos infinitos de la IA +rules.unitdrops = REcursos de las Unidades +rules.unitbuildspeedmultiplier = Multiplicador de velocidad de creación de unidades +rules.unithealthmultiplier = Multiplicador de la vida de las unidades +rules.playerhealthmultiplier = Multiplicador de la vida del jugador rules.playerdamagemultiplier = Multiplicador del daño del jugador -rules.unitdamagemultiplier = Multiplicador del daño de las tropas -rules.enemycorebuildradius = Radio del núcleo enemigo sin construir:[LIGHT_GRAY] (casillas) -rules.respawntime = Tiempo de reaparición:[LIGHT_GRAY] (segundos) -rules.wavespacing = Espaciado de oleadas:[LIGHT_GRAY] (segundos) -rules.buildcostmultiplier = Multiplicador del costeo de edificacion -rules.buildspeedmultiplier = Multiplicador de la velocidad de edificacion -rules.waitForWaveToEnd = Esperar oleadas del enemigo -rules.dropzoneradius = Radio de la zona de lanzamiento:[LIGHT_GRAY] (casillas) -rules.respawns = Maximas reapariciones por oleada -rules.limitedRespawns = Reapariciones limitadas +rules.unitdamagemultiplier = Multiplicador del daño de unidades +rules.enemycorebuildradius = Radio de No-Construcción del Núcleo Enemigo:[LIGHT_GRAY] (casillas) +rules.respawntime = Tiempo de reaparición:[LIGHT_GRAY] (sec) +rules.wavespacing = Tiempo entre oleadas:[LIGHT_GRAY] (sec) +rules.buildcostmultiplier = Multiplicador de coste de construcción +rules.buildspeedmultiplier = Multiplicador de velocidad de construcción +rules.waitForWaveToEnd = Las oleadas esperan a los enemigos +rules.dropzoneradius = Drop Zone Radius:[LIGHT_GRAY] (tiles) +rules.respawns = Reapariciones máximas por oleada +rules.limitedRespawns = Límite de reapariciones rules.title.waves = Oleadas rules.title.respawns = Reapariciones -rules.title.resourcesbuilding = REcursos y construcciones. +rules.title.resourcesbuilding = Recursos y Construcción rules.title.player = Jugadores rules.title.enemy = Enemigos rules.title.unit = Unidades @@ -599,18 +612,18 @@ item.thorium.name = Torio item.silicon.name = Silicona item.plastanium.name = Plastanio item.phase-fabric.name = Tejido de fase -item.surge-alloy.name = Aleación de sobretensión -item.spore-pod.name = Vaina de esporas +item.surge-alloy.name = Aleación Eléctrica +item.spore-pod.name = Spore Pod item.sand.name = Arena item.blast-compound.name = Compuesto Explosivo item.pyratite.name = Pirotita -item.metaglass.name = Vidrio Meta +item.metaglass.name = Metacristal item.scrap.name = Chatarra liquid.water.name = Agua -liquid.slag.name = Fundido +liquid.slag.name = Slag liquid.oil.name = Petróleo liquid.cryofluid.name = Criogénico -mech.alpha-mech.name = Alfa +mech.alpha-mech.name = Alpha mech.alpha-mech.weapon = Repetidor Pesado mech.alpha-mech.ability = Enjambre de Drones mech.delta-mech.name = Delta @@ -621,115 +634,115 @@ mech.tau-mech.weapon = Láser de reestructuración mech.tau-mech.ability = Ráfaga de reparación mech.omega-mech.name = Omega mech.omega-mech.weapon = Enjambre de misiles -mech.omega-mech.ability = Configuracion blindada +mech.omega-mech.ability = Configuración de armadura mech.dart-ship.name = Dardo mech.dart-ship.weapon = Repetidor mech.javelin-ship.name = Jabalina mech.javelin-ship.weapon = Ráfaga de misiles -mech.javelin-ship.ability = Bonificador de descarga +mech.javelin-ship.ability = Potenciador de descarga mech.trident-ship.name = Tridente -mech.trident-ship.weapon = Bombardero +mech.trident-ship.weapon = Bomb Bay mech.glaive-ship.name = Glaive -mech.glaive-ship.weapon = Repetidor flamiguero +mech.glaive-ship.weapon = Repetidor de Llamas item.explosiveness = [LIGHT_GRAY]Explosividad: {0} item.flammability = [LIGHT_GRAY]Inflamabilidad: {0} item.radioactivity = [LIGHT_GRAY]Radioactividad: {0} unit.health = [LIGHT_GRAY]Vida: {0} unit.speed = [LIGHT_GRAY]Velocidad: {0} mech.weapon = [LIGHT_GRAY]Arma: {0} -mech.health = [LIGHT_GRAY]Salud: {0} +mech.health = [LIGHT_GRAY]Vida: {0} mech.itemcapacity = [LIGHT_GRAY]Capacidad de objetos: {0} mech.minespeed = [LIGHT_GRAY]Velocidad de minado: {0} mech.minepower = [LIGHT_GRAY]Potencia de minado: {0} -mech.ability = [LIGHT_GRAY]Habilidad: {0} -mech.buildspeed = [LIGHT_GRAY]Building Speed: {0}% +mech.ability = [LIGHT_GRAY]Hablidad: {0} +mech.buildspeed = [LIGHT_GRAY]Velocidad de Construcción: {0}% liquid.heatcapacity = [LIGHT_GRAY]Capacidad Térmica: {0} liquid.viscosity = [LIGHT_GRAY]Viscosidad: {0} liquid.temperature = [LIGHT_GRAY]Temperatura: {0} -block.sand-boulder.name = Roca de arena -block.grass.name = Pasto +block.sand-boulder.name = Piedra de Arena +block.grass.name = Hierba block.salt.name = Sal -block.saltrocks.name = Rocas salinas -block.pebbles.name = Bolitas -block.tendrils.name = Zarcillos +block.saltrocks.name = Rocas de Sal +block.pebbles.name = Pebbles +block.tendrils.name = Tendrils block.sandrocks.name = Rocas de arena -block.spore-pine.name = Pinos de espora +block.spore-pine.name = Spore Pine block.sporerocks.name = Rocas de espora block.rock.name = Roca -block.snowrock.name = Roca de nieve -block.snow-pine.name = Pino de nieve -block.shale.name = Esquisto -block.shale-boulder.name = Roca de esquisto +block.snowrock.name = Snow Rock +block.snow-pine.name = Snow Pine +block.shale.name = Pizarra +block.shale-boulder.name = Piedra de Pizarra block.moss.name = Musgo block.shrubs.name = Arbustos block.spore-moss.name = Musgo de esporas -block.shalerocks.name = Rocas de esquistos -block.scrap-wall.name = Muro de chatarra -block.scrap-wall-large.name = Gran muro de chatarra -block.scrap-wall-huge.name = Enorme muro de chatarra -block.scrap-wall-gigantic.name = Gigantesco muro de chatarra -block.thruster.name = Propulsor +block.shalerocks.name = Rocas de Pizarra +block.scrap-wall.name = Muro de Chatarra +block.scrap-wall-large.name = Muro de Chatarra grande +block.scrap-wall-huge.name = Muro de Chatarra muy grande +block.scrap-wall-gigantic.name = Muro de Chatarra gigante +block.thruster.name = Thruster block.kiln.name = Horno block.graphite-press.name = Prensa de grafito -block.multi-press.name = Prensa multiple +block.multi-press.name = Multi-Prensa block.constructing = {0}\n[LIGHT_GRAY](Construyendo) block.spawn.name = Punto de generación -block.core-shard.name = Core: Fragmento -block.core-foundation.name = Core: Fundación -block.core-nucleus.name = Core: Núcleo +block.core-shard.name = Núcleo: Fragmento +block.core-foundation.name = Núcleo: Fundación +block.core-nucleus.name = Núcleo: Nucleus block.deepwater.name = Aguas profundas block.water.name = Agua -block.tainted-water.name = Agua contaminada -block.darksand-tainted-water.name = Arena negra de agua contaminada +block.tainted-water.name = Agua Contaminada +block.darksand-tainted-water.name = Dark Sand Tainted Water block.tar.name = Alquitrán block.stone.name = Piedra block.sand.name = Arena -block.darksand.name = Arena negra +block.darksand.name = Arena Oscura block.ice.name = Hielo block.snow.name = Nieve -block.craters.name = Craters -block.sand-water.name = Arena aguada -block.darksand-water.name = Arena oscura aguada -block.char.name = Carbonizado -block.holostone.name = Holo piedra -block.ice-snow.name = Hielo nieve +block.craters.name = Cráteres +block.sand-water.name = Arena Agua +block.darksand-water.name = Agua Arena Oscura +block.char.name = Char +block.holostone.name = Holo stone +block.ice-snow.name = Hielo Nieve block.rocks.name = Rocas block.icerocks.name = Rocas de hielo block.snowrocks.name = Rocas de nieve -block.dunerocks.name = Rocas de dunas +block.dunerocks.name = Dune Rocks block.pine.name = Pino -block.white-tree-dead.name = Arbol blanco muerto -block.white-tree.name = Arbol blanco -block.spore-cluster.name = Racimo de esporas -block.metal-floor.name = Suelo metalico -block.metal-floor-2.name = Suelo metalico 2 -block.metal-floor-3.name = Suelo metalico 3 -block.metal-floor-5.name = Suelo metalico 5 -block.metal-floor-damaged.name = Suelo metalico dañado -block.dark-panel-1.name = Panel oscuro 1 -block.dark-panel-2.name = Panel oscuro 2 -block.dark-panel-3.name = Panel oscuro 3 -block.dark-panel-4.name = Panel oscuro 4 -block.dark-panel-5.name = Panel oscuro 5 -block.dark-panel-6.name = Panel oscuro 7 -block.dark-metal.name = Metal oscuro -block.ignarock.name = Roca ignea -block.hotrock.name = Roca caliente -block.magmarock.name = Roca de magma -block.cliffs.name = Riscos -block.copper-wall.name = Muro de cobre -block.copper-wall-large.name = Muro de cobre grande -block.titanium-wall.name = Muro de titanio -block.titanium-wall-large.name = Muro de titanio grande +block.white-tree-dead.name = Árbol Blanco Muerto +block.white-tree.name = Árbol Blanco +block.spore-cluster.name = Concentración de Esporas +block.metal-floor.name = Suelo de Metal +block.metal-floor-2.name = Suelo de Metal 2 +block.metal-floor-3.name = Suelo de Metal 3 +block.metal-floor-5.name = Suelo de Metal 5 +block.metal-floor-damaged.name = Suelo de Metal dañado +block.dark-panel-1.name = Panel Oscuro 1 +block.dark-panel-2.name = Panel Oscuro 2 +block.dark-panel-3.name = Panel Oscuro 3 +block.dark-panel-4.name = Panel Oscuro 4 +block.dark-panel-5.name = Panel Oscuro 5 +block.dark-panel-6.name = Panel Oscuro 6 +block.dark-metal.name = Metal Oscuro +block.ignarock.name = Roca Igna +block.hotrock.name = Roca Caliente +block.magmarock.name = Roca de Magma +block.cliffs.name = Acantilados +block.copper-wall.name = Muro de Cobre +block.copper-wall-large.name = Muro de Cobre grande +block.titanium-wall.name = Muro de Titanio +block.titanium-wall-large.name = Muro de Titanio grande block.phase-wall.name = Muro de Fase grande block.phase-wall-large.name = Muro de Fase grande block.thorium-wall.name = Pared de Torio -block.thorium-wall-large.name = Pared de Torio grande +block.thorium-wall-large.name = Muro de Torio grande block.door.name = Puerta -block.door-large.name = Puerta Larga +block.door-large.name = Puerta Grande block.duo.name = Dúo -block.scorch.name = Quemador -block.scatter.name = Dispersión +block.scorch.name = Scorch +block.scatter.name = Scatter block.hail.name = Granizo block.lancer.name = Lancero block.conveyor.name = Cinta Transportadora @@ -745,24 +758,24 @@ block.pulverizer.name = Pulverizador block.cryofluidmixer.name = Mezclador de Criogénicos block.melter.name = Fundidor block.incinerator.name = Incinerador -block.spore-press.name = Prensa de esporas +block.spore-press.name = Prensa de Esporas block.separator.name = Separador -block.coal-centrifuge.name = Centrífuga de carbon +block.coal-centrifuge.name = Centrifugador de Carbón block.power-node.name = Nodo de Energía block.power-node-large.name = Nodo de Energía Grande -block.surge-tower.name = Torre de sobretensión +block.surge-tower.name = Surge Tower block.battery.name = Batería block.battery-large.name = Batería Grande block.combustion-generator.name = Generador de Combustión block.turbine-generator.name = Turbina -block.differential-generator.name = Grnerador diferencial -block.impact-reactor.name = Reactor de impacto +block.differential-generator.name = Generador Diferencial +block.impact-reactor.name = Reactor de Impacto block.mechanical-drill.name = Taladro mecánico block.pneumatic-drill.name = Taladro neumático -block.laser-drill.name = Taladro Laser +block.laser-drill.name = Taladro Láser block.water-extractor.name = Extractor de Agua block.cultivator.name = Cultivador -block.dart-mech-pad.name = Pad de mecanoide Dardo +block.dart-mech-pad.name = Pad de mecanoide Dart block.delta-mech-pad.name = Pad de mecanoide Delta block.javelin-ship-pad.name = Pad de nave Jabalina block.trident-ship-pad.name = Pad de nave Tridente @@ -783,23 +796,24 @@ block.swarmer.name = Enjambredor block.salvo.name = Salva block.ripple.name = Onda block.phase-conveyor.name = Cinta Transportadora de Fase -block.bridge-conveyor.name = Cinta Transportadora Puente +block.bridge-conveyor.name = Puente de Cinta Transportadora block.plastanium-compressor.name = Compresor de Plastanio block.pyratite-mixer.name = Mezclador de Pirotita block.blast-mixer.name = Mezclador de Explosivos block.solar-panel.name = Panel Solar block.solar-panel-large.name = Panel Solar Grande block.oil-extractor.name = Extractor de Petróleo -block.draug-factory.name = Fábrica de mineria de drones draug +block.command-center.name = Command Center +block.draug-factory.name = Fábrica de Drones Mineros Draug block.spirit-factory.name = Fábrica de Drones Espíritu block.phantom-factory.name = Fábrica de Drones Fantasmales -block.wraith-factory.name = Fábrica de peleador fantasma -block.ghoul-factory.name = Fábrica de bombardero ghoul -block.dagger-factory.name = Fábrica de Dagas -block.crawler-factory.name = Fábrica de rastreadores mecanoides -block.titan-factory.name = Fábrica de Titanes -block.fortress-factory.name = Fábrica de fortaleza mecanoide -block.revenant-factory.name = Fábrica de peleador revenant +block.wraith-factory.name = Fábrica de Wraith Fighter +block.ghoul-factory.name = Fábrica de Ghoul Bomber +block.dagger-factory.name = Fábrica de mecanoide Daga +block.crawler-factory.name = Fábrica de mecanoide Oruga +block.titan-factory.name = Fábrica de mecanoide Titán +block.fortress-factory.name = Fábrica de mecanoide Fortress +block.revenant-factory.name = Fábrica de Revenant Fighter block.repair-point.name = Punto de Reparación block.pulse-conduit.name = Conducto de Pulso block.phase-conduit.name = Conducto de Fase @@ -809,87 +823,87 @@ block.liquid-junction.name = Cruce de Líquidos block.bridge-conduit.name = Conducto Puente block.rotary-pump.name = Bomba Rotatoria block.thorium-reactor.name = Reactor de Torio -block.mass-driver.name = Teletransportador de Masa +block.mass-driver.name = Teletransportador Masivo block.blast-drill.name = Taladro de explosión block.thermal-pump.name = Bomba Térmica block.thermal-generator.name = Generador Térmico -block.alloy-smelter.name = Fundidor de aleación +block.alloy-smelter.name = Alloy Smelter block.mender.name = Reparador block.mend-projector.name = Proyector de reparación -block.surge-wall.name = Muro de sobretensión -block.surge-wall-large.name = Muro de sobretensión grande +block.surge-wall.name = Muro de Surge +block.surge-wall-large.name = Muro de Surge grande block.cyclone.name = Ciclón -block.fuse.name = Fusión -block.shock-mine.name = Mina electrica -block.overdrive-projector.name = Proyector de la sobremarcha +block.fuse.name = Fuse +block.shock-mine.name = Mina Shock +block.overdrive-projector.name = Proyector de sobremarcha block.force-projector.name = Proyector de fuerza block.arc.name = Arco block.rtg-generator.name = Generador RTG block.spectre.name = Espectro -block.meltdown.name = Fusión de reactor +block.meltdown.name = Meltdown block.container.name = Contenedor -block.launch-pad.name = Pad de lanzamiento -block.launch-pad-large.name = Pad de lanzamiento grande +block.launch-pad.name = Pad de Lanzamiento +block.launch-pad-large.name = Pad de Lanzammiento Grande team.blue.name = Azul -team.crux.name = Rojo -team.sharded.name = Fragmentado +team.crux.name = red +team.sharded.name = orange team.orange.name = Naranja -team.derelict.name = Abandonado +team.derelict.name = derelict team.green.name = Verde team.purple.name = Púrpura unit.spirit.name = Dron Espíritu unit.draug.name = Dron Minero Draug unit.phantom.name = Dron Fantasmal unit.dagger.name = Daga -unit.crawler.name = Rastreador +unit.crawler.name = Oruga unit.titan.name = Titán -unit.ghoul.name = Bombardero Ghoul -unit.wraith.name = Peleador fantasma -unit.fortress.name = Fortaleza +unit.ghoul.name = Ghoul Bomber +unit.wraith.name = Wraith Fighter +unit.fortress.name = Fortress unit.revenant.name = Revenant unit.eruptor.name = Eruptor -unit.chaos-array.name = Matriz del caos +unit.chaos-array.name = Chaos Array unit.eradicator.name = Erradicador unit.lich.name = Lich -unit.reaper.name = Segador -tutorial.next = [lightgray] -tutorial.intro = Acabas de entrar al[scarlet] tutorial de Mindustry.[]\nComienza por[accent] minar cobre[]. Toque una veta de mineral de cobre cerca de su núcleo para hacer esto.\n\n[accent]{0}/{1} copper +unit.reaper.name = Reaper +tutorial.next = [lightgray] +tutorial.intro = Has entrado en el[scarlet]Tutorial de Mindustry.[]\nComienza[accent]minando cobre[]. Toca en una veta de cobre cercana al núcleo para hacer esto.\n\n[accent]{0}/{1} cobre tutorial.drill = Minar manualmente es ineficiente.\nLos [accent]taladros pueden minar automáticamente.\nColoca uno en una veta de cobre. -tutorial.drill.mobile = La minería manual es ineficiente.\n[accent]Los taladros []puede minar automáticamente.\nToca la pestaña de exploración en la parte inferior derecha.\nSelecciona[accent] el taladro mecanico[].\nPonlo en una veta de cobre presionado sobre este, luego presione la[accent] marca de verificación[] a continuación para confirmar su selección.\nPresione el[accent] boton de X[] para cancelar la colocación. -tutorial.blockinfo = Cada bloque tiene diferentes estadísticas. Cada taladro solo puede extraer ciertos minerales.\nPara verificar la información y las estadísticas de un bloque,[accent] toque en el "?" botón mientras lo selecciona en el menú de construcción.[]\n\n[accent]Acceda ahora a las estadísticas del taladro mecánico.[] -tutorial.conveyor = Los [accent]Conveyors[] se usan para transportar objetos al núcleo.\nConstruye una línea de transportadores del taladro al núcleo. -tutorial.conveyor.mobile = [accent]Los transportadores[] se utilizan para transportar artículos al núcleo.\nHaga una línea de transportadores desde el taladro hasta el núcleo.\n[accent] Coloque en una línea manteniendo presionado el dedo durante unos segundos.[] y arrastrando en una dirección.\n\n[accent]{0}/{1} transportadores colocados en línea\n[accent]0/1 items entregados. +tutorial.drill.mobile = Minar manualmente es ineficiente.\nLos [accent]Taladros[] pueden minar automáticamente.\nToca la sección de taladros el la esquina de abajo a la derecha.\nSelecciona el[accent]taladro mecánico[].\nColócalo en una veta de cobre tocándola, después pulsa el [accent]botón de confirmación de debajo para confirmar tu selección.\nPulsa el[accent]botón "X" para cancelar la construcción. +tutorial.blockinfo = Cada bloque tiene diferentes estadísticas. Cada taladro solo puede minar ciertos minerales.\nPara comprobar la información y estadísticas de un bloque,[accent] toca el botón "?" mientras lo tienes seleccionado en el menú de construcción.[]\n\n[accent]Accede a las estadísticas del Taladro Mecánico ahora.[] +tutorial.conveyor = Las [accent]Cintas Transportadoras[] se usan para transportar recursos al núcleo.\nConstruye una línea de transportadores del taladro al núcleo. +tutorial.conveyor.mobile = Las [accent]Cintas Transportadoras[] se usan para transportar recursos al núcleo.\nConstruye una línea de transportadores del taladro al núcleo.\n[accent] Construye una línea manteniendo el dedo unos segundos[] y arrastrando hacia una dirección.\n\n[accet]{0}/{1} cintas colocadas en línea\n[ccent]]0/1 recursos transportados. tutorial.turret = Se tiene que construir estructuras defensivas para repeler el [LIGHT_GRAY]enemy[].\nConstruye una torreta dúo cerca de tu base. tutorial.drillturret = Los dúos requieren[accent] copper ammo[]para disparar.\nColoca un taladro junto a la torre para darle cobre. -tutorial.pause = Durante la batalla, puedes[accent] pausar el juego.[]\nPuede poner en cola edificios mientras está en pausa.\n\n[accent]Presione espacio para pausar. -tutorial.pause.mobile = Durante la batalla, puedes[accent] pausar el juego.[]\nPuede poner en cola edificios mientras está en pausa.\n\n[accent]Presione este botón en la esquina superior izquierda para pausar. -tutorial.unpause = Ahora presiona la barra espaciadora nuevamente para pausar. -tutorial.unpause.mobile = Ahora presiónelo nuevamente para pausar. -tutorial.breaking = Los bloques con frecuencia necesitan ser destruidos.\n[accent]Mantenga presionado el botón derecho[] para destruir todos los bloques en una selección.[]\n\n[accent]Destruye todos los bloques de chatarra a la izquierda de tu núcleo usando la selección de área. -tutorial.breaking.mobile = Los bloques con frecuencia necesitan ser destruidos.\n[accent]Seleccionar modo de deconstrucción[], luego toque un bloque para comenzar a romperlo.\nDestruye un área manteniendo presionado el dedo durante unos segundos.[] y arrastrar en una dirección.\nPresione el botón de marca de verificación para confirmar la ruptura.\n\n[accent]Destruye todos los bloques de chatarra a la izquierda de tu núcleo usando la selección de área. -tutorial.withdraw = En algunas situaciones, es necesario tomar elementos directamente de los bloques.\nPara hacer esto, [accent]toque un bloque[] con objetos dentro, entonces[accent]toque el objeto[] en el inventario.\nObjetos multiples se puede retirar[accent]tocando y manteniendo[].\n\n[accent]Retirar un poco de cobre del núcleo.[] -tutorial.deposit = Deposite artículos en bloques arrastrándolos desde su nave al bloque de destino.\n\n[accent]Deposita el cobre denuevo dentro del núcleo.[] -tutorial.waves = El[LIGHT_GRAY] enemigo[] se acerca.\n\nDefiende tu núcleo 2 hordas. Construye más torretas. -tutorial.waves.mobile = El[lightgray] enemigo[] se acerca.\n\nDefiende tu núcleo 2 hordas. Tu nave automaticamente le disparara a los enemigos.\nConstrulle mas torretas y taladros. Mina mas cobre. -tutorial.launch = Una vez alcances cierta oleada, seras capaz de[accent] lanzar el núcleo[], abandonando tus defensas y[accent] obteniendo todos los recursos en el núcleo.[]\nEstos recursos pueden ser utilizados para investigar nuevas tecnologias.\n\n[accent]Presiona el botón de lanzamiento. +tutorial.pause = Durante la batalla, puedes[accent]pausar el juego.[]\nPuedes dejar estructuras en cola mientras pausas.\n\n[accent]Pulsa Espacio para pausar. +tutorial.pause.mobile = During battle, you are able to[accent] pause the game.[]\nYou may queue buildings while paused.\n\n[accent]Press this button in the top left to pause. +tutorial.unpause = Ahora toca Espacio otra vez para dejar de pausar. +tutorial.unpause.mobile = Ahora tócalo otra vez para dejar de pausar. +tutorial.breaking = Muchas veces hace falta destruir bloques.\n[accent]Mantén el botón derecho[] para destruir todos los bloques en una selección.[]\n\n[accent]Destruye todos los bloques de chatarra de la izquierda de tu núcleo usando selección de área. +tutorial.breaking.mobile = Muchas veces hace falta destruir bloques.\n[accent]Selecciona el modo de desonstrucción[], después toca un bloque para comenzar a romperlo.\nDestruye un área manteniendo tu dedo algunos segundos[] y arrastrando hacia una dirección.\nUsa el botón de confirmación para confirmar la destrucción.\n\n[accent]Destruye todos los bloques de hatarra de la izquierda de tu núcleo usando selección de área.[] +tutorial.withdraw = En algunas situaciones, es necesario coger recursos directamente de bloques.\nPara hacer esto, [accent]toca un bloque[] con recursos en él, después [accent]toca el recurso[] en el inventario.\nSe pueden sacar múltiples recursos [accent]tocando y manteniendo[].\n\n[accent]Saca algo de cobre del núcleo.[] +tutorial.deposit = Deposita recursos en bloques arrastrándolos de tu nave al bloque de destino.\n\n[accent]Deposita tu cobre otra vez al núcleo.[] +tutorial.waves = El[LIGHT_GRAY] enemigo[] se acerca.\n\nDefiende tu núcleo por 2 oleadas. Construye más torretas y taladros. Mina más cobre. +tutorial.waves.mobile = El[lightgray] enemigo[] se acerca.\n\nDefiende tu núcleo por 2 oleadas. Tu nave disparará automáticamente a los enemigos.\nConstruye más torretas y taladros. Mina más cobre. +tutorial.launch = Una vez llegues a cierta oleada, podrás[accent]lanzar el núcleo[], dejando atrás tus defensas y los recursos en tu núcleo.[]\nEstos recursos pueden ser usados para investigar nueva tecnología.\n\n[accent]Pulsa el botón de lanzamiento. item.copper.description = Un útil material estructural. Usado extensivamente en todo tipo de bloques. item.lead.description = Un material básico. Usado extensivamente en electrónicos y bloques de transferencia de líquidos. -item.metaglass.description = Un compuesto de vidrio súper resistente. Ampliamente utilizado para la distribución y almacenamiento de líquidos. -item.graphite.description = Carbono mineralizado, utilizado para municiones y aislamiento eléctrico. -item.sand.description = Un material común que es usado extensivamente en la fundición, para alear y como fundente. +item.metaglass.description = Un compuesto muy duro de cristal. Usado extensivamente para almacenamiento y distribución de líquidos. +item.graphite.description = Carbón mineralizado, usasdo para munición y aislamiento eléctrico. +item.sand.description = Un material común que es usado extensivamente en la fundición, para aleaciones y como fundente. item.coal.description = Un combustible común y preparado para ser quemado. -item.titanium.description = Un metal raro super ligero usado extensivamente en transportación de liquidos, taladros y aeronaves. -item.thorium.description = Un metal radiactivo, muy denso usado en soporte de estructuras y combustible nuclear. -item.scrap.description = Restos de restos de estructuras y unidades antiguas. Contiene trazas de muchos metales diferentes. +item.titanium.description = Un metal raro muy ligero usado extensivamente en transportación de liquidos, taladros y aeronaves. +item.thorium.description = Un metal radiactivo, muy denso y usado en soporte de estructuras y combustible nuclear. +item.scrap.description = Restos de estructuras y unidades antiguas. Contiene pequeñas cantidades de muchos metales diferentes. item.silicon.description = Un semiconductor muy útil, se usa para paneles solares y muchos electrónicos complejos. -item.plastanium.description = Un material dúctil, ligero usado en aeronaves y proyectiles de fragmentación. +item.plastanium.description = Un material dúctil y ligero usado en aeronaves y proyectiles de fragmentación. item.phase-fabric.description = Una sustancia casi sin peso usada en electrónica avanzada y en tecnología autoreparadora. item.surge-alloy.description = Una aleación avanzada con propiedades eléctricas únicas. -item.spore-pod.description = Utilizado para la conversión en petróleo, explosivos y combustible. -item.blast-compound.description = Un compuesto volatil usado en bombas y explosivos. Aunque se puede quemar como combustible, esto no es recomendable. +item.spore-pod.description = Utilizado para ser convertido en petróleo, explosivos y combustible. +item.blast-compound.description = Un compuesto volátil usado en bombas y explosivos. Aunque se puede quemar como combustible, esto no es recomendable. item.pyratite.description = Una sustancia extremadamente inflamable usada en armas incendiarias. -liquid.water.description = Usado comúnmente para enfriar máquinas y para procesar residuos. -liquid.slag.description = Varios tipos diferentes de metal fundido se mezclan. Se puede separar en sus minerales constituyentes, o rociarse a las unidades enemigas como arma. +liquid.water.description = Usada comúnmente para enfriar máquinas y para procesar residuos. +liquid.slag.description = Diferentes tipos de metales fundidos mezclados. Puede ser separado en sus minerales constituyentes, o expulsado a unidades enemigas como arma. liquid.oil.description = Puede ser quemado, explotado o como un enfriador. liquid.cryofluid.description = El líquido más eficiente pra enfriar las cosas. mech.alpha-mech.description = El mecanoide estándar. Tiene velocidad y daño decentes, puede crear hasta 3 drones para poder ofensivo incremenado. @@ -900,51 +914,51 @@ mech.dart-ship.description = La nave normal. Bastante ligera y rápida, pero tie mech.javelin-ship.description = Una nave de ataque y retirada. Aunque inicialmente lento, puede acelerar a altas velocidades y volar sobre puestos enemigos, causando gran daño con su habilidad de rayos y misiles. mech.trident-ship.description = Un bombardero pesado. Razonablemente bien equipado. mech.glaive-ship.description = Una nave pistolera grande y bien armada. Equipada con un repetidor incendiario. Buena aceleración y velocidad máxima. -unit.draug.description = Un dron minero primitivo. Barato para producir. Reemplazable. Extrae automáticamente cobre y plomo en las cercanías. Entrega recursos minados al núcleo más cercano. -unit.spirit.description = El dron del comienzo. Aparece en el núcleo por defecto. Mina automáticamente minerales, recoge objetos y repara bloques. +unit.draug.description = Un dron minero primitivo. Barato de producir. Reciclable. Mina cobre y plomo cercanos automáticamente. Transporta los recursos minados al núcleo más cercano. +unit.spirit.description = Un dron draug modificaado, diseñado para reparar en vez de minar. Repara automáticamente cualquier bloque dañado en la zona. unit.phantom.description = Un dron avanzado. Mina automáticamente minerales, recoge objetos y repra bloques. Bastante más efectivo que un dron normal. -unit.dagger.description = Una unidad de terreno. Útil con enjambres. -unit.crawler.description = Una unidad terrestre que consiste en un marco despojado con altos explosivos atados en la parte superior. No es particularmente duradero. Explota al contacto con los enemigos. -unit.titan.description = Una unidad blindada de terreno, avanzada. Ataca blancos de aire y de terreno. +unit.dagger.description = Una unidad terrestre. Útil con enjambres. +unit.crawler.description = Una unidad terrestre que consiste en un marco desmontado con una gran cantidad de explosivos en la parte superior. No es muy duradero. Explota en contacto enemigo. +unit.titan.description = Una unidad terrestre blindada avanzada. Ataca objetivos aéreos y terrestres. unit.fortress.description = Una unidad terrestre pesada de artillería. -unit.eruptor.description = Un mecanoide pesado diseñado para derribar estructuras. Dispara una corriente de fundido a las fortificaciones enemigas, derritiéndolas y estableciendo volátiles en llamas. +unit.eruptor.description = Un mecanoide pesado diseñado para destruir estructuras. Dispara un líquido a las fortificaciones enemigas, fundiéndolas y quemando materiales volátiles. unit.wraith.description = Una unidad interceptora rápida. unit.ghoul.description = Una unidad bombardera pesada. Usa compuesto explosivo o pirotita como munición. -unit.revenant.description = Un pesado y flotante conjunto de misiles. -block.graphite-press.description = Comprime trozos de carbón en láminas puras de grafito. -block.multi-press.description = Una versión mejorada de la prensa de grafito. Emplea agua y energía para procesar carbón de manera rápida y eficiente. +unit.revenant.description = Una unidad aérea pesada con misiles. +block.graphite-press.description = Comprime carbón en piezas de grafito puro. +block.multi-press.description = Una versión mejorada de la prensa de grafito. Utiliza agua y energía para procesar carbón rápida y eficientemente. block.silicon-smelter.description = Reduce arena con coque de alta pureza para producir silicona. -block.kiln.description = Quema y fusiona arena y plomo en cristal meta. Requiere pequeñas cantidades de energía. +block.kiln.description = Funde arena y plomo en metacristal. Requiere cantidades pequeñas de energía. block.plastanium-compressor.description = Produce plastanio con aceite y titanio. -block.phase-weaver.description = Produce tejido de fase a partir de torio radiactivo y grandes cantidades de arena. -block.alloy-smelter.description = Produce "aleación de sobretensión" con titanio, plomo, silicona y cobre. -block.cryofluidmixer.description = Combina agua y titanio en líquido criogénico que es mucho más eficiente para enfriar. +block.phase-weaver.description = Produce tejido de fase del torio radioactivo y altas cantidades de arena. +block.alloy-smelter.description = Produce "surge alloy" con titanio, plomo, silicona y cobre. +block.cryofluidmixer.description = Combina agua y titanio en líquido criogénico, que es mucho más eficiente para enfriar. block.blast-mixer.description = Usa aceite para transformar pirotita en un objeto menos inflamable pero más explosivo: compuesto explosivo. block.pyratite-mixer.description = Mezcla carbón, plomo y arena en pirotita altamente inflamable. block.melter.description = Calienta piedra a temperaturas muy altas para obtener lava. block.separator.description = Expone piedra a la presión del agua para obtener diversos minerales contenidos en la piedra. -block.spore-press.description = Comprime las vainas de esporas en aceite. +block.spore-press.description = Comprime esporas en petróleo. block.pulverizer.description = Despedaza la piedra en arena. Útil cuando no hay arena natural. -block.coal-centrifuge.description = Solidifica el petróleo en trozos de carbón. -block.incinerator.description = Se deshace de cualquier líquido u objeto excesivo. +block.coal-centrifuge.description = Solidifica petróleo en piezas de carbón. +block.incinerator.description = Se deshace de cualquier líquido o material excesivo. block.power-void.description = Elimina toda la energía que se le da. Solo en sandbox. block.power-source.description = Da energía infinita. Solo en sandbox. block.item-source.description = Da objetos infinitos. Solo en sandbox. block.item-void.description = Destruye cuanquier objeto que va a él sin necesitar energía. Solo en sandbox. block.liquid-source.description = Da líquido infinito. Solo en sandbox. -block.copper-wall.description = Un bloque defensivo barato.\nÚtil para defneder e núcleo y las torres en las primeras hordas. -block.copper-wall-large.description = Un bloque defensivo barato.\nÚtil para defneder e núcleo y las torres en las primeras hordas.\nOcupa múltiples casillas. -block.titanium-wall.description = Un bloqueo defensivo moderadamente fuerte.\nProporciona protección moderada contra los enemigos. -block.titanium-wall-large.description = Un bloqueo defensivo moderado/fuerte.\nProporciona protección moderada/fuerte contra los enemigos.\nOcupa múltiples casillas. +block.copper-wall.description = Un bloque defensivo barato.\nÚtil para defender el núcleo y las torres en las primeras oleadas. +block.copper-wall-large.description = Un bloque defensivo barato.\nÚtil para defender el núcleo y las torres en las primeras oleadas.\nOcupa múltiples casillas. +block.titanium-wall.description = Un bloque defensivo moderadamente fuerte.\nProporciona protección moderada contra los enemigos. +block.titanium-wall-large.description = Un bloque defensivo moderadamente fuerte.\nProporciona protección moderada contra los enemigos.\nOcupa múltiples casillas. block.thorium-wall.description = Un bloque defensivo fuerte.\nBuena protección contra enemigos. block.thorium-wall-large.description = Un bloque defensivo fuerte.\nBuena protección contra enemigos.\nOcupa múltiples casillas. block.phase-wall.description = No es tan fuerte como un muro de torio pero rebota balas al enemigo si no son demasiado fuertes. block.phase-wall-large.description = No es tan fuerte como un muro de torio pero rebota balas al enemigo si no son demasiado fuertes.\nOcupa múltiples casillas. block.surge-wall.description = El bloque defensivo más fuerte.\nTiene una pequeña probabilidad de disparar rayos al atacante. block.surge-wall-large.description = El bloque defensivo más fuerte.\nTiene una pequeña probabilidad de disparar rayos al atacante.\nOcupa múltiplies casillas. -block.door.description = Una puerta pequeña que puede ser abierta y cerrada tocándola.\nSi está abirta, los enemigos pueden moverse y disparar a través de ella.\nOcupa múltiples casillas. +block.door.description = Una puerta pequeña que puede ser abierta y cerrada tocándola.\nSi está abirta, los enemigos pueden moverse y disparar a través de ella. block.door-large.description = Una puerta grande que puede ser abierta y cerrada tocándola.\nSi está abirta, los enemigos pueden moverse y disparar a través de ella.\nOcupa múltiples casillas. -block.mender.description = Periódicamente repara bloques en su vecindad. Mantiene las defensas reparadas entre olas.\nOpcionalmente utiliza silicio para aumentar el alcance y la eficiencia. +block.mender.description = Repara bloques cercanos periódicamente. Mantiene a las defensas reparadas entre oleadas.Puede usar silicona opcionalmente para mejorar el alcance y la eficiencia. block.mend-projector.description = Regenera edificios cercanos periódcamente. block.overdrive-projector.description = Aumenta la velocidad de edificios cercanos como taladros y transportadores. block.force-projector.description = Crea un área de fuerza hexagonal alrededor de él, protegiendo edificios y unidades dentro de él del daño de las balas. @@ -960,8 +974,8 @@ block.distributor.description = Un enrutador avanzado que distribuye objetos equ block.overflow-gate.description = Un enrutador que solo saca por la izquierda y la derecha si la cinta del frente está llena. block.mass-driver.description = El mejor bloque de transorte. Recoge varios objetos y los dispara a otro conductor de masa en un largo rango. block.mechanical-pump.description = Una bomba barata con extracción lenta, pero sin uso de energía. -block.rotary-pump.description = Una bomba avanzada que duplica la velocidad usando energía. -block.thermal-pump.description = La mejor bomba. Tres veces más rápido que la bomba mecánica, y la única bomba que puede extraer lava. +block.rotary-pump.description = Una bomba avanzada. Bombea más líquido, pero requiere energía. +block.thermal-pump.description = La mejor bomba. block.conduit.description = Bloque de transporte de líquidos básico. Funciona como un transportador, pero con líquidos. Usado con bombas, extractores u otros conductos. block.pulse-conduit.description = Bloque de transporte de líquidos avanzado. Transporta líquidos más rápidamente y almacena más que los conductos estándar. block.liquid-router.description = Acepta líquidos de una dirección y los deja en hasta 3 direcciones equitativamente. También puede amacenar cierta capacidad de líquido. Útil para dividir los líquidos de una fuente a varios objetivos. @@ -971,18 +985,18 @@ block.bridge-conduit.description = Bloque avanzado de transporte de líquidos. P block.phase-conduit.description = Bloque de transporte de líquidos avanzado. Usa energía para transportar líquidos a otro conducto de fase conectado por varias casillas. block.power-node.description = Transmite energía a nodos conectados, conecta hasta cuatro fuentes de energía, edificios que usan energía o nodos. El nodo obtendrá o transmitirá energía de cualquier bloque adyacente. block.power-node-large.description = Tiene un radio más amplio que el nodo de energía y conecta hasta seis fuentes de energía, edificios que usan energía o nodos. -block.surge-tower.description = Un nodo de alimentación de extremadamente largo alcance con menos conexiones disponibles. +block.surge-tower.description = Un nodo con un gran alcance con menos conexiones disponibles. block.battery.description = Guarda energía cuando hay abundancia y proporciona energía cuando hay escasez de energía mientras la batería tenga energía. block.battery-large.description = Almacena mucha más energía que una batería normal. block.combustion-generator.description = Genera energía quemando aceite o matteriales inflamables. block.thermal-generator.description = Genera una gran cantidad de energía con la lava. block.turbine-generator.description = Más eficiente que un generador de combustión, pero requiere agua adicional. -block.differential-generator.description = Genera grandes cantidades de energía. Utiliza la diferencia de temperatura entre el fluido criogenico y la quema de piratita. +block.differential-generator.description = Generates large amounts of energy. Utilizes the temperature difference between cryofluid and burning pyratite. block.rtg-generator.description = Un generador radioisótropo termoeléctrico que no necesita enfriamiento pero proporciona menos energía que un reactor de torio. block.solar-panel.description = Proporciona una pequeña cantidad de energía procedente del sol. block.solar-panel-large.description = Genera un mucho mejor suministro de energía que un panel solar estándar, pero también es mucho más caro de construir. block.thorium-reactor.description = Genera grandes cantidades de energía del torio altamente radioactivo. Necesita enfriamiento constante. Explotará violentamente si no se le aporta suficiente enfriamiento. -block.impact-reactor.description = Un generador avanzado, capaz de crear enormes cantidades de energía con la máxima eficiencia. Requiere una entrada de potencia significativa para iniciar el proceso. +block.impact-reactor.description = Un generador avanzado, capaz de crear cantidades masivas de energía a máxima eficiencia. Requiere una cantidad significante de energía para impulsar el comienzo del proceso. block.mechanical-drill.description = Un taladro barato. Cuando es colocado en casillas apropiadas, extrae objetos lentamente de forma indefinida. block.pneumatic-drill.description = Un taladro mejorado que es más rápido y puede obtener minerales más duros usando la presión. block.laser-drill.description = Permite obtener minerales incluso más rápido con la tecnología láser, pero requiere energía. Además, se puede obtener torio radioactivo con este taladro. @@ -990,17 +1004,17 @@ block.blast-drill.description = El mejor taladro. Requiere grandes cantidades de block.water-extractor.description = Extrae agua de la tierra. Úsalo cuando no haya lagos cercanos. block.cultivator.description = Cultiva la tierra para obtener biomateria. block.oil-extractor.description = Usa grandes cantidades de energía para extraer aceite de la arena. Úsalo cuando no hay fuentes directas de aceite cerca. -block.core-shard.description = La primera iteración de la cápsula central. Una vez destruido, se pierde todo contacto con la región. No dejes que esto suceda. +block.core-shard.description = La primera iteración de la cápsula del núcleo. Una vez destruido, todo el contacto con la región es perdido. No permitas que esto ocurra. block.core-foundation.description = La segunda versión del núcleo. Mejor blindado. Almacena más recursos. -block.core-nucleus.description = La tercera y última iteración de la cápsula central. Extremadamente bien blindado. Almacena cantidades masivas de recursos. +block.core-nucleus.description = La tercera y última iteración de la cápsula del núcleo. Muy bien blindado. Almacena cantidades masivas dde recursos. block.vault.description = Almacena una gran cantidad de objetos. Úsalo para crear almacenes cuando no hay una demanda constante de materales. Un [LIGHT_GRAY] unloader[] puede usarse para obtener objetos del almacén. block.container.description = Almacena una pequeña cantidad de objetos. Úsalo para crear almacenes cuando no hay una demanda constante de materales. Un [LIGHT_GRAY] unloader[] puede usarse para obtener objetos del contenedor. block.unloader.description = Descarga objetos de un contenedor, almacén o el núcleo a un transportador o directamente a un bloque adyacente. El tipo de objeto descargado puede ser cambiado tocando el descagador. -block.launch-pad.description = Lanza lotes de artículos sin necesidad de un lanzamiento central. Inconcluso. -block.launch-pad-large.description = Una versión mejorada de la plataforma de lanzamiento. Almacena más artículos. Se lanza con más frecuencia. +block.launch-pad.description = Lanza paquetes de recursos sin necesitar lanzar con el núcleo. +block.launch-pad-large.description = Una versión mejorada del pad de lanzamiento. Almacena más recursos y los lanza más frecuentemente. block.duo.description = Una torre pequeña y barata. -block.scatter.description = Una torreta antiaérea de tamaño mediano. Rocía grupos de plomo o chatarra en unidades enemigas. -block.scorch.description = Quema a cualquier enemigo terrestre cerca de él. Altamente efectivo a corta distancia. +block.scatter.description = Una torreta antiaérea de tamaño medio. Dispara fuego aéreo de plomo o chatarra a las unidades enemigas. +block.scorch.description = Quema a cualquier enemigo terrestre cercano a él. Altamente efectivo a corto alcance. block.hail.description = Una torre de artillería pequeña. block.wave.description = Una torre de tamaño mediano que dispara burbujas de líquido. block.lancer.description = Una torre de tamaño mediano que dispara rayos cargados eléctricamente. @@ -1012,21 +1026,22 @@ block.ripple.description = Una torre de artillería grande que dispara varios di block.cyclone.description = Una torre de disparo rápido grande. block.spectre.description = Una torre grande que dispara dos balas poderosas de una vez. block.meltdown.description = Una torre grande que dispara rayos poderosos de largo alcance. -block.draug-factory.description = Produce drones mineros "Draug". +block.command-center.description = Issues movement commands to allied units across the map.\nCauses units to patrol, attack an enemy core or retreat to the core/factory. When no enemy core is present, units will default to patrolling under the attack command. +block.draug-factory.description = Producedrones mineros Draug. block.spirit-factory.description = Produce drones ligeros que obtienen minerales y reparan bloques. block.phantom-factory.description = Produce drones avanzados que son significativamente más eficientes que un dron espíritu. block.wraith-factory.description = Produce unidades aéreas rápidas e interceptoras. block.ghoul-factory.description = Produce unidades bombarderas pesadas. block.revenant-factory.description = Produce unidades terrestres láser pesadas. block.dagger-factory.description = Produce unidades terrestres básicas. -block.crawler-factory.description = Produce unidades de ejambre de rapida destrucción. +block.crawler-factory.description = Produces fast self-destructing swarm units. block.titan-factory.description = Produce unidades terrestres avanzadas. block.fortress-factory.description = Produce unidades terrestres de artillería pesada. block.repair-point.description = Repara la unidad dañada más cercana a su alrededor. -block.dart-mech-pad.description = Proporciona transformación en un ataque básico..\nÚselo tocando mientras está parado sobre él. -block.delta-mech-pad.description = Deja tu nave actual y transfórmate en un mecanoide rápido y ligero hecho para ataques de emboscada y retirada.\nUsa el pad tocándolo dos veces mientras estás en él. -block.tau-mech-pad.description = Deja tu nave actual y transfórmate en un mecanoide de soporte que puede reparar construcciones y tropas aliadas.\nUsa el pad tocándolo dos veces mientras estás en él. -block.omega-mech-pad.description = Deja tu nave actual y transfórmate en un mecanoide pesado y bien armado, hecho para asaltos en primera línea.\nUsa el pad tocándolo dos veces mientras estás en él. -block.javelin-ship-pad.description = Deja tu nave actual y transfórmate en una unidad aérea fuerte y rápida interceptora con arma eléctrica.\nUsa el pad tocándolo dos veces mientras estás en él. -block.trident-ship-pad.description = Deja tu nave actual y transfórmate en una unidad aérea bombardera pesada.\nUsa el pad tocándolo dos veces mientras estás en él. -block.glaive-ship-pad.description = Deja tu nave actual y transfórmate en una unidad aérea grande y bien armada nave pistolera.\nUsa el pad tocándolo dos veces mientras estás en él. +block.dart-mech-pad.description = Proporciona transformación en un mecanoide de ataque básico.\nÚsalo tocándolo mientras estés en él. +block.delta-mech-pad.description = Proporciona transformación en un mecanoide rápido y ligero hecho para ataques de emboscada y retirada.\nUsa el pad tocándolo mientras estás en él. +block.tau-mech-pad.description = Proporciona transformación en un mecanoide de soporte que puede reparar construcciones y tropas aliadas.\nUsa el pad tocándolo mientras estás en él. +block.omega-mech-pad.description = Proporciona transformación en un mecanoide pesado y bien armado, hecho para asaltos en primera línea.\nUsa el pad tocándolo mientras estás en él. +block.javelin-ship-pad.description = Proporciona transformación en una unidad aérea fuerte y rápida interceptora con arma eléctrica.\nUsa el pad tocándolo mientras estás en él. +block.trident-ship-pad.description = Proporciona transformación en una unidad aérea bombardera pesada.\nUsa el pad tocándolo mientras estás en él. +block.glaive-ship-pad.description = Proporciona transformación en una unidad aérea grande y bien armada nave pistolera.\nUsa el pad tocándolo mientras estás en él. diff --git a/core/assets/bundles/bundle_et.properties b/core/assets/bundles/bundle_et.properties index fe226ace03..7c7835acc0 100644 --- a/core/assets/bundles/bundle_et.properties +++ b/core/assets/bundles/bundle_et.properties @@ -16,6 +16,11 @@ screenshot.invalid = Maailm liiga suur, tõenäoliselt pole piisavalt mälu salv gameover = Mäng Läbi gameover.pvp = [accent] {0}[] tiim võitis! highscore = [accent]Uus rekord! +load.sound = Sounds +load.map = Maps +load.image = Images +load.content = Content +load.system = System stat.wave = Raund:[accent] {0} stat.enemiesDestroyed = Vaenlasi hävitatud:[accent] {0} stat.built = Ehitisi ehitatud:[accent] {0} @@ -23,8 +28,6 @@ stat.destroyed = Ehitisi hävitatud:[accent] {0} stat.deconstructed = Ehitisi lahtivõetud:[accent] {0} stat.delivered = Materjale kaasa võetud: stat.rank = Lõplik Hinne: [accent]{0} -placeline = Sa valisid ehitise\nSa saad[accent] panna neid sirges reas[] hoides näpuga all ja, siis viibates mõnes suunas.\n\n[scarlet] TEE SEDA -removearea = Sa valisid hävitamise funktsiooni.\nsa saad[accent] hävitada[]hoides oma sõrme all mõne sekundi ja, siis viibates mõnele poole.\n\n[scarlet]TEE SEDA launcheditems = [accent]Kaasa võetud materjalid map.delete = Kas oled kindel, et soovid kustutada "[accent]{0}[]". level.highscore = Rekord: [accent]{0} @@ -63,9 +66,11 @@ players.single = {0} mängija mängus server.closing = [accent]Serveri sulgemine... server.kicked.kick = Sind visati serverist välja! server.kicked.serverClose = Server suletud. +server.kicked.vote = You have been vote-kicked. Goodbye. server.kicked.clientOutdated = Aegunud versioon! Uuenda oma mängu! server.kicked.serverOutdated = Aegunud server! Palu omanikul serverit uuendada! server.kicked.banned = Sul on keeld seal mängida. +server.kicked.typeMismatch = This server is not compatible with your build type. server.kicked.recentKick = Sind visati hiljuti välja.\nOota natuke enne uuesti proovimist. server.kicked.nameInUse = Keegi sellise nimega\non juba seal serveris. server.kicked.nameEmpty = Sinu valitud nimi ei sobi. @@ -156,6 +161,11 @@ cancel = Tühista openlink = Ava Link copylink = Kopeeri Link back = Tagasi +data.export = Export Data +data.import = Import Data +data.exported = Data exported. +data.invalid = This isn't valid game data. +data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. classic.export = Export Classic Data classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? quit.confirm = Oled kindel, et soovid lahkuda? @@ -376,6 +386,7 @@ zone.fungalPass.description = A transition area between high mountains and lower zone.impact0078.description = zone.crags.description = settings.language = Keel +settings.data = Game Data settings.reset = Reset to Defaults settings.rebind = Rebind settings.controls = Controls @@ -507,6 +518,7 @@ setting.mutemusic.name = Vaigista muusika setting.sfxvol.name = SFX Volume setting.mutesound.name = Mute Sound setting.crashreport.name = Send Anonymous Crash Reports +setting.savecreate.name = Auto-Create Saves setting.chatopacity.name = Chat Opacity setting.playerchat.name = Display In-Game Chat uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] seconds... @@ -527,6 +539,7 @@ keybind.press.axis = Press an axis or key... keybind.screenshot.name = Map Screenshot keybind.move_x.name = Move x keybind.move_y.name = Move y +keybind.fullscreen.name = Toggle Fullscreen keybind.select.name = Select/Shoot keybind.diagonal_placement.name = Diagonal Placement keybind.pick.name = Pick Block @@ -790,6 +803,7 @@ block.blast-mixer.name = Blast Mixer block.solar-panel.name = Solar Panel block.solar-panel-large.name = Large Solar Panel block.oil-extractor.name = Oil Extractor +block.command-center.name = Command Center block.draug-factory.name = Draug Miner Drone Factory block.spirit-factory.name = Spirit Drone Factory block.phantom-factory.name = Phantom Drone Factory @@ -1012,6 +1026,7 @@ block.ripple.description = A large artillery turret which fires several shots si block.cyclone.description = A large rapid fire turret. block.spectre.description = A large turret which shoots two powerful bullets at once. block.meltdown.description = A large turret which shoots powerful long-range beams. +block.command-center.description = Issues movement commands to allied units across the map.\nCauses units to patrol, attack an enemy core or retreat to the core/factory. When no enemy core is present, units will default to patrolling under the attack command. block.draug-factory.description = Produces Draug mining drones. block.spirit-factory.description = Produces light drones which mine ore and repair blocks. block.phantom-factory.description = Produces advanced drone units which are significantly more effective than a spirit drone. diff --git a/core/assets/bundles/bundle_fr.properties b/core/assets/bundles/bundle_fr.properties index 3a22a0a553..af8234d3b5 100644 --- a/core/assets/bundles/bundle_fr.properties +++ b/core/assets/bundles/bundle_fr.properties @@ -16,13 +16,11 @@ screenshot.invalid = La carte est trop large, il n'y a potentiellement pas assez gameover = Game over gameover.pvp = L'équipe [accent] {0}[] a gagnée ! highscore = [YELLOW]Nouveau meilleur score! - load.sound = Sonds load.map = Cartes load.image = Images load.content = Contenus load.system = Système - stat.wave = Vagues vaincues:[accent] {0} stat.enemiesDestroyed = Ennemis détruits:[accent] {0} stat.built = Bâtiments construits:[accent] {0} @@ -30,7 +28,6 @@ stat.destroyed = Bâtiments détruits:[accent] {0} stat.deconstructed = Bâtiments déconstruits:[accent] {0} stat.delivered = Ressources transférées: stat.rank = Rang Final: [accent]{0} - launcheditems = [accent]Ressources transférées map.delete = Êtes-vous sûr de supprimer cette carte "[accent]{0}[]"? level.highscore = Meilleur score: [accent]{0} @@ -257,13 +254,12 @@ editor.exportimage = Exporter l'image du terrain editor.exportimage.description = Exporter une image de la carte editor.loadimage = Importer le terrain editor.saveimage = Exporter le terrain -editor.unsaved = [scarlet]Vous avez des modifications non sauvegardés ![]\Voulez-vous vraiment quitter ? +editor.unsaved = [scarlet]Vous avez des modifications non sauvegardés ![]Voulez-vous vraiment quitter ? editor.resizemap = Redimensionner\nla carte editor.mapname = Nom de la carte: editor.overwrite = [accent]Attention !\nCeci réécrit une carte existante. editor.overwrite.confirm = [scarlet]Attention ![] Une carte avec ce nom existe déjà. Êtes-vous sûr de vouloir la réécrire? editor.selectmap = Sélectionnez une carte: - toolmode.replace = Remplacer toolmode.replace.description = Dessiner seulement sur les blocs solides. toolmode.replaceall = Tout remplacer @@ -278,7 +274,6 @@ toolmode.fillteams = Remplire les équipes toolmode.fillteams.description = Rempli les équipes au lieu de blocs. toolmode.drawteams = Dessiner les équipes toolmode.drawteams.description = Dessine les équipes au lieu de blocs. - filters.empty = [LIGHT_GRAY]Aucun filtre! Ajoutez-en un avec les boutons ci-dessous. filter.distort = Déformation filter.noise = Bruit @@ -310,7 +305,6 @@ filter.option.floor2 = Sol secondaire filter.option.threshold2 = Seuil secondaire filter.option.radius = Rayon filter.option.percentile = Centile - width = Largeur: height = Hauteur: menu = Menu @@ -328,7 +322,6 @@ tutorial.retake = Re-Take Tutorial editor = Éditeur mapeditor = Éditeur de carte donate = Faire un\ndon - abandon = Abandon abandon.text = Cette zone et toutes ses ressources vont être perdues. locked = Verrouillé @@ -354,7 +347,6 @@ zone.objective.survival = Survive zone.objective.attack = Détruire le noyau ennemi add = Ajouter... boss.health = Vie du Boss - connectfail = [crimson]Échec de la connexion au serveur : [accent]{0} error.unreachable = Serveur injoignable. error.invalidaddress = Adresse invalide. @@ -365,7 +357,6 @@ error.mapnotfound = Fichier de la carte introuvable! error.io = Erreur de Réseau (I/O) error.any = Erreur réseau inconnue error.bloom = Echec de l'initialisation du flou lumineux.\nVotre appareil peux ne pas le supporter. - zone.groundZero.name = Première Bataille zone.desertWastes.name = Décharge Désertique zone.craters.name = Les Cratères @@ -380,7 +371,6 @@ zone.saltFlats.name = Marais Salants zone.impact0078.name = Impact 0078 zone.crags.name = Rochers zone.fungalPass.name = Fungal Pass - zone.groundZero.description = L'emplacement optimal pour commencer. Faible menace ennemie. Peu de ressources. \nRecueillez autant de plomb et de cuivre que possible.\nBougez-vous. zone.frozenForest.description = Même ici, plus près des montagnes, les spores se sont propagées. Les températures glaciales ne pourront pas les contenir pour toujours.\n\nFamiliarisez vous avec l'Énergie. Construisez des generateurs a combustion. Aprenez a utiliser les réparateurs. zone.desertWastes.description = Ces déchets sont vastes, imprévisibles et se croisent avec des structures sectorielles abandonnées.\nLe charbon est présent dans la région. Brulew-le pour génerer de l'Énergie ou synthétisez-le en graphite.\n\n[lightgray]Ce lieu d'atterisage est imprévisible. @@ -395,7 +385,6 @@ zone.nuclearComplex.description = Une ancienne installation de production et de zone.fungalPass.description = A transition area between high mountains and lower, spore-ridden lands. A small enemy reconnaissance base is located here.\nDestroy it.\nUse Dagger and Crawler units. Take out the two cores. zone.impact0078.description = zone.crags.description = - settings.language = Langue settings.data = Données du Jeu settings.reset = Valeurs par défaut. @@ -449,7 +438,6 @@ blocks.inaccuracy = Précision blocks.shots = Tir blocks.reload = Tirs/Seconde blocks.ammo = Munitions - bar.drilltierreq = Meilleure Foreuse Requise bar.drillspeed = Vitesse de forage: {0}/s bar.efficiency = Efficacité: {0}% @@ -462,7 +450,6 @@ bar.heat = Chaleur bar.power = Énergie bar.progress = Progression de la construction bar.spawned = Unités: {0}/{1} - bullet.damage = [stat]{0}[lightgray] dgt bullet.splashdamage = [stat]{0}[lightgray] dgt de zone ~[stat] {1}[lightgray] tuiles bullet.incendiary = [stat]incendiaire @@ -474,7 +461,6 @@ bullet.freezing = [stat]gel bullet.tarred = [stat]Pétrolené bullet.multiplier = [stat]{0}[lightgray]x multiplicateur de munitions bullet.reload = [stat]{0}[lightgray]x rechargement - unit.blocks = blocs unit.powersecond = Énergie/seconde unit.liquidsecond = Liquides/seconde @@ -586,7 +572,6 @@ mode.pvp.description = Battez-vous contre d'autres joueurs en local.\n[gray]Requ mode.attack.name = Attaque mode.attack.description = Pas de vagues, le but étant de détruire la base ennemie.\n[gray]Requiert un noyaux rouge dans la map pour y jouer. mode.custom = Règles personnalisées - rules.infiniteresources = Ressources infinies rules.wavetimer = Minuterie pour les vagues rules.waves = Vagues @@ -613,7 +598,6 @@ rules.title.resourcesbuilding = Ressources & Constructions rules.title.player = Joueurs rules.title.enemy = Ennemis rules.title.unit = Unités - content.item.name = Objets content.liquid.name = Liquides content.unit.name = Unités @@ -675,7 +659,6 @@ mech.buildspeed = [LIGHT_GRAY]Vitesse de construction: {0}% liquid.heatcapacity = [LIGHT_GRAY]Capacité Thermique: {0} liquid.viscosity = [LIGHT_GRAY]Viscosité: {0} liquid.temperature = [LIGHT_GRAY]Température: {0} - block.sand-boulder.name = Bloc de sable block.grass.name = Herbe block.salt.name = Sel @@ -903,8 +886,6 @@ tutorial.deposit = Déposez des ressources dans des blocs en les faisant glisser tutorial.waves = L'[lightgray] ennemi[] approche.\n\nDefend le noyau pendant 2 vagues.[accent] Clique[] pour tirer.\nConstruisez plus de tourelles et de foreuses. Minez plus de cuivre. tutorial.waves.mobile = L'[lightgray] ennemi[] approche.\n\nDefend le noyau pendant 2 vagues. Votre vaisseau tirera automatiquement sur les ennemis.\nConstruisez plus de tourelles et de foreuses. Minez plus de cuivre. tutorial.launch = Une fois que vous aurez atteind une vague spécifique, vous aurez la possibilité de[accent] faire décoler le noyau[], abandonant vos défenses mais en [accent]sécurisant toutes les ressources de votre noyau.[]\nCes ressources peuvent ensuite être utilisées pour rechercher de nouvelles technologies.\n\n[accent]Appuyez sur le bouton de lancement. - - item.copper.description = Le matériau structurel de base. Utilisé intensivement dans tout les blocs. item.lead.description = Un matériau de départ. Utilisé intensivement en électronique et dans les blocs de trasports de liquides. item.metaglass.description = Un composé de vitre super-résistant. Utilisé largement pour le transport et le stockage de liquides. diff --git a/core/assets/bundles/bundle_fr_BE.properties b/core/assets/bundles/bundle_fr_BE.properties index cac937a5ee..71e5c21e8f 100644 --- a/core/assets/bundles/bundle_fr_BE.properties +++ b/core/assets/bundles/bundle_fr_BE.properties @@ -16,6 +16,11 @@ screenshot.invalid = Carte trop grande, potentiellement pas assez de mémoire po gameover = Le base a été détruite. gameover.pvp = L'équipe[accent] {0}[] a gagnée ! highscore = [accent]Nouveau meilleur score ! +load.sound = Sounds +load.map = Maps +load.image = Images +load.content = Content +load.system = System stat.wave = Vagues vaincues:[accent] {0} stat.enemiesDestroyed = Ennemies détruits:[accent] {0} stat.built = Bâtiments construits:[accent] {0} @@ -61,9 +66,11 @@ players.single = {0} joueur en ligne server.closing = [accent]Fermeture du serveur ... server.kicked.kick = Vous avez été expulsé du serveur ! server.kicked.serverClose = Serveur fermé. +server.kicked.vote = You have been vote-kicked. Goodbye. server.kicked.clientOutdated = Client dépassé! Mettez à jour votre jeu ! server.kicked.serverOutdated = Serveur dépassé! Demandez à l'hôte de le mettre à jour ! server.kicked.banned = Vous êtes banni de ce serveur. +server.kicked.typeMismatch = This server is not compatible with your build type. server.kicked.recentKick = Vous avez été expulsé récemment.\nAttendez avant de vous connecter à nouveau. server.kicked.nameInUse = Il y a déjà quelqu'un avec ce nom\nsur ce serveur. server.kicked.nameEmpty = Votre nom doit contenir au moins une lettre ou un chiffre. @@ -154,6 +161,11 @@ cancel = Annuler openlink = Ouvrir le lien copylink = Copier le lien back = Retour +data.export = Export Data +data.import = Import Data +data.exported = Data exported. +data.invalid = This isn't valid game data. +data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. classic.export = Export Classic Data classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? quit.confirm = Êtes-vous sûr de vouloir quitter? @@ -374,6 +386,7 @@ zone.fungalPass.description = A transition area between high mountains and lower zone.impact0078.description = zone.crags.description = settings.language = Langage +settings.data = Game Data settings.reset = Valeur par défaut. settings.rebind = Réatttribuer settings.controls = Contrôles @@ -505,6 +518,7 @@ setting.mutemusic.name = Couper la musique setting.sfxvol.name = Volume des SFX setting.mutesound.name = Couper les SFX setting.crashreport.name = Envoyer des rapports d'incident anonymement. +setting.savecreate.name = Auto-Create Saves setting.chatopacity.name = Opacité du tchat setting.playerchat.name = Afficher le tchat en jeu uiscale.reset = L'échelle de l'interface a été modifiée.\nAppuyez sur "OK" pour confirmer cette échelle.\n[scarlet]Revenir et sortir en[accent] {0}[] réglages... @@ -523,9 +537,9 @@ keybind.gridModeShift.name = Sélection de la catégorie keybind.press = Appuyez sur une touche ... keybind.press.axis = Appuyez sur un axe ou une touche... keybind.screenshot.name = Map Screenshot -keybind.fullscreen.name = Basculer en plein écran keybind.move_x.name = Mouvement X keybind.move_y.name = Mouvement Y +keybind.fullscreen.name = Basculer en plein écran keybind.select.name = Sélectionner/Tirer keybind.diagonal_placement.name = Placement en diagonal keybind.pick.name = Choisir un bloc @@ -912,7 +926,6 @@ unit.wraith.description = Une unité volante rapide harcelant les ennemis. Utili unit.ghoul.description = Un bombardier lourd. Utilise de la pyratite ou des explosifs comme munitions. unit.revenant.description = Un arsenal de missiles lourd et planant. block.graphite-press.description = Compresse des morceaux de charbon en feuilles de graphite. -block.command-center.description = Donne des ordres aux unités alliées sur la carte.\nPermet aux unités de patrouiller, d’attaquer un noyau ennemi ou de se retirer dans le noyau/l’usine. En l'absence de base ennemi, les unités patrouillent par défaut autour du centre de commandement. block.multi-press.description = Une version améliorée de la presse à graphite. Utilise de l'eau et de l'électricité pour traiter le charbon rapidement et efficacement. block.silicon-smelter.description = Réduit le sable avec du coke* très pur afin de produire du silicium. (*Coke produit à partir de charbon:REF) block.kiln.description = Fait fondre le sable et le plomb en métaverre. Nécessite de petites quantités d'énergie. @@ -1013,6 +1026,7 @@ block.ripple.description = Une grande tourelle d'artillerie qui tire plusieurs c block.cyclone.description = Une grande tourelle à tir rapide. block.spectre.description = Une grande tourelle qui tire deux balles puissantes à la fois. block.meltdown.description = Une grande tourelle qui tire de puissants faisceaux à longue portée. +block.command-center.description = Donne des ordres aux unités alliées sur la carte.\nPermet aux unités de patrouiller, d’attaquer un noyau ennemi ou de se retirer dans le noyau/l’usine. En l'absence de base ennemi, les unités patrouillent par défaut autour du centre de commandement. block.draug-factory.description = Produces Draug mining drones. block.spirit-factory.description = Produit des drones légers qui extraient du minerai et réparent des blocs. block.phantom-factory.description = Produit des drones avancés qui sont bien plus efficaces que les drones spirituels. diff --git a/core/assets/bundles/bundle_in_ID.properties b/core/assets/bundles/bundle_in_ID.properties index 3c44b1c5e9..18ec32d0bc 100644 --- a/core/assets/bundles/bundle_in_ID.properties +++ b/core/assets/bundles/bundle_in_ID.properties @@ -16,6 +16,11 @@ screenshot.invalid = Peta terlalu besar, tidak cukp memori untuk menangkap layar gameover = Permainan Habis gameover.pvp = Tim[accent] {0}[] menang! highscore = [accent]Rekor Baru! +load.sound = Sounds +load.map = Maps +load.image = Images +load.content = Content +load.system = System stat.wave = Gelombang Terkalahkan:[accent] {0} stat.enemiesDestroyed = Musuh Terhancurkan:[accent] {0} stat.built = Jumlah Blok yang Dibangun:[accent] {0} @@ -23,8 +28,6 @@ stat.destroyed = Jumlah Blok Dihancurkan Musuh:[accent] {0} stat.deconstructed = Jumlah Blok Dihancurkan Pemain:[accent] {0} stat.delivered = Sumber Daya yang Diluncurkan: stat.rank = Nilai Akhir: [accent]{0} -placeline = Anda telah memilih sebuah blok.\nAnda bisa[accent] menaruhnya berjejeran[] dengan[accent] menekan layar beberapa saat[] dan menarik jarimu ke arah yang dituju.\n\n[scarlet]Cobalah. -removearea = Anda telah memilih mode penghancuran.\nAnda bisa[accent] menghancurkan blok dalam sebuah kotak[] dengan[accent] menekan layar beberapa saat[] dan menarik jarimu sampai membentuk sebuah area.\n\n[scarlet]Cobalah. launcheditems = [accent]Sumber Daya map.delete = Apakah Anda yakin ingin menghapus peta "[accent]{0}[]"? level.highscore = Nilai Tertinggi: [accent]{0} @@ -63,9 +66,11 @@ players.single = {0} pemain aktif server.closing = [accent]Menutup server... server.kicked.kick = Anda telah dikeluarkan dari server! server.kicked.serverClose = Server ditutup. +server.kicked.vote = You have been vote-kicked. Goodbye. server.kicked.clientOutdated = Client kadaluarsa! perbarui permainan Anda! server.kicked.serverOutdated = Server kadaluarsa! Tanya host untuk diperbarui! server.kicked.banned = Anda telah dilarang untuk memasuki server ini. +server.kicked.typeMismatch = This server is not compatible with your build type. server.kicked.recentKick = Anda baru saja dikeluarkan dari server ini.\nTunggu sebelum masuk lagi. server.kicked.nameInUse = Sudah ada pemain dengan nama itu \ndi server ini. server.kicked.nameEmpty = Nama yang dipilih tidak valid. @@ -156,6 +161,11 @@ cancel = Batal openlink = Buka Tautan copylink = Salin Tautan back = Kembali +data.export = Export Data +data.import = Import Data +data.exported = Data exported. +data.invalid = This isn't valid game data. +data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. classic.export = Export Classic Data classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? quit.confirm = Apakah Anda yakin ingin keluar? @@ -376,6 +386,7 @@ zone.fungalPass.description = A transition area between high mountains and lower zone.impact0078.description = zone.crags.description = settings.language = Bahasa +settings.data = Game Data settings.reset = Atur ulang ke Default (standar) settings.rebind = Rebind settings.controls = Kontrol @@ -507,6 +518,7 @@ setting.mutemusic.name = Diamkan Musik setting.sfxvol.name = Volume SFX setting.mutesound.name = Diamkan Suara setting.crashreport.name = Laporkan Masalah +setting.savecreate.name = Auto-Create Saves setting.chatopacity.name = Jelas-Beningnya Chat setting.playerchat.name = Tunjukkan Chat dalam Permainan uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... @@ -527,6 +539,7 @@ keybind.press.axis = Tekan sumbu atau kunci... keybind.screenshot.name = Tangkapan Layar Peta keybind.move_x.name = Pindah x keybind.move_y.name = Pindah y +keybind.fullscreen.name = Toggle Fullscreen keybind.select.name = Pilih/Tembak keybind.diagonal_placement.name = Penaruhan Diagonal keybind.pick.name = Memilih Blok @@ -790,6 +803,7 @@ block.blast-mixer.name = Mixer Peledak block.solar-panel.name = Panel Surya block.solar-panel-large.name = Panel Surya Besar block.oil-extractor.name = Pegekstrak Oli +block.command-center.name = Command Center block.draug-factory.name = Draug Miner Drone Factory block.spirit-factory.name = Pabrik Drone Spirit block.phantom-factory.name = Pabrik Drone Phantom @@ -1012,6 +1026,7 @@ block.ripple.description = Menara meriam besar yang menembak beberapa peluru sek block.cyclone.description = Menara Penembak Beruntun Besar. block.spectre.description = Menara besar yang menembak dua peluru kuat sekaligus. block.meltdown.description = Menara besar ini menembak sinar panjang yang kuat. +block.command-center.description = Issues movement commands to allied units across the map.\nCauses units to patrol, attack an enemy core or retreat to the core/factory. When no enemy core is present, units will default to patrolling under the attack command. block.draug-factory.description = Produces Draug mining drones. block.spirit-factory.description = Memproduksi drone ringan yang menambang sumber daya dan memulih blok. block.phantom-factory.description = Memproduksi drone canggih yang lebih efektif dibandingkan drone spirit. diff --git a/core/assets/bundles/bundle_it.properties b/core/assets/bundles/bundle_it.properties index a68ddd8082..901e3eb399 100644 --- a/core/assets/bundles/bundle_it.properties +++ b/core/assets/bundles/bundle_it.properties @@ -1,10 +1,10 @@ credits.text = Creato da [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[]\n\n[GRAY](Nel caso non te ne sia accorto, la traduzione del gioco non è completa.\n Chi di dovere sta lavorando più velocemente possibile per completarla! Un aiutino non sarebbe male!) credits = Crediti -contributors = Translators and Contributors -discord = Unisciti sul server discord di mindustry! +contributors = Traduttori e Contributori +discord = Entra nel server discord di mindustry! link.discord.description = la chatroom ufficiale del server discord di Mindustry link.github.description = Codice sorgente del gioco -link.changelog.description = List of update changes +link.changelog.description = Elenco delle modifiche del gioco link.dev-builds.description = Build di sviluppo versioni instabili link.trello.description = Scheda ufficiale trello per funzionalità pianificate link.itch.io.description = pagina di itch.io con download per PC e versione web @@ -156,19 +156,19 @@ cancel = Annulla openlink = Apri Link copylink = Copia link back = Indietro -classic.export = Export Classic Data -classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? +classic.export = Esporta dati classici +classic.export.text = [accent]Mindustry[] ha appena rilasciato un aggiornamento importante.\nSalvataggio Classic (v3.5 build 40) o dati delle mappe è stato ritrovato. Vorresti esportare questi salvatagggi sul tuo telefono per usarli nella Mindustry Classic app? quit.confirm = Sei sicuro di voler uscire? -quit.confirm.tutorial = Are you sure you know what you're doing?\nThe tutorial can be re-taken in[accent] Settings->Game->Re-Take Tutorial.[] +quit.confirm.tutorial = Sei sicuro di sapere cosa stai facendo? Il tutorial può essere ripetuto in[accent] Impostazioni->Gioco->Ripeti il tutorial.[] loading = [accent]Caricamento in corso ... saving = [accent]Salvando . . . wave = [accent]Ondata {0} wave.waiting = Ondata in {0} -wave.waveInProgress = [LIGHT_GRAY]Wave in progress +wave.waveInProgress = [LIGHT_GRAY]Ondata in corso... waiting = In attesa... -waiting.players = Waiting for players... -wave.enemies = [LIGHT_GRAY]{0} Enemies Remaining -wave.enemy = [LIGHT_GRAY]{0} Enemy Remaining +waiting.players = Aspettando giocatori... +wave.enemies = [LIGHT_GRAY]{0} Nemici Rimasti +wave.enemy = [LIGHT_GRAY]{0} Nemico Rimasto loadimage = Carica immagine saveimage = Salva Immagine unknown = Sconosciuto @@ -188,10 +188,10 @@ editor.mapinfo = Informazioni mappa editor.author = Autore: editor.description = Descrizione: editor.waves = Ondate: -editor.rules = Rules: -editor.generation = Generation: -editor.ingame = Edit In-Game -editor.newmap = New Map +editor.rules = Regole: +editor.generation = Generazione: +editor.ingame = Modifica in gioco +editor.newmap = Nuova mappa waves.title = Ondate waves.remove = Rimuovi waves.never = @@ -206,18 +206,18 @@ waves.copy = Copia negli appunti waves.load = Caica dagli appunti waves.invalid = Onde dagli appunti non valide. waves.copied = Onde copiate. -waves.none = No enemies defined.\nNote that empty wave layouts will automatically be replaced with the default layout. +waves.none = Nessun nemico definiti.\n Nota che le disposizioni di ondate vuote verranno automaticamente rimpiazzate con la disposizione predefinita. editor.default = [LIGHT_GRAY] edit = Modifica... editor.name = Nome: -editor.spawn = Spawn Unit -editor.removeunit = Remove Unit +editor.spawn = Piazza un'unità +editor.removeunit = Rimuovi un'unità editor.teams = Squadre editor.errorload = Errore nel caricamento di:\n[accent]{0} editor.errorsave = Errore nel salvataggio di:\n[accent]{0} -editor.errorimage = That's an image, not a map. Don't go around changing extensions expecting it to work.\n\nIf you want to import a legacy map, use the 'import legacy map' button in the editor. -editor.errorlegacy = This map is too old, and uses a legacy map format that is no longer supported. -editor.errorheader = This map file is either not valid or corrupt. +editor.errorimage = Quella è un'immagine, non una mappa. Non cambiare estensioni sperando che funzioni.\n\n Se vuoi importare una mappa vecchia clicca su "importa una mappa vecchia" nell'editor. +editor.errorlegacy = La mappa è troppo vecchia e usa un formato che non è più supportato. +editor.errorheader = Questo file della mappa è invalido o corrotto. editor.errorname = Questa mappa è senza nome. editor.update = Aggiorna editor.randomize = Casualizza @@ -250,56 +250,56 @@ editor.mapname = Nome Mappa: editor.overwrite = [Accent]Attenzione!\nQuesto sovrascrive una mappa esistente. editor.overwrite.confirm = [scarlet]Attenzione![] Una mappa con questo nome esiste già. Sei sicuro di volerla sovrascrivere? editor.selectmap = Seleziona una mappa da caricare: -toolmode.replace = Replace -toolmode.replace.description = Draws only on solid blocks. -toolmode.replaceall = Replace All -toolmode.replaceall.description = Replace all blocks in map. -toolmode.orthogonal = Orthogonal -toolmode.orthogonal.description = Draws only orthogonal lines. -toolmode.square = Square -toolmode.square.description = Square brush. -toolmode.eraseores = Erase Ores -toolmode.eraseores.description = Erase only ores. -toolmode.fillteams = Fill Teams -toolmode.fillteams.description = Fill teams instead of blocks. -toolmode.drawteams = Draw Teams -toolmode.drawteams.description = Draw teams instead of blocks. -filters.empty = [LIGHT_GRAY]No filters! Add one with the button below. +toolmode.replace = Rimpiazzare +toolmode.replace.description = Disegna solo su blocchi solidi. +toolmode.replaceall = Rimpiazzare tutto +toolmode.replaceall.description = Rimpiazza tutti i blocchi nella mappa +toolmode.orthogonal = Ortogonale +toolmode.orthogonal.description = Disegna solo linee ortogonali +toolmode.square = Quadrato +toolmode.square.description = Pennello quadrato +toolmode.eraseores = Rimuovi Minerali +toolmode.eraseores.description = Rimuove solo minerali +toolmode.fillteams = Riempi squadre +toolmode.fillteams.description = Riempe squadre al posto di blocchi +toolmode.drawteams = Disegna squadre +toolmode.drawteams.description = Disegna squadre al posto di blocchi +filters.empty = [LIGHT_GRAY]Nessun filtro! Aggiungi uno cliccando il tasto sotto. filter.distort = Modifica filter.noise = Interferenza -filter.median = Median -filter.oremedian = Ore Median -filter.blend = Blend -filter.defaultores = Default Ores +filter.median = Mediana +filter.oremedian = Mediana Minerali +filter.blend = Miscela +filter.defaultores = Minerali predefiniti filter.ore = Minerali filter.rivernoise = Interferenze a fiume -filter.mirror = Mirror -filter.clear = Clear -filter.option.ignore = Ignore +filter.mirror = Specchia +filter.clear = Resetta il filtro +filter.option.ignore = Ignora filter.scatter = Dispersione filter.terrain = Terreno filter.option.scale = Scala filter.option.chance = Probabilità filter.option.mag = Magnitudine -filter.option.threshold = Threshold -filter.option.circle-scale = Circle Scale -filter.option.octaves = Octaves -filter.option.falloff = Falloff -filter.option.angle = Angle -filter.option.block = Block -filter.option.floor = Floor -filter.option.flooronto = Target Floor -filter.option.wall = Wall -filter.option.ore = Ore -filter.option.floor2 = Secondary Floor -filter.option.threshold2 = Secondary Threshold -filter.option.radius = Radius -filter.option.percentile = Percentile +filter.option.threshold = Soglia +filter.option.circle-scale = Modifica grandezza cerchio +filter.option.octaves = Ottavi +filter.option.falloff = Cadere +filter.option.angle = Angolo +filter.option.block = Blocco +filter.option.floor = Pavimento +filter.option.flooronto = Pavimento mirato +filter.option.wall = Muro +filter.option.ore = Minerale +filter.option.floor2 = Pavimento secondario +filter.option.threshold2 = Soglia secondaria +filter.option.radius = Raggio +filter.option.percentile = percentuale width = Larghezza: height = Altezza: menu = Menu play = Gioca -campaign = Campaign +campaign = Campagna load = Carica save = Salva fps = FPS: {0} @@ -308,148 +308,148 @@ ping = Ping: {0}ms language.restart = Riavvia il gioco affinché il cambiamento della lingua abbia effetto. settings = Impostazioni tutorial = Tutorial -tutorial.retake = Re-Take Tutorial +tutorial.retake = Ripeti il tutorial editor = Editor mapeditor = Editor Mappe donate = Dona -abandon = Abandon -abandon.text = This zone and all its resources will be lost to the enemy. -locked = Locked -complete = [LIGHT_GRAY]Complete: -zone.requirement = Wave {0} in zone {1} -resume = Resume Zone:\n[LIGHT_GRAY]{0} -bestwave = [LIGHT_GRAY]Best: {0} -launch = Launch -launch.title = Launch Successful -launch.next = [LIGHT_GRAY]next opportunity at wave {0} -launch.unable2 = [scarlet]Unable to LAUNCH.[] -launch.confirm = This will launch all resources in your core.\nYou will not be able to return to this base. -launch.skip.confirm = If you skip now, you will not be able to launch until later waves. -uncover = Uncover -configure = Configure Loadout -configure.locked = [LIGHT_GRAY]Reach wave {0}\nto configure loadout. -zone.unlocked = [LIGHT_GRAY]{0} unlocked. -zone.requirement.complete = Wave {0} reached:\n{1} zone requirements met. -zone.config.complete = Wave {0} reached:\nLoadout config unlocked. -zone.resources = Resources Detected: -zone.objective = [lightgray]Objective: [accent]{0} -zone.objective.survival = Survive -zone.objective.attack = Destroy Enemy Core -add = Add... -boss.health = Boss Health +abandon = Abbandona +abandon.text = Questa zona e tutte le sue risorse saranno perdute e passeranno al nemico. +locked = Bloccato +complete = [LIGHT_GRAY]Completato: +zone.requirement = Onda {0} in zona {1} +resume = Riprendi zona:\n[LIGHT_GRAY]{0} +bestwave = [LIGHT_GRAY]Migliore: {0} +launch = Decollare +launch.title = Decollo riuscito! +launch.next = [LIGHT_GRAY]Nuova opportunità all'ondata {0} +launch.unable2 = [scarlet]Decollo FALLITO![] +launch.confirm = Questo trasporterà tutte le risorse nel tuo nucleo.\nNon riuscirai a ritornare in questa base. +launch.skip.confirm = Se salti adesso non riuscirai a decollare fino alle onde sucessive +uncover = Svlare +configure = Configura l'equipaggio +configure.locked = [LIGHT_GRAY]Arriva all'ondata {0}\nper configurare l'equipaggiamento. +zone.unlocked = [LIGHT_GRAY]{0} sbloccata. +zone.requirement.complete = Ondata {0} raggiunta:\n{1} requisiti di zona soddisfatti. +zone.config.complete = Ondata {0} reached:\nLoadout config unlocked. +zone.resources = Risorse trovate: +zone.objective = [lightgray]Obiettivo: [accent]{0} +zone.objective.survival = Sopravvivere +zone.objective.attack = Distruggere il nucleo nemico +add = Aggiungi... +boss.health = Vita del Boss connectfail = [crimson] Impossibile connettersi al server: [accent] {0} -error.unreachable = Server unreachable. -error.invalidaddress = Invalid address. -error.timedout = Timed out!\nMake sure the host has port forwarding set up, and that the address is correct! -error.mismatch = Packet error:\npossible client/server version mismatch.\nMake sure you and the host have the latest version of Mindustry! -error.alreadyconnected = Already connected. -error.mapnotfound = Map file not found! -error.io = Network I/O error. -error.any = Unkown network error. +error.unreachable = Server irraggiungibile +error.invalidaddress = Indirizzo invalido. +error.timedout = Timeout!\n Assicurati che l'host abbia il port forwarding impostato e che l'indirizzo sia corretto! +error.mismatch = Errore pacchetti:\nPossibile discordanza della versione client / server.\n Assicurati che tu e l'host possiediate l'ultima versione di Mindustry! +error.alreadyconnected = Già connesso. +error.mapnotfound = Mappa non trovata +error.io = Errore I/O di rete. +error.any = Errore di rete sconosciuto. error.bloom = Failed to initialize bloom.\nYour device may not support it. -zone.groundZero.name = Ground Zero -zone.desertWastes.name = Desert Wastes -zone.craters.name = The Craters -zone.frozenForest.name = Frozen Forest -zone.ruinousShores.name = Ruinous Shores -zone.stainedMountains.name = Stained Mountains -zone.desolateRift.name = Desolate Rift -zone.nuclearComplex.name = Nuclear Production Complex -zone.overgrowth.name = Overgrowth -zone.tarFields.name = Tar Fields -zone.saltFlats.name = Salt Flats -zone.impact0078.name = Impact 0078 -zone.crags.name = Crags -zone.fungalPass.name = Fungal Pass -zone.groundZero.description = The optimal location to begin once more. Low enemy threat. Few resources.\nGather as much lead and copper as possible.\nMove on. -zone.frozenForest.description = Even here, closer to mountains, the spores have spread. The fridgid temperatures cannot contain them forever.\n\nBegin the venture into power. Build combustion generators. Learn to use menders. -zone.desertWastes.description = These wastes are vast, unpredictable, and criss-crossed with derelict sector structures.\nCoal is present in the region. Burn it for power, or synthesize graphite.\n\n[lightgray]This landing location cannot be guaranteed. -zone.saltFlats.description = On the outskirts of the desert lie the Salt Flats. Few resources can be found in this location.\n\nThe enemy has erected a resource storage complex here. Eradicate their core. Leave nothing standing. -zone.craters.description = Water has accumulated in this crater, relic of the old wars. Reclaim the area. Collect sand. Smelt metaglass. Pump water to cool turrets and drills. -zone.ruinousShores.description = Past the wastes, is the shoreline. Once, this location housed a coastal defense array. Not much of it remains. Only the most basic defense structures have remained unscathed, everything else reduced to scrap.\nContinue the expansion outwards. Rediscover the technology. -zone.stainedMountains.description = Further inland lie the mountains, yet untainted by spores.\nExtract the abundant titanium in this area. Learn how to use it.\n\nThe enemy presence is greater here. Do not give them time to send their strongest units. -zone.overgrowth.description = This area is overgrown, closer to the source of the spores.\nThe enemy has established an outpost here. Build dagger units. Destroy it. Reclaim that which was lost. -zone.tarFields.description = The outskirts of an oil production zone, between the mountains and desert. One of the few areas with usable tar reserves.\nAlthough abandoned, this area has some dangerous enemy forces nearby. Do not underestimate them.\n\n[lightgray]Research oil processing technology if possible. -zone.desolateRift.description = An extremely dangerous zone. Plentiful resources, but little space. High risk of destruction. Leave as soon as possible. Do not be fooled by the long spacing between enemy attacks. -zone.nuclearComplex.description = A former facility for the production and processing of thorium, reduced to ruins.\n[lightgray]Research the thorium and its many uses.\n\nThe enemy is present here in great numbers, constantly scouting for attackers. -zone.fungalPass.description = A transition area between high mountains and lower, spore-ridden lands. A small enemy reconnaissance base is located here.\nDestroy it.\nUse Dagger and Crawler units. Take out the two cores. -zone.impact0078.description = -zone.crags.description = +zone.groundZero.name = Terreno Zero +zone.desertWastes.name = Rifiuti Desertici +zone.craters.name = Crateri +zone.frozenForest.name = Foresta Ghiacciata +zone.ruinousShores.name = Spiaggie in Rovina +zone.stainedMountains.name = Montagne Macchiate +zone.desolateRift.name = Spaccatura Desolata +zone.nuclearComplex.name = Complesso di Produzione Nucleare +zone.overgrowth.name = Crescita Eccessiva +zone.tarFields.name = Campi di Catrame +zone.saltFlats.name = Saline +zone.impact0078.name = Impatto 0078 +zone.crags.name = Dirupi +zone.fungalPass.name = Passaggio Fungoso +zone.groundZero.description = La posizione ottimale per cominciare. Bassa minaccia nemica. Poche risorse.\nRaccogli quanto più piombo e rame possibile.\nProcedi. +zone.frozenForest.description = Anche qui, più vicino alle montagne, le spore si sono diffuse. Le temperature rigide non possono contenerle per sempre.\n Inizia la scoperta dell'energia. Costruisci generatori di combustione. Impara a usare i riparatori. +zone.desertWastes.description = Questi rifiuti sono vasti, imprevedibili e attraversati da strutture settoriali abbandonate.\n\nIl carbone è presente nella regione. Bruciatelo per ottenere energia o sintetizzate la grafite.\n\n[lightgray]Questa posizione di atterraggio non può essere garantita. +zone.saltFlats.description = Alle periferie del deserto si trovano le saline. Poche risorse possono essere trovate in questa posizione.\n\nIl nemico ha eretto un complesso di archiviazione delle risorse qui. Sradicare il loro nucleo. Non lasciare nulla in piedi. +zone.craters.description = L'acqua si è accumulata in questo cratere, reliquia delle vecchie guerre. Recupera l'area. Raccogli la sabbia. Fondi il metaglass. Pompa l'acqua per raffreddare torrette e trapani. +zone.ruinousShores.description = Oltre i rifiuti, c'è il litorale. Una volta, questa posizione ospitava una schiera di difesa costiera. Non rimane molto. Solo le strutture di difesa più elementari sono rimaste incolume, tutto il resto ridotto a rottami.\nContinua l'espansione verso l'esterno. Riscopri la tecnologia. +zone.stainedMountains.description = Più nell'entroterra si trovano le montagne, non ancora contaminate da spore.\nEstrai l'abbondante titanio in questa zona. Scopri come usarlo.\n\nLa presenza del nemico è maggiore qui. Non dare loro il tempo di inviare le loro unità più forti. +zone.overgrowth.description = Quest'area è invasa, più vicina alla fonte delle spore.\nIl nemico ha stabilito qui un avamposto. Costruisci unità col pugnale. Distruggilo. Riprenditi ciò che è stato perso. +zone.tarFields.description = La periferia di una zona di produzione di petrolio, tra le montagne e il deserto. Una delle poche aree con riserve di catrame utilizzabili.\nAnche se abbandonata, questa zona ha alcune pericolose forze nemiche nelle vicinanze. Non sottovalutarlo.\n\n[lightgray]Ricerca la tecnologia di lavorazione dell'olio, se possibile. +zone.desolateRift.description = Una zona estremamente pericolosa. Risorse abbondanti, ma poco spazio. Alto rischio di distruzione. Lascia il prima possibile. Non lasciarti ingannare dalla lunga distanza tra gli attacchi nemici. +zone.nuclearComplex.description = Un ex impianto per la produzione e la lavorazione del torio, ridotto in rovina.\n[lightgray] Ricerca il torio e i suoi numerosi usi.\n\nIl nemico è presente qui in gran numero, alla costante ricerca di aggressori. +zone.fungalPass.description = Un'area di transizione tra alte montagne e terre più basse, piene di spore. Qui si trova una piccola base di ricognizione nemica.\nDistruggila.\nUsa le unità Pugnale e Strisciatore. Elimina i due nuclei. +zone.impact0078.description = +zone.crags.description = settings.language = Lingua settings.reset = Resetta Alle Impostazioni Predefinite settings.rebind = Reimposta settings.controls = Controlli settings.game = Gioco -settings.sound = Suono +settings.sound = Suoni settings.graphics = Grafica -settings.cleardata = Clear Game Data... -settings.clear.confirm = Are you sure you want to clear this data?\nWhat is done cannot be undone! -settings.clearall.confirm = [scarlet]WARNING![]\nThis will clear all data, including saves, maps, unlocks and keybinds.\nOnce you press 'ok' the game will wipe all data and automatically exit. -settings.clearunlocks = Clear Unlocks -settings.clearall = Clear All +settings.cleardata = Cancella dati di gioco... +settings.clear.confirm = Sei sicuro di voler cancellare i dati?\nNon può essere annullato! +settings.clearall.confirm = [scarlet]ATTENZIONE![]\nQuesto cancellerà tutti i dati, includendo salvataggi, mappe, oggetti sbloccati, impostazioni.\nDopo aver premuto su 'ok' il gioco eliminerà i dati e si chiuderà. +settings.clearunlocks = Cancella oggetti sbloccati +settings.clearall = Cancella tutto paused = In pausa yes = Si no = No info.title = [accent] Info error.title = [crimson]Si è verificato un errore error.crashtitle = Si è verificato un errore -attackpvponly = [scarlet]Only available in Attack/PvP modes -blocks.input = Input -blocks.output = Output +attackpvponly = [scarlet]Solo possible nelle modalità Attacco/PvP +blocks.input = Ingresso +blocks.output = Uscita blocks.booster = Booster block.unknown = [LIGHT_GRAY]??? blocks.powercapacity = Capacità Energetica blocks.powershot = Danno/Colpo -blocks.damage = Damage +blocks.damage = Danno blocks.targetsair = Attacca nemici aerei -blocks.targetsground = Targets Ground -blocks.itemsmoved = Move Speed -blocks.launchtime = Time Between Launches +blocks.targetsground = Attacca nemici terreni +blocks.itemsmoved = Velocità movimento +blocks.launchtime = Tempo fra decolli blocks.shootrange = Raggio blocks.size = Grandezza blocks.liquidcapacity = Capacità del liquido blocks.powerrange = Raggio Energia blocks.poweruse = Utilizzo energia -blocks.powerdamage = Power/Damage +blocks.powerdamage = Energia/Danno blocks.itemcapacity = Capacità -blocks.basepowergeneration = Base Power Generation -blocks.productiontime = Production Time -blocks.repairtime = Block Full Repair Time -blocks.speedincrease = Speed Increase -blocks.range = Range +blocks.basepowergeneration = Generazione energia di base +blocks.productiontime = Tempo produzione +blocks.repairtime = Tempo di riparo completo +blocks.speedincrease = Aumento Velocità +blocks.range = Raggio blocks.drilltier = Scavabili blocks.drillspeed = Velocità scavo stbile -blocks.boosteffect = Boost Effect -blocks.maxunits = Max Active Units +blocks.boosteffect = Effetto boost +blocks.maxunits = Unità attive max blocks.health = Salute -blocks.buildtime = Build Time +blocks.buildtime = Tempo costruzione blocks.inaccuracy = Inaccuratezza blocks.shots = Colpi blocks.reload = Ricarica -blocks.ammo = Ammo -bar.drilltierreq = Better Drill Required -bar.drillspeed = Drill Speed: {0}/s -bar.efficiency = Efficiency: {0}% -bar.powerbalance = Power: {0} -bar.poweramount = Power: {0} -bar.poweroutput = Power Output: {0} -bar.items = Items: {0} -bar.liquid = Liquid -bar.heat = Heat -bar.power = Power -bar.progress = Build Progress -bar.spawned = Units: {0}/{1} -bullet.damage = [stat]{0}[lightgray] dmg -bullet.splashdamage = [stat]{0}[lightgray] area dmg ~[stat] {1}[lightgray] tiles -bullet.incendiary = [stat]incendiary -bullet.homing = [stat]homing +blocks.ammo = Munizioni +bar.drilltierreq = Migliore trapano richiesto +bar.drillspeed = Velocità scavo: {0}/s +bar.efficiency = Efficienza: {0}% +bar.powerbalance = Energia: {0} +bar.poweramount = Energia: {0} +bar.poweroutput = Energia in uscita: {0} +bar.items = Oggetti: {0} +bar.liquid = Liquido +bar.heat = Calore +bar.power = Energia +bar.progress = Progresso della costruzione +bar.spawned = Unità: {0}/{1} +bullet.damage = [stat]{0}[lightgray] danno +bullet.splashdamage = [stat]{0}[lightgray] danno ad area ~[stat] {1}[lightgray] blocchi +bullet.incendiary = [stat]incendiario +bullet.homing = [stat]autoguidato bullet.shock = [stat]shock -bullet.frag = [stat]frag -bullet.knockback = [stat]{0}[lightgray] knockback -bullet.freezing = [stat]freezing -bullet.tarred = [stat]tarred -bullet.multiplier = [stat]{0}[lightgray]x ammo multiplier -bullet.reload = [stat]{0}[lightgray]x reload +bullet.frag = [stat]frammentazione +bullet.knockback = [stat]{0}[lightgray] contraccolpo +bullet.freezing = [stat]congelamento +bullet.tarred = [stat]asfaltata +bullet.multiplier = [stat]{0}[lightgray]x moltiplicatore munizioni +bullet.reload = [stat]{0}[lightgray]x ricarica unit.blocks = blocchi unit.powersecond = unità energia/secondo unit.liquidsecond = unità liquide/secondo @@ -459,7 +459,7 @@ unit.powerunits = unità energia unit.degrees = gradi unit.seconds = secondi unit.persecond = /sec -unit.timesspeed = x speed +unit.timesspeed = x velocità unit.percent = % unit.items = oggetti category.general = Generali @@ -468,26 +468,26 @@ category.liquids = Liquidi category.items = Oggetti category.crafting = Produzione category.shooting = Potenza di fuoco -category.optional = Optional Enhancements -setting.landscape.name = Lock Landscape -setting.shadows.name = Shadows -setting.linear.name = Linear Filtering -setting.animatedwater.name = Animated Water -setting.animatedshields.name = Animated Shields -setting.antialias.name = Antialias[LIGHT_GRAY] (requires restart)[] -setting.indicators.name = Ally Indicators -setting.autotarget.name = Auto-Target -setting.keyboard.name = Mouse+Keyboard Controls +category.optional = Miglioramenti Opzionali +setting.landscape.name = Blocca paesaggio +setting.shadows.name = Ombre +setting.linear.name = Filtro lineare +setting.animatedwater.name = Acqua animata +setting.animatedshields.name = Scudi animati +setting.antialias.name = Antialias[LIGHT_GRAY] (richiede riapertura gioco)[] +setting.indicators.name = Indicatori Alleati +setting.autotarget.name = Mira automatica +setting.keyboard.name = Controlli Mouse+Tastiera setting.fpscap.name = Limite FPS setting.fpscap.none = Niente setting.fpscap.text = {0} FPS -setting.uiscale.name = UI Scaling[lightgray] (require restart)[] -setting.swapdiagonal.name = Always Diagonal Placement -setting.difficulty.training = training +setting.uiscale.name = Ridimensionamento dell'interfaccia utente[lightgray] (richiede riapertura gioco)[] +setting.swapdiagonal.name = Posizionamento sempre diagonale +setting.difficulty.training = formazione setting.difficulty.easy = facile setting.difficulty.normal = medio setting.difficulty.hard = difficile -setting.difficulty.insane = folle +setting.difficulty.insane = impossibile setting.difficulty.name = Difficoltà: setting.screenshake.name = Movimento dello schermo setting.effects.name = Visualizza effetti @@ -495,49 +495,49 @@ setting.sensitivity.name = Sensibilità del controller setting.saveinterval.name = Intervallo di salvataggio automatico setting.seconds = {0} Secondi setting.fullscreen.name = Schermo Intero -setting.borderlesswindow.name = Borderless Window[LIGHT_GRAY] (may require restart) +setting.borderlesswindow.name = Schermo senza bordi[LIGHT_GRAY] (potrebbe richiedere riapertura gioco) setting.fps.name = Mostra FPS setting.vsync.name = VSync setting.lasers.name = Mostra Laser Energetici -setting.pixelate.name = Pixelate [LIGHT_GRAY](may decrease performance) +setting.pixelate.name = Sfocare [LIGHT_GRAY](potrebbe ridure il rendimento) setting.minimap.name = Mostra minimappa setting.musicvol.name = Volume Musica -setting.ambientvol.name = Ambient Volume +setting.ambientvol.name = Volume Ambiente setting.mutemusic.name = Silenzia musica -setting.sfxvol.name = Volume SFX +setting.sfxvol.name = Volume Effetti setting.mutesound.name = Togli suoni -setting.crashreport.name = Send Anonymous Crash Reports -setting.chatopacity.name = Chat Opacity -setting.playerchat.name = Display In-Game Chat -uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... -uiscale.cancel = Cancel & Exit -setting.bloom.name = Bloom +setting.crashreport.name = Invia rapporti sugli arresti anomali anonimamente +setting.chatopacity.name = Opacità chat +setting.playerchat.name = Mostra Chat in-game +uiscale.reset = La scala dell'interfaccia utente è stata modificata.\nPremere "OK" per confermare questa scala.\n[scarlet] Ripristina ed esci dalle impostazioni [accent] {0}[] impostazioni... +uiscale.cancel = Annulla e esci +setting.bloom.name = Shaders keybind.title = Configurazione Tasti -keybinds.mobile = [scarlet]Most keybinds here are not functional on mobile. Only basic movement is supported. +keybinds.mobile = [scarlet]La maggior parte dei keybind qui non sono funzionali sui dispositivi mobili. È supportato solo il movimento di base. category.general.name = Generale category.view.name = Visualizzazione category.multiplayer.name = Multigiocatore -command.attack = Attack -command.retreat = Retreat -command.patrol = Patrol -keybind.gridMode.name = Block Select -keybind.gridModeShift.name = Category Select -keybind.press = Press a key... -keybind.press.axis = Press an axis or key... -keybind.screenshot.name = Map Screenshot +command.attack = Attacca +command.retreat = Ritorna indietro +command.patrol = Guardia +keybind.gridMode.name = Seleziona blocco +keybind.gridModeShift.name = Seleziona categoria +keybind.press = Premi un tasto... +keybind.press.axis = Premi un'asse o un tasto... +keybind.screenshot.name = Screenshot della mappa keybind.move_x.name = Sposta_x keybind.move_y.name = Sposta_y keybind.select.name = seleziona -keybind.diagonal_placement.name = Diagonal Placement -keybind.pick.name = Pick Block -keybind.break_block.name = Break Block -keybind.deselect.name = Deselect +keybind.diagonal_placement.name = Posizionamento diagonale +keybind.pick.name = Scegli Blocco +keybind.break_block.name = Rompi blocco +keybind.deselect.name = Deseleziona keybind.shoot.name = spara -keybind.zoom_hold.name = zoom_hold +keybind.zoom_hold.name = zoomma keybind.zoom.name = zoom keybind.menu.name = menu keybind.pause.name = pausa -keybind.minimap.name = Minimap +keybind.minimap.name = Minimappa keybind.dash.name = Scatto keybind.chat.name = Chat keybind.player_list.name = lista_giocatori @@ -550,66 +550,66 @@ keybind.chat_scroll.name = Scorri chat keybind.drop_unit.name = droppa materiali keybind.zoom_minimap.name = Zomma minimappa mode.help.title = Descrizione delle modalità -mode.survival.name = Survival -mode.survival.description = The normal mode. Limited resources and automatic incoming waves. +mode.survival.name = Sopravvivenza +mode.survival.description = La modalità normale. Risorse limitate e ondate in entrata automatiche. mode.sandbox.name = Sandbox mode.sandbox.description = risorse infinite e nessun timer per le ondate. mode.pvp.name = PvP -mode.pvp.description = fight against other players locally. -mode.attack.name = Attack -mode.attack.description = No waves, with the goal to destroy the enemy base. -mode.custom = Custom Rules -rules.infiniteresources = Infinite Resources -rules.wavetimer = Wave Timer -rules.waves = Waves -rules.attack = Attack Mode -rules.enemyCheat = Infinite AI Resources -rules.unitdrops = Unit Drops -rules.unitbuildspeedmultiplier = Unit Creation Speed Multiplier -rules.unithealthmultiplier = Unit Health Multiplier -rules.playerhealthmultiplier = Player Health Multiplier -rules.playerdamagemultiplier = Player Damage Multiplier -rules.unitdamagemultiplier = Unit Damage Multiplier -rules.enemycorebuildradius = Enemy Core No-Build Radius:[LIGHT_GRAY] (tiles) -rules.respawntime = Respawn Time:[LIGHT_GRAY] (sec) -rules.wavespacing = Wave Spacing:[LIGHT_GRAY] (sec) -rules.buildcostmultiplier = Build Cost 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 +mode.pvp.description = Lotta contro altri giocatori +mode.attack.name = Attacco +mode.attack.description = Obiettivo: Distruggere la base nemica, non ci sono ondate +mode.custom = Regole customizzabili +rules.infiniteresources = Risorse infinite +rules.wavetimer = Timer ondate +rules.waves = Ondate +rules.attack = Modalità attacco +rules.enemyCheat = Infinite Risorse AI +rules.unitdrops = Drops Unità +rules.unitbuildspeedmultiplier = Moltiplicatore velocità costruzione unità +rules.unithealthmultiplier = Moltiplicatore vita unità +rules.playerhealthmultiplier = Moltiplicatore vita giocatore +rules.playerdamagemultiplier = Moltiplicatore danno giocatore +rules.unitdamagemultiplier = Moltiplicatore danno unità +rules.enemycorebuildradius = Raggio dove non si può costruire attorno al nucleo nemico:[LIGHT_GRAY] (tiles) +rules.respawntime = Tempo di rigeneratione:[LIGHT_GRAY] (sec) +rules.wavespacing = Tempo fra ondate:[LIGHT_GRAY] (secondi) +rules.buildcostmultiplier = Moltiplicatore costo costruzione +rules.buildspeedmultiplier = Moltiplicatore velocità costruzione +rules.waitForWaveToEnd = Ondate aspettano fino a quando l'ondata precedente finisce +rules.dropzoneradius = Raggio di drop:[LIGHT_GRAY] (blocchi) +rules.respawns = Massimo di rigenerazioni per ondata +rules.limitedRespawns = Limite rigenerazioni +rules.title.waves = Ondate +rules.title.respawns = Rigenerazioni +rules.title.resourcesbuilding = Risorse e costruzioni +rules.title.player = Giocatori +rules.title.enemy = Nemici +rules.title.unit = Unità content.item.name = Oggetti content.liquid.name = Liquidi -content.unit.name = Units -content.block.name = Blocks -content.mech.name = Mech +content.unit.name = Unità +content.block.name = Blocchi +content.mech.name = Mechs item.copper.name = Rame item.lead.name = Piombo -item.coal.name = carbone +item.coal.name = Carbone item.graphite.name = Graphite item.titanium.name = titanio item.thorium.name = Torio item.silicon.name = Silicio -item.plastanium.name = Plastaniu -item.phase-fabric.name = Phase Fabric -item.surge-alloy.name = Surge Alloy -item.spore-pod.name = Spore Pod -item.sand.name = sabbia +item.plastanium.name = Plastanio +item.phase-fabric.name = Tessuto Fase +item.surge-alloy.name = Lega Ondata +item.spore-pod.name = Piattaforma Spore +item.sand.name = Sabbia item.blast-compound.name = Polvere esplosiva item.pyratite.name = Pirite item.metaglass.name = Metaglass -item.scrap.name = Scrap -liquid.water.name = acqua -liquid.slag.name = Slag -liquid.oil.name = petrolio -liquid.cryofluid.name = criogenium +item.scrap.name = Rottame +liquid.water.name = Acqua +liquid.slag.name = Scorie +liquid.oil.name = Petrolio +liquid.cryofluid.name = Criogenium mech.alpha-mech.name = Alpha mech.alpha-mech.weapon = Ripetitore pesante mech.alpha-mech.ability = Orda di droni @@ -620,13 +620,13 @@ mech.tau-mech.name = Tau mech.tau-mech.weapon = Laser ricostruttore mech.tau-mech.ability = Ripara esplosioni mech.omega-mech.name = Omega -mech.omega-mech.weapon = SCiame di missili +mech.omega-mech.weapon = Sciame di missili mech.omega-mech.ability = Configurazione armata mech.dart-ship.name = Dart mech.dart-ship.weapon = Ripetitore -mech.javelin-ship.name = Javelin +mech.javelin-ship.name = Giavellotto mech.javelin-ship.weapon = Missili esplosivi -mech.javelin-ship.ability = Discharge Booster +mech.javelin-ship.ability = Booster di scarico mech.trident-ship.name = Tridente mech.trident-ship.weapon = Valle delle bombe mech.glaive-ship.name = Glaive @@ -637,90 +637,90 @@ item.radioactivity = [LIGHT_GRAY]Radioattività: {0} unit.health = [LIGHT_GRAY]Vita: {0} unit.speed = [LIGHT_GRAY]Velocità: {0} mech.weapon = [LIGHT_GRAY]Armi: {0} -mech.health = [LIGHT_GRAY]Health: {0} +mech.health = [LIGHT_GRAY]Vita: {0} mech.itemcapacity = [LIGHT_GRAY]Capacità oggetti: {0} mech.minespeed = [LIGHT_GRAY]Velocità di scavo: {0} mech.minepower = [LIGHT_GRAY]Potenza di scavo: {0} mech.ability = [LIGHT_GRAY]Abilità: {0} -mech.buildspeed = [LIGHT_GRAY]Building Speed: {0}% +mech.buildspeed = [LIGHT_GRAY]Velocità costruzione: {0}% liquid.heatcapacity = [LIGHT_GRAY]Capacità calorifica: {0} liquid.viscosity = [LIGHT_GRAY]Viscosità: {0} liquid.temperature = [LIGHT_GRAY]Temperatura: {0} -block.sand-boulder.name = Sand Boulder +block.sand-boulder.name = Masso di Sabbia block.grass.name = Grass -block.salt.name = Salt -block.saltrocks.name = Salt Rocks -block.pebbles.name = Pebbles -block.tendrils.name = Tendrils -block.sandrocks.name = Sand Rocks -block.spore-pine.name = Spore Pine -block.sporerocks.name = Spore Rocks -block.rock.name = Rock -block.snowrock.name = Snow Rock -block.snow-pine.name = Snow Pine -block.shale.name = Shale -block.shale-boulder.name = Shale Boulder -block.moss.name = Moss -block.shrubs.name = Shrubs -block.spore-moss.name = Spore Moss -block.shalerocks.name = Shale Rocks -block.scrap-wall.name = Scrap Wall -block.scrap-wall-large.name = Large Scrap Wall -block.scrap-wall-huge.name = Huge Scrap Wall -block.scrap-wall-gigantic.name = Gigantic Scrap Wall -block.thruster.name = Thruster -block.kiln.name = Kiln -block.graphite-press.name = Graphite Press -block.multi-press.name = Multi-Press -block.constructing = {0}\n[LIGHT_GRAY](Constructing) -block.spawn.name = Enemy Spawn -block.core-shard.name = Core: Shard -block.core-foundation.name = Core: Foundation -block.core-nucleus.name = Core: Nucleus +block.salt.name = Sale +block.saltrocks.name = Rocce salate +block.pebbles.name = Ciottole +block.tendrils.name = Viticci +block.sandrocks.name = Rocce sabbiose +block.spore-pine.name = Pino Spora +block.sporerocks.name = Roccia Spora +block.rock.name = Roccia +block.snowrock.name = Roccia innevata +block.snow-pine.name = Pino innevato +block.shale.name = Scisto +block.shale-boulder.name = Masso di scisto +block.moss.name = Muschio +block.shrubs.name = Arbusti +block.spore-moss.name = Spore di Muschio +block.shalerocks.name = Roccie di scisto +block.scrap-wall.name = Muro di Rottami +block.scrap-wall-large.name = Muro di rottami grande +block.scrap-wall-huge.name = Muro di rottami enorme +block.scrap-wall-gigantic.name = Muro di Rottami Gigante +block.thruster.name = Propulsore +block.kiln.name = Forno +block.graphite-press.name = Pressa per grafite +block.multi-press.name = Multi Pressa +block.constructing = {0}\n[LIGHT_GRAY](In costruzione) +block.spawn.name = Spawning nemico +block.core-shard.name = Nucleo: Frammento +block.core-foundation.name = Nucleo: Fondamento +block.core-nucleus.name = Nucleo: Kernel block.deepwater.name = acqua profonda block.water.name = acqua -block.tainted-water.name = Tainted Water -block.darksand-tainted-water.name = Dark Sand Tainted Water -block.tar.name = Tar +block.tainted-water.name = Acqua contaminata +block.darksand-tainted-water.name = Acqua contaminata scura +block.tar.name = Catrame block.stone.name = pietra block.sand.name = sabbia -block.darksand.name = Dark Sand +block.darksand.name = Sabbia scura block.ice.name = ghiaccio block.snow.name = neve -block.craters.name = Craters -block.sand-water.name = Sand water -block.darksand-water.name = Dark Sand Water -block.char.name = Char -block.holostone.name = Holo stone -block.ice-snow.name = Ice Snow -block.rocks.name = Rocks -block.icerocks.name = Ice rocks -block.snowrocks.name = Snow Rocks -block.dunerocks.name = Dune Rocks -block.pine.name = Pine -block.white-tree-dead.name = White Tree Dead -block.white-tree.name = White Tree -block.spore-cluster.name = Spore Cluster -block.metal-floor.name = Metal Floor -block.metal-floor-2.name = Metal Floor 2 -block.metal-floor-3.name = Metal Floor 3 -block.metal-floor-5.name = Metal Floor 5 -block.metal-floor-damaged.name = Metal Floor Damaged -block.dark-panel-1.name = Dark Panel 1 -block.dark-panel-2.name = Dark Panel 2 -block.dark-panel-3.name = Dark Panel 3 -block.dark-panel-4.name = Dark Panel 4 -block.dark-panel-5.name = Dark Panel 5 -block.dark-panel-6.name = Dark Panel 6 -block.dark-metal.name = Dark Metal -block.ignarock.name = Igna Rock -block.hotrock.name = Hot Rock -block.magmarock.name = Magma Rock -block.cliffs.name = Cliffs +block.craters.name = Crateri +block.sand-water.name = Acqua sabbiosa +block.darksand-water.name = Acqua sabbiosa scura +block.char.name = Carbone +block.holostone.name = Pietra di holo +block.ice-snow.name = Neve ghiacciata +block.rocks.name = Roccie +block.icerocks.name = Rocce ghiacciate +block.snowrocks.name = Rocce innevate +block.dunerocks.name = Rocce delle dune +block.pine.name = Pino +block.white-tree-dead.name = Albero bianco morto +block.white-tree.name = Albero morto +block.spore-cluster.name = Agglomerato di spore +block.metal-floor.name = Pavimento metallico +block.metal-floor-2.name = Pavimento metallico 2 +block.metal-floor-3.name = Pavimento metallico 3 +block.metal-floor-5.name = Pavimento metallico 5 +block.metal-floor-damaged.name = Pavimento metallico danneggiato +block.dark-panel-1.name = Pannello scuro 1 +block.dark-panel-2.name = Pannello scuro 2 +block.dark-panel-3.name = Pannello scuro 3 +block.dark-panel-4.name = Pannello scuro 4 +block.dark-panel-5.name = Pannello scuro 5 +block.dark-panel-6.name = Pannello scuro 6 +block.dark-metal.name = Metallo Scuro +block.ignarock.name = Roccia Ignea +block.hotrock.name = Roccia bollente +block.magmarock.name = Roccia magmatica +block.cliffs.name = Scogliere block.copper-wall.name = Muro di rame block.copper-wall-large.name = Muro grande di rame -block.titanium-wall.name = Titanium Wall -block.titanium-wall-large.name = Large Titanium Wall +block.titanium-wall.name = Muro di titanio +block.titanium-wall-large.name = Muro grande di titanio block.phase-wall.name = Muro di fase block.phase-wall-large.name = Muro grande di fase block.thorium-wall.name = Muro di torio @@ -728,15 +728,15 @@ block.thorium-wall-large.name = Muro grande di torio block.door.name = porta block.door-large.name = Porta grande block.duo.name = Duo -block.scorch.name = Scorch -block.scatter.name = Scatter +block.scorch.name = Bruciatore +block.scatter.name = Spargimento block.hail.name = Bombardiere block.lancer.name = Idrogetto block.conveyor.name = trasportatore block.titanium-conveyor.name = Nastro trasportatore potenziato block.junction.name = Incrocio -block.router.name = router -block.distributor.name = Mega router +block.router.name = Separatore +block.distributor.name = Mega Separatore block.sorter.name = Filtro block.overflow-gate.name = splitter per eccesso block.silicon-smelter.name = Fonderia per silicio diff --git a/core/assets/bundles/bundle_ja.properties b/core/assets/bundles/bundle_ja.properties index 1f4067ecdf..4d44c9da24 100644 --- a/core/assets/bundles/bundle_ja.properties +++ b/core/assets/bundles/bundle_ja.properties @@ -16,6 +16,11 @@ screenshot.invalid = マップが広すぎます。スクリーンショット gameover = ゲームオーバー gameover.pvp = [accent] {0}[] チームの勝利! highscore = [accent]ハイスコアを記録! +load.sound = Sounds +load.map = Maps +load.image = Images +load.content = Content +load.system = System stat.wave = 防衛したウェーブ:[accent] {0} stat.enemiesDestroyed = 敵による破壊数:[accent] {0} stat.built = 建設した建造物数:[accent] {0} @@ -23,8 +28,6 @@ stat.destroyed = 破壊した建造物数:[accent] {0} stat.deconstructed = 解体した建造物数:[accent] {0} stat.delivered = 獲得した資源: stat.rank = 最終ランク: [accent]{0} -placeline = ブロックを選択しました。\n[accent]少し長押し[]して、好きな方向にドラッグすると[accent]一直線上にブロックを設置[]することができます。\nやってみよう。 -removearea = 撤去モードが選択されました。\n[accent]少し長押し[]して、ドラッグすると[accent]範囲内のブロックを撤去[]することができます。\nやってみよう。 launcheditems = [accent]回収したアイテム map.delete = マップ "[accent]{0}[]" を削除してもよろしいですか? level.highscore = ハイスコア: [accent]{0} @@ -63,9 +66,11 @@ players.single = {0} 人がオンライン server.closing = [accent]サーバーを閉じています... server.kicked.kick = サーバからキックされました! server.kicked.serverClose = サーバーが閉じられました。 +server.kicked.vote = You have been vote-kicked. Goodbye. server.kicked.clientOutdated = 古いクライアントです! ゲームをアップデートしてください! server.kicked.serverOutdated = 古いサーバーです! ホストに更新してもらってください! server.kicked.banned = サーバーからブロックされています。 +server.kicked.typeMismatch = This server is not compatible with your build type. server.kicked.recentKick = 直前にキックされています。\nもう一度接続できるまでお待ちください。 server.kicked.nameInUse = このサーバーでは、\nすでに同じ名前が使用されています。 server.kicked.nameEmpty = 無効な名前です。 @@ -156,6 +161,11 @@ cancel = キャンセル openlink = リンクを開く copylink = リンクをコピー back = 戻る +data.export = Export Data +data.import = Import Data +data.exported = Data exported. +data.invalid = This isn't valid game data. +data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. classic.export = Export Classic Data classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? quit.confirm = 終了してもよろしいですか? @@ -376,6 +386,7 @@ zone.fungalPass.description = A transition area between high mountains and lower zone.impact0078.description = zone.crags.description = settings.language = 言語 +settings.data = Game Data settings.reset = デフォルトにリセット settings.rebind = 再設定 settings.controls = コントロール @@ -507,6 +518,7 @@ setting.mutemusic.name = 音楽をミュート setting.sfxvol.name = 効果音 音量 setting.mutesound.name = 効果音をミュート setting.crashreport.name = 匿名でクラッシュレポートを送信する +setting.savecreate.name = Auto-Create Saves setting.chatopacity.name = チャットの透明度 setting.playerchat.name = ゲーム内にチャットを表示 uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... @@ -527,6 +539,7 @@ keybind.press.axis = 軸またはキーを押してください... keybind.screenshot.name = スクリーンショット keybind.move_x.name = 左右移動 keybind.move_y.name = 上下移動 +keybind.fullscreen.name = Toggle Fullscreen keybind.select.name = 選択/ショット keybind.diagonal_placement.name = 斜め設置 keybind.pick.name = ブロックの選択 @@ -790,6 +803,7 @@ block.blast-mixer.name = 化合物ミキサー block.solar-panel.name = ソーラーパネル block.solar-panel-large.name = 大型ソーラーパネル block.oil-extractor.name = 石油抽出機 +block.command-center.name = Command Center block.draug-factory.name = Draug Miner Drone Factory block.spirit-factory.name = スピリットドローン製造機 block.phantom-factory.name = ファントムドローン製造機 @@ -1012,6 +1026,7 @@ block.ripple.description = 同時に複数ショットを発射する大型タ block.cyclone.description = 大型の連射型ターレットです。 block.spectre.description = 一度に2発の強力な弾を放つ大型のターレットです。 block.meltdown.description = 強力な長距離攻撃が可能な大型のターレットです。 +block.command-center.description = Issues movement commands to allied units across the map.\nCauses units to patrol, attack an enemy core or retreat to the core/factory. When no enemy core is present, units will default to patrolling under the attack command. block.draug-factory.description = Produces Draug mining drones. block.spirit-factory.description = 鉱石の採掘やブロックの修復を行う小型のドローンユニットのスピリットを製造します。 block.phantom-factory.description = スピリットドローンの性能を遥かに凌ぐ上位のドローンユニットのファントムドローンを製造します。 diff --git a/core/assets/bundles/bundle_ko.properties b/core/assets/bundles/bundle_ko.properties index 5de1bce53a..b245155ceb 100644 --- a/core/assets/bundles/bundle_ko.properties +++ b/core/assets/bundles/bundle_ko.properties @@ -20,7 +20,7 @@ highscore = [accent]최고점수 달성! load.sound = 소리 load.map = 맵 load.image = 사진 -load.content = Content +load.content = 컨텐츠 load.system = 시스템 stat.wave = 웨이브 성공:[accent]{0} @@ -52,8 +52,17 @@ close = 닫기 website = 웹사이트 quit = 나가기 maps = 맵 +maps.browse = 맵 검색 continue = 계속하기 maps.none = [LIGHT_GRAY]맵을 찾을 수 없습니다! +invalid = 오류 +preparingconfig = 설정 사전준비 +preparingcontent = 컨텐츠 사전준비 +uploadingcontent = 컨텐츠 업로드 +uploadingpreviewfile = 미리보기 파일 업로드 +committingchanges = 바뀐 점 적용 +done = 완료 + about.button = 정보 name = 이름 : noname = 먼저 [accent] 유저 이름[] 을 설정하세요. @@ -68,16 +77,18 @@ players = 현재 {0}명 접속중 players.single = 현재 {0}명만 있음. server.closing = [accent]서버 닫는중... server.kicked.kick = 서버에서 추방되었습니다! +server.kicked.whitelist = 당신은 여기의 화이트리스트가 아닙니다. server.kicked.serverClose = 서버 종료됨. server.kicked.vote = 당신은 투표로 추방되었습니다. 그러니 좀 적당히 하지 그랬어요? server.kicked.clientOutdated = 오래된 버전의 게임입니다! 게임을 업데이트 하세요! server.kicked.serverOutdated = 오래된 버전의 서버입니다! 서버 호스트 관리자에게 문의하세요! server.kicked.banned = 서버 규칙 위반으로 인해, 이제 당신은 영원히 이 서버를 플레이 하실 수 없습니다. +server.kicked.typeMismatch = 클라이언트와 호환되지 않는 서버입니다. 디스코드에서 #mods에 들러보는 건 어떨까요? +server.kicked.playerLimit = 서버가 꽉 찼습니다. 빈 공간이 생길 때까지 기다려주세요. server.kicked.recentKick = 방금 추방처리 되었습니다.\n잠시 기다린 후에 접속 해 주세요. server.kicked.nameInUse = 이 닉네임이 이미 서버에서 사용중입니다. -server.kicked.nameEmpty = 닉네임에는 반드시 알파벳 또는 숫자가 있어야 합니다. -server.kicked.idInUse = 이미 서버에 접속중입니다! 다중 계정은 허용되지 않습니다. server.kicked.nameEmpty = 당신의 닉네임이 비어있습니다. +server.kicked.idInUse = 이미 서버에 접속중입니다! 다중 계정은 허용되지 않습니다. server.kicked.customClient = 이 서버는 직접 빌드한 버전을 지원하지 않습니다. 공식 버전을 사용하세요. server.kicked.gameover = 코어가 파괴되었습니다... server.versions = 클라이언트 버전 : [accent] {0}[]\n서버 버전 : [accent] {1}[] @@ -89,6 +100,7 @@ host = 서버 열기 hosting = [accent]서버 여는중... hosts.refresh = 새로고침 hosts.discovering = LAN 게임 찾기 +hosts.discovering.any = 서버 찾기 server.refreshing = 서버 목록 새로고치는중... hosts.none = [lightgray]LAN 게임을 찾을 수 없습니다! host.invalid = [scarlet]서버에 연결할 수 없습니다! @@ -118,12 +130,16 @@ confirmunadmin = 이 플레이어를 일반 유저로 만들겠습니까? joingame.title = 게임 참가 joingame.ip = 주소: disconnect = 서버와 연결이 해제되었습니다. -disconnect.data = 맵 데이터를 받아오는데 실패했습니다! +disconnect.data = 맵 데이터를 받아오는데 실패했습니다.. +disconnect.closed = 연결이 끊어졌습니다.. +disconnect.timeout = 연결 시간 한계 도달.. +disconnect.data = 월드 데이터 로딩 실패.. + connecting = [accent]연결중... -connecting.data = [accent]맵 데이터 다운로드중... +connecting.data = [accent]월드 데이터 로딩중... server.port = 포트: -server.addressinuse = 이 주소는 이미 사용중입니다! -server.invalidport = 포트 번호가 잘못되었습니다. +server.addressinuse = 주소가 이미 사용중입니다! +server.invalidport = 포트가 올바르지 않습니다! server.error = [accent]{0}[crimson]서버를 여는데 오류가 발생했습니다. save.old = 이 저장파일은 이전 버전의 게임용이며, 지금은 사용할 수 없습니다. \n\n[LIGHT_GRAY]4.0 정식때 이전 게임버전에서 만든 저장파일과 호환됩니다. save.new = 새로 저장 @@ -151,7 +167,7 @@ off = 끄기 save.autosave = 자동저장: {0} save.map = 맵: {0} save.wave = 웨이브 {0} -save.difficulty = 난이도: {0} +save.mode = 게임모드 : {0} save.date = 마지막 저장날짜: {0} save.playtime = 플레이시간: {0} warning = 경고. @@ -169,8 +185,8 @@ data.import = 데이터 불러오기 data.exported = 데이터를 내보냈습니다. data.invalid = 유효한 게임 데이터가 아닙니다. data.import.confirm = 외부 게임 데이터를 불러옵니다...\n[accent]이 작업시 현재 게임 데이터는 삭제되고, 외부의 게임 데이터를 불러오니 주의하세요. 실행 취소가 불가능하며, 작업 후 게임이 바로 꺼집니다. -classic.export.text = Mindustry 클래식 (v3.5 build 40)의 세이브파일 또는 맵 데이터가 발견되었습니다. 이 것들을 Mindustry 클래식 앱에서 사용하기 위해 홈 폴더로 추출할까요? classic.export = 클래식 데이터 추출 +classic.export.text = Mindustry 클래식 (v3.5 build 40)의 세이브파일 또는 맵 데이터가 발견되었습니다. 이 것들을 Mindustry 클래식 앱에서 사용하기 위해 홈 폴더로 추출할까요? quit.confirm = 정말로 종료하시겠습니까? quit.confirm.tutorial = 튜토리얼을 종료하시겠습니까?\n튜토리얼은 [accent]설정 -> 게임 -> 튜토리얼[]에서 다시 해보실 수 있습니다. loading = [accent]불러오는중... @@ -193,6 +209,9 @@ map.nospawn = 이 맵에 플레이어가 생성될 코어가 없습니다! 맵 map.nospawn.pvp = 이 맵에는 적팀 코어가 없습니다! 에디터에서 [ROYAL]노랑색 팀이 아닌[] 코어를 추가하세요. map.nospawn.attack = 이 맵에는 플레이어가 공격할 수 있는 적의 코어가 없습니다! 에디터에서 [ROYAL] 빨강색 팀[] 코어를 맵에 추가하세요. map.invalid = 파일이 잘못되었거나 손상되어 맵을 열 수 없습니다. +map.publish.error = 맵 업로드 오류 : {0} +map.publish = 맵 업로드 완료! +map.publishing = [accent]맵 업로드 중... editor.brush = 브러쉬 editor.openin = 편집기 열기 editor.oregen = 광물 무작위 생성 @@ -204,7 +223,9 @@ editor.waves = 웨이브: editor.rules = 규칙: editor.generation = 맵 생성 설정: editor.ingame = 인게임 편집 -editor.newmap = 신규 맵 +editor.publish.workshop = 워크샵 업로드 +editor.newmap = 신규 맵 +workshop = 워크샵 waves.title = 웨이브 waves.remove = 삭제 waves.never = 여기까지 유닛생성 @@ -221,6 +242,7 @@ waves.invalid = 클립보드의 잘못된 웨이브 데이터 waves.copied = 웨이브 복사됨 waves.none = 적 웨이브가 설정되지 않았습니다.\n비어있을 시 자동으로 기본 적 웨이브로 설정됩니다. editor.default = [LIGHT_GRAY]<기본값> +details = 설명 edit = 편집 editor.name = 이름: editor.spawn = 유닛 생성 @@ -230,6 +252,7 @@ editor.errorload = [accent]{0} 파일을 불러오는데 실패했습니다. editor.errorsave = [accent]{0} 파일을 저장하는데 실패했습니다. editor.errorimage = 이것은 맵이 아니라 사진입니다.\n\n예전 맵을 가져올려면 편집기의 '예전 맵 가져오기' 버튼을 사용하세요. editor.errorlegacy = 이 맵은 너무 오래되어, 더이상 지원하지 않는 맵 형식을 사용합니다. +editor.errornot = 선택한 대상이 맵 파일이 아닙니다. editor.errorheader = 이 맵 파일은 유효하지 않거나 손상되었습니다. editor.errorname = 맵에 이름이 지정되어 있지 않습니다. editor.update = 업데이트 @@ -345,6 +368,7 @@ launch.skip.confirm = 만약 지금 출격하시지 않고 스킵하신다면, uncover = 구역 개방 configure = 코어 시작자원 설정 configure.locked = {0} 단계에서 시작자원 설정 잠금이 해제됩니다. +configure.invalid = 해당 가격은 0 과 {0} 사이여야 합니다. zone.unlocked = [LIGHT_GRAY] 잠금 해제되었습니다! zone.requirement.complete = 웨이브 {0} 달성:\n{1} 지역 요구사항이 충족되었습니다! zone.config.complete = 웨이브 {0} 달성:\n시작자원 설정 기능이 해금되었습니다! @@ -422,7 +446,7 @@ blocks.booster = 가속 block.unknown = [LIGHT_GRAY]??? blocks.powercapacity = 전력 용량 blocks.powershot = 1발당 전력 소모량 -blocks.damage = Damage +blocks.damage = 공격력 blocks.targetsair = 공중공격 가능 blocks.targetsground = 지상공격 가능 blocks.itemsmoved = 이동 속도 @@ -445,6 +469,7 @@ blocks.boosteffect = 가속 효과 blocks.maxunits = 최대 활성유닛 blocks.health = 체력 blocks.buildtime = 건설 시간 +blocks.buildcost = 건설 재료 blocks.inaccuracy = 오차각 blocks.shots = 발포 횟수 blocks.reload = 재장전 @@ -533,6 +558,7 @@ setting.sfxvol.name = 효과음 크기 setting.mutesound.name = 소리 끄기 setting.crashreport.name = 오류 보고서 보내기 setting.savecreate.name = 자동 저장 활성화 +setting.publichost.name = 공용 서버 보이기 setting.chatopacity.name = 채팅 투명도 setting.playerchat.name = 인게임 채팅 표시 uiscale.reset = UI 스케일이 변경되었습니다.\n"확인"버튼을 눌러 스케일을 확인하세요.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... @@ -944,10 +970,6 @@ unit.eruptor.description = 지상 유닛. 광재를 넣은 파도와 같은 무 unit.wraith.description = 적 핵심 건물 및 유닛을 집중적으로 공격하는 방식을 사용하는 전투기 입니다. unit.ghoul.description = 무겁고 튼튼한 지상 폭격기 입니다.\n주로 적 건물로 이동하여 엄청난 폭격을 가합니다. unit.revenant.description = 플래이어가 생산가능한 최종 공중 전투기. 폭발물을 쓰는 스웜 포탑과 같은 무기를 사용합니다. -unit.chaos-array.description = 고속 설금 3연발 총을 장착한 지상 보스 유닛입니다. 중간보스 같다고 얕봤다가는 생산건물에 큰 타격을 입을 수 있습니다.\n\n[royal]하지만 스코치에겐 너도 한방! 나도 한방! -unit.eradicator.description = 강력한 토륨 연사 총을 2개 장착한 지상 보스 유닛입니다. 체력도 지상 유닛에 한해서 가장 많습니다. -unit.lich.description = 작은 폭발물 연사포탑을 2개 장착한 공중 보스 유닛입니다.\n\n[royal]망령 전함의 강화판이라 볼 수 있습니다. -unit.reaper.description = 강력한 토륨 연사 포탑를 2개 장착하고 Mindustry 내 모든 것중에서 가장 많은 체력을 가진 공중 보스 유닛입니다. block.graphite-press.description = 석탄 덩어리를 흑연으로 압축합니다. block.multi-press.description = 흑연 압축기의 상향 버전입니다. 물과 전력을 이용해 석탄을 빠르고 효율적으로 압축합니다. block.silicon-smelter.description = 석탄과 모래를 사용해 실리콘을 생산합니다. diff --git a/core/assets/bundles/bundle_nl.properties b/core/assets/bundles/bundle_nl.properties index e15caebf54..52a4a9c592 100644 --- a/core/assets/bundles/bundle_nl.properties +++ b/core/assets/bundles/bundle_nl.properties @@ -16,6 +16,11 @@ screenshot.invalid = Map too large, potentially not enough memory for screenshot gameover = Game Over gameover.pvp = het[accent] {0}[] team heeft gewonnen! highscore = [accent]Nieuw topscore! +load.sound = Sounds +load.map = Maps +load.image = Images +load.content = Content +load.system = System stat.wave = Waves Verslagen:[accent] {0} stat.enemiesDestroyed = Vijanden Vernietigd:[accent] {0} stat.built = Gebouwen Gebouwd:[accent] {0} @@ -23,8 +28,6 @@ stat.destroyed = Gebouwen Vernietigd:[accent] {0} stat.deconstructed = Gebouwen Gesloopt:[accent] {0} stat.delivered = Middelen Gelanceerd: stat.rank = Eindrang: [accent]{0} -placeline = You have selected a block.\nYou can[accent] place in a line[] by[accent] holding down your finger for a few seconds[] and dragging in a direction.\nTry it. -removearea = You have selected removal mode.\nYou can[accent] remove blocks in a rectangle[] by[accent] holding down your finger for a few seconds[] and dragging.\nTry it. launcheditems = [accent]Launched Items map.delete = Weet je zeker dat je de map wilt verwijderen? "[accent]{0}[]"? level.highscore = Topscore: [accent]{0} @@ -63,9 +66,11 @@ players.single = {0} player online server.closing = [accent]Closing server... server.kicked.kick = You have been kicked from the server! server.kicked.serverClose = Server closed. +server.kicked.vote = You have been vote-kicked. Goodbye. server.kicked.clientOutdated = Outdated client! Update your game! server.kicked.serverOutdated = Outdated server! Ask the host to update! server.kicked.banned = You are banned on this server. +server.kicked.typeMismatch = This server is not compatible with your build type. server.kicked.recentKick = You have been kicked recently.\nWait before connecting again. server.kicked.nameInUse = There is someone with that name\nalready on this server. server.kicked.nameEmpty = Your chosen name is invalid. @@ -156,6 +161,11 @@ cancel = Cancel openlink = Open Link copylink = Copy Link back = Back +data.export = Export Data +data.import = Import Data +data.exported = Data exported. +data.invalid = This isn't valid game data. +data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. classic.export = Export Classic Data classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? quit.confirm = Are you sure you want to quit? @@ -376,6 +386,7 @@ zone.fungalPass.description = A transition area between high mountains and lower zone.impact0078.description = zone.crags.description = settings.language = Language +settings.data = Game Data settings.reset = Reset to Defaults settings.rebind = Rebind settings.controls = Controls @@ -507,6 +518,7 @@ setting.mutemusic.name = Mute Music setting.sfxvol.name = SFX Volume setting.mutesound.name = Mute Sound setting.crashreport.name = Send Anonymous Crash Reports +setting.savecreate.name = Auto-Create Saves setting.chatopacity.name = Chat Opacity setting.playerchat.name = Display In-Game Chat uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... @@ -527,6 +539,7 @@ keybind.press.axis = Press an axis or key... keybind.screenshot.name = Map Screenshot keybind.move_x.name = Move x keybind.move_y.name = Move y +keybind.fullscreen.name = Toggle Fullscreen keybind.select.name = Select/Shoot keybind.diagonal_placement.name = Diagonal Placement keybind.pick.name = Pick Block @@ -790,6 +803,7 @@ block.blast-mixer.name = Blast Mixer block.solar-panel.name = Solar Panel block.solar-panel-large.name = Large Solar Panel block.oil-extractor.name = Oil Extractor +block.command-center.name = Command Center block.draug-factory.name = Draug Miner Drone Factory block.spirit-factory.name = Spirit Drone Factory block.phantom-factory.name = Phantom Drone Factory @@ -1012,6 +1026,7 @@ block.ripple.description = A large artillery turret which fires several shots si block.cyclone.description = A large rapid fire turret. block.spectre.description = A large turret which shoots two powerful bullets at once. block.meltdown.description = A large turret which shoots powerful long-range beams. +block.command-center.description = Issues movement commands to allied units across the map.\nCauses units to patrol, attack an enemy core or retreat to the core/factory. When no enemy core is present, units will default to patrolling under the attack command. block.draug-factory.description = Produces Draug mining drones. block.spirit-factory.description = Produces light drones which mine ore and repair blocks. block.phantom-factory.description = Produces advanced drone units which are significantly more effective than a spirit drone. diff --git a/core/assets/bundles/bundle_nl_BE.properties b/core/assets/bundles/bundle_nl_BE.properties index 0ae0769df1..6a866675e6 100644 --- a/core/assets/bundles/bundle_nl_BE.properties +++ b/core/assets/bundles/bundle_nl_BE.properties @@ -16,6 +16,11 @@ screenshot.invalid = Kaart te groot, mogelijks te weinig geheugen voor een scree gameover = Game Over gameover.pvp = Het[accent] {0}[] team heeft gewonnen! highscore = [accent]Nieuw record! +load.sound = Sounds +load.map = Maps +load.image = Images +load.content = Content +load.system = System stat.wave = Je overleefde tot aanvalsgolf: [accent]{0}[]. stat.enemiesDestroyed = Vijanden vernietigd:[accent] {0} stat.built = Gebouwen gebouwd:[accent] {0} @@ -23,8 +28,6 @@ stat.destroyed = Gebouwen vernietigd:[accent] {0} stat.deconstructed = Gebouwen afgebroken:[accent] {0} stat.delivered = Gronstoffen meegenomen: stat.rank = Eindresultaat: [accent]{0} -placeline = Je hebt een blok geselecteerd.\nJe kan[accent] in een lijn plaatsen[] door[accent] je vinger voor enkele seconden ingedrukt te houden[] en in een richting te slepen.\n\n[scarlet]DOE HET. -removearea = Je hebt verwijderingsmodus geselecteerd.\nJe kan[accent] blokken verwijderen in een rechthoek[] door[accent] je vinger voor enkele seconden ingedrukt te houden[] en te slepen.\n\n[scarlet]DOE HET. launcheditems = [accent]Meegenomen grondstoffen map.delete = Ben je zeker dat je de kaart "[accent]{0}[]" wilt verwijderen? level.highscore = Beste score: [accent]{0} @@ -63,9 +66,11 @@ players.single = {0} speler online server.closing = [accent]Server wordt gesloten... server.kicked.kick = Je bent uit de server gegooid! server.kicked.serverClose = Server gesloten. +server.kicked.vote = You have been vote-kicked. Goodbye. server.kicked.clientOutdated = Verouderde versie! Update Mindustry! server.kicked.serverOutdated = Verouderde server! Vraag de eigenaar van de server om de server te updaten! server.kicked.banned = Je bent verbannen van deze server. +server.kicked.typeMismatch = This server is not compatible with your build type. server.kicked.recentKick = Je bent daarnet van de server gegooid.\nWacht even voor je weer verbindt server.kicked.nameInUse = Er is al iemand met dezelfde naam op de server. server.kicked.nameEmpty = Je gekozen naam is ongeldig. @@ -156,6 +161,11 @@ cancel = Annuleer openlink = Open Link copylink = Kopiëer Link back = Terug +data.export = Export Data +data.import = Import Data +data.exported = Data exported. +data.invalid = This isn't valid game data. +data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. classic.export = Export Classic Data classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? quit.confirm = Weet je zeker dat je wilt stoppen? @@ -376,6 +386,7 @@ zone.fungalPass.description = A transition area between high mountains and lower zone.impact0078.description = zone.crags.description = settings.language = Language +settings.data = Game Data settings.reset = Reset to Defaults settings.rebind = Rebind settings.controls = Controls @@ -507,6 +518,7 @@ setting.mutemusic.name = Mute Music setting.sfxvol.name = SFX Volume setting.mutesound.name = Mute Sound setting.crashreport.name = Send Anonymous Crash Reports +setting.savecreate.name = Auto-Create Saves setting.chatopacity.name = Chat Opacity setting.playerchat.name = Display In-Game Chat uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... @@ -527,6 +539,7 @@ keybind.press.axis = Press an axis or key... keybind.screenshot.name = Map Screenshot keybind.move_x.name = Move x keybind.move_y.name = Move y +keybind.fullscreen.name = Toggle Fullscreen keybind.select.name = Select/Shoot keybind.diagonal_placement.name = Diagonal Placement keybind.pick.name = Pick Block @@ -790,6 +803,7 @@ block.blast-mixer.name = Blast Mixer block.solar-panel.name = Solar Panel block.solar-panel-large.name = Large Solar Panel block.oil-extractor.name = Oil Extractor +block.command-center.name = Command Center block.draug-factory.name = Draug Miner Drone Factory block.spirit-factory.name = Spirit Drone Factory block.phantom-factory.name = Phantom Drone Factory @@ -1012,6 +1026,7 @@ block.ripple.description = A large artillery turret which fires several shots si block.cyclone.description = A large rapid fire turret. block.spectre.description = A large turret which shoots two powerful bullets at once. block.meltdown.description = A large turret which shoots powerful long-range beams. +block.command-center.description = Issues movement commands to allied units across the map.\nCauses units to patrol, attack an enemy core or retreat to the core/factory. When no enemy core is present, units will default to patrolling under the attack command. block.draug-factory.description = Produces Draug mining drones. block.spirit-factory.description = Produces light drones which mine ore and repair blocks. block.phantom-factory.description = Produces advanced drone units which are significantly more effective than a spirit drone. diff --git a/core/assets/bundles/bundle_pl.properties b/core/assets/bundles/bundle_pl.properties index a3558de431..cd0681c8fb 100644 --- a/core/assets/bundles/bundle_pl.properties +++ b/core/assets/bundles/bundle_pl.properties @@ -4,7 +4,7 @@ contributors = Tłumacze i pomocnicy discord = Odwiedź nasz serwer Discord! link.discord.description = Oficjalny serwer Discord Mindustry link.github.description = Kod Gry -link.changelog.description = List of update changes +link.changelog.description = Informacje o aktualizacjach link.dev-builds.description = Niestabilne wersje gry link.trello.description = Oficjalna tablica Trello z planowanym funkcjami link.itch.io.description = Strona itch.io z oficjanymi wersjami do pobrania @@ -16,6 +16,13 @@ screenshot.invalid = Zrzut ekranu jest zbyt duży. Najprawdopodobniej brakuje mi gameover = Rdzeń został zniszczony. gameover.pvp = Zwyciężyła drużyna [accent]{0}[]! highscore = [YELLOW] Nowy rekord! + +load.sound = Dźwięki +load.map = Mapy +load.image = Obrazy +load.content = Treść +load.system = System + stat.wave = Fale powstrzymane:[accent] {0} stat.enemiesDestroyed = Przeciwnicy zniszczeni:[accent] {0} stat.built = Budynki zbudowane:[accent] {0} @@ -23,8 +30,7 @@ stat.destroyed = Budynki zniszczone:[accent] {0} stat.deconstructed = Budynki zrekonstruowane:[accent] {0} stat.delivered = Surowce wystrzelone: stat.rank = Ocena: [accent]{0} -placeline = Wybrałeś blok.\nMożesz umieścić[accent] w linii,[] [accent]przytrzymując palec przez kilka sekund[] i przeciągając.\nSpróbuj. -removearea = Wybrałeś tryb usuwania.\nMożesz[accent] usunąć bloki w prostokoncie,[] [accent]przytrzymując palec przez kilka sekund i przeciągając[] and dragging.\nTry it. + launcheditems = [accent]Wystrzelone przedmioty map.delete = Jesteś pewny, że chcesz usunąć "[accent]{0}[]"? level.highscore = Rekord: [accent]{0} @@ -43,11 +49,18 @@ newgame = Nowa Gra none = minimap = Minimapa close = Zamknij -website = Website +website = Strona Gry quit = Wyjdź maps = Mapy continue = Kontynuuj maps.none = [LIGHT_GRAY]Nie znaleziono żadnych map! +invalid = Invalid +preparingconfig = Preparing Config +preparingcontent = Preparing Content +uploadingcontent = Uploading Content +uploadingpreviewfile = Uploading Preview File +committingchanges = Comitting Changes +done = Done about.button = O grze name = Nazwa: noname = Najpierw wybierz [accent]nazwę gracza[] @@ -62,17 +75,21 @@ players = {0} graczy online players.single = {0} gracz online server.closing = [accent] Zamykanie serwera... server.kicked.kick = Zostałeś wyrzucony z serwera! +server.kicked.whitelist = You are not whitelisted here. server.kicked.serverClose = Serwer został zamknięty. +server.kicked.vote = Zostałeś wyrzucony z gry. Żegnaj. server.kicked.clientOutdated = Nieaktualna gra! Zaktualizują ją! server.kicked.serverOutdated = Nieaktualny serwer! Poproś hosta o jego aktualizację. server.kicked.banned = Zostałeś zbanowany na tym serwerze. +server.kicked.typeMismatch = Ten serwer jest niekompatybilny z twoją wersją gry. +server.kicked.playerLimit = Serwer pełny. Poczekaj na wolny slot. server.kicked.recentKick = Zostałeś niedawno wyrzucony.\nPoczekaj chwilę przed ponownym połączniem. server.kicked.nameInUse = Ta nazwa jest już zajęta na tym serwerze. server.kicked.nameEmpty = Wybrana przez Ciebie nazwa jest nieprawidłowa. server.kicked.idInUse = Jesteś już na serwerze! Używanie tego samego konta na 2 urządzeniach jest zabronione. server.kicked.customClient = Ten serwer nie wspomaga wersji deweloperskich. Pobierz oficjalną wersję. server.kicked.gameover = Koniec gry! -server.versions = Your version:[accent] {0}[]\nServer version:[accent] {1}[] +server.versions = Twoja wersja gry:[accent] {0}[]\nWersja gry serwera:[accent] {1}[] host.info = Przycisk [accent]host[] hostuje serwer na porcie [scarlet]6567[] i [scarlet]6568.[]\nKtokolwiek z tym samym [LIGHT_GRAY]wifi lub hotspotem[] powinien zobaczyć twój serwer.\n\nJeśli chcesz, aby każdy z twoim IP mógł dołączyć, [accent]przekierowywanie portów[] jest potrzebne.\n\n[LIGHT_GRAY]Notka:Jeśli ktokolwiek ma problem z dołączeniem do gry, upewnij się, że udostępniłeś Mindustry dostęp do sieci. join.info = Tutaj możesz wpisać [accent]IP serwera[], aby dołączyć lub wyszukaj [accent]serwery w lokalnej sieci[], do których chcesz dołączyć .\nGra wieloosobowa na LAN i WAN jest wspomagana.\n\n[LIGHT_GRAY]Notka: Nie ma automatycznej listy wszystkich serwerów; jeśli chcesz dołączyć przez IP, musisz zapytać się hosta o IP. hostserver = Stwórz Serwer @@ -81,6 +98,7 @@ host = Hostuj hosting = [accent] Otwieranie serwera... hosts.refresh = Odśwież hosts.discovering = Wyszukiwanie gier w sieci LAN +hosts.discovering.any = Discovering games server.refreshing = Odświeżanie serwera hosts.none = [lightgray] Brak serwerów w sieci LAN! host.invalid = [scarlet] Nie można połączyć się z hostem. @@ -88,7 +106,7 @@ trace = Zlokalizuj gracza trace.playername = Nazwa gracza: [accent]{0} trace.ip = IP: [accent]{0} trace.id = Wyjątkowe ID: [accent]{0} -trace.mobile = Mobile Client: [accent]{0} +trace.mobile = Klient Mobilny: [accent]{0} trace.modclient = Zmodowany klient: [accent]{0} invalidid = Złe ID klienta! Udostępnij raport błędu. server.bans = Bany @@ -110,6 +128,9 @@ confirmunadmin = Jesteś pewny, że chcesz zabrać rangę admina temu graczowi? joingame.title = Dołącz do gry joingame.ip = IP: disconnect = Rozłączono. +disconnect.error = Błąd połączenia. +disconnect.closed = Połączenie zostało zamknięte. +disconnect.timeout = Przekroczono limit czasu. disconnect.data = Nie udało się załadować mapy! connecting = [accent]Łączenie... connecting.data = [accent]Ładowanie danych świata... @@ -136,7 +157,7 @@ save.rename = Zmień nazwę save.rename.text = Nowa nazwa: selectslot = Wybierz zapis. slot = [accent]Slot {0} -save.corrupted = [accent]Zapis gry jest uszkodzony lub nieprawidłowy! Jeżeli aktualizowałeś grę, najprawdopodobniej zmiana w formacie zapisu i [scarlet]nie jest[] to błąd. +save.corrupted = [accent]Zapis gry jest uszkodzony lub nieprawidłowy! Jeżeli aktualizowałeś grę, najprawdopodobniej jest to zmiana w formacie zapisu i [scarlet]nie jest[] to błąd. empty = on = Włączone off = Wyłączone @@ -151,20 +172,25 @@ confirm = Potwierdź delete = Usuń ok = Ok open = Otwórz -customize = Customize +customize = Dostosuj cancel = Anuluj openlink = Otwórz link copylink = Kopiuj link back = Wróć -classic.export = Export Classic Data -classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? +data.export = Eksportuj Dane +data.import = Importuj Dane +data.exported = Dane wyeksportowane. +data.invalid = Nieprawidłowe dane gry. +data.import.confirm = Zaimportowanie zewnętrznych danych usunie[scarlet] wszystkie[] obecne dane gry.\n[accent]Nie można tego cofnąć![]\n\nGdy dane zostaną zimportowane, gra automatycznie się wyłączy. +classic.export = Eksportuj dane wersji klasycznej +classic.export.text = [accent]Mindustry[] otrzymało ostatnio ważną aktualizację.\nClassic (v3.5 build 40) zapis albo mapa zostały wykryte. Czy chciałbyś eksportować te zapisy do katalogu domowego swojego telefonu, do użycia w aplikacji Mindustry Classic? quit.confirm = Czy na pewno chcesz wyjść? -quit.confirm.tutorial = Are you sure you know what you're doing?\nThe tutorial can be re-taken in[accent] Settings->Game->Re-Take Tutorial.[] +quit.confirm.tutorial = Czy jesteś pewien tego co robisz?\nSamouczek może zostać powtórzony w[accent] Opcje->Gra->Powtórz samouczek.[] loading = [accent]Ładowanie... saving = [accent]Zapisywanie... wave = [accent]Fala {0} wave.waiting = Fala za {0} -wave.waveInProgress = [LIGHT_GRAY]Wave in progress +wave.waveInProgress = [LIGHT_GRAY]Fala w trakcie waiting = [LIGHT_GRAY]Oczekiwanie... waiting.players = Oczekiwanie na graczy... wave.enemies = Pozostało [LIGHT_GRAY]{0} wrogów @@ -180,6 +206,9 @@ map.nospawn = Ta mapa nie zawiera żadnego rdzenia! Dodaj [ROYAL]niebieski[] rdz map.nospawn.pvp = Ta mapa nie ma żadnego rdzenia przeciwnika, aby mogli się zrespić przeciwnicy! Dodaj[SCARLET] inny niż niebieski[] rdzeń do mapy w edytorze. map.nospawn.attack = Ta mapa nie ma żadnego rdzenia przeciwnika, aby można było go zaatakować! Dodaj[SCARLET] czerwony[] rdzeń do mapy w edytorze. map.invalid = Błąd podczas ładowania mapy: uszkodzony lub niepoprawny plik mapy. +map.publish.error = Błąd podczas publikowania mapy: {0} +map.publish = Opublikowano mapę. +map.publishing = [accent]Publikowanie mapy... editor.brush = Pędzel editor.openin = Otwórz w edytorze editor.oregen = Generacja złóż @@ -188,19 +217,21 @@ editor.mapinfo = Informacje o mapie editor.author = Autor: editor.description = Opis: editor.waves = Fale: -editor.rules = Rules: -editor.generation = Generation: +editor.rules = Zasady: +editor.generation = Generacja: editor.ingame = Edytuj w grze -editor.newmap = New Map +editor.publish.workshop = Opublikuj w Workshop +editor.newmap = Nowa Mapa +workshop = Workshop waves.title = Fale waves.remove = Usuń waves.never = waves.every = co -waves.waves = wave(s) -waves.perspawn = per spawn +waves.waves = fal(e) +waves.perspawn = co pojawienie waves.to = do waves.boss = Boss -waves.preview = Preview +waves.preview = Podgląd waves.edit = Edytuj... waves.copy = Kopiuj do schowka waves.load = Załaduj ze schowka @@ -208,15 +239,17 @@ waves.invalid = Nieprawidłowe fale w schowku. waves.copied = Fale zostały skopiowane. waves.none = Brak zdefiniowanych wrogów.\nPamiętaj, że puste układy fal zostaną automatycznie zastąpione układem domyślnym. editor.default = [LIGHT_GRAY] +details = Detale... edit = Edytuj... editor.name = Nazwa: -editor.spawn = Spawn Unit -editor.removeunit = Remove Unit +editor.spawn = Stwórz jednostkę +editor.removeunit = Usuń jednostkę editor.teams = Drużyny editor.errorload = Błąd podczas ładowania pliku:\n[accent]{0} editor.errorsave = Błąd podczas zapisywania pliku:\n[accent]{0} editor.errorimage = To obraz, nie mapa. Nie zmieniaj rozszeżenia spodziewając sie że to coś zmieni.\n\nJeśli chcesz zaimportować starszą mapę, użyj przycisku „importuj starszą mapę” w edytorze. editor.errorlegacy = Ta mapa jest zbyt stara i używa starszego formatu mapy, który nie jest już obsługiwany. +editor.errornot = To nie jest plik mapy. editor.errorheader = Ten plik mapy jest nieprawidłowy lub uszkodzony. editor.errorname = Mapa nie zawiera nazwy. editor.update = Aktualizuj @@ -250,6 +283,7 @@ editor.mapname = Nazwa mapy: editor.overwrite = [accent]Uwaga!\nSpowoduje to nadpisanie istniejącej mapy. editor.overwrite.confirm = [scarlet]Uwaga![] Mapa pod tą nazwą już istnieje. Jesteś pewny, że chcesz ją nadpisać? editor.selectmap = Wybierz mapę do załadowania: + toolmode.replace = Zastąp toolmode.replace.description = Rysuje tylko na stałych blokach. toolmode.replaceall = Zastąp wszystko @@ -257,30 +291,31 @@ toolmode.replaceall.description = Zastąp wszystkie bloki na mapie. toolmode.orthogonal = Prostokątny toolmode.orthogonal.description = Rysuje tylko prostopadłe linie. toolmode.square = Kwadrat -toolmode.square.description = Square brush. +toolmode.square.description = Kwadratowy pędzel. toolmode.eraseores = Wymaż Rudy toolmode.eraseores.description = Usuń tylko rudy. toolmode.fillteams = Wypełń Drużyny toolmode.fillteams.description = Wypełniaj drużyny zamiast bloków. toolmode.drawteams = Rysuj Drużyny toolmode.drawteams.description = Rysuj drużyny zamiast bloków. -filters.empty = [LIGHT_GRAY]Brak filtrów! Dodaj jeden za pomocą przycisku poniżej. + +filters.empty = [LIGHT_GRAY]Brak filtrów! Dodaj jeden za pomocą przycisku poniżej. filter.distort = Zniekształcanie filter.noise = Szum -filter.median = Median -filter.oremedian = Ore Median -filter.blend = Blend +filter.median = Mediana +filter.oremedian = Mediana rud +filter.blend = Wtopienie filter.defaultores = Domyślne rudy filter.ore = Ruda filter.rivernoise = Szum rzeki filter.mirror = Lustro filter.clear = Oczyść -filter.option.ignore = Ignore -filter.scatter = Zozprosz +filter.option.ignore = Ignoruj +filter.scatter = Rozprosz filter.terrain = Teren filter.option.scale = Skala filter.option.chance = Szansa -filter.option.mag = Magnituda +filter.option.mag = Wielkość filter.option.threshold = Próg filter.option.circle-scale = Skala koła filter.option.octaves = Oktawy @@ -292,14 +327,15 @@ filter.option.flooronto = Podłoga Docelowa filter.option.wall = Ściana filter.option.ore = Ruda filter.option.floor2 = Druga podłoga -filter.option.threshold2 = Secondary Threshold +filter.option.threshold2 = Drugi próg filter.option.radius = Zasięg filter.option.percentile = Percentyl + width = Szerokość: height = Wysokość: menu = Menu play = Graj -campaign = Campaign +campaign = Kampania load = Wczytaj save = Zapisz fps = FPS: {0} @@ -308,10 +344,11 @@ ping = Ping: {0}ms language.restart = Uruchom grę ponownie, aby ustawiony język zaczął funkcjonować. settings = Ustawienia tutorial = Poradnik -tutorial.retake = Re-Take Tutorial +tutorial.retake = Ponów Samouczek editor = Edytor mapeditor = Edytor map donate = Wspomóż nas + abandon = Opuść abandon.text = Ta strefa i wszystkie jej surowce będą przejęte przez przeciwników. locked = Zablokowane @@ -322,21 +359,23 @@ bestwave = [LIGHT_GRAY]Najwyższa fala: {0} launch = < WYSTRZEL > launch.title = Wystrzelenie Udane launch.next = [LIGHT_GRAY]Następna okazja przy fali {0} -launch.unable2 = [scarlet]Unable to LAUNCH.[] +launch.unable2 = [scarlet]WYSTZRZELENIE niedostępne.[] launch.confirm = Spowoduje to wystrzelenie wszystkich surowców w rdzeniu.\nNie będziesz mógł wrócić do tej bazy. -launch.skip.confirm = If you skip now, you will not be able to launch until later waves. +launch.skip.confirm = Jeśli teraz przejdziesz do kolejnej fali, Nie biędziesz miał możliwości wystrzelenia do czasu pokonania dalszych fal. uncover = Odkryj configure = Skonfiguruj ładunek configure.locked = [LIGHT_GRAY]Dotrzyj do fali {0}\nAby skonfigurować ładunek. +configure.invalid = Ilość musi być liczbą pomiędzy 0 a {0}. zone.unlocked = [LIGHT_GRAY]Strefa {0} odblokowana. zone.requirement.complete = Fala {0} osiągnięta:\n{1} Wymagania strefy zostały spełnione. zone.config.complete = Fala {0} osiągnięta:\nKonfiguracja ładunku odblokowana. zone.resources = Wykryte Zasoby: -zone.objective = [lightgray]Objective: [accent]{0} +zone.objective = [lightgray]Cel: [accent]{0} zone.objective.survival = Przeżyj zone.objective.attack = Zniszcz Rdzeń Wroga add = Dodaj... -boss.health = Boss Health +boss.health = Zdrowie Bossa + connectfail = [crimson]Nie można połączyć się z serwerem:\n\n[accent]{0} error.unreachable = Serwer niedostępny.\nCzy adres jest wpisany poprawnie? error.invalidaddress = Niepoprawny adres. @@ -346,36 +385,39 @@ error.alreadyconnected = Jesteś już połączony. error.mapnotfound = Plik mapy nie został znaleziony! error.io = Błąd siecowy I/O. error.any = Nieznany błąd sieci. -error.bloom = Failed to initialize bloom.\nYour device may not support it. +error.bloom = Nie udało się załadować bloom.\nTwoje urządzenie może nie wspierać tej funkcji. + zone.groundZero.name = Wybuch Lądowy zone.desertWastes.name = Pustynne Pustkowia zone.craters.name = Kratery zone.frozenForest.name = Zamrożony Las -zone.ruinousShores.name = Zniszczone Przybrzerza +zone.ruinousShores.name = Zniszczone Przybrzeża zone.stainedMountains.name = Zabarwione Góry zone.desolateRift.name = Ponura Szczelina zone.nuclearComplex.name = Centrum Wyrobu Jądrowego zone.overgrowth.name = Przerośnięty Las zone.tarFields.name = Pola Smołowe -zone.saltFlats.name = Salt Flats +zone.saltFlats.name = Solne Równiny zone.impact0078.name = Uderzenie 0078 zone.crags.name = Urwisko -zone.fungalPass.name = Fungal Pass +zone.fungalPass.name = Grzybowa Przełęcz zone.groundZero.description = Optymalna lokalizacja, aby rozpocząć jeszcze raz. Niskie zagrożenie. Niewiele zasobów.\nZbierz jak najwięcej miedzi i ołowiu, tyle ile jest możliwe.\nPrzejdź do następnej strefy jak najszybciej. -zone.frozenForest.description = Nawet tutaj, bliżej gór, zarodniki rozprzestrzeniły się. Niskie temperatury nie mogą ich zatrzymać na zawsze.\n\nRozpocznij przedsięwzięcie od władzy. Buduj generatory spalinowe. Naucz się korzystać z naprawiaczy. -zone.desertWastes.description = These wastes are vast, unpredictable, and criss-crossed with derelict sector structures.\nCoal is present in the region. Burn it for power, or synthesize graphite.\n\n[lightgray]This landing location cannot be guaranteed. -zone.saltFlats.description = On the outskirts of the desert lie the Salt Flats. Few resources can be found in this location.\n\nThe enemy has erected a resource storage complex here. Eradicate their core. Leave nothing standing. -zone.craters.description = Water has accumulated in this crater, relic of the old wars. Reclaim the area. Collect sand. Smelt metaglass. Pump water to cool turrets and drills. -zone.ruinousShores.description = Past the wastes, is the shoreline. Once, this location housed a coastal defense array. Not much of it remains. Only the most basic defense structures have remained unscathed, everything else reduced to scrap.\nContinue the expansion outwards. Rediscover the technology. +zone.frozenForest.description = Nawet tutaj, bliżej gór, zarodniki rozprzestrzeniły się. Niskie temperatury nie mogą ich zatrzymać na zawsze.\n\nRozpocznij przedsięwzięcie od władzy. Buduj generatory spalinowe. Naucz się korzystać z naprawiaczy. +zone.desertWastes.description = Te pustkowia są rozległe, nieprzewidywalne, i znajdują się na nich opuszczone struktury.\nWęgiel jest obecny w tym regionie. Użyj go do produkcji energii, lub do stworzenia grafitu.\n\n[lightgray]Miejsce lądowania nie jest pewne. +zone.saltFlats.description = Na obrzeżach pustyni spoczywają Solne Równiny. Można tu znaleźć niewiele surowców.\n\nWrogowie zbudowali tu bazę składującą surowce. Zniszcz ich rdżeń. Zniszcz wszystko co stanie ci na drodze. +zone.craters.description = W tym kraterze zebrała się woda. Pozostałość dawnych wojen. Odzyskaj ten teren. Wykop piasek. Wytop metaszkło. Pompuj wodę do działek obronnych i wierteł by je schłodzić +zone.ruinousShores.description = Za pustkowiami ciągnie się linia brzegowa. Kiedyś znajdowała się tu przybrzeżna linia obronna. Niewiele z niej zostało. Ostały się tylko podstawowe struktury obronne, z reszty został tylko złom.\nKontynuuj eksploracje. Odkryj pozostawioną tu technologię. zone.stainedMountains.description = W głębi lądu leżą góry, jeszcze nieskażone przez zarodniki.\nWydobądź obfity tytan w tym obszarze. Dowiedz się, jak z niego korzystać.\n\nObecność wroga jest tutaj większa. Nie daj im czasu na wysłanie swoich najsilniejszych jednostek. zone.overgrowth.description = Obszar ten jest zarośnięty, bliżej źródła zarodników.\nWróg założył tu placówkę. Zbuduj jednostki Nóż. Zniszcz to. Odzyskaj to, co nam odebrano. zone.tarFields.description = Obrzeża strefy produkcji ropy, między górami a pustynią. Jeden z niewielu obszarów z rezerwami użytecznej smoły.\nMimo że ta strefa jest opuszczona, w pobliżu znajdują się niebezpieczne siły wroga. Nie lekceważ ich.\n\n[lightgray]Jeśli to możliwe, zbadaj technologię przetwarzania oleju. -zone.desolateRift.description = Strefa wyjątkowo niebezpieczna. Opfita w zasoby ale mało miejsca. Wysokie ryzyko zniszczenia. Opuść tę strefe jak najszybciej. Nie daj się zwieść długiemu odstępowi między atakami wroga. +zone.desolateRift.description = Strefa wyjątkowo niebezpieczna. Obfita w zasoby ale mało miejsca. Wysokie ryzyko zniszczenia. Opuść tę strefe jak najszybciej. Nie daj się zwieść długiemu odstępowi między atakami wroga. zone.nuclearComplex.description = Dawny zakład produkcji i przetwarzania toru, zredukowny do ruin.\n[lightgray]Zbadaj tor i jego zastosowania.\n\nWróg jest tutaj obecny w dużej ilości, nieustannie poszukuje napastników. -zone.fungalPass.description = A transition area between high mountains and lower, spore-ridden lands. A small enemy reconnaissance base is located here.\nDestroy it.\nUse Dagger and Crawler units. Take out the two cores. +zone.fungalPass.description = Przejściowy obszar pomiędzy wysokimi górami a nisko znajdującymi się, ogarniętymi przez zarodniki równinami. Znajduje się tu mała postawiona przez wrogów baza zwiadowcza.\nZniszcz ją.\nUżyj jednostek Nóż i Pełzak. Zniszcz oba rdżenie. zone.impact0078.description = zone.crags.description = + settings.language = Język +settings.data = Dane Gry settings.reset = Przywróć domyślne settings.rebind = Zmień settings.controls = Sterowanie @@ -393,14 +435,14 @@ no = Nie ma mowy! info.title = Informacje error.title = [crimson]Wystąpił błąd error.crashtitle = Wystąpił błąd -attackpvponly = [scarlet]Only available in Attack/PvP modes +attackpvponly = [scarlet]Dostępne tylko w trybach Atak/PvP blocks.input = Wejście blocks.output = Wyjście blocks.booster = Wzmacniacz block.unknown = [LIGHT_GRAY]??? blocks.powercapacity = Pojemność mocy blocks.powershot = moc/strzał -blocks.damage = Damage +blocks.damage = Obrażenia blocks.targetsair = Namierzanie wrogów powietrznych blocks.targetsground = Namierzanie wrogów lądowych blocks.itemsmoved = Prędkość poruszania się @@ -423,22 +465,26 @@ blocks.boosteffect = Efekt wzmocnienia blocks.maxunits = Maksymalna ilość jednostek blocks.health = Zdrowie blocks.buildtime = Czas budowy +blocks.buildcost = Koszt budowy blocks.inaccuracy = Niedokładność blocks.shots = Strzały blocks.reload = Strzałów/sekundę blocks.ammo = Amunicja -bar.drilltierreq = Better Drill Required + +bar.drilltierreq = Wymagane Lepsze Wiertło bar.drillspeed = Prędkość wiertła: {0}/s bar.efficiency = Efektywność: {0}% bar.powerbalance = Moc: {0} bar.poweramount = Moc: {0} bar.poweroutput = Wyjście mocy: {0} bar.items = Przedmiotów: {0} +bar.capacity = Pojemność: {0} bar.liquid = Płyn bar.heat = Ciepło bar.power = Prąd bar.progress = Postęp Budowy bar.spawned = Jednostki: {0}/{1} + bullet.damage = [stat]{0}[lightgray] Obrażenia bullet.splashdamage = [stat]{0}[lightgray] Obrażenia obszarowe ~[stat] {1}[lightgray] kratki bullet.incendiary = [stat]zapalający @@ -450,6 +496,7 @@ bullet.freezing = [stat]zamrażający bullet.tarred = [stat]smolny bullet.multiplier = [stat]{0}[lightgray]x mnożnik amunicji bullet.reload = [stat]{0}[lightgray]x szybkość ataku + unit.blocks = Klocki unit.powersecond = jednostek prądu na sekundę unit.liquidsecond = jednostek płynów na sekundę @@ -471,17 +518,17 @@ category.shooting = Strzelanie category.optional = Dodatkowe ulepszenia setting.landscape.name = Zablokuj tryb panoramiczny setting.shadows.name = Cienie -setting.linear.name = Linear Filtering +setting.linear.name = Filtrowanie Liniowe setting.animatedwater.name = Animowana woda setting.animatedshields.name = Animowana Tarcza setting.antialias.name = Antialias[LIGHT_GRAY] (wymaga restartu)[] setting.indicators.name = Wskaźniki Przyjaciół setting.autotarget.name = Automatyczne Celowanie -setting.keyboard.name = Mouse+Keyboard Controls +setting.keyboard.name = Sterowanie Myszka+Klawiatura setting.fpscap.name = Maksymalny FPS setting.fpscap.none = Nieograniczone setting.fpscap.text = {0} FPS -setting.uiscale.name = UI Scaling[lightgray] (require restart)[] +setting.uiscale.name = Skalowanie Interfejsu[lightgray] (wymaga restartu)[] setting.swapdiagonal.name = Pozwala na ukośne stawianie setting.difficulty.training = trening setting.difficulty.easy = Łatwy @@ -502,18 +549,21 @@ setting.lasers.name = Pokaż lasery zasilające setting.pixelate.name = Pikselacja [LIGHT_GRAY](wyłącza animacje) setting.minimap.name = Pokaż Minimapę setting.musicvol.name = Głośność muzyki -setting.ambientvol.name = Ambient Volume +setting.ambientvol.name = Głośność otoczenia setting.mutemusic.name = Wycisz muzykę setting.sfxvol.name = Głośność dźwięków setting.mutesound.name = Wycisz dźwięki setting.crashreport.name = Wysyłaj anonimowo dane o crashu gry +setting.savecreate.name = Automatyczne tworzenie zapisu +setting.publichost.name = Widoczność gry publicznej + setting.chatopacity.name = Przezroczystość czatu setting.playerchat.name = Wyświetlaj czat w grze -uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... -uiscale.cancel = Cancel & Exit +uiscale.reset = Skala interfejsu uległa zmianie.\nNaciśnij "OK" by potwierdzić zmiany.\n[scarlet]Cofanie zmian i wyjście z gry za[accent] {0}[] +uiscale.cancel = Anuluj i wyjdź setting.bloom.name = Bloom keybind.title = Zmień -keybinds.mobile = [scarlet]Most keybinds here are not functional on mobile. Only basic movement is supported. +keybinds.mobile = [scarlet]Większość skrótów klawiszowych nie funkcjonuje w wersji mobilnej. Tylko podstawowe poruszanie się jest wspierane. category.general.name = Ogólne category.view.name = Wyświetl category.multiplayer.name = Multiplayer @@ -527,8 +577,9 @@ keybind.press.axis = Naciśnij oś lub klawisz... keybind.screenshot.name = Zrzut ekranu mapy keybind.move_x.name = Poruszanie w poziomie keybind.move_y.name = Poruszanie w pionie +keybind.fullscreen.name = Toggle Fullscreen keybind.select.name = Zaznacz -keybind.diagonal_placement.name = Diagonal Placement +keybind.diagonal_placement.name = Budowa po skosie keybind.pick.name = Wybierz Blok keybind.break_block.name = Zniszcz Blok keybind.deselect.name = Odznacz @@ -537,7 +588,7 @@ keybind.zoom_hold.name = Inicjator przybliżania keybind.zoom.name = Przybliżanie keybind.menu.name = Menu keybind.pause.name = Pauza -keybind.minimap.name = Minimap +keybind.minimap.name = Minimapa keybind.dash.name = Przyspieszenie keybind.chat.name = Czat keybind.player_list.name = Lista graczy @@ -559,24 +610,25 @@ mode.pvp.description = Walcz przeciwko innym graczom. mode.attack.name = Atak mode.attack.description = Brak fal, celem jest zniszczenie bazy przeciwnika. mode.custom = Własny tryb + rules.infiniteresources = Nieskończone zasoby rules.wavetimer = Zegar fal rules.waves = Fale -rules.attack = Attack Mode +rules.attack = Tryb Ataku rules.enemyCheat = Nieskończone zasoby komputera-przeciwnika (czerwonego zespołu) -rules.unitdrops = Unit Drops +rules.unitdrops = Surowce z zniszczonych jednostek rules.unitbuildspeedmultiplier = Mnożnik Prędkości Tworzenia Jednostek rules.unithealthmultiplier = Mnożnik Życia Jednostek rules.playerhealthmultiplier = Mnożnik Życia Gracza rules.playerdamagemultiplier = Mnożnik Obrażeń Gracza rules.unitdamagemultiplier = Mnożnik Obrażeń Jednostek -rules.enemycorebuildradius = Enemy Core No-Build Radius:[LIGHT_GRAY] (tiles) -rules.respawntime = Respawn Time:[LIGHT_GRAY] (sec) +rules.enemycorebuildradius = Zasięg blokady budowy przy rdżeniu wroga:[LIGHT_GRAY] (kratki) +rules.respawntime = Czas Odrodzenia:[LIGHT_GRAY] (sek) rules.wavespacing = Odstępy między falami:[LIGHT_GRAY] (sek) rules.buildcostmultiplier = Mnożnik Kosztów Budowania rules.buildspeedmultiplier = Mnożnik Prędkości Budowania rules.waitForWaveToEnd = Fale czekają na przeciwników -rules.dropzoneradius = Drop Zone Radius:[LIGHT_GRAY] (tiles) +rules.dropzoneradius = Zasięg strefy zrzutu:[LIGHT_GRAY] (kratki) rules.respawns = Maksymalna ilośc odrodzeń na falę rules.limitedRespawns = Ogranicz Odrodzenia rules.title.waves = Fale @@ -585,11 +637,12 @@ rules.title.resourcesbuilding = Zasoby i Budowanie rules.title.player = Gracze rules.title.enemy = Przeciwnicy rules.title.unit = Jednostki + content.item.name = Przedmioty content.liquid.name = Płyny content.unit.name = Jednostki content.block.name = Klocki -content.mech.name = Mechs +content.mech.name = Mechy item.copper.name = Miedź item.lead.name = Ołów item.coal.name = Węgiel @@ -624,7 +677,7 @@ mech.omega-mech.weapon = Rakiety Chmarowe mech.omega-mech.ability = Układ Obronny mech.dart-ship.name = Strzałka mech.dart-ship.weapon = Karabin -mech.javelin-ship.name = Javelin +mech.javelin-ship.name = Oszczep mech.javelin-ship.weapon = Seria Rakiet mech.javelin-ship.ability = Wyładowania Dopalacza mech.trident-ship.name = Trójząb @@ -642,11 +695,12 @@ mech.itemcapacity = [LIGHT_GRAY]Pojemność przedmiotów: {0} mech.minespeed = [LIGHT_GRAY]Prędkość kopania: {0} mech.minepower = [LIGHT_GRAY]Moc kopania: {0} mech.ability = [LIGHT_GRAY]Umiejętność: {0} -mech.buildspeed = [LIGHT_GRAY]Building Speed: {0}% +mech.buildspeed = [LIGHT_GRAY]Szybkość Budowy: {0}% liquid.heatcapacity = [LIGHT_GRAY]Wytrzymałość na przegrzewanie: {0} liquid.viscosity = [LIGHT_GRAY]Lepkość: {0} liquid.temperature = [LIGHT_GRAY]Temperatura: {0} -block.sand-boulder.name = Sand Boulder + +block.sand-boulder.name = Piaskowy Głaz block.grass.name = Trawa block.salt.name = Sól block.saltrocks.name = Skały Solne @@ -657,7 +711,7 @@ block.spore-pine.name = Sosna Zarodkowa block.sporerocks.name = Skała z Zarodkami block.rock.name = Skały block.snowrock.name = Skały śnieżne -block.snow-pine.name = Snow Pine +block.snow-pine.name = Sosna śniegowa block.shale.name = Łupek block.shale-boulder.name = Głaz Łupkowy block.moss.name = Mech @@ -690,13 +744,13 @@ block.snow.name = Śnieg block.craters.name = Kratery block.sand-water.name = Woda z Piaskiem block.darksand-water.name = Woda z Ciemnym Piaskiem -block.char.name = Char -block.holostone.name = Holo stone +block.char.name = Popiół +block.holostone.name = Błyszczący kamień block.ice-snow.name = Lodowy Śnieg block.rocks.name = Skały block.icerocks.name = Lodowe skały block.snowrocks.name = Śnieżne Skały -block.dunerocks.name = Dune Rocks +block.dunerocks.name = Skały wydmowe block.pine.name = Sosna block.white-tree-dead.name = Białe Drzewo Martwe block.white-tree.name = Białe Drzewo @@ -715,7 +769,7 @@ block.dark-panel-6.name = Ciemny Panel 6 block.dark-metal.name = Ciemny Metal block.ignarock.name = Skała Wulkaniczna block.hotrock.name = Gorący Kamień -block.magmarock.name = Magma Rock +block.magmarock.name = Skała magmowa block.cliffs.name = Klify block.copper-wall.name = Miedziana Ściana block.copper-wall-large.name = Duża miedziana ściana @@ -730,7 +784,7 @@ block.door-large.name = Duże drzwi block.duo.name = Podwójne działko block.scorch.name = Płomień block.scatter.name = Flak -block.hail.name = Hail +block.hail.name = Grad block.lancer.name = Lancer block.conveyor.name = Przenośnik block.titanium-conveyor.name = Tytanowy przenośnik @@ -747,7 +801,7 @@ block.melter.name = Przetapiacz block.incinerator.name = Spalacz block.spore-press.name = Prasa Zarodni block.separator.name = Rozdzielacz -block.coal-centrifuge.name = Coal Centrifuge +block.coal-centrifuge.name = Wirówka węglowa block.power-node.name = Węzeł Prądu block.power-node-large.name = Duży Węzeł Prądu block.surge-tower.name = Wieża Energetyczna @@ -778,7 +832,7 @@ block.power-void.name = Próżnia prądu block.power-source.name = Nieskończony Prąd block.unloader.name = Ekstraktor block.vault.name = Magazyn -block.wave.name = Wave +block.wave.name = Strumyk block.swarmer.name = Działo Rojowe block.salvo.name = Działo Salwowe block.ripple.name = Działo falowe @@ -799,7 +853,7 @@ block.ghoul-factory.name = Fabryka Bombowców Upiór block.dagger-factory.name = Fabryka Mechów Nóż block.crawler-factory.name = Fabryka Mechów Pełzacz block.titan-factory.name = Fabryka Mechów Tytan -block.fortress-factory.name = Fabryka Mechów Fortreca +block.fortress-factory.name = Fabryka Mechów Forteca block.revenant-factory.name = Fabryka Wojowników Zjawa block.repair-point.name = Punkt Napraw block.pulse-conduit.name = Rura Pulsacyjna @@ -833,8 +887,8 @@ block.launch-pad.name = Wyrzutnia block.launch-pad-large.name = Duża Wyrzutnia team.blue.name = niebieski team.crux.name = czerwony -team.sharded.name = pomarańczowy -team.orange.name = orange +team.sharded.name = żółty +team.orange.name = pomarańczowy team.derelict.name = szary team.green.name = zielony team.purple.name = fioletowy @@ -855,32 +909,32 @@ unit.lich.name = Obudzony unit.reaper.name = Żeniec tutorial.next = [lightgray] tutorial.intro = Wszedłeś do[scarlet] Samouczka Mindustry.[]\nZacznij od[accent] wydobycia miedzi[]. Aby to zrobić, dotknij żyły rudy miedzi w pobliżu rdzenia.\n\n[accent]{0}/{1} miedź -tutorial.drill = Wydobywanie ręczne jest nieefektywne.\n[accent]Wiertła []mogą kopać automatycznie.\nKliknij zakładkę wiertła w prawym dolnym rogu.\nWybierz[accent] wiertło mechaniczne[]. Umieść go na złożu miedzi, klikając.\n[accent]Kliknij prawym przyciskiem myszy[], aby przestać budować. -tutorial.drill.mobile = Mining manually is inefficient.\n[accent]Drills []can mine automatically.\nTap the drill tab in the bottom right.\nSelect the[accent] mechanical drill[].\nPlace it on a copper vein by tapping, then press the[accent] checkmark[] below to confirm your selection.\nPress the[accent] X button[] to cancel placement. -tutorial.blockinfo = Each block has different stats. Each drill can only mine certain ores.\nTo check a block's info and stats,[accent] tap the "?" button while selecting it in the build menu.[]\n\n[accent]Access the Mechanical Drill's stats now.[] -tutorial.conveyor = [accent]Conveyors[] are used to transport items to the core.\nMake a line of conveyors from the drill to the core.\n[accent]Hold down the mouse to place in a line.[]\nHold[accent] CTRL[] while selecting a line to place diagonally.\n\n[accent]{0}/{1} conveyors placed in line\n[accent]0/1 items delivered -tutorial.conveyor.mobile = [accent]Conveyors[] are used to transport items to the core.\nMake a line of conveyors from the drill to the core.\n[accent] Place in a line by holding down your finger for a few seconds[] and dragging in a direction.\n\n[accent]{0}/{1} conveyors placed in line\n[accent]0/1 items delivered -tutorial.turret = Once an item enters your core, it can be used for building.\nKeep in mind that not all items can be used for building.\nItems that are not used for building, such as[accent] coal[] or[accent] scrap[], cannot be put into the core.\nDefensive structures must be built to repel the[lightgray] enemy[].\nBuild a[accent] duo turret[] near your base. -tutorial.drillturret = Duo turrets require[accent] copper ammo []to shoot.\nPlace a drill near the turret.\nLead conveyors into the turret to supply it with copper.\n\n[accent]Ammo delivered: 0/1 -tutorial.pause = During battle, you are able to[accent] pause the game.[]\nYou may queue buildings while paused.\n\n[accent]Press space to pause. -tutorial.pause.mobile = During battle, you are able to[accent] pause the game.[]\nYou may queue buildings while paused.\n\n[accent]Press this button in the top left to pause. -tutorial.unpause = Now press space again to unpause. -tutorial.unpause.mobile = Now press it again to unpause. -tutorial.breaking = Blocks frequently need to be destroyed.\n[accent]Hold down right-click[] to destroy all blocks in a selection.[]\n\n[accent]Destroy all the scrap blocks to the left of your core using area selection. -tutorial.breaking.mobile = Blocks frequently need to be destroyed.\n[accent]Select deconstruction mode[], then tap a block to begin breaking it.\nDestroy an area by holding down your finger for a few seconds[] and dragging in a direction.\nPress the checkmark button to confirm breaking.\n\n[accent]Destroy all the scrap blocks to the left of your core using area selection. -tutorial.withdraw = In some situations, taking items directly from blocks is necessary.\nTo do this, [accent]tap a block[] with items in it, then [accent]tap the item[] in the inventory.\nMultiple items can be withdrawn by [accent]tapping and holding[].\n\n[accent]Withdraw some copper from the core.[] -tutorial.deposit = Deposit items into blocks by dragging from your ship to the destination block.\n\n[accent]Deposit your copper back into the core.[] -tutorial.waves = The[lightgray] enemy[] approaches.\n\nDefend the core for 2 waves.[accent] Click[] to shoot.\nBuild more turrets and drills. Mine more copper. -tutorial.waves.mobile = The[lightgray] enemy[] approaches.\n\nDefend the core for 2 waves. Your ship will automatically fire at enemies.\nBuild more turrets and drills. Mine more copper. -tutorial.launch = Once you reach a specific wave, you are able to[accent] launch the core[], leaving your defenses behind and[accent] obtaining all the resources in your core.[]\nThese resources can then be used to research new technology.\n\n[accent]Press the launch button. +tutorial.drill = Wydobywanie ręczne nie jest efektywne.\n[accent]Wiertła []mogą kopać automatycznie.\nKliknij zakładkę wiertła w prawym dolnym rogu.\nWybierz[accent] wiertło mechaniczne[]. Umieść go na złożu miedzi, klikając.\n[accent]Kliknij prawym przyciskiem myszy[], aby przestać budować. +tutorial.drill.mobile = Wydobywanie ręczne jest nieefektywne.\n[accent]Wiertła []mogą kopać automatycznie.\nDotknij zakładkę wiertła w prawym dolnym rogu.\nWybierz[accent] wiertło mechaniczne[].\nUmieść go na złożu miedzi poprzez Stuknięcie, potem wciśnij[accent] ptaszek[] na dole by potwierdzić wybór.\nNaciśnij przycisk[accent] X[] by anulować budowe. +tutorial.blockinfo = Każdy blok ma inne statystyki. Każde wiertło może kopać tylko wybrane rudy.\nBy sprawdzić informacje i statystyki bloku,[accent] kliknij przycisk "?" podczas jego wyboru w menu budowy.[]\n\n[accent]Sprawdź teraz statystyki mechanicznego wiertła.[] +tutorial.conveyor = [accent]Przenośnik[] jest używany do transportowania przedmiotów do rdzenia.\nStwórz linie przenośników z wierteł do rdzenia.\n[accent]Przytrzymaj przycisk myszy by położyć w linii.[]\nPrzytrzymaj[accent] CTRL[] podczas wybierania linii, by budować po skosie.\n\n[accent]{0}/{1} Przenośniki położone w linii\n[accent]0/1 Przedmioty dostarczone +tutorial.conveyor.mobile = [accent]Przenośnik[] jest używany do transportowania przedmiotów do rdzenia.\nStwórz linie przenośników z wierteł do rdzenia.\n[accent] Zbuduj w linii poprzez przytrzymanie palcem przez moment[] i przesunięcie w którymś kierunku.\n\n[accent]{0}/{1} Przenośniki położone w linii\n[accent]0/1 Przedmioty dostarczone +tutorial.turret = Kiedy przedmiot dociera do rdzenia, może zostać użyty do budowy.\nPamiętaj że nie każdy przedmiot może zostać użyty do budowy.\nprzedmioty które nie są używane do budowy, takie jak[accent] Węgiel[] lub[accent] złom[], nie moga zostać wprowadzone do rdzenia.\nStruktury obronne muszą zostać zbudowane by odeprzeć[lightgray] wroga[].\nZbuduj[accent] podwójne działko[] niedaleko swojej bazy. +tutorial.drillturret = Podwójne działka wymagają[accent] miedzianej amunicji []do strzelania.\nPołóż wiertło obok działka.\nPoprowadź przenośniki do działek by zaopatrzyć je w miedź.\n\n[accent]Amunicja dostarczona: 0/1 +tutorial.pause = Podczas gry, możesz[accent] zatrzymać grę.[]\nMożesz ustalić kolejkę budowy podczas pauzy.\n\n[accent]Naciśnij spacje by zapauzować. +tutorial.pause.mobile = Podczas gry, możesz[accent] zatrzymać grę.[]\nMożesz ustalić kolejkę budowy podczas pauzy.\n\n[accent]Nacniśnij przycisk w lewym górnym rogu by zapauzować. +tutorial.unpause = Teraz znowu naciśnij spacje by odpauzować. +tutorial.unpause.mobile = Naciśnij go znowu by odpauzować. +tutorial.breaking = Bloki często wymagają rozbiórki.\n[accent]Przytrzymaj prawy przcisk myszy[] by niszczyć wszystkie wybrane bloki.[]\n\n[accent]Zniszcz wszystkie bloki złomu na lewo od twojego rdzenia używając selekcji obszarowej. +tutorial.breaking.mobile = Bloki często wymagają rozbiórki.\n[accent]Wybierz tryb dekonstrukcji[], a następnie dotknij blok by zacząć go niszczyć.\nZdekonstruuj obszarowo poprzez przytrzymanie palcem przez moment[] i przesunięcie go w jakimś kierunku.\nNaciśnij przycisk ptaszka by potwierdzić rozbiórkę.\n\n[accent]Zniszcz wszystkie bloki złomu na lewo od twojego rdzenia używając selekcji obszarowej. +tutorial.withdraw = Czasami, konieczne jest wyjmowanie przedmiotów prosto z bloków.\nBy tego dokonać, [accent]kliknij blok[] z przedmiotami w nim, potem [accent]kliknij przedmiot[] w inwentarzu.\nMożesz zebrać wiele przedmiotów naraz poprzez [accent]kliknięcie i przytrzymanie[].\n\n[accent]Zabierz trochę miedzi z rdzenia.[] +tutorial.deposit = Włóż przedmioty do bloków poprzez przeciągnięcie z twojego statku do danego bloku.\n\n[accent]Włóż miedź z powrotem do rdzenia .[] +tutorial.waves = [lightgray] Wrogowie[] nadchodzą.\n\nBroń swój rdżeń przez 2 fale.[accent] Kliknij[] by strzelać.\nZbuduj wiecej działek i wierteł. Wydobądź więcej miedzi. +tutorial.waves.mobile = [lightgray] Wrogowie[] nadchodzą.\n\nBroń swój rdzeń przez 2 fale. Twój statek będzie automatycznie atakował wrogów.\nZbuduj wiecej działek i wierteł. Wydobądź więcej miedzi. +tutorial.launch = Kiedy dotrzesz do określonej fali, masz możliwość[accent] wystrzelenia rdzenia[], pozostawiając struktury obronne za sobą i[accent] otrzymując wszystkie surowce znajdujące się w rdzeniu.[]\nSurowce te mogą potem zostać użyte do odkrywania nowych technologii.\n\n[accent]Naciśnij przycisk Wystrzału. item.copper.description = Przydatny materiał budowlany. Szeroko używany w prawie każdej konstrukcji. item.lead.description = Podstawowy matriał. Używany w przesyle przemiotów i płynów. Nie jest on przypadkiem szkodliwy? -item.metaglass.description = Niesamowite silne szkło. Szeroko używane w transporcie i przechowywaniu płynów. +item.metaglass.description = Wyjątkowo wytrzymały stop szkła. Szeroko używany w transporcie i przechowywaniu płynów. item.graphite.description = Zmineralizowany węgiel, wykorzystywany do amunicji i izolacji elektrycznej. item.sand.description = Zwykły materiał używany pospolicie w przepalaniu, stopach i jako topnik. Dostanie piaskiem po oczach nie jest przyjemne. item.coal.description = Zwykły i łatwo dostępny materiał energetyczny. item.titanium.description = Rzadki i bardzo lekki materiał. Używany w bardzo zaawansowanym przewodnictwie, wiertłach i samolotach. Poczuj się jak Tytan! -item.thorium.description = Zwarty i radioaktywny materiał używany w struktucrach i paliwie nuklearnym. Nie trzymaj go w rękach! +item.thorium.description = Zwarty i radioaktywny materiał używany w strukturach i paliwie nuklearnym. Nie trzymaj go w rękach! item.scrap.description = Pozostałości starych budynków i jednostek. Składa się z małej ilości wszystkiego. item.silicon.description = Niesamowicie przydatny półprzewodnk uźywany w panelach słonecznych i skomplikowanej elektronice. Nie, w Dolinie Krzemowej już nie ma krzemu. item.plastanium.description = Lekki i plastyczny materiał używany w amunicji odłamkowej i samolotach. Używany też w klockach LEGO (dlatego są niezniszczalne)! @@ -890,12 +944,12 @@ item.spore-pod.description = Używany do wyrobu oleju, materiałów wybuchowych item.blast-compound.description = Lotny związek używany w pirotechnice. Może być używany jako materiał energetyczny, ale nie polecam, ale i tak warto spróbować. item.pyratite.description = Niesamowicie palny związek używany w zbrojeniu. Nielegalny w 9 państwach. liquid.water.description = Powszechnie używana do schładzania budowli i przetwarzania odpadów. -liquid.slag.description = Various different types of molten metal mixed together. Can be separated into its constituent minerals, or sprayed at enemy units as a weapon. -liquid.oil.description = Może się palić, eksplodować lub być używana do schładzania. +liquid.slag.description = Wiele różnych metali stopionych i zmieszanych razem. Może zostać rozdzielony na jego metale składowe, albo wystrzelony w wrogie jednostki i użyty jako broń. +liquid.oil.description = Używany w do produkcji złożonych materiałów. Może zostać przetworzony na węgiel, lub wystrzelony w wrogów przez wieżyczke. liquid.cryofluid.description = Najefektywniejsza ciecz do schładzania budowli. mech.alpha-mech.description = Standardowy mech. Średnia broń i prędkość, leć potrafi stworzyć trzy małe drony do walki. -mech.delta-mech.description = Szybki i wrażliwy mech stworzony do szybkih ataków i ucieczki. Budynką robi prawie nic, lec jest wstanie szybko rozwalić grupę wrogich jednostek piorunami. -mech.tau-mech.description = Mech pomocny. Naprawia budynki drużyny, strzelając w nie. Potrafi wygasić niedalekie pożary i uleczyć bliskich przyjaciół. +mech.delta-mech.description = Szybki i wrażliwy mech stworzony do szybkich ataków i ucieczki. Zadaje niewielkie obrażenia strukturom, lecz może bardzo szybko niszczyć spore grupy jednostek wroga przy pomocy jego działek tesli. +mech.tau-mech.description = Mech wsparcia. Naprawia budynki drużyny, strzelając w nie. Potrafi wygasić niedalekie pożary i uleczyć bliskich przyjaciół. mech.omega-mech.description = Duży i silny mech, zaprojektowany na ataki. Jego zdolność pozwala mu na zablokowanie do 90% obrażeń. mech.dart-ship.description = Standardowy statek. Lekki i szybki, ale jest kiepski jak chodzi o walkę i kopanie. mech.javelin-ship.description = Statek do ataku i szybkiej ucieczki. Zaczyna powoli, ale przyspiesza do wielkiej prędkości. Przy tej prędkości, może przelecieć koło wrogiej bazy i atakować piorunami czy rakietami. @@ -908,12 +962,12 @@ unit.dagger.description = Podstawowy mech lądowy. Sam jest słaby, lecz przydat unit.crawler.description = Jednostka naziemna składająca się z rozebranej ramy z przypiętymi na górze materiałami wybuchowymi. Niezbyt trwały. Wybucha przy kontakcie z wrogami. Chodzi na czterech nogach jak pies. unit.titan.description = Zaawansowana, opancerzona jednostka naziemna. Atakuje zarówno cele naziemne, jak i powietrzne. Wyposażony w dwa miniaturowe miotacze ognia typu Płomień. unit.fortress.description = Ciężki mech artyleryjski. Wyposażony w dwa zmodyfikowane działa typu gradowego do ataku na dalekie odległości na konstrukcje i jednostki wroga. -unit.eruptor.description = A heavy mech designed to take down structures. Fires a stream of slag at enemy fortifications, melting them and setting volatiles on fire. +unit.eruptor.description = Ciężki mech stworzony do niszczenia struktur. Strzela wiązką żużlu w kierunku fortyfikacji wroga, Topiąc je oraz podpalając łatwopalne przedmioty. unit.wraith.description = Szybka jednostka, stosuje taktyke uderz-uciekaj Namierza jakiekolwiek źródło prądu. unit.ghoul.description = Ciężki bombowiec dywanowy. Rozdziera struktury wroga, atakując krytyczną infrastrukturę. unit.revenant.description = Ciężka, unosząca sie platforma z rakietami. block.graphite-press.description = Kompresuje kawałki węgla w czyste blaszki grafitu. -block.multi-press.description = An upgraded version of the graphite press. Employs water and power to process coal quickly and efficiently. +block.multi-press.description = Ulepszona wersja prasy grafitowej. Używa wody i prądu do kompresowania węgla szybko i efektywnie. block.silicon-smelter.description = Redukuje piasek za pomocą wysoce czystego węgla w celu wytworzenia krzemu. block.kiln.description = Stapia ołów i piasek na metaszkło. Wymaga małej ilości energii. block.plastanium-compressor.description = Wytwarza plastan z oleju i tytanu. @@ -921,9 +975,9 @@ block.phase-weaver.description = Produkuje Włókna Fazowe z radioaktywnego toru block.alloy-smelter.description = Produkuje stop Elektrum z tytanu, ołowiu, krzemu i miedzi. block.cryofluidmixer.description = Łączy wodę i tytan w lodociecz, który jest znacznie bardziej wydajny w chłodzeniu niż woda. block.blast-mixer.description = Kruszy i miesza skupiska zarodników z piratytem, tworząc związek wybuchowy. -block.pyratite-mixer.description = Mixes coal, lead and sand into highly flammable pyratite. +block.pyratite-mixer.description = Miesza węgiel, ołów i piasek tworząc bardzo łatwopalny piratian. block.melter.description = Przetapia złom na żużel do dalszego przetwarzania lub użycia w wieżyczkach -block.separator.description = Oddziel użyteczne materiały z mieszaniny jaką jest żużel. +block.separator.description = Oddziela użyteczne materiały z mieszaniny jaką jest żużel. block.spore-press.description = Kompresuje kapsułki zarodników w olej. block.pulverizer.description = Mieli złom w drobny piasek. Przydatne, gdy brakuje naturalnego piasku. block.coal-centrifuge.description = Zestala olej w kawałki węgla. @@ -945,21 +999,21 @@ block.surge-wall.description = Najsilniejszy blok obronny.\nMa niewielką szans block.surge-wall-large.description = Najsilniejszy blok obronny.\nMa niewielką szansę na wywołanie błyskawicy w kierunku atakującego.\nObejmuje wiele kratek. block.door.description = Małe drzwi, które można otwierać i zamykać, klikając na nie.\nJeśli są otwarte, wrogowie mogą strzelać i się przemieszczać przez nie. block.door-large.description = Duże drzwi, które można otwierać i zamykać, klikając na nie.\nJeśli są otwarte, wrogowie mogą strzelać i się przemieszczać przez nie.\nObejmuje wiele kratek. -block.mender.description = Periodically repairs blocks in its vicinity. Keeps defenses repaired in-between waves.\nOptionally uses silicon to boost range and efficiency. -block.mend-projector.description = Periodically heals blocks in its vicinity. -block.overdrive-projector.description = Increases the speed of nearby buildings like drills and conveyors. -block.force-projector.description = Creates a hexagonal force field around itself, protecting buildings and units inside from damage through bullets. -block.shock-mine.description = Damages enemies stepping on the mine. Nearly invisible to the enemy. -block.conveyor.description = Basic item transport block. Moves items forward and automatically deposits them into turrets or crafters. Rotatable. -block.titanium-conveyor.description = Advanced item transport block. Moves items faster than standard conveyors. -block.junction.description = Acts as a bridge for two crossing conveyor belts. Useful in situations with two different conveyors carrying different materials to different locations. +block.mender.description = Co jakiś czas naprawia bloki w zasięgu. Utrzymuje struktury obronne w dobrym stanie.\nOpcjonalnie używa silikonu do zwiększenia zasięgu i szybkości naprawy. +block.mend-projector.description = Co jakiś czas naprawia bloki w zasięgu. Lepsza wersja naprawiacza. +block.overdrive-projector.description = Zwiększa szybkość budynków w zasięgu takich jak wiertła czy przenośniki. +block.force-projector.description = Wytwarza pole siłowe w kształcie sześciokąta wokół siebie, chroniąc budynki i jednostki wewnątrz od obrażeń zadanych przez pociski. +block.shock-mine.description = Zadaje obrażenia jednostkom wroga którzy na nią wejdą. Ledwo widoczne dla wrogów. +block.conveyor.description = Podstawowy blok transportowy dla przedmiotów. Automatycznie przesyła przedmioty naprzód do działek oraz maszyn. Można obrócić. +block.titanium-conveyor.description = Zaawansowany blok transportowy dla przedmiotów. Przesyła przedmioty szybciej od zwykłego przenośnika. +block.junction.description = Używany jako most dla dwóch krzyżujących się przenośników. Przydatne w sytuacjach kiedy dwa różne przenośniki transportują różne surowce do różnych miejsc. block.bridge-conveyor.description = Zaawansowany blok transportujący. Pozwala na przenoszenie przedmiotów nawet do 3 bloków na każdym terenie, przez każdy budynek. -block.phase-conveyor.description = Advanced item transport block. Uses power to teleport items to a connected phase conveyor over several tiles. +block.phase-conveyor.description = Zaawansowany blok transportowy dla przedmiotów. Używa energii przy teleportacji przedmiotów do podłączonego transportera fazowego na spore odległości. block.sorter.description = Sortuje przedmioty. Jeśli przedmiot pasuje to przechodzi dalej, jeśli nie - to przechodzi na boki. block.router.description = Akceptuje przedmioty z jednego miejsca i rozdziela je do trzech innych kierunków. Przydatne w rozdzielaniu materiałów z jednego źródła do wielu celów. block.distributor.description = Zaawansowany rozdzielacz, rozdzielający przedmioty do 7 innych kierunków. block.overflow-gate.description = Rozdzielacz, który przerzuca przedmioty, kiedy główna droga jest przepełniona -block.mass-driver.description = Ultimate item transport block. Collects several items and then shoots them to another mass driver over a long range. +block.mass-driver.description = Najlepszy blok do transportu przedmiotów. Zbiera wiele przedmiotów naraz a potem wystrzeliwuje je do kolejnej katapulty masy na bardzo duże odległości. block.mechanical-pump.description = Tania pompa o niskiej przepustowości. Nie wymaga prądu. block.rotary-pump.description = Zaawansowana pompa, dwukrotnie większa przepustowość od mechanicznej pompy. Wymaga prądu. block.thermal-pump.description = Najlepsza pompa. Trzy razy szybsza od mechanicznej pompy i jedyna, która może wypompować lawę. @@ -971,41 +1025,41 @@ block.liquid-junction.description = Działa jak most dla dwóch krzyżujących s block.bridge-conduit.description = Zaawansowany blok przenoszący ciecze. Pozwala na przenoszenie cieczy nawet do 3 bloków na każdym terenie, przez każdy budynek. block.phase-conduit.description = Zaawansowany blok do przenoszenia cieczy. Używa prądu, aby przenieść ciecz do połączonego transportera fazowego przez kilka bloków. block.power-node.description = Przesyła moc do połączonych węzłów. Można podłączyć do czterech źródeł zasilania, zlewów lub węzłów. Zasila też bloki które go dotykają. -block.power-node-large.description = Has a larger radius than the power node and connects to up to six power sources, sinks or nodes. -block.surge-tower.description = An extremely long-range power node with fewer available connections. -block.battery.description = Stores power whenever there is an abundance and provides power whenever there is a shortage, as long as there is capacity left. -block.battery-large.description = Stores much more power than a regular battery. +block.power-node-large.description = Posiada większy zasięg niż zwykły węzeł prądu. Można podłączyć do sześciu źródeł zasilania, zlewów lub węzłów. +block.surge-tower.description = Węzęł prądu z bardzo dużym zasięgiem, posiadający mniej możliwych podłączeń. +block.battery.description = Przechowuje energię przy nadwyżce produkcji oraz dostarcza energię kiedy jest jej brak, dopóki jest w niej miejsce. +block.battery-large.description = Przechowuje o wiele wiecej prądu niż standardowa bateria. block.combustion-generator.description = Wytwarza energię poprzez spalanie łatwopalnych materiałów. -block.thermal-generator.description = Generates power when placed in hot locations. +block.thermal-generator.description = Generuje prąd kiedy jest postawiony na źródłach ciepła. block.turbine-generator.description = Bardziej wydajny niż generator spalania, ale wymaga dodatkowej wody. -block.differential-generator.description = Generates large amounts of energy. Utilizes the temperature difference between cryofluid and burning pyratite. -block.rtg-generator.description = A radioisotope thermoelectric generator which does not require cooling but provides less power than a thorium reactor. -block.solar-panel.description = Provides a small amount of power from the sun. -block.solar-panel-large.description = Provides much better power supply than a standard solar panel, but is also much more expensive to build. -block.thorium-reactor.description = Generates huge amounts of power from highly radioactive thorium. Requires constant cooling. Will explode violently if insufficient amounts of coolant are supplied. Power output depends on fullness, with base power generated at full capacity. -block.impact-reactor.description = An advanced generator, capable of creating massive amounts of power at peak efficiency. Requires a significant power input to kickstart the process. +block.differential-generator.description = Generuje duże ilości prądu. Wykorzystuje różnice temperatur pomiędzy Lodocieczą a spalanym Piratianem. +block.rtg-generator.description = Termoelektryczny generator wykorzystujący izotopy promieniotwórcze. Nie wymaga chłodzenia, ale produkuje mniej energii od reaktora torowego. +block.solar-panel.description = Wytwarza małe ilości prądu wykorzystując energię słoneczną. +block.solar-panel-large.description = Wytwarza o wiele więcej prądu niż zwykły panel słoneczny, ale jest o wiele droższy w budowie. +block.thorium-reactor.description = Produkuje bardzo duże ilości prądu z wysoce radioaktywnego toru. Wymaga ciągłego chłodzenia. Silnie eksploduje jeśli nie zostanie dostarczona wystarczająca ilość chłodziwa. Produkcja energii zależy od zapełnienia, produkując bazową ilość energii przy całkowitym zapełnieniu. +block.impact-reactor.description = Zaawansowany generator, zdolny do produkcji ogromnych ilości prądu u szczytu swoich możliwości. Wymaga znacznych ilości energii do rozpoczęcia procesu. block.mechanical-drill.description = Tanie wiertło. Kiedy położnone na odpowiednich polach, wysyła przedmioty w wolnym tempie. -block.pneumatic-drill.description = An improved drill which is faster and able to process harder materials by making use of air pressure. -block.laser-drill.description = Allows drilling even faster through laser technology, but requires power. Additionally, radioactive thorium can be retrieved with this drill. -block.blast-drill.description = The ultimate drill. Requires large amounts of power. +block.pneumatic-drill.description = Ulepszone wiertło, które jest szybsze i może wykopywać twardsze surowce przy użyciu ciśnienia. +block.laser-drill.description = Pozwala kopać jeszcze szybciej poprzez technologię laserową, ale wymaga energii. Dodatkowo, radioaktywny tor może zostać wydobyty przez to wiertło. +block.blast-drill.description = Najlepsze wiertło. Wymaga dużych ilości energii. block.water-extractor.description = Wydobywa wodę z ziemi. Użyj go, gdy w pobliżu nie ma jeziora. block.cultivator.description = Uprawia małe skupiska zarodników w gotowe do użytku kapsułki. -block.oil-extractor.description = Uses large amounts of power in order to extract oil from sand. Use it when there is no direct source of oil nearby. -block.core-shard.description = The first iteration of the core capsule. Once destroyed, all contact to the region is lost. Do not let this happen. -block.core-foundation.description = The second version of the core. Better armored. Stores more resources. -block.core-nucleus.description = The third and final iteration of the core capsule. Extremely well armored. Stores massive amounts of resources. -block.vault.description = Stores a large amount of items of each type. An[LIGHT_GRAY] unloader[] can be used to retrieve items from the vault. -block.container.description = Stores a small amount of items of each type. An[LIGHT_GRAY] unloader[] can be used to retrieve items from the container. -block.unloader.description = Unloads items from a container, vault or core onto a conveyor or directly into an adjacent block. The type of item to be unloaded can be changed by tapping on the unloader. -block.launch-pad.description = Launches batches of items without any need for a core launch. Unfinished. -block.launch-pad-large.description = An improved version of the launch pad. Stores more items. Launches more frequently. -block.duo.description = Mała, tania wieża. Przydatny przeciwko jednostkom naziemnym. +block.oil-extractor.description = Używa bardzo dużych ilości energii do ekstrakcji ropy z piasku. Używaj go w sytuacji kiedy nie ma bezpośredniego źródła ropy w okolicy. +block.core-shard.description = Pierwsza wersja rdzenia. Gdy zostaje zniszczony, wszelki kontakt do regionu zostaje utracony. Nie pozwól na to. +block.core-foundation.description = Druga wersja rdzenia. Lepiej opancerzony. Przechowuje więcej surowców. +block.core-nucleus.description = Trzecia i ostatnia wersja rdzenia. Bardzo dobrze opanczerzony. Przechowuje ogromne ilości surowców. +block.vault.description = Przechowuje duże ilości przedmiotów każdego rodzaju. [LIGHT_GRAY] Ekstraktor[] może zostać użyty do rozładowania magazynu. +block.container.description = Przechowuje małe ilości przedmiotów każdego rodzaju. [LIGHT_GRAY] ekstraktor[] może zostać użyty do rozładowania kontenera. +block.unloader.description = Wyciąga przedmioty z kontenera, magazynu oraz rdżenia na przenośniki lub bezpośrednio na przyległe bloki. Typ przedmiotu jaki zostanie wyciągniety może zostać zmieniony poprzez kliknięcie. +block.launch-pad.description = Wysyła pakiety przedmiotów bez potrzeby wystrzeliwania rdżenia. Niedokończona. +block.launch-pad-large.description = Ulepszona wersja wyrzutni. Magazynuje więcej przedmiotów. Wysyła częściej. +block.duo.description = Mała, tania wieża. Przydatna przeciwko jednostkom naziemnym. block.scatter.description = Średniej wielkości wieża przeciwlotnicza. Rozsiewa śruty z ołowiu lub strzępy złomu na jednostki wroga. block.scorch.description = Spala wszystkich wrogów naziemnych w pobliżu. Bardzo skuteczny z bliskiej odległości. block.hail.description = Mała wieża artyleryjska, bardzo przydatna, atakuje tylko jednostki naziemne. block.wave.description = Średniej wielkości szybkostrzelna wieżyczka, która wystrzeliwuje płynne bąbelki. Gasi ogień jeżeli jest w niej woda lub lodociecz block.lancer.description = Średniej wielkości wieżyczka, która strzela naładowanymi wiązkami elektryczności. -block.arc.description = Mała wieża bliskiego zasięgu, która wystrzeliwuje elektryczność losowym łukiem w kierunku wroga. +block.arc.description = Mała wieża bliskiego zasięgu, która wystrzeliwuje wiązki tesli losowym łukiem w kierunku wroga. block.swarmer.description = Średniej wielkości wieżyczka, która strzela rakietami wybuchowymi. block.salvo.description = Średniej wielkości wieża strzelająca salwami. block.fuse.description = Duża wieża, która strzela potężnymi wiązkami krótkiego zasięgu. @@ -1016,19 +1070,19 @@ block.meltdown.description = Duża wieża, która strzela potężnymi wiązkami block.command-center.description = Wydaje polecenia ruchu sojuszniczym jednostkom na całej mapie.\nPowoduje patrolowanie jednostek, atakowanie wrogiego rdzenia lub wycofanie się do rdzenia / fabryki. Gdy nie ma rdzenia wroga, jednostki będą domyślnie patrolować pod dowództwem ataku. block.draug-factory.description = Produkuje drony wydobywcze Draug. block.spirit-factory.description = Produkuje lekkie drony, które naprawiają bloki. -block.phantom-factory.description = Produkuje zaawansowane drony które pomgają przy budowie. -block.wraith-factory.description = Produces fast, hit-and-run interceptor units. -block.ghoul-factory.description = Produces heavy carpet bombers. -block.revenant-factory.description = Produces heavy laser air units. -block.dagger-factory.description = Produces basic ground units. -block.crawler-factory.description = Produces fast self-destructing swarm units. -block.titan-factory.description = Produces advanced, armored ground units. -block.fortress-factory.description = Produces heavy artillery ground units. +block.phantom-factory.description = Produkuje zaawansowane drony które pomagają przy budowie. +block.wraith-factory.description = Produkuje szybkie jednostki powietrzne typu "uderz-uciekaj". +block.ghoul-factory.description = Produkuje ciężkie bombowce dywanowe. +block.revenant-factory.description = Produkuje ciężkie jednostki powietrzne z wyrzutniami rakiet. +block.dagger-factory.description = Produkuje podstawowe jednostki lądowe. +block.crawler-factory.description = Produkuje szybkie jednostki lądowe typu "kamikaze". +block.titan-factory.description = Produkuje zaawansowane, opancerzone jednostki lądowe. +block.fortress-factory.description = Produkuje naziemne jednostki ciężkiej artylerii. block.repair-point.description = Bez przerw ulecza najbliższą zniszczoną jednostkę w jego zasięgu. -block.dart-mech-pad.description = Provides transformation into a basic attack mech.\nUse by tapping while standing on it. -block.delta-mech-pad.description = Leave your current vessel and change into a fast, lightly-armored mech made for hit-and-run attacks.\nUse the pad by double tapping while standing on it. -block.tau-mech-pad.description = Leave your current vessel and change into a support mech which can heal friendly buildings and units.\nUse the pad by double tapping while standing on it. -block.omega-mech-pad.description = Leave your current vessel and change into a bulky and well-armored mech, made for front-line assaults.\nUse the pad by double tapping while standing on it. -block.javelin-ship-pad.description = Leave your current vessel and change into a strong and fast interceptor with lightning weapons.\nUse the pad by double tapping while standing on it. -block.trident-ship-pad.description = Leave your current vessel and change into a reasonably well armored heavy bomber.\nUse the pad by double tapping while standing on it. -block.glaive-ship-pad.description = Leave your current vessel and change into a large, well-armored gunship.\nUse the pad by double tapping while standing on it. +block.dart-mech-pad.description = Umożliwia transformacje w podstawowego mecha bojowego.\nUżyj klikając podczas stania na nim. +block.delta-mech-pad.description = Opuść swój obecny statek i zamień go na szybki, lekko opancerzony mech stworzony do ataków typu uderz-uciekaj.\nUżyj, klikając dwukrotnie podczas stania na lądowisku. +block.tau-mech-pad.description = Opuść swój obecny statek i zamień go na mech wsparcia który może leczyć sojusznicze struktury i jednostki.\nUżyj, klikając dwukrotnie podczas stania na lądowisku. +block.omega-mech-pad.description = Opuść swój obecny statek i zamień go na masywny, dobrze opancerzony mech, przeznaczony do ataków na froncie.\nUżyj, klikając dwukrotnie podczas stania na lądowisku. +block.javelin-ship-pad.description = Opuść swój obecny statek i zamień go na silny i szybki statek przechwytujący z bronią błyskawicową.\nUżyj, klikając dwukrotnie podczas stania na lądowisku. +block.trident-ship-pad.description = Opuść swój obecny statek i zamień go na dość dobrze opancerzony ciężki bombowiec.\nUżyj, klikając dwukrotnie podczas stania na lądowisku. +block.glaive-ship-pad.description = Opuść swój obecny statek i zamień go na duży, mocno opancerzony statek bojowy.\nUżyj, klikając dwukrotnie podczas stania na lądowisku. diff --git a/core/assets/bundles/bundle_pt_BR.properties b/core/assets/bundles/bundle_pt_BR.properties index 277931b660..3778f52ee0 100644 --- a/core/assets/bundles/bundle_pt_BR.properties +++ b/core/assets/bundles/bundle_pt_BR.properties @@ -16,6 +16,11 @@ screenshot.invalid = Mapa grande demais, Potencialmente sem memoria suficiente p gameover = O núcleo foi destruído. gameover.pvp = O time[accent] {0}[] É vitorioso! highscore = [YELLOW]Novo recorde! +load.sound = Sounds +load.map = Maps +load.image = Images +load.content = Content +load.system = System stat.wave = Hordas derrotadas:[accent] {0} stat.enemiesDestroyed = Enimigos Destruídos:[accent] {0} stat.built = Construções construídas:[accent] {0} @@ -23,8 +28,6 @@ stat.destroyed = Construções destruídas:[accent] {0} stat.deconstructed = Construções desconstruídas:[accent] {0} stat.delivered = Recursos lançados: stat.rank = Rank Final: [accent]{0} -placeline = Você selecionou um bloco.\nVocê pode[accent] colocar uma linha[] por[accent] carregar o seu dedo por alguns segundos[] e arrastar em uma direção.\nTente. -removearea = Você selecionou o modo de remoção.\nVocê pode[accent] remover blocos dentro de um retângulo[] por[accent] carregar o seu dedo por alguns segundos[] e arrastar.\nTente. launcheditems = [accent]Itens lançados map.delete = Certeza que quer deletar o mapa "[accent]{0}[]"? level.highscore = Melhor\npontuação: [accent] {0} @@ -63,9 +66,11 @@ players.single = {0} Jogador Ativo server.closing = [accent]Fechando servidor... server.kicked.kick = Voce foi expulso do servidor! server.kicked.serverClose = Servidor Fechado. +server.kicked.vote = You have been vote-kicked. Goodbye. server.kicked.clientOutdated = Cliente desatualizado! Atualize seu jogo! server.kicked.serverOutdated = Servidor desatualiado! Peca ao dono para atualizar! server.kicked.banned = Voce foi banido do servidor. +server.kicked.typeMismatch = This server is not compatible with your build type. server.kicked.recentKick = Voce foi banido recentemente.\nEspere para conectar de novo. server.kicked.nameInUse = Este nome ja esta sendo usado\nneste servidor. server.kicked.nameEmpty = Voce deve ter pelo menos uma letra ou numero. @@ -156,6 +161,11 @@ cancel = Cancelar openlink = Abrir Link copylink = Copiar link back = Voltar +data.export = Export Data +data.import = Import Data +data.exported = Data exported. +data.invalid = This isn't valid game data. +data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. classic.export = Export Classic Data classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? quit.confirm = Você tem certeza que quer sair? @@ -376,6 +386,7 @@ zone.fungalPass.description = A transition area between high mountains and lower zone.impact0078.description = zone.crags.description = settings.language = Linguagem +settings.data = Game Data settings.reset = Restaurar Padrões settings.rebind = Religar settings.controls = Controles @@ -507,6 +518,7 @@ setting.mutemusic.name = Desligar Música setting.sfxvol.name = Volume de Efeitos setting.mutesound.name = Desligar Som setting.crashreport.name = Enviar denuncias de crash anonimas +setting.savecreate.name = Auto-Create Saves setting.chatopacity.name = Opacidade do chat setting.playerchat.name = Mostrar chat em-jogo uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... @@ -527,6 +539,7 @@ keybind.press.axis = Pressione uma Axis ou tecla... keybind.screenshot.name = Captura do mapa keybind.move_x.name = mover_x keybind.move_y.name = mover_y +keybind.fullscreen.name = Toggle Fullscreen keybind.select.name = selecionar keybind.diagonal_placement.name = Colocação diagonal keybind.pick.name = Pegar bloco @@ -790,6 +803,7 @@ block.blast-mixer.name = Misturador de Explosão block.solar-panel.name = Painel Solar block.solar-panel-large.name = Painel Solar Grande block.oil-extractor.name = Extrator de Óleo +block.command-center.name = Command Center block.draug-factory.name = Draug Miner Drone Factory block.spirit-factory.name = Fabrica de Drone Spirit block.phantom-factory.name = Fabrica de Drone Phantom @@ -1012,6 +1026,7 @@ block.ripple.description = Uma grande torre que atira simultaneamente. block.cyclone.description = Uma grande torre de tiro rapido. block.spectre.description = Uma grande torre que da dois tiros poderosos ao mesmo tempo. block.meltdown.description = Uma grande torre que atira dois raios poderosos ao mesmo tempo. +block.command-center.description = Issues movement commands to allied units across the map.\nCauses units to patrol, attack an enemy core or retreat to the core/factory. When no enemy core is present, units will default to patrolling under the attack command. block.draug-factory.description = Produces Draug mining drones. block.spirit-factory.description = Produz drones leves que mineram e reparam blocos. block.phantom-factory.description = Produz unidades de drone avancadas Que são significativamente mais efetivos que um drone spirit. diff --git a/core/assets/bundles/bundle_ru.properties b/core/assets/bundles/bundle_ru.properties index ca8d96e388..eaf1a6be70 100644 --- a/core/assets/bundles/bundle_ru.properties +++ b/core/assets/bundles/bundle_ru.properties @@ -403,7 +403,6 @@ zone.saltFlats.name = Соляные равнины zone.impact0078.name = Воздействие 0078 zone.crags.name = Скалы zone.fungalPass.name = Грибной перевал - zone.groundZero.description = Оптимальная локация для повторных игр. Низкая вражеская угроза. Немного ресурсов.\nСоберите как можно больше свинца и меди.\nДвигайтесь дальше. zone.frozenForest.description = Даже здесь, ближе к горам, споры распространились. Холодные температуры не могут сдерживать их вечно.\n\nНачните вкладываться в энергию. Постройте генераторы внутреннего сгорания. Научитесь пользоваться регенератором. zone.desertWastes.description = Эти пустоши огромны, непредсказуемы и пронизаны заброшенными секторальными структурами.\nВ регионе представлен уголь. Сожгите его для энергии, или синтезируйте в графит.\n\n[lightgray]Место посадки здесь может не быть гарантировано. diff --git a/core/assets/bundles/bundle_se.properties b/core/assets/bundles/bundle_se.properties index 2d6984585f..eecfa31b6f 100644 --- a/core/assets/bundles/bundle_se.properties +++ b/core/assets/bundles/bundle_se.properties @@ -16,6 +16,11 @@ screenshot.invalid = Map too large, potentially not enough memory for screenshot gameover = Game Over gameover.pvp = The[accent] {0}[] team is victorious! highscore = [accent]Nytt rekord! +load.sound = Sounds +load.map = Maps +load.image = Images +load.content = Content +load.system = System stat.wave = Waves Defeated:[accent] {0} stat.enemiesDestroyed = Enemies Destroyed:[accent] {0} stat.built = Buildings Built:[accent] {0} @@ -23,8 +28,6 @@ stat.destroyed = Buildings Destroyed:[accent] {0} stat.deconstructed = Buildings Deconstructed:[accent] {0} stat.delivered = Resources Launched: stat.rank = Final Rank: [accent]{0} -placeline = Du har valt ett block.\nDu kan[accent] placera i en linje[] genom att[accent] hålla ner ett finger i några sekunder[] och sedan dra åt ett håll.\n\n[scarlet]GÖR DET. -removearea = Du har valt borttagningsläget.\nDu kan[accent] ta bort block inom en rektangel[] genom att[accent] hålla ner ett finger i några sekunder[] och dra.\n\n[scarlet]GÖR DET. launcheditems = [accent]Launched Items map.delete = Are you sure you want to delete the map "[accent]{0}[]"? level.highscore = High Score: [accent]{0} @@ -63,9 +66,11 @@ players.single = {0} spelare online server.closing = [accent]Stänger server... server.kicked.kick = You have been kicked from the server! server.kicked.serverClose = Server stängd. +server.kicked.vote = You have been vote-kicked. Goodbye. server.kicked.clientOutdated = Outdated client! Uppdatera ditt spel! server.kicked.serverOutdated = Outdated server! Ask the host to update! server.kicked.banned = Du är bannad från servern. +server.kicked.typeMismatch = This server is not compatible with your build type. server.kicked.recentKick = You have been kicked recently.\nWait before connecting again. server.kicked.nameInUse = Någon med det namnet finns redan\npå servern. server.kicked.nameEmpty = Ditt namn är ogiltigt. @@ -156,6 +161,11 @@ cancel = Avbryt openlink = Öppna Länk copylink = Kopiera Länk back = Tillbaka +data.export = Export Data +data.import = Import Data +data.exported = Data exported. +data.invalid = This isn't valid game data. +data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. classic.export = Exportera Classic-Data classic.export.text = Sparad data från Classic (v3.5 build 40) har hittats. Vill du exportera den här datan till telefonens hem-mapp för att använda i Mindustry Classic-appen? quit.confirm = Är du säker på att du vill avsluta? @@ -376,6 +386,7 @@ zone.fungalPass.description = A transition area between high mountains and lower zone.impact0078.description = zone.crags.description = settings.language = Språk +settings.data = Game Data settings.reset = Återställ till Standardvärden settings.rebind = Byt settings.controls = Kontroller @@ -507,6 +518,7 @@ setting.mutemusic.name = Stäng Av Musik setting.sfxvol.name = Ljudeffektvolym setting.mutesound.name = Stäng Av Ljudeffekter setting.crashreport.name = Skicka Anonyma Krashrapporter +setting.savecreate.name = Auto-Create Saves setting.chatopacity.name = Chattgenomskinlighet setting.playerchat.name = Visa Chatt uiscale.reset = UI-skalan har ändrats.\nTryck "OK" för att använda den här skalan.\n[scarlet]Avslutar och återställer om[accent] {0}[] sekunder... @@ -527,6 +539,7 @@ keybind.press.axis = Press an axis or key... keybind.screenshot.name = Map Screenshot keybind.move_x.name = Move x keybind.move_y.name = Move y +keybind.fullscreen.name = Toggle Fullscreen keybind.select.name = Select/Shoot keybind.diagonal_placement.name = Diagonal Placement keybind.pick.name = Pick Block @@ -790,6 +803,7 @@ block.blast-mixer.name = Blast Mixer block.solar-panel.name = Solpanel block.solar-panel-large.name = Stor Solpanel block.oil-extractor.name = Oljeextraktor +block.command-center.name = Command Center block.draug-factory.name = Draug Miner Drone Factory block.spirit-factory.name = Spirit Repair Drone Factory block.phantom-factory.name = Phantom Builder Drone Factory @@ -1012,6 +1026,7 @@ block.ripple.description = An extremely poweful artillery turret. Shoots cluster block.cyclone.description = A large anti-air and anti-ground turret. Fires explosive clumps of flak at nearby units. block.spectre.description = A massive dual-barreled cannon. Shoots large armor-piercing bullets at air and ground targets. block.meltdown.description = A massive laser cannon. Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate. +block.command-center.description = Issues movement commands to allied units across the map.\nCauses units to patrol, attack an enemy core or retreat to the core/factory. When no enemy core is present, units will default to patrolling under the attack command. block.draug-factory.description = Produces Draug mining drones. block.spirit-factory.description = Produces Spirit structural repair drones. block.phantom-factory.description = Produces advanced construction drones. diff --git a/core/assets/bundles/bundle_tk.properties b/core/assets/bundles/bundle_tk.properties index 1b7b93265a..a44ecdd746 100644 --- a/core/assets/bundles/bundle_tk.properties +++ b/core/assets/bundles/bundle_tk.properties @@ -16,6 +16,11 @@ screenshot.invalid = Map too large, potentially not enough memory for screenshot gameover = Cekirdegin yok edildi. gameover.pvp = The[accent] {0}[] team is victorious! highscore = [accent]Yeni Yuksek skor! +load.sound = Sounds +load.map = Maps +load.image = Images +load.content = Content +load.system = System stat.wave = Waves Defeated:[accent] {0} stat.enemiesDestroyed = Enemies Destroyed:[accent] {0} stat.built = Buildings Built:[accent] {0} @@ -23,8 +28,6 @@ stat.destroyed = Buildings Destroyed:[accent] {0} stat.deconstructed = Buildings Deconstructed:[accent] {0} stat.delivered = Resources Launched: stat.rank = Final Rank: [accent]{0} -placeline = You have selected a block.\nYou can[accent] place in a line[] by[accent] holding down your finger for a few seconds[] and dragging in a direction.\nTry it. -removearea = You have selected removal mode.\nYou can[accent] remove blocks in a rectangle[] by[accent] holding down your finger for a few seconds[] and dragging.\nTry it. launcheditems = [accent]Launched Items map.delete = Su haritayi silmek istediginden emin misin? "[accent]{0}[]"? level.highscore = Yuksek Skor: [accent]{0} @@ -63,9 +66,11 @@ players.single = {0} oyuncu cevrimici server.closing = [accent]Oyun kapaniyor. server.kicked.kick = Oyundan cikarildin server.kicked.serverClose = Oyun kapandi +server.kicked.vote = You have been vote-kicked. Goodbye. server.kicked.clientOutdated = Yeni bir versiyon mevcut! Hemen indir! server.kicked.serverOutdated = Eski oyun! Yapimciya guncellemesini soyle! server.kicked.banned = Oyundan kalici olarak cikarildin. +server.kicked.typeMismatch = This server is not compatible with your build type. server.kicked.recentKick = Oyundan cikarilmistin.\nBaglanmadn once biraz bekle. server.kicked.nameInUse = Oyunda bu isimde bir\nkisi zaten var. server.kicked.nameEmpty = ismin gecerli degil. @@ -156,6 +161,11 @@ cancel = iptal openlink = Linki ac copylink = Linki kopyala back = Geri don +data.export = Export Data +data.import = Import Data +data.exported = Data exported. +data.invalid = This isn't valid game data. +data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. classic.export = Export Classic Data classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? quit.confirm = Cikmak istedigine emin misin? @@ -376,6 +386,7 @@ zone.fungalPass.description = A transition area between high mountains and lower zone.impact0078.description = zone.crags.description = settings.language = Dil +settings.data = Game Data settings.reset = ilk ayarlara geri al settings.rebind = Geri al settings.controls = Kontroller @@ -507,6 +518,7 @@ setting.mutemusic.name = Sesi kapat setting.sfxvol.name = Ses seviyesi setting.mutesound.name = Sesi kapat setting.crashreport.name = Send Anonymous Crash Reports +setting.savecreate.name = Auto-Create Saves setting.chatopacity.name = Chat Opacity setting.playerchat.name = Display In-Game Chat uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... @@ -527,6 +539,7 @@ keybind.press.axis = Bir yone cevir yada tusa bas... keybind.screenshot.name = Map Screenshot keybind.move_x.name = Sol/Sag hareket keybind.move_y.name = Yukari/asagi hareket +keybind.fullscreen.name = Toggle Fullscreen keybind.select.name = Sec/silahi sik keybind.diagonal_placement.name = Diagonal Placement keybind.pick.name = Pick Block @@ -790,6 +803,7 @@ block.blast-mixer.name = Patlayici karistiricisi block.solar-panel.name = gunes paneli block.solar-panel-large.name = genis gunes paneli block.oil-extractor.name = benzin ayirici +block.command-center.name = Command Center block.draug-factory.name = Draug Miner Drone Factory block.spirit-factory.name = Spirit Drone Factory block.phantom-factory.name = Phantom Drone Factory @@ -1012,6 +1026,7 @@ block.ripple.description = A large artillery turret which fires several shots si block.cyclone.description = A large rapid fire turret. block.spectre.description = A large turret which shoots two powerful bullets at once. block.meltdown.description = A large turret which shoots powerful long-range beams. +block.command-center.description = Issues movement commands to allied units across the map.\nCauses units to patrol, attack an enemy core or retreat to the core/factory. When no enemy core is present, units will default to patrolling under the attack command. block.draug-factory.description = Produces Draug mining drones. block.spirit-factory.description = Produces light drones which mine ore and repair blocks. block.phantom-factory.description = Produces advanced drone units which are significantly more effective than a spirit drone. diff --git a/core/assets/bundles/bundle_tr.properties b/core/assets/bundles/bundle_tr.properties index 767e5afbe5..e6f01af1ea 100644 --- a/core/assets/bundles/bundle_tr.properties +++ b/core/assets/bundles/bundle_tr.properties @@ -16,7 +16,11 @@ screenshot.invalid = Harita çok büyük, ekran görüntüsü için potansiyel o gameover = Kaybettin gameover.pvp = [accent] {0}[] Takımı kazandı! highscore = [accent]Yeni rekor! - +load.sound = Sesler +load.map = Haritalar +load.image = Resimler +load.content = İçerik +load.system = Sistem stat.wave = Yenilen Dalgalar:[accent] {0} stat.enemiesDestroyed = Yok Edilen Düşmanlar:[accent] {0} stat.built = İnşa Edilen Yapılar:[accent] {0} @@ -24,10 +28,6 @@ stat.destroyed = Yok Edilen Yapılar:[accent] {0} stat.deconstructed = Yıkılan Yapılar:[accent] {0} stat.delivered = Gönderilen Kaynaklar: stat.rank = Rütbe: [accent]{0} - -placeline = Bir blok seçtin.\nYou can[accent] place in a line[] by[accent] holding down your finger for a few seconds[] and dragging in a direction.\n\n[scarlet]DO IT. -removearea = You have selected removal mode.\nYou can[accent] remove blocks in a rectangle[] by[accent] holding down your finger for a few seconds[] and dragging.\n\n[scarlet]DO IT. - launcheditems = [accent]Gönderilen Kaynaklar map.delete = "[accent]{0}[]"Haritasını silmek istediğine emin misin? level.highscore = Rekor: [accent]{0} @@ -35,7 +35,7 @@ level.select = Seviye Seçimi level.mode = Oyun Modu: showagain = Bir daha gösterme coreattack = < Çekirdek saldırı altında! > -nearpoint = [[ [scarlet]İNİŞ PİSTİNDEN AYRIL[] ]\nimha riski yüksek +nearpoint = [[ [scarlet]İNİŞ PİSTİNDEN AYRIL[] ]\nimha tehlikesi database = Çekirdek Veritabanı savegame = Oyunu Kaydet loadgame = Oyunu Yükle @@ -49,8 +49,17 @@ close = Kapat website = Website quit = Çık maps = Haritalar +maps.browse = Haritaları gör continue = Devam et maps.none = [lightgray]Harita Bulunamadı! +invalid = Invalid +preparingconfig = Yapılandırma Hazırlanıyor +preparingcontent = İçerik Hazırlanıyor +uploadingcontent = İçerik Yükleniyor +uploadingpreviewfile = Önizleme Dosyası Yükleniyor +committingchanges = Değişiklikler Uygulanıyor +done = Bittti + about.button = Hakkında name = İsim: noname = Bir[accent] kullanıcı adı[] seçmelisin. @@ -58,107 +67,119 @@ filename = Dosya Adı: unlocked = Yeni içerik açıldı! completed = [accent]Tamamlandı techtree = Yetenek Ağacı -research.list = [lightgray]Araştır: +research.list = [lightgray]Araştırmalar: research = Araştır researched = [lightgray]{0} Araştırıldı. -players = {0} oyuncu çevrimiçi -players.single = {0} oyuncu çevrimiçi -server.closing = [accent]Sunucu kapanıyor... +players = {0} çevrimiçi oyuncu +players.single = {0} çevrimiçi oyuncu +server.closing = [accent]Sunucu kapatılıyor... +server.kicked.whitelist = Beyaz listede değilsin. server.kicked.kick = Sunucudan atıldın! server.kicked.serverClose = Sunucu kapandı. -server.kicked.clientOutdated = Geçersiz sürüm! Oyununu güncelle! +server.kicked.vote = Oylama ile atıldın. Görüşürüz. +server.kicked.clientOutdated = Eski sürüm! Oyununu güncelle! server.kicked.serverOutdated = Geçersiz sunucu!\nKurucudan oyununu güncellemesini iste! server.kicked.banned = Bu sunucudan yasaklandın. -server.kicked.recentKick = Yakın bir zamanda bir sunucudan atıldın.\nBağlanmadan önce biraz bekle. +server.kicked.typeMismatch = Bu sunucu senin inşa türünle uyumlu değil. +server.kicked.playerLimit = Sunucu dolu. Yer açılmasını bekle. +server.kicked.recentKick = Yakın bir zamanda bir sunucudan atıldın.\nBağlanmadan önce bir süre bekle. server.kicked.nameInUse = Sunucuda zaten o isimde biri var. -server.kicked.nameEmpty = İsmin geçersiz. +server.kicked.nameEmpty = Seçtiğin isim geçersiz. server.kicked.idInUse = Zaten bu sunucudasın! İki hesapla bir sunucuya bağlanamazsın. server.kicked.customClient = Bu sunucu özel sürümleri kabul etmiyor. Resmi bir sürüm indir. -server.kicked.gameover = Game over! -server.versions = Senin versiyon:[accent] {0}[]\nSunucunun versiyonu:[accent] {1}[] -host.info = The [accent]host[] button hosts a server on port [scarlet]6567[]. \nAnybody on the same [lightgray]wifi or local network[] should be able to see your server in their server list.\n\nIf you want people to be able to connect from anywhere by IP, [accent]port forwarding[] is required.\n\n[lightgray]Note: If someone is experiencing trouble connecting to your LAN game, make sure you have allowed Mindustry access to your local network in your firewall settings. Note that public networks sometimes do not allow server discovery. -join.info = Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[lightgray]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP. +server.kicked.gameover = Oyun bitti! +server.versions = Kullandığın surum:[accent] {0}[]\nSunucunun sürümü:[accent] {1}[] +host.info = [accent]host[], [scarlet]6567[] portunda bir sunucuya ev sahipliği yapıyor. \nAynı [lightgray]wifi veya yerel ağdaki[] herkes sunucu listelerinde senin sunucunu görebiliyor olmalı.\n\nEğer diğerlerinin herhangi bir yerden IP ile bağlanabilmesini istiyorsan [accent]port yönlendirmesi[] gerekli.\n\n[lightgray]Not: Eğer birisi senin yerel ağ oyununa katılmakta sorun yaşıyorsa güvenlik duvarı ayarlarında Mindustry'ye yerel ağ bağlantısı izni verdiğinden emin olun. Halka açık ağların zaman zaman sunucu aramaya engel olduğunu unutmayın. +join.info = Burada, bağlanmak istediğin sunucunun [accent]IP[] adresini girebilir veya [accent]yerel ağ[] sunucularını görebilirsin..\nHem yerel ağ hem de geniş alan ağı çoklu oyuncu için destekleniyor.\n\n[lightgray]Not: Otomatik bir global sunucu listesi yok; eğer birisine IP adresi kullanarak bağlanmak istiyorsan IP adresini istemelisin. hostserver = Çok Oyunculu Oyun Aç hostserver.mobile = Oyun\nKur host = Kur hosting = [accent]Sunucu açılıyor... hosts.refresh = Yenile -hosts.discovering = LAN oyunu aranıyor -server.refreshing = Sunucular yenileniyor -hosts.none = [lightgray]LAN oyunu bulunamadı! +hosts.discovering = Yerel ağ oyunu aranıyor +server.refreshing = Sunucu yenileniyor +hosts.none = [lightgray]Yerel oyun bulunamadı! host.invalid = [scarlet]Kurucuya bağlanılamıyor. -trace = Oyuncuyu takip et +trace = Oyuncuyu Takip Et trace.playername = Oyuncu İsmi: [accent]{0} trace.ip = IP: [accent]{0} trace.id = Özel ID: [accent]{0} trace.mobile = Mobil Sürüm: [accent]{0} trace.modclient = Özel Sürüm: [accent]{0} invalidid = Geçersiz Sürüm ID'si! Bir hata raporu gönder. -server.bans = Yasaklar +server.bans = Yasaklılar server.bans.none = Yasaklanmış oyuncu bulunamadı! -server.admins = Yetkililer -server.admins.none = Yetkili bulunamadı! -server.add = Add Server -server.delete = Are you sure you want to delete this server? -server.edit = Edit Server -server.outdated = [crimson]Outdated Server![] -server.outdated.client = [crimson]Outdated Client![] +server.admins = Yönetici +server.admins.none = Yönetici bulunamadı! +server.add = Sunucu Ekle +server.delete = Bu sunucuyu silmek istediğine emin misin? +server.edit = Sunucuyu Düzenle +server.outdated = [crimson]Güncel Olmayan Sunucu![] +server.outdated.client = [crimson]Güncel Olmayan Sürüm![] server.version = [gray]v{0} {1} -server.custombuild = [yellow]Custom Build -confirmban = Are you sure you want to ban this player? -confirmkick = Are you sure you want to kick this player? -confirmunban = Are you sure you want to unban this player? -confirmadmin = Are you sure you want to make this player an admin? -confirmunadmin = Are you sure you want to remove admin status from this player? -joingame.title = Join Game -joingame.ip = Address: -disconnect = Disconnected. -disconnect.data = Failed to load world data! -connecting = [accent]Connecting... -connecting.data = [accent]Loading world data... +server.custombuild = [yellow]Özel Sürüm +confirmban = Bu kullanıcıyı yasaklamak istediğine emin misin?confirmkick = Bu kullanıcıyı atmak istediğine emin misin? +confirmunban = Bu kullanıcının yasağını kaldırmak istediğine emin misin? +confirmadmin = Bu kullanıcıyı bir yönetici yapmak istediğine emin misin? +confirmunadmin = Bu kullanıcının yönetici yetkilerini almak istediğine istediğine emin misin? +joingame.title = Oyuna Katıl +joingame.ip = Adres: +disconnect = Bağlantı kesildi. +disconnect.error = Bağlantı hatası. +disconnect.closed = Bağlantı kapatıldı. +disconnect.timeout = Zaman aşımı. +disconnect.data = Dünya verisi yüklenemedi! +connecting = [accent]Bağlanılıyor... +connecting.data = [accent]Dünya verisi yükleniyor... server.port = Port: -server.addressinuse = Address already in use! -server.invalidport = Invalid port number! -server.error = [crimson]Error hosting server: [accent]{0} -save.old = This save is for an older version of the game, and can no longer be used.\n\n[lightgray]Save backwards compatibility will be implemented in the full 4.0 release. -save.new = New Save -save.overwrite = Are you sure you want to overwrite\nthis save slot? -overwrite = Overwrite -save.none = No saves found! -saveload = Saving... -savefail = Failed to save game! -save.delete.confirm = Are you sure you want to delete this save? -save.delete = Delete -save.export = Export Save -save.import.invalid = [accent]This save is invalid! -save.import.fail = [crimson]Failed to import save: [accent]{0} -save.export.fail = [crimson]Failed to export save: [accent]{0} -save.import = Import Save -save.newslot = Save name: -save.rename = Rename -save.rename.text = New name: -selectslot = Select a save. +server.addressinuse = Adres zaten kullanılıyor! +server.invalidport = Geçersiz port sayısı! +server.error = [crimson]Sunucu kurulamadı: [accent]{0} +save.old = Bu kayıt oyunun eski bir sürümü için ve artık kullanılamaz.\n\n[lightgray]Tam 4.0 sürümü yayınlandığında geri kayıt özelliği eklenecek. +save.new = Yeni kayıt +save.overwrite = Bu kayıdın üstüne yazmak istediğine\nemin misin? +overwrite = Üstüne yaz +save.none = Kayıt bulunamadı! +saveload = Kaydediliyor... +savefail = Oyun kaydedilemedi! +save.delete.confirm = Bu kaydı silmek istediğine emin misin? +save.delete = Sil +save.export = Kayıdı Dışa Aktar +save.import.invalid = [accent]Bu kayıt geçersiz! +save.import.fail = [crimson]Kayıt içe aktarılamadı: [accent]{0} +save.export.fail = [crimson]Kayıt dışa aktarılamadı: [accent]{0} +save.import = Kayıdı İçe Aktar +save.newslot = İsmi kaydet: +save.rename = Yeniden isimlendir +save.rename.text = Yeni isim: +selectslot = Bir kayıt seçin. slot = [accent]Slot {0} -save.corrupted = [accent]Save file corrupted or invalid!\nIf you have just updated your game, this is probably a change in the save format and [scarlet]not[] a bug. -empty = -on = On -off = Off -save.autosave = Autosave: {0} -save.map = Map: {0} -save.wave = Wave {0} -save.difficulty = Difficulty: {0} -save.date = Last Saved: {0} -save.playtime = Playtime: {0} -warning = Warning. -confirm = Confirm -delete = Delete +save.corrupted = [accent]Kayıt dosyası bozuk veya geçersiz!\nEğer oyununuzu kısa süre öce güncellediyseniz bu, kayıt formatındaki bir değişiklik. Bir hata [scarlet]değil[]. +empty = +on = Aç +off = Kapa +save.autosave = Otomatk kayıt: {0} +save.map = Harita: {0} +save.wave = Dalga {0} +save.mode = Oyun modu: {0} +save.difficulty = Zorluk: {0} +save.date = Son Kayıt: {0} +save.playtime = Oynama süresi: {0} +warning = Uyarı. +confirm = Doğrula +delete = Sil ok = OK -open = Open -customize = Customize Rules -cancel = Cancel -openlink = Open Link -copylink = Copy Link -back = Back +open = Aç +customize = Kuralları Özelleştir +cancel = İptal +openlink = Bağlantıyı Aç +copylink = Bağlantıyı Kopyala +back = Geri +data.export = Veriyi Dışa Aktar +data.import = Veriyi İçe Aktar +data.exported = Veri dışa aktarıldı. +data.invalid = Bu oyun verisi geçerli değil. +data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. classic.export = Export Classic Data classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? quit.confirm = Are you sure you want to quit? @@ -253,7 +274,6 @@ editor.mapname = Map Name: editor.overwrite = [accent]Warning!\nThis overwrites an existing map. editor.overwrite.confirm = [scarlet]Warning![] A map with this name already exists. Are you sure you want to overwrite it? editor.selectmap = Select a map to load: - toolmode.replace = Replace toolmode.replace.description = Draws only on solid blocks. toolmode.replaceall = Replace All @@ -268,7 +288,6 @@ toolmode.fillteams = Fill Teams toolmode.fillteams.description = Fill teams instead of blocks. toolmode.drawteams = Draw Teams toolmode.drawteams.description = Draw teams instead of blocks. - filters.empty = [lightgray]No filters! Add one with the button below. filter.distort = Distort filter.noise = Noise @@ -300,7 +319,6 @@ filter.option.floor2 = Secondary Floor filter.option.threshold2 = Secondary Threshold filter.option.radius = Radius filter.option.percentile = Percentile - width = Width: height = Height: menu = Menu @@ -318,7 +336,6 @@ tutorial.retake = Re-Take Tutorial editor = Editor mapeditor = Map Editor donate = Donate - abandon = Abandon abandon.text = This zone and all its resources will be lost to the enemy. locked = Locked @@ -344,7 +361,6 @@ zone.objective.survival = Survive zone.objective.attack = Destroy Enemy Core add = Add... boss.health = Boss Health - connectfail = [crimson]Connection error:\n\n[accent]{0} error.unreachable = Server unreachable.\nIs the address spelled correctly? error.invalidaddress = Invalid address. @@ -355,7 +371,6 @@ error.mapnotfound = Map file not found! error.io = Network I/O error. error.any = Unknown network error. error.bloom = Failed to initialize bloom.\nYour device may not support it. - zone.groundZero.name = Ground Zero zone.desertWastes.name = Desert Wastes zone.craters.name = The Craters @@ -370,7 +385,6 @@ zone.saltFlats.name = Salt Flats zone.impact0078.name = Impact 0078 zone.crags.name = Crags zone.fungalPass.name = Fungal Pass - zone.groundZero.description = The optimal location to begin once more. Low enemy threat. Few resources.\nGather as much lead and copper as possible.\nMove on. zone.frozenForest.description = Even here, closer to mountains, the spores have spread. The frigid temperatures cannot contain them forever.\n\nBegin the venture into power. Build combustion generators. Learn to use menders. zone.desertWastes.description = These wastes are vast, unpredictable, and criss-crossed with derelict sector structures.\nCoal is present in the region. Burn it for power, or synthesize graphite.\n\n[lightgray]This landing location cannot be guaranteed. @@ -385,8 +399,8 @@ zone.nuclearComplex.description = A former facility for the production and proce zone.fungalPass.description = A transition area between high mountains and lower, spore-ridden lands. A small enemy reconnaissance base is located here.\nDestroy it.\nUse Dagger and Crawler units. Take out the two cores. zone.impact0078.description = zone.crags.description = - settings.language = Language +settings.data = Game Data settings.reset = Reset to Defaults settings.rebind = Rebind settings.controls = Controls @@ -438,7 +452,6 @@ blocks.inaccuracy = Inaccuracy blocks.shots = Shots blocks.reload = Shots/Second blocks.ammo = Ammo - bar.drilltierreq = Better Drill Required bar.drillspeed = Drill Speed: {0}/s bar.efficiency = Efficiency: {0}% @@ -451,7 +464,6 @@ bar.heat = Heat bar.power = Power bar.progress = Build Progress bar.spawned = Units: {0}/{1} - bullet.damage = [stat]{0}[lightgray] damage bullet.splashdamage = [stat]{0}[lightgray] area dmg ~[stat] {1}[lightgray] tiles bullet.incendiary = [stat]incendiary @@ -463,7 +475,6 @@ bullet.freezing = [stat]freezing bullet.tarred = [stat]tarred bullet.multiplier = [stat]{0}[lightgray]x ammo multiplier bullet.reload = [stat]{0}[lightgray]x fire rate - unit.blocks = blocks unit.powersecond = power units/second unit.liquidsecond = liquid units/second @@ -521,6 +532,7 @@ setting.mutemusic.name = Mute Music setting.sfxvol.name = SFX Volume setting.mutesound.name = Mute Sound setting.crashreport.name = Send Anonymous Crash Reports +setting.savecreate.name = Auto-Create Saves setting.chatopacity.name = Chat Opacity setting.playerchat.name = Display In-Game Chat uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] seconds... @@ -541,6 +553,7 @@ keybind.press.axis = Press an axis or key... keybind.screenshot.name = Map Screenshot keybind.move_x.name = Move x keybind.move_y.name = Move y +keybind.fullscreen.name = Toggle Fullscreen keybind.select.name = Select/Shoot keybind.diagonal_placement.name = Diagonal Placement keybind.pick.name = Pick Block @@ -573,7 +586,6 @@ mode.pvp.description = Fight against other players locally.\n[gray]Requires at l mode.attack.name = Attack mode.attack.description = Destroy the enemy's base. No waves.\n[gray]Requires a red core in the map to play. mode.custom = Custom Rules - rules.infiniteresources = Infinite Resources rules.wavetimer = Wave Timer rules.waves = Waves @@ -600,7 +612,6 @@ rules.title.resourcesbuilding = Resources & Building rules.title.player = Players rules.title.enemy = Enemies rules.title.unit = Units - content.item.name = Items content.liquid.name = Liquids content.unit.name = Units @@ -662,7 +673,6 @@ mech.buildspeed = [lightgray]Building Speed: {0}% liquid.heatcapacity = [lightgray]Heat Capacity: {0} liquid.viscosity = [lightgray]Viscosity: {0} liquid.temperature = [lightgray]Temperature: {0} - block.sand-boulder.name = Sand Boulder block.grass.name = Grass block.salt.name = Salt @@ -807,6 +817,7 @@ block.blast-mixer.name = Blast Mixer block.solar-panel.name = Solar Panel block.solar-panel-large.name = Large Solar Panel block.oil-extractor.name = Oil Extractor +block.command-center.name = Command Center block.draug-factory.name = Draug Miner Drone Factory block.spirit-factory.name = Spirit Repair Drone Factory block.phantom-factory.name = Phantom Builder Drone Factory @@ -889,8 +900,6 @@ tutorial.deposit = Deposit items into blocks by dragging from your ship to the d tutorial.waves = The[lightgray] enemy[] approaches.\n\nDefend the core for 2 waves.[accent] Click[] to shoot.\nBuild more turrets and drills. Mine more copper. tutorial.waves.mobile = The[lightgray] enemy[] approaches.\n\nDefend the core for 2 waves. Your ship will automatically fire at enemies.\nBuild more turrets and drills. Mine more copper. tutorial.launch = Once you reach a specific wave, you are able to[accent] launch the core[], leaving your defenses behind and[accent] obtaining all the resources in your core.[]\nThese resources can then be used to research new technology.\n\n[accent]Press the launch button. - - item.copper.description = The most basic structural material. Used extensively in all types of blocks. item.lead.description = A basic starter material. Used extensively in electronics and liquid transportation blocks. item.metaglass.description = A super-tough glass compound. Extensively used for liquid distribution and storage. @@ -1031,6 +1040,7 @@ block.ripple.description = An extremely powerful artillery turret. Shoots cluste block.cyclone.description = A large anti-air and anti-ground turret. Fires explosive clumps of flak at nearby units. block.spectre.description = A massive dual-barreled cannon. Shoots large armor-piercing bullets at air and ground targets. block.meltdown.description = A massive laser cannon. Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate. +block.command-center.description = Issues movement commands to allied units across the map.\nCauses units to patrol, attack an enemy core or retreat to the core/factory. When no enemy core is present, units will default to patrolling under the attack command. block.draug-factory.description = Produces Draug mining drones. block.spirit-factory.description = Produces Spirit structural repair drones. block.phantom-factory.description = Produces advanced construction drones. diff --git a/core/assets/bundles/bundle_zh_CN.properties b/core/assets/bundles/bundle_zh_CN.properties index ccae754338..4a3e77854d 100644 --- a/core/assets/bundles/bundle_zh_CN.properties +++ b/core/assets/bundles/bundle_zh_CN.properties @@ -16,7 +16,11 @@ screenshot.invalid = 地图太大,可能没有足够的内存用于截图。 gameover = 你的核心被摧毁了! gameover.pvp = [accent] {0}[] 队获胜! highscore = [accent]新纪录! - +load.sound = Sounds +load.map = Maps +load.image = Images +load.content = Content +load.system = System stat.wave = 战胜的波数:[accent]{0} stat.enemiesDestroyed = 消灭的敌人:[accent]{0} stat.built = 建造的建筑:[accent]{0} @@ -24,7 +28,6 @@ stat.destroyed = 摧毁的建筑:[accent]{0} stat.deconstructed = 拆除的建筑:[accent]{0} stat.delivered = 发射的资源: stat.rank = 最终等级:[accent]{0} - launcheditems = [accent]发射的资源 map.delete = 确定要删除 "[accent]{0}[]" 地图吗? level.highscore = 最高分:[accent]{0} @@ -63,9 +66,11 @@ players.single = {0}玩家在线 server.closing = [accent]正在关闭服务器…… server.kicked.kick = 你被踢出服务器了! server.kicked.serverClose = 服务器已关闭。 +server.kicked.vote = You have been vote-kicked. Goodbye. server.kicked.clientOutdated = 客户端过旧,请更新你的游戏。 server.kicked.serverOutdated = 服务器过旧,请联系房主升级服务器。 server.kicked.banned = 你在这个服务器上被拉入黑名单了。 +server.kicked.typeMismatch = This server is not compatible with your build type. server.kicked.recentKick = 你刚刚被踢出服务器。\n请稍后重新连接! server.kicked.nameInUse = 你的名字与服务器中的一个人重复了。 server.kicked.nameEmpty = 无效的名字! @@ -156,6 +161,11 @@ cancel = 取消 openlink = 打开链接 copylink = 复制链接 back = 返回 +data.export = Export Data +data.import = Import Data +data.exported = Data exported. +data.invalid = This isn't valid game data. +data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. classic.export = 导出老版本数据 classic.export.text = [accent]Mindustry []刚刚有了一个重要的更新。\n检测到此为老版本(v3.5 build 40)的存档或地图。是否要将这些保存导出到手机的主文件夹中,以便在 Mindustry 老版本应用程序中使用? quit.confirm = 确定退出? @@ -250,7 +260,6 @@ editor.mapname = 地图名称: editor.overwrite = [accent]警告!\n这将会覆盖一个已经存在的地图。 editor.overwrite.confirm = [scarlet]警告![]存在同名地图。你确定你想要覆盖? editor.selectmap = 选择一个地图加载: - toolmode.replace = 替换 toolmode.replace.description = 仅在实心块上绘制。 toolmode.replaceall = 全部替换 @@ -265,7 +274,6 @@ toolmode.fillteams = 填充团队 toolmode.fillteams.description = 填充团队而不是方块。 toolmode.drawteams = 绘制团队 toolmode.drawteams.description = 绘制团队而不是方块。 - filters.empty = [LIGHT_GRAY]没有筛选器!用下方的按钮添加一个。 filter.distort = Distort filter.noise = Noise @@ -297,7 +305,6 @@ filter.option.floor2 = Secondary Floor filter.option.threshold2 = Secondary Threshold filter.option.radius = Radius filter.option.percentile = Percentile - width = 宽度: height = 高度: menu = 菜单 @@ -315,7 +322,6 @@ tutorial.retake = 重新游玩教程 editor = 编辑器 mapeditor = 地图编辑器 donate = 打赏 - abandon = 放弃 abandon.text = 这个区域和它的所有资源会被敌人重置。 locked = 已被锁定 @@ -341,7 +347,6 @@ zone.objective.survival = 生存 zone.objective.attack = 摧毁敌方核心 add = 添加…… boss.health = BOSS 生命值 - connectfail = [crimson]服务器连接失败:[accent]{0} error.unreachable = 服务器无法访问。 error.invalidaddress = 地址无效。 @@ -352,7 +357,6 @@ error.mapnotfound = 找不到地图文件! error.io = 网络 I/O 错误。 error.any = 未知网络错误。 error.bloom = 未能初始化特效。\n您的设备可能不支持它。 - zone.groundZero.name = 零号地区 zone.desertWastes.name = 荒芜沙漠 zone.craters.name = 陨石带 @@ -367,7 +371,6 @@ zone.saltFlats.name = 盐碱荒滩 zone.impact0078.name = 0078号冲击 zone.crags.name = 悬崖 zone.fungalPass.name = 真菌通道 - zone.groundZero.description = 重新开始的最佳位置。敌人威胁很小,资源少。\n尽可能收集多的铅和铜。\n行动。 zone.frozenForest.description = 即使在这里,靠近山脉的地方,孢子也已经扩散。寒冷的温度不可能永远容纳它们。\n\n此行动须投入电力。建造燃烧发电机并学会使用修理者。 zone.desertWastes.description = 这些废物是巨大的,不可预测的,并且与废弃的结构交错在一起。燃烧它以获取动力或合成石墨。\n\n[lightgray]无法保证此着陆位置。 @@ -382,8 +385,8 @@ zone.nuclearComplex.description = 以前生产和加工钍的设施已变成废 zone.fungalPass.description = 介于高山和低矮孢子丛生的土地之间的过渡地带。这里有一个小型的敌方侦察基地。\n侦察它。\n使用尖刀和爬行者单位来消灭两个核心。 zone.impact0078.description = <在此处插入说明> zone.crags.description = <在此处插入说明> - settings.language = 语言 +settings.data = Game Data settings.reset = 恢复默认 settings.rebind = 重新绑定 settings.controls = 控制 @@ -435,7 +438,6 @@ blocks.inaccuracy = 误差 blocks.shots = 每秒发射数 blocks.reload = 重新装弹 blocks.ammo = 子弹 - bar.drilltierreq = 需要更好的钻头 bar.drillspeed = 挖掘速度:{0}/s bar.efficiency = 效率:{0}% @@ -448,7 +450,6 @@ bar.heat = 热量 bar.power = 电力 bar.progress = 制造进度 bar.spawned = 单位数量:{0}/{1} - bullet.damage = [stat]{0}[lightgray] 伤害 bullet.splashdamage = [stat]{0}[lightgray] 范围伤害 ~[stat] {1}[lightgray] 格 bullet.incendiary = [stat] 燃烧 @@ -460,7 +461,6 @@ bullet.freezing = [stat] 冰冻 bullet.tarred = [stat] 减速 bullet.multiplier = [stat]{0}[lightgray]x 子弹数量 bullet.reload = [stat]{0}[lightgray]x 装弹 - unit.blocks = 方块 unit.powersecond = 能量单位/秒 unit.liquidsecond = 液体单位/秒 @@ -518,6 +518,7 @@ setting.mutemusic.name = 静音 setting.sfxvol.name = 音效音量 setting.mutesound.name = 静音 setting.crashreport.name = 发送匿名崩溃报告 +setting.savecreate.name = Auto-Create Saves setting.chatopacity.name = 聊天界面透明度 setting.playerchat.name = 显示游戏内聊天界面 uiscale.reset = UI缩放比例已经改变。\n按下“确定”来确定缩放比例\n[accent]{0}[]秒后[scarlet]退出并恢复设定。 @@ -571,7 +572,6 @@ mode.pvp.description = 和本地玩家对战。 mode.attack.name = 攻击 mode.attack.description = 没有波数,但是有摧毁敌人基地的任务。 mode.custom = 自定义模式 - rules.infiniteresources = 无限资源 rules.wavetimer = 波次计时器 rules.waves = 波次 @@ -598,7 +598,6 @@ rules.title.resourcesbuilding = 资源和建造 rules.title.player = 玩家 rules.title.enemy = 敌人 rules.title.unit = 单位 - content.item.name = 物品 content.liquid.name = 液体 content.unit.name = 部队 @@ -660,7 +659,6 @@ mech.buildspeed = [LIGHT_GRAY]建造速度:{0}% liquid.heatcapacity = [LIGHT_GRAY]热容量:{0} liquid.viscosity = [LIGHT_GRAY]粘度:{0} liquid.temperature = [LIGHT_GRAY]温度:{0} - block.sand-boulder.name = 沙砂巨石 block.grass.name = 草地 block.salt.name = 盐碱地 @@ -888,8 +886,6 @@ tutorial.deposit = 将物品从机甲拖向方块来放下物品。\n\n[accent] tutorial.waves = [lightgray]敌人[]来了。\n\n保护核心,防御2波攻击。造更多的炮塔。[accent]点击[]以射击。\n建造更多的炮塔和钻头,并采更多的矿。 tutorial.waves.mobile = [lightgray]敌人[]来了。\n\n保护核心,防御2波攻击。造更多的炮塔。你的机甲将对敌人自动开火。\n建造更多的炮塔和钻头,并采更多的矿。 tutorial.launch = 特定波次中,你可以[accent]发射核心[],[accent]携带核心中所有资源[]离开所有的建筑。\n资源可用来研究科技。\n\n[accent]点击发射按钮。 - - item.copper.description = 一种有用的结构材料。在各种类型的方块中广泛使用。 item.lead.description = 一种基本的起始材料。被广泛用于电子设备和液体运输方块。 item.metaglass.description = 一种超级强硬的复合玻璃。通常用来传送和收藏液体。 diff --git a/core/assets/bundles/bundle_zh_TW.properties b/core/assets/bundles/bundle_zh_TW.properties index a760f1bf4a..459c0eaa5b 100644 --- a/core/assets/bundles/bundle_zh_TW.properties +++ b/core/assets/bundles/bundle_zh_TW.properties @@ -16,6 +16,11 @@ screenshot.invalid = 地圖太大了,可能沒有足夠的內存用於截圖 gameover = 遊戲結束 gameover.pvp = [accent]{0}[]隊獲勝! highscore = [accent]新的高分紀錄! +load.sound = Sounds +load.map = Maps +load.image = Images +load.content = Content +load.system = System stat.wave = 打敗的波次:[accent]{0} stat.enemiesDestroyed = 摧毀的敵人:[accent]{0} stat.built = 建設的建築:[accent]{0} @@ -23,8 +28,6 @@ stat.destroyed = 摧毀的建築:[accent]{0} stat.deconstructed = 移除的建築:[accent]{0} stat.delivered = 發射的資源: stat.rank = 最終排名:[accent]{0} -placeline = 你選擇了一個方塊。\n[accent]按住你的手指幾秒鐘[]並拖動以[accent]直線放置方塊[]。\n試試吧。 -removearea = 你選擇了移除模式。\n[accent]按住你的手指幾秒鐘[]並拖動以[accent]移除矩形中的方塊[]。\n試試吧。 launcheditems = [accent]發射了的物品 map.delete = 確認要刪除「[accent]{0}[]」地圖嗎? level.highscore = 最高分:[accent]{0} @@ -63,9 +66,11 @@ players.single = {0}個線上玩家 server.closing = [accent]正在關閉伺服器…… server.kicked.kick = 您已被踢出伺服器! server.kicked.serverClose = 伺服器已關閉。 +server.kicked.vote = You have been vote-kicked. Goodbye. server.kicked.clientOutdated = 客戶端版本過舊!請更新遊戲! server.kicked.serverOutdated = 伺服器版本過舊!請聯絡伺服主更新伺服器! server.kicked.banned = 您已經從這個伺服器被封禁。 +server.kicked.typeMismatch = This server is not compatible with your build type. server.kicked.recentKick = 您已經從伺服器被踢除。\n請稍後再進行連線。 server.kicked.nameInUse = 伺服器中已經\n有人有相同的名稱了。 server.kicked.nameEmpty = 你的名稱必須至少包含一個字母或數字。 @@ -156,6 +161,11 @@ cancel = 取消 openlink = 開啟連結 copylink = 複製連結 back = 返回 +data.export = Export Data +data.import = Import Data +data.exported = Data exported. +data.invalid = This isn't valid game data. +data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. classic.export = Export Classic Data classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? quit.confirm = 您確定要退出嗎? @@ -376,6 +386,7 @@ zone.fungalPass.description = A transition area between high mountains and lower zone.impact0078.description = zone.crags.description = settings.language = 語言 +settings.data = Game Data settings.reset = 重設為預設設定 settings.rebind = 重新綁定 settings.controls = 操作 @@ -507,6 +518,7 @@ setting.mutemusic.name = 靜音 setting.sfxvol.name = 音效音量 setting.mutesound.name = 靜音 setting.crashreport.name = 發送匿名崩潰報告 +setting.savecreate.name = Auto-Create Saves setting.chatopacity.name = 聊天框不透明度 setting.playerchat.name = 在遊戲中顯示聊天框 uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... @@ -527,6 +539,7 @@ keybind.press.axis = 按一下軸心或鍵…… keybind.screenshot.name = 地圖截圖 keybind.move_x.name = 水平移動 keybind.move_y.name = 垂直移動 +keybind.fullscreen.name = Toggle Fullscreen keybind.select.name = 選取 keybind.diagonal_placement.name = 對角線放置 keybind.pick.name = 選擇方塊 @@ -790,6 +803,7 @@ block.blast-mixer.name = 爆炸混合器 block.solar-panel.name = 太陽能板 block.solar-panel-large.name = 大型太陽能板 block.oil-extractor.name = 石油鑽井 +block.command-center.name = Command Center block.draug-factory.name = Draug Miner Drone Factory block.spirit-factory.name = 輕型無人機工廠 block.phantom-factory.name = 幻影無人機工廠 @@ -1012,6 +1026,7 @@ block.ripple.description = 一種一次射出幾發子彈的大型火砲。 block.cyclone.description = 一種快速射擊的大型砲塔。 block.spectre.description = 一種一次射出兩顆強大的子彈的大型砲塔。 block.meltdown.description = 一種射出強大的遠程光束的大型砲塔。 +block.command-center.description = Issues movement commands to allied units across the map.\nCauses units to patrol, attack an enemy core or retreat to the core/factory. When no enemy core is present, units will default to patrolling under the attack command. block.draug-factory.description = Produces Draug mining drones. block.spirit-factory.description = 生產輕型無人機,用於開採礦石和修復方塊。 block.phantom-factory.description = 生產高級的無人機,比輕型無人機明顯更有效。 diff --git a/core/assets/maps/overgrowth.msav b/core/assets/maps/overgrowth.msav index 23db0583ed..56dddd5bae 100644 Binary files a/core/assets/maps/overgrowth.msav and b/core/assets/maps/overgrowth.msav differ diff --git a/core/assets/maps/stainedMountains.msav b/core/assets/maps/stainedMountains.msav index fabee936e8..07d2d6ad81 100644 Binary files a/core/assets/maps/stainedMountains.msav and b/core/assets/maps/stainedMountains.msav differ diff --git a/core/assets/music/menu.ogg b/core/assets/music/menu.ogg index 90dfbb6378..c23fe679fb 100644 Binary files a/core/assets/music/menu.ogg and b/core/assets/music/menu.ogg differ diff --git a/core/assets/saves/settings.bin b/core/assets/saves/settings.bin deleted file mode 100644 index 44231e7b88..0000000000 Binary files a/core/assets/saves/settings.bin and /dev/null differ diff --git a/core/assets/saves/settings_backup.bin b/core/assets/saves/settings_backup.bin deleted file mode 100644 index 44231e7b88..0000000000 Binary files a/core/assets/saves/settings_backup.bin and /dev/null differ diff --git a/core/assets/sounds/explosion.ogg b/core/assets/sounds/explosion.ogg index 7c7f2c43da..5f4a69281d 100644 Binary files a/core/assets/sounds/explosion.ogg and b/core/assets/sounds/explosion.ogg differ diff --git a/core/assets/sprites/block_colors.png b/core/assets/sprites/block_colors.png index 2f8914711b..9b00505564 100644 Binary files a/core/assets/sprites/block_colors.png and b/core/assets/sprites/block_colors.png differ diff --git a/core/assets/sprites/sprites.atlas b/core/assets/sprites/sprites.atlas index d2b078ade6..377a6c22ee 100644 --- a/core/assets/sprites/sprites.atlas +++ b/core/assets/sprites/sprites.atlas @@ -6,5194 +6,5194 @@ filter: Nearest,Nearest repeat: none force-projector rotate: false - xy: 1423, 1659 + xy: 521, 478 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 force-projector-icon-full rotate: false - xy: 1423, 1659 + xy: 521, 478 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 force-projector-top rotate: false - xy: 1521, 1659 + xy: 489, 380 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mend-projector rotate: false - xy: 715, 1322 + xy: 1676, 1595 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mend-projector-icon-full rotate: false - xy: 715, 1322 + xy: 1676, 1595 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mend-projector-top rotate: false - xy: 781, 1322 + xy: 1742, 1591 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mender rotate: false - xy: 907, 696 + xy: 1347, 889 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mender-icon-full rotate: false - xy: 907, 696 + xy: 1347, 889 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mender-top rotate: false - xy: 847, 662 + xy: 1347, 855 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 overdrive-projector rotate: false - xy: 913, 1331 + xy: 1874, 1591 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 overdrive-projector-icon-full rotate: false - xy: 913, 1331 + xy: 1874, 1591 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 overdrive-projector-top rotate: false - xy: 649, 1190 + xy: 1940, 1591 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 shock-mine rotate: false - xy: 1043, 739 + xy: 1415, 721 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-arrow rotate: false - xy: 962, 909 + xy: 1361, 1095 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor rotate: false - xy: 1132, 909 + xy: 1395, 1197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor-icon-full rotate: false - xy: 1132, 909 + xy: 1395, 1197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor-bridge rotate: false - xy: 1166, 909 + xy: 1395, 1163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor-end rotate: false - xy: 1200, 909 + xy: 1395, 1129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 center rotate: false - xy: 1234, 909 + xy: 1395, 1095 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-0-0 rotate: false - xy: 1444, 931 + xy: 1063, 212 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-icon-full rotate: false - xy: 1444, 931 + xy: 1063, 212 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-0-1 rotate: false - xy: 1478, 931 + xy: 1097, 246 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-0-2 rotate: false - xy: 1512, 931 + xy: 1097, 212 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-0-3 rotate: false - xy: 1546, 931 + xy: 1135, 416 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-1-0 rotate: false - xy: 1580, 931 + xy: 1135, 382 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-1-1 rotate: false - xy: 1614, 931 + xy: 1135, 348 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-1-2 rotate: false - xy: 1444, 897 + xy: 1131, 314 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-1-3 rotate: false - xy: 1478, 897 + xy: 1131, 280 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-2-0 rotate: false - xy: 1512, 897 + xy: 1131, 246 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-2-1 rotate: false - xy: 1546, 897 + xy: 1131, 212 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-2-2 rotate: false - xy: 1580, 897 + xy: 1153, 749 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-2-3 rotate: false - xy: 1614, 897 + xy: 1155, 584 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-3-0 rotate: false - xy: 1656, 975 + xy: 1361, 1061 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-3-1 rotate: false - xy: 1690, 975 + xy: 1395, 1061 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-3-2 rotate: false - xy: 1724, 975 + xy: 1360, 1027 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-3-3 rotate: false - xy: 1758, 975 + xy: 1394, 1027 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-4-0 rotate: false - xy: 1792, 975 + xy: 1433, 1333 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-4-1 rotate: false - xy: 1826, 975 + xy: 1433, 1299 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-4-2 rotate: false - xy: 1860, 975 + xy: 1429, 1265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-4-3 rotate: false - xy: 1656, 941 + xy: 1429, 1231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-0-0 rotate: false - xy: 1145, 739 + xy: 1671, 1363 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-icon-full rotate: false - xy: 1145, 739 + xy: 1671, 1363 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-0-1 rotate: false - xy: 1179, 773 + xy: 1637, 1329 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-0-2 rotate: false - xy: 1213, 807 + xy: 1671, 1329 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-0-3 rotate: false - xy: 1247, 841 + xy: 1497, 1295 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-1-0 rotate: false - xy: 1145, 705 + xy: 1497, 1261 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-1-1 rotate: false - xy: 1179, 739 + xy: 1531, 1295 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-1-2 rotate: false - xy: 1213, 773 + xy: 1497, 1227 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-1-3 rotate: false - xy: 1247, 807 + xy: 1565, 1295 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-2-0 rotate: false - xy: 1179, 705 + xy: 1531, 1261 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-2-1 rotate: false - xy: 1213, 739 + xy: 1497, 1193 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-2-2 rotate: false - xy: 1247, 773 + xy: 1599, 1295 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-2-3 rotate: false - xy: 1213, 705 + xy: 1565, 1261 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-3-0 rotate: false - xy: 1247, 739 + xy: 1531, 1227 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-3-1 rotate: false - xy: 1247, 705 + xy: 1497, 1159 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-3-2 rotate: false - xy: 983, 671 + xy: 1633, 1295 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-3-3 rotate: false - xy: 983, 637 + xy: 1599, 1261 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-4-0 rotate: false - xy: 1017, 671 + xy: 1565, 1227 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-4-1 rotate: false - xy: 983, 603 + xy: 1531, 1193 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-4-2 rotate: false - xy: 1017, 637 + xy: 1497, 1125 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-4-3 rotate: false - xy: 1051, 671 + xy: 1667, 1295 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 distributor rotate: false - xy: 1325, 1399 + xy: 525, 118 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 distributor-icon-full rotate: false - xy: 1325, 1399 + xy: 525, 118 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 junction rotate: false - xy: 839, 798 + xy: 1221, 739 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 junction-icon-full rotate: false - xy: 839, 798 + xy: 1221, 739 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mass-driver-base rotate: false - xy: 1619, 1463 + xy: 651, 750 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 overflow-gate rotate: false - xy: 915, 628 + xy: 1347, 821 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 overflow-gate-icon-full rotate: false - xy: 915, 628 + xy: 1347, 821 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor rotate: false - xy: 897, 424 + xy: 1279, 797 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor-icon-full rotate: false - xy: 897, 424 + xy: 1279, 797 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor-arrow rotate: false - xy: 897, 390 + xy: 1347, 787 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor-bridge rotate: false - xy: 897, 356 + xy: 1381, 789 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor-end rotate: false - xy: 931, 458 + xy: 1415, 789 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 router rotate: false - xy: 1009, 841 + xy: 1463, 1231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 router-icon-full rotate: false - xy: 1009, 841 + xy: 1463, 1231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sorter rotate: false - xy: 1111, 773 + xy: 1467, 1329 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sorter-icon-full rotate: false - xy: 1111, 773 + xy: 1467, 1329 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 blast-drill rotate: false - xy: 645, 1716 + xy: 1804, 1917 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 blast-drill-rim rotate: false - xy: 453, 1355 + xy: 526, 1595 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 blast-drill-rotator rotate: false - xy: 775, 1716 + xy: 453, 1392 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 blast-drill-top rotate: false - xy: 905, 1757 + xy: 163, 1031 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 drill-top rotate: false - xy: 649, 1454 + xy: 591, 52 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 turbine-generator-liquid rotate: false - xy: 649, 1454 + xy: 591, 52 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 laser-drill rotate: false - xy: 423, 265 + xy: 685, 184 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 laser-drill-rim rotate: false - xy: 683, 769 + xy: 583, 1436 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 laser-drill-rotator rotate: false - xy: 683, 671 + xy: 681, 1436 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 laser-drill-top rotate: false - xy: 933, 1463 + xy: 609, 1338 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mechanical-drill rotate: false - xy: 1177, 1397 + xy: 1412, 1557 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mechanical-drill-rotator rotate: false - xy: 649, 1322 + xy: 1544, 1595 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mechanical-drill-top rotate: false - xy: 649, 1256 + xy: 1610, 1595 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 oil-extractor rotate: false - xy: 1717, 1401 + xy: 749, 1142 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 oil-extractor-liquid rotate: false - xy: 553, 509 + xy: 749, 946 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 oil-extractor-rotator rotate: false - xy: 651, 573 + xy: 749, 848 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 oil-extractor-top rotate: false - xy: 651, 475 + xy: 749, 750 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 pneumatic-drill rotate: false - xy: 1045, 1331 + xy: 1214, 1491 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pneumatic-drill-rotator rotate: false - xy: 913, 1199 + xy: 1346, 1491 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pneumatic-drill-top rotate: false - xy: 715, 1124 + xy: 1412, 1491 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 water-extractor rotate: false - xy: 922, 1001 + xy: 979, 889 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 water-extractor-liquid rotate: false - xy: 988, 1001 + xy: 979, 823 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 water-extractor-rotator rotate: false - xy: 1120, 1067 + xy: 913, 757 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 water-extractor-top rotate: false - xy: 1054, 1001 + xy: 979, 757 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-border rotate: false - xy: 1920, 995 + xy: 1361, 1197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-middle rotate: false - xy: 285, 11 + xy: 1361, 1163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-select rotate: false - xy: 319, 11 + xy: 1361, 1129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-liquid rotate: false - xy: 1588, 999 + xy: 1029, 280 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 place-arrow rotate: false - xy: 1913, 1597 + xy: 717, 554 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 rubble-1-0 rotate: false - xy: 979, 1199 + xy: 1742, 1459 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 rubble-1-1 rotate: false - xy: 913, 1133 + xy: 1808, 1459 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 rubble-2-0 rotate: false - xy: 1177, 1331 + xy: 1874, 1459 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 rubble-2-1 rotate: false - xy: 1111, 1265 + xy: 1940, 1459 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 rubble-3-0 rotate: false - xy: 749, 475 + xy: 783, 260 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 rubble-3-1 rotate: false - xy: 749, 475 + xy: 783, 260 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 rubble-4-0 rotate: false - xy: 423, 705 + xy: 293, 742 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 rubble-4-1 rotate: false - xy: 423, 705 + xy: 293, 742 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 bridge-conduit rotate: false - xy: 996, 909 + xy: 1399, 1333 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conduit-icon-full rotate: false - xy: 996, 909 + xy: 1399, 1333 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conduit-arrow rotate: false - xy: 1030, 909 + xy: 1399, 1299 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor-arrow rotate: false - xy: 1030, 909 + xy: 1399, 1299 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conduit-bridge rotate: false - xy: 1064, 909 + xy: 1395, 1265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conduit-end rotate: false - xy: 1098, 909 + xy: 1395, 1231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom rotate: false - xy: 1418, 975 + xy: 1101, 416 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-0 rotate: false - xy: 1410, 907 + xy: 1101, 382 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-1 rotate: false - xy: 1452, 999 + xy: 1033, 348 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-2 rotate: false - xy: 1486, 999 + xy: 1067, 348 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-3 rotate: false - xy: 1486, 999 + xy: 1067, 348 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-4 rotate: false - xy: 1486, 999 + xy: 1067, 348 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-6 rotate: false - xy: 1486, 999 + xy: 1067, 348 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-5 rotate: false - xy: 1520, 999 + xy: 1101, 348 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-0 rotate: false - xy: 1622, 999 + xy: 1063, 314 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-1 rotate: false - xy: 1452, 965 + xy: 1029, 246 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-2 rotate: false - xy: 1486, 965 + xy: 1063, 280 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-3 rotate: false - xy: 1520, 965 + xy: 1097, 314 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-3 rotate: false - xy: 1520, 965 + xy: 1097, 314 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-4 rotate: false - xy: 1554, 965 + xy: 1029, 212 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-5 rotate: false - xy: 1588, 965 + xy: 1063, 246 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-6 rotate: false - xy: 1622, 965 + xy: 1097, 280 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-junction rotate: false - xy: 873, 832 + xy: 1379, 959 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-junction-icon-full rotate: false - xy: 873, 832 + xy: 1379, 959 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-router-bottom rotate: false - xy: 873, 798 + xy: 1447, 959 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-router-liquid rotate: false - xy: 839, 730 + xy: 1279, 899 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-router-top rotate: false - xy: 873, 764 + xy: 1279, 865 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-tank-bottom rotate: false - xy: 1129, 1463 + xy: 651, 1240 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 liquid-tank-liquid rotate: false - xy: 1325, 1465 + xy: 651, 1044 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 liquid-tank-top rotate: false - xy: 1423, 1463 + xy: 651, 946 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mechanical-pump rotate: false - xy: 873, 696 + xy: 1313, 839 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mechanical-pump-icon-full rotate: false - xy: 873, 696 + xy: 1313, 839 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit rotate: false - xy: 915, 560 + xy: 1415, 823 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit-icon-full rotate: false - xy: 915, 560 + xy: 1415, 823 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit-arrow rotate: false - xy: 915, 526 + xy: 1449, 823 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit-bridge rotate: false - xy: 915, 492 + xy: 1483, 823 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit-end rotate: false - xy: 897, 458 + xy: 1313, 805 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-0 rotate: false - xy: 941, 764 + xy: 1449, 755 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-1 rotate: false - xy: 941, 730 + xy: 1483, 755 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-2 rotate: false - xy: 941, 696 + xy: 1289, 737 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-4 rotate: false - xy: 949, 662 + xy: 1165, 314 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-5 rotate: false - xy: 949, 628 + xy: 1165, 280 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-6 rotate: false - xy: 949, 594 + xy: 1165, 246 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rotary-pump rotate: false - xy: 1111, 1331 + xy: 1610, 1463 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 rotary-pump-icon-full rotate: false - xy: 1111, 1331 + xy: 1610, 1463 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thermal-pump rotate: false - xy: 521, 215 + xy: 881, 162 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 thermal-pump-icon-full rotate: false - xy: 521, 215 + xy: 881, 162 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dart-mech-pad rotate: false - xy: 821, 13 + xy: 393, 58 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dart-mech-pad-icon-full rotate: false - xy: 821, 13 + xy: 393, 58 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 delta-mech-pad rotate: false - xy: 887, 13 + xy: 459, 118 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 delta-mech-pad-icon-full rotate: false - xy: 887, 13 + xy: 459, 118 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 glaive-ship-pad rotate: false - xy: 1815, 1597 + xy: 685, 282 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 glaive-ship-pad-icon-full rotate: false - xy: 1815, 1597 + xy: 685, 282 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 javelin-ship-pad rotate: false - xy: 781, 1388 + xy: 1280, 1623 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 javelin-ship-pad-icon-full rotate: false - xy: 781, 1388 + xy: 1280, 1623 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 omega-mech-pad rotate: false - xy: 1913, 1695 + xy: 749, 652 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 omega-mech-pad-icon-full rotate: false - xy: 1913, 1695 + xy: 749, 652 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 tau-mech-pad rotate: false - xy: 1375, 1133 + xy: 979, 1285 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 tau-mech-pad-icon-full rotate: false - xy: 1375, 1133 + xy: 979, 1285 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 trident-ship-pad rotate: false - xy: 790, 1058 + xy: 979, 1087 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 trident-ship-pad-icon-full rotate: false - xy: 790, 1058 + xy: 979, 1087 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 battery rotate: false - xy: 1960, 1033 + xy: 1361, 1265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 battery-icon-full rotate: false - xy: 1960, 1033 + xy: 1361, 1265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 battery-large rotate: false - xy: 423, 363 + xy: 293, 384 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 battery-large-icon-full rotate: false - xy: 423, 363 + xy: 293, 384 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 combustion-generator rotate: false - xy: 359, 19 + xy: 1067, 416 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 combustion-generator-icon-full rotate: false - xy: 359, 19 + xy: 1067, 416 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 combustion-generator-top rotate: false - xy: 1410, 941 + xy: 1067, 382 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 differential-generator rotate: false - xy: 1129, 1561 + xy: 656, 1534 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 differential-generator-icon-full rotate: false - xy: 1129, 1561 + xy: 656, 1534 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 differential-generator-liquid rotate: false - xy: 1227, 1659 + xy: 293, 188 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 differential-generator-top rotate: false - xy: 1227, 1561 + xy: 391, 384 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 impact-reactor rotate: false - xy: 519, 1225 + xy: 1888, 1787 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-bottom rotate: false - xy: 519, 1095 + xy: 1498, 1661 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-light rotate: false - xy: 594, 965 + xy: 1758, 1657 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-plasma-0 rotate: false - xy: 163, 814 + xy: 1888, 1657 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-plasma-1 rotate: false - xy: 163, 684 + xy: 163, 251 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-plasma-2 rotate: false - xy: 163, 554 + xy: 155, 121 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-plasma-3 rotate: false - xy: 163, 424 + xy: 219, 1262 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 power-node rotate: false - xy: 931, 390 + xy: 1483, 789 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-node-icon-full rotate: false - xy: 931, 390 + xy: 1483, 789 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-node-large rotate: false - xy: 781, 1124 + xy: 1478, 1463 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 power-node-large-icon-full rotate: false - xy: 781, 1124 + xy: 1478, 1463 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 power-source rotate: false - xy: 931, 356 + xy: 1313, 771 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-void rotate: false - xy: 941, 832 + xy: 1381, 755 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-void-icon-full rotate: false - xy: 941, 832 + xy: 1381, 755 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rtg-generator rotate: false - xy: 1045, 1265 + xy: 1676, 1463 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 rtg-generator-icon-full rotate: false - xy: 1045, 1265 + xy: 1676, 1463 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 rtg-generator-top rotate: false - xy: 1077, 875 + xy: 1463, 1197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel rotate: false - xy: 1077, 739 + xy: 1467, 1363 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel-icon-full rotate: false - xy: 1077, 739 + xy: 1467, 1363 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel-large rotate: false - xy: 733, 377 + xy: 881, 260 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 solar-panel-large-icon-full rotate: false - xy: 733, 377 + xy: 881, 260 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 surge-tower rotate: false - xy: 1573, 1331 + xy: 903, 1351 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 surge-tower-icon-full rotate: false - xy: 1573, 1331 + xy: 903, 1351 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thermal-generator rotate: false - xy: 1441, 1133 + xy: 913, 1219 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thermal-generator-icon-full rotate: false - xy: 1441, 1133 + xy: 913, 1219 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thorium-reactor rotate: false - xy: 619, 279 + xy: 754, 1632 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 thorium-reactor-icon-full rotate: false - xy: 619, 279 + xy: 754, 1632 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 thorium-reactor-center rotate: false - xy: 717, 279 + xy: 754, 1534 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 thorium-reactor-lights rotate: false - xy: 619, 181 + xy: 779, 1436 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 turbine-generator rotate: false - xy: 790, 992 + xy: 913, 1021 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 turbine-generator-icon-full rotate: false - xy: 790, 992 + xy: 913, 1021 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 turbine-generator-top rotate: false - xy: 856, 1058 + xy: 979, 1021 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 alloy-smelter rotate: false - xy: 541, 1629 + xy: 1, 1 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 alloy-smelter-icon-full rotate: false - xy: 541, 1629 + xy: 1, 1 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 alloy-smelter-top rotate: false - xy: 553, 607 + xy: 1934, 1949 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 blast-mixer rotate: false - xy: 359, 53 + xy: 651, 586 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 blast-mixer-icon-full rotate: false - xy: 359, 53 + xy: 651, 586 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 coal-centrifuge rotate: false - xy: 831, 343 + xy: 295, 24 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 coal-centrifuge-icon-full rotate: false - xy: 831, 343 + xy: 295, 24 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cryofluidmixer-bottom rotate: false - xy: 557, 83 + xy: 847, 942 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cryofluidmixer-liquid rotate: false - xy: 623, 115 + xy: 847, 810 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cryofluidmixer-top rotate: false - xy: 689, 115 + xy: 847, 744 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cultivator rotate: false - xy: 623, 49 + xy: 847, 678 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cultivator-middle rotate: false - xy: 755, 79 + xy: 1016, 1549 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cultivator-top rotate: false - xy: 821, 79 + xy: 877, 1493 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 graphite-press rotate: false - xy: 715, 1388 + xy: 1148, 1557 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 graphite-press-icon-full rotate: false - xy: 715, 1388 + xy: 1148, 1557 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 incinerator rotate: false - xy: 1920, 893 + xy: 1447, 993 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 incinerator-icon-full rotate: false - xy: 1920, 893 + xy: 1447, 993 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-source rotate: false - xy: 846, 900 + xy: 2006, 1487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-source-icon-full rotate: false - xy: 846, 900 + xy: 2006, 1487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-void rotate: false - xy: 873, 866 + xy: 1229, 773 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-void-icon-full rotate: false - xy: 873, 866 + xy: 1229, 773 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 kiln rotate: false - xy: 847, 1388 + xy: 1214, 1557 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 kiln-icon-full rotate: false - xy: 847, 1388 + xy: 1214, 1557 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 kiln-top rotate: false - xy: 913, 1397 + xy: 1346, 1623 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 silicon-smelter-top rotate: false - xy: 913, 1397 + xy: 1346, 1623 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 liquid-source rotate: false - xy: 839, 696 + xy: 1255, 739 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-source-icon-full rotate: false - xy: 839, 696 + xy: 1255, 739 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 melter rotate: false - xy: 907, 730 + xy: 1347, 923 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 melter-icon-full rotate: false - xy: 907, 730 + xy: 1347, 923 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 multi-press rotate: false - xy: 1815, 1499 + xy: 749, 1240 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 multi-press-icon-full rotate: false - xy: 1815, 1499 + xy: 749, 1240 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 phase-weaver rotate: false - xy: 979, 1331 + xy: 1676, 1529 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phase-weaver-bottom rotate: false - xy: 913, 1265 + xy: 1742, 1525 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phase-weaver-weave rotate: false - xy: 715, 1190 + xy: 1874, 1525 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 plastanium-compressor rotate: false - xy: 781, 1190 + xy: 1940, 1525 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 plastanium-compressor-icon-full rotate: false - xy: 781, 1190 + xy: 1940, 1525 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 plastanium-compressor-top rotate: false - xy: 847, 1190 + xy: 1148, 1491 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pulverizer rotate: false - xy: 949, 560 + xy: 1165, 212 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulverizer-rotator rotate: false - xy: 949, 492 + xy: 1173, 144 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pump-liquid rotate: false - xy: 975, 875 + xy: 1173, 110 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pyratite-mixer rotate: false - xy: 847, 1124 + xy: 1544, 1463 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pyratite-mixer-icon-full rotate: false - xy: 847, 1124 + xy: 1544, 1463 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 separator rotate: false - xy: 1309, 1333 + xy: 1405, 1425 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 separator-icon-full rotate: false - xy: 1309, 1333 + xy: 1405, 1425 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 separator-liquid rotate: false - xy: 1309, 1267 + xy: 1471, 1397 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 silicon-smelter rotate: false - xy: 1309, 1201 + xy: 1537, 1397 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 silicon-smelter-icon-full rotate: false - xy: 1309, 1201 + xy: 1537, 1397 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press rotate: false - xy: 1375, 1265 + xy: 1735, 1393 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press-frame0 rotate: false - xy: 1441, 1331 + xy: 1801, 1393 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press-frame1 rotate: false - xy: 1375, 1199 + xy: 1867, 1393 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press-frame2 rotate: false - xy: 1441, 1265 + xy: 1933, 1393 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press-liquid rotate: false - xy: 1441, 1199 + xy: 1045, 1417 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press-top rotate: false - xy: 1507, 1265 + xy: 913, 1417 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 container rotate: false - xy: 815, 211 + xy: 1098, 1689 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 container-icon-full rotate: false - xy: 815, 211 + xy: 1098, 1689 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 core-foundation rotate: false - xy: 1555, 1757 + xy: 163, 381 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 core-foundation-icon-full rotate: false - xy: 1555, 1757 + xy: 163, 381 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 core-nucleus rotate: false - xy: 848, 1887 + xy: 1, 999 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 core-nucleus-icon-full rotate: false - xy: 848, 1887 + xy: 1, 999 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 core-shard rotate: false - xy: 639, 1618 + xy: 293, 286 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 core-shard-icon-full rotate: false - xy: 639, 1618 + xy: 293, 286 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 launch-pad rotate: false - xy: 1031, 1463 + xy: 707, 1338 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 launch-pad-icon-full rotate: false - xy: 1031, 1463 + xy: 707, 1338 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 launch-pad-large rotate: false - xy: 163, 294 + xy: 349, 1262 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 launch-pad-large-icon-full rotate: false - xy: 163, 294 + xy: 349, 1262 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 unloader rotate: false - xy: 1051, 637 + xy: 1565, 1193 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unloader-icon-full rotate: false - xy: 1051, 637 + xy: 1565, 1193 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 vault rotate: false - xy: 285, 119 + xy: 852, 1559 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 vault-icon-full rotate: false - xy: 285, 119 + xy: 852, 1559 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 arc-heat rotate: false - xy: 1979, 1793 + xy: 877, 1459 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-1 rotate: false - xy: 1994, 1033 + xy: 1361, 1231 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-2 rotate: false - xy: 831, 409 + xy: 717, 488 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-3 rotate: false - xy: 541, 1531 + xy: 423, 514 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-4 rotate: false - xy: 1035, 1757 + xy: 163, 901 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 hail-heat rotate: false - xy: 541, 1489 + xy: 609, 1296 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 lancer-heat rotate: false - xy: 1045, 1397 + xy: 1412, 1623 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 meltdown-heat rotate: false - xy: 155, 34 + xy: 293, 1132 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 ripple-heat rotate: false - xy: 1913, 1401 + xy: 783, 456 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 salvo-heat rotate: false - xy: 979, 1133 + xy: 789, 96 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 salvo-panel-left rotate: false - xy: 1177, 1265 + xy: 921, 96 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 salvo-panel-right rotate: false - xy: 1111, 1199 + xy: 723, 30 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scorch-heat rotate: false - xy: 1077, 841 + xy: 1517, 925 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 wave-liquid rotate: false - xy: 1186, 1001 + xy: 1045, 1285 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 command-center rotate: false - xy: 815, 277 + xy: 950, 1615 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 command-center-icon-full rotate: false - xy: 815, 277 + xy: 950, 1615 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 crawler-factory rotate: false - xy: 515, 149 + xy: 847, 1140 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dagger-factory rotate: false - xy: 515, 149 + xy: 847, 1140 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 draug-factory rotate: false - xy: 515, 149 + xy: 847, 1140 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phantom-factory rotate: false - xy: 515, 149 + xy: 847, 1140 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spirit-factory rotate: false - xy: 515, 149 + xy: 847, 1140 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 wraith-factory rotate: false - xy: 515, 149 + xy: 847, 1140 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 crawler-factory-top rotate: false - xy: 491, 1 + xy: 847, 1008 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dagger-factory-top rotate: false - xy: 755, 13 + xy: 1009, 1483 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 draug-factory-top rotate: false - xy: 1589, 1397 + xy: 525, 52 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 fortress-factory rotate: false - xy: 1423, 1561 + xy: 489, 282 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 fortress-factory-top rotate: false - xy: 1619, 1659 + xy: 619, 478 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 ghoul-factory-top rotate: false - xy: 1619, 1659 + xy: 619, 478 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 titan-factory-top rotate: false - xy: 1619, 1659 + xy: 619, 478 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 ghoul-factory rotate: false - xy: 1717, 1597 + xy: 587, 184 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 phantom-factory-top rotate: false - xy: 781, 1256 + xy: 1544, 1529 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 repair-point-base rotate: false - xy: 975, 841 + xy: 1173, 42 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 revenant-factory rotate: false - xy: 293, 705 + xy: 423, 1132 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 revenant-factory-top rotate: false - xy: 293, 575 + xy: 423, 1002 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 spirit-factory-top rotate: false - xy: 1375, 1331 + xy: 1669, 1397 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 titan-factory rotate: false - xy: 717, 181 + xy: 805, 1338 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 wraith-factory-top rotate: false - xy: 1252, 1001 + xy: 1045, 1153 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 copper-wall rotate: false - xy: 1690, 941 + xy: 1429, 1197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper-wall-icon-full rotate: false - xy: 1690, 941 + xy: 1429, 1197 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper-wall-large rotate: false - xy: 815, 145 + xy: 1016, 1615 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 copper-wall-large-icon-full rotate: false - xy: 815, 145 + xy: 1016, 1615 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 door rotate: false - xy: 1336, 891 + xy: 1037, 76 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 door-icon-full rotate: false - xy: 1336, 891 + xy: 1037, 76 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 door-large rotate: false - xy: 1391, 1397 + xy: 591, 118 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 door-large-icon-full rotate: false - xy: 1391, 1397 + xy: 591, 118 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 door-large-open rotate: false - xy: 1457, 1397 + xy: 657, 118 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 door-open rotate: false - xy: 1370, 891 + xy: 1071, 110 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall rotate: false - xy: 931, 424 + xy: 1449, 789 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall-icon-full rotate: false - xy: 931, 424 + xy: 1449, 789 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall-large rotate: false - xy: 847, 1256 + xy: 1610, 1529 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phase-wall-large-icon-full rotate: false - xy: 847, 1256 + xy: 1610, 1529 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scrap-wall-gigantic rotate: false - xy: 553, 835 + xy: 423, 872 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 scrap-wall-gigantic-icon-full rotate: false - xy: 553, 835 + xy: 423, 872 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 scrap-wall-huge1 rotate: false - xy: 537, 411 + xy: 783, 162 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 scrap-wall-huge-icon-full rotate: false - xy: 537, 411 + xy: 783, 162 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 scrap-wall-huge2 rotate: false - xy: 521, 313 + xy: 881, 456 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 scrap-wall-huge3 rotate: false - xy: 635, 377 + xy: 881, 358 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 scrap-wall-large1 rotate: false - xy: 1177, 1199 + xy: 921, 30 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scrap-wall-large2 rotate: false - xy: 1111, 1133 + xy: 1141, 1425 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scrap-wall-large3 rotate: false - xy: 1243, 1199 + xy: 1207, 1425 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scrap-wall-large4 rotate: false - xy: 1177, 1133 + xy: 1273, 1425 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scrap-wall1 rotate: false - xy: 975, 705 + xy: 1517, 857 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall-icon-full rotate: false - xy: 975, 705 + xy: 1517, 857 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall2 rotate: false - xy: 1009, 739 + xy: 1517, 823 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall3 rotate: false - xy: 1043, 773 + xy: 1517, 789 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall4 rotate: false - xy: 1077, 807 + xy: 1517, 755 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall5 rotate: false - xy: 1077, 807 + xy: 1517, 755 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 surge-wall rotate: false - xy: 1111, 739 + xy: 1535, 1329 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 surge-wall-icon-full rotate: false - xy: 1111, 739 + xy: 1535, 1329 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 surge-wall-large rotate: false - xy: 1507, 1199 + xy: 969, 1351 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 surge-wall-large-icon-full rotate: false - xy: 1507, 1199 + xy: 969, 1351 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thorium-wall rotate: false - xy: 1111, 705 + xy: 1603, 1329 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium-wall-icon-full rotate: false - xy: 1111, 705 + xy: 1603, 1329 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium-wall-large rotate: false - xy: 1507, 1133 + xy: 979, 1219 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thorium-wall-large-icon-full rotate: false - xy: 1507, 1133 + xy: 979, 1219 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thruster rotate: false - xy: 553, 705 + xy: 293, 482 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 thruster-icon-full rotate: false - xy: 553, 705 + xy: 293, 482 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 titanium-wall rotate: false - xy: 983, 569 + xy: 1633, 1261 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-wall-icon-full rotate: false - xy: 983, 569 + xy: 1633, 1261 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-wall-large rotate: false - xy: 724, 992 + xy: 913, 1087 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 titanium-wall-large-icon-full rotate: false - xy: 724, 992 + xy: 913, 1087 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 bullet rotate: false - xy: 1318, 1081 + xy: 979, 405 size: 52, 52 orig: 52, 52 offset: 0, 0 index: -1 bullet-back rotate: false - xy: 1318, 1027 + xy: 979, 351 size: 52, 52 orig: 52, 52 offset: 0, 0 index: -1 casing rotate: false - xy: 537, 557 + xy: 903, 1423 size: 8, 16 orig: 8, 16 offset: 0, 0 index: -1 circle-shadow rotate: false - xy: 1, 944 + xy: 645, 1844 size: 201, 201 orig: 201, 201 offset: 0, 0 index: -1 error rotate: false - xy: 1639, 1347 + xy: 1351, 1375 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 laser rotate: false - xy: 515, 215 + xy: 155, 301 size: 4, 48 orig: 4, 48 offset: 0, 0 index: -1 laser-end rotate: false - xy: 285, 45 + xy: 759, 1770 size: 72, 72 orig: 72, 72 offset: 0, 0 index: -1 minelaser rotate: false - xy: 419, 3 + xy: 155, 251 size: 4, 48 orig: 4, 48 offset: 0, 0 index: -1 minelaser-end rotate: false - xy: 1966, 1901 + xy: 950, 1681 size: 72, 72 orig: 72, 72 offset: 0, 0 index: -1 missile rotate: false - xy: 581, 177 + xy: 759, 1732 size: 36, 36 orig: 36, 36 offset: 0, 0 index: -1 missile-back rotate: false - xy: 848, 1849 + xy: 1361, 1337 size: 36, 36 orig: 36, 36 offset: 0, 0 index: -1 scale_marker rotate: false - xy: 639, 1721 + xy: 459, 184 size: 4, 4 orig: 4, 4 offset: 0, 0 index: -1 scorch1 rotate: false - xy: 2019, 1799 + xy: 1705, 1295 size: 28, 100 orig: 28, 100 offset: 0, 0 index: -1 scorch2 rotate: false - xy: 965, 390 + xy: 1735, 1291 size: 28, 100 orig: 28, 100 offset: 0, 0 index: -1 scorch3 rotate: false - xy: 1281, 791 + xy: 1765, 1291 size: 28, 100 orig: 28, 100 offset: 0, 0 index: -1 scorch4 rotate: false - xy: 1281, 689 + xy: 1795, 1291 size: 28, 100 orig: 28, 100 offset: 0, 0 index: -1 scorch5 rotate: false - xy: 947, 254 + xy: 1825, 1291 size: 28, 100 orig: 28, 100 offset: 0, 0 index: -1 shell rotate: false - xy: 1882, 1013 + xy: 1103, 721 size: 36, 36 orig: 36, 36 offset: 0, 0 index: -1 shell-back rotate: false - xy: 1922, 1029 + xy: 1361, 1299 size: 36, 36 orig: 36, 36 offset: 0, 0 index: -1 shot rotate: false - xy: 1111, 807 + xy: 1483, 721 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 transfer rotate: false - xy: 417, 265 + xy: 285, 201 size: 4, 48 orig: 4, 48 offset: 0, 0 index: -1 transfer-arrow rotate: false - xy: 1017, 603 + xy: 1599, 1227 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 transfer-end rotate: false - xy: 1945, 1827 + xy: 1024, 1681 size: 72, 72 orig: 72, 72 offset: 0, 0 index: -1 white rotate: false - xy: 254, 1142 + xy: 645, 1725 size: 3, 3 orig: 3, 3 offset: 0, 0 index: -1 arc rotate: false - xy: 1945, 1793 + xy: 609, 1262 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 arc-icon-full rotate: false - xy: 755, 147 + xy: 797, 1736 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 blast-drill-icon-full rotate: false - xy: 323, 1355 + xy: 323, 1392 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 char-icon-full rotate: false - xy: 1268, 909 + xy: 1033, 416 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cliffs-icon-full rotate: false - xy: 1302, 893 + xy: 1033, 382 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-icon-full rotate: false - xy: 1554, 999 + xy: 1029, 314 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-0 rotate: false - xy: 1724, 941 + xy: 1429, 1163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-1 rotate: false - xy: 1758, 941 + xy: 1429, 1129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-2 rotate: false - xy: 1792, 941 + xy: 1429, 1095 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-3 rotate: false - xy: 1826, 941 + xy: 1429, 1061 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-4 rotate: false - xy: 1860, 941 + xy: 1428, 1027 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-5 rotate: false - xy: 1648, 907 + xy: 1163, 550 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-6 rotate: false - xy: 1682, 907 + xy: 1163, 516 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-7 rotate: false - xy: 1716, 907 + xy: 1163, 482 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-2-0 rotate: false - xy: 391, 199 + xy: 1164, 1689 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-1 rotate: false - xy: 383, 133 + xy: 1230, 1689 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-2 rotate: false - xy: 881, 277 + xy: 1296, 1689 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-3 rotate: false - xy: 881, 211 + xy: 1362, 1689 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-4 rotate: false - xy: 881, 145 + xy: 1428, 1689 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-5 rotate: false - xy: 425, 67 + xy: 393, 124 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-6 rotate: false - xy: 425, 1 + xy: 847, 1272 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-7 rotate: false - xy: 449, 133 + xy: 847, 1206 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-3-0 rotate: false - xy: 737, 1618 + xy: 656, 1632 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-1 rotate: false - xy: 639, 1520 + xy: 553, 1164 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-2 rotate: false - xy: 737, 1520 + xy: 553, 1066 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-3 rotate: false - xy: 835, 1618 + xy: 553, 968 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-4 rotate: false - xy: 835, 1520 + xy: 553, 870 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-5 rotate: false - xy: 933, 1659 + xy: 553, 772 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-6 rotate: false - xy: 933, 1561 + xy: 553, 674 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-7 rotate: false - xy: 1031, 1659 + xy: 553, 576 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-4-0 rotate: false - xy: 1685, 1793 + xy: 848, 1755 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-1 rotate: false - xy: 1815, 1793 + xy: 978, 1755 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-2 rotate: false - xy: 259, 1225 + xy: 1108, 1755 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-3 rotate: false - xy: 389, 1225 + xy: 1238, 1755 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-4 rotate: false - xy: 259, 1095 + xy: 1368, 1755 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-5 rotate: false - xy: 389, 1095 + xy: 1498, 1791 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-6 rotate: false - xy: 204, 965 + xy: 1628, 1791 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-7 rotate: false - xy: 334, 965 + xy: 1758, 1787 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-5-0 rotate: false - xy: 1, 782 + xy: 848, 1885 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-1 rotate: false - xy: 1010, 1887 + xy: 1, 837 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-2 rotate: false - xy: 1, 620 + xy: 1010, 1885 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-3 rotate: false - xy: 1172, 1887 + xy: 1, 675 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-4 rotate: false - xy: 1, 458 + xy: 1172, 1885 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-5 rotate: false - xy: 1334, 1887 + xy: 1, 513 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-6 rotate: false - xy: 1, 296 + xy: 1334, 1885 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-7 rotate: false - xy: 1496, 1887 + xy: 1, 351 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 craters-icon-full rotate: false - xy: 1, 1147 - size: 256, 256 - orig: 256, 256 + xy: 1203, 807 + size: 32, 32 + orig: 32, 32 offset: 0, 0 index: -1 crawler-factory-icon-full rotate: false - xy: 491, 67 + xy: 847, 1074 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cryofluidmixer-icon-full rotate: false - xy: 557, 17 + xy: 847, 876 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cultivator-icon-full rotate: false - xy: 689, 49 + xy: 950, 1549 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cyclone rotate: false - xy: 1031, 1561 + xy: 99, 1 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cyclone-icon-full rotate: false - xy: 1129, 1659 + xy: 197, 23 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dagger-factory-icon-full rotate: false - xy: 887, 79 + xy: 943, 1483 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dark-metal-icon-full rotate: false - xy: 1750, 907 + xy: 1195, 773 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-1-icon-full rotate: false - xy: 1784, 907 + xy: 1187, 739 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-2-icon-full rotate: false - xy: 1818, 907 + xy: 1345, 991 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-3-icon-full rotate: false - xy: 1852, 907 + xy: 1379, 993 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-4-icon-full rotate: false - xy: 1648, 873 + xy: 1413, 993 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-5-icon-full rotate: false - xy: 1682, 873 + xy: 1037, 178 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-6-icon-full rotate: false - xy: 1716, 873 + xy: 1037, 144 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-icon-full rotate: false - xy: 1750, 873 + xy: 1071, 178 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-tainted-water-icon-full rotate: false - xy: 1784, 873 + xy: 1037, 110 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-water-icon-full rotate: false - xy: 1818, 873 + xy: 1071, 144 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 deepwater-icon-full rotate: false - xy: 1852, 873 + xy: 1105, 178 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 draug-factory-icon-full rotate: false - xy: 1523, 1397 + xy: 459, 52 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dunerocks-icon-full rotate: false - xy: 1404, 873 + xy: 1105, 144 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 duo rotate: false - xy: 1438, 863 + xy: 1071, 76 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 duo-icon-full rotate: false - xy: 1472, 863 + xy: 1105, 110 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 fortress-factory-icon-full rotate: false - xy: 1521, 1561 + xy: 489, 184 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 fuse rotate: false - xy: 1619, 1561 + xy: 587, 380 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 fuse-icon-full rotate: false - xy: 1717, 1695 + xy: 587, 282 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 ghoul-factory-icon-full rotate: false - xy: 1815, 1695 + xy: 685, 380 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 grass-icon-full rotate: false - xy: 1506, 863 + xy: 1105, 76 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 hail rotate: false - xy: 1540, 863 + xy: 1037, 42 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 hail-icon-full rotate: false - xy: 1574, 863 + xy: 1071, 42 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 holostone-icon-full rotate: false - xy: 1608, 863 + xy: 1105, 42 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 hotrock-icon-full rotate: false - xy: 1894, 961 + xy: 1139, 178 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-icon-full rotate: false - xy: 1928, 961 + xy: 1139, 144 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-snow-icon-full rotate: false - xy: 1894, 927 + xy: 1139, 110 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 icerocks-icon-full rotate: false - xy: 1928, 927 + xy: 1139, 76 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ignarock-icon-full rotate: false - xy: 1886, 893 + xy: 1139, 42 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 impact-reactor-icon-full rotate: false - xy: 464, 965 + xy: 1628, 1661 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 item-blast-compound-medium rotate: false - xy: 789, 155 + xy: 583, 1410 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-blast-compound-small rotate: false - xy: 1894, 995 + xy: 583, 1392 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-blast-compound-xlarge rotate: false - xy: 1, 2 + xy: 1029, 576 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-blast-compound-xxlarge rotate: false - xy: 1689, 1301 + xy: 1111, 1159 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-coal-medium rotate: false - xy: 1658, 1897 + xy: 847, 652 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-coal-small rotate: false - xy: 353, 1 + xy: 155, 103 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-coal-xlarge rotate: false - xy: 1922, 1109 + xy: 1203, 883 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-coal-xxlarge rotate: false - xy: 1739, 1351 + xy: 1161, 1325 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-copper-medium rotate: false - xy: 905, 1731 + xy: 873, 652 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-copper-small rotate: false - xy: 371, 1 + xy: 852, 1541 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-copper-xlarge rotate: false - xy: 43, 2 + xy: 1253, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-copper-xxlarge rotate: false - xy: 1689, 1251 + xy: 1211, 1325 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-graphite-medium rotate: false - xy: 1685, 1767 + xy: 1934, 1923 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-graphite-small rotate: false - xy: 204, 947 + xy: 723, 166 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-graphite-xlarge rotate: false - xy: 1922, 1067 + xy: 1303, 983 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-graphite-xxlarge rotate: false - xy: 1739, 1301 + xy: 1161, 1275 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-lead-medium rotate: false - xy: 651, 679 + xy: 521, 586 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-lead-small rotate: false - xy: 1945, 1905 + xy: 913, 557 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-lead-xlarge rotate: false - xy: 1964, 1109 + xy: 1153, 783 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-lead-xxlarge rotate: false - xy: 1789, 1351 + xy: 1261, 1325 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-metaglass-medium rotate: false - xy: 391, 289 + xy: 423, 488 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-metaglass-small rotate: false - xy: 913, 1502 + xy: 877, 1441 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-metaglass-xlarge rotate: false - xy: 85, 2 + xy: 1071, 576 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-metaglass-xxlarge rotate: false - xy: 1689, 1201 + xy: 1211, 1275 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-phase-fabric-medium rotate: false - xy: 583, 1362 + xy: 219, 1162 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-phase-fabric-small rotate: false - xy: 886, 1869 + xy: 895, 1441 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-phase-fabric-xlarge rotate: false - xy: 1964, 1067 + xy: 1203, 841 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-phase-fabric-xxlarge rotate: false - xy: 1739, 1251 + xy: 1161, 1225 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-plastanium-medium rotate: false - xy: 649, 1098 + xy: 1111, 1457 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-plastanium-small rotate: false - xy: 2028, 1049 + xy: 197, 5 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-plastanium-xlarge rotate: false - xy: 2006, 1109 + xy: 1113, 576 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-plastanium-xxlarge rotate: false - xy: 1789, 1301 + xy: 1311, 1325 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-pyratite-medium rotate: false - xy: 724, 966 + xy: 1163, 456 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-pyratite-small rotate: false - xy: 1311, 875 + xy: 1323, 753 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-pyratite-xlarge rotate: false - xy: 2006, 1067 + xy: 1037, 534 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-pyratite-xxlarge rotate: false - xy: 1839, 1351 + xy: 1261, 1275 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-sand-medium rotate: false - xy: 1639, 1155 + xy: 2006, 1461 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-sand-small rotate: false - xy: 391, 271 + xy: 1451, 1407 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-sand-xlarge rotate: false - xy: 623, 7 + xy: 1037, 492 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-sand-xxlarge rotate: false - xy: 1739, 1201 + xy: 1211, 1225 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-scrap-medium rotate: false - xy: 127, 18 + xy: 361, 64 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-scrap-small rotate: false - xy: 675, 1106 + xy: 449, 496 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-scrap-xlarge rotate: false - xy: 665, 7 + xy: 1079, 534 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-scrap-xxlarge rotate: false - xy: 1789, 1251 + xy: 1161, 1175 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-silicon-medium rotate: false - xy: 581, 151 + xy: 429, 32 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-silicon-small rotate: false - xy: 750, 974 + xy: 245, 1170 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-silicon-xlarge rotate: false - xy: 707, 7 + xy: 1079, 492 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-silicon-xxlarge rotate: false - xy: 1839, 1301 + xy: 1311, 1275 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-spore-pod-medium rotate: false - xy: 393, 27 + xy: 1257, 713 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-spore-pod-small rotate: false - xy: 1665, 1163 + xy: 1111, 1439 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-spore-pod-xlarge rotate: false - xy: 1672, 1009 + xy: 1121, 534 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-spore-pod-xxlarge rotate: false - xy: 1889, 1351 + xy: 1261, 1225 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-surge-alloy-medium rotate: false - xy: 393, 1 + xy: 1467, 1303 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-surge-alloy-small rotate: false - xy: 1639, 1137 + xy: 1497, 1081 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-surge-alloy-xlarge rotate: false - xy: 1714, 1009 + xy: 1121, 492 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-surge-alloy-xxlarge rotate: false - xy: 1789, 1201 + xy: 1211, 1175 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-thorium-medium rotate: false - xy: 1017, 577 + xy: 1497, 1099 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-thorium-small rotate: false - xy: 983, 525 + xy: 1855, 1349 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-thorium-xlarge rotate: false - xy: 1756, 1009 + xy: 1037, 450 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-thorium-xxlarge rotate: false - xy: 1839, 1251 + xy: 1311, 1225 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-titanium-medium rotate: false - xy: 1051, 611 + xy: 1633, 1235 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-titanium-small rotate: false - xy: 1145, 687 + xy: 1881, 1375 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-titanium-xlarge rotate: false - xy: 1798, 1009 + xy: 1079, 450 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-titanium-xxlarge rotate: false - xy: 1889, 1301 + xy: 1261, 1175 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 lancer rotate: false - xy: 979, 1397 + xy: 1280, 1557 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 lancer-icon-full rotate: false - xy: 1111, 1397 + xy: 1346, 1557 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 laser-drill-icon-full rotate: false - xy: 683, 867 + xy: 295, 90 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 liquid-router-icon-full rotate: false - xy: 907, 832 + xy: 1481, 959 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-tank-icon-full rotate: false - xy: 1227, 1463 + xy: 651, 1142 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 magmarock-icon-full rotate: false - xy: 907, 764 + xy: 1313, 873 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mass-driver rotate: false - xy: 1521, 1463 + xy: 651, 848 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mass-driver-icon-full rotate: false - xy: 1717, 1499 + xy: 651, 652 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mech-icon-alpha-mech rotate: false - xy: 1939, 1301 + xy: 1261, 1125 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 mech-icon-dart-ship rotate: false - xy: 1889, 1201 + xy: 1311, 1125 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 mech-icon-delta-mech rotate: false - xy: 1939, 1251 + xy: 1111, 1109 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 mech-icon-glaive-ship rotate: false - xy: 1655, 1405 + xy: 1045, 892 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 mech-icon-javelin-ship rotate: false - xy: 1939, 1201 + xy: 1110, 1059 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 mech-icon-omega-mech rotate: false - xy: 846, 934 + xy: 584, 1537 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 mech-icon-tau-mech rotate: false - xy: 781, 731 + xy: 1045, 834 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 mech-icon-trident-ship rotate: false - xy: 781, 673 + xy: 1045, 776 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 mechanical-drill-icon-full rotate: false - xy: 1243, 1397 + xy: 1478, 1595 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 meltdown rotate: false - xy: 155, 164 + xy: 479, 1262 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 meltdown-icon-full rotate: false - xy: 293, 835 + xy: 293, 1002 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 metal-floor-2-icon-full rotate: false - xy: 847, 628 + xy: 1381, 925 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-3-icon-full rotate: false - xy: 881, 662 + xy: 1381, 891 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-5-icon-full rotate: false - xy: 847, 594 + xy: 1415, 925 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-damaged-icon-full rotate: false - xy: 881, 628 + xy: 1381, 857 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-icon-full rotate: false - xy: 847, 560 + xy: 1415, 891 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 moss-icon-full rotate: false - xy: 881, 594 + xy: 1449, 925 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 oil-extractor-icon-full rotate: false - xy: 1815, 1401 + xy: 749, 1044 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 ore-coal-icon-full rotate: false - xy: 847, 526 + xy: 1415, 857 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-coal-icon-medium rotate: false - xy: 847, 526 + xy: 1415, 857 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-coal-icon-large rotate: false - xy: 1989, 1351 + xy: 1103, 1009 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 ore-coal-icon-small rotate: false - xy: 1085, 645 + xy: 1599, 1201 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 ore-copper-icon-full rotate: false - xy: 881, 560 + xy: 1449, 891 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-copper-icon-medium rotate: false - xy: 881, 560 + xy: 1449, 891 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-copper-icon-large rotate: false - xy: 1989, 1301 + xy: 1103, 959 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 ore-copper-icon-small rotate: false - xy: 983, 543 + xy: 1565, 1167 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 ore-lead-icon-full rotate: false - xy: 847, 492 + xy: 1449, 857 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-lead-icon-medium rotate: false - xy: 847, 492 + xy: 1449, 857 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-lead-icon-large rotate: false - xy: 1989, 1251 + xy: 1103, 909 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 ore-lead-icon-small rotate: false - xy: 1119, 679 + xy: 1531, 1133 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 ore-scrap-icon-full rotate: false - xy: 881, 526 + xy: 1483, 925 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-scrap-icon-medium rotate: false - xy: 881, 526 + xy: 1483, 925 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-scrap-icon-large rotate: false - xy: 1989, 1201 + xy: 1103, 859 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 ore-scrap-icon-small rotate: false - xy: 947, 228 + xy: 1667, 1269 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 ore-thorium-icon-full rotate: false - xy: 881, 492 + xy: 1483, 891 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-thorium-icon-medium rotate: false - xy: 881, 492 + xy: 1483, 891 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-thorium-icon-large rotate: false - xy: 1689, 1151 + xy: 1103, 809 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 ore-thorium-icon-small rotate: false - xy: 965, 364 + xy: 1855, 1367 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 ore-titanium-icon-full rotate: false - xy: 915, 662 + xy: 1483, 857 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-titanium-icon-medium rotate: false - xy: 915, 662 + xy: 1483, 857 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ore-titanium-icon-large rotate: false - xy: 1739, 1151 + xy: 1103, 759 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 ore-titanium-icon-small rotate: false - xy: 609, 1362 + xy: 1960, 1923 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 pebbles-icon-full rotate: false - xy: 915, 594 + xy: 1381, 823 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phantom-factory-icon-full rotate: false - xy: 715, 1256 + xy: 1478, 1529 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phase-weaver-icon-full rotate: false - xy: 649, 1124 + xy: 1808, 1525 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pine-icon-full rotate: false - xy: 1789, 1151 + xy: 1161, 1075 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 pneumatic-drill-icon-full rotate: false - xy: 979, 1265 + xy: 1280, 1491 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 power-source-icon-full rotate: false - xy: 941, 866 + xy: 1347, 753 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-icon-full rotate: false - xy: 941, 798 + xy: 1415, 755 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulverizer-icon-full rotate: false - xy: 949, 526 + xy: 1173, 178 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 repair-point rotate: false - xy: 1009, 875 + xy: 1173, 76 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 repair-point-icon-full rotate: false - xy: 1043, 875 + xy: 1191, 8 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 revenant-factory-icon-full rotate: false - xy: 423, 835 + xy: 293, 872 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 ripple rotate: false - xy: 1913, 1499 + xy: 815, 554 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 ripple-icon-full rotate: false - xy: 749, 573 + xy: 783, 358 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 rock-icon-full rotate: false - xy: 1939, 1151 + xy: 1311, 1075 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 rocks-icon-full rotate: false - xy: 975, 807 + xy: 1463, 1265 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 salt-icon-full rotate: false - xy: 975, 773 + xy: 1463, 1163 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 saltrocks-icon-full rotate: false - xy: 1009, 807 + xy: 1463, 1129 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 salvo rotate: false - xy: 1045, 1199 + xy: 723, 96 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 salvo-icon-full rotate: false - xy: 1243, 1331 + xy: 855, 96 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 sand-boulder-icon-full rotate: false - xy: 1043, 841 + xy: 1463, 1095 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-icon-full rotate: false - xy: 1111, 875 + xy: 1463, 1061 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-water-icon-full rotate: false - xy: 975, 739 + xy: 1496, 1027 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sandrocks-icon-full rotate: false - xy: 1009, 773 + xy: 1515, 993 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scatter rotate: false - xy: 1045, 1133 + xy: 789, 30 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scatter-icon-full rotate: false - xy: 1243, 1265 + xy: 855, 30 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scorch rotate: false - xy: 1043, 807 + xy: 1515, 959 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scorch-icon-full rotate: false - xy: 1145, 875 + xy: 1517, 891 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall-large-icon-full rotate: false - xy: 1243, 1133 + xy: 1339, 1425 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 shale-boulder-icon-full rotate: false - xy: 1111, 841 + xy: 361, 24 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale-icon-full rotate: false - xy: 1179, 875 + xy: 395, 24 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shalerocks-icon-full rotate: false - xy: 1009, 705 + xy: 1381, 721 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shock-mine-icon-full rotate: false - xy: 1077, 773 + xy: 1449, 721 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shrubs-icon-full rotate: false - xy: 1145, 841 + xy: 1517, 721 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snow-icon-full rotate: false - xy: 1213, 875 + xy: 1189, 705 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snow-pine-icon-full rotate: false - xy: 1672, 1101 + xy: 1210, 1025 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 snowrock-icon-full rotate: false - xy: 1672, 1051 + xy: 1260, 1025 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 snowrocks-icon-full rotate: false - xy: 1043, 705 + xy: 1223, 705 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spawn-icon-full rotate: false - xy: 1145, 807 + xy: 1501, 1363 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spectre rotate: false - xy: 293, 445 + xy: 293, 612 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 spectre-icon-full rotate: false - xy: 423, 575 + xy: 423, 742 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 spirit-factory-icon-full rotate: false - xy: 1309, 1135 + xy: 1603, 1397 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-cluster-icon-full rotate: false - xy: 1840, 1009 + xy: 1121, 450 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 spore-moss-icon-full rotate: false - xy: 1179, 841 + xy: 1535, 1363 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-pine-icon-full rotate: false - xy: 1722, 1051 + xy: 1153, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 spore-press-icon-full rotate: false - xy: 1507, 1331 + xy: 979, 1417 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 sporerocks-icon-full rotate: false - xy: 1247, 875 + xy: 1501, 1329 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 stone-icon-full rotate: false - xy: 1077, 705 + xy: 1569, 1363 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 swarmer rotate: false - xy: 1573, 1265 + xy: 1035, 1351 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 swarmer-icon-full rotate: false - xy: 1573, 1199 + xy: 913, 1285 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 tainted-water-icon-full rotate: false - xy: 1145, 773 + xy: 1603, 1363 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tar-icon-full rotate: false - xy: 1179, 807 + xy: 1569, 1329 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tendrils-icon-full rotate: false - xy: 1213, 841 + xy: 1637, 1363 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titan-factory-icon-full rotate: false - xy: 293, 217 + xy: 852, 1657 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 unit-icon-chaos-array rotate: false - xy: 293, 315 + xy: 423, 612 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 unit-icon-crawler rotate: false - xy: 1822, 1051 + xy: 1203, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-icon-dagger rotate: false - xy: 1872, 1101 + xy: 1253, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unit-icon-eradicator rotate: false - xy: 1812, 1923 + xy: 1, 99 size: 152, 124 orig: 152, 124 offset: 0, 0 index: -1 unit-icon-eruptor rotate: false - xy: 856, 992 + xy: 913, 955 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 unit-icon-fortress rotate: false - xy: 922, 1067 + xy: 979, 955 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 unit-icon-titan rotate: false - xy: 988, 1067 + xy: 913, 889 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 water-extractor-icon-full rotate: false - xy: 1054, 1067 + xy: 913, 823 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 water-icon-full rotate: false - xy: 1085, 671 + xy: 1531, 1159 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 wave rotate: false - xy: 1186, 1067 + xy: 913, 691 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 wave-icon-full rotate: false - xy: 1120, 1001 + xy: 979, 691 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 white-tree-dead-icon-full rotate: false - xy: 1, 1405 + xy: 1, 1403 size: 320, 320 orig: 320, 320 offset: 0, 0 index: -1 white-tree-icon-full rotate: false - xy: 323, 1727 + xy: 323, 1725 size: 320, 320 orig: 320, 320 offset: 0, 0 index: -1 wraith-factory-icon-full rotate: false - xy: 1252, 1067 + xy: 1045, 1219 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 item-blast-compound rotate: false - xy: 1886, 859 + xy: 1462, 1027 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-coal rotate: false - xy: 1920, 859 + xy: 1481, 993 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-copper rotate: false - xy: 1954, 995 + xy: 987, 9 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-graphite rotate: false - xy: 1988, 999 + xy: 1021, 8 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-lead rotate: false - xy: 1962, 961 + xy: 1055, 8 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-metaglass rotate: false - xy: 1962, 927 + xy: 1089, 8 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-phase-fabric rotate: false - xy: 1954, 893 + xy: 1123, 8 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-plastanium rotate: false - xy: 1954, 859 + xy: 1157, 8 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-pyratite rotate: false - xy: 1996, 965 + xy: 2006, 1623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-sand rotate: false - xy: 1996, 931 + xy: 2006, 1589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-scrap rotate: false - xy: 1988, 893 + xy: 2006, 1555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-silicon rotate: false - xy: 1988, 859 + xy: 2006, 1521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-spore-pod rotate: false - xy: 880, 900 + xy: 1245, 891 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-surge-alloy rotate: false - xy: 914, 900 + xy: 1245, 857 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-thorium rotate: false - xy: 839, 866 + xy: 1245, 823 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-titanium rotate: false - xy: 839, 832 + xy: 1295, 941 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-cryofluid rotate: false - xy: 907, 866 + xy: 1345, 957 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-oil rotate: false - xy: 839, 764 + xy: 1413, 959 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-slag rotate: false - xy: 907, 798 + xy: 1279, 831 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-water rotate: false - xy: 873, 730 + xy: 1313, 907 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 alpha-mech rotate: false - xy: 259, 1355 + xy: 1999, 1409 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 alpha-mech-base rotate: false - xy: 204, 1097 + xy: 1999, 1359 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 alpha-mech-leg rotate: false - xy: 1372, 1083 + xy: 979, 301 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 delta-mech rotate: false - xy: 1310, 927 + xy: 1151, 1375 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 delta-mech-base rotate: false - xy: 1360, 925 + xy: 1201, 1375 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 delta-mech-leg rotate: false - xy: 1622, 1083 + xy: 1251, 1375 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 omega-mech rotate: false - xy: 904, 934 + xy: 1045, 718 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 omega-mech-armor rotate: false - xy: 847, 1322 + xy: 1808, 1591 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 omega-mech-base rotate: false - xy: 962, 943 + xy: 913, 633 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 omega-mech-leg rotate: false - xy: 1020, 943 + xy: 913, 575 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 tau-mech rotate: false - xy: 1194, 943 + xy: 979, 517 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 tau-mech-base rotate: false - xy: 1772, 1051 + xy: 1203, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 tau-mech-leg rotate: false - xy: 1822, 1101 + xy: 1153, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dart-ship rotate: false - xy: 1368, 975 + xy: 1101, 1367 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 glaive-ship rotate: false - xy: 457, 207 + xy: 526, 1537 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 javelin-ship rotate: false - xy: 1939, 1351 + xy: 1311, 1175 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 javelin-ship-shield rotate: false - xy: 1839, 1201 + xy: 1161, 1125 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 trident-ship rotate: false - xy: 1252, 943 + xy: 979, 459 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 blank rotate: false - xy: 848, 1846 + xy: 1029, 348 size: 1, 1 orig: 1, 1 offset: 0, 0 index: -1 circle rotate: false - xy: 645, 1846 + xy: 323, 1522 size: 201, 201 orig: 201, 201 offset: 0, 0 index: -1 shape-3 rotate: false - xy: 781, 927 + xy: 1045, 1088 size: 63, 63 orig: 63, 63 offset: 0, 0 index: -1 chaos-array rotate: false - xy: 1165, 1757 + xy: 163, 771 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 chaos-array-base rotate: false - xy: 1295, 1757 + xy: 163, 641 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 chaos-array-leg rotate: false - xy: 1425, 1757 + xy: 163, 511 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 crawler rotate: false - xy: 1472, 1033 + xy: 1079, 618 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 crawler-base rotate: false - xy: 1522, 1083 + xy: 1095, 668 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 crawler-leg rotate: false - xy: 1522, 1033 + xy: 1129, 618 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dagger rotate: false - xy: 1572, 1083 + xy: 987, 143 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dagger-base rotate: false - xy: 1572, 1033 + xy: 987, 93 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dagger-leg rotate: false - xy: 1318, 977 + xy: 987, 43 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 draug rotate: false - xy: 1622, 1033 + xy: 1301, 1375 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 eradicator rotate: false - xy: 1, 170 + xy: 1496, 1921 size: 152, 124 orig: 152, 124 offset: 0, 0 index: -1 eradicator-base rotate: false - xy: 1658, 1923 + xy: 1, 225 size: 152, 124 orig: 152, 124 offset: 0, 0 index: -1 eradicator-leg rotate: false - xy: 1, 44 + xy: 1650, 1921 size: 152, 124 orig: 152, 124 offset: 0, 0 index: -1 eruptor rotate: false - xy: 715, 1454 + xy: 657, 52 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 eruptor-base rotate: false - xy: 781, 1454 + xy: 1082, 1615 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 eruptor-leg rotate: false - xy: 847, 1454 + xy: 1082, 1549 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 fortress rotate: false - xy: 583, 1454 + xy: 1075, 1483 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 fortress-base rotate: false - xy: 583, 1388 + xy: 1148, 1623 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 titan-base rotate: false - xy: 583, 1388 + xy: 1148, 1623 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 fortress-leg rotate: false - xy: 649, 1388 + xy: 1214, 1623 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 ghoul rotate: false - xy: 1966, 1975 + xy: 219, 1188 size: 72, 72 orig: 72, 72 offset: 0, 0 index: -1 lich rotate: false - xy: 323, 1485 + xy: 1, 1161 size: 216, 240 orig: 216, 240 offset: 0, 0 index: -1 phantom rotate: false - xy: 1078, 943 + xy: 971, 633 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 power-cell rotate: false - xy: 1136, 943 + xy: 971, 575 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 reaper rotate: false - xy: 1, 1727 + xy: 1, 1725 size: 320, 320 orig: 320, 320 offset: 0, 0 index: -1 revenant rotate: false - xy: 423, 461 + xy: 645, 1730 size: 112, 112 orig: 112, 112 offset: 0, 0 index: -1 spirit rotate: false - xy: 1722, 1101 + xy: 1310, 1025 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 titan rotate: false - xy: 1573, 1133 + xy: 913, 1153 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 titan-leg rotate: false - xy: 724, 1058 + xy: 979, 1153 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 wraith rotate: false - xy: 1872, 1051 + xy: 1153, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 artillery-equip rotate: false - xy: 1372, 1025 + xy: 979, 243 size: 48, 56 orig: 48, 56 offset: 0, 0 index: -1 blaster-equip rotate: false - xy: 1422, 1083 + xy: 979, 193 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 bomber-equip rotate: false - xy: 1422, 1033 + xy: 1045, 668 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 missiles-equip rotate: false - xy: 1422, 1033 + xy: 1045, 668 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 chain-blaster-equip rotate: false - xy: 1472, 1083 + xy: 1029, 618 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 chaos-equip rotate: false - xy: 781, 789 + xy: 1045, 950 size: 56, 136 orig: 56, 136 offset: 0, 0 index: -1 eradication-equip rotate: false - xy: 1325, 1563 + xy: 391, 190 size: 96, 192 orig: 96, 192 offset: 0, 0 index: -1 eruption-equip rotate: false - xy: 1639, 1289 + xy: 1401, 1367 size: 48, 56 orig: 48, 56 offset: 0, 0 index: -1 flakgun-equip rotate: false - xy: 1639, 1239 + xy: 1111, 1317 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 flamethrower-equip rotate: false - xy: 1639, 1181 + xy: 1111, 1259 size: 48, 56 orig: 48, 56 offset: 0, 0 index: -1 heal-blaster-equip rotate: false - xy: 1689, 1351 + xy: 1111, 1209 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 lich-missiles-equip rotate: false - xy: 1889, 1251 + xy: 1211, 1125 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 reaper-gun-equip rotate: false - xy: 1839, 1151 + xy: 1211, 1075 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 revenant-missiles-equip rotate: false - xy: 1889, 1151 + xy: 1261, 1075 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 shockgun-equip rotate: false - xy: 1989, 1151 + xy: 1160, 1025 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 swarmer-equip rotate: false - xy: 1772, 1101 + xy: 1153, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 @@ -5206,1967 +5206,1967 @@ filter: Nearest,Nearest repeat: none alloy-smelter-icon-editor rotate: false - xy: 453, 651 + xy: 1, 15 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 arc-icon-editor rotate: false - xy: 2015, 973 + xy: 261, 137 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 battery-icon-editor rotate: false - xy: 2015, 939 + xy: 427, 87 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 battery-large-icon-editor rotate: false - xy: 581, 779 + xy: 745, 919 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 blast-drill-icon-editor rotate: false - xy: 323, 619 + xy: 1, 243 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 blast-mixer-icon-editor rotate: false - xy: 1, 5 + xy: 745, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-border-editor rotate: false - xy: 865, 679 + xy: 477, 137 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conduit-icon-editor rotate: false - xy: 651, 481 + xy: 611, 391 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor-icon-editor rotate: false - xy: 815, 587 + xy: 427, 53 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 char-icon-editor rotate: false - xy: 899, 679 + xy: 511, 137 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-char1 rotate: false - xy: 899, 679 + xy: 511, 137 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 clear-editor rotate: false - xy: 1231, 906 + xy: 261, 370 size: 1, 1 orig: 1, 1 offset: 0, 0 index: -1 cliffs-icon-editor rotate: false - xy: 685, 481 + xy: 645, 391 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 coal-centrifuge-icon-editor rotate: false - xy: 1757, 843 + xy: 811, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 combustion-generator-icon-editor rotate: false - xy: 933, 679 + xy: 679, 391 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 command-center-icon-editor rotate: false - xy: 1823, 843 + xy: 877, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 conduit-icon-editor rotate: false - xy: 967, 679 + xy: 295, 5 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 container-icon-editor rotate: false - xy: 1889, 843 + xy: 943, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 conveyor-icon-editor rotate: false - xy: 1001, 679 + xy: 329, 5 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper-wall-icon-editor rotate: false - xy: 1035, 679 + xy: 363, 5 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper-wall-large-icon-editor rotate: false - xy: 67, 5 + xy: 1009, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 core-foundation-icon-editor rotate: false - xy: 581, 877 + xy: 323, 725 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 core-nucleus-icon-editor rotate: false - xy: 1, 201 + xy: 323, 855 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 core-shard-icon-editor rotate: false - xy: 323, 391 + xy: 99, 15 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 craters-icon-editor rotate: false - xy: 323, 749 - size: 256, 256 - orig: 256, 256 + xy: 397, 5 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +editor-craters1 + rotate: false + xy: 397, 5 + size: 32, 32 + orig: 32, 32 offset: 0, 0 index: -1 crawler-factory-icon-editor rotate: false - xy: 1955, 843 + xy: 1075, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cryofluidmixer-icon-editor rotate: false - xy: 163, 167 + xy: 1141, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cultivator-icon-editor rotate: false - xy: 229, 167 + xy: 1207, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cyclone-icon-editor rotate: false - xy: 1231, 909 + xy: 843, 919 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dagger-factory-icon-editor rotate: false - xy: 131, 101 + xy: 1273, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dark-metal-icon-editor rotate: false - xy: 1069, 679 + xy: 461, 87 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-1-icon-editor rotate: false - xy: 1103, 679 + xy: 461, 53 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-1 rotate: false - xy: 1103, 679 + xy: 461, 53 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-2-icon-editor rotate: false - xy: 1137, 679 + xy: 431, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-2 rotate: false - xy: 1137, 679 + xy: 431, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-3-icon-editor rotate: false - xy: 1171, 679 + xy: 465, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-3 rotate: false - xy: 1171, 679 + xy: 465, 19 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-4-icon-editor rotate: false - xy: 1205, 679 + xy: 495, 103 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-4 rotate: false - xy: 1205, 679 + xy: 495, 103 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-5-icon-editor rotate: false - xy: 133, 1 + xy: 495, 69 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-5 rotate: false - xy: 133, 1 + xy: 495, 69 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-6-icon-editor rotate: false - xy: 167, 1 + xy: 529, 103 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-6 rotate: false - xy: 167, 1 + xy: 529, 103 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-icon-editor rotate: false - xy: 201, 1 + xy: 529, 69 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand1 rotate: false - xy: 201, 1 + xy: 529, 69 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-tainted-water-icon-editor rotate: false - xy: 235, 1 + xy: 545, 137 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand-tainted-water rotate: false - xy: 235, 1 + xy: 545, 137 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-water-icon-editor rotate: false - xy: 269, 1 + xy: 499, 35 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand-water rotate: false - xy: 269, 1 + xy: 499, 35 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dart-mech-pad-icon-editor rotate: false - xy: 197, 101 + xy: 1339, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 deepwater-icon-editor rotate: false - xy: 719, 481 + xy: 533, 35 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-deepwater rotate: false - xy: 719, 481 + xy: 533, 35 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 delta-mech-pad-icon-editor rotate: false - xy: 133, 35 + xy: 1405, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 differential-generator-icon-editor rotate: false - xy: 453, 553 + xy: 941, 919 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 distributor-icon-editor rotate: false - xy: 199, 35 + xy: 1471, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 door-icon-editor rotate: false - xy: 303, 1 + xy: 499, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 door-large-icon-editor rotate: false - xy: 263, 101 + xy: 1537, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 draug-factory-icon-editor rotate: false - xy: 265, 35 + xy: 1603, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dunerocks-icon-editor rotate: false - xy: 553, 431 + xy: 533, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 duo-icon-editor rotate: false - xy: 553, 397 + xy: 563, 103 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-char2 rotate: false - xy: 587, 431 + xy: 563, 69 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-char3 rotate: false - xy: 587, 397 + xy: 567, 35 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-clear rotate: false - xy: 295, 167 + xy: 733, 875 size: 10, 10 orig: 10, 10 offset: 0, 0 index: -1 -editor-craters1 - rotate: false - xy: 621, 431 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 editor-craters2 rotate: false - xy: 621, 397 + xy: 567, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-craters3 rotate: false - xy: 295, 213 + xy: 611, 357 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand2 rotate: false - xy: 295, 179 + xy: 645, 357 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand3 rotate: false - xy: 753, 497 + xy: 679, 357 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-grass1 rotate: false - xy: 655, 447 + xy: 569, 349 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 grass-icon-editor rotate: false - xy: 655, 447 + xy: 569, 349 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-grass2 rotate: false - xy: 655, 413 + xy: 555, 315 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-grass3 rotate: false - xy: 689, 447 + xy: 555, 281 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-holostone1 rotate: false - xy: 689, 413 + xy: 555, 247 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 holostone-icon-editor rotate: false - xy: 689, 413 + xy: 555, 247 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-holostone2 rotate: false - xy: 723, 447 + xy: 555, 213 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-holostone3 rotate: false - xy: 723, 413 + xy: 555, 179 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-hotrock1 rotate: false - xy: 343, 263 + xy: 589, 315 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 hotrock-icon-editor rotate: false - xy: 343, 263 + xy: 589, 315 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-hotrock2 rotate: false - xy: 799, 547 + xy: 589, 281 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-hotrock3 rotate: false - xy: 865, 645 + xy: 589, 247 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice-snow1 rotate: false - xy: 1001, 645 + xy: 623, 323 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-snow-icon-editor rotate: false - xy: 1001, 645 + xy: 623, 323 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice-snow2 rotate: false - xy: 1035, 645 + xy: 623, 289 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice-snow3 rotate: false - xy: 1069, 645 + xy: 657, 323 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice1 rotate: false - xy: 899, 645 + xy: 589, 213 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-icon-editor rotate: false - xy: 899, 645 + xy: 589, 213 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice2 rotate: false - xy: 933, 645 + xy: 589, 179 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice3 rotate: false - xy: 967, 645 + xy: 579, 145 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ignarock1 rotate: false - xy: 1103, 645 + xy: 623, 255 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ignarock-icon-editor rotate: false - xy: 1103, 645 + xy: 623, 255 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ignarock2 rotate: false - xy: 1137, 645 + xy: 657, 289 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ignarock3 rotate: false - xy: 1171, 645 + xy: 623, 221 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-magmarock1 rotate: false - xy: 1205, 645 + xy: 657, 255 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 magmarock-icon-editor rotate: false - xy: 1205, 645 + xy: 657, 255 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-magmarock2 rotate: false - xy: 655, 379 + xy: 623, 187 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-magmarock3 rotate: false - xy: 689, 379 + xy: 657, 221 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor rotate: false - xy: 723, 379 + xy: 657, 187 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-icon-editor rotate: false - xy: 723, 379 + xy: 657, 187 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-2 rotate: false - xy: 343, 229 + xy: 691, 323 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-2-icon-editor rotate: false - xy: 343, 229 + xy: 691, 323 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-3 rotate: false - xy: 329, 195 + xy: 691, 289 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-3-icon-editor rotate: false - xy: 329, 195 + xy: 691, 289 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-5 rotate: false - xy: 329, 161 + xy: 691, 255 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-5-icon-editor rotate: false - xy: 329, 161 + xy: 691, 255 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-damaged1 rotate: false - xy: 329, 127 + xy: 691, 221 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-damaged-icon-editor rotate: false - xy: 329, 127 + xy: 691, 221 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-damaged2 rotate: false - xy: 799, 513 + xy: 691, 187 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-damaged3 rotate: false - xy: 857, 611 + xy: 613, 145 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-moss1 rotate: false - xy: 891, 611 + xy: 597, 111 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 moss-icon-editor rotate: false - xy: 891, 611 + xy: 597, 111 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-moss2 rotate: false - xy: 925, 611 + xy: 597, 77 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-moss3 rotate: false - xy: 959, 611 + xy: 647, 153 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-coal1 rotate: false - xy: 993, 611 + xy: 681, 153 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-coal2 rotate: false - xy: 1027, 611 + xy: 601, 43 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-coal3 rotate: false - xy: 1061, 611 + xy: 601, 9 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-copper1 rotate: false - xy: 1095, 611 + xy: 631, 111 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-copper2 rotate: false - xy: 1129, 611 + xy: 631, 77 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-copper3 rotate: false - xy: 1163, 611 + xy: 635, 43 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-lead1 rotate: false - xy: 1197, 611 + xy: 635, 9 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-lead2 rotate: false - xy: 849, 577 + xy: 665, 119 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-lead3 rotate: false - xy: 883, 577 + xy: 665, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-scrap1 rotate: false - xy: 917, 577 + xy: 669, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-scrap2 rotate: false - xy: 951, 577 + xy: 669, 17 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-scrap3 rotate: false - xy: 985, 577 + xy: 699, 119 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-thorium1 rotate: false - xy: 1019, 577 + xy: 699, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-thorium2 rotate: false - xy: 1053, 577 + xy: 703, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-thorium3 rotate: false - xy: 1087, 577 + xy: 703, 17 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-titanium1 rotate: false - xy: 1121, 577 + xy: 715, 153 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-titanium2 rotate: false - xy: 1155, 577 + xy: 733, 119 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-titanium3 rotate: false - xy: 1189, 577 + xy: 733, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-pebbles1 rotate: false - xy: 833, 543 + xy: 737, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-pebbles2 rotate: false - xy: 867, 543 + xy: 737, 17 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-pebbles3 rotate: false - xy: 901, 543 + xy: 713, 391 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-salt rotate: false - xy: 935, 543 + xy: 713, 357 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 salt-icon-editor rotate: false - xy: 935, 543 + xy: 713, 357 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-sand-water rotate: false - xy: 1071, 543 + xy: 725, 221 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-water-icon-editor rotate: false - xy: 1071, 543 + xy: 725, 221 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-sand1 rotate: false - xy: 969, 543 + xy: 725, 323 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-icon-editor rotate: false - xy: 969, 543 + xy: 725, 323 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-sand2 rotate: false - xy: 1003, 543 + xy: 725, 289 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-sand3 rotate: false - xy: 1037, 543 + xy: 725, 255 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-shale1 rotate: false - xy: 1105, 543 + xy: 725, 187 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale-icon-editor rotate: false - xy: 1105, 543 + xy: 725, 187 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-shale2 rotate: false - xy: 1139, 543 + xy: 749, 153 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-shale3 rotate: false - xy: 1173, 543 + xy: 767, 119 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-snow1 rotate: false - xy: 833, 509 + xy: 767, 85 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-snow2 rotate: false - xy: 867, 509 + xy: 771, 51 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-snow3 rotate: false - xy: 901, 509 + xy: 771, 17 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-spawn rotate: false - xy: 935, 509 + xy: 733, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-spore-moss1 rotate: false - xy: 969, 509 + xy: 767, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-moss-icon-editor rotate: false - xy: 969, 509 + xy: 767, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-spore-moss2 rotate: false - xy: 1003, 509 + xy: 801, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-spore-moss3 rotate: false - xy: 1037, 509 + xy: 835, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-stone1 rotate: false - xy: 1071, 509 + xy: 869, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 stone-icon-editor rotate: false - xy: 1071, 509 + xy: 869, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-stone2 rotate: false - xy: 1105, 509 + xy: 903, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-stone3 rotate: false - xy: 1139, 509 + xy: 937, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tainted-water rotate: false - xy: 1173, 509 + xy: 971, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tainted-water-icon-editor rotate: false - xy: 1173, 509 + xy: 971, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tar rotate: false - xy: 1207, 543 + xy: 1005, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tar-icon-editor rotate: false - xy: 1207, 543 + xy: 1005, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tendrils1 rotate: false - xy: 1207, 509 + xy: 1039, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tendrils2 rotate: false - xy: 1223, 577 + xy: 1073, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tendrils3 rotate: false - xy: 1231, 611 + xy: 1107, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-water rotate: false - xy: 1241, 543 + xy: 1141, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 water-icon-editor rotate: false - xy: 1241, 543 + xy: 1141, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 force-projector-icon-editor rotate: false - xy: 679, 779 + xy: 1039, 919 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 fortress-factory-icon-editor rotate: false - xy: 1329, 909 + xy: 1137, 919 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 fuse-icon-editor rotate: false - xy: 777, 779 + xy: 1235, 919 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 ghoul-factory-icon-editor rotate: false - xy: 1427, 909 + xy: 1333, 919 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 glaive-ship-pad-icon-editor rotate: false - xy: 875, 779 + xy: 1431, 919 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 graphite-press-icon-editor rotate: false - xy: 421, 389 + xy: 1669, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 hail-icon-editor rotate: false - xy: 1241, 509 + xy: 1175, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 icerocks-icon-editor rotate: false - xy: 1257, 577 + xy: 1209, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 impact-reactor-icon-editor rotate: false - xy: 1, 71 + xy: 485, 887 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 incinerator-icon-editor rotate: false - xy: 1275, 543 + xy: 1243, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-source-icon-editor rotate: false - xy: 1275, 509 + xy: 1277, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-void-icon-editor rotate: false - xy: 757, 463 + xy: 1311, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 javelin-ship-pad-icon-editor rotate: false - xy: 487, 389 + xy: 1735, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 junction-icon-editor rotate: false - xy: 757, 429 + xy: 1345, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 kiln-icon-editor rotate: false - xy: 1267, 745 + xy: 1801, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 lancer-icon-editor rotate: false - xy: 1333, 745 + xy: 1867, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 laser-drill-icon-editor rotate: false - xy: 1525, 909 + xy: 1529, 919 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 launch-pad-icon-editor rotate: false - xy: 973, 779 + xy: 1627, 919 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 launch-pad-large-icon-editor rotate: false - xy: 163, 233 + xy: 1, 113 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 liquid-junction-icon-editor rotate: false - xy: 757, 395 + xy: 1379, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-router-icon-editor rotate: false - xy: 757, 361 + xy: 1413, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-source-icon-editor rotate: false - xy: 363, 195 + xy: 1447, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-tank-icon-editor rotate: false - xy: 1623, 909 + xy: 1725, 919 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mass-driver-icon-editor rotate: false - xy: 1071, 779 + xy: 1823, 919 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mechanical-drill-icon-editor rotate: false - xy: 1399, 745 + xy: 1933, 853 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mechanical-pump-icon-editor rotate: false - xy: 363, 161 + xy: 1481, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 meltdown-icon-editor rotate: false - xy: 323, 489 + xy: 131, 243 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 melter-icon-editor rotate: false - xy: 363, 127 + xy: 1515, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mend-projector-icon-editor rotate: false - xy: 1465, 745 + xy: 485, 821 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mender-icon-editor rotate: false - xy: 791, 479 + xy: 1549, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 multi-press-icon-editor rotate: false - xy: 1721, 909 + xy: 1921, 919 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 oil-extractor-icon-editor rotate: false - xy: 1819, 909 + xy: 323, 367 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 omega-mech-pad-icon-editor rotate: false - xy: 1917, 909 + xy: 197, 15 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 overdrive-projector-icon-editor rotate: false - xy: 1531, 745 + xy: 551, 821 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 overflow-gate-icon-editor rotate: false - xy: 791, 445 + xy: 1583, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pebbles-icon-editor rotate: false - xy: 791, 411 + xy: 1617, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phantom-factory-icon-editor rotate: false - xy: 1597, 745 + xy: 617, 821 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phase-conduit-icon-editor rotate: false - xy: 791, 377 + xy: 1651, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor-icon-editor rotate: false - xy: 825, 475 + xy: 1685, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall-icon-editor rotate: false - xy: 825, 441 + xy: 1719, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall-large-icon-editor rotate: false - xy: 1663, 745 + xy: 453, 755 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phase-weaver-icon-editor rotate: false - xy: 1757, 777 + xy: 519, 755 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pine-icon-editor rotate: false - xy: 293, 247 + xy: 1999, 869 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 plastanium-compressor-icon-editor rotate: false - xy: 1823, 777 + xy: 453, 689 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pneumatic-drill-icon-editor rotate: false - xy: 1889, 777 + xy: 519, 689 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 power-node-icon-editor rotate: false - xy: 859, 475 + xy: 1753, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-node-large-icon-editor rotate: false - xy: 1955, 777 + xy: 585, 755 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 power-source-icon-editor rotate: false - xy: 825, 407 + xy: 1787, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-void-icon-editor rotate: false - xy: 859, 441 + xy: 1821, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-icon-editor rotate: false - xy: 893, 475 + xy: 1855, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulverizer-icon-editor rotate: false - xy: 859, 407 + xy: 1889, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pyratite-mixer-icon-editor rotate: false - xy: 293, 297 + xy: 453, 623 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 repair-point-icon-editor rotate: false - xy: 893, 441 + xy: 1923, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 revenant-factory-icon-editor rotate: false - xy: 711, 877 + xy: 323, 595 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 ripple-icon-editor rotate: false - xy: 453, 455 + xy: 261, 269 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 rock-icon-editor rotate: false - xy: 551, 465 + xy: 1999, 819 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 rocks-icon-editor rotate: false - xy: 927, 475 + xy: 1957, 819 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rotary-pump-icon-editor rotate: false - xy: 581, 713 + xy: 519, 623 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 router-icon-editor rotate: false - xy: 893, 407 + xy: 717, 785 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rtg-generator-icon-editor rotate: false - xy: 647, 713 + xy: 585, 689 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 saltrocks-icon-editor rotate: false - xy: 927, 441 + xy: 717, 751 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 salvo-icon-editor rotate: false - xy: 713, 713 + xy: 453, 557 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 sand-boulder-icon-editor rotate: false - xy: 961, 475 + xy: 751, 785 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sandrocks-icon-editor rotate: false - xy: 927, 407 + xy: 717, 717 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scatter-icon-editor rotate: false - xy: 779, 713 + xy: 519, 557 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scorch-icon-editor rotate: false - xy: 961, 441 + xy: 785, 785 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall-gigantic-icon-editor rotate: false - xy: 841, 877 + xy: 615, 887 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 scrap-wall-huge-icon-editor rotate: false - xy: 1169, 779 + xy: 261, 171 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 scrap-wall-icon-editor rotate: false - xy: 995, 475 + xy: 751, 751 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall-large-icon-editor rotate: false - xy: 845, 713 + xy: 585, 623 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 separator-icon-editor rotate: false - xy: 911, 713 + xy: 453, 491 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 shale-boulder-icon-editor rotate: false - xy: 961, 407 + xy: 717, 683 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shalerocks-icon-editor rotate: false - xy: 995, 441 + xy: 819, 785 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shock-mine-icon-editor rotate: false - xy: 1029, 475 + xy: 785, 751 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shrubs-icon-editor rotate: false - xy: 995, 407 + xy: 751, 717 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 silicon-smelter-icon-editor rotate: false - xy: 977, 713 + xy: 519, 491 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 snow-icon-editor rotate: false - xy: 1029, 441 + xy: 717, 649 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snow-pine-icon-editor rotate: false - xy: 815, 663 + xy: 519, 375 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 snowrock-icon-editor rotate: false - xy: 749, 531 + xy: 683, 837 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 snowrocks-icon-editor rotate: false - xy: 1063, 475 + xy: 853, 785 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel-icon-editor rotate: false - xy: 1029, 407 + xy: 819, 751 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel-large-icon-editor rotate: false - xy: 1267, 811 + xy: 359, 269 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 sorter-icon-editor rotate: false - xy: 1063, 441 + xy: 785, 717 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spawn-icon-editor rotate: false - xy: 1097, 475 + xy: 751, 683 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spectre-icon-editor rotate: false - xy: 971, 877 + xy: 131, 113 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 spirit-factory-icon-editor rotate: false - xy: 1043, 713 + xy: 585, 557 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-cluster-icon-editor rotate: false - xy: 815, 621 + xy: 569, 383 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 spore-pine-icon-editor rotate: false - xy: 601, 465 + xy: 427, 121 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 spore-press-icon-editor rotate: false - xy: 1109, 713 + xy: 585, 491 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 sporerocks-icon-editor rotate: false - xy: 1063, 407 + xy: 717, 615 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 surge-tower-icon-editor rotate: false - xy: 1175, 713 + xy: 519, 425 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 surge-wall-icon-editor rotate: false - xy: 1097, 441 + xy: 887, 785 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 surge-wall-large-icon-editor rotate: false - xy: 551, 647 + xy: 585, 425 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 swarmer-icon-editor rotate: false - xy: 551, 581 + xy: 651, 755 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 tau-mech-pad-icon-editor rotate: false - xy: 617, 647 + xy: 651, 689 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 tendrils-icon-editor rotate: false - xy: 1131, 475 + xy: 853, 751 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thermal-generator-icon-editor rotate: false - xy: 551, 515 + xy: 651, 623 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thermal-pump-icon-editor rotate: false - xy: 1365, 811 + xy: 359, 171 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 thorium-reactor-icon-editor rotate: false - xy: 1463, 811 + xy: 421, 367 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 thorium-wall-icon-editor rotate: false - xy: 1097, 407 + xy: 819, 717 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium-wall-large-icon-editor rotate: false - xy: 617, 581 + xy: 651, 557 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thruster-icon-editor rotate: false - xy: 1101, 877 + xy: 323, 465 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 titan-factory-icon-editor rotate: false - xy: 1561, 811 + xy: 457, 269 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 titanium-conveyor-icon-editor rotate: false - xy: 1131, 441 + xy: 785, 683 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-wall-icon-editor rotate: false - xy: 1165, 475 + xy: 751, 649 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-wall-large-icon-editor rotate: false - xy: 683, 647 + xy: 651, 491 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 trident-ship-pad-icon-editor rotate: false - xy: 617, 515 + xy: 651, 425 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 turbine-generator-icon-editor rotate: false - xy: 683, 581 + xy: 295, 105 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 unloader-icon-editor rotate: false - xy: 1131, 407 + xy: 717, 581 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 vault-icon-editor rotate: false - xy: 1659, 811 + xy: 457, 171 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 water-extractor-icon-editor rotate: false - xy: 749, 647 + xy: 295, 39 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 wave-icon-editor rotate: false - xy: 683, 515 + xy: 361, 105 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 white-tree-dead-icon-editor rotate: false - xy: 1, 685 + xy: 1, 695 size: 320, 320 orig: 320, 320 offset: 0, 0 index: -1 white-tree-icon-editor rotate: false - xy: 1, 363 + xy: 1, 373 size: 320, 320 orig: 320, 320 offset: 0, 0 index: -1 wraith-factory-icon-editor rotate: false - xy: 749, 581 + xy: 361, 39 size: 64, 64 orig: 64, 64 offset: 0, 0 @@ -7177,84 +7177,84 @@ size: 1024,1024 format: RGBA8888 filter: Nearest,Nearest repeat: none -craters +zone-craters rotate: false xy: 605, 767 size: 256, 256 orig: 256, 256 offset: 0, 0 index: -1 -desertWastes +zone-desertWastes rotate: false xy: 303, 461 size: 260, 260 orig: 260, 260 offset: 0, 0 index: -1 -desolateRift +zone-desolateRift rotate: false xy: 817, 163 size: 100, 350 orig: 100, 350 offset: 0, 0 index: -1 -frozenForest +zone-frozenForest rotate: false xy: 303, 1 size: 200, 200 orig: 200, 200 offset: 0, 0 index: -1 -fungalPass +zone-fungalPass rotate: false xy: 863, 773 size: 150, 250 orig: 150, 250 offset: 0, 0 index: -1 -groundZero +zone-groundZero rotate: false xy: 303, 203 size: 256, 256 orig: 256, 256 offset: 0, 0 index: -1 -nuclearComplex +zone-nuclearComplex rotate: false xy: 605, 515 size: 250, 250 orig: 250, 250 offset: 0, 0 index: -1 -overgrowth +zone-overgrowth rotate: false xy: 1, 723 size: 300, 300 orig: 300, 300 offset: 0, 0 index: -1 -ruinousShores +zone-ruinousShores rotate: false xy: 1, 421 size: 300, 300 orig: 300, 300 offset: 0, 0 index: -1 -saltFlats +zone-saltFlats rotate: false xy: 303, 723 size: 300, 300 orig: 300, 300 offset: 0, 0 index: -1 -stainedMountains +zone-stainedMountains rotate: false xy: 1, 119 size: 300, 300 orig: 300, 300 offset: 0, 0 index: -1 -tarFields +zone-tarFields rotate: false xy: 565, 263 size: 250, 250 @@ -8647,49 +8647,49 @@ filter: Nearest,Nearest repeat: none alloy-smelter-icon-large rotate: false - xy: 1, 663 + xy: 1, 670 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 alloy-smelter-icon-medium rotate: false - xy: 301, 629 + xy: 301, 575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 alloy-smelter-icon-small rotate: false - xy: 1975, 684 + xy: 471, 1 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 arc-icon-large rotate: false - xy: 259, 921 + xy: 259, 928 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 arc-icon-medium rotate: false - xy: 301, 595 + xy: 301, 541 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 arc-icon-small rotate: false - xy: 1639, 560 + xy: 497, 1 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 bar rotate: false - xy: 1581, 548 + xy: 567, 209 size: 27, 36 split: 9, 9, 9, 9 orig: 27, 36 @@ -8697,7 +8697,7 @@ bar index: -1 bar-top rotate: false - xy: 1552, 548 + xy: 567, 247 size: 27, 36 split: 9, 10, 9, 10 orig: 27, 36 @@ -8705,133 +8705,133 @@ bar-top index: -1 battery-icon-large rotate: false - xy: 1, 613 + xy: 1, 620 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 battery-icon-medium rotate: false - xy: 301, 561 + xy: 301, 507 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 battery-icon-small rotate: false - xy: 1665, 560 + xy: 523, 1 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 battery-large-icon-large rotate: false - xy: 259, 871 + xy: 259, 878 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 battery-large-icon-medium rotate: false - xy: 301, 527 + xy: 301, 473 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 battery-large-icon-small rotate: false - xy: 1639, 534 + xy: 2023, 712 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 blast-drill-icon-large rotate: false - xy: 1, 563 + xy: 1, 570 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 blast-drill-icon-medium rotate: false - xy: 301, 493 + xy: 301, 439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 blast-drill-icon-small rotate: false - xy: 1665, 534 + xy: 2023, 686 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 blast-mixer-icon-large rotate: false - xy: 259, 821 + xy: 259, 828 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 blast-mixer-icon-medium rotate: false - xy: 301, 459 + xy: 301, 405 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 blast-mixer-icon-small rotate: false - xy: 2001, 681 + xy: 567, 120 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 bridge-conduit-icon-large rotate: false - xy: 1, 513 + xy: 1, 520 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 bridge-conduit-icon-medium rotate: false - xy: 301, 425 + xy: 301, 371 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conduit-icon-small rotate: false - xy: 1639, 508 + xy: 567, 94 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 bridge-conveyor-icon-large rotate: false - xy: 259, 771 + xy: 259, 778 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 bridge-conveyor-icon-medium rotate: false - xy: 301, 391 + xy: 301, 337 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor-icon-small rotate: false - xy: 1665, 508 + xy: 567, 68 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 button rotate: false - xy: 1813, 710 + xy: 301, 667 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8839,7 +8839,7 @@ button index: -1 button-disabled rotate: false - xy: 2009, 939 + xy: 2009, 946 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8847,7 +8847,7 @@ button-disabled index: -1 button-down rotate: false - xy: 2009, 910 + xy: 2009, 917 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8855,7 +8855,7 @@ button-down index: -1 button-edge-1 rotate: false - xy: 2009, 881 + xy: 2009, 888 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8863,7 +8863,7 @@ button-edge-1 index: -1 button-edge-2 rotate: false - xy: 2009, 852 + xy: 2009, 859 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8871,7 +8871,7 @@ button-edge-2 index: -1 button-edge-3 rotate: false - xy: 2009, 823 + xy: 2009, 830 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8879,7 +8879,7 @@ button-edge-3 index: -1 button-edge-4 rotate: false - xy: 2009, 794 + xy: 2009, 801 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8887,7 +8887,7 @@ button-edge-4 index: -1 button-edge-over-4 rotate: false - xy: 1779, 739 + xy: 1879, 746 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8895,7 +8895,7 @@ button-edge-over-4 index: -1 button-over rotate: false - xy: 1817, 739 + xy: 1917, 746 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8903,7 +8903,7 @@ button-over index: -1 button-red rotate: false - xy: 1855, 739 + xy: 1955, 746 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8911,7 +8911,7 @@ button-red index: -1 button-right rotate: false - xy: 1969, 739 + xy: 1875, 717 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8919,7 +8919,7 @@ button-right index: -1 button-right-down rotate: false - xy: 1893, 739 + xy: 2009, 772 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8927,7 +8927,7 @@ button-right-down index: -1 button-right-over rotate: false - xy: 1931, 739 + xy: 1837, 720 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8935,7 +8935,7 @@ button-right-over index: -1 button-select rotate: false - xy: 1988, 655 + xy: 567, 42 size: 24, 24 split: 4, 4, 4, 4 orig: 24, 24 @@ -8943,7 +8943,7 @@ button-select index: -1 button-square rotate: false - xy: 2007, 736 + xy: 301, 696 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8951,7 +8951,7 @@ button-square index: -1 button-square-down rotate: false - xy: 2009, 765 + xy: 1913, 717 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8959,7 +8959,7 @@ button-square-down index: -1 button-square-over rotate: false - xy: 1737, 713 + xy: 1951, 717 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8967,7 +8967,7 @@ button-square-over index: -1 button-trans rotate: false - xy: 1775, 710 + xy: 339, 696 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -8975,889 +8975,889 @@ button-trans index: -1 char-icon-large rotate: false - xy: 1, 463 + xy: 1, 470 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 char-icon-medium rotate: false - xy: 301, 357 + xy: 301, 303 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 char-icon-small rotate: false - xy: 2014, 655 + xy: 549, 3 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 check-disabled rotate: false - xy: 301, 323 + xy: 301, 269 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-off rotate: false - xy: 301, 289 + xy: 301, 235 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-on rotate: false - xy: 301, 255 + xy: 301, 201 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-on-disabled rotate: false - xy: 301, 221 + xy: 301, 167 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-on-over rotate: false - xy: 301, 187 + xy: 301, 133 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-over rotate: false - xy: 301, 153 + xy: 301, 99 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 clear rotate: false - xy: 1, 1 + xy: 1969, 671 size: 10, 10 orig: 10, 10 offset: 0, 0 index: -1 cliffs-icon-large rotate: false - xy: 1, 413 + xy: 1, 420 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 cliffs-icon-medium rotate: false - xy: 301, 119 + xy: 301, 65 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cliffs-icon-small rotate: false - xy: 2003, 629 + xy: 301, 5 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 coal-centrifuge-icon-large rotate: false - xy: 1, 363 + xy: 1, 370 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 coal-centrifuge-icon-medium rotate: false - xy: 301, 85 + xy: 301, 31 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 coal-centrifuge-icon-small rotate: false - xy: 2003, 603 + xy: 575, 16 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 combustion-generator-icon-large rotate: false - xy: 1, 313 + xy: 1, 320 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 combustion-generator-icon-medium rotate: false - xy: 301, 51 + xy: 339, 604 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 combustion-generator-icon-small rotate: false - xy: 2003, 577 + xy: 635, 301 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 command-center-icon-large rotate: false - xy: 1, 263 + xy: 1, 270 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 command-center-icon-medium rotate: false - xy: 301, 17 + xy: 335, 570 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 command-center-icon-small rotate: false - xy: 403, 14 + xy: 661, 301 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 conduit-icon-large rotate: false - xy: 1, 213 + xy: 1, 220 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 conduit-icon-medium rotate: false - xy: 377, 684 + xy: 335, 536 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-icon-small rotate: false - xy: 429, 14 + xy: 687, 301 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 container-icon-large rotate: false - xy: 1, 163 + xy: 1, 170 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 container-icon-medium rotate: false - xy: 411, 684 + xy: 335, 502 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 container-icon-small rotate: false - xy: 469, 80 + xy: 596, 261 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 conveyor-icon-large rotate: false - xy: 1, 113 + xy: 1, 120 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 conveyor-icon-medium rotate: false - xy: 445, 684 + xy: 335, 468 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-icon-small rotate: false - xy: 469, 54 + xy: 596, 235 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 copper-wall-icon-large rotate: false - xy: 1, 63 + xy: 1, 70 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 copper-wall-icon-medium rotate: false - xy: 479, 684 + xy: 335, 434 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper-wall-icon-small rotate: false - xy: 495, 82 + xy: 596, 209 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 copper-wall-large-icon-large rotate: false - xy: 1, 13 + xy: 1, 20 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 copper-wall-large-icon-medium rotate: false - xy: 513, 684 + xy: 335, 400 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper-wall-large-icon-small rotate: false - xy: 495, 56 + xy: 596, 183 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 core-foundation-icon-large rotate: false - xy: 87, 710 + xy: 87, 717 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 core-foundation-icon-medium rotate: false - xy: 547, 684 + xy: 335, 366 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 core-foundation-icon-small rotate: false - xy: 537, 148 + xy: 596, 157 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 core-nucleus-icon-large rotate: false - xy: 137, 710 + xy: 137, 717 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 core-nucleus-icon-medium rotate: false - xy: 581, 684 + xy: 335, 332 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 core-nucleus-icon-small rotate: false - xy: 537, 122 + xy: 596, 131 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 core-shard-icon-large rotate: false - xy: 187, 710 + xy: 187, 717 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 core-shard-icon-medium rotate: false - xy: 615, 684 + xy: 335, 298 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 core-shard-icon-small rotate: false - xy: 563, 150 + xy: 593, 105 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 craters-icon-large rotate: false - xy: 345, 968 + xy: 345, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 craters-icon-medium rotate: false - xy: 649, 684 + xy: 335, 264 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 craters-icon-small rotate: false - xy: 563, 124 + xy: 593, 79 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 crawler-factory-icon-large rotate: false - xy: 395, 968 + xy: 395, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 crawler-factory-icon-medium rotate: false - xy: 683, 684 + xy: 335, 230 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 crawler-factory-icon-small rotate: false - xy: 605, 216 + xy: 593, 53 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 cryofluidmixer-icon-large rotate: false - xy: 445, 968 + xy: 445, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 cryofluidmixer-icon-medium rotate: false - xy: 717, 684 + xy: 335, 196 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cryofluidmixer-icon-small rotate: false - xy: 605, 190 + xy: 601, 27 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 cultivator-icon-large rotate: false - xy: 495, 968 + xy: 495, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 cultivator-icon-medium rotate: false - xy: 751, 684 + xy: 335, 162 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cultivator-icon-small rotate: false - xy: 631, 218 + xy: 601, 1 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 cursor rotate: false - xy: 259, 765 + xy: 363, 20 size: 4, 4 orig: 4, 4 offset: 0, 0 index: -1 cyclone-icon-large rotate: false - xy: 545, 968 + xy: 545, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 cyclone-icon-medium rotate: false - xy: 785, 684 + xy: 335, 128 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cyclone-icon-small rotate: false - xy: 631, 192 + xy: 619, 105 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 dagger-factory-icon-large rotate: false - xy: 595, 968 + xy: 595, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dagger-factory-icon-medium rotate: false - xy: 819, 684 + xy: 335, 94 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dagger-factory-icon-small rotate: false - xy: 673, 284 + xy: 619, 79 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 dark-metal-icon-large rotate: false - xy: 645, 968 + xy: 645, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dark-metal-icon-medium rotate: false - xy: 853, 684 + xy: 335, 60 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-metal-icon-small rotate: false - xy: 673, 258 + xy: 619, 53 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 dark-panel-1-icon-large rotate: false - xy: 695, 968 + xy: 695, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dark-panel-1-icon-medium rotate: false - xy: 887, 684 + xy: 377, 633 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-1-icon-small rotate: false - xy: 699, 286 + xy: 627, 27 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 dark-panel-2-icon-large rotate: false - xy: 745, 968 + xy: 745, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dark-panel-2-icon-medium rotate: false - xy: 921, 684 + xy: 415, 662 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-2-icon-small rotate: false - xy: 699, 260 + xy: 627, 1 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 dark-panel-3-icon-large rotate: false - xy: 795, 968 + xy: 795, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dark-panel-3-icon-medium rotate: false - xy: 955, 684 + xy: 335, 26 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-3-icon-small rotate: false - xy: 741, 352 + xy: 743, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 dark-panel-4-icon-large rotate: false - xy: 845, 968 + xy: 845, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dark-panel-4-icon-medium rotate: false - xy: 989, 684 + xy: 490, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-4-icon-small rotate: false - xy: 741, 326 + xy: 769, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 dark-panel-5-icon-large rotate: false - xy: 895, 968 + xy: 895, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dark-panel-5-icon-medium rotate: false - xy: 1023, 684 + xy: 524, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-5-icon-small rotate: false - xy: 767, 354 + xy: 795, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 dark-panel-6-icon-large rotate: false - xy: 945, 968 + xy: 945, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dark-panel-6-icon-medium rotate: false - xy: 1057, 684 + xy: 558, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-6-icon-small rotate: false - xy: 767, 328 + xy: 821, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 darksand-icon-large rotate: false - xy: 995, 968 + xy: 995, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 darksand-icon-medium rotate: false - xy: 1091, 684 + xy: 592, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-icon-small rotate: false - xy: 809, 420 + xy: 847, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 darksand-tainted-water-icon-large rotate: false - xy: 1045, 968 + xy: 1045, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 darksand-tainted-water-icon-medium rotate: false - xy: 1125, 684 + xy: 626, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-tainted-water-icon-small rotate: false - xy: 809, 394 + xy: 873, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 darksand-water-icon-large rotate: false - xy: 1095, 968 + xy: 1095, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 darksand-water-icon-medium rotate: false - xy: 1159, 684 + xy: 660, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-water-icon-small rotate: false - xy: 835, 422 + xy: 899, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 dart-mech-pad-icon-large rotate: false - xy: 1145, 968 + xy: 1145, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dart-mech-pad-icon-medium rotate: false - xy: 1193, 684 + xy: 694, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dart-mech-pad-icon-small rotate: false - xy: 835, 396 + xy: 925, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 deepwater-icon-large rotate: false - xy: 1195, 968 + xy: 1195, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 deepwater-icon-medium rotate: false - xy: 1227, 684 + xy: 728, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 deepwater-icon-small rotate: false - xy: 911, 522 + xy: 951, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 delta-mech-pad-icon-large rotate: false - xy: 1245, 968 + xy: 1245, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 delta-mech-pad-icon-medium rotate: false - xy: 1261, 684 + xy: 762, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 delta-mech-pad-icon-small rotate: false - xy: 937, 524 + xy: 977, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 differential-generator-icon-large rotate: false - xy: 1295, 968 + xy: 1295, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 differential-generator-icon-medium rotate: false - xy: 1295, 684 + xy: 796, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 differential-generator-icon-small rotate: false - xy: 963, 528 + xy: 1003, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 discord-banner rotate: false - xy: 1, 713 + xy: 1, 720 size: 84, 45 orig: 84, 45 offset: 0, 0 index: -1 distributor-icon-large rotate: false - xy: 1345, 968 + xy: 1345, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 distributor-icon-medium rotate: false - xy: 1329, 684 + xy: 830, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 distributor-icon-small rotate: false - xy: 989, 528 + xy: 1029, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 door-icon-large rotate: false - xy: 1395, 968 + xy: 1395, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 door-icon-medium rotate: false - xy: 1363, 684 + xy: 864, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 door-icon-small rotate: false - xy: 1015, 528 + xy: 1055, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 door-large-icon-large rotate: false - xy: 1445, 968 + xy: 1445, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 door-large-icon-medium rotate: false - xy: 1397, 684 + xy: 898, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 door-large-icon-small rotate: false - xy: 1041, 528 + xy: 1081, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 draug-factory-icon-large rotate: false - xy: 1495, 968 + xy: 1495, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 draug-factory-icon-medium rotate: false - xy: 1431, 684 + xy: 932, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 draug-factory-icon-small rotate: false - xy: 1067, 528 + xy: 1107, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 dunerocks-icon-large rotate: false - xy: 1545, 968 + xy: 1545, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dunerocks-icon-medium rotate: false - xy: 1465, 684 + xy: 966, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dunerocks-icon-small rotate: false - xy: 1093, 528 + xy: 1133, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 duo-icon-large rotate: false - xy: 1595, 968 + xy: 1595, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 duo-icon-medium rotate: false - xy: 1499, 684 + xy: 1000, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 duo-icon-small rotate: false - xy: 1119, 528 + xy: 1159, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 flat-down-base rotate: false - xy: 1851, 710 + xy: 377, 696 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -9865,2611 +9865,3430 @@ flat-down-base index: -1 force-projector-icon-large rotate: false - xy: 1645, 968 + xy: 1645, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 force-projector-icon-medium rotate: false - xy: 1533, 684 + xy: 1034, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 force-projector-icon-small rotate: false - xy: 1145, 528 + xy: 1185, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 fortress-factory-icon-large rotate: false - xy: 1695, 968 + xy: 1695, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 fortress-factory-icon-medium rotate: false - xy: 1567, 684 + xy: 1068, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 fortress-factory-icon-small rotate: false - xy: 1171, 528 + xy: 1211, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 fuse-icon-large rotate: false - xy: 1745, 968 + xy: 1745, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 fuse-icon-medium rotate: false - xy: 1601, 684 + xy: 1102, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 fuse-icon-small rotate: false - xy: 1197, 528 + xy: 1237, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 ghoul-factory-icon-large rotate: false - xy: 1795, 968 + xy: 1795, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 ghoul-factory-icon-medium rotate: false - xy: 1635, 684 + xy: 1136, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ghoul-factory-icon-small rotate: false - xy: 1223, 528 + xy: 1263, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 glaive-ship-pad-icon-large rotate: false - xy: 1845, 968 + xy: 1845, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 glaive-ship-pad-icon-medium rotate: false - xy: 1669, 684 + xy: 1170, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 glaive-ship-pad-icon-small rotate: false - xy: 1249, 528 + xy: 1289, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 graphite-press-icon-large rotate: false - xy: 1895, 968 + xy: 1895, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 graphite-press-icon-medium rotate: false - xy: 1703, 684 + xy: 1204, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 graphite-press-icon-small rotate: false - xy: 1275, 528 + xy: 1315, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 grass-icon-large rotate: false - xy: 1945, 968 + xy: 1945, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 grass-icon-medium rotate: false - xy: 1737, 679 + xy: 1238, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 grass-icon-small rotate: false - xy: 1301, 528 + xy: 1341, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 hail-icon-large rotate: false - xy: 1995, 968 + xy: 1995, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 hail-icon-medium rotate: false - xy: 1771, 676 + xy: 1272, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 hail-icon-small rotate: false - xy: 1327, 528 + xy: 1367, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 holostone-icon-large rotate: false - xy: 237, 710 + xy: 237, 717 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 holostone-icon-medium rotate: false - xy: 1805, 676 + xy: 1306, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 holostone-icon-small rotate: false - xy: 1353, 528 + xy: 1393, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 hotrock-icon-large rotate: false - xy: 51, 660 + xy: 51, 667 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 hotrock-icon-medium rotate: false - xy: 1839, 676 + xy: 1340, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 hotrock-icon-small rotate: false - xy: 1379, 528 + xy: 1419, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 ice-icon-large rotate: false - xy: 51, 610 + xy: 51, 617 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 ice-icon-medium rotate: false - xy: 1873, 676 + xy: 1374, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-icon-small rotate: false - xy: 1405, 528 + xy: 1445, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 ice-snow-icon-large rotate: false - xy: 101, 660 + xy: 101, 667 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 ice-snow-icon-medium rotate: false - xy: 1907, 676 + xy: 1408, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-snow-icon-small rotate: false - xy: 1431, 528 + xy: 1471, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 icerocks-icon-large rotate: false - xy: 51, 560 + xy: 51, 567 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 icerocks-icon-medium rotate: false - xy: 1941, 676 + xy: 1442, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 icerocks-icon-small rotate: false - xy: 1457, 520 + xy: 1497, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 icon-about rotate: false - xy: 101, 610 + xy: 101, 617 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-about-med - rotate: false - xy: 947, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-about-small rotate: false - xy: 338, 655 + xy: 1476, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-about-smaller + rotate: false + xy: 641, 455 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-about-tiny + rotate: false + xy: 1, 2 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-add rotate: false - xy: 151, 660 + xy: 151, 667 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-add-med - rotate: false - xy: 403, 40 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-add-small rotate: false - xy: 335, 621 + xy: 1510, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-add-smaller + rotate: false + xy: 675, 489 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-add-tiny + rotate: false + xy: 2027, 754 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-admin rotate: false - xy: 51, 510 + xy: 51, 517 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-admin-med +icon-admin-badge rotate: false - xy: 437, 74 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 -icon-admin-small - rotate: false - xy: 101, 560 + xy: 101, 567 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-admin-small-med +icon-admin-badge-small rotate: false - xy: 471, 108 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 -icon-admin-small-small - rotate: false - xy: 335, 587 + xy: 1544, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-admin-badge-smaller + rotate: false + xy: 709, 523 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-admin-badge-tiny + rotate: false + xy: 1210, 435 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +icon-admin-small + rotate: false + xy: 1578, 691 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +icon-admin-smaller + rotate: false + xy: 743, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-admin-tiny + rotate: false + xy: 1236, 461 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-arrow rotate: false - xy: 151, 610 + xy: 151, 617 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 icon-arrow-16 rotate: false - xy: 151, 610 + xy: 151, 617 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-arrow-16-med - rotate: false - xy: 505, 142 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 -icon-arrow-med - rotate: false - xy: 505, 142 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-arrow-16-small rotate: false - xy: 335, 553 + xy: 1612, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 icon-arrow-small rotate: false - xy: 335, 553 + xy: 1612, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-arrow-16-smaller + rotate: false + xy: 471, 251 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-arrow-smaller + rotate: false + xy: 471, 251 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-arrow-16-tiny + rotate: false + xy: 1262, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +icon-arrow-tiny + rotate: false + xy: 1262, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-arrow-down rotate: false - xy: 201, 660 + xy: 201, 667 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-arrow-down-med - rotate: false - xy: 539, 176 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-arrow-down-small rotate: false - xy: 335, 519 + xy: 1646, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-arrow-down-smaller + rotate: false + xy: 505, 285 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-arrow-down-tiny + rotate: false + xy: 19, 2 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-arrow-left rotate: false - xy: 51, 460 + xy: 51, 467 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-arrow-left-med - rotate: false - xy: 573, 210 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-arrow-left-small rotate: false - xy: 335, 485 + xy: 1680, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-arrow-left-smaller + rotate: false + xy: 539, 319 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-arrow-left-tiny + rotate: false + xy: 1210, 417 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-arrow-right rotate: false - xy: 101, 510 + xy: 101, 517 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-arrow-right-med - rotate: false - xy: 607, 244 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-arrow-right-small rotate: false - xy: 335, 451 + xy: 1714, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-arrow-right-smaller + rotate: false + xy: 573, 353 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-arrow-right-tiny + rotate: false + xy: 1280, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-arrow-up rotate: false - xy: 151, 560 + xy: 151, 567 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-arrow-up-med - rotate: false - xy: 641, 278 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-arrow-up-small rotate: false - xy: 335, 417 + xy: 1748, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-arrow-up-smaller + rotate: false + xy: 607, 387 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-arrow-up-tiny + rotate: false + xy: 1298, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-back rotate: false - xy: 201, 610 + xy: 201, 617 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-back-med - rotate: false - xy: 675, 312 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-back-small rotate: false - xy: 335, 383 + xy: 1782, 691 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-back-smaller + rotate: false + xy: 641, 423 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-back-tiny + rotate: false + xy: 1316, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-ban rotate: false - xy: 51, 410 + xy: 51, 417 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-ban-med - rotate: false - xy: 709, 346 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-ban-small rotate: false - xy: 335, 349 + xy: 373, 599 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-ban-smaller + rotate: false + xy: 775, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-ban-tiny + rotate: false + xy: 1334, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-break rotate: false - xy: 101, 460 + xy: 101, 467 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-break-med - rotate: false - xy: 743, 380 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-break-small rotate: false - xy: 335, 315 + xy: 369, 565 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-break-smaller + rotate: false + xy: 471, 219 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-break-tiny + rotate: false + xy: 1352, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-cancel rotate: false - xy: 151, 510 + xy: 151, 517 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-cancel-med - rotate: false - xy: 777, 414 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-cancel-small rotate: false - xy: 335, 281 + xy: 369, 531 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-cancel-smaller + rotate: false + xy: 807, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-cancel-tiny + rotate: false + xy: 1370, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +icon-quit-tiny + rotate: false + xy: 1370, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-changelog rotate: false - xy: 201, 560 + xy: 201, 567 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-changelog-med - rotate: false - xy: 811, 448 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-changelog-small rotate: false - xy: 335, 247 + xy: 369, 497 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-changelog-smaller + rotate: false + xy: 471, 187 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-changelog-tiny + rotate: false + xy: 1388, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-chat rotate: false - xy: 51, 360 + xy: 51, 367 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-chat-med - rotate: false - xy: 845, 482 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-chat-small rotate: false - xy: 335, 213 + xy: 369, 463 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-chat-smaller + rotate: false + xy: 839, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-chat-tiny + rotate: false + xy: 1406, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-check rotate: false - xy: 101, 410 + xy: 101, 417 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-check-med - rotate: false - xy: 879, 516 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-check-small rotate: false - xy: 335, 179 + xy: 369, 429 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-check-smaller + rotate: false + xy: 471, 155 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-check-tiny + rotate: false + xy: 1424, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-command-attack rotate: false - xy: 151, 460 + xy: 151, 467 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-command-attack-med - rotate: false - xy: 913, 550 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-command-attack-small rotate: false - xy: 335, 145 + xy: 369, 395 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-command-attack-smaller + rotate: false + xy: 871, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-command-attack-tiny + rotate: false + xy: 1442, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-command-idle rotate: false - xy: 201, 510 + xy: 201, 517 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-command-idle-med - rotate: false - xy: 947, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-command-idle-small rotate: false - xy: 335, 111 + xy: 369, 361 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-command-idle-smaller + rotate: false + xy: 471, 123 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-command-idle-tiny + rotate: false + xy: 1460, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-command-patrol rotate: false - xy: 51, 310 + xy: 51, 317 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-command-patrol-med - rotate: false - xy: 979, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-command-patrol-small rotate: false - xy: 335, 77 + xy: 369, 327 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-command-patrol-smaller + rotate: false + xy: 903, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-command-patrol-tiny + rotate: false + xy: 1478, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-command-retreat rotate: false - xy: 101, 360 + xy: 101, 367 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-command-retreat-med - rotate: false - xy: 979, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-command-retreat-small rotate: false - xy: 335, 43 + xy: 369, 293 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-command-retreat-smaller + rotate: false + xy: 471, 91 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-command-retreat-tiny + rotate: false + xy: 1496, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-copy rotate: false - xy: 151, 410 + xy: 151, 417 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-copy-med - rotate: false - xy: 1011, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-copy-small rotate: false - xy: 335, 9 + xy: 369, 259 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-copy-smaller + rotate: false + xy: 935, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-copy-tiny + rotate: false + xy: 1514, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-crafting rotate: false - xy: 201, 460 + xy: 201, 467 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-crafting-med - rotate: false - xy: 1011, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-crafting-small rotate: false - xy: 372, 650 + xy: 369, 225 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-crafting-smaller + rotate: false + xy: 471, 59 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-crafting-tiny + rotate: false + xy: 1532, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-cursor rotate: false - xy: 51, 260 + xy: 51, 267 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-cursor-med - rotate: false - xy: 1043, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-cursor-small rotate: false - xy: 406, 650 + xy: 369, 191 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-cursor-smaller + rotate: false + xy: 967, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-cursor-tiny + rotate: false + xy: 1550, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-database rotate: false - xy: 101, 310 + xy: 101, 317 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-database-med - rotate: false - xy: 1043, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-database-small rotate: false - xy: 440, 650 + xy: 369, 157 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-database-smaller + rotate: false + xy: 471, 27 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-database-tiny + rotate: false + xy: 1568, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-defense rotate: false - xy: 151, 360 + xy: 151, 367 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-defense-med - rotate: false - xy: 1075, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-defense-small rotate: false - xy: 474, 650 + xy: 369, 123 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-defense-smaller + rotate: false + xy: 999, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-defense-tiny + rotate: false + xy: 1586, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-dev-builds rotate: false - xy: 201, 410 + xy: 201, 417 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-dev-builds-med - rotate: false - xy: 1075, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-dev-builds-small rotate: false - xy: 508, 650 + xy: 369, 89 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-dev-builds-smaller + rotate: false + xy: 1031, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-dev-builds-tiny + rotate: false + xy: 1604, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-diagonal rotate: false - xy: 51, 210 + xy: 51, 217 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-diagonal-med - rotate: false - xy: 1107, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-diagonal-small rotate: false - xy: 542, 650 + xy: 369, 55 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-diagonal-smaller + rotate: false + xy: 1063, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-diagonal-tiny + rotate: false + xy: 1622, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-discord rotate: false - xy: 101, 260 + xy: 101, 267 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-discord-med - rotate: false - xy: 1107, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-discord-small rotate: false - xy: 576, 650 + xy: 369, 21 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-discord-smaller + rotate: false + xy: 1095, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-discord-tiny + rotate: false + xy: 1640, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-distribution rotate: false - xy: 151, 310 + xy: 151, 317 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-distribution-med - rotate: false - xy: 1139, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-distribution-small rotate: false - xy: 610, 650 + xy: 411, 628 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-distribution-smaller + rotate: false + xy: 1127, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-distribution-tiny + rotate: false + xy: 1658, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-donate rotate: false - xy: 201, 360 + xy: 201, 367 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-donate-med - rotate: false - xy: 1139, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-donate-small rotate: false - xy: 644, 650 + xy: 407, 594 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-donate-smaller + rotate: false + xy: 1159, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-donate-tiny + rotate: false + xy: 1676, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-dots rotate: false - xy: 51, 160 + xy: 51, 167 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-dots-med - rotate: false - xy: 1171, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-dots-small rotate: false - xy: 678, 650 + xy: 403, 560 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-dots-smaller + rotate: false + xy: 1191, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-dots-tiny + rotate: false + xy: 1694, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-editor rotate: false - xy: 101, 210 + xy: 101, 217 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-editor-med - rotate: false - xy: 1171, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-editor-small rotate: false - xy: 712, 650 + xy: 403, 526 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-editor-smaller + rotate: false + xy: 1223, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-editor-tiny + rotate: false + xy: 1712, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-effect rotate: false - xy: 151, 260 + xy: 151, 267 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-effect-med - rotate: false - xy: 1203, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-effect-small rotate: false - xy: 746, 650 + xy: 403, 492 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-effect-smaller + rotate: false + xy: 1255, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-effect-tiny + rotate: false + xy: 1730, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-elevation rotate: false - xy: 201, 310 + xy: 201, 317 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-elevation-med - rotate: false - xy: 1203, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-elevation-small rotate: false - xy: 780, 650 + xy: 403, 458 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-elevation-smaller + rotate: false + xy: 1287, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-elevation-tiny + rotate: false + xy: 1748, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-eraser rotate: false - xy: 51, 110 + xy: 51, 117 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-eraser-med - rotate: false - xy: 1235, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-eraser-small rotate: false - xy: 814, 650 + xy: 403, 424 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-exit +icon-eraser-smaller rotate: false - xy: 101, 160 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -icon-exit-med - rotate: false - xy: 1235, 586 + xy: 1319, 557 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-eraser-tiny + rotate: false + xy: 1766, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +icon-exit + rotate: false + xy: 101, 167 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 icon-exit-small rotate: false - xy: 848, 650 + xy: 403, 390 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-exit-smaller + rotate: false + xy: 1351, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-exit-tiny + rotate: false + xy: 1784, 487 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +icon-fdroid + rotate: false + xy: 151, 217 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +icon-fdroid-small + rotate: false + xy: 403, 356 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +icon-fdroid-smaller + rotate: false + xy: 1383, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-fdroid-tiny + rotate: false + xy: 1809, 540 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-file rotate: false - xy: 151, 210 + xy: 201, 267 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 icon-file-image rotate: false - xy: 201, 260 + xy: 51, 67 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-file-image-med - rotate: false - xy: 1267, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-file-image-small rotate: false - xy: 882, 650 + xy: 403, 322 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-file-med +icon-file-image-smaller rotate: false - xy: 1267, 586 + xy: 1415, 557 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-file-image-tiny + rotate: false + xy: 1210, 399 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-file-small rotate: false - xy: 916, 650 + xy: 403, 288 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-file-smaller + rotate: false + xy: 1447, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 icon-file-text rotate: false - xy: 51, 60 + xy: 101, 117 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-file-text-med - rotate: false - xy: 1299, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-file-text-small rotate: false - xy: 950, 650 + xy: 403, 254 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-fill +icon-file-text-smaller rotate: false - xy: 101, 110 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -icon-fill-med - rotate: false - xy: 1299, 586 + xy: 1479, 557 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-file-text-tiny + rotate: false + xy: 924, 383 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +icon-file-tiny + rotate: false + xy: 942, 383 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +icon-fill + rotate: false + xy: 151, 167 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 icon-fill-small rotate: false - xy: 984, 650 + xy: 403, 220 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-fill-smaller + rotate: false + xy: 1511, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-fill-tiny + rotate: false + xy: 960, 383 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-floppy rotate: false - xy: 151, 160 + xy: 201, 217 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 icon-floppy-16 rotate: false - xy: 201, 210 + xy: 101, 67 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-floppy-16-med - rotate: false - xy: 1331, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-floppy-16-small rotate: false - xy: 1018, 650 + xy: 403, 186 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-floppy-med +icon-floppy-16-smaller rotate: false - xy: 1331, 586 + xy: 1543, 557 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-floppy-16-tiny + rotate: false + xy: 978, 383 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-floppy-small rotate: false - xy: 1052, 650 + xy: 403, 152 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-floppy-smaller + rotate: false + xy: 1575, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-floppy-tiny + rotate: false + xy: 996, 383 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-folder rotate: false - xy: 101, 60 + xy: 151, 117 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-folder-med - rotate: false - xy: 1363, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-folder-parent rotate: false - xy: 151, 110 + xy: 201, 167 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-folder-parent-med - rotate: false - xy: 1363, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-folder-parent-small rotate: false - xy: 1086, 650 + xy: 403, 118 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-folder-parent-smaller + rotate: false + xy: 1607, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-folder-parent-tiny + rotate: false + xy: 1014, 383 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-folder-small rotate: false - xy: 1120, 650 + xy: 403, 84 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-folder-smaller + rotate: false + xy: 1639, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-folder-tiny + rotate: false + xy: 1032, 383 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-github rotate: false - xy: 201, 160 + xy: 151, 67 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-github-med - rotate: false - xy: 1395, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-github-small rotate: false - xy: 1154, 650 + xy: 403, 50 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-github-smaller + rotate: false + xy: 1671, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-github-tiny + rotate: false + xy: 1050, 383 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-google-play rotate: false - xy: 151, 60 + xy: 201, 117 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-google-play-med - rotate: false - xy: 1395, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-google-play-small rotate: false - xy: 1188, 650 + xy: 403, 16 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-google-play-smaller + rotate: false + xy: 1703, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-google-play-tiny + rotate: false + xy: 1068, 383 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-grid rotate: false - xy: 201, 110 + xy: 201, 67 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-grid-med - rotate: false - xy: 1427, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-grid-small rotate: false - xy: 1222, 650 + xy: 1993, 738 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-grid-smaller + rotate: false + xy: 1735, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-grid-tiny + rotate: false + xy: 1086, 383 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-home rotate: false - xy: 201, 60 + xy: 51, 17 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-home-med - rotate: false - xy: 1427, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-home-small rotate: false - xy: 1256, 650 + xy: 1989, 704 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-home-smaller + rotate: false + xy: 1767, 557 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-home-tiny + rotate: false + xy: 1104, 383 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-host rotate: false - xy: 51, 10 + xy: 101, 17 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-host-med - rotate: false - xy: 1459, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-host-small rotate: false - xy: 1290, 650 + xy: 1816, 686 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-host-smaller + rotate: false + xy: 1809, 654 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-host-tiny + rotate: false + xy: 1122, 383 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-info rotate: false - xy: 101, 10 + xy: 151, 17 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-info-med - rotate: false - xy: 1459, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-info-small rotate: false - xy: 1324, 650 + xy: 1850, 683 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-info-smaller + rotate: false + xy: 1805, 622 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-info-tiny + rotate: false + xy: 1140, 383 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-itch.io rotate: false - xy: 151, 10 + xy: 201, 17 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-itch.io-med - rotate: false - xy: 1491, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-itch.io-small rotate: false - xy: 1358, 650 + xy: 1884, 683 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-itch.io-smaller + rotate: false + xy: 1801, 590 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-itch.io-tiny + rotate: false + xy: 1158, 383 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-item rotate: false - xy: 201, 10 + xy: 251, 667 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-item-med - rotate: false - xy: 1491, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-item-small rotate: false - xy: 1392, 650 + xy: 1918, 683 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-item-smaller + rotate: false + xy: 1841, 651 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-item-tiny + rotate: false + xy: 1176, 383 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-line rotate: false - xy: 251, 660 + xy: 251, 617 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-line-med - rotate: false - xy: 1523, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-line-small rotate: false - xy: 1426, 650 + xy: 1952, 683 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-link +icon-line-smaller rotate: false - xy: 251, 610 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -icon-link-med - rotate: false - xy: 1523, 586 + xy: 1873, 651 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-line-tiny + rotate: false + xy: 327, 8 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +icon-link + rotate: false + xy: 251, 567 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 icon-link-small rotate: false - xy: 1460, 650 + xy: 1986, 670 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-link-smaller + rotate: false + xy: 1905, 651 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-link-tiny + rotate: false + xy: 345, 8 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-liquid rotate: false - xy: 251, 560 + xy: 251, 517 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 icon-liquid-consume rotate: false - xy: 251, 510 + xy: 251, 467 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-liquid-consume-med - rotate: false - xy: 1555, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-liquid-consume-small rotate: false - xy: 1494, 650 + xy: 449, 662 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-liquid-med +icon-liquid-consume-smaller rotate: false - xy: 1555, 586 + xy: 1937, 651 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-liquid-consume-tiny + rotate: false + xy: 872, 367 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-liquid-small rotate: false - xy: 1528, 650 + xy: 445, 628 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-liquid-smaller + rotate: false + xy: 1837, 619 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-liquid-tiny + rotate: false + xy: 1809, 522 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-load rotate: false - xy: 251, 460 + xy: 251, 417 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 icon-load-image rotate: false - xy: 251, 410 + xy: 251, 367 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-load-image-med - rotate: false - xy: 1587, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-load-image-small rotate: false - xy: 1562, 650 + xy: 441, 594 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-load-image-smaller + rotate: false + xy: 1869, 619 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-load-image-tiny + rotate: false + xy: 1807, 504 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-load-map rotate: false - xy: 251, 360 + xy: 251, 317 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-load-map-med - rotate: false - xy: 1587, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-load-map-small rotate: false - xy: 1596, 650 + xy: 437, 560 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-load-med +icon-load-map-smaller rotate: false - xy: 1619, 618 + xy: 1901, 619 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-load-map-tiny + rotate: false + xy: 1827, 537 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-load-small rotate: false - xy: 1630, 650 + xy: 437, 526 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-load-smaller + rotate: false + xy: 1933, 619 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-load-tiny + rotate: false + xy: 1845, 537 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-loading rotate: false - xy: 251, 310 + xy: 251, 267 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-loading-med - rotate: false - xy: 1619, 586 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-loading-small rotate: false - xy: 1664, 650 + xy: 437, 492 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-loading-smaller + rotate: false + xy: 1833, 587 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-loading-tiny + rotate: false + xy: 1863, 537 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-locked rotate: false - xy: 251, 260 + xy: 251, 217 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-locked-med - rotate: false - xy: 1651, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-locked-small rotate: false - xy: 1698, 650 + xy: 437, 458 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-map +icon-locked-smaller rotate: false - xy: 251, 210 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -icon-map-med - rotate: false - xy: 1651, 586 + xy: 1865, 587 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-locked-tiny + rotate: false + xy: 1881, 537 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +icon-map + rotate: false + xy: 251, 167 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 icon-map-small rotate: false - xy: 369, 616 + xy: 437, 424 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-map-smaller + rotate: false + xy: 1897, 587 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-map-tiny + rotate: false + xy: 1899, 537 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-menu rotate: false - xy: 251, 160 + xy: 251, 117 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 icon-menu-large rotate: false - xy: 251, 110 + xy: 251, 67 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-menu-large-med - rotate: false - xy: 1683, 618 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-menu-large-small rotate: false - xy: 369, 582 + xy: 437, 390 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-menu-med +icon-menu-large-smaller rotate: false - xy: 1683, 586 + xy: 1929, 587 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-menu-large-tiny + rotate: false + xy: 1917, 537 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-menu-small rotate: false - xy: 403, 616 + xy: 437, 356 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-menu-smaller + rotate: false + xy: 641, 391 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-menu-tiny + rotate: false + xy: 1935, 537 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-missing rotate: false - xy: 251, 60 + xy: 251, 17 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-missing-med - rotate: false - xy: 369, 6 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-missing-small rotate: false - xy: 369, 548 + xy: 437, 322 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-missing-smaller + rotate: false + xy: 1965, 619 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-missing-tiny + rotate: false + xy: 1953, 537 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-mode-attack rotate: false - xy: 251, 10 + xy: 309, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-mode-attack-med - rotate: false - xy: 1732, 647 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-mode-attack-small rotate: false - xy: 403, 582 + xy: 437, 288 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-mode-attack-smaller + rotate: false + xy: 1961, 587 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-mode-attack-tiny + rotate: false + xy: 1971, 537 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-mode-pvp rotate: false - xy: 309, 918 + xy: 309, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-mode-pvp-med - rotate: false - xy: 1764, 644 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-mode-pvp-small rotate: false - xy: 437, 616 + xy: 437, 254 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-mode-pvp-smaller + rotate: false + xy: 1801, 558 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-mode-pvp-tiny + rotate: false + xy: 1827, 519 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-mode-survival rotate: false - xy: 309, 868 + xy: 359, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-mode-survival-med - rotate: false - xy: 1796, 644 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-mode-survival-small rotate: false - xy: 369, 514 + xy: 437, 220 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-mode-survival-smaller + rotate: false + xy: 1833, 555 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-mode-survival-tiny + rotate: false + xy: 1845, 519 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-none rotate: false - xy: 359, 918 + xy: 309, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-none-med - rotate: false - xy: 1828, 644 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-none-small rotate: false - xy: 403, 548 + xy: 437, 186 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-none-smaller + rotate: false + xy: 1865, 555 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-none-tiny + rotate: false + xy: 1863, 519 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-paste rotate: false - xy: 309, 818 + xy: 359, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-paste-med - rotate: false - xy: 1860, 644 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-paste-small rotate: false - xy: 437, 582 + xy: 437, 152 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-paste-smaller + rotate: false + xy: 1897, 555 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-paste-tiny + rotate: false + xy: 1881, 519 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-pause rotate: false - xy: 359, 868 + xy: 409, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-pause-med - rotate: false - xy: 1892, 644 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-pause-small rotate: false - xy: 471, 616 + xy: 437, 118 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-pause-smaller + rotate: false + xy: 1929, 555 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-pause-tiny + rotate: false + xy: 1899, 519 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-pencil rotate: false - xy: 409, 918 + xy: 359, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-pencil-med - rotate: false - xy: 1924, 644 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-pencil-small rotate: false - xy: 369, 480 + xy: 437, 84 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-pick +icon-pencil-smaller rotate: false - xy: 359, 818 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -icon-pick-med - rotate: false - xy: 1956, 644 + xy: 1961, 555 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-pencil-tiny + rotate: false + xy: 1917, 519 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +icon-pick + rotate: false + xy: 409, 875 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 icon-pick-small rotate: false - xy: 403, 514 + xy: 437, 50 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-pick-smaller + rotate: false + xy: 1997, 638 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-pick-tiny + rotate: false + xy: 1935, 519 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-play rotate: false - xy: 409, 868 + xy: 459, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 icon-play-2 rotate: false - xy: 459, 918 + xy: 409, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-play-2-med - rotate: false - xy: 1715, 615 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-play-2-small rotate: false - xy: 437, 548 + xy: 437, 16 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-play-2-smaller + rotate: false + xy: 1997, 606 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-play-2-tiny + rotate: false + xy: 1953, 519 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +icon-play-tiny + rotate: false + xy: 1953, 519 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-play-custom rotate: false - xy: 409, 818 + xy: 459, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-play-custom-med - rotate: false - xy: 1715, 583 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-play-custom-small rotate: false - xy: 471, 582 + xy: 483, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-play-med +icon-play-custom-smaller rotate: false - xy: 1747, 612 + xy: 1993, 574 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-play-custom-tiny + rotate: false + xy: 1971, 519 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-play-small rotate: false - xy: 505, 616 + xy: 517, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-play-smaller + rotate: false + xy: 1993, 542 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 icon-players rotate: false - xy: 459, 868 + xy: 509, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-players-med - rotate: false - xy: 1779, 612 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-players-small rotate: false - xy: 369, 446 + xy: 551, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-players-smaller + rotate: false + xy: 673, 455 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-players-tiny + rotate: false + xy: 1989, 524 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-power rotate: false - xy: 509, 918 + xy: 459, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-power-med - rotate: false - xy: 1811, 612 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-power-small rotate: false - xy: 403, 480 + xy: 585, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-power-smaller + rotate: false + xy: 673, 423 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-power-tiny + rotate: false + xy: 2007, 524 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-production rotate: false - xy: 459, 818 + xy: 509, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-production-med - rotate: false - xy: 1843, 612 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-production-small rotate: false - xy: 437, 514 + xy: 619, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-production-smaller + rotate: false + xy: 673, 391 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-production-tiny + rotate: false + xy: 1825, 501 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-quit rotate: false - xy: 509, 868 + xy: 559, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-quit-med - rotate: false - xy: 1875, 612 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-quit-small rotate: false - xy: 471, 548 + xy: 653, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-quit-smaller + rotate: false + xy: 707, 489 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 icon-redo rotate: false - xy: 559, 918 + xy: 509, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-redo-med - rotate: false - xy: 1907, 612 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-redo-small rotate: false - xy: 505, 582 + xy: 687, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-redo-smaller + rotate: false + xy: 705, 457 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-redo-tiny + rotate: false + xy: 1843, 501 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-refresh rotate: false - xy: 509, 818 + xy: 559, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-refresh-med - rotate: false - xy: 1939, 612 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-refresh-small rotate: false - xy: 539, 616 + xy: 721, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-refresh-smaller + rotate: false + xy: 705, 425 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-refresh-tiny + rotate: false + xy: 1861, 501 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-rename rotate: false - xy: 559, 868 + xy: 609, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-rename-med - rotate: false - xy: 1747, 580 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-rename-small rotate: false - xy: 369, 412 + xy: 755, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-resize +icon-rename-smaller rotate: false - xy: 609, 918 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -icon-resize-med - rotate: false - xy: 1779, 580 + xy: 705, 393 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-rename-tiny + rotate: false + xy: 1879, 501 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +icon-resize + rotate: false + xy: 559, 825 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 icon-resize-small rotate: false - xy: 403, 446 + xy: 789, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-resize-smaller + rotate: false + xy: 503, 251 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-resize-tiny + rotate: false + xy: 1897, 501 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-rotate rotate: false - xy: 559, 818 + xy: 609, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 icon-rotate-arrow rotate: false - xy: 609, 868 + xy: 659, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-rotate-arrow-med - rotate: false - xy: 1811, 580 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-rotate-arrow-small rotate: false - xy: 437, 480 + xy: 823, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-rotate-arrow-smaller + rotate: false + xy: 503, 219 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-rotate-arrow-tiny + rotate: false + xy: 1915, 501 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-rotate-left rotate: false - xy: 659, 918 + xy: 609, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-rotate-left-med - rotate: false - xy: 1843, 580 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-rotate-left-small rotate: false - xy: 471, 514 + xy: 857, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-rotate-med +icon-rotate-left-smaller rotate: false - xy: 1875, 580 + xy: 503, 187 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-rotate-left-tiny + rotate: false + xy: 1933, 501 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-rotate-right rotate: false - xy: 609, 818 + xy: 659, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-rotate-right-med +icon-rotate-right-small rotate: false - xy: 1907, 580 + xy: 891, 657 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +icon-rotate-right-smaller + rotate: false + xy: 503, 155 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 -icon-rotate-right-small +icon-rotate-right-tiny rotate: false - xy: 505, 548 - size: 32, 32 - orig: 32, 32 + xy: 1951, 501 + size: 16, 16 + orig: 16, 16 offset: 0, 0 index: -1 icon-rotate-small rotate: false - xy: 539, 582 + xy: 925, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-rotate-smaller + rotate: false + xy: 503, 123 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-rotate-tiny + rotate: false + xy: 1969, 501 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-save rotate: false - xy: 659, 868 + xy: 709, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 icon-save-image rotate: false - xy: 709, 918 + xy: 659, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-save-image-med - rotate: false - xy: 1939, 580 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-save-image-small rotate: false - xy: 573, 616 + xy: 959, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-save-image-smaller + rotate: false + xy: 503, 91 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-save-image-tiny + rotate: false + xy: 1802, 486 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-save-map rotate: false - xy: 659, 818 + xy: 709, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-save-map-med - rotate: false - xy: 1971, 612 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-save-map-small rotate: false - xy: 369, 378 + xy: 993, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-save-med +icon-save-map-smaller rotate: false - xy: 1971, 580 + xy: 503, 59 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-save-map-tiny + rotate: false + xy: 1820, 483 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-save-small rotate: false - xy: 403, 412 + xy: 1027, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-save-smaller + rotate: false + xy: 503, 27 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-save-tiny + rotate: false + xy: 1838, 483 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-settings rotate: false - xy: 709, 868 + xy: 759, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-settings-med - rotate: false - xy: 947, 554 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-settings-small rotate: false - xy: 437, 446 + xy: 1061, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-settings-smaller + rotate: false + xy: 537, 285 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-settings-tiny + rotate: false + xy: 1856, 483 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-spray rotate: false - xy: 759, 918 + xy: 709, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-spray-med - rotate: false - xy: 979, 554 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-spray-small rotate: false - xy: 471, 480 + xy: 1095, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-spray-smaller + rotate: false + xy: 535, 253 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-spray-tiny + rotate: false + xy: 1874, 483 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-terrain rotate: false - xy: 709, 818 + xy: 759, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-terrain-med - rotate: false - xy: 1011, 554 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-terrain-small rotate: false - xy: 505, 514 + xy: 1129, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-tools +icon-terrain-smaller rotate: false - xy: 759, 868 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -icon-tools-med - rotate: false - xy: 1043, 554 + xy: 535, 221 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-terrain-tiny + rotate: false + xy: 1892, 483 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +icon-tools + rotate: false + xy: 809, 925 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 icon-tools-small rotate: false - xy: 539, 548 + xy: 1163, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-tools-smaller + rotate: false + xy: 535, 189 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-tools-tiny + rotate: false + xy: 1910, 483 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-trash rotate: false - xy: 809, 918 + xy: 759, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 icon-trash-16 rotate: false - xy: 759, 818 + xy: 809, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-trash-16-med - rotate: false - xy: 1075, 554 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-trash-16-small rotate: false - xy: 573, 582 + xy: 1197, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-trash-med +icon-trash-16-smaller rotate: false - xy: 1107, 554 + xy: 535, 157 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 +icon-trash-16-tiny + rotate: false + xy: 1928, 483 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-trash-small rotate: false - xy: 607, 616 + xy: 1231, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-trash-smaller + rotate: false + xy: 535, 125 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-trash-tiny + rotate: false + xy: 1946, 483 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-tree rotate: false - xy: 809, 868 + xy: 859, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-tree-med - rotate: false - xy: 1139, 554 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-tree-small rotate: false - xy: 369, 344 + xy: 1265, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-tree-smaller + rotate: false + xy: 535, 93 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-tree-tiny + rotate: false + xy: 1964, 483 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-trello rotate: false - xy: 859, 918 + xy: 809, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-trello-med - rotate: false - xy: 1171, 554 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-trello-small rotate: false - xy: 403, 378 + xy: 1299, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-trello-smaller + rotate: false + xy: 535, 61 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-trello-tiny + rotate: false + xy: 1228, 435 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-turret rotate: false - xy: 809, 818 + xy: 859, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-turret-med - rotate: false - xy: 1203, 554 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-turret-small rotate: false - xy: 437, 412 + xy: 1333, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-turret-smaller + rotate: false + xy: 535, 29 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-turret-tiny + rotate: false + xy: 1228, 417 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-tutorial rotate: false - xy: 859, 868 + xy: 909, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-tutorial-med - rotate: false - xy: 1235, 554 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-tutorial-small rotate: false - xy: 471, 446 + xy: 1367, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-tutorial-smaller + rotate: false + xy: 571, 319 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-tutorial-tiny + rotate: false + xy: 1228, 399 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-undo rotate: false - xy: 909, 918 + xy: 859, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-undo-med - rotate: false - xy: 1267, 554 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-undo-small rotate: false - xy: 505, 480 + xy: 1401, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-undo-smaller + rotate: false + xy: 569, 287 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-undo-tiny + rotate: false + xy: 1254, 461 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-units rotate: false - xy: 859, 818 + xy: 909, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-units-med - rotate: false - xy: 1299, 554 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-units-small rotate: false - xy: 539, 514 + xy: 1435, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-units-smaller + rotate: false + xy: 605, 353 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-units-tiny + rotate: false + xy: 1246, 443 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-unlocks rotate: false - xy: 909, 868 + xy: 959, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-unlocks-med - rotate: false - xy: 1331, 554 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-unlocks-small rotate: false - xy: 573, 548 + xy: 1469, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-unlocks-smaller + rotate: false + xy: 603, 321 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-unlocks-tiny + rotate: false + xy: 1246, 425 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-upgrade rotate: false - xy: 959, 918 + xy: 909, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-upgrade-med - rotate: false - xy: 1363, 554 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-upgrade-small rotate: false - xy: 607, 582 + xy: 1503, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-upgrade-smaller + rotate: false + xy: 639, 359 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-upgrade-tiny + rotate: false + xy: 1246, 407 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 icon-wiki rotate: false - xy: 909, 818 + xy: 959, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -icon-wiki-med - rotate: false - xy: 1395, 554 - size: 30, 30 - orig: 30, 30 - offset: 0, 0 - index: -1 icon-wiki-small rotate: false - xy: 641, 616 + xy: 1537, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -icon-zoom +icon-wiki-smaller rotate: false - xy: 959, 868 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -icon-zoom-med - rotate: false - xy: 1427, 554 + xy: 671, 359 size: 30, 30 orig: 30, 30 offset: 0, 0 index: -1 -icon-zoom-small +icon-wiki-tiny rotate: false - xy: 369, 310 + xy: 1272, 469 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +icon-workshop + rotate: false + xy: 1009, 925 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +icon-workshop-small + rotate: false + xy: 1571, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +icon-workshop-smaller + rotate: false + xy: 637, 327 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-workshop-tiny + rotate: false + xy: 1290, 469 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +icon-zoom + rotate: false + xy: 959, 825 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +icon-zoom-small + rotate: false + xy: 1605, 657 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +icon-zoom-smaller + rotate: false + xy: 669, 327 + size: 30, 30 + orig: 30, 30 + offset: 0, 0 + index: -1 +icon-zoom-tiny + rotate: false + xy: 1308, 469 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 ignarock-icon-large rotate: false - xy: 1009, 918 + xy: 1009, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 ignarock-icon-medium rotate: false - xy: 403, 344 + xy: 1639, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ignarock-icon-small rotate: false - xy: 1483, 520 + xy: 1523, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 impact-reactor-icon-large rotate: false - xy: 959, 818 + xy: 1059, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 impact-reactor-icon-medium rotate: false - xy: 437, 378 + xy: 1673, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 impact-reactor-icon-small rotate: false - xy: 1509, 520 + xy: 1549, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 incinerator-icon-large rotate: false - xy: 1009, 868 + xy: 1009, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 incinerator-icon-medium rotate: false - xy: 471, 412 + xy: 1707, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 incinerator-icon-small rotate: false - xy: 1535, 520 + xy: 1575, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 info-banner rotate: false - xy: 259, 971 + xy: 259, 978 size: 84, 45 orig: 84, 45 offset: 0, 0 index: -1 inventory rotate: false - xy: 1561, 506 + xy: 741, 489 size: 24, 40 split: 10, 10, 10, 14 orig: 24, 40 @@ -12477,686 +13296,686 @@ inventory index: -1 item-source-icon-large rotate: false - xy: 1059, 918 + xy: 1059, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-source-icon-medium rotate: false - xy: 505, 446 + xy: 1741, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-source-icon-small rotate: false - xy: 911, 496 + xy: 1601, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-void-icon-large rotate: false - xy: 1009, 818 + xy: 1109, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-void-icon-medium rotate: false - xy: 539, 480 + xy: 1775, 657 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-void-icon-small rotate: false - xy: 937, 498 + xy: 767, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 javelin-ship-pad-icon-large rotate: false - xy: 1059, 868 + xy: 1059, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 javelin-ship-pad-icon-medium rotate: false - xy: 573, 514 + xy: 479, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 javelin-ship-pad-icon-small rotate: false - xy: 963, 502 + xy: 1627, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 junction-icon-large rotate: false - xy: 1109, 918 + xy: 1109, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 junction-icon-medium rotate: false - xy: 607, 548 + xy: 513, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 junction-icon-small rotate: false - xy: 989, 502 + xy: 793, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 kiln-icon-large rotate: false - xy: 1059, 818 + xy: 1159, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 kiln-icon-medium rotate: false - xy: 641, 582 + xy: 547, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 kiln-icon-small rotate: false - xy: 1015, 502 + xy: 1653, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 lancer-icon-large rotate: false - xy: 1109, 868 + xy: 1109, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 lancer-icon-medium rotate: false - xy: 675, 616 + xy: 581, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 lancer-icon-small rotate: false - xy: 1041, 502 + xy: 819, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 laser-drill-icon-large rotate: false - xy: 1159, 918 + xy: 1159, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 laser-drill-icon-medium rotate: false - xy: 369, 276 + xy: 615, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 laser-drill-icon-small rotate: false - xy: 1067, 502 + xy: 1679, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 launch-pad-icon-large rotate: false - xy: 1109, 818 + xy: 1209, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 launch-pad-icon-medium rotate: false - xy: 403, 310 + xy: 649, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 launch-pad-icon-small rotate: false - xy: 1093, 502 + xy: 845, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 launch-pad-large-icon-large rotate: false - xy: 1159, 868 + xy: 1159, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 launch-pad-large-icon-medium rotate: false - xy: 437, 344 + xy: 683, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 launch-pad-large-icon-small rotate: false - xy: 1119, 502 + xy: 1705, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 liquid-junction-icon-large rotate: false - xy: 1209, 918 + xy: 1209, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 liquid-junction-icon-medium rotate: false - xy: 471, 378 + xy: 717, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-junction-icon-small rotate: false - xy: 1145, 502 + xy: 871, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 liquid-router-icon-large rotate: false - xy: 1159, 818 + xy: 1259, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 liquid-router-icon-medium rotate: false - xy: 505, 412 + xy: 751, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-router-icon-small rotate: false - xy: 1171, 502 + xy: 1731, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 liquid-source-icon-large rotate: false - xy: 1209, 868 + xy: 1209, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 liquid-source-icon-medium rotate: false - xy: 539, 446 + xy: 785, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-source-icon-small rotate: false - xy: 1197, 502 + xy: 897, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 liquid-tank-icon-large rotate: false - xy: 1259, 918 + xy: 1259, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 liquid-tank-icon-medium rotate: false - xy: 573, 480 + xy: 819, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-tank-icon-small rotate: false - xy: 1223, 502 + xy: 1757, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 magmarock-icon-large rotate: false - xy: 1209, 818 + xy: 1309, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 magmarock-icon-medium rotate: false - xy: 607, 514 + xy: 853, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 magmarock-icon-small rotate: false - xy: 1249, 502 + xy: 923, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 mass-driver-icon-large rotate: false - xy: 1259, 868 + xy: 1259, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 mass-driver-icon-medium rotate: false - xy: 641, 548 + xy: 887, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mass-driver-icon-small rotate: false - xy: 1275, 502 + xy: 949, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 mechanical-drill-icon-large rotate: false - xy: 1309, 918 + xy: 1309, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 mechanical-drill-icon-medium rotate: false - xy: 675, 582 + xy: 921, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mechanical-drill-icon-small rotate: false - xy: 1301, 502 + xy: 975, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 mechanical-pump-icon-large rotate: false - xy: 1259, 818 + xy: 1359, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 mechanical-pump-icon-medium rotate: false - xy: 709, 616 + xy: 955, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mechanical-pump-icon-small rotate: false - xy: 1327, 502 + xy: 1001, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 meltdown-icon-large rotate: false - xy: 1309, 868 + xy: 1309, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 meltdown-icon-medium rotate: false - xy: 369, 242 + xy: 989, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 meltdown-icon-small rotate: false - xy: 1353, 502 + xy: 1027, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 melter-icon-large rotate: false - xy: 1359, 918 + xy: 1359, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 melter-icon-medium rotate: false - xy: 403, 276 + xy: 1023, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 melter-icon-small rotate: false - xy: 1379, 502 + xy: 1053, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 mend-projector-icon-large rotate: false - xy: 1309, 818 + xy: 1409, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 mend-projector-icon-medium rotate: false - xy: 437, 310 + xy: 1057, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mend-projector-icon-small rotate: false - xy: 1405, 502 + xy: 1079, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 mender-icon-large rotate: false - xy: 1359, 868 + xy: 1359, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 mender-icon-medium rotate: false - xy: 471, 344 + xy: 1091, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mender-icon-small rotate: false - xy: 1431, 502 + xy: 1105, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 metal-floor-2-icon-large rotate: false - xy: 1409, 918 + xy: 1409, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 metal-floor-2-icon-medium rotate: false - xy: 505, 378 + xy: 1125, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-2-icon-small rotate: false - xy: 1457, 494 + xy: 1131, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 metal-floor-3-icon-large rotate: false - xy: 1359, 818 + xy: 1459, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 metal-floor-3-icon-medium rotate: false - xy: 539, 412 + xy: 1159, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-3-icon-small rotate: false - xy: 1483, 494 + xy: 1157, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 metal-floor-5-icon-large rotate: false - xy: 1409, 868 + xy: 1409, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 metal-floor-5-icon-medium rotate: false - xy: 573, 446 + xy: 1193, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-5-icon-small rotate: false - xy: 1509, 494 + xy: 1183, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 metal-floor-damaged-icon-large rotate: false - xy: 1459, 918 + xy: 1459, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 metal-floor-damaged-icon-medium rotate: false - xy: 607, 480 + xy: 1227, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-damaged-icon-small rotate: false - xy: 1535, 494 + xy: 1209, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 metal-floor-icon-large rotate: false - xy: 1409, 818 + xy: 1509, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 metal-floor-icon-medium rotate: false - xy: 641, 514 + xy: 1261, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-icon-small rotate: false - xy: 1561, 480 + xy: 1235, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 moss-icon-large rotate: false - xy: 1459, 868 + xy: 1459, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 moss-icon-medium rotate: false - xy: 675, 548 + xy: 1295, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 moss-icon-small rotate: false - xy: 963, 476 + xy: 1261, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 multi-press-icon-large rotate: false - xy: 1509, 918 + xy: 1509, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 multi-press-icon-medium rotate: false - xy: 709, 582 + xy: 1329, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 multi-press-icon-small rotate: false - xy: 989, 476 + xy: 1287, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 nomap rotate: false - xy: 1, 760 + xy: 1, 767 size: 256, 256 orig: 256, 256 offset: 0, 0 index: -1 oil-extractor-icon-large rotate: false - xy: 1459, 818 + xy: 1559, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 oil-extractor-icon-medium rotate: false - xy: 743, 616 + xy: 1363, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 oil-extractor-icon-small rotate: false - xy: 1015, 476 + xy: 1313, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 omega-mech-pad-icon-large rotate: false - xy: 1509, 868 + xy: 1509, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 omega-mech-pad-icon-medium rotate: false - xy: 369, 208 + xy: 1397, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 omega-mech-pad-icon-small rotate: false - xy: 1041, 476 + xy: 1339, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 overdrive-projector-icon-large rotate: false - xy: 1559, 918 + xy: 1559, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 overdrive-projector-icon-medium rotate: false - xy: 403, 242 + xy: 1431, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 overdrive-projector-icon-small rotate: false - xy: 1067, 476 + xy: 1365, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 overflow-gate-icon-large rotate: false - xy: 1509, 818 + xy: 1609, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 overflow-gate-icon-medium rotate: false - xy: 437, 276 + xy: 1465, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 overflow-gate-icon-small rotate: false - xy: 1093, 476 + xy: 1391, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 pane rotate: false - xy: 1927, 710 + xy: 339, 667 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -13164,7 +13983,7 @@ pane index: -1 pane-2 rotate: false - xy: 1889, 710 + xy: 301, 638 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -13172,805 +13991,805 @@ pane-2 index: -1 pebbles-icon-large rotate: false - xy: 1559, 868 + xy: 1559, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 pebbles-icon-medium rotate: false - xy: 471, 310 + xy: 1499, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pebbles-icon-small rotate: false - xy: 1119, 476 + xy: 1417, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 phantom-factory-icon-large rotate: false - xy: 1609, 918 + xy: 1609, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 phantom-factory-icon-medium rotate: false - xy: 505, 344 + xy: 1533, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phantom-factory-icon-small rotate: false - xy: 1145, 476 + xy: 1443, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 phase-conduit-icon-large rotate: false - xy: 1559, 818 + xy: 1659, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 phase-conduit-icon-medium rotate: false - xy: 539, 378 + xy: 1567, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit-icon-small rotate: false - xy: 1171, 476 + xy: 1469, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 phase-conveyor-icon-large rotate: false - xy: 1609, 868 + xy: 1609, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 phase-conveyor-icon-medium rotate: false - xy: 573, 412 + xy: 1601, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor-icon-small rotate: false - xy: 1197, 476 + xy: 1495, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 phase-wall-icon-large rotate: false - xy: 1659, 918 + xy: 1659, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 phase-wall-icon-medium rotate: false - xy: 607, 446 + xy: 1635, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall-icon-small rotate: false - xy: 1223, 476 + xy: 1521, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 phase-wall-large-icon-large rotate: false - xy: 1609, 818 + xy: 1709, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 phase-wall-large-icon-medium rotate: false - xy: 641, 480 + xy: 1669, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall-large-icon-small rotate: false - xy: 1249, 476 + xy: 1547, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 phase-weaver-icon-large rotate: false - xy: 1659, 868 + xy: 1659, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 phase-weaver-icon-medium rotate: false - xy: 675, 514 + xy: 1703, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-weaver-icon-small rotate: false - xy: 1275, 476 + xy: 1573, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 pine-icon-large rotate: false - xy: 1709, 918 + xy: 1709, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 pine-icon-medium rotate: false - xy: 709, 548 + xy: 1737, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pine-icon-small rotate: false - xy: 1301, 476 + xy: 1599, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 plastanium-compressor-icon-large rotate: false - xy: 1659, 818 + xy: 1759, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 plastanium-compressor-icon-medium rotate: false - xy: 743, 582 + xy: 1771, 623 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plastanium-compressor-icon-small rotate: false - xy: 1327, 476 + xy: 1625, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 pneumatic-drill-icon-large rotate: false - xy: 1709, 868 + xy: 1709, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 pneumatic-drill-icon-medium rotate: false - xy: 777, 616 + xy: 475, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pneumatic-drill-icon-small rotate: false - xy: 1353, 476 + xy: 1651, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 power-node-icon-large rotate: false - xy: 1759, 918 + xy: 1759, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 power-node-icon-medium rotate: false - xy: 369, 174 + xy: 509, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-node-icon-small rotate: false - xy: 1379, 476 + xy: 1677, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 power-node-large-icon-large rotate: false - xy: 1709, 818 + xy: 1809, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 power-node-large-icon-medium rotate: false - xy: 403, 208 + xy: 543, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-node-large-icon-small rotate: false - xy: 1405, 476 + xy: 1703, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 power-source-icon-large rotate: false - xy: 1759, 868 + xy: 1759, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 power-source-icon-medium rotate: false - xy: 437, 242 + xy: 577, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-source-icon-small rotate: false - xy: 1431, 476 + xy: 1729, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 power-void-icon-large rotate: false - xy: 1809, 918 + xy: 1809, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 power-void-icon-medium rotate: false - xy: 471, 276 + xy: 611, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-void-icon-small rotate: false - xy: 937, 472 + xy: 1755, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 pulse-conduit-icon-large rotate: false - xy: 1759, 818 + xy: 1859, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 pulse-conduit-icon-medium rotate: false - xy: 505, 310 + xy: 645, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-icon-small rotate: false - xy: 1457, 468 + xy: 1783, 531 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 pulverizer-icon-large rotate: false - xy: 1809, 868 + xy: 1809, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 pulverizer-icon-medium rotate: false - xy: 539, 344 + xy: 679, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulverizer-icon-small rotate: false - xy: 1483, 468 + xy: 1781, 505 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 pyratite-mixer-icon-large rotate: false - xy: 1859, 918 + xy: 1859, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 pyratite-mixer-icon-medium rotate: false - xy: 573, 378 + xy: 713, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pyratite-mixer-icon-small rotate: false - xy: 1509, 468 + xy: 768, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 repair-point-icon-large rotate: false - xy: 1809, 818 + xy: 1909, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 repair-point-icon-medium rotate: false - xy: 607, 412 + xy: 747, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 repair-point-icon-small rotate: false - xy: 1535, 468 + xy: 768, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 revenant-factory-icon-large rotate: false - xy: 1859, 868 + xy: 1859, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 revenant-factory-icon-medium rotate: false - xy: 641, 446 + xy: 781, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 revenant-factory-icon-small rotate: false - xy: 1561, 454 + xy: 794, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 ripple-icon-large rotate: false - xy: 1909, 918 + xy: 1909, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 ripple-icon-medium rotate: false - xy: 675, 480 + xy: 815, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ripple-icon-small rotate: false - xy: 963, 450 + xy: 768, 427 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 rock-icon-large rotate: false - xy: 1859, 818 + xy: 1959, 925 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 rock-icon-medium rotate: false - xy: 709, 514 + xy: 849, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rock-icon-small rotate: false - xy: 989, 450 + xy: 794, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 rocks-icon-large rotate: false - xy: 1909, 868 + xy: 1909, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 rocks-icon-medium rotate: false - xy: 743, 548 + xy: 883, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rocks-icon-small rotate: false - xy: 1015, 450 + xy: 820, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 rotary-pump-icon-large rotate: false - xy: 1959, 918 + xy: 1959, 875 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 rotary-pump-icon-medium rotate: false - xy: 777, 582 + xy: 917, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rotary-pump-icon-small rotate: false - xy: 1041, 450 + xy: 768, 401 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 router-icon-large rotate: false - xy: 1909, 818 + xy: 1959, 825 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 router-icon-medium rotate: false - xy: 811, 616 + xy: 951, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 router-icon-small rotate: false - xy: 1067, 450 + xy: 794, 427 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 rtg-generator-icon-large rotate: false - xy: 1959, 868 + xy: 309, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 rtg-generator-icon-medium rotate: false - xy: 369, 140 + xy: 985, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rtg-generator-icon-small rotate: false - xy: 1093, 450 + xy: 820, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 salt-icon-large rotate: false - xy: 1959, 818 + xy: 359, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 salt-icon-medium rotate: false - xy: 403, 174 + xy: 1019, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 salt-icon-small rotate: false - xy: 1119, 450 + xy: 846, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 saltrocks-icon-large rotate: false - xy: 309, 768 + xy: 409, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 saltrocks-icon-medium rotate: false - xy: 437, 208 + xy: 1053, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 saltrocks-icon-small rotate: false - xy: 1145, 450 + xy: 768, 375 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 salvo-icon-large rotate: false - xy: 359, 768 + xy: 459, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 salvo-icon-medium rotate: false - xy: 471, 242 + xy: 1087, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 salvo-icon-small rotate: false - xy: 1171, 450 + xy: 794, 401 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 sand-boulder-icon-large rotate: false - xy: 409, 768 + xy: 509, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 sand-boulder-icon-medium rotate: false - xy: 505, 276 + xy: 1121, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-boulder-icon-small rotate: false - xy: 1197, 450 + xy: 820, 427 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 sand-icon-large rotate: false - xy: 459, 768 + xy: 559, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 sand-icon-medium rotate: false - xy: 539, 310 + xy: 1155, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-icon-small rotate: false - xy: 1223, 450 + xy: 846, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 sand-water-icon-large rotate: false - xy: 509, 768 + xy: 609, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 sand-water-icon-medium rotate: false - xy: 573, 344 + xy: 1189, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-water-icon-small rotate: false - xy: 1249, 450 + xy: 872, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 sandrocks-icon-large rotate: false - xy: 559, 768 + xy: 659, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 sandrocks-icon-medium rotate: false - xy: 607, 378 + xy: 1223, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sandrocks-icon-small rotate: false - xy: 1275, 450 + xy: 794, 375 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 scatter-icon-large rotate: false - xy: 609, 768 + xy: 709, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 scatter-icon-medium rotate: false - xy: 641, 412 + xy: 1257, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scatter-icon-small rotate: false - xy: 1301, 450 + xy: 820, 401 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 scorch-icon-large rotate: false - xy: 659, 768 + xy: 759, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 scorch-icon-medium rotate: false - xy: 675, 446 + xy: 1291, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scorch-icon-small rotate: false - xy: 1327, 450 + xy: 846, 427 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 scrap-wall-gigantic-icon-large rotate: false - xy: 709, 768 + xy: 809, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 scrap-wall-gigantic-icon-medium rotate: false - xy: 709, 480 + xy: 1325, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall-gigantic-icon-small rotate: false - xy: 1353, 450 + xy: 872, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 scrap-wall-huge-icon-large rotate: false - xy: 759, 768 + xy: 859, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 scrap-wall-huge-icon-medium rotate: false - xy: 743, 514 + xy: 1359, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall-huge-icon-small rotate: false - xy: 1379, 450 + xy: 898, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 scrap-wall-icon-large rotate: false - xy: 809, 768 + xy: 909, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 scrap-wall-icon-medium rotate: false - xy: 777, 548 + xy: 1393, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall-icon-small rotate: false - xy: 1405, 450 + xy: 820, 375 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 scrap-wall-large-icon-large rotate: false - xy: 859, 768 + xy: 959, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 scrap-wall-large-icon-medium rotate: false - xy: 811, 582 + xy: 1427, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall-large-icon-small rotate: false - xy: 1431, 450 + xy: 846, 401 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 scroll rotate: false - xy: 1613, 486 + xy: 898, 442 size: 24, 35 split: 10, 10, 6, 5 orig: 24, 35 @@ -13978,7 +14797,7 @@ scroll index: -1 scroll-horizontal rotate: false - xy: 301, 663 + xy: 453, 699 size: 35, 24 split: 6, 5, 10, 10 orig: 35, 24 @@ -13986,7 +14805,7 @@ scroll-horizontal index: -1 scroll-knob-horizontal-black rotate: false - xy: 1737, 742 + xy: 1837, 749 size: 40, 24 split: 11, 10, 10, 10 orig: 40, 24 @@ -13994,7 +14813,7 @@ scroll-knob-horizontal-black index: -1 scroll-knob-vertical-black rotate: false - xy: 1587, 481 + xy: 872, 411 size: 24, 40 split: 10, 10, 6, 10 orig: 24, 40 @@ -14002,952 +14821,952 @@ scroll-knob-vertical-black index: -1 selection rotate: false - xy: 309, 968 + xy: 309, 975 size: 1, 1 orig: 1, 1 offset: 0, 0 index: -1 separator-icon-large rotate: false - xy: 909, 768 + xy: 1009, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 separator-icon-medium rotate: false - xy: 845, 616 + xy: 1461, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 separator-icon-small rotate: false - xy: 1587, 455 + xy: 924, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 shale-boulder-icon-large rotate: false - xy: 959, 768 + xy: 1059, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 shale-boulder-icon-medium rotate: false - xy: 369, 106 + xy: 1495, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale-boulder-icon-small rotate: false - xy: 1613, 460 + xy: 846, 375 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 shale-icon-large rotate: false - xy: 1009, 768 + xy: 1109, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 shale-icon-medium rotate: false - xy: 403, 140 + xy: 1529, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale-icon-small rotate: false - xy: 1639, 482 + xy: 872, 385 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 shalerocks-icon-large rotate: false - xy: 1059, 768 + xy: 1159, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 shalerocks-icon-medium rotate: false - xy: 437, 174 + xy: 1563, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shalerocks-icon-small rotate: false - xy: 1665, 482 + xy: 898, 416 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 shock-mine-icon-large rotate: false - xy: 1109, 768 + xy: 1209, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 shock-mine-icon-medium rotate: false - xy: 471, 208 + xy: 1597, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shock-mine-icon-small rotate: false - xy: 1639, 456 + xy: 924, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 shrubs-icon-large rotate: false - xy: 1159, 768 + xy: 1259, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 shrubs-icon-medium rotate: false - xy: 505, 242 + xy: 1631, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shrubs-icon-small rotate: false - xy: 1665, 456 + xy: 950, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 silicon-smelter-icon-large rotate: false - xy: 1209, 768 + xy: 1309, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 silicon-smelter-icon-medium rotate: false - xy: 539, 276 + xy: 1665, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 silicon-smelter-icon-small rotate: false - xy: 1457, 442 + xy: 898, 390 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 slider rotate: false - xy: 2045, 1008 + xy: 1986, 707 size: 1, 8 orig: 1, 8 offset: 0, 0 index: -1 slider-knob rotate: false - xy: 1459, 546 + xy: 737, 449 size: 29, 38 orig: 29, 38 offset: 0, 0 index: -1 slider-knob-down rotate: false - xy: 1490, 546 + xy: 737, 409 size: 29, 38 orig: 29, 38 offset: 0, 0 index: -1 slider-knob-over rotate: false - xy: 1521, 546 + xy: 737, 369 size: 29, 38 orig: 29, 38 offset: 0, 0 index: -1 slider-vertical rotate: false - xy: 51, 710 + xy: 51, 717 size: 8, 1 orig: 8, 1 offset: 0, 0 index: -1 snow-icon-large rotate: false - xy: 1259, 768 + xy: 1359, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 snow-icon-medium rotate: false - xy: 573, 310 + xy: 1699, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snow-icon-small rotate: false - xy: 1483, 442 + xy: 924, 427 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 snow-pine-icon-large rotate: false - xy: 1309, 768 + xy: 1409, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 snow-pine-icon-medium rotate: false - xy: 607, 344 + xy: 1733, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snow-pine-icon-small rotate: false - xy: 1509, 442 + xy: 950, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 snowrock-icon-large rotate: false - xy: 1359, 768 + xy: 1459, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 snowrock-icon-medium rotate: false - xy: 641, 378 + xy: 1767, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snowrock-icon-small rotate: false - xy: 1535, 442 + xy: 976, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 snowrocks-icon-large rotate: false - xy: 1409, 768 + xy: 1509, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 snowrocks-icon-medium rotate: false - xy: 675, 412 + xy: 471, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snowrocks-icon-small rotate: false - xy: 1561, 428 + xy: 924, 401 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 solar-panel-icon-large rotate: false - xy: 1459, 768 + xy: 1559, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 solar-panel-icon-medium rotate: false - xy: 709, 446 + xy: 471, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel-icon-small rotate: false - xy: 1587, 429 + xy: 950, 427 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 solar-panel-large-icon-large rotate: false - xy: 1509, 768 + xy: 1609, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 solar-panel-large-icon-medium rotate: false - xy: 743, 480 + xy: 505, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel-large-icon-small rotate: false - xy: 1613, 434 + xy: 976, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 sorter-icon-large rotate: false - xy: 1559, 768 + xy: 1659, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 sorter-icon-medium rotate: false - xy: 777, 514 + xy: 471, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sorter-icon-small rotate: false - xy: 1639, 430 + xy: 1002, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 spawn-icon-large rotate: false - xy: 1609, 768 + xy: 1709, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 spawn-icon-medium rotate: false - xy: 811, 548 + xy: 505, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spawn-icon-small rotate: false - xy: 1665, 430 + xy: 950, 401 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 spectre-icon-large rotate: false - xy: 1659, 768 + xy: 1759, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 spectre-icon-medium rotate: false - xy: 845, 582 + xy: 539, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spectre-icon-small rotate: false - xy: 1613, 408 + xy: 976, 427 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 spirit-factory-icon-large rotate: false - xy: 1709, 768 + xy: 1809, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 spirit-factory-icon-medium rotate: false - xy: 879, 616 + xy: 471, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spirit-factory-icon-small rotate: false - xy: 1587, 403 + xy: 1002, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 spore-cluster-icon-large rotate: false - xy: 1759, 768 + xy: 1859, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 spore-cluster-icon-medium rotate: false - xy: 369, 72 + xy: 505, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-cluster-icon-small rotate: false - xy: 1639, 404 + xy: 1028, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 spore-moss-icon-large rotate: false - xy: 1809, 768 + xy: 1909, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 spore-moss-icon-medium rotate: false - xy: 403, 106 + xy: 539, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-moss-icon-small rotate: false - xy: 1665, 404 + xy: 976, 401 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 spore-pine-icon-large rotate: false - xy: 1859, 768 + xy: 1959, 775 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 spore-pine-icon-medium rotate: false - xy: 437, 140 + xy: 573, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-pine-icon-small rotate: false - xy: 1613, 382 + xy: 1002, 427 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 spore-press-icon-large rotate: false - xy: 1909, 768 + xy: 287, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 spore-press-icon-medium rotate: false - xy: 471, 174 + xy: 471, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-press-icon-small rotate: false - xy: 1639, 378 + xy: 1028, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 sporerocks-icon-large rotate: false - xy: 1959, 768 + xy: 337, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 sporerocks-icon-medium rotate: false - xy: 505, 208 + xy: 505, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sporerocks-icon-small rotate: false - xy: 1665, 378 + xy: 1054, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 stone-icon-large rotate: false - xy: 287, 718 + xy: 387, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 stone-icon-medium rotate: false - xy: 539, 242 + xy: 539, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 stone-icon-small rotate: false - xy: 1691, 557 + xy: 1002, 401 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 surge-tower-icon-large rotate: false - xy: 337, 718 + xy: 437, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 surge-tower-icon-medium rotate: false - xy: 573, 276 + xy: 573, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 surge-tower-icon-small rotate: false - xy: 1717, 557 + xy: 1028, 427 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 surge-wall-icon-large rotate: false - xy: 387, 718 + xy: 487, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 surge-wall-icon-medium rotate: false - xy: 607, 310 + xy: 607, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 surge-wall-icon-small rotate: false - xy: 1691, 531 + xy: 1054, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 surge-wall-large-icon-large rotate: false - xy: 437, 718 + xy: 537, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 surge-wall-large-icon-medium rotate: false - xy: 641, 344 + xy: 471, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 surge-wall-large-icon-small rotate: false - xy: 1691, 505 + xy: 1080, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 swarmer-icon-large rotate: false - xy: 487, 718 + xy: 587, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 swarmer-icon-medium rotate: false - xy: 675, 378 + xy: 505, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 swarmer-icon-small rotate: false - xy: 1717, 531 + xy: 1028, 401 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 tainted-water-icon-large rotate: false - xy: 537, 718 + xy: 637, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 tainted-water-icon-medium rotate: false - xy: 709, 412 + xy: 539, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tainted-water-icon-small rotate: false - xy: 1691, 479 + xy: 1054, 427 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 tar-icon-large rotate: false - xy: 587, 718 + xy: 687, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 tar-icon-medium rotate: false - xy: 743, 446 + xy: 573, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tar-icon-small rotate: false - xy: 1717, 505 + xy: 1080, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 tau-mech-pad-icon-large rotate: false - xy: 637, 718 + xy: 737, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 tau-mech-pad-icon-medium rotate: false - xy: 777, 480 + xy: 607, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tau-mech-pad-icon-small rotate: false - xy: 1691, 453 + xy: 1106, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 tendrils-icon-large rotate: false - xy: 687, 718 + xy: 787, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 tendrils-icon-medium rotate: false - xy: 811, 514 + xy: 641, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tendrils-icon-small rotate: false - xy: 1717, 479 + xy: 1054, 401 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 thermal-generator-icon-large rotate: false - xy: 737, 718 + xy: 837, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 thermal-generator-icon-medium rotate: false - xy: 845, 548 + xy: 471, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thermal-generator-icon-small rotate: false - xy: 1691, 427 + xy: 1080, 427 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 thermal-pump-icon-large rotate: false - xy: 787, 718 + xy: 887, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 thermal-pump-icon-medium rotate: false - xy: 879, 582 + xy: 505, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thermal-pump-icon-small rotate: false - xy: 1717, 453 + xy: 1106, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 thorium-reactor-icon-large rotate: false - xy: 837, 718 + xy: 937, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 thorium-reactor-icon-medium rotate: false - xy: 913, 616 + xy: 539, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium-reactor-icon-small rotate: false - xy: 1691, 401 + xy: 1132, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 thorium-wall-icon-large rotate: false - xy: 887, 718 + xy: 987, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 thorium-wall-icon-medium rotate: false - xy: 369, 38 + xy: 573, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium-wall-icon-small rotate: false - xy: 1717, 427 + xy: 1080, 401 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 thorium-wall-large-icon-large rotate: false - xy: 937, 718 + xy: 1037, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 thorium-wall-large-icon-medium rotate: false - xy: 403, 72 + xy: 607, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium-wall-large-icon-small rotate: false - xy: 1717, 401 + xy: 1106, 427 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 thruster-icon-large rotate: false - xy: 987, 718 + xy: 1087, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 thruster-icon-medium rotate: false - xy: 437, 106 + xy: 641, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thruster-icon-small rotate: false - xy: 1691, 375 + xy: 1132, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 titan-factory-icon-large rotate: false - xy: 1037, 718 + xy: 1137, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 titan-factory-icon-medium rotate: false - xy: 471, 140 + xy: 675, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titan-factory-icon-small rotate: false - xy: 1717, 375 + xy: 1158, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 titanium-conveyor-icon-large rotate: false - xy: 1087, 718 + xy: 1187, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 titanium-conveyor-icon-medium rotate: false - xy: 505, 174 + xy: 471, 317 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-icon-small rotate: false - xy: 1743, 554 + xy: 1106, 401 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 titanium-wall-icon-large rotate: false - xy: 1137, 718 + xy: 1237, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 titanium-wall-icon-medium rotate: false - xy: 539, 208 + xy: 505, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-wall-icon-small rotate: false - xy: 1743, 528 + xy: 1132, 427 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 titanium-wall-large-icon-large rotate: false - xy: 1187, 718 + xy: 1287, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 titanium-wall-large-icon-medium rotate: false - xy: 573, 242 + xy: 539, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-wall-large-icon-small rotate: false - xy: 1769, 554 + xy: 1158, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 trident-ship-pad-icon-large rotate: false - xy: 1237, 718 + xy: 1337, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 trident-ship-pad-icon-medium rotate: false - xy: 607, 276 + xy: 573, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 trident-ship-pad-icon-small rotate: false - xy: 1743, 502 + xy: 1184, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 turbine-generator-icon-large rotate: false - xy: 1287, 718 + xy: 1387, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 turbine-generator-icon-medium rotate: false - xy: 641, 310 + xy: 607, 453 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 turbine-generator-icon-small rotate: false - xy: 1769, 528 + xy: 1132, 401 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 underline rotate: false - xy: 339, 689 + xy: 377, 667 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -14955,7 +15774,7 @@ underline index: -1 underline-2 rotate: false - xy: 1965, 710 + xy: 415, 696 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -14963,7 +15782,7 @@ underline-2 index: -1 underline-disabled rotate: false - xy: 2003, 707 + xy: 301, 609 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -14971,7 +15790,7 @@ underline-disabled index: -1 underline-red rotate: false - xy: 301, 689 + xy: 339, 638 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -14979,183 +15798,183 @@ underline-red index: -1 unloader-icon-large rotate: false - xy: 1337, 718 + xy: 1437, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 unloader-icon-medium rotate: false - xy: 675, 344 + xy: 641, 487 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unloader-icon-small rotate: false - xy: 1795, 554 + xy: 1158, 427 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 vault-icon-large rotate: false - xy: 1387, 718 + xy: 1487, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 vault-icon-medium rotate: false - xy: 709, 378 + xy: 675, 521 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 vault-icon-small rotate: false - xy: 1743, 476 + xy: 1184, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 water-extractor-icon-large rotate: false - xy: 1437, 718 + xy: 1537, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 water-extractor-icon-medium rotate: false - xy: 743, 412 + xy: 709, 555 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 water-extractor-icon-small rotate: false - xy: 1769, 502 + xy: 1210, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 water-icon-large rotate: false - xy: 1487, 718 + xy: 1587, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 water-icon-medium rotate: false - xy: 777, 446 + xy: 471, 283 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 water-icon-small rotate: false - xy: 1795, 528 + xy: 1158, 401 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 wave-icon-large rotate: false - xy: 1537, 718 + xy: 1637, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 wave-icon-medium rotate: false - xy: 811, 480 + xy: 505, 317 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 wave-icon-small rotate: false - xy: 1821, 554 + xy: 1184, 427 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 white-tree-dead-icon-large rotate: false - xy: 1587, 718 + xy: 1687, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 white-tree-dead-icon-medium rotate: false - xy: 845, 514 + xy: 539, 351 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 white-tree-dead-icon-small rotate: false - xy: 1743, 450 + xy: 1210, 453 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 white-tree-icon-large rotate: false - xy: 1637, 718 + xy: 1737, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 white-tree-icon-medium rotate: false - xy: 879, 548 + xy: 573, 385 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 white-tree-icon-small rotate: false - xy: 1769, 476 + xy: 1236, 479 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 whiteui rotate: false - xy: 372, 684 + xy: 1816, 720 size: 3, 3 orig: 3, 3 offset: 0, 0 index: -1 window-empty rotate: false - xy: 1610, 523 + xy: 567, 146 size: 27, 61 - split: 8, 8, 44, 11 + split: 4, 4, 2, 2 orig: 27, 61 offset: 0, 0 index: -1 wraith-factory-icon-large rotate: false - xy: 1687, 718 + xy: 1787, 725 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 wraith-factory-icon-medium rotate: false - xy: 913, 582 + xy: 607, 419 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 wraith-factory-icon-small rotate: false - xy: 1795, 502 + xy: 1184, 401 size: 24, 24 orig: 24, 24 offset: 0, 0 diff --git a/core/assets/sprites/sprites.png b/core/assets/sprites/sprites.png index 4d22a79c42..e5e1823e00 100644 Binary files a/core/assets/sprites/sprites.png and b/core/assets/sprites/sprites.png differ diff --git a/core/assets/sprites/sprites2.png b/core/assets/sprites/sprites2.png index 305ed3765f..4c744e487e 100644 Binary files a/core/assets/sprites/sprites2.png and b/core/assets/sprites/sprites2.png differ diff --git a/core/assets/sprites/sprites5.png b/core/assets/sprites/sprites5.png index 15c16ea0ae..669ccc9965 100644 Binary files a/core/assets/sprites/sprites5.png and b/core/assets/sprites/sprites5.png differ diff --git a/core/assets/sprites/uiskin.json b/core/assets/sprites/uiskin.json deleted file mode 100644 index b929cf8457..0000000000 --- a/core/assets/sprites/uiskin.json +++ /dev/null @@ -1,367 +0,0 @@ -{ - Color: { - black: { a: 1, b: 0, g: 0, r: 0 }, - white: { a: 1, b: 1, g: 1, r: 1 }, - gray: { a: 1, b: 0.32, g: 0.32, r: 0.32 }, - lightgray: { a: 1, b: 0.65, g: 0.65, r: 0.65 } - orange: { hex: "FFA500" }, - accent: { hex: "ffd37f" } - }, - TintedDrawable: { - dialogDim: { - name: whiteui, - color: { r: 0, g: 0, b: 0, a: 0.9 } - }, - guideDim: { - name: whiteui, - color: { r: 0, g: 0, b: 0, a: 0.3 } - }, - invis: { - name: whiteui, - color: { r: 0, g: 0, b: 0, a: 0 } - } - loadDim: { - name: white, - color: { r: 0, g: 0, b: 0, a: 0.8 } - }, - chatfield: { - name: whiteui, - color: { r: 0, g: 0, b: 0, a: 0.2 } - }, - dark: { - name: whiteui, - color: { hex: "#000000ff" } - }, - none: { - name: whiteui, - color: { r: 0, g: 0, b: 0, a: 0 } - }, - flat-trans: { - name: whiteui, - color: { r: 0.0, g: 0.0, b: 0.0, a: 0.6 } - }, - flat: { - name: whiteui, - color: { r: 0.0, g: 0.0, b: 0.0, a: 1 } - }, - flat-over: { - name: whiteui, - color: { hex: "#454545ff" } - } - }, - ButtonStyle: { - default: { - down: button-down, - up: button, - over: button-over, - disabled: button-disabled - }, - square: { - over: button-square-over, - disabled: button-disabled, - down: button-square-down, - up: button-square - }, - toggle: { - checked: button-down, - down: button-down, - up: button - }, - wave: { - up: button-edge-4, - over: button-edge-over-4, - disabled: button-edge-4 - }, - }, - TextButtonStyle: { - default: { - over: button-over, - disabled: button-disabled, - font: default, - fontColor: white, - disabledFontColor: gray, - down: button-down, - up: button - }, - square: { - font: default, - fontColor: white, - disabledFontColor: gray, - over: button-square-over, - disabled: button-disabled, - down: button-square-down, - up: button-square - }, - node: { - disabled: button, - font: default, - fontColor: white, - disabledFontColor: gray, - up: button-over, - over: button-down - }, - right: { - over: button-right-over, - font: default, - fontColor: white, - disabledFontColor: gray, - down: button-right-down, - up: button-right - }, - wave: { - font: default, - fontColor: white, - disabledFontColor: gray, - up: button-edge-4 - }, - clear: { - over: flat-over, - font: default, - fontColor: white, - disabledFontColor: gray, - down: flat-over, - up: flat - }, - discord: { - font: default, - fontColor: white, - up: discord-banner - }, - info: { - font: default, - fontColor: white, - up: info-banner - }, - clear-partial: { - down: whiteui, - up: pane, - over: flat-down, - font: default, - fontColor: white, - disabledFontColor: gray - }, - clear-partial-2: { - down: flat-over, - up: none, - over: flat-over, - font: default, - fontColor: white, - disabledFontColor: gray - }, - empty: { - font: default - }, - clear-toggle: { - font: default, - fontColor: white, - checked: flat-down, - down: flat-down, - up: flat, - over: flat-over, - disabled: flat, - disabledFontColor: gray - }, - clear-toggle-menu: { - font: default, - fontColor: white, - checked: flat-down, - down: flat-down, - up: clear, - over: flat-over, - disabled: flat, - disabledFontColor: gray - } - toggle: { - font: default, - fontColor: white, - checked: button-down, - down: button-down, - up: button, - over: button-over, - disabled: button-disabled, - disabledFontColor: gray - } - }, - ImageButtonStyle: { - default: { - down: button-down, - up: button, - over: button-over, - imageDisabledColor: gray, - imageUpColor: white, - disabled: button-disabled - }, - node: { - up: button-over, - over: button-down - }, - right: { - over: button-right-over, - down: button-right-down, - up: button-right - }, - empty: { - imageDownColor: accent, - imageUpColor: white - }, - emptytoggle: { - imageCheckedColor: white, - imageDownColor: white, - imageUpColor: gray - }, - static: { - up: button - }, - static-down: { - up: button-down - }, - toggle: { - checked: button-down, - down: button-down, - up: button, - imageDisabledColor: gray, - imageUpColor: white - }, - select: { - checked: button-select, - up: none - }, - clear: { - down: flat-over, - up: flat, - over: flat-over - }, - clear-full: { - down: whiteui, - up: pane, - over: flat-down - }, - clear-partial: { - down: flat-down, - up: none, - over: flat-over - }, - clear-toggle: { - down: flat-down, - checked: flat-down, - up: flat, - over: flat-over - }, - clear-trans: { - down: flat-down, - up: flat-trans, - over: flat-over - }, - clear-toggle-trans: { - down: flat-down, - checked: flat-down, - up: flat-trans, - over: flat-over - }, - clear-toggle-partial: { - down: flat-down, - checked: flat-down, - up: none, - over: flat-over - }, - }, - ScrollPaneStyle: { - default: { - vScroll: scroll, - vScrollKnob: scroll-knob-vertical-black - }, - horizontal: { - vScroll: scroll, - vScrollKnob: scroll-knob-vertical-black, - hScroll: scroll-horizontal, - hScrollKnob: scroll-knob-horizontal-black - }, - }, - WindowStyle: { - default: { - titleFont: default, - titleFontColor: accent - }, - dialog: { - stageBackground: dialogDim, - titleFont: default, - background: window-empty, - titleFontColor: accent - }, - fulldialog: { - stageBackground: dark, - titleFont: default, - background: window-empty, - titleFontColor: accent - } - }, - KeybindDialogStyle: { - default: { - keyColor: accent, - keyNameColor: white, - controllerColor: lightgray - }, - }, - SliderStyle: { - default-horizontal: { - background: slider, - knob: slider-knob, - knobOver: slider-knob-over, - knobDown: slider-knob-down - }, - default-vertical: { - background: slider-vertical, - knob: slider-knob, - knobOver: slider-knob-over, - knobDown: slider-knob-down - } - }, - LabelStyle: { - default: { - font: default, - fontColor: white - }, - outline: { - font: outline, - fontColor: white - } - }, - TextFieldStyle: { - default: { - font: chat, - fontColor: white, - disabledFontColor: gray, - disabledBackground: underline-disabled, - selection: selection, - background: underline, - invalidBackground: underline-red, - cursor: cursor, - messageFont: default, - messageFontColor: gray - } - textarea: { - font: chat, - fontColor: white, - disabledFontColor: gray, - selection: selection, - background: underline, - cursor: cursor, - messageFont: default, - messageFontColor: gray - } - }, - CheckBoxStyle: { - default: { - checkboxOn: check-on, - checkboxOff: check-off, - checkboxOnOver: check-on-over, - checkboxOver: check-over, - checkboxOnDisabled: check-on-disabled, - checkboxOffDisabled: check-disabled, - font: default, - fontColor: white, - disabledFontColor: gray, - - } - } -} diff --git a/core/src/io/anuke/mindustry/ClientLauncher.java b/core/src/io/anuke/mindustry/ClientLauncher.java index 39a605f507..e63fc9ac01 100644 --- a/core/src/io/anuke/mindustry/ClientLauncher.java +++ b/core/src/io/anuke/mindustry/ClientLauncher.java @@ -13,6 +13,7 @@ import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.maps.*; +import io.anuke.mindustry.net.Net; import static io.anuke.arc.Core.*; import static io.anuke.mindustry.Vars.*; @@ -40,6 +41,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform assets = new AssetManager(); assets.setLoader(Texture.class, "." + mapExtension, new MapPreviewLoader()); atlas = TextureAtlas.blankAtlas(); + Vars.net = new Net(platform.getNet()); UI.loadSystemCursors(); @@ -47,7 +49,9 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform UI.loadDefaultFont(); - assets.load(new AssetDescriptor<>("sprites/sprites.atlas", TextureAtlas.class)).loaded = t -> atlas = (TextureAtlas)t; + assets.load(new AssetDescriptor<>("sprites/sprites.atlas", TextureAtlas.class)).loaded = t -> { + atlas = (TextureAtlas)t; + }; assets.loadRun("maps", Map.class, () -> maps.loadPreviews()); @@ -84,10 +88,12 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform @Override public void resize(int width, int height){ - super.resize(width, height); + if(assets == null) return; if(!assets.isFinished()){ Draw.proj().setOrtho(0, 0, width, height); + }else{ + super.resize(width, height); } } @@ -100,6 +106,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform for(ApplicationListener listener : modules){ listener.init(); } + super.resize(graphics.getWidth(), graphics.getHeight()); finished = true; Events.fire(new ClientLoadEvent()); } @@ -149,15 +156,15 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform Core.graphics.clear(Pal.darkerGray); Draw.proj().setOrtho(0, 0, Core.graphics.getWidth(), Core.graphics.getHeight()); - float height = UnitScl.dp.scl(50f); + float height = Scl.scl(50f); - Draw.color(Color.BLACK); + Draw.color(Color.black); Fill.poly(graphics.getWidth()/2f, graphics.getHeight()/2f, 6, Mathf.dst(graphics.getWidth()/2f, graphics.getHeight()/2f) * smoothProgress); Draw.reset(); float w = graphics.getWidth()*0.6f; - Draw.color(Color.BLACK); + Draw.color(Color.black); Fill.rect(graphics.getWidth()/2f, graphics.getHeight()/2f, w, height); Draw.color(Pal.accent); @@ -169,13 +176,13 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform if(assets.isLoaded("outline")){ BitmapFont font = assets.get("outline"); - font.draw((int)(assets.getProgress() * 100) + "%", graphics.getWidth() / 2f, graphics.getHeight() / 2f + UnitScl.dp.scl(10f), Align.center); - font.draw(bundle.get("loading", "").replace("[accent]", ""), graphics.getWidth() / 2f, graphics.getHeight() / 2f + height / 2f + UnitScl.dp.scl(20), Align.center); + font.draw((int)(assets.getProgress() * 100) + "%", graphics.getWidth() / 2f, graphics.getHeight() / 2f + Scl.scl(10f), Align.center); + font.draw(bundle.get("loading", "").replace("[accent]", ""), graphics.getWidth() / 2f, graphics.getHeight() / 2f + height / 2f + Scl.scl(20), Align.center); if(assets.getCurrentLoading() != null){ String name = assets.getCurrentLoading().fileName.toLowerCase(); String key = name.contains("content") ? "content" : name.contains("msav") || name.contains("maps") ? "map" : name.contains("ogg") || name.contains("mp3") ? "sound" : name.contains("png") ? "image" : "system"; - font.draw(bundle.get("load." + key, ""), graphics.getWidth() / 2f, graphics.getHeight() / 2f - height / 2f - UnitScl.dp.scl(10f), Align.center); + font.draw(bundle.get("load." + key, ""), graphics.getWidth() / 2f, graphics.getHeight() / 2f - height / 2f - Scl.scl(10f), Align.center); } } Draw.flush(); diff --git a/core/src/io/anuke/mindustry/Vars.java b/core/src/io/anuke/mindustry/Vars.java index ad684bc223..99a0f31a56 100644 --- a/core/src/io/anuke/mindustry/Vars.java +++ b/core/src/io/anuke/mindustry/Vars.java @@ -3,6 +3,7 @@ package io.anuke.mindustry; import io.anuke.arc.Application.*; import io.anuke.arc.*; import io.anuke.arc.assets.*; +import io.anuke.arc.collection.*; import io.anuke.arc.files.*; import io.anuke.arc.graphics.*; import io.anuke.arc.scene.ui.layout.*; @@ -10,11 +11,11 @@ import io.anuke.arc.util.*; import io.anuke.mindustry.ai.*; import io.anuke.mindustry.core.*; import io.anuke.mindustry.entities.*; -import io.anuke.mindustry.entities.bullet.*; import io.anuke.mindustry.entities.effect.*; -import io.anuke.mindustry.entities.impl.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.entities.type.Bullet; +import io.anuke.mindustry.entities.type.EffectEntity; import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.input.*; @@ -43,6 +44,8 @@ public class Vars implements Loadable{ public static final String discordURL = "https://discord.gg/mindustry"; /** URL for sending crash reports to */ public static final String crashReportURL = "http://mins.us.to/report"; + /** list of built-in servers.*/ + public static final Array defaultServers = Array.with(/*"mins.us.to"*/); /** maximum distance between mine and core that supports automatic transferring */ public static final float mineTransferRange = 220f; /** team of the player by default */ @@ -59,14 +62,6 @@ public class Vars implements Loadable{ public static final float itemSize = 5f; /** extra padding around the world; units outside this bound will begin to self-destruct. */ public static final float worldBounds = 100f; - /** default size of UI icons.*/ - public static final int iconsize = 48; - /** size of UI icons (small)*/ - public static final int iconsizesmall = 32; - /** size of UI icons (medium)*/ - public static final int iconsizemed = 30; - /** size of UI icons (medium)*/ - public static final int iconsizetiny = 16; /** units outside of this bound will simply die instantly */ public static final float finalWorldBounds = worldBounds + 500; /** ticks spent out of bound until self destruct. */ @@ -112,6 +107,8 @@ public class Vars implements Loadable{ public static boolean android; /** whether the game is running on a headless server */ public static boolean headless; + /** whether steam is enabled for this game */ + public static boolean steam; /** application data directory, equivalent to {@link io.anuke.arc.Settings#getDataDirectory()} */ public static FileHandle dataDirectory; /** data subdirectory used for screenshots */ @@ -136,6 +133,7 @@ public class Vars implements Loadable{ /** list of all locales that can be switched to */ public static Locale[] locales; + public static Net net; public static ContentLoader content; public static GameState state; public static GlobalData data; @@ -168,7 +166,6 @@ public class Vars implements Loadable{ public static EntityGroup fireGroup; public static EntityGroup[] unitGroups; - /** all local players, currently only has one player. may be used for local co-op in the future */ public static Player player; @Override @@ -226,7 +223,7 @@ public class Vars implements Loadable{ for(EntityGroup group : entities.all()){ group.setRemoveListener(entity -> { - if(entity instanceof SyncTrait && Net.client()){ + if(entity instanceof SyncTrait && net.client()){ netClient.addRemovedEntity((entity).getID()); } }); @@ -252,11 +249,16 @@ public class Vars implements Loadable{ public static void loadSettings(){ Core.settings.setAppName(appName); + + if(steam){ + Core.settings.setDataDirectory(Core.files.local("saves/")); + } + Core.settings.defaults("locale", "default"); Core.keybinds.setDefaults(Binding.values()); Core.settings.load(); - UnitScl.dp.setProduct(settings.getInt("uiscale", 100) / 100f); + Scl.setProduct(settings.getInt("uiscale", 100) / 100f); if(!loadLocales) return; @@ -268,6 +270,7 @@ public class Vars implements Loadable{ Core.bundle = I18NBundle.createBundle(handle, locale); Log.info("NOTE: external translation bundle has been loaded."); + if(!headless){ Time.run(10f, () -> ui.showInfo("Note: You have successfully loaded an external translation bundle.")); } diff --git a/core/src/io/anuke/mindustry/ai/BlockIndexer.java b/core/src/io/anuke/mindustry/ai/BlockIndexer.java index a31b2bbf8a..a9e575f35d 100644 --- a/core/src/io/anuke/mindustry/ai/BlockIndexer.java +++ b/core/src/io/anuke/mindustry/ai/BlockIndexer.java @@ -242,14 +242,13 @@ public class BlockIndexer{ int quadrantY = tile.y / quadrantSize; itemSet.clear(); - Tile rounded = world.tile(Mathf.clamp(quadrantX * quadrantSize + quadrantSize / 2, 0, world.width() - 1), - Mathf.clamp(quadrantY * quadrantSize + quadrantSize / 2, 0, world.height() - 1)); + Tile rounded = world.tile(Mathf.clamp(quadrantX * quadrantSize + quadrantSize / 2, 0, world.width() - 1), Mathf.clamp(quadrantY * quadrantSize + quadrantSize / 2, 0, world.height() - 1)); //find all items that this quadrant contains - for(int x = quadrantX * quadrantSize; x < world.width() && x < (quadrantX + 1) * quadrantSize; x++){ - for(int y = quadrantY * quadrantSize; y < world.height() && y < (quadrantY + 1) * quadrantSize; y++){ + for(int x = Math.max(0, rounded.x - quadrantSize / 2); x < rounded.x + quadrantSize / 2 && x < world.width(); x++){ + for(int y = Math.max(0, rounded.y - quadrantSize / 2); y < rounded.y + quadrantSize / 2 && y < world.height(); y++){ Tile result = world.tile(x, y); - if(result == null || result.drop() == null || !scanOres.contains(result.drop())) continue; + if(result == null || result.drop() == null || !scanOres.contains(result.drop()) || result.block() != Blocks.air) continue; itemSet.add(result.drop()); } diff --git a/core/src/io/anuke/mindustry/ai/Pathfinder.java b/core/src/io/anuke/mindustry/ai/Pathfinder.java index 27e74e11be..9df0c432c8 100644 --- a/core/src/io/anuke/mindustry/ai/Pathfinder.java +++ b/core/src/io/anuke/mindustry/ai/Pathfinder.java @@ -5,8 +5,7 @@ import io.anuke.arc.collection.IntArray; import io.anuke.arc.collection.IntQueue; import io.anuke.arc.math.geom.Geometry; import io.anuke.arc.math.geom.Point2; -import io.anuke.arc.util.Structs; -import io.anuke.arc.util.Time; +import io.anuke.arc.util.*; import io.anuke.mindustry.game.EventType.TileChangeEvent; import io.anuke.mindustry.game.EventType.WorldLoadEvent; import io.anuke.mindustry.game.Team; @@ -26,7 +25,7 @@ public class Pathfinder{ public Pathfinder(){ Events.on(WorldLoadEvent.class, event -> clear()); Events.on(TileChangeEvent.class, event -> { - if(Net.client()) return; + if(net.client()) return; for(Team team : Team.all){ TeamData data = state.teams.get(team); @@ -44,7 +43,7 @@ public class Pathfinder{ } public void update(){ - if(Net.client() || paths == null) return; + if(net.client() || paths == null) return; for(Team team : Team.all){ if(state.teams.isActive(team)){ @@ -86,7 +85,7 @@ public class Pathfinder{ } private boolean passable(Tile tile, Team team){ - return (!tile.solid()) || (tile.breakable() && (tile.getTeam() != team)); + return ((!tile.solid()) || (tile.breakable() && (tile.getTeam() != team))) && tile.floor().drownTime <= 0f; } /** diff --git a/core/src/io/anuke/mindustry/ai/WaveSpawner.java b/core/src/io/anuke/mindustry/ai/WaveSpawner.java index 5863594f4f..daf4e7b00a 100644 --- a/core/src/io/anuke/mindustry/ai/WaveSpawner.java +++ b/core/src/io/anuke/mindustry/ai/WaveSpawner.java @@ -14,7 +14,6 @@ import io.anuke.mindustry.entities.Effects; import io.anuke.mindustry.entities.type.BaseUnit; import io.anuke.mindustry.game.EventType.WorldLoadEvent; import io.anuke.mindustry.game.SpawnGroup; -import io.anuke.mindustry.net.Net; import io.anuke.mindustry.world.Tile; import static io.anuke.mindustry.Vars.*; @@ -116,7 +115,7 @@ public class WaveSpawner{ } public boolean isSpawning(){ - return spawning && !Net.client(); + return spawning && !net.client(); } private void reset(){ diff --git a/core/src/io/anuke/mindustry/content/Blocks.java b/core/src/io/anuke/mindustry/content/Blocks.java index c5784aeeab..93637d966d 100644 --- a/core/src/io/anuke/mindustry/content/Blocks.java +++ b/core/src/io/anuke/mindustry/content/Blocks.java @@ -8,6 +8,7 @@ import io.anuke.arc.util.*; import io.anuke.mindustry.*; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.bullet.*; +import io.anuke.mindustry.entities.type.Bullet; import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; @@ -500,6 +501,7 @@ public class Blocks implements ContentList{ consumes.items(new ItemStack(Items.thorium, 4), new ItemStack(Items.sand, 10)); consumes.power(5f); + itemCapacity = 20; int bottomRegion = reg("-bottom"), weaveRegion = reg("-weave"); @@ -589,7 +591,7 @@ public class Blocks implements ContentList{ pyratiteMixer = new GenericSmelter("pyratite-mixer"){{ requirements(Category.crafting, ItemStack.with(Items.copper, 50, Items.lead, 25)); - flameColor = Color.CLEAR; + flameColor = Color.clear; hasItems = true; hasPower = true; outputItem = new ItemStack(Items.pyratite, 1); @@ -660,7 +662,7 @@ public class Blocks implements ContentList{ Draw.rect(region, tile.drawx(), tile.drawy()); Draw.rect(reg(frameRegions[(int)Mathf.absin(entity.totalProgress, 5f, 2.999f)]), tile.drawx(), tile.drawy()); - Draw.color(Color.CLEAR, tile.entity.liquids.current().color, tile.entity.liquids.total() / liquidCapacity); + Draw.color(Color.clear, tile.entity.liquids.current().color, tile.entity.liquids.total() / liquidCapacity); Draw.rect(reg(liquidRegion), tile.drawx(), tile.drawy()); Draw.color(); Draw.rect(reg(topRegion), tile.drawx(), tile.drawy()); @@ -982,7 +984,6 @@ public class Blocks implements ContentList{ pulseConduit = new Conduit("pulse-conduit"){{ requirements(Category.liquid, ItemStack.with(Items.titanium, 1, Items.metaglass, 1)); liquidCapacity = 16f; - liquidFlowFactor = 4.9f; health = 90; }}; @@ -1397,7 +1398,7 @@ public class Blocks implements ContentList{ smokeEffect = Fx.lancerLaserShootSmoke; chargeEffect = Fx.lancerLaserCharge; chargeBeginEffect = Fx.lancerLaserChargeBegin; - heatColor = Color.RED; + heatColor = Color.red; size = 2; health = 280 * size * size; targetAir = false; @@ -1405,16 +1406,16 @@ public class Blocks implements ContentList{ }}; arc = new PowerTurret("arc"){{ - requirements(Category.turret, ItemStack.with(Items.copper, 35, Items.lead, 35)); + requirements(Category.turret, ItemStack.with(Items.copper, 35, Items.lead, 50)); shootType = Bullets.arc; - reload = 24f; + reload = 35f; shootCone = 40f; rotatespeed = 8f; - powerUse = 0.9f; + powerUse = 1.5f; targetAir = false; - range = 95f; + range = 90f; shootEffect = Fx.lightningShoot; - heatColor = Color.RED; + heatColor = Color.red; recoil = 1f; size = 1; health = 260; @@ -1493,7 +1494,7 @@ public class Blocks implements ContentList{ } @Override - public void init(Bullet b){ + public void init(io.anuke.mindustry.entities.type.Bullet b){ for(int i = 0; i < rays; i++){ Damage.collideLine(b, b.getTeam(), hitEffect, b.x, b.y, b.rot(), rayLength - Math.abs(i - (rays / 2)) * 20f); } @@ -1502,7 +1503,7 @@ public class Blocks implements ContentList{ @Override public void draw(Bullet b){ super.draw(b); - Draw.color(Color.WHITE, Pal.lancerLaser, b.fin()); + Draw.color(Color.white, Pal.lancerLaser, b.fin()); //Draw.alpha(b.fout()); for(int i = 0; i < 7; i++){ Tmp.v1.trns(b.rot(), i * 8f); @@ -1775,4 +1776,4 @@ public class Blocks implements ContentList{ //endregion } -} \ No newline at end of file +} diff --git a/core/src/io/anuke/mindustry/content/Bullets.java b/core/src/io/anuke/mindustry/content/Bullets.java index c0b2ad732c..dad4758000 100644 --- a/core/src/io/anuke/mindustry/content/Bullets.java +++ b/core/src/io/anuke/mindustry/content/Bullets.java @@ -7,12 +7,14 @@ import io.anuke.arc.util.*; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.bullet.*; import io.anuke.mindustry.entities.effect.*; +import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.entities.type.Bullet; import io.anuke.mindustry.game.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.blocks.*; -import static io.anuke.mindustry.Vars.world; +import static io.anuke.mindustry.Vars.*; public class Bullets implements ContentList{ public static BulletType @@ -249,7 +251,7 @@ public class Bullets implements ContentList{ splashDamageRadius = 25f; splashDamage = 10f; lifetime = 120f; - trailColor = Color.GRAY; + trailColor = Color.gray; backColor = Pal.bulletYellowBack; frontColor = Pal.bulletYellow; hitEffect = Fx.blastExplosion; @@ -395,7 +397,7 @@ public class Bullets implements ContentList{ Draw.color(Pal.heal); Lines.stroke(2f); Lines.lineAngleCenter(b.x, b.y, b.rot(), 7f); - Draw.color(Color.WHITE); + Draw.color(Color.white); Lines.lineAngleCenter(b.x, b.y, b.rot(), 3f); Draw.reset(); } @@ -429,7 +431,7 @@ public class Bullets implements ContentList{ @Override public void draw(Bullet b){ - Draw.color(Pal.lightFlame, Pal.darkFlame, Color.GRAY, b.fin()); + Draw.color(Pal.lightFlame, Pal.darkFlame, Color.gray, b.fin()); Fill.circle(b.x, b.y, 3f * b.fout()); Draw.reset(); } @@ -497,7 +499,7 @@ public class Bullets implements ContentList{ }; lancerLaser = new BulletType(0.001f, 140){ - Color[] colors = {Pal.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Pal.lancerLaser, Color.WHITE}; + Color[] colors = {Pal.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Pal.lancerLaser, Color.white}; float[] tscales = {1f, 0.7f, 0.5f, 0.2f}; float[] lenscales = {1f, 1.1f, 1.13f, 1.14f}; float length = 160f; @@ -539,7 +541,7 @@ public class Bullets implements ContentList{ meltdownLaser = new BulletType(0.001f, 70){ Color tmpColor = new Color(); - Color[] colors = {Color.valueOf("ec745855"), Color.valueOf("ec7458aa"), Color.valueOf("ff9c5a"), Color.WHITE}; + Color[] colors = {Color.valueOf("ec745855"), Color.valueOf("ec7458aa"), Color.valueOf("ff9c5a"), Color.white}; float[] tscales = {1f, 0.7f, 0.5f, 0.2f}; float[] strokes = {2f, 1.5f, 1f, 0.3f}; float[] lenscales = {1f, 1.12f, 1.15f, 1.17f}; @@ -631,11 +633,11 @@ public class Bullets implements ContentList{ @Override public void init(Bullet b){ - Lightning.create(b.getTeam(), Pal.lancerLaser, damage, b.x, b.y, b.rot(), 30); + Lightning.create(b.getTeam(), Pal.lancerLaser, damage * (b.getOwner() instanceof Player ? state.rules.playerDamageMultiplier : 1f), b.x, b.y, b.rot(), 30); } }; - arc = new BulletType(0.001f, 25){ + arc = new BulletType(0.001f, 21){ { lifetime = 1; despawnEffect = Fx.none; @@ -687,7 +689,7 @@ public class Bullets implements ContentList{ bulletHeight = 12f; hitEffect = Fx.pulverize; backColor = new Color(0x4f4f4fff); - frontColor = Color.GRAY; + frontColor = Color.gray; } @Override diff --git a/core/src/io/anuke/mindustry/content/Fx.java b/core/src/io/anuke/mindustry/content/Fx.java index e6cd3b6236..a507f62261 100644 --- a/core/src/io/anuke/mindustry/content/Fx.java +++ b/core/src/io/anuke/mindustry/content/Fx.java @@ -1,19 +1,17 @@ package io.anuke.mindustry.content; -import io.anuke.arc.Core; -import io.anuke.arc.graphics.Color; +import io.anuke.arc.*; +import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.g2d.*; -import io.anuke.arc.math.Angles; -import io.anuke.arc.math.Mathf; -import io.anuke.arc.util.Tmp; -import io.anuke.mindustry.entities.Effects.Effect; -import io.anuke.mindustry.entities.effect.GroundEffectEntity.GroundEffect; -import io.anuke.mindustry.entities.type.BaseUnit; -import io.anuke.mindustry.game.ContentList; -import io.anuke.mindustry.graphics.Pal; -import io.anuke.mindustry.graphics.Drawf; -import io.anuke.mindustry.type.Item; -import io.anuke.mindustry.type.Item.Icon; +import io.anuke.arc.math.*; +import io.anuke.arc.util.*; +import io.anuke.mindustry.entities.Effects.*; +import io.anuke.mindustry.entities.effect.GroundEffectEntity.*; +import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.game.*; +import io.anuke.mindustry.graphics.*; +import io.anuke.mindustry.type.*; +import io.anuke.mindustry.type.Item.*; import static io.anuke.mindustry.Vars.tilesize; @@ -32,7 +30,7 @@ public class Fx implements ContentList{ bigShockwave, nuclearShockwave, explosion, blockExplosion, blockExplosionSmoke, shootSmall, shootHeal, shootSmallSmoke, shootBig, shootBig2, shootBigSmoke, shootBigSmoke2, shootSmallFlame, shootPyraFlame, shootLiquid, shellEjectSmall, shellEjectMedium, shellEjectBig, lancerLaserShoot, lancerLaserShootSmoke, lancerLaserCharge, lancerLaserChargeBegin, lightningCharge, lightningShoot, - unitSpawn, spawnShockwave, magmasmoke, impactShockwave, impactcloud, impactsmoke, dynamicExplosion, padlaunch, commandSend; + unitSpawn, spawnShockwave, magmasmoke, impactShockwave, impactcloud, impactsmoke, dynamicExplosion, padlaunch, commandSend, coreLand; @Override public void load(){ @@ -93,14 +91,14 @@ public class Fx implements ContentList{ }); smoke = new Effect(100, e -> { - Draw.color(Color.GRAY, Pal.darkishGray, e.fin()); + Draw.color(Color.gray, Pal.darkishGray, e.fin()); float size = 7f - e.fin() * 7f; Draw.rect("circle", e.x, e.y, size, size); Draw.reset(); }); magmasmoke = new Effect(110, e -> { - Draw.color(Color.GRAY); + Draw.color(Color.gray); Fill.circle(e.x, e.y, e.fslope() * 6f); Draw.reset(); }); @@ -180,7 +178,7 @@ public class Fx implements ContentList{ hitBulletSmall = new Effect(14, e -> { - Draw.color(Color.WHITE, Pal.lightOrange, e.fin()); + Draw.color(Color.white, Pal.lightOrange, e.fin()); e.scaled(7f, s -> { Lines.stroke(0.5f + s.fout()); @@ -199,7 +197,7 @@ public class Fx implements ContentList{ }); hitFuse = new Effect(14, e -> { - Draw.color(Color.WHITE, Pal.surge, e.fin()); + Draw.color(Color.white, Pal.surge, e.fin()); e.scaled(7f, s -> { Lines.stroke(0.5f + s.fout()); @@ -218,7 +216,7 @@ public class Fx implements ContentList{ }); hitBulletBig = new Effect(13, e -> { - Draw.color(Color.WHITE, Pal.lightOrange, e.fin()); + Draw.color(Color.white, Pal.lightOrange, e.fin()); Lines.stroke(0.5f + e.fout() * 1.5f); Angles.randLenVectors(e.id, 8, e.finpow() * 30f, e.rotation, 50f, (x, y) -> { @@ -252,7 +250,7 @@ public class Fx implements ContentList{ }); hitLancer = new Effect(12, e -> { - Draw.color(Color.WHITE); + Draw.color(Color.white); Lines.stroke(e.fout() * 1.5f); Angles.randLenVectors(e.id, 8, e.finpow() * 17f, e.rotation, 360f, (x, y) -> { @@ -276,14 +274,14 @@ public class Fx implements ContentList{ }); hitLaser = new Effect(8, e -> { - Draw.color(Color.WHITE, Pal.heal, e.fin()); + Draw.color(Color.white, Pal.heal, e.fin()); Lines.stroke(0.5f + e.fout()); Lines.circle(e.x, e.y, e.fin() * 5f); Draw.reset(); }); despawn = new Effect(12, e -> { - Draw.color(Pal.lighterOrange, Color.GRAY, e.fin()); + Draw.color(Pal.lighterOrange, Color.gray, e.fin()); Lines.stroke(e.fout()); Angles.randLenVectors(e.id, 7, e.fin() * 7f, e.rotation, 40f, (x, y) -> { @@ -302,7 +300,7 @@ public class Fx implements ContentList{ Lines.circle(e.x, e.y, 3f + i.fin() * 10f); }); - Draw.color(Color.GRAY); + Draw.color(Color.gray); Angles.randLenVectors(e.id, 5, 2f + 23f * e.finpow(), (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 3f + 0.5f); @@ -326,7 +324,7 @@ public class Fx implements ContentList{ Lines.circle(e.x, e.y, 3f + i.fin() * 24f); }); - Draw.color(Color.GRAY); + Draw.color(Color.gray); Angles.randLenVectors(e.id, 7, 2f + 28f * e.finpow(), (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f); @@ -350,7 +348,7 @@ public class Fx implements ContentList{ Lines.circle(e.x, e.y, 3f + i.fin() * 34f); }); - Draw.color(Color.GRAY); + Draw.color(Color.gray); Angles.randLenVectors(e.id, 7, 2f + 30f * e.finpow(), (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f); @@ -374,7 +372,7 @@ public class Fx implements ContentList{ Lines.circle(e.x, e.y, 3f + i.fin() * 15f); }); - Draw.color(Color.GRAY); + Draw.color(Color.gray); Angles.randLenVectors(e.id, 5, 2f + 23f * e.finpow(), (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f); @@ -423,7 +421,7 @@ public class Fx implements ContentList{ Lines.circle(e.x, e.y, 3f + i.fin() * 25f); }); - Draw.color(Color.GRAY); + Draw.color(Color.gray); Angles.randLenVectors(e.id, 6, 2f + 23f * e.finpow(), (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f); @@ -461,7 +459,7 @@ public class Fx implements ContentList{ }); fireSmoke = new Effect(35f, e -> { - Draw.color(Color.GRAY); + Draw.color(Color.gray); Angles.randLenVectors(e.id, 1, 2f + e.fin() * 7f, (x, y) -> { Fill.circle(e.x + x, e.y + y, 0.2f + e.fslope() * 1.5f); @@ -471,7 +469,7 @@ public class Fx implements ContentList{ }); steam = new Effect(35f, e -> { - Draw.color(Color.LIGHT_GRAY); + Draw.color(Color.lightGray); Angles.randLenVectors(e.id, 2, 2f + e.fin() * 7f, (x, y) -> { Fill.circle(e.x + x, e.y + y, 0.2f + e.fslope() * 1.5f); @@ -481,7 +479,7 @@ public class Fx implements ContentList{ }); fireballsmoke = new Effect(25f, e -> { - Draw.color(Color.GRAY); + Draw.color(Color.gray); Angles.randLenVectors(e.id, 1, 2f + e.fin() * 7f, (x, y) -> { Fill.circle(e.x + x, e.y + y, 0.2f + e.fout() * 1.5f); @@ -511,7 +509,7 @@ public class Fx implements ContentList{ }); melting = new Effect(40f, e -> { - Draw.color(Liquids.slag.color, Color.WHITE, e.fout() / 5f + Mathf.randomSeedRange(e.id, 0.12f)); + Draw.color(Liquids.slag.color, Color.white, e.fout() / 5f + Mathf.randomSeedRange(e.id, 0.12f)); Angles.randLenVectors(e.id, 2, 1f + e.fin() * 3f, (x, y) -> { Fill.circle(e.x + x, e.y + y, .2f + e.fout() * 1.2f); @@ -559,35 +557,35 @@ public class Fx implements ContentList{ shockwave = new Effect(10f, 80f, e -> { - Draw.color(Color.WHITE, Color.LIGHT_GRAY, e.fin()); + Draw.color(Color.white, Color.lightGray, e.fin()); Lines.stroke(e.fout() * 2f + 0.2f); Lines.circle(e.x, e.y, e.fin() * 28f); Draw.reset(); }); bigShockwave = new Effect(10f, 80f, e -> { - Draw.color(Color.WHITE, Color.LIGHT_GRAY, e.fin()); + Draw.color(Color.white, Color.lightGray, e.fin()); Lines.stroke(e.fout() * 3f); Lines.circle(e.x, e.y, e.fin() * 50f); Draw.reset(); }); nuclearShockwave = new Effect(10f, 200f, e -> { - Draw.color(Color.WHITE, Color.LIGHT_GRAY, e.fin()); + Draw.color(Color.white, Color.lightGray, e.fin()); Lines.stroke(e.fout() * 3f + 0.2f); Lines.circle(e.x, e.y, e.fin() * 140f); Draw.reset(); }); impactShockwave = new Effect(13f, 300f, e -> { - Draw.color(Pal.lighterOrange, Color.LIGHT_GRAY, e.fin()); + Draw.color(Pal.lighterOrange, Color.lightGray, e.fin()); Lines.stroke(e.fout() * 4f + 0.2f); Lines.circle(e.x, e.y, e.fin() * 200f); Draw.reset(); }); spawnShockwave = new Effect(20f, 400f, e -> { - Draw.color(Color.WHITE, Color.LIGHT_GRAY, e.fin()); + Draw.color(Color.white, Color.lightGray, e.fin()); Lines.stroke(e.fout() * 3f + 0.5f); Lines.circle(e.x, e.y, e.fin() * (e.rotation + 50f)); Draw.reset(); @@ -599,14 +597,14 @@ public class Fx implements ContentList{ Lines.circle(e.x, e.y, 3f + i.fin() * 10f); }); - Draw.color(Color.GRAY); + Draw.color(Color.gray); Angles.randLenVectors(e.id, 6, 2f + 19f * e.finpow(), (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 3f + 0.5f); Fill.circle(e.x + x / 2f, e.y + y / 2f, e.fout() * 1f); }); - Draw.color(Pal.lighterOrange, Pal.lightOrange, Color.GRAY, e.fin()); + Draw.color(Pal.lighterOrange, Pal.lightOrange, Color.gray, e.fin()); Lines.stroke(1.5f * e.fout()); Angles.randLenVectors(e.id + 1, 8, 1f + 23f * e.finpow(), (x, y) -> { @@ -624,14 +622,14 @@ public class Fx implements ContentList{ Lines.circle(e.x, e.y, (3f + i.fin() * 14f) * intensity); }); - Draw.color(Color.GRAY); + Draw.color(Color.gray); Angles.randLenVectors(e.id, e.finpow(), (int)(6 * intensity), 21f * intensity, (x, y, in, out) -> { Fill.circle(e.x + x, e.y + y, out * (2f + intensity) * 3 + 0.5f); Fill.circle(e.x + x / 2f, e.y + y / 2f, out * (intensity) * 3); }); - Draw.color(Pal.lighterOrange, Pal.lightOrange, Color.GRAY, e.fin()); + Draw.color(Pal.lighterOrange, Pal.lightOrange, Color.gray, e.fin()); Lines.stroke((1.7f * e.fout()) * (1f + (intensity - 1f) / 2f)); Angles.randLenVectors(e.id + 1, e.finpow(), (int)(9 * intensity), 40f * intensity, (x, y, in, out) -> { @@ -647,14 +645,14 @@ public class Fx implements ContentList{ Lines.circle(e.x, e.y, 3f + i.fin() * 14f); }); - Draw.color(Color.GRAY); + Draw.color(Color.gray); Angles.randLenVectors(e.id, 6, 2f + 19f * e.finpow(), (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 3f + 0.5f); Fill.circle(e.x + x / 2f, e.y + y / 2f, e.fout() * 1f); }); - Draw.color(Pal.lighterOrange, Pal.lightOrange, Color.GRAY, e.fin()); + Draw.color(Pal.lighterOrange, Pal.lightOrange, Color.gray, e.fin()); Lines.stroke(1.7f * e.fout()); Angles.randLenVectors(e.id + 1, 9, 1f + 23f * e.finpow(), (x, y) -> { @@ -665,7 +663,7 @@ public class Fx implements ContentList{ }); blockExplosionSmoke = new Effect(30, e -> { - Draw.color(Color.GRAY); + Draw.color(Color.gray); Angles.randLenVectors(e.id, 6, 4f + 30f * e.finpow(), (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 3f); @@ -693,7 +691,7 @@ public class Fx implements ContentList{ }); shootSmallSmoke = new Effect(20f, e -> { - Draw.color(Pal.lighterOrange, Color.LIGHT_GRAY, Color.GRAY, e.fin()); + Draw.color(Pal.lighterOrange, Color.lightGray, Color.gray, e.fin()); Angles.randLenVectors(e.id, 5, e.finpow() * 6f, e.rotation, 20f, (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 1.5f); @@ -711,7 +709,7 @@ public class Fx implements ContentList{ }); shootBig2 = new Effect(10, e -> { - Draw.color(Pal.lightOrange, Color.GRAY, e.fin()); + Draw.color(Pal.lightOrange, Color.gray, e.fin()); float w = 1.2f + 8 * e.fout(); Drawf.tri(e.x, e.y, w, 29f * e.fout(), e.rotation); Drawf.tri(e.x, e.y, w, 5f * e.fout(), e.rotation + 180f); @@ -719,7 +717,7 @@ public class Fx implements ContentList{ }); shootBigSmoke = new Effect(17f, e -> { - Draw.color(Pal.lighterOrange, Color.LIGHT_GRAY, Color.GRAY, e.fin()); + Draw.color(Pal.lighterOrange, Color.lightGray, Color.gray, e.fin()); Angles.randLenVectors(e.id, 8, e.finpow() * 19f, e.rotation, 10f, (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 2f + 0.2f); @@ -729,7 +727,7 @@ public class Fx implements ContentList{ }); shootBigSmoke2 = new Effect(18f, e -> { - Draw.color(Pal.lightOrange, Color.LIGHT_GRAY, Color.GRAY, e.fin()); + Draw.color(Pal.lightOrange, Color.lightGray, Color.gray, e.fin()); Angles.randLenVectors(e.id, 9, e.finpow() * 23f, e.rotation, 20f, (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 2.4f + 0.2f); @@ -739,7 +737,7 @@ public class Fx implements ContentList{ }); shootSmallFlame = new Effect(32f, e -> { - Draw.color(Pal.lightFlame, Pal.darkFlame, Color.GRAY, e.fin()); + Draw.color(Pal.lightFlame, Pal.darkFlame, Color.gray, e.fin()); Angles.randLenVectors(e.id, 8, e.finpow() * 60f, e.rotation, 10f, (x, y) -> { Fill.circle(e.x + x, e.y + y, 0.65f + e.fout() * 1.5f); @@ -749,7 +747,7 @@ public class Fx implements ContentList{ }); shootPyraFlame = new Effect(33f, e -> { - Draw.color(Pal.lightPyraFlame, Pal.darkPyraFlame, Color.GRAY, e.fin()); + Draw.color(Pal.lightPyraFlame, Pal.darkPyraFlame, Color.gray, e.fin()); Angles.randLenVectors(e.id, 10, e.finpow() * 70f, e.rotation, 10f, (x, y) -> { Fill.circle(e.x + x, e.y + y, 0.65f + e.fout() * 1.6f); @@ -759,7 +757,7 @@ public class Fx implements ContentList{ }); shootLiquid = new Effect(40f, e -> { - Draw.color(e.color, Color.WHITE, e.fout() / 6f + Mathf.randomSeedRange(e.id, 0.1f)); + Draw.color(e.color, Color.white, e.fout() / 6f + Mathf.randomSeedRange(e.id, 0.1f)); Angles.randLenVectors(e.id, 6, e.finpow() * 60f, e.rotation, 11f, (x, y) -> { Fill.circle(e.x + x, e.y + y, 0.5f + e.fout() * 2.5f); @@ -769,7 +767,7 @@ public class Fx implements ContentList{ }); shellEjectSmall = new GroundEffect(30f, 400f, e -> { - Draw.color(Pal.lightOrange, Color.LIGHT_GRAY, Pal.lightishGray, e.fin()); + Draw.color(Pal.lightOrange, Color.lightGray, Pal.lightishGray, e.fin()); float rot = Math.abs(e.rotation) + 90f; int i = Mathf.sign(e.rotation); @@ -784,7 +782,7 @@ public class Fx implements ContentList{ }); shellEjectMedium = new GroundEffect(34f, 400f, e -> { - Draw.color(Pal.lightOrange, Color.LIGHT_GRAY, Pal.lightishGray, e.fin()); + Draw.color(Pal.lightOrange, Color.lightGray, Pal.lightishGray, e.fin()); float rot = e.rotation + 90f; for(int i : Mathf.signs){ float len = (2f + e.finpow() * 10f) * i; @@ -795,7 +793,7 @@ public class Fx implements ContentList{ 2f, 3f, rot); } - Draw.color(Color.LIGHT_GRAY, Color.GRAY, e.fin()); + Draw.color(Color.lightGray, Color.gray, e.fin()); for(int i : Mathf.signs){ float ex = e.x, ey = e.y, fout = e.fout(); @@ -808,7 +806,7 @@ public class Fx implements ContentList{ }); shellEjectBig = new GroundEffect(22f, 400f, e -> { - Draw.color(Pal.lightOrange, Color.LIGHT_GRAY, Pal.lightishGray, e.fin()); + Draw.color(Pal.lightOrange, Color.lightGray, Pal.lightishGray, e.fin()); float rot = e.rotation + 90f; for(int i : Mathf.signs){ float len = (4f + e.finpow() * 8f) * i; @@ -820,7 +818,7 @@ public class Fx implements ContentList{ rot + e.fin() * 30f * i + Mathf.randomSeedRange(e.id + i + 9, 40f * e.fin())); } - Draw.color(Color.LIGHT_GRAY); + Draw.color(Color.lightGray); for(int i : Mathf.signs){ float ex = e.x, ey = e.y, fout = e.fout(); @@ -881,7 +879,7 @@ public class Fx implements ContentList{ }); lightningShoot = new Effect(12f, e -> { - Draw.color(Color.WHITE, Pal.lancerLaser, e.fin()); + Draw.color(Color.white, Pal.lancerLaser, e.fin()); Lines.stroke(e.fout() * 1.2f + 0.5f); Angles.randLenVectors(e.id, 7, 25f * e.finpow(), e.rotation, 50f, (x, y) -> { @@ -895,7 +893,7 @@ public class Fx implements ContentList{ reactorsmoke = new Effect(17, e -> { Angles.randLenVectors(e.id, 4, e.fin() * 8f, (x, y) -> { float size = 1f + e.fout() * 5f; - Draw.color(Color.LIGHT_GRAY, Color.GRAY, e.fin()); + Draw.color(Color.lightGray, Color.gray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, size, size); Draw.reset(); }); @@ -903,7 +901,7 @@ public class Fx implements ContentList{ nuclearsmoke = new Effect(40, e -> { Angles.randLenVectors(e.id, 4, e.fin() * 13f, (x, y) -> { float size = e.fslope() * 4f; - Draw.color(Color.LIGHT_GRAY, Color.GRAY, e.fin()); + Draw.color(Color.lightGray, Color.gray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, size, size); Draw.reset(); }); @@ -911,7 +909,7 @@ public class Fx implements ContentList{ nuclearcloud = new Effect(90, 200f, e -> { Angles.randLenVectors(e.id, 10, e.finpow() * 90f, (x, y) -> { float size = e.fout() * 14f; - Draw.color(Color.LIME, Color.GRAY, e.fin()); + Draw.color(Color.lime, Color.gray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, size, size); Draw.reset(); }); @@ -919,7 +917,7 @@ public class Fx implements ContentList{ impactsmoke = new Effect(60, e -> { Angles.randLenVectors(e.id, 7, e.fin() * 20f, (x, y) -> { float size = e.fslope() * 4f; - Draw.color(Color.LIGHT_GRAY, Color.GRAY, e.fin()); + Draw.color(Color.lightGray, Color.gray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, size, size); Draw.reset(); }); @@ -927,7 +925,7 @@ public class Fx implements ContentList{ impactcloud = new Effect(140, 400f, e -> { Angles.randLenVectors(e.id, 20, e.finpow() * 160f, (x, y) -> { float size = e.fout() * 15f; - Draw.color(Pal.lighterOrange, Color.LIGHT_GRAY, e.fin()); + Draw.color(Pal.lighterOrange, Color.lightGray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, size, size); Draw.reset(); }); @@ -935,7 +933,7 @@ public class Fx implements ContentList{ redgeneratespark = new Effect(18, e -> { Angles.randLenVectors(e.id, 5, e.fin() * 8f, (x, y) -> { float len = e.fout() * 4f; - Draw.color(Pal.redSpark, Color.GRAY, e.fin()); + Draw.color(Pal.redSpark, Color.gray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, len, len); Draw.reset(); }); @@ -943,7 +941,7 @@ public class Fx implements ContentList{ generatespark = new Effect(18, e -> { Angles.randLenVectors(e.id, 5, e.fin() * 8f, (x, y) -> { float len = e.fout() * 4f; - Draw.color(Pal.orangeSpark, Color.GRAY, e.fin()); + Draw.color(Pal.orangeSpark, Color.gray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, len, len); Draw.reset(); }); @@ -951,14 +949,14 @@ public class Fx implements ContentList{ fuelburn = new Effect(23, e -> { Angles.randLenVectors(e.id, 5, e.fin() * 9f, (x, y) -> { float len = e.fout() * 4f; - Draw.color(Color.LIGHT_GRAY, Color.GRAY, e.fin()); + Draw.color(Color.lightGray, Color.gray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, len, len); Draw.reset(); }); }); plasticburn = new Effect(40, e -> { Angles.randLenVectors(e.id, 5, 3f + e.fin() * 5f, (x, y) -> { - Draw.color(Color.valueOf("e9ead3"), Color.GRAY, e.fin()); + Draw.color(Color.valueOf("e9ead3"), Color.gray, e.fin()); Fill.circle(e.x + x, e.y + y, e.fout() * 1f); Draw.reset(); }); @@ -1000,21 +998,21 @@ public class Fx implements ContentList{ }); producesmoke = new Effect(12, e -> { Angles.randLenVectors(e.id, 8, 4f + e.fin() * 18f, (x, y) -> { - Draw.color(Color.WHITE, Pal.accent, e.fin()); + Draw.color(Color.white, Pal.accent, e.fin()); Fill.square(e.x + x, e.y + y, 1f + e.fout() * 3f, 45); Draw.reset(); }); }); smeltsmoke = new Effect(15, e -> { Angles.randLenVectors(e.id, 6, 4f + e.fin() * 5f, (x, y) -> { - Draw.color(Color.WHITE, e.color, e.fin()); + Draw.color(Color.white, e.color, e.fin()); Fill.square(e.x + x, e.y + y, 0.5f + e.fout() * 2f, 45); Draw.reset(); }); }); formsmoke = new Effect(40, e -> { Angles.randLenVectors(e.id, 6, 5f + e.fin() * 8f, (x, y) -> { - Draw.color(Pal.plasticSmoke, Color.LIGHT_GRAY, e.fin()); + Draw.color(Pal.plasticSmoke, Color.lightGray, e.fin()); Fill.square(e.x + x, e.y + y, 0.2f + e.fout() * 2f, 45); Draw.reset(); }); @@ -1022,7 +1020,7 @@ public class Fx implements ContentList{ blastsmoke = new Effect(26, e -> { Angles.randLenVectors(e.id, 12, 1f + e.fin() * 23f, (x, y) -> { float size = 2f + e.fout() * 6f; - Draw.color(Color.LIGHT_GRAY, Color.DARK_GRAY, e.fin()); + Draw.color(Color.lightGray, Color.darkGray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, size, size); Draw.reset(); }); @@ -1030,7 +1028,7 @@ public class Fx implements ContentList{ lava = new Effect(18, e -> { Angles.randLenVectors(e.id, 3, 1f + e.fin() * 10f, (x, y) -> { float size = e.fslope() * 4f; - Draw.color(Color.ORANGE, Color.GRAY, e.fin()); + Draw.color(Color.orange, Color.gray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, size, size); Draw.reset(); }); @@ -1056,53 +1054,53 @@ public class Fx implements ContentList{ Draw.reset(); }); purify = new Effect(10, e -> { - Draw.color(Color.ROYAL, Color.GRAY, e.fin()); + Draw.color(Color.royal, Color.gray, e.fin()); Lines.stroke(2f); Lines.spikes(e.x, e.y, e.fin() * 4f, 2, 6); Draw.reset(); }); purifyoil = new Effect(10, e -> { - Draw.color(Color.BLACK, Color.GRAY, e.fin()); + Draw.color(Color.black, Color.gray, e.fin()); Lines.stroke(2f); Lines.spikes(e.x, e.y, e.fin() * 4f, 2, 6); Draw.reset(); }); purifystone = new Effect(10, e -> { - Draw.color(Color.ORANGE, Color.GRAY, e.fin()); + Draw.color(Color.orange, Color.gray, e.fin()); Lines.stroke(2f); Lines.spikes(e.x, e.y, e.fin() * 4f, 2, 6); Draw.reset(); }); generate = new Effect(11, e -> { - Draw.color(Color.ORANGE, Color.YELLOW, e.fin()); + Draw.color(Color.orange, Color.yellow, e.fin()); Lines.stroke(1f); Lines.spikes(e.x, e.y, e.fin() * 5f, 2, 8); Draw.reset(); }); mine = new Effect(20, e -> { Angles.randLenVectors(e.id, 6, 3f + e.fin() * 6f, (x, y) -> { - Draw.color(e.color, Color.LIGHT_GRAY, e.fin()); + Draw.color(e.color, Color.lightGray, e.fin()); Fill.square(e.x + x, e.y + y, e.fout() * 2f, 45); Draw.reset(); }); }); mineBig = new Effect(30, e -> { Angles.randLenVectors(e.id, 6, 4f + e.fin() * 8f, (x, y) -> { - Draw.color(e.color, Color.LIGHT_GRAY, e.fin()); + Draw.color(e.color, Color.lightGray, e.fin()); Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.2f, 45); Draw.reset(); }); }); mineHuge = new Effect(40, e -> { Angles.randLenVectors(e.id, 8, 5f + e.fin() * 10f, (x, y) -> { - Draw.color(e.color, Color.LIGHT_GRAY, e.fin()); + Draw.color(e.color, Color.lightGray, e.fin()); Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.5f, 45); Draw.reset(); }); }); smelt = new Effect(20, e -> { Angles.randLenVectors(e.id, 6, 2f + e.fin() * 5f, (x, y) -> { - Draw.color(Color.WHITE, e.color, e.fin()); + Draw.color(Color.white, e.color, e.fin()); Fill.square(e.x + x, e.y + y, 0.5f + e.fout() * 2f, 45); Draw.reset(); }); @@ -1209,5 +1207,8 @@ public class Fx implements ContentList{ Lines.poly(e.x, e.y, 6, e.rotation + e.fin(), 90); Draw.reset(); }); + + coreLand = new Effect(120f, e -> { + }); } } diff --git a/core/src/io/anuke/mindustry/content/Items.java b/core/src/io/anuke/mindustry/content/Items.java index b8c567bfcc..f367c9656c 100644 --- a/core/src/io/anuke/mindustry/content/Items.java +++ b/core/src/io/anuke/mindustry/content/Items.java @@ -39,7 +39,7 @@ public class Items implements ContentList{ }}; coal = new Item("coal", Color.valueOf("272727")){{ - explosiveness = 0.4f; + explosiveness = 0.2f; flammability = 1f; hardness = 2; }}; diff --git a/core/src/io/anuke/mindustry/content/StatusEffects.java b/core/src/io/anuke/mindustry/content/StatusEffects.java index a869b0cbe9..cb4035dd0e 100644 --- a/core/src/io/anuke/mindustry/content/StatusEffects.java +++ b/core/src/io/anuke/mindustry/content/StatusEffects.java @@ -1,10 +1,14 @@ package io.anuke.mindustry.content; +import io.anuke.arc.*; import io.anuke.arc.math.Mathf; import io.anuke.mindustry.entities.Effects; import io.anuke.mindustry.game.ContentList; +import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.type.StatusEffect; +import static io.anuke.mindustry.Vars.waveTeam; + public class StatusEffects implements ContentList{ public static StatusEffect none, burning, freezing, wet, melting, tarred, overdrive, shielded, shocked, corroded, boss; @@ -37,8 +41,13 @@ public class StatusEffects implements ContentList{ speedMultiplier = 0.9f; effect = Fx.wet; - trans(() -> shocked, ((unit, time, newTime, result) -> unit.damage(15f))); - opposite(() -> burning, () -> shocked); + trans(() -> shocked, ((unit, time, newTime, result) -> { + unit.damage(20f); + if(unit.getTeam() == waveTeam){ + Events.fire(Trigger.shock); + } + })); + opposite(() -> burning); }}; melting = new StatusEffect(){{ diff --git a/core/src/io/anuke/mindustry/content/TechTree.java b/core/src/io/anuke/mindustry/content/TechTree.java index 721408bf56..0c325b47a1 100644 --- a/core/src/io/anuke/mindustry/content/TechTree.java +++ b/core/src/io/anuke/mindustry/content/TechTree.java @@ -8,10 +8,13 @@ import io.anuke.mindustry.world.Block; import static io.anuke.mindustry.content.Blocks.*; public class TechTree implements ContentList{ + public static Array all; public static TechNode root; @Override public void load(){ + all = new Array<>(); + root = node(coreShard, () -> { node(conveyor, () -> { @@ -326,6 +329,7 @@ public class TechTree implements ContentList{ context = this; children.run(); context = last; + all.add(this); } } } diff --git a/core/src/io/anuke/mindustry/content/UnitTypes.java b/core/src/io/anuke/mindustry/content/UnitTypes.java index db601d03af..06ad0a9e17 100644 --- a/core/src/io/anuke/mindustry/content/UnitTypes.java +++ b/core/src/io/anuke/mindustry/content/UnitTypes.java @@ -3,6 +3,7 @@ package io.anuke.mindustry.content; import io.anuke.arc.collection.*; import io.anuke.mindustry.entities.bullet.*; import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.entities.type.Bullet; import io.anuke.mindustry.entities.type.base.*; import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index 049053b9c0..13aad0a319 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -2,7 +2,6 @@ package io.anuke.mindustry.core; import io.anuke.arc.*; import io.anuke.arc.assets.*; -import io.anuke.arc.files.*; import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.input.*; @@ -18,7 +17,6 @@ import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.input.*; import io.anuke.mindustry.maps.Map; -import io.anuke.mindustry.net.Net; import io.anuke.mindustry.type.*; import io.anuke.mindustry.ui.dialogs.*; import io.anuke.mindustry.world.*; @@ -30,6 +28,7 @@ import java.util.*; import static io.anuke.arc.Core.*; import static io.anuke.mindustry.Vars.*; +import static io.anuke.mindustry.Vars.net; /** * Control module. @@ -48,6 +47,10 @@ public class Control implements ApplicationListener, Loadable{ private boolean wasPaused = false; public Control(){ + saves = new Saves(); + tutorial = new Tutorial(); + music = new MusicControl(); + Events.on(StateChangeEvent.class, event -> { if((event.from == State.playing && event.to == State.menu) || (event.from == State.menu && event.to != State.menu)){ Time.runTask(5f, platform::updateRPC); @@ -64,7 +67,7 @@ public class Control implements ApplicationListener, Loadable{ Events.on(WorldLoadEvent.class, event -> { Core.app.post(() -> Core.app.post(() -> { - if(Net.active() && player.getClosestCore() != null){ + 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.isDead() ? player.getClosestCore() : player); }else{ @@ -96,7 +99,7 @@ public class Control implements ApplicationListener, Loadable{ Effects.shake(5, 6, Core.camera.position.x, Core.camera.position.y); //the restart dialog can show info for any number of scenarios Call.onGameOver(event.winner); - if(state.rules.zone != null && !Net.client()){ + if(state.rules.zone != null && !net.client()){ //remove zone save on game over if(saves.getZoneSlot() != null && !state.rules.tutorial){ saves.getZoneSlot().delete(); @@ -106,12 +109,12 @@ public class Control implements ApplicationListener, Loadable{ //autohost for pvp maps Events.on(WorldLoadEvent.class, event -> { - if(state.rules.pvp && !Net.active()){ + if(state.rules.pvp && !net.active()){ try{ - Net.host(port); + net.host(port); player.isAdmin = true; }catch(IOException e){ - ui.showError(Core.bundle.format("server.error", Strings.parseException(e, true))); + ui.showException("$server.error", e); Core.app.post(() -> state.set(State.menu)); } } @@ -148,14 +151,24 @@ public class Control implements ApplicationListener, Loadable{ Events.on(ZoneConfigureCompleteEvent.class, e -> { ui.hudfrag.showToast(Core.bundle.format("zone.config.complete", e.zone.configureWave)); }); + + Events.on(Trigger.newGame, () -> { + TileEntity core = player.getClosestCore(); + + if(core == null) return; + + app.post(() -> ui.hudfrag.showLand()); + renderer.zoomIn(Fx.coreLand.lifetime); + app.post(() -> Effects.effect(Fx.coreLand, core.x, core.y, 0, core.block)); + Time.run(Fx.coreLand.lifetime, () -> { + Effects.effect(Fx.launch, core); + Effects.shake(5f, 5f, core); + }); + }); } @Override public void loadAsync(){ - saves = new Saves(); - tutorial = new Tutorial(); - music = new MusicControl(); - Draw.scl = 1f / Core.atlas.find("scale_marker").getWidth(); Core.input.setCatch(KeyCode.BACK, true); @@ -174,35 +187,6 @@ public class Control implements ApplicationListener, Loadable{ saves.load(); } - //checks for existing 3.5 app data, android only - public void checkClassicData(){ - try{ - if(files.local("mindustry-maps").exists() || files.local("mindustry-saves").exists()){ - settings.getBoolOnce("classic-backup-check", () -> { - app.post(() -> app.post(() -> ui.showConfirm("$classic.export", "$classic.export.text", () -> { - try{ - platform.requestExternalPerms(() -> { - FileHandle external = files.external("MindustryClassic"); - if(files.local("mindustry-maps").exists()){ - files.local("mindustry-maps").copyTo(external); - } - - if(files.local("mindustry-saves").exists()){ - files.local("mindustry-saves").copyTo(external); - } - }); - }catch(Exception e){ - e.printStackTrace(); - ui.showError(Strings.parseException(e, true)); - } - }))); - }); - } - }catch(Throwable t){ - t.printStackTrace(); - } - } - void createPlayer(){ player = new Player(); player.name = Core.settings.getString("name"); @@ -234,13 +218,14 @@ public class Control implements ApplicationListener, Loadable{ if(settings.getBool("savecreate") && !world.isInvalidMap()){ control.saves.addSave(map.name() + " " + new SimpleDateFormat("MMM dd h:mm", Locale.getDefault()).format(new Date())); } + Events.fire(Trigger.newGame); }); } public void playZone(Zone zone){ ui.loadAnd(() -> { logic.reset(); - Net.reset(); + net.reset(); world.loadGenerator(zone.generator); zone.rules.accept(state.rules); state.rules.zone = zone; @@ -252,6 +237,7 @@ public class Control implements ApplicationListener, Loadable{ state.set(State.playing); control.saves.zoneSave(); logic.play(); + Events.fire(Trigger.newGame); }); } @@ -259,7 +245,7 @@ public class Control implements ApplicationListener, Loadable{ Zone zone = Zones.groundZero; ui.loadAnd(() -> { logic.reset(); - Net.reset(); + net.reset(); world.beginMapLoad(); @@ -304,6 +290,7 @@ public class Control implements ApplicationListener, Loadable{ state.rules.waveSpacing = 60f * 30; state.rules.buildCostMultiplier = 0.3f; state.rules.tutorial = true; + Events.fire(Trigger.newGame); }); } @@ -314,7 +301,7 @@ public class Control implements ApplicationListener, Loadable{ @Override public void dispose(){ content.dispose(); - Net.dispose(); + net.dispose(); Musics.dispose(); Sounds.dispose(); ui.editor.dispose(); @@ -379,7 +366,6 @@ public class Control implements ApplicationListener, Loadable{ if(android){ Sounds.empty.loop(0f, 1f, 0f); - checkClassicData(); } } @@ -414,7 +400,7 @@ public class Control implements ApplicationListener, Loadable{ if(world.isZone()){ for(Tile tile : state.teams.get(player.getTeam()).cores){ for(Item item : content.items()){ - if(tile.entity.items.has(item)){ + if(tile.entity != null && tile.entity.items.has(item)){ data.unlockContent(item); } } diff --git a/core/src/io/anuke/mindustry/core/GameState.java b/core/src/io/anuke/mindustry/core/GameState.java index 1e755de6c6..0e1c7a2d4b 100644 --- a/core/src/io/anuke/mindustry/core/GameState.java +++ b/core/src/io/anuke/mindustry/core/GameState.java @@ -1,14 +1,12 @@ package io.anuke.mindustry.core; -import io.anuke.arc.Events; -import io.anuke.mindustry.entities.type.BaseUnit; -import io.anuke.mindustry.entities.type.base.BaseDrone; -import io.anuke.mindustry.game.EventType.StateChangeEvent; +import io.anuke.arc.*; +import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.entities.type.base.*; +import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.*; -import io.anuke.mindustry.net.Net; -import static io.anuke.mindustry.Vars.unitGroups; -import static io.anuke.mindustry.Vars.waveTeam; +import static io.anuke.mindustry.Vars.*; public class GameState{ /** Current wave number, can be anything in non-wave modes. */ @@ -29,7 +27,7 @@ public class GameState{ private State state = State.menu; public int enemies(){ - return Net.client() ? enemies : unitGroups[waveTeam.ordinal()].count(b -> !(b instanceof BaseDrone)); + return net.client() ? enemies : unitGroups[waveTeam.ordinal()].count(b -> !(b instanceof BaseDrone)); } public BaseUnit boss(){ @@ -46,7 +44,7 @@ public class GameState{ } public boolean isPaused(){ - return (is(State.paused) && !Net.active()) || (gameOver && !Net.active()); + return (is(State.paused) && !net.active()) || (gameOver && !net.active()); } public boolean is(State astate){ diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index abfb994939..eaa60fe80a 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -1,28 +1,21 @@ package io.anuke.mindustry.core; -import io.anuke.annotations.Annotations.Loc; -import io.anuke.annotations.Annotations.Remote; -import io.anuke.arc.ApplicationListener; -import io.anuke.arc.Events; -import io.anuke.arc.collection.ObjectSet.ObjectSetIterator; +import io.anuke.annotations.Annotations.*; +import io.anuke.arc.*; +import io.anuke.arc.collection.ObjectSet.*; import io.anuke.arc.util.*; import io.anuke.mindustry.content.*; -import io.anuke.mindustry.core.GameState.State; +import io.anuke.mindustry.core.GameState.*; 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.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.*; -import io.anuke.mindustry.game.Teams.TeamData; -import io.anuke.mindustry.gen.BrokenBlock; -import io.anuke.mindustry.gen.Call; -import io.anuke.mindustry.net.Net; -import io.anuke.mindustry.type.Item; -import io.anuke.mindustry.type.ItemStack; -import io.anuke.mindustry.world.Block; -import io.anuke.mindustry.world.Tile; -import io.anuke.mindustry.world.blocks.BuildBlock; -import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity; +import io.anuke.mindustry.game.Teams.*; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.type.*; +import io.anuke.mindustry.world.*; +import io.anuke.mindustry.world.blocks.*; +import io.anuke.mindustry.world.blocks.BuildBlock.*; import static io.anuke.mindustry.Vars.*; @@ -164,6 +157,7 @@ public class Logic implements ApplicationListener{ } state.launched = true; state.gameOver = true; + Events.fire(new LaunchEvent()); //manually fire game over event now Events.fire(new GameOverEvent(defaultTeam)); }); @@ -190,7 +184,7 @@ public class Logic implements ApplicationListener{ } } - if(!Net.client() && state.wavetime <= 0 && state.rules.waves){ + if(!net.client() && state.wavetime <= 0 && state.rules.waves){ runWave(); } @@ -237,7 +231,7 @@ public class Logic implements ApplicationListener{ pathfinder.update(); } - if(!Net.client() && !world.isInvalidMap() && !state.isEditor()){ + if(!net.client() && !world.isInvalidMap() && !state.isEditor()){ checkGameOver(); } } diff --git a/core/src/io/anuke/mindustry/core/NetClient.java b/core/src/io/anuke/mindustry/core/NetClient.java index 88abd225db..57aa94fdcd 100644 --- a/core/src/io/anuke/mindustry/core/NetClient.java +++ b/core/src/io/anuke/mindustry/core/NetClient.java @@ -1,37 +1,33 @@ package io.anuke.mindustry.core; import io.anuke.annotations.Annotations.*; -import io.anuke.arc.ApplicationListener; -import io.anuke.arc.Core; -import io.anuke.arc.collection.IntSet; -import io.anuke.arc.graphics.Color; -import io.anuke.arc.math.RandomXS128; -import io.anuke.arc.util.*; +import io.anuke.arc.*; +import io.anuke.arc.collection.*; +import io.anuke.arc.graphics.*; +import io.anuke.arc.math.*; import io.anuke.arc.util.CommandHandler.*; -import io.anuke.arc.util.io.ReusableByteInStream; -import io.anuke.arc.util.serialization.Base64Coder; -import io.anuke.mindustry.Vars; -import io.anuke.mindustry.core.GameState.State; -import io.anuke.mindustry.entities.EntityGroup; -import io.anuke.mindustry.entities.traits.BuilderTrait.BuildRequest; -import io.anuke.mindustry.entities.traits.SyncTrait; -import io.anuke.mindustry.entities.type.Player; -import io.anuke.mindustry.entities.type.Unit; -import io.anuke.mindustry.game.TypeID; -import io.anuke.mindustry.game.Version; -import io.anuke.mindustry.gen.Call; -import io.anuke.mindustry.gen.RemoteReadClient; -import io.anuke.mindustry.net.Administration.TraceInfo; +import io.anuke.arc.util.*; +import io.anuke.arc.util.io.*; +import io.anuke.arc.util.serialization.*; +import io.anuke.mindustry.*; +import io.anuke.mindustry.core.GameState.*; +import io.anuke.mindustry.entities.*; +import io.anuke.mindustry.entities.traits.BuilderTrait.*; +import io.anuke.mindustry.entities.traits.*; +import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.game.EventType.*; +import io.anuke.mindustry.game.*; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.net.Administration.*; +import io.anuke.mindustry.net.Net.*; import io.anuke.mindustry.net.*; -import io.anuke.mindustry.net.Net.SendMode; import io.anuke.mindustry.net.Packets.*; -import io.anuke.mindustry.type.ContentType; -import io.anuke.mindustry.world.Tile; -import io.anuke.mindustry.world.modules.ItemModule; +import io.anuke.mindustry.type.*; +import io.anuke.mindustry.world.*; +import io.anuke.mindustry.world.modules.*; -import java.io.DataInputStream; -import java.io.IOException; -import java.util.zip.InflaterInputStream; +import java.io.*; +import java.util.zip.*; import static io.anuke.mindustry.Vars.*; @@ -40,6 +36,7 @@ public class NetClient implements ApplicationListener{ private final static float playerSyncTime = 2; public final static float viewScale = 2f; + private long ping; private Interval timer = new Interval(5); /** Whether the client is currently connecting. */ private boolean connecting = false; @@ -60,7 +57,7 @@ public class NetClient implements ApplicationListener{ public NetClient(){ - Net.handleClient(Connect.class, packet -> { + net.handleClient(Connect.class, packet -> { Log.info("Connecting to server: {0}", packet.addressTCP); player.isAdmin = false; @@ -74,7 +71,7 @@ public class NetClient implements ApplicationListener{ ui.loadfrag.hide(); connecting = false; quiet = true; - Net.disconnect(); + net.disconnect(); }); ConnectPacket c = new ConnectPacket(); @@ -86,16 +83,16 @@ public class NetClient implements ApplicationListener{ c.uuid = platform.getUUID(); if(c.uuid == null){ - ui.showError("$invalidid"); + ui.showErrorMessage("$invalidid"); ui.loadfrag.hide(); disconnectQuietly(); return; } - Net.send(c, SendMode.tcp); + net.send(c, SendMode.tcp); }); - Net.handleClient(Disconnect.class, packet -> { + net.handleClient(Disconnect.class, packet -> { if(quietReset) return; connecting = false; @@ -107,17 +104,27 @@ public class NetClient implements ApplicationListener{ Time.runTask(3f, ui.loadfrag::hide); - ui.showError("$disconnect"); + if(packet.reason != null){ + if(packet.reason.equals("closed")){ + ui.showSmall("$disconnect", "$disconnect.closed"); + }else if(packet.reason.equals("timeout")){ + ui.showSmall("$disconnect", "$disconnect.timeout"); + }else if(packet.reason.equals("error")){ + ui.showSmall("$disconnect", "$disconnect.error"); + } + }else{ + ui.showErrorMessage("$disconnect"); + } }); - Net.handleClient(WorldStream.class, data -> { + net.handleClient(WorldStream.class, data -> { Log.info("Recieved world data: {0} bytes.", data.stream.available()); NetworkIO.loadWorld(new InflaterInputStream(data.stream)); finishConnecting(); }); - Net.handleClient(InvokePacket.class, packet -> { + net.handleClient(InvokePacket.class, packet -> { packet.writeBuffer.position(0); RemoteReadClient.readPacket(packet.writeBuffer, packet.type); }); @@ -180,6 +187,8 @@ public class NetClient implements ApplicationListener{ player.sendMessage(text); } } + + Events.fire(new PlayerChatEvent(player, message)); } public static String colorizeName(int id, String name){ @@ -188,6 +197,16 @@ public class NetClient implements ApplicationListener{ return "[#" + player.color.toString().toUpperCase() + "]" + name; } + @Remote(targets = Loc.client) + public static void onPing(Player player, long time){ + Call.onPingResponse(player.con, time); + } + + @Remote(variants = Variant.one) + public static void onPingResponse(long time){ + netClient.ping = Time.timeSinceMillis(time); + } + @Remote(variants = Variant.one) public static void onTraceInfo(Player player, TraceInfo info){ if(player != null){ @@ -223,7 +242,7 @@ public class NetClient implements ApplicationListener{ logic.reset(); ui.chatfrag.clearMessages(); - Net.setClientLoaded(false); + net.setClientLoaded(false); ui.loadfrag.show("$connecting.data"); @@ -231,7 +250,7 @@ public class NetClient implements ApplicationListener{ ui.loadfrag.hide(); netClient.connecting = false; netClient.quiet = true; - Net.disconnect(); + net.disconnect(); }); } @@ -249,7 +268,7 @@ public class NetClient implements ApplicationListener{ @Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true) public static void onEntitySnapshot(byte groupID, short amount, short dataLen, byte[] data){ try{ - netClient.byteStream.setBytes(Net.decompressSnapshot(data, dataLen)); + netClient.byteStream.setBytes(net.decompressSnapshot(data, dataLen)); DataInputStream input = netClient.dataStream; EntityGroup group = entities.get(groupID); @@ -305,7 +324,7 @@ public class NetClient implements ApplicationListener{ state.wave = wave; state.enemies = enemies; - netClient.byteStream.setBytes(Net.decompressSnapshot(coreData, coreDataLen)); + netClient.byteStream.setBytes(net.decompressSnapshot(coreData, coreDataLen)); DataInputStream input = netClient.dataStream; byte cores = input.readByte(); @@ -327,20 +346,20 @@ public class NetClient implements ApplicationListener{ @Override public void update(){ - if(!Net.client()) return; + if(!net.client()) return; if(!state.is(State.menu)){ if(!connecting) sync(); }else if(!connecting){ - Net.disconnect(); + net.disconnect(); }else{ //...must be connecting timeoutTime += Time.delta(); if(timeoutTime > dataTimeout){ Log.err("Failed to load data!"); ui.loadfrag.hide(); quiet = true; - ui.showError("$disconnect.data"); - Net.disconnect(); + ui.showErrorMessage("$disconnect.data"); + net.disconnect(); timeoutTime = 0f; } } @@ -350,18 +369,22 @@ public class NetClient implements ApplicationListener{ return connecting; } + public int getPing(){ + return (int)ping; + } + private void finishConnecting(){ state.set(State.playing); connecting = false; ui.join.hide(); - Net.setClientLoaded(true); + net.setClientLoaded(true); Core.app.post(Call::connectConfirm); Time.runTask(40f, platform::updateRPC); Core.app.post(() -> ui.loadfrag.hide()); } private void reset(){ - Net.setClientLoaded(false); + net.setClientLoaded(false); removed.clear(); timeoutTime = 0f; connecting = true; @@ -380,13 +403,13 @@ public class NetClient implements ApplicationListener{ /** Disconnects, resetting state to the menu. */ public void disconnectQuietly(){ quiet = true; - Net.disconnect(); + net.disconnect(); } /** Disconnects, causing no further changes or reset.*/ public void disconnectNoReset(){ quiet = quietReset = true; - Net.disconnect(); + net.disconnect(); } /** When set, any disconnects will be ignored and no dialogs will be shown. */ @@ -425,7 +448,7 @@ public class NetClient implements ApplicationListener{ } if(timer.get(1, 60)){ - Net.updatePing(); + Call.onPing(Time.millis()); } } diff --git a/core/src/io/anuke/mindustry/core/NetServer.java b/core/src/io/anuke/mindustry/core/NetServer.java index 36ac50ade2..74caa7e884 100644 --- a/core/src/io/anuke/mindustry/core/NetServer.java +++ b/core/src/io/anuke/mindustry/core/NetServer.java @@ -1,39 +1,31 @@ package io.anuke.mindustry.core; -import io.anuke.annotations.Annotations.Loc; -import io.anuke.annotations.Annotations.Remote; -import io.anuke.arc.ApplicationListener; -import io.anuke.arc.Events; +import io.anuke.annotations.Annotations.*; +import io.anuke.arc.*; import io.anuke.arc.collection.*; -import io.anuke.arc.graphics.Color; -import io.anuke.arc.graphics.Colors; -import io.anuke.arc.math.Mathf; -import io.anuke.arc.math.geom.Rectangle; -import io.anuke.arc.math.geom.Vector2; +import io.anuke.arc.graphics.*; +import io.anuke.arc.math.*; +import io.anuke.arc.math.geom.*; import io.anuke.arc.util.*; import io.anuke.arc.util.CommandHandler.*; import io.anuke.arc.util.io.*; -import io.anuke.mindustry.content.Blocks; -import io.anuke.mindustry.core.GameState.State; -import io.anuke.mindustry.entities.EntityGroup; -import io.anuke.mindustry.entities.traits.BuilderTrait.BuildRequest; -import io.anuke.mindustry.entities.traits.Entity; -import io.anuke.mindustry.entities.traits.SyncTrait; -import io.anuke.mindustry.entities.type.Player; -import io.anuke.mindustry.game.EventType.WorldLoadEvent; -import io.anuke.mindustry.game.Team; -import io.anuke.mindustry.game.Version; -import io.anuke.mindustry.gen.Call; -import io.anuke.mindustry.gen.RemoteReadServer; +import io.anuke.mindustry.content.*; +import io.anuke.mindustry.core.GameState.*; +import io.anuke.mindustry.entities.*; +import io.anuke.mindustry.entities.traits.BuilderTrait.*; +import io.anuke.mindustry.entities.traits.*; +import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.game.EventType.*; +import io.anuke.mindustry.game.*; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.net.*; -import io.anuke.mindustry.net.Administration.PlayerInfo; -import io.anuke.mindustry.net.Administration.TraceInfo; +import io.anuke.mindustry.net.Administration.*; import io.anuke.mindustry.net.Packets.*; -import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.*; import java.io.*; -import java.nio.ByteBuffer; -import java.util.zip.DeflaterOutputStream; +import java.nio.*; +import java.util.zip.*; import static io.anuke.mindustry.Vars.*; @@ -48,8 +40,6 @@ public class NetServer implements ApplicationListener{ public final Administration admins = new Administration(); public final CommandHandler clientCommands = new CommandHandler("/"); - /** Maps connection IDs to players. */ - private IntMap connections = new IntMap<>(); private boolean closing = false; private ByteBuffer writeBuffer = ByteBuffer.allocate(127); @@ -61,57 +51,67 @@ public class NetServer implements ApplicationListener{ private DataOutputStream dataStream = new DataOutputStream(syncStream); public NetServer(){ - Events.on(WorldLoadEvent.class, event -> { - if(!headless){ - connections.clear(); - } - }); - Net.handleServer(Connect.class, (id, connect) -> { + net.handleServer(Connect.class, (con, connect) -> { if(admins.isIPBanned(connect.addressTCP)){ - kick(id, KickReason.banned); + con.kick(KickReason.banned); } }); - Net.handleServer(Disconnect.class, (id, packet) -> { - Player player = connections.get(id); - if(player != null){ - onDisconnect(player); + net.handleServer(Disconnect.class, (con, packet) -> { + if(con.player != null){ + onDisconnect(con.player, packet.reason); } - connections.remove(id); }); - Net.handleServer(ConnectPacket.class, (id, packet) -> { + net.handleServer(ConnectPacket.class, (con, packet) -> { String uuid = packet.uuid; - NetConnection connection = Net.getConnection(id); + if(admins.isIPBanned(con.address)) return; - if(connection == null || - admins.isIPBanned(connection.address)) return; - - if(connection.hasBegunConnecting){ - kick(id, KickReason.idInUse); + if(con.hasBegunConnecting){ + con.kick(KickReason.idInUse); return; } - connection.hasBegunConnecting = true; - PlayerInfo info = admins.getInfo(uuid); - connection.mobile = packet.mobile; + con.hasBegunConnecting = true; + con.mobile = packet.mobile; if(admins.isIDBanned(uuid)){ - kick(id, KickReason.banned); + con.kick(KickReason.banned); return; } if(Time.millis() - info.lastKicked < kickDuration){ - kick(id, KickReason.recentKick); + con.kick(KickReason.recentKick); + return; + } + + if(admins.isIDBanned(uuid)){ + con.kick(KickReason.banned); + return; + } + + if(admins.getPlayerLimit() > 0 && playerGroup.size() >= admins.getPlayerLimit()){ + con.kick(KickReason.playerLimit); + return; + } + + if(!admins.isWhitelisted(packet.uuid, packet.usid)){ + info.adminUsid = packet.usid; + info.lastName = packet.name; + info.id = packet.uuid; + admins.save(); + Call.onInfoMessage(con, "You are not whitelisted here."); + Log.info("&lcDo &lywhitelist-add {0}&lc to whitelist the player &lb'{1}'", packet.uuid, packet.name); + con.kick(KickReason.whitelist); return; } if(packet.versionType == null || ((packet.version == -1 || !packet.versionType.equals(Version.type)) && Version.build != -1 && !admins.allowsCustomClients())){ - kick(id, !Version.type.equals(packet.versionType) ? KickReason.typeMismatch : KickReason.customClient); + con.kick(!Version.type.equals(packet.versionType) ? KickReason.typeMismatch : KickReason.customClient); return; } @@ -120,12 +120,12 @@ public class NetServer implements ApplicationListener{ if(preventDuplicates){ for(Player player : playerGroup.all()){ if(player.name.trim().equalsIgnoreCase(packet.name.trim())){ - kick(id, KickReason.nameInUse); + con.kick(KickReason.nameInUse); return; } if(player.uuid.equals(packet.uuid) || player.usid.equals(packet.usid)){ - kick(id, KickReason.idInUse); + con.kick(KickReason.idInUse); return; } } @@ -134,28 +134,26 @@ public class NetServer implements ApplicationListener{ packet.name = fixName(packet.name); if(packet.name.trim().length() <= 0){ - kick(id, KickReason.nameEmpty); + con.kick(KickReason.nameEmpty); return; } - Log.debug("Recieved connect packet for player '{0}' / UUID {1} / IP {2}", packet.name, uuid, connection.address); - - String ip = Net.getConnection(id).address; + String ip = con.address; admins.updatePlayerJoined(uuid, ip, packet.name); if(packet.version != Version.build && Version.build != -1 && packet.version != -1){ - kick(id, packet.version > Version.build ? KickReason.serverOutdated : KickReason.clientOutdated); + con.kick(packet.version > Version.build ? KickReason.serverOutdated : KickReason.clientOutdated); return; } if(packet.version == -1){ - connection.modclient = true; + con.modclient = true; } Player player = new Player(); player.isAdmin = admins.isAdmin(uuid, packet.usid); - player.con = Net.getConnection(id); + player.con = con; player.usid = packet.usid; player.name = packet.name; player.uuid = uuid; @@ -170,27 +168,28 @@ public class NetServer implements ApplicationListener{ player.write(outputBuffer); }catch(Throwable t){ t.printStackTrace(); - kick(id, KickReason.nameEmpty); + con.kick(KickReason.nameEmpty); return; } + con.player = player; + //playing in pvp mode automatically assigns players to teams if(state.rules.pvp){ player.setTeam(assignTeam(player, playerGroup.all())); Log.info("Auto-assigned player {0} to team {1}.", player.name, player.getTeam()); } - connections.put(id, player); - - sendWorldData(player, id); + sendWorldData(player); platform.updateRPC(); + + Events.fire(new PlayerConnect(player)); }); - Net.handleServer(InvokePacket.class, (id, packet) -> { - Player player = connections.get(id); - if(player == null) return; - RemoteReadServer.readPacket(packet.writeBuffer, packet.type, player); + net.handleServer(InvokePacket.class, (con, packet) -> { + if(con.player == null) return; + RemoteReadServer.readPacket(packet.writeBuffer, packet.type, con.player); }); registerCommands(); @@ -228,32 +227,43 @@ public class NetServer implements ApplicationListener{ }); //duration of a a kick in seconds - int kickDuration = 10 * 60; + int kickDuration = 15 * 60; class VoteSession{ Player target; ObjectSet voted = new ObjectSet<>(); - ObjectMap map; + VoteSession[] map; Timer.Task task; int votes; - public VoteSession(ObjectMap map, Player target){ + public VoteSession(VoteSession[] map, Player target){ this.target = target; this.map = map; this.task = Timer.schedule(() -> { if(!checkPass()){ Call.sendMessage(Strings.format("[lightgray]Vote failed. Not enough votes to kick[orange] {0}[lightgray].", target.name)); + map[0] = null; + task.cancel(); } - map.remove(target); - task.cancel(); - }, 60 * 1.5f); + }, 60 * 1); + } + + void vote(Player player, int d){ + votes += d; + voted.addAll(player.uuid, admins.getInfo(player.uuid).lastIP); + + Call.sendMessage(Strings.format("[orange]{0}[lightgray] has voted to kick[orange] {1}[].[accent] ({2}/{3})\n[lightgray]Type[orange] /vote [] to agree.", + player.name, target.name, votes, votesRequired())); + //checkPass(); } boolean checkPass(){ if(votes >= votesRequired() && target.isAdded() && target.con.isConnected()){ Call.sendMessage(Strings.format("[orange]Vote passed.[scarlet] {0}[orange] will be kicked from the server.", target.name)); admins.getInfo(target.uuid).lastKicked = Time.millis() + kickDuration*1000; - kick(target.con.id, KickReason.vote); + target.con.kick(KickReason.vote); + map[0] = null; + task.cancel(); return true; } return false; @@ -261,10 +271,10 @@ public class NetServer implements ApplicationListener{ } //cooldown between votes - int voteTime = 60 * 10; + int voteTime = 60 * 5; Timekeeper vtime = new Timekeeper(voteTime); //current kick sessions - ObjectMap currentlyKicking = new ObjectMap<>(); + VoteSession[] currentlyKicking = {null}; clientCommands.register("votekick", "[player...]", "Vote to kick a player, with a cooldown.", (args, player) -> { if(playerGroup.size() < 3){ @@ -272,8 +282,8 @@ public class NetServer implements ApplicationListener{ return; } - if(currentlyKicking.values().toArray().contains(v -> v.voted.contains(player.uuid) || v.voted.contains(admins.getInfo(player.uuid).lastIP))){ - player.sendMessage("[scarlet]You've already voted. Sit down."); + if(player.isLocal){ + player.sendMessage("[scarlet]Just kick them yourself if you're the host."); return; } @@ -283,37 +293,33 @@ public class NetServer implements ApplicationListener{ for(Player p : playerGroup.all()){ if(p.isAdmin || p.con == null || p == player) continue; - builder.append("[lightgray] ").append(p.name).append("[accent] (#").append(p.con.id).append(")\n"); + builder.append("[lightgray] ").append(p.name).append("[accent] (#").append(p.id).append(")\n"); } player.sendMessage(builder.toString()); }else{ Player found; if(args[0].length() > 1 && args[0].startsWith("#") && Strings.canParseInt(args[0].substring(1))){ int id = Strings.parseInt(args[0].substring(1)); - found = playerGroup.find(p -> p.con != null && p.con.id == id); + found = playerGroup.find(p -> p.id == id); }else{ found = playerGroup.find(p -> p.name.equalsIgnoreCase(args[0])); } if(found != null){ - if(player == found){ - player.sendMessage("[scarlet]If you're interested in kicking yourself, just leave."); - }else if(found.isAdmin){ + if(found.isAdmin){ player.sendMessage("[scarlet]Did you really expect to be able to kick an admin?"); + }else if(found.isLocal){ + player.sendMessage("[scarlet]Local players cannot be kicked."); }else{ - if(!currentlyKicking.containsKey(found) && !vtime.get()){ + if(!vtime.get()){ player.sendMessage("[scarlet]You must wait " + voteTime/60 + " minutes between votekicks."); return; } - VoteSession session = currentlyKicking.getOr(found, () -> new VoteSession(currentlyKicking, found)); - session.votes ++; - session.voted.addAll(player.uuid, admins.getInfo(player.uuid).lastIP); - - Call.sendMessage(Strings.format("[orange]{0}[lightgray] has voted to kick[orange] {1}[].[accent] ({2}/{3})\n[lightgray]Type[orange] /votekick #{4}[] to agree.", - player.name, found.name, session.votes, votesRequired(), found.con.id)); - session.checkPass(); - vtime.reset(); + VoteSession session = new VoteSession(currentlyKicking, found); + session.vote(player, 1); + vtime.reset(); + currentlyKicking[0] = session; } }else{ player.sendMessage("[scarlet]No player[orange]'" + args[0] + "'[scarlet] found."); @@ -321,18 +327,43 @@ public class NetServer implements ApplicationListener{ } }); + clientCommands.register("vote", "", "Vote to kick the current player.", (arg, player) -> { + if(currentlyKicking[0] == null){ + player.sendMessage("[scarlet]Nobody is being voted on."); + }else{ + if(currentlyKicking[0].voted.contains(player.uuid) || currentlyKicking[0].voted.contains(admins.getInfo(player.uuid).lastIP)){ + player.sendMessage("[scarlet]You've already voted. Sit down."); + return; + } + + if(currentlyKicking[0].target == player){ + player.sendMessage("[scarlet]You can't vote on your own trial."); + return; + } + + if(!arg[0].toLowerCase().equals("y") && !arg[0].toLowerCase().equals("n")){ + player.sendMessage("[scarlet]Vote either 'y' (yes) or 'n' (no)."); + return; + } + + int sign = arg[0].toLowerCase().equals("y") ? 1 : -1; + currentlyKicking[0].vote(player, sign); + } + }); + + clientCommands.register("sync", "Re-synchronize world state.", (args, player) -> { if(player.isLocal){ player.sendMessage("[scarlet]Re-synchronizing as the host is pointless."); }else{ - Call.onWorldDataBegin(player.con.id); - netServer.sendWorldData(player, player.con.id); + Call.onWorldDataBegin(player.con); + netServer.sendWorldData(player); } }); } public int votesRequired(){ - return playerGroup.size() * 2 / 3; + return 2 + (playerGroup.size() > 4 ? 1 : 0); } public Team assignTeam(Player current, Iterable players){ @@ -351,18 +382,18 @@ public class NetServer implements ApplicationListener{ }); } - public void sendWorldData(Player player, int clientID){ + public void sendWorldData(Player player){ ByteArrayOutputStream stream = new ByteArrayOutputStream(); DeflaterOutputStream def = new FastDeflaterOutputStream(stream); NetworkIO.writeWorld(player, def); WorldStream data = new WorldStream(); data.stream = new ByteArrayInputStream(stream.toByteArray()); - Net.sendStream(clientID, data); + player.con.sendStream(data); Log.debug("Packed {0} compressed bytes of world data.", stream.size()); } - public static void onDisconnect(Player player){ + public static void onDisconnect(Player player, String reason){ //singleplayer multiplayer wierdness if(player.con == null){ player.remove(); @@ -370,12 +401,12 @@ public class NetServer implements ApplicationListener{ } if(player.con.hasConnected){ + Events.fire(new PlayerLeave(player)); Call.sendMessage("[accent]" + player.name + "[accent] has disconnected."); Call.onPlayerDisconnect(player.id); } player.remove(); - netServer.connections.remove(player.con.id); - Log.info("&lm[{1}] &lc{0} has disconnected.", player.name, player.uuid); + Log.info("&lm[{1}] &lc{0} has disconnected. &lg&fi({2})", player.name, player.uuid, reason); } private static float compound(float speed, float drag){ @@ -456,7 +487,7 @@ public class NetServer implements ApplicationListener{ newx = x; newy = y; }else if(Mathf.dst(x, y, newx, newy) > correctDist){ - Call.onPositionSet(player.con.id, newx, newy); //teleport and correct position when necessary + Call.onPositionSet(player.con, newx, newy); //teleport and correct position when necessary } //reset player to previous synced position so it gets interpolated @@ -491,15 +522,15 @@ public class NetServer implements ApplicationListener{ state.wavetime = 0f; }else if(action == AdminAction.ban){ netServer.admins.banPlayerIP(other.con.address); - netServer.kick(other.con.id, KickReason.banned); + other.con.kick(KickReason.banned); Log.info("&lc{0} has banned {1}.", player.name, other.name); }else if(action == AdminAction.kick){ - netServer.kick(other.con.id, KickReason.kick); + other.con.kick(KickReason.kick); Log.info("&lc{0} has kicked {1}.", player.name, other.name); }else if(action == AdminAction.trace){ TraceInfo info = new TraceInfo(other.con.address, other.uuid, other.con.modclient, other.con.mobile); if(player.con != null){ - Call.onTraceInfo(player.con.id, other, info); + Call.onTraceInfo(player.con, other, info); }else{ NetClient.onTraceInfo(other, info); } @@ -515,6 +546,8 @@ public class NetServer implements ApplicationListener{ player.con.hasConnected = true; Call.sendMessage("[accent]" + player.name + "[accent] has connected."); Log.info("&lm[{1}] &y{0} has connected. ", player.name, player.uuid); + + Events.fire(new PlayerJoin(player)); } public boolean isWaitingForPlayers(){ @@ -532,51 +565,27 @@ public class NetServer implements ApplicationListener{ public void update(){ - if(!headless && !closing && Net.server() && state.is(State.menu)){ + if(!headless && !closing && net.server() && state.is(State.menu)){ closing = true; ui.loadfrag.show("$server.closing"); Time.runTask(5f, () -> { - Net.closeServer(); + net.closeServer(); ui.loadfrag.hide(); closing = false; }); } - if(!state.is(State.menu) && Net.server()){ + if(!state.is(State.menu) && net.server()){ sync(); } } public void kickAll(KickReason reason){ - for(NetConnection con : Net.getConnections()){ - kick(con.id, reason); + for(NetConnection con : net.getConnections()){ + con.kick(reason); } } - public void kick(int connection, KickReason reason){ - NetConnection con = Net.getConnection(connection); - if(con == null){ - Log.err("Cannot kick unknown player!"); - return; - }else{ - Log.info("Kicking connection #{0} / IP: {1}. Reason: {2}", connection, con.address, reason.name()); - } - - Player player = connections.get(con.id); - - if(player != null && (reason == KickReason.kick || reason == KickReason.banned || reason == KickReason.vote) && player.uuid != null){ - PlayerInfo info = admins.getInfo(player.uuid); - info.timesKicked++; - info.lastKicked = Math.max(Time.millis(), info.lastKicked); - } - - Call.onKick(connection, reason); - - Time.runTask(2f, con::close); - - admins.save(); - } - public void writeSnapshot(Player player) throws IOException{ syncStream.reset(); ObjectSet cores = state.teams.get(player.getTeam()).cores; @@ -592,7 +601,7 @@ public class NetServer implements ApplicationListener{ byte[] stateBytes = syncStream.toByteArray(); //write basic state data. - Call.onStateSnapshot(player.con.id, state.wavetime, state.wave, state.enemies(), (short)stateBytes.length, Net.compressSnapshot(stateBytes)); + Call.onStateSnapshot(player.con, state.wavetime, state.wave, state.enemies(), (short)stateBytes.length, net.compressSnapshot(stateBytes)); viewport.setSize(player.con.viewWidth, player.con.viewHeight).setCenter(player.con.viewX, player.con.viewY); @@ -623,7 +632,7 @@ public class NetServer implements ApplicationListener{ if(syncStream.size() > maxSnapshotSize){ dataStream.close(); byte[] syncBytes = syncStream.toByteArray(); - Call.onEntitySnapshot(player.con.id, (byte)group.getID(), (short)sent, (short)syncBytes.length, Net.compressSnapshot(syncBytes)); + Call.onEntitySnapshot(player.con, (byte)group.getID(), (short)sent, (short)syncBytes.length, net.compressSnapshot(syncBytes)); sent = 0; syncStream.reset(); } @@ -633,7 +642,7 @@ public class NetServer implements ApplicationListener{ dataStream.close(); byte[] syncBytes = syncStream.toByteArray(); - Call.onEntitySnapshot(player.con.id, (byte)group.getID(), (short)sent, (short)syncBytes.length, Net.compressSnapshot(syncBytes)); + Call.onEntitySnapshot(player.con, (byte)group.getID(), (short)sent, (short)syncBytes.length, net.compressSnapshot(syncBytes)); } } } @@ -699,9 +708,9 @@ public class NetServer implements ApplicationListener{ NetConnection connection = player.con; - if(connection == null || !connection.isConnected() || !connections.containsKey(connection.id)){ + if(connection == null || !connection.isConnected()){ //player disconnected, call d/c event - onDisconnect(player); + onDisconnect(player, "disappeared"); return; } diff --git a/core/src/io/anuke/mindustry/core/Platform.java b/core/src/io/anuke/mindustry/core/Platform.java index 085242a3f6..7ccb700499 100644 --- a/core/src/io/anuke/mindustry/core/Platform.java +++ b/core/src/io/anuke/mindustry/core/Platform.java @@ -1,18 +1,38 @@ package io.anuke.mindustry.core; -import io.anuke.arc.Core; -import io.anuke.arc.Input.TextInput; -import io.anuke.arc.files.FileHandle; -import io.anuke.arc.function.Consumer; -import io.anuke.arc.function.Predicate; -import io.anuke.arc.math.RandomXS128; -import io.anuke.arc.scene.ui.TextField; -import io.anuke.arc.util.serialization.Base64Coder; +import io.anuke.arc.*; +import io.anuke.arc.Input.*; +import io.anuke.arc.files.*; +import io.anuke.arc.function.*; +import io.anuke.arc.math.*; +import io.anuke.arc.scene.ui.*; +import io.anuke.arc.util.serialization.*; +import io.anuke.mindustry.maps.*; +import io.anuke.mindustry.net.*; +import io.anuke.mindustry.net.Net.*; +import io.anuke.mindustry.ui.dialogs.*; import static io.anuke.mindustry.Vars.mobile; public interface Platform{ + /** Steam: Update lobby visibility.*/ + default void updateLobby(){} + + /** Steam: Show multiplayer friend invite dialog.*/ + default void inviteFriends(){} + + /** Steam: Share a map on the workshop.*/ + default void publishMap(Map map){} + + /** Steam: Open workshop for maps.*/ + default void openWorkshop(){} + + /** Get the networking implementation.*/ + default NetProvider getNet(){ + return new ArcNetImpl(); + } + /** Add a text input dialog that should show up after the field is tapped. */ default void addDialog(TextField field){ addDialog(field, 16); @@ -36,11 +56,6 @@ public interface Platform{ }); } - /** Request external read/write perms. Run callback when complete.*/ - default void requestExternalPerms(Runnable callback){ - callback.run(); - } - /** Update discord RPC. */ default void updateRPC(){ } @@ -70,24 +85,29 @@ public interface Platform{ /** * Show a file chooser. - * @param text File chooser title text - * @param content Description of the type of files to be loaded * @param cons Selection listener * @param open Whether to open or save files - * @param filetype File extension to filter + * @param extension File extension to filter */ - default void showFileChooser(String text, String content, Consumer cons, boolean open, Predicate filetype){ + default void showFileChooser(boolean open, String extension, Consumer cons){ + new FileChooser(open ? "$open" : "$save", file -> file.extension().toLowerCase().equals(extension), open, file -> { + if(!open){ + cons.accept(file.parent().child(file.nameWithoutExtension() + "." + extension)); + }else{ + cons.accept(file); + } + }).show(); } /** Hide the app. Android only. */ default void hide(){ } - /** Forces the app into landscape mode. Currently Android only. */ + /** Forces the app into landscape mode.*/ default void beginForceLandscape(){ } - /** Stops forcing the app into landscape orientation. Currently Android only. */ + /** Stops forcing the app into landscape orientation.*/ default void endForceLandscape(){ } } \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/core/Renderer.java b/core/src/io/anuke/mindustry/core/Renderer.java index b23e46dc91..e5245d5e78 100644 --- a/core/src/io/anuke/mindustry/core/Renderer.java +++ b/core/src/io/anuke/mindustry/core/Renderer.java @@ -16,12 +16,13 @@ import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.effect.*; import io.anuke.mindustry.entities.effect.GroundEffectEntity.*; -import io.anuke.mindustry.entities.impl.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.entities.type.EffectEntity; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.*; import io.anuke.mindustry.graphics.*; +import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.blocks.defense.ForceProjector.*; import static io.anuke.arc.Core.*; @@ -36,8 +37,10 @@ public class Renderer implements ApplicationListener{ public FrameBuffer shieldBuffer = new FrameBuffer(2, 2); private Bloom bloom; private Color clearColor; - private float targetscale = UnitScl.dp.scl(4); + private float targetscale = Scl.scl(4); private float camerascale = targetscale; + private float landscale = 0f, landTime; + private float minZoomScl = Scl.scl(0.01f); private Rectangle rect = new Rectangle(), rect2 = new Rectangle(); private float shakeIntensity, shaketime; @@ -99,15 +102,22 @@ public class Renderer implements ApplicationListener{ @Override public void update(){ - //TODO hack, find source of this bug - Color.WHITE.set(1f, 1f, 1f, 1f); + Color.white.set(1f, 1f, 1f, 1f); camerascale = Mathf.lerpDelta(camerascale, targetscale, 0.1f); + + if(landTime > 0){ + landTime -= Time.delta(); + landscale = Interpolation.pow5In.apply(minZoomScl, Scl.scl(4f), 1f - landTime / Fx.coreLand.lifetime); + camerascale = landscale; + } + camera.width = graphics.getWidth() / camerascale; camera.height = graphics.getHeight() / camerascale; if(state.is(State.menu)){ - graphics.clear(Color.BLACK); + landTime = 0f; + graphics.clear(Color.black); }else{ Vector2 position = Tmp.v3.set(player); @@ -131,6 +141,10 @@ public class Renderer implements ApplicationListener{ } } + public float landScale(){ + return landTime > 0 ? landscale : 1f; + } + @Override public void dispose(){ minimap.dispose(); @@ -162,7 +176,7 @@ public class Renderer implements ApplicationListener{ e.printStackTrace(); settings.put("bloom", false); settings.save(); - ui.showError("$error.bloom"); + ui.showErrorMessage("$error.bloom"); } } @@ -257,13 +271,13 @@ public class Renderer implements ApplicationListener{ } overlays.drawBottom(); - playerGroup.draw(p -> true, Player::drawBuildRequests); + playerGroup.draw(p -> p.isLocal, Player::drawBuildRequests); if(shieldGroup.countInBounds() > 0){ if(settings.getBool("animatedshields") && Shaders.shield != null){ Draw.flush(); shieldBuffer.begin(); - graphics.clear(Color.CLEAR); + graphics.clear(Color.clear); shieldGroup.draw(); shieldGroup.draw(shield -> true, ShieldEntity::drawOver); Draw.flush(); @@ -282,10 +296,37 @@ public class Renderer implements ApplicationListener{ playerGroup.draw(p -> !p.isDead() && !p.isLocal, Player::drawName); + drawLanding(); + Draw.color(); Draw.flush(); } + private void drawLanding(){ + if(landTime > 0 && player.getClosestCore() != null){ + float fract = landTime / Fx.coreLand.lifetime; + TileEntity entity = player.getClosestCore(); + + TextureRegion reg = entity.block.icon(Block.Icon.full); + float scl = Scl.scl(4f) / camerascale; + float s = reg.getWidth() * Draw.scl * scl * 4f * fract; + + Draw.color(Pal.lightTrail); + Draw.rect("circle-shadow", entity.x, entity.y, s, s); + + Angles.randLenVectors(1, (1f- fract), 100, 1000f * scl * (1f-fract), (x, y, fin, fout) -> { + Lines.stroke(scl * fin); + Lines.lineAngle(entity.x + x, entity.y + y, Mathf.angle(x, y), (fin * 20 + 1f) * scl); + }); + + Draw.color(); + Draw.mixcol(Color.white, fract); + Draw.rect(reg, entity.x, entity.y, reg.getWidth() * Draw.scl * scl, reg.getHeight() * Draw.scl * scl, fract * 135f); + + Draw.reset(); + } + } + private void drawGroundShadows(){ Draw.color(0, 0, 0, 0.4f); float rad = 1.6f; @@ -348,7 +389,7 @@ public class Renderer implements ApplicationListener{ } public void clampScale(){ - float s = UnitScl.dp.scl(1f); + float s = Scl.scl(1f); targetscale = Mathf.clamp(targetscale, s * 1.5f, Math.round(s * 6)); } @@ -361,6 +402,11 @@ public class Renderer implements ApplicationListener{ clampScale(); } + public void zoomIn(float duration){ + landscale = minZoomScl; + landTime = duration; + } + public void takeMapScreenshot(){ drawGroundShadows(); diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index 194754f328..e649b974e2 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -3,6 +3,7 @@ package io.anuke.mindustry.core; import io.anuke.arc.*; import io.anuke.arc.Graphics.*; import io.anuke.arc.Graphics.Cursor.*; +import io.anuke.arc.Input.*; import io.anuke.arc.assets.*; import io.anuke.arc.assets.loaders.*; import io.anuke.arc.assets.loaders.resolvers.*; @@ -13,14 +14,13 @@ import io.anuke.arc.freetype.FreeTypeFontGenerator.*; import io.anuke.arc.freetype.FreetypeFontLoader.*; import io.anuke.arc.function.*; import io.anuke.arc.graphics.*; +import io.anuke.arc.graphics.Texture.*; import io.anuke.arc.graphics.g2d.*; -import io.anuke.arc.graphics.g2d.TextureAtlas.*; import io.anuke.arc.input.*; import io.anuke.arc.math.*; import io.anuke.arc.scene.*; import io.anuke.arc.scene.actions.*; import io.anuke.arc.scene.event.*; -import io.anuke.arc.scene.style.*; import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.TextField.*; import io.anuke.arc.scene.ui.Tooltip.*; @@ -31,6 +31,7 @@ import io.anuke.mindustry.editor.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; +import io.anuke.mindustry.ui.*; import io.anuke.mindustry.ui.dialogs.*; import io.anuke.mindustry.ui.fragments.*; @@ -38,8 +39,6 @@ import static io.anuke.arc.scene.actions.Actions.*; import static io.anuke.mindustry.Vars.*; public class UI implements ApplicationListener, Loadable{ - private Skin skin; - public MenuFragment menufrag; public HudFragment hudfrag; public ChatFragment chatfrag; @@ -73,7 +72,6 @@ public class UI implements ApplicationListener, Loadable{ public Cursor drillCursor, unloadCursor; public UI(){ - skin = new Skin(); setupFonts(); } @@ -84,22 +82,19 @@ public class UI implements ApplicationListener, Loadable{ @Override public void loadSync(){ - //TODO type-safe skin files - skin.addRegions(Core.atlas); - loadExtraStyle(skin); - skin.add("outline", Core.assets.get("outline")); - skin.getFont("outline").getData().markupEnabled = true; - skin.getFont("default").getData().markupEnabled = true; - skin.getFont("default").setOwnsTexture(false); - skin.load(Core.files.internal("sprites/uiskin.json")); + Fonts.outline.getData().markupEnabled = true; + Fonts.def.getData().markupEnabled = true; + Fonts.def.setOwnsTexture(false); - for(BitmapFont font : skin.getAll(BitmapFont.class).values()){ - font.setUseIntegerPositions(true); - } - - Core.scene = new Scene(skin); + Core.assets.getAll(BitmapFont.class, new Array<>()).each(font -> font.setUseIntegerPositions(true)); + Core.scene = new Scene(); Core.input.addProcessor(Core.scene); + Tex.load(); + Icon.load(); + Styles.load(); + Tex.loadStyles(); + Dialog.setShowAction(() -> sequence(alpha(0f), fadeIn(0.1f))); Dialog.setHideAction(() -> sequence(fadeOut(0.1f))); @@ -107,13 +102,13 @@ public class UI implements ApplicationListener, Loadable{ Core.settings.setErrorHandler(e -> { e.printStackTrace(); - Core.app.post(() -> showError("Failed to access local storage.\nSettings will not be saved.")); + Core.app.post(() -> showErrorMessage("Failed to access local storage.\nSettings will not be saved.")); }); ClickListener.clicked = () -> Sounds.press.play(); Colors.put("accent", Pal.accent); - Colors.put("highlight", Pal.accent.cpy().lerp(Color.WHITE, 0.3f)); + Colors.put("highlight", Pal.accent.cpy().lerp(Color.white, 0.3f)); Colors.put("stat", Pal.stat); loadExtraCursors(); } @@ -140,39 +135,22 @@ public class UI implements ApplicationListener, Loadable{ @Override public BitmapFont loadSync(AssetManager manager, String fileName, FileHandle file, FreeTypeFontLoaderParameter parameter){ if(fileName.equals("outline")){ - parameter.fontParameters.borderWidth = UnitScl.dp.scl(2f); + parameter.fontParameters.borderWidth = Scl.scl(2f); parameter.fontParameters.spaceX -= parameter.fontParameters.borderWidth; } + parameter.fontParameters.magFilter = TextureFilter.Linear; + parameter.fontParameters.minFilter = TextureFilter.Linear; parameter.fontParameters.size = fontParameter().size; return super.loadSync(manager, fileName, file, parameter); } }); FreeTypeFontParameter param = new FreeTypeFontParameter(){{ - borderColor = Color.DARK_GRAY; + borderColor = Color.darkGray; incremental = true; }}; - Core.assets.load("outline", BitmapFont.class, new FreeTypeFontLoaderParameter("fonts/font.ttf", param)); - } - - void loadExtraStyle(Skin skin){ - AtlasRegion region = Core.atlas.find("flat-down-base"); - int[] splits = region.splits; - - ScaledNinePatchDrawable copy = new ScaledNinePatchDrawable(new NinePatch(region, splits[0], splits[1], splits[2], splits[3])){ - public float getLeftWidth(){ return 0; } - public float getRightWidth(){ return 0; } - public float getTopHeight(){ return 0; } - public float getBottomHeight(){ return 0; } - }; - copy.setMinWidth(0); - copy.setMinHeight(0); - copy.setTopHeight(0); - copy.setRightWidth(0); - copy.setBottomHeight(0); - copy.setLeftWidth(0); - skin.add("flat-down", copy, Drawable.class); + Core.assets.load("outline", BitmapFont.class, new FreeTypeFontLoaderParameter("fonts/font.ttf", param)).loaded = t -> Fonts.outline = (BitmapFont)t; } void loadExtraCursors(){ @@ -185,14 +163,14 @@ public class UI implements ApplicationListener, Loadable{ FreeTypeFontParameter param = fontParameter(); - Core.assets.load("default", BitmapFont.class, new FreeTypeFontLoaderParameter(fontName, param)).loaded = f -> skin.add("default", f); - Core.assets.load("chat", BitmapFont.class, new FreeTypeFontLoaderParameter(fontName, param)).loaded = f -> skin.add("chat", f); + Core.assets.load("default", BitmapFont.class, new FreeTypeFontLoaderParameter(fontName, param)).loaded = f -> Fonts.def = (BitmapFont)f; + Core.assets.load("chat", BitmapFont.class, new FreeTypeFontLoaderParameter(fontName, param)).loaded = f -> Fonts.chat = (BitmapFont)f; } static FreeTypeFontParameter fontParameter(){ return new FreeTypeFontParameter(){{ - size = (int)(UnitScl.dp.scl(18f)); - shadowColor = Color.DARK_GRAY; + size = (int)(Scl.scl(18f)); + shadowColor = Color.darkGray; shadowOffsetY = 2; incremental = true; }}; @@ -290,28 +268,37 @@ public class UI implements ApplicationListener, Loadable{ }); } - public void showTextInput(String titleText, String text, int textLength, String def, TextFieldFilter filter, Consumer confirmed){ - new Dialog(titleText, "dialog"){{ - cont.margin(30).add(text).padRight(6f); - TextField field = cont.addField(def, t -> { - }).size(170f, 50f).get(); - field.setFilter((f, c) -> field.getText().length() < textLength && filter.acceptChar(f, c)); - platform.addDialog(field); - buttons.defaults().size(120, 54).pad(4); - buttons.addButton("$ok", () -> { - confirmed.accept(field.getText()); - hide(); - }).disabled(b -> field.getText().isEmpty()); - buttons.addButton("$cancel", this::hide); - }}.show(); + public void showTextInput(String titleText, String dtext, int textLength, String def, boolean inumeric, Consumer confirmed){ + if(mobile){ + Core.input.getTextInput(new TextInput(){{ + this.title = (titleText.startsWith("$") ? Core.bundle.get(titleText.substring(1)) : titleText); + this.text = def; + this.numeric = inumeric; + this.maxLength = textLength; + this.accepted = confirmed; + }}); + }else{ + new Dialog(titleText){{ + cont.margin(30).add(dtext).padRight(6f); + TextFieldFilter filter = inumeric ? TextFieldFilter.digitsOnly : (f, c) -> true; + TextField field = cont.addField(def, t -> {}).size(170f, 50f).get(); + field.setFilter((f, c) -> field.getText().length() < textLength && filter.acceptChar(f, c)); + buttons.defaults().size(120, 54).pad(4); + buttons.addButton("$ok", () -> { + confirmed.accept(field.getText()); + hide(); + }).disabled(b -> field.getText().isEmpty()); + buttons.addButton("$cancel", this::hide); + }}.show(); + } } public void showTextInput(String title, String text, String def, Consumer confirmed){ - showTextInput(title, text, 12, def, (field, c) -> true, confirmed); + showTextInput(title, text, 24, def, confirmed); } - public void showTextInput(String title, String text, int textLength, String def, Consumer confirmed){ - showTextInput(title, text, textLength < 0 ? 12 : textLength, def, (field, c) -> true, confirmed); + public void showTextInput(String titleText, String text, int textLength, String def, Consumer confirmed){ + showTextInput(titleText, text, textLength, def, false, confirmed); } public void showInfoFade(String info){ @@ -323,43 +310,75 @@ public class UI implements ApplicationListener, Loadable{ } public void showInfo(String info){ - new Dialog("", "dialog"){{ + new Dialog(""){{ getCell(cont).growX(); cont.margin(15).add(info).width(400f).wrap().get().setAlignment(Align.center, Align.center); buttons.addButton("$ok", this::hide).size(90, 50).pad(4); }}.show(); } - public void showError(String text){ - new Dialog("", "dialog"){{ - setFillParent(true); + public void showErrorMessage(String text){ + new Dialog(""){{ + setFillParent(false); + cont.margin(15f); cont.add("$error.title"); cont.row(); - cont.margin(15).pane(t -> { - Label l = t.add(text).pad(14f).get(); - l.setAlignment(Align.center, Align.left); - if(mobile){ - t.getCell(l).wrap().width(400f); - } - }); - buttons.addButton("$ok", this::hide).size(90, 50).pad(4); + cont.addImage().fillX().pad(2).height(4f).color(Color.scarlet); + cont.row(); + cont.add(text).pad(2f); + buttons.addButton("$ok", this::hide).size(120, 50).pad(4); + }}.show(); + } + + public void showException(Throwable t){ + showException("", t); + } + + public void showException(String text, Throwable exc){ + new Dialog(""){{ + String message = Strings.getFinalMesage(exc); + + setFillParent(true); + cont.margin(15); + cont.add("$error.title").colspan(2); + cont.row(); + cont.addImage().width(300f).pad(2).colspan(2).height(4f).color(Color.scarlet); + cont.row(); + cont.add((text.startsWith("$") ? Core.bundle.get(text.substring(1)) : text) + (message == null ? "" : "\n[lightgray](" + message + ")")).colspan(2).wrap().growX().center().get().setAlignment(Align.center); + cont.row(); + + Collapser col = new Collapser(base -> base.pane(t -> t.margin(14f).add(Strings.parseException(exc, true)).color(Color.lightGray).left()), true); + + cont.addButton("$details", Styles.togglet, col::toggle).size(180f, 50f).checked(b -> !col.isCollapsed()).fillX().right(); + cont.addButton("$ok", this::hide).size(100, 50).fillX().left(); + cont.row(); + cont.add(col).colspan(2).pad(2); }}.show(); } public void showText(String titleText, String text){ - new Dialog(titleText, "dialog"){{ + new Dialog(titleText){{ cont.margin(15).add(text).width(400f).wrap().get().setAlignment(Align.center, Align.center); buttons.addButton("$ok", this::hide).size(90, 50).pad(4); }}.show(); } public void showInfoText(String titleText, String text){ - new Dialog(titleText, "dialog"){{ + new Dialog(titleText){{ cont.margin(15).add(text).width(400f).wrap().left().get().setAlignment(Align.left, Align.left); buttons.addButton("$ok", this::hide).size(90, 50).pad(4); }}.show(); } + public void showSmall(String titleText, String text){ + new Dialog(titleText){{ + cont.margin(10).add(text); + titleTable.row(); + titleTable.addImage().color(Pal.accent).height(3f).growX().pad(2f); + buttons.addButton("$ok", this::hide).size(90, 50).pad(4); + }}.show(); + } + public void showConfirm(String title, String text, Runnable confirmed){ showConfirm(title, text, null, confirmed); } diff --git a/core/src/io/anuke/mindustry/core/World.java b/core/src/io/anuke/mindustry/core/World.java index 5f47708369..26e0441e8a 100644 --- a/core/src/io/anuke/mindustry/core/World.java +++ b/core/src/io/anuke/mindustry/core/World.java @@ -215,7 +215,7 @@ public class World{ }catch(Exception e){ Log.err(e); if(!headless){ - ui.showError("$map.invalid"); + ui.showErrorMessage("$map.invalid"); Core.app.post(() -> state.set(State.menu)); invalidMap = true; } @@ -229,7 +229,7 @@ public class World{ if(!headless){ if(state.teams.get(defaultTeam).cores.size == 0 && !checkRules.pvp){ - ui.showError("$map.nospawn"); + ui.showErrorMessage("$map.nospawn"); invalidMap = true; }else if(checkRules.pvp){ //pvp maps need two cores to be valid int teams = 0; @@ -240,12 +240,12 @@ public class World{ } if(teams < 2){ invalidMap = true; - ui.showError("$map.nospawn.pvp"); + ui.showErrorMessage("$map.nospawn.pvp"); } }else if(checkRules.attackMode){ //attack maps need two cores to be valid invalidMap = state.teams.get(waveTeam).cores.isEmpty(); if(invalidMap){ - ui.showError("$map.nospawn.attack"); + ui.showErrorMessage("$map.nospawn.attack"); } } }else{ diff --git a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java index ab62680ddb..8f2dd20d92 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java @@ -13,19 +13,19 @@ import io.anuke.arc.scene.actions.*; import io.anuke.arc.scene.event.*; import io.anuke.arc.scene.style.*; import io.anuke.arc.scene.ui.*; -import io.anuke.arc.scene.ui.TextButton.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.game.*; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.io.*; import io.anuke.mindustry.maps.*; +import io.anuke.mindustry.ui.Styles; import io.anuke.mindustry.ui.dialogs.*; import io.anuke.mindustry.world.*; -import io.anuke.mindustry.world.Block.*; import io.anuke.mindustry.world.blocks.*; import io.anuke.mindustry.world.blocks.storage.*; @@ -47,9 +47,9 @@ public class MapEditorDialog extends Dialog implements Disposable{ private Array blocksOut = new Array<>(); public MapEditorDialog(){ - super("", "dialog"); + super(""); - background("dark"); + background(Styles.black); editor = new MapEditor(); view = new MapView(editor); @@ -59,27 +59,26 @@ public class MapEditorDialog extends Dialog implements Disposable{ menu = new FloatingDialog("$menu"); menu.addCloseButton(); - float isize = iconsize; float swidth = 180f; menu.cont.table(t -> { t.defaults().size(swidth, 60f).padBottom(5).padRight(5).padLeft(5); - t.addImageTextButton("$editor.savemap", "icon-floppy-16", isize, this::save); + t.addImageTextButton("$editor.savemap", Icon.floppy16Small, this::save); - t.addImageTextButton("$editor.mapinfo", "icon-pencil", isize, () -> { + t.addImageTextButton("$editor.mapinfo", Icon.pencilSmall, () -> { infoDialog.show(); menu.hide(); }); t.row(); - t.addImageTextButton("$editor.generate", "icon-editor", isize, () -> { + t.addImageTextButton("$editor.generate", Icon.editorSmall, () -> { generateDialog.show(generateDialog::applyToEditor); menu.hide(); }); - t.addImageTextButton("$editor.resize", "icon-resize", isize, () -> { + t.addImageTextButton("$editor.resize", Icon.resizeSmall, () -> { resizeDialog.show(); menu.hide(); }); @@ -87,54 +86,50 @@ public class MapEditorDialog extends Dialog implements Disposable{ t.row(); if(!ios){ - t.addImageTextButton("$editor.import", "icon-load-map", isize, () -> + t.addImageTextButton("$editor.import", Icon.loadMapSmall, () -> createDialog("$editor.import", - "$editor.importmap", "$editor.importmap.description", "icon-load-map", (Runnable)loadDialog::show, - "$editor.importfile", "$editor.importfile.description", "icon-file", (Runnable)() -> - platform.showFileChooser("$editor.loadmap", "Map Files", file -> ui.loadAnd(() -> { + "$editor.importmap", "$editor.importmap.description", Icon.loadMap, (Runnable)loadDialog::show, + "$editor.importfile", "$editor.importfile.description", Icon.file, (Runnable)() -> + platform.showFileChooser(true, mapExtension, file -> ui.loadAnd(() -> { maps.tryCatchMapError(() -> { if(MapIO.isImage(file)){ ui.showInfo("$editor.errorimage"); - }else if(file.extension().equalsIgnoreCase(oldMapExtension)){ - editor.beginEdit(maps.makeLegacyMap(file)); }else{ editor.beginEdit(MapIO.createMap(file, true)); } }); - }), true, FileChooser.anyMapFiles), + })), - "$editor.importimage", "$editor.importimage.description", "icon-file-image", (Runnable)() -> - platform.showFileChooser("$loadimage", "Image Files", file -> + "$editor.importimage", "$editor.importimage.description", Icon.fileImage, (Runnable)() -> + platform.showFileChooser(true, "png", file -> ui.loadAnd(() -> { try{ Pixmap pixmap = new Pixmap(file); editor.beginEdit(pixmap); pixmap.dispose(); }catch(Exception e){ - ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, true))); + ui.showException("$editor.errorload", e); Log.err(e); } - }), true, FileChooser.pngFiles)) + }))) ); } - Cell cell = t.addImageTextButton("$editor.export", "icon-save-map", isize, () -> { + Cell cell = t.addImageTextButton("$editor.export", Icon.saveMapSmall, () -> { if(!ios){ - platform.showFileChooser("$editor.savemap", "Map Files", file -> { - file = file.parent().child(file.nameWithoutExtension() + "." + mapExtension); - FileHandle result = file; + platform.showFileChooser(false, mapExtension, file -> { ui.loadAnd(() -> { try{ if(!editor.getTags().containsKey("name")){ - editor.getTags().put("name", result.nameWithoutExtension()); + editor.getTags().put("name", file.nameWithoutExtension()); } - MapIO.writeMap(result, editor.createMap(result)); + MapIO.writeMap(file, editor.createMap(file)); }catch(Exception e){ - ui.showError(Core.bundle.format("editor.errorsave", Strings.parseException(e, true))); + ui.showException("$editor.errorsave", e); Log.err(e); } }); - }, false, FileChooser.mapFiles); + }); }else{ ui.loadAnd(() -> { try{ @@ -142,7 +137,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ MapIO.writeMap(result, editor.createMap(result)); platform.shareFile(result); }catch(Exception e){ - ui.showError(Core.bundle.format("editor.errorsave", Strings.parseException(e, true))); + ui.showException("$editor.errorsave", e); Log.err(e); } }); @@ -156,11 +151,22 @@ public class MapEditorDialog extends Dialog implements Disposable{ menu.cont.row(); - menu.cont.addImageTextButton("$editor.ingame", "icon-arrow", isize, this::playtest).padTop(-5).size(swidth * 2f + 10, 60f); + if(steam){ + menu.cont.addImageTextButton("$editor.publish.workshop", Icon.linkSmall, () -> { + Map map = save(); + if(map != null){ + platform.publishMap(map); + } + }).padTop(-3).size(swidth * 2f + 10, 60f); + + menu.cont.row(); + } + + menu.cont.addImageTextButton("$editor.ingame", Icon.arrowSmall, this::playtest).padTop(!steam ? -3 : 1).size(swidth * 2f + 10, 60f); menu.cont.row(); - menu.cont.addImageTextButton("$quit", "icon-back", isize, () -> { + menu.cont.addImageTextButton("$quit", Icon.backSmall, () -> { tryExit(); menu.hide(); }).size(swidth * 2f + 10, 60f); @@ -177,7 +183,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ try{ editor.beginEdit(map); }catch(Exception e){ - ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, true))); + ui.showException("$editor.errorload", e); Log.err(e); } })); @@ -186,7 +192,6 @@ public class MapEditorDialog extends Dialog implements Disposable{ clearChildren(); margin(0); - shown(this::build); update(() -> { if(Core.scene.getKeyboardFocus() instanceof Dialog && Core.scene.getKeyboardFocus() != this){ @@ -228,11 +233,8 @@ public class MapEditorDialog extends Dialog implements Disposable{ platform.updateRPC(); if(!Core.settings.getBool("landscape")) platform.endForceLandscape(); }); - } - @Override - protected void drawBackground(float x, float y){ - drawDefaultBackground(x, y); + shown(this::build); } public void resumeEditing(){ @@ -274,33 +276,36 @@ public class MapEditorDialog extends Dialog implements Disposable{ }); } - private void save(){ + private Map save(){ String name = editor.getTags().get("name", "").trim(); editor.getTags().put("rules", JsonIO.write(state.rules)); editor.getTags().remove("width"); editor.getTags().remove("height"); player.dead = true; + Map returned = null; + if(name.isEmpty()){ infoDialog.show(); - Core.app.post(() -> ui.showError("$editor.save.noname")); + Core.app.post(() -> ui.showErrorMessage("$editor.save.noname")); }else{ Map map = maps.all().find(m -> m.name().equals(name)); if(map != null && !map.custom){ handleSaveBuiltin(map); }else{ - maps.saveMap(editor.getTags()); + returned = maps.saveMap(editor.getTags()); ui.showInfoFade("$editor.saved"); } } menu.hide(); saved = true; + return returned; } /** Called when a built-in map save is attempted.*/ protected void handleSaveBuiltin(Map map){ - ui.showError("$editor.save.overwrite"); + ui.showErrorMessage("$editor.save.overwrite"); } /** @@ -320,7 +325,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ for(int i = 0; i < arguments.length; i += 4){ String name = (String)arguments[i]; String description = (String)arguments[i + 1]; - String iconname = (String)arguments[i + 2]; + Drawable iconname = (Drawable)arguments[i + 2]; Runnable listenable = (Runnable)arguments[i + 3]; TextButton button = dialog.cont.addButton(name, () -> { @@ -330,11 +335,11 @@ public class MapEditorDialog extends Dialog implements Disposable{ }).left().margin(0).get(); button.clearChildren(); - button.addImage(iconname).size(iconsize).padLeft(10); + button.addImage(iconname).padLeft(10); button.table(t -> { t.add(name).growX().wrap(); t.row(); - t.add(description).color(Color.GRAY).growX().wrap(); + t.add(description).color(Color.gray).growX().wrap(); }).growX().pad(10f).padLeft(5); button.row(); @@ -369,7 +374,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ show(); }catch(Exception e){ Log.err(e); - ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, true))); + ui.showException("$editor.errorload", e); } }); } @@ -407,14 +412,13 @@ public class MapEditorDialog extends Dialog implements Disposable{ Consumer addTool = tool -> { - ImageButton button = new ImageButton("icon-" + tool.name() + "-small", "clear-toggle"); + ImageButton button = new ImageButton(Core.atlas.drawable("icon-" + tool.name() + "-small"), Styles.clearTogglei); button.clicked(() -> { view.setTool(tool); if(lastTable[0] != null){ lastTable[0].remove(); } }); - button.resizeImage(iconsizesmall); button.update(() -> button.setChecked(view.getTool() == tool)); group.add(button); @@ -434,7 +438,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ lastTable[0].remove(); } - Table table = new Table("dialogDim"); + Table table = new Table(Styles.black9); table.defaults().size(300f, 70f); for(int i = 0; i < tool.altModes.length; i++){ @@ -444,10 +448,10 @@ public class MapEditorDialog extends Dialog implements Disposable{ table.addButton(b -> { b.left(); b.marginLeft(6); - b.setStyle(Core.scene.skin.get("clear-toggle", TextButtonStyle.class)); + b.setStyle(Styles.clearTogglet); b.add(Core.bundle.get("toolmode." + name)).left(); b.row(); - b.add(Core.bundle.get("toolmode." + name + ".description")).color(Color.LIGHT_GRAY).left(); + b.add(Core.bundle.get("toolmode." + name + ".description")).color(Color.lightGray).left(); }, () -> { tool.mode = (tool.mode == mode ? -1 : mode); table.remove(); @@ -484,16 +488,16 @@ public class MapEditorDialog extends Dialog implements Disposable{ tools.defaults().size(size, size); - tools.addImageButton("icon-menu-large-small", "clear", iconsizesmall, menu::show); + tools.addImageButton(Icon.menuLargeSmall, Styles.cleari, menu::show); - ImageButton grid = tools.addImageButton("icon-grid-small", "clear-toggle", iconsizesmall, () -> view.setGrid(!view.isGrid())).get(); + ImageButton grid = tools.addImageButton(Icon.gridSmall, Styles.clearTogglei, () -> view.setGrid(!view.isGrid())).get(); addTool.accept(EditorTool.zoom); tools.row(); - ImageButton undo = tools.addImageButton("icon-undo-small", "clear", iconsizesmall, editor::undo).get(); - ImageButton redo = tools.addImageButton("icon-redo-small", "clear", iconsizesmall, editor::redo).get(); + ImageButton undo = tools.addImageButton(Icon.undoSmall, Styles.cleari, editor::undo).get(); + ImageButton redo = tools.addImageButton(Icon.redoSmall, Styles.cleari, editor::redo).get(); addTool.accept(EditorTool.pick); @@ -502,8 +506,8 @@ public class MapEditorDialog extends Dialog implements Disposable{ undo.setDisabled(() -> !editor.canUndo()); redo.setDisabled(() -> !editor.canRedo()); - undo.update(() -> undo.getImage().setColor(undo.isDisabled() ? Color.GRAY : Color.WHITE)); - redo.update(() -> redo.getImage().setColor(redo.isDisabled() ? Color.GRAY : Color.WHITE)); + undo.update(() -> undo.getImage().setColor(undo.isDisabled() ? Color.gray : Color.white)); + redo.update(() -> redo.getImage().setColor(redo.isDisabled() ? Color.gray : Color.white)); grid.update(() -> grid.setChecked(view.isGrid())); addTool.accept(EditorTool.line); @@ -515,7 +519,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ addTool.accept(EditorTool.fill); addTool.accept(EditorTool.spray); - ImageButton rotate = tools.addImageButton("icon-arrow-16-small", "clear", iconsizesmall, () -> editor.rotation = (editor.rotation + 1) % 4).get(); + ImageButton rotate = tools.addImageButton(Icon.arrow16Small, Styles.cleari, () -> editor.rotation = (editor.rotation + 1) % 4).get(); rotate.getImage().update(() -> { rotate.getImage().setRotation(editor.rotation * 90); rotate.getImage().setOrigin(Align.center); @@ -523,7 +527,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ tools.row(); - tools.table("underline", t -> t.add("$editor.teams")) + tools.table(Tex.underline, t -> t.add("$editor.teams")) .colspan(3).height(40).width(size * 3f + 3f).padBottom(3); tools.row(); @@ -533,7 +537,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ int i = 0; for(Team team : Team.all){ - ImageButton button = new ImageButton("whiteui", "clear-toggle-partial"); + ImageButton button = new ImageButton(Tex.whiteui, Styles.clearTogglePartiali); button.margin(4f); button.getImageCell().grow(); button.getStyle().imageUpColor = team.color; @@ -549,7 +553,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ mid.row(); - mid.table("underline", t -> { + mid.table(Tex.underline, t -> { Slider slider = new Slider(0, MapEditor.brushSizes.length - 1, 1, false); slider.moved(f -> editor.brushSize = MapEditor.brushSizes[(int)(float)f]); for(int j = 0; j < MapEditor.brushSizes.length; j++){ @@ -578,7 +582,6 @@ public class MapEditorDialog extends Dialog implements Disposable{ if(Core.input.ctrl()){ //alt mode select - //TODO these keycode are unusable, tweak later for(int i = 0; i < view.getTool().altModes.length + 1; i++){ if(Core.input.keyTap(KeyCode.valueOf("NUM_" + (i + 1)))){ view.getTool().mode = i - 1; @@ -681,11 +684,11 @@ public class MapEditorDialog extends Dialog implements Disposable{ }); for(Block block : blocksOut){ - TextureRegion region = block.icon(Icon.medium); + TextureRegion region = block.icon(Block.Icon.medium); if(!Core.atlas.isFound(region)) continue; - ImageButton button = new ImageButton("whiteui", "clear-toggle"); + ImageButton button = new ImageButton(Tex.whiteui, Styles.clearTogglei); button.getStyle().imageUp = new TextureRegionDrawable(region); button.clicked(() -> editor.drawBlock = block); button.resizeImage(8 * 4f); @@ -700,7 +703,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ group.getButtons().get(2).setChecked(true); - table.table("underline", extra -> extra.labelWrap(() -> editor.drawBlock.localizedName).width(200f).center()).growX(); + table.table(Tex.underline, extra -> extra.labelWrap(() -> editor.drawBlock.localizedName).width(200f).center()).growX(); table.row(); table.add(pane).growY().fillX(); } diff --git a/core/src/io/anuke/mindustry/editor/MapGenerateDialog.java b/core/src/io/anuke/mindustry/editor/MapGenerateDialog.java index 1538318170..7acee240e7 100644 --- a/core/src/io/anuke/mindustry/editor/MapGenerateDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapGenerateDialog.java @@ -8,10 +8,12 @@ import io.anuke.arc.graphics.Pixmap.*; import io.anuke.arc.math.*; import io.anuke.arc.math.geom.*; import io.anuke.arc.scene.ui.*; +import io.anuke.arc.scene.ui.ImageButton.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.arc.util.async.*; import io.anuke.mindustry.game.*; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.io.*; import io.anuke.mindustry.maps.filters.*; @@ -84,7 +86,7 @@ public class MapGenerateDialog extends FloatingDialog{ update(); }).size(160f, 64f); - buttons.addImageTextButton("$add", "icon-add", iconsize, this::showAdd).height(64f).width(140f); + buttons.addImageTextButton("$add", Icon.add, this::showAdd).height(64f).width(140f); if(!applied){ hidden(this::apply); @@ -176,10 +178,8 @@ public class MapGenerateDialog extends FloatingDialog{ } } }, new Stack(){{ - add(new Image("loadDim")); - add(new Image("icon-refresh"){{ - setScaling(Scaling.none); - }}); + add(new Image(Styles.black8)); + add(new Image(Icon.refresh, Scaling.none)); visible(() -> generating && !updateEditorOnChange); }}).grow().padRight(10); t.pane(p -> filterTable = p.marginRight(6)).update(pane -> { @@ -216,7 +216,7 @@ public class MapGenerateDialog extends FloatingDialog{ } void rebuildFilters(){ - int cols = Math.max((int)(Math.max(filterTable.getParent().getWidth(), Core.graphics.getWidth()/2f * 0.9f) / UnitScl.dp.scl(290f)), 1); + int cols = Math.max((int)(Math.max(filterTable.getParent().getWidth(), Core.graphics.getWidth()/2f * 0.9f) / Scl.scl(290f)), 1); filterTable.clearChildren(); filterTable.top().left(); int i = 0; @@ -224,7 +224,7 @@ public class MapGenerateDialog extends FloatingDialog{ for(GenerateFilter filter : filters){ //main container - filterTable.table("button", c -> { + filterTable.table(Tex.button, c -> { //icons to perform actions c.table(t -> { t.top(); @@ -233,26 +233,26 @@ public class MapGenerateDialog extends FloatingDialog{ t.row(); t.table(b -> { - String style = "clear"; + ImageButtonStyle style = Styles.cleari; b.defaults().size(50f); - b.addImageButton("icon-refresh-small", style, iconsizesmall, () -> { + b.addImageButton(Icon.refreshSmall, style, () -> { filter.randomize(); update(); }); - b.addImageButton("icon-arrow-up-small", style, iconsizesmall, () -> { + b.addImageButton(Icon.arrowUpSmall, style, () -> { int idx = filters.indexOf(filter); filters.swap(idx, Math.max(0, idx - 1)); rebuildFilters(); update(); }); - b.addImageButton("icon-arrow-down-small",style, iconsizesmall, () -> { + b.addImageButton(Icon.arrowDownSmall, style, () -> { int idx = filters.indexOf(filter); filters.swap(idx, Math.min(filters.size - 1, idx + 1)); rebuildFilters(); update(); }); - b.addImageButton("icon-trash-small", style, iconsizesmall, () -> { + b.addImageButton(Icon.trashSmall, style, () -> { filters.remove(filter); rebuildFilters(); update(); diff --git a/core/src/io/anuke/mindustry/editor/MapInfoDialog.java b/core/src/io/anuke/mindustry/editor/MapInfoDialog.java index bc5ca110bc..084258120a 100644 --- a/core/src/io/anuke/mindustry/editor/MapInfoDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapInfoDialog.java @@ -6,6 +6,7 @@ import io.anuke.arc.scene.ui.*; import io.anuke.mindustry.*; import io.anuke.mindustry.game.*; import io.anuke.mindustry.io.*; +import io.anuke.mindustry.ui.*; import io.anuke.mindustry.ui.dialogs.*; public class MapInfoDialog extends FloatingDialog{ @@ -42,7 +43,7 @@ public class MapInfoDialog extends FloatingDialog{ t.row(); t.add("$editor.description").padRight(8).left(); - TextArea description = t.addArea(tags.get("description", ""), "textarea", text -> { + TextArea description = t.addArea(tags.get("description", ""), Styles.areaField, text -> { tags.put("description", text); }).size(400f, 140f).get(); diff --git a/core/src/io/anuke/mindustry/editor/MapLoadDialog.java b/core/src/io/anuke/mindustry/editor/MapLoadDialog.java index 27453cb187..6cfaaeca7a 100644 --- a/core/src/io/anuke/mindustry/editor/MapLoadDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapLoadDialog.java @@ -48,12 +48,12 @@ public class MapLoadDialog extends FloatingDialog{ table.defaults().size(200f, 90f).pad(4f); table.margin(10f); - ScrollPane pane = new ScrollPane(table, "horizontal"); + ScrollPane pane = new ScrollPane(table, Styles.horizontalPane); pane.setFadeScrollBars(false); for(Map map : maps.all()){ - TextButton button = new TextButton(map.name(), "toggle"); + TextButton button = new TextButton(map.name(), Styles.togglet); button.add(new BorderImage(map.texture, 2f).setScaling(Scaling.fit)).size(16 * 4f); button.getCells().reverse(); button.clicked(() -> selected = map); diff --git a/core/src/io/anuke/mindustry/editor/MapRenderer.java b/core/src/io/anuke/mindustry/editor/MapRenderer.java index c6ec218735..619b03567a 100644 --- a/core/src/io/anuke/mindustry/editor/MapRenderer.java +++ b/core/src/io/anuke/mindustry/editor/MapRenderer.java @@ -155,7 +155,7 @@ public class MapRenderer implements Disposable{ } mesh.draw(idxDecal, region, wx * tilesize + offsetX, wy * tilesize + offsetY, width, height); - mesh.setColor(Color.WHITE); + mesh.setColor(Color.white); } @Override diff --git a/core/src/io/anuke/mindustry/editor/MapResizeDialog.java b/core/src/io/anuke/mindustry/editor/MapResizeDialog.java index fb6c4f6adb..4639faf878 100644 --- a/core/src/io/anuke/mindustry/editor/MapResizeDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapResizeDialog.java @@ -1,9 +1,10 @@ package io.anuke.mindustry.editor; -import io.anuke.arc.function.IntPositionConsumer; -import io.anuke.arc.math.Mathf; -import io.anuke.arc.scene.ui.layout.Table; -import io.anuke.mindustry.ui.dialogs.FloatingDialog; +import io.anuke.arc.function.*; +import io.anuke.arc.math.*; +import io.anuke.arc.scene.ui.layout.*; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.ui.dialogs.*; public class MapResizeDialog extends FloatingDialog{ private static final int minSize = 50, maxSize = 500, increment = 50; @@ -28,7 +29,7 @@ public class MapResizeDialog extends FloatingDialog{ height = move(height, -1); }).size(60f); - table.table("button", t -> t.label(() -> (w ? width : height) + "")).width(200); + table.table(Tex.button, t -> t.label(() -> (w ? width : height) + "")).width(200); table.addButton(">", () -> { if(w) diff --git a/core/src/io/anuke/mindustry/editor/MapSaveDialog.java b/core/src/io/anuke/mindustry/editor/MapSaveDialog.java index 18360445a1..d0f8ce77ae 100644 --- a/core/src/io/anuke/mindustry/editor/MapSaveDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapSaveDialog.java @@ -55,7 +55,7 @@ public class MapSaveDialog extends FloatingDialog{ if(!invalid()){ listener.accept(field.getText()); }else{ - ui.showError("$editor.failoverwrite"); + ui.showErrorMessage("$editor.failoverwrite"); } } diff --git a/core/src/io/anuke/mindustry/editor/MapView.java b/core/src/io/anuke/mindustry/editor/MapView.java index 0481d4a3f4..2e06352e49 100644 --- a/core/src/io/anuke/mindustry/editor/MapView.java +++ b/core/src/io/anuke/mindustry/editor/MapView.java @@ -11,7 +11,7 @@ import io.anuke.arc.math.geom.*; import io.anuke.arc.scene.Element; import io.anuke.arc.scene.event.*; import io.anuke.arc.scene.ui.TextField; -import io.anuke.arc.scene.ui.layout.UnitScl; +import io.anuke.arc.scene.ui.layout.Scl; import io.anuke.arc.util.*; import io.anuke.mindustry.graphics.Pal; import io.anuke.mindustry.input.Binding; @@ -241,7 +241,7 @@ public class MapView extends Element implements GestureListener{ Draw.reset(); if(grid){ - Draw.color(Color.GRAY); + Draw.color(Color.gray); image.setBounds(centerx - sclwidth / 2, centery - sclheight / 2, sclwidth, sclheight); image.draw(); Draw.color(); @@ -258,7 +258,7 @@ public class MapView extends Element implements GestureListener{ float scaling = zoom * Math.min(width, height) / editor.width(); Draw.color(Pal.accent); - Lines.stroke(UnitScl.dp.scl(2f)); + Lines.stroke(Scl.scl(2f)); if((!editor.drawBlock.isMultiblock() || tool == EditorTool.eraser) && tool != EditorTool.fill){ if(tool == EditorTool.line && drawing){ @@ -294,7 +294,7 @@ public class MapView extends Element implements GestureListener{ } Draw.color(Pal.accent); - Lines.stroke(UnitScl.dp.scl(3f)); + Lines.stroke(Scl.scl(3f)); Lines.rect(x, y, width, height); Draw.reset(); @@ -320,7 +320,7 @@ public class MapView extends Element implements GestureListener{ public boolean zoom(float initialDistance, float distance){ if(!active()) return false; float nzoom = distance - initialDistance; - zoom += nzoom / 10000f / UnitScl.dp.scl(1f) * zoom; + zoom += nzoom / 10000f / Scl.scl(1f) * zoom; clampZoom(); return false; } diff --git a/core/src/io/anuke/mindustry/editor/WaveInfoDialog.java b/core/src/io/anuke/mindustry/editor/WaveInfoDialog.java index ad5dccb5d8..f36a9f759e 100644 --- a/core/src/io/anuke/mindustry/editor/WaveInfoDialog.java +++ b/core/src/io/anuke/mindustry/editor/WaveInfoDialog.java @@ -1,22 +1,23 @@ package io.anuke.mindustry.editor; -import io.anuke.arc.Core; -import io.anuke.arc.collection.Array; -import io.anuke.arc.graphics.Color; -import io.anuke.arc.input.KeyCode; -import io.anuke.arc.math.Mathf; -import io.anuke.arc.scene.event.Touchable; -import io.anuke.arc.scene.ui.Label; -import io.anuke.arc.scene.ui.TextField.TextFieldFilter; -import io.anuke.arc.scene.ui.layout.Table; +import io.anuke.arc.*; +import io.anuke.arc.collection.*; +import io.anuke.arc.graphics.*; +import io.anuke.arc.input.*; +import io.anuke.arc.math.*; +import io.anuke.arc.scene.event.*; +import io.anuke.arc.scene.ui.*; +import io.anuke.arc.scene.ui.TextField.*; +import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; -import io.anuke.mindustry.Vars; +import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.game.*; -import io.anuke.mindustry.graphics.Pal; -import io.anuke.mindustry.io.JsonIO; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.graphics.*; +import io.anuke.mindustry.io.*; import io.anuke.mindustry.type.*; -import io.anuke.mindustry.ui.dialogs.FloatingDialog; +import io.anuke.mindustry.ui.dialogs.*; import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.game.SpawnGroup.never; @@ -61,7 +62,8 @@ public class WaveInfoDialog extends FloatingDialog{ groups = maps.readWaves(Core.app.getClipboardText()); buildGroups(); }catch(Exception e){ - ui.showError("$waves.invalid"); + e.printStackTrace(); + ui.showErrorMessage("$waves.invalid"); } dialog.hide(); }).disabled(b -> Core.app.getClipboardText() == null || Core.app.getClipboardText().isEmpty()); @@ -79,7 +81,7 @@ public class WaveInfoDialog extends FloatingDialog{ groups = JsonIO.copy(state.rules.spawns.isEmpty() ? defaultWaves.get() : state.rules.spawns); cont.clear(); - cont.stack(new Table("clear", main -> { + cont.stack(new Table(Tex.clear, main -> { main.pane(t -> table = t).growX().growY().padRight(8f).get().setScrollingDisabled(true, false); main.row(); main.addButton("$add", () -> { @@ -94,8 +96,8 @@ public class WaveInfoDialog extends FloatingDialog{ setAlignment(Align.center, Align.center); }}).width(390f).growY(); - cont.table("clear", m -> { - m.add("$waves.preview").color(Color.LIGHT_GRAY).growX().center().get().setAlignment(Align.center, Align.center); + cont.table(Tex.clear, m -> { + m.add("$waves.preview").color(Color.lightGray).growX().center().get().setAlignment(Align.center, Align.center); m.row(); m.addButton("-", () -> { }).update(t -> { @@ -134,7 +136,7 @@ public class WaveInfoDialog extends FloatingDialog{ if(groups != null){ for(SpawnGroup group : groups){ - table.table("button", t -> { + table.table(Tex.button, t -> { t.margin(0).defaults().pad(3).padLeft(5f).growX().left(); t.addButton(b -> { b.left(); @@ -238,7 +240,7 @@ public class WaveInfoDialog extends FloatingDialog{ for(int i = start; i < displayed + start; i++){ int wave = i; - preview.table("underline", table -> { + preview.table(Tex.underline, table -> { table.add((wave + 1) + "").color(Pal.accent).center().colspan(2).get().setAlignment(Align.center, Align.center); table.row(); @@ -252,7 +254,7 @@ public class WaveInfoDialog extends FloatingDialog{ if(spawned[j] > 0){ UnitType type = content.getByID(ContentType.unit, j); table.addImage(type.iconRegion).size(30f).padRight(4); - table.add(spawned[j] + "x").color(Color.LIGHT_GRAY).padRight(6); + table.add(spawned[j] + "x").color(Color.lightGray).padRight(6); table.row(); } } diff --git a/core/src/io/anuke/mindustry/entities/Damage.java b/core/src/io/anuke/mindustry/entities/Damage.java index 9b75085b0f..8d920e214a 100644 --- a/core/src/io/anuke/mindustry/entities/Damage.java +++ b/core/src/io/anuke/mindustry/entities/Damage.java @@ -1,20 +1,22 @@ package io.anuke.mindustry.entities; import io.anuke.annotations.Annotations.Struct; +import io.anuke.arc.*; import io.anuke.arc.collection.GridBits; import io.anuke.arc.collection.IntQueue; import io.anuke.arc.function.*; import io.anuke.arc.graphics.Color; import io.anuke.arc.math.Mathf; import io.anuke.arc.math.geom.*; -import io.anuke.arc.util.Time; +import io.anuke.arc.util.*; import io.anuke.mindustry.content.Bullets; import io.anuke.mindustry.content.Fx; import io.anuke.mindustry.entities.Effects.Effect; -import io.anuke.mindustry.entities.bullet.Bullet; +import io.anuke.mindustry.entities.type.Bullet; import io.anuke.mindustry.entities.effect.Fire; import io.anuke.mindustry.entities.effect.Lightning; import io.anuke.mindustry.entities.type.Unit; +import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.gen.Call; import io.anuke.mindustry.gen.PropCell; @@ -187,6 +189,10 @@ public class Damage{ //TODO better velocity displacement float dst = tr.set(entity.x - x, entity.y - y).len(); entity.velocity().add(tr.setLength((1f - dst / radius) * 2f / entity.mass())); + + if(complete && damage >= 9999999f && entity == player){ + Events.fire(Trigger.exclusionDeath); + } }; rect.setSize(radius * 2).setCenter(x, y); diff --git a/core/src/io/anuke/mindustry/entities/Effects.java b/core/src/io/anuke/mindustry/entities/Effects.java index 625d4b69e9..62bcd9a3ce 100644 --- a/core/src/io/anuke/mindustry/entities/Effects.java +++ b/core/src/io/anuke/mindustry/entities/Effects.java @@ -7,7 +7,7 @@ import io.anuke.arc.graphics.Color; import io.anuke.arc.math.Mathf; import io.anuke.arc.math.geom.Position; import io.anuke.arc.util.pooling.Pools; -import io.anuke.mindustry.entities.impl.EffectEntity; +import io.anuke.mindustry.entities.type.EffectEntity; import io.anuke.mindustry.entities.traits.ScaleTrait; public class Effects{ @@ -49,7 +49,7 @@ public class Effects{ } public static void effect(Effect effect, float x, float y, float rotation){ - provider.createEffect(effect, Color.WHITE, x, y, rotation, null); + provider.createEffect(effect, Color.white, x, y, rotation, null); } public static void effect(Effect effect, float x, float y){ @@ -61,7 +61,7 @@ public class Effects{ } public static void effect(Effect effect, Position loc){ - provider.createEffect(effect, Color.WHITE, loc.getX(), loc.getY(), 0f, null); + provider.createEffect(effect, Color.white, loc.getX(), loc.getY(), 0f, null); } public static void effect(Effect effect, Color color, float x, float y, float rotation){ @@ -73,7 +73,7 @@ public class Effects{ } public static void effect(Effect effect, float x, float y, float rotation, Object data){ - provider.createEffect(effect, Color.WHITE, x, y, rotation, data); + provider.createEffect(effect, Color.white, x, y, rotation, data); } /** Default value is 1000. Higher numbers mean more powerful shake (less falloff). */ diff --git a/core/src/io/anuke/mindustry/entities/bullet/ArtilleryBulletType.java b/core/src/io/anuke/mindustry/entities/bullet/ArtilleryBulletType.java index 734c3f59a8..81da65344d 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/ArtilleryBulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/ArtilleryBulletType.java @@ -4,6 +4,7 @@ import io.anuke.arc.graphics.g2d.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.Effects.*; +import io.anuke.mindustry.entities.type.Bullet; import io.anuke.mindustry.gen.*; //TODO scale velocity depending on fslope() @@ -20,7 +21,7 @@ public class ArtilleryBulletType extends BasicBulletType{ } @Override - public void update(Bullet b){ + public void update(io.anuke.mindustry.entities.type.Bullet b){ super.update(b); if(b.timer.get(0, 3 + b.fslope() * 2f)){ diff --git a/core/src/io/anuke/mindustry/entities/bullet/BasicBulletType.java b/core/src/io/anuke/mindustry/entities/bullet/BasicBulletType.java index 86b96ba7a8..8f54b58995 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/BasicBulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/BasicBulletType.java @@ -4,6 +4,7 @@ import io.anuke.arc.Core; import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.g2d.Draw; import io.anuke.arc.graphics.g2d.TextureRegion; +import io.anuke.mindustry.entities.type.Bullet; import io.anuke.mindustry.graphics.Pal; /** An extended BulletType for most ammo-based bullets shot from turrets and units. */ diff --git a/core/src/io/anuke/mindustry/entities/bullet/BulletType.java b/core/src/io/anuke/mindustry/entities/bullet/BulletType.java index 693112d53f..58b186c28d 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/BulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/BulletType.java @@ -7,6 +7,7 @@ import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.Effects.*; import io.anuke.mindustry.entities.effect.*; import io.anuke.mindustry.entities.traits.*; +import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; diff --git a/core/src/io/anuke/mindustry/entities/bullet/FlakBulletType.java b/core/src/io/anuke/mindustry/entities/bullet/FlakBulletType.java index 0a435d0bcb..3669909097 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/FlakBulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/FlakBulletType.java @@ -4,6 +4,7 @@ import io.anuke.arc.math.geom.Rectangle; import io.anuke.arc.util.Time; import io.anuke.mindustry.content.Fx; import io.anuke.mindustry.entities.Units; +import io.anuke.mindustry.entities.type.Bullet; public abstract class FlakBulletType extends BasicBulletType{ protected static Rectangle rect = new Rectangle(); diff --git a/core/src/io/anuke/mindustry/entities/bullet/LiquidBulletType.java b/core/src/io/anuke/mindustry/entities/bullet/LiquidBulletType.java index e9edaef777..186ea47425 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/LiquidBulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/LiquidBulletType.java @@ -6,6 +6,7 @@ import io.anuke.arc.math.geom.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.effect.*; +import io.anuke.mindustry.entities.type.Bullet; import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.*; @@ -35,7 +36,7 @@ public class LiquidBulletType extends BulletType{ } @Override - public void update(Bullet b){ + public void update(io.anuke.mindustry.entities.type.Bullet b){ super.update(b); if(liquid.canExtinguish()){ @@ -49,8 +50,8 @@ public class LiquidBulletType extends BulletType{ } @Override - public void draw(Bullet b){ - Draw.color(liquid.color, Color.WHITE, b.fout() / 100f); + public void draw(io.anuke.mindustry.entities.type.Bullet b){ + Draw.color(liquid.color, Color.white, b.fout() / 100f); Fill.circle(b.x, b.y, 0.5f + b.fout() * 2.5f); } diff --git a/core/src/io/anuke/mindustry/entities/bullet/MassDriverBolt.java b/core/src/io/anuke/mindustry/entities/bullet/MassDriverBolt.java index a3bd379542..fe357b7f5f 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/MassDriverBolt.java +++ b/core/src/io/anuke/mindustry/entities/bullet/MassDriverBolt.java @@ -6,6 +6,7 @@ import io.anuke.arc.math.Angles; import io.anuke.arc.math.Mathf; import io.anuke.mindustry.content.Fx; import io.anuke.mindustry.entities.Effects; +import io.anuke.mindustry.entities.type.Bullet; import io.anuke.mindustry.graphics.Pal; import io.anuke.mindustry.world.blocks.distribution.MassDriver.DriverBulletData; @@ -23,7 +24,7 @@ public class MassDriverBolt extends BulletType{ } @Override - public void draw(Bullet b){ + public void draw(io.anuke.mindustry.entities.type.Bullet b){ float w = 11f, h = 13f; Draw.color(Pal.bulletYellowBack); @@ -36,7 +37,7 @@ public class MassDriverBolt extends BulletType{ } @Override - public void update(Bullet b){ + public void update(io.anuke.mindustry.entities.type.Bullet b){ //data MUST be an instance of DriverBulletData if(!(b.getData() instanceof DriverBulletData)){ hit(b); @@ -82,7 +83,7 @@ public class MassDriverBolt extends BulletType{ } @Override - public void despawned(Bullet b){ + public void despawned(io.anuke.mindustry.entities.type.Bullet b){ super.despawned(b); if(!(b.getData() instanceof DriverBulletData)) return; @@ -93,7 +94,7 @@ public class MassDriverBolt extends BulletType{ int amountDropped = Mathf.random(0, data.items[i]); if(amountDropped > 0){ float angle = b.rot() + Mathf.range(100f); - Effects.effect(Fx.dropItem, Color.WHITE, b.x, b.y, angle, content.item(i)); + Effects.effect(Fx.dropItem, Color.white, b.x, b.y, angle, content.item(i)); } } } diff --git a/core/src/io/anuke/mindustry/entities/bullet/MissileBulletType.java b/core/src/io/anuke/mindustry/entities/bullet/MissileBulletType.java index 94220d1ece..06d05d1110 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/MissileBulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/MissileBulletType.java @@ -5,6 +5,7 @@ import io.anuke.arc.math.Mathf; import io.anuke.arc.util.Time; import io.anuke.mindustry.content.Fx; import io.anuke.mindustry.entities.Effects; +import io.anuke.mindustry.entities.type.Bullet; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.Pal; diff --git a/core/src/io/anuke/mindustry/entities/effect/Decal.java b/core/src/io/anuke/mindustry/entities/effect/Decal.java index dd8a499f50..103bc14919 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Decal.java +++ b/core/src/io/anuke/mindustry/entities/effect/Decal.java @@ -3,7 +3,7 @@ package io.anuke.mindustry.entities.effect; import io.anuke.arc.graphics.g2d.Draw; import io.anuke.arc.math.Mathf; import io.anuke.mindustry.entities.EntityGroup; -import io.anuke.mindustry.entities.impl.TimedEntity; +import io.anuke.mindustry.entities.type.TimedEntity; import io.anuke.mindustry.entities.traits.BelowLiquidTrait; import io.anuke.mindustry.entities.traits.DrawTrait; import io.anuke.mindustry.graphics.Pal; diff --git a/core/src/io/anuke/mindustry/entities/effect/Fire.java b/core/src/io/anuke/mindustry/entities/effect/Fire.java index 8ee58d742a..31cc65ab6a 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Fire.java +++ b/core/src/io/anuke/mindustry/entities/effect/Fire.java @@ -1,18 +1,19 @@ package io.anuke.mindustry.entities.effect; import io.anuke.annotations.Annotations.*; +import io.anuke.arc.*; import io.anuke.arc.collection.*; import io.anuke.arc.math.*; import io.anuke.arc.math.geom.*; import io.anuke.arc.util.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.entities.*; -import io.anuke.mindustry.entities.impl.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.entities.type.TimedEntity; +import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; -import io.anuke.mindustry.net.*; import io.anuke.mindustry.world.*; import java.io.*; @@ -40,7 +41,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait{ /** Start a fire on the tile. If there already is a file there, refreshes its lifetime. */ public static void create(Tile tile){ - if(Net.client() || tile == null) return; //not clientside. + if(net.client() || tile == null) return; //not clientside. Fire fire = map.get(tile.pos()); @@ -70,7 +71,11 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait{ */ public static void extinguish(Tile tile, float intensity){ if(tile != null && map.containsKey(tile.pos())){ - map.get(tile.pos()).time += intensity * Time.delta(); + Fire fire = map.get(tile.pos()); + fire.time += intensity * Time.delta(); + if(fire.time >= fire.lifetime()){ + Events.fire(Trigger.fireExtinguish); + } } } @@ -106,7 +111,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait{ time = Mathf.clamp(time + Time.delta(), 0, lifetime()); map.put(tile.pos(), this); - if(Net.client()){ + if(net.client()){ return; } diff --git a/core/src/io/anuke/mindustry/entities/effect/GroundEffectEntity.java b/core/src/io/anuke/mindustry/entities/effect/GroundEffectEntity.java index 54094c4a87..4dfd0a694e 100644 --- a/core/src/io/anuke/mindustry/entities/effect/GroundEffectEntity.java +++ b/core/src/io/anuke/mindustry/entities/effect/GroundEffectEntity.java @@ -6,7 +6,7 @@ import io.anuke.mindustry.Vars; import io.anuke.mindustry.entities.Effects; import io.anuke.mindustry.entities.Effects.Effect; import io.anuke.mindustry.entities.Effects.EffectRenderer; -import io.anuke.mindustry.entities.impl.EffectEntity; +import io.anuke.mindustry.entities.type.EffectEntity; import io.anuke.mindustry.world.Tile; /** diff --git a/core/src/io/anuke/mindustry/entities/effect/ItemTransfer.java b/core/src/io/anuke/mindustry/entities/effect/ItemTransfer.java index 2cb7f567e1..888f7e7f60 100644 --- a/core/src/io/anuke/mindustry/entities/effect/ItemTransfer.java +++ b/core/src/io/anuke/mindustry/entities/effect/ItemTransfer.java @@ -10,14 +10,14 @@ import io.anuke.arc.math.geom.Vector2; import io.anuke.arc.util.Time; import io.anuke.arc.util.pooling.Pools; import io.anuke.mindustry.entities.EntityGroup; -import io.anuke.mindustry.entities.impl.TimedEntity; +import io.anuke.mindustry.entities.type.TimedEntity; import io.anuke.mindustry.entities.traits.DrawTrait; import io.anuke.mindustry.entities.type.Unit; import io.anuke.mindustry.graphics.Pal; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.Tile; -import static io.anuke.mindustry.Vars.effectGroup; +import static io.anuke.mindustry.Vars.*; public class ItemTransfer extends TimedEntity implements DrawTrait{ private Vector2 from = new Vector2(); diff --git a/core/src/io/anuke/mindustry/entities/effect/Lightning.java b/core/src/io/anuke/mindustry/entities/effect/Lightning.java index bc842d7d95..db8eeb5b1b 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Lightning.java +++ b/core/src/io/anuke/mindustry/entities/effect/Lightning.java @@ -12,8 +12,8 @@ import io.anuke.arc.util.pooling.Pools; import io.anuke.mindustry.content.Bullets; import io.anuke.mindustry.entities.EntityGroup; import io.anuke.mindustry.entities.Units; -import io.anuke.mindustry.entities.bullet.Bullet; -import io.anuke.mindustry.entities.impl.TimedEntity; +import io.anuke.mindustry.entities.type.Bullet; +import io.anuke.mindustry.entities.type.TimedEntity; import io.anuke.mindustry.entities.traits.DrawTrait; import io.anuke.mindustry.entities.traits.TimeTrait; import io.anuke.mindustry.entities.type.Unit; @@ -110,7 +110,7 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{ @Override public void draw(){ Lines.stroke(3f * fout()); - Draw.color(color, Color.WHITE, fin()); + Draw.color(color, Color.white, fin()); Lines.beginLine(); Lines.linePoint(x, y); diff --git a/core/src/io/anuke/mindustry/entities/effect/Puddle.java b/core/src/io/anuke/mindustry/entities/effect/Puddle.java index b9885f5a20..69bb64c9c2 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Puddle.java +++ b/core/src/io/anuke/mindustry/entities/effect/Puddle.java @@ -14,11 +14,10 @@ import io.anuke.arc.util.pooling.Pool.Poolable; import io.anuke.arc.util.pooling.Pools; import io.anuke.mindustry.content.*; import io.anuke.mindustry.entities.*; -import io.anuke.mindustry.entities.impl.SolidEntity; +import io.anuke.mindustry.entities.type.SolidEntity; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.game.TypeID; import io.anuke.mindustry.gen.Call; -import io.anuke.mindustry.net.Net; import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.Tile; @@ -83,7 +82,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai Puddle p = map.get(tile.pos()); if(p == null){ - if(Net.client()) return; //not clientside. + if(net.client()) return; //not clientside. Puddle puddle = Pools.obtain(Puddle.class, Puddle::new); puddle.tile = tile; @@ -168,7 +167,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai public void update(){ //no updating happens clientside - if(Net.client()){ + if(net.client()){ amount = Mathf.lerpDelta(amount, targetAmount, 0.15f); }else{ //update code diff --git a/core/src/io/anuke/mindustry/entities/traits/MinerTrait.java b/core/src/io/anuke/mindustry/entities/traits/MinerTrait.java index 76a66396e1..a312740804 100644 --- a/core/src/io/anuke/mindustry/entities/traits/MinerTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/MinerTrait.java @@ -88,7 +88,7 @@ public interface MinerTrait extends Entity{ float ex = tile.worldx() + Mathf.sin(Time.time() + 48, swingScl, swingMag); float ey = tile.worldy() + Mathf.sin(Time.time() + 48, swingScl + 2f, swingMag); - Draw.color(Color.LIGHT_GRAY, Color.WHITE, 1f - flashScl + Mathf.absin(Time.time(), 0.5f, flashScl)); + Draw.color(Color.lightGray, Color.white, 1f - flashScl + Mathf.absin(Time.time(), 0.5f, flashScl)); Drawf.laser(Core.atlas.find("minelaser"), Core.atlas.find("minelaser-end"), px, py, ex, ey, 0.75f); diff --git a/core/src/io/anuke/mindustry/entities/traits/SpawnerTrait.java b/core/src/io/anuke/mindustry/entities/traits/SpawnerTrait.java index df23a1053d..c890d4cbfc 100644 --- a/core/src/io/anuke/mindustry/entities/traits/SpawnerTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/SpawnerTrait.java @@ -1,7 +1,7 @@ package io.anuke.mindustry.entities.traits; import io.anuke.arc.math.geom.Position; -import io.anuke.mindustry.entities.type.Player; +import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.world.Tile; public interface SpawnerTrait extends TargetTrait, Position{ @@ -9,6 +9,8 @@ public interface SpawnerTrait extends TargetTrait, Position{ void updateSpawning(Player unit); + boolean hasUnit(Unit unit); + @Override default boolean isValid(){ return getTile().entity instanceof SpawnerTrait; diff --git a/core/src/io/anuke/mindustry/entities/impl/BaseEntity.java b/core/src/io/anuke/mindustry/entities/type/BaseEntity.java similarity index 96% rename from core/src/io/anuke/mindustry/entities/impl/BaseEntity.java rename to core/src/io/anuke/mindustry/entities/type/BaseEntity.java index e2da48908e..ee938afd39 100755 --- a/core/src/io/anuke/mindustry/entities/impl/BaseEntity.java +++ b/core/src/io/anuke/mindustry/entities/type/BaseEntity.java @@ -1,4 +1,4 @@ -package io.anuke.mindustry.entities.impl; +package io.anuke.mindustry.entities.type; import io.anuke.mindustry.entities.EntityGroup; import io.anuke.mindustry.entities.traits.Entity; diff --git a/core/src/io/anuke/mindustry/entities/type/BaseUnit.java b/core/src/io/anuke/mindustry/entities/type/BaseUnit.java index 82615e8a01..4a9d8695f3 100644 --- a/core/src/io/anuke/mindustry/entities/type/BaseUnit.java +++ b/core/src/io/anuke/mindustry/entities/type/BaseUnit.java @@ -11,11 +11,12 @@ import io.anuke.mindustry.content.*; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.entities.units.*; +import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; -import io.anuke.mindustry.net.Net; import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.*; +import io.anuke.mindustry.world.blocks.defense.DeflectorWall.*; import io.anuke.mindustry.world.blocks.units.CommandCenter.*; import io.anuke.mindustry.world.blocks.units.UnitFactory.*; import io.anuke.mindustry.world.meta.*; @@ -48,7 +49,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ public static void onUnitDeath(BaseUnit unit){ if(unit == null) return; - if(Net.server() || !Net.active()){ + if(net.server() || !net.active()){ UnitDrops.dropItems(unit); } @@ -56,9 +57,9 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ unit.type.deathSound.at(unit); //visual only. - if(Net.client()){ + if(net.client()){ Tile tile = world.tile(unit.spawner); - if(tile != null && !Net.client()){ + if(tile != null){ tile.block().unitRemoved(tile, unit); } @@ -79,6 +80,17 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ return type.typeID; } + @Override + public void onHit(SolidTrait entity){ + if(entity instanceof Bullet && ((Bullet)entity).getOwner() instanceof DeflectorEntity && player != null && getTeam() != player.getTeam()){ + Core.app.post(() -> { + if(isDead()){ + Events.fire(Trigger.phaseDeflectHit); + } + }); + } + } + public @Nullable Tile getSpawner(){ return world.tile(spawner); } @@ -255,7 +267,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ hitTime -= Time.delta(); - if(Net.client()){ + if(net.client()){ interpolate(); status.update(this); return; @@ -297,7 +309,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ public void removed(){ super.removed(); Tile tile = world.tile(spawner); - if(tile != null && !Net.client()){ + if(tile != null && !net.client()){ tile.block().unitRemoved(tile, this); } diff --git a/core/src/io/anuke/mindustry/entities/bullet/Bullet.java b/core/src/io/anuke/mindustry/entities/type/Bullet.java similarity index 91% rename from core/src/io/anuke/mindustry/entities/bullet/Bullet.java rename to core/src/io/anuke/mindustry/entities/type/Bullet.java index afe97b5399..97051a2faa 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/Bullet.java +++ b/core/src/io/anuke/mindustry/entities/type/Bullet.java @@ -1,23 +1,19 @@ -package io.anuke.mindustry.entities.bullet; +package io.anuke.mindustry.entities.type; -import io.anuke.annotations.Annotations.Loc; -import io.anuke.annotations.Annotations.Remote; -import io.anuke.arc.math.Mathf; -import io.anuke.arc.math.geom.Rectangle; -import io.anuke.arc.math.geom.Vector2; +import io.anuke.annotations.Annotations.*; +import io.anuke.arc.math.*; +import io.anuke.arc.math.geom.*; import io.anuke.arc.util.*; -import io.anuke.arc.util.pooling.Pool.Poolable; -import io.anuke.arc.util.pooling.Pools; -import io.anuke.mindustry.entities.EntityGroup; -import io.anuke.mindustry.entities.effect.Lightning; -import io.anuke.mindustry.entities.impl.SolidEntity; +import io.anuke.arc.util.pooling.Pool.*; +import io.anuke.arc.util.pooling.*; +import io.anuke.mindustry.entities.*; +import io.anuke.mindustry.entities.bullet.*; +import io.anuke.mindustry.entities.effect.*; import io.anuke.mindustry.entities.traits.*; -import io.anuke.mindustry.entities.type.Unit; -import io.anuke.mindustry.game.Team; -import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.game.*; +import io.anuke.mindustry.world.*; -import static io.anuke.mindustry.Vars.bulletGroup; -import static io.anuke.mindustry.Vars.world; +import static io.anuke.mindustry.Vars.*; public class Bullet extends SolidEntity implements DamageTrait, ScaleTrait, Poolable, DrawTrait, VelocityTrait, TimeTrait, TeamTrait, AbsorbTrait{ public Interval timer = new Interval(3); @@ -25,7 +21,7 @@ public class Bullet extends SolidEntity implements DamageTrait, ScaleTrait, Pool private float lifeScl; private Team team; private Object data; - private boolean supressCollision, supressOnce, initialized; + private boolean supressCollision, supressOnce, initialized, deflected; protected BulletType type; protected Entity owner; @@ -100,9 +96,14 @@ public class Bullet extends SolidEntity implements DamageTrait, ScaleTrait, Pool return type.collidesTiles; } - public void supress(){ + public void deflect(){ supressCollision = true; supressOnce = true; + deflected = true; + } + + public boolean isDeflected(){ + return deflected; } public BulletType getBulletType(){ @@ -239,6 +240,7 @@ public class Bullet extends SolidEntity implements DamageTrait, ScaleTrait, Pool data = null; supressCollision = false; supressOnce = false; + deflected = false; initialized = false; } diff --git a/core/src/io/anuke/mindustry/entities/impl/DestructibleEntity.java b/core/src/io/anuke/mindustry/entities/type/DestructibleEntity.java similarity index 95% rename from core/src/io/anuke/mindustry/entities/impl/DestructibleEntity.java rename to core/src/io/anuke/mindustry/entities/type/DestructibleEntity.java index dce6f3dae5..350a47f9cf 100644 --- a/core/src/io/anuke/mindustry/entities/impl/DestructibleEntity.java +++ b/core/src/io/anuke/mindustry/entities/type/DestructibleEntity.java @@ -1,4 +1,4 @@ -package io.anuke.mindustry.entities.impl; +package io.anuke.mindustry.entities.type; import io.anuke.mindustry.entities.traits.*; diff --git a/core/src/io/anuke/mindustry/entities/impl/EffectEntity.java b/core/src/io/anuke/mindustry/entities/type/EffectEntity.java similarity index 93% rename from core/src/io/anuke/mindustry/entities/impl/EffectEntity.java rename to core/src/io/anuke/mindustry/entities/type/EffectEntity.java index 789ce78dfa..33b2f47475 100644 --- a/core/src/io/anuke/mindustry/entities/impl/EffectEntity.java +++ b/core/src/io/anuke/mindustry/entities/type/EffectEntity.java @@ -1,4 +1,4 @@ -package io.anuke.mindustry.entities.impl; +package io.anuke.mindustry.entities.type; import io.anuke.arc.graphics.Color; import io.anuke.arc.util.pooling.Pool.Poolable; @@ -13,7 +13,7 @@ import static io.anuke.mindustry.Vars.effectGroup; public class EffectEntity extends TimedEntity implements Poolable, DrawTrait{ public Effect effect; - public Color color = new Color(Color.WHITE); + public Color color = new Color(Color.white); public Object data; public float rotation = 0f; @@ -63,7 +63,7 @@ public class EffectEntity extends TimedEntity implements Poolable, DrawTrait{ @Override public void reset(){ effect = null; - color.set(Color.WHITE); + color.set(Color.white); rotation = time = poffsetx = poffsety = 0f; parent = null; data = null; diff --git a/core/src/io/anuke/mindustry/entities/type/FlyingUnit.java b/core/src/io/anuke/mindustry/entities/type/FlyingUnit.java index d02ad55ec1..2a0e18160e 100644 --- a/core/src/io/anuke/mindustry/entities/type/FlyingUnit.java +++ b/core/src/io/anuke/mindustry/entities/type/FlyingUnit.java @@ -9,7 +9,6 @@ import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.bullet.*; import io.anuke.mindustry.entities.units.*; import io.anuke.mindustry.graphics.*; -import io.anuke.mindustry.net.*; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.meta.*; @@ -123,10 +122,10 @@ public abstract class FlyingUnit extends BaseUnit{ public void update(){ super.update(); - if(!Net.client()){ + if(!net.client()){ updateRotation(); - wobble(); } + wobble(); } @Override @@ -136,7 +135,7 @@ public abstract class FlyingUnit extends BaseUnit{ @Override public void draw(){ - Draw.mixcol(Color.WHITE, hitTime / hitDuration); + Draw.mixcol(Color.white, hitTime / hitDuration); Draw.rect(type.region, x, y, rotation - 90); drawWeapons(); @@ -153,7 +152,7 @@ public abstract class FlyingUnit extends BaseUnit{ Fill.circle(x + Angles.trnsx(rotation + 180, type.engineOffset), y + Angles.trnsy(rotation + 180, type.engineOffset), type.engineSize + Mathf.absin(Time.time(), 2f, type.engineSize / 4f)); - Draw.color(Color.WHITE); + Draw.color(Color.white); Fill.circle(x + Angles.trnsx(rotation + 180, type.engineOffset - 1f), y + Angles.trnsy(rotation + 180, type.engineOffset - 1f), (type.engineSize + Mathf.absin(Time.time(), 2f, type.engineSize / 4f)) / 2f); Draw.color(); @@ -176,7 +175,7 @@ public abstract class FlyingUnit extends BaseUnit{ } protected void wobble(){ - if(Net.client()) return; + if(net.client()) return; x += Mathf.sin(Time.time() + id * 999, 25f, 0.05f) * Time.delta(); y += Mathf.cos(Time.time() + id * 999, 25f, 0.05f) * Time.delta(); diff --git a/core/src/io/anuke/mindustry/entities/type/GroundUnit.java b/core/src/io/anuke/mindustry/entities/type/GroundUnit.java index d538d05c10..ccc1536c1a 100644 --- a/core/src/io/anuke/mindustry/entities/type/GroundUnit.java +++ b/core/src/io/anuke/mindustry/entities/type/GroundUnit.java @@ -125,14 +125,14 @@ public abstract class GroundUnit extends BaseUnit{ @Override public void draw(){ - Draw.mixcol(Color.WHITE, hitTime / hitDuration); + Draw.mixcol(Color.white, hitTime / hitDuration); float ft = Mathf.sin(walkTime * type.speed * 5f, 6f, 2f + type.hitsize / 15f); Floor floor = getFloorOn(); if(floor.isLiquid){ - Draw.color(Color.WHITE, floor.color, 0.5f); + Draw.color(Color.white, floor.color, 0.5f); } for(int i : Mathf.signs){ @@ -143,9 +143,9 @@ public abstract class GroundUnit extends BaseUnit{ } if(floor.isLiquid){ - Draw.color(Color.WHITE, floor.color, drownTime * 0.4f); + Draw.color(Color.white, floor.color, drownTime * 0.4f); }else{ - Draw.color(Color.WHITE); + Draw.color(Color.white); } Draw.rect(type.baseRegion, x, y, baseRotation - 90); diff --git a/core/src/io/anuke/mindustry/entities/type/Player.java b/core/src/io/anuke/mindustry/entities/type/Player.java index 0b481a6105..3f1fd7fde7 100644 --- a/core/src/io/anuke/mindustry/entities/type/Player.java +++ b/core/src/io/anuke/mindustry/entities/type/Player.java @@ -1,33 +1,31 @@ package io.anuke.mindustry.entities.type; -import io.anuke.annotations.Annotations.Loc; -import io.anuke.annotations.Annotations.Remote; -import io.anuke.arc.Core; -import io.anuke.arc.collection.Queue; -import io.anuke.arc.graphics.Color; +import io.anuke.annotations.Annotations.*; +import io.anuke.arc.*; +import io.anuke.arc.collection.*; +import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.g2d.*; -import io.anuke.arc.math.Angles; -import io.anuke.arc.math.Mathf; +import io.anuke.arc.math.*; import io.anuke.arc.math.geom.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; -import io.anuke.arc.util.pooling.Pools; -import io.anuke.mindustry.Vars; +import io.anuke.arc.util.pooling.*; +import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.core.*; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; -import io.anuke.mindustry.graphics.Pal; +import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.input.*; -import io.anuke.mindustry.input.InputHandler.PlaceDraw; -import io.anuke.mindustry.io.TypeIO; -import io.anuke.mindustry.net.Net; -import io.anuke.mindustry.net.NetConnection; +import io.anuke.mindustry.input.InputHandler.*; +import io.anuke.mindustry.io.*; +import io.anuke.mindustry.net.Administration.*; +import io.anuke.mindustry.net.*; import io.anuke.mindustry.type.*; -import io.anuke.mindustry.world.Block; -import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.ui.*; +import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.blocks.*; import java.io.*; @@ -37,6 +35,7 @@ import static io.anuke.mindustry.Vars.*; public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ public static final int timerSync = 2; public static final int timerAbility = 3; + public static final int timerTransfer = 4; private static final int timerShootLeft = 0; private static final int timerShootRight = 1; private static final float liftoffBoost = 0.2f; @@ -48,7 +47,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ public float baseRotation; public float pointerX, pointerY; public String name = "name"; - public String uuid, usid; + public @Nullable String uuid, usid; public boolean isAdmin, isTransferring, isShooting, isBoosting, isMobile, isTyping; public float boostHeat, shootHeat, destructTime; public boolean achievedFlight; @@ -57,13 +56,13 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ public SpawnerTrait spawner, lastSpawner; public int respawns; - public NetConnection con; + public @Nullable NetConnection con; public boolean isLocal = false; - public Interval timer = new Interval(4); + public Interval timer = new Interval(6); public TargetTrait target; public TargetTrait moveTarget; - public String lastText; + public @Nullable String lastText; public float textFadeTime; private float walktime, itemtime; @@ -227,7 +226,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ @Override public void damage(float amount){ hitTime = hitDuration; - if(!Net.client()){ + if(!net.client()){ health -= calculateDamage(amount); } @@ -296,11 +295,11 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ Floor floor = getFloorOn(); Draw.color(); - Draw.mixcol(Color.WHITE, hitTime / hitDuration); + Draw.mixcol(Color.white, hitTime / hitDuration); if(!mech.flying){ if(floor.isLiquid){ - Draw.color(Color.WHITE, floor.color, 0.5f); + Draw.color(Color.white, floor.color, 0.5f); } float boostTrnsY = -boostHeat * 3f; @@ -320,9 +319,9 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ } if(floor.isLiquid){ - Draw.color(Color.WHITE, floor.color, drownTime); + Draw.color(Color.white, floor.color, drownTime); }else{ - Draw.color(Color.WHITE); + Draw.color(Color.white); } Draw.rect(mech.region, x, y, rotation - 90); @@ -345,7 +344,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ @Override public void drawStats(){ - Draw.color(Color.BLACK, team.color, healthf() + Mathf.absin(Time.time(), healthf() * 5f, 1f - healthf())); + Draw.color(Color.black, team.color, healthf() + Mathf.absin(Time.time(), healthf() * 5f, 1f - healthf())); Draw.rect(getPowerCellRegion(), x + Angles.trnsx(rotation, mech.cellTrnsY, 0f), y + Angles.trnsy(rotation, mech.cellTrnsY, 0f), rotation - 90); Draw.reset(); drawBackItems(itemtime, isLocal); @@ -367,21 +366,21 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ Fill.circle(x + Angles.trnsx(rotation + 180, mech.engineOffset), y + Angles.trnsy(rotation + 180, mech.engineOffset), size + Mathf.absin(Time.time(), 2f, size / 4f)); - Draw.color(Color.WHITE); + Draw.color(Color.white); Fill.circle(x + Angles.trnsx(rotation + 180, mech.engineOffset - 1f), y + Angles.trnsy(rotation + 180, mech.engineOffset - 1f), (size + Mathf.absin(Time.time(), 2f, size / 4f)) / 2f); Draw.color(); } public void drawName(){ - BitmapFont font = Core.scene.skin.getFont("default"); + BitmapFont font = Fonts.def; GlyphLayout layout = Pools.obtain(GlyphLayout.class, GlyphLayout::new); final float nameHeight = 11; final float textHeight = 15; boolean ints = font.usesIntegerPositions(); font.setUseIntegerPositions(false); - font.getData().setScale(0.25f / UnitScl.dp.scl(1f)); + font.getData().setScale(0.25f / Scl.scl(1f)); layout.setText(font, name); Draw.color(0f, 0f, 0f, 0.3f); Fill.rect(x, y + nameHeight - layout.height / 2, layout.width + 2, layout.height + 3); @@ -393,9 +392,9 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ if(isAdmin){ float s = 3f; Draw.color(color.r * 0.5f, color.g * 0.5f, color.b * 0.5f, 1f); - Draw.rect(Core.atlas.find("icon-admin-small"), x + layout.width / 2f + 2 + 1, y + nameHeight - 1.5f, s, s); + Draw.rect(Core.atlas.find("icon-admin-badge"), x + layout.width / 2f + 2 + 1, y + nameHeight - 1.5f, s, s); Draw.color(color); - Draw.rect(Core.atlas.find("icon-admin-small"), x + layout.width / 2f + 2 + 1, y + nameHeight - 1f, s, s); + Draw.rect(Core.atlas.find("icon-admin-badge"), x + layout.width / 2f + 2 + 1, y + nameHeight - 1f, s, s); } if(Core.settings.getBool("playerchat") && ((textFadeTime > 0 && lastText != null) || isTyping)){ @@ -404,7 +403,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ float visualFadeTime = 1f - Mathf.curve(1f - textFadeTime, 0.9f); font.setColor(1f, 1f, 1f, textFadeTime <= 0 || lastText == null ? 1f : visualFadeTime); - layout.setText(font, text, Color.WHITE, width, Align.bottom, true); + layout.setText(font, text, Color.white, width, Align.bottom, true); Draw.color(0f, 0f, 0f, 0.3f * (textFadeTime <= 0 || lastText == null ? 1f : visualFadeTime)); Fill.rect(x, y + textHeight + layout.height - layout.height/2f, layout.width + 2, layout.height + 3); @@ -414,7 +413,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ Draw.reset(); Pools.free(layout); font.getData().setScale(1f); - font.setColor(Color.WHITE); + font.setColor(Color.white); font.setUseIntegerPositions(ints); } @@ -528,7 +527,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ spawner = null; } - if(isLocal || Net.server()){ + if(isLocal || net.server()){ avoidOthers(); } @@ -559,7 +558,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ status.update(this); //status effect updating also happens with non locals for effect purposes updateVelocityStatus(); //velocity too, for visual purposes - if(Net.server()){ + if(net.server()){ updateShooting(); //server simulates player shooting } return; @@ -782,7 +781,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ Vars.ui.chatfrag.addMessage(text, null); } }else{ - Call.sendMessage(con.id, text, null, null); + Call.sendMessage(con, text, null, null); } } @@ -796,7 +795,15 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ Vars.ui.chatfrag.addMessage(text, fromName); } }else{ - Call.sendMessage(con.id, text, fromName, from); + Call.sendMessage(con, text, fromName, from); + } + } + + public PlayerInfo getInfo(){ + if(uuid == null){ + throw new IllegalArgumentException("Local players cannot be traced and do not have info."); + }else{ + return netServer.admins.getInfo(uuid); } } @@ -837,7 +844,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ }else if(spawner != null && spawner.isValid()){ spawner.updateSpawning(this); }else if(!netServer.isWaitingForPlayers()){ - if(!Net.client()){ + if(!net.client()){ if(lastSpawner != null && lastSpawner.isValid()){ this.spawner = lastSpawner; }else if(getClosestCore() != null){ @@ -909,7 +916,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ buffer.writeInt(Color.rgba8888(color)); buffer.writeByte(mech.id); buffer.writeInt(mining == null ? noSpawner : mining.pos()); - buffer.writeInt(spawner == null ? noSpawner : spawner.getTile().pos()); + buffer.writeInt(spawner == null || !spawner.hasUnit(this) ? noSpawner : spawner.getTile().pos()); buffer.writeShort((short)(baseRotation * 2)); writeBuilding(buffer); diff --git a/core/src/io/anuke/mindustry/entities/impl/SolidEntity.java b/core/src/io/anuke/mindustry/entities/type/SolidEntity.java similarity index 91% rename from core/src/io/anuke/mindustry/entities/impl/SolidEntity.java rename to core/src/io/anuke/mindustry/entities/type/SolidEntity.java index 544abdbefa..7dc6b0aa89 100644 --- a/core/src/io/anuke/mindustry/entities/impl/SolidEntity.java +++ b/core/src/io/anuke/mindustry/entities/type/SolidEntity.java @@ -1,4 +1,4 @@ -package io.anuke.mindustry.entities.impl; +package io.anuke.mindustry.entities.type; import io.anuke.arc.math.geom.Vector2; import io.anuke.mindustry.entities.traits.SolidTrait; diff --git a/core/src/io/anuke/mindustry/entities/type/TileEntity.java b/core/src/io/anuke/mindustry/entities/type/TileEntity.java index 3205eee53a..30aa8b9cb7 100644 --- a/core/src/io/anuke/mindustry/entities/type/TileEntity.java +++ b/core/src/io/anuke/mindustry/entities/type/TileEntity.java @@ -8,8 +8,6 @@ import io.anuke.arc.math.geom.Point2; import io.anuke.arc.math.geom.Vector2; import io.anuke.arc.util.*; import io.anuke.mindustry.entities.EntityGroup; -import io.anuke.mindustry.entities.bullet.Bullet; -import io.anuke.mindustry.entities.impl.BaseEntity; import io.anuke.mindustry.entities.traits.HealthTrait; import io.anuke.mindustry.entities.traits.TargetTrait; import io.anuke.mindustry.game.*; @@ -207,14 +205,12 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ if(other == null) continue; if(other.entity == null || !(other.interactable(tile.getTeam()))) continue; - other.block().onProximityUpdate(other); - - tmpTiles.add(other); - //add this tile to proximity of nearby tiles if(!other.entity.proximity.contains(tile, true)){ other.entity.proximity.add(tile); } + + tmpTiles.add(other); } //using a set to prevent duplicates @@ -224,6 +220,10 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ block.onProximityAdded(tile); block.onProximityUpdate(tile); + + for(Tile other : tmpTiles){ + other.block().onProximityUpdate(other); + } } public Array proximity(){ diff --git a/core/src/io/anuke/mindustry/entities/impl/TimedEntity.java b/core/src/io/anuke/mindustry/entities/type/TimedEntity.java similarity index 93% rename from core/src/io/anuke/mindustry/entities/impl/TimedEntity.java rename to core/src/io/anuke/mindustry/entities/type/TimedEntity.java index e4007a5c4b..dbd74260fe 100644 --- a/core/src/io/anuke/mindustry/entities/impl/TimedEntity.java +++ b/core/src/io/anuke/mindustry/entities/type/TimedEntity.java @@ -1,4 +1,4 @@ -package io.anuke.mindustry.entities.impl; +package io.anuke.mindustry.entities.type; import io.anuke.arc.util.pooling.Pool.Poolable; import io.anuke.mindustry.entities.traits.ScaleTrait; diff --git a/core/src/io/anuke/mindustry/entities/type/Unit.java b/core/src/io/anuke/mindustry/entities/type/Unit.java index 2bf5f63b17..3dfd2e0364 100644 --- a/core/src/io/anuke/mindustry/entities/type/Unit.java +++ b/core/src/io/anuke/mindustry/entities/type/Unit.java @@ -11,7 +11,6 @@ import io.anuke.arc.util.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.effect.*; -import io.anuke.mindustry.entities.impl.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.entities.units.*; import io.anuke.mindustry.game.EventType.*; @@ -19,9 +18,9 @@ import io.anuke.mindustry.game.*; import io.anuke.mindustry.game.Teams.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; -import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.*; import io.anuke.mindustry.type.*; +import io.anuke.mindustry.ui.*; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.blocks.*; @@ -78,7 +77,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ @Override public void damage(float amount){ - if(!Net.client()){ + if(!net.client()){ super.damage(calculateDamage(amount)); } hitTime = hitDuration; @@ -110,6 +109,10 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ drownTime = 0f; status.clear(); Events.fire(new UnitDestroyEvent(this)); + + if(explosiveness > 7f && this == player){ + Events.fire(Trigger.suicideBomb); + } } @Override @@ -308,8 +311,11 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ drownTime = Mathf.clamp(drownTime); - if(drownTime >= 0.999f && !Net.client()){ + if(drownTime >= 0.999f && !net.client()){ damage(health + 1); + if(this == player){ + Events.fire(Trigger.drown); + } } float px = x, py = y; @@ -347,7 +353,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } public void applyEffect(StatusEffect effect, float duration){ - if(dead || Net.client()) return; //effects are synced and thus not applied through clients + if(dead || net.client()) return; //effects are synced and thus not applied through clients status.handleApply(this, effect, duration); } @@ -372,7 +378,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ } public void drawStats(){ - Draw.color(Color.BLACK, team.color, healthf() + Mathf.absin(Time.time(), Math.max(healthf() * 5f, 1f), 1f - healthf())); + Draw.color(Color.black, team.color, healthf() + Mathf.absin(Time.time(), Math.max(healthf() * 5f, 1f), 1f - healthf())); Draw.rect(getPowerCellRegion(), x, y, rotation - 90); Draw.color(); @@ -400,10 +406,10 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ (3f + Mathf.absin(Time.time(), 5f, 1f)) * itemtime); if(number){ - Core.scene.skin.getFont("outline").draw(item.amount + "", + Fonts.outline.draw(item.amount + "", x + Angles.trnsx(rotation + 180f, backTrns), y + Angles.trnsy(rotation + 180f, backTrns) - 3, - Pal.accent, 0.25f * itemtime / UnitScl.dp.scl(1f), false, Align.center + Pal.accent, 0.25f * itemtime / Scl.scl(1f), false, Align.center ); } } diff --git a/core/src/io/anuke/mindustry/entities/units/Statuses.java b/core/src/io/anuke/mindustry/entities/units/Statuses.java index 75551f692b..8d7a392a5c 100644 --- a/core/src/io/anuke/mindustry/entities/units/Statuses.java +++ b/core/src/io/anuke/mindustry/entities/units/Statuses.java @@ -60,7 +60,7 @@ public class Statuses implements Saveable{ public Color getStatusColor(){ if(statuses.size == 0){ - return Tmp.c1.set(Color.WHITE); + return Tmp.c1.set(Color.white); } float r = 0f, g = 0f, b = 0f; diff --git a/core/src/io/anuke/mindustry/game/EventType.java b/core/src/io/anuke/mindustry/game/EventType.java index 6d8b8a0b40..5be7008c1a 100644 --- a/core/src/io/anuke/mindustry/game/EventType.java +++ b/core/src/io/anuke/mindustry/game/EventType.java @@ -1,13 +1,64 @@ package io.anuke.mindustry.game; +import io.anuke.annotations.Annotations.*; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.entities.traits.BuilderTrait; -import io.anuke.mindustry.entities.type.Unit; -import io.anuke.mindustry.type.Zone; +import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.entities.units.*; +import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.Tile; public class EventType{ + //events that occur very often + public enum Trigger{ + shock, + phaseDeflectHit, + impactPower, + thoriumReactorOverheat, + itemLaunch, + fireExtinguish, + newGame, + tutorialComplete, + flameAmmo, + turretCool, + enablePixelation, + drown, + exclusionDeath, + suicideBomb, + openWiki + } + + public static class WinEvent{} + + public static class LoseEvent{} + + public static class LaunchEvent{} + + public static class MapMakeEvent{} + + public static class MapPublishEvent{} + + public static class CommandIssueEvent{ + public final Tile tile; + public final UnitCommand command; + + public CommandIssueEvent(Tile tile, UnitCommand command){ + this.tile = tile; + this.command = command; + } + } + + public static class PlayerChatEvent{ + public final Player player; + public final String message; + + public PlayerChatEvent(Player player, String message){ + this.player = player; + this.message = message; + } + } + /** Called when a zone's requirements are met. */ public static class ZoneRequireCompleteEvent{ public final Zone zone, required; @@ -117,6 +168,14 @@ public class EventType{ } } + public static class ResearchEvent{ + public final UnlockableContent content; + + public ResearchEvent(UnlockableContent content){ + this.content = content; + } + } + /** * Called when block building begins by placing down the BuildBlock. * The tile's block will nearly always be a BuildBlock. @@ -136,11 +195,13 @@ public class EventType{ public static class BlockBuildEndEvent{ public final Tile tile; public final Team team; + public final @Nullable Player player; public final boolean breaking; - public BlockBuildEndEvent(Tile tile, Team team, boolean breaking){ + public BlockBuildEndEvent(Tile tile, @Nullable Player player, Team team, boolean breaking){ this.tile = tile; this.team = team; + this.player = player; this.breaking = breaking; } } @@ -181,8 +242,53 @@ public class EventType{ } } + public static class UnitCreateEvent{ + public final BaseUnit unit; + + public UnitCreateEvent(BaseUnit unit){ + this.unit = unit; + } + } + public static class ResizeEvent{ } + + public static class MechChangeEvent{ + public final Player player; + public final Mech mech; + + public MechChangeEvent(Player player, Mech mech){ + this.player = player; + this.mech = mech; + } + } + + /** Called after connecting; when a player recieves world data and is ready to play.*/ + public static class PlayerJoin{ + public final Player player; + + public PlayerJoin(Player player){ + this.player = player; + } + } + + /** Called when a player connects, but has not joined the game yet.*/ + public static class PlayerConnect{ + public final Player player; + + public PlayerConnect(Player player){ + this.player = player; + } + } + + public static class PlayerLeave{ + public final Player player; + + public PlayerLeave(Player player){ + this.player = player; + } + } + } diff --git a/core/src/io/anuke/mindustry/game/Gamemode.java b/core/src/io/anuke/mindustry/game/Gamemode.java index 16f129f065..79fa228305 100644 --- a/core/src/io/anuke/mindustry/game/Gamemode.java +++ b/core/src/io/anuke/mindustry/game/Gamemode.java @@ -22,7 +22,6 @@ public enum Gamemode{ attack(rules -> { rules.unitDrops = true; rules.attackMode = true; - rules.waves = true; }, map -> map.teams.contains(waveTeam.ordinal())), pvp(rules -> { rules.pvp = true; @@ -69,6 +68,20 @@ public enum Gamemode{ this.validator = validator; } + public static Gamemode bestFit(Rules rules){ + if(rules.pvp){ + return pvp; + }else if(rules.editor){ + return editor; + }else if(rules.attackMode){ + return attack; + }else if(rules.infiniteResources){ + return sandbox; + }else{ + return survival; + } + } + /** Applies this preset to this ruleset. */ public Rules apply(Rules in){ rules.accept(in); diff --git a/core/src/io/anuke/mindustry/game/GlobalData.java b/core/src/io/anuke/mindustry/game/GlobalData.java index 43b8095937..a782dc3f07 100644 --- a/core/src/io/anuke/mindustry/game/GlobalData.java +++ b/core/src/io/anuke/mindustry/game/GlobalData.java @@ -52,10 +52,12 @@ public class GlobalData{ } public void importData(FileHandle file){ - FileHandle zipped = new ZipFileHandle(file); + FileHandle dest = Core.files.local("zipdata.zip"); + file.copyTo(dest); + FileHandle zipped = new ZipFileHandle(dest); FileHandle base = Core.settings.getDataDirectory(); - if(!base.child("settings.bin").exists()){ + if(!zipped.child("settings.bin").exists()){ throw new IllegalArgumentException("Not valid save data."); } @@ -63,12 +65,13 @@ public class GlobalData{ for(FileHandle f : base.list()){ if(f.isDirectory()){ f.deleteDirectory(); - }else{ + }else if(!f.name().equals("zipdata.zip")){ f.delete(); } } zipped.walk(f -> f.copyTo(base.child(f.path()))); + dest.delete(); } public void modified(){ diff --git a/core/src/io/anuke/mindustry/game/MusicControl.java b/core/src/io/anuke/mindustry/game/MusicControl.java index 28991e87e2..81b0cdf0b6 100644 --- a/core/src/io/anuke/mindustry/game/MusicControl.java +++ b/core/src/io/anuke/mindustry/game/MusicControl.java @@ -14,7 +14,7 @@ import static io.anuke.mindustry.Vars.*; /** Controls playback of multiple music tracks.*/ public class MusicControl{ - private static final float finTime = 120f, foutTime = 120f, musicInterval = 60 * 60 * 3f, musicChance = 0.5f, musicWaveChance = 0.4f; + private static final float finTime = 120f, foutTime = 120f, musicInterval = 60 * 60 * 3f, musicChance = 0.6f, musicWaveChance = 0.5f; /** normal, ambient music, plays at any time */ public final Array ambientMusic = Array.with(Musics.game1, Musics.game3, Musics.game4, Musics.game6); @@ -133,8 +133,8 @@ public class MusicControl{ } /** Plays a music track once and only once. If something is already playing, does nothing.*/ - private void playOnce(@NonNull Music music){ - if(current != null) return; //do not interrupt already-playing tracks + private void playOnce(Music music){ + if(current != null || music == null) return; //do not interrupt already-playing tracks //save last random track played to prevent duplicates lastRandomPlayed = music; diff --git a/core/src/io/anuke/mindustry/game/Rules.java b/core/src/io/anuke/mindustry/game/Rules.java index 014a918904..0d85482976 100644 --- a/core/src/io/anuke/mindustry/game/Rules.java +++ b/core/src/io/anuke/mindustry/game/Rules.java @@ -74,4 +74,9 @@ public class Rules{ public Rules copy(){ return JsonIO.copy(this); } + + /** Returns the gamemode that best fits these rules.*/ + public Gamemode mode(){ + return Gamemode.bestFit(this); + } } diff --git a/core/src/io/anuke/mindustry/game/Saves.java b/core/src/io/anuke/mindustry/game/Saves.java index 284de3572b..74046d2fa4 100644 --- a/core/src/io/anuke/mindustry/game/Saves.java +++ b/core/src/io/anuke/mindustry/game/Saves.java @@ -266,6 +266,10 @@ public class Saves{ return meta == null || meta.rules == null ? null : meta.rules.zone; } + public Gamemode mode(){ + return Gamemode.bestFit(meta.rules); + } + public int getBuild(){ return meta.build; } @@ -293,9 +297,6 @@ public class Saves{ public void exportFile(FileHandle file) throws IOException{ try{ - if(!file.extension().equals(saveExtension)){ - file = file.parent().child(file.nameWithoutExtension() + "." + saveExtension); - } SaveIO.fileFor(index).copyTo(file); }catch(Exception e){ throw new IOException(e); diff --git a/core/src/io/anuke/mindustry/game/Team.java b/core/src/io/anuke/mindustry/game/Team.java index b4cb74c02c..57209fc62c 100644 --- a/core/src/io/anuke/mindustry/game/Team.java +++ b/core/src/io/anuke/mindustry/game/Team.java @@ -10,7 +10,7 @@ public enum Team{ crux(Color.valueOf("e82d2d")), green(Color.valueOf("4dd98b")), purple(Color.valueOf("9a4bdf")), - blue(Color.ROYAL.cpy()); + blue(Color.royal.cpy()); public final static Team[] all = values(); public final Color color; diff --git a/core/src/io/anuke/mindustry/game/Tutorial.java b/core/src/io/anuke/mindustry/game/Tutorial.java index 4989d07c73..d2534c151b 100644 --- a/core/src/io/anuke/mindustry/game/Tutorial.java +++ b/core/src/io/anuke/mindustry/game/Tutorial.java @@ -115,9 +115,7 @@ public class Tutorial{ outline("blockinfo"); } }, - conveyor( - line -> Strings.format(line, Math.min(placed(Blocks.conveyor), 2), 2), - () -> placed(Blocks.conveyor, 2) && event("lineconfirm") && event("coreitem")){ + conveyor(() -> placed(Blocks.conveyor, 2) && event("lineconfirm") && event("coreitem")){ void draw(){ outline("category-distribution"); outline("block-conveyor"); @@ -179,6 +177,7 @@ public class Tutorial{ state.wave = 5; //end tutorial, never show it again + Events.fire(Trigger.tutorialComplete); Core.settings.put("playedtutorial", true); Core.settings.save(); } @@ -190,13 +189,12 @@ public class Tutorial{ protected final String line = Core.bundle.has("tutorial." + name() + ".mobile") && mobile ? "tutorial." + name() + ".mobile" : "tutorial." + name(); protected final Function text; - protected final Array sentences; + protected Array sentences; protected final BooleanProvider done; TutorialStage(Function text, BooleanProvider done){ this.text = text; this.done = done; - this.sentences = Array.select(Core.bundle.get(line).split("\n"), s -> !s.isEmpty()); } TutorialStage(BooleanProvider done){ @@ -205,6 +203,7 @@ public class Tutorial{ /** displayed tutorial stage text.*/ public String text(){ + if(sentences == null) this.sentences = Array.select(Core.bundle.get(line).split("\n"), s -> !s.isEmpty()); String line = sentences.get(control.tutorial.sentence); return line.contains("{") ? text.get(line) : line; } @@ -273,20 +272,20 @@ public class Tutorial{ Element element = Core.scene.findVisible(name); if(element != null && !toggled(name)){ element.localToStageCoordinates(Tmp.v1.setZero()); - float sin = Mathf.sin(11f, UnitScl.dp.scl(4f)); - Lines.stroke(UnitScl.dp.scl(7f), Pal.place); + float sin = Mathf.sin(11f, Scl.scl(4f)); + Lines.stroke(Scl.scl(7f), Pal.place); Lines.rect(Tmp.v1.x - sin, Tmp.v1.y - sin, element.getWidth() + sin*2, element.getHeight() + sin*2); - float size = Math.max(element.getWidth(), element.getHeight()) + Mathf.absin(11f/2f, UnitScl.dp.scl(18f)); + float size = Math.max(element.getWidth(), element.getHeight()) + Mathf.absin(11f/2f, Scl.scl(18f)); float angle = Angles.angle(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f, Tmp.v1.x + element.getWidth()/2f, Tmp.v1.y + element.getHeight()/2f); Tmp.v2.trns(angle + 180f, size*1.4f); - float fs = UnitScl.dp.scl(40f); - float fs2 = UnitScl.dp.scl(56f); + float fs = Scl.scl(40f); + float fs2 = Scl.scl(56f); Draw.color(Pal.gray); Drawf.tri(Tmp.v1.x + element.getWidth()/2f + Tmp.v2.x, Tmp.v1.y + element.getHeight()/2f + Tmp.v2.y, fs2, fs2, angle); Draw.color(Pal.place); - Tmp.v2.setLength(Tmp.v2.len() - UnitScl.dp.scl(4)); + Tmp.v2.setLength(Tmp.v2.len() - Scl.scl(4)); Drawf.tri(Tmp.v1.x + element.getWidth()/2f + Tmp.v2.x, Tmp.v1.y + element.getHeight()/2f + Tmp.v2.y, fs, fs, angle); Draw.reset(); } diff --git a/core/src/io/anuke/mindustry/game/Version.java b/core/src/io/anuke/mindustry/game/Version.java index 77a14dac1a..3cbd43f52b 100644 --- a/core/src/io/anuke/mindustry/game/Version.java +++ b/core/src/io/anuke/mindustry/game/Version.java @@ -1,12 +1,13 @@ package io.anuke.mindustry.game; -import io.anuke.arc.Core; -import io.anuke.arc.collection.ObjectMap; -import io.anuke.arc.files.FileHandle; -import io.anuke.arc.util.Strings; -import io.anuke.arc.util.io.PropertiesUtils; +import io.anuke.arc.*; +import io.anuke.arc.Files.*; +import io.anuke.arc.collection.*; +import io.anuke.arc.files.*; +import io.anuke.arc.util.*; +import io.anuke.arc.util.io.*; -import java.io.IOException; +import java.io.*; public class Version{ /** Build type. 'official' for official releases; 'custom' or 'bleeding edge' are also used. */ @@ -26,7 +27,7 @@ public class Version{ if(!enabled) return; try{ - FileHandle file = Core.files.internal("version.properties"); + FileHandle file = OS.isAndroid || OS.isIos ? Core.files.internal("version.properties") : new FileHandle("version.properties", FileType.Internal); ObjectMap map = new ObjectMap<>(); PropertiesUtils.load(map, file.reader()); diff --git a/core/src/io/anuke/mindustry/graphics/BlockRenderer.java b/core/src/io/anuke/mindustry/graphics/BlockRenderer.java index 292052479c..ab9af0d674 100644 --- a/core/src/io/anuke/mindustry/graphics/BlockRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/BlockRenderer.java @@ -44,7 +44,7 @@ public class BlockRenderer implements Disposable{ shadows.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear); shadows.resize(world.width(), world.height()); shadows.begin(); - Core.graphics.clear(Color.WHITE); + Core.graphics.clear(Color.white); Draw.proj().setOrtho(0, 0, shadows.getWidth(), shadows.getHeight()); Draw.color(shadowColor); @@ -65,7 +65,7 @@ public class BlockRenderer implements Disposable{ fog.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear); fog.resize(world.width(), world.height()); fog.begin(); - Core.graphics.clear(Color.WHITE); + Core.graphics.clear(Color.white); Draw.proj().setOrtho(0, 0, fog.getWidth(), fog.getHeight()); for(int x = 0; x < world.width(); x++){ @@ -129,10 +129,10 @@ public class BlockRenderer implements Disposable{ for(Tile tile : shadowEvents){ //clear it first - Draw.color(Color.WHITE); + Draw.color(Color.white); Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1); //then draw the shadow - Draw.color(!tile.block().hasShadow ? Color.WHITE : shadowColor); + Draw.color(!tile.block().hasShadow ? Color.white : shadowColor); Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1); } diff --git a/core/src/io/anuke/mindustry/graphics/CacheLayer.java b/core/src/io/anuke/mindustry/graphics/CacheLayer.java index 9c96f4d3c5..6b5c66683b 100644 --- a/core/src/io/anuke/mindustry/graphics/CacheLayer.java +++ b/core/src/io/anuke/mindustry/graphics/CacheLayer.java @@ -47,7 +47,7 @@ public enum CacheLayer{ renderer.blocks.floor.endc(); renderer.shieldBuffer.begin(); - Core.graphics.clear(Color.CLEAR); + Core.graphics.clear(Color.clear); renderer.blocks.floor.beginc(); } diff --git a/core/src/io/anuke/mindustry/graphics/IndexedRenderer.java b/core/src/io/anuke/mindustry/graphics/IndexedRenderer.java index b4165dbe63..fe7a39b51d 100644 --- a/core/src/io/anuke/mindustry/graphics/IndexedRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/IndexedRenderer.java @@ -53,7 +53,7 @@ public class IndexedRenderer implements Disposable{ private Matrix3 projMatrix = new Matrix3(); private Matrix3 transMatrix = new Matrix3(); private Matrix3 combined = new Matrix3(); - private float color = Color.WHITE.toFloatBits(); + private float color = Color.white.toFloatBits(); public IndexedRenderer(int sprites){ resize(sprites); diff --git a/core/src/io/anuke/mindustry/graphics/MenuRenderer.java b/core/src/io/anuke/mindustry/graphics/MenuRenderer.java index 240f7e584f..0fcd5b82d3 100644 --- a/core/src/io/anuke/mindustry/graphics/MenuRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/MenuRenderer.java @@ -8,7 +8,7 @@ import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.glutils.FrameBuffer; import io.anuke.arc.math.*; -import io.anuke.arc.scene.ui.layout.UnitScl; +import io.anuke.arc.scene.ui.layout.Scl; import io.anuke.arc.util.*; import io.anuke.arc.util.noise.RidgedPerlin; import io.anuke.arc.util.noise.Simplex; @@ -168,8 +168,8 @@ public class MenuRenderer implements Disposable{ //draw shadows Draw.proj().setOrtho(0, 0, shadows.getWidth(), shadows.getHeight()); - shadows.beginDraw(Color.CLEAR); - Draw.color(Color.BLACK); + shadows.beginDraw(Color.clear); + Draw.color(Color.black); for(int x = 0; x < width; x++){ for(int y = 0; y < height; y++){ if(world.rawTile(x, y).block() != Blocks.air){ @@ -220,7 +220,7 @@ public class MenuRenderer implements Disposable{ public void render(){ time += Time.delta(); - float scaling = Math.max(UnitScl.dp.scl(4f), Math.max(Core.graphics.getWidth() / ((width - 1f) * tilesize), Core.graphics.getHeight() / ((height - 1f) * tilesize))); + float scaling = Math.max(Scl.scl(4f), Math.max(Core.graphics.getWidth() / ((width - 1f) * tilesize), Core.graphics.getHeight() / ((height - 1f) * tilesize))); camera.position.set(width * tilesize / 2f, height * tilesize / 2f); camera.resize(Core.graphics.getWidth() / scaling, Core.graphics.getHeight() / scaling); @@ -270,7 +270,7 @@ public class MenuRenderer implements Disposable{ Fill.circle(x + Angles.trnsx(rotation + 180, engineOffset), y + Angles.trnsy(rotation + 180, engineOffset), engineSize + Mathf.absin(Time.time(), 2f, engineSize / 4f)); - Draw.color(Color.WHITE); + Draw.color(Color.white); Fill.circle(x + Angles.trnsx(rotation + 180, engineOffset - 1f), y + Angles.trnsy(rotation + 180, engineOffset - 1f), (engineSize + Mathf.absin(Time.time(), 2f, engineSize / 4f)) / 2f); Draw.color(); diff --git a/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java b/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java index 653efeacd4..629ed54791 100644 --- a/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java @@ -82,7 +82,7 @@ public class MinimapRenderer implements Disposable{ for(Unit unit : units){ float rx = (unit.x - rect.x) / rect.width * w, ry = (unit.y - rect.y) / rect.width * h; Draw.color(unit.getTeam().color); - Fill.rect(x + rx, y + ry, UnitScl.dp.scl(baseSize / 2f), UnitScl.dp.scl(baseSize / 2f)); + Fill.rect(x + rx, y + ry, Scl.scl(baseSize / 2f), Scl.scl(baseSize / 2f)); } Draw.color(); diff --git a/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java b/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java index 4ca26d2317..97b74f881f 100644 --- a/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java @@ -84,7 +84,7 @@ public class OverlayRenderer{ for(Tile core : state.teams.get(enemy).cores){ float dst = Mathf.dst(player.x, player.y, core.drawx(), core.drawy()); if(dst < state.rules.enemyCoreBuildRadius * 1.5f){ - Draw.color(Color.DARK_GRAY); + Draw.color(Color.darkGray); Lines.circle(core.drawx(), core.drawy() - 2, state.rules.enemyCoreBuildRadius); Draw.color(Pal.accent, enemy.color, 0.5f + Mathf.absin(Time.time(), 10f, 0.5f)); Lines.circle(core.drawx(), core.drawy(), state.rules.enemyCoreBuildRadius); @@ -94,7 +94,7 @@ public class OverlayRenderer{ } Lines.stroke(2f); - Draw.color(Color.GRAY, Color.LIGHT_GRAY, Mathf.absin(Time.time(), 8f, 1f)); + Draw.color(Color.gray, Color.lightGray, Mathf.absin(Time.time(), 8f, 1f)); for(Tile tile : spawner.getGroundSpawns()){ if(tile.withinDst(player.x, player.y, state.rules.dropZoneRadius + spawnerMargin)){ diff --git a/core/src/io/anuke/mindustry/graphics/Pal.java b/core/src/io/anuke/mindustry/graphics/Pal.java index e24b04ed69..3017cc6c26 100644 --- a/core/src/io/anuke/mindustry/graphics/Pal.java +++ b/core/src/io/anuke/mindustry/graphics/Pal.java @@ -51,7 +51,7 @@ public class Pal{ health = Color.valueOf("ff341c"), heal = Color.valueOf("98ffa9"), - bar = Color.SLATE, + bar = Color.slate, accent = Color.valueOf("ffd37f"), stat = Color.valueOf("ffd37f"), gray = Color.valueOf("454545"), diff --git a/core/src/io/anuke/mindustry/graphics/Pixelator.java b/core/src/io/anuke/mindustry/graphics/Pixelator.java index 5637ae8d8a..448e35bffe 100644 --- a/core/src/io/anuke/mindustry/graphics/Pixelator.java +++ b/core/src/io/anuke/mindustry/graphics/Pixelator.java @@ -37,8 +37,8 @@ public class Pixelator implements Disposable{ float px = Core.camera.position.x, py = Core.camera.position.y; Core.camera.position.set((int)px + ((int)(camera.width) % 2 == 0 ? 0 : 0.5f), (int)py + ((int)(camera.height) % 2 == 0 ? 0 : 0.5f)); - int w = (int)(Core.camera.width); - int h = (int)(Core.camera.height); + int w = (int)(Core.camera.width * renderer.landScale()); + int h = (int)(Core.camera.height * renderer.landScale()); if(!graphics.isHidden() && (buffer.getWidth() != w || buffer.getHeight() != h)){ buffer.resize(w, h); diff --git a/core/src/io/anuke/mindustry/graphics/Shaders.java b/core/src/io/anuke/mindustry/graphics/Shaders.java index afa94cd6ec..2c2316c07d 100644 --- a/core/src/io/anuke/mindustry/graphics/Shaders.java +++ b/core/src/io/anuke/mindustry/graphics/Shaders.java @@ -5,7 +5,7 @@ import io.anuke.arc.Core; import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.g2d.TextureRegion; import io.anuke.arc.graphics.glutils.Shader; -import io.anuke.arc.scene.ui.layout.UnitScl; +import io.anuke.arc.scene.ui.layout.Scl; import io.anuke.arc.util.Time; public class Shaders{ @@ -48,7 +48,7 @@ public class Shaders{ setUniformf("u_resolution", Core.graphics.getWidth(), Core.graphics.getHeight()); setUniformi("u_time", (int)(time += Core.graphics.getDeltaTime() * 60f)); setUniformf("u_uv", Core.atlas.white().getU(), Core.atlas.white().getV()); - setUniformf("u_scl", UnitScl.dp.scl(1f)); + setUniformf("u_scl", Scl.scl(1f)); setUniformf("u_uv2", Core.atlas.white().getU2(), Core.atlas.white().getV2()); } } @@ -124,8 +124,8 @@ public class Shaders{ @Override public void apply(){ - setUniformf("u_dp", UnitScl.dp.scl(1f)); - setUniformf("u_time", Time.time() / UnitScl.dp.scl(1f)); + setUniformf("u_dp", Scl.scl(1f)); + setUniformf("u_time", Time.time() / Scl.scl(1f)); setUniformf("u_offset", Core.camera.position.x - Core.camera.width / 2, Core.camera.position.y - Core.camera.height / 2); diff --git a/core/src/io/anuke/mindustry/input/DesktopInput.java b/core/src/io/anuke/mindustry/input/DesktopInput.java index caf01eeb25..874e29ae5b 100644 --- a/core/src/io/anuke/mindustry/input/DesktopInput.java +++ b/core/src/io/anuke/mindustry/input/DesktopInput.java @@ -123,7 +123,7 @@ public class DesktopInput extends InputHandler{ @Override public void update(){ - if(Net.active() && Core.input.keyTap(Binding.player_list)){ + if(net.active() && Core.input.keyTap(Binding.player_list)){ ui.listfrag.toggle(); } diff --git a/core/src/io/anuke/mindustry/input/InputHandler.java b/core/src/io/anuke/mindustry/input/InputHandler.java index 6ed371a7ec..e4e8dadfc7 100644 --- a/core/src/io/anuke/mindustry/input/InputHandler.java +++ b/core/src/io/anuke/mindustry/input/InputHandler.java @@ -19,7 +19,6 @@ import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; -import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.*; import io.anuke.mindustry.type.*; import io.anuke.mindustry.ui.fragments.*; @@ -49,21 +48,22 @@ public abstract class InputHandler implements InputProcessor{ @Remote(targets = Loc.client, called = Loc.server) public static void dropItem(Player player, float angle){ - if(Net.server() && player.item().amount <= 0){ + if(net.server() && player.item().amount <= 0){ throw new ValidateException(player, "Player cannot drop an item."); } - Effects.effect(Fx.dropItem, Color.WHITE, player.x, player.y, angle, player.item().item); + Effects.effect(Fx.dropItem, Color.white, player.x, player.y, angle, player.item().item); player.clearItem(); } @Remote(targets = Loc.both, forward = true, called = Loc.server) public static void transferInventory(Player player, Tile tile){ - if(Net.server() && (player.item().amount <= 0 || player.isTransferring)){ + if(!player.timer.get(Player.timerTransfer, 40)) return; + if(net.server() && (player.item().amount <= 0 || player.isTransferring|| !tile.interactable(player.getTeam()))){ throw new ValidateException(player, "Player cannot transfer an item."); } - if(player == null || tile.entity == null) return; + if(tile.entity == null) return; player.isTransferring = true; @@ -288,7 +288,7 @@ public abstract class InputHandler implements InputProcessor{ } public void tryDropItems(Tile tile, float x, float y){ - if(!droppingItem || player.item().amount <= 0 || canTapPlayer(x, y) || state.isPaused()){ + if(!droppingItem || player.item().amount <= 0 || canTapPlayer(x, y) || state.isPaused() || !player.timer.check(Player.timerTransfer, 40)){ droppingItem = false; return; } @@ -297,7 +297,7 @@ public abstract class InputHandler implements InputProcessor{ ItemStack stack = player.item(); - if(tile.block().acceptStack(stack.item, stack.amount, tile, player) > 0 && tile.interactable(player.getTeam()) && tile.block().hasItems){ + if(tile.block().acceptStack(stack.item, stack.amount, tile, player) > 0 && tile.interactable(player.getTeam()) && tile.block().hasItems && player.item().amount > 0 && !player.isTransferring && tile.interactable(player.getTeam())){ Call.transferInventory(player, tile); }else{ Call.dropItem(player.angleTo(x, y)); diff --git a/core/src/io/anuke/mindustry/input/MobileInput.java b/core/src/io/anuke/mindustry/input/MobileInput.java index 442a05a226..14f86e360f 100644 --- a/core/src/io/anuke/mindustry/input/MobileInput.java +++ b/core/src/io/anuke/mindustry/input/MobileInput.java @@ -17,8 +17,10 @@ import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.game.EventType.*; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.input.PlaceUtils.*; +import io.anuke.mindustry.ui.*; import io.anuke.mindustry.world.*; import static io.anuke.mindustry.Vars.*; @@ -29,7 +31,7 @@ public class MobileInput extends InputHandler implements GestureListener{ private static final float maxPanSpeed = 1.3f; private static Rectangle r1 = new Rectangle(), r2 = new Rectangle(); /** Distance to edge of screen to start panning. */ - private final float edgePan = UnitScl.dp.scl(60f); + private final float edgePan = Scl.scl(60f); //gesture data private Vector2 vector = new Vector2(); @@ -65,7 +67,33 @@ public class MobileInput extends InputHandler implements GestureListener{ public MobileInput(){ Events.on(ClientLoadEvent.class, e -> { - Core.input.addProcessor(new GestureDetector(20, 0.5f, 0.4f, 0.15f, this)); + GestureDetector dec = new GestureDetector(20, 0.5f, 0.4f, 0.15f, this){ + boolean clearMouse = false; + + @Override + public boolean touchDown(int x, int y, int pointer, KeyCode button){ + if(Core.scene.hasMouse(x, y)){ + clearMouse = true; + return false; + } + return super.touchDown(x, y, pointer, button); + } + + @Override + public boolean touchDragged(int x, int y, int pointer){ + if(!clearMouse){ + return super.touchDragged(x, y, pointer); + } + return false; + } + + @Override + public boolean touchUp(int x, int y, int pointer, KeyCode button){ + clearMouse = false; + return super.touchUp(x, y, pointer, button); + } + }; + Core.input.getInputProcessors().insert(0, dec); }); } @@ -190,7 +218,7 @@ public class MobileInput extends InputHandler implements GestureListener{ TextureRegion region = placeDraw.region; Draw.mixcol(Pal.accent, Mathf.clamp((1f - request.scale) / 0.5f + 0.12f + Mathf.absin(Time.time(), 8f, 0.35f))); - Draw.tint(Color.WHITE, Pal.breakInvalid, request.redness); + Draw.tint(Color.white, Pal.breakInvalid, request.redness); Draw.rect(region, tile.worldx() + offset, tile.worldy() + offset, region.getWidth() * request.scale * Draw.scl * placeDraw.scalex, @@ -249,27 +277,27 @@ public class MobileInput extends InputHandler implements GestureListener{ @Override public void buildUI(Table table){ - table.addImage("whiteui").color(Pal.gray).height(4f).colspan(4).growX(); + table.addImage().color(Pal.gray).height(4f).colspan(4).growX(); table.row(); table.left().margin(0f).defaults().size(48f); - table.addImageButton("icon-break-small", "clear-toggle-partial", iconsizesmall, () -> { + table.addImageButton(Icon.breakSmall, Styles.clearTogglePartiali, () -> { mode = mode == breaking ? block == null ? none : placing : breaking; lastBlock = block; }).update(l -> l.setChecked(mode == breaking)).name("breakmode"); //diagonal swap button - table.addImageButton("icon-diagonal-small", "clear-toggle-partial", iconsizesmall, () -> { + table.addImageButton(Icon.diagonalSmall, Styles.clearTogglePartiali, () -> { Core.settings.put("swapdiagonal", !Core.settings.getBool("swapdiagonal")); Core.settings.save(); }).update(l -> l.setChecked(Core.settings.getBool("swapdiagonal"))); //rotate button - table.addImageButton("icon-arrow-small", "clear-partial", iconsizesmall, () -> rotation = Mathf.mod(rotation + 1, 4)) + table.addImageButton(Icon.arrowSmall, Styles.clearPartiali,() -> rotation = Mathf.mod(rotation + 1, 4)) .update(i -> i.getImage().setRotationOrigin(rotation * 90, Align.center)).visible(() -> block != null && block.rotate); //confirm button - table.addImageButton("icon-check-small", "clear-partial", iconsizesmall, () -> { + table.addImageButton(Icon.checkSmall, Styles.clearPartiali, () -> { for(PlaceRequest request : selection){ Tile tile = request.tile(); @@ -295,7 +323,7 @@ public class MobileInput extends InputHandler implements GestureListener{ Core.scene.table(t -> { t.bottom().left().visible(() -> (player.isBuilding() || block != null || mode == breaking) && !state.is(State.menu)); - t.addImageTextButton("$cancel", "icon-cancel", 16*2, () -> { + t.addImageTextButton("$cancel", Icon.cancelSmall, () -> { player.clearBuilding(); mode = none; block = null; diff --git a/core/src/io/anuke/mindustry/io/LegacyMapIO.java b/core/src/io/anuke/mindustry/io/LegacyMapIO.java index d948fbee19..31ebe0403d 100644 --- a/core/src/io/anuke/mindustry/io/LegacyMapIO.java +++ b/core/src/io/anuke/mindustry/io/LegacyMapIO.java @@ -207,7 +207,7 @@ public class LegacyMapIO{ if(block.ore != null) tile.setOverlay(block.ore); //place core - if(color == Color.rgba8888(Color.GREEN)){ + if(color == Color.rgba8888(Color.green)){ for(int dx = 0; dx < 3; dx++){ for(int dy = 0; dy < 3; dy++){ int worldx = dx - 1 + x; diff --git a/core/src/io/anuke/mindustry/io/MapIO.java b/core/src/io/anuke/mindustry/io/MapIO.java index 722dcaae8b..eb462724b2 100644 --- a/core/src/io/anuke/mindustry/io/MapIO.java +++ b/core/src/io/anuke/mindustry/io/MapIO.java @@ -73,7 +73,7 @@ public class MapIO{ Pixmap floors = new Pixmap(map.width, map.height, Format.RGBA8888); Pixmap walls = new Pixmap(map.width, map.height, Format.RGBA8888); - int black = Color.rgba8888(Color.BLACK); + int black = Color.rgba8888(Color.black); int shade = Color.rgba8888(0f, 0f, 0f, 0.5f); CachedTile tile = new CachedTile(){ @Override diff --git a/core/src/io/anuke/mindustry/io/TypeIO.java b/core/src/io/anuke/mindustry/io/TypeIO.java index 25d6f92bec..1d17e0bc44 100644 --- a/core/src/io/anuke/mindustry/io/TypeIO.java +++ b/core/src/io/anuke/mindustry/io/TypeIO.java @@ -5,7 +5,7 @@ import io.anuke.annotations.Annotations.WriteClass; import io.anuke.arc.graphics.Color; import io.anuke.mindustry.entities.Effects; import io.anuke.mindustry.entities.Effects.Effect; -import io.anuke.mindustry.entities.bullet.Bullet; +import io.anuke.mindustry.entities.type.Bullet; import io.anuke.mindustry.entities.bullet.BulletType; import io.anuke.mindustry.entities.traits.BuilderTrait.BuildRequest; import io.anuke.mindustry.entities.traits.ShooterTrait; diff --git a/core/src/io/anuke/mindustry/io/versions/LegacyTypeTable.java b/core/src/io/anuke/mindustry/io/versions/LegacyTypeTable.java index 6205313247..9af7e9f785 100644 --- a/core/src/io/anuke/mindustry/io/versions/LegacyTypeTable.java +++ b/core/src/io/anuke/mindustry/io/versions/LegacyTypeTable.java @@ -1,7 +1,7 @@ package io.anuke.mindustry.io.versions; import io.anuke.arc.function.Supplier; -import io.anuke.mindustry.entities.bullet.Bullet; +import io.anuke.mindustry.entities.type.Bullet; import io.anuke.mindustry.entities.effect.*; import io.anuke.mindustry.entities.type.Player; import io.anuke.mindustry.entities.type.base.*; diff --git a/core/src/io/anuke/mindustry/maps/Maps.java b/core/src/io/anuke/mindustry/maps/Maps.java index 932045d016..7336e63114 100644 --- a/core/src/io/anuke/mindustry/maps/Maps.java +++ b/core/src/io/anuke/mindustry/maps/Maps.java @@ -108,7 +108,7 @@ public class Maps{ * Save a custom map to the directory. This updates all values and stored data necessary. * The tags are copied to prevent mutation later. */ - public void saveMap(ObjectMap baseTags){ + public Map saveMap(ObjectMap baseTags){ try{ StringMap tags = new StringMap(baseTags); @@ -166,6 +166,9 @@ public class Maps{ } maps.add(map); maps.sort(); + + return map; + }catch(IOException e){ throw new RuntimeException(e); } @@ -184,7 +187,23 @@ public class Maps{ FileHandle dest = findFile(); file.copyTo(dest); - loadMap(dest, true); + Map map = loadMap(dest, true); + Exception[] error = {null}; + + createNewPreview(map, e -> { + maps.remove(map); + try{ + map.file.delete(); + }catch(Throwable ignored){ + + } + error[0] = e; + }); + + if(error[0] != null){ + throw new IOException(error[0]); + } + } /** Attempts to run the following code; @@ -196,11 +215,11 @@ public class Maps{ Log.err(e); if("Outdated legacy map format".equals(e.getMessage())){ - ui.showError("$editor.errorlegacy"); + ui.showErrorMessage("$editor.errornot"); }else if(e.getMessage() != null && e.getMessage().contains("Incorrect header!")){ - ui.showError("$editor.errorheader"); + ui.showErrorMessage("$editor.errorheader"); }else{ - ui.showError(Core.bundle.format("editor.errorload", Strings.parseException(e, true))); + ui.showException("$editor.errorload", e); } } } @@ -290,34 +309,6 @@ public class Maps{ return str == null ? null : str.equals("[]") ? new Array<>() : Array.with(json.fromJson(SpawnGroup[].class, str)); } - public void loadLegacyMaps(){ - boolean convertedAny = false; - for(FileHandle file : customMapDirectory.list()){ - if(file.extension().equalsIgnoreCase(oldMapExtension)){ - try{ - convertedAny = true; - LegacyMapIO.convertMap(file, file.sibling(file.nameWithoutExtension() + "." + mapExtension)); - //delete old, converted file; it is no longer useful - file.delete(); - Log.info("Converted file {0}", file); - }catch(Exception e){ - //rename the file to a 'mmap_conversion_failed' extension to keep it there just in case - //but don't delete it - file.copyTo(file.sibling(file.name() + "_conversion_failed")); - file.delete(); - Log.err(e); - } - } - } - - //free up any potential memory that was used up during conversion - if(convertedAny){ - world.createTiles(1, 1); - //reload maps to load the converted ones - reload(); - } - } - public void loadPreviews(){ for(Map map : maps){ @@ -341,7 +332,7 @@ public class Maps{ private void createAllPreviews(){ Core.app.post(() -> { for(Map map : previewList){ - createNewPreview(map); + createNewPreview(map, e -> Core.app.post(() -> map.texture = new Texture("sprites/error.png"))); } previewList.clear(); }); @@ -351,12 +342,12 @@ public class Maps{ Core.app.post(() -> previewList.add(map)); } - private void createNewPreview(Map map){ + private void createNewPreview(Map map, Consumer failed){ try{ //if it's here, then the preview failed to load or doesn't exist, make it //this has to be done synchronously! Pixmap pix = MapIO.generatePreview(map); - Core.app.post(() -> map.texture = new Texture(pix)); + map.texture = new Texture(pix); executor.submit(() -> { try{ map.previewFile().writePNG(pix); @@ -365,9 +356,9 @@ public class Maps{ e.printStackTrace(); } }); - }catch(IOException e){ + }catch(Exception e){ + failed.accept(e); Log.err("Failed to generate preview!", e); - Core.app.post(() -> map.texture = new Texture("sprites/error.png")); } } @@ -404,7 +395,7 @@ public class Maps{ return customMapDirectory.child("map_" + i + "." + mapExtension); } - private void loadMap(FileHandle file, boolean custom) throws IOException{ + private Map loadMap(FileHandle file, boolean custom) throws IOException{ Map map = MapIO.createMap(file, custom); if(map.name() == null){ @@ -413,6 +404,7 @@ public class Maps{ maps.add(map); maps.sort(); + return map; } private void loadCustomMaps(){ diff --git a/core/src/io/anuke/mindustry/maps/filters/MirrorFilter.java b/core/src/io/anuke/mindustry/maps/filters/MirrorFilter.java index 27fc101b5e..f46673676e 100644 --- a/core/src/io/anuke/mindustry/maps/filters/MirrorFilter.java +++ b/core/src/io/anuke/mindustry/maps/filters/MirrorFilter.java @@ -59,7 +59,7 @@ public class MirrorFilter extends GenerateFilter{ clamper.accept(Tmp.v1.trns(angle - 90, size).add(image.getWidth()/2f + image.getX(), image.getHeight()/2f + image.getY())); clamper.accept(Tmp.v2.set(Tmp.v1).sub(image.getWidth()/2f + image.getX(), image.getHeight()/2f + image.getY()).rotate(180f).add(image.getWidth()/2f + image.getX(), image.getHeight()/2f + image.getY())); - Lines.stroke(UnitScl.dp.scl(3f), Pal.accent); + Lines.stroke(Scl.scl(3f), Pal.accent); Lines.line(Tmp.v1.x, Tmp.v1.y, Tmp.v2.x, Tmp.v2.y); Draw.reset(); } diff --git a/core/src/io/anuke/mindustry/net/Administration.java b/core/src/io/anuke/mindustry/net/Administration.java index bebd0c9115..0aaeb8542f 100644 --- a/core/src/io/anuke/mindustry/net/Administration.java +++ b/core/src/io/anuke/mindustry/net/Administration.java @@ -1,7 +1,7 @@ package io.anuke.mindustry.net; -import io.anuke.annotations.Annotations.Serialize; -import io.anuke.arc.Core; +import io.anuke.annotations.Annotations.*; +import io.anuke.arc.*; import io.anuke.arc.collection.*; import static io.anuke.mindustry.Vars.headless; @@ -10,6 +10,7 @@ public class Administration{ /** All player info. Maps UUIDs to info. This persists throughout restarts. */ private ObjectMap playerInfo = new ObjectMap<>(); private Array bannedIPs = new Array<>(); + private Array whitelist = new Array<>(); public Administration(){ Core.settings.defaults( @@ -20,9 +21,16 @@ public class Administration{ load(); } + public int getPlayerLimit(){ + return Core.settings.getInt("playerlimit", 0); + } + + public void setPlayerLimit(int limit){ + Core.settings.putSave("playerlimit", limit); + } + public void setStrict(boolean on){ - Core.settings.put("strict", on); - Core.settings.save(); + Core.settings.putSave("strict", on); } public boolean getStrict(){ @@ -186,6 +194,36 @@ public class Administration{ return true; } + public boolean isWhitelistEnabled(){ + return Core.settings.getBool("whitelist", false); + } + + public void setWhitelist(boolean enabled){ + Core.settings.putSave("whitelist", enabled); + } + + public boolean isWhitelisted(String id, String usid){ + return !isWhitelistEnabled() || whitelist.contains(usid + id); + } + + public boolean whitelist(String id){ + PlayerInfo info = getCreateInfo(id); + if(whitelist.contains(info.adminUsid + id)) return false; + whitelist.add(info.adminUsid + id); + save(); + return true; + } + + public boolean unwhitelist(String id){ + PlayerInfo info = getCreateInfo(id); + if(whitelist.contains(info.adminUsid + id)){ + whitelist.remove(info.adminUsid + id); + save(); + return true; + } + return false; + } + public boolean isIPBanned(String ip){ return bannedIPs.contains(ip, false) || (findByIP(ip) != null && findByIP(ip).banned); } @@ -242,6 +280,10 @@ public class Administration{ return null; } + public Array getWhitelisted(){ + return playerInfo.values().toArray().select(p -> isWhitelisted(p.id, p.adminUsid)); + } + private PlayerInfo getCreateInfo(String id){ if(playerInfo.containsKey(id)){ return playerInfo.get(id); @@ -256,6 +298,7 @@ public class Administration{ public void save(){ Core.settings.putObject("player-info", playerInfo); Core.settings.putObject("banned-ips", bannedIPs); + Core.settings.putObject("whitelisted", whitelist); Core.settings.save(); } @@ -263,6 +306,7 @@ public class Administration{ private void load(){ playerInfo = Core.settings.getObject("player-info", ObjectMap.class, ObjectMap::new); bannedIPs = Core.settings.getObject("banned-ips", Array.class, Array::new); + whitelist = Core.settings.getObject("whitelisted", Array.class, Array::new); } @Serialize diff --git a/core/src/io/anuke/mindustry/net/ArcNetImpl.java b/core/src/io/anuke/mindustry/net/ArcNetImpl.java new file mode 100644 index 0000000000..1c924b60c6 --- /dev/null +++ b/core/src/io/anuke/mindustry/net/ArcNetImpl.java @@ -0,0 +1,425 @@ +package io.anuke.mindustry.net; + +import io.anuke.arc.*; +import io.anuke.arc.collection.*; +import io.anuke.arc.function.*; +import io.anuke.arc.net.*; +import io.anuke.arc.net.FrameworkMessage.*; +import io.anuke.arc.util.*; +import io.anuke.arc.util.async.*; +import io.anuke.arc.util.pooling.*; +import io.anuke.mindustry.net.Net.*; +import io.anuke.mindustry.net.Packets.*; + +import java.io.*; +import java.net.*; +import java.nio.*; +import java.nio.channels.*; +import java.util.concurrent.*; + +import static io.anuke.mindustry.Vars.*; + +public class ArcNetImpl implements NetProvider{ + final Client client; + final Supplier packetSupplier = () -> new DatagramPacket(new byte[256], 256); + + final Server server; + final CopyOnWriteArrayList connections = new CopyOnWriteArrayList<>(); + Thread serverThread; + + public ArcNetImpl(){ + client = new Client(8192, 4096, new PacketSerializer()); + client.setDiscoveryPacket(packetSupplier); + client.addListener(new NetListener(){ + @Override + public void connected(Connection connection){ + Connect c = new Connect(); + c.addressTCP = connection.getRemoteAddressTCP().getAddress().getHostAddress(); + if(connection.getRemoteAddressTCP() != null) c.addressTCP = connection.getRemoteAddressTCP().toString(); + + Core.app.post(() -> net.handleClientReceived(c)); + } + + @Override + public void disconnected(Connection connection, DcReason reason){ + if(connection.getLastProtocolError() != null){ + netClient.setQuiet(); + } + + Disconnect c = new Disconnect(); + c.reason = reason.toString(); + Core.app.post(() -> net.handleClientReceived(c)); + } + + @Override + public void received(Connection connection, Object object){ + if(object instanceof FrameworkMessage) return; + + Core.app.post(() -> { + try{ + net.handleClientReceived(object); + }catch(Exception e){ + handleException(e); + } + }); + + } + }); + + server = new Server(4096 * 2, 4096, new PacketSerializer()); + server.setMulticast(multicastGroup, multicastPort); + server.setDiscoveryHandler((address, handler) -> { + ByteBuffer buffer = NetworkIO.writeServerData(); + buffer.position(0); + handler.respond(buffer); + }); + + server.addListener(new NetListener(){ + + @Override + public void connected(Connection connection){ + String ip = connection.getRemoteAddressTCP().getAddress().getHostAddress(); + + ArcConnection kn = new ArcConnection(ip, connection); + + Connect c = new Connect(); + c.addressTCP = ip; + + Log.debug("&bRecieved connection: {0}", c.addressTCP); + + connections.add(kn); + Core.app.post(() -> net.handleServerReceived(kn, c)); + } + + @Override + public void disconnected(Connection connection, DcReason reason){ + ArcConnection k = getByArcID(connection.getID()); + if(k == null) return; + + Disconnect c = new Disconnect(); + c.reason = reason.toString(); + + Core.app.post(() -> { + net.handleServerReceived(k, c); + connections.remove(k); + }); + } + + @Override + public void received(Connection connection, Object object){ + ArcConnection k = getByArcID(connection.getID()); + if(object instanceof FrameworkMessage || k == null) return; + + Core.app.post(() -> { + try{ + net.handleServerReceived(k, object); + }catch(RuntimeException e){ + if(e.getCause() instanceof ValidateException){ + ValidateException v = (ValidateException)e.getCause(); + Log.err("Validation failed: {0} ({1})", v.player.name, v.getMessage()); + }else{ + e.printStackTrace(); + } + }catch(Exception e){ + e.printStackTrace(); + } + }); + } + }); + } + + private static boolean isLocal(InetAddress addr){ + if(addr.isAnyLocalAddress() || addr.isLoopbackAddress()) return true; + + try{ + return NetworkInterface.getByInetAddress(addr) != null; + }catch(Exception e){ + return false; + } + } + + @Override + public void connectClient(String ip, int port, Runnable success){ + Threads.daemon(() -> { + try{ + //just in case + client.stop(); + + Threads.daemon("Net Client", () -> { + try{ + client.run(); + }catch(Exception e){ + if(!(e instanceof ClosedSelectorException)) handleException(e); + } + }); + + client.connect(5000, ip, port, port); + success.run(); + }catch(Exception e){ + handleException(e); + } + }); + } + + @Override + public void disconnectClient(){ + client.close(); + } + + @Override + public void sendClient(Object object, SendMode mode){ + try{ + if(mode == SendMode.tcp){ + client.sendTCP(object); + }else{ + client.sendUDP(object); + } + //sending things can cause an under/overflow, catch it and disconnect instead of crashing + }catch(BufferOverflowException | BufferUnderflowException e){ + net.showError(e); + } + + Pools.free(object); + } + + @Override + public void pingHost(String address, int port, Consumer valid, Consumer invalid){ + Threads.daemon(() -> { + try{ + DatagramSocket socket = new DatagramSocket(); + socket.send(new DatagramPacket(new byte[]{-2, 1}, 2, InetAddress.getByName(address), port)); + socket.setSoTimeout(2000); + + DatagramPacket packet = packetSupplier.get(); + socket.receive(packet); + + ByteBuffer buffer = ByteBuffer.wrap(packet.getData()); + Host host = NetworkIO.readServerData(packet.getAddress().getHostAddress(), buffer); + + Core.app.post(() -> valid.accept(host)); + }catch(Exception e){ + Core.app.post(() -> invalid.accept(e)); + } + }); + } + + @Override + public void discoverServers(Consumer callback, Runnable done){ + Array foundAddresses = new Array<>(); + client.discoverHosts(port, multicastGroup, multicastPort, 3000, packet -> { + Core.app.post(() -> { + try{ + if(foundAddresses.contains(address -> address.equals(packet.getAddress()) || (isLocal(address) && isLocal(packet.getAddress())))){ + return; + } + ByteBuffer buffer = ByteBuffer.wrap(packet.getData()); + Host host = NetworkIO.readServerData(packet.getAddress().getHostAddress(), buffer); + callback.accept(host); + foundAddresses.add(packet.getAddress()); + }catch(Exception e){ + //don't crash when there's an error pinging a a server or parsing data + e.printStackTrace(); + } + }); + }, () -> Core.app.post(done)); + } + + @Override + public void dispose(){ + disconnectClient(); + closeServer(); + try{ + client.dispose(); + }catch(IOException ignored){ + } + } + + @Override + public Iterable getConnections(){ + return connections; + } + + @Override + public void hostServer(int port) throws IOException{ + connections.clear(); + server.bind(port, port); + + serverThread = new Thread(() -> { + try{ + server.run(); + }catch(Throwable e){ + if(!(e instanceof ClosedSelectorException)) Threads.throwAppException(e); + } + }, "Net Server"); + serverThread.setDaemon(true); + serverThread.start(); + } + + @Override + public void closeServer(){ + connections.clear(); + Threads.daemon(server::stop); + } + + ArcConnection getByArcID(int id){ + for(int i = 0; i < connections.size(); i++){ + ArcConnection con = connections.get(i); + if(con.connection != null && con.connection.getID() == id){ + return con; + } + } + + return null; + } + + private void handleException(Exception e){ + if(e instanceof ArcNetException){ + Core.app.post(() -> net.showError(new IOException("mismatch"))); + }else if(e instanceof ClosedChannelException){ + Core.app.post(() -> net.showError(new IOException("alreadyconnected"))); + }else{ + Core.app.post(() -> net.showError(e)); + } + } + + class ArcConnection extends NetConnection{ + public final Connection connection; + + public ArcConnection(String address, Connection connection){ + super(address); + this.connection = connection; + } + + @Override + public boolean isConnected(){ + return connection.isConnected(); + } + + @Override + public void sendStream(Streamable stream){ + connection.addListener(new InputStreamSender(stream.stream, 512){ + int id; + + @Override + protected void start(){ + //send an object so the receiving side knows how to handle the following chunks + StreamBegin begin = new StreamBegin(); + begin.total = stream.stream.available(); + begin.type = Registrator.getID(stream.getClass()); + connection.sendTCP(begin); + id = begin.id; + } + + @Override + protected Object next(byte[] bytes){ + StreamChunk chunk = new StreamChunk(); + chunk.id = id; + chunk.data = bytes; + return chunk; //wrap the byte[] with an object so the receiving side knows how to handle it. + } + }); + } + + @Override + public void send(Object object, SendMode mode){ + try{ + if(mode == SendMode.tcp){ + connection.sendTCP(object); + }else{ + connection.sendUDP(object); + } + }catch(Exception e){ + Log.err(e); + Log.info("Error sending packet. Disconnecting invalid client!"); + connection.close(DcReason.error); + + ArcConnection k = getByArcID(connection.getID()); + if(k != null) connections.remove(k); + } + } + + @Override + public void close(){ + if(connection.isConnected()) connection.close(DcReason.closed); + } + } + + @SuppressWarnings("unchecked") + public static class PacketSerializer implements NetSerializer{ + + @Override + public void write(ByteBuffer byteBuffer, Object o){ + if(o instanceof FrameworkMessage){ + byteBuffer.put((byte)-2); //code for framework message + writeFramework(byteBuffer, (FrameworkMessage)o); + }else{ + if(!(o instanceof Packet)) + throw new RuntimeException("All sent objects must implement be Packets! Class: " + o.getClass()); + byte id = Registrator.getID(o.getClass()); + if(id == -1) + throw new RuntimeException("Unregistered class: " + o.getClass()); + byteBuffer.put(id); + ((Packet)o).write(byteBuffer); + } + } + + @Override + public Object read(ByteBuffer byteBuffer){ + byte id = byteBuffer.get(); + if(id == -2){ + return readFramework(byteBuffer); + }else{ + Packet packet = Pools.obtain((Class)Registrator.getByID(id).type, (Supplier)Registrator.getByID(id).constructor); + packet.read(byteBuffer); + return packet; + } + } + + public void writeFramework(ByteBuffer buffer, FrameworkMessage message){ + if(message instanceof Ping){ + Ping p = (Ping)message; + buffer.put((byte)0); + buffer.putInt(p.id); + buffer.put(p.isReply ? 1 : (byte)0); + }else if(message instanceof DiscoverHost){ + buffer.put((byte)1); + }else if(message instanceof KeepAlive){ + buffer.put((byte)2); + }else if(message instanceof RegisterUDP){ + RegisterUDP p = (RegisterUDP)message; + buffer.put((byte)3); + buffer.putInt(p.connectionID); + }else if(message instanceof RegisterTCP){ + RegisterTCP p = (RegisterTCP)message; + buffer.put((byte)4); + buffer.putInt(p.connectionID); + } + } + + public FrameworkMessage readFramework(ByteBuffer buffer){ + byte id = buffer.get(); + + if(id == 0){ + Ping p = new Ping(); + p.id = buffer.getInt(); + p.isReply = buffer.get() == 1; + return p; + }else if(id == 1){ + return new DiscoverHost(); + }else if(id == 2){ + return new KeepAlive(); + }else if(id == 3){ + RegisterUDP p = new RegisterUDP(); + p.connectionID = buffer.getInt(); + return p; + }else if(id == 4){ + RegisterTCP p = new RegisterTCP(); + p.connectionID = buffer.getInt(); + return p; + }else{ + throw new RuntimeException("Unknown framework message!"); + } + } + } + +} \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/net/CrashSender.java b/core/src/io/anuke/mindustry/net/CrashSender.java index b8a5b44854..6970e9521b 100644 --- a/core/src/io/anuke/mindustry/net/CrashSender.java +++ b/core/src/io/anuke/mindustry/net/CrashSender.java @@ -17,6 +17,7 @@ import java.nio.file.Files; import java.nio.file.*; import java.text.*; import java.util.*; +import static io.anuke.mindustry.Vars.*; public class CrashSender{ @@ -78,9 +79,9 @@ public class CrashSender{ //attempt to close connections, if applicable try{ - netActive = Net.active(); - netServer = Net.server(); - Net.dispose(); + netActive = net.active(); + netServer = net.server(); + net.dispose(); }catch(Throwable ignored){ } diff --git a/core/src/io/anuke/mindustry/net/Host.java b/core/src/io/anuke/mindustry/net/Host.java index 77a281d8ec..44b6c6a665 100644 --- a/core/src/io/anuke/mindustry/net/Host.java +++ b/core/src/io/anuke/mindustry/net/Host.java @@ -1,15 +1,18 @@ package io.anuke.mindustry.net; +import io.anuke.mindustry.game.*; + public class Host{ public final String name; public final String address; public final String mapname; public final int wave; - public final int players; + public final int players, playerLimit; public final int version; public final String versionType; + public final Gamemode mode; - public Host(String name, String address, String mapname, int wave, int players, int version, String versionType){ + public Host(String name, String address, String mapname, int wave, int players, int version, String versionType, Gamemode mode, int playerLimit){ this.name = name; this.address = address; this.players = players; @@ -17,5 +20,7 @@ public class Host{ this.wave = wave; this.version = version; this.versionType = versionType; + this.playerLimit = playerLimit; + this.mode = mode; } } diff --git a/core/src/io/anuke/mindustry/net/Net.java b/core/src/io/anuke/mindustry/net/Net.java index 2398526bc1..66482ab729 100644 --- a/core/src/io/anuke/mindustry/net/Net.java +++ b/core/src/io/anuke/mindustry/net/Net.java @@ -1,5 +1,6 @@ package io.anuke.mindustry.net; +import io.anuke.annotations.Annotations.*; import io.anuke.arc.*; import io.anuke.arc.collection.*; import io.anuke.arc.function.*; @@ -17,20 +18,26 @@ import static io.anuke.mindustry.Vars.*; @SuppressWarnings("unchecked") public class Net{ - private static boolean server; - private static boolean active; - private static boolean clientLoaded; - private static Array packetQueue = new Array<>(); - private static ObjectMap, Consumer> clientListeners = new ObjectMap<>(); - private static ObjectMap, BiConsumer> serverListeners = new ObjectMap<>(); - private static ClientProvider clientProvider; - private static ServerProvider serverProvider; - private static IntMap streams = new IntMap<>(); - private static final LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor(); - private static final LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor(); + private boolean server; + private boolean active; + private boolean clientLoaded; + private @Nullable StreamBuilder currentStream; + + private final Array packetQueue = new Array<>(); + private final ObjectMap, Consumer> clientListeners = new ObjectMap<>(); + private final ObjectMap, BiConsumer> serverListeners = new ObjectMap<>(); + private final IntMap streams = new IntMap<>(); + + private final NetProvider provider; + private final LZ4FastDecompressor decompressor = LZ4Factory.fastestInstance().fastDecompressor(); + private final LZ4Compressor compressor = LZ4Factory.fastestInstance().fastCompressor(); + + public Net(NetProvider provider){ + this.provider = provider; + } /** Display a network error. Call on the graphics thread. */ - public static void showError(Throwable e){ + public void showError(Throwable e){ if(!headless){ @@ -56,18 +63,18 @@ public class Net{ }else if(error.equals("alreadyconnected") || error.contains("connection is closed")){ error = Core.bundle.get("error.alreadyconnected"); }else if(!error.isEmpty()){ - error = Core.bundle.get("error.any") + "\n" + Strings.parseException(e, true); + error = Core.bundle.get("error.any"); isError = true; } if(isError){ - ui.showError(Core.bundle.format("connectfail", error)); + ui.showException("$error.any", e); }else{ ui.showText("", Core.bundle.format("connectfail", error)); } ui.loadfrag.hide(); - if(Net.client()){ + if(client()){ netClient.disconnectQuietly(); } } @@ -78,7 +85,7 @@ public class Net{ /** * Sets the client loaded status, or whether it will recieve normal packets from the server. */ - public static void setClientLoaded(boolean loaded){ + public void setClientLoaded(boolean loaded){ clientLoaded = loaded; if(loaded){ @@ -91,13 +98,18 @@ public class Net{ packetQueue.clear(); } + public void setClientConnected(){ + active = true; + server = false; + } + /** * Connect to an address. */ - public static void connect(String ip, int port, Runnable success){ + public void connect(String ip, int port, Runnable success){ try{ if(!active){ - clientProvider.connect(ip, port, success); + provider.connectClient(ip, port, success); active = true; server = false; }else{ @@ -111,8 +123,8 @@ public class Net{ /** * Host a server at an address. */ - public static void host(int port) throws IOException{ - serverProvider.host(port); + public void host(int port) throws IOException{ + provider.hostServer(port); active = true; server = true; @@ -122,32 +134,32 @@ public class Net{ /** * Closes the server. */ - public static void closeServer(){ + public void closeServer(){ for(NetConnection con : getConnections()){ - Call.onKick(con.id, KickReason.serverClose); + Call.onKick(con, KickReason.serverClose); } - serverProvider.close(); + provider.closeServer(); server = false; active = false; } - public static void reset(){ + public void reset(){ closeServer(); netClient.disconnectNoReset(); } - public static void disconnect(){ - clientProvider.disconnect(); + public void disconnect(){ + provider.disconnectClient(); server = false; active = false; } - public static byte[] compressSnapshot(byte[] input){ + public byte[] compressSnapshot(byte[] input){ return compressor.compress(input); } - public static byte[] decompressSnapshot(byte[] input, int size){ + public byte[] decompressSnapshot(byte[] input, int size){ return decompressor.decompress(input, size); } @@ -155,92 +167,64 @@ public class Net{ * Starts discovering servers on a different thread. * Callback is run on the main libGDX thread. */ - public static void discoverServers(Consumer cons, Runnable done){ - clientProvider.discover(cons, done); + public void discoverServers(Consumer cons, Runnable done){ + provider.discoverServers(cons, done); } /** * Returns a list of all connections IDs. */ - public static Iterable getConnections(){ - return (Iterable)serverProvider.getConnections(); + public Iterable getConnections(){ + return (Iterable)provider.getConnections(); } - /** - * Returns a connection by ID - */ - public static NetConnection getConnection(int id){ - return serverProvider.getByID(id); - } - - /** - * Send an object to all connected clients, or to the server if this is a client. - */ - public static void send(Object object, SendMode mode){ + /** Send an object to all connected clients, or to the server if this is a client.*/ + public void send(Object object, SendMode mode){ if(server){ - if(serverProvider != null) serverProvider.send(object, mode); + for(NetConnection con : provider.getConnections()){ + con.send(object, mode); + } }else{ - if(clientProvider != null) clientProvider.send(object, mode); + provider.sendClient(object, mode); } } - /** - * Send an object to a certain client. Server-side only - */ - public static void sendTo(int id, Object object, SendMode mode){ - serverProvider.sendTo(id, object, mode); + /** Send an object to everyone EXCEPT a certain client. Server-side only.*/ + public void sendExcept(NetConnection except, Object object, SendMode mode){ + for(NetConnection con : getConnections()){ + if(con != except){ + con.send(object, mode); + } + } } - /** - * Send an object to everyone EXCEPT certain client. Server-side only - */ - public static void sendExcept(int id, Object object, SendMode mode){ - serverProvider.sendExcept(id, object, mode); - } - - /** - * Send a stream to a specific client. Server-side only. - */ - public static void sendStream(int id, Streamable stream){ - serverProvider.sendStream(id, stream); - } - - /** - * Sets the net clientProvider, e.g. what handles sending, recieving and connecting to a server. - */ - public static void setClientProvider(ClientProvider provider){ - Net.clientProvider = provider; - } - - /** - * Sets the net serverProvider, e.g. what handles hosting a server. - */ - public static void setServerProvider(ServerProvider provider){ - Net.serverProvider = provider; + public @Nullable StreamBuilder getCurrentStream(){ + return currentStream; } /** * Registers a client listener for when an object is recieved. */ - public static void handleClient(Class type, Consumer listener){ + public void handleClient(Class type, Consumer listener){ clientListeners.put(type, listener); } /** * Registers a server listener for when an object is recieved. */ - public static void handleServer(Class type, BiConsumer listener){ - serverListeners.put(type, (BiConsumer)listener); + public void handleServer(Class type, BiConsumer listener){ + serverListeners.put(type, (BiConsumer)listener); } /** * Call to handle a packet being recieved for the client. */ - public static void handleClientReceived(Object object){ + public void handleClientReceived(Object object){ if(object instanceof StreamBegin){ StreamBegin b = (StreamBegin)object; - streams.put(b.id, new StreamBuilder(b)); + streams.put(b.id, currentStream = new StreamBuilder(b)); + }else if(object instanceof StreamChunk){ StreamChunk c = (StreamChunk)object; StreamBuilder builder = streams.get(c.id); @@ -251,6 +235,7 @@ public class Net{ if(builder.isDone()){ streams.remove(builder.id); handleClientReceived(builder.build()); + currentStream = null; } }else if(clientListeners.get(object.getClass()) != null){ @@ -271,7 +256,7 @@ public class Net{ /** * Call to handle a packet being recieved for the server. */ - public static void handleServerReceived(int connection, Object object){ + public void handleServerReceived(NetConnection connection, Object object){ if(serverListeners.get(object.getClass()) != null){ if(serverListeners.get(object.getClass()) != null) @@ -285,50 +270,33 @@ public class Net{ /** * Pings a host in an new thread. If an error occured, failed() should be called with the exception. */ - public static void pingHost(String address, int port, Consumer valid, Consumer failed){ - clientProvider.pingHost(address, port, valid, failed); - } - - /** - * Update client ping. - */ - public static void updatePing(){ - clientProvider.updatePing(); - } - - /** - * Get the client ping. Only valid after updatePing(). - */ - public static int getPing(){ - return server() ? 0 : clientProvider.getPing(); + public void pingHost(String address, int port, Consumer valid, Consumer failed){ + provider.pingHost(address, port, valid, failed); } /** * Whether the net is active, e.g. whether this is a multiplayer game. */ - public static boolean active(){ + public boolean active(){ return active; } /** * Whether this is a server or not. */ - public static boolean server(){ + public boolean server(){ return server && active; } /** * Whether this is a client or not. */ - public static boolean client(){ + public boolean client(){ return !server && active; } - public static void dispose(){ - if(clientProvider != null) clientProvider.dispose(); - if(serverProvider != null) serverProvider.close(); - clientProvider = null; - serverProvider = null; + public void dispose(){ + provider.dispose(); server = false; active = false; } @@ -337,98 +305,40 @@ public class Net{ tcp, udp } - /** Client implementation. */ - public interface ClientProvider{ + /** Networking implementation. */ + public interface NetProvider{ /** Connect to a server. */ - void connect(String ip, int port, Runnable success) throws IOException; + void connectClient(String ip, int port, Runnable success) throws IOException; /** Send an object to the server. */ - void send(Object object, SendMode mode); - - /** Update the ping. Should be done every second or so. */ - void updatePing(); - - /** Get ping in milliseconds. Will only be valid after a call to updatePing. */ - int getPing(); + void sendClient(Object object, SendMode mode); /** Disconnect from the server. */ - void disconnect(); + void disconnectClient(); /** * Discover servers. This should run the callback regardless of whether any servers are found. Should not block. - * Callback should be run on libGDX main thread. + * Callback should be run on the main thread. * @param done is the callback that should run after discovery. */ - void discover(Consumer callback, Runnable done); + void discoverServers(Consumer callback, Runnable done); /** Ping a host. If an error occured, failed() should be called with the exception. */ void pingHost(String address, int port, Consumer valid, Consumer failed); - /** Close all connections. */ - void dispose(); - } - - /** Server implementation. */ - public interface ServerProvider{ /** Host a server at specified port. */ - void host(int port) throws IOException; - - /** Sends a large stream of data to a specific client. */ - default void sendStream(int id, Streamable stream){ - NetConnection connection = getByID(id); - if(connection == null) return; - try{ - int cid; - StreamBegin begin = new StreamBegin(); - begin.total = stream.stream.available(); - begin.type = Registrator.getID(stream.getClass()); - connection.send(begin, SendMode.tcp); - cid = begin.id; - - while(stream.stream.available() > 0){ - byte[] bytes = new byte[Math.min(512, stream.stream.available())]; - stream.stream.read(bytes); - - StreamChunk chunk = new StreamChunk(); - chunk.id = cid; - chunk.data = bytes; - connection.send(chunk, SendMode.tcp); - } - }catch(IOException e){ - throw new RuntimeException(e); - } - } - - default void send(Object object, SendMode mode){ - for(NetConnection con : getConnections()){ - con.send(object, mode); - } - } - - default void sendTo(int id, Object object, SendMode mode){ - NetConnection conn = getByID(id); - if(conn == null){ - Log.err("Failed to find connection with ID {0}.", id); - return; - } - conn.send(object, mode); - } - - default void sendExcept(int id, Object object, SendMode mode){ - for(NetConnection con : getConnections()){ - if(con.id != id){ - con.send(object, mode); - } - } - } - - /** Close the server connection. */ - void close(); + void hostServer(int port) throws IOException; /** Return all connected users. */ Iterable getConnections(); - /** Returns a connection by ID. */ - NetConnection getByID(int id); + /** Close the server connection. */ + void closeServer(); + + /** Close all connections. */ + default void dispose(){ + disconnectClient(); + closeServer(); + } } } diff --git a/core/src/io/anuke/mindustry/net/NetConnection.java b/core/src/io/anuke/mindustry/net/NetConnection.java index ba2a004a03..d2e1c3f86c 100644 --- a/core/src/io/anuke/mindustry/net/NetConnection.java +++ b/core/src/io/anuke/mindustry/net/NetConnection.java @@ -1,35 +1,77 @@ package io.anuke.mindustry.net; -import io.anuke.mindustry.net.Net.SendMode; +import io.anuke.annotations.Annotations.*; +import io.anuke.arc.util.*; +import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.net.Administration.*; +import io.anuke.mindustry.net.Net.*; +import io.anuke.mindustry.net.Packets.*; + +import java.io.*; + +import static io.anuke.mindustry.Vars.netServer; public abstract class NetConnection{ - private static int lastID; - - public final int id; public final String address; - - public boolean modclient; - public boolean mobile; + public boolean mobile, modclient; + public @Nullable Player player; /** ID of last recieved client snapshot. */ public int lastRecievedClientSnapshot = -1; /** Timestamp of last recieved snapshot. */ public long lastRecievedClientTime; - public boolean hasConnected = false; - public boolean hasBegunConnecting = false; + public boolean hasConnected, hasBegunConnecting; public float viewWidth, viewHeight, viewX, viewY; - /** Assigns this connection a unique ID. No two connections will ever have the same ID.*/ public NetConnection(String address){ - this.id = lastID++; this.address = address; } + public void kick(KickReason reason){ + Log.info("Kicking connection {0}; Reason: {1}", address, reason.name()); + + if(player != null && (reason == KickReason.kick || reason == KickReason.banned || reason == KickReason.vote) && player.uuid != null){ + PlayerInfo info = netServer.admins.getInfo(player.uuid); + info.timesKicked++; + info.lastKicked = Math.max(Time.millis(), info.lastKicked); + } + + Call.onKick(this, reason); + + Time.runTask(2f, this::close); + + netServer.admins.save(); + } + public boolean isConnected(){ return true; } + public void sendStream(Streamable stream){ + try{ + int cid; + StreamBegin begin = new StreamBegin(); + begin.total = stream.stream.available(); + begin.type = Registrator.getID(stream.getClass()); + send(begin, SendMode.tcp); + cid = begin.id; + + while(stream.stream.available() > 0){ + byte[] bytes = new byte[Math.min(512, stream.stream.available())]; + stream.stream.read(bytes); + + StreamChunk chunk = new StreamChunk(); + chunk.id = cid; + chunk.data = bytes; + send(chunk, SendMode.tcp); + } + }catch(IOException e){ + throw new RuntimeException(e); + } + } + public abstract void send(Object object, SendMode mode); public abstract void close(); diff --git a/core/src/io/anuke/mindustry/net/NetworkIO.java b/core/src/io/anuke/mindustry/net/NetworkIO.java index 663cfcdf0d..9bc881f08c 100644 --- a/core/src/io/anuke/mindustry/net/NetworkIO.java +++ b/core/src/io/anuke/mindustry/net/NetworkIO.java @@ -1,17 +1,15 @@ package io.anuke.mindustry.net; -import io.anuke.arc.Core; -import io.anuke.arc.util.Time; -import io.anuke.mindustry.entities.Entities; -import io.anuke.mindustry.entities.type.Player; +import io.anuke.arc.*; +import io.anuke.arc.util.*; +import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.game.*; -import io.anuke.mindustry.io.JsonIO; -import io.anuke.mindustry.io.SaveIO; +import io.anuke.mindustry.io.*; import io.anuke.mindustry.maps.Map; import java.io.*; -import java.nio.ByteBuffer; -import java.util.Arrays; +import java.nio.*; +import java.util.*; import static io.anuke.mindustry.Vars.*; @@ -71,8 +69,9 @@ public class NetworkIO{ buffer.putInt(state.wave); buffer.putInt(Version.build); writeString(buffer, Version.type); - //TODO additional information: - // - gamemode ID/name (just pick the closest one?) + + buffer.put((byte)Gamemode.bestFit(state.rules).ordinal()); + buffer.putInt(netServer.admins.getPlayerLimit()); return buffer; } @@ -83,13 +82,15 @@ public class NetworkIO{ int wave = buffer.getInt(); int version = buffer.getInt(); String vertype = readString(buffer); + Gamemode gamemode = Gamemode.all[buffer.get()]; + int limit = buffer.getInt(); - return new Host(host, hostAddress, map, wave, players, version, vertype); + return new Host(host, hostAddress, map, wave, players, version, vertype, gamemode, limit); } private static void writeString(ByteBuffer buffer, String string, int maxlen){ byte[] bytes = string.getBytes(charset); - //truncating this way may lead to wierd encoding errors at the ends of strings... + //todo truncating this way may lead to wierd encoding errors at the ends of strings... if(bytes.length > maxlen){ bytes = Arrays.copyOfRange(bytes, 0, maxlen); } diff --git a/core/src/io/anuke/mindustry/net/Packets.java b/core/src/io/anuke/mindustry/net/Packets.java index 12d9d75067..117c9348c4 100644 --- a/core/src/io/anuke/mindustry/net/Packets.java +++ b/core/src/io/anuke/mindustry/net/Packets.java @@ -14,7 +14,7 @@ public class Packets{ public enum KickReason{ kick, clientOutdated, serverOutdated, banned, gameover(true), recentKick, - nameInUse, idInUse, nameEmpty, customClient, serverClose, vote, typeMismatch; + nameInUse, idInUse, nameEmpty, customClient, serverClose, vote, typeMismatch, whitelist, playerLimit; public final boolean quiet; @@ -41,7 +41,6 @@ public class Packets{ } public static class Connect implements Packet{ - public int id; public String addressTCP; @Override @@ -51,7 +50,7 @@ public class Packets{ } public static class Disconnect implements Packet{ - public int id; + public String reason; @Override public boolean isImportant(){ diff --git a/core/src/io/anuke/mindustry/net/Streamable.java b/core/src/io/anuke/mindustry/net/Streamable.java index 9f2c3c0fbc..01cc829412 100644 --- a/core/src/io/anuke/mindustry/net/Streamable.java +++ b/core/src/io/anuke/mindustry/net/Streamable.java @@ -16,13 +16,16 @@ public class Streamable implements Packet{ public final int id; public final byte type; public final int total; - public final ByteArrayOutputStream stream; + public final ByteArrayOutputStream stream = new ByteArrayOutputStream(); public StreamBuilder(StreamBegin begin){ id = begin.id; type = begin.type; total = begin.total; - stream = new ByteArrayOutputStream(); + } + + public float progress(){ + return (float)stream.size() / total; } public void add(byte[] bytes){ diff --git a/core/src/io/anuke/mindustry/plugin/Plugins.java b/core/src/io/anuke/mindustry/plugin/Plugins.java index e371c78b66..bd97013f6b 100644 --- a/core/src/io/anuke/mindustry/plugin/Plugins.java +++ b/core/src/io/anuke/mindustry/plugin/Plugins.java @@ -1,12 +1,11 @@ package io.anuke.mindustry.plugin; -import io.anuke.arc.collection.Array; +import io.anuke.arc.collection.*; import io.anuke.arc.files.*; import io.anuke.arc.function.*; import io.anuke.arc.util.*; import io.anuke.mindustry.io.*; -import java.lang.reflect.*; import java.net.*; import static io.anuke.mindustry.Vars.pluginDirectory; @@ -50,12 +49,8 @@ public class Plugins{ PluginMeta meta = JsonIO.read(PluginMeta.class, metaf.readString()); - URLClassLoader classLoader = (URLClassLoader)ClassLoader.getSystemClassLoader(); - Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); - method.setAccessible(true); - method.invoke(classLoader, jar.file().toURI().toURL()); - - Class main = Class.forName(meta.main); + URLClassLoader classLoader = new URLClassLoader(new URL[]{jar.file().toURI().toURL()}, ClassLoader.getSystemClassLoader()); + Class main = classLoader.loadClass(meta.main); return new LoadedPlugin(jar, zip, (Plugin)main.newInstance(), meta); } diff --git a/core/src/io/anuke/mindustry/type/Loadout.java b/core/src/io/anuke/mindustry/type/Loadout.java index 05339c3d1b..136018acc2 100644 --- a/core/src/io/anuke/mindustry/type/Loadout.java +++ b/core/src/io/anuke/mindustry/type/Loadout.java @@ -8,6 +8,7 @@ import io.anuke.mindustry.world.blocks.storage.*; import static io.anuke.mindustry.Vars.*; +//TODO this class is a disappointment public class Loadout extends Content{ private final Array outArray = new Array<>(); private final IntMap entries = new IntMap(){{ diff --git a/core/src/io/anuke/mindustry/type/StatusEffect.java b/core/src/io/anuke/mindustry/type/StatusEffect.java index 785bcab946..19b662d76c 100644 --- a/core/src/io/anuke/mindustry/type/StatusEffect.java +++ b/core/src/io/anuke/mindustry/type/StatusEffect.java @@ -17,7 +17,7 @@ public class StatusEffect extends Content{ public float damageMultiplier = 1f; //damage dealt public float armorMultiplier = 1f; //armor points public float speedMultiplier = 1f; //speed - public Color color = Color.WHITE.cpy(); //tint color + public Color color = Color.white.cpy(); //tint color /** Transition handler map. */ private ObjectMap transitions = new ObjectMap<>(); diff --git a/core/src/io/anuke/mindustry/type/Weapon.java b/core/src/io/anuke/mindustry/type/Weapon.java index 4e77b2bc4a..980859c01d 100644 --- a/core/src/io/anuke/mindustry/type/Weapon.java +++ b/core/src/io/anuke/mindustry/type/Weapon.java @@ -13,9 +13,10 @@ import io.anuke.mindustry.entities.Effects.*; import io.anuke.mindustry.entities.bullet.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.entities.type.Bullet; import io.anuke.mindustry.gen.*; -import io.anuke.mindustry.gen.Sounds; -import io.anuke.mindustry.net.Net; + +import static io.anuke.mindustry.Vars.net; public class Weapon{ public final String name; @@ -73,7 +74,7 @@ public class Weapon{ if(player == null) return; //clients do not see their own shoot events: they are simulated completely clientside to prevent laggy visuals //messing with the firerate or any other stats does not affect the server (take that, script kiddies!) - if(Net.client() && player == Vars.player){ + if(net.client() && player == Vars.player){ return; } @@ -154,7 +155,7 @@ public class Weapon{ } public void shoot(ShooterTrait p, float x, float y, float angle, boolean left){ - if(Net.client()){ + if(net.client()){ //call it directly, don't invoke on server shootDirect(p, x, y, angle, left); }else{ diff --git a/core/src/io/anuke/mindustry/type/Zone.java b/core/src/io/anuke/mindustry/type/Zone.java index 34a42d9d17..8bfd5a0ebf 100644 --- a/core/src/io/anuke/mindustry/type/Zone.java +++ b/core/src/io/anuke/mindustry/type/Zone.java @@ -42,7 +42,7 @@ public class Zone extends UnlockableContent{ @Override public void load(){ - preview = Core.atlas.find(name); + preview = Core.atlas.find("zone-" + name); } public Rules getRules(){ diff --git a/core/src/io/anuke/mindustry/ui/Bar.java b/core/src/io/anuke/mindustry/ui/Bar.java index 1fbe5b02f4..3937a950ff 100644 --- a/core/src/io/anuke/mindustry/ui/Bar.java +++ b/core/src/io/anuke/mindustry/ui/Bar.java @@ -1,15 +1,15 @@ package io.anuke.mindustry.ui; -import io.anuke.arc.Core; -import io.anuke.arc.function.FloatProvider; -import io.anuke.arc.function.Supplier; -import io.anuke.arc.graphics.Color; +import io.anuke.arc.*; +import io.anuke.arc.function.*; +import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.g2d.*; -import io.anuke.arc.math.Mathf; -import io.anuke.arc.math.geom.Rectangle; -import io.anuke.arc.scene.Element; -import io.anuke.arc.scene.style.Drawable; -import io.anuke.arc.util.pooling.Pools; +import io.anuke.arc.math.*; +import io.anuke.arc.math.geom.*; +import io.anuke.arc.scene.*; +import io.anuke.arc.scene.style.*; +import io.anuke.arc.util.pooling.*; +import io.anuke.mindustry.gen.*; public class Bar extends Element{ private static Rectangle scissor = new Rectangle(); @@ -37,6 +37,18 @@ public class Bar extends Element{ }); } + public Bar(){ + + } + + public void set(Supplier name, FloatProvider fraction, Color color){ + this.fraction = fraction; + this.lastValue = fraction.get(); + this.blinkColor.set(color); + setColor(color); + update(() -> this.name = name.get()); + } + public Bar blink(Color color){ blinkColor.set(color); return this; @@ -44,6 +56,8 @@ public class Bar extends Element{ @Override public void draw(){ + if(fraction == null) return; + float computed = Mathf.clamp(fraction.get()); if(!Mathf.isEqual(lastValue, computed)){ blink = 1f; @@ -53,11 +67,13 @@ public class Bar extends Element{ blink = Mathf.lerpDelta(blink, 0f, 0.2f); value = Mathf.lerpDelta(value, computed, 0.15f); + Drawable bar = Tex.bar; + Draw.colorl(0.1f); - Draw.drawable("bar", x, y, width, height); + bar.draw(x, y, width, height); Draw.color(color, blinkColor, blink); - Drawable top = Core.scene.skin.getDrawable("bar-top"); + Drawable top = Tex.barTop; float topWidth = width * value; if(topWidth > Core.atlas.find("bar-top").getWidth()){ @@ -71,11 +87,11 @@ public class Bar extends Element{ Draw.color(); - BitmapFont font = Core.scene.skin.getFont("default"); + BitmapFont font = Fonts.outline; GlyphLayout lay = Pools.obtain(GlyphLayout.class, GlyphLayout::new); lay.setText(font, name); - font.setColor(Color.WHITE); + font.setColor(Color.white); font.draw(name, x + width / 2f - lay.width / 2f, y + height / 2f + lay.height / 2f + 1); Pools.free(lay); diff --git a/core/src/io/anuke/mindustry/ui/BorderImage.java b/core/src/io/anuke/mindustry/ui/BorderImage.java index bd396f8e01..cff7b610b1 100644 --- a/core/src/io/anuke/mindustry/ui/BorderImage.java +++ b/core/src/io/anuke/mindustry/ui/BorderImage.java @@ -3,7 +3,7 @@ package io.anuke.mindustry.ui; import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.scene.ui.Image; -import io.anuke.arc.scene.ui.layout.UnitScl; +import io.anuke.arc.scene.ui.layout.Scl; import io.anuke.mindustry.graphics.Pal; public class BorderImage extends Image{ @@ -42,7 +42,7 @@ public class BorderImage extends Image{ Draw.color(borderColor); Draw.alpha(parentAlpha); - Lines.stroke(UnitScl.dp.scl(thickness)); + Lines.stroke(Scl.scl(thickness)); Lines.rect(x + imageX, y + imageY, imageWidth * scaleX, imageHeight * scaleY); Draw.reset(); } diff --git a/core/src/io/anuke/mindustry/ui/ContentDisplay.java b/core/src/io/anuke/mindustry/ui/ContentDisplay.java index 6c293d1686..afab2468c6 100644 --- a/core/src/io/anuke/mindustry/ui/ContentDisplay.java +++ b/core/src/io/anuke/mindustry/ui/ContentDisplay.java @@ -25,7 +25,7 @@ public class ContentDisplay{ table.row(); - table.addImage("whiteui").height(3).color(Color.LIGHT_GRAY).pad(8).padLeft(0).padRight(0).fillX(); + table.addImage().height(3).color(Color.lightGray).pad(8).padLeft(0).padRight(0).fillX(); table.row(); @@ -33,7 +33,7 @@ public class ContentDisplay{ table.add(block.description).padLeft(5).padRight(5).width(400f).wrap().fillX(); table.row(); - table.addImage("whiteui").height(3).color(Color.LIGHT_GRAY).pad(8).padLeft(0).padRight(0).fillX(); + table.addImage().height(3).color(Color.lightGray).pad(8).padLeft(0).padRight(0).fillX(); table.row(); } @@ -73,7 +73,7 @@ public class ContentDisplay{ table.row(); - table.addImage("whiteui").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX(); + table.addImage().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); table.row(); @@ -81,7 +81,7 @@ public class ContentDisplay{ table.add(item.description).padLeft(5).padRight(5).width(400f).wrap().fillX(); table.row(); - table.addImage("whiteui").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX(); + table.addImage().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); table.row(); } @@ -104,7 +104,7 @@ public class ContentDisplay{ table.row(); - table.addImage("whiteui").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX(); + table.addImage().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); table.row(); @@ -112,7 +112,7 @@ public class ContentDisplay{ table.add(liquid.description).padLeft(5).padRight(5).width(400f).wrap().fillX(); table.row(); - table.addImage("whiteui").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX(); + table.addImage().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); table.row(); } @@ -139,7 +139,7 @@ public class ContentDisplay{ table.row(); - table.addImage("whiteui").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX(); + table.addImage().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); table.row(); @@ -147,7 +147,7 @@ public class ContentDisplay{ table.add(mech.description).padLeft(5).padRight(5).width(400f).wrap().fillX(); table.row(); - table.addImage("whiteui").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX(); + table.addImage().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); table.row(); } @@ -186,7 +186,7 @@ public class ContentDisplay{ table.row(); - table.addImage("whiteui").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX(); + table.addImage().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); table.row(); @@ -194,7 +194,7 @@ public class ContentDisplay{ table.add(unit.description).padLeft(5).padRight(5).width(400f).wrap().fillX(); table.row(); - table.addImage("whiteui").height(3).color(Color.LIGHT_GRAY).pad(15).padLeft(0).padRight(0).fillX(); + table.addImage().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); table.row(); } diff --git a/core/src/io/anuke/mindustry/ui/Fonts.java b/core/src/io/anuke/mindustry/ui/Fonts.java new file mode 100644 index 0000000000..cf30e810aa --- /dev/null +++ b/core/src/io/anuke/mindustry/ui/Fonts.java @@ -0,0 +1,9 @@ +package io.anuke.mindustry.ui; + +import io.anuke.arc.graphics.g2d.*; + +public class Fonts{ + public static BitmapFont def; + public static BitmapFont outline; + public static BitmapFont chat; +} diff --git a/core/src/io/anuke/mindustry/ui/IconSize.java b/core/src/io/anuke/mindustry/ui/IconSize.java new file mode 100644 index 0000000000..ba3ac5114c --- /dev/null +++ b/core/src/io/anuke/mindustry/ui/IconSize.java @@ -0,0 +1,14 @@ +package io.anuke.mindustry.ui; + +public enum IconSize{ + def(48), + small(32), + smaller(30), + tiny(16); + + public final int size; + + IconSize(int size){ + this.size = size; + } +} diff --git a/core/src/io/anuke/mindustry/ui/ItemDisplay.java b/core/src/io/anuke/mindustry/ui/ItemDisplay.java index 728d99a710..1efcd10919 100644 --- a/core/src/io/anuke/mindustry/ui/ItemDisplay.java +++ b/core/src/io/anuke/mindustry/ui/ItemDisplay.java @@ -13,11 +13,15 @@ public class ItemDisplay extends Table{ this(item, 0); } - public ItemDisplay(Item item, int amount){ - add(new ItemImage(new ItemStack(item, amount))).size(8 * 4); - add(item.localizedName()).padLeft(4); + public ItemDisplay(Item item, int amount, boolean showName){ + add(new ItemImage(new ItemStack(item, amount))).size(8 * 4).padRight(amount > 99 ? 12 : 0); + if(showName) add(item.localizedName()).padLeft(4 + amount > 99 ? 4 : 0); this.item = item; this.amount = amount; } + + public ItemDisplay(Item item, int amount){ + this(item, amount, true); + } } diff --git a/core/src/io/anuke/mindustry/ui/ItemsDisplay.java b/core/src/io/anuke/mindustry/ui/ItemsDisplay.java index 97208b54ab..81f0732c81 100644 --- a/core/src/io/anuke/mindustry/ui/ItemsDisplay.java +++ b/core/src/io/anuke/mindustry/ui/ItemsDisplay.java @@ -3,6 +3,7 @@ package io.anuke.mindustry.ui; import io.anuke.arc.collection.ObjectIntMap; import io.anuke.arc.graphics.Color; import io.anuke.arc.scene.ui.layout.Table; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Item.Icon; import io.anuke.mindustry.type.ItemType; @@ -26,7 +27,7 @@ public class ItemsDisplay extends Table{ top().left(); margin(0); - table("button", t -> { + table(Tex.button,t -> { t.margin(10).marginLeft(15).marginTop(15f); t.add("$launcheditems").colspan(3).left().padBottom(5); t.row(); @@ -35,7 +36,7 @@ public class ItemsDisplay extends Table{ if(item.type == ItemType.material && data.isUnlocked(item)){ t.label(() -> format.format(items.get(item, 0))).left(); t.addImage(item.icon(Icon.medium)).size(8 * 3).padLeft(4).padRight(4); - t.add(item.localizedName()).color(Color.LIGHT_GRAY).left(); + t.add(item.localizedName()).color(Color.lightGray).left(); t.row(); } } diff --git a/core/src/io/anuke/mindustry/ui/Links.java b/core/src/io/anuke/mindustry/ui/Links.java index a0c0cae0f9..cdb91c8655 100644 --- a/core/src/io/anuke/mindustry/ui/Links.java +++ b/core/src/io/anuke/mindustry/ui/Links.java @@ -16,8 +16,7 @@ public class Links{ new LinkEntry("itch.io", "https://anuke.itch.io/mindustry", Color.valueOf("fa5c5c")), new LinkEntry("google-play", "https://play.google.com/store/apps/details?id=io.anuke.mindustry", Color.valueOf("689f38")), new LinkEntry("github", "https://github.com/Anuken/Mindustry/", Color.valueOf("24292e")), - new LinkEntry("dev-builds", "https://jenkins.hellomouse.net/job/mindustry/", Color.valueOf("fafbfc")) - + new LinkEntry("dev-builds", "https://github.com/Anuken/MindustryBuilds", Color.valueOf("fafbfc")) }; } diff --git a/core/src/io/anuke/mindustry/ui/LiquidDisplay.java b/core/src/io/anuke/mindustry/ui/LiquidDisplay.java index 86f5323102..993cf48863 100644 --- a/core/src/io/anuke/mindustry/ui/LiquidDisplay.java +++ b/core/src/io/anuke/mindustry/ui/LiquidDisplay.java @@ -27,10 +27,10 @@ public class LiquidDisplay extends Table{ t.add(Strings.autoFixed(amount, 1)); add(t); } - }}).size(8 * 4).padRight(3); + }}).size(8 * 4).padRight(3 + (amount != 0 && Strings.autoFixed(amount, 1).length() > 2 ? 8 : 0)); if(perSecond){ - add(StatUnit.perSecond.localized()).padLeft(2).padRight(5).color(Color.LIGHT_GRAY); + add(StatUnit.perSecond.localized()).padLeft(2).padRight(5).color(Color.lightGray); } add(liquid.localizedName()); diff --git a/core/src/io/anuke/mindustry/ui/Minimap.java b/core/src/io/anuke/mindustry/ui/Minimap.java index 4dfc419a70..16acc67a57 100644 --- a/core/src/io/anuke/mindustry/ui/Minimap.java +++ b/core/src/io/anuke/mindustry/ui/Minimap.java @@ -6,24 +6,25 @@ import io.anuke.arc.input.KeyCode; import io.anuke.arc.scene.Element; import io.anuke.arc.scene.event.*; import io.anuke.arc.scene.ui.layout.*; +import io.anuke.mindustry.gen.*; import static io.anuke.mindustry.Vars.*; public class Minimap extends Table{ public Minimap(){ - background("pane"); + background(Tex.pane); float margin = 5f; touchable(Touchable.enabled); add(new Element(){ { - setSize(UnitScl.dp.scl(140f)); + setSize(Scl.scl(140f)); } @Override public void act(float delta){ - setPosition(UnitScl.dp.scl(margin), UnitScl.dp.scl(margin)); + setPosition(Scl.scl(margin), Scl.scl(margin)); super.act(delta); } @@ -52,7 +53,7 @@ public class Minimap extends Table{ addListener(new ClickListener(){ { - tapSquareSize = UnitScl.dp.scl(11f); + tapSquareSize = Scl.scl(11f); } @Override diff --git a/core/src/io/anuke/mindustry/ui/MobileButton.java b/core/src/io/anuke/mindustry/ui/MobileButton.java index 102357e80c..b674830ebd 100644 --- a/core/src/io/anuke/mindustry/ui/MobileButton.java +++ b/core/src/io/anuke/mindustry/ui/MobileButton.java @@ -1,13 +1,13 @@ package io.anuke.mindustry.ui; +import io.anuke.arc.scene.style.*; import io.anuke.arc.scene.ui.ImageButton; import io.anuke.arc.util.Align; public class MobileButton extends ImageButton{ - public MobileButton(String icon, float isize, String text, Runnable listener){ + public MobileButton(Drawable icon, String text, Runnable listener){ super(icon); - resizeImage(isize); clicked(listener); row(); add(text).growX().wrap().center().get().setAlignment(Align.center, Align.center); diff --git a/core/src/io/anuke/mindustry/ui/ReqImage.java b/core/src/io/anuke/mindustry/ui/ReqImage.java index d14c5341d5..ddb66961b3 100644 --- a/core/src/io/anuke/mindustry/ui/ReqImage.java +++ b/core/src/io/anuke/mindustry/ui/ReqImage.java @@ -5,7 +5,7 @@ import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.scene.Element; import io.anuke.arc.scene.ui.Image; import io.anuke.arc.scene.ui.layout.Stack; -import io.anuke.arc.scene.ui.layout.UnitScl; +import io.anuke.arc.scene.ui.layout.Scl; import io.anuke.mindustry.graphics.Pal; public class ReqImage extends Stack{ @@ -21,7 +21,7 @@ public class ReqImage extends Stack{ @Override public void draw(){ - Lines.stroke(UnitScl.dp.scl(2f), Pal.removeBack); + Lines.stroke(Scl.scl(2f), Pal.removeBack); Lines.line(x, y - 2f + height, x + width, y - 2f); Draw.color(Pal.remove); Lines.line(x, y + height, x + width, y); diff --git a/core/src/io/anuke/mindustry/ui/Styles.java b/core/src/io/anuke/mindustry/ui/Styles.java new file mode 100644 index 0000000000..cd9af651ad --- /dev/null +++ b/core/src/io/anuke/mindustry/ui/Styles.java @@ -0,0 +1,324 @@ +package io.anuke.mindustry.ui; + +import io.anuke.annotations.Annotations.*; +import io.anuke.arc.*; +import io.anuke.arc.graphics.*; +import io.anuke.arc.graphics.g2d.*; +import io.anuke.arc.graphics.g2d.TextureAtlas.*; +import io.anuke.arc.scene.style.*; +import io.anuke.arc.scene.ui.Button.*; +import io.anuke.arc.scene.ui.CheckBox.*; +import io.anuke.arc.scene.ui.Dialog.*; +import io.anuke.arc.scene.ui.ImageButton.*; +import io.anuke.arc.scene.ui.KeybindDialog.*; +import io.anuke.arc.scene.ui.Label.*; +import io.anuke.arc.scene.ui.ScrollPane.*; +import io.anuke.arc.scene.ui.Slider.*; +import io.anuke.arc.scene.ui.TextButton.*; +import io.anuke.arc.scene.ui.TextField.*; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.graphics.*; + +import static io.anuke.mindustry.gen.Tex.*; + +@StyleDefaults +public class Styles{ + public static Drawable black, black9, black8, black6, black3, none, flatDown, flatOver; + public static ButtonStyle defaultb, waveb; + public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet; + public static ImageButtonStyle defaulti, nodei, righti, emptyi, emptytogglei, selecti, cleari, clearFulli, clearPartiali, clearPartial2i, clearTogglei, clearTransi, clearToggleTransi, clearTogglePartiali; + public static ScrollPaneStyle defaultPane, horizontalPane; + public static KeybindDialogStyle defaultKeybindDialog; + public static SliderStyle defaultSlider, vSlider; + public static LabelStyle defaultLabel, outlineLabel; + public static TextFieldStyle defaultField, areaField; + public static CheckBoxStyle defaultCheck; + public static DialogStyle defaultDialog, fullDialog; + + public static void load(){ + black = whiteui.tint(0f, 0f, 0f, 1f); + black9 = whiteui.tint(0f, 0f, 0f, 0.9f); + black8 = whiteui.tint(0f, 0f, 0f, 0.8f); + black6 = whiteui.tint(0f, 0f, 0f, 0.6f); + black3 = whiteui.tint(0f, 0f, 0f, 0.3f); + none = whiteui.tint(0f, 0f, 0f, 0f); + flatDown = createFlatDown(); + flatOver = whiteui.tint(Color.valueOf("454545")); + + defaultb = new ButtonStyle(){{ + down = buttonDown; + up = button; + over = buttonOver; + disabled = buttonDisabled; + }}; + + waveb = new ButtonStyle(){{ + up = buttonEdge4; + over = buttonEdgeOver4; + disabled = buttonEdge4; + }}; + + defaultt = new TextButtonStyle(){{ + over = buttonOver; + disabled = buttonDisabled; + font = Fonts.def; + fontColor = Color.white; + disabledFontColor = Color.gray; + down = buttonDown; + up = button; + }}; + squaret = new TextButtonStyle(){{ + font = Fonts.def; + fontColor = Color.white; + disabledFontColor = Color.gray; + over = buttonSquareOver; + disabled = buttonDisabled; + down = buttonSquareDown; + up = buttonSquare; + }}; + nodet = new TextButtonStyle(){{ + disabled = button; + font = Fonts.def; + fontColor = Color.white; + disabledFontColor = Color.gray; + up = buttonOver; + over = buttonDown; + }}; + cleart = new TextButtonStyle(){{ + over = flatOver; + font = Fonts.def; + fontColor = Color.white; + disabledFontColor = Color.gray; + down = flatOver; + up = black; + }}; + discordt = new TextButtonStyle(){{ + font = Fonts.def; + fontColor = Color.white; + up = discordBanner; + }}; + infot = new TextButtonStyle(){{ + font = Fonts.def; + fontColor = Color.white; + up = infoBanner; + }}; + clearPartialt = new TextButtonStyle(){{ + down = whiteui; + up = pane; + over = flatDown; + font = Fonts.def; + fontColor = Color.white; + disabledFontColor = Color.gray; + }}; + clearTogglet = new TextButtonStyle(){{ + font = Fonts.def; + fontColor = Color.white; + checked = flatDown; + down = flatDown; + up = black; + over = flatOver; + disabled = black; + disabledFontColor = Color.gray; + }}; + clearToggleMenut = new TextButtonStyle(){{ + font = Fonts.def; + fontColor = Color.white; + checked = flatDown; + down = flatDown; + up = clear; + over = flatOver; + disabled = black; + disabledFontColor = Color.gray; + }}; + togglet = new TextButtonStyle(){{ + font = Fonts.def; + fontColor = Color.white; + checked = buttonDown; + down = buttonDown; + up = button; + over = buttonOver; + disabled = buttonDisabled; + disabledFontColor = Color.gray; + }}; + + defaulti = new ImageButtonStyle(){{ + down = buttonDown; + up = button; + over = buttonOver; + imageDisabledColor = Color.gray; + imageUpColor = Color.white; + disabled = buttonDisabled; + }}; + nodei = new ImageButtonStyle(){{ + up = buttonOver; + over = buttonDown; + }}; + righti = new ImageButtonStyle(){{ + over = buttonRightOver; + down = buttonRightDown; + up = buttonRight; + }}; + emptyi = new ImageButtonStyle(){{ + imageDownColor = Pal.accent; + imageUpColor = Color.white; + }}; + emptytogglei = new ImageButtonStyle(){{ + imageCheckedColor = Color.white; + imageDownColor = Color.white; + imageUpColor = Color.gray; + }}; + selecti = new ImageButtonStyle(){{ + checked = buttonSelect; + up = none; + }}; + cleari = new ImageButtonStyle(){{ + down = flatOver; + up = black; + over = flatOver; + }}; + clearFulli = new ImageButtonStyle(){{ + down = whiteui; + up = pane; + over = flatDown; + }}; + clearPartiali = new ImageButtonStyle(){{ + down = flatDown; + up = none; + over = flatOver; + }}; + clearPartial2i = new ImageButtonStyle(){{ + down = whiteui; + up = pane; + over = flatDown; + }}; + clearTogglei = new ImageButtonStyle(){{ + down = flatDown; + checked = flatDown; + up = black; + over = flatOver; + }}; + clearTransi = new ImageButtonStyle(){{ + down = flatDown; + up = black6; + over = flatOver; + }}; + clearToggleTransi = new ImageButtonStyle(){{ + down = flatDown; + checked = flatDown; + up = black6; + over = flatOver; + }}; + clearTogglePartiali = new ImageButtonStyle(){{ + down = flatDown; + checked = flatDown; + up = none; + over = flatOver; + }}; + + defaultPane = new ScrollPaneStyle(){{ + vScroll = scroll; + vScrollKnob = scrollKnobVerticalBlack; + }}; + horizontalPane = new ScrollPaneStyle(){{ + vScroll = scroll; + vScrollKnob = scrollKnobVerticalBlack; + hScroll = scrollHorizontal; + hScrollKnob = scrollKnobHorizontalBlack; + }}; + + defaultKeybindDialog = new KeybindDialogStyle(){{ + keyColor = Pal.accent; + keyNameColor = Color.white; + controllerColor = Color.lightGray; + }}; + + defaultSlider = new SliderStyle(){{ + background = slider; + knob = sliderKnob; + knobOver = sliderKnobOver; + knobDown = sliderKnobDown; + }}; + vSlider = new SliderStyle(){{ + background = sliderVertical; + knob = sliderKnob; + knobOver = sliderKnobOver; + knobDown = sliderKnobDown; + }}; + + defaultLabel = new LabelStyle(){{ + font = Fonts.def; + fontColor = Color.white; + }}; + outlineLabel = new LabelStyle(){{ + font = Fonts.outline; + fontColor = Color.white; + }}; + + defaultField = new TextFieldStyle(){{ + font = Fonts.chat; + fontColor = Color.white; + disabledFontColor = Color.gray; + disabledBackground = underlineDisabled; + selection = Tex.selection; + background = underline; + invalidBackground = underlineRed; + cursor = Tex.cursor; + messageFont = Fonts.def; + messageFontColor = Color.gray; + }}; + areaField = new TextFieldStyle(){{ + font = Fonts.chat; + fontColor = Color.white; + disabledFontColor = Color.gray; + selection = Tex.selection; + background = underline; + cursor = Tex.cursor; + messageFont = Fonts.def; + messageFontColor = Color.gray; + }}; + + defaultCheck = new CheckBoxStyle(){{ + checkboxOn = checkOn; + checkboxOff = checkOff; + checkboxOnOver = checkOnOver; + checkboxOver = checkOver; + checkboxOnDisabled = checkOnDisabled; + checkboxOffDisabled = checkDisabled; + font = Fonts.def; + fontColor = Color.white; + disabledFontColor = Color.gray; + }}; + + defaultDialog = new DialogStyle(){{ + stageBackground = black9; + titleFont = Fonts.def; + background = windowEmpty; + titleFontColor = Pal.accent; + }}; + fullDialog = new DialogStyle(){{ + stageBackground = black; + titleFont = Fonts.def; + background = windowEmpty; + titleFontColor = Pal.accent; + }}; + } + + private static Drawable createFlatDown(){ + AtlasRegion region = Core.atlas.find("flat-down-base"); + int[] splits = region.splits; + + ScaledNinePatchDrawable copy = new ScaledNinePatchDrawable(new NinePatch(region, splits[0], splits[1], splits[2], splits[3])){ + public float getLeftWidth(){ return 0; } + public float getRightWidth(){ return 0; } + public float getTopHeight(){ return 0; } + public float getBottomHeight(){ return 0; } + }; + copy.setMinWidth(0); + copy.setMinHeight(0); + copy.setTopHeight(0); + copy.setRightWidth(0); + copy.setBottomHeight(0); + copy.setLeftWidth(0); + return copy; + } +} diff --git a/core/src/io/anuke/mindustry/ui/dialogs/AboutDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/AboutDialog.java index bac51b97bf..00c0ac0835 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/AboutDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/AboutDialog.java @@ -1,20 +1,22 @@ package io.anuke.mindustry.ui.dialogs; -import io.anuke.arc.Core; +import io.anuke.arc.*; import io.anuke.arc.collection.*; -import io.anuke.arc.graphics.Color; -import io.anuke.arc.scene.ui.ScrollPane; +import io.anuke.arc.graphics.*; +import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; -import io.anuke.mindustry.graphics.Pal; -import io.anuke.mindustry.ui.Links; -import io.anuke.mindustry.ui.Links.LinkEntry; +import io.anuke.mindustry.game.EventType.*; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.graphics.*; +import io.anuke.mindustry.ui.*; +import io.anuke.mindustry.ui.Links.*; import static io.anuke.mindustry.Vars.*; public class AboutDialog extends FloatingDialog{ private Array contributors = new Array<>(); - private static ObjectSet bannedItems = ObjectSet.with("google-play", "itch.io", "dev-builds", "trello"); + private static ObjectSet bannedItems = ObjectSet.with("google-play", "itch.io", "dev-builds"); public AboutDialog(){ super("$about.button"); @@ -39,32 +41,34 @@ public class AboutDialog extends FloatingDialog{ ScrollPane pane = new ScrollPane(in); for(LinkEntry link : Links.getLinks()){ - if((ios || OS.isMac) && bannedItems.contains(link.name)){ //because Apple doesn't like me mentioning things + if((ios || OS.isMac || steam) && bannedItems.contains(link.name)){ continue; } - Table table = new Table("underline"); + Table table = new Table(Tex.underline); table.margin(0); table.table(img -> { - img.addImage("whiteui").height(h - 5).width(40f).color(link.color); + img.addImage().height(h - 5).width(40f).color(link.color); img.row(); - img.addImage("whiteui").height(5).width(40f).color(link.color.cpy().mul(0.8f, 0.8f, 0.8f, 1f)); + img.addImage().height(5).width(40f).color(link.color.cpy().mul(0.8f, 0.8f, 0.8f, 1f)); }).expandY(); table.table(i -> { - i.background("button-edge-3"); - i.addImage("icon-" + link.name).size(iconsize); + i.background(Tex.buttonEdge3); + i.addImage(Core.atlas.drawable("icon-" + link.name)); }).size(h - 5, h); table.table(inset -> { inset.add("[accent]" + Strings.capitalize(link.name.replace("-", " "))).growX().left(); inset.row(); - inset.labelWrap(link.description).width(w - 100f).color(Color.LIGHT_GRAY).growX(); + inset.labelWrap(link.description).width(w - 100f).color(Color.lightGray).growX(); }).padLeft(8); - table.addImageButton("icon-link", iconsize, () -> { + table.addImageButton(Icon.link, () -> { + if(link.name.equals("wiki")) Events.fire(Trigger.openWiki); + if(!Core.net.openURI(link.link)){ - ui.showError("$linkfail"); + ui.showErrorMessage("$linkfail"); Core.app.setClipboardText(link.link); } }).size(h - 5, h); @@ -94,7 +98,7 @@ public class AboutDialog extends FloatingDialog{ dialog.cont.add("$credits.text"); dialog.cont.row(); if(!contributors.isEmpty()){ - dialog.cont.addImage("whiteui").color(Pal.accent).fillX().height(3f).pad(3f); + dialog.cont.addImage().color(Pal.accent).fillX().height(3f).pad(3f); dialog.cont.row(); dialog.cont.add("$contributors"); dialog.cont.row(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/AdminsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/AdminsDialog.java index 2462ec9fe4..c53cbc3ec7 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/AdminsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/AdminsDialog.java @@ -1,8 +1,9 @@ package io.anuke.mindustry.ui.dialogs; -import io.anuke.arc.scene.ui.ScrollPane; -import io.anuke.arc.scene.ui.layout.Table; -import io.anuke.mindustry.net.Administration.PlayerInfo; +import io.anuke.arc.scene.ui.*; +import io.anuke.arc.scene.ui.layout.*; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.net.Administration.*; import static io.anuke.mindustry.Vars.*; @@ -32,12 +33,12 @@ public class AdminsDialog extends FloatingDialog{ } for(PlayerInfo info : netServer.admins.getAdmins()){ - Table res = new Table("button"); + Table res = new Table(Tex.button); res.margin(14f); res.labelWrap("[LIGHT_GRAY]" + info.lastName).width(w - h - 24f); res.add().growX(); - res.addImageButton("icon-cancel", iconsize, () -> { + res.addImageButton(Icon.cancel, () -> { ui.showConfirm("$confirm", "$confirmunadmin", () -> { netServer.admins.unAdminPlayer(info.id); playerGroup.all().each(player -> { diff --git a/core/src/io/anuke/mindustry/ui/dialogs/BansDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/BansDialog.java index 9caad501c1..4a09b24b65 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/BansDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/BansDialog.java @@ -1,8 +1,9 @@ package io.anuke.mindustry.ui.dialogs; -import io.anuke.arc.scene.ui.ScrollPane; -import io.anuke.arc.scene.ui.layout.Table; -import io.anuke.mindustry.net.Administration.PlayerInfo; +import io.anuke.arc.scene.ui.*; +import io.anuke.arc.scene.ui.layout.*; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.net.Administration.*; import static io.anuke.mindustry.Vars.*; @@ -33,12 +34,12 @@ public class BansDialog extends FloatingDialog{ } for(PlayerInfo info : netServer.admins.getBanned()){ - Table res = new Table("button"); + Table res = new Table(Tex.button); res.margin(14f); res.labelWrap("IP: [LIGHT_GRAY]" + info.lastIP + "\n[]Name: [LIGHT_GRAY]" + info.lastName).width(w - h - 24f); res.add().growX(); - res.addImageButton("icon-cancel", iconsize, () -> { + res.addImageButton(Icon.cancel, () -> { ui.showConfirm("$confirm", "$confirmunban", () -> { netServer.admins.unbanPlayerID(info.id); setup(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/ColorPickDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/ColorPickDialog.java index 3ea7f3d3d4..4402d740c4 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/ColorPickDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/ColorPickDialog.java @@ -1,20 +1,20 @@ package io.anuke.mindustry.ui.dialogs; -import io.anuke.arc.function.Consumer; -import io.anuke.arc.graphics.Color; -import io.anuke.arc.input.KeyCode; -import io.anuke.arc.scene.ui.Dialog; -import io.anuke.arc.scene.ui.ImageButton; -import io.anuke.arc.scene.ui.layout.Table; +import io.anuke.arc.function.*; +import io.anuke.arc.graphics.*; +import io.anuke.arc.input.*; +import io.anuke.arc.scene.ui.*; +import io.anuke.arc.scene.ui.layout.*; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.ui.*; -import static io.anuke.mindustry.Vars.player; -import static io.anuke.mindustry.Vars.playerColors; +import static io.anuke.mindustry.Vars.*; public class ColorPickDialog extends Dialog{ private Consumer cons; public ColorPickDialog(){ - super("", "dialog"); + super(""); build(); } @@ -25,7 +25,7 @@ public class ColorPickDialog extends Dialog{ for(int i = 0; i < playerColors.length; i++){ Color color = playerColors[i]; - ImageButton button = table.addImageButton("whiteui", "clear-toggle", 34, () -> { + ImageButton button = table.addImageButton(Tex.whiteui, Styles.clearTogglei, 34, () -> { cons.accept(color); hide(); }).size(48).get(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/ControlsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/ControlsDialog.java index c63c845248..1031474167 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/ControlsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/ControlsDialog.java @@ -1,21 +1,19 @@ package io.anuke.mindustry.ui.dialogs; -import io.anuke.arc.Core; -import io.anuke.arc.input.KeyCode; +import io.anuke.arc.input.*; import io.anuke.arc.scene.ui.*; -import io.anuke.arc.util.Align; -import io.anuke.mindustry.Vars; -import io.anuke.mindustry.graphics.Pal; +import io.anuke.arc.util.*; +import io.anuke.mindustry.*; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.graphics.*; public class ControlsDialog extends KeybindDialog{ public ControlsDialog(){ - setStyle(Core.scene.skin.get("dialog", WindowStyle.class)); - setFillParent(true); title.setAlignment(Align.center); titleTable.row(); - titleTable.add(new Image("whiteui")) + titleTable.add(new Image()) .growX().height(3f).pad(4f).get().setColor(Pal.accent); if(Vars.mobile){ cont.row(); @@ -26,7 +24,7 @@ public class ControlsDialog extends KeybindDialog{ @Override public void addCloseButton(){ - buttons.addImageTextButton("$back", "icon-arrow-left", 30f, this::hide).size(230f, 64f); + buttons.addImageTextButton("$back", Icon.arrowLeftSmall, this::hide).size(230f, 64f); keyDown(key -> { if(key == KeyCode.ESCAPE || key == KeyCode.BACK) diff --git a/core/src/io/anuke/mindustry/ui/dialogs/CustomGameDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/CustomGameDialog.java index 9fd1f6f847..efbdfa65df 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/CustomGameDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/CustomGameDialog.java @@ -8,6 +8,7 @@ import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.*; import io.anuke.mindustry.game.*; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.maps.*; import io.anuke.mindustry.ui.*; @@ -36,7 +37,7 @@ public class CustomGameDialog extends FloatingDialog{ ScrollPane pane = new ScrollPane(maps); pane.setFadeScrollBars(false); - int maxwidth = Mathf.clamp((int)(Core.graphics.getWidth() / UnitScl.dp.scl(200)), 1, 8); + int maxwidth = Mathf.clamp((int)(Core.graphics.getWidth() / Scl.scl(200)), 1, 8); float images = 146f; int i = 0; @@ -47,7 +48,7 @@ public class CustomGameDialog extends FloatingDialog{ maps.row(); } - ImageButton image = new ImageButton(new TextureRegion(map.texture), "clear"); + ImageButton image = new ImageButton(new TextureRegion(map.texture), Styles.cleari); image.margin(5); image.top(); @@ -59,14 +60,14 @@ public class CustomGameDialog extends FloatingDialog{ t.left(); for(Gamemode mode : Gamemode.all){ if(mode.valid(map) && Core.atlas.has("icon-mode-" + mode.name())){ - t.addImage("icon-mode-" + mode.name()).size(16f).pad(4f); + t.addImage(Core.atlas.drawable("icon-mode-" + mode.name())).size(16f).pad(4f); } } }).left(); image.row(); image.add(map.name()).pad(1f).growX().wrap().left().get().setEllipsis(true); image.row(); - image.addImage("whiteui", Pal.gray).growX().pad(3).height(4f); + image.addImage(Tex.whiteui, Pal.gray).growX().pad(3).height(4f); image.row(); image.add(img).size(images); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/CustomRulesDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/CustomRulesDialog.java index 22e8f4a233..58cf4cb4eb 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/CustomRulesDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/CustomRulesDialog.java @@ -101,7 +101,7 @@ public class CustomRulesDialog extends FloatingDialog{ main.table(t -> { t.left(); t.add(text).left().padRight(5) - .update(a -> a.setColor(condition.get() ? Color.WHITE : Color.GRAY)); + .update(a -> a.setColor(condition.get() ? Color.white : Color.gray)); Vars.platform.addDialog(t.addField((integer ? (int)prov.get() : prov.get()) + "", s -> cons.accept(Strings.parseFloat(s))) .padRight(100f) .update(a -> a.setDisabled(!condition.get())) diff --git a/core/src/io/anuke/mindustry/ui/dialogs/DatabaseDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/DatabaseDialog.java index 1f5dfc8679..3381b029f2 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/DatabaseDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/DatabaseDialog.java @@ -12,6 +12,7 @@ import io.anuke.mindustry.Vars; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.game.Content; import io.anuke.mindustry.game.UnlockableContent; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.Pal; import io.anuke.mindustry.type.ContentType; @@ -43,7 +44,7 @@ public class DatabaseDialog extends FloatingDialog{ table.add("$content." + type.name() + ".name").growX().left().color(Pal.accent); table.row(); - table.addImage("whiteui").growX().pad(5).padLeft(0).padRight(0).height(3).color(Pal.accent); + table.addImage().growX().pad(5).padLeft(0).padRight(0).height(3).color(Pal.accent); table.row(); table.table(list -> { list.left(); @@ -55,18 +56,18 @@ public class DatabaseDialog extends FloatingDialog{ for(int i = 0; i < array.size; i++){ UnlockableContent unlock = (UnlockableContent)array.get(i); - Image image = unlocked(unlock) ? new Image(unlock.getContentIcon()) : new Image("icon-locked", Pal.gray); - list.add(image).size(unlocked(unlock) ? 8*4 : Vars.iconsize).pad(3); + Image image = unlocked(unlock) ? new Image(unlock.getContentIcon()) : new Image(Icon.lockedSmall, Pal.gray); + list.add(image).size(8*4).pad(3); ClickListener listener = new ClickListener(); image.addListener(listener); if(!Vars.mobile && unlocked(unlock)){ image.addListener(new HandCursorListener()); - image.update(() -> image.getColor().lerp(!listener.isOver() ? Color.LIGHT_GRAY : Color.WHITE, 0.4f * Time.delta())); + image.update(() -> image.getColor().lerp(!listener.isOver() ? Color.lightGray : Color.white, 0.4f * Time.delta())); } if(unlocked(unlock)){ image.clicked(() -> Vars.ui.content.show(unlock)); - image.addListener(new Tooltip(t -> t.background("button").add(unlock.localizedName()))); + image.addListener(new Tooltip(t -> t.background(Tex.button).add(unlock.localizedName()))); } if((++count) % maxWidth == 0){ diff --git a/core/src/io/anuke/mindustry/ui/dialogs/DeployDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/DeployDialog.java index 64c7e3792c..1ba3c9ca82 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/DeployDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/DeployDialog.java @@ -17,36 +17,37 @@ import io.anuke.arc.util.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.game.Saves.*; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.io.SaveIO.*; -import io.anuke.mindustry.net.Net; import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.Zone.*; import io.anuke.mindustry.ui.*; +import io.anuke.mindustry.ui.Styles; import io.anuke.mindustry.ui.TreeLayout.*; import static io.anuke.mindustry.Vars.*; public class DeployDialog extends FloatingDialog{ - private final float nodeSize = UnitScl.dp.scl(230f); + private final float nodeSize = Scl.scl(230f); private ObjectSet nodes = new ObjectSet<>(); private ZoneInfoDialog info = new ZoneInfoDialog(); private Rectangle bounds = new Rectangle(); public DeployDialog(){ - super("", "fulldialog"); + super("", Styles.fullDialog); ZoneNode root = new ZoneNode(Zones.groundZero, null); TreeLayout layout = new TreeLayout(); - layout.gapBetweenLevels = layout.gapBetweenNodes = UnitScl.dp.scl(60f); - layout.gapBetweenNodes = UnitScl.dp.scl(120f); + layout.gapBetweenLevels = layout.gapBetweenNodes = Scl.scl(60f); + layout.gapBetweenNodes = Scl.scl(120f); layout.layout(root); bounds.set(layout.getBounds()); bounds.y += nodeSize*0.4f; addCloseButton(); - buttons.addImageTextButton("$techtree", "icon-tree", iconsize, () -> ui.tech.show()).size(230f, 64f); + buttons.addImageTextButton("$techtree", Icon.tree, () -> ui.tech.show()).size(230f, 64f); shown(this::setup); } @@ -86,7 +87,7 @@ public class DeployDialog extends FloatingDialog{ Stack sub = new Stack(); if(slot.getZone() != null){ - sub.add(new Table(f -> f.margin(4f).add(new Image("whiteui")).color(Color.fromGray(0.1f)).grow())); + sub.add(new Table(f -> f.margin(4f).add(new Image()).color(Color.fromGray(0.1f)).grow())); sub.add(new Table(f -> f.margin(4f).add(new Image(slot.getZone().preview).setScaling(Scaling.fit)).update(img -> { TextureRegionDrawable draw = (TextureRegionDrawable)img.getDrawable(); @@ -98,14 +99,14 @@ public class DeployDialog extends FloatingDialog{ if(draw.getRegion() == slot.getZone().preview && text != null){ draw.setRegion(new TextureRegion(text)); } - }).color(Color.DARK_GRAY).grow())); + }).color(Color.darkGray).grow())); } - TextButton button = Elements.newButton(Core.bundle.format("resume", slot.getZone().localizedName()), "square", () -> { + TextButton button = Elements.newButton(Core.bundle.format("resume", slot.getZone().localizedName()), Styles.squaret, () -> { hide(); ui.loadAnd(() -> { logic.reset(); - Net.reset(); + net.reset(); try{ control.saves.getZoneSlot().load(); state.set(State.playing); @@ -169,20 +170,15 @@ public class DeployDialog extends FloatingDialog{ return false; } - @Override - protected void drawBackground(float x, float y){ - drawDefaultBackground(x, y); - } - void buildButton(Zone zone, Button button){ button.setDisabled(() -> hidden(zone)); button.clicked(() -> info.show(zone)); if(zone.unlocked() && !hidden(zone)){ - button.labelWrap(zone.localizedName()).style("outline").width(140).growX().get().setAlignment(Align.center); + button.labelWrap(zone.localizedName()).style(Styles.outlineLabel).width(140).growX().get().setAlignment(Align.center); }else{ - Consumer flasher = zone.canUnlock() && !hidden(zone) ? e -> e.update(() -> e.getColor().set(Color.WHITE).lerp(Pal.accent, Mathf.absin(3f, 1f))) : e -> {}; - flasher.accept(button.addImage("icon-locked").get()); + Consumer flasher = zone.canUnlock() && !hidden(zone) ? e -> e.update(() -> e.getColor().set(Color.white).lerp(Pal.accent, Mathf.absin(3f, 1f))) : e -> {}; + flasher.accept(button.addImage(Icon.locked).get()); button.row(); flasher.accept(button.add("$locked").get()); } @@ -202,10 +198,10 @@ public class DeployDialog extends FloatingDialog{ } stack.setSize(Tmp.v1.x, Tmp.v1.y); - stack.add(new Table(t -> t.margin(4f).add(new Image(node.zone.preview).setScaling(Scaling.stretch)).color(node.zone.unlocked() ? Color.DARK_GRAY : Color.fromGray(0.2f)).grow())); + stack.add(new Table(t -> t.margin(4f).add(new Image(node.zone.preview).setScaling(Scaling.stretch)).color(node.zone.unlocked() ? Color.darkGray : Color.fromGray(0.2f)).grow())); stack.update(() -> stack.setPosition(node.x + panX + width / 2f, node.y + panY + height / 2f, Align.center)); - Button button = new Button("square"); + Button button = new Button(Styles.squaret); buildButton(node.zone, button); stack.add(button); addChild(stack); @@ -237,7 +233,7 @@ public class DeployDialog extends FloatingDialog{ for(ZoneNode node : nodes){ for(ZoneNode child : node.allChildren){ - Lines.stroke(UnitScl.dp.scl(4f), node.zone.locked() || child.zone.locked() ? Pal.gray : Pal.gray); + Lines.stroke(Scl.scl(4f), node.zone.locked() || child.zone.locked() ? Pal.gray : Pal.gray); Draw.alpha(parentAlpha); Lines.line(node.x + offsetX, node.y + offsetY, child.x + offsetX, child.y + offsetY); } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/DiscordDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/DiscordDialog.java index c7c343c6c6..2b87ed6a7d 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/DiscordDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/DiscordDialog.java @@ -3,6 +3,7 @@ package io.anuke.mindustry.ui.dialogs; import io.anuke.arc.Core; import io.anuke.arc.graphics.Color; import io.anuke.arc.scene.ui.Dialog; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.Pal; import static io.anuke.mindustry.Vars.*; @@ -10,7 +11,7 @@ import static io.anuke.mindustry.Vars.*; public class DiscordDialog extends Dialog{ public DiscordDialog(){ - super("", "dialog"); + super(""); float h = 70f; @@ -19,17 +20,17 @@ public class DiscordDialog extends Dialog{ Color color = Color.valueOf("7289da"); cont.table(t -> { - t.background("button").margin(0); + t.background(Tex.button).margin(0); t.table(img -> { - img.addImage("whiteui").height(h - 5).width(40f).color(color); + img.addImage().height(h - 5).width(40f).color(color); img.row(); - img.addImage("whiteui").height(5).width(40f).color(color.cpy().mul(0.8f, 0.8f, 0.8f, 1f)); + img.addImage().height(5).width(40f).color(color.cpy().mul(0.8f, 0.8f, 0.8f, 1f)); }).expandY(); t.table(i -> { - i.background("button"); - i.addImage("icon-discord").size(iconsize); + i.background(Tex.button); + i.addImage(Icon.discord); }).size(h).left(); t.add("$discord").color(Pal.accent).growX().padLeft(10f); @@ -43,7 +44,7 @@ public class DiscordDialog extends Dialog{ }); buttons.addButton("$openlink", () -> { if(!Core.net.openURI(discordURL)){ - ui.showError("$linkfail"); + ui.showErrorMessage("$linkfail"); Core.app.setClipboardText(discordURL); } }); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java b/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java index 75d5a4c352..b7faca0abe 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java @@ -1,21 +1,21 @@ package io.anuke.mindustry.ui.dialogs; -import io.anuke.arc.Core; -import io.anuke.arc.collection.Array; -import io.anuke.arc.files.FileHandle; -import io.anuke.arc.function.Consumer; -import io.anuke.arc.function.Predicate; -import io.anuke.arc.graphics.g2d.GlyphLayout; -import io.anuke.arc.scene.event.Touchable; +import io.anuke.arc.*; +import io.anuke.arc.collection.*; +import io.anuke.arc.files.*; +import io.anuke.arc.function.*; +import io.anuke.arc.graphics.g2d.*; +import io.anuke.arc.scene.event.*; import io.anuke.arc.scene.ui.*; -import io.anuke.arc.scene.ui.layout.Table; -import io.anuke.arc.scene.ui.layout.UnitScl; +import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; -import io.anuke.arc.util.pooling.Pools; +import io.anuke.arc.util.pooling.*; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.ui.*; -import java.util.Arrays; +import java.util.*; -import static io.anuke.mindustry.Vars.*; +import static io.anuke.mindustry.Vars.platform; public class FileChooser extends FloatingDialog{ private static final FileHandle homeDirectory = Core.files.absolute(OS.isMac ? OS.getProperty("user.home") + "/Downloads/" : Core.files.getExternalStoragePath()); @@ -31,13 +31,9 @@ public class FileChooser extends FloatingDialog{ private Consumer selectListener; private boolean open; - public static final Predicate pngFiles = str -> str.equals("png"); - public static final Predicate anyMapFiles = str -> str.equals(oldMapExtension) || str.equals(mapExtension); - public static final Predicate mapFiles = str -> str.equals(mapExtension); - public static final Predicate saveFiles = str -> str.equals(saveExtension); - public FileChooser(String title, Predicate filter, boolean open, Consumer result){ super(title); + setFillParent(true); this.open = open; this.filter = filter; this.selectListener = result; @@ -88,11 +84,7 @@ public class FileChooser extends FloatingDialog{ files.marginRight(10); files.marginLeft(3); - pane = new ScrollPane(files){ - public float getPrefHeight(){ - return Core.graphics.getHeight(); - } - }; + pane = new ScrollPane(files); pane.setOverscroll(false, false); pane.setFadeScrollBars(false); @@ -100,10 +92,7 @@ public class FileChooser extends FloatingDialog{ Table icontable = new Table(); - float isize = iconsize; - - ImageButton up = new ImageButton("icon-folder-parent"); - up.resizeImage(isize); + ImageButton up = new ImageButton(Icon.folderParent); up.clicked(() -> { directory = directory.parent(); updateFiles(true); @@ -114,19 +103,15 @@ public class FileChooser extends FloatingDialog{ up.setDisabled(true); } - ImageButton back = new ImageButton("icon-arrow-left"); - back.resizeImage(isize); - - ImageButton forward = new ImageButton("icon-arrow-right"); - forward.resizeImage(isize); + ImageButton back = new ImageButton(Icon.arrowLeft); + ImageButton forward = new ImageButton(Icon.arrowRight); forward.clicked(() -> stack.forward()); back.clicked(() -> stack.back()); forward.setDisabled(() -> !stack.canForward()); back.setDisabled(() -> !stack.canBack()); - ImageButton home = new ImageButton("icon-home"); - home.resizeImage(isize); + ImageButton home = new ImageButton(Icon.home); home.clicked(() -> { directory = homeDirectory; lastDirectory = directory; @@ -152,7 +137,7 @@ public class FileChooser extends FloatingDialog{ content.add(icontable).expandX().fillX(); content.row(); - content.center().add(pane).width(Core.graphics.isPortrait() ? Core.graphics.getWidth() / UnitScl.dp.scl(1) : Core.graphics.getWidth() / UnitScl.dp.scl(2)).colspan(3).grow(); + content.center().add(pane).colspan(3).grow(); content.row(); if(!open){ @@ -162,7 +147,7 @@ public class FileChooser extends FloatingDialog{ content.add(buttons).growX(); - cont.add(content); + cont.add(content).grow(); } private void updateFileFieldStatus(){ @@ -191,7 +176,7 @@ public class FileChooser extends FloatingDialog{ GlyphLayout layout = Pools.obtain(GlyphLayout.class, GlyphLayout::new); - layout.setText(Core.scene.skin.getFont("default"), navigation.getText()); + layout.setText(Fonts.def, navigation.getText()); if(layout.width < navigation.getWidth()){ navigation.setCursorPosition(0); @@ -207,15 +192,15 @@ public class FileChooser extends FloatingDialog{ //macs are confined to the Downloads/ directory if(!OS.isMac){ - Image upimage = new Image("icon-folder-parent-small"); - TextButton upbutton = new TextButton(".." + directory.toString(), "clear-toggle"); + Image upimage = new Image(Icon.folderParentSmall); + TextButton upbutton = new TextButton(".." + directory.toString(), Styles.clearTogglet); upbutton.clicked(() -> { directory = directory.parent(); lastDirectory = directory; updateFiles(true); }); - upbutton.left().add(upimage).padRight(4f).size(iconsizesmall).padLeft(4); + upbutton.left().add(upimage).padRight(4f).padLeft(4); upbutton.getLabel().setAlignment(Align.left); upbutton.getCells().reverse(); @@ -231,7 +216,7 @@ public class FileChooser extends FloatingDialog{ String filename = file.name(); - TextButton button = new TextButton(shorten(filename), "clear-toggle"); + TextButton button = new TextButton(shorten(filename), Styles.clearTogglet); group.add(button); button.clicked(() -> { @@ -249,9 +234,9 @@ public class FileChooser extends FloatingDialog{ button.setChecked(filename.equals(filefield.getText())); }); - Image image = new Image(file.isDirectory() ? "icon-folder-small" : "icon-file-text-small"); + Image image = new Image(file.isDirectory() ? Icon.folderSmall : Icon.fileTextSmall); - button.add(image).padRight(4f).padLeft(4).size(iconsizesmall); + button.add(image).padRight(4f).padLeft(4); button.getCells().reverse(); files.top().left().add(button).align(Align.topLeft).fillX().expandX() .height(50).pad(2).padTop(0).padBottom(0).colspan(2); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/FloatingDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/FloatingDialog.java index 54a502627e..de9f1ad85e 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/FloatingDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/FloatingDialog.java @@ -8,7 +8,6 @@ import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; -import io.anuke.mindustry.net.Net; import static io.anuke.mindustry.Vars.*; @@ -16,17 +15,17 @@ public class FloatingDialog extends Dialog{ private boolean wasPaused; protected boolean shouldPause; - public FloatingDialog(String title, String style){ + public FloatingDialog(String title, DialogStyle style){ super(title, style); setFillParent(true); this.title.setAlignment(Align.center); titleTable.row(); - titleTable.addImage("whiteui", Pal.accent) + titleTable.addImage(Tex.whiteui, Pal.accent) .growX().height(3f).pad(4f); hidden(() -> { if(shouldPause && !state.is(State.menu)){ - if(!wasPaused || Net.active()){ + if(!wasPaused || net.active()){ state.set(State.playing); } } @@ -42,7 +41,7 @@ public class FloatingDialog extends Dialog{ } public FloatingDialog(String title){ - this(title, "dialog"); + this(title, Core.scene.getStyle(DialogStyle.class)); } protected void onResize(Runnable run){ @@ -56,7 +55,7 @@ public class FloatingDialog extends Dialog{ @Override public void addCloseButton(){ - buttons.addImageTextButton("$back", "icon-arrow-left", iconsize, this::hide).size(210f, 64f); + buttons.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f, 64f); keyDown(key -> { if(key == KeyCode.ESCAPE || key == KeyCode.BACK){ diff --git a/core/src/io/anuke/mindustry/ui/dialogs/GameOverDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/GameOverDialog.java index 3078c01d56..02d967ac26 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/GameOverDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/GameOverDialog.java @@ -2,6 +2,7 @@ package io.anuke.mindustry.ui.dialogs; import io.anuke.arc.*; import io.anuke.mindustry.core.GameState.*; +import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.Stats.*; import io.anuke.mindustry.game.*; import io.anuke.mindustry.type.*; @@ -21,6 +22,11 @@ public class GameOverDialog extends FloatingDialog{ public void show(Team winner){ this.winner = winner; show(); + if(winner == player.getTeam()){ + Events.fire(new WinEvent()); + }else{ + Events.fire(new LoseEvent()); + } } void rebuild(){ diff --git a/core/src/io/anuke/mindustry/ui/dialogs/HostDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/HostDialog.java index 82ddf20e6b..a7e82e0c75 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/HostDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/HostDialog.java @@ -1,17 +1,16 @@ package io.anuke.mindustry.ui.dialogs; -import io.anuke.arc.Core; -import io.anuke.arc.graphics.Color; -import io.anuke.arc.scene.ui.ImageButton; -import io.anuke.arc.util.Strings; -import io.anuke.arc.util.Time; -import io.anuke.mindustry.Vars; -import io.anuke.mindustry.net.Net; +import io.anuke.arc.*; +import io.anuke.arc.graphics.*; +import io.anuke.arc.scene.ui.*; +import io.anuke.arc.util.*; +import io.anuke.mindustry.*; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.ui.*; -import java.io.IOException; +import java.io.*; -import static io.anuke.mindustry.Vars.player; -import static io.anuke.mindustry.Vars.ui; +import static io.anuke.mindustry.Vars.*; public class HostDialog extends FloatingDialog{ float w = 300; @@ -30,7 +29,7 @@ public class HostDialog extends FloatingDialog{ ui.listfrag.rebuild(); }).grow().pad(8).get().setMaxLength(40); - ImageButton button = t.addImageButton("whiteui", "clear-full", 40, () -> { + ImageButton button = t.addImageButton(Tex.whiteui, Styles.clearFulli, 40, () -> { new ColorPickDialog().show(color -> { player.color.set(color); Core.settings.put("color-0", Color.rgba8888(color)); @@ -50,23 +49,29 @@ public class HostDialog extends FloatingDialog{ return; } - ui.loadfrag.show("$hosting"); - Time.runTask(5f, () -> { - try{ - Net.host(Vars.port); - player.isAdmin = true; - }catch(IOException e){ - ui.showError(Core.bundle.format("server.error", Strings.parseException(e, true))); - } - ui.loadfrag.hide(); - hide(); - }); + runHost(); }).width(w).height(70f); cont.addButton("?", () -> ui.showInfo("$host.info")).size(65f, 70f).padLeft(6f); shown(() -> { - Core.app.post(() -> Core.settings.getBoolOnce("hostinfo", () -> ui.showInfo("$host.info"))); + if(!steam){ + Core.app.post(() -> Core.settings.getBoolOnce("hostinfo", () -> ui.showInfo("$host.info"))); + } + }); + } + + public void runHost(){ + ui.loadfrag.show("$hosting"); + Time.runTask(5f, () -> { + try{ + net.host(Vars.port); + player.isAdmin = true; + }catch(IOException e){ + ui.showException("$server.error", e); + } + ui.loadfrag.hide(); + hide(); }); } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java index 0a30c476bf..1570f5bcbb 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/JoinDialog.java @@ -4,16 +4,17 @@ import io.anuke.annotations.Annotations.*; import io.anuke.arc.*; import io.anuke.arc.collection.*; import io.anuke.arc.graphics.*; +import io.anuke.arc.input.*; import io.anuke.arc.math.*; -import io.anuke.arc.scene.style.*; import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.*; import io.anuke.mindustry.game.*; -import io.anuke.mindustry.net.Net; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.net.*; import io.anuke.mindustry.net.Packets.*; +import io.anuke.mindustry.ui.*; import static io.anuke.mindustry.Vars.*; @@ -67,7 +68,7 @@ public class JoinDialog extends FloatingDialog{ refreshRemote(); } add.hide(); - }).disabled(b -> Core.settings.getString("ip").isEmpty() || Net.active()); + }).disabled(b -> Core.settings.getString("ip").isEmpty() || net.active()); add.shown(() -> { add.title.setText(renaming != null ? "$server.edit" : "$server.add"); @@ -76,6 +77,11 @@ public class JoinDialog extends FloatingDialog{ } }); + keyDown(KeyCode.F5, () -> { + refreshLocal(); + refreshRemote(); + }); + shown(() -> { setup(); refreshLocal(); @@ -93,7 +99,7 @@ public class JoinDialog extends FloatingDialog{ //why are java lambdas this bad TextButton[] buttons = {null}; - TextButton button = buttons[0] = remote.addButton("[accent]" + server.displayIP(), "clear", () -> { + TextButton button = buttons[0] = remote.addButton("[accent]" + server.displayIP(), Styles.cleart, () -> { if(!buttons[0].childrenPressed()){ if(server.lastHost != null && server.lastHost.version != Version.build && Version.build != -1 && server.lastHost.version != -1){ ui.showInfo("[scarlet]" + (server.lastHost.version > Version.build ? KickReason.clientOutdated : KickReason.serverOutdated).toString() + "\n[]" + @@ -112,7 +118,7 @@ public class JoinDialog extends FloatingDialog{ inner.add(button.getLabel()).growX(); - inner.addImageButton("icon-arrow-up-small", "empty", iconsizesmall, () -> { + inner.addImageButton(Icon.arrowUpSmall, Styles.emptyi, () -> { int index = servers.indexOf(server); if(index > 0){ servers.remove(index); @@ -131,16 +137,16 @@ public class JoinDialog extends FloatingDialog{ }).margin(3f).padTop(6f).top().right(); - inner.addImageButton("icon-loading-small", "empty", iconsizesmall, () -> { + inner.addImageButton(Icon.loadingSmall, Styles.emptyi, () -> { refreshServer(server); }).margin(3f).padTop(6f).top().right(); - inner.addImageButton("icon-pencil-small", "empty", iconsizesmall, () -> { + inner.addImageButton(Icon.pencilSmall, Styles.emptyi, () -> { renaming = server; add.show(); }).margin(3f).padTop(6f).top().right(); - inner.addImageButton("icon-trash-16-small", "empty", iconsizesmall, () -> { + inner.addImageButton(Icon.trash16Small, Styles.emptyi, () -> { ui.showConfirm("$confirm", "$server.delete", () -> { servers.removeValue(server, true); saveServers(); @@ -151,8 +157,7 @@ public class JoinDialog extends FloatingDialog{ button.row(); - server.content = button.table(t -> { - }).grow().get(); + server.content = button.table(t -> {}).grow().get(); remote.row(); } @@ -168,7 +173,7 @@ public class JoinDialog extends FloatingDialog{ server.content.clear(); server.content.label(() -> Core.bundle.get("server.refreshing") + Strings.animated(Time.time(), 4, 11, ".")); - Net.pingHost(server.ip, server.port, host -> setupServer(server, host), e -> { + net.pingHost(server.ip, server.port, host -> setupServer(server, host), e -> { server.content.clear(); server.content.add("$host.invalid"); }); @@ -176,6 +181,11 @@ public class JoinDialog extends FloatingDialog{ void setupServer(Server server, Host host){ server.lastHost = host; + server.content.clear(); + buildServer(host, server.content); + } + + void buildServer(Host host, Table content){ String versionString; if(host.version == -1){ @@ -192,14 +202,13 @@ public class JoinDialog extends FloatingDialog{ versionString = Core.bundle.format("server.version", host.version, host.versionType); } - server.content.clear(); - server.content.table(t -> { + content.table(t -> { t.add("[lightgray]" + host.name + " " + versionString).width(targetWidth() - 10f).left().get().setEllipsis(true); t.row(); - t.add("[lightgray]" + (host.players != 1 ? Core.bundle.format("players", host.players == 0 ? host.players : "[accent]" + host.players + "[lightgray]") : Core.bundle.format("players.single", "[accent]" + host.players + "[lightgray]"))).left(); + t.add("[lightgray]" + (Core.bundle.format("players" + (host.players == 1 && host.playerLimit <= 0 ? ".single" : ""), (host.players == 0 ? "[lightgray]" : "[accent]") + host.players + (host.playerLimit > 0 ? "[lightgray]/[accent]" + host.playerLimit : "")+ "[lightgray]"))).left(); t.row(); - t.add("[lightgray]" + Core.bundle.format("save.map", host.mapname) + "[lightgray] / " + Core.bundle.format("save.wave", host.wave)).width(targetWidth() - 10f).left().get().setEllipsis(true); + t.add("[lightgray]" + Core.bundle.format("save.map", host.mapname) + "[lightgray] / " + host.mode.toString()).width(targetWidth() - 10f).left().get().setEllipsis(true); }).expand().left().bottom().padLeft(12f).padBottom(8); } @@ -222,13 +231,17 @@ public class JoinDialog extends FloatingDialog{ cont.clear(); cont.table(t -> { t.add("$name").padRight(10); - t.addField(Core.settings.getString("name"), text -> { - player.name = text; - Core.settings.put("name", text); - Core.settings.save(); - }).grow().pad(8).get().setMaxLength(maxNameLength); + if(!steam){ + t.addField(Core.settings.getString("name"), text -> { + player.name = text; + Core.settings.put("name", text); + Core.settings.save(); + }).grow().pad(8).get().setMaxLength(maxNameLength); + }else{ + t.add(player.name).update(l -> l.setColor(player.color)).grow().pad(8); + } - ImageButton button = t.addImageButton("whiteui", "clear-full", 40, () -> { + ImageButton button = t.addImageButton(Tex.whiteui, Styles.clearFulli, 40, () -> { new ColorPickDialog().show(color -> { player.color.set(color); Core.settings.put("color-0", Color.rgba8888(color)); @@ -240,7 +253,7 @@ public class JoinDialog extends FloatingDialog{ cont.row(); cont.add(pane).width(w + 38).pad(0); cont.row(); - cont.addCenteredImageTextButton("$server.add", "icon-add", iconsize, () -> { + cont.addCenteredImageTextButton("$server.add", Icon.add, () -> { renaming = null; add.show(); }).marginLeft(6).width(w).height(80f).update(button -> { @@ -265,20 +278,23 @@ public class JoinDialog extends FloatingDialog{ totalHosts = 0; local.clear(); - local.background((Drawable)null); - local.table("button", t -> t.label(() -> "[accent]" + Core.bundle.get("hosts.discovering") + Strings.animated(Time.time(), 4, 10f, ".")).pad(10f)).growX(); - Net.discoverServers(this::addLocalHost, this::finishLocalHosts); + local.background(null); + local.table(Tex.button, t -> t.label(() -> "[accent]" + Core.bundle.get("hosts.discovering.any") + Strings.animated(Time.time(), 4, 10f, ".")).pad(10f)).growX(); + net.discoverServers(this::addLocalHost, this::finishLocalHosts); + for(String host : defaultServers){ + net.pingHost(host, port, this::addLocalHost, e -> {}); + } } void finishLocalHosts(){ if(totalHosts == 0){ local.clear(); - local.background("button"); + local.background(Tex.button); local.add("$hosts.none").pad(10f); local.add().growX(); - local.addImageButton("icon-loading", iconsize, this::refreshLocal).pad(-12f).padLeft(0).size(70f); + local.addImageButton(Icon.loading, this::refreshLocal).pad(-12f).padLeft(0).size(70f); }else{ - local.background((Drawable)null); + local.background(null); } } @@ -286,22 +302,20 @@ public class JoinDialog extends FloatingDialog{ if(totalHosts == 0){ local.clear(); } - local.background((Drawable)null); + local.background(null); totalHosts++; float w = targetWidth(); local.row(); - TextButton button = local.addButton("[accent]" + host.name, "clear", () -> connect(host.address, port)) - .width(w).height(80f).pad(4f).get(); - button.left(); - button.row(); - button.add("[lightgray]" + (host.players != 1 ? Core.bundle.format("players", host.players) : - Core.bundle.format("players.single", host.players))).padBottom(5); + TextButton button = local.addButton("", Styles.cleart, () -> connect(host.address, port)) + .width(w).pad(5f).get(); + button.clearChildren(); + buildServer(host, button); } - void connect(String ip, int port){ - if(Core.settings.getString("name").trim().isEmpty()){ + public void connect(String ip, int port){ + if(player.name.trim().isEmpty()){ ui.showInfo("$noname"); return; } @@ -315,9 +329,9 @@ public class JoinDialog extends FloatingDialog{ Time.runTask(2f, () -> { logic.reset(); - Net.reset(); + net.reset(); Vars.netClient.beginConnecting(); - Net.connect(ip, port, () -> { + net.connect(ip, port, () -> { hide(); add.hide(); }); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/LanguageDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/LanguageDialog.java index f1a1a15ac2..487f2fa372 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/LanguageDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/LanguageDialog.java @@ -5,6 +5,7 @@ import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.layout.Table; import io.anuke.arc.util.Log; import io.anuke.arc.util.Strings; +import io.anuke.mindustry.ui.*; import java.util.Locale; @@ -29,7 +30,7 @@ public class LanguageDialog extends FloatingDialog{ ButtonGroup group = new ButtonGroup<>(); for(Locale loc : locales){ - TextButton button = new TextButton(Strings.capitalize(loc.getDisplayName(loc)), "clear-toggle"); + TextButton button = new TextButton(Strings.capitalize(loc.getDisplayName(loc)), Styles.clearTogglet); button.clicked(() -> { if(getLocale().equals(loc)) return; Core.settings.put("locale", loc.toString()); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java index b8b17e803e..4ee58e10af 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java @@ -9,13 +9,13 @@ import io.anuke.arc.scene.style.*; import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; -import io.anuke.mindustry.*; import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.game.Saves.*; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.io.*; import io.anuke.mindustry.io.SaveIO.*; -import io.anuke.mindustry.net.Net; import io.anuke.mindustry.ui.*; +import io.anuke.mindustry.ui.Styles; import java.io.*; @@ -59,7 +59,7 @@ public class LoadDialog extends FloatingDialog{ for(SaveSlot slot : array){ if(slot.isHidden()) continue; - TextButton button = new TextButton("", "clear"); + TextButton button = new TextButton("", Styles.cleart); button.getLabel().remove(); button.clearChildren(); @@ -71,45 +71,44 @@ public class LoadDialog extends FloatingDialog{ title.table(t -> { t.right(); - t.addImageButton("icon-floppy", "emptytoggle", iconsize, () -> { + t.addImageButton(Icon.floppy, Styles.emptytogglei, () -> { slot.setAutosave(!slot.isAutosave()); }).checked(slot.isAutosave()).right(); - t.addImageButton("icon-trash", "empty", iconsize, () -> { + t.addImageButton(Icon.trash, Styles.emptyi, () -> { ui.showConfirm("$confirm", "$save.delete.confirm", () -> { slot.delete(); setup(); }); - }).size(iconsize).right(); + }).right(); - t.addImageButton("icon-pencil", "empty", iconsize, () -> { + t.addImageButton(Icon.pencil, Styles.emptyi, () -> { ui.showTextInput("$save.rename", "$save.rename.text", slot.getName(), text -> { slot.setName(text); setup(); }); - }).size(iconsize).right(); + }).right(); - t.addImageButton("icon-save", "empty", iconsize, () -> { - if(!ios){ - platform.showFileChooser(Core.bundle.get("save.export"), "Mindustry Save", file -> { + t.addImageButton(Icon.save, Styles.emptyi, () -> { + if(!ios){ + platform.showFileChooser(false, saveExtension, file -> { + try{ + slot.exportFile(file); + setup(); + }catch(IOException e){ + ui.showException("save.export.fail", e); + } + }); + }else{ try{ + FileHandle file = Core.files.local("save-" + slot.getName() + "." + saveExtension); slot.exportFile(file); - setup(); - }catch(IOException e){ - ui.showError(Core.bundle.format("save.export.fail", Strings.parseException(e, true))); + platform.shareFile(file); + }catch(Exception e){ + ui.showException("save.export.fail", e); } - }, false, FileChooser.saveFiles); - }else{ - try{ - FileHandle file = Core.files.local("save-" + slot.getName() + "." + Vars.saveExtension); - slot.exportFile(file); - platform.shareFile(file); - }catch(Exception e){ - ui.showError(Core.bundle.format("save.export.fail", Strings.parseException(e, true))); } - } - }).size(iconsize).right(); - + }).right(); }).padRight(-10).growX(); }).growX().colspan(2); @@ -137,13 +136,13 @@ public class LoadDialog extends FloatingDialog{ meta.row(); meta.labelWrap(Core.bundle.format("save.map", color + (slot.getMap() == null ? Core.bundle.get("unknown") : slot.getMap().name()))); meta.row(); - meta.labelWrap(Core.bundle.format("save.wave", color + slot.getWave())); + meta.labelWrap(slot.mode().toString() + " /" + color + " " + Core.bundle.format("save.wave", color + slot.getWave())); meta.row(); meta.labelWrap(() -> Core.bundle.format("save.autosave", color + Core.bundle.get(slot.isAutosave() ? "on" : "off"))); meta.row(); meta.labelWrap(() -> Core.bundle.format("save.playtime", color + slot.getPlayTime())); meta.row(); - meta.labelWrap(Core.bundle.format("save.date", color + slot.getDate())); + meta.labelWrap(color + slot.getDate()); meta.row(); }).left().growX().width(250f); @@ -171,20 +170,20 @@ public class LoadDialog extends FloatingDialog{ if(ios) return; - slots.addImageTextButton("$save.import", "icon-add", iconsize, () -> { - platform.showFileChooser(Core.bundle.get("save.import"), "Mindustry Save", file -> { + slots.addImageTextButton("$save.import", Icon.add, () -> { + platform.showFileChooser(true, saveExtension, file -> { if(SaveIO.isSaveValid(file)){ try{ control.saves.importSave(file); setup(); }catch(IOException e){ e.printStackTrace(); - ui.showError(Core.bundle.format("save.import.fail", Strings.parseException(e, true))); + ui.showException("$save.import.fail", e); } }else{ - ui.showError("$save.import.invalid"); + ui.showErrorMessage("$save.import.invalid"); } - }, true, FileChooser.saveFiles); + }); }).fillX().margin(10f).minWidth(300f).height(70f).pad(4f).padRight(-4); } @@ -194,14 +193,14 @@ public class LoadDialog extends FloatingDialog{ ui.loadAnd(() -> { try{ - Net.reset(); + net.reset(); slot.load(); state.set(State.playing); }catch(SaveException e){ Log.err(e); state.set(State.menu); logic.reset(); - ui.showError("$save.corrupted"); + ui.showErrorMessage("$save.corrupted"); } }); } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/LoadoutDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/LoadoutDialog.java index eb05a7502f..ca5302f4f5 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/LoadoutDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/LoadoutDialog.java @@ -6,7 +6,10 @@ import io.anuke.arc.function.*; import io.anuke.arc.input.*; import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.layout.*; +import io.anuke.arc.util.*; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.type.*; +import io.anuke.mindustry.ui.*; import static io.anuke.mindustry.Vars.*; @@ -44,7 +47,7 @@ public class LoadoutDialog extends FloatingDialog{ FloatingDialog dialog = new FloatingDialog(""); dialog.setFillParent(false); for(Item item : content.items().select(item -> filter.test(item) && item.type == ItemType.material && supplier.get().find(stack -> stack.item == item) == null)){ - TextButton button = dialog.cont.addButton("", "clear", () -> { + TextButton button = dialog.cont.addButton("", Styles.cleart, () -> { dialog.hide(); supplier.get().add(new ItemStack(item, 0)); updater.run(); @@ -67,7 +70,7 @@ public class LoadoutDialog extends FloatingDialog{ }).size(210f, 64f); cont.row(); - cont.addImageTextButton("$back", "icon-arrow-left", iconsize, this::hide).size(210f, 64f); + cont.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f, 64f); } public void show(int capacity, Supplier> supplier, Runnable reseter, Runnable updater, Runnable hider, Predicate filter){ @@ -87,21 +90,34 @@ public class LoadoutDialog extends FloatingDialog{ int step = 50; for(ItemStack stack : supplier.get()){ - items.addButton("x", "clear-partial", () -> { + items.addButton("x", Styles.clearPartialt, () -> { supplier.get().remove(stack); updater.run(); setup(); }).size(bsize); - items.addButton("-", "clear-partial", () -> { + items.addButton("-", Styles.clearPartialt, () -> { stack.amount = Math.max(stack.amount - step, 0); updater.run(); }).size(bsize); - items.addButton("+", "clear-partial", () -> { + + items.addButton("+", Styles.clearPartialt, () -> { stack.amount = Math.min(stack.amount + step, capacity); updater.run(); }).size(bsize); + items.addImageButton(Icon.pencilSmaller, Styles.clearPartial2i, () -> ui.showTextInput("$configure", stack.item.localizedName, 10, stack.amount + "", true, str -> { + if(Strings.canParsePostiveInt(str)){ + int amount = Strings.parseInt(str); + if(amount >= 0 && amount <= capacity){ + stack.amount = amount; + updater.run(); + return; + } + } + ui.showInfo(Core.bundle.format("configure.invalid", capacity)); + })).size(bsize); + items.addImage(stack.item.icon(Item.Icon.medium)).size(8 * 3).padRight(4).padLeft(4); items.label(() -> stack.amount + "").left(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/MapPlayDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/MapPlayDialog.java index 26ed6bf1c9..c55b4f6fb8 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/MapPlayDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/MapPlayDialog.java @@ -6,6 +6,7 @@ import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.game.*; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.maps.*; import io.anuke.mindustry.ui.*; @@ -55,7 +56,7 @@ public class MapPlayDialog extends FloatingDialog{ for(Gamemode mode : Gamemode.values()){ if(mode.hidden) continue; - modes.addButton(mode.toString(), "toggle", () -> { + modes.addButton(mode.toString(), Styles.togglet, () -> { selectedGamemode = mode; rules = map.applyRules(mode); }).update(b -> b.setChecked(selectedGamemode == mode)).size(140f, 54f).disabled(!mode.valid(map)); @@ -66,7 +67,7 @@ public class MapPlayDialog extends FloatingDialog{ cont.add(selmode); cont.row(); - cont.addImageTextButton("$customize", "icon-tools-small", iconsizesmall, () -> dialog.show(rules, () -> rules = map.applyRules(selectedGamemode))).width(230); + cont.addImageTextButton("$customize", Icon.toolsSmall, () -> dialog.show(rules, () -> rules = map.applyRules(selectedGamemode))).width(230); cont.row(); cont.add(new BorderImage(map.texture, 3f)).size(mobile && !Core.graphics.isPortrait() ? 150f : 250f).get().setScaling(Scaling.fit); //only maps with survival are valid for high scores @@ -78,7 +79,7 @@ public class MapPlayDialog extends FloatingDialog{ buttons.clearChildren(); addCloseButton(); - buttons.addImageTextButton("$play", "icon-play", iconsize, () -> { + buttons.addImageTextButton("$play", Icon.play, () -> { control.playMap(map, rules); hide(); ui.custom.hide(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java index 546d7a3b5a..956c76bbd5 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java @@ -9,6 +9,8 @@ import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.*; +import io.anuke.mindustry.game.EventType.*; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.io.*; import io.anuke.mindustry.maps.*; @@ -43,70 +45,70 @@ public class MapsDialog extends FloatingDialog{ buttons.clearChildren(); if(Core.graphics.isPortrait() && !ios){ - buttons.addImageTextButton("$back", "icon-arrow-left", iconsize, this::hide).size(210f*2f, 64f).colspan(2); + buttons.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f*2f, 64f).colspan(2); buttons.row(); }else{ - buttons.addImageTextButton("$back", "icon-arrow-left", iconsize, this::hide).size(210f, 64f); + buttons.addImageTextButton("$back", Icon.arrowLeft, this::hide).size(210f, 64f); } - buttons.addImageTextButton("$editor.newmap", "icon-add", iconsize, () -> { + buttons.addImageTextButton("$editor.newmap", Icon.add, () -> { ui.showTextInput("$editor.newmap", "$name", "", text -> { ui.loadAnd(() -> { hide(); ui.editor.show(); ui.editor.editor.getTags().put("name", text); + Events.fire(new MapMakeEvent()); }); }); }).size(210f, 64f); if(!ios){ - buttons.addImageTextButton("$editor.importmap", "icon-load", iconsize, () -> { - platform.showFileChooser("$editor.importmap", "Map File", file -> { - maps.tryCatchMapError(() -> { - if(MapIO.isImage(file)){ - ui.showError("$editor.errorimage"); - return; - } + buttons.addImageTextButton("$editor.importmap", Icon.load, () -> { + platform.showFileChooser(true, mapExtension, file -> { + ui.loadAnd(() -> { + maps.tryCatchMapError(() -> { + if(MapIO.isImage(file)){ + ui.showErrorMessage("$editor.errorimage"); + return; + } - Map map; - if(file.extension().equalsIgnoreCase(mapExtension)){ - map = MapIO.createMap(file, true); - }else{ - map = maps.makeLegacyMap(file); - } + Map map = MapIO.createMap(file, true); - //when you attempt to import a save, it will have no name, so generate one - String name = map.tags.getOr("name", () -> { - String result = "unknown"; - int number = 0; - while(maps.byName(result + number++) != null) ; - return result + number; - }); - //this will never actually get called, but it remains just in case - if(name == null){ - ui.showError("$editor.errorname"); - return; - } - - Map conflict = maps.all().find(m -> m.name().equals(name)); - - if(conflict != null && !conflict.custom){ - ui.showInfo(Core.bundle.format("editor.import.exists", name)); - }else if(conflict != null){ - ui.showConfirm("$confirm", "$editor.overwrite.confirm", () -> { - maps.tryCatchMapError(() -> { - maps.importMap(file); - setup(); - }); + //when you attempt to import a save, it will have no name, so generate one + String name = map.tags.getOr("name", () -> { + String result = "unknown"; + int number = 0; + while(maps.byName(result + number++) != null); + return result + number; }); - }else{ - maps.importMap(map.file); - setup(); - } + //this will never actually get called, but it remains just in case + if(name == null){ + ui.showErrorMessage("$editor.errorname"); + return; + } + + Map conflict = maps.all().find(m -> m.name().equals(name)); + + if(conflict != null && !conflict.custom){ + ui.showInfo(Core.bundle.format("editor.import.exists", name)); + }else if(conflict != null){ + ui.showConfirm("$confirm", "$editor.overwrite.confirm", () -> { + maps.tryCatchMapError(() -> { + maps.removeMap(conflict); + maps.importMap(map.file); + setup(); + }); + }); + }else{ + maps.importMap(map.file); + setup(); + } + + }); }); - }, true, FileChooser.anyMapFiles); + }); }).size(210f, 64f); } @@ -118,7 +120,7 @@ public class MapsDialog extends FloatingDialog{ ScrollPane pane = new ScrollPane(maps); pane.setFadeScrollBars(false); - int maxwidth = Mathf.clamp((int)(Core.graphics.getWidth() / UnitScl.dp.scl(230)), 1, 8); + int maxwidth = Mathf.clamp((int)(Core.graphics.getWidth() / Scl.scl(230)), 1, 8); float mapsize = 200f; int i = 0; @@ -128,16 +130,16 @@ public class MapsDialog extends FloatingDialog{ maps.row(); } - TextButton button = maps.addButton("", "clear", () -> showMapInfo(map)).width(mapsize).pad(8).get(); + TextButton button = maps.addButton("", Styles.cleart, () -> showMapInfo(map)).width(mapsize).pad(8).get(); button.clearChildren(); button.margin(9); button.add(map.name()).width(mapsize - 18f).center().get().setEllipsis(true); button.row(); - button.addImage("whiteui").growX().pad(4).color(Pal.gray); + button.addImage().growX().pad(4).color(Pal.gray); button.row(); button.stack(new Image(map.texture).setScaling(Scaling.fit), new BorderImage(map.texture).setScaling(Scaling.fit)).size(mapsize - 20f); button.row(); - button.add(map.custom ? "$custom" : "$builtin").color(Color.GRAY).padTop(3); + button.add(map.custom ? "$custom" : "$builtin").color(Color.gray).padTop(3); i++; } @@ -160,7 +162,7 @@ public class MapsDialog extends FloatingDialog{ table.stack(new Image(map.texture).setScaling(Scaling.fit), new BorderImage(map.texture).setScaling(Scaling.fit)).size(mapsize); - table.table("flat", desc -> { + table.table(Styles.black, desc -> { desc.top(); Table t = new Table(); t.margin(6); @@ -171,33 +173,33 @@ public class MapsDialog extends FloatingDialog{ t.top(); t.defaults().padTop(10).left(); - t.add("$editor.name").padRight(10).color(Color.GRAY).padTop(0); + t.add("$editor.name").padRight(10).color(Color.gray).padTop(0); t.row(); t.add(map.name()).growX().wrap().padTop(2); t.row(); - t.add("$editor.author").padRight(10).color(Color.GRAY); + t.add("$editor.author").padRight(10).color(Color.gray); t.row(); t.add(map.custom && map.author().isEmpty() ? "Anuke" : map.author()).growX().wrap().padTop(2); t.row(); - t.add("$editor.description").padRight(10).color(Color.GRAY).top(); + t.add("$editor.description").padRight(10).color(Color.gray).top(); t.row(); t.add(map.description()).growX().wrap().padTop(2); }).height(mapsize).width(mapsize); table.row(); - table.addImageTextButton("$editor.openin", "icon-load-map-small", iconsizesmall, () -> { + table.addImageTextButton("$editor.openin", Icon.loadMapSmall, () -> { try{ Vars.ui.editor.beginEditMap(map.file); dialog.hide(); hide(); }catch(Exception e){ e.printStackTrace(); - ui.showError("$error.mapnotfound"); + ui.showErrorMessage("$error.mapnotfound"); } }).fillX().height(54f).marginLeft(10); - table.addImageTextButton("$delete", "icon-trash-16-small", iconsizesmall, () -> { + table.addImageTextButton("$delete", Icon.trash16Small, () -> { ui.showConfirm("$confirm", Core.bundle.format("map.delete", map.name()), () -> { maps.removeMap(map); dialog.hide(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/MinimapDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/MinimapDialog.java index feb374fd2e..3c904b84f0 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/MinimapDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/MinimapDialog.java @@ -5,6 +5,8 @@ import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.input.*; import io.anuke.arc.scene.event.*; +import io.anuke.arc.scene.ui.layout.*; +import io.anuke.mindustry.gen.*; import static io.anuke.mindustry.Vars.renderer; @@ -22,17 +24,13 @@ public class MinimapDialog extends FloatingDialog{ onResize(this::setup); } - public void drawBackground(float x, float y){ - drawDefaultBackground(x, y); - } - void setup(){ cont.clearChildren(); - cont.table("pane", t -> { + cont.table(Tex.pane,t -> { t.addRect((x, y, width, height) -> { if(renderer.minimap.getRegion() == null) return; - Draw.color(Color.WHITE); + Draw.color(Color.white); Draw.alpha(parentAlpha); Draw.rect(renderer.minimap.getRegion(), x + width / 2f, y + height / 2f, width, height); @@ -40,7 +38,7 @@ public class MinimapDialog extends FloatingDialog{ renderer.minimap.drawEntities(x, y, width, height); } }).grow(); - }).size(Math.min(Core.graphics.getWidth() / 1.1f, Core.graphics.getHeight() / 1.3f)).padTop(-20f); + }).size(Math.min(Core.graphics.getWidth() / 1.1f, Core.graphics.getHeight() / 1.3f) / Scl.scl(1f)).padTop(-20f); cont.addListener(new InputListener(){ @Override diff --git a/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java index 62b4f24a79..aaf1e63d49 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java @@ -1,9 +1,9 @@ package io.anuke.mindustry.ui.dialogs; -import io.anuke.arc.Core; -import io.anuke.arc.input.KeyCode; -import io.anuke.mindustry.core.GameState.State; -import io.anuke.mindustry.net.Net; +import io.anuke.arc.*; +import io.anuke.arc.input.*; +import io.anuke.mindustry.core.GameState.*; +import io.anuke.mindustry.gen.*; import static io.anuke.mindustry.Vars.*; @@ -52,12 +52,22 @@ public class PausedDialog extends FloatingDialog{ if(!world.isZone() && !state.isEditor()){ cont.row(); cont.addButton("$savegame", save::show); - cont.addButton("$loadgame", load::show).disabled(b -> Net.active()); + cont.addButton("$loadgame", load::show).disabled(b -> net.active()); } cont.row(); - cont.addButton("$hostserver", ui.host::show).disabled(b -> Net.active()).colspan(2).width(dw * 2 + 20f); + cont.addButton("$hostserver", () -> { + if(net.active() && steam){ + platform.inviteFriends(); + }else{ + if(steam){ + ui.host.runHost(); + }else{ + ui.host.show(); + } + } + }).disabled(b -> net.active() && !steam).colspan(2).width(dw * 2 + 20f).update(e -> e.setText(net.active() && steam ? "$invitefriends" : "$hostserver")); } cont.row(); @@ -66,24 +76,22 @@ public class PausedDialog extends FloatingDialog{ }else{ cont.defaults().size(120f).pad(5); - float isize = iconsize; - - cont.addRowImageTextButton("$back", "icon-play-2", isize, this::hide); - cont.addRowImageTextButton("$settings", "icon-tools", isize, ui.settings::show); + cont.addRowImageTextButton("$back", Icon.play2, this::hide); + cont.addRowImageTextButton("$settings", Icon.tools, ui.settings::show); if(!world.isZone() && !state.isEditor()){ - cont.addRowImageTextButton("$save", "icon-save", isize, save::show); + cont.addRowImageTextButton("$save", Icon.save, save::show); cont.row(); - cont.addRowImageTextButton("$load", "icon-load", isize, load::show).disabled(b -> Net.active()); + cont.addRowImageTextButton("$load", Icon.load, load::show).disabled(b -> net.active()); }else{ cont.row(); } - cont.addRowImageTextButton("$hostserver.mobile", "icon-host", isize, ui.host::show).disabled(b -> Net.active()); + cont.addRowImageTextButton("$hostserver.mobile", Icon.host, ui.host::show).disabled(b -> net.active()); - cont.addRowImageTextButton("$quit", "icon-quit", isize, this::showQuitConfirm); + cont.addRowImageTextButton("$quit", Icon.quit, this::showQuitConfirm); } } @@ -93,8 +101,8 @@ public class PausedDialog extends FloatingDialog{ Core.settings.put("playedtutorial", true); Core.settings.save(); } - wasClient = Net.client(); - if(Net.client()) netClient.disconnectQuietly(); + wasClient = net.client(); + if(net.client()) netClient.disconnectQuietly(); runExitSave(); hide(); }); @@ -117,7 +125,7 @@ public class PausedDialog extends FloatingDialog{ control.saves.getCurrent().save(); }catch(Throwable e){ e.printStackTrace(); - ui.showError("[accent]" + Core.bundle.get("savefail")); + ui.showException("[accent]" + Core.bundle.get("savefail"), e); } state.set(State.menu); logic.reset(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/SaveDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/SaveDialog.java index 1a3966b4d1..68b22313b9 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/SaveDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/SaveDialog.java @@ -5,6 +5,7 @@ import io.anuke.arc.scene.ui.TextButton; import io.anuke.arc.util.Time; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.game.Saves.SaveSlot; +import io.anuke.mindustry.gen.*; import static io.anuke.mindustry.Vars.*; @@ -22,7 +23,7 @@ public class SaveDialog extends LoadDialog{ public void addSetup(){ slots.row(); - slots.addImageTextButton("$save.new", "icon-add", 14 * 3, () -> + slots.addImageTextButton("$save.new", Icon.add, () -> ui.showTextInput("$save", "$save.newslot", 30, "", text -> { ui.loadAnd("$saving", () -> { control.saves.addSave(text); @@ -53,7 +54,7 @@ public class SaveDialog extends LoadDialog{ }catch(Throwable e){ e.printStackTrace(); - ui.showError("[accent]" + Core.bundle.get("savefail")); + ui.showException("[accent]" + Core.bundle.get("savefail"), e); } }); } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java index 4bc481f992..28226b215d 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -10,12 +10,14 @@ import io.anuke.arc.scene.*; import io.anuke.arc.scene.event.*; import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.SettingsDialog.SettingsTable.*; +import io.anuke.arc.scene.ui.TextButton.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.core.GameState.*; +import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; -import io.anuke.mindustry.net.Net; +import io.anuke.mindustry.ui.*; import static io.anuke.arc.Core.bundle; import static io.anuke.mindustry.Vars.*; @@ -31,12 +33,10 @@ public class SettingsMenuDialog extends SettingsDialog{ private boolean wasPaused; public SettingsMenuDialog(){ - setStyle(Core.scene.skin.get("dialog", WindowStyle.class)); - hidden(() -> { Sounds.back.play(); if(!state.is(State.menu)){ - if(!wasPaused || Net.active()) + if(!wasPaused || net.active()) state.set(State.playing); } }); @@ -54,13 +54,13 @@ public class SettingsMenuDialog extends SettingsDialog{ setFillParent(true); title.setAlignment(Align.center); titleTable.row(); - titleTable.add(new Image("whiteui")).growX().height(3f).pad(4f).get().setColor(Pal.accent); + titleTable.add(new Image()).growX().height(3f).pad(4f).get().setColor(Pal.accent); cont.clearChildren(); cont.remove(); buttons.remove(); - menu = new Table("button"); + menu = new Table(Tex.button); game = new SettingsTable(); graphics = new SettingsTable(); @@ -78,9 +78,9 @@ public class SettingsMenuDialog extends SettingsDialog{ dataDialog = new FloatingDialog("$settings.data"); dataDialog.addCloseButton(); - dataDialog.cont.table("button", t -> { + dataDialog.cont.table(Tex.button, t -> { t.defaults().size(240f, 60f).left(); - String style = "clear"; + TextButtonStyle style = Styles.cleart; t.addButton("$settings.cleardata", style, () -> ui.showConfirm("$confirm", "$settings.clearall.confirm", () -> { ObjectMap map = new ObjectMap<>(); @@ -102,56 +102,48 @@ public class SettingsMenuDialog extends SettingsDialog{ t.row(); - if(android && (Core.files.local("mindustry-maps").exists() || Core.files.local("mindustry-saves").exists())){ - t.addButton("$classic.export", style, () -> { - control.checkClassicData(); - }); - } - - t.row(); - t.addButton("$data.export", style, () -> { if(ios){ FileHandle file = Core.files.local("mindustry-data-export.zip"); try{ data.exportData(file); }catch(Exception e){ - ui.showError(Strings.parseException(e, true)); + ui.showException(e); } platform.shareFile(file); }else{ - platform.showFileChooser("$data.export", "Zip Files", file -> { - FileHandle ff = file; - if(!ff.extension().equals("zip")){ - ff = ff.sibling(ff.nameWithoutExtension() + ".zip"); - } + platform.showFileChooser(false, "zip", file -> { try{ - data.exportData(ff); + data.exportData(file); ui.showInfo("$data.exported"); }catch(Exception e){ e.printStackTrace(); - ui.showError(Strings.parseException(e, true)); + ui.showException(e); } - }, false, f -> false); + }); } }); t.row(); //iOS doesn't have a file chooser. - if(!ios){ - t.addButton("$data.import", style, () -> ui.showConfirm("$confirm", "$data.import.confirm", () -> platform.showFileChooser("$data.import", "Zip Files", file -> { + //if(!ios){ + t.addButton("$data.import", style, () -> ui.showConfirm("$confirm", "$data.import.confirm", () -> platform.showFileChooser(true, "zip", file -> { try{ data.importData(file); Core.app.exit(); }catch(IllegalArgumentException e){ - ui.showError("$data.invalid"); + ui.showErrorMessage("$data.invalid"); }catch(Exception e){ e.printStackTrace(); - ui.showError(Strings.parseException(e, true)); + if(e.getMessage() == null || !e.getMessage().contains("too short")){ + ui.showException(e); + }else{ + ui.showErrorMessage("$data.invalid"); + } } - }, true, f -> f.equalsIgnoreCase("zip")))); - } + }))); + //} }); ScrollPane pane = new ScrollPane(prefs); @@ -186,7 +178,7 @@ public class SettingsMenuDialog extends SettingsDialog{ void rebuildMenu(){ menu.clearChildren(); - String style = "clear"; + TextButtonStyle style = Styles.cleart; menu.defaults().size(300f, 60f); menu.addButton("$settings.game", style, () -> visible(0)); @@ -223,6 +215,12 @@ public class SettingsMenuDialog extends SettingsDialog{ game.checkPref("savecreate", true); + if(steam){ + game.checkPref("publichost", false, i -> { + platform.updateLobby(); + }); + } + game.pref(new Setting(){ @Override public void add(SettingsTable table){ @@ -290,7 +288,11 @@ public class SettingsMenuDialog extends SettingsDialog{ } graphics.checkPref("bloom", false, val -> renderer.toggleBloom(val)); graphics.checkPref("lasers", true); - graphics.checkPref("pixelate", false); + graphics.checkPref("pixelate", false, val -> { + if(val){ + Events.fire(Trigger.enablePixelation); + } + }); graphics.checkPref("linear", false, b -> { for(Texture tex : Core.atlas.getTextures()){ @@ -320,7 +322,7 @@ public class SettingsMenuDialog extends SettingsDialog{ @Override public void addCloseButton(){ - buttons.addImageTextButton("$back", "icon-arrow-left", 30f, () -> { + buttons.addImageTextButton("$back", Icon.arrowLeftSmaller, () -> { if(prefs.getChildren().first() != menu){ back(); }else{ diff --git a/core/src/io/anuke/mindustry/ui/dialogs/TechTreeDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/TechTreeDialog.java index 4af3810a1f..21e5f76ce2 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/TechTreeDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/TechTreeDialog.java @@ -15,17 +15,19 @@ import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.content.TechTree.*; +import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.type.*; import io.anuke.mindustry.ui.*; +import io.anuke.mindustry.ui.Styles; import io.anuke.mindustry.ui.TreeLayout.*; -import io.anuke.mindustry.world.Block.*; +import io.anuke.mindustry.world.*; import static io.anuke.mindustry.Vars.*; public class TechTreeDialog extends FloatingDialog{ - private final float nodeSize = UnitScl.dp.scl(60f); + private final float nodeSize = Scl.scl(60f); private ObjectSet nodes = new ObjectSet<>(); private TechTreeNode root = new TechTreeNode(TechTree.root, null); private Rectangle bounds = new Rectangle(); @@ -47,21 +49,16 @@ public class TechTreeDialog extends FloatingDialog{ addCloseButton(); - buttons.addImageTextButton("$database", "icon-database", iconsize, () -> { + buttons.addImageTextButton("$database", Icon.database, () -> { hide(); ui.database.show(); }).size(210f, 64f); } - @Override - protected void drawBackground(float x, float y){ - drawDefaultBackground(x, y); - } - void treeLayout(){ TreeLayout layout = new TreeLayout(); - layout.gapBetweenLevels = UnitScl.dp.scl(60f); - layout.gapBetweenNodes = UnitScl.dp.scl(40f); + layout.gapBetweenLevels = Scl.scl(60f); + layout.gapBetweenNodes = Scl.scl(40f); LayoutNode node = new LayoutNode(root, null); layout.layout(node); bounds.set(layout.getBounds()); @@ -147,7 +144,7 @@ public class TechTreeDialog extends FloatingDialog{ infoTable.touchable(Touchable.enabled); for(TechTreeNode node : nodes){ - ImageButton button = new ImageButton(node.node.block.icon(Icon.medium), "node"); + ImageButton button = new ImageButton(node.node.block.icon(Block.Icon.medium), Styles.nodei); button.visible(() -> node.visible); button.clicked(() -> { if(mobile){ @@ -191,10 +188,10 @@ public class TechTreeDialog extends FloatingDialog{ button.update(() -> { float offset = (Core.graphics.getHeight() % 2) / 2f; button.setPosition(node.x + panX + width / 2f, node.y + panY + height / 2f + offset, Align.center); - button.getStyle().up = Core.scene.skin.getDrawable(!locked(node.node) ? "button-over" : !data.hasItems(node.node.requirements) ? "button-red" : "button"); + button.getStyle().up = !locked(node.node) ? Tex.buttonOver : !data.hasItems(node.node.requirements) ? Tex.buttonRed : Tex.button; ((TextureRegionDrawable)button.getStyle().imageUp) - .setRegion(node.visible ? node.node.block.icon(Icon.medium) : Core.atlas.find("icon-locked")); - button.getImage().setColor(!locked(node.node) ? Color.WHITE : Color.GRAY); + .setRegion(node.visible ? node.node.block.icon(Block.Icon.medium) : Core.atlas.find("icon-locked")); + button.getImage().setColor(!locked(node.node) ? Color.white : Color.gray); }); addChild(button); } @@ -239,6 +236,7 @@ public class TechTreeDialog extends FloatingDialog{ rebuild(); Core.scene.act(); Sounds.unlock.play(); + Events.fire(new ResearchEvent(node.block)); } void rebuild(){ @@ -262,12 +260,12 @@ public class TechTreeDialog extends FloatingDialog{ infoTable.update(() -> infoTable.setPosition(button.getX() + button.getWidth(), button.getY() + button.getHeight(), Align.topLeft)); infoTable.left(); - infoTable.background("button").margin(8f); + infoTable.background(Tex.button).margin(8f); infoTable.table(b -> { b.margin(0).left().defaults().left(); - b.addImageButton("icon-info-small", "clear", iconsizesmall, () -> ui.content.show(node.block)).growY().width(50f); + b.addImageButton(Icon.infoSmall, Styles.cleari, () -> ui.content.show(node.block)).growY().width(50f); b.add().grow(); b.table(desc -> { desc.left().defaults().left(); @@ -280,9 +278,9 @@ public class TechTreeDialog extends FloatingDialog{ t.table(list -> { list.left(); list.addImage(req.item.icon(Item.Icon.medium)).size(8 * 3).padRight(3); - list.add(req.item.localizedName()).color(Color.LIGHT_GRAY); + list.add(req.item.localizedName()).color(Color.lightGray); list.label(() -> " " + Math.min(data.getItem(req.item), req.amount) + " / " + req.amount) - .update(l -> l.setColor(data.has(req.item, req.amount) ? Color.LIGHT_GRAY : Color.SCARLET)); + .update(l -> l.setColor(data.has(req.item, req.amount) ? Color.lightGray : Color.scarlet)); }).fillX().left(); t.row(); } @@ -294,14 +292,14 @@ public class TechTreeDialog extends FloatingDialog{ if(mobile && locked(node)){ b.row(); - b.addImageTextButton("$research", "icon-check-small", "node", iconsizesmall, () -> unlock(node)) + b.addImageTextButton("$research", Icon.checkSmall, Styles.nodet, () -> unlock(node)) .disabled(i -> !data.hasItems(node.requirements)).growX().height(44f).colspan(3); } }); infoTable.row(); if(node.block.description != null){ - infoTable.table(t -> t.margin(3f).left().labelWrap(node.block.description).color(Color.LIGHT_GRAY).growX()).fillX(); + infoTable.table(t -> t.margin(3f).left().labelWrap(node.block.description).color(Color.lightGray).growX()).fillX(); } @@ -320,7 +318,7 @@ public class TechTreeDialog extends FloatingDialog{ for(TechTreeNode child : node.children){ if(!child.visible) continue; - Lines.stroke(UnitScl.dp.scl(4f), locked(node.node) || locked(child.node) ? Pal.gray : Pal.accent); + Lines.stroke(Scl.scl(4f), locked(node.node) || locked(child.node) ? Pal.gray : Pal.accent); Draw.alpha(parentAlpha); Lines.line(node.x + offsetX, node.y + offsetY, child.x + offsetX, child.y + offsetY); } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/TraceDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/TraceDialog.java index 354156e954..6635da8a45 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/TraceDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/TraceDialog.java @@ -3,6 +3,7 @@ package io.anuke.mindustry.ui.dialogs; import io.anuke.arc.Core; import io.anuke.arc.scene.ui.layout.Table; import io.anuke.mindustry.entities.type.Player; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.net.Administration.TraceInfo; public class TraceDialog extends FloatingDialog{ @@ -17,7 +18,7 @@ public class TraceDialog extends FloatingDialog{ public void show(Player player, TraceInfo info){ cont.clear(); - Table table = new Table("clear"); + Table table = new Table(Tex.clear); table.margin(14); table.defaults().pad(1); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/ZoneInfoDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/ZoneInfoDialog.java index 55de763cc2..910f4516af 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/ZoneInfoDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/ZoneInfoDialog.java @@ -10,7 +10,6 @@ import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.Zone.*; import io.anuke.mindustry.world.*; -import io.anuke.mindustry.world.Block.*; import static io.anuke.mindustry.Vars.*; @@ -24,11 +23,6 @@ public class ZoneInfoDialog extends FloatingDialog{ addCloseButton(); } - @Override - protected void drawBackground(float x, float y){ - drawDefaultBackground(x, y); - } - public void show(Zone zone){ setup(zone); show(); @@ -52,7 +46,7 @@ public class ZoneInfoDialog extends FloatingDialog{ iteminfo.row(); } iteminfo.addImage(stack.item.icon(Item.Icon.medium)).size(8 * 3).padRight(1); - iteminfo.add(stack.amount + "").color(Color.LIGHT_GRAY).padRight(5); + iteminfo.add(stack.amount + "").color(Color.lightGray).padRight(5); } }; @@ -60,7 +54,7 @@ public class ZoneInfoDialog extends FloatingDialog{ cont.pane(cont -> { if(zone.locked()){ - cont.addImage("icon-locked"); + cont.addImage(Icon.locked); cont.row(); cont.add("$locked").padBottom(6); cont.row(); @@ -73,9 +67,9 @@ public class ZoneInfoDialog extends FloatingDialog{ r.add("$complete").colspan(2).left(); r.row(); for(ZoneRequirement other : zone.zoneRequirements){ - r.addImage("icon-terrain").padRight(4); - r.add(Core.bundle.format("zone.requirement", other.wave, other.zone.localizedName())).color(Color.LIGHT_GRAY); - r.addImage(other.zone.bestWave() >= other.wave ? "icon-check-small" : "icon-cancel-small", other.zone.bestWave() >= other.wave ? Color.LIGHT_GRAY : Color.SCARLET).padLeft(3); + r.addImage(Icon.terrain).padRight(4); + r.add(Core.bundle.format("zone.requirement", other.wave, other.zone.localizedName())).color(Color.lightGray); + r.addImage(other.zone.bestWave() >= other.wave ? Icon.checkSmall : Icon.cancelSmall, other.zone.bestWave() >= other.wave ? Color.lightGray : Color.scarlet).padLeft(3); r.row(); } }); @@ -88,9 +82,9 @@ public class ZoneInfoDialog extends FloatingDialog{ r.add("$research.list").colspan(2).left(); r.row(); for(Block block : zone.blockRequirements){ - r.addImage(block.icon(Icon.small)).size(8 * 3).padRight(4); - r.add(block.localizedName).color(Color.LIGHT_GRAY); - r.addImage(data.isUnlocked(block) ? "icon-check-small" : "icon-cancel-small", data.isUnlocked(block) ? Color.LIGHT_GRAY : Color.SCARLET).padLeft(3); + r.addImage(block.icon(Block.Icon.small)).size(8 * 3).padRight(4); + r.add(block.localizedName).color(Color.lightGray); + r.addImage(data.isUnlocked(block) ? Icon.checkSmall : Icon.cancelSmall, data.isUnlocked(block) ? Color.lightGray : Color.scarlet).padLeft(3); r.row(); } @@ -101,7 +95,7 @@ public class ZoneInfoDialog extends FloatingDialog{ }else{ cont.add(zone.localizedName()).color(Pal.accent).growX().center(); cont.row(); - cont.addImage("whiteui").color(Pal.accent).height(3).pad(6).growX(); + cont.addImage().color(Pal.accent).height(3).pad(6).growX(); cont.row(); cont.table(desc -> { desc.left().defaults().left().width(Core.graphics.isPortrait() ? 350f : 500f); diff --git a/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java b/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java index 4a8b96707e..fc80e13ac8 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java @@ -22,7 +22,7 @@ import io.anuke.arc.util.*; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.entities.type.Player; import io.anuke.mindustry.game.EventType.*; -import io.anuke.mindustry.gen.Call; +import io.anuke.mindustry.gen.*; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Item.Icon; import io.anuke.mindustry.world.Tile; @@ -40,7 +40,7 @@ public class BlockInventoryFragment extends Fragment{ @Remote(called = Loc.server, targets = Loc.both, forward = true) public static void requestItem(Player player, Tile tile, Item item, int amount){ - if(player == null || tile == null) return; + if(player == null || tile == null || !player.timer.get(Player.timerTransfer, 20) || !tile.interactable(player.getTeam())) return; int removed = tile.block().removeStack(tile, item, amount); @@ -71,6 +71,8 @@ public class BlockInventoryFragment extends Fragment{ } public void hide(){ + if(table == null) return; + table.actions(Actions.scaleTo(0f, 1f, 0.06f, Interpolation.pow3Out), Actions.run(() -> { table.clearChildren(); table.clearListeners(); @@ -86,7 +88,7 @@ public class BlockInventoryFragment extends Fragment{ table.clearChildren(); table.clearActions(); - table.background("inventory"); + table.background(Tex.inventory); table.touchable(Touchable.enabled); table.update(() -> { diff --git a/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java b/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java index ca8aab453a..ab7889594a 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java @@ -1,28 +1,24 @@ package io.anuke.mindustry.ui.fragments; -import io.anuke.arc.Core; -import io.anuke.arc.Input.TextInput; -import io.anuke.arc.collection.Array; -import io.anuke.arc.graphics.Color; +import io.anuke.arc.*; +import io.anuke.arc.Input.*; +import io.anuke.arc.collection.*; +import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.g2d.*; -import io.anuke.arc.math.Mathf; -import io.anuke.arc.scene.Group; -import io.anuke.arc.scene.ui.Label; -import io.anuke.arc.scene.ui.Label.LabelStyle; -import io.anuke.arc.scene.ui.TextField; -import io.anuke.arc.scene.ui.layout.Table; -import io.anuke.arc.scene.ui.layout.UnitScl; -import io.anuke.arc.util.Align; -import io.anuke.arc.util.Time; -import io.anuke.mindustry.Vars; -import io.anuke.mindustry.gen.Call; -import io.anuke.mindustry.input.Binding; -import io.anuke.mindustry.net.Net; +import io.anuke.arc.math.*; +import io.anuke.arc.scene.*; +import io.anuke.arc.scene.ui.*; +import io.anuke.arc.scene.ui.Label.*; +import io.anuke.arc.scene.ui.layout.*; +import io.anuke.arc.util.*; +import io.anuke.mindustry.*; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.input.*; +import io.anuke.mindustry.ui.*; -import static io.anuke.arc.Core.input; -import static io.anuke.arc.Core.scene; -import static io.anuke.mindustry.Vars.maxTextLength; -import static io.anuke.mindustry.Vars.mobile; +import static io.anuke.arc.Core.*; +import static io.anuke.mindustry.Vars.net; +import static io.anuke.mindustry.Vars.*; public class ChatFragment extends Table{ private final static int messagesShown = 10; @@ -33,9 +29,9 @@ public class ChatFragment extends Table{ private Label fieldlabel = new Label(">"); private BitmapFont font; private GlyphLayout layout = new GlyphLayout(); - private float offsetx = UnitScl.dp.scl(4), offsety = UnitScl.dp.scl(4), fontoffsetx = UnitScl.dp.scl(2), chatspace = UnitScl.dp.scl(50); + private float offsetx = Scl.scl(4), offsety = Scl.scl(4), fontoffsetx = Scl.scl(2), chatspace = Scl.scl(50); private Color shadowColor = new Color(0, 0, 0, 0.4f); - private float textspacing = UnitScl.dp.scl(10); + private float textspacing = Scl.scl(10); private Array history = new Array<>(); private int historyPos = 0; private int scrollPos = 0; @@ -50,10 +46,10 @@ public class ChatFragment extends Table{ super(); setFillParent(true); - font = scene.skin.getFont("default"); + font = Fonts.def; visible(() -> { - if(!Net.active() && messages.size > 0){ + if(!net.active() && messages.size > 0){ clearMessages(); if(chatOpen){ @@ -61,12 +57,12 @@ public class ChatFragment extends Table{ } } - return Net.active(); + return net.active(); }); update(() -> { - if(Net.active() && input.keyTap(Binding.chat)){ + if(net.active() && input.keyTap(Binding.chat)){ toggle(); } @@ -103,11 +99,11 @@ public class ChatFragment extends Table{ fieldlabel.getStyle().font = font; fieldlabel.setStyle(fieldlabel.getStyle()); - chatfield = new TextField("", new TextField.TextFieldStyle(scene.skin.get(TextField.TextFieldStyle.class))); + chatfield = new TextField("", new TextField.TextFieldStyle(scene.getStyle(TextField.TextFieldStyle.class))); chatfield.setFilter((field, c) -> field.getText().length() < Vars.maxTextLength); chatfield.getStyle().background = null; - chatfield.getStyle().font = scene.skin.getFont("chat"); - chatfield.getStyle().fontColor = Color.WHITE; + chatfield.getStyle().font = Fonts.chat; + chatfield.getStyle().fontColor = Color.white; chatfield.setStyle(chatfield.getStyle()); bottom().left().marginBottom(offsety).marginLeft(offsetx * 2).add(fieldlabel).padBottom(6f); @@ -123,7 +119,7 @@ public class ChatFragment extends Table{ @Override public void draw(){ float opacity = Core.settings.getInt("chatopacity") / 100f; - float textWidth = Math.min(Core.graphics.getWidth()/1.5f, UnitScl.dp.scl(700f)); + float textWidth = Math.min(Core.graphics.getWidth()/1.5f, Scl.scl(700f)); Draw.color(shadowColor); @@ -144,7 +140,7 @@ public class ChatFragment extends Table{ float theight = offsety + spacing + getMarginBottom(); for(int i = scrollPos; i < messages.size && i < messagesShown + scrollPos && (i < fadetime || chatOpen); i++){ - layout.setText(font, messages.get(i).formattedMessage, Color.WHITE, textWidth, Align.bottomLeft, true); + layout.setText(font, messages.get(i).formattedMessage, Color.white, textWidth, Align.bottomLeft, true); theight += layout.height + textspacing; if(i - scrollPos == 0) theight -= textspacing + 1; @@ -158,7 +154,7 @@ public class ChatFragment extends Table{ font.getCache().setAlphas(opacity); } - Fill.crect(offsetx, theight - layout.height - 2, textWidth + UnitScl.dp.scl(4f), layout.height + textspacing); + Fill.crect(offsetx, theight - layout.height - 2, textWidth + Scl.scl(4f), layout.height + textspacing); Draw.color(shadowColor); Draw.alpha(opacity * shadowColor.a); diff --git a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java index d3cc688ebb..37c48d27a0 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java @@ -13,6 +13,7 @@ import io.anuke.arc.scene.actions.*; import io.anuke.arc.scene.event.*; import io.anuke.arc.scene.style.*; import io.anuke.arc.scene.ui.*; +import io.anuke.arc.scene.ui.ImageButton.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.core.GameState.*; @@ -23,10 +24,10 @@ import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.input.*; -import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Packets.*; import io.anuke.mindustry.type.*; import io.anuke.mindustry.ui.*; +import io.anuke.mindustry.ui.Styles; import io.anuke.mindustry.ui.dialogs.*; import static io.anuke.mindustry.Vars.*; @@ -60,28 +61,28 @@ public class HudFragment extends Fragment{ select.left(); select.defaults().size(dsize).left(); - String style = "clear-trans"; + ImageButtonStyle style = Styles.clearTransi; - select.addImageButton("icon-menu-large", style, iconsize, ui.paused::show); - flip = select.addImageButton("icon-arrow-up", style, iconsize, this::toggleMenus).get(); + select.addImageButton(Icon.menuLarge, style, ui.paused::show); + flip = select.addImageButton(Icon.arrowUp, style, this::toggleMenus).get(); - select.addImageButton("icon-pause", style, iconsize, () -> { - if(Net.active()){ + select.addImageButton(Icon.pause, style, () -> { + if(net.active()){ ui.listfrag.toggle(); }else{ state.set(state.is(State.paused) ? State.playing : State.paused); } }).name("pause").update(i -> { - if(Net.active()){ - i.getStyle().imageUp = Core.scene.skin.getDrawable("icon-players"); + if(net.active()){ + i.getStyle().imageUp = Icon.players; }else{ i.setDisabled(false); - i.getStyle().imageUp = Core.scene.skin.getDrawable(state.is(State.paused) ? "icon-play" : "icon-pause"); + i.getStyle().imageUp = state.is(State.paused) ? Icon.play : Icon.pause; } }).get(); - select.addImageButton("icon-settings", style, iconsize, () -> { - if(Net.active() && mobile){ + select.addImageButton(Icon.settings, style,() -> { + if(net.active() && mobile){ if(ui.chatfrag.chatOpen()){ ui.chatfrag.hide(); }else{ @@ -93,16 +94,16 @@ public class HudFragment extends Fragment{ ui.database.show(); } }).update(i -> { - if(Net.active() && mobile){ - i.getStyle().imageUp = Core.scene.skin.getDrawable("icon-chat"); + if(net.active() && mobile){ + i.getStyle().imageUp = Icon.chat; }else{ - i.getStyle().imageUp = Core.scene.skin.getDrawable("icon-database"); + i.getStyle().imageUp = Icon.database; } }).get(); - select.addImage("whiteui").color(Pal.gray).width(4f).fillY(); + select.addImage().color(Pal.gray).width(4f).fillY(); - float size = UnitScl.dp.scl(dsize); + float size = Scl.scl(dsize); Array children = new Array<>(select.getChildren()); //now, you may be wondering, why is this necessary? the answer is, I don't know, but it fixes layout issues somehow @@ -114,7 +115,7 @@ public class HudFragment extends Fragment{ if(fi < 4){ elem.setSize(size); }else{ - elem.setSize(UnitScl.dp.scl(4f), size); + elem.setSize(Scl.scl(4f), size); } elem.setPosition(fi * size, Core.graphics.getHeight(), Align.topLeft); return true; @@ -125,7 +126,7 @@ public class HudFragment extends Fragment{ } cont.row(); - cont.addImage("whiteui").height(4f).color(Pal.gray).fillX(); + cont.addImage().height(4f).color(Pal.gray).fillX(); cont.row(); } @@ -143,7 +144,7 @@ public class HudFragment extends Fragment{ wavesMain.visible(() -> shown && !state.isEditor()); wavesMain.top().left(); Stack stack = new Stack(); - Button waves = new Button("wave"); + Button waves = new Button(Styles.waveb); Table btable = new Table().margin(0); stack.add(waves); @@ -153,13 +154,13 @@ public class HudFragment extends Fragment{ addPlayButton(btable); wavesMain.add(stack).width(dsize * 4 + 4f); wavesMain.row(); - wavesMain.table("button", t -> t.margin(10f).add(new Bar("boss.health", Pal.health, () -> state.boss() == null ? 0f : state.boss().healthf()).blink(Color.WHITE)) + wavesMain.table(Tex.button, t -> t.margin(10f).add(new Bar("boss.health", Pal.health, () -> state.boss() == null ? 0f : state.boss().healthf()).blink(Color.white)) .grow()).fillX().visible(() -> state.rules.waves && state.boss() != null).height(60f).get(); wavesMain.row(); } { - editorMain.table("button-edge-4", t -> { + editorMain.table(Tex.buttonEdge4, t -> { //t.margin(0f); t.add("$editor.teams").growX().left(); t.row(); @@ -167,7 +168,7 @@ public class HudFragment extends Fragment{ teams.left(); int i = 0; for(Team team : Team.all){ - ImageButton button = teams.addImageButton("white", "clear-toggle-partial", 40f, () -> Call.setPlayerTeamEditor(player, team)) + ImageButton button = teams.addImageButton(Tex.whiteui, Styles.clearTogglePartiali, 40f, () -> Call.setPlayerTeamEditor(player, team)) .size(50f).margin(6f).get(); button.getImageCell().grow(); button.getStyle().imageUpColor = team.color; @@ -182,11 +183,11 @@ public class HudFragment extends Fragment{ if(enableUnitEditing){ t.row(); - t.addImageTextButton("$editor.spawn", "icon-add", iconsize, () -> { + t.addImageTextButton("$editor.spawn", Icon.add, () -> { FloatingDialog dialog = new FloatingDialog("$editor.spawn"); int i = 0; for(UnitType type : content.getBy(ContentType.unit)){ - dialog.cont.addImageButton("white", 48, () -> { + dialog.cont.addImageButton(Tex.whiteui, 48, () -> { Call.spawnUnitEditor(player, type); dialog.hide(); }).get().getStyle().imageUp = new TextureRegionDrawable(type.iconRegion); @@ -201,7 +202,7 @@ public class HudFragment extends Fragment{ float[] position = {0, 0}; t.row(); - t.addImageTextButton("$editor.removeunit", "icon-quit", "toggle", iconsize, () -> {}).fillX().update(b -> { + t.addImageTextButton("$editor.removeunit", Icon.quit, Styles.togglet, () -> {}).fillX().update(b -> { boolean[] found = {false}; if(b.isChecked()){ Element e = Core.scene.hit(Core.input.mouseX(), Core.input.mouseY(), true); @@ -222,7 +223,7 @@ public class HudFragment extends Fragment{ } } - Draw.color(Pal.accent, Color.WHITE, Mathf.absin(Time.time(), 8f, 1f)); + Draw.color(Pal.accent, Color.white, Mathf.absin(Time.time(), 8f, 1f)); Lines.poly(position[0], position[1], 4, size[0] / 2f); Draw.reset(); @@ -238,13 +239,13 @@ public class HudFragment extends Fragment{ //fps display cont.table(info -> { info.top().left().margin(4).visible(() -> Core.settings.getBool("fps")); - info.update(() -> info.setTranslation(state.rules.waves || state.isEditor() ? 0f : -UnitScl.dp.scl(dsize * 4 + 3), 0)); + info.update(() -> info.setTranslation(state.rules.waves || state.isEditor() ? 0f : -Scl.scl(dsize * 4 + 3), 0)); IntFormat fps = new IntFormat("fps"); IntFormat ping = new IntFormat("ping"); - info.label(() -> fps.get(Core.graphics.getFramesPerSecond())).left().style("outline"); + info.label(() -> fps.get(Core.graphics.getFramesPerSecond())).left().style(Styles.outlineLabel); info.row(); - info.label(() -> ping.get(Net.getPing())).visible(Net::client).left().style("outline"); + info.label(() -> ping.get(netClient.getPing())).visible(net::client).left().style(Styles.outlineLabel); }).top().left(); }); @@ -254,15 +255,15 @@ public class HudFragment extends Fragment{ //spawner warning parent.fill(t -> { t.touchable(Touchable.disabled); - t.table("flat", c -> c.add("$nearpoint") - .update(l -> l.setColor(Tmp.c1.set(Color.WHITE).lerp(Color.SCARLET, Mathf.absin(Time.time(), 10f, 1f)))) + t.table(Styles.black, c -> c.add("$nearpoint") + .update(l -> l.setColor(Tmp.c1.set(Color.white).lerp(Color.scarlet, Mathf.absin(Time.time(), 10f, 1f)))) .get().setAlignment(Align.center, Align.center)) .margin(6).update(u -> u.color.a = Mathf.lerpDelta(u.color.a, Mathf.num(spawner.playerNear()), 0.1f)).get().color.a = 0f; }); parent.fill(t -> { t.visible(() -> netServer.isWaitingForPlayers()); - t.table("button", c -> c.add("$waiting.players")); + t.table(Tex.button, c -> c.add("$waiting.players")); }); //'core is under attack' table @@ -308,8 +309,8 @@ public class HudFragment extends Fragment{ return coreAttackOpacity > 0; }); - t.table("button", top -> top.add("$coreattack").pad(2) - .update(label -> label.getColor().set(Color.ORANGE).lerp(Color.SCARLET, Mathf.absin(Time.time(), 2f, 1f)))).touchable(Touchable.disabled); + t.table(Tex.button, top -> top.add("$coreattack").pad(2) + .update(label -> label.getColor().set(Color.orange).lerp(Color.scarlet, Mathf.absin(Time.time(), 2f, 1f)))).touchable(Touchable.disabled); }); //tutorial text @@ -317,14 +318,14 @@ public class HudFragment extends Fragment{ Runnable resize = () -> { t.clearChildren(); t.top().right().visible(() -> state.rules.tutorial); - t.stack(new Button("default"){{ + t.stack(new Button(){{ marginLeft(48f); labelWrap(() -> control.tutorial.stage.text() + (control.tutorial.canNext() ? "\n\n" + Core.bundle.get("tutorial.next") : "")).width(!Core.graphics.isPortrait() ? 400f : 160f).pad(2f); clicked(() -> control.tutorial.nextSentence()); setDisabled(() -> !control.tutorial.canNext()); }}, new Table(f -> { - f.left().addImageButton("icon-arrow-left-small", "empty", iconsizesmall, () -> { + f.left().addImageButton(Icon.arrowLeftSmall, Styles.emptyi, () -> { control.tutorial.prevSentence(); }).width(44f).growY().visible(() -> control.tutorial.canPrev()); })); @@ -337,13 +338,13 @@ public class HudFragment extends Fragment{ //paused table parent.fill(t -> { t.top().visible(() -> state.isPaused()).touchable(Touchable.disabled); - t.table("button-trans", top -> top.add("$paused").pad(5f)); + t.table(Tex.buttonTrans, top -> top.add("$paused").pad(5f)); }); //'saving' indicator parent.fill(t -> { t.bottom().visible(() -> control.saves.isSaving()); - t.add("$saveload").style("outline"); + t.add("$saveload").style(Styles.outlineLabel); }); blockfrag.build(parent); @@ -391,14 +392,14 @@ public class HudFragment extends Fragment{ scheduleToast(() -> { Sounds.message.play(); - Table table = new Table("button"); + Table table = new Table(Tex.button); table.update(() -> { if(state.is(State.menu)){ table.remove(); } }); table.margin(12); - table.addImage("icon-check").size(iconsize).pad(3); + table.addImage(Icon.check).pad(3); table.add(text).wrap().width(280f).get().setAlignment(Align.center, Align.center); table.pack(); @@ -427,7 +428,7 @@ public class HudFragment extends Fragment{ //if there's currently no unlock notification... if(lastUnlockTable == null){ scheduleToast(() -> { - Table table = new Table("button"); + Table table = new Table(Tex.button); table.update(() -> { if(state.is(State.menu)){ table.remove(); @@ -499,7 +500,7 @@ public class HudFragment extends Fragment{ lastUnlockLayout.add(image); }else{ //else, add a specific icon to denote no more space - lastUnlockLayout.addImage("icon-add"); + lastUnlockLayout.addImage(Icon.add); } lastUnlockLayout.pack(); @@ -507,7 +508,7 @@ public class HudFragment extends Fragment{ } public void showLaunch(){ - Image image = new Image("whiteui"); + Image image = new Image(); image.getColor().a = 0f; image.setFillParent(true); image.actions(Actions.fadeIn(40f / 60f)); @@ -519,6 +520,21 @@ public class HudFragment extends Fragment{ Core.scene.add(image); } + public void showLand(){ + Image image = new Image(); + image.getColor().a = 1f; + image.touchable(Touchable.disabled); + image.setFillParent(true); + image.actions(Actions.fadeOut(0.8f), Actions.remove()); + image.update(() -> { + image.toFront(); + if(state.is(State.menu)){ + image.remove(); + } + }); + Core.scene.add(image); + } + private void showLaunchConfirm(){ FloatingDialog dialog = new FloatingDialog("$launch"); dialog.update(() -> { @@ -542,7 +558,7 @@ public class HudFragment extends Fragment{ private boolean inLaunchWave(){ return world.isZone() && world.getZone().metCondition() && - !Net.client() && + !net.client() && state.wave % world.getZone().launchPeriod == 0 && !spawner.isSpawning(); } @@ -552,7 +568,7 @@ public class HudFragment extends Fragment{ private void toggleMenus(){ if(flip != null){ - flip.getStyle().imageUp = Core.scene.skin.getDrawable(shown ? "icon-arrow-down" : "icon-arrow-up"); + flip.getStyle().imageUp = shown ? Icon.arrowDown : Icon.arrowUp; } shown = !shown; @@ -597,7 +613,7 @@ public class HudFragment extends Fragment{ if(inLaunchWave()){ builder.append("[#"); - Tmp.c1.set(Color.WHITE).lerp(state.enemies() > 0 ? Color.WHITE : Color.SCARLET, Mathf.absin(Time.time(), 2f, 1f)).toString(builder); + Tmp.c1.set(Color.white).lerp(state.enemies() > 0 ? Color.white : Color.scarlet, Mathf.absin(Time.time(), 2f, 1f)).toString(builder); builder.append("]"); if(!canLaunch()){ @@ -639,12 +655,12 @@ public class HudFragment extends Fragment{ } private boolean canSkipWave(){ - return state.rules.waves && ((Net.server() || player.isAdmin) || !Net.active()) && state.enemies() == 0 && !spawner.isSpawning() && !state.rules.tutorial; + return state.rules.waves && ((net.server() || player.isAdmin) || !net.active()) && state.enemies() == 0 && !spawner.isSpawning() && !state.rules.tutorial; } private void addPlayButton(Table table){ - table.right().addImageButton("icon-play", "right", 30f, () -> { - if(Net.client() && player.isAdmin){ + table.right().addImageButton(Icon.playSmaller, Styles.righti, 30f, () -> { + if(net.client() && player.isAdmin){ Call.onAdminRequest(player, AdminAction.wave); }else if(inLaunchWave()){ ui.showConfirm("$confirm", "$launch.skip.confirm", () -> !canSkipWave(), () -> state.wavetime = 0f); diff --git a/core/src/io/anuke/mindustry/ui/fragments/LoadingFragment.java b/core/src/io/anuke/mindustry/ui/fragments/LoadingFragment.java index 9eb53bb913..ad29b50afa 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/LoadingFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/LoadingFragment.java @@ -1,5 +1,7 @@ package io.anuke.mindustry.ui.fragments; +import io.anuke.arc.function.*; +import io.anuke.arc.graphics.*; import io.anuke.arc.scene.Group; import io.anuke.arc.scene.actions.*; import io.anuke.arc.scene.event.Touchable; @@ -7,42 +9,57 @@ import io.anuke.arc.scene.ui.Label; import io.anuke.arc.scene.ui.TextButton; import io.anuke.arc.scene.ui.layout.Table; import io.anuke.mindustry.graphics.Pal; +import io.anuke.mindustry.ui.*; public class LoadingFragment extends Fragment{ private Table table; private TextButton button; + private Bar bar; @Override public void build(Group parent){ - parent.fill("loadDim", t -> { + parent.fill(Styles.black8, t -> { t.visible(false); t.touchable(Touchable.enabled); - t.add().height(70f).row(); + t.add().height(133f).row(); - t.addImage("whiteui").growX().height(3f).pad(4f).growX().get().setColor(Pal.accent); + t.addImage().growX().height(3f).pad(4f).growX().get().setColor(Pal.accent); t.row(); t.add("$loading").name("namelabel").pad(10f); t.row(); - t.addImage("whiteui").growX().height(3f).pad(4f).growX().get().setColor(Pal.accent); + t.addImage().growX().height(3f).pad(4f).growX().get().setColor(Pal.accent); t.row(); - button = t.addButton("$cancel", () -> { - }).pad(20).size(250f, 70f).visible(false).get(); + bar = t.add(new Bar()).pad(3).size(500f, 40f).visible(false).get(); + t.row(); + button = t.addButton("$cancel", () -> {}).pad(20).size(250f, 70f).visible(false).get(); table = t; }); } + public void setProgress(FloatProvider progress){ + bar.visible(true); + bar.set(() -> ((int)(progress.get() * 100) + "%"), progress, Pal.accent); + } + public void setButton(Runnable listener){ button.visible(true); button.getListeners().remove(button.getListeners().size - 1); button.clicked(listener); } + public void setText(String text){ + table.