diff --git a/.gitignore b/.gitignore index c93640b15c..8017b41b6f 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ steam_appid.txt /android/assets/mindustry-maps/ /android/assets/mindustry-saves/ /core/assets/gifexport/ +/annotations/src/main/resources/META-INF/services /core/assets/version.properties /core/assets/locales /ios/src/mindustry/gen/ diff --git a/README.md b/README.md index 2f0cab8ff3..088d6576fb 100644 --- a/README.md +++ b/README.md @@ -22,12 +22,14 @@ First, make sure you have [JDK 8](https://adoptopenjdk.net/) installed. Open a t #### Windows _Running:_ `gradlew desktop:run` -_Building:_ `gradlew desktop:dist` +_Building:_ `gradlew desktop:dist` +_Sprite Packing:_ `gradlew tools:pack` #### Linux/Mac OS _Running:_ `./gradlew desktop:run` -_Building:_ `./gradlew desktop:dist` +_Building:_ `./gradlew desktop:dist` +_Sprite Packing:_ `./gradlew tools:pack` #### Server diff --git a/SERVERLIST.md b/SERVERLIST.md new file mode 100644 index 0000000000..58e717fb01 --- /dev/null +++ b/SERVERLIST.md @@ -0,0 +1,26 @@ +### Adding a server to the list + +Mindustry now has a public list of servers that everyone can see and connect to. +This is done by letting clients `GET` a [JSON list of servers](https://github.com/Anuken/Mindustry/blob/master/servers.json) in this repository. + +You may want to add your server to this list. The steps for getting this done are as follows: + +1. **Ensure your server is properly moderated.** For the most part, this applies to survival servers, but PvP servers can be affected as well. +You'll need to either hire some moderators, or make use of (currently non-existent) anti-grief and anti-curse plugins. +*Consider enabling a rate limit:* `config messageRateLimit 2` will make it so that players can only send messages every 2 seconds, for example. +2. **Set an approppriate MOTD, name and description.** This is set with `config `. "Approppriate" means that: + - Your name or description must reflect the type of server you're hosting. + Since new players may be exposed to the server list early on, put in a phrase like "Co-op survival" or "PvP" so players know what they're getting into. Yes, this is also displayed in the server mode info text, but having extra info in the name doesn't hurt. + - Make sure players know where to refer to for server support. It should be fairly clear that the server owner is not me, but you. + - Try to be professional in your text; use common sense. +3. **Get some good maps.** *(optional, but highly recommended)*. Add some maps to your server and set the map rotation to custom-only. You can get maps from the Steam workshop by subscribing and exporting them; using the `#maps` channel on Discord is also an option. +4. **Check your server configuration.** *(optional)* I would recommend adding a message rate limit of 1 second (`config messageRateLimit 1`), and disabling connect/disconnect messages to reduce spam (`config showConnectMessages false`). +5. Finally, **submit a pull request** to add your server's IP to the list. +This should be fairly straightforward: Press the edit button on the [server file](https://github.com/Anuken/Mindustry/blob/master/servers.json), then add a JSON object with a single key, indicating your server address. +For example, if your server address is `google.com`, you would add a comma after the last entry and insert: +```json + { + "address": "google.com" + } +``` +Then, press the *'submit pull request'* button and I'll take a look at your server. If I have any issues with it, I'll let you know in the PR comments. diff --git a/android/src/mindustry/android/AndroidLauncher.java b/android/src/mindustry/android/AndroidLauncher.java index 9ddd1602f6..2070f7c93b 100644 --- a/android/src/mindustry/android/AndroidLauncher.java +++ b/android/src/mindustry/android/AndroidLauncher.java @@ -149,10 +149,22 @@ public class AndroidLauncher extends AndroidApplication{ }}); checkFiles(getIntent()); + //new external folder Fi data = Core.files.absolute(getContext().getExternalFilesDir(null).getAbsolutePath()); + Core.settings.setDataDirectory(data); - //moved to internal storage if there's no file indicating that it moved + //delete old external files due to screwup + if(Core.files.local("files_moved").exists() && !Core.files.local("files_moved_103").exists()){ + for(Fi fi : data.list()){ + fi.deleteDirectory(); + } + + Core.files.local("files_moved").delete(); + Core.files.local("files_moved_103").writeString("files moved again"); + } + + //move to internal storage if there's no file indicating that it moved if(!Core.files.local("files_moved").exists()){ Log.info("Moving files to external storage..."); @@ -160,17 +172,16 @@ public class AndroidLauncher extends AndroidApplication{ //current local storage folder Fi src = Core.files.absolute(Core.files.getLocalStoragePath()); for(Fi fi : src.list()){ - fi.copyTo(data.child(fi.name())); + fi.copyTo(data); } //create marker Core.files.local("files_moved").writeString("files moved to " + data); + Core.files.local("files_moved_103").writeString("files moved again"); Log.info("Files moved."); }catch(Throwable t){ Log.err("Failed to move files!"); t.printStackTrace(); } - }else{ - Core.settings.setDataDirectory(data); } } diff --git a/annotations/build.gradle b/annotations/build.gradle index d894ed0abf..d87bfffb22 100644 --- a/annotations/build.gradle +++ b/annotations/build.gradle @@ -2,5 +2,4 @@ apply plugin: "java" sourceCompatibility = 1.8 sourceSets.main.java.srcDirs = ["src/main/java/"] -sourceSets.main.resources.srcDirs = ["src/main/resources/"] - +sourceSets.main.resources.srcDirs = ["src/main/resources/"] \ No newline at end of file diff --git a/annotations/src/main/java/mindustry/annotations/Annotations.java b/annotations/src/main/java/mindustry/annotations/Annotations.java index 8124930825..0c9ddc7c4e 100644 --- a/annotations/src/main/java/mindustry/annotations/Annotations.java +++ b/annotations/src/main/java/mindustry/annotations/Annotations.java @@ -3,10 +3,87 @@ package mindustry.annotations; import java.lang.annotation.*; public class Annotations{ + //region entity interfaces + + public enum DrawLayer{ + floor, + floorOver, + groundShadows, + groundUnder, + ground, + flyingShadows, + flying, + bullets, + effects, + names, + } + + /** Indicates that a method overrides other methods. */ + @Target({ElementType.METHOD}) + @Retention(RetentionPolicy.SOURCE) + public @interface Replace{ + } + + /** Indicates that a component field is read-only. */ + @Target({ElementType.FIELD, ElementType.METHOD}) + @Retention(RetentionPolicy.SOURCE) + public @interface ReadOnly{ + } + + /** Indicates multiple inheritance on a component type. */ + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.SOURCE) + public @interface Component{ + } + + /** Indicates that a method is implemented by the annotation processor. */ + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.SOURCE) + public @interface InternalImpl{ + } + + /** Indicates priority of a method in an entity. Methods with higher priority are done last. */ + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.SOURCE) + public @interface MethodPriority{ + float value(); + } + + /** Indicates that a component def is present on all entities. */ + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.SOURCE) + public @interface BaseComponent{ + } + + /** Creates a group that only examines entities that have all the components listed. */ + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.SOURCE) + public @interface GroupDef{ + Class[] value(); + boolean spatial() default false; + boolean mapping() default false; + } + + /** Indicates an entity definition. */ + @Retention(RetentionPolicy.SOURCE) + public @interface EntityDef{ + Class[] value(); + boolean isFinal() default true; + boolean pooled() default false; + } + + /** Indicates an internal interface for entity components. */ + @Target(ElementType.TYPE) + @Retention(RetentionPolicy.SOURCE) + public @interface EntityInterface{ + } + + //endregion + //region misc. utility @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) - public @interface StyleDefaults { + public @interface StyleDefaults{ } /** Indicates that a method should always call its super version. */ @@ -16,10 +93,10 @@ public class Annotations{ } - /** Annotation that allows overriding CallSuper annotation. To be used on method that overrides method with CallSuper annotation from parent class.*/ + /** Annotation that allows overriding CallSuper annotation. To be used on method that overrides method with CallSuper annotation from parent class. */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) - public @interface OverrideCallSuper { + public @interface OverrideCallSuper{ } /** Marks a class as serializable. */ @@ -29,6 +106,9 @@ public class Annotations{ } + //endregion + //region struct + /** Marks a class as a special value type struct. Class name must end in 'Struct'. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) @@ -44,6 +124,9 @@ public class Annotations{ int value(); } + //endregion + //region remote + public enum PacketPriority{ /** Gets put in a queue and processed if not connected. */ normal, @@ -138,4 +221,6 @@ public class Annotations{ public @interface ReadClass{ Class value(); } + + //endregion } diff --git a/annotations/src/main/java/mindustry/annotations/BaseProcessor.java b/annotations/src/main/java/mindustry/annotations/BaseProcessor.java new file mode 100644 index 0000000000..f66a5aa302 --- /dev/null +++ b/annotations/src/main/java/mindustry/annotations/BaseProcessor.java @@ -0,0 +1,203 @@ +package mindustry.annotations; + +import arc.files.*; +import arc.struct.Array; +import arc.util.*; +import arc.util.Log.*; +import com.squareup.javapoet.*; +import com.sun.source.util.*; +import mindustry.annotations.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import javax.lang.model.util.*; +import javax.tools.Diagnostic.*; +import javax.tools.*; +import java.io.*; +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; + +@SupportedSourceVersion(SourceVersion.RELEASE_8) +public abstract class BaseProcessor extends AbstractProcessor{ + /** Name of the base package to put all the generated classes. */ + public static final String packageName = "mindustry.gen"; + + public static Types typeu; + public static Elements elementu; + public static Filer filer; + public static Messager messager; + public static Trees trees; + + protected int round; + protected int rounds = 1; + protected RoundEnvironment env; + protected Fi rootDirectory; + + public static String getMethodName(Element element){ + return ((TypeElement)element.getEnclosingElement()).getQualifiedName().toString() + "." + element.getSimpleName(); + } + + public static boolean isPrimitive(String type){ + return type.equals("boolean") || type.equals("byte") || type.equals("short") || type.equals("int") + || type.equals("long") || type.equals("float") || type.equals("double") || type.equals("char"); + } + + public static String getDefault(String value){ + switch(value){ + case "float": + case "double": + case "int": + case "long": + case "short": + case "char": + case "byte": + return "0"; + case "boolean": + return "false"; + default: + return "null"; + } + } + + public static String simpleName(String str){ + return str.contains(".") ? str.substring(str.lastIndexOf('.') + 1) : str; + } + + public static TypeName tname(String name) throws Exception{ + Constructor cons = TypeName.class.getDeclaredConstructor(String.class); + cons.setAccessible(true); + return cons.newInstance(name); + } + + public static TypeName tname(Class c){ + return ClassName.get(c).box(); + } + + public static TypeVariableName getTVN(TypeParameterElement element) { + String name = element.getSimpleName().toString(); + List boundsMirrors = element.getBounds(); + + List boundsTypeNames = new ArrayList<>(); + for (TypeMirror typeMirror : boundsMirrors) { + boundsTypeNames.add(TypeName.get(typeMirror)); + } + + return TypeVariableName.get(name, boundsTypeNames.toArray(new TypeName[0])); + } + + public static void write(TypeSpec.Builder builder) throws Exception{ + write(builder, null); + } + + public static void write(TypeSpec.Builder builder, Array imports) throws Exception{ + JavaFile file = JavaFile.builder(packageName, builder.build()).skipJavaLangImports(true).build(); + + if(imports != null){ + String rawSource = file.toString(); + Array result = new Array<>(); + for (String s : rawSource.split("\n", -1)) { + result.add(s); + if (s.startsWith("package ")) { + result.add(""); + for (String i : imports) { + result.add(i); + } + } + } + + String out = result.toString("\n"); + JavaFileObject object = filer.createSourceFile(file.packageName + "." + file.typeSpec.name, file.typeSpec.originatingElements.toArray(new Element[0])); + OutputStream stream = object.openOutputStream(); + stream.write(out.getBytes()); + stream.close(); + }else{ + file.writeTo(filer); + } + } + + public Array elements(Class type){ + return Array.with(env.getElementsAnnotatedWith(type)).map(Selement::new); + } + + public Array types(Class type){ + return Array.with(env.getElementsAnnotatedWith(type)).select(e -> e instanceof TypeElement) + .map(e -> new Stype((TypeElement)e)); + } + + public Array fields(Class type){ + return Array.with(env.getElementsAnnotatedWith(type)).select(e -> e instanceof VariableElement) + .map(e -> new Svar((VariableElement)e)); + } + + public Array methods(Class type){ + return Array.with(env.getElementsAnnotatedWith(type)).select(e -> e instanceof ExecutableElement) + .map(e -> new Smethod((ExecutableElement)e)); + } + + public static void err(String message){ + messager.printMessage(Kind.ERROR, message); + Log.err("[CODEGEN ERROR] " +message); + } + + public static void err(String message, Element elem){ + messager.printMessage(Kind.ERROR, message, elem); + Log.err("[CODEGEN ERROR] " + message + ": " + elem); + } + + public void err(String message, Selement elem){ + err(message, elem.e); + } + + @Override + public synchronized void init(ProcessingEnvironment env){ + super.init(env); + + trees = Trees.instance(env); + typeu = env.getTypeUtils(); + elementu = env.getElementUtils(); + filer = env.getFiler(); + messager = env.getMessager(); + + Log.setLogLevel(LogLevel.info); + + if(System.getProperty("debug") != null){ + Log.setLogLevel(LogLevel.debug); + } + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv){ + if(round++ >= rounds) return false; //only process 1 round + if(rootDirectory == null){ + try{ + String path = Fi.get(filer.getResource(StandardLocation.CLASS_OUTPUT, "no", "no") + .toUri().toURL().toString().substring(OS.isWindows ? 6 : "file:".length())) + .parent().parent().parent().parent().parent().parent().parent().toString().replace("%20", " "); + rootDirectory = Fi.get(path); + }catch(IOException e){ + throw new RuntimeException(e); + } + } + + this.env = roundEnv; + try{ + process(roundEnv); + }catch(Throwable e){ + e.printStackTrace(); + throw new RuntimeException(e); + } + return true; + } + + @Override + public SourceVersion getSupportedSourceVersion(){ + return SourceVersion.RELEASE_8; + } + + public void process(RoundEnvironment env) throws Exception{ + + } +} diff --git a/annotations/src/main/java/mindustry/annotations/CallSuperAnnotationProcessor.java b/annotations/src/main/java/mindustry/annotations/CallSuperAnnotationProcessor.java deleted file mode 100644 index 01a3fdb0e1..0000000000 --- a/annotations/src/main/java/mindustry/annotations/CallSuperAnnotationProcessor.java +++ /dev/null @@ -1,62 +0,0 @@ -package mindustry.annotations; - -import com.sun.source.util.*; -import com.sun.tools.javac.tree.*; -import com.sun.tools.javac.tree.JCTree.*; -import mindustry.annotations.Annotations.*; - -import javax.annotation.processing.*; -import javax.lang.model.*; -import javax.lang.model.element.*; -import javax.tools.Diagnostic.*; -import java.util.*; - -@SupportedAnnotationTypes({"java.lang.Override"}) -public class CallSuperAnnotationProcessor extends AbstractProcessor{ - private Trees trees; - - @Override - public void init(ProcessingEnvironment pe){ - super.init(pe); - trees = Trees.instance(pe); - } - - public boolean process(Set annotations, RoundEnvironment roundEnv){ - for(Element e : roundEnv.getElementsAnnotatedWith(Override.class)){ - if(e.getAnnotation(OverrideCallSuper.class) != null) return false; - - CodeAnalyzerTreeScanner codeScanner = new CodeAnalyzerTreeScanner(); - codeScanner.setMethodName(e.getSimpleName().toString()); - - TreePath tp = trees.getPath(e.getEnclosingElement()); - codeScanner.scan(tp, trees); - - if(codeScanner.isCallSuperUsed()){ - List list = codeScanner.getMethod().getBody().getStatements(); - - if(!doesCallSuper(list, codeScanner.getMethodName())){ - processingEnv.getMessager().printMessage(Kind.ERROR, "Overriding method '" + codeScanner.getMethodName() + "' must explicitly call super method from its parent class.", e); - } - } - } - - return false; - } - - private boolean doesCallSuper(List list, String methodName){ - for(Object object : list){ - if(object instanceof JCTree.JCExpressionStatement){ - JCTree.JCExpressionStatement expr = (JCExpressionStatement)object; - String exprString = expr.toString(); - if(exprString.startsWith("super." + methodName) && exprString.endsWith(");")) return true; - } - } - - return false; - } - - @Override - public SourceVersion getSupportedSourceVersion(){ - return SourceVersion.RELEASE_8; - } -} diff --git a/annotations/src/main/java/mindustry/annotations/CodeAnalyzerTreeScanner.java b/annotations/src/main/java/mindustry/annotations/CodeAnalyzerTreeScanner.java deleted file mode 100644 index 13059b38b8..0000000000 --- a/annotations/src/main/java/mindustry/annotations/CodeAnalyzerTreeScanner.java +++ /dev/null @@ -1,110 +0,0 @@ -package mindustry.annotations; - -import com.sun.source.tree.*; -import com.sun.source.util.TreePathScanner; -import com.sun.source.util.Trees; -import com.sun.tools.javac.code.Scope; -import com.sun.tools.javac.code.Symbol; -import com.sun.tools.javac.code.Symbol.MethodSymbol; -import com.sun.tools.javac.code.Type.ClassType; -import com.sun.tools.javac.tree.JCTree.JCIdent; -import com.sun.tools.javac.tree.JCTree.JCTypeApply; -import mindustry.annotations.Annotations.CallSuper; - -import java.lang.annotation.Annotation; - -class CodeAnalyzerTreeScanner extends TreePathScanner { - private String methodName; - private MethodTree method; - private boolean callSuperUsed; - - @Override - public Object visitClass (ClassTree classTree, Trees trees) { - Tree extendTree = classTree.getExtendsClause(); - - if (extendTree instanceof JCTypeApply) { //generic classes case - JCTypeApply generic = (JCTypeApply) extendTree; - extendTree = generic.clazz; - } - - if (extendTree instanceof JCIdent) { - JCIdent tree = (JCIdent) extendTree; - Scope members = tree.sym.members(); - - if (checkScope(members)) - return super.visitClass(classTree, trees); - - if (checkSuperTypes((ClassType) tree.type)) - return super.visitClass(classTree, trees); - - } - callSuperUsed = false; - - return super.visitClass(classTree, trees); - } - - public boolean checkSuperTypes (ClassType type) { - if (type.supertype_field != null && type.supertype_field.tsym != null) { - if (checkScope(type.supertype_field.tsym.members())) - return true; - else - return checkSuperTypes((ClassType) type.supertype_field); - } - - return false; - } - - @SuppressWarnings("unchecked") - public boolean checkScope (Scope members) { - 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; - - if (ms.getSimpleName().toString().equals(methodName)) { - Annotation annotation = ms.getAnnotation(CallSuper.class); - if (annotation != null) { - callSuperUsed = true; - return true; - } - } - } - } - - return false; - } - - @Override - public Object visitMethod (MethodTree methodTree, Trees trees) { - if (methodTree.getName().toString().equals(methodName)) - method = methodTree; - - return super.visitMethod(methodTree, trees); - } - - public void setMethodName (String methodName) { - this.methodName = methodName; - } - - public String getMethodName () { - return methodName; - } - - public MethodTree getMethod () { - return method; - } - - public boolean isCallSuperUsed () { - return callSuperUsed; - } -} \ No newline at end of file diff --git a/annotations/src/main/java/mindustry/annotations/RemoteMethodAnnotationProcessor.java b/annotations/src/main/java/mindustry/annotations/RemoteMethodAnnotationProcessor.java deleted file mode 100644 index 2da9ddb35c..0000000000 --- a/annotations/src/main/java/mindustry/annotations/RemoteMethodAnnotationProcessor.java +++ /dev/null @@ -1,154 +0,0 @@ -package mindustry.annotations; - -import com.squareup.javapoet.*; -import mindustry.annotations.Annotations.Loc; -import mindustry.annotations.Annotations.Remote; -import mindustry.annotations.IOFinder.ClassSerializer; - -import javax.annotation.processing.*; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.*; -import javax.tools.Diagnostic.Kind; -import java.util.*; -import java.util.stream.Collectors; - - -/** The annotation processor for generating remote method call code. */ -@SupportedSourceVersion(SourceVersion.RELEASE_8) -@SupportedAnnotationTypes({ -"mindustry.annotations.Annotations.Remote", -"mindustry.annotations.Annotations.WriteClass", -"mindustry.annotations.Annotations.ReadClass", -}) -public class RemoteMethodAnnotationProcessor extends AbstractProcessor{ - /** Maximum size of each event packet. */ - public static final int maxPacketSize = 4096; - /** Warning on top of each autogenerated file. */ - public static final String autogenWarning = "Autogenerated file. Do not modify!\n"; - /** Name of the base package to put all the generated classes. */ - private static final String packageName = "mindustry.gen"; - - /** Name of class that handles reading and invoking packets on the server. */ - private static final String readServerName = "RemoteReadServer"; - /** Name of class that handles reading and invoking packets on the client. */ - private static final String readClientName = "RemoteReadClient"; - /** Simple class name of generated class name. */ - private static final String callLocation = "Call"; - - /** Processing round number. */ - private int round; - - //class serializers - private HashMap serializers; - //all elements with the Remote annotation - private Set elements; - //map of all classes to generate by name - private HashMap classMap; - //list of all method entries - private ArrayList methods; - //list of all method entries - private ArrayList classes; - - @Override - public synchronized void init(ProcessingEnvironment processingEnv){ - super.init(processingEnv); - //put all relevant utils into utils class - Utils.typeUtils = processingEnv.getTypeUtils(); - Utils.elementUtils = processingEnv.getElementUtils(); - Utils.filer = processingEnv.getFiler(); - Utils.messager = processingEnv.getMessager(); - } - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv){ - if(round > 1) return false; //only process 2 rounds - - round++; - - try{ - - //round 1: find all annotations, generate *writers* - if(round == 1){ - //get serializers - serializers = new IOFinder().findSerializers(roundEnv); - //last method ID used - int lastMethodID = 0; - //find all elements with the Remote annotation - elements = roundEnv.getElementsAnnotatedWith(Remote.class); - //map of all classes to generate by name - classMap = new HashMap<>(); - //list of all method entries - methods = new ArrayList<>(); - //list of all method entries - classes = new ArrayList<>(); - - List orderedElements = new ArrayList<>(elements); - orderedElements.sort(Comparator.comparing(Object::toString)); - - //create methods - for(Element element : orderedElements){ - Remote annotation = element.getAnnotation(Remote.class); - - //check for static - if(!element.getModifiers().contains(Modifier.STATIC) || !element.getModifiers().contains(Modifier.PUBLIC)){ - Utils.messager.printMessage(Kind.ERROR, "All @Remote methods must be public and static: ", element); - } - - //can't generate none methods - if(annotation.targets() == Loc.none){ - Utils.messager.printMessage(Kind.ERROR, "A @Remote method's targets() cannot be equal to 'none':", element); - } - - //get and create class entry if needed - if(!classMap.containsKey(callLocation)){ - ClassEntry clas = new ClassEntry(callLocation); - classMap.put(callLocation, clas); - classes.add(clas); - } - - ClassEntry entry = classMap.get(callLocation); - - //create and add entry - MethodEntry method = new MethodEntry(entry.name, Utils.getMethodName(element), annotation.targets(), annotation.variants(), - annotation.called(), annotation.unreliable(), annotation.forward(), lastMethodID++, (ExecutableElement)element, annotation.priority()); - - entry.methods.add(method); - methods.add(method); - } - - //create read/write generators - RemoteWriteGenerator writegen = new RemoteWriteGenerator(serializers); - - //generate the methods to invoke (write) - writegen.generateFor(classes, packageName); - - return true; - }else if(round == 2){ //round 2: generate all *readers* - RemoteReadGenerator readgen = new RemoteReadGenerator(serializers); - - //generate server readers - readgen.generateFor(methods.stream().filter(method -> method.where.isClient).collect(Collectors.toList()), readServerName, packageName, true); - //generate client readers - readgen.generateFor(methods.stream().filter(method -> method.where.isServer).collect(Collectors.toList()), readClientName, packageName, false); - - //create class for storing unique method hash - TypeSpec.Builder hashBuilder = TypeSpec.classBuilder("MethodHash").addModifiers(Modifier.PUBLIC); - hashBuilder.addJavadoc(autogenWarning); - hashBuilder.addField(FieldSpec.builder(int.class, "HASH", Modifier.STATIC, Modifier.PUBLIC, Modifier.FINAL) - .initializer("$1L", Objects.hash(methods)).build()); - - //build and write resulting hash class - TypeSpec spec = hashBuilder.build(); - JavaFile.builder(packageName, spec).build().writeTo(Utils.filer); - - return true; - } - - }catch(Exception e){ - e.printStackTrace(); - throw new RuntimeException(e); - } - - return false; - } -} diff --git a/annotations/src/main/java/mindustry/annotations/SerializeAnnotationProcessor.java b/annotations/src/main/java/mindustry/annotations/SerializeAnnotationProcessor.java deleted file mode 100644 index 117c421176..0000000000 --- a/annotations/src/main/java/mindustry/annotations/SerializeAnnotationProcessor.java +++ /dev/null @@ -1,131 +0,0 @@ -package mindustry.annotations; - -import com.squareup.javapoet.*; -import mindustry.annotations.Annotations.*; - -import javax.annotation.processing.*; -import javax.lang.model.*; -import javax.lang.model.element.Modifier; -import javax.lang.model.element.*; -import javax.lang.model.util.*; -import javax.tools.Diagnostic.*; -import java.io.*; -import java.lang.reflect.*; -import java.util.*; -import java.util.zip.*; - -@SupportedSourceVersion(SourceVersion.RELEASE_8) -@SupportedAnnotationTypes("mindustry.annotations.Annotations.Serialize") -public class SerializeAnnotationProcessor extends AbstractProcessor{ - /** Target class name. */ - private static final String className = "Serialization"; - /** Name of the base package to put all the generated classes. */ - private static final String packageName = "mindustry.gen"; - private static final String data = "eJztV0tvGzcQvvfQ3zDRIeDCKhsbQVDUsgP5UViH2IHl9BIEBsUdSYxX3C3Jlawm+XH9Z53hUg/bkuOmOfRQwfDuDme++ebBWe6PfwU3/wTwUU2VLJQdSYfDAnWQvxkschjCAUyMzWtPetJikF2nzzG8deXU5OjkW6VvMPTRGVWYP0mgC+W9HGE4Qbp1mEcg0Zo5E9C1sn2AofQYulqj92ZQoAiuxqVc2Loo2iCU03JYWy2PS+v3OndJNF7bDW1rSnk0D3hUD4foDjNRtWGQwU+HQIGZoajAWB+U1VgOYROOZx+Wgm4eMzJ7ghpoyo14Cl5FsQ2I4PsPcE2/XXpssk7kOMw6mEJe9KXxXZu70uTM4Jjz2Hl9CJ79xCc5LN25mqBoqUZPVosy9DEEY0eebnTtMKZ5iaDddgRd2oA2MGO+XqIvi2mq0xJAqQ0ARHzA8dncywWar91QaZwanMkUS7eqCqNVMKW9x+qRuO6wug3R8GGLvsEwLnMYMZBS6z3XrIgWidYhLgYfyQ50IyKrkZbGTssbjHU4Lh1KVVWbvaUNEf8fUFXYX+rt7vnJ5UXv5Lp3Et30g6NagDK55RZpHrNoyUaxwx+PyA+XLtZCaYBabSpoOzlptttX0uM8oen7aJsqnhLkkixmyPlFjlLe1kL0a/ER6YVis4UXKO2YCbYyNkCBnBQv6ToKY5Gt9kauAveZxVkjYc2fYe8DT4bSCTY2tP5iny4dxuGbnQPY4+3Cxu9N1GdODJAJcTxWTmmaOzI3IxOEl5ok3SBM1obdVxl0OvAyA9iB7Zq0uNtoM9cvy9gpvLoIiXAjW+1mnwZi7Ht5pDy+enlc8k5Fq+kqmG8EpBnQIEn8o1aFp25a/C66B60sgzB25Sx6uaxtMBM8vdVYMbBoHakc3r3rnchYvjhdiBGDM1csPD4cMr3Sc8ZSGHVtuJ+X/e8Xk2TZcKLFOtR2rVYizM8EdDqpwlxkDJZKeCcnUfYLl4+f2MFEhbG8pE0uMhqXt4Gntk/hM3Ti8k0JTSgM8zCWqg7LKPiyWcurKYr1PDaYi0x+Wi08gVaOkdYT85paa+Enbubo4NTWE3QRvtO87eg1Qy/gWeluerQd47w9BCRSsHWdfd6XebGcGptMoKw58Dhe4IwrXJYFKkspEKnYfImdRB0R7+GAasezjRIXamdhSP2M+1/rjv7cB5xI5Zya67KaN2BteNFOFvE2CtPUYObJxbN/1Sxb9hw8f/7dgbsMnKoMcAbjlIezWAcecJRxkmHcGacFTmg48xrLuYBnyuUzerl185y8UPkW6YbPn+HZWFJhtmlmMSKUY+XfUC8m8NgBG52uDeXrVFnYhv3Py3u9sb7X9wu8eMUE9x1GArUoAW0rNyVw42r3WwfwanDQHx1+9FhcMYii4y6E/6fvf3T6UiaZLA3BtXO9Zvvf0Xn2MahNEfmv1unr42peYe9Cxk+chD6gU5qcNla8/GQbSwfhJyvXvslmpC2oxOXAUIe9TgegXfgVXizXOSxN4RSlW9nEnK4eGzsGolO9pw+6xXC6d/pa0yDBzs7db6ZHGEczPgSbO+88qBpVMYjSbH/Trgn0vUM8+oE+O67otMbt8uWHvwGqGwCj"; - - private int round; - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv){ - if(round++ != 0) return false; //only process 1 round - - try{ - Set elements = ElementFilter.typesIn(roundEnv.getElementsAnnotatedWith(Serialize.class)); - - TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC); - classBuilder.addStaticBlock(CodeBlock.of(new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(data)))).readUTF())); - classBuilder.addAnnotation(AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "\"unchecked\"").build()); - classBuilder.addJavadoc(RemoteMethodAnnotationProcessor.autogenWarning); - - MethodSpec.Builder method = MethodSpec.methodBuilder("init").addModifiers(Modifier.PUBLIC, Modifier.STATIC); - - for(TypeElement elem : elements){ - TypeName type = TypeName.get(elem.asType()); - String simpleTypeName = type.toString().substring(type.toString().lastIndexOf('.') + 1); - - TypeSpec.Builder serializer = TypeSpec.anonymousClassBuilder("") - .addSuperinterface(ParameterizedTypeName.get( - ClassName.bestGuess("arc.Settings.TypeSerializer"), type)); - - MethodSpec.Builder writeMethod = MethodSpec.methodBuilder("write") - .returns(void.class) - .addParameter(DataOutput.class, "stream") - .addParameter(type, "object") - .addException(IOException.class) - .addModifiers(Modifier.PUBLIC); - - MethodSpec.Builder readMethod = MethodSpec.methodBuilder("read") - .returns(type) - .addParameter(DataInput.class, "stream") - .addException(IOException.class) - .addModifiers(Modifier.PUBLIC); - - readMethod.addStatement("$L object = new $L()", type, type); - - List fields = ElementFilter.fieldsIn(Utils.elementUtils.getAllMembers(elem)); - for(VariableElement field : fields){ - if(field.getModifiers().contains(Modifier.STATIC) || field.getModifiers().contains(Modifier.TRANSIENT) || field.getModifiers().contains(Modifier.PRIVATE)) - continue; - - String name = field.getSimpleName().toString(); - String typeName = Utils.typeUtils.erasure(field.asType()).toString().replace('$', '.'); - String capName = Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1); - - if(field.asType().getKind().isPrimitive()){ - writeMethod.addStatement("stream.write" + capName + "(object." + name + ")"); - readMethod.addStatement("object." + name + "= stream.read" + capName + "()"); - }else{ - writeMethod.addStatement("arc.Core.settings.getSerializer(" + typeName + ".class).write(stream, object." + name + ")"); - readMethod.addStatement("object." + name + " = (" + typeName + ")arc.Core.settings.getSerializer(" + typeName + ".class).read(stream)"); - } - } - - readMethod.addStatement("return object"); - - serializer.addMethod(writeMethod.build()); - serializer.addMethod(readMethod.build()); - - method.addStatement("arc.Core.settings.setSerializer($N, $L)", Utils.elementUtils.getBinaryName(elem).toString().replace('$', '.') + ".class", serializer.build()); - - name(writeMethod, "write" + simpleTypeName); - name(readMethod, "read" + simpleTypeName); - - writeMethod.addModifiers(Modifier.STATIC); - readMethod.addModifiers(Modifier.STATIC); - - classBuilder.addMethod(writeMethod.build()); - classBuilder.addMethod(readMethod.build()); - } - - classBuilder.addMethod(method.build()); - - //write result - JavaFile.builder(packageName, classBuilder.build()).build().writeTo(Utils.filer); - - return true; - }catch(Exception e){ - e.printStackTrace(); - throw new RuntimeException(e); - } - } - - @Override - public synchronized void init(ProcessingEnvironment processingEnv){ - super.init(processingEnv); - //put all relevant utils into utils class - Utils.typeUtils = processingEnv.getTypeUtils(); - Utils.elementUtils = processingEnv.getElementUtils(); - Utils.filer = processingEnv.getFiler(); - Utils.messager = processingEnv.getMessager(); - } - - static void name(MethodSpec.Builder builder, String name){ - try{ - Field field = builder.getClass().getDeclaredField("name"); - field.setAccessible(true); - field.set(builder, name); - }catch(Exception e){ - throw new RuntimeException(e); - } - } -} diff --git a/annotations/src/main/java/mindustry/annotations/StructAnnotationProcessor.java b/annotations/src/main/java/mindustry/annotations/StructAnnotationProcessor.java deleted file mode 100644 index 632e14a91a..0000000000 --- a/annotations/src/main/java/mindustry/annotations/StructAnnotationProcessor.java +++ /dev/null @@ -1,226 +0,0 @@ -package mindustry.annotations; - -import com.squareup.javapoet.*; -import mindustry.annotations.Annotations.Struct; -import mindustry.annotations.Annotations.StructField; - -import javax.annotation.processing.*; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.*; -import javax.lang.model.type.TypeKind; -import javax.lang.model.util.ElementFilter; -import javax.tools.Diagnostic.Kind; -import java.util.List; -import java.util.Set; - -/** - * Generates ""value types"" classes that are packed into integer primitives of the most aproppriate size. - * It would be nice if Java didn't make crazy hacks like this necessary. - */ -@SupportedSourceVersion(SourceVersion.RELEASE_8) -@SupportedAnnotationTypes({ -"mindustry.annotations.Annotations.Struct" -}) -public class StructAnnotationProcessor extends AbstractProcessor{ - /** Name of the base package to put all the generated classes. */ - private static final String packageName = "mindustry.gen"; - private int round; - - @Override - public synchronized void init(ProcessingEnvironment processingEnv){ - super.init(processingEnv); - //put all relevant utils into utils class - Utils.typeUtils = processingEnv.getTypeUtils(); - Utils.elementUtils = processingEnv.getElementUtils(); - Utils.filer = processingEnv.getFiler(); - Utils.messager = processingEnv.getMessager(); - } - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv){ - if(round++ != 0) return false; //only process 1 round - - try{ - Set elements = ElementFilter.typesIn(roundEnv.getElementsAnnotatedWith(Struct.class)); - - for(TypeElement elem : elements){ - - if(!elem.getSimpleName().toString().endsWith("Struct")){ - Utils.messager.printMessage(Kind.ERROR, "All classes annotated with @Struct must have their class names end in 'Struct'.", elem); - continue; - } - - String structName = elem.getSimpleName().toString().substring(0, elem.getSimpleName().toString().length() - "Struct".length()); - String structParam = structName.toLowerCase(); - - TypeSpec.Builder classBuilder = TypeSpec.classBuilder(structName) - .addModifiers(Modifier.FINAL, Modifier.PUBLIC); - - try{ - List variables = ElementFilter.fieldsIn(elem.getEnclosedElements()); - int structSize = variables.stream().mapToInt(StructAnnotationProcessor::varSize).sum(); - int structTotalSize = (structSize <= 8 ? 8 : structSize <= 16 ? 16 : structSize <= 32 ? 32 : 64); - - if(variables.size() == 0){ - Utils.messager.printMessage(Kind.ERROR, "making a struct with no fields is utterly pointles.", elem); - continue; - } - - //obtain type which will be stored - Class structType = typeForSize(structSize); - - //[constructor] get(fields...) : structType - MethodSpec.Builder constructor = MethodSpec.methodBuilder("get") - .addModifiers(Modifier.STATIC, Modifier.PUBLIC) - .returns(structType); - - StringBuilder cons = new StringBuilder(); - StringBuilder doc = new StringBuilder(); - doc.append("Bits used: ").append(structSize).append(" / ").append(structTotalSize).append("\n"); - - int offset = 0; - for(VariableElement var : variables){ - int size = varSize(var); - TypeName varType = TypeName.get(var.asType()); - String varName = var.getSimpleName().toString(); - - //add val param to constructor - constructor.addParameter(varType, varName); - - //[get] field(structType) : fieldType - MethodSpec.Builder getter = MethodSpec.methodBuilder(var.getSimpleName().toString()) - .addModifiers(Modifier.STATIC, Modifier.PUBLIC) - .returns(varType) - .addParameter(structType, structParam); - //[set] field(structType, fieldType) : structType - MethodSpec.Builder setter = MethodSpec.methodBuilder(var.getSimpleName().toString()) - .addModifiers(Modifier.STATIC, Modifier.PUBLIC) - .returns(structType) - .addParameter(structType, structParam).addParameter(varType, "value"); - - //[getter] - if(varType == TypeName.BOOLEAN){ - //bools: single bit, is simplified - getter.addStatement("return ($L & (1L << $L)) != 0", structParam, offset); - }else if(varType == TypeName.FLOAT){ - //floats: need conversion - getter.addStatement("return Float.intBitsToFloat((int)(($L >>> $L) & $L))", structParam, offset, bitString(size, structTotalSize)); - }else{ - //bytes, shorts, chars, ints - getter.addStatement("return ($T)(($L >>> $L) & $L)", varType, structParam, offset, bitString(size, structTotalSize)); - } - - //[setter] + [constructor building] - if(varType == TypeName.BOOLEAN){ - cons.append(" | (").append(varName).append(" ? ").append("1L << ").append(offset).append("L : 0)"); - - //bools: single bit, needs special case to clear things - setter.beginControlFlow("if(value)"); - setter.addStatement("return ($T)(($L & ~(1L << $LL)))", structType, structParam, offset); - setter.nextControlFlow("else"); - setter.addStatement("return ($T)(($L & ~(1L << $LL)) | (1L << $LL))", structType, structParam, offset, offset); - setter.endControlFlow(); - }else if(varType == TypeName.FLOAT){ - cons.append(" | (").append("(").append(structType).append(")").append("Float.floatToIntBits(").append(varName).append(") << ").append(offset).append("L)"); - - //floats: need conversion - setter.addStatement("return ($T)(($L & $L) | (($T)Float.floatToIntBits(value) << $LL))", structType, structParam, bitString(offset, size, structTotalSize), structType, offset); - }else{ - cons.append(" | (((").append(structType).append(")").append(varName).append(" << ").append(offset).append("L)").append(" & ").append(bitString(offset, size, structTotalSize)).append(")"); - - //bytes, shorts, chars, ints - setter.addStatement("return ($T)(($L & $L) | (($T)value << $LL))", structType, structParam, bitString(offset, size, structTotalSize), structType, offset); - } - - doc.append("
").append(varName).append(" [").append(offset).append("..").append(size + offset).append("]\n"); - - //add finished methods - classBuilder.addMethod(getter.build()); - classBuilder.addMethod(setter.build()); - - offset += size; - } - - classBuilder.addJavadoc(doc.toString()); - - //add constructor final statement + add to class and build - constructor.addStatement("return ($T)($L)", structType, cons.toString().substring(3)); - classBuilder.addMethod(constructor.build()); - - JavaFile.builder(packageName, classBuilder.build()).build().writeTo(Utils.filer); - }catch(IllegalArgumentException e){ - e.printStackTrace(); - Utils.messager.printMessage(Kind.ERROR, e.getMessage(), elem); - } - } - - return true; - }catch(Exception e){ - e.printStackTrace(); - throw new RuntimeException(e); - } - } - - static String bitString(int offset, int size, int totalSize){ - StringBuilder builder = new StringBuilder(); - for(int i = 0; i < offset; i++) builder.append('0'); - for(int i = 0; i < size; i++) builder.append('1'); - for(int i = 0; i < totalSize - size - offset; i++) builder.append('0'); - return "0b" + builder.reverse().toString() + "L"; - } - - static String bitString(int size, int totalSize){ - StringBuilder builder = new StringBuilder(); - for(int i = 0; i < size; i++) builder.append('1'); - for(int i = 0; i < totalSize - size; i++) builder.append('0'); - return "0b" + builder.reverse().toString() + "L"; - } - - static int varSize(VariableElement var) throws IllegalArgumentException{ - if(!var.asType().getKind().isPrimitive()){ - throw new IllegalArgumentException("All struct fields must be primitives: " + var); - } - - StructField an = var.getAnnotation(StructField.class); - if(var.asType().getKind() == TypeKind.BOOLEAN && an != null && an.value() != 1){ - throw new IllegalArgumentException("Booleans can only be one bit long... why would you do this?"); - } - - if(var.asType().getKind() == TypeKind.FLOAT && an != null && an.value() != 32){ - throw new IllegalArgumentException("Float size can't be changed. Very sad."); - } - - return an == null ? typeSize(var.asType().getKind()) : an.value(); - } - - static Class typeForSize(int size) throws IllegalArgumentException{ - if(size <= 8){ - return byte.class; - }else if(size <= 16){ - return short.class; - }else if(size <= 32){ - return int.class; - }else if(size <= 64){ - return long.class; - } - throw new IllegalArgumentException("Too many fields, must fit in 64 bits. Curent size: " + size); - } - - /** returns a type's element size in bits. */ - static int typeSize(TypeKind kind) throws IllegalArgumentException{ - switch(kind){ - case BOOLEAN: - return 1; - case BYTE: - return 8; - case SHORT: - return 16; - case FLOAT: - case CHAR: - case INT: - return 32; - default: - throw new IllegalArgumentException("Invalid type kind: " + kind + ". Note that doubles and longs are not supported."); - } - } -} diff --git a/annotations/src/main/java/mindustry/annotations/Utils.java b/annotations/src/main/java/mindustry/annotations/Utils.java deleted file mode 100644 index 773d6561d2..0000000000 --- a/annotations/src/main/java/mindustry/annotations/Utils.java +++ /dev/null @@ -1,24 +0,0 @@ -package mindustry.annotations; - -import javax.annotation.processing.Filer; -import javax.annotation.processing.Messager; -import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; -import javax.lang.model.util.Elements; -import javax.lang.model.util.Types; - -public class Utils{ - public static Types typeUtils; - public static Elements elementUtils; - public static Filer filer; - public static Messager messager; - - public static String getMethodName(Element element){ - return ((TypeElement)element.getEnclosingElement()).getQualifiedName().toString() + "." + element.getSimpleName(); - } - - public static boolean isPrimitive(String type){ - return type.equals("boolean") || type.equals("byte") || type.equals("short") || type.equals("int") - || type.equals("long") || type.equals("float") || type.equals("double") || type.equals("char"); - } -} diff --git a/annotations/src/main/java/mindustry/annotations/AssetsAnnotationProcessor.java b/annotations/src/main/java/mindustry/annotations/impl/AssetsProcess.java similarity index 72% rename from annotations/src/main/java/mindustry/annotations/AssetsAnnotationProcessor.java rename to annotations/src/main/java/mindustry/annotations/impl/AssetsProcess.java index 0a1c0be2e9..2ace8d96b9 100644 --- a/annotations/src/main/java/mindustry/annotations/AssetsAnnotationProcessor.java +++ b/annotations/src/main/java/mindustry/annotations/impl/AssetsProcess.java @@ -1,4 +1,4 @@ -package mindustry.annotations; +package mindustry.annotations.impl; import arc.files.*; import arc.scene.style.*; @@ -6,51 +6,21 @@ import arc.struct.*; import arc.util.serialization.*; import com.squareup.javapoet.*; import mindustry.annotations.Annotations.*; +import mindustry.annotations.*; import javax.annotation.processing.*; import javax.lang.model.*; import javax.lang.model.element.*; -import javax.tools.Diagnostic.*; -import javax.tools.*; import java.util.*; -@SupportedSourceVersion(SourceVersion.RELEASE_8) @SupportedAnnotationTypes("mindustry.annotations.Annotations.StyleDefaults") -public class AssetsAnnotationProcessor extends AbstractProcessor{ - /** Name of the base package to put all the generated classes. */ - private static final String packageName = "mindustry.gen"; - private String path; - private int round; +public class AssetsProcess extends BaseProcessor{ @Override - public synchronized void init(ProcessingEnvironment processingEnv){ - super.init(processingEnv); - //put all relevant utils into utils class - Utils.typeUtils = processingEnv.getTypeUtils(); - Utils.elementUtils = processingEnv.getElementUtils(); - Utils.filer = processingEnv.getFiler(); - Utils.messager = processingEnv.getMessager(); - } - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv){ - if(round++ != 0) return false; //only process 1 round - - try{ - path = Fi.get(Utils.filer.createResource(StandardLocation.CLASS_OUTPUT, "no", "no") - .toUri().toURL().toString().substring(System.getProperty("os.name").contains("Windows") ? 6 : "file:".length())) - .parent().parent().parent().parent().parent().parent().toString(); - path = path.replace("%20", " "); - - processSounds("Sounds", path + "/assets/sounds", "arc.audio.Sound"); - processSounds("Musics", path + "/assets/music", "arc.audio.Music"); - processUI(roundEnv.getElementsAnnotatedWith(StyleDefaults.class)); - - return true; - }catch(Exception e){ - e.printStackTrace(); - throw new RuntimeException(e); - } + public void process(RoundEnvironment env) throws Exception{ + processSounds("Sounds", rootDirectory + "/core/assets/sounds", "arc.audio.Sound"); + processSounds("Musics", rootDirectory + "/core/assets/music", "arc.audio.Music"); + processUI(env.getElementsAnnotatedWith(StyleDefaults.class)); } void processUI(Set elements) throws Exception{ @@ -60,8 +30,8 @@ public class AssetsAnnotationProcessor extends AbstractProcessor{ 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"; - Jval icons = Jval.read(Fi.get(path + "/assets-raw/fontgen/config.json").readString()); + String resources = rootDirectory + "/core/assets-raw/sprites/ui"; + Jval icons = Jval.read(Fi.get(rootDirectory + "/core/assets-raw/fontgen/config.json").readString()); ictype.addField(FieldSpec.builder(ParameterizedTypeName.get(ObjectMap.class, String.class, TextureRegionDrawable.class), "icons", Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).initializer("new ObjectMap<>()").build()); @@ -71,17 +41,18 @@ public class AssetsAnnotationProcessor extends AbstractProcessor{ int code = val.getInt("code", 0); ichtype.addField(FieldSpec.builder(char.class, name, Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL).initializer("(char)" + code).build()); - ictype.addField(TextureRegionDrawable.class, name + "Sm", Modifier.PUBLIC, Modifier.STATIC); - icload.addStatement(name + "Sm = mindustry.ui.Fonts.getGlyph(mindustry.ui.Fonts.def, (char)" + code + ")"); + ictype.addField(TextureRegionDrawable.class, name + "Small", Modifier.PUBLIC, Modifier.STATIC); + icload.addStatement(name + "Small = mindustry.ui.Fonts.getGlyph(mindustry.ui.Fonts.def, (char)" + code + ")"); ictype.addField(TextureRegionDrawable.class, name, Modifier.PUBLIC, Modifier.STATIC); icload.addStatement(name + " = mindustry.ui.Fonts.getGlyph(mindustry.ui.Fonts.icon, (char)" + code + ")"); icload.addStatement("icons.put($S, " + name + ")", name); + icload.addStatement("icons.put($S, " + name + "Small)", name + "Small"); } Fi.get(resources).walk(p -> { - if(p.nameWithoutExtension().equals(".DS_Store")) return; + if(!p.extEquals("png")) return; String filename = p.name(); filename = filename.substring(0, filename.indexOf(".")); @@ -107,12 +78,12 @@ public class AssetsAnnotationProcessor extends AbstractProcessor{ } ictype.addMethod(icload.build()); - JavaFile.builder(packageName, ichtype.build()).build().writeTo(Utils.filer); - JavaFile.builder(packageName, ictype.build()).build().writeTo(Utils.filer); + JavaFile.builder(packageName, ichtype.build()).build().writeTo(BaseProcessor.filer); + JavaFile.builder(packageName, ictype.build()).build().writeTo(BaseProcessor.filer); type.addMethod(load.build()); type.addMethod(loadStyles.build()); - JavaFile.builder(packageName, type.build()).build().writeTo(Utils.filer); + JavaFile.builder(packageName, type.build()).build().writeTo(BaseProcessor.filer); } void processSounds(String classname, String path, String rtype) throws Exception{ @@ -126,7 +97,7 @@ public class AssetsAnnotationProcessor extends AbstractProcessor{ String name = p.nameWithoutExtension(); if(names.contains(name)){ - Utils.messager.printMessage(Kind.ERROR, "Duplicate file name: " + p.toString() + "!"); + BaseProcessor.err("Duplicate file name: " + p.toString() + "!"); }else{ names.add(name); } @@ -152,7 +123,7 @@ public class AssetsAnnotationProcessor extends AbstractProcessor{ type.addMethod(loadBegin.build()); type.addMethod(dispose.build()); - JavaFile.builder(packageName, type.build()).build().writeTo(Utils.filer); + JavaFile.builder(packageName, type.build()).build().writeTo(BaseProcessor.filer); } static String capitalize(String s){ diff --git a/annotations/src/main/java/mindustry/annotations/impl/CallSuperProcess.java b/annotations/src/main/java/mindustry/annotations/impl/CallSuperProcess.java new file mode 100644 index 0000000000..b43a2d3eef --- /dev/null +++ b/annotations/src/main/java/mindustry/annotations/impl/CallSuperProcess.java @@ -0,0 +1,151 @@ +package mindustry.annotations.impl; + +import com.sun.source.tree.*; +import com.sun.source.util.*; +import com.sun.tools.javac.code.Scope; +import com.sun.tools.javac.code.*; +import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.code.Type.*; +import com.sun.tools.javac.tree.*; +import com.sun.tools.javac.tree.JCTree.*; +import mindustry.annotations.Annotations.*; + +import javax.annotation.processing.*; +import javax.lang.model.*; +import javax.lang.model.element.*; +import javax.tools.Diagnostic.*; +import java.lang.annotation.*; +import java.util.*; + +@SupportedAnnotationTypes({"java.lang.Override"}) +public class CallSuperProcess extends AbstractProcessor{ + private Trees trees; + + @Override + public void init(ProcessingEnvironment pe){ + super.init(pe); + trees = Trees.instance(pe); + } + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv){ + for(Element e : roundEnv.getElementsAnnotatedWith(Override.class)){ + if(e.getAnnotation(OverrideCallSuper.class) != null) return false; + + CodeAnalyzerTreeScanner codeScanner = new CodeAnalyzerTreeScanner(); + codeScanner.methodName = e.getSimpleName().toString(); + + TreePath tp = trees.getPath(e.getEnclosingElement()); + codeScanner.scan(tp, trees); + + if(codeScanner.callSuperUsed){ + List list = codeScanner.method.getBody().getStatements(); + + if(!doesCallSuper(list, codeScanner.methodName)){ + processingEnv.getMessager().printMessage(Kind.ERROR, "Overriding method '" + codeScanner.methodName + "' must explicitly call super method from its parent class.", e); + } + } + } + + return false; + } + + private boolean doesCallSuper(List list, String methodName){ + for(Object object : list){ + if(object instanceof JCTree.JCExpressionStatement){ + JCTree.JCExpressionStatement expr = (JCExpressionStatement)object; + String exprString = expr.toString(); + if(exprString.startsWith("super." + methodName) && exprString.endsWith(");")) return true; + } + } + + return false; + } + + @Override + public SourceVersion getSupportedSourceVersion(){ + return SourceVersion.RELEASE_8; + } + + static class CodeAnalyzerTreeScanner extends TreePathScanner{ + private String methodName; + private MethodTree method; + private boolean callSuperUsed; + + @Override + public Object visitClass(ClassTree classTree, Trees trees){ + Tree extendTree = classTree.getExtendsClause(); + + if(extendTree instanceof JCTypeApply){ //generic classes case + JCTypeApply generic = (JCTypeApply)extendTree; + extendTree = generic.clazz; + } + + if(extendTree instanceof JCIdent){ + JCIdent tree = (JCIdent)extendTree; + com.sun.tools.javac.code.Scope members = tree.sym.members(); + + if(checkScope(members)) + return super.visitClass(classTree, trees); + + if(checkSuperTypes((ClassType)tree.type)) + return super.visitClass(classTree, trees); + + } + callSuperUsed = false; + + return super.visitClass(classTree, trees); + } + + public boolean checkSuperTypes(ClassType type){ + if(type.supertype_field != null && type.supertype_field.tsym != null){ + if(checkScope(type.supertype_field.tsym.members())) + return true; + else + return checkSuperTypes((ClassType)type.supertype_field); + } + + return false; + } + + @SuppressWarnings("unchecked") + public boolean checkScope(Scope members){ + 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; + + if(ms.getSimpleName().toString().equals(methodName)){ + Annotation annotation = ms.getAnnotation(CallSuper.class); + if(annotation != null){ + callSuperUsed = true; + return true; + } + } + } + } + + return false; + } + + @Override + public Object visitMethod(MethodTree methodTree, Trees trees){ + if(methodTree.getName().toString().equals(methodName)) + method = methodTree; + + return super.visitMethod(methodTree, trees); + } + + } +} diff --git a/annotations/src/main/java/mindustry/annotations/impl/EntityProcess.java b/annotations/src/main/java/mindustry/annotations/impl/EntityProcess.java new file mode 100644 index 0000000000..1d80e46c61 --- /dev/null +++ b/annotations/src/main/java/mindustry/annotations/impl/EntityProcess.java @@ -0,0 +1,713 @@ +package mindustry.annotations.impl; + +import arc.files.*; +import arc.func.*; +import arc.struct.*; +import arc.util.*; +import arc.util.io.*; +import arc.util.pooling.*; +import arc.util.pooling.Pool.*; +import com.squareup.javapoet.*; +import com.squareup.javapoet.TypeSpec.*; +import com.sun.source.tree.*; +import mindustry.annotations.Annotations.*; +import mindustry.annotations.*; +import mindustry.annotations.util.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import java.lang.annotation.*; + +@SupportedAnnotationTypes({ +"mindustry.annotations.Annotations.EntityDef", +"mindustry.annotations.Annotations.GroupDef", +"mindustry.annotations.Annotations.EntityInterface", +"mindustry.annotations.Annotations.BaseComponent" +}) +public class EntityProcess extends BaseProcessor{ + Array definitions = new Array<>(); + Array groupDefs = new Array<>(); + Array baseComponents; + ObjectMap componentNames = new ObjectMap<>(); + ObjectMap> componentDependencies = new ObjectMap<>(); + ObjectMap> defComponents = new ObjectMap<>(); + ObjectMap varInitializers = new ObjectMap<>(); + ObjectMap methodBlocks = new ObjectMap<>(); + ObjectSet imports = new ObjectSet<>(); + Array allGroups = new Array<>(); + Array allDefs = new Array<>(); + Array allInterfaces = new Array<>(); + + { + rounds = 3; + } + + @Override + public void process(RoundEnvironment env) throws Exception{ + allGroups.addAll(methods(GroupDef.class)); + allDefs.addAll(elements(EntityDef.class)); + allInterfaces.addAll(types(EntityInterface.class)); + + //round 1: generate component interfaces + if(round == 1){ + baseComponents = types(BaseComponent.class); + Array allComponents = types(Component.class); + + //store code + for(Stype component : allComponents){ + for(Svar f : component.fields()){ + VariableTree tree = f.tree(); + + //add initializer if it exists + if(tree.getInitializer() != null){ + String init = tree.getInitializer().toString(); + varInitializers.put(f, init); + } + } + + for(Smethod elem : component.methods()){ + if(elem.is(Modifier.ABSTRACT) || elem.is(Modifier.NATIVE)) continue; + //get all statements in the method, store them + methodBlocks.put(elem, elem.tree().getBody().toString()); + } + } + + //store components + for(Stype type : allComponents){ + componentNames.put(type.name(), type); + } + + //add component imports + for(Stype comp : allComponents){ + imports.addAll(getImports(comp.e)); + } + + //create component interfaces + for(Stype component : allComponents){ + TypeSpec.Builder inter = TypeSpec.interfaceBuilder(interfaceName(component)) + .addModifiers(Modifier.PUBLIC).addAnnotation(EntityInterface.class); + + //implement extra interfaces these components may have, e.g. position + for(Stype extraInterface : component.interfaces().select(i -> !isCompInterface(i))){ + //javapoet completely chokes on this if I add `addSuperInterface` or create the type name with TypeName.get + inter.superinterfaces.add(tname(extraInterface.fullName())); + } + + //implement super interfaces + Array depends = getDependencies(component); + for(Stype type : depends){ + inter.addSuperinterface(ClassName.get(packageName, interfaceName(type))); + } + + ObjectSet signatures = new ObjectSet<>(); + + //add utility methods to interface + for(Smethod method : component.methods()){ + //skip private methods, those are for internal use. + if(method.is(Modifier.PRIVATE)) continue; + + //keep track of signatures used to prevent dupes + signatures.add(method.e.toString()); + + inter.addMethod(MethodSpec.methodBuilder(method.name()) + .addExceptions(method.thrownt()) + .addTypeVariables(method.typeVariables().map(TypeVariableName::get)) + .returns(method.ret().toString().equals("void") ? TypeName.VOID : method.retn()) + .addParameters(method.params().map(v -> ParameterSpec.builder(v.tname(), v.name()) + .build())).addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT).build()); + } + + for(Svar field : component.fields().select(e -> !e.is(Modifier.STATIC) && !e.is(Modifier.PRIVATE) && !e.is(Modifier.TRANSIENT))){ + String cname = field.name(); + + //getter + if(!signatures.contains(cname + "()")){ + inter.addMethod(MethodSpec.methodBuilder(cname).addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC) + .addAnnotations(Array.with(field.annotations()).select(a -> a.toString().contains("Null")).map(AnnotationSpec::get)) + .returns(field.tname()).build()); + } + + //setter + if(!field.is(Modifier.FINAL) && !signatures.contains(cname + "(" + field.mirror().toString() + ")") && + !field.annotations().contains(f -> f.toString().equals("@mindustry.annotations.Annotations.ReadOnly"))){ + inter.addMethod(MethodSpec.methodBuilder(cname).addModifiers(Modifier.ABSTRACT, Modifier.PUBLIC) + .addParameter(ParameterSpec.builder(field.tname(), field.name()) + .addAnnotations(Array.with(field.annotations()) + .select(a -> a.toString().contains("Null")).map(AnnotationSpec::get)).build()).build()); + } + } + + write(inter); + + //LOGGING + + Log.debug("&gGenerating interface for " + component.name()); + + for(TypeName tn : inter.superinterfaces){ + Log.debug("&g> &lbextends {0}", simpleName(tn.toString())); + } + + //log methods generated + for(MethodSpec spec : inter.methodSpecs){ + Log.debug("&g> > &c{0} {1}({2})", simpleName(spec.returnType.toString()), spec.name, Array.with(spec.parameters).toString(", ", p -> simpleName(p.type.toString()) + " " + p.name)); + } + + Log.debug(""); + } + + //generate special render layer interfaces + for(DrawLayer layer : DrawLayer.values()){ + //create the DrawLayer interface that entities need to implement + String name = "DrawLayer" + Strings.capitalize(layer.name()) + "c"; + TypeSpec.Builder inter = TypeSpec.interfaceBuilder(name) + .addSuperinterface(tname(packageName + ".Entityc")) + .addModifiers(Modifier.PUBLIC).addAnnotation(EntityInterface.class); + inter.addMethod(MethodSpec.methodBuilder("draw" + Strings.capitalize(layer.name())).addModifiers(Modifier.PUBLIC, Modifier.ABSTRACT).build()); + write(inter); + } + }else if(round == 2){ //round 2: get component classes and generate interfaces for them + + //parse groups + for(Smethod group : allGroups){ + GroupDef an = group.annotation(GroupDef.class); + Array types = types(an, GroupDef::value).map(this::interfaceToComp);; + groupDefs.add(new GroupDefinition(group.name(), ClassName.bestGuess(packageName + "." + interfaceName(types.first())), types, an.spatial(), an.mapping())); + } + + //add special generated groups + for(DrawLayer layer : DrawLayer.values()){ + String name = "DrawLayer" + Strings.capitalize(layer.name()) + "c"; + //create group definition with no components directly + GroupDefinition def = new GroupDefinition(layer.name(), ClassName.bestGuess(packageName + "." + name), Array.with(), false, false); + //add manual inclusions of entities to be added to this group + def.manualInclusions.addAll(allDefs.select(s -> allComponents(s).contains(comp -> comp.interfaces().contains(in -> in.name().equals(name))))); + groupDefs.add(def); + } + + ObjectMap usedNames = new ObjectMap<>(); + ObjectMap> extraNames = new ObjectMap<>(); + + //look at each definition + for(Selement type : allDefs){ + EntityDef ann = type.annotation(EntityDef.class); + boolean isFinal = ann.isFinal(); + if(type.isType() && !type.name().endsWith("Def")){ + err("All entity def names must end with 'Def'", type.e); + } + String name = type.isType() ? + type.name().replace("Def", "Entity") : + createName(type); + + //skip double classes + if(usedNames.containsKey(name)){ + extraNames.getOr(usedNames.get(name), ObjectSet::new).add(type.name()); + continue; + } + + usedNames.put(name, type); + extraNames.getOr(type, ObjectSet::new).add(name); + if(!type.isType()){ + extraNames.getOr(type, ObjectSet::new).add(type.name()); + } + + TypeSpec.Builder builder = TypeSpec.classBuilder(name).addModifiers(Modifier.PUBLIC); + if(isFinal) builder.addModifiers(Modifier.FINAL); + + Array components = allComponents(type); + Array groups = groupDefs.select(g -> (!g.components.isEmpty() && !g.components.contains(s -> !components.contains(s))) || g.manualInclusions.contains(type)); + ObjectMap> methods = new ObjectMap<>(); + ObjectMap specVariables = new ObjectMap<>(); + + //add all components + for(Stype comp : components){ + + //write fields to the class; ignoring transient ones + Array fields = comp.fields().select(f -> !f.is(Modifier.TRANSIENT)); + for(Svar f : fields){ + FieldSpec.Builder fbuilder = FieldSpec.builder(f.tname(), f.name()); + //keep statics/finals + if(f.is(Modifier.STATIC)){ + fbuilder.addModifiers(Modifier.STATIC); + if(f.is(Modifier.FINAL)) fbuilder.addModifiers(Modifier.FINAL); + } + //add initializer if it exists + if(varInitializers.containsKey(f)){ + fbuilder.initializer(varInitializers.get(f)); + } + + if(!isFinal) fbuilder.addModifiers(Modifier.PROTECTED); + fbuilder.addAnnotations(f.annotations().map(AnnotationSpec::get)); + builder.addField(fbuilder.build()); + specVariables.put(builder.fieldSpecs.get(builder.fieldSpecs.size() - 1), f); + } + + //get all utility methods from components + for(Smethod elem : comp.methods()){ + methods.getOr(elem.toString(), Array::new).add(elem); + } + } + + //override toString method + builder.addMethod(MethodSpec.methodBuilder("toString") + .addAnnotation(Override.class) + .returns(String.class) + .addModifiers(Modifier.PUBLIC) + .addStatement("return $S + $L", name + "#", "id").build()); + + //add all methods from components + for(ObjectMap.Entry> entry : methods){ + if(entry.value.contains(m -> m.has(Replace.class))){ + //check replacements + if(entry.value.count(m -> m.has(Replace.class)) > 1){ + err("Type " + type + " has multiple components replacing method " + entry.key + "."); + } + Smethod base = entry.value.find(m -> m.has(Replace.class)); + entry.value.clear(); + entry.value.add(base); + } + + //check multi return + if(entry.value.count(m -> !m.isAny(Modifier.NATIVE, Modifier.ABSTRACT) && !m.isVoid()) > 1){ + err("Type " + type + " has multiple components implementing non-void method " + entry.key + "."); + } + + entry.value.sort(Structs.comps(Structs.comparingFloat(m -> m.has(MethodPriority.class) ? m.annotation(MethodPriority.class).value() : 0), Structs.comparing(Selement::name))); + + //representative method + Smethod first = entry.value.first(); + + //skip internal impl + if(first.has(InternalImpl.class)){ + continue; + } + + //build method using same params/returns + MethodSpec.Builder mbuilder = MethodSpec.methodBuilder(first.name()).addModifiers(first.is(Modifier.PRIVATE) ? Modifier.PRIVATE : Modifier.PUBLIC); + if(isFinal) mbuilder.addModifiers(Modifier.FINAL); + mbuilder.addTypeVariables(first.typeVariables().map(TypeVariableName::get)); + mbuilder.returns(first.retn()); + mbuilder.addExceptions(first.thrownt()); + + for(Svar var : first.params()){ + mbuilder.addParameter(var.tname(), var.name()); + } + + //only write the block if it's a void method with several entries + boolean writeBlock = first.ret().toString().equals("void") && entry.value.size > 1; + + if((entry.value.first().is(Modifier.ABSTRACT) || entry.value.first().is(Modifier.NATIVE)) && entry.value.size == 1 && !entry.value.first().has(InternalImpl.class)){ + err(entry.value.first().up().getSimpleName() + "#" + entry.value.first() + " is an abstract method and must be implemented in some component", type); + } + + //SPECIAL CASE: inject group add/remove code + if(first.name().equals("add") || first.name().equals("remove")){ + for(GroupDefinition def : groups){ + //remove/add from each group, assume imported + mbuilder.addStatement("Groups.$L.$L(this)", def.name, first.name()); + } + } + + for(Smethod elem : entry.value){ + if(elem.is(Modifier.ABSTRACT) || elem.is(Modifier.NATIVE) || !methodBlocks.containsKey(elem)) continue; + + //get all statements in the method, copy them over + String str = methodBlocks.get(elem); + //name for code blocks in the methods + String blockName = elem.up().getSimpleName().toString().toLowerCase().replace("comp", ""); + + //skip empty blocks + if(str.replace("{", "").replace("\n", "").replace("}", "").replace("\t", "").replace(" ", "").isEmpty()){ + continue; + } + + //wrap scope to prevent variable leakage + if(writeBlock){ + //replace return; with block break + str = str.replace("return;", "break " + blockName + ";"); + mbuilder.addCode(blockName + ": {\n"); + } + + //trim block + str = str.substring(2, str.length() - 1); + + //make sure to remove braces here + mbuilder.addCode(str); + + //end scope + if(writeBlock) mbuilder.addCode("}\n"); + } + + //add free code to remove methods + if(first.name().equals("remove") && ann.pooled()){ + mbuilder.addStatement("$T.free(this)", Pools.class); + } + + builder.addMethod(mbuilder.build()); + } + + //add pool reset method and implment Poolable + if(ann.pooled()){ + builder.addSuperinterface(Poolable.class); + //implement reset() + MethodSpec.Builder resetBuilder = MethodSpec.methodBuilder("reset").addModifiers(Modifier.PUBLIC); + for(FieldSpec spec : builder.fieldSpecs){ + Svar variable = specVariables.get(spec); + if(spec.type.isPrimitive()){ + //set to primitive default + resetBuilder.addStatement("$L = $L", spec.name, varInitializers.containsKey(variable) ? varInitializers.get(variable) : getDefault(spec.type.toString())); + }else{ + //set to default null + if(!varInitializers.containsKey(variable)){ + resetBuilder.addStatement("$L = null", spec.name); + } //else... TODO reset if poolable + } + } + + builder.addMethod(resetBuilder.build()); + } + + //make constructor private + builder.addMethod(MethodSpec.constructorBuilder().addModifiers(Modifier.PROTECTED).build()); + + //add create() method + builder.addMethod(MethodSpec.methodBuilder("create").addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns(tname(packageName + "." + name)) + .addStatement(ann.pooled() ? "return Pools.obtain($L.class, " +name +"::new)" : "return new $L()", name).build()); + + definitions.add(new EntityDefinition(packageName + "." + name, builder, type, components, groups)); + } + + //generate groups + TypeSpec.Builder groupsBuilder = TypeSpec.classBuilder("Groups").addModifiers(Modifier.PUBLIC); + MethodSpec.Builder groupInit = MethodSpec.methodBuilder("init").addModifiers(Modifier.PUBLIC, Modifier.STATIC); + for(GroupDefinition group : groupDefs){ + //Stype ctype = group.components.first(); + //class names for interface/group + ClassName itype = group.baseType; + ClassName groupc = ClassName.bestGuess("mindustry.entities.EntityGroup"); + + //add field... + groupsBuilder.addField(ParameterizedTypeName.get( + ClassName.bestGuess("mindustry.entities.EntityGroup"), itype), group.name, Modifier.PUBLIC, Modifier.STATIC); + + groupInit.addStatement("$L = new $T<>($L.class, $L, $L)", group.name, groupc, itype, group.spatial, group.mapping); + } + + //write the groups + groupsBuilder.addMethod(groupInit.build()); + + //add method for resizing all necessary groups + MethodSpec.Builder groupResize = MethodSpec.methodBuilder("resize") + .addParameter(TypeName.FLOAT, "x").addParameter(TypeName.FLOAT, "y").addParameter(TypeName.FLOAT, "w").addParameter(TypeName.FLOAT, "h") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC); + + MethodSpec.Builder groupUpdate = MethodSpec.methodBuilder("update") + .addModifiers(Modifier.PUBLIC, Modifier.STATIC); + + //method resize + for(GroupDefinition group : groupDefs){ + if(group.spatial){ + groupResize.addStatement("$L.resize(x, y, w, h)", group.name); + groupUpdate.addStatement("$L.updatePhysics()", group.name); + } + } + + groupUpdate.addStatement("all.update()"); + + for(DrawLayer layer : DrawLayer.values()){ + MethodSpec.Builder groupDraw = MethodSpec.methodBuilder("draw" + Strings.capitalize(layer.name())) + .addModifiers(Modifier.PUBLIC, Modifier.STATIC); + groupDraw.addStatement("$L.draw($L::$L)", layer.name(), "DrawLayer" + Strings.capitalize(layer.name()) + "c", "draw" + Strings.capitalize(layer.name())); + groupsBuilder.addMethod(groupDraw.build()); + } + + groupsBuilder.addMethod(groupResize.build()); + groupsBuilder.addMethod(groupUpdate.build()); + + write(groupsBuilder); + + //load map of sync IDs + StringMap map = new StringMap(); + Fi idProps = rootDirectory.child("annotations/src/main/resources/classids.properties"); + if(!idProps.exists()) idProps.writeString(""); + PropertiesUtils.load(map, idProps.reader()); + //next ID to be used in generation + Integer max = map.values().toArray().map(Integer::parseInt).max(i -> i); + int maxID = max == null ? 0 : max + 1; + + //assign IDs + definitions.sort(Structs.comparing(t -> t.base.toString())); + for(EntityDefinition def : definitions){ + String name = def.base.fullName(); + if(map.containsKey(name)){ + def.classID = map.getInt(name); + }else{ + def.classID = maxID++; + map.put(name, def.classID + ""); + } + } + + //write assigned IDs + PropertiesUtils.store(map, idProps.writer(false), "Maps entity names to IDs. Autogenerated."); + + //build mapping class for sync IDs + TypeSpec.Builder idBuilder = TypeSpec.classBuilder("EntityMapping").addModifiers(Modifier.PUBLIC) + .addField(FieldSpec.builder(TypeName.get(Prov[].class), "idMap", Modifier.PRIVATE, Modifier.STATIC).initializer("new Prov[256]").build()) + .addField(FieldSpec.builder(ParameterizedTypeName.get(ClassName.get(ObjectMap.class), + tname(String.class), tname(Prov.class)), + "nameMap", Modifier.PRIVATE, Modifier.STATIC).initializer("new ObjectMap<>()").build()) + .addMethod(MethodSpec.methodBuilder("map").addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns(TypeName.get(Prov.class)).addParameter(int.class, "id").addStatement("return idMap[id]").build()) + .addMethod(MethodSpec.methodBuilder("map").addModifiers(Modifier.PUBLIC, Modifier.STATIC) + .returns(TypeName.get(Prov.class)).addParameter(String.class, "name").addStatement("return nameMap.get(name)").build()); + + CodeBlock.Builder idStore = CodeBlock.builder(); + + //store the mappings + for(EntityDefinition def : definitions){ + //store mapping + idStore.addStatement("idMap[$L] = $L::new", def.classID, def.name); + extraNames.get(def.base).each(extra -> { + idStore.addStatement("nameMap.put($S, $L::new)", extra, def.name); + }); + + //return mapping + def.builder.addMethod(MethodSpec.methodBuilder("classId").addAnnotation(Override.class) + .returns(int.class).addModifiers(Modifier.PUBLIC).addStatement("return " + def.classID).build()); + } + + idBuilder.addStaticBlock(idStore.build()); + + write(idBuilder); + }else{ + //round 3: generate actual classes and implement interfaces + + //implement each definition + for(EntityDefinition def : definitions){ + + //get interface for each component + for(Stype comp : def.components){ + + //implement the interface + Stype inter = allInterfaces.find(i -> i.name().equals(interfaceName(comp))); + if(inter == null){ + err("Failed to generate interface for", comp); + return; + } + + def.builder.addSuperinterface(inter.tname()); + + //generate getter/setter for each method + for(Smethod method : inter.methods()){ + String var = method.name(); + FieldSpec field = Array.with(def.builder.fieldSpecs).find(f -> f.name.equals(var)); + //make sure it's a real variable AND that the component doesn't already implement it with custom logic + if(field == null || comp.methods().contains(m -> m.simpleString().equals(method.simpleString()))) continue; + + //getter + if(!method.isVoid()){ + def.builder.addMethod(MethodSpec.overriding(method.e).addStatement("return " + var).addModifiers(Modifier.FINAL).build()); + } + + //setter + if(method.isVoid() && !Array.with(field.annotations).contains(f -> f.type.toString().equals("@mindustry.annotations.Annotations.ReadOnly"))){ + def.builder.addMethod(MethodSpec.overriding(method.e).addModifiers(Modifier.FINAL).addStatement("this." + var + " = " + var).build()); + } + } + } + + write(def.builder, imports.asArray()); + } + + //store nulls + TypeSpec.Builder nullsBuilder = TypeSpec.classBuilder("Nulls").addModifiers(Modifier.PUBLIC).addModifiers(Modifier.FINAL); + + //create mock types of all components + for(Stype interf : allInterfaces){ + //indirect interfaces to implement methods for + Array dependencies = interf.allInterfaces().and(interf); + Array methods = dependencies.flatMap(Stype::methods); + methods.sortComparing(Object::toString); + + //used method signatures + ObjectSet signatures = new ObjectSet<>(); + + //create null builder + String baseName = interf.name().substring(0, interf.name().length() - 1); + String className = "Null" + baseName; + TypeSpec.Builder nullBuilder = TypeSpec.classBuilder(className) + .addModifiers(Modifier.FINAL); + + nullBuilder.addSuperinterface(interf.tname()); + + for(Smethod method : methods){ + String signature = method.toString(); + if(signatures.contains(signature)) continue; + + Stype compType = interfaceToComp(method.type()); + MethodSpec.Builder builder = MethodSpec.overriding(method.e).addModifiers(Modifier.PUBLIC, Modifier.FINAL); + + if(!method.isVoid()){ + if(method.name().equals("isNull")){ + builder.addStatement("return true"); + }else if(method.name().equals("id")){ + builder.addStatement("return -1"); + }else{ + Svar variable = compType == null || method.params().size > 0 ? null : compType.fields().find(v -> v.name().equals(method.name())); + if(variable == null || !varInitializers.containsKey(variable)){ + builder.addStatement("return " + getDefault(method.ret().toString())); + }else{ + String init = varInitializers.get(variable); + builder.addStatement("return " + (init.equals("{}") ? "new " + variable.mirror().toString() : "") + init); + } + } + } + + nullBuilder.addMethod(builder.build()); + + signatures.add(signature); + } + + nullsBuilder.addField(FieldSpec.builder(interf.cname(), Strings.camelize(baseName)).initializer("new " + className + "()").addModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PUBLIC).build()); + + write(nullBuilder); + } + + write(nullsBuilder); + } + } + + Array getImports(Element elem){ + return Array.with(trees.getPath(elem).getCompilationUnit().getImports()).map(Object::toString); + } + + /** @return interface for a component type */ + String interfaceName(Stype comp){ + String suffix = "Comp"; + if(!comp.name().endsWith(suffix)){ + err("All components must have names that end with 'Comp'", comp.e); + } + return comp.name().substring(0, comp.name().length() - suffix.length()) + "c"; + } + + /** @return all components that a entity def has */ + Array allComponents(Selement type){ + if(!defComponents.containsKey(type)){ + //get base defs + Array components = types(type.annotation(EntityDef.class), EntityDef::value).map(this::interfaceToComp); + ObjectSet out = new ObjectSet<>(); + for(Stype comp : components){ + //get dependencies for each def, add them + out.add(comp); + out.addAll(getDependencies(comp)); + } + + defComponents.put(type, out.asArray()); + } + + return defComponents.get(type); + } + + Array getDependencies(Stype component){ + if(!componentDependencies.containsKey(component)){ + ObjectSet out = new ObjectSet<>(); + //add base component interfaces + out.addAll(component.interfaces().select(this::isCompInterface).map(this::interfaceToComp)); + //remove self interface + out.remove(component); + + //out now contains the base dependencies; finish constructing the tree + ObjectSet result = new ObjectSet<>(); + for(Stype type : out){ + result.add(type); + result.addAll(getDependencies(type)); + } + + if(component.annotation(BaseComponent.class) == null){ + result.addAll(baseComponents); + } + + //remove it again just in case + out.remove(component); + componentDependencies.put(component, result.asArray()); + } + + return componentDependencies.get(component); + } + + boolean isCompInterface(Stype type){ + return interfaceToComp(type) != null; + } + + Stype interfaceToComp(Stype type){ + String name = type.name().substring(0, type.name().length() - 1) + "Comp"; + return componentNames.get(name); + } + + String createName(Selement elem){ + Array comps = types(elem.annotation(EntityDef.class), EntityDef::value).map(this::interfaceToComp);; + comps.sortComparing(Selement::name); + return comps.toString("", s -> s.name().replace("Comp", "")) + "Entity"; + } + + boolean isComponent(Stype type){ + return type.annotation(Component.class) != null; + } + + Array types(T t, Cons consumer){ + try{ + consumer.get(t); + }catch(MirroredTypesException e){ + return Array.with(e.getTypeMirrors()).map(Stype::of); + } + throw new IllegalArgumentException("Missing types."); + } + + class GroupDefinition{ + final String name; + final ClassName baseType; + final Array components; + final boolean spatial, mapping; + final ObjectSet manualInclusions = new ObjectSet<>(); + + public GroupDefinition(String name, ClassName bestType, Array components, boolean spatial, boolean mapping){ + this.baseType = bestType; + this.components = components; + this.name = name; + this.spatial = spatial; + this.mapping = mapping; + } + + @Override + public String toString(){ + return name; + } + } + + class EntityDefinition{ + final Array groups; + final Array components; + final TypeSpec.Builder builder; + final Selement base; + final String name; + int classID; + + public EntityDefinition(String name, Builder builder, Selement base, Array components, Array groups){ + this.builder = builder; + this.name = name; + this.base = base; + this.groups = groups; + this.components = components; + } + + @Override + public String toString(){ + return "Definition{" + + "groups=" + groups + + "components=" + components + + ", base=" + base + + '}'; + } + } +} diff --git a/annotations/src/main/java/mindustry/annotations/impl/SerializeProcess.java b/annotations/src/main/java/mindustry/annotations/impl/SerializeProcess.java new file mode 100644 index 0000000000..9bade20179 --- /dev/null +++ b/annotations/src/main/java/mindustry/annotations/impl/SerializeProcess.java @@ -0,0 +1,108 @@ +package mindustry.annotations.impl; + +import com.squareup.javapoet.*; +import mindustry.annotations.*; +import mindustry.annotations.Annotations.*; +import mindustry.annotations.remote.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.*; +import javax.lang.model.util.*; +import java.io.*; +import java.lang.reflect.*; +import java.util.*; +import java.util.zip.*; + +@SupportedAnnotationTypes("mindustry.annotations.Annotations.Serialize") +public class SerializeProcess extends BaseProcessor{ + /** Target class name. */ + private static final String className = "Serialization"; + /** Name of the base package to put all the generated classes. */ + private static final String data = "eJztV0tvGzcQvvfQ3zDRIeDCKhsbQVDUsgP5UViH2IHl9BIEBsUdSYxX3C3Jlawm+XH9Z53hUg/bkuOmOfRQwfDuDme++ebBWe6PfwU3/wTwUU2VLJQdSYfDAnWQvxkschjCAUyMzWtPetJikF2nzzG8deXU5OjkW6VvMPTRGVWYP0mgC+W9HGE4Qbp1mEcg0Zo5E9C1sn2AofQYulqj92ZQoAiuxqVc2Loo2iCU03JYWy2PS+v3OndJNF7bDW1rSnk0D3hUD4foDjNRtWGQwU+HQIGZoajAWB+U1VgOYROOZx+Wgm4eMzJ7ghpoyo14Cl5FsQ2I4PsPcE2/XXpssk7kOMw6mEJe9KXxXZu70uTM4Jjz2Hl9CJ79xCc5LN25mqBoqUZPVosy9DEEY0eebnTtMKZ5iaDddgRd2oA2MGO+XqIvi2mq0xJAqQ0ARHzA8dncywWar91QaZwanMkUS7eqCqNVMKW9x+qRuO6wug3R8GGLvsEwLnMYMZBS6z3XrIgWidYhLgYfyQ50IyKrkZbGTssbjHU4Lh1KVVWbvaUNEf8fUFXYX+rt7vnJ5UXv5Lp3Et30g6NagDK55RZpHrNoyUaxwx+PyA+XLtZCaYBabSpoOzlptttX0uM8oen7aJsqnhLkkixmyPlFjlLe1kL0a/ER6YVis4UXKO2YCbYyNkCBnBQv6ToKY5Gt9kauAveZxVkjYc2fYe8DT4bSCTY2tP5iny4dxuGbnQPY4+3Cxu9N1GdODJAJcTxWTmmaOzI3IxOEl5ok3SBM1obdVxl0OvAyA9iB7Zq0uNtoM9cvy9gpvLoIiXAjW+1mnwZi7Ht5pDy+enlc8k5Fq+kqmG8EpBnQIEn8o1aFp25a/C66B60sgzB25Sx6uaxtMBM8vdVYMbBoHakc3r3rnchYvjhdiBGDM1csPD4cMr3Sc8ZSGHVtuJ+X/e8Xk2TZcKLFOtR2rVYizM8EdDqpwlxkDJZKeCcnUfYLl4+f2MFEhbG8pE0uMhqXt4Gntk/hM3Ti8k0JTSgM8zCWqg7LKPiyWcurKYr1PDaYi0x+Wi08gVaOkdYT85paa+Enbubo4NTWE3QRvtO87eg1Qy/gWeluerQd47w9BCRSsHWdfd6XebGcGptMoKw58Dhe4IwrXJYFKkspEKnYfImdRB0R7+GAasezjRIXamdhSP2M+1/rjv7cB5xI5Zya67KaN2BteNFOFvE2CtPUYObJxbN/1Sxb9hw8f/7dgbsMnKoMcAbjlIezWAcecJRxkmHcGacFTmg48xrLuYBnyuUzerl185y8UPkW6YbPn+HZWFJhtmlmMSKUY+XfUC8m8NgBG52uDeXrVFnYhv3Py3u9sb7X9wu8eMUE9x1GArUoAW0rNyVw42r3WwfwanDQHx1+9FhcMYii4y6E/6fvf3T6UiaZLA3BtXO9Zvvf0Xn2MahNEfmv1unr42peYe9Cxk+chD6gU5qcNla8/GQbSwfhJyvXvslmpC2oxOXAUIe9TgegXfgVXizXOSxN4RSlW9nEnK4eGzsGolO9pw+6xXC6d/pa0yDBzs7db6ZHGEczPgSbO+88qBpVMYjSbH/Trgn0vUM8+oE+O67otMbt8uWHvwGqGwCj"; + + @Override + public void process(RoundEnvironment env) throws Exception{ + Set elements = ElementFilter.typesIn(env.getElementsAnnotatedWith(Serialize.class)); + + TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC); + classBuilder.addStaticBlock(CodeBlock.of(new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(data)))).readUTF())); + classBuilder.addAnnotation(AnnotationSpec.builder(SuppressWarnings.class).addMember("value", "\"unchecked\"").build()); + classBuilder.addJavadoc(RemoteProcess.autogenWarning); + + MethodSpec.Builder method = MethodSpec.methodBuilder("init").addModifiers(Modifier.PUBLIC, Modifier.STATIC); + + for(TypeElement elem : elements){ + TypeName type = TypeName.get(elem.asType()); + String simpleTypeName = type.toString().substring(type.toString().lastIndexOf('.') + 1); + + TypeSpec.Builder serializer = TypeSpec.anonymousClassBuilder("") + .addSuperinterface(ParameterizedTypeName.get( + ClassName.bestGuess("arc.Settings.TypeSerializer"), type)); + + MethodSpec.Builder writeMethod = MethodSpec.methodBuilder("write") + .returns(void.class) + .addParameter(DataOutput.class, "stream") + .addParameter(type, "object") + .addException(IOException.class) + .addModifiers(Modifier.PUBLIC); + + MethodSpec.Builder readMethod = MethodSpec.methodBuilder("read") + .returns(type) + .addParameter(DataInput.class, "stream") + .addException(IOException.class) + .addModifiers(Modifier.PUBLIC); + + readMethod.addStatement("$L object = new $L()", type, type); + + List fields = ElementFilter.fieldsIn(BaseProcessor.elementu.getAllMembers(elem)); + for(VariableElement field : fields){ + if(field.getModifiers().contains(Modifier.STATIC) || field.getModifiers().contains(Modifier.TRANSIENT) || field.getModifiers().contains(Modifier.PRIVATE)) + continue; + + String name = field.getSimpleName().toString(); + String typeName = BaseProcessor.typeu.erasure(field.asType()).toString().replace('$', '.'); + String capName = Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1); + + if(field.asType().getKind().isPrimitive()){ + writeMethod.addStatement("stream.write" + capName + "(object." + name + ")"); + readMethod.addStatement("object." + name + "= stream.read" + capName + "()"); + }else{ + writeMethod.addStatement("arc.Core.settings.getSerializer(" + typeName + ".class).write(stream, object." + name + ")"); + readMethod.addStatement("object." + name + " = (" + typeName + ")arc.Core.settings.getSerializer(" + typeName + ".class).read(stream)"); + } + } + + readMethod.addStatement("return object"); + + serializer.addMethod(writeMethod.build()); + serializer.addMethod(readMethod.build()); + + method.addStatement("arc.Core.settings.setSerializer($N, $L)", BaseProcessor.elementu.getBinaryName(elem).toString().replace('$', '.') + ".class", serializer.build()); + + name(writeMethod, "write" + simpleTypeName); + name(readMethod, "read" + simpleTypeName); + + writeMethod.addModifiers(Modifier.STATIC); + readMethod.addModifiers(Modifier.STATIC); + + classBuilder.addMethod(writeMethod.build()); + classBuilder.addMethod(readMethod.build()); + } + + classBuilder.addMethod(method.build()); + + //write result + JavaFile.builder(packageName, classBuilder.build()).build().writeTo(BaseProcessor.filer); + } + + static void name(MethodSpec.Builder builder, String name){ + try{ + Field field = builder.getClass().getDeclaredField("name"); + field.setAccessible(true); + field.set(builder, name); + }catch(Exception e){ + throw new RuntimeException(e); + } + } +} diff --git a/annotations/src/main/java/mindustry/annotations/impl/StructProcess.java b/annotations/src/main/java/mindustry/annotations/impl/StructProcess.java new file mode 100644 index 0000000000..7eadedb856 --- /dev/null +++ b/annotations/src/main/java/mindustry/annotations/impl/StructProcess.java @@ -0,0 +1,204 @@ +package mindustry.annotations.impl; + +import com.squareup.javapoet.*; +import mindustry.annotations.*; +import mindustry.annotations.Annotations.Struct; +import mindustry.annotations.Annotations.StructField; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.type.TypeKind; +import javax.lang.model.util.ElementFilter; +import javax.tools.Diagnostic.Kind; +import java.util.List; +import java.util.Set; + +/** + * Generates ""value types"" classes that are packed into integer primitives of the most aproppriate size. + * It would be nice if Java didn't make crazy hacks like this necessary. + */ +@SupportedAnnotationTypes({ +"mindustry.annotations.Annotations.Struct" +}) +public class StructProcess extends BaseProcessor{ + + @Override + public void process(RoundEnvironment env) throws Exception{ + Set elements = ElementFilter.typesIn(env.getElementsAnnotatedWith(Struct.class)); + + for(TypeElement elem : elements){ + + if(!elem.getSimpleName().toString().endsWith("Struct")){ + BaseProcessor.err("All classes annotated with @Struct must have their class names end in 'Struct'.", elem); + continue; + } + + String structName = elem.getSimpleName().toString().substring(0, elem.getSimpleName().toString().length() - "Struct".length()); + String structParam = structName.toLowerCase(); + + TypeSpec.Builder classBuilder = TypeSpec.classBuilder(structName) + .addModifiers(Modifier.FINAL, Modifier.PUBLIC); + + try{ + List variables = ElementFilter.fieldsIn(elem.getEnclosedElements()); + int structSize = variables.stream().mapToInt(StructProcess::varSize).sum(); + int structTotalSize = (structSize <= 8 ? 8 : structSize <= 16 ? 16 : structSize <= 32 ? 32 : 64); + + if(variables.size() == 0){ + BaseProcessor.err("making a struct with no fields is utterly pointles.", elem); + continue; + } + + //obtain type which will be stored + Class structType = typeForSize(structSize); + + //[constructor] get(fields...) : structType + MethodSpec.Builder constructor = MethodSpec.methodBuilder("get") + .addModifiers(Modifier.STATIC, Modifier.PUBLIC) + .returns(structType); + + StringBuilder cons = new StringBuilder(); + StringBuilder doc = new StringBuilder(); + doc.append("Bits used: ").append(structSize).append(" / ").append(structTotalSize).append("\n"); + + int offset = 0; + for(VariableElement var : variables){ + int size = varSize(var); + TypeName varType = TypeName.get(var.asType()); + String varName = var.getSimpleName().toString(); + + //add val param to constructor + constructor.addParameter(varType, varName); + + //[get] field(structType) : fieldType + MethodSpec.Builder getter = MethodSpec.methodBuilder(var.getSimpleName().toString()) + .addModifiers(Modifier.STATIC, Modifier.PUBLIC) + .returns(varType) + .addParameter(structType, structParam); + //[set] field(structType, fieldType) : structType + MethodSpec.Builder setter = MethodSpec.methodBuilder(var.getSimpleName().toString()) + .addModifiers(Modifier.STATIC, Modifier.PUBLIC) + .returns(structType) + .addParameter(structType, structParam).addParameter(varType, "value"); + + //[getter] + if(varType == TypeName.BOOLEAN){ + //bools: single bit, is simplified + getter.addStatement("return ($L & (1L << $L)) != 0", structParam, offset); + }else if(varType == TypeName.FLOAT){ + //floats: need conversion + getter.addStatement("return Float.intBitsToFloat((int)(($L >>> $L) & $L))", structParam, offset, bitString(size, structTotalSize)); + }else{ + //bytes, shorts, chars, ints + getter.addStatement("return ($T)(($L >>> $L) & $L)", varType, structParam, offset, bitString(size, structTotalSize)); + } + + //[setter] + [constructor building] + if(varType == TypeName.BOOLEAN){ + cons.append(" | (").append(varName).append(" ? ").append("1L << ").append(offset).append("L : 0)"); + + //bools: single bit, needs special case to clear things + setter.beginControlFlow("if(value)"); + setter.addStatement("return ($T)(($L & ~(1L << $LL)))", structType, structParam, offset); + setter.nextControlFlow("else"); + setter.addStatement("return ($T)(($L & ~(1L << $LL)) | (1L << $LL))", structType, structParam, offset, offset); + setter.endControlFlow(); + }else if(varType == TypeName.FLOAT){ + cons.append(" | (").append("(").append(structType).append(")").append("Float.floatToIntBits(").append(varName).append(") << ").append(offset).append("L)"); + + //floats: need conversion + setter.addStatement("return ($T)(($L & $L) | (($T)Float.floatToIntBits(value) << $LL))", structType, structParam, bitString(offset, size, structTotalSize), structType, offset); + }else{ + cons.append(" | (((").append(structType).append(")").append(varName).append(" << ").append(offset).append("L)").append(" & ").append(bitString(offset, size, structTotalSize)).append(")"); + + //bytes, shorts, chars, ints + setter.addStatement("return ($T)(($L & $L) | (($T)value << $LL))", structType, structParam, bitString(offset, size, structTotalSize), structType, offset); + } + + doc.append("
").append(varName).append(" [").append(offset).append("..").append(size + offset).append("]\n"); + + //add finished methods + classBuilder.addMethod(getter.build()); + classBuilder.addMethod(setter.build()); + + offset += size; + } + + classBuilder.addJavadoc(doc.toString()); + + //add constructor final statement + add to class and build + constructor.addStatement("return ($T)($L)", structType, cons.toString().substring(3)); + classBuilder.addMethod(constructor.build()); + + JavaFile.builder(packageName, classBuilder.build()).build().writeTo(BaseProcessor.filer); + }catch(IllegalArgumentException e){ + e.printStackTrace(); + BaseProcessor.err(e.getMessage(), elem); + } + } + + } + + static String bitString(int offset, int size, int totalSize){ + StringBuilder builder = new StringBuilder(); + for(int i = 0; i < offset; i++) builder.append('0'); + for(int i = 0; i < size; i++) builder.append('1'); + for(int i = 0; i < totalSize - size - offset; i++) builder.append('0'); + return "0b" + builder.reverse().toString() + "L"; + } + + static String bitString(int size, int totalSize){ + StringBuilder builder = new StringBuilder(); + for(int i = 0; i < size; i++) builder.append('1'); + for(int i = 0; i < totalSize - size; i++) builder.append('0'); + return "0b" + builder.reverse().toString() + "L"; + } + + static int varSize(VariableElement var) throws IllegalArgumentException{ + if(!var.asType().getKind().isPrimitive()){ + throw new IllegalArgumentException("All struct fields must be primitives: " + var); + } + + StructField an = var.getAnnotation(StructField.class); + if(var.asType().getKind() == TypeKind.BOOLEAN && an != null && an.value() != 1){ + throw new IllegalArgumentException("Booleans can only be one bit long... why would you do this?"); + } + + if(var.asType().getKind() == TypeKind.FLOAT && an != null && an.value() != 32){ + throw new IllegalArgumentException("Float size can't be changed. Very sad."); + } + + return an == null ? typeSize(var.asType().getKind()) : an.value(); + } + + static Class typeForSize(int size) throws IllegalArgumentException{ + if(size <= 8){ + return byte.class; + }else if(size <= 16){ + return short.class; + }else if(size <= 32){ + return int.class; + }else if(size <= 64){ + return long.class; + } + throw new IllegalArgumentException("Too many fields, must fit in 64 bits. Curent size: " + size); + } + + /** returns a type's element size in bits. */ + static int typeSize(TypeKind kind) throws IllegalArgumentException{ + switch(kind){ + case BOOLEAN: + return 1; + case BYTE: + return 8; + case SHORT: + return 16; + case FLOAT: + case CHAR: + case INT: + return 32; + default: + throw new IllegalArgumentException("Invalid type kind: " + kind + ". Note that doubles and longs are not supported."); + } + } +} diff --git a/annotations/src/main/java/mindustry/annotations/ClassEntry.java b/annotations/src/main/java/mindustry/annotations/remote/ClassEntry.java similarity index 90% rename from annotations/src/main/java/mindustry/annotations/ClassEntry.java rename to annotations/src/main/java/mindustry/annotations/remote/ClassEntry.java index 002dcac88c..3474eff468 100644 --- a/annotations/src/main/java/mindustry/annotations/ClassEntry.java +++ b/annotations/src/main/java/mindustry/annotations/remote/ClassEntry.java @@ -1,4 +1,4 @@ -package mindustry.annotations; +package mindustry.annotations.remote; import java.util.ArrayList; diff --git a/annotations/src/main/java/mindustry/annotations/IOFinder.java b/annotations/src/main/java/mindustry/annotations/remote/IOFinder.java similarity index 73% rename from annotations/src/main/java/mindustry/annotations/IOFinder.java rename to annotations/src/main/java/mindustry/annotations/remote/IOFinder.java index e586cbd4a8..b5f09fdba3 100644 --- a/annotations/src/main/java/mindustry/annotations/IOFinder.java +++ b/annotations/src/main/java/mindustry/annotations/remote/IOFinder.java @@ -1,18 +1,16 @@ -package mindustry.annotations; +package mindustry.annotations.remote; -import mindustry.annotations.Annotations.ReadClass; -import mindustry.annotations.Annotations.WriteClass; +import mindustry.annotations.Annotations.*; +import mindustry.annotations.*; -import javax.annotation.processing.RoundEnvironment; -import javax.lang.model.element.Element; -import javax.lang.model.type.MirroredTypeException; -import javax.tools.Diagnostic.Kind; -import java.util.HashMap; -import java.util.Set; +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import java.util.*; /** - * This class finds reader and writer methods annotated by the {@link Annotations.WriteClass} - * and {@link Annotations.ReadClass} annotations. + * This class finds reader and writer methods annotated by the {@link WriteClass} + * and {@link ReadClass} annotations. */ public class IOFinder{ @@ -34,21 +32,21 @@ public class IOFinder{ //make sure there's only one read method if(readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).count() > 1){ - Utils.messager.printMessage(Kind.ERROR, "Multiple writer methods for type '" + typeName + "'", writer); + BaseProcessor.err("Multiple writer methods for type '" + typeName + "'", writer); } //make sure there's only one write method long count = readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).count(); if(count == 0){ - Utils.messager.printMessage(Kind.ERROR, "Writer method does not have an accompanying reader: ", writer); + BaseProcessor.err("Writer method does not have an accompanying reader: ", writer); }else if(count > 1){ - Utils.messager.printMessage(Kind.ERROR, "Writer method has multiple reader for type: ", writer); + BaseProcessor.err("Writer method has multiple reader for type: ", writer); } Element reader = readers.stream().filter(elem -> getValue(elem.getAnnotation(ReadClass.class)).equals(typeName)).findFirst().get(); //add to result list - result.put(typeName, new ClassSerializer(Utils.getMethodName(reader), Utils.getMethodName(writer), typeName)); + result.put(typeName, new ClassSerializer(BaseProcessor.getMethodName(reader), BaseProcessor.getMethodName(writer), typeName)); } return result; diff --git a/annotations/src/main/java/mindustry/annotations/MethodEntry.java b/annotations/src/main/java/mindustry/annotations/remote/MethodEntry.java similarity index 98% rename from annotations/src/main/java/mindustry/annotations/MethodEntry.java rename to annotations/src/main/java/mindustry/annotations/remote/MethodEntry.java index 0010d4b4d4..68ea81dec0 100644 --- a/annotations/src/main/java/mindustry/annotations/MethodEntry.java +++ b/annotations/src/main/java/mindustry/annotations/remote/MethodEntry.java @@ -1,4 +1,4 @@ -package mindustry.annotations; +package mindustry.annotations.remote; import mindustry.annotations.Annotations.*; diff --git a/annotations/src/main/java/mindustry/annotations/remote/RemoteProcess.java b/annotations/src/main/java/mindustry/annotations/remote/RemoteProcess.java new file mode 100644 index 0000000000..f405f44a07 --- /dev/null +++ b/annotations/src/main/java/mindustry/annotations/remote/RemoteProcess.java @@ -0,0 +1,124 @@ +package mindustry.annotations.remote; + +import com.squareup.javapoet.*; +import mindustry.annotations.*; +import mindustry.annotations.Annotations.*; +import mindustry.annotations.remote.IOFinder.*; + +import javax.annotation.processing.*; +import javax.lang.model.element.*; +import javax.tools.Diagnostic.*; +import java.util.*; +import java.util.stream.*; + + +/** The annotation processor for generating remote method call code. */ +@SupportedAnnotationTypes({ +"mindustry.annotations.Annotations.Remote", +"mindustry.annotations.Annotations.WriteClass", +"mindustry.annotations.Annotations.ReadClass", +}) +public class RemoteProcess extends BaseProcessor{ + /** Maximum size of each event packet. */ + public static final int maxPacketSize = 4096; + /** Warning on top of each autogenerated file. */ + public static final String autogenWarning = "Autogenerated file. Do not modify!\n"; + + /** Name of class that handles reading and invoking packets on the server. */ + private static final String readServerName = "RemoteReadServer"; + /** Name of class that handles reading and invoking packets on the client. */ + private static final String readClientName = "RemoteReadClient"; + /** Simple class name of generated class name. */ + private static final String callLocation = "Call"; + + //class serializers + private HashMap serializers; + //all elements with the Remote annotation + private Set elements; + //map of all classes to generate by name + private HashMap classMap; + //list of all method entries + private ArrayList methods; + //list of all method entries + private ArrayList classes; + + { + rounds = 2; + } + + @Override + public void process(RoundEnvironment roundEnv) throws Exception{ + //round 1: find all annotations, generate *writers* + if(round == 1){ + //get serializers + serializers = new IOFinder().findSerializers(roundEnv); + //last method ID used + int lastMethodID = 0; + //find all elements with the Remote annotation + elements = roundEnv.getElementsAnnotatedWith(Remote.class); + //map of all classes to generate by name + classMap = new HashMap<>(); + //list of all method entries + methods = new ArrayList<>(); + //list of all method entries + classes = new ArrayList<>(); + + List orderedElements = new ArrayList<>(elements); + orderedElements.sort(Comparator.comparing(Object::toString)); + + //create methods + for(Element element : orderedElements){ + Remote annotation = element.getAnnotation(Remote.class); + + //check for static + if(!element.getModifiers().contains(Modifier.STATIC) || !element.getModifiers().contains(Modifier.PUBLIC)){ + err("All @Remote methods must be public and static: ", element); + } + + //can't generate none methods + if(annotation.targets() == Loc.none){ + err("A @Remote method's targets() cannot be equal to 'none':", element); + } + + //get and create class entry if needed + if(!classMap.containsKey(callLocation)){ + ClassEntry clas = new ClassEntry(callLocation); + classMap.put(callLocation, clas); + classes.add(clas); + } + + ClassEntry entry = classMap.get(callLocation); + + //create and add entry + MethodEntry method = new MethodEntry(entry.name, BaseProcessor.getMethodName(element), annotation.targets(), annotation.variants(), + annotation.called(), annotation.unreliable(), annotation.forward(), lastMethodID++, (ExecutableElement)element, annotation.priority()); + + entry.methods.add(method); + methods.add(method); + } + + //create read/write generators + RemoteWriteGenerator writegen = new RemoteWriteGenerator(serializers); + + //generate the methods to invoke (write) + writegen.generateFor(classes, packageName); + }else if(round == 2){ //round 2: generate all *readers* + RemoteReadGenerator readgen = new RemoteReadGenerator(serializers); + + //generate server readers + readgen.generateFor(methods.stream().filter(method -> method.where.isClient).collect(Collectors.toList()), readServerName, packageName, true); + //generate client readers + readgen.generateFor(methods.stream().filter(method -> method.where.isServer).collect(Collectors.toList()), readClientName, packageName, false); + + //create class for storing unique method hash + TypeSpec.Builder hashBuilder = TypeSpec.classBuilder("MethodHash").addModifiers(Modifier.PUBLIC); + hashBuilder.addJavadoc(autogenWarning); + hashBuilder.addField(FieldSpec.builder(int.class, "HASH", Modifier.STATIC, Modifier.PUBLIC, Modifier.FINAL) + .initializer("$1L", Objects.hash(methods)).build()); + + //build and write resulting hash class + TypeSpec spec = hashBuilder.build(); + JavaFile.builder(packageName, spec).build().writeTo(BaseProcessor.filer); + } + } +} diff --git a/annotations/src/main/java/mindustry/annotations/RemoteReadGenerator.java b/annotations/src/main/java/mindustry/annotations/remote/RemoteReadGenerator.java similarity index 84% rename from annotations/src/main/java/mindustry/annotations/RemoteReadGenerator.java rename to annotations/src/main/java/mindustry/annotations/remote/RemoteReadGenerator.java index 166c7c5ce5..d2d102887f 100644 --- a/annotations/src/main/java/mindustry/annotations/RemoteReadGenerator.java +++ b/annotations/src/main/java/mindustry/annotations/remote/RemoteReadGenerator.java @@ -1,16 +1,14 @@ -package mindustry.annotations; +package mindustry.annotations.remote; import com.squareup.javapoet.*; -import mindustry.annotations.IOFinder.ClassSerializer; +import mindustry.annotations.*; +import mindustry.annotations.remote.IOFinder.*; +import javax.lang.model.element.Modifier; import javax.lang.model.element.*; -import javax.tools.Diagnostic.Kind; -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.nio.ByteBuffer; -import java.util.HashMap; -import java.util.List; +import java.lang.reflect.*; +import java.nio.*; +import java.util.*; /** Generates code for reading remote invoke packets on the client and server. */ public class RemoteReadGenerator{ @@ -28,11 +26,10 @@ public class RemoteReadGenerator{ * @param packageName Full target package name. * @param needsPlayer Whether this read method requires a reference to the player sender. */ - public void generateFor(List entries, String className, String packageName, boolean needsPlayer) - throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, IOException{ + public void generateFor(List entries, String className, String packageName, boolean needsPlayer) throws Exception{ TypeSpec.Builder classBuilder = TypeSpec.classBuilder(className).addModifiers(Modifier.PUBLIC); - classBuilder.addJavadoc(RemoteMethodAnnotationProcessor.autogenWarning); + classBuilder.addJavadoc(RemoteProcess.autogenWarning); //create main method builder MethodSpec.Builder readMethod = MethodSpec.methodBuilder("readPacket") @@ -47,7 +44,7 @@ public class RemoteReadGenerator{ Constructor cons = TypeName.class.getDeclaredConstructor(String.class); cons.setAccessible(true); - TypeName playerType = cons.newInstance("mindustry.entities.type.Player"); + TypeName playerType = cons.newInstance("mindustry.gen.Playerc"); //add player parameter readMethod.addParameter(playerType, "player"); } @@ -82,7 +79,7 @@ public class RemoteReadGenerator{ String capName = typeName.equals("byte") ? "" : Character.toUpperCase(typeName.charAt(0)) + typeName.substring(1); //write primitives automatically - if(Utils.isPrimitive(typeName)){ + if(BaseProcessor.isPrimitive(typeName)){ if(typeName.equals("boolean")){ readBlock.addStatement("boolean " + varName + " = buffer.get() == 1"); }else{ @@ -90,10 +87,10 @@ public class RemoteReadGenerator{ } }else{ //else, try and find a serializer - ClassSerializer ser = serializers.get(typeName); + ClassSerializer ser = serializers.getOrDefault(typeName, SerializerResolver.locate(entry.element, var.asType())); if(ser == null){ //make sure a serializer exists! - Utils.messager.printMessage(Kind.ERROR, "No @ReadClass method to read class type: '" + typeName + "'", var); + BaseProcessor.err("No @ReadClass method to read class type '" + typeName + "' in method " + entry.targetMethod, var); return; } @@ -118,7 +115,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" + (varResult.length() == 0 ? "" : ", ") + varResult.toString() + ")"); + "__forward(player.con()" + (varResult.length() == 0 ? "" : ", ") + varResult.toString() + ")"); } readBlock.nextControlFlow("catch (java.lang.Exception e)"); @@ -139,6 +136,6 @@ public class RemoteReadGenerator{ //build and write resulting class TypeSpec spec = classBuilder.build(); - JavaFile.builder(packageName, spec).build().writeTo(Utils.filer); + JavaFile.builder(packageName, spec).build().writeTo(BaseProcessor.filer); } } diff --git a/annotations/src/main/java/mindustry/annotations/RemoteWriteGenerator.java b/annotations/src/main/java/mindustry/annotations/remote/RemoteWriteGenerator.java similarity index 86% rename from annotations/src/main/java/mindustry/annotations/RemoteWriteGenerator.java rename to annotations/src/main/java/mindustry/annotations/remote/RemoteWriteGenerator.java index dfe3f1fa00..bf6330bc51 100644 --- a/annotations/src/main/java/mindustry/annotations/RemoteWriteGenerator.java +++ b/annotations/src/main/java/mindustry/annotations/remote/RemoteWriteGenerator.java @@ -1,15 +1,15 @@ -package mindustry.annotations; +package mindustry.annotations.remote; +import arc.struct.*; import com.squareup.javapoet.*; -import mindustry.annotations.Annotations.Loc; -import mindustry.annotations.IOFinder.ClassSerializer; +import mindustry.annotations.Annotations.*; +import mindustry.annotations.*; +import mindustry.annotations.remote.IOFinder.*; import javax.lang.model.element.*; -import javax.tools.Diagnostic.Kind; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.util.HashMap; -import java.util.List; +import java.io.*; +import java.nio.*; +import java.util.*; /** Generates code for writing remote invoke packets on the client and server. */ public class RemoteWriteGenerator{ @@ -26,11 +26,11 @@ public class RemoteWriteGenerator{ for(ClassEntry entry : entries){ //create builder TypeSpec.Builder classBuilder = TypeSpec.classBuilder(entry.name).addModifiers(Modifier.PUBLIC); - classBuilder.addJavadoc(RemoteMethodAnnotationProcessor.autogenWarning); + classBuilder.addJavadoc(RemoteProcess.autogenWarning); //add temporary write buffer classBuilder.addField(FieldSpec.builder(ByteBuffer.class, "TEMP_BUFFER", Modifier.STATIC, Modifier.PRIVATE, Modifier.FINAL) - .initializer("ByteBuffer.allocate($1L)", RemoteMethodAnnotationProcessor.maxPacketSize).build()); + .initializer("ByteBuffer.allocate($1L)", RemoteProcess.maxPacketSize).build()); //go through each method entry in this class for(MethodEntry methodEntry : entry.methods){ @@ -52,7 +52,7 @@ public class RemoteWriteGenerator{ //build and write resulting class TypeSpec spec = classBuilder.build(); - JavaFile.builder(packageName, spec).build().writeTo(Utils.filer); + JavaFile.builder(packageName, spec).build().writeTo(BaseProcessor.filer); } } @@ -73,12 +73,12 @@ public class RemoteWriteGenerator{ //validate client methods to make sure if(methodEntry.where.isClient){ if(elem.getParameters().isEmpty()){ - Utils.messager.printMessage(Kind.ERROR, "Client invoke methods must have a first parameter of type Player.", elem); + BaseProcessor.err("Client invoke methods must have a first parameter of type Player", elem); return; } - if(!elem.getParameters().get(0).asType().toString().equals("mindustry.entities.type.Player")){ - Utils.messager.printMessage(Kind.ERROR, "Client invoke methods should have a first parameter of type Player.", elem); + if(!elem.getParameters().get(0).asType().toString().equals("Playerc")){ + BaseProcessor.err("Client invoke methods should have a first parameter of type Playerc", elem); return; } } @@ -137,6 +137,8 @@ public class RemoteWriteGenerator{ //rewind buffer method.addStatement("TEMP_BUFFER.position(0)"); + method.addTypeVariables(Array.with(elem.getTypeParameters()).map(BaseProcessor::getTVN)); + for(int i = 0; i < elem.getParameters().size(); i++){ //first argument is skipped as it is always the player caller if((!methodEntry.where.isServer/* || methodEntry.mode == Loc.both*/) && i == 0){ @@ -145,8 +147,12 @@ public class RemoteWriteGenerator{ VariableElement var = elem.getParameters().get(i); - //add parameter to method - method.addParameter(TypeName.get(var.asType()), var.getSimpleName().toString()); + try{ + //add parameter to method + method.addParameter(TypeName.get(var.asType()), var.getSimpleName().toString()); + }catch(Throwable t){ + throw new RuntimeException("Error parsing method " + methodEntry.targetMethod); + } //name of parameter String varName = var.getSimpleName().toString(); @@ -162,7 +168,7 @@ public class RemoteWriteGenerator{ method.beginControlFlow("if(mindustry.Vars.net.server())"); } - if(Utils.isPrimitive(typeName)){ //check if it's a primitive, and if so write it + if(BaseProcessor.isPrimitive(typeName)){ //check if it's a primitive, and if so write it if(typeName.equals("boolean")){ //booleans are special method.addStatement("TEMP_BUFFER.put(" + varName + " ? (byte)1 : 0)"); }else{ @@ -171,10 +177,10 @@ public class RemoteWriteGenerator{ } }else{ //else, try and find a serializer - ClassSerializer ser = serializers.get(typeName); + ClassSerializer ser = serializers.getOrDefault(typeName, SerializerResolver.locate(elem, var.asType())); if(ser == null){ //make sure a serializer exists! - Utils.messager.printMessage(Kind.ERROR, "No @WriteClass method to write class type: '" + typeName + "'", var); + BaseProcessor.err("No @WriteClass method to write class type: '" + typeName + "'", var); return; } diff --git a/annotations/src/main/java/mindustry/annotations/remote/SerializerResolver.java b/annotations/src/main/java/mindustry/annotations/remote/SerializerResolver.java new file mode 100644 index 0000000000..d1668bdfc2 --- /dev/null +++ b/annotations/src/main/java/mindustry/annotations/remote/SerializerResolver.java @@ -0,0 +1,29 @@ +package mindustry.annotations.remote; + +import arc.struct.*; +import mindustry.annotations.remote.IOFinder.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class SerializerResolver{ + private static final ClassSerializer entitySerializer = new ClassSerializer("mindustry.io.TypeIO.readEntity", "mindustry.io.TypeIO.writeEntity", "Entityc"); + + public static ClassSerializer locate(ExecutableElement elem, TypeMirror mirror){ + //generic type + if(mirror.toString().equals("T")){ + TypeParameterElement param = elem.getTypeParameters().get(0); + if(Array.with(param.getBounds()).contains(SerializerResolver::isEntity)){ + return entitySerializer; + } + } + if(isEntity(mirror)){ + return entitySerializer; + } + return null; + } + + private static boolean isEntity(TypeMirror mirror){ + return !mirror.toString().contains(".") && mirror.toString().endsWith("c"); + } +} diff --git a/annotations/src/main/java/mindustry/annotations/util/AnnotationProxyMaker.java b/annotations/src/main/java/mindustry/annotations/util/AnnotationProxyMaker.java new file mode 100644 index 0000000000..352c684e74 --- /dev/null +++ b/annotations/src/main/java/mindustry/annotations/util/AnnotationProxyMaker.java @@ -0,0 +1,287 @@ +package mindustry.annotations.util; + +import com.sun.tools.javac.code.*; +import com.sun.tools.javac.code.Attribute.Array; +import com.sun.tools.javac.code.Attribute.Enum; +import com.sun.tools.javac.code.Attribute.Error; +import com.sun.tools.javac.code.Attribute.Visitor; +import com.sun.tools.javac.code.Attribute.*; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Symbol.*; +import com.sun.tools.javac.code.Type.ArrayType; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.*; +import sun.reflect.annotation.*; + +import javax.lang.model.type.*; +import java.io.*; +import java.lang.annotation.*; +import java.lang.reflect.*; +import java.util.*; +import java.util.Map.*; +import java.lang.Class; + +//replaces the standard Java AnnotationProxyMaker with one that doesn't crash +//thanks, oracle. +@SuppressWarnings({"sunapi", "unchecked"}) +public class AnnotationProxyMaker{ + private final Compound anno; + private final Class annoType; + + private AnnotationProxyMaker(Compound var1, Class var2){ + this.anno = var1; + this.annoType = var2; + } + + public static A generateAnnotation(Compound var0, Class var1){ + AnnotationProxyMaker var2 = new AnnotationProxyMaker(var0, var1); + return (A)var1.cast(var2.generateAnnotation()); + } + + private Annotation generateAnnotation(){ + return AnnotationParser.annotationForMap(this.annoType, this.getAllReflectedValues()); + } + + private Map getAllReflectedValues(){ + LinkedHashMap var1 = new LinkedHashMap(); + Iterator var2 = this.getAllValues().entrySet().iterator(); + + while(var2.hasNext()){ + Entry var3 = (Entry)var2.next(); + MethodSymbol var4 = (MethodSymbol)var3.getKey(); + Object var5 = this.generateValue(var4, (Attribute)var3.getValue()); + if(var5 != null){ + var1.put(var4.name.toString(), var5); + } + } + + return var1; + } + + private Map getAllValues(){ + LinkedHashMap var1 = new LinkedHashMap(); + ClassSymbol var2 = (ClassSymbol)this.anno.type.tsym; + + for(com.sun.tools.javac.code.Scope.Entry var3 = var2.members().elems; var3 != null; var3 = var3.sibling){ + if(var3.sym.kind == 16){ + MethodSymbol var4 = (MethodSymbol)var3.sym; + Attribute var5 = var4.getDefaultValue(); + if(var5 != null){ + var1.put(var4, var5); + } + } + } + + Iterator var6 = this.anno.values.iterator(); + + while(var6.hasNext()){ + Pair var7 = (Pair)var6.next(); + var1.put(var7.fst, var7.snd); + } + + return var1; + } + + private Object generateValue(MethodSymbol var1, Attribute var2){ + AnnotationProxyMaker.ValueVisitor var3 = new AnnotationProxyMaker.ValueVisitor(var1); + return var3.getValue(var2); + } + + private static final class MirroredTypesExceptionProxy extends ExceptionProxy{ + static final long serialVersionUID = 269L; + private transient List types; + private final String typeStrings; + + MirroredTypesExceptionProxy(List var1){ + this.types = var1; + this.typeStrings = var1.toString(); + } + + public String toString(){ + return this.typeStrings; + } + + public int hashCode(){ + return (this.types != null ? this.types : this.typeStrings).hashCode(); + } + + public boolean equals(Object var1){ + return this.types != null && var1 instanceof AnnotationProxyMaker.MirroredTypesExceptionProxy && this.types.equals(((AnnotationProxyMaker.MirroredTypesExceptionProxy)var1).types); + } + + protected RuntimeException generateException(){ + return new MirroredTypesException(this.types); + } + + private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException{ + var1.defaultReadObject(); + this.types = null; + } + } + + private static final class MirroredTypeExceptionProxy extends ExceptionProxy{ + static final long serialVersionUID = 269L; + private transient TypeMirror type; + private final String typeString; + + MirroredTypeExceptionProxy(TypeMirror var1){ + this.type = var1; + this.typeString = var1.toString(); + } + + public String toString(){ + return this.typeString; + } + + public int hashCode(){ + return (this.type != null ? this.type : this.typeString).hashCode(); + } + + public boolean equals(Object var1){ + return this.type != null && var1 instanceof AnnotationProxyMaker.MirroredTypeExceptionProxy && this.type.equals(((AnnotationProxyMaker.MirroredTypeExceptionProxy)var1).type); + } + + protected RuntimeException generateException(){ + return new MirroredTypeException(this.type); + } + + private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException{ + var1.defaultReadObject(); + this.type = null; + } + } + + private class ValueVisitor implements Visitor{ + private MethodSymbol meth; + private Class returnClass; + private Object value; + + ValueVisitor(MethodSymbol var2){ + this.meth = var2; + } + + Object getValue(Attribute var1){ + Method var2; + try{ + var2 = AnnotationProxyMaker.this.annoType.getMethod(this.meth.name.toString()); + }catch(NoSuchMethodException var4){ + return null; + } + + this.returnClass = var2.getReturnType(); + var1.accept(this); + if(!(this.value instanceof ExceptionProxy) && !AnnotationType.invocationHandlerReturnType(this.returnClass).isInstance(this.value)){ + this.typeMismatch(var2, var1); + } + + return this.value; + } + + public void visitConstant(Constant var1){ + this.value = var1.getValue(); + } + + public void visitClass(com.sun.tools.javac.code.Attribute.Class var1){ + this.value = new AnnotationProxyMaker.MirroredTypeExceptionProxy(var1.classType); + } + + public void visitArray(Array var1){ + Name var2 = ((ArrayType)var1.type).elemtype.tsym.getQualifiedName(); + int var6; + if(var2.equals(var2.table.names.java_lang_Class)){ + ListBuffer var14 = new ListBuffer(); + Attribute[] var15 = var1.values; + int var16 = var15.length; + + for(var6 = 0; var6 < var16; ++var6){ + Attribute var7 = var15[var6]; + Type var8 = var7 instanceof UnresolvedClass ? ((UnresolvedClass)var7).classType : ((com.sun.tools.javac.code.Attribute.Class)var7).classType; + var14.append(var8); + } + + this.value = new AnnotationProxyMaker.MirroredTypesExceptionProxy(var14.toList()); + }else{ + int var3 = var1.values.length; + Class var4 = this.returnClass; + this.returnClass = this.returnClass.getComponentType(); + + try{ + Object var5 = java.lang.reflect.Array.newInstance(this.returnClass, var3); + + for(var6 = 0; var6 < var3; ++var6){ + var1.values[var6].accept(this); + if(this.value == null || this.value instanceof ExceptionProxy){ + return; + } + + try{ + java.lang.reflect.Array.set(var5, var6, this.value); + }catch(IllegalArgumentException var12){ + this.value = null; + return; + } + } + + this.value = var5; + }finally{ + this.returnClass = var4; + } + } + } + + public void visitEnum(Enum var1){ + if(this.returnClass.isEnum()){ + String var2 = var1.value.toString(); + + try{ + this.value = java.lang.Enum.valueOf((Class)this.returnClass, var2); + }catch(IllegalArgumentException var4){ + this.value = new EnumConstantNotPresentExceptionProxy((Class)this.returnClass, var2); + } + }else{ + this.value = null; + } + + } + + public void visitCompound(Compound var1){ + try{ + Class var2 = this.returnClass.asSubclass(Annotation.class); + this.value = AnnotationProxyMaker.generateAnnotation(var1, var2); + }catch(ClassCastException var3){ + this.value = null; + } + + } + + public void visitError(Error var1){ + if(var1 instanceof UnresolvedClass){ + this.value = new AnnotationProxyMaker.MirroredTypeExceptionProxy(((UnresolvedClass)var1).classType); + }else{ + this.value = null; + } + + } + + private void typeMismatch(Method var1, final Attribute var2){ + class AnnotationTypeMismatchExceptionProxy extends ExceptionProxy{ + static final long serialVersionUID = 269L; + final transient Method method; + + AnnotationTypeMismatchExceptionProxy(Method var2x){ + this.method = var2x; + } + + public String toString(){ + return ""; + } + + protected RuntimeException generateException(){ + return new AnnotationTypeMismatchException(this.method, var2.type.toString()); + } + } + + this.value = new AnnotationTypeMismatchExceptionProxy(var1); + } + } +} diff --git a/annotations/src/main/java/mindustry/annotations/util/Selement.java b/annotations/src/main/java/mindustry/annotations/util/Selement.java new file mode 100644 index 0000000000..def6b001e9 --- /dev/null +++ b/annotations/src/main/java/mindustry/annotations/util/Selement.java @@ -0,0 +1,106 @@ +package mindustry.annotations.util; + +import arc.struct.Array; +import com.squareup.javapoet.*; +import com.sun.tools.javac.code.Attribute.*; +import mindustry.annotations.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; +import java.lang.Class; +import java.lang.annotation.*; +import java.lang.reflect.*; + +public class Selement{ + public final T e; + + public Selement(T e){ + this.e = e; + } + + public Array> enclosed(){ + return Array.with(e.getEnclosedElements()).map(Selement::new); + } + + public String fullName(){ + return e.toString(); + } + + public Stype asType(){ + return new Stype((TypeElement)e); + } + + public Svar asVar(){ + return new Svar((VariableElement)e); + } + + public Smethod asMethod(){ + return new Smethod((ExecutableElement)e); + } + + public boolean isVar(){ + return e instanceof VariableElement; + } + + public boolean isType(){ + return e instanceof TypeElement; + } + + public boolean isMethod(){ + return e instanceof ExecutableElement; + } + + public Array annotations(){ + return Array.with(e.getAnnotationMirrors()); + } + + public A annotation(Class annotation){ + try{ + Method m = com.sun.tools.javac.code.AnnoConstruct.class.getDeclaredMethod("getAttribute", Class.class); + m.setAccessible(true); + Compound compound = (Compound)m.invoke(e, annotation); + return compound == null ? null : AnnotationProxyMaker.generateAnnotation(compound, annotation); + }catch(Exception e){ + throw new RuntimeException(e); + } + } + + public boolean has(Class annotation){ + return annotation(annotation) != null; + } + + public Element up(){ + return e.getEnclosingElement(); + } + + public TypeMirror mirror(){ + return e.asType(); + } + + public TypeName tname(){ + return TypeName.get(mirror()); + } + + public ClassName cname(){ + return ClassName.get((TypeElement)BaseProcessor.typeu.asElement(mirror())); + } + + public String name(){ + return e.getSimpleName().toString(); + } + + @Override + public String toString(){ + return e.toString(); + } + + @Override + public int hashCode(){ + return e.hashCode(); + } + + @Override + public boolean equals(Object o){ + return o != null && o.getClass() == getClass() && e == ((Selement)o).e; + } +} diff --git a/annotations/src/main/java/mindustry/annotations/util/Smethod.java b/annotations/src/main/java/mindustry/annotations/util/Smethod.java new file mode 100644 index 0000000000..9eedb5bb7e --- /dev/null +++ b/annotations/src/main/java/mindustry/annotations/util/Smethod.java @@ -0,0 +1,67 @@ +package mindustry.annotations.util; + +import arc.struct.*; +import com.squareup.javapoet.*; +import com.sun.source.tree.*; +import mindustry.annotations.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class Smethod extends Selement{ + + public Smethod(ExecutableElement executableElement){ + super(executableElement); + } + + public boolean isAny(Modifier... mod){ + for(Modifier m : mod){ + if(is(m)) return true; + } + return false; + } + + public boolean is(Modifier mod){ + return e.getModifiers().contains(mod); + } + + public Stype type(){ + return new Stype((TypeElement)up()); + } + + public Array thrown(){ + return Array.with(e.getThrownTypes()).as(TypeMirror.class); + } + + public Array thrownt(){ + return Array.with(e.getThrownTypes()).map(TypeName::get); + } + + public Array typeVariables(){ + return Array.with(e.getTypeParameters()).as(TypeParameterElement.class); + } + + public Array params(){ + return Array.with(e.getParameters()).map(Svar::new); + } + + public boolean isVoid(){ + return ret().toString().equals("void"); + } + + public TypeMirror ret(){ + return e.getReturnType(); + } + + public TypeName retn(){ + return TypeName.get(ret()); + } + + public MethodTree tree(){ + return BaseProcessor.trees.getTree(e); + } + + public String simpleString(){ + return name() + "(" + params().toString(", ", p -> BaseProcessor.simpleName(p.mirror().toString())) + ")"; + } +} diff --git a/annotations/src/main/java/mindustry/annotations/util/Stype.java b/annotations/src/main/java/mindustry/annotations/util/Stype.java new file mode 100644 index 0000000000..2582ae2fbb --- /dev/null +++ b/annotations/src/main/java/mindustry/annotations/util/Stype.java @@ -0,0 +1,61 @@ +package mindustry.annotations.util; + +import arc.struct.*; +import mindustry.annotations.*; + +import javax.lang.model.element.*; +import javax.lang.model.type.*; + +public class Stype extends Selement{ + + public Stype(TypeElement typeElement){ + super(typeElement); + } + + public static Stype of(TypeMirror mirror){ + return new Stype((TypeElement)BaseProcessor.typeu.asElement(mirror)); + } + + public String fullName(){ + return mirror().toString(); + } + + public Array interfaces(){ + return Array.with(e.getInterfaces()).map(Stype::of); + } + + public Array allInterfaces(){ + return interfaces().flatMap(s -> s.allInterfaces().and(s)).distinct(); + } + + public Array superclasses(){ + return Array.with(BaseProcessor.typeu.directSupertypes(mirror())).map(Stype::of); + } + + public Array allSuperclasses(){ + return superclasses().flatMap(s -> s.allSuperclasses().and(s)).distinct(); + } + + public Stype superclass(){ + return new Stype((TypeElement)BaseProcessor.typeu.asElement(BaseProcessor.typeu.directSupertypes(mirror()).get(0))); + } + + public Array fields(){ + return Array.with(e.getEnclosedElements()).select(e -> e instanceof VariableElement).map(e -> new Svar((VariableElement)e)); + } + + public Array methods(){ + return Array.with(e.getEnclosedElements()).select(e -> e instanceof ExecutableElement + && !e.getSimpleName().toString().contains("<")).map(e -> new Smethod((ExecutableElement)e)); + } + + public Array constructors(){ + return Array.with(e.getEnclosedElements()).select(e -> e instanceof ExecutableElement + && e.getSimpleName().toString().contains("<")).map(e -> new Smethod((ExecutableElement)e)); + } + + @Override + public TypeMirror mirror(){ + return e.asType(); + } +} diff --git a/annotations/src/main/java/mindustry/annotations/util/Svar.java b/annotations/src/main/java/mindustry/annotations/util/Svar.java new file mode 100644 index 0000000000..cf58d7a6f5 --- /dev/null +++ b/annotations/src/main/java/mindustry/annotations/util/Svar.java @@ -0,0 +1,21 @@ +package mindustry.annotations.util; + +import com.sun.source.tree.*; +import mindustry.annotations.*; + +import javax.lang.model.element.*; + +public class Svar extends Selement{ + + public Svar(VariableElement e){ + super(e); + } + + public boolean is(Modifier mod){ + return e.getModifiers().contains(mod); + } + + public VariableTree tree(){ + return (VariableTree)BaseProcessor.trees.getTree(e); + } +} diff --git a/annotations/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/annotations/src/main/resources/META-INF/services/javax.annotation.processing.Processor deleted file mode 100644 index 0888df74ee..0000000000 --- a/annotations/src/main/resources/META-INF/services/javax.annotation.processing.Processor +++ /dev/null @@ -1,5 +0,0 @@ -mindustry.annotations.RemoteMethodAnnotationProcessor -mindustry.annotations.SerializeAnnotationProcessor -mindustry.annotations.StructAnnotationProcessor -mindustry.annotations.CallSuperAnnotationProcessor -mindustry.annotations.AssetsAnnotationProcessor \ No newline at end of file diff --git a/annotations/src/main/resources/classids.properties b/annotations/src/main/resources/classids.properties new file mode 100644 index 0000000000..42de63b71b --- /dev/null +++ b/annotations/src/main/resources/classids.properties @@ -0,0 +1,14 @@ +#Maps entity names to IDs. Autogenerated. + +dagger=7 +mindustry.entities.AllEntities.GenericBuilderDef=6 +mindustry.entities.AllEntities.BulletDef=0 +mindustry.entities.AllEntities.PlayerDef=4 +mindustry.entities.AllEntities.GroundEffectDef=9 +mindustry.entities.AllEntities.FireDef=11 +mindustry.entities.AllEntities.EffectDef=2 +mindustry.entities.AllEntities.GenericUnitDef=5 +mindustry.entities.AllEntities.TileDef=3 +vanguard=10 +dagger2=8 +mindustry.entities.AllEntities.DecalDef=1 \ No newline at end of file diff --git a/build.gradle b/build.gradle index fa8bf4d7aa..8aa9762606 100644 --- a/build.gradle +++ b/build.gradle @@ -1,4 +1,12 @@ buildscript{ + ext{ + getArcHash = { + return new Properties().with{ p -> p.load(file('gradle.properties').newReader()); return p }["archash"] + } + + arcHash = getArcHash() + } + repositories{ mavenLocal() mavenCentral() @@ -10,8 +18,9 @@ buildscript{ dependencies{ classpath 'com.mobidevelop.robovm:robovm-gradle-plugin:2.3.8' - classpath "com.badlogicgames.gdx:gdx-tools:1.9.10" classpath "com.github.anuken:packr:-SNAPSHOT" + classpath "com.github.Anuken.Arc:packer:$arcHash" + classpath "com.github.Anuken.Arc:arc-core:$arcHash" } } @@ -28,7 +37,6 @@ allprojects{ gdxVersion = '1.9.10' roboVMVersion = '2.3.8' steamworksVersion = '891ed912791e01fe9ee6237a6497e5212b85c256' - arcHash = null loadVersionProps = { return new Properties().with{p -> p.load(file('../core/assets/version.properties').newReader()); return p } @@ -42,10 +50,6 @@ allprojects{ return !project.hasProperty("release") && new File(projectDir.parent, '../Arc').exists() } - getArcHash = { - return new Properties().with{ p -> p.load(file('gradle.properties').newReader()); return p }["archash"] - } - arcModule = { String name -> if(localArc()){ return project(":Arc:$name") @@ -128,6 +132,20 @@ allprojects{ props.store(pfile.newWriter(), "Autogenerated file. Do not modify.") } } + + writeProcessors = { + new File(rootDir, "annotations/src/main/resources/META-INF/services/").mkdirs() + def processorFile = new File(rootDir, "annotations/src/main/resources/META-INF/services/javax.annotation.processing.Processor") + def text = new StringBuilder() + def files = new File(rootDir, "annotations/src/main/java") + files.eachFileRecurse(groovy.io.FileType.FILES){ file -> + if(file.name.endsWith(".java") && (file.text.contains(" extends BaseProcessor") || (file.text.contains(" extends AbstractProcessor") && !file.text.contains("abstract class")))){ + text.append(file.path.substring(files.path.length() + 1)).append("\n") + } + } + + processorFile.text = text.toString().replace(".java", "").replace("/", ".").replace("\\", ".") + } } repositories{ @@ -145,6 +163,9 @@ allprojects{ project(":desktop"){ apply plugin: "java" + compileJava.options.fork = true + compileJava.options.compilerArgs += ["-XDignore.symbol.file"] + dependencies{ compile project(":core") @@ -201,6 +222,7 @@ project(":core"){ outputs.upToDateWhen{ false } generateLocales() writeVersion() + writeProcessors() } task copyChangelog{ @@ -225,31 +247,6 @@ project(":core"){ } dependencies{ - if(System.properties["user.name"] == "anuke"){ - task cleanGen{ - doFirst{ - delete{ - delete "../core/src/mindustry/gen/" - } - } - } - - task copyGen{ - doLast{ - copy{ - from("../core/build/generated/sources/annotationProcessor/java/main/mindustry/gen"){ - include "**/*.java" - } - - into "../core/src/mindustry/gen" - } - } - } - - compileJava.dependsOn(cleanGen) - compileJava.finalizedBy(copyGen) - } - compileJava.dependsOn(preGen) compile "org.lz4:lz4-java:1.4.1" @@ -299,7 +296,7 @@ project(":tools"){ compile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" compile "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop" - compile "org.reflections:reflections:0.9.11" + compile "org.reflections:reflections:0.9.12" compile arcModule("backends:backend-sdl") } @@ -309,8 +306,8 @@ project(":annotations"){ apply plugin: "java" dependencies{ - compile 'com.squareup:javapoet:1.11.0' - compile "com.github.Anuken.Arc:arc-core:b77767039334b2658f44d69e72d1ef6bc84f95b0" + compile 'com.squareup:javapoet:1.12.1' + compile "com.github.Anuken.Arc:arc-core:$arcHash" compile files("${System.getProperty('java.home')}/../lib/tools.jar") } } diff --git a/core/assets-raw/fontgen/config.json b/core/assets-raw/fontgen/config.json index 7d79a71094..e5034e70fe 100644 --- a/core/assets-raw/fontgen/config.json +++ b/core/assets-raw/fontgen/config.json @@ -164,12 +164,6 @@ "code": 59414, "src": "typicons" }, - { - "uid": "b90868gfogj970a1g0dnot6hm5r4uj55", - "css": "chat", - "code": 59415, - "src": "typicons" - }, { "uid": "890649841b2c37d56ff90065872fecf3", "css": "chart-bar", @@ -182,12 +176,6 @@ "code": 59418, "src": "typicons" }, - { - "uid": "bczb7qup4axmc490xmuuv8qdhcnbgeyf", - "css": "user", - "code": 59420, - "src": "typicons" - }, { "uid": "4109c474ff99cad28fd5a2c38af2ec6f", "css": "filter", @@ -296,12 +284,6 @@ "code": 59439, "src": "typicons" }, - { - "uid": "e45e9f27ce40ba9837cc984076d98067", - "css": "zoom", - "code": 59441, - "src": "elusive" - }, { "uid": "0e26e70b4aa537cc206f41b21dcf2fcc", "css": "lock", @@ -819,6 +801,124 @@ "search": [ "pencil" ] + }, + { + "uid": "346f9aef245e0c2ded44e31ad7c66acb", + "css": "mode-pvp", + "code": 59477, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M305.8 0C296.1 0 286.4 1.6 276.7 4.9 257.3 11.3 244.3 24.3 237.9 43.7 231.4 63.1 231.4 82.5 237.9 101.9 244.3 121.4 254 137.5 267 150.5L305.8 189.3 344.7 228.2 383.5 267C396.4 279.9 409.4 286.4 422.3 286.4 435.3 286.4 448.2 279.9 461.2 267L500 228.2C512.9 215.2 519.4 202.3 519.4 189.3 519.4 176.4 512.9 163.4 500 150.5L461.2 111.7 422.3 72.8 383.5 34C370.6 21 354.4 11.3 335 4.9 325.2 1.6 315.5 0 305.8 0ZM927.2 0C917.5 0 907.8 1.6 898.1 4.9 878.6 11.3 862.5 21 849.5 34L810.7 72.8 771.8 111.7 733 150.5 694.2 189.3 655.3 228.2 616.5 267 577.7 305.8 538.8 344.7 500 383.5 461.2 422.3 422.3 461.2 383.5 500C370.6 512.9 354.4 522.7 335 529.1 315.5 535.6 296.1 535.6 276.7 529.1 257.3 522.7 241.1 512.9 228.2 500 215.2 487.1 199 477.3 179.6 470.9 160.2 464.4 140.8 464.4 121.4 470.9 101.9 477.3 89 490.3 82.5 509.7 76.1 529.1 76.1 548.5 82.5 568 89 587.4 98.7 603.6 111.7 616.5 124.6 629.5 134.3 645.6 140.8 665 147.2 684.5 147.2 703.9 140.8 723.3 134.3 742.7 124.6 758.9 111.7 771.8L72.8 810.7 34 849.5C21 862.5 11.3 878.6 4.9 898.1-1.6 917.5-1.6 936.9 4.9 956.3 11.3 975.7 24.3 988.7 43.7 995.1 63.1 1001.6 82.5 1001.6 101.9 995.1 121.4 988.7 137.5 979 150.5 966L189.3 927.2 228.2 888.3C241.1 875.4 257.3 865.7 276.7 859.2 296.1 852.8 315.5 852.8 335 859.2 354.4 865.7 370.6 875.4 383.5 888.3 396.4 901.3 412.6 911 432 917.5 451.5 923.9 470.9 923.9 490.3 917.5 509.7 911 522.7 898.1 529.1 878.6 535.6 859.2 535.6 839.8 529.1 820.4 522.7 801 512.9 784.8 500 771.8 487.1 758.9 477.3 742.7 470.9 723.3 464.4 703.9 464.4 684.5 470.9 665 477.3 645.6 487.1 629.5 500 616.5L538.8 577.7 577.7 538.8 616.5 500 655.3 461.2 694.2 422.3 733 383.5 771.8 344.7 810.7 305.8 849.5 267 888.3 228.2 927.2 189.3 966 150.5C979 137.5 988.7 121.4 995.1 101.9 1001.6 82.5 1001.6 63.1 995.1 43.7 988.7 24.3 975.7 11.3 956.3 4.9 946.6 1.6 936.9 0 927.2 0ZM1082.5 466C1072.8 466 1063.1 467.6 1053.4 470.9 1034 477.3 1017.8 487.1 1004.9 500 991.9 512.9 975.7 522.7 956.3 529.1 936.9 535.6 917.5 535.6 898.1 529.1 878.6 522.7 862.5 512.9 849.5 500 836.6 487.1 823.6 480.6 810.7 480.6 797.7 480.6 784.8 487.1 771.8 500L733 538.8C720.1 551.8 713.6 564.7 713.6 577.7 713.6 590.6 720.1 603.6 733 616.5 746 629.5 755.7 645.6 762.1 665 768.6 684.5 768.6 703.9 762.1 723.3 755.7 742.7 746 758.9 733 771.8 720.1 784.8 710.4 801 703.9 820.4 697.4 839.8 697.4 859.2 703.9 878.6 710.4 898.1 723.3 911 742.7 917.5 762.1 923.9 781.6 923.9 801 917.5 820.4 911 836.6 901.3 849.5 888.3 862.5 875.4 878.6 865.7 898.1 859.2 917.5 852.8 936.9 852.8 956.3 859.2 975.7 865.7 991.9 875.4 1004.9 888.3L1043.7 927.2 1082.5 966C1095.5 979 1111.7 988.7 1131.1 995.1 1150.5 1001.6 1169.9 1001.6 1189.3 995.1 1208.7 988.7 1221.7 975.7 1228.2 956.3 1234.6 936.9 1234.6 917.5 1228.2 898.1 1221.7 878.6 1212 862.5 1199 849.5L1160.2 810.7 1121.4 771.8C1108.4 758.9 1098.7 742.7 1092.2 723.3 1085.8 703.9 1085.8 684.5 1092.2 665 1098.7 645.6 1108.4 629.5 1121.4 616.5 1134.3 603.6 1144 587.4 1150.5 568 1157 548.5 1157 529.1 1150.5 509.7 1144 490.3 1131.1 477.3 1111.7 470.9 1101.9 467.6 1092.2 466 1082.5 466Z", + "width": 1233 + }, + "search": [ + "mode-pvp" + ] + }, + { + "uid": "8d74cd519427de451b48df6554aaf593", + "css": "mode-attack", + "code": 59478, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M849.5 34Q868.9 14.6 898.1 4.9 927.2-4.9 956.3 4.9 985.4 14.6 995.1 43.7 1004.9 72.8 995.1 101.9 985.4 131.1 966 150.5 946.6 169.9 927.2 189.3 907.8 208.7 888.3 228.2 868.9 247.6 849.5 267 830.1 286.4 810.7 305.8 791.3 325.2 771.8 344.7 752.4 364.1 733 383.5 713.6 402.9 694.2 422.3 674.8 441.7 655.3 461.2 635.9 480.6 616.5 500 597.1 519.4 577.7 538.8 558.3 558.3 538.8 577.7 519.4 597.1 500 616.5 480.6 635.9 470.9 665 461.2 694.2 470.9 723.3 480.6 752.4 500 771.8 519.4 791.3 529.1 820.4 538.8 849.5 529.1 878.6 519.4 907.8 490.3 917.5 461.2 927.2 432 917.5 402.9 907.8 383.5 888.3 364.1 868.9 335 859.2 305.8 849.5 276.7 859.2 247.6 868.9 228.2 888.3 208.7 907.8 189.3 927.2 169.9 946.6 150.5 966 131.1 985.4 101.9 995.1 72.8 1004.9 43.7 995.1 14.6 985.4 4.9 956.3-4.9 927.2 4.9 898.1 14.6 868.9 34 849.5 53.4 830.1 72.8 810.7 92.2 791.3 111.7 771.8 131.1 752.4 140.8 723.3 150.5 694.2 140.8 665 131.1 635.9 111.7 616.5 92.2 597.1 82.5 568 72.8 538.8 82.5 509.7 92.2 480.6 121.4 470.9 150.5 461.2 179.6 470.9 208.7 480.6 228.2 500 247.6 519.4 276.7 529.1 305.8 538.8 335 529.1 364.1 519.4 383.5 500 402.9 480.6 422.3 461.2 441.7 441.7 461.2 422.3 480.6 402.9 500 383.5 519.4 364.1 538.8 344.7 558.3 325.2 577.7 305.8 597.1 286.4 616.5 267 635.9 247.6 655.3 228.2 674.8 208.7 694.2 189.3 713.6 169.9 733 150.5 752.4 131.1 771.8 111.7 791.3 92.2 810.7 72.8 830.1 53.4 849.5 34", + "width": 1000 + }, + "search": [ + "mode-attack" + ] + }, + { + "uid": "09e5948ca30589e5baa8d27e1c509588", + "css": "mode-survival", + "code": 59479, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M9.7 43.5Q19.3 14.5 48.3 4.8 77.3-4.8 106.3 4.8 135.3 14.5 154.6 33.8 173.9 53.1 193.2 72.5 212.6 91.8 231.9 111.1 251.2 130.4 280.2 140.1 309.2 149.8 347.8 149.8 386.5 149.8 425.1 149.8 463.8 149.8 502.4 149.8 541.1 149.8 579.7 149.8 618.4 149.8 647.3 140.1 676.3 130.4 695.7 111.1 715 91.8 734.3 72.5 753.6 53.1 772.9 33.8 792.3 14.5 821.3 4.8 850.2-4.8 879.2 4.8 908.2 14.5 917.9 43.5 927.5 72.5 927.5 111.1 927.5 149.8 927.5 188.4 927.5 227.1 927.5 265.7 927.5 304.3 927.5 343 927.5 381.6 927.5 420.3 927.5 458.9 927.5 497.6 927.5 536.2 927.5 574.9 927.5 613.5 917.9 642.5 908.2 671.5 888.9 690.8 869.6 710.1 850.2 729.5 830.9 748.8 811.6 768.1 792.3 787.4 772.9 806.8 753.6 826.1 734.3 845.4 715 864.7 695.7 884.1 676.3 903.4 657 922.7 637.7 942 618.4 961.4 599 980.7 570 990.3 541.1 1000 502.4 1000 463.8 1000 425.1 1000 386.5 1000 357.5 990.3 328.5 980.7 309.2 961.4 289.9 942 270.5 922.7 251.2 903.4 231.9 884.1 212.6 864.7 193.2 845.4 173.9 826.1 154.6 806.8 135.3 787.4 115.9 768.1 96.6 748.8 77.3 729.5 58 710.1 38.6 690.8 19.3 671.5 9.7 642.5 0 613.5 0 574.9 0 536.2 0 497.6 0 458.9 0 420.3 0 381.6 0 343 0 304.3 0 265.7 0 227.1 0 188.4 0 149.8 0 111.1 0 72.5 9.7 43.5", + "width": 928 + }, + "search": [ + "mode-survival" + ] + }, + { + "uid": "3a617b3ed2fe766baec5b723b1d9502f", + "css": "command-rally", + "code": 59480, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M166.7 83.3Q208.3 41.7 270.8 20.8 333.3 0 416.7 0 500 0 583.3 0 666.7 0 729.2 20.8 791.7 41.7 833.3 83.3 875 125 916.7 166.7 958.3 208.3 979.2 270.8 1000 333.3 1000 416.7 1000 500 1000 583.3 1000 666.7 979.2 729.2 958.3 791.7 916.7 833.3 875 875 833.3 916.7 791.7 958.3 729.2 979.2 666.7 1000 583.3 1000 500 1000 416.7 1000 333.3 1000 270.8 979.2 208.3 958.3 166.7 916.7 125 875 83.3 833.3 41.7 791.7 20.8 729.2 0 666.7 0 583.3 0 500 0 416.7 0 333.3 20.8 270.8 41.7 208.3 83.3 166.7 125 125 166.7 83.3M437.5 812.5Q500 833.3 562.5 812.5 625 791.7 666.7 750 708.3 708.3 750 666.7 791.7 625 812.5 562.5 833.3 500 812.5 437.5 791.7 375 750 333.3 708.3 291.7 666.7 250 625 208.3 562.5 187.5 500 166.7 437.5 187.5 375 208.3 333.3 250 291.7 291.7 250 333.3 208.3 375 187.5 437.5 166.7 500 187.5 562.5 208.3 625 250 666.7 291.7 708.3 333.3 750 375 791.7 437.5 812.5", + "width": 1000 + }, + "search": [ + "command-rally" + ] + }, + { + "uid": "90fb5a431ca95c46a446c8f4a481d5ce", + "css": "command-attack", + "code": 59481, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M670.2 74.5Q712.8 31.9 776.6 10.6 840.4-10.6 904.3 10.6 968.1 31.9 989.4 95.7 1010.6 159.6 989.4 223.4 968.1 287.2 925.5 329.8 883 372.3 840.4 414.9 797.9 457.4 755.3 500 712.8 542.6 670.2 585.1 627.7 627.7 585.1 670.2 542.6 712.8 542.6 755.3 542.6 797.9 585.1 840.4 627.7 883 627.7 925.5 627.7 968.1 585.1 968.1 542.6 968.1 500 925.5 457.4 883 414.9 883 372.3 883 329.8 925.5 287.2 968.1 223.4 989.4 159.6 1010.6 95.7 989.4 31.9 968.1 10.6 904.3-10.6 840.4 10.6 776.6 31.9 712.8 74.5 670.2 117 627.7 117 585.1 117 542.6 74.5 500 31.9 457.4 31.9 414.9 31.9 372.3 74.5 372.3 117 372.3 159.6 414.9 202.1 457.4 244.7 457.4 287.2 457.4 329.8 414.9 372.3 372.3 414.9 329.8 457.4 287.2 500 244.7 542.6 202.1 585.1 159.6 627.7 117 670.2 74.5", + "width": 1000 + }, + "search": [ + "command-attack" + ] + }, + { + "uid": "17ef812a059c83b5ea3612f860f9569a", + "css": "command-retreat", + "code": 59482, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M352.3 45.5Q397.7 0 443.2 0 488.6 0 511.4 68.2 534.1 136.4 556.8 204.5 579.5 272.7 647.7 295.5 715.9 318.2 806.8 318.2 897.7 318.2 965.9 340.9 1034.1 363.6 1056.8 431.8 1079.5 500 1056.8 568.2 1034.1 636.4 965.9 659.1 897.7 681.8 806.8 681.8 715.9 681.8 647.7 704.5 579.5 727.3 556.8 795.5 534.1 863.6 511.4 931.8 488.6 1000 443.2 1000 397.7 1000 352.3 954.5 306.8 909.1 261.4 863.6 215.9 818.2 170.5 772.7 125 727.3 79.5 681.8 34.1 636.4 11.4 568.2-11.4 500 11.4 431.8 34.1 363.6 79.5 318.2 125 272.7 170.5 227.3 215.9 181.8 261.4 136.4 306.8 90.9 352.3 45.5", + "width": 1068 + }, + "search": [ + "command-retreat" + ] + }, + { + "uid": "1bc31b80669cb5edc2ee5d1370554bc9", + "css": "players", + "code": 59483, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M370.1 55.1Q401.6 23.6 448.8 7.9 496.1-7.9 543.3 7.9 590.6 23.6 622 55.1 653.5 86.6 685 118.1 716.5 149.6 732.3 196.9 748 244.1 732.3 291.3 716.5 338.6 685 370.1 653.5 401.6 653.5 433.1 653.5 464.6 685 496.1 716.5 527.6 748 559.1 779.5 590.6 811 622 842.5 653.5 874 685 905.5 716.5 937 748 968.5 779.5 984.3 826.8 1000 874 984.3 921.3 968.5 968.5 921.3 984.3 874 1000 811 1000 748 1000 685 1000 622 1000 559.1 1000 496.1 1000 433.1 1000 370.1 1000 307.1 1000 244.1 1000 181.1 1000 118.1 1000 70.9 984.3 23.6 968.5 7.9 921.3-7.9 874 7.9 826.8 23.6 779.5 55.1 748 86.6 716.5 118.1 685 149.6 653.5 181.1 622 212.6 590.6 244.1 559.1 275.6 527.6 307.1 496.1 338.6 464.6 338.6 433.1 338.6 401.6 307.1 370.1 275.6 338.6 259.8 291.3 244.1 244.1 259.8 196.9 275.6 149.6 307.1 118.1 338.6 86.6 370.1 55.1", + "width": 992 + }, + "search": [ + "players" + ] + }, + { + "uid": "2073dbd997e5d8e1ffc1322d13ba5585", + "css": "chat", + "code": 59484, + "src": "custom_icons", + "selected": true, + "svg": { + "path": "M129 64.5Q161.3 32.3 209.7 16.1 258.1 0 322.6 0 387.1 0 451.6 0 516.1 0 580.6 0 645.2 0 709.7 0 774.2 0 822.6 16.1 871 32.3 903.2 64.5 935.5 96.8 967.7 129 1000 161.3 1016.1 209.7 1032.3 258.1 1032.3 322.6 1032.3 387.1 1032.3 451.6 1032.3 516.1 1016.1 564.5 1000 612.9 967.7 645.2 935.5 677.4 903.2 709.7 871 741.9 822.6 758.1 774.2 774.2 709.7 774.2 645.2 774.2 580.6 774.2 516.1 774.2 451.6 774.2 387.1 774.2 338.7 790.3 290.3 806.5 274.2 854.8 258.1 903.2 241.9 951.6 225.8 1000 193.5 1000 161.3 1000 129 967.7 96.8 935.5 64.5 903.2 32.3 871 16.1 822.6 0 774.2 0 709.7 0 645.2 0 580.6 0 516.1 0 451.6 0 387.1 0 322.6 0 258.1 16.1 209.7 32.3 161.3 64.5 129 96.8 96.8 129 64.5", + "width": 1032 + }, + "search": [ + "chat" + ] + }, + { + "uid": "9dd9e835aebe1060ba7190ad2b2ed951", + "css": "zoom", + "code": 59415, + "src": "fontawesome" } ] -} +} \ No newline at end of file diff --git a/core/assets-raw/fontgen/icons/chat.svg b/core/assets-raw/fontgen/icons/chat.svg new file mode 100644 index 0000000000..dab837b908 --- /dev/null +++ b/core/assets-raw/fontgen/icons/chat.svg @@ -0,0 +1,62 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/core/assets-raw/fontgen/icons/command-attack.svg b/core/assets-raw/fontgen/icons/command-attack.svg new file mode 100644 index 0000000000..ffd597b7a5 --- /dev/null +++ b/core/assets-raw/fontgen/icons/command-attack.svg @@ -0,0 +1,62 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/core/assets-raw/fontgen/icons/command-rally.svg b/core/assets-raw/fontgen/icons/command-rally.svg new file mode 100644 index 0000000000..b402671f69 --- /dev/null +++ b/core/assets-raw/fontgen/icons/command-rally.svg @@ -0,0 +1,62 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/core/assets-raw/fontgen/icons/command-retreat.svg b/core/assets-raw/fontgen/icons/command-retreat.svg new file mode 100644 index 0000000000..a608141b9b --- /dev/null +++ b/core/assets-raw/fontgen/icons/command-retreat.svg @@ -0,0 +1,62 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/core/assets-raw/fontgen/icons/mode-attack.svg b/core/assets-raw/fontgen/icons/mode-attack.svg new file mode 100644 index 0000000000..cc78940688 --- /dev/null +++ b/core/assets-raw/fontgen/icons/mode-attack.svg @@ -0,0 +1,62 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/core/assets-raw/fontgen/icons/mode-pvp.svg b/core/assets-raw/fontgen/icons/mode-pvp.svg new file mode 100644 index 0000000000..76c7f31f77 --- /dev/null +++ b/core/assets-raw/fontgen/icons/mode-pvp.svg @@ -0,0 +1,62 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/core/assets-raw/fontgen/icons/mode-survival.svg b/core/assets-raw/fontgen/icons/mode-survival.svg new file mode 100644 index 0000000000..aa5d0dcac8 --- /dev/null +++ b/core/assets-raw/fontgen/icons/mode-survival.svg @@ -0,0 +1,63 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/core/assets-raw/fontgen/icons/players.svg b/core/assets-raw/fontgen/icons/players.svg new file mode 100644 index 0000000000..3cdfa46245 --- /dev/null +++ b/core/assets-raw/fontgen/icons/players.svg @@ -0,0 +1,62 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + diff --git a/core/assets-raw/sprites/blocks/distribution/underflow-gate.png b/core/assets-raw/sprites/blocks/distribution/underflow-gate.png new file mode 100644 index 0000000000..7eece491ec Binary files /dev/null and b/core/assets-raw/sprites/blocks/distribution/underflow-gate.png differ diff --git a/core/assets-raw/sprites/blocks/extra/rubble-3-1.png b/core/assets-raw/sprites/blocks/extra/rubble-3-1.png deleted file mode 100644 index 83853df7a2..0000000000 Binary files a/core/assets-raw/sprites/blocks/extra/rubble-3-1.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/extra/rubble-4-1.png b/core/assets-raw/sprites/blocks/extra/rubble-4-1.png deleted file mode 100644 index f937d25c8e..0000000000 Binary files a/core/assets-raw/sprites/blocks/extra/rubble-4-1.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/extra/rubble-5-1.png b/core/assets-raw/sprites/blocks/extra/rubble-5-1.png deleted file mode 100644 index 8b22b6fc14..0000000000 Binary files a/core/assets-raw/sprites/blocks/extra/rubble-5-1.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/extra/rubble-6-1.png b/core/assets-raw/sprites/blocks/extra/rubble-6-1.png deleted file mode 100644 index 3f3fb19086..0000000000 Binary files a/core/assets-raw/sprites/blocks/extra/rubble-6-1.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/extra/rubble-7-1.png b/core/assets-raw/sprites/blocks/extra/rubble-7-1.png deleted file mode 100644 index ba3fb3f3af..0000000000 Binary files a/core/assets-raw/sprites/blocks/extra/rubble-7-1.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/extra/rubble-8-1.png b/core/assets-raw/sprites/blocks/extra/rubble-8-1.png deleted file mode 100644 index 5db796476d..0000000000 Binary files a/core/assets-raw/sprites/blocks/extra/rubble-8-1.png and /dev/null differ diff --git a/core/assets-raw/sprites/blocks/mechs/alpha-mech-pad.png b/core/assets-raw/sprites/blocks/mechs/alpha-mech-pad.png new file mode 100644 index 0000000000..e5a90abb4b Binary files /dev/null and b/core/assets-raw/sprites/blocks/mechs/alpha-mech-pad.png differ diff --git a/core/assets-raw/sprites/blocks/mechs/dart-mech-pad.png b/core/assets-raw/sprites/blocks/mechs/dart-ship-pad.png similarity index 100% rename from core/assets-raw/sprites/blocks/mechs/dart-mech-pad.png rename to core/assets-raw/sprites/blocks/mechs/dart-ship-pad.png diff --git a/core/assets-raw/sprites/blocks/storage/core-nucleus.png b/core/assets-raw/sprites/blocks/storage/core-nucleus.png index 90c5a6c1f4..d92d7033ea 100644 Binary files a/core/assets-raw/sprites/blocks/storage/core-nucleus.png and b/core/assets-raw/sprites/blocks/storage/core-nucleus.png differ diff --git a/core/assets-raw/sprites/effects/scorch1.png b/core/assets-raw/sprites/effects/scorch1.png deleted file mode 100644 index 9044dc696c..0000000000 Binary files a/core/assets-raw/sprites/effects/scorch1.png and /dev/null differ diff --git a/core/assets-raw/sprites/effects/scorch2.png b/core/assets-raw/sprites/effects/scorch2.png deleted file mode 100644 index e5f2f11105..0000000000 Binary files a/core/assets-raw/sprites/effects/scorch2.png and /dev/null differ diff --git a/core/assets-raw/sprites/effects/scorch3.png b/core/assets-raw/sprites/effects/scorch3.png deleted file mode 100644 index 555ca5f288..0000000000 Binary files a/core/assets-raw/sprites/effects/scorch3.png and /dev/null differ diff --git a/core/assets-raw/sprites/effects/scorch4.png b/core/assets-raw/sprites/effects/scorch4.png deleted file mode 100644 index 981a1c8ac4..0000000000 Binary files a/core/assets-raw/sprites/effects/scorch4.png and /dev/null differ diff --git a/core/assets-raw/sprites/effects/scorch5.png b/core/assets-raw/sprites/effects/scorch5.png deleted file mode 100644 index 0a8d1e2ef2..0000000000 Binary files a/core/assets-raw/sprites/effects/scorch5.png and /dev/null differ diff --git a/core/assets-raw/sprites/mechs/mechs/alpha-mech-base.png b/core/assets-raw/sprites/mechs/mechs/alpha-mech-base.png deleted file mode 100644 index 703f86e430..0000000000 Binary files a/core/assets-raw/sprites/mechs/mechs/alpha-mech-base.png and /dev/null differ diff --git a/core/assets-raw/sprites/mechs/mechs/alpha-mech-leg.png b/core/assets-raw/sprites/mechs/mechs/alpha-mech-leg.png deleted file mode 100644 index d60217a0bc..0000000000 Binary files a/core/assets-raw/sprites/mechs/mechs/alpha-mech-leg.png and /dev/null differ diff --git a/core/assets-raw/sprites/mechs/mechs/alpha-mech.png b/core/assets-raw/sprites/mechs/mechs/alpha-mech.png deleted file mode 100644 index 623b8e7791..0000000000 Binary files a/core/assets-raw/sprites/mechs/mechs/alpha-mech.png and /dev/null differ diff --git a/core/assets-raw/sprites/mechs/ships/dart-ship.png b/core/assets-raw/sprites/mechs/ships/dart-ship.png deleted file mode 100644 index e9567d8ecd..0000000000 Binary files a/core/assets-raw/sprites/mechs/ships/dart-ship.png and /dev/null differ diff --git a/core/assets-raw/sprites/rubble/pack.json b/core/assets-raw/sprites/rubble/pack.json new file mode 100644 index 0000000000..2612f17acc --- /dev/null +++ b/core/assets-raw/sprites/rubble/pack.json @@ -0,0 +1,8 @@ +{ + duplicatePadding: true, + combineSubdirectories: true, + flattenPaths: true, + maxWidth: 2048, + maxHeight: 2048, + fast: true +} diff --git a/core/assets-raw/sprites/blocks/extra/rubble-1-0.png b/core/assets-raw/sprites/rubble/rubble-1-0.png similarity index 100% rename from core/assets-raw/sprites/blocks/extra/rubble-1-0.png rename to core/assets-raw/sprites/rubble/rubble-1-0.png diff --git a/core/assets-raw/sprites/blocks/extra/rubble-1-1.png b/core/assets-raw/sprites/rubble/rubble-1-1.png similarity index 100% rename from core/assets-raw/sprites/blocks/extra/rubble-1-1.png rename to core/assets-raw/sprites/rubble/rubble-1-1.png diff --git a/core/assets-raw/sprites/blocks/extra/rubble-2-0.png b/core/assets-raw/sprites/rubble/rubble-2-0.png similarity index 100% rename from core/assets-raw/sprites/blocks/extra/rubble-2-0.png rename to core/assets-raw/sprites/rubble/rubble-2-0.png diff --git a/core/assets-raw/sprites/blocks/extra/rubble-2-1.png b/core/assets-raw/sprites/rubble/rubble-2-1.png similarity index 100% rename from core/assets-raw/sprites/blocks/extra/rubble-2-1.png rename to core/assets-raw/sprites/rubble/rubble-2-1.png diff --git a/core/assets-raw/sprites/blocks/extra/rubble-3-0.png b/core/assets-raw/sprites/rubble/rubble-3-0.png similarity index 100% rename from core/assets-raw/sprites/blocks/extra/rubble-3-0.png rename to core/assets-raw/sprites/rubble/rubble-3-0.png diff --git a/core/assets-raw/sprites/blocks/extra/rubble-4-0.png b/core/assets-raw/sprites/rubble/rubble-4-0.png similarity index 100% rename from core/assets-raw/sprites/blocks/extra/rubble-4-0.png rename to core/assets-raw/sprites/rubble/rubble-4-0.png diff --git a/core/assets-raw/sprites/blocks/extra/rubble-5-0.png b/core/assets-raw/sprites/rubble/rubble-5-0.png similarity index 100% rename from core/assets-raw/sprites/blocks/extra/rubble-5-0.png rename to core/assets-raw/sprites/rubble/rubble-5-0.png diff --git a/core/assets-raw/sprites/blocks/extra/rubble-6-0.png b/core/assets-raw/sprites/rubble/rubble-6-0.png similarity index 100% rename from core/assets-raw/sprites/blocks/extra/rubble-6-0.png rename to core/assets-raw/sprites/rubble/rubble-6-0.png diff --git a/core/assets-raw/sprites/blocks/extra/rubble-7-0.png b/core/assets-raw/sprites/rubble/rubble-7-0.png similarity index 100% rename from core/assets-raw/sprites/blocks/extra/rubble-7-0.png rename to core/assets-raw/sprites/rubble/rubble-7-0.png diff --git a/core/assets-raw/sprites/blocks/extra/rubble-8-0.png b/core/assets-raw/sprites/rubble/rubble-8-0.png similarity index 100% rename from core/assets-raw/sprites/blocks/extra/rubble-8-0.png rename to core/assets-raw/sprites/rubble/rubble-8-0.png diff --git a/core/assets-raw/sprites/units/alpha-base.png b/core/assets-raw/sprites/units/alpha-base.png new file mode 100644 index 0000000000..61fb31cf47 Binary files /dev/null and b/core/assets-raw/sprites/units/alpha-base.png differ diff --git a/core/assets-raw/sprites/units/alpha-leg.png b/core/assets-raw/sprites/units/alpha-leg.png new file mode 100644 index 0000000000..3be6f210e2 Binary files /dev/null and b/core/assets-raw/sprites/units/alpha-leg.png differ diff --git a/core/assets-raw/sprites/units/alpha.png b/core/assets-raw/sprites/units/alpha.png new file mode 100644 index 0000000000..a01baf8e22 Binary files /dev/null and b/core/assets-raw/sprites/units/alpha.png differ diff --git a/core/assets-raw/sprites/units/dart.png b/core/assets-raw/sprites/units/dart.png new file mode 100644 index 0000000000..12f4d9c924 Binary files /dev/null and b/core/assets-raw/sprites/units/dart.png differ diff --git a/core/assets-raw/sprites/mechs/mechs/delta-mech-base.png b/core/assets-raw/sprites/units/delta-base.png similarity index 100% rename from core/assets-raw/sprites/mechs/mechs/delta-mech-base.png rename to core/assets-raw/sprites/units/delta-base.png diff --git a/core/assets-raw/sprites/mechs/mechs/delta-mech-leg.png b/core/assets-raw/sprites/units/delta-leg.png similarity index 100% rename from core/assets-raw/sprites/mechs/mechs/delta-mech-leg.png rename to core/assets-raw/sprites/units/delta-leg.png diff --git a/core/assets-raw/sprites/mechs/mechs/delta-mech.png b/core/assets-raw/sprites/units/delta.png similarity index 100% rename from core/assets-raw/sprites/mechs/mechs/delta-mech.png rename to core/assets-raw/sprites/units/delta.png diff --git a/core/assets-raw/sprites/mechs/ships/glaive-ship.png b/core/assets-raw/sprites/units/glaive.png similarity index 100% rename from core/assets-raw/sprites/mechs/ships/glaive-ship.png rename to core/assets-raw/sprites/units/glaive.png diff --git a/core/assets-raw/sprites/mechs/ships/javelin-ship-shield.png b/core/assets-raw/sprites/units/javelin-shield.png similarity index 100% rename from core/assets-raw/sprites/mechs/ships/javelin-ship-shield.png rename to core/assets-raw/sprites/units/javelin-shield.png diff --git a/core/assets-raw/sprites/mechs/ships/javelin-ship.png b/core/assets-raw/sprites/units/javelin.png similarity index 100% rename from core/assets-raw/sprites/mechs/ships/javelin-ship.png rename to core/assets-raw/sprites/units/javelin.png diff --git a/core/assets-raw/sprites/mechs/mechs/omega-mech-armor.png b/core/assets-raw/sprites/units/omega-armor.png similarity index 100% rename from core/assets-raw/sprites/mechs/mechs/omega-mech-armor.png rename to core/assets-raw/sprites/units/omega-armor.png diff --git a/core/assets-raw/sprites/mechs/mechs/omega-mech-base.png b/core/assets-raw/sprites/units/omega-base.png similarity index 100% rename from core/assets-raw/sprites/mechs/mechs/omega-mech-base.png rename to core/assets-raw/sprites/units/omega-base.png diff --git a/core/assets-raw/sprites/mechs/mechs/omega-mech-leg.png b/core/assets-raw/sprites/units/omega-leg.png similarity index 100% rename from core/assets-raw/sprites/mechs/mechs/omega-mech-leg.png rename to core/assets-raw/sprites/units/omega-leg.png diff --git a/core/assets-raw/sprites/mechs/mechs/omega-mech.png b/core/assets-raw/sprites/units/omega.png similarity index 100% rename from core/assets-raw/sprites/mechs/mechs/omega-mech.png rename to core/assets-raw/sprites/units/omega.png diff --git a/core/assets-raw/sprites/mechs/mechs/tau-mech-base.png b/core/assets-raw/sprites/units/tau-base.png similarity index 100% rename from core/assets-raw/sprites/mechs/mechs/tau-mech-base.png rename to core/assets-raw/sprites/units/tau-base.png diff --git a/core/assets-raw/sprites/mechs/mechs/tau-mech-leg.png b/core/assets-raw/sprites/units/tau-leg.png similarity index 100% rename from core/assets-raw/sprites/mechs/mechs/tau-mech-leg.png rename to core/assets-raw/sprites/units/tau-leg.png diff --git a/core/assets-raw/sprites/mechs/mechs/tau-mech.png b/core/assets-raw/sprites/units/tau.png similarity index 100% rename from core/assets-raw/sprites/mechs/mechs/tau-mech.png rename to core/assets-raw/sprites/units/tau.png diff --git a/core/assets-raw/sprites/mechs/ships/trident-ship.png b/core/assets-raw/sprites/units/trident.png similarity index 100% rename from core/assets-raw/sprites/mechs/ships/trident-ship.png rename to core/assets-raw/sprites/units/trident.png diff --git a/core/assets-raw/sprites/units/vanguard.png b/core/assets-raw/sprites/units/vanguard.png new file mode 100644 index 0000000000..f4ac2a3210 Binary files /dev/null and b/core/assets-raw/sprites/units/vanguard.png differ diff --git a/core/assets-raw/sprites/weapons/shockgun-equip.png b/core/assets-raw/sprites/weapons/shockgun-equip.png index c53587d7ee..6e1993212b 100644 Binary files a/core/assets-raw/sprites/weapons/shockgun-equip.png and b/core/assets-raw/sprites/weapons/shockgun-equip.png differ diff --git a/core/assets-raw/sprites/weapons/vanguard-blaster-equip.png b/core/assets-raw/sprites/weapons/vanguard-blaster-equip.png new file mode 100644 index 0000000000..7d1e246dd4 Binary files /dev/null and b/core/assets-raw/sprites/weapons/vanguard-blaster-equip.png differ diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 0b218eec31..e8454ca944 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -59,6 +59,7 @@ stat.built = Buildings Built:[accent] {0} stat.destroyed = Buildings Destroyed:[accent] {0} stat.deconstructed = Buildings Deconstructed:[accent] {0} stat.delivered = Resources Launched: +stat.playtime = Time Played:[accent] {0} stat.rank = Final Rank: [accent]{0} launcheditems = [accent]Launched Items @@ -104,6 +105,7 @@ mods.none = [LIGHT_GRAY]No mods found! mods.guide = Modding Guide mods.report = Report Bug mods.openfolder = Open Mod Folder +mod.display = [gray]Mod:[orange] {0} mod.enabled = [lightgray]Enabled mod.disabled = [scarlet]Disabled mod.disable = Disable @@ -532,9 +534,12 @@ no = No info.title = Info error.title = [crimson]An error has occured error.crashtitle = An error has occured +unit.nobuild = [scarlet]Unit can't build blocks.input = Input blocks.output = Output blocks.booster = Booster +blocks.tiles = Required Tiles +blocks.affinities = Affinities block.unknown = [lightgray]??? blocks.powercapacity = Power Capacity blocks.powershot = Power/Shot @@ -669,6 +674,7 @@ 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.playerlimit.name = Player Limit setting.chatopacity.name = Chat Opacity setting.lasersopacity.name = Power Laser Opacity setting.bridgeopacity.name = Bridge Opacity @@ -948,6 +954,7 @@ block.message.name = Message block.illuminator.name = Illuminator block.illuminator.description = A small, compact, configurable light source. Requires power to function. block.overflow-gate.name = Overflow Gate +block.underflow-gate.name = Underflow Gate block.silicon-smelter.name = Silicon Smelter block.phase-weaver.name = Phase Weaver block.pulverizer.name = Pulverizer @@ -972,7 +979,8 @@ block.pneumatic-drill.name = Pneumatic Drill block.laser-drill.name = Laser Drill block.water-extractor.name = Water Extractor block.cultivator.name = Cultivator -block.dart-mech-pad.name = Alpha Mech Pad +block.dart-ship-pad.name = Dart Ship Pad +block.alpha-mech-pad.name = Alpha Mech Pad block.delta-mech-pad.name = Delta Mech Pad block.javelin-ship-pad.name = Javelin Ship Pad block.trident-ship-pad.name = Trident Ship Pad @@ -1178,6 +1186,7 @@ block.inverted-sorter.description = Processes items like a standard sorter, but block.router.description = Accepts items, then outputs them to up to 3 other directions equally. Useful for splitting the materials from one source to multiple targets.\n\n[scarlet]Never use next to production inputs, as they will get clogged by output.[] block.distributor.description = An advanced router. Splits items to up to 7 other directions equally. block.overflow-gate.description = Only outputs to the left and right if the front path is blocked. +block.underflow-gate.description = The opposite of an overflow gate. Outputs to the front if the left and right paths are blocked. block.mass-driver.description = The ultimate item transport block. Collects several items and then shoots them to another mass driver over a long range. Requires power to operate. block.mechanical-pump.description = A cheap pump with slow output, but no power consumption. block.rotary-pump.description = An advanced pump. Pumps more liquid, but requires power. @@ -1246,7 +1255,6 @@ 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.repair-point.description = Continuously heals the closest damaged unit in its vicinity. -block.dart-mech-pad.description = Provides transformation into a basic attack mech.\nUse by tapping while standing on it. block.delta-mech-pad.description = Provides transformation into a lightly armored hit-and-run attack mech.\nUse by tapping while standing on it. block.tau-mech-pad.description = Provides transformation into an advanced support mech.\nUse by tapping while standing on it. block.omega-mech-pad.description = Provides transformation into a heavily-armored missile mech.\nUse by tapping while standing on it. diff --git a/core/assets/bundles/bundle_cs.properties b/core/assets/bundles/bundle_cs.properties index cd22f0d91a..9249b5d1f5 100644 --- a/core/assets/bundles/bundle_cs.properties +++ b/core/assets/bundles/bundle_cs.properties @@ -43,10 +43,10 @@ schematic.replace = Šablona tohoto jména již existuje. Chceš ji nahradit? schematic.import = Importuji šablonu... schematic.exportfile = Exportovat soubor schematic.importfile = Importovat soubor -schematic.browseworkshop = Procházet dílnu +schematic.browseworkshop = Procházet Workshop na Steamu schematic.copy = Zkopírovat do schránky schematic.copy.import = Importovat ze schránky -schematic.shareworkshop = Sdílet skrze Steam Workshop +schematic.shareworkshop = Sdílet skrze Workshop na Steamu schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Převrátit šablonu schematic.saved = Šablona byla uložena. schematic.delete.confirm = Šablona bude kompletně vyhlazena. @@ -123,8 +123,8 @@ mod.item.remove = Tato položka je součástí [accent]'{0}'[] modifikace. Pokud mod.remove.confirm = Tato modifikace bude odstraněna. mod.author = [lightgray]Autor:[] {0} mod.missing = Toto uložení hra obsahuje modifikace, které byly nedávno aktualizovány, nebo již nejsou nainstalovány. Použití tohoto uložení může vést k chybám. Jsi si jist, že chceš nahrát toto uložení hry?\n[lightgray]Modifikace:\n{0} -mod.preview.missing = Než vystavíš svou modifikaci v dílně, musíš přidat obrázek pro náhled.\nUmísti obrázek pojmenovaný [accent]preview.png[] do složky modifikace a zkus to znovu. -mod.folder.missing = V dílně mohou být vystaveny pouze modifikace ve formě složky.\nAbys převedl modifikaci na formu složky, jednoduše rozbal zip soubor do složky a smaž starý zip soubor. Potom znovu spusť hru nebo znovu načti modifikace. +mod.preview.missing = Než vystavíš svou modifikaci ve Workshopu na Steamu, musíš přidat obrázek pro náhled.\nUmísti obrázek pojmenovaný [accent]preview.png[] do složky modifikace a zkus to znovu. +mod.folder.missing = Ve Workshopu na Steamu mohou být vystaveny pouze modifikace ve formě složky.\nAbys převedl modifikaci na formu složky, jednoduše rozbal zip soubor do složky a smaž starý zip soubor. Potom znovu spusť hru nebo znovu načti modifikace. mod.scripts.unsupported = Tvoje zařízení nepodporuje skripty. Některé modifikace nemusí správně fungovat. about.button = O hře @@ -240,8 +240,8 @@ save.playtime = Herní čas: {0} warning = Varování. confirm = Potvrdit delete = Smazat -view.workshop = Prohlédnout v dílně -workshop.listing = Upravit popis v dílně +view.workshop = Prohlédnout ve Workshopu na Steamu +workshop.listing = Upravit popis ve Workshopu na Steamu ok = OK open = Otevřít customize = Přizpůsobit pravidla @@ -285,15 +285,15 @@ map.nospawn.pvp = Tato mapa nemá nepřátelská jádra, u kterých by se mohli map.nospawn.attack = Tato mapa nemá nepřátelská jádra, která by mohla být zničena. Přidej v editoru do této mapy aspoň jedno [SCARLET]červené[] jádro. map.invalid = Chyba v načítání mapy: poškozený nebo neplatný soubor mapy. workshop.update = Aktualizovat položku -workshop.error = Chyba při načítání podrobností z dílny: {0} -map.publish.confirm = Jsi si jistý, že chceš vystavit tuto mapu?\n\n[lightgray]Ujisti se nejprve, že souhlasíš se smluvními podmínkami dílny (EULA), jinak se Tvoje mapa nezobrazí.[] +workshop.error = Chyba při načítání podrobností z Workshopu na Steamu: {0} +map.publish.confirm = Jsi si jistý, že chceš vystavit tuto mapu?\n\n[lightgray]Ujisti se nejprve, že souhlasíš se smluvními podmínkami Workshopu na Steamu (EULA), jinak se Tvoje mapa nezobrazí.[] workshop.menu = Vyber si, co bys chtěl dělat s touto položkou. workshop.info = Informace o položce changelog = Seznam změn (volitelně): eula = Smluvní podmínky platformy Steam -missing = Tato položka byla smazána nebo přesunuta.\n[lightgray]Položka bude automaticky odebrána ze seznamu dílny. +missing = Tato položka byla smazána nebo přesunuta.\n[lightgray]Položka bude automaticky odebrána ze seznamu Workshopu na Steamu. publishing = [accent]Publikuji... -publish.confirm = Opravdu chceš toto vystavit?\n\n[lightgray]Ujisti se nejprve, že souhlasíš se smluvními podmínkami dílny (EULA), jinak se Tvoje položky nezobrazí.[] +publish.confirm = Opravdu chceš toto vystavit?\n\n[lightgray]Ujisti se nejprve, že souhlasíš se smluvními podmínkami Workshopu na Steamu (EULA), jinak se Tvoje položky nezobrazí.[] publish.error = Chyba při vystavování položky: {0} steam.error = Nepodařilo se inicializovat služby platformy Steam.\Chyba: {0} @@ -309,9 +309,9 @@ editor.waves = Vln: editor.rules = Pravidla: editor.generation = Generace: editor.ingame = Upravit ve hře -editor.publish.workshop = Vystavit v dílně +editor.publish.workshop = Vystavit ve Workshopu na Steamu editor.newmap = Nová mapa -workshop = Dílna +workshop = Workshop na Steamu waves.title = Vlny waves.remove = Odebrat waves.never = @@ -532,6 +532,8 @@ error.crashtitle = Objevila se chyba blocks.input = Vstup blocks.output = Výstup blocks.booster = Posilovač +blocks.tiles = Vyžadované dlaždice +blocks.affinities = Synergie block.unknown = [lightgray]???[] blocks.powercapacity = Kapacita energie blocks.powershot = Energie na 1 výstřel @@ -666,6 +668,7 @@ setting.mutesound.name = Ztišit zvuk setting.crashreport.name = Poslat anonymní hlášení o spadnutí Mindustry setting.savecreate.name = Automaticky ukládat hru setting.publichost.name = Veřejná viditelnost hry +setting.playerlimit.name = Nejvyšší počet hráčů setting.chatopacity.name = Průsvitnost kanálu zpráv setting.lasersopacity.name = Průsvitnost energetického laseru setting.bridgeopacity.name = Průsvitnost přemostění @@ -761,13 +764,13 @@ rules.blockhealthmultiplier = Násobek zdraví bloků rules.playerhealthmultiplier = Násobek zdraví hráče rules.playerdamagemultiplier = Násobek útoku hráče rules.unitdamagemultiplier = Násobek poškození jednotkami -rules.enemycorebuildradius = Poloměr, ve kterém se okolo nepřítelského jádra nesmí stavět: [lightgray](dlaždic)[] +rules.enemycorebuildradius = Poloměr, ve kterém se okolo nepřátelského jádra nesmí stavět: [lightgray](dlaždic)[] rules.respawntime = Čas znovuzrození: [lightgray](vteřin)[] rules.wavespacing = Čas rozestupu mezi vlnami: [lightgray](vteřin)[] rules.buildcostmultiplier = Násobek ceny stavění rules.buildspeedmultiplier = Násobek rychlosti stavění rules.waitForWaveToEnd = Vlny čekají na nepřátele -rules.dropzoneradius = Poloměr oblasti pro sestoupení: [lightgray](dlaždic)[] +rules.dropzoneradius = Poloměr oblasti pro vylíhnutí: [lightgray](dlaždic)[] rules.respawns = Maximální počet znovuvylíhnutí za vlnu rules.limitedRespawns = Maximální počet znovuzrození rules.title.waves = Vlny @@ -943,7 +946,8 @@ block.inverted-sorter.name = Obrácená třídička block.message.name = Zpráva block.illuminator.name = Osvětlovač block.illuminator.description = Malý, kompaktní, konfigurovatelný zdroj světla. Vyžaduje pro svoje fungování energii. -block.overflow-gate.name = Přepadová brána +block.overflow-gate.name = Brána s přepadem +block.underflow-gate.name = Brána s podtokem block.silicon-smelter.name = Křemíková huť block.phase-weaver.name = Tkalcovna pro fázovou tkaninu block.pulverizer.name = Rozmělňovač @@ -1034,8 +1038,8 @@ block.overdrive-projector.name = Urychlující projektor block.force-projector.name = Silový projektor block.arc.name = Oblouk block.rtg-generator.name = RTG -block.spectre.name = Duch -block.meltdown.name = Tavička +block.spectre.name = Spectre +block.meltdown.name = Meltdown block.container.name = Kontejnér block.launch-pad.name = Vysílací plošina block.launch-pad-large.name = Velká vysílací plošina @@ -1174,6 +1178,7 @@ block.inverted-sorter.description = Třídí předměty. Pokud je předmět shod block.router.description = Přijímá předměty z jednoho směru a posílá je rovnoměrně do zbylých tří směrů. Užitečný pro rozdělení předmětů z jednoho zdroje do různých cílů, jako odbočení z dopravníků a podobně.\n\n[scarlet]Pozor, nepoužívejte pro vstup do produkční budovy, jinak se bude ucpávat výstupními předměty[]. block.distributor.description = Pokročilý směrovač. Rozděluje předměty rovnoměrně až do 7 dalších směrů. block.overflow-gate.description = Předměty jsou poslány do strany, pokud je směr vpřed zablokován. Užitečné například pro zpracování přebytečného materiálu, pokud je primární příjemce saturován. +block.underflow-gate.description = Předměty jsou poslány vpřed, pokud je směr do strany zablokován. Užitečné například pro zpracování přebytečného materiálu, pokud je primární příjemce saturován. block.mass-driver.description = Ultimátní blok pro přepravu předmětů. Sebere několik předmětů a vystřelí je k dalšímu hromadnému distributoru přes několik dlaždic. Vyžaduje ke své funkci energii. block.mechanical-pump.description = Levné čerpadlo s pomalým průtokem, nevyžaduje však energii k provozu. block.rotary-pump.description = Pokročilé čerpadlo, které za pomoci energie vyčerpá větší množství kapalin, než standardní. @@ -1228,9 +1233,9 @@ block.salvo.description = Větší, pokročilejší verze střílny Duo. Pálí block.fuse.description = Velká střílna s krátkým dosahem. Pálí trojice energetických paprsků blízké nepřátele. block.ripple.description = Extrémně silná dělostřelecká střílna. Pálí na dálku shluky střel na nepřátelské jednotky. block.cyclone.description = Velká protiletecká a protipozemní střílna. Pálí explodující dávky na nepřítele v okolí. -block.spectre.description = Velká střílna s kanónem s dvěma hlavněmi. Střílí velké náboje, které pronikají brněním jak pozemních, tak vzdušných nepřítelských cílů. +block.spectre.description = Velká střílna s kanónem s dvěma hlavněmi. Střílí velké náboje, které pronikají brněním jak pozemních, tak vzdušných nepřátelských cílů. block.meltdown.description = Masivní laserový kanón. Nabije se a pak pálí nepřetržitý laserový paprsek na nepřátele v okolí. Vyžaduje ke své funkci chlazení. -block.command-center.description = Vydává příkazy spojeneckým jednotkám na mapě.\nInstruuje jednotky k útoku na nepřítelské jádro, návratu do jádra nebo továrny a ke shromáždění se. Pokud se na mapě nepřátelské jádro nenachází, jednotky budou v útočném režimu držet hlídku. +block.command-center.description = Vydává příkazy spojeneckým jednotkám na mapě.\nInstruuje jednotky k útoku na nepřátelské jádro, návratu do jádra nebo továrny a ke shromáždění se. Pokud se na mapě nepřátelské jádro nenachází, jednotky budou v útočném režimu držet hlídku. block.draug-factory.description = Vyrábí těžící drony Dragoun. block.spirit-factory.description = Vyrábí drony, které opravují budovy. block.phantom-factory.description = Vyrábí drony s pokročilou konstrukcí. @@ -1249,3 +1254,4 @@ block.omega-mech-pad.description = Umožňuje přeměnu Tvého vozidla na těžc block.javelin-ship-pad.description = Umožňuje přeměnu Tvého vozidla na rychlou, lehce obrněnou stíhačku.\nAktivuj kliknutím nebo ťupnutím, když se nacházíš nad plošinou. block.trident-ship-pad.description = Umožňuje přeměnu Tvého vozidla na těžkého podpůrného bombardéra.\nAktivuj kliknutím nebo ťupnutím, když se nacházíš nad plošinou. block.glaive-ship-pad.description = Umožňuje přeměnu Tvého vozidla na velkou, dobře obrněnou střeleckou loď.\nAktivuj kliknutím nebo ťupnutím, když se nacházíš nad plošinou. + \ No newline at end of file diff --git a/core/assets/bundles/bundle_de.properties b/core/assets/bundles/bundle_de.properties index b0a3cd5953..f61896411f 100644 --- a/core/assets/bundles/bundle_de.properties +++ b/core/assets/bundles/bundle_de.properties @@ -141,14 +141,14 @@ players = {0} Spieler online players.single = {0} Spieler online server.closing = [accent]Schließe den Server ... server.kicked.kick = Du wurdest vom Server gekickt! -server.kicked.whitelist = Du bist nicht auf der Whitelist. +server.kicked.whitelist = Du bist hier nicht auf der Whitelist. server.kicked.serverClose = Server geschlossen. server.kicked.vote = Es wurde abgestimmt, dich zu kicken. Tschüss. 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 = Der Server ist nicht mit deinem Versionstyp kompatibel. -server.kicked.playerLimit = Der Server ist voll.\nWarte für einen freien Platz. +server.kicked.playerLimit = Dieser Server ist voll. Warte auf einen freien Platz. 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. @@ -190,7 +190,7 @@ server.version = [lightgray]Version: {0} server.custombuild = [yellow]Benutzerdefinierter Build confirmban = Bist du sicher, dass du diesen Spieler verbannen möchtest? confirmkick = Bist du sicher, dass du diesen Spieler kicken willst? -confirmvotekick = Willst du wirklich eine Abstimmung zum kicken des spielers machen? +confirmvotekick = Bist du sicher diesen Spieler mit einer Abstimmung rauszuwerfen? confirmunban = Bist du sicher, dass du die Verbannung des Spielers rückgängig machen willst? confirmadmin = Bist du sicher, dass du diesen Spieler zu einem Admin machen möchtest? confirmunadmin = Bis du sicher, dass dieser Spieler kein Admin mehr sein soll? @@ -199,9 +199,9 @@ joingame.ip = IP: disconnect = Verbindung unterbrochen. disconnect.error = Verbindungsfehler. disconnect.closed = Verbindung geschlossen. -disconnect.timeout = Zu langer Verbindungsversuch. +disconnect.timeout = Zeit Überschreitung. disconnect.data = Fehler beim Laden der Welt! -cantconnect = Unfähig, dem Spiel beizutreten ([accent]{0}[]). +cantconnect = Nicht möglich beizutreten ([accent]{0}[]). connecting = [accent] Verbinde... connecting.data = [accent] Welt wird geladen... server.port = Port: @@ -226,7 +226,7 @@ save.rename = Umbenennen save.rename.text = Neuer Name selectslot = Wähle einen Spielstand slot = [accent] Platz {0} -editmessage = Edit Message +editmessage = Nachricht bearbeiten save.corrupted = [accent] Datei beschädigt oder ungültig! empty = on = An @@ -392,7 +392,7 @@ filters.empty = [LIGHT_GRAY]Keine Filter! Füge einen mit dem unteren Knopf hinz filter.distort = Verzerren filter.noise = Rauschen filter.median = Mittelwert -filter.oremedian = Ore Median +filter.oremedian =Erz Median filter.blend = Mischen filter.defaultores = Standard Erze filter.ore = Erz @@ -569,11 +569,11 @@ bar.drillspeed = Bohrgeschwindigkeit: {0}/s bar.pumpspeed = Pump Speed: {0}/s bar.efficiency = Effizienz: {0}% bar.powerbalance = Strom: {0} -bar.powerstored = Stored: {0}/{1} +bar.powerstored = Gespeichert: {0}/{1} bar.poweramount = Strom: {0} bar.poweroutput = Stromgeneration: {0} bar.items = Items: {0} -bar.capacity = Capacity: {0} +bar.capacity = Kapazität: {0} bar.liquid = Flüssigkeit bar.heat = Hitze bar.power = Strom @@ -800,7 +800,7 @@ item.pyratite.name = Pyratit item.metaglass.name = Metaglass item.scrap.name = Schrott liquid.water.name = Wasser -liquid.slag.name = Schlacke +liquid.slag.name = Lava liquid.oil.name = Öl liquid.cryofluid.name = Kryoflüssigkeit mech.alpha-mech.name = Alpha @@ -820,7 +820,7 @@ mech.dart-ship.weapon = Mehrlader mech.javelin-ship.name = Javelin mech.javelin-ship.weapon = Raketensalve mech.javelin-ship.ability = Statische Entladung -mech.trident-ship.name = Trident +mech.trident-ship.name = Dreizack mech.trident-ship.weapon = Bombenschacht mech.glaive-ship.name = Glaive mech.glaive-ship.weapon = Flammen-Mehrlader @@ -924,9 +924,9 @@ block.thorium-wall.name = Thorium-Mauer block.thorium-wall-large.name = Große Thorium-Mauer block.door.name = Tor block.door-large.name = Großes Tor -block.duo.name = Duo -block.scorch.name = Flammenwerfer -block.scatter.name = Scatter +block.duo.name = Doppelgeschütz +block.scorch.name = Scatter +block.scatter.name = Luftgeschütz block.hail.name = Streuer block.lancer.name = Lanzer block.conveyor.name = Förderband @@ -938,7 +938,7 @@ block.router.name = Verteiler block.distributor.name = Großer Verteiler block.sorter.name = Sortierer block.inverted-sorter.name = Inverted Sorter -block.message.name = Message +block.message.name = Nachricht block.illuminator.name = Illuminator block.illuminator.description = A small, compact, configurable light source. Requires power to function. block.overflow-gate.name = Überlauftor @@ -969,7 +969,7 @@ block.cultivator.name = Kultivierer block.dart-mech-pad.name = Dart Mech-Pad block.delta-mech-pad.name = Delta Mech-Pad block.javelin-ship-pad.name = Javelin Luftschiff-Pad -block.trident-ship-pad.name = Trident Luftschiff-Pad +block.trident-ship-pad.name = Dreizack Luftschiff-Pad block.glaive-ship-pad.name = Glaive Luftschiff-Pad block.omega-mech-pad.name = Omega Mech-Pad block.tau-mech-pad.name = Tau Mech-Pad @@ -986,7 +986,7 @@ block.vault.name = Tresor block.wave.name = Welle block.swarmer.name = Schwärmer block.salvo.name = Salve -block.ripple.name = Riffel +block.ripple.name = Zerstörer block.phase-conveyor.name = Phasen-Transportband block.bridge-conveyor.name = Brücken-Transportband block.plastanium-compressor.name = Plastanium-Verdichter @@ -995,7 +995,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.command-center.name = Kommandozentrum block.draug-factory.name = Draug Miner-Drohnenfactory block.spirit-factory.name = Spirit-Drohnenfabrik block.phantom-factory.name = Phantom-Drohnenfabrik @@ -1010,7 +1010,7 @@ block.repair-point.name = Reparaturpunkt block.pulse-conduit.name = Impulskanal block.plated-conduit.name = Plated Conduit block.phase-conduit.name = Phasenkanal -block.liquid-router.name = Flüssigkeits-Router +block.liquid-router.name = Flüssigkeits-Verteiler block.liquid-tank.name = Flüssigkeitstank block.liquid-junction.name = Flüssigkeits-Kreuzung block.bridge-conduit.name = Kanalbrücke @@ -1120,7 +1120,7 @@ unit.eruptor.description = Ein schwerer Mech, der Strukturen abbaut. Feuert eine unit.wraith.description = Eine schneller Abfangjäger. unit.ghoul.description = Ein schwerer Flächenbomber. unit.revenant.description = Eine schwere, schwebende Raketengruppe. -block.message.description = Stores a message. Used for communication between allies. +block.message.description = Benutzt um Nachrichten mit Verbündeten auszutauschen. block.graphite-press.description = Komprimiert Kohlestücke zu reinen Graphitplatten. block.multi-press.description = Eine aktualisierte Version der Graphitpresse. Setzt Wasser und Strom ein, um Kohle schnell und effizient zu verarbeiten. block.silicon-smelter.description = Reduziert Sand mit hochreinem Kohlenstoff, um Silizium zu produzieren. @@ -1236,7 +1236,7 @@ block.wraith-factory.description = Produziert schnelle Abfangjäger. block.ghoul-factory.description = Produziert schwere Flächenbomber. block.revenant-factory.description = Produziert schwere Raketen basierte Flugeinheiten. block.dagger-factory.description = Produziert Standard-Bodeneinheiten. -block.crawler-factory.description = Produziert schnelle selbstzerstörende Schwarmeinheiten. +block.crawler-factory.description = Produziert schnelle, selbstzerstörende Schwarmeinheiten. block.titan-factory.description = Produziert fortgeschrittene, gepanzerte Bodeneinheiten. block.fortress-factory.description = Produziert schwere Artillerie-Bodeneinheiten. block.repair-point.description = Heilt durchgehend die nächste befreundete, beschädigte Einheit in der Umgebung. diff --git a/core/assets/bundles/bundle_fi.properties b/core/assets/bundles/bundle_fi.properties index a4c189dca4..cefc5181ec 100644 --- a/core/assets/bundles/bundle_fi.properties +++ b/core/assets/bundles/bundle_fi.properties @@ -3,7 +3,7 @@ credits = Tekijät contributors = Kääntäjät ja avustajat discord = Liity Mindustryn Discordiin! link.discord.description = Mindustryn virallinen Discord-keskusteluhuone -link.reddit.description = The Mindustry subreddit +link.reddit.description = Mindustry subreddit link.github.description = Pelin lähdekoodi link.changelog.description = Lista päivityksien muutoksista link.dev-builds.description = Epävakaat kehitysversiot @@ -19,47 +19,47 @@ screenshot.invalid = Kartta liian laaja, kuvankaappaukselle ei mahdollisesti ole gameover = Peli ohi gameover.pvp = [accent] {0}[] joukkue voittaa! highscore = [accent]Uusi ennätys! -copied = Copied. +copied = Kopioitu. -load.sound = Sounds -load.map = Maps -load.image = Images -load.content = Content -load.system = System -load.mod = Mods -load.scripts = Scripts +load.sound = Ääni +load.map = Kartat +load.image = Kuvat +load.content = Sisältö +load.system = Systeemi +load.mod = Modit +load.scripts = Skriptit be.update = A new Bleeding Edge build is available: -be.update.confirm = Download it and restart now? -be.updating = Updating... -be.ignore = Ignore -be.noupdates = No updates found. -be.check = Check for updates +be.update.confirm = Lataa se ja käynnistä peli uudelleen? +be.updating = Päivitetään... +be.ignore = Sivuuta +be.noupdates = Ei päivityksiä saatavilla. +be.check = Tarkista päivityksiä -schematic = Schematic -schematic.add = Save Schematic... -schematics = Schematics -schematic.replace = A schematic by that name already exists. Replace it? -schematic.import = Import Schematic... -schematic.exportfile = Export File -schematic.importfile = Import File -schematic.browseworkshop = Browse Workshop -schematic.copy = Copy to Clipboard -schematic.copy.import = Import from Clipboard -schematic.shareworkshop = Share on Workshop -schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Flip Schematic -schematic.saved = Schematic saved. -schematic.delete.confirm = This schematic will be utterly eradicated. -schematic.rename = Rename Schematic -schematic.info = {0}x{1}, {2} blocks +schematic = Kaavio +schematic.add = Tallenna Kaavio... +schematics = Kaaviot +schematic.replace = Kaavio tällä nimellä on jo olemassa. Haluatko korvata sen? +schematic.import = Tuo Kaavio... +schematic.exportfile = Luo Tiedosto +schematic.importfile = Tuo Tiedosto +schematic.browseworkshop = Selaa Työpajaa +schematic.copy = Kopioi Leikepöydälle +schematic.copy.import = Tou Leikepöydälle +schematic.shareworkshop = Jaa työpajaan +schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Käännä Kaavio +schematic.saved = Kaavio tallennettu. +schematic.delete.confirm = Tämä kaavio poistetaan. +schematic.rename = Uudelleennimeä Kaavio +schematic.info = {0}x{1}, {2} palikkaa -stat.wave = Aaltoja voitettu:[accent] {0} +stat.wave = Tasoja voitettu:[accent] {0} stat.enemiesDestroyed = Vihollisia tuhottu:[accent] {0} stat.built = Rakennuksia rakennettu:[accent] {0} stat.destroyed = Rakennuksia tuhottu:[accent] {0} stat.deconstructed = Rakennuksia purettu:[accent] {0} stat.delivered = Resursseja laukaistu: -stat.rank = Lopullinen arvo: [accent]{0} +stat.rank = Lopullinen arvosana: [accent]{0} launcheditems = [accent]Laukaistut tavarat launchinfo = [unlaunched][[LAUNCH] your core to obtain the items indicated in blue. @@ -78,49 +78,49 @@ customgame = Mukautettu peli newgame = Uusi peli none = minimap = Pienoiskartta -position = Position +position = Sijainti close = Sulje website = Verkkosivu quit = Poistu -save.quit = Save & Quit +save.quit = Tallenna ja Poistu maps = Kartat -maps.browse = Browse Maps +maps.browse = Selaa Karttoja continue = Jatka maps.none = [lightgray]Karttoja ei löytynyt! -invalid = Invalid -pickcolor = Pick Color +invalid = Invalidi +pickcolor = Valitse väri preparingconfig = Preparing Config preparingcontent = Preparing Content uploadingcontent = Uploading Content uploadingpreviewfile = Uploading Preview File committingchanges = Comitting Changes -done = Done -feature.unsupported = Your device does not support this feature. +done = Valmis +feature.unsupported = Sinun laitteesi ei tue tätä toimintoa. -mods.alphainfo = Keep in mind that mods are in alpha, and[scarlet] may be very buggy[].\nReport any issues you find to the Mindustry GitHub or Discord. +mods.alphainfo = Pidä mielessä että modit ovat alpha-tilassa, ja[scarlet] ne voivat olla virheellisiä[].\nRaportoi kaikki virheet Mindustry GitHub-sivuille tai Discordiin. mods.alpha = [accent](Alpha) -mods = Mods -mods.none = [LIGHT_GRAY]No mods found! -mods.guide = Modding Guide -mods.report = Report Bug -mods.openfolder = Open Mod Folder -mod.enabled = [lightgray]Enabled -mod.disabled = [scarlet]Disabled -mod.disable = Disable -mod.delete.error = Unable to delete mod. File may be in use. -mod.requiresversion = [scarlet]Requires min game version: [accent]{0} -mod.missingdependencies = [scarlet]Missing dependencies: {0} -mod.erroredcontent = [scarlet]Content Errors -mod.errors = Errors have occurred loading content. -mod.noerrorplay = [scarlet]You have mods with errors.[] Either disable the affected mods or fix the errors before playing. +mods = Modit +mods.none = [LIGHT_GRAY]Modeja ei löytynyt! +mods.guide = Modaamisen opas +mods.report = Raportoi ohjelmistovirhe +mods.openfolder = Avaa Modikansio +mod.enabled = [lightgray]Käytössä +mod.disabled = [scarlet]Epäkäytössä +mod.disable = Laita pois päältä +mod.delete.error = Modia ei pystynyt poistamaan. Tiedosto voi olla käytössä. +mod.requiresversion = [scarlet]Tarvitsee vähintää pelin version: [accent]{0} +mod.missingdependencies = [scarlet]Tarvitsee nämä modit: {0} +mod.erroredcontent = [scarlet]Sisältö Virheet +mod.errors = Virheitä on tapahtunut pelin ladatessa. +mod.noerrorplay = [scarlet]Sinulla on virheellisiä modeja.[] Joko poista ne käytöstä tai korjaa virheet. mod.nowdisabled = [scarlet]Mod '{0}' is missing dependencies:[accent] {1}\n[lightgray]These mods need to be downloaded first.\nThis mod will be automatically disabled. -mod.enable = Enable -mod.requiresrestart = The game will now close to apply the mod changes. -mod.reloadrequired = [scarlet]Reload Required -mod.import = Import Mod +mod.enable = Käytä +mod.requiresrestart = Peli suljetaan jotta muutokset voisivat toteutua. +mod.reloadrequired = [scarlet]Vaatii Uudelleenkäynnistystä +mod.import = Tuo Modi mod.import.github = Import GitHub Mod mod.item.remove = This item is part of the[accent] '{0}'[] mod. To remove it, uninstall that mod. -mod.remove.confirm = This mod will be deleted. +mod.remove.confirm = Tämä modi poistetaan. mod.author = [LIGHT_GRAY]Author:[] {0} mod.missing = This save contains mods that you have recently updated or no longer have installed. Save corruption may occur. Are you sure you want to load it?\n[lightgray]Mods:\n{0} mod.preview.missing = Before publishing this mod in the workshop, you must add an image preview.\nPlace an image named[accent] preview.png[] into the mod's folder and try again. @@ -143,34 +143,34 @@ server.closing = [accent]Suljetaan palvelinta... server.kicked.kick = Sinut on potkittu palvelimelta! server.kicked.whitelist = You are not whitelisted here. server.kicked.serverClose = Palvelin suljettu. -server.kicked.vote = You have been vote-kicked. Goodbye. +server.kicked.vote = Sinut on äänetetty pois. Hyvästi. server.kicked.clientOutdated = Pelisi on vanhentunut! Päivitä se! -server.kicked.serverOutdated = Outdated server! Ask the host to update! +server.kicked.serverOutdated = Vanhentunut palvelin! Pyydä isäntää päivittämään! server.kicked.banned = Sinulla on portikielto tälle palvelimelle. 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.playerLimit = Tämä palvelin on täynnä. Odota vapaata tilaa. server.kicked.recentKick = Sinut on potkittu äskettäin.\nOdota ennen kuin yhdistät uudestaan. server.kicked.nameInUse = Joku tuon niminen\non jo tällä palvelimella. server.kicked.nameEmpty = Valitsemasi nimi on virheellinen. server.kicked.idInUse = Olet jo tällä palvelimella! Kahdella käyttäjällä yhdistäminen ei ole sallittua. server.kicked.customClient = Tämä palvelin ei tue muokattuja versioita. Lataa virallinen versio. server.kicked.gameover = Peli ohi! -server.kicked.serverRestarting = The server is restarting. +server.kicked.serverRestarting = Tämä palvelin on uudelleenkäynnistymässä. server.versions = Versiosi:[accent] {0}[]\nPalvelimen versio:[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 = Pidä yllä monipelaaja peliä +invitefriends = Pyydä Ystäviä hostserver.mobile = Host\nGame host = Host hosting = [accent]Avataan palvelinta... hosts.refresh = Päivitä -hosts.discovering = Discovering LAN games -hosts.discovering.any = Discovering games +hosts.discovering = Etsitään LAN pelejä +hosts.discovering.any = Etsitään Pelejä server.refreshing = Päivitetään palvelimen tietoja -hosts.none = [lightgray]No local games found! -host.invalid = [scarlet]Can't connect to host. -trace = Trace Player +hosts.none = [lightgray]Paikallisia pelejä ei löytynyt! +host.invalid = [scarlet]Isäntään ei voitu yhdistää. +trace = Seuraa Pelaajaa trace.playername = Pelaajanimi: [accent]{0} trace.ip = IP-osoite: [accent]{0} trace.id = Uniikki tunniste: [accent]{0} @@ -188,17 +188,17 @@ server.outdated = [crimson]Vanhentunut palvelin![] server.outdated.client = [crimson]Vanhentunut asiakasohjelma![] 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? -confirmvotekick = Are you sure you want to vote-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? +confirmban = Oletko varma että haluat potkia tämän pelaajan? +confirmkick = Oletko varma että haluat poistaa tämän pelaajan? +confirmvotekick = Oletko varma että haluat äänestää tämän pelaajan potkituksi? +confirmunban = Oletko varma että haluat päästää tämän pelaajan takaisin? +confirmadmin = Oletko varma että haluat antaa pelaajalle hallinto-oikeuksia? confirmunadmin = Are you sure you want to remove admin status from this player? joingame.title = Liity peliin joingame.ip = Osoite: -disconnect = Disconnected. -disconnect.error = Connection error. -disconnect.closed = Connection closed. +disconnect = Yhteys katkaistu. +disconnect.error = Yhteysvirhe. +disconnect.closed = Yhteys poistettu. disconnect.timeout = Timed out. disconnect.data = Failed to load world data! cantconnect = Unable to join game ([accent]{0}[]). @@ -212,7 +212,7 @@ save.new = New Save save.overwrite = Are you sure you want to overwrite\nthis save slot? overwrite = Overwrite save.none = No saves found! -saveload = Saving... +saveload = Tallennetaan... savefail = Failed to save game! save.delete.confirm = Are you sure you want to delete this save? save.delete = Delete @@ -220,7 +220,7 @@ 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.import = Tuo Tallennus save.newslot = Tallennuksen nimi: save.rename = Nimeä uudelleen save.rename.text = Uusi nimi: @@ -265,8 +265,8 @@ cancelbuilding = [accent][[{0}][] to clear plan selectschematic = [accent][[{0}][] to select+copy pausebuilding = [accent][[{0}][] to pause building resumebuilding = [scarlet][[{0}][] to resume building -wave = [accent]Aalto {0} -wave.waiting = [lightgray]Wave in {0} +wave = [accent]Taso {0} +wave.waiting = [lightgray]Seuraava taso {0} wave.waveInProgress = [lightgray]Wave in progress waiting = [lightgray]Odotetaan... waiting.players = Odotetaan pelaajia... @@ -275,7 +275,7 @@ wave.enemy = [lightgray]{0} vihollinen jäljellä loadimage = Lataa kuva saveimage = Tallenna kuva unknown = Tuntematon -custom = Custom +custom = Mukautettu builtin = Sisäänrakennettu map.delete.confirm = Oletko varma että haluat poistaa tämän kartan? Poistoa ei voi peruuttaa! map.random = [accent]Satunnainen kartta @@ -296,30 +296,30 @@ publish.confirm = Are you sure you want to publish this?\n\n[lightgray]Make sure publish.error = Error publishing item: {0} steam.error = Failed to initialize Steam services.\nError: {0} -editor.brush = Brush +editor.brush = Sivellin editor.openin = Avaa editorissa editor.oregen = Ore Generation editor.oregen.info = Ore Generation: editor.mapinfo = Kartan tiedot -editor.author = Author: +editor.author = Tekijä: editor.description = Kuvaus: -editor.nodescription = A map must have a description of at least 4 characters before being published. -editor.waves = Aallot: +editor.nodescription = Kartan kuvaksessa täytyy olla vähintään neljä kirjainta ennen julkaisua. +editor.waves = Tasot: editor.rules = Säännöt: -editor.generation = Generation: -editor.ingame = Edit In-Game -editor.publish.workshop = Publish On Workshop +editor.generation = Generaatio: +editor.ingame = Muokka pelin sisällä +editor.publish.workshop = Julkaise työpajaan editor.newmap = Uusi kartta -workshop = Workshop -waves.title = Aallot -waves.remove = Remove +workshop = Työpaja +waves.title = Tasot +waves.remove = Poista waves.never = waves.every = every waves.waves = wave(s) -waves.perspawn = per spawn +waves.perspawn = per spawni waves.to = to -waves.boss = Boss -waves.preview = Preview +waves.boss = Pomo +waves.preview = Esikatselu waves.edit = Muokkaa... waves.copy = Kopioi leikepöydälle waves.load = Lataa leikepöydältä @@ -327,11 +327,11 @@ waves.invalid = Invalid waves in clipboard. waves.copied = Aallot kopioitu. waves.none = No enemies defined.\nNote that empty wave layouts will automatically be replaced with the default layout. editor.default = [lightgray] -details = Details... +details = Yksityiskohdat... edit = Muokkaa... editor.name = Nimi: -editor.spawn = Spawn Unit -editor.removeunit = Remove Unit +editor.spawn = Spawni yksikkö +editor.removeunit = Poista yksikkö editor.teams = Joukkueet editor.errorload = Virhe ladattaessa tiedostoa:\n[accent]{0} editor.errorsave = Virhe tallennettaessa tiedostoa:\n[accent]{0} @@ -341,10 +341,10 @@ 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 = Päivitä -editor.randomize = Randomize -editor.apply = Apply -editor.generate = Generate -editor.resize = Resize +editor.randomize = Satunnaista +editor.apply = Käytä +editor.generate = Generoi +editor.resize = Säädä kokoa editor.loadmap = Lataa kartta editor.savemap = Tallenna kartta editor.saved = Tallennettu! @@ -370,12 +370,12 @@ editor.resizemap = Resize Map editor.mapname = Kartan nimi: 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.exists = A map with this name already exists. -editor.selectmap = Select a map to load: +editor.exists = Kartta tällä nimellä on jo olemassa. +editor.selectmap = Valitse kartta ladattavaksi: -toolmode.replace = Replace +toolmode.replace = Korvaa toolmode.replace.description = Draws only on solid blocks. -toolmode.replaceall = Replace All +toolmode.replaceall = Korvaa kaikki toolmode.replaceall.description = Replace all blocks in map. toolmode.orthogonal = Orthogonal toolmode.orthogonal.description = Draws only orthogonal lines. @@ -424,48 +424,48 @@ width = Leveys: height = Korkeus: menu = Valikko play = Pelaa -campaign = Campaign +campaign = Polku load = Lataa save = Tallenna fps = FPS: {0} ping = Ping: {0}ms language.restart = Please restart your game for the language settings to take effect. settings = Asetukset -tutorial = Perehdytys -tutorial.retake = Re-Take Tutorial -editor = Editor -mapeditor = Map Editor +tutorial = Tutoriaali +tutorial.retake = Uusita Tutoriaali +editor = Editori +mapeditor = Kartan Editori abandon = Hylkää abandon.text = This zone and all its resources will be lost to the enemy. locked = Lukittu complete = [lightgray]Reach: -requirement.wave = Reach Wave {0} in {1} -requirement.core = Destroy Enemy Core in {0} -requirement.unlock = Unlock {0} +requirement.wave = Pääse Tasolle {0} kartassa {1} +requirement.core = Tuhoa vihollise ydin kartassa {0} +requirement.unlock = Avaa {0} resume = Resume Zone:\n[lightgray]{0} -bestwave = [lightgray]Best Wave: {0} +bestwave = [lightgray]Paras taso: {0} launch = < LAUNCH > -launch.title = Launch Successful +launch.title = Onnistunut laukaisu launch.next = [lightgray]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 +launch.confirm = Tämä laukaisee kaikki resourssit ytimestäsi.\nEt voi enää palata takaisin. +launch.skip.confirm = Jos ohitat nyt, voit laukaista vasta myöhemmissä tasoissa. +uncover = Paljasta configure = Configure Loadout -bannedblocks = Banned Blocks -addall = Add All +bannedblocks = Kielletyt Palikat +addall = Lisää kaikki 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.unlocked = Loadout unlocked:[lightgray]\n{0} -zone.resources = [lightgray]Resources Detected: -zone.objective = [lightgray]Objective: [accent]{0} -zone.objective.survival = Survive +zone.resources = [lightgray]Resoursseja havaittu: +zone.objective = [lightgray]Objectiivi: [accent]{0} +zone.objective.survival = Selviydy zone.objective.attack = Destroy Enemy Core -add = Add... -boss.health = Boss Health +add = Lisää... +boss.health = Pomon elinpisteet connectfail = [crimson]Connection error:\n\n[accent]{0} error.unreachable = Server unreachable.\nIs the address spelled correctly? @@ -478,209 +478,209 @@ 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 -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.name = Vaara Alue +zone.desertWastes.name = Aavikon Jätteet +zone.craters.name = Kraatterit +zone.frozenForest.name = Jäätynyt Metsä +zone.ruinousShores.name = Tuhoisa Ranta +zone.stainedMountains.name = Tahravuoret +zone.desolateRift.name = Autio Syvänne +zone.nuclearComplex.name = Ydinvoima Kompleksi +zone.overgrowth.name = Liikakasvu +zone.tarFields.name = Terva Pellot +zone.saltFlats.name = Suolainen Tasanne +zone.impact0078.name = Isku 0078 +zone.crags.name = Kalliot +zone.fungalPass.name = Sienilaakso -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. -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 Titan 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.groundZero.description = Suotuisa alue aloittaa peli. Matala vaarataso. Vähän resoursseja.\nKerää mahdollisimman paljon kuparia ja lyijyä.\nJatka eteenpäin. +zone.frozenForest.description = Jopa täällä, lähellä vuoria, asustaa itiöitä. Mutta ne eivöt voi elää ikuisesti jäätävässä ilmastossa.\n\nAloita matkasi energiaan. Rakenna polttogeneraattoreita. Opettele korjaajien käyttö. +zone.desertWastes.description = Valtavia määriä jätteitä ränsityneiden rakennuksien seassa.\nVoit löytää hiiltä. Polta se energiaksi, tai tiivistä siitä grafiittia.\n\n[lightgray]Laskeutumiskohta on epävarma. +zone.saltFlats.description = Aavikoiden reunoilla on suolainen tasanne. Vain vähän resoursse on saatavilla.\n\nVihollinen on rakentanut resurssi hankinnan. Hävitä vihollisen ydin. Älä jätä mitään jäljelle. +zone.craters.description = Vettä on kertynyt tähän kraatteriin vanhojen sotien jäänteinä. Ota alue itsellesi. Kerää hiekkaa. Sulata metallilasia. Pumppaa vettä jäähdyttääksesi kaivausporia ja tykkejä. +zone.ruinousShores.description = Jätteiden takaa, löydät rantaviivan. Kerran täma paikka asutti sotilasjoukkoja. Paljoa jäljella ei ole. Vain perus puolustus rekenteet ovat vahingoittumattomia, kaakki muu on romua.\nJatka laajentamista eteenpäin. Tutki teknologiaa. +zone.stainedMountains.description = Alankoa vuroien sisämaassa, löydät paljon itiöelämää.\nOta talteen runsas titaani jota täältä löytyy. Opi käyttämään sitä.\n\nVihollinen on läasnäoleva. Älä anna heille liikaa aikaa lähettää heidän vahvimpia aseitaan. +zone.overgrowth.description = Tämä alue on ylikasvanut, lähempänä itiöiden pesäkettä.\nVihollinen on muodostanut etuvartion. Rakenna titaani yksikköjä. Tuhoa vihollinen. Hanki se alue joka joskus on menetetty. +zone.tarFields.description = Öljytuotannon laitamia, vuorien ja aavikkojen välissä. Yksi ainoista paikosta joissa on tervalähde.\nLöydät vaarallisia vihollis joukkoja täältä hylätystä paikasta. Älä aliarvio niitä.\n\n[lightgray]Tutki öljyprosessointi mekanismeja jos mahdollista. +zone.desolateRift.description = Extremaalisen vaarallinen alue. Runsaasti resursseja, mutta vain vähän tilaa. Korke riski eliminaatiolle. Lähde mahdollisimman nopeasti. Älä tule huijatuksi pitkien taukojen vihollisten hyökkäyksien vällillä. +zone.nuclearComplex.description = Entinen laitos tehty toriumin tuotantoa ja prosessointia varten, nykyään vain rauniota.\n[lightgray]Tutki toriumin monia hyödyllisiä käyttötarkoituksia.\n\nVihollinen on läsnä isoin joukkoin kokoajan partioimassa tunkeilijoilta. +zone.fungalPass.description = Siirtymis alue korkeiden ja matalien vuorien välillä, itiöiden peitossa. Pieni vihollis tiedustelu tukikohta on täällä. Tuhoa se.\nKäytä Dagger- ja Crawler yksikköjä. Tuhoa kaksi vihollisydintä. zone.impact0078.description = zone.crags.description = -settings.language = Language -settings.data = Game Data -settings.reset = Reset to Defaults -settings.rebind = Rebind -settings.resetKey = Reset -settings.controls = Controls -settings.game = Game -settings.sound = Sound -settings.graphics = Graphics -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. -paused = [accent]< Paused > -clear = Clear -banned = [scarlet]Banned -yes = Yes -no = No -info.title = Info +settings.language = Kieli +settings.data = Peli Data +settings.reset = Nollaa Asetukset +settings.rebind = Uudelleenaseta +settings.resetKey = Aseta Uudelleen +settings.controls = Kontrollit +settings.game = Peli +settings.sound = Ääni +settings.graphics = Grafiikat +settings.cleardata = Tyhjennä Pelin Data... +settings.clear.confirm = Oletko varma että haluat tyhjentää pelin datan?\nMitä on tehty ei voi peruuttaa! +settings.clearall.confirm = [scarlet]WARNING![]\nTämä poistaa kaiken datan, mukaanlukien kesken olevat pelit, kartat, avatut asiat ja kontrolliasetukset.\nKun painat 'ok' kaikki datasi poistetaan ja peli suljetaan. +paused = [accent]< Pysäytetty > +clear = Tyhjä +banned = [scarlet]Kielletty +yes = Kyllä +no = Ei +info.title = Informaatio error.title = [crimson]An error has occured error.crashtitle = An error has occured -blocks.input = Input -blocks.output = Output -blocks.booster = Booster +blocks.input = Sisääntulo +blocks.output = Ulostulo +blocks.booster = Boostaa block.unknown = [lightgray]??? -blocks.powercapacity = Power Capacity -blocks.powershot = Power/Shot -blocks.damage = Damage -blocks.targetsair = Targets Air -blocks.targetsground = Targets Ground -blocks.itemsmoved = Move Speed -blocks.launchtime = Time Between Launches -blocks.shootrange = Range -blocks.size = Size -blocks.liquidcapacity = Liquid Capacity -blocks.powerrange = Power Range -blocks.powerconnections = Max Connections -blocks.poweruse = Power Use -blocks.powerdamage = Power/Damage -blocks.itemcapacity = Item Capacity -blocks.basepowergeneration = Base Power Generation -blocks.productiontime = Production Time -blocks.repairtime = Block Full Repair Time -blocks.speedincrease = Speed Increase -blocks.range = Range -blocks.drilltier = Drillables -blocks.drillspeed = Base Drill Speed -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 -blocks.ammo = Ammo +blocks.powercapacity = Energiakapasiteetti +blocks.powershot = Energiaa/Ammus +blocks.damage = Vahinko +blocks.targetsair = Hyökkää Ilmaan +blocks.targetsground = Hyökkää Maahan +blocks.itemsmoved = Liikkumisnopeus +blocks.launchtime = Aika Laukaisujen Välillä +blocks.shootrange = Kantama +blocks.size = Koko +blocks.liquidcapacity = Neste Kapasiteetti +blocks.powerrange = Energia Kantama +blocks.powerconnections = Maksimi konnektio määrä +blocks.poweruse = Energian Käyttö +blocks.powerdamage = Energia/Vahinko +blocks.itemcapacity = Tavara Kapasiteetti +blocks.basepowergeneration = Kanta Enegian Generointi +blocks.productiontime = Produktion Aika +blocks.repairtime = Kokonaisen Palikan Korjaus Aika +blocks.speedincrease = Nopeuden Kasvu +blocks.range = Etäisyys +blocks.drilltier = Porattavat +blocks.drillspeed = Kanta Poran Nopeus +blocks.boosteffect = Boostaamisen Vaikutus +blocks.maxunits = Maksimi Määrä Yksikköjä +blocks.health = Elämäpisteet +blocks.buildtime = Rakentamisen Aika +blocks.buildcost = Rakentamisen Hinta +blocks.inaccuracy = Epätarkkuus +blocks.shots = Ammusta +blocks.reload = Ammusta/Sekunnissa +blocks.ammo = Ammus -bar.drilltierreq = Better Drill Required -bar.drillspeed = Drill Speed: {0}/s -bar.pumpspeed = Pump Speed: {0}/s -bar.efficiency = Efficiency: {0}% -bar.powerbalance = Power: {0}/s -bar.powerstored = Stored: {0}/{1} -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 -bar.progress = Build Progress -bar.spawned = Units: {0}/{1} -bar.input = Input -bar.output = Output +bar.drilltierreq = Parempi Pora Vaadittu +bar.drillspeed = Poran Nopeus: {0}/s +bar.pumpspeed = Pumpun Nopeus: {0}/s +bar.efficiency = Tehokkuus: {0}% +bar.powerbalance = Energia: {0}/s +bar.powerstored = Säilöttynä: {0}/{1} +bar.poweramount = Energia: {0} +bar.poweroutput = Energian Ulostulo: {0} +bar.items = Tavaroita: {0} +bar.capacity = Kapasiteetti: {0} +bar.liquid = Neste +bar.heat = Lämpö +bar.power = Energia +bar.progress = Rakennuksen Edistys +bar.spawned = Yksikköjä: {0}/{1} +bar.input = Sisääntulo +bar.output = Ulostulo -bullet.damage = [stat]{0}[lightgray] damage -bullet.splashdamage = [stat]{0}[lightgray] area dmg ~[stat] {1}[lightgray] tiles -bullet.incendiary = [stat]incendiary -bullet.homing = [stat]homing -bullet.shock = [stat]shock -bullet.frag = [stat]frag +bullet.damage = [stat]{0}[lightgray] Vahinko +bullet.splashdamage = [stat]{0}[lightgray] Alue vahinko ~[stat] {1}[lightgray] palikkaa +bullet.incendiary = [stat]sytyttävä +bullet.homing = [stat]itseohjautuva +bullet.shock = [stat]shokki +bullet.frag = [stat]sirpaloituva 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 fire rate +bullet.freezing = [stat]jäädyttävä +bullet.tarred = [stat]tervattu +bullet.multiplier = [stat]{0}[lightgray]x ammusten multiplikaatio +bullet.reload = [stat]{0}[lightgray]x ammunta nopeus -unit.blocks = blocks -unit.powersecond = power units/second -unit.liquidsecond = liquid units/second -unit.itemssecond = items/second -unit.liquidunits = liquid units -unit.powerunits = power units -unit.degrees = degrees -unit.seconds = seconds -unit.persecond = /sec -unit.timesspeed = x speed +unit.blocks = palikat +unit.powersecond = energia yksikköä/sekunti +unit.liquidsecond = neste yksikköä/sekunti +unit.itemssecond = esinettä/sekunti +unit.liquidunits = neste yksikköä +unit.powerunits = energia yksikköä +unit.degrees = astetta +unit.seconds = sekunttia +unit.persecond = /s +unit.timesspeed = x nopeus unit.percent = % -unit.items = items -unit.thousands = k +unit.items = esinettä +unit.thousands = t unit.millions = mil -category.general = General -category.power = Power -category.liquids = Liquids -category.items = Items -category.crafting = Input/Output -category.shooting = Shooting -category.optional = Optional Enhancements -setting.landscape.name = Lock Landscape -setting.shadows.name = Shadows -setting.blockreplace.name = Automatic Block Suggestions -setting.linear.name = Linear Filtering -setting.hints.name = Hints -setting.buildautopause.name = Auto-Pause Building -setting.animatedwater.name = Animated Water -setting.animatedshields.name = Animated Shields -setting.antialias.name = Antialias[lightgray] (requires restart)[] -setting.indicators.name = Enemy/Ally Indicators -setting.autotarget.name = Auto-Target -setting.keyboard.name = Mouse+Keyboard Controls -setting.touchscreen.name = Touchscreen Controls -setting.fpscap.name = Max FPS -setting.fpscap.none = None +category.general = Yleinen +category.power = Energia +category.liquids = Neste +category.items = Tavarat +category.crafting = Ulos/Sisääntulo +category.shooting = Ammunta +category.optional = Mahdolliset Lumoukset +setting.landscape.name = Lukitse tasavaakaan +setting.shadows.name = Varjot +setting.blockreplace.name = Automaattisia Palikka Suosituksia +setting.linear.name = Lineararien Filteeraus +setting.hints.name = Vihjeet +setting.buildautopause.name = Automaattisest Pysäytä Rakentaessa +setting.animatedwater.name = Animoitu Vesi +setting.animatedshields.name = Animoitu Kilpi +setting.antialias.name = Antialiaasi[lightgray] (vaatii uudelleenkäynnistyksen)[] +setting.indicators.name = Vihollis/Puolulais Indikaattorit +setting.autotarget.name = Automaatinen Tähtäys +setting.keyboard.name = Hiiri+Näppäimistö Kontrollit +setting.touchscreen.name = Kosketusnäyttö kontrollit +setting.fpscap.name = Maksimi FPS +setting.fpscap.none = Ei Mitään setting.fpscap.text = {0} FPS -setting.uiscale.name = UI Scaling[lightgray] (require restart)[] -setting.swapdiagonal.name = Always Diagonal Placement -setting.difficulty.training = Training -setting.difficulty.easy = Easy -setting.difficulty.normal = Normal -setting.difficulty.hard = Hard -setting.difficulty.insane = Insane -setting.difficulty.name = Difficulty: -setting.screenshake.name = Screen Shake -setting.effects.name = Display Effects -setting.destroyedblocks.name = Display Destroyed Blocks +setting.uiscale.name = UI Koko[lightgray] (vaatii uudelleenkäynnistyksen)[] +setting.swapdiagonal.name = Aina Vino Korvaus +setting.difficulty.training = Treeni +setting.difficulty.easy = Helppo +setting.difficulty.normal = Keskivaikea +setting.difficulty.hard = Haastava +setting.difficulty.insane = Järjetön +setting.difficulty.name = Vaikeustaso: +setting.screenshake.name = Näytön keikkuminen +setting.effects.name = Naytön Efektit +setting.destroyedblocks.name = Näytä Tuhoutuneet Palikat setting.conveyorpathfinding.name = Conveyor Placement Pathfinding setting.coreselect.name = Allow Schematic Cores -setting.sensitivity.name = Controller Sensitivity -setting.saveinterval.name = Save Interval -setting.seconds = {0} Seconds +setting.sensitivity.name = Kontrollin Herkkyys +setting.saveinterval.name = Tallennuksen Aikaväli +setting.seconds = {0} Sekunttia setting.blockselecttimeout.name = Block Select Timeout -setting.milliseconds = {0} milliseconds +setting.milliseconds = {0} millisekunttia setting.fullscreen.name = Fullscreen -setting.borderlesswindow.name = Borderless Window[lightgray] (may require restart) -setting.fps.name = Show FPS -setting.blockselectkeys.name = Show Block Select Keys +setting.borderlesswindow.name = Borderless Window[lightgray] (vaatii uudelleenkäynnistyksen) +setting.fps.name = Näytä FPS +setting.blockselectkeys.name = Bäytä Palikan Selektio Kontrollit setting.vsync.name = VSync -setting.pixelate.name = Pixelate[lightgray] (disables animations) -setting.minimap.name = Show Minimap -setting.position.name = Show Player Position -setting.musicvol.name = Music Volume -setting.ambientvol.name = Ambient Volume -setting.mutemusic.name = Mute Music -setting.sfxvol.name = SFX Volume -setting.mutesound.name = Mute Sound +setting.pixelate.name = Pixeloi[lightgray] (poistaa animaation käytöstä) +setting.minimap.name = Näytä Minimappi +setting.position.name = Näytä pelaajan sijainti +setting.musicvol.name = Musiikin Äänenvoimakkuus +setting.ambientvol.name = Tausta Äänet +setting.mutemusic.name = Sulje Musiikki +setting.sfxvol.name = SFX Volyymi +setting.mutesound.name = Sulje Äänet setting.crashreport.name = Send Anonymous Crash Reports -setting.savecreate.name = Auto-Create Saves +setting.savecreate.name = Luo Automaattisesti Tallennukset setting.publichost.name = Public Game Visibility -setting.chatopacity.name = Chat Opacity -setting.lasersopacity.name = Power Laser Opacity -setting.playerchat.name = Display In-Game Chat +setting.chatopacity.name = Chatin Läpinäkymättömyys +setting.lasersopacity.name = Energia Laaserin Läpinäkymattämyys +setting.playerchat.name = Näytä Pelinsisäinen Keskustelu public.confirm = Do you want to make your game public?\n[accent]Anyone will be able to join your games.\n[lightgray]This can be changed later in Settings->Game->Public Game Visibility. public.beta = Note that beta versions of the game cannot make public lobbies. 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 +uiscale.cancel = Peruuta ja Poistu 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 = View category.multiplayer.name = Multiplayer -command.attack = Attack -command.rally = Rally -command.retreat = Retreat +command.attack = Hyökkää +command.rally = Kutsu Koolle +command.retreat = Palaa placement.blockselectkeys = \n[lightgray]Key: [{0}, keybind.clear_building.name = Clear Building keybind.press = Press a key... @@ -692,7 +692,7 @@ keybind.move_y.name = Move y keybind.mouse_move.name = Follow Mouse keybind.dash.name = Dash keybind.schematic_select.name = Select Region -keybind.schematic_menu.name = Schematic Menu +keybind.schematic_menu.name = Kaavio Valikko keybind.schematic_flip_x.name = Flip Schematic X keybind.schematic_flip_y.name = Flip Schematic Y keybind.category_prev.name = Previous Category @@ -711,7 +711,7 @@ keybind.block_select_07.name = Category/Block Select 7 keybind.block_select_08.name = Category/Block Select 8 keybind.block_select_09.name = Category/Block Select 9 keybind.block_select_10.name = Category/Block Select 10 -keybind.fullscreen.name = Toggle Fullscreen +keybind.fullscreen.name = Vaihda Fullscreen keybind.select.name = Select/Shoot keybind.diagonal_placement.name = Diagonal Placement keybind.pick.name = Pick Block @@ -722,8 +722,8 @@ keybind.zoom.name = Zoom keybind.menu.name = Menu keybind.pause.name = Pause keybind.pause_building.name = Pause/Resume Building -keybind.minimap.name = Minimap -keybind.chat.name = Chat +keybind.minimap.name = Minimappi +keybind.chat.name = Chatti keybind.player_list.name = Player list keybind.console.name = Console keybind.rotate.name = Rotate @@ -736,20 +736,20 @@ keybind.drop_unit.name = Drop Unit keybind.zoom_minimap.name = Zoom minimap mode.help.title = Description of modes mode.survival.name = Survival -mode.survival.description = The normal mode. Limited resources and automatic incoming waves.\n[gray]Requires enemy spawns in the map to play. -mode.sandbox.name = Sandbox -mode.sandbox.description = Infinite resources and no timer for waves. -mode.editor.name = Editor +mode.survival.description = Normaali moodi. Rajoitettu määrä resursseja ja tasoilla on aika.\n[gray]Vaatii vihollis spawneja kartassa. +mode.sandbox.name = Hiekkalaatikko +mode.sandbox.description = Ikuisesti resursseja ja tasoilla ei ole aikaa. +mode.editor.name = Editori mode.pvp.name = PvP mode.pvp.description = Fight against other players locally.\n[gray]Requires at least 2 differently-colored cores in the map to play. 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.reactorexplosions = Reactor Explosions -rules.wavetimer = Wave Timer -rules.waves = Waves +rules.infiniteresources = Ikuisesti Resursseja +rules.reactorexplosions = Reaktori Räjähdykset +rules.wavetimer = Tasojen Aikaraja +rules.waves = Tasot rules.attack = Attack Mode rules.enemyCheat = Infinite AI (Red Team) Resources rules.unitdrops = Unit Drops @@ -778,31 +778,31 @@ rules.title.experimental = Experimental rules.lighting = Lighting rules.ambientlight = Ambient Light -content.item.name = Items -content.liquid.name = Liquids -content.unit.name = Units -content.block.name = Blocks -content.mech.name = Mechs -item.copper.name = Copper -item.lead.name = Lead -item.coal.name = Coal -item.graphite.name = Graphite -item.titanium.name = Titanium -item.thorium.name = Thorium -item.silicon.name = Silicon -item.plastanium.name = Plastanium -item.phase-fabric.name = Phase Fabric -item.surge-alloy.name = Surge Alloy -item.spore-pod.name = Spore Pod +content.item.name = Tavarat +content.liquid.name = Nesteet +content.unit.name = Yksiköt +content.block.name = Palikat +content.mech.name = Yksikkö +item.copper.name = Kupari +item.lead.name = Lyijy +item.coal.name = Hiili +item.graphite.name = Grafiitti +item.titanium.name = Titaani +item.thorium.name = Torium +item.silicon.name = Pii +item.plastanium.name = Plastaniumi +item.phase-fabric.name = Kiihde Kuitu +item.surge-alloy.name = Taite Seos +item.spore-pod.name = Itiö Palko item.sand.name = Hiekka -item.blast-compound.name = Blast Compound -item.pyratite.name = Pyratite -item.metaglass.name = Metaglass -item.scrap.name = Scrap +item.blast-compound.name = Räjähde Yhdiste +item.pyratite.name = Pyratiitti +item.metaglass.name = Metallilasi +item.scrap.name = Romu liquid.water.name = Vesi -liquid.slag.name = Slag -liquid.oil.name = Oil -liquid.cryofluid.name = Cryofluid +liquid.slag.name = Kuona +liquid.oil.name = Öljy +liquid.cryofluid.name = Kryoneste mech.alpha-mech.name = Alpha mech.alpha-mech.weapon = Heavy Repeater mech.alpha-mech.ability = Regeneration @@ -824,22 +824,22 @@ mech.trident-ship.name = Trident mech.trident-ship.weapon = Bomb Bay mech.glaive-ship.name = Glaive mech.glaive-ship.weapon = Flame Repeater -item.corestorable = [lightgray]Storable in Core: {0} -item.explosiveness = [lightgray]Explosiveness: {0}% +item.corestorable = [lightgray]Säilöttävissä Ytimeen: {0} +item.explosiveness = [lightgray]Räjädysmäisyys: {0}% item.flammability = [lightgray]Flammability: {0}% item.radioactivity = [lightgray]Radioactivity: {0}% -unit.health = [lightgray]Health: {0} -unit.speed = [lightgray]Speed: {0} -mech.weapon = [lightgray]Weapon: {0} -mech.health = [lightgray]Health: {0} -mech.itemcapacity = [lightgray]Item Capacity: {0} -mech.minespeed = [lightgray]Mining Speed: {0}% -mech.minepower = [lightgray]Mining Power: {0} -mech.ability = [lightgray]Ability: {0} -mech.buildspeed = [lightgray]Building Speed: {0}% -liquid.heatcapacity = [lightgray]Heat Capacity: {0} -liquid.viscosity = [lightgray]Viscosity: {0} -liquid.temperature = [lightgray]Temperature: {0} +unit.health = [lightgray]Elämäpisteet: {0} +unit.speed = [lightgray]Nopeus: {0} +mech.weapon = [lightgray]Ase: {0} +mech.health = [lightgray]Elämäpisteet: {0} +mech.itemcapacity = [lightgray]Tavara Kapasiteetti: {0} +mech.minespeed = [lightgray]Louhimis Nopeus: {0}% +mech.minepower = [lightgray]Louhimis Voima: {0} +mech.ability = [lightgray]Spesiaalikyky: {0} +mech.buildspeed = [lightgray]Rakennus Nopeus: {0}% +liquid.heatcapacity = [lightgray]Lämpö Kapasiteetti: {0} +liquid.viscosity = [lightgray]Tahmeus: {0} +liquid.temperature = [lightgray]Lämpö: {0} block.sand-boulder.name = Sand Boulder block.grass.name = Grass @@ -865,24 +865,24 @@ 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} [lightgray](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.deepwater.name = Deep Water -block.water.name = Water -block.tainted-water.name = Tainted Water +block.graphite-press.name = Grafiitti Puristin +block.multi-press.name = Multi-Puristin +block.constructing = {0} [lightgray](Rakentamassa) +block.spawn.name = Vihollis Spawni +block.core-shard.name = Ydin: Siru +block.core-foundation.name = Ydin: Pohjaus +block.core-nucleus.name = Ydin: Tuma +block.deepwater.name = Syvä Vesi +block.water.name = Vesi +block.tainted-water.name = Pilattu Vesi block.darksand-tainted-water.name = Dark Sand Tainted Water -block.tar.name = Tar -block.stone.name = Stone -block.sand.name = Sand -block.darksand.name = Dark Sand -block.ice.name = Ice -block.snow.name = Snow -block.craters.name = Craters +block.tar.name = Terva +block.stone.name = Kivi +block.sand.name = Hiekka +block.darksand.name = Tumma Hiekka +block.ice.name = Jää +block.snow.name = Lumi +block.craters.name = Kraatterit block.sand-water.name = Sand water block.darksand-water.name = Dark Sand Water block.char.name = Char diff --git a/core/assets/bundles/bundle_it.properties b/core/assets/bundles/bundle_it.properties index f7d9474c8c..c142113cc3 100644 --- a/core/assets/bundles/bundle_it.properties +++ b/core/assets/bundles/bundle_it.properties @@ -3,7 +3,7 @@ credits = Crediti contributors = Traduttori e Contributori discord = Entra nel server Discord di Mindustry! link.discord.description = La chatroom ufficiale del server Discord di Mindustry -link.reddit.description = The Mindustry subreddit +link.reddit.description = Il subreddit di Mindustry! link.github.description = Codice sorgente del gioco link.changelog.description = Elenco delle modifiche del gioco link.dev-builds.description = Build di sviluppo versioni instabili @@ -40,7 +40,7 @@ schematic = Schematica schematic.add = Salva Schematica... schematics = Schematiche schematic.replace = Una schematica con questo nome esiste già. Sostituirla? -schematic.import = Importa schematica... +schematic.import = Importa schematica schematic.exportfile = Esporta File schematic.importfile = Importa File schematic.browseworkshop = Naviga nel Workshop @@ -59,6 +59,7 @@ stat.built = Costruzioni Erette:[accent] {0} stat.destroyed = Costruzioni Distrutte:[accent] {0} stat.deconstructed = Costruzioni Smantellate:[accent] {0} stat.delivered = Risorse Lanciate: +stat.playtime = Tempo Di Gioco:[accent] {0} stat.rank = Livello Finale: [accent]{0} launcheditems = [accent]Oggetti Lanciati @@ -79,7 +80,7 @@ newgame = Nuova partita none = minimap = Minimappa position = Posizione -close = Chiuso +close = Chiudi website = Sito Web quit = Esci save.quit = Salva ed Esci @@ -104,6 +105,7 @@ mods.none = [lightgray]Nessuna mod trovata! mods.guide = Guida per il modding mods.report = Segnala un Bug mods.openfolder = Apri Cartella Mods +mod.display = [gray]Mod:[orange] {0} mod.enabled = [lightgray]Abilitato mod.disabled = [scarlet]Disabilitato mod.disable = Disabilita @@ -138,12 +140,12 @@ research.list = [lightgray]Ricerca: research = Ricerca researched = [lightgray]{0} cercati. players = {0} giocatori online -players.single = {0} giocatori online +players.single = {0} giocatore online server.closing = [accent]Chiusura server... -server.kicked.kick = Sei stato cacciato dal server! +server.kicked.kick = Sei stato espulso dal server! server.kicked.whitelist = Non sei presente nella whitelist. server.kicked.serverClose = Server chiuso. -server.kicked.vote = Sei stato cacciato su richiesta dei giocatori. Tanti saluti. +server.kicked.vote = Sei stato espulso su richiesta dei giocatori. Tanti saluti. server.kicked.clientOutdated = Versione del client obsoleta! Aggiorna il gioco! server.kicked.serverOutdated = Server obsoleto! Chiedi all'host di aggiornare la versione del server! server.kicked.banned = Sei stato bandito da questo server. @@ -157,7 +159,7 @@ server.kicked.customClient = Questo server non supporta i client personalizzati. server.kicked.gameover = Game over! server.kicked.serverRestarting = Il server si sta riavviando. server.versions = Versione client:[accent] {0}[]\nVersione server:[accent] {1}[] -host.info = Il pulsante [accent]Ospita[] ospita un server sulla porta [scarlet]6567[].[] Chiunque sulla stessa [lightgray]rete Wi-Fi o locale[] dovrebbe essere in grado di vedere il server nell'elenco server.\nSe vuoi che le persone siano in grado di connettersi ovunque tramite il tuo IP, è richiesto il [accent]port forwarding[].\n\n[lightgray]Nota: se qualcuno sta riscontrando problemi durante la connessione al gioco LAN, assicurati di aver consentito a Mindustry di accedere alla rete locale nelle impostazioni del firewall. +host.info = Il pulsante [accent]Ospita[] ospita un server sulla porta [scarlet]6567[].[] Chiunque sulla stessa [lightgray]rete Wi-Fi o locale[] dovrebbe essere in grado di vedere il server nell'elenco server.\nSe vuoi che le persone siano in grado di connettersi ovunque tramite il tuo IP, è necessario eseguire il [accent]port forwarding[].\n\n[lightgray]Nota: se qualcuno sta riscontrando problemi durante la connessione al gioco LAN, assicurati di aver consentito a Mindustry di accedere alla rete locale nelle impostazioni del firewall. join.info = Qui è possibile inserire l'[accent]IP del server[] a cui connettersi, o scoprire [accent]un server sulla rete locale[] disponibile.\nSono supportati sia il multiplayer LAN che WAN.\n\n[lightgray]Nota: non esiste un elenco automatico dei server globali; se desideri connetterti a qualcuno tramite il suo IP, è necessario chiedere all'host il proprio IP. hostserver = Ospita Server invitefriends = Invita Amici @@ -199,7 +201,7 @@ joingame.ip = Indirizzo: disconnect = Disconnesso. disconnect.error = Errore di connessione. disconnect.closed = Connessione chiusa. -disconnect.timeout = Timed out. +disconnect.timeout = Connessione scaduta. disconnect.data = Errore durante il caricamento del mondo! cantconnect = Impossibile unirsi alla partita ([accent]{0}[]). connecting = [accent]Connessione in corso... @@ -251,6 +253,7 @@ copylink = Copia link back = Indietro data.export = Esporta Salvataggio data.import = Importa Salvataggio +data.openfolder = Apri Cartella\nSalvataggi data.exported = Dati esportati. data.invalid = Questi non sono dati di gioco validi. data.import.confirm = Importare dati di gioco esterni sovrascriverà[scarlet] tutti[] i tuoi progressi attuali.\n[accent]L'operazione è irreversibile![]\n\nUna volta importati i dati, il gioco si chiuderà immediatamente. @@ -263,7 +266,7 @@ reloading = [accent]Ricaricamento delle mods... saving = [accent]Salvataggio in corso... cancelbuilding = [accent][[{0}][] per pulire la selezione selectschematic = [accent][[{0}][] per selezionare+copiare -pausebuilding = [accent][[{0}][] to pause building +pausebuilding = [accent][[{0}][] per smettere di costruire resumebuilding = [scarlet][[{0}][] per riprendere a costruire wave = [accent]Ondata {0} wave.waiting = [lightgray]Ondata tra {0} @@ -279,7 +282,7 @@ custom = Personalizzato builtin = Incluso map.delete.confirm = Sei sicuro di voler eliminare questa mappa? L'operazione è irreversibile! map.random = [accent]Mappa casuale -map.nospawn = Questa mappa non possiede un Nucleo in cui spawnare! Aggiungine uno nell'editor. +map.nospawn = Questa mappa non possiede un Nucleo in cui generare! Aggiungine uno nell'editor. map.nospawn.pvp = Questa mappa non ha un Nucleo Nemico! Aggiungi dei Nuclei nell'editor per poter giocare. map.nospawn.attack = Questa mappa non ha nessun Nucleo Nemico da poter attaccare! Aggiungi dei Nuclei Nemici nell'editor per poter giocare. map.invalid = Errore nel caricamento della mappa: file mappa corrotto o non valido. @@ -464,7 +467,7 @@ zone.resources = [lightgray]Risorse Trovate: zone.objective = [lightgray]Obiettivo: [accent]{0} zone.objective.survival = Sopravvivere zone.objective.attack = Distruggere il Nucleo Nemico -add = Aggiungi... +add = Aggiungi boss.health = Vita del Boss connectfail = [crimson]Impossibile connettersi al server:\n\n[accent] {0} @@ -531,6 +534,8 @@ error.crashtitle = Si è verificato un errore blocks.input = Ingresso blocks.output = Uscita blocks.booster = Potenziamenti +blocks.tiles = Blocchi Richiesti +blocks.affinities = Affinità block.unknown = [lightgray]??? blocks.powercapacity = Capacità Energetica blocks.powershot = Danno/Colpo @@ -642,7 +647,7 @@ setting.difficulty.name = Difficoltà: setting.screenshake.name = Movimento dello Schermo setting.effects.name = Visualizza Effetti setting.destroyedblocks.name = Mostra Blocchi Distrutti -setting.conveyorpathfinding.name = Conveyor Placement Pathfinding +setting.conveyorpathfinding.name = Posizionamento Nastri Trasportatori Intelligente setting.coreselect.name = Consenti Schematiche dei Nuclei setting.sensitivity.name = Sensibilità del Controller setting.saveinterval.name = Intervallo di Salvataggio Automatico @@ -665,10 +670,11 @@ setting.mutesound.name = Silenzia Suoni setting.crashreport.name = Invia rapporti anonimi sugli arresti anomali setting.savecreate.name = Salvataggio Automatico setting.publichost.name = Gioco Visibile Pubblicamente +setting.playerlimit.name = Limite Giocatori setting.chatopacity.name = Opacità Chat setting.lasersopacity.name = Opacità Raggi Energetici setting.bridgeopacity.name = Opacità Nastri e Condotti Sopraelevati -setting.playerchat.name = Mostra Chat in-game +setting.playerchat.name = Mostra Chat public.confirm = Vuoi rendere la tua partita pubblica?\n[accent]Chiunque sarà in grado di accedere alle tue partite.\n[lightgray]Questo può essere modificato più tardi in Impostazioni->Gioco->Partite Pubbliche. public.beta = Nota che le versioni beta del gioco non possono creare lobby pubbliche. uiscale.reset = La scala dell'interfaccia utente è stata modificata.\nPremere 'OK' per confermare questa scala.\n[scarlet]Ripristina ed esci in [accent] {0}[] secondi... @@ -933,7 +939,6 @@ block.lancer.name = Lanciere block.conveyor.name = Nastro Trasportatore block.titanium-conveyor.name = Nastro Avanzato block.armored-conveyor.name = Nastro Corazzato -block.armored-conveyor.description = Trasporta gli oggetti alla stessa velocità del nastro avanzato, ma è più resistente. Accetta input dai lati solo da altri nastri. block.junction.name = Incrocio block.router.name = Distributore block.distributor.name = Distributore Grande @@ -943,6 +948,7 @@ block.message.name = Messaggio block.illuminator.name = Lanterna block.illuminator.description = Una piccola, compatta sorgente di luce. Richiede energia per funzionare. block.overflow-gate.name = Separatore per Eccesso +block.underflow-gate.name = Separatore per Eccesso Inverso block.silicon-smelter.name = Fonderia block.phase-weaver.name = Tessitore di Fase block.pulverizer.name = Polverizzatore @@ -1138,12 +1144,12 @@ block.spore-press.description = Comprime le spore in petrolio. block.pulverizer.description = Polverizza la pietra.\nUtile quando manca la sabbia naturale. block.coal-centrifuge.description = Solidifica il petrolio in pezzi di carbone. block.incinerator.description = Elimina qualsiasi oggetto o liquido in eccesso. -block.power-void.description = Elimina tutta l'energia che riceve, esiste solo nella modalità creativa. -block.power-source.description = Produce energia infinita, esiste solo nella modalità creativa. -block.item-source.description = Produce oggetti infiniti, esiste solo nella modalità creativa. -block.item-void.description = Elimina gli oggetti che vi entrano senza bisogno di energia, esiste solo nella modalità creativa. +block.power-void.description = Elimina tutta l'energia che riceve. Esiste solo nella modalità creativa. +block.power-source.description = Produce energia infinita. Esiste solo nella modalità creativa. +block.item-source.description = Produce oggetti infiniti. Esiste solo nella modalità creativa. +block.item-void.description = Elimina gli oggetti che vi entrano senza bisogno di energia. Esiste solo nella modalità creativa. block.liquid-source.description = Emette continuamente liquidi. Esiste solo nella modalità creativa. -block.liquid-void.description = Elimina i liquidi in entrata, esiste solo nella modalità creativa. +block.liquid-void.description = Elimina i liquidi in entrata. Esiste solo nella modalità creativa. block.copper-wall.description = Un blocco difensivo economico.\nUtile per proteggere il Nucleo e le torrette nelle prime ondate. block.copper-wall-large.description = Un blocco difensivo economico.\nUtile per proteggere il Nucleo e le torrette nelle prime ondate.\nOccupa più blocchi. block.titanium-wall.description = Un blocco difensivo moderatamente forte.\nFornisce una protezione moderata dai nemici. @@ -1163,17 +1169,19 @@ block.mend-projector.description = Ripara periodicamente blocchi nelle vicinanze block.overdrive-projector.description = Aumenta la velocità di edifici vicini come trivelle e nastri trasportatori. block.force-projector.description = Crea un campo di forza esagonale attorno a sé, proteggendo gli edifici e le unità all'interno da danni causati da proiettili. block.shock-mine.description = Danneggia i nemici che la calpestano. Quasi invisibile al nemico. -block.conveyor.description = Nastro di base. Sposta gli oggetti in avanti e li deposita automaticamente in altri blocchi. Ruotabile. +block.conveyor.description = Nastro di base. Sposta gli oggetti in avanti e li deposita automaticamente in altri blocchi. È rotabile. block.titanium-conveyor.description = Nastro avanzato. Sposta gli oggetti più velocemente dei nastri standard. +block.armored-conveyor.description = Trasporta gli oggetti alla stessa velocità del nastro avanzato, ma è più resistente. Accetta input dai lati solo da altri nastri. block.junction.description = Permette di incrociare nastri che trasportano materiali diversi in posizioni diverse. block.bridge-conveyor.description = Consente il trasporto di oggetti fino a 3 blocchi ad un altro nastro sopraelevato.\nPuò passare sopra ad altri blocchi od edifici. block.phase-conveyor.description = Nastro avanzato. Consuma energia per teletrasportare gli oggetti su un altro nastro di fase collegato. block.sorter.description = Divide gli oggetti. Se l'oggetto corrisponde a quello selezionato, Può passare. Altrimenti viene espulso sui lati. -block.inverted-sorter.description = Elabora gli oggetti come uno smistatore standard, ma in uscita dà gli elementi selezionati ai lati. +block.inverted-sorter.description = Elabora gli oggetti come uno filtro standard, ma in uscita dà gli elementi selezionati ai lati. block.router.description = Accetta gli elementi da una direzione e li emette fino a 3 altre direzioni allo stesso modo. Utile per suddividere i materiali da una fonte a più destinazioni. block.distributor.description = Un distributore avanzato che divide gli oggetti in altre 7 direzioni allo stesso modo. -block.overflow-gate.description = Una combinazione di un incrocio e di un distributore, che distribuisce sui suoi lati se in nastro difronte si satura. -block.mass-driver.description = Ultimo blocco di trasporto di oggetti. Raccoglie diversi oggetti e poi li spara su un'altra Lìlancia materiali a lungo raggio. +block.overflow-gate.description = Distribuisce gli oggetti ai lati se il nastro davanti a sé è saturo. +block.underflow-gate.description = L'opposto di un separatore per eccesso. Distribuisce gli oggetti nel nastro davanti a sé se i nastri a destra e a sinistra sono saturi. +block.mass-driver.description = Ultimo blocco di trasporto di oggetti. Raccoglie diversi oggetti e poi li spara su un'altra lancia materiali a lungo raggio. block.mechanical-pump.description = Una pompa economica a bassa efficienza, ma nessun consumo di energia. block.rotary-pump.description = Una pompa avanzata che raddoppia la velocità consumando energia. block.thermal-pump.description = La pompa migliore. Tre volte più veloce di una pompa meccanica e l'unica pompa in grado di recuperare la lava. diff --git a/core/assets/bundles/bundle_ko.properties b/core/assets/bundles/bundle_ko.properties index d2d9b54b9a..28efe4d483 100644 --- a/core/assets/bundles/bundle_ko.properties +++ b/core/assets/bundles/bundle_ko.properties @@ -29,12 +29,12 @@ load.system = 시스템 load.mod = 모드 load.scripts = 스크립트 -be.update = A new Bleeding Edge build is available: -be.update.confirm = Download it and restart now? -be.updating = Updating... -be.ignore = Ignore -be.noupdates = No updates found. -be.check = Check for updates +be.update = 새로운 블리딩 엣지 버전이 출시되었습니다. +be.update.confirm = 다운로드 후 게임을 재시작하시겠습니까? +be.updating = 업데이트 중... +be.ignore = 무시 +be.noupdates = 새로운 업데이트가 발견되지 않았습니다. +be.check = 업데이트 확인 schematic = 설계도 schematic.add = 설계도 저장하기 @@ -98,15 +98,15 @@ done = 완료 feature.unsupported = 당신의 기기는 이 기능을 지원하지 않습니다. mods.alphainfo = 현재의 모드는 첫 번째 시도이며, 그리고[scarlet] 버그가 매우 많음을 명심하십시오[].\n만약 버그를 발견할경우 Mindustry 깃허브 또는 디스코드로 제보해주세요. -mods.alpha = [scarlet](Alpha) +mods.alpha=[accent](시험적 기능) mods = 모드 mods.none = [LIGHT_GRAY]추가한 모드가 없습니다! mods.guide = 모드 가이드 mods.report = 문제 신고 mods.openfolder = 모드 폴더 열기 -mod.enabled = [lightgray]활성화 -mod.disabled = [scarlet]비활성화 -mod.disable = 비활성화 +mod.enabled=[blue]활성화 +mod.disabled=[scarlet]적용 안됨 +mod.disable=[lightgray]비활성화 mod.delete.error = 모드를 삭제할 수 없습니다. 아마도 해당 모드가 사용중인 것 같습니다. mod.requiresversion = [scarlet]게임의 버전이 낮아 모드를 활성화할 수 없습니다!\n[scarlet]요구되는 게임 버전 : [accent]{0} mod.missingdependencies = [scarlet]의존되는 모드: {0} @@ -114,7 +114,7 @@ mod.erroredcontent = [scarlet]컨텐츠 오류 mod.errors = 컨텐츠를 불러오는 중 오류가 발생하였습니다. mod.noerrorplay = [scarlet]모드에 오류가 존재합니다.[] 해당 오류가 발생하는 모드를 비활성화하거나 모드의 오류를 고친 후 플레이가 가능합니다. mod.nowdisabled = [scarlet]모드 '{0}'는 다음의 모드에 의존합니다 : [accent] {1}\n[lightgray]이 모드를 먼저 다운로드해야합니다.\n이 모드는 자동으로 비활성화됩니다. -mod.enable = 활성화 +mod.enable=활성화 mod.requiresrestart = 모드 변경사항을 적용하기 위해 게임을 종료합니다. mod.reloadrequired = [scarlet]새로고침 예정됨 mod.import = 모드 추가 @@ -123,8 +123,8 @@ mod.item.remove = 이것은 모드[accent] '{0}'[]의 자원입니다. 이 자 mod.remove.confirm = 이 모드를 삭제하시겠습니까? mod.author = [LIGHT_GRAY]제작자 : [] {0} mod.missing = 이 세이브파일에는 설치하지 않은 모드 혹은 현재 버전에 속해있지 않은 데이터가 포함되어 있습니다. 이 파일을 불러올 경우 세이브파일의 데이터가 손상될 수 있습니다. 정말로 이 파일을 불러오시겠습니까?\n[lightgray]모드 :\n{0} -mod.preview.missing = 워크샵에 당신의 모드를 업로드하기 전에 미리보기 이미지를 먼저 추가해야합니다.\n[accent] preview.png[]라는 이름으로 미리보기 이미지를 당신의 모드 폴더안에 준비한 후 다시 시도해주세요. -mod.folder.missing = 워크샵에는 폴더 형태의 모드만 게시할 수 있습니다.\n모드를 폴더 형태로 바꾸려면 파일을 폴더에 압축 해제하고 이전 압축파일을 제거한 후, 게임을 재시작하거나 모드를 다시 로드하십시오. +mod.preview.missing=Workshop에 당신의 모드를 업로드하기 전에 미리보기 이미지를 먼저 추가해야합니다.\n[accent] preview.png[]라는 이름으로 미리보기 이미지를 당신의 모드 폴더안에 준비한 후 다시 시도해주세요. +mod.folder.missing=Workshop에는 폴더 형태의 모드만 게시할 수 있습니다.\n모드를 폴더 형태로 바꾸려면 파일을 폴더에 압축 해제하고 이전 압축파일을 제거한 후, 게임을 재시작하거나 모드를 다시 로드하십시오. mod.scripts.unsupported = 당신의 기기는 모드스크립트를 지원하지 않습니다. 모드의 일부 기능이 작동하지 않을 수 있습니다. about.button = 정보 @@ -155,10 +155,10 @@ server.kicked.nameEmpty = 당신의 닉네임이 비어있습니다. server.kicked.idInUse = 이미 서버에 접속중입니다! 다중 계정은 허용되지 않습니다. server.kicked.customClient = 이 서버는 직접 빌드한 버전을 지원하지 않습니다. 공식 버전을 사용하세요. server.kicked.gameover = 코어가 파괴되었습니다... -server.kicked.serverRestarting = The server is restarting. +server.kicked.serverRestarting = 서버가 재시작합니다. server.versions = 클라이언트 버전 : [accent] {0}[]\n서버 버전 : [accent] {1}[] host.info = [accent]호스트[] 버튼은 현재 네트워크의 [scarlet]6567[] 포트를 사용합니다.\n[LIGHT_GRAY]같은 Wi-Fi 또는 로컬 네트워크[] 에서 서버 목록을 볼 수 있습니다.\n\n만약 플레이어들이 이 IP를 통해 어디에서나 연결할 수 있게 하고 싶다면, 공유기 설정에서 [accent]포트 포워딩[]을 하시거나 VPN을 사용하셔야 합니다.\n\n[LIGHT_GRAY]참고: LAN 게임 연결에 문제가 있는 사람이 있다면, 방화벽 설정에서 Mindustry 가 로컬 네트워크에 액세스하도록 허용했는지 확인해주세요. -join.info = 여기서 서버 추가를 누르신 후, [accent]서버 IP[]를 입력하여 다른 서버에 접속할 수 있습니다.\n또는 [accent]로컬 네트워크(LAN)[] 서버를 검색하여 접속할 수 있습니다.\nLAN 및 WAN 멀티 플레이어 모두 지원합니다.\n\n[LIGHT_GRAY]참고:여기에서는 자동으로 글로벌 서버를 추가하지 않습니다. IP로 다른 사람의 서버에 접속하려면 직접 서버 주소를 찾아서 적으셔야합니다.[]\n\n[ROYAL]한국의 서버로는 [accent]mindustry.kr[]의 6567, 6568포트와 [accent]server1.mindustry.r-e.kr[]의 8000, 8002 포트가 있습니다.\n서버 주소 입력방법은 < 주소:포트 >의 형식입니다.\n[royal]포트가 없을 시에는 그냥 주소만 입력하시면 됩니다.\n\n[royal]예시) mindustry.kr의 6567포트\nmindustry.kr:6567\n포트가 6567일 경우에는 :6567을 생략할 수 있습니다. +join.info = 여기서 서버 추가를 누르신 후, [accent]서버 IP[]를 입력하여 다른 서버에 접속할 수 있습니다.\n또는 [accent]로컬 네트워크(LAN)[] 서버를 검색하여 접속할 수 있습니다.\nLAN 및 WAN 멀티 플레이어 모두 지원합니다.\n\n[LIGHT_GRAY]참고:여기에서는 자동으로 글로벌 서버를 추가하지 않습니다. IP로 다른 사람의 서버에 접속하려면 직접 서버 주소를 찾아서 적으셔야합니다.[]\n\n[ROYAL]한국의 서버로는 [accent]mindustry.kr[]가 있습니다.\n서버 주소 입력방법은 < 주소:포트 >의 형식입니다.\n[royal]포트가 없을 시에는 그냥 주소만 입력하시면 됩니다.\n\n[royal]예시) mindustry.kr의 6567포트\nmindustry.kr:6567\n포트가 6567일 경우에는 :6567을 생략할 수 있습니다. hostserver = 서버 열기 invitefriends = 친구 초대 hostserver.mobile = 서버\n열기 @@ -240,8 +240,8 @@ save.playtime = 플레이타임 : {0} warning = 경고. confirm = 확인 delete = 삭제 -view.workshop = 워크샵에서 보기 -workshop.listing = 워크샵 목록 편집하기 +view.workshop=Workshop에서 보기 +workshop.listing=Workshop 목록 편집하기 ok = 확인 open = 열기 customize = 맞춤설정 @@ -310,7 +310,7 @@ editor.generation = 맵 생성 설정 : editor.ingame = 인게임 편집 editor.publish.workshop = 워크샵 업로드 editor.newmap = 신규 맵 -workshop = 워크샵 +workshop=Workshop waves.title = 단계 waves.remove = 삭제 waves.never = 여기까지 유닛생성 @@ -377,15 +377,15 @@ toolmode.replace = 재배치 toolmode.replace.description = 블록을 배치합니다. toolmode.replaceall = 모두 재배치 toolmode.replaceall.description = 맵에 있는 모든 블록을 재배치합니다. -toolmode.orthogonal = 직교 -toolmode.orthogonal.description = 직교로 블록을 배치합니다. +toolmode.orthogonal=직각 +toolmode.orthogonal.description=직각으로 블록을 배치합니다. toolmode.square = 정사각형 toolmode.square.description = 정사각형 형태의 브러시. toolmode.eraseores = 자원 초기화 toolmode.eraseores.description = 자원만 초기화합니다. toolmode.fillteams = 팀 채우기 toolmode.fillteams.description = 블록 대신 팀 건물로 채웁니다. -toolmode.drawteams = 팀 그리기 +toolmode.drawteams=팀 색상으로 그리기 toolmode.drawteams.description = 블록 대신 팀 건물을 배치합니다. filters.empty = [LIGHT_GRAY]필터가 없습니다!! 아래 버튼을 눌러 추가하세요. @@ -580,7 +580,7 @@ bar.power = 전력 bar.progress = 생산 진행도 bar.spawned = 최대 {1}기 중 {0}기 생산됨 bar.input = 입력 -bar.output = Output +bar.output = bullet.damage = [lightgray]피해량 : [stat]{0}[] bullet.splashdamage = [lightgray]범위 피해량 : [stat]{0}[] / [lightgray]피해 범위 : [stat]{1}[lightgray] 타일 @@ -643,7 +643,7 @@ setting.screenshake.name = 화면 흔들기 setting.effects.name = 화면 효과 setting.destroyedblocks.name = 부서진 블럭 표시 setting.conveyorpathfinding.name = 교차기 자동 설치 -setting.coreselect.name = Allow Schematic Cores +setting.coreselect.name = Schematic Cores 켜기 setting.sensitivity.name = 컨트롤러 감도 setting.saveinterval.name = 저장 간격 setting.seconds = {0} 초 @@ -690,7 +690,7 @@ keybind.toggle_power_lines.name = 전력 라인 허용 keybind.move_x.name = 오른쪽 / 왼쪽 이동 keybind.move_y.name = 위 / 아래 이동 keybind.mouse_move.name = 커서를 따라서 이동 -keybind.dash.name = 달리기 +keybind.dash.name = 부스터 keybind.schematic_select.name = 영역 설정 keybind.schematic_menu.name = 설계도 메뉴 keybind.schematic_flip_x.name = 설계도 X축 뒤집기 @@ -755,7 +755,7 @@ rules.enemyCheat = 무한한 적 자원 rules.unitdrops = 유닛 처치시 자원 약탈 rules.unitbuildspeedmultiplier = 유닛 제조속도 배수 rules.unithealthmultiplier = 유닛 체력 배수 -rules.blockhealthmultiplier = Block Health Multiplier +rules.blockhealthmultiplier = 건물 체력 배수 rules.playerhealthmultiplier = 플레이어 체력 배수 rules.playerdamagemultiplier = 플레이어 공격력 배수 rules.unitdamagemultiplier = 유닛 공격력 배수 @@ -978,7 +978,6 @@ block.mechanical-pump.name = 기계식 펌프 block.item-source.name = 아이템 소스 block.item-void.name = 아이템 삭제 장치 block.liquid-source.name = 무한 액체공급 장치 -block.liquid-void.name = Liquid Void block.power-void.name = 방전장치 block.power-source.name = 무한 전력공급 장치 block.unloader.name = 언로더 @@ -1142,7 +1141,6 @@ block.power-source.description = 무한한 전력을 공급해주는 블록입 block.item-source.description = 자원을 선택하면 그 자원이 무한하게 생성되는 블록입니다.\n샌드박스에서만 건설가능. block.item-void.description = 자원을 사라지게 만듭니다.\n샌드박스에서만 건설가능. block.liquid-source.description = 무한한 액체를 출력합니다.\n샌드박스에서만 건설가능. -block.liquid-void.description = Removes any liquids. Sandbox only. block.copper-wall.description = 게임 시작 초기에 방어용으로 적합합니다. block.copper-wall-large.description = 구리 벽 4개를 뭉친 블럭입니다. block.titanium-wall.description = 흑연이 생산될 즈음에 사용하기 적합합니다. diff --git a/core/assets/bundles/bundle_nl.properties b/core/assets/bundles/bundle_nl.properties index 6a8681f28a..8a45402b26 100644 --- a/core/assets/bundles/bundle_nl.properties +++ b/core/assets/bundles/bundle_nl.properties @@ -40,7 +40,7 @@ schematic = Blauwdruk schematic.add = Bewaar blauwdruk... schematics = Blauwdrukken schematic.replace = Er bestaat al een blauwdruk met die naam. Overschrijven? -schematic.import = Importeer blauwdrul... +schematic.import = Importeer blauwdruk... schematic.exportfile = Exporteer bestand schematic.importfile = Importeer bestand schematic.browseworkshop = Blader Werkplaats @@ -245,13 +245,13 @@ workshop.listing = Bewerk Workshop vermelding ok = Oke open = Open customize = Aanpassen -cancel = Anuleer +cancel = Annuleer openlink = Open Link copylink = Customize Link -back = Teru +back = Terug data.export = Exporteer Data data.import = Importeer Data -data.exported = Data Geexporteerd. +data.exported = Data Geëxporteerd. data.invalid = Dit is geen geldige game data. data.import.confirm = Importeren van data verwijderd[scarlet] alle[] huidige data.\n[accent]Dit kan niet ongedaan worden gemaakt![]\n\nWanneer de data is geimport herstart deze game automatisch. classic.export = Exporteer klassieke data @@ -450,7 +450,7 @@ launch.title = Lancering Sucessvol launch.next = [LIGHT_GRAY]volgende lanceerkans in ronde {0} launch.unable2 = [scarlet]Lanceren niet mogelijk.[] launch.confirm = Dit lanceert alle items in je core.\nJe zal niet meer terug kunnen keren naar deze basis. -launch.skip.confirm = Als je nu niet lanceert, zul je moeten wachten tot het wel weer kan. +launch.skip.confirm = Als je nu niet lanceert zul je moeten wachten tot de volgende mogelijkheid. uncover = Ontdek configure = Configureer startinventaris bannedblocks = Verboden Blokken @@ -532,21 +532,21 @@ blocks.input = Input blocks.output = Output blocks.booster = Booster block.unknown = [LIGHT_GRAY]??? -blocks.powercapacity = Stroom Capaciteit -blocks.powershot = Stroom/Shot -blocks.damage = Damage +blocks.powercapacity = Stroomcapaciteit +blocks.powershot = Stroom/Schot +blocks.damage = Schade blocks.targetsair = Luchtdoelwitten blocks.targetsground = Gronddoelwitten blocks.itemsmoved = Beweegsnelheid blocks.launchtime = Tijd tussen lanceringen blocks.shootrange = Bereik blocks.size = Formaat -blocks.liquidcapacity = Vloeistof Capaciteit -blocks.powerrange = Stroom Bereik -blocks.powerconnections = Maximale Hoeveelheid Dradem -blocks.poweruse = Stroom verbruik -blocks.powerdamage = Stroom/Damage -blocks.itemcapacity = Materiaal Capaciteit +blocks.liquidcapacity = Vloeistofcapaciteit +blocks.powerrange = Stroombereik +blocks.powerconnections = Maximale Hoeveelheid Connecties +blocks.poweruse = Stroomverbruik +blocks.powerdamage = Stroom/Schade +blocks.itemcapacity = Materiaalcapaciteit blocks.basepowergeneration = Standaard Stroom Generatie blocks.productiontime = Productie Tijd blocks.repairtime = Volledige Blok Repareertijd @@ -556,17 +556,17 @@ blocks.drilltier = Valt te delven blocks.drillspeed = Standaard mine snelheid blocks.boosteffect = Boost Effect blocks.maxunits = Maximaal Actieve Units -blocks.health = Health -blocks.buildtime = Bouw tijd -blocks.buildcost = Bouw kosten +blocks.health = Levenspunten +blocks.buildtime = Bouwtijd +blocks.buildcost = Bouwkosten blocks.inaccuracy = Onnauwkeurigheid blocks.shots = Shoten blocks.reload = Schoten/Seconde -blocks.ammo = Ammonutie +blocks.ammo = Ammunitie bar.drilltierreq = Betere miner nodig bar.drillspeed = Mining Snelheid: {0}/s -bar.pumpspeed = Pomp Snelheid: {0}/s +bar.pumpspeed = Pompsnelheid: {0}/s bar.efficiency = Rendement: {0}% bar.powerbalance = Stroom: {0} bar.powerstored = Opgeslagen: {0}/{1} @@ -591,15 +591,15 @@ bullet.frag = [stat]clusterbom bullet.knockback = [stat]{0}[lightgray] terugslag bullet.freezing = [stat]bevriezend bullet.tarred = [stat]pek -bullet.multiplier = [stat]{0}[lightgray]x ammonutie verdubbelaar +bullet.multiplier = [stat]{0}[lightgray]x ammunitieverdubbelaar bullet.reload = [stat]{0}[lightgray]x herlaad unit.blocks = blokken -unit.powersecond = stroom eenheid/seconde -unit.liquidsecond = vloeistof eenheid/seconde +unit.powersecond = stroomeenheid/seconde +unit.liquidsecond = vloeistofeenheid/seconde unit.itemssecond = items/seconde -unit.liquidunits = vloeistof eenheid -unit.powerunits = stroom eenheid +unit.liquidunits = vloeistofeenheid +unit.powerunits = stroomeenheid unit.degrees = graden unit.seconds = secondes unit.persecond = /sec @@ -615,8 +615,8 @@ category.items = Items category.crafting = Productie category.shooting = Wapens category.optional = Optionele Verbeteringen -setting.landscape.name = Vergrendel Landscape -setting.shadows.name = Schaduws +setting.landscape.name = Vergrendel Landschap +setting.shadows.name = Schaduwen setting.blockreplace.name = Automatische Blok Suggesties setting.linear.name = Linear Filtering setting.hints.name = Hints @@ -629,14 +629,14 @@ setting.autotarget.name = Auto-Target setting.keyboard.name = Muis+Toetsenbord Controls setting.touchscreen.name = Touchscreen Controls setting.fpscap.name = Max FPS -setting.fpscap.none = None +setting.fpscap.none = Geen setting.fpscap.text = {0} FPS setting.uiscale.name = UI Schaal[lightgray] (herstart vereist)[] setting.swapdiagonal.name = Altijd Diagonaal Plaatsen -setting.difficulty.training = kalm +setting.difficulty.training = oefening setting.difficulty.easy = makkelijk setting.difficulty.normal = normaal -setting.difficulty.hard = hard +setting.difficulty.hard = moeilijk setting.difficulty.insane = krankzinnig setting.difficulty.name = Moeilijkheidsgraad: setting.screenshake.name = Schuddend Scherm @@ -932,7 +932,7 @@ block.lancer.name = Lancer block.conveyor.name = Lopende Band block.titanium-conveyor.name = Titanium Lopende Band block.armored-conveyor.name = Gepantserde Lopende Band -block.armored-conveyor.description = Verplaatst items met dezelfde snelheid als een van titanium, maar heeft meer levenspunten. accepteert alleen items van de zijkanten als het ook lopende banden zijn. +block.armored-conveyor.description = Verplaatst items met dezelfde snelheid als een van titanium, maar heeft meer levenspunten. Accepteert alleen items van de zijkanten als het ook lopende banden zijn. block.junction.name = Kruising block.router.name = Router block.distributor.name = Distributor @@ -1060,7 +1060,7 @@ unit.eradicator.name = Eradicator unit.lich.name = Lich unit.reaper.name = Reaper tutorial.next = [lightgray] -tutorial.intro = Welkom bij de[scarlet] Mindustry Tutorial.[]\nBegin met het[accent] delven van koper[]. Klik op een vakje die het heeft om het te delven.\n\n[accent]{0}/{1} koper +tutorial.intro = Welkom bij de[scarlet] Mindustry Tutorial.[]\nBegin met het[accent] delven van koper[]. Klik op een vakje met koper om het te delven.\n\n[accent]{0}/{1} koper tutorial.intro.mobile = Welkom bij de[scarlet] Mindustry Tutorial.[]\nVeeg over het scherm om te bewegen.\n[accent]Knijp met 2 vingers [] om in en uit te zoomen.\nBegin met het[accent] delven van koper[]. Beweeg dichterbij, en klik er dan op.\n\n[accent]{0}/{1} koper tutorial.drill = Met de hand delven is inefficient.\n[accent]Drills []kunnen automatisch voor je delven.\nPlaats er een op de koper. tutorial.drill.mobile = Met de hand delven is inefficient.\n[accent]Drills []kunnen automatisch voor je delven.\nZoek de drill rechts onderin.\nSelecter de[accent] mechanische drill[].\nPlaats het op de koper door erop te klikken, druk dan op het[accent] vinkje[] om het bouwen te bevestigen.\nKlik op de[accent] X knop[] om het te anuleren. @@ -1068,8 +1068,8 @@ tutorial.blockinfo = Elk blok heeft andere statistieken. Elke drill kan enkel be tutorial.conveyor = [accent]Lopende Banden[] worden gebruikt om je items naar je core te krijgen.\nLeg een line aan van je drills tot aan je core. tutorial.conveyor.mobile = [accent]Lopende Banden[] worden gebruikt om je items naar je core te krijgen.\nLeg een line aan van je drills tot aan je core.\n[accent] Doe dit door je vinger een paar seconden stil te houden[] en dan in een richting te slepen.\n\n[accent]{0}/{1} lopende banden in 1x geplaatst\n[accent]0/1 items afgeleverd tutorial.turret = Defensieve gebouwen moeten worden gebouwd tegen de[LIGHT_GRAY] vijand[].\nBouw een duo kannon bij je basis. -tutorial.drillturret = Duo's hebben[accent] koperen ammonutie []nodig om te schieten.\nPlaatst een drill ernaast om het van koper te voorzien. -tutorial.pause = Tijdens een gevecht is het mogelijk[accent] het spel te pauzeren.[]\nJe kan nog wel je gebouwen plannen dan.\n\n[accent]Pauzeer het spel (spatie) nu. +tutorial.drillturret = Duo's hebben[accent] koperen ammunitie []nodig om te schieten.\nPlaats een drill ernaast om het van koper te voorzien. +tutorial.pause = Tijdens een gevecht is het mogelijk[accent] het spel te pauzeren.[]\nJe kan nog wel je gebouwen plannen.\n\n[accent]Pauzeer het spel (spatie) nu. 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 = Doe het opnieuw om weer verder te gaan. tutorial.unpause.mobile = Doe het opnieuw om weer verder te gaan. @@ -1079,10 +1079,10 @@ tutorial.withdraw = In sommige situaties, is het nodig om items uit een blok te tutorial.deposit = Je kan de items weer terugstoppen door van je schip het terug te slepen naar waar je het wilt.\n\n[accent]Stop het nu weer terug in de core.[] tutorial.waves = De[LIGHT_GRAY] vijand[] naderd.\n\nVerdedig je core voor 2 rondes. Bouw meer verdedigingen. tutorial.waves.mobile = De[LIGHT_GRAY] vijand[] naderd.\n\nVerdedig je core voor 2 rondes. Je schip schiet automatisch op vijanden.\nBouw meer verdedigingen, en mine meer koper. -tutorial.launch = Tijdens sommige waves, kan je je core[accent] lanceren[], hiermee verlaat je de basis permanent[accent] maar je neemt wel alles dat in de core zit met je mee.[]\nVervolgens valt ermee te onderzoeken.\n\n[accent]Druk op de lanceer knop. +tutorial.launch = Tijdens sommige waves, kan je je core[accent] lanceren[], hiermee verlaat je de basis permanent[accent] maar je neemt wel alles dat in de core zit met je mee.[]\nMet deze grondstoffen kan je nieuwe technologieën onderzoeken.\n\n[accent]Druk op de lanceerknop. -item.copper.description = A useful structure material. Used extensively in all types of blocks. -item.lead.description = A basic starter material. Used extensively in electronics and liquid transportation blocks. +item.copper.description = Een nuttig materiaal voor gebouwen. Wordt erg vaak in blokken gebruikt. +item.lead.description = Een basismateriaal. Wordt vaak gebruikt in elektronica en vloeistoftransport. item.metaglass.description = A super-tough glass compound. Extensively used for liquid distribution and storage. item.graphite.description = Mineralized carbon, used for ammunition and electrical insulation. item.sand.description = A common material that is used extensively in smelting, both in alloying and as a flux. diff --git a/core/assets/bundles/bundle_pt_PT.properties b/core/assets/bundles/bundle_pt_PT.properties index 1375245580..f845f98200 100644 --- a/core/assets/bundles/bundle_pt_PT.properties +++ b/core/assets/bundles/bundle_pt_PT.properties @@ -12,7 +12,7 @@ link.itch.io.description = Pagina da Itch.io com os Descarregamentos link.google-play.description = Listamento do google play store link.f-droid.description = F-Droid catalogue listing link.wiki.description = Wiki oficial do Mindustry -link.feathub.description = Suggest new features +link.feathub.description = Sugerir novas funcionalidades linkfail = Falha ao abrir a ligação\nO Url foi copiado screenshot = Screenshot gravado para {0} screenshot.invalid = Mapa grande demais, Potencialmente sem memória suficiente para captura. @@ -29,12 +29,12 @@ load.system = Sistema load.mod = Mods load.scripts = Scripts -be.update = A new Bleeding Edge build is available: -be.update.confirm = Download it and restart now? -be.updating = Updating... -be.ignore = Ignore -be.noupdates = No updates found. -be.check = Check for updates +be.update = Uma nova versão do Bleeding Edge está disponível: +be.update.confirm = Transferir e reiniciar agora? +be.updating = A atualizar... +be.ignore = Ignora +be.noupdates = Atualizações não encontradas. +be.check = A Verificar por atualizações schematic = Esquema schematic.add = Gravar Esquema... @@ -62,7 +62,7 @@ stat.delivered = Recursos lançados: stat.rank = Rank Final: [accent]{0} launcheditems = [accent]Itens lançados -launchinfo = [unlaunched][[LAUNCH] your core to obtain the items indicated in blue. +launchinfo = [unlaunched][[LAUNCH] seu núcleo para obter os itens indicados em azul. map.delete = Certeza que quer deletar o mapa "[accent]{0}[]"? level.highscore = Melhor\npontuação: [accent] {0} level.select = Seleção de Fase @@ -108,18 +108,18 @@ mod.enabled = [lightgray]Ativado mod.disabled = [scarlet]Desativado mod.disable = Desativar mod.delete.error = Incapaz de apagar o mod. Ficheiro já em uso. -mod.requiresversion = [scarlet]Requires min game version: [accent]{0} +mod.requiresversion = [scarlet]Requer versão minima de jogo: [accent]{0} mod.missingdependencies = [scarlet]Dependências ausentes: {0} -mod.erroredcontent = [scarlet]Content Errors -mod.errors = Errors have occurred loading content. -mod.noerrorplay = [scarlet]You have mods with errors.[] Either disable the affected mods or fix the errors before playing. +mod.erroredcontent = [scarlet]Erros de conteudo +mod.errors = Ocorreram erros ao carregar o conteúdo. +mod.noerrorplay = [scarlet]Tens mods com erros.[] Desative os mods afetados ou corrija os erros antes de jogar. mod.nowdisabled = [scarlet]Mod '{0}' está faltando dependências:[accent] {1}\n[lightgray]Esses mods precisam ser baixados primeiro. NEste mod será automaticamente desativado mod.enable = Ativar mod.requiresrestart = O jogo será fechado agora para aplicar as alterações no mod. -mod.reloadrequired = [scarlet]Reload Required +mod.reloadrequired = [scarlet]É necessario recarregar mod.import = Importar Mod mod.import.github = Importar Mod pelo GitHub -mod.item.remove = This item is part of the[accent] '{0}'[] mod. To remove it, uninstall that mod. +mod.item.remove = Este item faz parte do [accent] '{0}'[] mod. Para lhe remover, desinstala o mod. mod.remove.confirm = Este mod irá ser apagado. mod.author = [LIGHT_GRAY]Autor:[] {0} mod.missing = Este save contém mods que foram recentemente atualizados ou que não estão mais instalados. Ao guardar pode ocorreu corrupção. Tem certeza de que deseja carregá-lo?\n[lightgray]Mods:\n{0} diff --git a/core/assets/bundles/bundle_ru.properties b/core/assets/bundles/bundle_ru.properties index 35e6b5be56..1e7f44254e 100644 --- a/core/assets/bundles/bundle_ru.properties +++ b/core/assets/bundles/bundle_ru.properties @@ -251,6 +251,7 @@ copylink = Скопировать ссылку back = Назад data.export = Экспортировать данные data.import = Импортировать данные +data.openfolder = Открыть папку с данными data.exported = Данные экспортированы. data.invalid = Эти игровые данные являются недействительными. data.import.confirm = Импорт внешних данных сотрёт[scarlet] все[] Ваши игровые данные.\n[accent]Это не может быть отменено![]\n\nКак только данные импортированы, Ваша игра немедленно закроется. @@ -531,6 +532,8 @@ error.crashtitle = Произошла ошибка blocks.input = Вход blocks.output = Выход blocks.booster = Ускоритель +blocks.tiles = Необходимые плитки +blocks.affinities = Увеличение эффективности block.unknown = [lightgray]??? blocks.powercapacity = Вместимость энергии blocks.powershot = Энергия/Выстрел @@ -607,7 +610,7 @@ unit.timesspeed = x скорость unit.percent = % unit.items = предметов unit.thousands = тыс -unit.millions = мил +unit.millions = млн category.general = Основные category.power = Энергия category.liquids = Жидкости @@ -666,7 +669,9 @@ setting.crashreport.name = Отправлять анонимные отчёты setting.savecreate.name = Автоматическое создание сохранений setting.publichost.name = Общедоступность игры setting.chatopacity.name = Непрозрачность чата +setting.playerlimit.name = Лимит игроков setting.lasersopacity.name = Непрозрачность лазеров энергоснабжения +setting.bridgeopacity.name = Непрозрачность мостов setting.playerchat.name = Отображать облака чата над игроками public.confirm = Вы хотите, чтобы Ваша игра стала публичной?\n[accent] Любой игрок сможет присоединиться к Вашем играм.\n[lightgray]Позже, это можно будет изменить в Настройки->Игра->Общедоступность игры. public.beta = Имейте в виду, что бета-версия игры не может делать игры публичными. @@ -942,6 +947,7 @@ block.message.name = Сообщение block.illuminator.name = Осветитель block.illuminator.description = Маленький, компактный, настраиваемый источник света. Требуется энергия для работы. block.overflow-gate.name = Избыточный затвор +block.underflow-gate.name = Избыточный шлюз block.silicon-smelter.name = Кремниевый плавильный завод block.phase-weaver.name = Фазовый ткач block.pulverizer.name = Измельчитель @@ -978,7 +984,7 @@ block.mechanical-pump.name = Механическая помпа block.item-source.name = Источник предметов block.item-void.name = Предметный вакуум block.liquid-source.name = Источник жидкостей -block.liquid-void.name = Liquid Void +block.liquid-void.name = Жидкостный вакуум block.power-void.name = Энергетический вакуум block.power-source.name = Источник энергии block.unloader.name = Разгрузчик @@ -1128,7 +1134,7 @@ block.kiln.description = Выплавляет песок и свинец в со block.plastanium-compressor.description = Производит пластан из нефти и титана. block.phase-weaver.description = Синтезирует фазовую ткань из радиоактивного тория и песка. Требуется огромное количество энергии для работы. block.alloy-smelter.description = Объединяет титан, свинец, кремний и медь для производства кинетического сплава. -block.cryofluidmixer.description = Смешивает воду и мелкий титановый порошок титана в криогеннную жидкость. Неотъемлемая часть при использования ториевого реактора +block.cryofluidmixer.description = Смешивает воду и мелкий титановый порошок в криогеннную жидкость. Неотъемлемая часть при использования ториевого реактора block.blast-mixer.description = Раздавливает и смешивает скопления спор с пиротитом для получения взрывчатого вещества. block.pyratite-mixer.description = Смешивает уголь, свинец и песок в легковоспламеняющийся пиротит. block.melter.description = Плавит металлолом в шлак для дальнейшей обработки или использования в турелях «Волна». @@ -1142,7 +1148,7 @@ block.power-source.description = Бесконечно выводит энерг block.item-source.description = Бесконечно выводит элементы. Только песочница. block.item-void.description = Уничтожает любые предметы. Только песочница. block.liquid-source.description = Бесконечно выводит жидкости. Только песочница. -block.liquid-void.description = Removes any liquids. Sandbox only. +block.liquid-void.description = Уничтожает любые жидкости. Только песочница. block.copper-wall.description = Дешёвый защитный блок.\nПолезен для защиты ядра и турелей в первые несколько волн. block.copper-wall-large.description = Дешёвый защитный блок.\nПолезен для защиты ядра и турелей в первые несколько волн.\nРазмещается на нескольких плитках. block.titanium-wall.description = Умеренно сильный защитный блок.\nОбеспечивает умеренную защиту от врагов. @@ -1172,6 +1178,7 @@ block.inverted-sorter.description = Работает с предметами т block.router.description = Принимает предмет в одном направлении и выводит их до 3 других направлений в равной степени. Полезен для разделения материалов из одного источника на несколько целей.\n\n[scarlet]Никогда не используйте рядом с заводами и т.п., так как маршрутизатор будет забит выходными предметами.[] block.distributor.description = Расширенный маршрутизатор. Разделяет предметы до 7 других направлений в равной степени. block.overflow-gate.description = Выводит предметы влево и вправо, только если передний путь заблокирован. +block.underflow-gate.description = Противоположность избыточного затвора. Выводит предметы вперёд только в том случае, если левый и правый пути заблокированы. block.mass-driver.description = Самый продвинутый транспортный блок. Собирает несколько предметов и затем стреляет ими в другую катапульту на большом расстоянии. Требуется энергия для работы. block.mechanical-pump.description = Дешёвый насос с низкой производительностью, но без энергопотребления. block.rotary-pump.description = Продвинутый насос. Качает больше жидкости, но требуют энергию. diff --git a/core/assets/bundles/bundle_uk_UA.properties b/core/assets/bundles/bundle_uk_UA.properties index b78e537eff..a5ffab3aed 100644 --- a/core/assets/bundles/bundle_uk_UA.properties +++ b/core/assets/bundles/bundle_uk_UA.properties @@ -1,23 +1,23 @@ -credits.text = Створив [ROYAL]Anuken[] — [SKY]anukendev@gmail.com[]\n\nЄ питання по грі або проблеми з перекладом?\nЙдіть в офіційний сервер discord Mindustrу\nу канал #український.\nПерекладач: [blue]Prosta4ok_ua[green]#[yellow]6336 +credits.text = Створив [ROYAL]Anuken[] — [SKY]anukendev@gmail.com[]\n\nЄ ігрові питання або помилки в перекладі?\nЗавітайте до офіційного Discord-сервера Mindustrу\nв канал #український.\nПереклав українською: [blue]Prosta4ok_ua[green]#[yellow]6336 credits = Творці contributors = Перекладачі та помічники -discord = Приєднуйтесь до Mindustry Discord! -link.discord.description = Офіційний Discord сервер Mindustry +discord = Офіційний сервер Mindustry в Discord +link.discord.description = Приєднуйтесь до Discord-сервера Mindustrу! link.reddit.description = Спільнота Mindustry на Reddit link.github.description = Вихідний код гри -link.changelog.description = Список змін +link.changelog.description = Змінопис link.dev-builds.description = Нестабільні версії link.trello.description = Офіційна дошка Trello для запланованих функцій -link.itch.io.description = Itch.io сторінка, на якій можна завантажити гру +link.itch.io.description = Завантажити гру з Itch.io (окрім IOS) link.google-play.description = Завантажити для Android з Google Play link.f-droid.description = Завантажити для Android з F-Droid -link.wiki.description = Офіційна Mindustry wiki +link.wiki.description = Офіційна ігрова Wiki link.feathub.description = Запропонувати нові функції linkfail = Не вдалося відкрити посилання!\nURL-адреса скопійована в буфер обміну. -screenshot = Зняток мапи збережено в {0} +screenshot = Зняток мапи збережено до {0} screenshot.invalid = Мапа занадто велика, тому, мабуть, не вистачає пам’яті для знятку мапи. gameover = Гра завершена -gameover.pvp = [accent] {0}[] команда перемогла! +gameover.pvp = [accent]{0}[] команда перемогла! highscore = [YELLOW]Новий рекорд! copied = Скопійовано. @@ -47,9 +47,9 @@ schematic.browseworkshop = Переглянути в Майстерні schematic.copy = Копіювати в буфер обміну schematic.copy.import = Імпортувати з клавіатури schematic.shareworkshop = Поширити в Майстерню -schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Відобразити схему +schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Обернути схему schematic.saved = Схема збережена. -schematic.delete.confirm = Ця схема буде повністю випалена. +schematic.delete.confirm = Ця схема буде повністю випалена Викорінювачем. schematic.rename = Перейменувати схему. schematic.info = {0}x{1}, {2} блоків @@ -57,19 +57,19 @@ stat.wave = Хвиль відбито:[accent] {0} stat.enemiesDestroyed = Ворогів знищено:[accent] {0} stat.built = Будівель збудувано:[accent] {0} stat.destroyed = Будівель знищено:[accent] {0} -stat.deconstructed = Будівель декоструйовано[accent] {0} +stat.deconstructed = Будівель деконструйовано:[accent] {0} stat.delivered = Ресурсів запущено: stat.rank = Фінальний рахунок: [accent]{0} launcheditems = [accent]Запущені предмети -launchinfo = [unlaunched]Натисніть на кнопку «[[ЗАПУСК]», щоб ваше ядро отримало предмети, які виділені синім кольором. +launchinfo = [unlaunched]Натисніть на кнопку [[ЗАПУСК], щоб ваше ядро отримало предмети, які виділені синім кольором. map.delete = Ви впевнені, що хочете видалити мапу «[accent]{0}[]»? level.highscore = Рекорд: [accent]{0} level.select = Вибір мапи level.mode = Режим гри: showagain = Не показувати знову до наступного сеансу coreattack = < Ядро знаходиться під атакою! > -nearpoint = [[ [scarlet]ЗАЛИШТЕ ЗОНУ ВИСАДКИ НЕГАЙНО[] ]\nАннігіляція неминуча. +nearpoint = [[ [scarlet]ЗАЛИШТЕ ЗОНУ ВИСАДКИ НЕГАЙНО[] ]\nаннігіляція неминуча. database = База даних ядра savegame = Зберегти гру loadgame = Завантажити гру @@ -80,7 +80,7 @@ none = <нічого> minimap = Мінімапа position = Місцерозташування close = Закрити -website = Веб-сайт +website = Вебсайт quit = Вихід save.quit = Зберегти & Вийти maps = Мапи @@ -89,48 +89,49 @@ continue = Продовжити maps.none = [lightgray]Мап не знайдено! invalid = Недійсне pickcolor = Вибрати колір -preparingconfig = Підготовка конфігурації +preparingconfig = Підготовка налаштувань preparingcontent = Підготовка вмісту uploadingcontent = Вивантаження вмісту -uploadingpreviewfile = Вивантаження файлу передперегляду +uploadingpreviewfile = Вивантаження файлу попереднього перегляду committingchanges = Здійснення змін done = Зроблено -feature.unsupported = Your device does not support this feature. +feature.unsupported = Ваш пристрій не підтримує цю функцію -mods.alphainfo = Майте на увазі, що модифікації знаходяться в альфі, і [scarlet]може бути дуже глючними[].\nПовідомте про будь-які проблеми, які ви знайдете до Mindustry Github або Discord. +mods.alphainfo = Майте на увазі, що модифікації знаходяться в альфі, і [scarlet]можуть бути дуже глючними[].\nПовідомте про будь-які проблеми, які ви знайдете до Mindustry Github або Discord. mods.alpha = [scarlet](Альфа) mods = Модифікації mods.none = [LIGHT_GRAY]Модифікацій не знайдено! -mods.guide = Посібник з модифицій +mods.guide = Посібник з модифікацій mods.report = Повідомити про ваду -mods.openfolder = Відкрити теку модифікацій +mods.openfolder = Відкрити мод. теку +mod.display = [gray]Модифікація:[orange] {0} mod.enabled = [lightgray]Увімкнено mod.disabled = [scarlet]Вимкнено -mod.disable = Вимкн. +mod.disable = Вимкнути mod.delete.error = Неможливо видалити модифікацію. Файл, можливо, використовується. mod.requiresversion = [scarlet]Необхідна мінімальна версія гри: [accent]{0} mod.missingdependencies = [scarlet]Відсутні залежності: {0} mod.erroredcontent = [scarlet]Помилки при завантаженнні -mod.errors = Сталася помилка при завантаження змісту. +mod.errors = Виникли помилки при завантаження змісту. mod.noerrorplay = [scarlet]Ви маєте модифікації з помилками.[] Або вимкніть проблемні модифікації, або виправте їх. mod.nowdisabled = [scarlet]Модифікації «{0}» не вистачає залежних модифікацій:[accent] {1}\n[lightgray]Ці модифікації потрібно завантажити спочатку.\nЦя модифікація буде автоматично вимкнена. -mod.enable = Увімк. +mod.enable = Увімкнути mod.requiresrestart = А тепер гра закриється, щоб застосувати зміни модифікацій. mod.reloadrequired = [scarlet]Потрібно перезавантаження mod.import = Імпортувати модифікацію -mod.import.github = Завантажити мод з GitHub +mod.import.github = Завантажити мод. з GitHub mod.item.remove = Цей предмет є частиною модифікації [accent] «{0}»[]. Щоб видалити його, видаліть цю модифікацію. mod.remove.confirm = Цю модифікацію буде видалено. mod.author = [LIGHT_GRAY]Автор:[] {0} mod.missing = Це збереження містить модифікації, які ви нещодавно оновили або більше не встановлювали. Збереження може зіпсуватися. Ви впевнені, що хочете завантажити його?\n[lightgray]Модифікації:\n{0} mod.preview.missing = До публікації цієї модифікації в Майстерні, ви повинні додати зображення попереднього перегляду.\nПомістіть зображення з назвою [accent] preview.png[] у теку з модификаціями і спробуйте знову. mod.folder.missing = Тільки модификації у формі теці можуть бути опубліковані в Майстерні.\nЩоб перетворити будь-яку модификацію у теку, просто розархівуйте цей файлу теку та видаліть старий архів, і потім перезапустіть гру або перезавантажте ваші модификації. -mod.scripts.unsupported = Ваш пристрій не підтримує скрипти модифікацій. Деякі модифифікаціх не будуть працювати правильно. +mod.scripts.unsupported = Ваш пристрій не підтримує скрипти модифікацій. Деякі модифікації не будуть працювати правильно. about.button = Про гру name = Ім’я: noname = Спочатку придумайте[accent] собі ім’я[]. -filename = Ім’я файлу: +filename = Назва файлу: unlocked = Доступний новий вміст! completed = [accent]Завершено techtree = Дерево технологій @@ -141,35 +142,35 @@ players = Гравців: {0} players.single = {0} гравець на сервері server.closing = [accent]Закриття сервера… server.kicked.kick = Ви були вигнані з сервера! -server.kicked.whitelist = Ви не в білому спискі сервера! +server.kicked.whitelist = Ви не в білому списку сервера! server.kicked.serverClose = Сервер закрито. server.kicked.vote = Вас було вигнано із сервера за допомогою голосування. Прощавайте. server.kicked.clientOutdated = Застарілий клієнт! Оновіть свою гру! -server.kicked.serverOutdated = Застарілий сервер! Попросіть адміністратора сервера оновити сервер/гру! +server.kicked.serverOutdated = Застарілий сервер! Попрохайте адміністратора сервера оновити сервер/гру! server.kicked.banned = Ви заблоковані на цьому сервері. server.kicked.typeMismatch = Цей сервер не сумісний з вашим типом збірки. -server.kicked.playerLimit = Цей сервер — заповнений. Дочекайтесь вільного слота. -server.kicked.recentKick = Нещодавно вас вигнали. \nПочекайте трохи перед наступним підключенням. -server.kicked.nameInUse = На цьому сервері є хтось з таким ім’ям. +server.kicked.playerLimit = Цей сервер — заповнений. Дочекайтесь вільного місця. +server.kicked.recentKick = Нещодавно вас вигнали. \nПочекайте трохи перед наступним під’єднанням. +server.kicked.nameInUse = На цьому сервері вже є хтось з таким ім’ям. server.kicked.nameEmpty = Ваше ім’я має містити принаймні один символ або цифру. -server.kicked.idInUse = Ви вже на цьому сервері! Підключення двох облікових записів не дозволяється. +server.kicked.idInUse = Ви вже на цьому сервері! Під’єднанням двох облікових записів не дозволяється. server.kicked.customClient = Цей сервер не підтримує користувацькі збірки. Завантажте офіційну версію. server.kicked.gameover = Гра завершена! server.kicked.serverRestarting = Сервер перезавантажується server.versions = Ваша версія:[accent] {0}[]\nВерсія на сервері:[accent] {1}[] -host.info = Кнопка [accent]Сервер[] розміщує сервер на порті [scarlet]6567[]. \nКористувачі, які знаходяться у тій же [lightgray]WiFi або локальній мережі[], повинні бачити ваш сервер у своєму списку серверів.\n\nЯкщо ви хочете, щоб люди могли приєднуватися з будь-якої точки через IP, то[accent] переадресація порту []обов’язкова.\n\n[lightgray]Примітка. Якщо у вас виникли проблеми з підключенням до вашої локальної гри, переконайтеся, що ви дозволили Mindustry доступ до вашої локальної мережі в налаштуваннях брандмауера. Зауважте, що публічні мережі іноді не дозволяють виявити сервер. -join.info = Тут ви можете ввести [accent]IP сервера[] для підключення або знайти сервери у [accent]локальній мережі[] для підключення до них.\nПідтримується локальна мережа(LAN) і широкосмугова мережа(WAN).\n\n[lightgray] Примітка. Тут немає автоматичного глобального списку серверів; якщо ви хочете підключитися до когось через IP, вам доведеться попросити створювача сервера дати свій ip. +host.info = Кнопка [accent]Сервер[] розміщує сервер на порті [scarlet]6567[]. \nКористувачі, які знаходяться у тій же [lightgray]WiFi або локальній мережах[], повинні побачити ваш сервер у своєму списку серверів.\n\nЯкщо ви хочете, щоб люди могли приєднуватися з будь-якої точки планети через IP, то потрібно зробити[accent] переадресація порту[].\n\n[lightgray]Примітка. Якщо у вас виникли проблеми з приєднанням до вашої локальної гри, переконайтеся, що ви дозволили Mindustry доступ до вашої локальної мережі в налаштуваннях брандмауера. Зауважте, що публічні мережі іноді не дозволяють виявити сервер. +join.info = Тут ви можете ввести [accent]IP сервера[] для під’єднання або знайти сервери у [accent]локальній мережі[] для приєднання до них.\nПідтримується локальна мережа(LAN) і широкосмугова мережа(WAN).\n\n[lightgray] Примітка. Це не є автоматичним глобальним списком серверів; якщо ви хочете приєднатися до когось через IP, вам доведеться попросити власникасервера дати свій ip. hostserver = Запустити багатокористувацький сервер invitefriends = Запросити друзів hostserver.mobile = Запустити\nсервер -host = Сервер +host = Запустити hosting = [accent]Відкриття сервера… hosts.refresh = Оновити hosts.discovering = Пошук локальних ігор hosts.discovering.any = Пошук ігор server.refreshing = Оновлення сервера hosts.none = [lightgray]Локальних ігр не знайдено -host.invalid = [scarlet]Не вдалося підключитися до сервера. +host.invalid = [scarlet]Не вдалося під’єднатися до сервера. trace = Стежити за гравцем trace.playername = Ім’я гравця: [accent]{0} trace.ip = IP: [accent]{0} @@ -182,14 +183,14 @@ server.bans.none = Заблокованих гравців немає! server.admins = Адміністратори server.admins.none = Адміністраторів немає! server.add = Додати сервер -server.delete = Ви впевнені, що хочете видалити цей сервер? +server.delete = Ви дійсно хочете видалити цей сервер? server.edit = Редагувати сервер server.outdated = [crimson]Застарілий сервер![] server.outdated.client = [crimson]Застарілий клієнт![] server.version = [lightgray]Версія: {0} server.custombuild = [yellow]Користувацька збірка confirmban = Ви дійсно хочете заблокувати цього гравця? -confirmkick = Ви дійсно хочете викинути цього гравця? +confirmkick = Ви дійсно хочете вигнати цього гравця? confirmvotekick = Ви дійсно хочете вигнати цього гравця за допомогою голосуванняr? confirmunban = Ви дійсно хочете розблокувати цього гравця? confirmadmin = Ви дійсно хочете зробити цього гравця адміністратором? @@ -200,23 +201,23 @@ disconnect = Відключено. disconnect.error = Помилка з’єднання. disconnect.closed = З'єднання закрито. disconnect.timeout = Час вийшов. -disconnect.data = Не вдалося завантажити дані світу! +disconnect.data = Не вдалося завантажити світові дані! cantconnect = Не вдалося під’єднатися до гри ([accent]{0}[]). -connecting = [accent]Підключення… +connecting = [accent]Приєднання… connecting.data = [accent]Завантаження даних світу… server.port = Порт: server.addressinuse = Ця адреса вже використовується! server.invalidport = Недійсний номер порту! server.error = [crimson]Помилка створення сервера: [accent]{0} save.new = Нове збереження -save.overwrite = Ви впевнені, що хочете перезаписати цей слот для збереження? +save.overwrite = Ви дійсно хочете перезаписати це місце збереження? overwrite = Перезаписати save.none = Збережень не знайдено! saveload = [accent]Збереження… savefail = Не вдалося зберегти гру! save.delete.confirm = Ви дійсно хочете видалити це збереження? save.delete = Видалити -save.export = Експортувати збереження +save.export = Вивантажити збереження save.import.invalid = [accent]Це збереження недійсне! save.import.fail = [crimson]Не вдалося завантажити збереження: [accent]{0} save.export.fail = [crimson]Не вдалося вивантажити збереження: [accent]{0} @@ -224,18 +225,18 @@ save.import = Імпортувати збереження save.newslot = Ім’я збереження: save.rename = Перейменувати save.rename.text = Нова назва: -selectslot = Виберіть збереження. -slot = [accent]Слот {0} +selectslot = Виберіть збережений файл. +slot = [accent]Місце збережання{0} editmessage = Редагувати повідомлення -save.corrupted = [accent]Збережений файл пошкоджено або недійсний! \nЯкщо ви щойно оновили свою гру, це, мабуть, є зміною формату збереження та [scarlet] не є[] помилкою. -empty = <Порожньо> +save.corrupted = [accent]Збережений файл пошкоджено або він є недійсним! \nЯкщо ви щойно оновили свою гру, це, мабуть, є зміною формату збереження та [scarlet] не є[] помилкою. +empty = <порожньо> on = Увімкнено off = Вимкнено save.autosave = Автозбереження: {0} save.map = Мапа: {0} save.wave = Хвиля {0} save.mode = Режим гри: {0} -save.date = Останнє збереження +save.date = Останнє збереження: {0} save.playtime = Час гри: {0} warning = Попередження confirm = Підтвердження @@ -251,13 +252,14 @@ copylink = Скопіювати посилання back = Назад data.export = Вивантажити дані data.import = Завантажити дані +data.openfolder = Відкрити теку з даними data.exported = Дані вивантажено. data.invalid = Це не дійсні ігрові дані. data.import.confirm = Вивантаження зовнішніх даних перезапише[scarlet] ВСІ[] ваші поточні ігрові дані.\n[accent]Це неможливо скасувати![]\n\nЩойно дані імпортуються, гра негайно закриється. classic.export = Вивантажити класичні дані classic.export.text = Класичне (версія 3.5 збірка 40) збереження або мапа були знайдені. Ви хочете експортувати ці дані в домашню теку телефону, для використання у застосунку Mindustry Classic? -quit.confirm = Ви впевнені, що хочете вийти? -quit.confirm.tutorial = Ви впевнені, що хочете вийти з навчання? +quit.confirm = Ви дійсно хочете вийти? +quit.confirm.tutorial = Ви дійсно хочете вийти з навчання? loading = [accent]Завантаження… reloading = [accent]Перезавантаження модифікацій… saving = [accent]Збереження… @@ -270,14 +272,14 @@ wave.waiting = Хвиля через {0} wave.waveInProgress = [lightgray]Хвиля триває waiting = Очікування… waiting.players = Очікування гравців… -wave.enemies = [lightgray]{0} ворог. залишилося -wave.enemy = [lightgray]{0} ворог залишився +wave.enemies = Залишилося [lightgray]{0} ворог. +wave.enemy = Залишився [lightgray]{0} ворог loadimage = Завантажити зображення saveimage = Зберегти зображення unknown = Невідомо custom = Користувацька builtin = Вбудована -map.delete.confirm = Ви дійсно хочете видалити цю мапу? Це неможливо буде скасувати! +map.delete.confirm = Ви дійсно хочете видалити цю мапу? Цю дію неможливо буде скасувати! map.random = [accent]Випадкова мапа map.nospawn = Ця мапа не має жодного ядра для появи гравця! Додайте [ROYAL]помаранчеве[] ядро до цієї мапи в редакторі. map.nospawn.pvp = У цієї мапи немає ворожих ядер, в яких гравець може з’явитися! Додайте [SCARLET]не помаранчеве[] ядро до цієї мапи в редакторі. @@ -285,15 +287,15 @@ map.nospawn.attack = У цієї мапи немає ворожих ядер, в map.invalid = Помилка завантаження мапи: пошкоджений або невірний файл мапи. workshop.update = Оновити предмет workshop.error = Помилка при отриманні інформації з Майстерні: {0} -map.publish.confirm = Ви дійсно хочете опублікувати цю мапу?\n\n[lightgray]Переконайтеся, що спершу ви згодні з Ліцензійною угодою Steam, або ваші мапи не з’являться! +map.publish.confirm = Ви дійсно хочете опублікувати цю мапу?\n\n[lightgray]Спершу переконайтеся, що ви згодні з Ліцензійною угодою Steam, або ваші мапи не з’являться! workshop.menu = Виберіть, що ви хочете зробити з цим предметом. workshop.info = Інформація про предмет -changelog = Журнал змін (за бажанням): -eula = Ліцензійна угода +changelog = Змінопис (за бажанням): +eula = Ліцензійна угода Steam missing = Цей предмет було видалено або переміщено.\n[lightgray]Список Майстерні тепер автоматично від’єднано. publishing = [accent]Публікація… publish.confirm = Ви дійсно хочете опублікувати це?\n\n[lightgray]Переконайтеся, що ви спочатку погоджуєтеся з EULA Майстерні, або ваші предмети не з’являться! -publish.error = Сталася помилка при публікації предмета: {0} +publish.error = Виникла помилка при публікації предмета: {0} steam.error = Не вдалося ініціалізувати сервіси Steam.\nПомилка: {0} editor.brush = Пензлик @@ -320,8 +322,8 @@ waves.perspawn = за появу waves.to = до waves.boss = Бос waves.preview = Попередній перегляд -waves.edit = Редагувати … -waves.copy = Копіювати у буфер обміну +waves.edit = Редагувати… +waves.copy = Копіювати в буфер обміну waves.load = Завантажити з буфера обміну waves.invalid = Недійсні хвилі у буфері обміну. waves.copied = Хвилі скопійовані. @@ -335,11 +337,11 @@ editor.removeunit = Видалити бойову одиницю editor.teams = Команди editor.errorload = Помилка завантаження зображення:\n[accent] {0} editor.errorsave = Помилка збереження зображення:\n[accent]{0} -editor.errorimage = Це зображення, а не мапа. Не змінюйте розширення, очікуючи, що це запрацює.\n\nЯкщо ви хочете імпортувати застарілку мапу, то використовуйте кнопку «Імпортувати застаріле зображення» у редакторі. +editor.errorimage = Це зображення, а не мапа. Не змінюйте розширення, очікуючи, що це спрацює.\n\nЯкщо ви хочете імпортувати застарілу мапу, то використовуйте кнопку «Імпортувати застаріле зображення» у редакторі. editor.errorlegacy = Ця мапа занадто стара і використовує попередній формат мапи, який більше не підтримується. editor.errornot = Це не мапа. editor.errorheader = Цей файл мапи недійсний або пошкоджений. -editor.errorname = Мапа не має імені. Може Ви намагаєтеся завантажити збереження? +editor.errorname = Мапа не має назви. Може Ви намагаєтеся завантажити збереження? editor.update = Оновити editor.randomize = Випадково editor.apply = Застосувати @@ -348,8 +350,8 @@ editor.resize = Змінити\nрозмір editor.loadmap = Завантажити мапу editor.savemap = Зберегти мапу editor.saved = Збережено! -editor.save.noname = Ваша мапа не має імені! Встановіть його в «Інформація про мапу». -editor.save.overwrite = Ваша мапа перезаписує вбудовану мапу! Виберіть інше ім’я в «Інформація про мапу». +editor.save.noname = Ваша мапа не має назви! Установіть його в «Інформація про мапу». +editor.save.overwrite = Ваша мапа перезаписує вбудовану мапу! Виберіть іншу назву в «Інформація про мапу». editor.import.exists = [scarlet]Неможливо імпортувати:[] вбудована мапа з назвою «{0}» вже існує! editor.import = Імпорт… editor.importmap = Імпортувати мапу @@ -362,7 +364,7 @@ editor.export = Експорт… editor.exportfile = Експорт файлу editor.exportfile.description = Експортувати файл мапи editor.exportimage = Експорт зображення місцевості -editor.exportimage.description = Експорт файла з зображенням мапи +editor.exportimage.description = Експорт файлу з зображенням мапи editor.loadimage = Завантажити\nзображення editor.saveimage = Зберегти\nзображення editor.unsaved = [scarlet]У вас є незбережені зміни![]\nВи впевнені, що хочете вийти? @@ -370,13 +372,13 @@ editor.resizemap = Змінити розмір мапи editor.mapname = Назва мапи: editor.overwrite = [accent]Попередження!\nЦе перезаписує існуючу мапу. editor.overwrite.confirm = [scarlet]Попередження![] Мапа з такою назвою вже існує. Ви впевнені, що хочете переписати її? -editor.exists = Мапа за такою назвою вже існує. +editor.exists = Мапа з такою назвою вже існує. editor.selectmap = Виберіть мапу для завантаження: toolmode.replace = Замінити toolmode.replace.description = Малює тільки\nна суцільних блоках. toolmode.replaceall = Замінити все -toolmode.replaceall.description = Замінює усі блоки на мапі. +toolmode.replaceall.description = Замінює всі блоки на мапі. toolmode.orthogonal = Ортогональна toolmode.orthogonal.description = Малює лише\nортогональні лінії. toolmode.square = Прямокутник @@ -428,16 +430,16 @@ campaign = Кампанія load = Завантажити save = Зберегти fps = FPS: {0} -ping = Пінг: {0} мс +ping = Затримка: {0} мс language.restart = Будь ласка, перезапустіть свою гру, щоб налаштування мови набули чинності. settings = Налаштування tutorial = Навчання -tutorial.retake = Відкрити навчання +tutorial.retake = Пройти навчання ще раз editor = Редактор mapeditor = Редактор мап abandon = Покинути -abandon.text = Ця зона і всі її ресурси будуть втрачені. +abandon.text = Ця зона і всі її ресурси будуть утрачені. locked = Заблоковано complete = [lightgray]Досягнута: requirement.wave = Досягніть хвилі {0} у зоні «{1}» @@ -449,41 +451,41 @@ launch = < ЗАПУСК > launch.title = Запуск вдалий launch.next = [lightgray]наступна можливість на {0}-тій хвилі launch.unable2 = [scarlet]ЗАПУСК неможливий.[] -launch.confirm = Це видалить всі ресурси у Вашому ядрі.\nВи не зможете повернутися до цієї бази. -launch.skip.confirm = Якщо ви пропустите зараз, Ви не зможете не запускати до більш пізніх хвиль. +launch.confirm = Це видалить всі ресурси у вашому ядрі.\nВи не зможете повернутися до цієї бази. +launch.skip.confirm = Якщо ви пропустите зараз, ви не зможете не запускати до більш пізніх хвиль. uncover = Розкрити -configure = Вивантажити конфігурацію +configure = Налаштувати вивантаження bannedblocks = Заборонені блоки addall = Додати все configure.locked = {0}[lightgray]Тільки після цього можливість розблокувати вивантаження ресурсів буде доступна. configure.invalid = Кількість повинна бути числом між 0 та {0}. zone.unlocked = Зона «[lightgray]{0}» тепер розблокована. -zone.requirement.complete = Ви досягли {0}-тої хвилі. \nВимоги до зони «{1}» виконані. +zone.requirement.complete = Ви досягли {0}-тої хвилі.\nВимоги до зони «{1}» виконані. zone.config.unlocked = Вивантаження розблоковано:[lightgray]\n{0} zone.resources = Виявлені ресурси: zone.objective = [lightgray]Мета: [accent]{0} -zone.objective.survival = Вижити -zone.objective.attack = Знищити вороже ядро +zone.objective.survival = вижити. +zone.objective.attack = знищити вороже ядро. add = Додати… boss.health = Здоров’я босу -connectfail = [crimson]Помилка підключення: [accent]{0} -error.unreachable = Сервер не доступний. +connectfail = [crimson]Помилка з’єднання: [accent]{0} +error.unreachable = Сервер не є доступним.\nЧи правильно написана адреса? error.invalidaddress = Некоректна адреса. error.timedout = Час очікування вийшов.\nПереконайтеся, що адреса коректна і що власник сервера налаштував переадресацію порту! -error.mismatch = Помилка пакету:\nможливе невідповідність версії клієнта/сервера.\nПереконайтеся, що у вас та у володара сервера встановлена остання версія Mindustry! -error.alreadyconnected = Ви вже підключилися. -error.mapnotfound = Файл мапи не знайдено -error.io = Мережева помилка введення-виведення +error.mismatch = Помилка пакету:\nможлива невідповідність версії клієнта/сервера.\nПереконайтеся, що у вас та у власника сервера встановлена остання версія Mindustry! +error.alreadyconnected = Ви вже під’єдналися. +error.mapnotfound = Файл мапи не знайдено! +error.io = Мережева помилка введення-виведення. error.any = Невідома мережева помилка -error.bloom = Не вдалося ініціалізувати цвітіння.\nВаш пристрій, мабуть, не підтримує це. +error.bloom = Не вдалося ініціалізувати світіння.\nВаш пристрій, мабуть, не підтримує це. zone.groundZero.name = Відправний пункт zone.desertWastes.name = Пустельні відходи zone.craters.name = Кратери zone.frozenForest.name = Крижаний ліс -zone.ruinousShores.name = Зруйновані берега -zone.stainedMountains.name = Пофарбовані гори +zone.ruinousShores.name = Зруйновані береги +zone.stainedMountains.name = Забруднені гори zone.desolateRift.name = Пустельний розлом zone.nuclearComplex.name = Ядерний виробничий комплекс zone.overgrowth.name = Зарості @@ -493,24 +495,24 @@ zone.impact0078.name = Імпульс 0078 zone.crags.name = Скелі zone.fungalPass.name = Грибний перевал -zone.groundZero.description = Оптимальне місце для повторних ігор. Низька ворожа загроза. Мало ресурсів. \nЗбирайте якомога більше свинцю та міді. \nЙдіть далі. -zone.frozenForest.description = Навіть тут, ближче до гір, спори поширилися. Холодна температура не може їх утримувати тут завжди.\nЗважтесь створити енергію. Побудуйте генератори внутрішнього згорання. Навчіться користуватися регенераторами. -zone.desertWastes.description = Ці відходи є величезними, непередбачуваними і перетинаються з занедбаними секторальними структурами.\nВугілля присутнє в регіоні. Спаліть його для енергії або синтезуйте у графіт.\n\n[lightgray]Це місце посадки не можна гарантувати. -zone.saltFlats.description = На околиці пустелі лежать соляні рівнини. У цьому місці можна знайти небагато ресурсів.\n\nТут вороги спорудили комплекс сховищ ресурсів. Викорініть їх ядро. Не залишайте нічого цінного. -zone.craters.description = У цьому кратері накопичилася вода, пережиток старих воєн. Відновіть місцевість. Зберіть пісок. Виплавіть метакскло. Накачайте воду, щоб охолодити турелі і бури. -zone.ruinousShores.description = Минулі відходи - це берегова лінія. Колись у цьому місці розташувався береговий оборонний масив. Залишилося не так багато чого. Тільки найосновніші оборонні споруди залишилися непошкодженими, все інше зводиться до брухту.\nПродовжуйте експансію назовні. Повторно розкрийте технологію. -zone.stainedMountains.description = Далі у вглиб материка лежать гори, ще не заражені спорами.\nВидобудьте надлишковий титан у цій місцевості. Дізнайтеся, як використовувати його.\n\nТут ворожа присутність більша. Не дайте їм часу відправити свої найсильніші одиниці. -zone.overgrowth.description = Ця територія заросла, ближче до джерела спор.\nВорог тут встановив форпост. Побудуйте бойові одиниці Кинджал. Знищте його. Поверніть те, що було втрачено. -zone.tarFields.description = Окраїна зони видобутку нафти, між горами та пустелею. Один з небагатьох районів із корисними запасами смоли.\nНезважаючи на те, що покинута, ця територія має поблизу небезпечні сили противника. Не варто їх недооцінювати.\n\n[lightgray]Якщо можливо, дослідіть технологію переробки нафти. -zone.desolateRift.description = Надзвичайно небезпечна зона. Багато ресурсів, але мало місця. Евакуюватися потрібно якомога швидше. Не розслабляйтеся між ворожими атаками. -zone.nuclearComplex.description = Колишній об’єкт для виробництва та переробки торію, зведений до руїн.\n[lightgray]Дослідіть торій та його безліч застосувань.\n\nВраг присутній тут у великій кількості, постійно шукаючи нападників. -zone.fungalPass.description = Перехідна зона між високими і низькими горами, земля яких покрита спорами. Тут знаходиться невелика розвідувальна база ворога.\nЗнижте її.\nВикористовуйте одиниці Кинджал і Камікадзе. +zone.groundZero.description = Оптимальне місце для повторних ігор. Низька ворожа загроза. Мало ресурсів. \nЗбирайте якомога більше свинцю та міді. \nНе затримуйтесь і йдіть далі. +zone.frozenForest.description = Спори поширилися навіть тут, ближче до гір. Холодна температура не може стримувати їх завжди.\nЗважтесь створити енергію. Побудуйте генератори внутрішнього згорання. Навчіться користуватися регенераторами. +zone.desertWastes.description = Ці відходи є величезними, непередбачуваними і перетинаються з занедбаними секторальними структурами.\nВугілля присутнє в регіоні. Спаліть його для енергії або синтезуйте у графіт.\n\n[lightgray]Є декілька варіантів для місць посадок. +zone.saltFlats.description = На околицях пустелі лежать Соляні рівнини. У цьому місці можна знайти небагато ресурсів.\n\nСаме тут вороги спорудили комплекс сховищ ресурсів. Викорініть їхнє ядро. Не залишайте нічого цінного. +zone.craters.description = У цьому кратері накопичилася вода, пережиток старих воєн. Відновіть місцевість. Зберіть пісок. Виплавте метаскло. Качайте воду, щоб охолодити турелі і бури. +zone.ruinousShores.description = Саме берегова лінія є минулим цих відходів. Колись у цьому місці розташувався береговий оборонний масив, проте залишилося не так багато чого. Тільки основні оборонні споруди залишилися неушкодженими, а все інше перетворилося на металобрухт.\nПродовжуйте експансію назовні. Повторно розкрийте технології. +zone.stainedMountains.description = Якщо йти далі у вглиб материка, то можна побачити гори, які ще не заражені спорами.\nВидобудьте надлишковий титан у цій місцевості. Дізнайтеся, як використовувати його.\n\nНа жаль, тут більше ворогів ніж в інших місцевостях. Не дайте їм часу надіслати свої найсильніші одиниці. +zone.overgrowth.description = Ближче до джерела спор є територія, що заросла.\nНе дивуйтеся, що ворог встановив тут свій форпост. Побудуйте бойові одиниці під кодовою назвою «Титан». Зруйнуйте вщент супротивника. Поверніть те, що колись належало нам. +zone.tarFields.description = Між горами та пустелею простягається окраїна зони видобутку нафти. Це один з небагатьох районів із корисними для використання запасами смоли.\nНезважаючи на те, що територія покинута, вона має поблизу небезпечні сили противника. Не варто їх недооцінювати.\n\n[lightgray]Якщо можливо, дослідіть технологію переробки нафти. +zone.desolateRift.description = Надзвичайно небезпечна зона. Багато ресурсів, але мало місця. Евакуюватися потрібно якомога швидше. Не розслабляйтеся між ворожими атаками та знайдіть ахіллесову п'яту супротивника. +zone.nuclearComplex.description = Колишній об’єкт для виробництва та переробки торію було зведено до руїн.\n[lightgray]Дослідіть торій та його нескінченну кількість застосувань.\n\nВорог, який постійно шукає нападників, присутній тут у великій кількості, тому не баріться з евакуацією! +zone.fungalPass.description = Перехідна зона між високими і низькими горами, земля яких вкрита спорами. Тут знаходиться невелика розвідувальна база ворога.\nЗнищте її.\nВикористовуйте одиниці з кодовими назвами «Кинджал» і «Камікадзе» для повного знищення двох ворожих ядер. zone.impact0078.description = <вставити опис тут> zone.crags.description = <вставити опис тут> settings.language = Мова settings.data = Ігрові дані -settings.reset = Скинути за замовчуванням +settings.reset =За замовчуванням settings.rebind = Змінити settings.resetKey = Скинути settings.controls = Керування @@ -518,9 +520,9 @@ settings.game = Гра settings.sound = Звук settings.graphics = Графіка settings.cleardata = Очистити дані… -settings.clear.confirm = Ви впевнені, що хочете очистити ці дані?\nЦя дія не може бути скасовано! -settings.clearall.confirm = [scarlet]УВАГА![]\nЦе очистить всі дані, включаючи збереження, мапи, розблоковане та налаштування керування.\nПісля того, як ви натиснете ОК, гра видалить усі дані та автоматично закриється. -paused = Пауза +settings.clear.confirm = Ви дійсно хочете очистити ці дані?\nЦю дію не можна скасовати! +settings.clearall.confirm = [scarlet]УВАГА![]\nЦе очистить усі дані, включаючи збереження, мапи, розблоковане та налаштування керування.\nПісля натискання ОК гра видалить усі дані та автоматично закриється. +paused = [accent]< Пауза> clear = Очистити banned = [scarlet]Заблоковано yes = Так @@ -531,21 +533,23 @@ error.crashtitle = Виникла помилка blocks.input = Вхід blocks.output = Вихід blocks.booster = Прискорювач +blocks.tiles = Необхідні плитки +blocks.affinities = Збільшення ефективності block.unknown = [lightgray]??? blocks.powercapacity = Місткість енергії blocks.powershot = Енергія за постріл blocks.damage = Шкода -blocks.targetsair = Повітряні мішені -blocks.targetsground = Наземні мішені +blocks.targetsair = Повітряні вороги +blocks.targetsground = Наземні вороги blocks.itemsmoved = Швидкість переміщення blocks.launchtime = Час між запусками blocks.shootrange = Діапазон дії blocks.size = Розмір -blocks.liquidcapacity = Місткість рідини +blocks.liquidcapacity = Рідинна місткість blocks.powerrange = Діапазон передачі енергії blocks.powerconnections = Максимальна кількість з’єднань blocks.poweruse = Енергії використовує -blocks.powerdamage = Енергія/шкода +blocks.powerdamage = Енергії за од. шкоди blocks.itemcapacity = Місткість предметів blocks.basepowergeneration = Базова генерація енергії blocks.productiontime = Час виробництва @@ -583,11 +587,11 @@ bar.input = Ввід bar.output = Вивід bullet.damage = [stat]{0}[lightgray] шкода -bullet.splashdamage = [stat]{0}[lightgray] шкода по ділянці ~[stat] {1}[lightgray] блок. +bullet.splashdamage = [stat]{0}[lightgray] шкода по ділянці ~[stat] {1}[lightgray] плиток. bullet.incendiary = [stat]запальний bullet.homing = [stat]самонаведення bullet.shock = [stat]шок -bullet.frag = [stat]осколкова граната +bullet.frag = [stat]шкода по ділянці bullet.knockback = [stat]{0}[lightgray] відкидання bullet.freezing = [stat]заморожування bullet.tarred = [stat]дьогтьовий @@ -629,9 +633,9 @@ setting.autotarget.name = Авто-стрільба setting.keyboard.name = Миш+Керування з клавіатури setting.touchscreen.name = Керування сенсорним екраном setting.fpscap.name = Максимальний FPS -setting.fpscap.none = Необмежений +setting.fpscap.none = Жодне setting.fpscap.text = {0} FPS -setting.uiscale.name = Масштаб користувальницького інтерфейсу[lightgray] (потребує перезапуск)[] +setting.uiscale.name = Масштаб користувацького інтерфейсу[lightgray] (потребує перезапуск)[] setting.swapdiagonal.name = Завжди діагональне розміщення setting.difficulty.training = Навчання setting.difficulty.easy = Легка @@ -646,7 +650,7 @@ setting.conveyorpathfinding.name = Пошук шляху для встановл setting.coreselect.name = Дозволити схематичні ядра setting.sensitivity.name = Чутливість контролера setting.saveinterval.name = Інтервал збереження -setting.seconds = {0} с +setting.seconds = {0} секунд setting.blockselecttimeout.name = Час вибору блока setting.milliseconds = {0} мілісекунд setting.fullscreen.name = Повноекранний режим @@ -665,12 +669,14 @@ setting.mutesound.name = Заглушити звук setting.crashreport.name = Відсилати анонімні звіти про аварійне завершення гри setting.savecreate.name = Автоматичне створення збережень setting.publichost.name = Загальнодоступність гри +setting.playerlimit.name = Обмеження гравців setting.chatopacity.name = Непрозорість чату setting.lasersopacity.name = Непрозорість лазерів енергопостачання +setting.bridgeopacity.name = Місткість мостів setting.playerchat.name = Відображати хмару чата над гравцями public.confirm = Ви хочете зробити цю гру загальнодоступною?\n[lightgray]Це можна змінити у Налаштування→Гра→Загальнодоступність гри public.beta = Зауважте, що в бета-версії гри ви не можете робити публічні ігри. -uiscale.reset = Масштаб користувальницького інтерфейсу було змінено.\nНатисніть «ОК» для підтверждення цього масшатабу.\n[scarlet]Повернення налаштувань і вихід через[accent] {0}[] … +uiscale.reset = Масштаб користувацького інтерфейсу було змінено.\nНатисніть «ОК» для підтвердження цього масштабу.\n[scarlet]Повернення налаштувань і вихід через[accent] {0}[] секунд… uiscale.cancel = Скасувати & Вийти setting.bloom.name = Світіння keybind.title = Налаштування керування @@ -698,7 +704,7 @@ keybind.schematic_flip_y.name = Відобразити по осі Y keybind.category_prev.name = Попередня категорія keybind.category_next.name = Наступна категорія keybind.block_select_left.name = Вибрати блок ліворуч -keybind.block_select_right.name = Вибрати блок ліворуч праворуч +keybind.block_select_right.name = Вибрати блок праворуч keybind.block_select_up.name = Вибрати блок зверху keybind.block_select_down.name = Вибрати блок знизу keybind.block_select_01.name = Категорія/Вибрати перший блок @@ -733,39 +739,39 @@ keybind.chat_history_prev.name = Попередня історія чату keybind.chat_history_next.name = Наступна історія чату keybind.chat_scroll.name = Прокрутка чату keybind.drop_unit.name = Скинути бойову одиницю -keybind.zoom_minimap.name = Збільшити міні-мапу -mode.help.title = Опис режимів -mode.survival.name = Хвилі -mode.survival.description = Звичайний режим. В цьому режимі треба самим добувати ресурси та хвилі йдуть автоматично.\n[gray]Потребуються точки появи ворогів для гри. +keybind.zoom_minimap.name = Збільшити мінімапу +mode.help.title = Опис режимів гри +mode.survival.name = Виживання +mode.survival.description = Звичайний режим. В цьому режимі треба самим видобувати ресурси та хвилі йдуть автоматично.\n[gray]Потребуються точки появи ворогів для гри. mode.sandbox.name = Пісочниця -mode.sandbox.description = В режимі «Пісочниця» незкінченні ресурси(але їх все одно можно добувати) та хвилі йдуть за вашим бажанням. +mode.sandbox.description = Нескінченні ресурси та хвилі йдуть за вашим бажанням. mode.editor.name = Редактор mode.pvp.name = PVP -mode.pvp.description = боріться проти інших гравців.\n[gray]Для гри потрібно принаймні 2 ядра різного кольору на мапі. +mode.pvp.description = Боріться проти інших гравців.\n[gray]Для гри потрібно принаймні 2 ядра різного кольору на мапі. mode.attack.name = Атака mode.attack.description = Зруйнуйте ворожу базу.\n[gray]Потрібно червоне ядро на мапі для гри. mode.custom = Користувацькі правила rules.infiniteresources = Нескінченні ресурси rules.reactorexplosions = Вибухи реактора -rules.wavetimer = Таймер хвиль +rules.wavetimer = Таймер для хвиль rules.waves = Хвилі rules.attack = Режим атаки -rules.enemyCheat = Нескінченні ресурси для ШІ -rules.unitdrops = Ресурс бойових одиниць +rules.enemyCheat = Нескінченні ресурси для червоної команди ШІ +rules.unitdrops = Випадіння ресурсів з бойових одиниць rules.unitbuildspeedmultiplier = Множник швидкості виробництва бойових одиниць rules.unithealthmultiplier = Множник здоров’я бойових одиниць rules.blockhealthmultiplier = Множник здоров’я блоків rules.playerhealthmultiplier = Множник здоров’я гравця rules.playerdamagemultiplier = Множник шкоди гравця rules.unitdamagemultiplier = Множник шкоди бойових одиниць -rules.enemycorebuildradius = Радіус захисту для ворожого ядра:[lightgray] (блоків) -rules.respawntime = Час відродження:[lightgray] (sec) -rules.wavespacing = Інтервал хвиль:[lightgray] (sec) +rules.enemycorebuildradius = Радіус захисту для ворожого ядра:[lightgray] (плитки) +rules.respawntime = Час відродження:[lightgray] (секунди) +rules.wavespacing = Інтервал хвиль:[lightgray] (секунди) rules.buildcostmultiplier = Множник затрат на будування rules.buildspeedmultiplier = Множник швидкості будування -rules.waitForWaveToEnd = Хвилі чекають на ворогів -rules.dropzoneradius = Радіус зони висадки:[lightgray] (блоків) +rules.waitForWaveToEnd = Хвилі чекають на смерть усіх ворогів +rules.dropzoneradius = Радіус зони висадки:[lightgray] (плитки) rules.respawns = Максимальна кількість відроджень за хвилю rules.limitedRespawns = Обмеження відроджень rules.title.waves = Хвилі @@ -773,7 +779,7 @@ rules.title.respawns = Відродження rules.title.resourcesbuilding = Ресурси & будування rules.title.player = Гравці rules.title.enemy = Вороги -rules.title.unit = Бойов. од. +rules.title.unit = Бойові одиниці rules.title.experimental = Есперементальне! rules.lighting = Світлотінь rules.ambientlight = Навколишнє світло @@ -885,7 +891,7 @@ block.snow.name = Сніг block.craters.name = Кратери block.sand-water.name = Пісок з водою block.darksand-water.name = Темний пісок з водою -block.char.name = Випалена Земля +block.char.name = Випалена земля block.holostone.name = Голографічний камінь block.ice-snow.name = Крижаний сніг block.rocks.name = Камені @@ -896,11 +902,11 @@ block.pine.name = Сосна block.white-tree-dead.name = Мертве біле дерево block.white-tree.name = Біле дерево block.spore-cluster.name = Скупчення спор -block.metal-floor.name = Металевий пол 1 -block.metal-floor-2.name = Металевий пол 2 -block.metal-floor-3.name = Металевий пол 3 -block.metal-floor-5.name = Металевий пол 4 -block.metal-floor-damaged.name = Пошкоджений иеталевий пол +block.metal-floor.name = Металева підлога 1 +block.metal-floor-2.name = Металева підлога 2 +block.metal-floor-3.name = Металева підлога 3 +block.metal-floor-5.name = Металева підлога 4 +block.metal-floor-damaged.name = Пошкоджена металевий підлога block.dark-panel-1.name = Темна панель 1 block.dark-panel-2.name = Темна панель 2 block.dark-panel-3.name = Темна панель 3 @@ -928,11 +934,11 @@ block.duo.name = Подвійна турель block.scorch.name = Випалювач block.scatter.name = Розсіювач block.hail.name = Град -block.lancer.name = Списоносець +block.lancer.name = Списник block.conveyor.name = Конвеєр block.titanium-conveyor.name = Титановий конвеєр block.armored-conveyor.name = Броньований конвеєр -block.armored-conveyor.description = Переміщує предмети з тією ж швидкістю, як і титанові конвеєри, але має більше міцності. Не приймає введення з боків ні з чого, крім інших конвеєрних стрічок. +block.armored-conveyor.description = Переміщує предмети з тією ж швидкістю, що і титанові конвеєри, але має більше міцності. Не приймає введення з боків ні з чого, крім інших конвеєрних стрічок. block.junction.name = Перехрестя block.router.name = Маршрутизатор block.distributor.name = Розподілювач @@ -940,15 +946,16 @@ block.sorter.name = Сортувальник block.inverted-sorter.name = Зворотній сортувальник block.message.name = Повідомлення block.illuminator.name = Освітлювач -block.illuminator.description = Невелике, компактне, джерело світла, яку можна налаштувати. Для функціонування потрібна енергія. -block.overflow-gate.name = Надмірний затвор +block.illuminator.description = Невелике, компактне, джерело світла, яку можна налаштувати. Для роботи потребує енергії. +block.overflow-gate.name = Надмірний затвір +block.underflow-gate.name = Інвертований затвір block.silicon-smelter.name = Кремнієвий плавильний завод block.phase-weaver.name = Фазовий ткач block.pulverizer.name = Подрібнювач block.cryofluidmixer.name = Змішувач кріогенної рідини block.melter.name = Плавильня block.incinerator.name = Сміттєспалювальний завод -block.spore-press.name = Споровий Прес +block.spore-press.name = Споровий прес block.separator.name = Відокремлювач block.coal-centrifuge.name = Вугільна центрифуга block.power-node.name = Енергійний вузол @@ -978,7 +985,7 @@ block.mechanical-pump.name = Механічна помпа block.item-source.name = Нескінченне джерело предметів block.item-void.name = Предметний вакуум block.liquid-source.name = Нескінченне джерело рідин -block.liquid-void.name = Liquid Void +block.liquid-void.name = Рідинний вакуум block.power-void.name = Енергетичний вакуум block.power-source.name = Нескінченне джерело енергії block.unloader.name = Розвантажувач @@ -986,11 +993,11 @@ block.vault.name = Сховище block.wave.name = Хвиля block.swarmer.name = Роєвик block.salvo.name = Залп -block.ripple.name = Рябь +block.ripple.name = Ряб block.phase-conveyor.name = Фазовий конвеєр block.bridge-conveyor.name = Мостовий конвеєр -block.plastanium-compressor.name = Пластиновий компресор -block.pyratite-mixer.name = Змішувач піротиту +block.plastanium-compressor.name = Пластинієвий компресор +block.pyratite-mixer.name = Змішувач піротита block.blast-mixer.name = Мішалка вибухонебезпечного з’єднання block.solar-panel.name = Сонячна панель block.solar-panel-large.name = Велика сонячна панель @@ -1007,12 +1014,12 @@ block.titan-factory.name = Завод мехів «Титан» block.fortress-factory.name = Завод мехів «Фортеця» block.revenant-factory.name = Завод бомбардувальників «Потойбічний вбивця» block.repair-point.name = Ремонтний пункт -block.pulse-conduit.name = Імпульсний водопровід -block.plated-conduit.name = Зміцнений водопровід -block.phase-conduit.name = Фазовий водопровід -block.liquid-router.name = Рідкий маршрутизатор -block.liquid-tank.name = Рідкий резервуар -block.liquid-junction.name = Рідке перехрестя +block.pulse-conduit.name = Імпульсний трубопровід +block.plated-conduit.name = Зміцнений трубопровід +block.phase-conduit.name = Фазовий трубопровід +block.liquid-router.name = Рідинний маршрутизатор +block.liquid-tank.name = Рідинний резервуар +block.liquid-junction.name = Рідинне перехрестя block.bridge-conduit.name = Мостовий водопровід block.rotary-pump.name = Роторний насос block.thorium-reactor.name = Торієвий реактор @@ -1022,18 +1029,18 @@ block.thermal-pump.name = Тепловий насос block.thermal-generator.name = Тепловий генератор block.alloy-smelter.name = Сплавовий завод block.mender.name = Регенератор -block.mend-projector.name = Ремонтувальний гранатомет +block.mend-projector.name = Відновлювальна установка block.surge-wall.name = Кінетична стіна block.surge-wall-large.name = Велика кінетична стіна block.cyclone.name = Циклон block.fuse.name = Підривник block.shock-mine.name = Шокуюча міна -block.overdrive-projector.name = Сверхприводний проектор -block.force-projector.name = Силовий проектор +block.overdrive-projector.name = Швидкісна пускова установка +block.force-projector.name = Силова пускова установка block.arc.name = Дуга block.rtg-generator.name = Радіоізотопний термоелектричний генератор block.spectre.name = Спектр -block.meltdown.name = Випалювач +block.meltdown.name = Розплавлювач block.container.name = Склад block.launch-pad.name = Стартовий майданчик block.launch-pad-large.name = Великий стартовий майданчик @@ -1056,43 +1063,43 @@ unit.fortress.name = Фортеця unit.revenant.name = Потойбічний вбивця unit.eruptor.name = Вивиргатель unit.chaos-array.name = Масив хаосу -unit.eradicator.name = Випалювач +unit.eradicator.name = Викорінювач unit.lich.name = Лич unit.reaper.name = Жнець tutorial.next = [lightgray]<Натисніть для продовження> tutorial.intro = Ви розпочали[scarlet] навчання по Mindustry.[]\nРозпочніть з [accent]видобутку міді[]. Використовуйте [[WASD] для руху.\n[accent]Прокручуйте миш[] для приближення і віддалення. Наблизьтесь до мідної жили біля вашого ядра, а потім натисніть на неї, щоб розпочати видобуток.\n\n[accent]{0}/{1} міді -tutorial.intro.mobile = Ви розпочали[scarlet] навчання по Mindustry.[]\nПроведіть екраном, щоб рухатися.\n[accent] Зведіть або розведіть 2 пальця [] для приближення і віддалення відповідно.\nз[accent] видобування міді.[] Наблизьтесь, а потім натисність на мідну жилу біля вашого ядра, щоб зробити це.\n\n[accent]{0}/{1} міді -tutorial.drill = Добування вручну не є ефективним.\n[accent]Бури []можуть добувати автоматично.\nНатисніть на вкладку із зображенням свердла знизу праворуч.\nВиберіть[accent] механічний бур[]. Розмістіть його на мідній жилі натисканням.\nВи також можете вибрати бур, натиснувши [accent][[2][], а потім швидко натиснути [accent][[1][], незалежно від того, яка вкладка відкрита.\n[accent]Натисніть ПКМ[], щоб зупинити будування. -tutorial.drill.mobile = Добування вручну неефективне.\n[accent]Бури []можуть добувати автоматично.\nНатисність на вкладку із зображенням сведла знизу зправа.\nВиберіть[accent] механічний бур[]. Розмістіть його на мідній жилі натисканням, потім натисність на [accent]галочку[] нижче, щоб підтвердити розміщення .\nНатисніть [accent]кнопку X[], щоб скасувати розміщення. -tutorial.blockinfo = Кожен блок має різні характеристики. Кожний бур може видобувати тільки певні руди.\nЩоб переглянути інформацію та характеристики блока,[accent] натисність на кнопку «?», коли ви вибрали блок у меню будування.[]\n\n[accent]Перегляньте характеристику Механічного бура прямо зараз.[] -tutorial.conveyor = [accent]Конвеєри[] використовуються для транспортування предметів до ядра.\nЗробіть лінію конвеєрів від бура до ядра.\n[accent]Утримуйте миш, щоб розмістити у лінію.[]\nУтримуйте[accent] CTRL[] під час вибору лінії для розміщення по діагоналі.\\nПрокручуйте, щоб обертати блоки до їх установлення.\n[accent]Розмістіть 2 конвеєри у лінію, а потім доставте предмет в ядро.tutorial.conveyor.mobile = [accent]Конвеєри[] використовується для транспортування предметів до ядра.\nЗробіть лінію конвеєрів від бура до ядра.\n[accent] Розмістить у лінію, утримуючи палець кілька секунд[] і тягніть у напрямку, який Ви вибрали.\nВикористовуйте колесо прокрутки, щоб обертати блоки перед їх розміщенням\n[accent]{0}/{1} конвеєрів, які розміщені в лінію\n[accent]0/1 предмет доставлено -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.intro.mobile = Ви розпочали[scarlet] навчання по Mindustry.[]\nПроведіть екраном, щоб рухатися.\n[accent] Зведіть або розведіть 2 пальця [] для приближення і віддалення відповідно.\nз[accent] видобування міді.[] Наблизьтесь, а потім натисніть на мідну жилу біля вашого ядра, щоб зробити це.\n\n[accent]{0}/{1} міді +tutorial.drill = Добування вручну не є ефективним.\n[accent]Бури []можуть добувати автоматично.\nНатисніть на вкладку із зображенням свердла праворуч знизу.\nВиберіть[accent] механічний бур[]. Розмістіть його на мідній жилі натисканням.\nВи також можете вибрати бур, натиснувши [accent][[2][], а потім швидко натиснувши [accent][[1][], незалежно від відкритої вкладки.\n[accent]Натисніть ПКМ[], щоб зупинити будування. +tutorial.drill.mobile = Добування вручну неефективне.\n[accent]Бури []можуть добувати автоматично.\nНатисніть на вкладку із зображенням свердла праворуч знизу.\nВиберіть[accent] механічний бур[]. Розмістіть його на мідній жилі натисканням, потім натисніть на [accent]галочку[] нижче, щоб підтвердити розміщення .\nНатисніть [accent]кнопку X[], щоб скасувати розміщення. +tutorial.blockinfo = Кожний блок має різні характеристики. Кожний бур може видобувати тільки певні руди.\nЩоб переглянути інформацію та характеристики блока,[accent] натисність на кнопку «?», коли ви вибрали блок у меню будування.[]\n\n[accent]Перегляньте характеристику Механічного бура негайно[] +tutorial.conveyor = [accent]Конвеєри[] використовуються для транспортування предметів до ядра.\nЗробіть лінію конвеєрів від бура до ядра.\n[accent]Утримуйте миш для розміщення у лінію.[]\nУтримуйте[accent] CTRL[] під час вибору лінії для розміщення по діагоналі.\\nПрокручуйте, щоб обертати блоки до їх установлення.\n[accent]Розмістіть 2 конвеєри у лінію, а потім доставте предмет в ядро. +tutorial.conveyor.mobile =[accent]Конвеєри[] використовується для транспортування предметів до ядра.\nЗробіть лінію конвеєрів від бура до ядра.\n[accent] Розмістить у лінію, утримуючи палець кілька секунд[] і тягніть у напрямку, який Ви вибрали.\nВикористовуйте колесо прокрутки, щоб обертати блоки перед їх розміщенням\n[accent]{0}/{1} конвеєрів, які розміщені в лінію\n[accent]0/1 предмет доставлено tutorial.turret = Оборонні споруди повинні бути побудовані для відбиття[lightgray] ворогів[].\nПобудуйте[accent] башту «Подвійна»[] біля вашої бази. -tutorial.drillturret = «Подвійна» потребує [accent]мідні боєприпаси[] для стрільби.\nРозмістіть бур біля башточки\nПроведіть конвеєри до башточки, щоб заповнити її боєприпасами.\n\n[accent]Доставлено боєприпасів: 0/1 -tutorial.pause = Під час бою ви можете[accent] поставити на павзу гру.[]\nВи можете зробити чергу на будування під час паузи.\n\n[accent]Натисність пробіл для павзи. -tutorial.pause.mobile = Під час бою ви можете[accent] поставити на павзу гру.[]\nВи можете зробити чергу на будування під час паузи.\n\n[accent]Натисніть кнопку вгорі ліворуч для павзи. -tutorial.unpause = Тепер натисність пробіл, щоб зняти павзу. +tutorial.drillturret = «Подвійна» потребує [accent]мідні боєприпаси[] для стрільби.\nРозмістіть бур біля башти\nПроведіть конвеєри до башти, щоб заповнити її боєприпасами.\n\n[accent]Доставлено боєприпасів: 0/1 +tutorial.pause = Під час гри ви можете[accent] поставити на павзу.[]\nВи можете зробити чергу на будування під час паузи.\n\n[accent]Натисніть пробіл для павзи. +tutorial.pause.mobile = Під час гри ви можете[accent] поставити на павзу.[]\nВи можете зробити чергу на будування під час паузи.\n\n[accent]Натисніть кнопку вгорі ліворуч для павзи. +tutorial.unpause = Призупиніть гру, натиснувши на пробіл. tutorial.unpause.mobile = Тепер натисність туди ще раз, щоб зняти павзу. -tutorial.breaking = Блоки часто повинні бути знищені.\n[accent]Утримуючи ПКМ[] ви знищите всі виділені блоки.[]\n\n[accent]Необхідно знищити всі стіни з металобрухту ліворуч від вашого ядра використовуючи видалення у зоні. -tutorial.breaking.mobile = Блоки часто повинні бути знищені.\n[accent]Виберіть режим руйнування[], потім натисніть на блок, щоб зламати його.\nЗнищіть область, утримуючи палець протягом декількох секунд [] і потягнувши в потрібному напрямку.\nНатисніть кнопку галочки, щоб підтвердити руйнування.\n\n[accent]Необхідно знищити всі стіни з металобрухту ліворуч від вашого ядра використовуючи видалення у зоні. +tutorial.breaking = Блоки часто треба знищувати.\n[accent]Утримуючи ПКМ[] ви знищите всі виділені блоки.[]\n\n[accent]Необхідно знищити всі стіни з металобрухту ліворуч від вашого ядра використовуючи видалення у зоні. +tutorial.breaking.mobile = Блоки часто треба знищувати.\n[accent]Виберіть режим руйнування[], потім натисніть на блок, щоб зламати його.\nЗнищте область, утримуючи палець протягом декількох секунд [] і потягнувши в потрібному напрямку.\nНатисніть кнопку галочки, щоб підтвердити руйнування.\n\n[accent]Необхідно знищити всі стіни з металобрухту ліворуч від вашого ядра використовуючи видалення у зоні. tutorial.withdraw = У деяких ситуаціях потрібно брати предмети безпосередньо з блоків.\nЩоб зробити це, [accent]натисність на блок[] з предметами, і потім [accent]натисніть на предмет[] в інвентарі.\nМожна вилучити кілька предметів [accent]натискаючи та утримуючи[].\n\n[accent]Вилучіть трохи міді з ядра.[] -tutorial.deposit = Покладіть предмети в блоки, перетягнувши з вашого корабля в потрібний блок.\n\n[accent]Покладіть мідь назад у ядро.[] -tutorial.waves = [lightgray] Ворог[] з’явився.\n\nЗахистіть ядро від двух хвиль.[accent] Натисніть ЛКМ[], щоб стріляти.\nСтворіть більше башт і бурів. Добудьте більше міді. -tutorial.waves.mobile = [lightgray] Ворог[] з’явився.\n\nЗахистіть ядро від двух хвиль. Ваш корабель буде автоматично атакувати ворогів.\nСтворіть більше башт і бурів. Добудьте більше міді. -tutorial.launch = Як тільки ви досягнете певної хвилі, ви зможете[accent] запустити ядро[], залишивши захисні сили позаду та [accent]отримати всі ресурси у вашому ядрі.[]\nЦі отримані ресурси можуть бути використані для дослідження нових технологій.\n\n[accent]Натисніть кнопку запуску. +tutorial.deposit = Покладіть предмети в блок, перетягнувши з вашого корабля в потрібний блок.\n\n[accent]Покладіть мідь назад у ядро.[] +tutorial.waves = [lightgray] Ворог[] з’явився.\n\nЗахистіть ядро від двух хвиль.[accent] Натисніть ЛКМ[], щоб стріляти.\nПобудуйте більше башт і бурів. Добудьте більше міді. +tutorial.waves.mobile = [lightgray] Ворог[] з’явився.\n\nЗахистіть ядро від двух хвиль. Ваш корабель буде автоматично атакувати ворогів.\nПобудуйте більше башт і бурів. Добудьте більше міді. +tutorial.launch = Як тільки ви досягнете певної хвилі, ви зможете[accent] запустити ядро[], залишивши свою базу позаду, та [accent]отримати всі ресурси у вашому ядрі.[]\nЦі отримані ресурси можуть бути використані для дослідження нових технологій.\n\n[accent]Натисніть кнопку запуску. -item.copper.description = Найбільш базовий будівельний матеріал. Широко використовується у всіх типах блоків. -item.lead.description = Основний стартовий матеріал. Широко застосовується в електроніці та транспортуванні рідин. -item.metaglass.description = Супер жорсткий склад скла. Широко застосовується для розподілу та зберігання рідини. -item.graphite.description = Мінералізований вуглець, що використовується для боєприпасів та як компонент. +item.copper.description = Початковий будівельний матеріал. Широко використовується у всіх типах блоків. +item.lead.description = Основний стартовий матеріал. Широко застосовується в електроніці та у транспортуванні рідин. +item.metaglass.description = Дуже жорсткий склад скла. Широко застосовується для розподілу та зберігання рідини. +item.graphite.description = Мінералізований вуглець, що використовується для боєприпасів та як електричний компонент. item.sand.description = Поширений матеріал, який широко використовується при виплавці, як при сплавленні, так і в якості відходів. item.coal.description = Окам’янілі рослинні речовини, що утворюються задовго до посіву. Широко використовується для виробництва пального та ресурсів. item.titanium.description = Рідкісний надлегкий метал, який широко використовується для транспортування рідини, бурів і літаків. -item.thorium.description = Щільний, радіоактивний метал, що використовується в якості конструкційної опори та ядерного палива. -item.scrap.description = Залишилися залишки старих споруд та підрозділів. Містить мікроелементи багатьох різних металів. -item.silicon.description = Надзвичайно корисний напівпровідник. Застосовується в сонячних батареях, складній електроніці та бойових боєприпасах. -item.plastanium.description = Легкий, пластичний матеріал, що використовується в сучасних літальних апаратах та у роздроблених боєприпасах. -item.phase-fabric.description = Майже невагома речовина, що застосовується в передовій електроніці та технології саморемонту. +item.thorium.description = Щільний радіоактивний метал, що використовується в якості конструкційної опори та ядерного палива. +item.scrap.description = Залишки старих споруд та підрозділів. Містить мікроелементи багатьох різних металів. +item.silicon.description = Надзвичайно корисний напівпровідник. Має застосування в сонячних батареях, складній електроніці та баштових боєприпасах. +item.plastanium.description = Легкий пластичний матеріал, що використовується в сучасних літальних апаратах та у фрагментованих боєприпасах. +item.phase-fabric.description = Майже невагома речовина, що застосовується в передовій електроніці та у технології самовідновлення. item.surge-alloy.description = Удосконалений сплав з унікальними електричними властивостями. item.spore-pod.description = Струмок синтетичних спор, синтезований з атмосферних концентрацій для промислових цілей. Використовується для перетворення на нафту, вибухівку та паливо. item.blast-compound.description = Нестабільна сполука, яка використовується в бомбах і вибухівках. Синтезується із спорових стручків та інших летких речовин. Використовувати як паливо не рекомендується. @@ -1143,7 +1150,7 @@ block.item-source.description = Нескінченно виводить пред block.item-void.description = Знищує будь-які предмети. block.liquid-source.description = Нескінченно виводить рідини. block.liquid-void.description = Removes any liquids. Sandbox only. -block.copper-wall.description = Дешевий захисний блок.\nКорисна для захисту ядра та башто у перші кілька хвиль. +block.copper-wall.description = Дешевий захисний блок.\nКорисна для захисту ядра та башти у перші кілька хвиль. block.copper-wall-large.description = Дешевий захисний блок.\nКорисна для захисту ядра та башт у перші кілька хвиль.\nОхоплює кілька плиток. block.titanium-wall.description = Відносно сильний захисний блок.\nЗабезпечує помірний захист від ворогів. block.titanium-wall-large.description = Відносно сильний захисний блок.\nЗабезпечує помірний захист від ворогів.\nОхоплює кілька плиток. @@ -1157,7 +1164,7 @@ block.surge-wall.description = Надзвичайно міцний захисн block.surge-wall-large.description = Надзвичайно міцний захисний блок.\nЗбільшує заряд при контакті з кулями, вивільняючи його випадковим чином.\nОхоплює кілька плиток. block.door.description = Невеликі двері. Можна відкрити або закрити, натиснувши. block.door-large.description = Великі двері. Можна відкрити або закрити, натиснувши.\nОхоплює кілька плиток. -block.mender.description = Періодично ремонтує блоки у його радіусі дії. Захищає башточки та стіни.\nЗа бажанням, можна використати кремній для підвищення дальності та ефективності. +block.mender.description = Періодично ремонтує блоки у його радіусі дії. Захищає башти та стіни.\nЗа бажанням, можна використати кремній для підвищення дальності та ефективності. block.mend-projector.description = Покращена версія «Регенератора». Періодично ремонтує блоки у його радіусі дії.\nЗа бажанням, можна використати фазова тканина для підвищення дальності та ефективності. block.overdrive-projector.description = Збільшує швидкість прилеглих будівель.\nЗа бажанням, можна використати фазова тканина для підвищення дальності та ефективності. block.force-projector.description = Створює навколо себе шестикутне силове поле, захищаючи будівлі та блоки всередині від пошкоджень.\nПерегрівається, якщо завдано занадто великої шкоди. За бажанням, можна використати теплоносій для запобігання перегріву. Для збільшення розміру щита можна використовувати фазову тканину. @@ -1166,12 +1173,13 @@ block.conveyor.description = Базовий транспортний блок. block.titanium-conveyor.description = Покращений блок транспорту елементів. Переміщує предмети швидше, ніж звичайні конвеєри. block.junction.description = Діє як міст для двох перехресних конвеєрних стрічок. Корисно в ситуаціях, коли два різних конвеєри перевозять різні матеріали в різні місця. block.bridge-conveyor.description = Покращений блок транспорту елементів. Дозволяє транспортувати предмети до 3-ох плиток з будь-якої місцевості чи будівлі. -block.phase-conveyor.description = Покращений блок транспорту елементів. Використовує енергію для телепортування елементів на підключений фазовий конвеєр через кілька плиток. +block.phase-conveyor.description = Покращений блок транспорту елементів. Використовує енергію для телепортування елементів на під’єднаний фазовий конвеєр через кілька плиток. block.sorter.description = Сортує предмети. Якщо елемент відповідає вибраному, його можна передати. В іншому випадку елемент виводиться зліва та справа. block.inverted-sorter.description = Обробляє елементи, як звичайний сортувальник, але виводить обрані елементи на сторони. block.router.description = Приймає елементи з одного напрямку та виводить їх до трьох інших напрямків порівну. Корисно для поділу матеріалів від одного джерела до кількох цілей.\n\n[scarlet]Ніколи не використовуйте поруч із входами до механізмів, оскільки вони будуть забиті вихідними предметами.[] block.distributor.description = Розширений маршрутизатор. Розділяє предмети до 7 інших напрямків порівну. block.overflow-gate.description = Виходи лише вліво і вправо, якщо передній шлях заблокований. +block.underflow-gate.description = Повна протилежність надмірному затвору. Виводить предмет прямо, якщо лівий і/чи правий шлях заблоковано. block.mass-driver.description = Кінцевий елемент транспортного блоку. Збирає кілька предметів, а потім вистрілює їх до іншої електромагнитної катапульти на великій відстані. Для роботи потрібна енергія. block.mechanical-pump.description = Недорогий насос з повільним виходом, але без енергоспоживання. block.rotary-pump.description = Удосконалений насос. Насоси більше викачують, але потребують енергію. @@ -1183,8 +1191,8 @@ block.liquid-router.description = Приймає рідини з одного н block.liquid-tank.description = Зберігає велику кількість рідини. Використовуйте для створення буферів у ситуаціях з непостійним попитом на матеріали або як гарантію охолодження життєво важливих блоків. block.liquid-junction.description = Діє як міст для двох каналів перетину. Корисно в ситуаціях, коли два різні трубопроводи перевозять різні рідини в різні місця. block.bridge-conduit.description = Розширений блок транспортування рідини. Дозволяє транспортувати рідину до 3 плиток будь-якої місцевості чи будівлі. -block.phase-conduit.description = Розширений блок транспортування рідини. Використовує енергію для транспортування рідин до підключеного фазового каналу через декілька плиток. -block.power-node.description = Передає живлення на підключені вузли. Вузол буде отримувати живлення від будь-яких сусідніх блоків або подавати живлення до них. +block.phase-conduit.description = Розширений блок транспортування рідини. Використовує енергію для транспортування рідин до приєднаного фазового каналу через декілька плиток. +block.power-node.description = Передає живлення на приєднані вузли. Вузол буде отримувати живлення від будь-яких сусідніх блоків або подавати живлення до них. block.power-node-large.description = Удосконалений вузол живлення з більшим діапазоном. block.surge-tower.description = Надзвичайно дальний вузол живлення з меншою кількістю доступних з’єднань. block.diode.description = Живлення акумулятора може протікати через цей блок лише в одному напрямку, але лише в тому випадку, якщо інша сторона має менше енергії. @@ -1198,7 +1206,7 @@ block.rtg-generator.description = Простий, надійний генера block.solar-panel.description = Забезпечує невелику кількість енергії від сонця. block.solar-panel-large.description = Значно ефективніша версія стандартної сонячної панелі. block.thorium-reactor.description = Виробляє значну кількість енергії з торію. Вимагає постійного охолодження. Вибухне сильно, якщо подаватиметься недостатньо кількості теплоносія. Вихідна потужність залежить від повноти, базова потужність генерується на повній потужності. -block.impact-reactor.description = Удосконалений генератор, здатний створювати величезну кількість енергії при максимальній ефективності. Для швидкого запуску процесу потрібно значне введення енергії. +block.impact-reactor.description = Удосконалений генератор, здатний створювати величезну кількість енергії при максимальній ефективності. Для запуску процесу потрібно значні обсяги енергії. block.mechanical-drill.description = Недорогий бур. Розміщуючи їх на відповідних плитках, виводить предмети повільним темпом нескінченно. Здатний видобувати лише мідь, свинець і вугілля. block.pneumatic-drill.description = Вдосконалений бур, здатний добувати титан. Шахти швидше, ніж механічна дриль. block.laser-drill.description = Дозволяє виконувати свердління ще швидше за допомогою лазерної технології, але вимагає енергії. Здатний до видобутку торію. @@ -1233,17 +1241,17 @@ block.draug-factory.description = Виробляє дронів, які видо block.spirit-factory.description = Виробляє дронів, які ремонтують блоки. block.phantom-factory.description = Виробляє дронів, які допомогають у будівництві. block.wraith-factory.description = Виробляє швидких перехоплювачів, які використовують тактику «стріляй і біжи». -block.ghoul-factory.description = Виробляє важкі килимові бомбардувальники. -block.revenant-factory.description = Випускає важкі ракетні одиниці. -block.dagger-factory.description = Виробляє елементарні наземні одиниці. -block.crawler-factory.description = Виробляє швидкі саморуйнуючі бойові одиниці. -block.titan-factory.description = Виробляє поліпшених наземних бойових одиниць. -block.fortress-factory.description = Виробляє наземних бойових одиници, які схожі на важку артилерію. -block.repair-point.description = Безперервно лікує найближчий пошкоджену бойову одиницю чи мех, що знаходиться поруч. -block.dart-mech-pad.description = Забезпечує перетворення в основий атакуючий мех.\nВикористовуйте, натискаючи, стоячи на ньому. -block.delta-mech-pad.description = Забезпечує перетворення в легкоброньований атакуючий мех.\nВикористовуйте, натискаючи, стоячи на ньому. -block.tau-mech-pad.description = Забезпечує перетворення в поліпшений мех підтримки.\nВикористовуйте, натискаючи, стоячи на ньому. -block.omega-mech-pad.description = Забезпечує перетворення в тяжкоброньований ракетний мех.\nВикористовуйте, натискаючи, стоячи на ньому. -block.javelin-ship-pad.description = Забезпечує перетворення в швидкий, легкоброньований перехоплювач.\nВикористовуйте, натискаючи, стоячи на ньому. +block.ghoul-factory.description = Виробляє важкокилимових бомбардувальників. +block.revenant-factory.description = Виробляє важких ракетних одиниць. +block.dagger-factory.description = Виробляє початкових наземних одиниць. +block.crawler-factory.description = Виробляє швидких і самовибухових одиниць. +block.titan-factory.description = Виробляє поліпшених наземних одиниць. +block.fortress-factory.description = Виробляє важкоартилерійних наземних одиниць. +block.repair-point.description = Безперервно лікує найближчу пошкоджену бойову одиницю, що знаходиться поруч. +block.dart-mech-pad.description = Забезпечує перетворення в основий атакуючий мех.\nВикористовуйте, натиснувши, коли стоїте на ньому. +block.delta-mech-pad.description = Забезпечує перетворення в легкоброньований атакуючий мех.\nВикористовуйте, натиснувши, коли стоїте на ньому. +block.tau-mech-pad.description = Забезпечує перетворення в поліпшений мех підтримки.\nВикористовуйте, натиснувши, коли стоїте на ньому. +block.omega-mech-pad.description = Забезпечує перетворення в тяжкоброньований ракетний мех.\nВикористовуйте, натиснувши, коли стоїте на ньому. +block.javelin-ship-pad.description = Забезпечує перетворення в швидкий, легкоброньований перехоплювач.\nВикористовуйте, натиснувши, коли стоїте на ньому. block.trident-ship-pad.description = Забезпечує перетворення в тяжкий бомбардувальник.\nВикористовуйте, натискаючи, стоячи на ньому. -block.glaive-ship-pad.description = Забезпечує перетворення в великий, добреброньований корабель.\nВикористовуйте, натискаючи, стоячи на ньому. +block.glaive-ship-pad.description = Забезпечує перетворення в великий добреброньований корабель зі зроєю.\nВикористовуйте, натиснувши, коли стоїте на ньому. diff --git a/core/assets/bundles/bundle_zh_CN.properties b/core/assets/bundles/bundle_zh_CN.properties index 884ac22dd0..db38a26842 100644 --- a/core/assets/bundles/bundle_zh_CN.properties +++ b/core/assets/bundles/bundle_zh_CN.properties @@ -12,7 +12,7 @@ link.itch.io.description = itch.io 上的 PC 版下载 link.google-play.description = Google Play 页面 link.f-droid.description = F-Droid 页面 link.wiki.description = Mindustry 官方 Wiki -link.feathub.description = Suggest new features +link.feathub.description = 提出新特性的建议 linkfail = 打开链接失败!\n网址已复制到您的剪贴板。 screenshot = 屏幕截图已保存到 {0} screenshot.invalid = 地图太大,可能没有足够的内存用于截图。 @@ -29,12 +29,13 @@ load.system = 系统加载中 load.mod = 模组加载中 load.scripts = Scripts -be.update = A new Bleeding Edge build is available: -be.update.confirm = Download it and restart now? -be.updating = Updating... -be.ignore = Ignore -be.noupdates = No updates found. -be.check = Check for updates + +be.update = 发现游戏最新版本: +be.update.confirm = 现在下载并重启游戏? +be.updating = 更新... +be.ignore = 忽略 +be.noupdates = 未发现更新。 +be.check = 检测更新 schematic = 蓝图 schematic.add = 保存蓝图… @@ -110,22 +111,22 @@ mod.disable = 禁用 mod.delete.error = 无法删除模组。可能文件被占用。 mod.requiresversion = [scarlet]所需的游戏版本:[accent]{0} mod.missingdependencies = [scarlet]缺少依赖条件:{0} -mod.erroredcontent = [scarlet]Content Errors -mod.errors = Errors have occurred loading content. -mod.noerrorplay = [scarlet]You have mods with errors.[] Either disable the affected mods or fix the errors before playing. +mod.erroredcontent = [scarlet]内容(content)错误 +mod.errors = 读取内容(content)时发生错误. +mod.noerrorplay = [scarlet]你的模组发生了错误.[] 禁用相关模组或修复错误后才能进入游戏. mod.nowdisabled = [scarlet]“{0}”模组缺少依赖条件:[accent] {1}\n[lightgray]需要先下载上述模组。\n此模组现在将自动禁用。 mod.enable = 启用 mod.requiresrestart = 需要重启使模组生效。 mod.reloadrequired = [scarlet]需要重启 mod.import = 导入模组 mod.import.github = 导入 GitHub 模组 -mod.item.remove = This item is part of the[accent] '{0}'[] mod. To remove it, uninstall that mod. +mod.item.remove = 这个物品是[accent] '{0}'[]模组的一部分. 删除物品需要先卸载此模组. mod.remove.confirm = 此模组将被删除。 mod.author = [LIGHT_GRAY]作者:[] {0} mod.missing = 此存档包含您最近已更新或者现在未安装的模组。存档可能会损坏。确定要加载它吗?\n[lightgray]模组:\n{0} mod.preview.missing = 在创意工坊中发布此模组前,您必须添加一则预览图像。\n请将名为[accent] preview.png[] 的图像放入模组文件夹,然后重试。 mod.folder.missing = 只有文件夹形式的模组能在创意工坊上发布。\n若要将任何模组转换为文件夹,只需将其文件解压缩到文件夹中并删除旧压缩包,然后重新启动游戏或重新加载模组。 -mod.scripts.unsupported = Your device does not support mod scripts. Some mods will not function correctly. +mod.scripts.unsupported = 你的设备不支持模组脚本,一些模组可能不会正确工作。 about.button = 关于 name = 名字: @@ -155,7 +156,7 @@ server.kicked.nameEmpty = 无效的名字! server.kicked.idInUse = 你已在这个服务器上!不允许用两个账号连接。 server.kicked.customClient = 这个服务器不支持自定义版本。请下载官方版本。 server.kicked.gameover = 游戏结束! -server.kicked.serverRestarting = The server is restarting. +server.kicked.serverRestarting = 服务器正在重启. server.versions = 客户端版本:[accent] {0}[]\n服务器版本:[accent] {1}[] host.info = [accent]创建局域网游戏[]按钮会在[scarlet] 6567 []端口运行一个服务器。[]\n任何在同一个[lightgray] Wi-Fi 或本地网络[]下的人应该都可以在服务器列表中看到你的服务器。\n\n如果你想让别人在任何地方都能通过 IP 地址连接,你需要设定[accent]端口转发[]。\n\n[lightgray]注意:如果某人无法连接到你的局域网游戏,请确保你在防火墙设置里允许了 Mindustry 访问本地网络。 join.info = 您可以输入[accent]服务器的 IP 地址[]来连接,或寻找[accent]本地网络[]中的服务器来连接。\n支持局域网或广域网的多人游戏。\n\n[lightgray]注意:没有全球服务器列表;如果你想通过 IP 地址连接某个服务器,你需要向房主询问 IP 地址。 @@ -325,7 +326,7 @@ waves.copy = 复制到剪贴板 waves.load = 从剪贴板读取 waves.invalid = 剪贴板中的波次信息无效。 waves.copied = 波次信息已复制。 -waves.none = 没有定义敌人。\n请注意,空布局将自动替换为默认布局。 +waves.none = 没有定义敌人。\n请注意,这将自动替换为默认的敌人列表。 editor.default = [lightgray]<默认> details = 详情… edit = 编辑… @@ -453,7 +454,7 @@ launch.confirm = 您将装载并发射核心中的所有资源。\n此地图将 launch.skip.confirm = 如果现在跳过,在下一个发射窗口到来前,您都无法发射。 uncover = 解锁 configure = 设定装运的数量 -bannedblocks = 禁用方块 +bannedblocks = 禁用建筑 addall = 添加所有 configure.locked = [lightgray]完成{0}\n解锁装运配置。 configure.invalid = 数量必须是0到{0}之间的数字。 @@ -512,7 +513,7 @@ settings.language = 语言 settings.data = 游戏数据 settings.reset = 恢复默认设置 settings.rebind = 重新绑定 -settings.resetKey = Reset +settings.resetKey = 重置按键 settings.controls = 控制 settings.game = 游戏 settings.sound = 声音 @@ -549,7 +550,7 @@ blocks.powerdamage = 功率/损伤 blocks.itemcapacity = 物品容量 blocks.basepowergeneration = 基础能源输出 blocks.productiontime = 生产时间 -blocks.repairtime = 方块完全修复时间 +blocks.repairtime = 建筑完全修复时间 blocks.speedincrease = 提速 blocks.range = 范围 blocks.drilltier = 可钻探矿物 @@ -591,8 +592,8 @@ bullet.frag = [stat] 分裂 bullet.knockback = [stat]{0}[lightgray] 击退 bullet.freezing = [stat] 冰冻 bullet.tarred = [stat] 减速 -bullet.multiplier = [stat]{0}[lightgray]x 弹药数量 -bullet.reload = [stat]{0}[lightgray]x 装弹 +bullet.multiplier = [stat]{0}[lightgray]x 装弹数量 +bullet.reload = [stat]{0}[lightgray]x 装弹速度 unit.blocks = 方块 unit.powersecond = 能量/秒 @@ -617,7 +618,7 @@ category.shooting = 发射 category.optional = 可选的增强 setting.landscape.name = 锁定横屏 setting.shadows.name = 影子 -setting.blockreplace.name = 自动推荐块 +setting.blockreplace.name = 自动推荐合适的建筑 setting.linear.name = 抗锯齿 setting.hints.name = 提示 setting.buildautopause.name = 自动暂停建造 @@ -632,7 +633,7 @@ setting.fpscap.name = 最大FPS setting.fpscap.none = 无 setting.fpscap.text = {0} FPS setting.uiscale.name = UI缩放比例[lightgray](需要重新启动)[] -setting.swapdiagonal.name = 自动铺设 +setting.swapdiagonal.name = 自动斜线建造 setting.difficulty.training = 训练 setting.difficulty.easy = 简单 setting.difficulty.normal = 普通 @@ -641,18 +642,18 @@ setting.difficulty.insane = 疯狂 setting.difficulty.name = 难度: setting.screenshake.name = 屏幕抖动 setting.effects.name = 显示效果 -setting.destroyedblocks.name = 显示摧毁的块 -setting.conveyorpathfinding.name = 传送带放置寻路 -setting.coreselect.name = Allow Schematic Cores +setting.destroyedblocks.name = 显示摧毁的建筑 +setting.conveyorpathfinding.name = 传送带自动寻路 +setting.coreselect.name = 允许蓝图包含核心 setting.sensitivity.name = 控制器灵敏度 setting.saveinterval.name = 自动保存间隔 setting.seconds = {0} 秒 -setting.blockselecttimeout.name = 块选择超时 +setting.blockselecttimeout.name = 建筑选择超时 setting.milliseconds = {0} 毫秒 setting.fullscreen.name = 全屏 setting.borderlesswindow.name = 无边框窗口[lightgray](可能需要重启) setting.fps.name = 显示 FPS 和网络延迟 -setting.blockselectkeys.name = 显示块选择按键 +setting.blockselectkeys.name = 显示建筑选择按键 setting.vsync.name = 垂直同步 setting.pixelate.name = 像素画面 [lightgray](禁用动画) setting.minimap.name = 显示小地图 @@ -667,6 +668,7 @@ setting.savecreate.name = 自动创建存档 setting.publichost.name = 游戏公开可见 setting.chatopacity.name = 聊天界面不透明度 setting.lasersopacity.name = 能量激光不透明度 +setting.bridgeopacity.name = 桥梁不透明度 setting.playerchat.name = 显示玩家聊天气泡 public.confirm = 确定使您的游戏公开可见?\n[accent]其他人将可以加入到您的游戏。\n[lightgray]您之后可以在 设置->游戏->游戏公开可见 更改。 public.beta = 请注意,测试版的游戏不能公开可见。 @@ -697,25 +699,25 @@ keybind.schematic_flip_x.name = 水平翻转 keybind.schematic_flip_y.name = 竖直翻转 keybind.category_prev.name = 上一分类 keybind.category_next.name = 下一分类 -keybind.block_select_left.name = 块选择向左 -keybind.block_select_right.name = 块选择向右 -keybind.block_select_up.name = 块选择向上 -keybind.block_select_down.name = 块选择向下 -keybind.block_select_01.name = 分类/块选择 1 -keybind.block_select_02.name = 分类/块选择 2 -keybind.block_select_03.name = 分类/块选择 3 -keybind.block_select_04.name = 分类/块选择 4 -keybind.block_select_05.name = 分类/块选择 5 -keybind.block_select_06.name = 分类/块选择 6 -keybind.block_select_07.name = 分类/块选择 7 -keybind.block_select_08.name = 分类/块选择 8 -keybind.block_select_09.name = 分类/块选择 9 -keybind.block_select_10.name = 分类/块选择 10 +keybind.block_select_left.name = 建筑朝向向左 +keybind.block_select_right.name = 建筑朝向向右 +keybind.block_select_up.name = 建筑朝向向上 +keybind.block_select_down.name = 建筑朝向向下 +keybind.block_select_01.name = 分类/建筑选择 1 +keybind.block_select_02.name = 分类/建筑选择 2 +keybind.block_select_03.name = 分类/建筑选择 3 +keybind.block_select_04.name = 分类/建筑选择 4 +keybind.block_select_05.name = 分类/建筑选择 5 +keybind.block_select_06.name = 分类/建筑选择 6 +keybind.block_select_07.name = 分类/建筑选择 7 +keybind.block_select_08.name = 分类/建筑选择 8 +keybind.block_select_09.name = 分类/建筑选择 9 +keybind.block_select_10.name = 分类/建筑选择 10 keybind.fullscreen.name = 切换全屏 keybind.select.name = 选择/射击 -keybind.diagonal_placement.name = 自动铺设 -keybind.pick.name = 选择方块 -keybind.break_block.name = 破坏方块 +keybind.diagonal_placement.name = 斜线建造 +keybind.pick.name = 选择建筑 +keybind.break_block.name = 破坏建筑 keybind.deselect.name = 取消选择 keybind.shoot.name = 射击 keybind.zoom.name = 缩放 @@ -755,7 +757,7 @@ rules.enemyCheat = 敌人(红队)无限资源 rules.unitdrops = 敌人出生点 rules.unitbuildspeedmultiplier = 单位生产速度倍数 rules.unithealthmultiplier = 单位生命倍数 -rules.blockhealthmultiplier = Block Health Multiplier +rules.blockhealthmultiplier = 建筑生命倍数 rules.playerhealthmultiplier = 玩家生命倍数 rules.playerdamagemultiplier = 玩家伤害倍数 rules.unitdamagemultiplier = 单位伤害倍数 @@ -824,7 +826,7 @@ mech.trident-ship.name = Trident mech.trident-ship.weapon = 炸弹 mech.glaive-ship.name = Glaive mech.glaive-ship.weapon = 火焰机枪 -item.corestorable = [lightgray]Storable in Core: {0} +item.corestorable = [lightgray]核心可存储: {0} item.explosiveness = [lightgray]爆炸性:{0}% item.flammability = [lightgray]易燃性:{0}% item.radioactivity = [lightgray]放射性:{0}% @@ -933,7 +935,7 @@ block.conveyor.name = 传送带 block.titanium-conveyor.name = 钛传送带 block.armored-conveyor.name = 装甲传送带 block.armored-conveyor.description = 运送物品,与钛传送带一样的速度,但有更强的装甲。除其他传送带,不接受任何边的输入。 -block.junction.name = 交叉器 +block.junction.name = 连接器 block.router.name = 路由器 block.distributor.name = 分配器 block.sorter.name = 分类器 @@ -942,6 +944,7 @@ block.message.name = 信息板 block.illuminator.name = 照明器 block.illuminator.description = 小型、紧凑、可配置的光源。需要能量运行。 block.overflow-gate.name = 溢流门 +block.underflow-gate.name = 反向溢流门 block.silicon-smelter.name = 硅冶炼厂 block.phase-weaver.name = 相织布编织器 block.pulverizer.name = 粉碎机 @@ -978,7 +981,7 @@ block.mechanical-pump.name = 机械泵 block.item-source.name = 无限物品 block.item-void.name = 物品黑洞 block.liquid-source.name = 无限液体 -block.liquid-void.name = Liquid Void +block.liquid-void.name = 液体黑洞 block.power-void.name = 能源黑洞 block.power-source.name = 无限能源 block.unloader.name = 装卸器 @@ -1057,14 +1060,14 @@ unit.revenant.name = 亡魂 unit.eruptor.name = 暴君 unit.chaos-array.name = 混沌者 unit.eradicator.name = 根除者 -unit.lich.name = 尸鬼 +unit.lich.name = 巫妖 unit.reaper.name = 死神 tutorial.next = [lightgray]<点击以继续> tutorial.intro = 您已进入[scarlet] Mindustry 教程[]。[]\n使用[accent][[WASD][]键移动主角和视角。\n[accent]按住[[Ctrl]并转动鼠标滚轮[]缩放视野。\n让我们从[accent]采集铜矿[]开始。先移动到铜矿旁边,然后点按矿脉附近散落的矿物。\n\n[accent]{0}/{1} 铜 tutorial.intro.mobile = 您已进入[scarlet] Mindustry 教程[]。\n在屏幕上滑动来继续。\n[accent]双指捏合[] 来缩小和放大。\n让我们从[accent]采集铜矿[]开始。先移动到铜矿旁边,然后点按矿脉附近散落的矿物。\n\n[accent]铜 {0}/{1} tutorial.drill = 手动采矿效率不高。\n[accent]钻头[]可以自动采矿。\n让我们在在铜矿上放一个。\n点击右下角的钻头菜单。\n选择[accent]机械钻头[]。\n单击将其放置在铜矿上。\n[accent]右键单击[]来停止。 tutorial.drill.mobile = 手动采矿效率不高。\n[accent]钻头[]可以自动采矿。\n点右下角的钻头菜单。\n选择[accent]机械钻头[]。\n点一下将其放在铜矿上,点[accent]对号[]来确定。\n点[accent]叉号[]来取消。 -tutorial.blockinfo = 每种方块都有其独特的数据。每个钻头只能开采部分矿石。\n若要查看块的信息和统计信息,[accent]在菜单中点击问号。[]\n\n[accent]现在查看机械钻头的数据吧。[] +tutorial.blockinfo = 每种钻头都有其独特的数据。每个钻头只能开采部分矿石。\n若要查看建筑的详细信息,[accent]在菜单中点击问号。[]\n\n[accent]现在查看机械钻头的数据吧。[] tutorial.conveyor = [accent]传送带[]可以把物资传送到核心。\n请在钻头到核心间建造一条传送带。 tutorial.conveyor.mobile = [accent]传送带[]可以把物资传送到核心。\n请在钻头到核心间建造一条传送带。\n[accent]长按数秒[]并向一个方向拖动来直线放置。\n\n[accent]{0}/{1} 条传送带\n[accent]0/1 物品 tutorial.turret = 必须建造防御建筑来击退[lightgray]敌人[]。\n请在核心附近造一个双管炮。 @@ -1073,20 +1076,20 @@ tutorial.pause = 在战斗中,您可以[accent]暂停游戏[]。\n暂停时您 tutorial.pause.mobile = 在战斗中,您可以[accent]暂停游戏[]。\n暂停时您可以规划建筑物。\n\n[accent]点击左上角的按钮以暂停。 tutorial.unpause = 现在再次按空格以继续。 tutorial.unpause.mobile = 现在再次点按以继续。 -tutorial.breaking = 方块经常需要拆除。\n[accent]按住鼠标右键[]来拆除选中的方块。[]\n\n[accent]使用范围拆除来拆除核心左侧的废墙。 -tutorial.breaking.mobile = 方块经常需要拆除。\n[accent]选择拆除模式[],点击方块以拆除。\n[accent]长按几秒[]并拖动来范围拆除。\n点击对号来确定。\n\n[accent]使用范围拆除来拆除核心左侧的废墙。 -tutorial.withdraw = 有时,从方块中取出物品是必要的。\n[accent]点击有物品的方块[],然后[accent]点击在方框中的物品[]。\n可以通过[accent]点击或长按[]来取出物品。\n\n[accent]从核心中取出一些铜[]。 -tutorial.deposit = 将物品从机甲拖向方块来放下物品。\n\n[accent]将铜放回核心[]。 +tutorial.breaking = 建筑经常需要拆除。\n[accent]按住鼠标右键[]来拆除选中的建筑。[]\n\n[accent]使用范围拆除来拆除核心左侧的废墙。 +tutorial.breaking.mobile = 建筑经常需要拆除。\n[accent]选择拆除模式[],点击建筑以拆除。\n[accent]长按几秒[]并拖动来范围拆除。\n点击对号来确定。\n\n[accent]使用范围拆除来拆除核心左侧的废墙。 +tutorial.withdraw = 有时,从建筑中取出物品是必要的。\n[accent]点击包含物品的建筑[],然后[accent]点击在方框中的物品[]。\n可以通过[accent]点击或长按[]来取出物品。\n\n[accent]从核心中取出一些铜[]。 +tutorial.deposit = 将物品从机甲拖向建筑来放下物品。\n\n[accent]将铜放回核心[]。 tutorial.waves = [lightgray]敌人[]来了。\n\n保护核心,防御两波攻击。造更多的炮塔。[accent]点击[]以射击。\n建造更多的炮塔和钻头,并采更多的矿。 tutorial.waves.mobile = [lightgray]敌人[]来了。\n\n保护核心,防御两波攻击。造更多的炮塔。你的机甲将对敌人自动开火。\n建造更多的炮塔和钻头,并采更多的矿。 tutorial.launch = 进入特定波次后,你可以[accent]发射核心(起飞)[],[accent]带走核心中的所有资源[]并抛下所有的建筑。\n装运的资源可用于研究科技。\n\n[accent]点击发射按钮。 -item.copper.description = 最基本的的结构材料。在各种类型的方块中被广泛使用。 +item.copper.description = 最基本的的建筑材料。在各种类型的建筑中被广泛使用。 item.lead.description = 一种基本的电力材料。广泛用于电子设备和液体输送模块。 item.metaglass.description = 一种致密坚硬的复合玻璃。广泛用于液体输送和存储。 -item.graphite.description = 矿化碳,用于弹药和电路绝缘。 +item.graphite.description = 一种高密度的碳材料,用于弹药和电器元件。 item.sand.description = 一种常见的材料,广泛用于冶炼,包括制作合金和助熔剂。 -item.coal.description = 植物的化石,常见且容易获得,常用作燃料或其他资源的生产。 +item.coal.description = 在农耕文明前就形成的植物化石,常见且容易获得,常用作燃料或其他资源的生产。 item.titanium.description = 一种罕见的超轻金属,被广泛运用于液体运输、钻头和飞机。 item.thorium.description = 一种致密的放射性金属,用作结构支撑和核燃料。 item.scrap.description = 一种废弃的建筑物及废弃单位的残骸,富含多种金属元素。 @@ -1110,7 +1113,7 @@ mech.javelin-ship.description = 一艘一击即退的攻击船。虽然最初很 mech.trident-ship.description = 为建造和摧毁敌人防御工事而建造的重型轰炸机。有相当好的装甲。 mech.glaive-ship.description = 一种大型的装甲厚重的武装直升机。配备火焰机枪。有优秀的加速能力和最快的速度。 unit.draug.description = 一种原始的采矿机。生产成本低,消耗品。在附近自动开采铜和铅。将开采的资源输送到最近的核心。 -unit.spirit.description = 一种改进的德鲁格无人机,设计用于维修而不是采矿。自动修复该区域中任何损坏的块。 +unit.spirit.description = 采矿机的改进版本,用于维修而不是采矿。自动修复该区域中任何损坏的建筑。 unit.phantom.description = 一种先进的无人机。跟随玩家并协助建造。 unit.dagger.description = 一种最基本的地面机甲。生产成本低。集群使用时比较有用。 unit.crawler.description = 一种地面装置,由一个框架和绑在上面的烈性炸药组成。不是特别耐用。与敌人接触后爆炸。 @@ -1120,14 +1123,14 @@ unit.eruptor.description = 一种用来拆除建筑物的重型机甲。在敌 unit.wraith.description = 一种快速、一击即退的拦截器机甲。目标是发电机。 unit.ghoul.description = 一种重型地毯式轰炸机。瞄准关键的基础设施来击溃敌人的基地。 unit.revenant.description = 一种发射导弹的重型飞行机甲。 -block.message.description = 储存一条消息。用于盟友间的交流。 +block.message.description = 保存一条文字信息。用于队友之间进行交流。 block.graphite-press.description = 将煤块压缩成纯石墨片材料。 block.multi-press.description = 石墨压缩机的升级版。利用水和电力快速高效地处理煤炭。 block.silicon-smelter.description = 用高纯度的焦炭来加工沙子以生产硅。 block.kiln.description = 将铅和沙子熔炼成钢化玻璃,需要少量电力。 block.plastanium-compressor.description = 用石油和钛生产塑钢。 block.phase-weaver.description = 用放射性钍和大量沙子生产相织物。 -block.alloy-smelter.description = 用钛、铅、硅和铜生产浪涌合金。 +block.alloy-smelter.description = 用钛、铅、硅和铜生产巨浪合金。 block.cryofluidmixer.description = 将水和细的钛粉混成冷却液。钍反应堆的必备之物。 block.blast-mixer.description = 用油料将硫转化为不易燃但更具爆炸性的爆炸化合物。 block.pyratite-mixer.description = 将煤、铅和沙子混合成高度易燃的硫。 @@ -1142,56 +1145,57 @@ block.power-source.description = 无限输出能量。仅限沙盒。 block.item-source.description = 无限输出物品。仅限沙盒。 block.item-void.description = 销毁输入的所有物品。仅限沙盒。 block.liquid-source.description = 无限输出液体。仅限沙盒。 -block.liquid-void.description = Removes any liquids. Sandbox only. -block.copper-wall.description = 廉价的防御方块。\n适合在前几个波次中保护核心和炮塔。 -block.copper-wall-large.description = 廉价的防御方块。\n适合在前几个波次中保护核心和炮塔。\n占多个方格。 -block.titanium-wall.description = 中等强度的防御方块。\n提供中等强度的防御以抵御敌人。 -block.titanium-wall-large.description = 中等强度的防御方块。\n提供中等强度的防御以防敌人攻击。\n占多个方格。 -block.plastanium-wall.description = 一种特殊的防御方块,能吸收电弧、自动与能量节点连接。 -block.plastanium-wall-large.description = 一种特殊的防御方块,能吸收电弧、自动与能量节点连接。\n占多个方格。 -block.thorium-wall.description = 强大的防御方块。\n可以很好的防御敌人。 -block.thorium-wall-large.description = 强大的防御方块。\n很好地防御敌人。\n占多个方格。 +block.liquid-void.description = 销毁输入的所有液体。仅限沙盒 +block.copper-wall.description = 廉价的防御建筑。\n适合在前几个波次中保护核心和炮塔。 +block.copper-wall-large.description = 廉价的防御建筑。\n适合在前几个波次中保护核心和炮塔。\n占多个方格。 +block.titanium-wall.description = 中等强度的防御建筑。\n提供中等强度的防御以抵御敌人。 +block.titanium-wall-large.description = 中等强度的防御建筑。\n提供中等强度的防御以防敌人攻击。\n占多个方格。 +block.plastanium-wall.description = 一种特殊的防御建筑,能吸收电弧、自动与能量节点连接。 +block.plastanium-wall-large.description = 一种特殊的防御建筑,能吸收电弧、自动与能量节点连接。\n占多个方格。 +block.thorium-wall.description = 强大的防御建筑。\n可以很好的防御敌人。 +block.thorium-wall-large.description = 强大的防御建筑。\n很好地防御敌人。\n占多个方格。 block.phase-wall.description = 没有钍墙那样坚固,但是它可以使不太强的弹药发生偏转。 block.phase-wall-large.description = 没有钍墙那样坚固,但是它可以使不太强的弹药发生偏转。\n占多个方格。 -block.surge-wall.description = 强大的防御方块。\n有很小的机会向攻击者发射闪电。 -block.surge-wall-large.description = 强大的防御方块。\n有很小的机会向攻击者发射闪电。\n占多个方格。 -block.door.description = 一扇小门。点按切换它的打开/关闭状态。 -block.door-large.description = 一扇大门。点按切换它的打开/关闭状态。\n占多个方格。 -block.mender.description = 定期修理附近的方块,使防御系统在波次之间得到修复。\n可选使用硅来提高修复范围和修复效率。 +block.surge-wall.description = 强大的防御建筑。\n被攻击时有很小的机会向攻击者发射闪电。 +block.surge-wall-large.description = 强大的防御建筑。\n被攻击时有很小的机会向攻击者发射闪电。\n占多个方格。 +block.door.description = 一扇门。点按切换它的打开/关闭状态。 +block.door-large.description = 一扇大型门。点按切换它的打开/关闭状态。\n占多个方格。 +block.mender.description = 定期修理附近的建筑,使防御系统在波次之间得到修复。\n可选使用硅来提高修复范围和修复效率。 block.mend-projector.description = 修理者的升级版,定期修复附近的建筑物。 block.overdrive-projector.description = 提高附近建筑物的速度,如钻头和传送带。 block.force-projector.description = 在自身周围创建一个六角形力场,使里面的建筑物和单位免受伤害。\n持续承受高伤害会导致过热,可以使用冷却液降温。相织物可用于增加屏障大小。 block.shock-mine.description = 伤害踩到它的敌人。敌人几乎看不到它。 -block.conveyor.description = 初级物资传送带。将物品向前输送并在可能时运入建筑。可旋转方向。 -block.titanium-conveyor.description = 高级物资传送带。运送物品的速度优于初级传送带。 -block.junction.description = 两条传送带的交叉桥连接。适用于两条不同方向的传送带要分别将不同的物品运送到不同的位置。 +block.conveyor.description = 初级物品传送带。将物品向前输送并在可能时运入建筑。可旋转方向。 +block.titanium-conveyor.description = 高级物品传送带。运送物品的速度快于初级传送带。 +block.junction.description = 两条交叉传送带的桥梁。用于连接两条不同的传输线路使其互不影响。 block.bridge-conveyor.description = 先进的物品运输方块。允许跨越任意地形或建筑物运输物品,最多跨越3格。 -block.phase-conveyor.description = 先进的传送带,使用电力将物品传送到距离几个块的相位传送带上。 +block.phase-conveyor.description = 先进的传送带,使用电力将物品传送到距离几个方块的相位传送带上。 block.sorter.description = 对物品进行分类,如果物品与所选种类相同,则允许其通过。否则,物品将从左边和右边输出。 -block.inverted-sorter.description = 同分类器一样分类物品,但所选物品输出到左边和右边。 -block.router.description = 从一个方向接受物品,并将它们平均输出到其他3个方向。可以将材料分成多份。 -block.distributor.description = 改进的路由器,可将物品输出到周围的最多7个其他方向。 -block.overflow-gate.description = 仅在前路被阻塞时向左和右输出。 -block.mass-driver.description = 终极传送带,收集若干物品后将其射到远处的另一个质量驱动器。 -block.mechanical-pump.description = 一种廉价泵,输出速度慢,但无需能量。 +block.inverted-sorter.description = 像分类器一样处理物品,但却是向两侧输出选定的物品。 +block.router.description = 从一个方向接受物品,并将它们平均输出到其他3个方向。可以将材料分成多份\n\n[scarlet]永远不要把它与生产建筑相连,因为它会被产出的产品阻塞[]。 +block.distributor.description = 大型路由器,可将物品输出到周围的最多7个其他方向。 +block.overflow-gate.description = 当前方被阻塞时才会向左和右输出,用于处理多余的物品。 +block.underflow-gate.description = 与溢流门相反。 当左右均堵塞时才向前方运输。 +block.mass-driver.description = 终极物品传输器,收集若干物品后将其射到远处的另一个质量驱动器。 +block.mechanical-pump.description = 一种廉价液体泵,输出速度慢,但无需能量。 block.rotary-pump.description = 先进液泵。泵送更多液体,但需要能量。 block.thermal-pump.description = 终级液泵。 block.conduit.description = 基本液体传输管道。像传送带一样工作,但仅适用于液体。用于从泵或其他导管中提取液体。 block.pulse-conduit.description = 高级液体传输管道。比普通导管更快地输送液体且能储存更多液体。 -block.plated-conduit.description = 转移液体的速度与脉冲导管相同,但护甲更强。两侧只接受通过导管传入液体。\n更少泄漏。 +block.plated-conduit.description = 转移液体的速度与脉冲导管相同,但护甲更强。两侧只接受通过导管传入液体。\n发生泄漏时泄漏较少。 block.liquid-router.description = 接受一个方向的液体并将它们平均输出到其他3个方向。同时可以储存一定量的液体。用于将液体从一个源分往多个目标。 -block.liquid-tank.description = 存储大量液体,可在材料需求不恒定作为缓冲区,或作为供给冷却液体的保障设施。 -block.liquid-junction.description = 两条管道的交叉桥连接。适用于两条不同方向的导管要将不同的液体输送到不同的位置。 -block.bridge-conduit.description = 先进的液体传输方块。可以跨越任何地形或建筑物,最多跨越3格来传输液体。 -block.phase-conduit.description = 先进的液体传输方块。使用电力将液体传送到多个块上的连接管道。 +block.liquid-tank.description = 存储大量液体,可在材料需求不恒定时作为缓冲区,或作为供给冷却液体的保障设施。 +block.liquid-junction.description = 两条交叉管道的桥梁。适用连接两条不同方向的导管线路。 +block.bridge-conduit.description = 先进的液体传输建筑。可以跨越任何地形或建筑物,最多跨越3格来传输液体。 +block.phase-conduit.description = 先进的液体传输建筑。使用电力将液体传送到多个方块上的连接管道。 block.power-node.description = 将电源传输到连接的节点上。节点将接收来自任何方块的能量或向任何方块供给能量。 block.power-node-large.description = 更大范围、更多连接点的高级能量节点。 block.surge-tower.description = 连接数低但范围很远的能量节点。 -block.diode.description = 此方块上的电能只能单向流动,仅当对方的储能更低时流动。 -block.battery.description = 存储能量作为缓冲,在能源亏空时提供。 +block.diode.description = 此方块上的电能只能单向流动,仅当另一侧的电池储能更低时输送电力。 +block.battery.description = 存储能量作为缓冲,在发电量不足时提供保障。 block.battery-large.description = 比普通电池容量更大。 block.combustion-generator.description = 燃烧煤等材料发电。 -block.thermal-generator.description = 放置在炽热的地方发电。 +block.thermal-generator.description = 放置在炽热的地形上能够发电。 block.turbine-generator.description = 先进的火力发电机,效率更高,但需要水来产生蒸汽。 block.differential-generator.description = 利用低温流体与燃烧的硫之间的温差产生大量能量。 block.rtg-generator.description = 一种简单可靠的发电机。利用放射性化合物的衰变产生的热量,以缓慢的速度产生能量。 @@ -1206,9 +1210,9 @@ block.blast-drill.description = 终极钻头,需要大量能量。 block.water-extractor.description = 从地下提取水。当附近没有水源时使用它。 block.cultivator.description = 将微小的孢子培养成工业用的孢子荚。 block.oil-extractor.description = 使用大量能量、沙子和水提炼石油。 -block.core-shard.description = 初代核心。一旦被摧毁,与该地区的所有连接都将断开。不要让它被摧毁。 -block.core-foundation.description = 二代核心。血量更高。可以存储更多资源。 -block.core-nucleus.description = 三代核心,也是最新一代,血量非常高。能存储大量资源。 +block.core-shard.description = 小型核心。一旦被摧毁,与该地区的所有连接都将断开。不要让它被摧毁。 +block.core-foundation.description = 中型核心。血量更高。可以存储更多资源。 +block.core-nucleus.description = 大型核心,也是最强大的,血量非常高。能存储大量资源。 block.vault.description = 存储大量物品。当存在非恒定的材料需求时,使用它来创建缓冲区。[lightgray]卸载器[]可从仓库中提取物品。 block.container.description = 存储少量物品。当存在非恒定的材料需求时,使用它来创建缓冲区。[lightgray]卸载器[]可从容器中提取物品。 block.unloader.description = 将物品从容器、仓库或你的核心中提取到传送带或直接提取到相邻的方块。点击卸载器本身更改所要卸载的物品类型。 @@ -1218,9 +1222,9 @@ block.duo.description = 小而便宜的炮塔,对地很有效。 block.scatter.description = 基本型防空炮塔。向空中敌人喷出一团铅或废料。 block.scorch.description = 小型炮塔,点燃任何靠近它的地面敌人。近距离非常有效。 block.hail.description = 小型远程炮台。 -block.wave.description = 中型快速炮塔,射出液体泡泡。有液体输入时自动灭火。 +block.wave.description = 中型快速炮塔,射出液体泡泡。使用水或者冷却液时能够自动灭火。 block.lancer.description = 中型对地炮塔。会充能并发射强力的的能量束。 -block.arc.description = 小型炮塔,发射电弧。 +block.arc.description = 小型炮塔,发射电弧。电弧无法穿过塑钢墙。 block.swarmer.description = 中型炮塔,对空对地,发射跟踪爆炸导弹。 block.salvo.description = 双管炮的升级版。中型,快速射出一串子弹。 block.fuse.description = 大型近程炮塔,发射三道刺穿敌人的短程光束。 @@ -1228,7 +1232,7 @@ block.ripple.description = 大型远程炮台,非常强力,向远处的敌 block.cyclone.description = 大型炮塔,对空对地,发射在敌人周围引爆的爆炸物。 block.spectre.description = 超大型炮塔,对空对地,一次射出两颗强大的穿甲弹药。 block.meltdown.description = 超大型激光炮塔,充能之后持续发射光束,需要冷却剂。 -block.command-center.description = 在地图上向联盟单位发出移动命令。\n使部队巡逻、攻击一个敌人核心,或者撤退到核心/工厂。当没有敌人核心时,得到攻击命令的部队默认执行巡逻。 +block.command-center.description = 在地图上向联盟单位发出移动命令。\n使部队攻击一个敌人核心,或者撤退到核心/工厂或者集合。当没有敌人核心时,得到攻击命令的部队默认向最近的敌人出现的地方集结。 block.draug-factory.description = 生产德鲁格釆矿机。 block.spirit-factory.description = 生产幽灵修理机。 block.phantom-factory.description = 生产幻影建造机。 diff --git a/core/assets/bundles/bundle_zh_TW.properties b/core/assets/bundles/bundle_zh_TW.properties index aad624d1e2..5a9da9dddf 100644 --- a/core/assets/bundles/bundle_zh_TW.properties +++ b/core/assets/bundles/bundle_zh_TW.properties @@ -104,6 +104,7 @@ mods.none = [lightgray]找不到模組! mods.guide = 模組指南 mods.report = 回報錯誤 mods.openfolder = 開啟模組資料夾 +mod.display = [gray]模組:[orange]{0} mod.enabled = [lightgray]已啟用 mod.disabled = [scarlet]已禁用 mod.disable = 禁用 @@ -251,7 +252,8 @@ copylink = 複製連結 back = 返回 data.export = 匯出數據 data.import = 匯入數據 -data.exported = 數據已匯出. +data.openfolder = 開啟檔案資料夾 +data.exported = 數據已匯出。 data.invalid = 這不是有效的遊戲資料。 data.import.confirm = 導入外部數據將覆蓋您當前[scarlet]所有的[]遊戲數據,\n[accent]這個動作不能撤銷![]\n\n匯入數據後,您的遊戲將立即退出。 classic.export = 匯出 Classic 數據 @@ -530,7 +532,9 @@ error.title = [crimson]發生錯誤 error.crashtitle = 發生錯誤 blocks.input = 輸入 blocks.output = 輸出 -blocks.booster = 加速器 +blocks.booster = 強化 +blocks.tiles = 需求方塊 +blocks.affinities = 親和方塊 block.unknown = [lightgray]??? blocks.powercapacity = 蓄電量 blocks.powershot = 能量/射擊 @@ -665,8 +669,10 @@ setting.mutesound.name = 靜音 setting.crashreport.name = 發送匿名崩潰報告 setting.savecreate.name = 自動建立存檔 setting.publichost.name = 公開遊戲可見度 +setting.playerlimit.name = 玩家數限制 setting.chatopacity.name = 聊天框不透明度 setting.lasersopacity.name = 激光不透明度 +setting.bridgeopacity.name = 橋透明度 setting.playerchat.name = 在遊戲中顯示聊天框 public.confirm = 您想公開遊戲嗎?\n[accent]任何人都可以加入您的遊戲。\n[lightgray]以後可以在“設置”->“遊戲”->“公開遊戲可見度”中進行更改。 public.beta = 請注意,該遊戲的Beta版本無法公開遊戲大廳。 @@ -942,6 +948,7 @@ block.message.name = 訊息板 block.illuminator.name = 照明燈 block.illuminator.description = 小、緊湊而且可調整的光源。需要能源來運作。 block.overflow-gate.name = 溢流器 +block.underflow-gate.name = 反向溢流器 block.silicon-smelter.name = 煉矽廠 block.phase-weaver.name = 相織布編織器 block.pulverizer.name = 粉碎機 @@ -978,7 +985,7 @@ block.mechanical-pump.name = 機械泵 block.item-source.name = 物品源 block.item-void.name = 物品虛空 block.liquid-source.name = 液體源 -block.liquid-void.name = Liquid Void +block.liquid-void.name = 液體虛空 block.power-void.name = 能量虛空 block.power-source.name = 無限能量源 block.unloader.name = 裝卸器 @@ -1078,7 +1085,7 @@ tutorial.breaking.mobile = 方塊經常需要被拆除。\n[accent]選擇拆除 tutorial.withdraw = 在某些情況下,直接從方塊中取出物品是必要的。\n[accent]點擊有物品的方塊[],然後[accent]點擊在方框中的物品[]以將其取出。\n可以通過[accent]點擊或長按[]來取出物品。\n\n[accent]從核心中取出一些銅。[] tutorial.deposit = 通過將物品從船上拖到目標方塊,將物品放入方塊中。\n\n[accent]將您的銅放到核心中。[] tutorial.waves = [lightgray]敵人[]來臨。\n\n保護核心抵抗兩波攻擊。\n建造更多的砲塔和鑽頭。開採更多的銅。 -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.waves.mobile = [lightgray]敵人[]來臨。\n\n保護核心抵抗兩波攻擊。您的飛船會自動向敵人開火。\n建造更多的砲塔和鑽頭。開採更多的銅。 tutorial.launch = 一旦您達到特定的波數, 您就可以[accent] 發射核心[],放棄防禦並[accent]獲取核心中的所有資源。[]\n這些資源可以用於研究新科技。\n\n[accent]按下發射按鈕。 item.copper.description = 最基本的結構材料。在各種類型的方塊中廣泛使用。 @@ -1142,7 +1149,7 @@ block.power-source.description = 無限輸出能量。僅限沙盒。 block.item-source.description = 無限輸出物品。僅限沙盒。 block.item-void.description = 不使用能量銷毀任何進入它的物品。僅限沙盒。 block.liquid-source.description = 無限輸出液體。僅限沙盒。 -block.liquid-void.description = Removes any liquids. Sandbox only. +block.liquid-void.description = 銷毀所有輸入的液體。僅限沙盒。 block.copper-wall.description = 一種便宜的防禦方塊。\n用於前幾波防衛核心和砲塔。 block.copper-wall-large.description = 一種便宜的防禦方塊。\n用於前幾波防禦核心和砲塔\n佔據多個方塊。 block.titanium-wall.description = 一個中等強度的防禦方塊。\n提供對敵人的適度保護。 @@ -1169,9 +1176,10 @@ block.bridge-conveyor.description = 高級的物品運輸方塊。允許跨過 block.phase-conveyor.description = 高級物品傳輸方塊。使用能量將物品傳送到幾個方塊外連接的相織輸送帶。 block.sorter.description = 對物品進行分類。如果物品與所選種類匹配,則允許其通過。否則,物品將從左邊和右邊輸出。 block.inverted-sorter.description = 處理物品的方式類似於分類器,但將所選擇的物品輸出到側面。 -block.router.description = 接受來自一個方向的物品並將它們平均輸出到最多3個其他方向。用於將物品從一個來源分割為多個目標。 +block.router.description = 接受來自一個方向的物品並將它們平均輸出到最多3個其他方向。用於將物品從一個來源分割為多個目標。\n\n[[scarlet]]不建議緊貼在生產型方塊旁使用,可能導致其被產出堵塞。[] block.distributor.description = 高級的分配器,可將物品均分到最多7個其他方向。 -block.overflow-gate.description = 如果前面被擋住,則向左邊和右邊輸出物品。 +block.overflow-gate.description = 如果前面被阻擋,則向左邊和右邊輸出物品。 +block.underflow-gate.description = 反向的溢流器。如果側面被阻擋,則向前方輸出物品。 block.mass-driver.description = 終極物品運輸方塊。收集大量物品,然後將它們射向另一個質量驅動器。需要能源以運作。 block.mechanical-pump.description = 一種便宜的泵,輸出速度慢,但不使用能量。 block.rotary-pump.description = 高級的泵。抽更多液體,但需要能量。 diff --git a/core/assets/fonts/font.ttf b/core/assets/fonts/font.ttf index 6280981559..9d7390954d 100644 Binary files a/core/assets/fonts/font.ttf and b/core/assets/fonts/font.ttf differ diff --git a/core/assets/fonts/fontello.ttf b/core/assets/fonts/fontello.ttf new file mode 100644 index 0000000000..7eaf076f22 Binary files /dev/null and b/core/assets/fonts/fontello.ttf differ diff --git a/core/assets/fonts/icon.ttf b/core/assets/fonts/icon.ttf index ac50ebe006..0cde9685b5 100644 Binary files a/core/assets/fonts/icon.ttf and b/core/assets/fonts/icon.ttf differ diff --git a/core/assets/icons/icons.properties b/core/assets/icons/icons.properties index 7c91ca4bb9..2c7a2536c9 100755 --- a/core/assets/icons/icons.properties +++ b/core/assets/icons/icons.properties @@ -217,3 +217,6 @@ 63527=slag|liquid-slag-icon 63526=oil|liquid-oil-icon 63525=cryofluid|liquid-cryofluid-icon +63524=underflow-gate|block-underflow-gate-medium +63523=dart-ship-pad|block-dart-ship-pad-medium +63522=alpha-mech-pad|block-alpha-mech-pad-medium diff --git a/core/assets/sprites/block_colors.png b/core/assets/sprites/block_colors.png index 708d0fb049..fdf9397b46 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 27e65fba7c..e2b3889d35 100644 --- a/core/assets/sprites/sprites.atlas +++ b/core/assets/sprites/sprites.atlas @@ -6,3948 +6,3829 @@ filter: Nearest,Nearest repeat: none force-projector-top rotate: false - xy: 619, 340 + xy: 852, 1659 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mend-projector-top rotate: false - xy: 1077, 662 + xy: 1179, 1035 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mender-top rotate: false - xy: 1481, 781 + xy: 939, 230 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 overdrive-projector-top rotate: false - xy: 1077, 596 + xy: 981, 771 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 shock-mine rotate: false - xy: 1489, 373 + xy: 1023, 505 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-arrow rotate: false - xy: 1895, 1139 + xy: 1941, 1337 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor-bridge rotate: false - xy: 1328, 1121 + xy: 2009, 1353 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor-end rotate: false - xy: 1328, 1087 + xy: 2009, 1319 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 center rotate: false - xy: 1328, 1053 + xy: 1611, 1335 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-0-0 rotate: false - xy: 890, 851 + xy: 1377, 1145 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-armored-conveyor-full rotate: false - xy: 890, 851 + xy: 1377, 1145 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-0-1 rotate: false - xy: 389, 15 + xy: 1377, 1111 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-0-2 rotate: false - xy: 423, 10 + xy: 1377, 1077 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-0-3 rotate: false - xy: 457, 10 + xy: 1377, 1043 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-1-0 rotate: false - xy: 491, 10 + xy: 1377, 1009 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-1-1 rotate: false - xy: 525, 10 + xy: 1377, 975 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-1-2 rotate: false - xy: 559, 10 + xy: 1377, 941 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-1-3 rotate: false - xy: 593, 10 + xy: 1377, 907 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-2-0 rotate: false - xy: 627, 12 + xy: 1377, 873 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-2-1 rotate: false - xy: 661, 12 + xy: 1377, 839 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-2-2 rotate: false - xy: 911, 11 + xy: 1377, 805 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-2-3 rotate: false - xy: 945, 11 + xy: 1377, 771 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-3-0 rotate: false - xy: 695, 10 + xy: 1415, 1255 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-3-1 rotate: false - xy: 729, 10 + xy: 1415, 1221 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-3-2 rotate: false - xy: 763, 10 + xy: 719, 156 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-3-3 rotate: false - xy: 1158, 1181 + xy: 719, 122 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-4-0 rotate: false - xy: 1158, 1147 + xy: 719, 88 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-4-1 rotate: false - xy: 1192, 1181 + xy: 873, 330 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-4-2 rotate: false - xy: 1158, 1113 + xy: 907, 332 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-4-3 rotate: false - xy: 1192, 1147 + xy: 941, 332 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-0-1 rotate: false - xy: 1356, 869 + xy: 1747, 1269 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-0-2 rotate: false - xy: 1345, 835 + xy: 1781, 1269 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-0-3 rotate: false - xy: 1345, 801 + xy: 1815, 1269 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-1-0 rotate: false - xy: 1345, 767 + xy: 1849, 1269 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-1-1 rotate: false - xy: 1345, 733 + xy: 1883, 1269 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-1-2 rotate: false - xy: 1345, 699 + xy: 1917, 1269 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-1-3 rotate: false - xy: 1345, 665 + xy: 1951, 1269 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-2-0 rotate: false - xy: 1345, 631 + xy: 1985, 1285 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-2-1 rotate: false - xy: 1345, 597 + xy: 1985, 1251 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-2-2 rotate: false - xy: 1345, 563 + xy: 1445, 1153 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-2-3 rotate: false - xy: 1345, 529 + xy: 1445, 1119 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-3-0 rotate: false - xy: 1345, 495 + xy: 1445, 1085 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-3-1 rotate: false - xy: 1397, 1175 + xy: 1445, 1051 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-3-2 rotate: false - xy: 1396, 1141 + xy: 1445, 1017 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-3-3 rotate: false - xy: 1396, 1107 + xy: 1445, 983 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-4-0 rotate: false - xy: 1396, 1073 + xy: 1445, 949 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-4-1 rotate: false - xy: 1396, 1039 + xy: 1445, 915 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-4-2 rotate: false - xy: 1396, 1005 + xy: 1445, 881 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-4-3 rotate: false - xy: 1396, 971 + xy: 1445, 847 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-0-1 rotate: false - xy: 1489, 305 + xy: 1091, 539 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-0-2 rotate: false - xy: 1387, 271 + xy: 1023, 471 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-0-3 rotate: false - xy: 1421, 271 + xy: 1057, 505 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-1-0 rotate: false - xy: 1455, 271 + xy: 989, 403 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-1-1 rotate: false - xy: 1489, 271 + xy: 1023, 437 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-1-2 rotate: false - xy: 1492, 917 + xy: 1091, 505 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-1-3 rotate: false - xy: 1492, 883 + xy: 1057, 471 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-2-0 rotate: false - xy: 1492, 849 + xy: 989, 369 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-2-1 rotate: false - xy: 1515, 815 + xy: 1023, 403 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-2-2 rotate: false - xy: 1515, 781 + xy: 1091, 471 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-2-3 rotate: false - xy: 1515, 747 + xy: 1057, 437 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-3-0 rotate: false - xy: 1515, 713 + xy: 1023, 369 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-3-1 rotate: false - xy: 1515, 679 + xy: 1091, 437 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-3-2 rotate: false - xy: 1515, 645 + xy: 1057, 403 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-3-3 rotate: false - xy: 1515, 611 + xy: 1091, 403 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-4-0 rotate: false - xy: 1515, 577 + xy: 1057, 369 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-4-1 rotate: false - xy: 1515, 543 + xy: 1091, 369 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-4-2 rotate: false - xy: 1515, 509 + xy: 1009, 335 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-4-3 rotate: false - xy: 1515, 475 + xy: 1009, 301 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mass-driver-base rotate: false - xy: 1939, 1431 + xy: 779, 1440 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 phase-conveyor-arrow rotate: false - xy: 1481, 645 + xy: 957, 196 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor-bridge rotate: false - xy: 1481, 611 + xy: 923, 128 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor-end rotate: false - xy: 1481, 577 + xy: 957, 162 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +underflow-gate + rotate: false + xy: 1009, 267 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 blast-drill rotate: false - xy: 204, 993 + xy: 1, 97 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 blast-drill-rim rotate: false - xy: 334, 993 + xy: 1804, 1919 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 blast-drill-rotator rotate: false - xy: 477, 1371 + xy: 323, 1394 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 blast-drill-top rotate: false - xy: 413, 1241 + xy: 526, 1597 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 drill-top rotate: false - xy: 1026, 1124 + xy: 1179, 1233 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 turbine-generator-liquid rotate: false - xy: 1026, 1124 + xy: 1179, 1233 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 laser-drill rotate: false - xy: 717, 632 + xy: 1048, 1561 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 laser-drill-rim rotate: false - xy: 717, 534 + xy: 1146, 1659 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 laser-drill-rotator rotate: false - xy: 717, 436 + xy: 1146, 1561 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 laser-drill-top rotate: false - xy: 717, 338 + xy: 1244, 1659 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mechanical-drill rotate: false - xy: 1011, 662 + xy: 981, 837 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mechanical-drill-rotator rotate: false - xy: 1077, 728 + xy: 1047, 903 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mechanical-drill-top rotate: false - xy: 1011, 596 + xy: 1113, 969 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 oil-extractor rotate: false - xy: 758, 849 + xy: 877, 1463 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 oil-extractor-liquid rotate: false - xy: 749, 751 + xy: 975, 1463 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 oil-extractor-rotator rotate: false - xy: 815, 653 + xy: 1073, 1463 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 oil-extractor-top rotate: false - xy: 815, 555 + xy: 1171, 1463 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 pneumatic-drill rotate: false - xy: 1053, 266 + xy: 1113, 837 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pneumatic-drill-rotator rotate: false - xy: 1119, 398 + xy: 1179, 903 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pneumatic-drill-top rotate: false - xy: 1119, 332 + xy: 1245, 969 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 water-extractor rotate: false - xy: 1201, 1431 + xy: 1311, 771 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 water-extractor-liquid rotate: false - xy: 1201, 1365 + xy: 1279, 705 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 water-extractor-rotator rotate: false - xy: 1135, 1299 + xy: 1279, 639 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 water-extractor-top rotate: false - xy: 1267, 1431 + xy: 1345, 705 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-border rotate: false - xy: 1192, 1113 + xy: 2006, 1625 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-middle rotate: false - xy: 1209, 637 + xy: 1411, 1017 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-select rotate: false - xy: 1311, 841 + xy: 1955, 1405 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-liquid rotate: false - xy: 1362, 1005 + xy: 1781, 1303 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 place-arrow rotate: false - xy: 815, 457 + xy: 1269, 1463 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 -rubble-1-0 - rotate: false - xy: 1111, 200 - size: 64, 64 - orig: 64, 64 - offset: 0, 0 - index: -1 -rubble-1-1 - rotate: false - xy: 1111, 134 - size: 64, 64 - orig: 64, 64 - offset: 0, 0 - index: -1 -rubble-2-0 - rotate: false - xy: 1111, 68 - size: 64, 64 - orig: 64, 64 - offset: 0, 0 - index: -1 -rubble-2-1 - rotate: false - xy: 1003, 1388 - size: 64, 64 - orig: 64, 64 - offset: 0, 0 - index: -1 -rubble-3-0 - rotate: false - xy: 815, 163 - size: 96, 96 - orig: 96, 96 - offset: 0, 0 - index: -1 -rubble-3-1 - rotate: false - xy: 815, 163 - size: 96, 96 - orig: 96, 96 - offset: 0, 0 - index: -1 -rubble-4-0 - rotate: false - xy: 1059, 1497 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -rubble-4-1 - rotate: false - xy: 1059, 1497 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -rubble-5-0 - rotate: false - xy: 1876, 1887 - size: 160, 160 - orig: 160, 160 - offset: 0, 0 - index: -1 -rubble-5-1 - rotate: false - xy: 1876, 1887 - size: 160, 160 - orig: 160, 160 - offset: 0, 0 - index: -1 -rubble-6-0 - rotate: false - xy: 1, 750 - size: 192, 192 - orig: 192, 192 - offset: 0, 0 - index: -1 -rubble-6-1 - rotate: false - xy: 1, 750 - size: 192, 192 - orig: 192, 192 - offset: 0, 0 - index: -1 -rubble-7-0 - rotate: false - xy: 323, 1501 - size: 224, 224 - orig: 224, 224 - offset: 0, 0 - index: -1 -rubble-7-1 - rotate: false - xy: 323, 1501 - size: 224, 224 - orig: 224, 224 - offset: 0, 0 - index: -1 -rubble-8-0 - rotate: false - xy: 1, 1147 - size: 256, 256 - orig: 256, 256 - offset: 0, 0 - index: -1 -rubble-8-1 - rotate: false - xy: 1, 1147 - size: 256, 256 - orig: 256, 256 - offset: 0, 0 - index: -1 bridge-conduit-arrow rotate: false - xy: 1929, 1139 + xy: 1975, 1371 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor-arrow rotate: false - xy: 1929, 1139 + xy: 1975, 1371 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conduit-bridge rotate: false - xy: 1329, 1189 + xy: 1975, 1337 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conduit-end rotate: false - xy: 1328, 1155 + xy: 2009, 1387 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom rotate: false - xy: 1363, 1175 + xy: 1645, 1309 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-0 rotate: false - xy: 1362, 1141 + xy: 1645, 1275 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-1 rotate: false - xy: 1362, 1107 + xy: 1679, 1303 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-2 rotate: false - xy: 1362, 1073 + xy: 1713, 1303 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-3 rotate: false - xy: 1362, 1073 + xy: 1713, 1303 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-4 rotate: false - xy: 1362, 1073 + xy: 1713, 1303 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-6 rotate: false - xy: 1362, 1073 + xy: 1713, 1303 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-bottom-5 rotate: false - xy: 1362, 1039 + xy: 1747, 1303 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-0 rotate: false - xy: 1328, 985 + xy: 1815, 1303 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-1 rotate: false - xy: 1322, 951 + xy: 1849, 1303 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-2 rotate: false - xy: 1322, 917 + xy: 1883, 1303 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-3 rotate: false - xy: 1322, 883 + xy: 1917, 1303 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-3 rotate: false - xy: 1322, 883 + xy: 1917, 1303 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-4 rotate: false - xy: 1362, 971 + xy: 1951, 1303 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-5 rotate: false - xy: 1356, 937 + xy: 1679, 1269 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conduit-top-6 rotate: false - xy: 1356, 903 + xy: 1713, 1269 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-overflow-gate rotate: false - xy: 1447, 611 + xy: 1450, 541 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-overflow-gate-top rotate: false - xy: 1413, 543 + xy: 1416, 507 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-router-bottom rotate: false - xy: 1447, 577 + xy: 1450, 507 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-router-liquid rotate: false - xy: 1413, 509 + xy: 1484, 541 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-router-top rotate: false - xy: 1447, 543 + xy: 1484, 507 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-tank-bottom rotate: false - xy: 717, 240 + xy: 1244, 1561 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 liquid-tank-liquid rotate: false - xy: 717, 142 + xy: 1342, 1659 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 liquid-tank-top rotate: false - xy: 717, 44 + xy: 1342, 1561 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 phase-conduit-arrow rotate: false - xy: 1481, 747 + xy: 973, 230 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit-bridge rotate: false - xy: 1481, 713 + xy: 923, 196 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit-end rotate: false - xy: 1481, 679 + xy: 923, 162 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plated-conduit-cap rotate: false - xy: 1481, 543 + xy: 923, 94 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plated-conduit-top-0 rotate: false - xy: 1481, 509 + xy: 957, 128 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plated-conduit-top-1 rotate: false - xy: 1481, 475 + xy: 923, 60 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plated-conduit-top-2 rotate: false - xy: 1353, 461 + xy: 957, 94 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plated-conduit-top-3 rotate: false - xy: 1353, 427 + xy: 923, 26 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plated-conduit-top-4 rotate: false - xy: 1353, 393 + xy: 957, 60 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plated-conduit-top-5 rotate: false - xy: 1353, 359 + xy: 957, 26 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plated-conduit-top-6 rotate: false - xy: 1353, 325 + xy: 991, 196 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-0 rotate: false - xy: 1387, 441 + xy: 991, 128 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-1 rotate: false - xy: 1387, 407 + xy: 991, 94 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-2 rotate: false - xy: 1421, 441 + xy: 991, 60 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-4 rotate: false - xy: 1387, 373 + xy: 991, 26 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-5 rotate: false - xy: 1421, 407 + xy: 1007, 230 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-top-6 rotate: false - xy: 1455, 441 + xy: 1025, 196 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +alpha-mech-pad + rotate: false + xy: 1393, 1397 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +block-alpha-mech-pad-full + rotate: false + xy: 1393, 1397 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 battery rotate: false - xy: 1226, 1181 + xy: 1543, 1311 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-battery-full rotate: false - xy: 1226, 1181 + xy: 1543, 1311 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 battery-large rotate: false - xy: 527, 1143 + xy: 293, 315 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-battery-large-full rotate: false - xy: 527, 1143 + xy: 293, 315 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 combustion-generator-top rotate: false - xy: 1328, 1019 + xy: 1611, 1301 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 differential-generator-liquid rotate: false - xy: 660, 849 + xy: 681, 1438 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 differential-generator-top rotate: false - xy: 619, 632 + xy: 609, 1340 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 diode-arrow rotate: false - xy: 1379, 665 + xy: 769, 280 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 illuminator-top rotate: false - xy: 1379, 529 + xy: 837, 288 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 impact-reactor rotate: false - xy: 1586, 1757 + xy: 219, 1264 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-bottom rotate: false - xy: 1716, 1757 + xy: 349, 1264 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-light rotate: false - xy: 1846, 1757 + xy: 479, 1264 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-plasma-0 rotate: false - xy: 929, 1586 + xy: 293, 1134 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-plasma-1 rotate: false - xy: 1059, 1627 + xy: 293, 1004 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-plasma-2 rotate: false - xy: 1189, 1627 + xy: 423, 1134 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 impact-reactor-plasma-3 rotate: false - xy: 1319, 1627 + xy: 293, 874 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 power-source rotate: false - xy: 1353, 291 + xy: 991, 162 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rtg-generator-top rotate: false - xy: 1455, 373 + xy: 1147, 540 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium-reactor-center rotate: false - xy: 913, 653 + xy: 1099, 1365 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 thorium-reactor-lights rotate: false - xy: 913, 555 + xy: 1197, 1365 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 turbine-generator-top rotate: false - xy: 1069, 1365 + xy: 1311, 837 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 alloy-smelter rotate: false - xy: 1, 4 + xy: 1934, 1951 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-alloy-smelter-full rotate: false - xy: 1, 4 + xy: 1934, 1951 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 alloy-smelter-top rotate: false - xy: 1449, 1529 + xy: 423, 646 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 blast-mixer rotate: false - xy: 549, 1513 + xy: 683, 1274 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-blast-mixer-full rotate: false - xy: 549, 1513 + xy: 683, 1274 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cryofluidmixer-bottom rotate: false - xy: 945, 1454 + xy: 981, 1233 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cryofluidmixer-liquid rotate: false - xy: 937, 1388 + xy: 981, 1167 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cryofluidmixer-top rotate: false - xy: 937, 1322 + xy: 1047, 1233 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cultivator rotate: false - xy: 937, 1256 + xy: 981, 1101 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cultivator-middle rotate: false - xy: 921, 1190 + xy: 1047, 1167 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cultivator-top rotate: false - xy: 987, 1190 + xy: 1113, 1233 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 kiln-top rotate: false - xy: 1011, 794 + xy: 1113, 1035 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 silicon-smelter-top rotate: false - xy: 1011, 794 + xy: 1113, 1035 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phase-weaver rotate: false - xy: 1077, 530 + xy: 1113, 903 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phase-weaver-bottom rotate: false - xy: 1077, 464 + xy: 1179, 969 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phase-weaver-weave rotate: false - xy: 1053, 398 + xy: 1245, 1035 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 plastanium-compressor-top rotate: false - xy: 1053, 332 + xy: 1047, 771 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pulverizer rotate: false - xy: 1387, 339 + xy: 1025, 162 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulverizer-rotator rotate: false - xy: 1421, 373 + xy: 1025, 128 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pump-liquid rotate: false - xy: 1455, 407 + xy: 1025, 94 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 separator-liquid rotate: false - xy: 1143, 728 + xy: 1081, 705 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 separator-spinner rotate: false - xy: 1143, 662 + xy: 1081, 639 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press rotate: false - xy: 1143, 530 + xy: 1147, 639 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press-frame0 rotate: false - xy: 1143, 464 + xy: 1213, 705 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press-frame1 rotate: false - xy: 1185, 398 + xy: 1213, 639 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press-frame2 rotate: false - xy: 1185, 332 + xy: 1311, 1233 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press-liquid rotate: false - xy: 1185, 266 + xy: 1311, 1167 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-press-top rotate: false - xy: 1177, 200 + xy: 1311, 1101 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 unloader-center rotate: false - xy: 1523, 407 + xy: 1077, 335 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 arc-heat rotate: false - xy: 856, 851 + xy: 1377, 1179 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-1 rotate: false - xy: 1158, 1079 + xy: 1577, 1311 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-2 rotate: false - xy: 913, 243 + xy: 749, 1274 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-3 rotate: false - xy: 1547, 1529 + xy: 656, 1634 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-4 rotate: false - xy: 543, 1241 + xy: 453, 1394 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 hail-heat rotate: false - xy: 887, 1593 + xy: 1648, 1571 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 lancer-heat rotate: false - xy: 1011, 728 + xy: 1245, 1167 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 meltdown-heat rotate: false - xy: 1579, 1627 + xy: 293, 744 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 ripple-heat rotate: false - xy: 815, 261 + xy: 805, 1342 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 salvo-heat rotate: false - xy: 1003, 1256 + xy: 1245, 903 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 salvo-panel-left rotate: false - xy: 1053, 1190 + xy: 1179, 771 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 salvo-panel-right rotate: false - xy: 1092, 1124 + xy: 1245, 837 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scorch-heat rotate: false - xy: 1455, 339 + xy: 989, 505 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 wave-liquid rotate: false - xy: 1201, 1299 + xy: 1015, 573 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 crawler-factory rotate: false - xy: 871, 1281 + xy: 883, 682 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dagger-factory rotate: false - xy: 871, 1281 + xy: 883, 682 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 draug-factory rotate: false - xy: 871, 1281 + xy: 883, 682 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phantom-factory rotate: false - xy: 871, 1281 + xy: 883, 682 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spirit-factory rotate: false - xy: 871, 1281 + xy: 883, 682 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 wraith-factory rotate: false - xy: 871, 1281 + xy: 883, 682 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 crawler-factory-top rotate: false - xy: 945, 1520 + xy: 883, 616 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dagger-factory-top rotate: false - xy: 960, 1124 + xy: 981, 1035 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 draug-factory-top rotate: false - xy: 960, 992 + xy: 1113, 1167 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 fortress-factory rotate: false - xy: 619, 242 + xy: 852, 1561 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 fortress-factory-top rotate: false - xy: 619, 144 + xy: 950, 1659 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 ghoul-factory-top rotate: false - xy: 619, 144 + xy: 950, 1659 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 titan-factory-top rotate: false - xy: 619, 144 + xy: 950, 1659 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 ghoul-factory rotate: false - xy: 651, 730 + xy: 1048, 1659 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 phantom-factory-top rotate: false - xy: 1011, 464 + xy: 1047, 837 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 rally-point rotate: false - xy: 1119, 266 + xy: 1113, 771 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 repair-point-base rotate: false - xy: 1421, 339 + xy: 1025, 26 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 revenant-factory rotate: false - xy: 1709, 1627 + xy: 423, 874 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 revenant-factory-top rotate: false - xy: 1839, 1627 + xy: 293, 614 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 spirit-factory-top rotate: false - xy: 1143, 596 + xy: 1147, 705 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 titan-factory rotate: false - xy: 913, 457 + xy: 1295, 1365 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 wraith-factory-top rotate: false - xy: 1333, 1431 + xy: 1081, 573 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 door-large-open rotate: false - xy: 960, 1058 + xy: 1047, 1101 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 door-open rotate: false - xy: 1379, 631 + xy: 769, 246 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 insulator-wall rotate: false - xy: 1379, 495 + xy: 803, 254 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 insulator-wall-large rotate: false - xy: 945, 794 + xy: 1047, 969 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scrap-wall-huge2 rotate: false - xy: 815, 65 + xy: 903, 1365 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 scrap-wall-huge3 rotate: false - xy: 847, 751 + xy: 1001, 1365 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 scrap-wall-large1 rotate: false - xy: 1092, 992 + xy: 949, 682 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scrap-wall-large2 rotate: false - xy: 1120, 926 + xy: 949, 616 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scrap-wall-large3 rotate: false - xy: 1120, 860 + xy: 1015, 705 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scrap-wall-large4 rotate: false - xy: 1143, 794 + xy: 1015, 639 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scrap-wall2 rotate: false - xy: 1455, 305 + xy: 1023, 539 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall3 rotate: false - xy: 1489, 441 + xy: 989, 471 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall4 rotate: false - xy: 1489, 407 + xy: 1057, 539 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall5 rotate: false - xy: 1489, 407 + xy: 1057, 539 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bullet rotate: false - xy: 1153, 14 + xy: 75, 43 size: 52, 52 orig: 52, 52 offset: 0, 0 index: -1 bullet-back rotate: false - xy: 1207, 14 + xy: 1270, 585 size: 52, 52 orig: 52, 52 offset: 0, 0 index: -1 casing rotate: false - xy: 1176, 993 + xy: 1601, 1351 size: 8, 16 orig: 8, 16 offset: 0, 0 index: -1 circle-end rotate: false - xy: 464, 926 + xy: 293, 413 size: 100, 199 orig: 100, 199 offset: 0, 0 index: -1 circle-mid rotate: false - xy: 1549, 648 + xy: 2018, 1732 size: 1, 199 orig: 1, 199 offset: 0, 0 index: -1 circle-shadow rotate: false - xy: 863, 1846 + xy: 645, 1846 size: 201, 201 orig: 201, 201 offset: 0, 0 index: -1 error rotate: false - xy: 1749, 1331 + xy: 527, 8 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 laser rotate: false - xy: 1053, 1536 + xy: 385, 167 size: 4, 48 orig: 4, 48 offset: 0, 0 index: -1 laser-end rotate: false - xy: 913, 383 + xy: 1, 23 size: 72, 72 orig: 72, 72 offset: 0, 0 index: -1 minelaser rotate: false - xy: 1053, 1486 + xy: 1453, 1281 size: 4, 48 orig: 4, 48 offset: 0, 0 index: -1 minelaser-end rotate: false - xy: 549, 1579 + xy: 609, 1266 size: 72, 72 orig: 72, 72 offset: 0, 0 index: -1 missile rotate: false - xy: 863, 1808 + xy: 759, 1734 size: 36, 36 orig: 36, 36 offset: 0, 0 index: -1 missile-back rotate: false - xy: 921, 1152 + xy: 797, 1734 size: 36, 36 orig: 36, 36 offset: 0, 0 index: -1 scale_marker rotate: false - xy: 723, 1143 + xy: 1465, 1555 size: 4, 4 orig: 4, 4 offset: 0, 0 index: -1 -scorch1 - rotate: false - xy: 1523, 305 - size: 28, 100 - orig: 28, 100 - offset: 0, 0 - index: -1 -scorch2 - rotate: false - xy: 1553, 305 - size: 28, 100 - orig: 28, 100 - offset: 0, 0 - index: -1 -scorch3 - rotate: false - xy: 1498, 1053 - size: 28, 100 - orig: 28, 100 - offset: 0, 0 - index: -1 -scorch4 - rotate: false - xy: 1498, 951 - size: 28, 100 - orig: 28, 100 - offset: 0, 0 - index: -1 -scorch5 - rotate: false - xy: 1526, 849 - size: 28, 100 - orig: 28, 100 - offset: 0, 0 - index: -1 shell rotate: false - xy: 873, 27 + xy: 1377, 1251 size: 36, 36 orig: 36, 36 offset: 0, 0 index: -1 shell-back rotate: false - xy: 1371, 1209 + xy: 1377, 1213 size: 36, 36 orig: 36, 36 offset: 0, 0 index: -1 shot rotate: false - xy: 1489, 339 + xy: 989, 437 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 transfer rotate: false - xy: 2043, 1231 + xy: 642, 1547 size: 4, 48 orig: 4, 48 offset: 0, 0 index: -1 transfer-arrow rotate: false - xy: 1523, 441 + xy: 1043, 335 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 transfer-end rotate: false - xy: 913, 309 + xy: 759, 1772 size: 72, 72 orig: 72, 72 offset: 0, 0 index: -1 white rotate: false - xy: 1251, 266 + xy: 645, 1727 size: 3, 3 orig: 3, 3 offset: 0, 0 index: -1 arc rotate: false - xy: 389, 49 + xy: 685, 156 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-arc-full rotate: false - xy: 1226, 1147 + xy: 975, 332 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-blast-drill-full rotate: false - xy: 799, 1677 + xy: 163, 1033 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 block-bridge-conduit-full rotate: false - xy: 1260, 1181 + xy: 2006, 1591 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conduit rotate: false - xy: 1260, 1181 + xy: 2006, 1591 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-bridge-conveyor-full rotate: false - xy: 1158, 1045 + xy: 1732, 1575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor rotate: false - xy: 1158, 1045 + xy: 1732, 1575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-char-full rotate: false - xy: 1260, 1147 + xy: 1766, 1575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-cliffs-full rotate: false - xy: 1226, 1113 + xy: 1800, 1575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-coal-centrifuge-full rotate: false - xy: 913, 177 + xy: 815, 1276 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 coal-centrifuge rotate: false - xy: 913, 177 + xy: 815, 1276 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-combustion-generator-full rotate: false - xy: 1192, 1079 + xy: 1834, 1575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 combustion-generator rotate: false - xy: 1192, 1079 + xy: 1834, 1575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-command-center-full rotate: false - xy: 913, 111 + xy: 1393, 1331 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 command-center rotate: false - xy: 913, 111 + xy: 1393, 1331 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-conduit-full rotate: false - xy: 1294, 1181 + xy: 1868, 1575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-container-full rotate: false - xy: 1976, 1821 + xy: 651, 1200 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 container rotate: false - xy: 1976, 1821 + xy: 651, 1200 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-conveyor-full rotate: false - xy: 1158, 1011 + xy: 1902, 1575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 conveyor-0-0 rotate: false - xy: 1158, 1011 + xy: 1902, 1575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-copper-wall-full rotate: false - xy: 1294, 1147 + xy: 1936, 1575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper-wall rotate: false - xy: 1294, 1147 + xy: 1936, 1575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-copper-wall-large-full rotate: false - xy: 1976, 1755 + xy: 651, 1134 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 copper-wall-large rotate: false - xy: 1976, 1755 + xy: 651, 1134 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-core-foundation-full rotate: false - xy: 929, 1716 + xy: 163, 903 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 core-foundation rotate: false - xy: 929, 1716 + xy: 163, 903 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 block-core-nucleus-full rotate: false - xy: 1066, 1887 + xy: 1, 1001 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 core-nucleus rotate: false - xy: 1066, 1887 + xy: 1, 1001 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 block-core-shard-full rotate: false - xy: 1645, 1529 + xy: 293, 217 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 core-shard rotate: false - xy: 1645, 1529 + xy: 293, 217 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-craters-full rotate: false - xy: 1260, 1113 + xy: 1970, 1575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-crawler-factory-full rotate: false - xy: 1969, 1689 + xy: 651, 1068 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-cryofluidmixer-full rotate: false - xy: 913, 45 + xy: 651, 1002 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-cultivator-full rotate: false - xy: 623, 1615 + xy: 651, 936 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-cyclone-full rotate: false - xy: 1743, 1529 + xy: 553, 1166 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-dagger-factory-full rotate: false - xy: 689, 1615 + xy: 651, 870 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-dark-metal-full rotate: false - xy: 1226, 1079 + xy: 1733, 1541 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-1-full rotate: false - xy: 1192, 1045 + xy: 1733, 1507 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-2-full rotate: false - xy: 1294, 1113 + xy: 1767, 1541 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-3-full rotate: false - xy: 1260, 1079 + xy: 1733, 1473 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-4-full rotate: false - xy: 1226, 1045 + xy: 1767, 1507 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-5-full rotate: false - xy: 1192, 1011 + xy: 1801, 1541 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-dark-panel-6-full rotate: false - xy: 1294, 1079 + xy: 1767, 1473 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-darksand-full rotate: false - xy: 1260, 1045 + xy: 1801, 1507 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-darksand-tainted-water-full rotate: false - xy: 1226, 1011 + xy: 1835, 1541 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-darksand-water-full rotate: false - xy: 1294, 1045 + xy: 1801, 1473 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-dart-mech-pad-full +block-dart-ship-pad-full rotate: false - xy: 623, 1549 + xy: 651, 804 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 -dart-mech-pad +dart-ship-pad rotate: false - xy: 623, 1549 + xy: 651, 804 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-deepwater-full rotate: false - xy: 1260, 1011 + xy: 1835, 1507 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-delta-mech-pad-full rotate: false - xy: 689, 1549 + xy: 717, 1208 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 delta-mech-pad rotate: false - xy: 689, 1549 + xy: 717, 1208 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-differential-generator-full rotate: false - xy: 1841, 1529 + xy: 553, 1068 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 differential-generator rotate: false - xy: 1841, 1529 + xy: 553, 1068 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-diode-full rotate: false - xy: 1294, 1011 + xy: 1869, 1541 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 diode rotate: false - xy: 1294, 1011 + xy: 1869, 1541 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-distributor-full rotate: false - xy: 615, 1483 + xy: 717, 1142 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 distributor rotate: false - xy: 615, 1483 + xy: 717, 1142 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-door-full rotate: false - xy: 1186, 977 + xy: 1835, 1473 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 door rotate: false - xy: 1186, 977 + xy: 1835, 1473 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-door-large-full rotate: false - xy: 681, 1483 + xy: 717, 1076 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 door-large rotate: false - xy: 681, 1483 + xy: 717, 1076 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-draug-factory-full rotate: false - xy: 607, 1417 + xy: 717, 1010 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-dunerocks-full rotate: false - xy: 1186, 943 + xy: 1869, 1507 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-duo-full rotate: false - xy: 1220, 977 + xy: 1903, 1541 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-force-projector-full rotate: false - xy: 464, 828 + xy: 553, 970 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 force-projector rotate: false - xy: 464, 828 + xy: 553, 970 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-fortress-factory-full rotate: false - xy: 455, 730 + xy: 553, 872 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-fuse-full rotate: false - xy: 423, 632 + xy: 553, 774 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-ghoul-factory-full rotate: false - xy: 423, 534 + xy: 656, 1536 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-glaive-ship-pad-full rotate: false - xy: 423, 436 + xy: 423, 548 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 glaive-ship-pad rotate: false - xy: 423, 436 + xy: 423, 548 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-graphite-press-full rotate: false - xy: 673, 1417 + xy: 717, 944 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 graphite-press rotate: false - xy: 673, 1417 + xy: 717, 944 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-grass-full rotate: false - xy: 1186, 909 + xy: 1869, 1473 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-hail-full rotate: false - xy: 1254, 977 + xy: 1903, 1507 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-holostone-full rotate: false - xy: 1220, 943 + xy: 1937, 1541 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-hotrock-full rotate: false - xy: 1186, 875 + xy: 1903, 1473 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ice-full rotate: false - xy: 1288, 977 + xy: 1937, 1507 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ice-snow-full rotate: false - xy: 1254, 943 + xy: 1937, 1473 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-icerocks-full rotate: false - xy: 1220, 909 + xy: 1971, 1541 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ignarock-full rotate: false - xy: 1288, 943 + xy: 1971, 1507 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-illuminator-full rotate: false - xy: 1254, 909 + xy: 1971, 1473 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 illuminator rotate: false - xy: 1254, 909 + xy: 1971, 1473 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-impact-reactor-full rotate: false - xy: 204, 863 + xy: 163, 773 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 block-incinerator-full rotate: false - xy: 1220, 875 + xy: 1733, 1439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 incinerator rotate: false - xy: 1220, 875 + xy: 1733, 1439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-inverted-sorter-full rotate: false - xy: 1288, 909 + xy: 1767, 1439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 inverted-sorter rotate: false - xy: 1288, 909 + xy: 1767, 1439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-item-source-full rotate: false - xy: 1254, 875 + xy: 1801, 1439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-source rotate: false - xy: 1254, 875 + xy: 1801, 1439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-item-void-full rotate: false - xy: 1288, 875 + xy: 1835, 1439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-void rotate: false - xy: 1288, 875 + xy: 1835, 1439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-javelin-ship-pad-full rotate: false - xy: 987, 391 + xy: 717, 878 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 javelin-ship-pad rotate: false - xy: 987, 391 + xy: 717, 878 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-junction-full rotate: false - xy: 1209, 841 + xy: 1869, 1439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 junction rotate: false - xy: 1209, 841 + xy: 1869, 1439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-kiln-full rotate: false - xy: 987, 325 + xy: 717, 812 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 kiln rotate: false - xy: 987, 325 + xy: 717, 812 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-lancer-full rotate: false - xy: 755, 1611 + xy: 783, 1208 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-laser-drill-full rotate: false - xy: 423, 338 + xy: 395, 450 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-launch-pad-full rotate: false - xy: 423, 240 + xy: 395, 352 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 launch-pad rotate: false - xy: 423, 240 + xy: 395, 352 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-launch-pad-large-full rotate: false - xy: 334, 863 + xy: 163, 643 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 launch-pad-large rotate: false - xy: 334, 863 + xy: 163, 643 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 block-liquid-junction-full rotate: false - xy: 1209, 807 + xy: 1903, 1439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-junction rotate: false - xy: 1209, 807 + xy: 1903, 1439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-router-full rotate: false - xy: 1243, 841 + xy: 1937, 1439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-source-full rotate: false - xy: 1209, 773 + xy: 1971, 1439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-source rotate: false - xy: 1209, 773 + xy: 1971, 1439 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-tank-full rotate: false - xy: 423, 142 + xy: 391, 254 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-liquid-void-full rotate: false - xy: 1277, 841 + xy: 2005, 1557 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-void rotate: false - xy: 1277, 841 + xy: 2005, 1557 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-magmarock-full rotate: false - xy: 1243, 807 + xy: 2005, 1523 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mass-driver-full rotate: false - xy: 423, 44 + xy: 391, 156 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-mechanical-drill-full rotate: false - xy: 821, 1611 + xy: 783, 1142 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-mechanical-pump-full rotate: false - xy: 1209, 739 + xy: 2005, 1489 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mechanical-pump rotate: false - xy: 1209, 739 + xy: 2005, 1489 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-meltdown-full rotate: false - xy: 195, 733 + xy: 163, 513 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 block-melter-full rotate: false - xy: 1277, 807 + xy: 2005, 1455 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 melter rotate: false - xy: 1277, 807 + xy: 2005, 1455 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mend-projector-full rotate: false - xy: 755, 1545 + xy: 783, 1076 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mend-projector rotate: false - xy: 755, 1545 + xy: 783, 1076 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-mender-full rotate: false - xy: 1243, 773 + xy: 2005, 1421 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mender rotate: false - xy: 1243, 773 + xy: 2005, 1421 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-message-full rotate: false - xy: 1209, 705 + xy: 229, 219 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 message rotate: false - xy: 1209, 705 + xy: 229, 219 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-2-full rotate: false - xy: 1277, 773 + xy: 1415, 1187 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-3-full rotate: false - xy: 1243, 739 + xy: 1411, 1153 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-5-full rotate: false - xy: 1209, 671 + xy: 1411, 1119 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-damaged-full rotate: false - xy: 1277, 739 + xy: 1411, 1085 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-full rotate: false - xy: 1243, 705 + xy: 1411, 1051 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-moss-full rotate: false - xy: 1277, 705 + xy: 1411, 983 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-multi-press-full rotate: false - xy: 625, 1143 + xy: 521, 646 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 multi-press rotate: false - xy: 625, 1143 + xy: 521, 646 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-oil-extractor-full rotate: false - xy: 566, 1045 + xy: 521, 548 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-omega-mech-pad-full rotate: false - xy: 566, 947 + xy: 493, 450 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 omega-mech-pad rotate: false - xy: 566, 947 + xy: 493, 450 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-ore-coal-full rotate: false - xy: 1243, 671 + xy: 1411, 949 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-copper-full rotate: false - xy: 1209, 603 + xy: 1411, 915 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-lead-full rotate: false - xy: 1277, 671 + xy: 1411, 881 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-scrap-full rotate: false - xy: 1243, 637 + xy: 1411, 847 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-thorium-full rotate: false - xy: 1209, 569 + xy: 1411, 813 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-titanium-full rotate: false - xy: 1277, 637 + xy: 1411, 779 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-overdrive-projector-full rotate: false - xy: 821, 1545 + xy: 783, 1010 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 overdrive-projector rotate: false - xy: 821, 1545 + xy: 783, 1010 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-overflow-gate-full rotate: false - xy: 1243, 603 + xy: 1411, 745 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 overflow-gate rotate: false - xy: 1243, 603 + xy: 1411, 745 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pebbles-full rotate: false - xy: 1209, 535 + xy: 1411, 711 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phantom-factory-full rotate: false - xy: 747, 1479 + xy: 783, 944 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-phase-conduit-full rotate: false - xy: 1277, 603 + xy: 1411, 677 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conduit rotate: false - xy: 1277, 603 + xy: 1411, 677 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-conveyor-full rotate: false - xy: 1243, 569 + xy: 1411, 643 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor rotate: false - xy: 1243, 569 + xy: 1411, 643 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-wall-full rotate: false - xy: 1209, 501 + xy: 1424, 609 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall rotate: false - xy: 1209, 501 + xy: 1424, 609 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-wall-large-full rotate: false - xy: 813, 1479 + xy: 783, 878 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phase-wall-large rotate: false - xy: 813, 1479 + xy: 783, 878 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-phase-weaver-full rotate: false - xy: 739, 1413 + xy: 783, 812 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-pine-full rotate: false - xy: 1549, 1381 + xy: 689, 440 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-plastanium-compressor-full rotate: false - xy: 805, 1413 + xy: 651, 738 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 plastanium-compressor rotate: false - xy: 805, 1413 + xy: 651, 738 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-plastanium-wall-full rotate: false - xy: 1277, 569 + xy: 1424, 575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plastanium-wall rotate: false - xy: 1277, 569 + xy: 1424, 575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-plastanium-wall-large-full rotate: false - xy: 673, 1351 + xy: 717, 746 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 plastanium-wall-large rotate: false - xy: 673, 1351 + xy: 717, 746 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-plated-conduit-full rotate: false - xy: 1243, 535 + xy: 739, 314 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pneumatic-drill-full rotate: false - xy: 673, 1285 + xy: 783, 746 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-power-node-full rotate: false - xy: 1209, 467 + xy: 735, 280 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-node rotate: false - xy: 1209, 467 + xy: 735, 280 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-power-node-large-full rotate: false - xy: 739, 1347 + xy: 619, 672 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 power-node-large rotate: false - xy: 739, 1347 + xy: 619, 672 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-power-source-full rotate: false - xy: 1277, 535 + xy: 735, 246 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-power-void-full rotate: false - xy: 1243, 501 + xy: 735, 212 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-void rotate: false - xy: 1243, 501 + xy: 735, 212 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pulse-conduit-full rotate: false - xy: 1277, 501 + xy: 873, 296 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pulverizer-full rotate: false - xy: 1243, 467 + xy: 907, 298 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pyratite-mixer-full rotate: false - xy: 805, 1347 + xy: 619, 606 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pyratite-mixer rotate: false - xy: 805, 1347 + xy: 619, 606 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-repair-point-full rotate: false - xy: 1277, 467 + xy: 941, 298 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-revenant-factory-full rotate: false - xy: 325, 733 + xy: 163, 383 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 block-ripple-full rotate: false - xy: 664, 1045 + xy: 493, 352 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-rock-full rotate: false - xy: 1599, 1381 + xy: 1656, 1613 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-rocks-full rotate: false - xy: 1251, 433 + xy: 975, 298 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-rotary-pump-full rotate: false - xy: 739, 1281 + xy: 685, 672 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 rotary-pump rotate: false - xy: 739, 1281 + xy: 685, 672 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-router-full rotate: false - xy: 1251, 399 + xy: 1649, 1411 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 router rotate: false - xy: 1251, 399 + xy: 1649, 1411 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-rtg-generator-full rotate: false - xy: 805, 1281 + xy: 685, 606 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 rtg-generator rotate: false - xy: 805, 1281 + xy: 685, 606 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-salt-full rotate: false - xy: 1251, 365 + xy: 1683, 1411 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-saltrocks-full rotate: false - xy: 1251, 331 + xy: 1717, 1405 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-salvo-full rotate: false - xy: 987, 259 + xy: 751, 680 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-sand-boulder-full rotate: false - xy: 1251, 297 + xy: 1751, 1405 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sand-full rotate: false - xy: 1285, 433 + xy: 1785, 1405 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sand-water-full rotate: false - xy: 1285, 399 + xy: 1819, 1405 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sandrocks-full rotate: false - xy: 1285, 365 + xy: 1853, 1405 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scatter-full rotate: false - xy: 979, 193 + xy: 751, 614 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-scorch-full rotate: false - xy: 1285, 331 + xy: 1887, 1405 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-full rotate: false - xy: 1285, 297 + xy: 1921, 1405 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall1 rotate: false - xy: 1285, 297 + xy: 1921, 1405 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-gigantic-full rotate: false - xy: 163, 603 + xy: 848, 1757 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 scrap-wall-gigantic rotate: false - xy: 163, 603 + xy: 848, 1757 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 block-scrap-wall-huge-full rotate: false - xy: 664, 947 + xy: 489, 254 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 scrap-wall-huge1 rotate: false - xy: 664, 947 + xy: 489, 254 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-scrap-wall-large-full rotate: false - xy: 979, 127 + xy: 817, 680 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-separator-full rotate: false - xy: 979, 61 + xy: 817, 614 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 separator rotate: false - xy: 979, 61 + xy: 817, 614 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-shale-boulder-full rotate: false - xy: 1311, 807 + xy: 1607, 1403 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shale-full rotate: false - xy: 1311, 773 + xy: 1601, 1369 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shalerocks-full rotate: false - xy: 1311, 739 + xy: 1212, 547 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shock-mine-full rotate: false - xy: 1311, 705 + xy: 1246, 547 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shrubs-full rotate: false - xy: 1311, 671 + xy: 1280, 551 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-silicon-smelter-full rotate: false - xy: 723, 1215 + xy: 849, 1210 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 silicon-smelter rotate: false - xy: 723, 1215 + xy: 849, 1210 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-slag-full rotate: false - xy: 1311, 637 + xy: 1314, 551 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snow-full rotate: false - xy: 1311, 603 + xy: 1635, 1369 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snow-pine-full rotate: false - xy: 1649, 1381 + xy: 689, 390 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-snowrock-full rotate: false - xy: 1699, 1381 + xy: 1706, 1613 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-snowrocks-full rotate: false - xy: 1311, 569 + xy: 1669, 1377 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-solar-panel-full rotate: false - xy: 1311, 535 + xy: 1703, 1371 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel rotate: false - xy: 1311, 535 + xy: 1703, 1371 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-solar-panel-large-full rotate: false - xy: 1449, 1431 + xy: 489, 156 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 solar-panel-large rotate: false - xy: 1449, 1431 + xy: 489, 156 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-sorter-full rotate: false - xy: 1311, 501 + xy: 1737, 1371 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sorter rotate: false - xy: 1311, 501 + xy: 1737, 1371 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-spawn-full rotate: false - xy: 1311, 467 + xy: 1771, 1371 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-spectre-full rotate: false - xy: 163, 473 + xy: 978, 1757 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 block-spirit-factory-full rotate: false - xy: 723, 1149 + xy: 849, 1144 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-spore-cluster-full rotate: false - xy: 887, 1635 + xy: 75, 1 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-spore-moss-full rotate: false - xy: 1319, 433 + xy: 1805, 1371 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-spore-pine-full rotate: false - xy: 1749, 1381 + xy: 1498, 1555 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-spore-press-full rotate: false - xy: 789, 1215 + xy: 849, 1078 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-sporerocks-full rotate: false - xy: 1319, 399 + xy: 1839, 1371 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-stone-full rotate: false - xy: 1319, 365 + xy: 1873, 1371 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-surge-tower-full rotate: false - xy: 789, 1149 + xy: 849, 1012 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 surge-tower rotate: false - xy: 789, 1149 + xy: 849, 1012 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-surge-wall-full rotate: false - xy: 1319, 331 + xy: 1907, 1371 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 surge-wall rotate: false - xy: 1319, 331 + xy: 1907, 1371 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-surge-wall-large-full rotate: false - xy: 762, 1083 + xy: 849, 946 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 surge-wall-large rotate: false - xy: 762, 1083 + xy: 849, 946 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-swarmer-full rotate: false - xy: 762, 1017 + xy: 849, 880 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-tainted-water-full rotate: false - xy: 1319, 297 + xy: 1941, 1371 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-tar-full rotate: false - xy: 1975, 1147 + xy: 1669, 1343 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-tau-mech-pad-full rotate: false - xy: 762, 951 + xy: 849, 814 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 tau-mech-pad rotate: false - xy: 762, 951 + xy: 849, 814 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-tendrils-full rotate: false - xy: 2009, 1147 + xy: 1703, 1337 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-thermal-generator-full rotate: false - xy: 828, 1083 + xy: 849, 748 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thermal-generator rotate: false - xy: 828, 1083 + xy: 849, 748 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-thermal-pump-full rotate: false - xy: 1547, 1431 + xy: 591, 450 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 thermal-pump rotate: false - xy: 1547, 1431 + xy: 591, 450 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-thorium-reactor-full rotate: false - xy: 1645, 1431 + xy: 591, 352 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 thorium-reactor rotate: false - xy: 1645, 1431 + xy: 591, 352 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-thorium-wall-full rotate: false - xy: 1725, 1155 + xy: 1737, 1337 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium-wall rotate: false - xy: 1725, 1155 + xy: 1737, 1337 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-thorium-wall-large-full rotate: false - xy: 828, 1017 + xy: 881, 1276 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thorium-wall-large rotate: false - xy: 828, 1017 + xy: 881, 1276 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-thruster-full rotate: false - xy: 293, 603 + xy: 1108, 1757 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 thruster rotate: false - xy: 293, 603 + xy: 1108, 1757 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 block-titan-factory-full rotate: false - xy: 1743, 1431 + xy: 587, 254 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-titanium-conveyor-full rotate: false - xy: 1759, 1147 + xy: 1771, 1337 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-conveyor-0-0 rotate: false - xy: 1759, 1147 + xy: 1771, 1337 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-titanium-wall-full rotate: false - xy: 1793, 1147 + xy: 1805, 1337 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-wall rotate: false - xy: 1793, 1147 + xy: 1805, 1337 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-titanium-wall-large-full rotate: false - xy: 828, 951 + xy: 947, 1299 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 titanium-wall-large rotate: false - xy: 828, 951 + xy: 947, 1299 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-trident-ship-pad-full rotate: false - xy: 856, 885 + xy: 1013, 1299 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 trident-ship-pad rotate: false - xy: 856, 885 + xy: 1013, 1299 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-turbine-generator-full rotate: false - xy: 855, 1215 + xy: 1079, 1299 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 turbine-generator rotate: false - xy: 855, 1215 + xy: 1079, 1299 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 +block-underflow-gate-full + rotate: false + xy: 1839, 1337 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 block-unloader-full rotate: false - xy: 1827, 1147 + xy: 1873, 1337 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 unloader rotate: false - xy: 1827, 1147 + xy: 1873, 1337 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-vault-full rotate: false - xy: 1841, 1431 + xy: 587, 156 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 vault rotate: false - xy: 1841, 1431 + xy: 587, 156 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 block-water-extractor-full rotate: false - xy: 855, 1149 + xy: 1145, 1299 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-water-full rotate: false - xy: 1861, 1139 + xy: 1907, 1337 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-wave-full rotate: false - xy: 894, 1083 + xy: 1211, 1299 size: 64, 64 orig: 64, 64 offset: 0, 0 @@ -3968,1652 +3849,1533 @@ block-white-tree-full index: -1 block-wraith-factory-full rotate: false - xy: 894, 1017 + xy: 1277, 1299 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-1-0 rotate: false - xy: 1390, 937 + xy: 1445, 813 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-1 rotate: false - xy: 1390, 903 + xy: 1445, 779 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-2 rotate: false - xy: 1390, 869 + xy: 1445, 745 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-3 rotate: false - xy: 1379, 835 + xy: 1445, 711 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-4 rotate: false - xy: 1379, 801 + xy: 1445, 677 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-5 rotate: false - xy: 1379, 767 + xy: 1445, 643 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-6 rotate: false - xy: 1379, 733 + xy: 1458, 609 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-1-7 rotate: false - xy: 1379, 699 + xy: 1458, 575 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 cracks-2-0 rotate: false - xy: 894, 951 + xy: 915, 1210 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-1 rotate: false - xy: 922, 885 + xy: 915, 1144 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-2 rotate: false - xy: 1045, 193 + xy: 915, 1078 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-3 rotate: false - xy: 1045, 127 + xy: 915, 1012 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-4 rotate: false - xy: 1045, 61 + xy: 915, 946 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-5 rotate: false - xy: 879, 1479 + xy: 915, 880 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-6 rotate: false - xy: 871, 1413 + xy: 915, 814 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-2-7 rotate: false - xy: 871, 1347 + xy: 915, 748 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cracks-3-0 rotate: false - xy: 521, 632 + xy: 131, 129 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-1 rotate: false - xy: 521, 534 + xy: 131, 31 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-2 rotate: false - xy: 521, 436 + xy: 229, 119 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-3 rotate: false - xy: 521, 338 + xy: 229, 21 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-4 rotate: false - xy: 521, 240 + xy: 327, 58 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-5 rotate: false - xy: 521, 142 + xy: 425, 58 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-6 rotate: false - xy: 521, 44 + xy: 523, 58 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-3-7 rotate: false - xy: 553, 730 + xy: 621, 58 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 cracks-4-0 rotate: false - xy: 293, 343 + xy: 1628, 1793 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-1 rotate: false - xy: 293, 213 + xy: 1758, 1789 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-2 rotate: false - xy: 163, 83 + xy: 1888, 1789 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-3 rotate: false - xy: 293, 83 + xy: 1498, 1663 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-4 rotate: false - xy: 1066, 1757 + xy: 1628, 1663 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-5 rotate: false - xy: 1196, 1757 + xy: 1758, 1659 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-6 rotate: false - xy: 1326, 1757 + xy: 1888, 1659 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-4-7 rotate: false - xy: 1456, 1757 + xy: 163, 253 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 cracks-5-0 rotate: false - xy: 1, 588 + xy: 848, 1887 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-1 rotate: false - xy: 1228, 1887 + xy: 1, 839 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-2 rotate: false - xy: 1, 426 + xy: 1010, 1887 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-3 rotate: false - xy: 1390, 1887 + xy: 1, 677 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-4 rotate: false - xy: 1, 264 + xy: 1172, 1887 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-5 rotate: false - xy: 1552, 1887 + xy: 1, 515 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-6 rotate: false - xy: 1, 102 + xy: 1334, 1887 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cracks-5-7 rotate: false - xy: 1714, 1887 + xy: 1, 353 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 cyclone rotate: false - xy: 562, 828 + xy: 583, 1438 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 duo rotate: false - xy: 1379, 597 + xy: 769, 212 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 fuse rotate: false - xy: 619, 46 + xy: 950, 1561 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 hail rotate: false - xy: 1379, 563 + xy: 803, 288 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-blast-compound-large rotate: false - xy: 887, 1551 + xy: 1690, 1571 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-blast-compound-medium rotate: false - xy: 1465, 1189 + xy: 837, 254 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-blast-compound-small rotate: false - xy: 1499, 1197 + xy: 583, 1412 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-blast-compound-tiny rotate: false - xy: 797, 26 + xy: 1985, 1319 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-blast-compound-xlarge rotate: false - xy: 1999, 1331 + xy: 739, 498 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-coal-large rotate: false - xy: 607, 1375 + xy: 1565, 1513 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-coal-medium rotate: false - xy: 1465, 1155 + xy: 871, 262 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-coal-small rotate: false - xy: 873, 1 + xy: 155, 227 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-coal-tiny rotate: false - xy: 797, 8 + xy: 735, 194 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-coal-xlarge rotate: false - xy: 1849, 1281 + xy: 739, 448 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-copper-large rotate: false - xy: 673, 1243 + xy: 1565, 1471 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-copper-medium rotate: false - xy: 1464, 1121 + xy: 753, 178 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-copper-small rotate: false - xy: 1499, 1171 + xy: 181, 227 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-copper-tiny rotate: false - xy: 204, 1129 + xy: 583, 1394 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-copper-xlarge rotate: false - xy: 1899, 1273 + xy: 739, 398 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-graphite-large rotate: false - xy: 945, 752 + xy: 1607, 1521 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-graphite-medium rotate: false - xy: 1430, 1053 + xy: 753, 110 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-graphite-small rotate: false - xy: 259, 1379 + xy: 1934, 1925 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-graphite-tiny rotate: false - xy: 566, 929 + xy: 852, 1543 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-graphite-xlarge rotate: false - xy: 1949, 1281 + xy: 739, 348 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-lead-large rotate: false - xy: 1011, 1544 + xy: 1607, 1479 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-lead-medium rotate: false - xy: 1430, 1019 + xy: 787, 178 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-lead-small rotate: false - xy: 960, 966 + xy: 395, 588 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-lead-tiny rotate: false - xy: 660, 831 + xy: 877, 1445 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-lead-xlarge rotate: false - xy: 1999, 1281 + xy: 677, 8 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-metaglass-large rotate: false - xy: 1069, 1257 + xy: 1649, 1529 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-metaglass-medium rotate: false - xy: 1430, 985 + xy: 787, 110 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-metaglass-small rotate: false - xy: 1237, 1273 + xy: 219, 1164 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-metaglass-tiny rotate: false - xy: 749, 733 + xy: 903, 1347 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-metaglass-xlarge rotate: false - xy: 1325, 1315 + xy: 785, 564 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-phase-fabric-large rotate: false - xy: 1725, 1189 + xy: 1649, 1487 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-phase-fabric-medium rotate: false - xy: 1464, 985 + xy: 821, 186 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-phase-fabric-small rotate: false - xy: 901, 1820 + xy: 553, 748 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-phase-fabric-tiny rotate: false - xy: 623, 1709 + xy: 947, 1281 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-phase-fabric-xlarge rotate: false - xy: 1375, 1297 + xy: 835, 564 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-plastanium-large rotate: false - xy: 1011, 1502 + xy: 1691, 1529 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-plastanium-medium rotate: false - xy: 1464, 951 + xy: 821, 118 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-plastanium-small rotate: false - xy: 1251, 271 + xy: 263, 227 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-plastanium-tiny rotate: false - xy: 1425, 1329 + xy: 981, 753 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-plastanium-xlarge rotate: false - xy: 1325, 1265 + xy: 885, 566 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-pyratite-large rotate: false - xy: 1111, 1257 + xy: 1691, 1487 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-pyratite-medium rotate: false - xy: 1424, 883 + xy: 855, 186 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-pyratite-small rotate: false - xy: 1523, 279 + xy: 719, 62 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-pyratite-tiny rotate: false - xy: 1825, 1305 + xy: 1, 5 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-pyratite-xlarge rotate: false - xy: 1375, 1247 + xy: 935, 566 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-sand-large rotate: false - xy: 1011, 1460 + xy: 1459, 1313 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-sand-medium rotate: false - xy: 1458, 883 + xy: 855, 118 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-sand-small rotate: false - xy: 285, 1379 + xy: 1181, 548 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-sand-tiny rotate: false - xy: 649, 1399 + xy: 1435, 1313 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-sand-xlarge rotate: false - xy: 1425, 1273 + xy: 789, 514 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-scrap-large rotate: false - xy: 1153, 1257 + xy: 1501, 1313 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-scrap-medium rotate: false - xy: 1458, 849 + xy: 821, 50 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-scrap-small rotate: false - xy: 1277, 271 + xy: 985, 590 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-scrap-tiny rotate: false - xy: 987, 776 + xy: 1435, 1295 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-scrap-xlarge rotate: false - xy: 1425, 1223 + xy: 789, 464 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-silicon-large rotate: false - xy: 1195, 1257 + xy: 789, 322 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-silicon-medium rotate: false - xy: 1413, 781 + xy: 889, 194 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-silicon-small rotate: false - xy: 1549, 279 + xy: 1043, 309 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-silicon-tiny rotate: false - xy: 924, 867 + xy: 1645, 1351 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-silicon-xlarge rotate: false - xy: 1475, 1273 + xy: 789, 414 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-spore-pod-large rotate: false - xy: 1119, 1215 + xy: 831, 322 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-spore-pod-medium rotate: false - xy: 1413, 747 + xy: 889, 126 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-spore-pod-small rotate: false - xy: 1303, 271 + xy: 1960, 1925 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-spore-pod-tiny rotate: false - xy: 924, 849 + xy: 2019, 1301 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-spore-pod-xlarge rotate: false - xy: 1475, 1223 + xy: 789, 364 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-surge-alloy-large rotate: false - xy: 1161, 1215 + xy: 1565, 1429 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-surge-alloy-medium rotate: false - xy: 1413, 713 + xy: 889, 58 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-surge-alloy-small rotate: false - xy: 1301, 245 + xy: 395, 562 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-surge-alloy-tiny rotate: false - xy: 1119, 1197 + xy: 1125, 555 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-surge-alloy-xlarge rotate: false - xy: 1525, 1281 + xy: 839, 514 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-thorium-large rotate: false - xy: 99, 2 + xy: 1607, 1437 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-thorium-medium rotate: false - xy: 1413, 679 + xy: 1280, 517 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-thorium-small rotate: false - xy: 1301, 219 + xy: 245, 1164 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-thorium-tiny rotate: false - xy: 1158, 993 + xy: 207, 235 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-thorium-xlarge rotate: false - xy: 1525, 1231 + xy: 839, 464 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 item-titanium-large rotate: false - xy: 1203, 1215 + xy: 1649, 1445 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 item-titanium-medium rotate: false - xy: 1413, 645 + xy: 1348, 547 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-titanium-small rotate: false - xy: 1301, 193 + xy: 579, 748 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 item-titanium-tiny rotate: false - xy: 2025, 1263 + xy: 271, 1172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 item-titanium-xlarge rotate: false - xy: 1575, 1281 + xy: 839, 414 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 lancer rotate: false - xy: 1077, 794 + xy: 1179, 1101 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 liquid-cryofluid-large rotate: false - xy: 1767, 1181 + xy: 1691, 1445 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 liquid-cryofluid-medium rotate: false - xy: 1413, 611 + xy: 1348, 513 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-cryofluid-small rotate: false - xy: 1301, 167 + xy: 1069, 309 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 liquid-cryofluid-tiny rotate: false - xy: 1387, 477 + xy: 1069, 291 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 liquid-cryofluid-xlarge rotate: false - xy: 1675, 1281 + xy: 889, 416 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 liquid-oil-large rotate: false - xy: 1245, 1215 + xy: 1559, 1387 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 liquid-oil-medium rotate: false - xy: 1413, 577 + xy: 1416, 541 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-oil-small rotate: false - xy: 1301, 141 + xy: 1043, 283 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 liquid-oil-tiny rotate: false - xy: 1329, 279 + xy: 2012, 1933 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 liquid-oil-xlarge rotate: false - xy: 1675, 1231 + xy: 889, 366 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 liquid-slag-large rotate: false - xy: 1287, 1215 + xy: 1559, 1345 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 liquid-slag-medium rotate: false - xy: 1413, 475 + xy: 941, 264 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-slag-small rotate: false - xy: 1301, 115 + xy: 1986, 1925 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 liquid-slag-tiny rotate: false - xy: 1301, 71 + xy: 631, 756 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 liquid-slag-xlarge rotate: false - xy: 1725, 1281 + xy: 939, 516 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 liquid-water-large rotate: false - xy: 1329, 1223 + xy: 1393, 1289 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 liquid-water-medium rotate: false - xy: 1481, 815 + xy: 905, 230 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-water-small rotate: false - xy: 1301, 89 + xy: 605, 748 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 liquid-water-tiny rotate: false - xy: 222, 1129 + xy: 631, 738 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 liquid-water-xlarge rotate: false - xy: 1725, 1231 + xy: 939, 466 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 mass-driver rotate: false - xy: 1939, 1529 + xy: 707, 1340 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 -mech-alpha-mech-full - rotate: false - xy: 1775, 1273 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -mech-dart-ship-full - rotate: false - xy: 1775, 1223 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -mech-delta-mech-full - rotate: false - xy: 1825, 1231 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -mech-glaive-ship-full - rotate: false - xy: 1969, 1631 - size: 56, 56 - orig: 56, 56 - offset: 0, 0 - index: -1 -mech-javelin-ship-full - rotate: false - xy: 1875, 1223 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -mech-omega-mech-full - rotate: false - xy: 1243, 70 - size: 56, 56 - orig: 56, 56 - offset: 0, 0 - index: -1 -mech-tau-mech-full - rotate: false - xy: 1267, 1307 - size: 56, 56 - orig: 56, 56 - offset: 0, 0 - index: -1 -mech-trident-ship-full - rotate: false - xy: 157, 25 - size: 56, 56 - orig: 56, 56 - offset: 0, 0 - index: -1 meltdown rotate: false - xy: 1449, 1627 + xy: 423, 1004 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 repair-point rotate: false - xy: 1387, 305 + xy: 1025, 60 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ripple rotate: false - xy: 815, 359 + xy: 1367, 1463 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 salvo rotate: false - xy: 1003, 1322 + xy: 1179, 837 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scatter rotate: false - xy: 1092, 1058 + xy: 1245, 771 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scorch rotate: false - xy: 1421, 305 + xy: 989, 539 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spectre rotate: false - xy: 1189, 1497 + xy: 423, 744 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 swarmer rotate: false - xy: 1177, 134 + xy: 1311, 1035 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 -unit-chaos-array-full - rotate: false - xy: 1319, 1497 - size: 128, 128 - orig: 128, 128 - offset: 0, 0 - index: -1 -unit-crawler-full - rotate: false - xy: 1575, 1181 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 unit-dagger-full rotate: false - xy: 1625, 1181 + xy: 1515, 1455 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -unit-eradicator-full +unit-vanguard-full rotate: false - xy: 259, 1123 - size: 152, 124 - orig: 152, 124 - offset: 0, 0 - index: -1 -unit-eruptor-full - rotate: false - xy: 1135, 1431 - size: 64, 64 - orig: 64, 64 - offset: 0, 0 - index: -1 -unit-fortress-full - rotate: false - xy: 1069, 1299 - size: 64, 64 - orig: 64, 64 - offset: 0, 0 - index: -1 -unit-titan-full - rotate: false - xy: 1135, 1365 - size: 64, 64 - orig: 64, 64 + xy: 1509, 1405 + size: 48, 48 + orig: 48, 48 offset: 0, 0 index: -1 wave rotate: false - xy: 1267, 1365 + xy: 1345, 639 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 item-blast-compound rotate: false - xy: 1431, 1189 + xy: 803, 220 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-coal rotate: false - xy: 1431, 1155 + xy: 837, 220 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-copper rotate: false - xy: 1430, 1121 + xy: 871, 228 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-graphite rotate: false - xy: 1430, 1087 + xy: 753, 144 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-lead rotate: false - xy: 1464, 1087 + xy: 753, 76 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-metaglass rotate: false - xy: 1464, 1053 + xy: 787, 144 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-phase-fabric rotate: false - xy: 1464, 1019 + xy: 787, 76 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-plastanium rotate: false - xy: 1430, 951 + xy: 821, 152 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-pyratite rotate: false - xy: 1424, 917 + xy: 821, 84 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-sand rotate: false - xy: 1458, 917 + xy: 855, 152 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-scrap rotate: false - xy: 1424, 849 + xy: 855, 84 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-silicon rotate: false - xy: 1413, 815 + xy: 855, 50 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-spore-pod rotate: false - xy: 1447, 815 + xy: 889, 160 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-surge-alloy rotate: false - xy: 1447, 781 + xy: 889, 92 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-thorium rotate: false - xy: 1447, 747 + xy: 889, 24 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-titanium rotate: false - xy: 1447, 713 + xy: 1314, 517 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-cryofluid rotate: false - xy: 1447, 679 + xy: 1382, 547 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-oil rotate: false - xy: 1447, 645 + xy: 1382, 513 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-slag rotate: false - xy: 1447, 509 + xy: 907, 264 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-water rotate: false - xy: 1447, 475 + xy: 975, 264 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -alpha-mech - rotate: false - xy: 1399, 1447 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -alpha-mech-base - rotate: false - xy: 1261, 20 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -alpha-mech-leg - rotate: false - xy: 1399, 1397 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -delta-mech - rotate: false - xy: 1549, 1331 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -delta-mech-base - rotate: false - xy: 1599, 1331 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -delta-mech-leg - rotate: false - xy: 1649, 1331 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -omega-mech - rotate: false - xy: 215, 25 - size: 56, 56 - orig: 56, 56 - offset: 0, 0 - index: -1 -omega-mech-armor - rotate: false - xy: 1011, 530 - size: 64, 64 - orig: 64, 64 - offset: 0, 0 - index: -1 -omega-mech-base - rotate: false - xy: 273, 25 - size: 56, 56 - orig: 56, 56 - offset: 0, 0 - index: -1 -omega-mech-leg - rotate: false - xy: 331, 25 - size: 56, 56 - orig: 56, 56 - offset: 0, 0 - index: -1 -tau-mech - rotate: false - xy: 1037, 3 - size: 56, 56 - orig: 56, 56 - offset: 0, 0 - index: -1 -tau-mech-base - rotate: false - xy: 1975, 1181 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -tau-mech-leg - rotate: false - xy: 1525, 1181 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -dart-ship - rotate: false - xy: 1499, 1331 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -glaive-ship - rotate: false - xy: 99, 44 - size: 56, 56 - orig: 56, 56 - offset: 0, 0 - index: -1 -javelin-ship - rotate: false - xy: 1575, 1231 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -javelin-ship-shield - rotate: false - xy: 1625, 1281 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -trident-ship - rotate: false - xy: 1095, 3 - size: 56, 56 - orig: 56, 56 - offset: 0, 0 - index: -1 blank rotate: false - xy: 423, 730 + xy: 327, 156 size: 1, 1 orig: 1, 1 offset: 0, 0 index: -1 circle rotate: false - xy: 1, 944 + xy: 323, 1524 size: 201, 201 orig: 201, 201 offset: 0, 0 index: -1 shape-3 rotate: false - xy: 1333, 1366 + xy: 1147, 574 size: 63, 63 orig: 63, 63 offset: 0, 0 index: -1 +alpha + rotate: false + xy: 1343, 1315 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +alpha-base + rotate: false + xy: 1556, 1613 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +alpha-leg + rotate: false + xy: 1324, 589 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 chaos-array rotate: false - xy: 163, 343 + xy: 1238, 1757 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 chaos-array-base rotate: false - xy: 293, 473 + xy: 1368, 1757 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 chaos-array-leg rotate: false - xy: 163, 213 + xy: 1498, 1793 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 crawler rotate: false - xy: 1899, 1381 + xy: 1856, 1609 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 crawler-base rotate: false - xy: 1949, 1381 + xy: 1906, 1609 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 crawler-leg rotate: false - xy: 1999, 1381 + xy: 1956, 1609 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dagger rotate: false - xy: 1398, 1347 + xy: 689, 340 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dagger-base rotate: false - xy: 1448, 1323 + xy: 685, 290 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 dagger-leg rotate: false - xy: 1267, 1257 + xy: 685, 240 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +dart + rotate: false + xy: 685, 190 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +delta + rotate: false + xy: 327, 8 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +delta-base + rotate: false + xy: 377, 8 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +delta-leg + rotate: false + xy: 427, 8 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 draug rotate: false - xy: 1699, 1331 + xy: 477, 8 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 eradicator rotate: false - xy: 323, 1375 + xy: 1496, 1923 size: 152, 124 orig: 152, 124 offset: 0, 0 index: -1 eradicator-base rotate: false - xy: 645, 1681 + xy: 1, 227 size: 152, 124 orig: 152, 124 offset: 0, 0 index: -1 eradicator-leg rotate: false - xy: 259, 1249 + xy: 1650, 1923 size: 152, 124 orig: 152, 124 offset: 0, 0 index: -1 eruptor rotate: false - xy: 1026, 1058 + xy: 981, 969 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 eruptor-base rotate: false - xy: 1026, 992 + xy: 1047, 1035 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 eruptor-leg rotate: false - xy: 988, 926 + xy: 1113, 1101 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 fortress rotate: false - xy: 988, 860 + xy: 1179, 1167 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 fortress-base rotate: false - xy: 1054, 926 + xy: 1245, 1233 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 titan-base rotate: false - xy: 1054, 926 + xy: 1245, 1233 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 fortress-leg rotate: false - xy: 1054, 860 + xy: 981, 903 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 ghoul rotate: false - xy: 549, 1653 + xy: 219, 1190 size: 72, 72 orig: 72, 72 offset: 0, 0 index: -1 +glaive + rotate: false + xy: 619, 548 + size: 56, 56 + orig: 56, 56 + offset: 0, 0 + index: -1 +javelin + rotate: false + xy: 839, 364 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +javelin-shield + rotate: false + xy: 889, 516 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 lich rotate: false - xy: 645, 1807 + xy: 1, 1163 size: 216, 240 orig: 216, 240 offset: 0, 0 index: -1 +omega + rotate: false + xy: 1440, 1561 + size: 56, 56 + orig: 56, 56 + offset: 0, 0 + index: -1 +omega-armor + rotate: false + xy: 1245, 1101 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +omega-base + rotate: false + xy: 677, 548 + size: 56, 56 + orig: 56, 56 + offset: 0, 0 + index: -1 +omega-leg + rotate: false + xy: 327, 159 + size: 56, 56 + orig: 56, 56 + offset: 0, 0 + index: -1 phantom rotate: false - xy: 815, 7 + xy: 526, 1539 size: 56, 56 orig: 56, 56 offset: 0, 0 index: -1 power-cell rotate: false - xy: 979, 3 + xy: 1212, 581 size: 56, 56 orig: 56, 56 offset: 0, 0 @@ -5627,153 +5389,481 @@ reaper index: -1 revenant rotate: false - xy: 413, 1127 + xy: 645, 1732 size: 112, 112 orig: 112, 112 offset: 0, 0 index: -1 spirit rotate: false - xy: 1875, 1173 + xy: 1465, 1455 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +tau + rotate: false + xy: 1498, 1605 + size: 56, 56 + orig: 56, 56 + offset: 0, 0 + index: -1 +tau-base + rotate: false + xy: 1459, 1355 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +tau-leg + rotate: false + xy: 1515, 1505 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 titan rotate: false - xy: 1177, 68 + xy: 1311, 969 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 titan-leg rotate: false - xy: 1069, 1431 + xy: 1311, 903 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 +trident + rotate: false + xy: 584, 1539 + size: 56, 56 + orig: 56, 56 + offset: 0, 0 + index: -1 +vanguard + rotate: false + xy: 1509, 1355 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 wraith rotate: false - xy: 1675, 1181 + xy: 1598, 1563 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 artillery-equip rotate: false - xy: 1449, 1373 + xy: 689, 490 size: 48, 56 orig: 48, 56 offset: 0, 0 index: -1 blaster-equip rotate: false - xy: 1499, 1381 + xy: 1606, 1613 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 bomber-equip rotate: false - xy: 1799, 1381 + xy: 1756, 1609 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 missiles-equip rotate: false - xy: 1799, 1381 + xy: 1756, 1609 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 chain-blaster-equip rotate: false - xy: 1849, 1381 + xy: 1806, 1609 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 chaos-equip rotate: false - xy: 1243, 128 + xy: 1440, 1619 size: 56, 136 orig: 56, 136 offset: 0, 0 index: -1 eradication-equip rotate: false - xy: 619, 438 + xy: 754, 1538 size: 96, 192 orig: 96, 192 offset: 0, 0 index: -1 eruption-equip rotate: false - xy: 1799, 1323 + xy: 1374, 581 size: 48, 56 orig: 48, 56 offset: 0, 0 index: -1 flakgun-equip rotate: false - xy: 1849, 1331 + xy: 577, 8 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 flamethrower-equip rotate: false - xy: 1899, 1323 + xy: 735, 548 size: 48, 56 orig: 48, 56 offset: 0, 0 index: -1 heal-blaster-equip rotate: false - xy: 1949, 1331 + xy: 627, 8 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 lich-missiles-equip rotate: false - xy: 1625, 1231 + xy: 889, 466 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 reaper-gun-equip rotate: false - xy: 1925, 1223 + xy: 939, 416 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 revenant-missiles-equip rotate: false - xy: 1975, 1231 + xy: 939, 366 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 shockgun-equip rotate: false - xy: 1825, 1181 + xy: 1465, 1505 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 swarmer-equip rotate: false - xy: 1925, 1173 + xy: 1459, 1405 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +vanguard-blaster-equip + rotate: false + xy: 1548, 1555 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 sprites2.png +size: 2048,1024 +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +rubble-1-0 + rotate: false + xy: 1933, 723 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +rubble-1-1 + rotate: false + xy: 839, 363 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +rubble-2-0 + rotate: false + xy: 1335, 191 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +rubble-2-1 + rotate: false + xy: 1401, 191 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 +rubble-3-0 + rotate: false + xy: 1237, 189 + size: 96, 96 + orig: 96, 96 + offset: 0, 0 + index: -1 +rubble-4-0 + rotate: false + xy: 1827, 115 + size: 128, 128 + orig: 128, 128 + offset: 0, 0 + index: -1 +rubble-5-0 + rotate: false + xy: 1887, 387 + size: 160, 160 + orig: 160, 160 + offset: 0, 0 + index: -1 +rubble-6-0 + rotate: false + xy: 1043, 33 + size: 192, 192 + orig: 192, 192 + offset: 0, 0 + index: -1 +rubble-7-0 + rotate: false + xy: 817, 1 + size: 224, 224 + orig: 224, 224 + offset: 0, 0 + index: -1 +rubble-8-0 + rotate: false + xy: 1611, 463 + size: 256, 256 + orig: 256, 256 + offset: 0, 0 + index: -1 +scorch-0-0 + rotate: false + xy: 675, 347 + size: 80, 80 + orig: 80, 80 + offset: 0, 0 + index: -1 +scorch-0-1 + rotate: false + xy: 757, 347 + size: 80, 80 + orig: 80, 80 + offset: 0, 0 + index: -1 +scorch-0-2 + rotate: false + xy: 1957, 163 + size: 80, 80 + orig: 80, 80 + offset: 0, 0 + index: -1 +scorch-1-0 + rotate: false + xy: 1933, 901 + size: 110, 110 + orig: 110, 110 + offset: 0, 0 + index: -1 +scorch-1-1 + rotate: false + xy: 1933, 789 + size: 110, 110 + orig: 110, 110 + offset: 0, 0 + index: -1 +scorch-1-2 + rotate: false + xy: 1237, 33 + size: 110, 110 + orig: 110, 110 + offset: 0, 0 + index: -1 +scorch-2-0 + rotate: false + xy: 1887, 245 + size: 140, 140 + orig: 140, 140 + offset: 0, 0 + index: -1 +scorch-2-1 + rotate: false + xy: 1543, 145 + size: 140, 140 + orig: 140, 140 + offset: 0, 0 + index: -1 +scorch-2-2 + rotate: false + xy: 1685, 145 + size: 140, 140 + orig: 140, 140 + offset: 0, 0 + index: -1 +scorch-3-0 + rotate: false + xy: 1543, 287 + size: 170, 170 + orig: 170, 170 + offset: 0, 0 + index: -1 +scorch-3-1 + rotate: false + xy: 1715, 291 + size: 170, 170 + orig: 170, 170 + offset: 0, 0 + index: -1 +scorch-3-2 + rotate: false + xy: 1869, 549 + size: 170, 170 + orig: 170, 170 + offset: 0, 0 + index: -1 +scorch-4-0 + rotate: false + xy: 1139, 489 + size: 200, 200 + orig: 200, 200 + offset: 0, 0 + index: -1 +scorch-4-1 + rotate: false + xy: 1139, 287 + size: 200, 200 + orig: 200, 200 + offset: 0, 0 + index: -1 +scorch-4-2 + rotate: false + xy: 1341, 257 + size: 200, 200 + orig: 200, 200 + offset: 0, 0 + index: -1 +scorch-5-0 + rotate: false + xy: 675, 429 + size: 230, 230 + orig: 230, 230 + offset: 0, 0 + index: -1 +scorch-5-1 + rotate: false + xy: 907, 459 + size: 230, 230 + orig: 230, 230 + offset: 0, 0 + index: -1 +scorch-5-2 + rotate: false + xy: 907, 227 + size: 230, 230 + orig: 230, 230 + offset: 0, 0 + index: -1 +scorch-6-0 + rotate: false + xy: 293, 47 + size: 260, 260 + orig: 260, 260 + offset: 0, 0 + index: -1 +scorch-6-1 + rotate: false + xy: 555, 77 + size: 260, 260 + orig: 260, 260 + offset: 0, 0 + index: -1 +scorch-6-2 + rotate: false + xy: 1349, 459 + size: 260, 260 + orig: 260, 260 + offset: 0, 0 + index: -1 +scorch-7-0 + rotate: false + xy: 1, 17 + size: 290, 290 + orig: 290, 290 + offset: 0, 0 + index: -1 +scorch-7-1 + rotate: false + xy: 1349, 721 + size: 290, 290 + orig: 290, 290 + offset: 0, 0 + index: -1 +scorch-7-2 + rotate: false + xy: 1641, 721 + size: 290, 290 + orig: 290, 290 + offset: 0, 0 + index: -1 +scorch-8-0 + rotate: false + xy: 353, 339 + size: 320, 320 + orig: 320, 320 + offset: 0, 0 + index: -1 +scorch-8-1 + rotate: false + xy: 705, 691 + size: 320, 320 + orig: 320, 320 + offset: 0, 0 + index: -1 +scorch-8-2 + rotate: false + xy: 1027, 691 + size: 320, 320 + orig: 320, 320 + offset: 0, 0 + index: -1 +scorch-9-0 + rotate: false + xy: 1, 661 + size: 350, 350 + orig: 350, 350 + offset: 0, 0 + index: -1 +scorch-9-1 + rotate: false + xy: 1, 309 + size: 350, 350 + orig: 350, 350 + offset: 0, 0 + index: -1 +scorch-9-2 + rotate: false + xy: 353, 661 + size: 350, 350 + orig: 350, 350 + offset: 0, 0 + index: -1 + +sprites3.png size: 2048,512 format: RGBA8888 filter: Nearest,Nearest @@ -7165,2057 +7255,2071 @@ white-tree-dead offset: 0, 0 index: -1 -sprites3.png +sprites4.png size: 2048,1024 format: RGBA8888 filter: Nearest,Nearest repeat: none alloy-smelter-icon-editor rotate: false - xy: 1, 23 + xy: 1, 11 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 +alpha-mech-pad-icon-editor + rotate: false + xy: 745, 849 + size: 64, 64 + orig: 64, 64 + offset: 0, 0 + index: -1 arc-icon-editor rotate: false - xy: 261, 145 + xy: 261, 133 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 armored-conveyor-icon-editor rotate: false - xy: 569, 399 + xy: 493, 83 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 battery-icon-editor rotate: false - xy: 603, 399 + xy: 611, 387 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 battery-large-icon-editor rotate: false - xy: 745, 927 + xy: 745, 915 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 blast-drill-icon-editor rotate: false - xy: 1, 251 + xy: 1, 239 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 blast-mixer-icon-editor rotate: false - xy: 745, 861 + xy: 811, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 block-border-editor rotate: false - xy: 637, 399 + xy: 493, 49 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conduit-icon-editor rotate: false - xy: 671, 399 + xy: 645, 387 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 bridge-conveyor-icon-editor rotate: false - xy: 295, 13 + xy: 679, 387 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 char-icon-editor rotate: false - xy: 329, 13 + xy: 295, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-char1 rotate: false - xy: 329, 13 + xy: 295, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 clear-editor rotate: false - xy: 261, 378 + xy: 261, 366 size: 1, 1 orig: 1, 1 offset: 0, 0 index: -1 cliffs-icon-editor rotate: false - xy: 363, 13 + xy: 329, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 coal-centrifuge-icon-editor rotate: false - xy: 811, 861 + xy: 877, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 combustion-generator-icon-editor rotate: false - xy: 397, 13 + xy: 363, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 command-center-icon-editor rotate: false - xy: 877, 861 + xy: 943, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 conduit-icon-editor rotate: false - xy: 493, 103 + xy: 397, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 container-icon-editor rotate: false - xy: 943, 861 + xy: 1009, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 conveyor-icon-editor rotate: false - xy: 535, 145 + xy: 431, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper-wall-icon-editor rotate: false - xy: 431, 29 + xy: 465, 1 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 copper-wall-large-icon-editor rotate: false - xy: 1009, 861 + xy: 1075, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 core-foundation-icon-editor rotate: false - xy: 323, 733 + xy: 323, 721 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 core-nucleus-icon-editor rotate: false - xy: 323, 863 + xy: 323, 851 size: 160, 160 orig: 160, 160 offset: 0, 0 index: -1 core-shard-icon-editor rotate: false - xy: 99, 23 + xy: 99, 11 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 craters-icon-editor rotate: false - xy: 477, 69 + xy: 527, 83 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-craters1 rotate: false - xy: 477, 69 + xy: 527, 83 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 crawler-factory-icon-editor rotate: false - xy: 1075, 861 + xy: 1141, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cryofluidmixer-icon-editor rotate: false - xy: 1141, 861 + xy: 1207, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cultivator-icon-editor rotate: false - xy: 1207, 861 + xy: 1273, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 cyclone-icon-editor rotate: false - xy: 843, 927 + xy: 843, 915 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 dagger-factory-icon-editor rotate: false - xy: 1273, 861 + xy: 1339, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dark-metal-icon-editor rotate: false - xy: 569, 365 + xy: 527, 49 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-1-icon-editor rotate: false - xy: 603, 365 + xy: 499, 15 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-1 rotate: false - xy: 603, 365 + xy: 499, 15 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-2-icon-editor rotate: false - xy: 637, 365 + xy: 533, 15 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-2 rotate: false - xy: 637, 365 + xy: 533, 15 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-3-icon-editor rotate: false - xy: 671, 365 + xy: 543, 133 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-3 rotate: false - xy: 671, 365 + xy: 543, 133 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-4-icon-editor rotate: false - xy: 555, 331 + xy: 611, 353 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-4 rotate: false - xy: 555, 331 + xy: 611, 353 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-5-icon-editor rotate: false - xy: 589, 331 + xy: 645, 353 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-5 rotate: false - xy: 589, 331 + xy: 645, 353 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 dark-panel-6-icon-editor rotate: false - xy: 555, 297 + xy: 679, 353 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-dark-panel-6 rotate: false - xy: 555, 297 + xy: 679, 353 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-icon-editor rotate: false - xy: 623, 331 + xy: 577, 345 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand1 rotate: false - xy: 623, 331 + xy: 577, 345 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-tainted-water-icon-editor rotate: false - xy: 589, 297 + xy: 555, 311 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand-tainted-water rotate: false - xy: 589, 297 + xy: 555, 311 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 darksand-water-icon-editor rotate: false - xy: 555, 263 + xy: 555, 277 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand-water rotate: false - xy: 555, 263 + xy: 555, 277 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -dart-mech-pad-icon-editor +dart-ship-pad-icon-editor rotate: false - xy: 1339, 861 + xy: 1405, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 deepwater-icon-editor rotate: false - xy: 657, 331 + xy: 555, 243 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-deepwater rotate: false - xy: 657, 331 + xy: 555, 243 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 delta-mech-pad-icon-editor rotate: false - xy: 1405, 861 + xy: 1471, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 differential-generator-icon-editor rotate: false - xy: 941, 927 + xy: 941, 915 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 diode-icon-editor rotate: false - xy: 623, 297 + xy: 555, 209 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 distributor-icon-editor rotate: false - xy: 1471, 861 + xy: 1537, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 door-icon-editor rotate: false - xy: 589, 263 + xy: 555, 175 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 door-large-icon-editor rotate: false - xy: 1537, 861 + xy: 1603, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 draug-factory-icon-editor rotate: false - xy: 1603, 861 + xy: 1669, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 dunerocks-icon-editor rotate: false - xy: 555, 229 + xy: 589, 311 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 duo-icon-editor rotate: false - xy: 657, 297 + xy: 589, 277 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-char2 rotate: false - xy: 623, 263 + xy: 589, 243 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-char3 rotate: false - xy: 589, 229 + xy: 589, 209 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-clear rotate: false - xy: 733, 883 + xy: 733, 871 size: 10, 10 orig: 10, 10 offset: 0, 0 index: -1 editor-craters2 rotate: false - xy: 555, 195 + xy: 589, 175 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-craters3 rotate: false - xy: 657, 263 + xy: 577, 141 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand2 rotate: false - xy: 623, 229 + xy: 623, 319 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-darksand3 rotate: false - xy: 589, 195 + xy: 623, 285 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-grass1 rotate: false - xy: 657, 229 + xy: 657, 319 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 grass-icon-editor rotate: false - xy: 657, 229 + xy: 657, 319 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-grass2 rotate: false - xy: 623, 195 + xy: 623, 251 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-grass3 rotate: false - xy: 657, 195 + xy: 657, 285 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-holostone1 rotate: false - xy: 569, 161 + xy: 623, 217 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 holostone-icon-editor rotate: false - xy: 569, 161 + xy: 623, 217 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-holostone2 rotate: false - xy: 603, 161 + xy: 657, 251 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-holostone3 rotate: false - xy: 637, 161 + xy: 623, 183 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-hotrock1 rotate: false - xy: 671, 161 + xy: 657, 217 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 hotrock-icon-editor rotate: false - xy: 671, 161 + xy: 657, 217 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-hotrock2 rotate: false - xy: 511, 69 + xy: 657, 183 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-hotrock3 rotate: false - xy: 527, 103 + xy: 691, 319 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice-snow1 rotate: false - xy: 671, 127 + xy: 691, 183 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-snow-icon-editor rotate: false - xy: 671, 127 + xy: 691, 183 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice-snow2 rotate: false - xy: 545, 69 + xy: 611, 141 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice-snow3 rotate: false - xy: 691, 331 + xy: 645, 149 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice1 rotate: false - xy: 569, 127 + xy: 691, 285 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ice-icon-editor rotate: false - xy: 569, 127 + xy: 691, 285 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice2 rotate: false - xy: 603, 127 + xy: 691, 251 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ice3 rotate: false - xy: 637, 127 + xy: 691, 217 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ignarock1 rotate: false - xy: 691, 297 + xy: 679, 149 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 ignarock-icon-editor rotate: false - xy: 691, 297 + xy: 679, 149 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ignarock2 rotate: false - xy: 691, 263 + xy: 713, 149 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ignarock3 rotate: false - xy: 691, 229 + xy: 577, 107 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-magmarock1 rotate: false - xy: 691, 195 + xy: 611, 107 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 magmarock-icon-editor rotate: false - xy: 691, 195 + xy: 611, 107 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-magmarock2 rotate: false - xy: 705, 161 + xy: 645, 115 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-magmarock3 rotate: false - xy: 705, 127 + xy: 679, 115 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor rotate: false - xy: 465, 29 + xy: 713, 115 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-icon-editor rotate: false - xy: 465, 29 + xy: 713, 115 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-2 rotate: false - xy: 499, 35 + xy: 561, 73 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-2-icon-editor rotate: false - xy: 499, 35 + xy: 561, 73 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-3 rotate: false - xy: 499, 1 + xy: 595, 73 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-3-icon-editor rotate: false - xy: 499, 1 + xy: 595, 73 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-5 rotate: false - xy: 533, 35 + xy: 629, 73 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-5-icon-editor rotate: false - xy: 533, 35 + xy: 629, 73 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-damaged1 rotate: false - xy: 533, 1 + xy: 663, 81 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 metal-floor-damaged-icon-editor rotate: false - xy: 533, 1 + xy: 663, 81 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-damaged2 rotate: false - xy: 705, 399 + xy: 697, 81 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-metal-floor-damaged3 rotate: false - xy: 705, 365 + xy: 731, 81 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-moss1 rotate: false - xy: 725, 331 + xy: 567, 39 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 moss-icon-editor rotate: false - xy: 725, 331 + xy: 567, 39 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-moss2 rotate: false - xy: 725, 297 + xy: 601, 39 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-moss3 rotate: false - xy: 725, 263 + xy: 635, 39 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-coal1 rotate: false - xy: 725, 229 + xy: 669, 47 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-coal2 rotate: false - xy: 725, 195 + xy: 703, 47 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-coal3 rotate: false - xy: 739, 161 + xy: 737, 47 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-copper1 rotate: false - xy: 739, 127 + xy: 567, 5 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-copper2 rotate: false - xy: 567, 35 + xy: 601, 5 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-copper3 rotate: false - xy: 567, 1 + xy: 635, 5 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-lead1 rotate: false - xy: 579, 93 + xy: 669, 13 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-lead2 rotate: false - xy: 613, 93 + xy: 703, 13 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-lead3 rotate: false - xy: 647, 93 + xy: 737, 13 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-scrap1 rotate: false - xy: 681, 93 + xy: 713, 387 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-scrap2 rotate: false - xy: 715, 93 + xy: 713, 353 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-scrap3 rotate: false - xy: 749, 93 + xy: 725, 319 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-thorium1 rotate: false - xy: 601, 59 + xy: 725, 285 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-thorium2 rotate: false - xy: 601, 25 + xy: 725, 251 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-thorium3 rotate: false - xy: 635, 59 + xy: 725, 217 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-titanium1 rotate: false - xy: 635, 25 + xy: 725, 183 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-titanium2 rotate: false - xy: 669, 59 + xy: 747, 149 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-ore-titanium3 rotate: false - xy: 669, 25 + xy: 747, 115 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-pebbles1 rotate: false - xy: 703, 59 + xy: 765, 81 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-pebbles2 rotate: false - xy: 703, 25 + xy: 771, 47 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-pebbles3 rotate: false - xy: 737, 59 + xy: 771, 13 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-salt rotate: false - xy: 737, 25 + xy: 733, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 salt-icon-editor rotate: false - xy: 737, 25 + xy: 733, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-sand-water rotate: false - xy: 767, 827 + xy: 869, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-water-icon-editor rotate: false - xy: 767, 827 + xy: 869, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-sand1 rotate: false - xy: 771, 59 + xy: 767, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sand-icon-editor rotate: false - xy: 771, 59 + xy: 767, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-sand2 rotate: false - xy: 771, 25 + xy: 801, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-sand3 rotate: false - xy: 733, 827 + xy: 835, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-shale1 rotate: false - xy: 801, 827 + xy: 903, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shale-icon-editor rotate: false - xy: 801, 827 + xy: 903, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-shale2 rotate: false - xy: 835, 827 + xy: 937, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-shale3 rotate: false - xy: 869, 827 + xy: 971, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-slag rotate: false - xy: 903, 827 + xy: 1005, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 slag-icon-editor rotate: false - xy: 903, 827 + xy: 1005, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-snow1 rotate: false - xy: 937, 827 + xy: 1039, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-snow2 rotate: false - xy: 971, 827 + xy: 1073, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-snow3 rotate: false - xy: 1005, 827 + xy: 1107, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-spawn rotate: false - xy: 1039, 827 + xy: 1141, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-spore-moss1 rotate: false - xy: 1073, 827 + xy: 1175, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spore-moss-icon-editor rotate: false - xy: 1073, 827 + xy: 1175, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-spore-moss2 rotate: false - xy: 1107, 827 + xy: 1209, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-spore-moss3 rotate: false - xy: 1141, 827 + xy: 1243, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-stone1 rotate: false - xy: 1175, 827 + xy: 1277, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 stone-icon-editor rotate: false - xy: 1175, 827 + xy: 1277, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-stone2 rotate: false - xy: 1209, 827 + xy: 1311, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-stone3 rotate: false - xy: 1243, 827 + xy: 1345, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tainted-water rotate: false - xy: 1277, 827 + xy: 1379, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tainted-water-icon-editor rotate: false - xy: 1277, 827 + xy: 1379, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tar rotate: false - xy: 1311, 827 + xy: 1413, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 tar-icon-editor rotate: false - xy: 1311, 827 + xy: 1413, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tendrils1 rotate: false - xy: 1345, 827 + xy: 1447, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tendrils2 rotate: false - xy: 1379, 827 + xy: 1481, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-tendrils3 rotate: false - xy: 1413, 827 + xy: 1515, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 editor-water rotate: false - xy: 1447, 827 + xy: 1549, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 water-icon-editor rotate: false - xy: 1447, 827 + xy: 1549, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 force-projector-icon-editor rotate: false - xy: 1039, 927 + xy: 1039, 915 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 fortress-factory-icon-editor rotate: false - xy: 1137, 927 + xy: 1137, 915 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 fuse-icon-editor rotate: false - xy: 1235, 927 + xy: 1235, 915 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 ghoul-factory-icon-editor rotate: false - xy: 1333, 927 + xy: 1333, 915 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 glaive-ship-pad-icon-editor rotate: false - xy: 1431, 927 + xy: 1431, 915 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 graphite-press-icon-editor rotate: false - xy: 1669, 861 + xy: 1735, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 hail-icon-editor rotate: false - xy: 1481, 827 + xy: 1583, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 icerocks-icon-editor rotate: false - xy: 1515, 827 + xy: 1617, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 illuminator-icon-editor rotate: false - xy: 1549, 827 + xy: 1651, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 impact-reactor-icon-editor rotate: false - xy: 485, 895 + xy: 485, 883 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 incinerator-icon-editor rotate: false - xy: 1583, 827 + xy: 1685, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 inverted-sorter-icon-editor rotate: false - xy: 1617, 827 + xy: 1719, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-source-icon-editor rotate: false - xy: 1651, 827 + xy: 1753, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-void-icon-editor rotate: false - xy: 1685, 827 + xy: 1787, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 javelin-ship-pad-icon-editor rotate: false - xy: 1735, 861 + xy: 1801, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 junction-icon-editor rotate: false - xy: 1719, 827 + xy: 1821, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 kiln-icon-editor rotate: false - xy: 1801, 861 + xy: 1867, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 lancer-icon-editor rotate: false - xy: 1867, 861 + xy: 1933, 849 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 laser-drill-icon-editor rotate: false - xy: 1529, 927 + xy: 1529, 915 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 launch-pad-icon-editor rotate: false - xy: 1627, 927 + xy: 1627, 915 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 launch-pad-large-icon-editor rotate: false - xy: 1, 121 + xy: 1, 109 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 liquid-junction-icon-editor rotate: false - xy: 1753, 827 + xy: 1855, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-router-icon-editor rotate: false - xy: 1787, 827 + xy: 1889, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-source-icon-editor rotate: false - xy: 1821, 827 + xy: 1923, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-tank-icon-editor rotate: false - xy: 1725, 927 + xy: 1725, 915 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 liquid-void-icon-editor rotate: false - xy: 1855, 827 + xy: 1957, 815 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mass-driver-icon-editor rotate: false - xy: 1823, 927 + xy: 1823, 915 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 mechanical-drill-icon-editor rotate: false - xy: 1933, 861 + xy: 485, 817 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mechanical-pump-icon-editor rotate: false - xy: 1889, 827 + xy: 717, 781 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 meltdown-icon-editor rotate: false - xy: 131, 251 + xy: 131, 239 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 melter-icon-editor rotate: false - xy: 1923, 827 + xy: 717, 747 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 mend-projector-icon-editor rotate: false - xy: 485, 829 + xy: 551, 817 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 mender-icon-editor rotate: false - xy: 1957, 827 + xy: 751, 781 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 message-icon-editor rotate: false - xy: 717, 793 + xy: 717, 713 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 multi-press-icon-editor rotate: false - xy: 1921, 927 + xy: 1921, 915 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 oil-extractor-icon-editor rotate: false - xy: 323, 375 + xy: 323, 363 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 omega-mech-pad-icon-editor rotate: false - xy: 197, 23 + xy: 197, 11 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 overdrive-projector-icon-editor rotate: false - xy: 551, 829 + xy: 617, 817 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 overflow-gate-icon-editor rotate: false - xy: 717, 759 + xy: 785, 781 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pebbles-icon-editor rotate: false - xy: 751, 793 + xy: 751, 747 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phantom-factory-icon-editor rotate: false - xy: 617, 829 + xy: 453, 751 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phase-conduit-icon-editor rotate: false - xy: 717, 725 + xy: 717, 679 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-conveyor-icon-editor rotate: false - xy: 785, 793 + xy: 819, 781 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall-icon-editor rotate: false - xy: 751, 759 + xy: 785, 747 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 phase-wall-large-icon-editor rotate: false - xy: 453, 763 + xy: 519, 751 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 phase-weaver-icon-editor rotate: false - xy: 519, 763 + xy: 453, 685 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 pine-icon-editor rotate: false - xy: 1999, 877 + xy: 1999, 865 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 plastanium-compressor-icon-editor rotate: false - xy: 453, 697 + xy: 519, 685 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 plastanium-wall-icon-editor rotate: false - xy: 717, 691 + xy: 751, 713 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 plastanium-wall-large-icon-editor rotate: false - xy: 519, 697 + xy: 585, 751 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 plated-conduit-icon-editor rotate: false - xy: 819, 793 + xy: 717, 645 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pneumatic-drill-icon-editor rotate: false - xy: 585, 763 + xy: 453, 619 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 power-node-icon-editor rotate: false - xy: 785, 759 + xy: 853, 781 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-node-large-icon-editor rotate: false - xy: 453, 631 + xy: 519, 619 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 power-source-icon-editor rotate: false - xy: 751, 725 + xy: 819, 747 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 power-void-icon-editor rotate: false - xy: 717, 657 + xy: 785, 713 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulse-conduit-icon-editor rotate: false - xy: 853, 793 + xy: 751, 679 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pulverizer-icon-editor rotate: false - xy: 819, 759 + xy: 717, 611 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 pyratite-mixer-icon-editor rotate: false - xy: 519, 631 + xy: 585, 685 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 repair-point-icon-editor rotate: false - xy: 785, 725 + xy: 887, 781 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 revenant-factory-icon-editor rotate: false - xy: 323, 603 + xy: 323, 591 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 ripple-icon-editor rotate: false - xy: 261, 277 + xy: 261, 265 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 rock-icon-editor rotate: false - xy: 1999, 827 + xy: 1999, 815 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 rocks-icon-editor rotate: false - xy: 751, 691 + xy: 853, 747 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rotary-pump-icon-editor rotate: false - xy: 585, 697 + xy: 453, 553 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 router-icon-editor rotate: false - xy: 717, 623 + xy: 819, 713 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 rtg-generator-icon-editor rotate: false - xy: 453, 565 + xy: 519, 553 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 saltrocks-icon-editor rotate: false - xy: 887, 793 + xy: 785, 679 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 salvo-icon-editor rotate: false - xy: 519, 565 + xy: 585, 619 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 sand-boulder-icon-editor rotate: false - xy: 853, 759 + xy: 751, 645 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 sandrocks-icon-editor rotate: false - xy: 819, 725 + xy: 717, 577 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scatter-icon-editor rotate: false - xy: 585, 631 + xy: 453, 487 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 scorch-icon-editor rotate: false - xy: 785, 691 + xy: 921, 781 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall-gigantic-icon-editor rotate: false - xy: 615, 895 + xy: 615, 883 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 scrap-wall-huge-icon-editor rotate: false - xy: 261, 179 + xy: 261, 167 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 scrap-wall-icon-editor rotate: false - xy: 751, 657 + xy: 887, 747 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 scrap-wall-large-icon-editor rotate: false - xy: 453, 499 + xy: 519, 487 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 separator-icon-editor rotate: false - xy: 519, 499 + xy: 585, 553 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 shale-boulder-icon-editor rotate: false - xy: 717, 589 + xy: 853, 713 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shalerocks-icon-editor rotate: false - xy: 921, 793 + xy: 819, 679 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shock-mine-icon-editor rotate: false - xy: 887, 759 + xy: 785, 645 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 shrubs-icon-editor rotate: false - xy: 853, 725 + xy: 751, 611 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 silicon-smelter-icon-editor rotate: false - xy: 585, 565 + xy: 585, 487 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 snow-icon-editor rotate: false - xy: 819, 691 + xy: 717, 543 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 snow-pine-icon-editor rotate: false - xy: 519, 383 + xy: 519, 371 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 snowrock-icon-editor rotate: false - xy: 683, 845 + xy: 683, 833 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 snowrocks-icon-editor rotate: false - xy: 785, 657 + xy: 955, 781 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel-icon-editor rotate: false - xy: 751, 623 + xy: 921, 747 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 solar-panel-large-icon-editor rotate: false - xy: 359, 277 + xy: 359, 265 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 sorter-icon-editor rotate: false - xy: 717, 555 + xy: 887, 713 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spawn-icon-editor rotate: false - xy: 955, 793 + xy: 853, 679 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 spectre-icon-editor rotate: false - xy: 131, 121 + xy: 131, 109 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 spirit-factory-icon-editor rotate: false - xy: 585, 499 + xy: 519, 421 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 spore-cluster-icon-editor rotate: false - xy: 493, 137 + xy: 569, 379 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 spore-pine-icon-editor rotate: false - xy: 427, 63 + xy: 493, 117 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 spore-press-icon-editor rotate: false - xy: 519, 433 + xy: 585, 421 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 sporerocks-icon-editor rotate: false - xy: 921, 759 + xy: 819, 645 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 surge-tower-icon-editor rotate: false - xy: 585, 433 + xy: 651, 751 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 surge-wall-icon-editor rotate: false - xy: 887, 725 + xy: 785, 611 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 surge-wall-large-icon-editor rotate: false - xy: 651, 763 + xy: 651, 685 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 swarmer-icon-editor rotate: false - xy: 651, 697 + xy: 651, 619 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 tau-mech-pad-icon-editor rotate: false - xy: 651, 631 + xy: 651, 553 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 tendrils-icon-editor rotate: false - xy: 853, 691 + xy: 751, 577 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thermal-generator-icon-editor rotate: false - xy: 651, 565 + xy: 651, 487 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thermal-pump-icon-editor rotate: false - xy: 359, 179 + xy: 359, 167 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 thorium-reactor-icon-editor rotate: false - xy: 421, 375 + xy: 421, 363 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 thorium-wall-icon-editor rotate: false - xy: 819, 657 + xy: 717, 509 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 thorium-wall-large-icon-editor rotate: false - xy: 651, 499 + xy: 651, 421 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 thruster-icon-editor rotate: false - xy: 323, 473 + xy: 323, 461 size: 128, 128 orig: 128, 128 offset: 0, 0 index: -1 titan-factory-icon-editor rotate: false - xy: 457, 277 + xy: 457, 265 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 titanium-conveyor-icon-editor rotate: false - xy: 785, 623 + xy: 989, 781 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-wall-icon-editor rotate: false - xy: 751, 589 + xy: 955, 747 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 titanium-wall-large-icon-editor rotate: false - xy: 651, 433 + xy: 295, 101 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 trident-ship-pad-icon-editor rotate: false - xy: 295, 113 + xy: 295, 35 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 turbine-generator-icon-editor rotate: false - xy: 295, 47 + xy: 361, 101 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 +underflow-gate-icon-editor + rotate: false + xy: 921, 713 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 unloader-icon-editor rotate: false - xy: 717, 521 + xy: 887, 679 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 vault-icon-editor rotate: false - xy: 457, 179 + xy: 457, 167 size: 96, 96 orig: 96, 96 offset: 0, 0 index: -1 water-extractor-icon-editor rotate: false - xy: 361, 113 + xy: 361, 35 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 wave-icon-editor rotate: false - xy: 361, 47 + xy: 427, 101 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 white-tree-dead-icon-editor rotate: false - xy: 1, 703 + xy: 1, 691 size: 320, 320 orig: 320, 320 offset: 0, 0 index: -1 white-tree-icon-editor rotate: false - xy: 1, 381 + xy: 1, 369 size: 320, 320 orig: 320, 320 offset: 0, 0 index: -1 wraith-factory-icon-editor rotate: false - xy: 427, 113 + xy: 427, 35 size: 64, 64 orig: 64, 64 offset: 0, 0 index: -1 -sprites4.png +sprites5.png size: 1024,1024 format: RGBA8888 filter: Nearest,Nearest @@ -9305,7 +9409,7 @@ zone-tarFields offset: 0, 0 index: -1 -sprites5.png +sprites6.png size: 2048,1024 format: RGBA8888 filter: Nearest,Nearest @@ -9319,7 +9423,7 @@ alpha-bg index: -1 bar rotate: false - xy: 1085, 560 + xy: 519, 86 size: 27, 36 split: 9, 9, 9, 9 orig: 27, 36 @@ -9327,7 +9431,7 @@ bar index: -1 bar-top rotate: false - xy: 1056, 560 + xy: 519, 124 size: 27, 36 split: 9, 10, 9, 10 orig: 27, 36 @@ -9342,7 +9446,7 @@ block-alloy-smelter-large index: -1 block-alloy-smelter-medium rotate: false - xy: 1681, 899 + xy: 881, 589 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -9356,7 +9460,7 @@ block-alloy-smelter-small index: -1 block-alloy-smelter-tiny rotate: false - xy: 1989, 957 + xy: 301, 1 size: 16, 16 orig: 16, 16 offset: 0, 0 @@ -9368,2277 +9472,2312 @@ block-alloy-smelter-xlarge orig: 48, 48 offset: 0, 0 index: -1 -block-arc-large +block-alpha-mech-pad-large rotate: false xy: 2007, 941 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-arc-medium +block-alpha-mech-pad-medium rotate: false - xy: 1715, 899 + xy: 957, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-arc-small +block-alpha-mech-pad-small rotate: false - xy: 43, 2 + xy: 80, 2 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-arc-tiny - rotate: false - xy: 929, 494 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-arc-xlarge - rotate: false - xy: 131, 608 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-armored-conveyor-large - rotate: false - xy: 501, 424 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-armored-conveyor-medium - rotate: false - xy: 1749, 899 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-armored-conveyor-small - rotate: false - xy: 2021, 915 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-armored-conveyor-tiny - rotate: false - xy: 301, 1 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-armored-conveyor-xlarge - rotate: false - xy: 771, 928 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-battery-large - rotate: false - xy: 551, 474 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-battery-large-large - rotate: false - xy: 601, 524 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-battery-large-medium - rotate: false - xy: 1783, 899 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-battery-large-small - rotate: false - xy: 895, 538 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-battery-large-tiny +block-alpha-mech-pad-tiny rotate: false xy: 319, 1 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-battery-large-xlarge +block-alpha-mech-pad-xlarge rotate: false - xy: 259, 819 + xy: 131, 608 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-battery-medium +block-arc-large rotate: false - xy: 1817, 899 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-battery-small - rotate: false - xy: 1114, 572 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-battery-tiny - rotate: false - xy: 947, 494 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-battery-xlarge - rotate: false - xy: 1, 428 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-blast-drill-large - rotate: false - xy: 651, 574 + xy: 601, 524 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-blast-drill-medium +block-arc-medium rotate: false - xy: 1851, 899 + xy: 991, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-blast-drill-small +block-arc-small rotate: false - xy: 1629, 611 + xy: 106, 2 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-blast-drill-tiny +block-arc-tiny rotate: false xy: 131, 540 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-blast-drill-xlarge +block-arc-xlarge rotate: false - xy: 51, 478 + xy: 771, 928 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-blast-mixer-large +block-armored-conveyor-large rotate: false - xy: 351, 224 + xy: 651, 574 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-blast-mixer-medium +block-armored-conveyor-medium rotate: false - xy: 1885, 899 + xy: 1025, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-blast-mixer-small +block-armored-conveyor-small rotate: false - xy: 69, 2 + xy: 550, 264 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-blast-mixer-tiny +block-armored-conveyor-tiny rotate: false xy: 309, 698 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-blast-mixer-xlarge +block-armored-conveyor-xlarge rotate: false - xy: 131, 558 + xy: 259, 819 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-bridge-conduit-large +block-battery-large + rotate: false + xy: 351, 224 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-battery-large-large rotate: false xy: 401, 274 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-bridge-conduit-medium +block-battery-large-medium rotate: false - xy: 882, 870 + xy: 1059, 647 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-bridge-conduit-small +block-battery-large-small rotate: false - xy: 2021, 889 + xy: 550, 238 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-bridge-conduit-tiny +block-battery-large-tiny rotate: false xy: 331, 598 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-bridge-conduit-xlarge +block-battery-large-xlarge rotate: false - xy: 181, 608 + xy: 1, 428 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-bridge-conveyor-large +block-battery-medium + rotate: false + xy: 1093, 647 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-battery-small + rotate: false + xy: 550, 212 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-battery-tiny + rotate: false + xy: 1133, 561 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-battery-xlarge + rotate: false + xy: 51, 478 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-blast-drill-large rotate: false xy: 451, 324 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-bridge-conveyor-medium +block-blast-drill-medium rotate: false - xy: 916, 870 + xy: 919, 618 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-bridge-conveyor-small +block-blast-drill-small rotate: false - xy: 921, 538 + xy: 550, 186 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-bridge-conveyor-tiny +block-blast-drill-tiny rotate: false - xy: 859, 682 + xy: 132, 10 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-bridge-conveyor-xlarge +block-blast-drill-xlarge + rotate: false + xy: 131, 558 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-blast-mixer-large + rotate: false + xy: 501, 374 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-blast-mixer-medium + rotate: false + xy: 1127, 647 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-blast-mixer-small + rotate: false + xy: 576, 246 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-blast-mixer-tiny + rotate: false + xy: 914, 190 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-blast-mixer-xlarge + rotate: false + xy: 181, 608 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-bridge-conduit-large + rotate: false + xy: 551, 424 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-bridge-conduit-medium + rotate: false + xy: 915, 584 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-bridge-conduit-small + rotate: false + xy: 576, 220 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-bridge-conduit-tiny + rotate: false + xy: 860, 8 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-bridge-conduit-xlarge rotate: false xy: 259, 769 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-char-large +block-bridge-conveyor-large rotate: false - xy: 501, 382 + xy: 601, 482 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-char-medium +block-bridge-conveyor-medium rotate: false - xy: 950, 870 + xy: 953, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-char-small +block-bridge-conveyor-small rotate: false - xy: 1140, 572 + xy: 602, 246 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-char-tiny +block-bridge-conveyor-tiny rotate: false - xy: 1658, 639 + xy: 1331, 638 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-char-xlarge +block-bridge-conveyor-xlarge rotate: false xy: 1, 378 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-cliffs-large +block-char-large rotate: false xy: 693, 574 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-cliffs-medium +block-char-medium rotate: false - xy: 984, 870 + xy: 987, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-cliffs-small +block-char-small rotate: false - xy: 95, 2 + xy: 576, 194 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-cliffs-tiny +block-char-tiny rotate: false - xy: 1901, 726 + xy: 1495, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-cliffs-xlarge +block-char-xlarge rotate: false xy: 51, 428 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-coal-centrifuge-large +block-cliffs-large rotate: false xy: 351, 182 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-coal-centrifuge-medium +block-cliffs-medium rotate: false - xy: 1018, 870 + xy: 1021, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-coal-centrifuge-small +block-cliffs-small rotate: false - xy: 1166, 572 + xy: 602, 220 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-coal-centrifuge-tiny +block-cliffs-tiny rotate: false - xy: 309, 680 + xy: 1435, 695 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-coal-centrifuge-xlarge +block-cliffs-xlarge rotate: false xy: 181, 558 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-combustion-generator-large +block-coal-centrifuge-large rotate: false xy: 735, 574 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-combustion-generator-medium +block-coal-centrifuge-medium rotate: false - xy: 1052, 870 + xy: 1055, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-combustion-generator-small +block-coal-centrifuge-small rotate: false - xy: 121, 2 + xy: 628, 246 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-combustion-generator-tiny +block-coal-centrifuge-tiny rotate: false - xy: 331, 580 + xy: 1461, 732 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-combustion-generator-xlarge +block-coal-centrifuge-xlarge rotate: false xy: 259, 719 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-command-center-large +block-combustion-generator-large rotate: false xy: 351, 140 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-command-center-medium +block-combustion-generator-medium rotate: false - xy: 1086, 870 + xy: 1089, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-command-center-small +block-combustion-generator-small rotate: false - xy: 1192, 572 + xy: 602, 194 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-command-center-tiny +block-combustion-generator-tiny rotate: false - xy: 435, 4 + xy: 309, 680 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-command-center-xlarge +block-combustion-generator-xlarge rotate: false xy: 1, 328 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-conduit-large +block-command-center-large rotate: false xy: 351, 98 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-conduit-medium +block-command-center-medium rotate: false - xy: 1120, 870 + xy: 1123, 613 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-conduit-small +block-command-center-small rotate: false - xy: 1218, 572 + xy: 628, 220 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-conduit-tiny +block-command-center-tiny rotate: false - xy: 453, 4 + xy: 331, 580 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-conduit-xlarge +block-command-center-xlarge rotate: false xy: 51, 378 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-container-large +block-conduit-large rotate: false xy: 351, 56 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-container-medium +block-conduit-medium rotate: false - xy: 1154, 870 + xy: 949, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-container-small +block-conduit-small rotate: false - xy: 1244, 572 + xy: 654, 246 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-container-tiny +block-conduit-tiny rotate: false - xy: 687, 2 + xy: 914, 172 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-container-xlarge +block-conduit-xlarge rotate: false xy: 259, 669 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-conveyor-large +block-container-large rotate: false xy: 351, 14 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-conveyor-medium +block-container-medium rotate: false - xy: 1188, 870 + xy: 983, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-conveyor-small +block-container-small rotate: false - xy: 1270, 572 + xy: 628, 194 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-conveyor-tiny +block-container-tiny rotate: false - xy: 705, 2 + xy: 878, 8 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-conveyor-xlarge +block-container-xlarge rotate: false xy: 1, 278 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-copper-wall-large +block-conveyor-large rotate: false - xy: 501, 340 + xy: 601, 440 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-copper-wall-large-large +block-conveyor-medium rotate: false - xy: 543, 424 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-copper-wall-large-medium - rotate: false - xy: 1222, 870 + xy: 1017, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-copper-wall-large-small +block-conveyor-small rotate: false - xy: 1296, 572 + xy: 654, 220 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-copper-wall-large-tiny +block-conveyor-tiny rotate: false - xy: 723, 2 + xy: 1349, 638 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-copper-wall-large-xlarge +block-conveyor-xlarge rotate: false xy: 51, 328 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-copper-wall-medium - rotate: false - xy: 1256, 870 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-copper-wall-small - rotate: false - xy: 1322, 572 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-copper-wall-tiny - rotate: false - xy: 741, 2 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-copper-wall-xlarge - rotate: false - xy: 1, 228 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-core-foundation-large - rotate: false - xy: 543, 382 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-core-foundation-medium - rotate: false - xy: 1290, 870 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-core-foundation-small - rotate: false - xy: 1348, 572 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-core-foundation-tiny - rotate: false - xy: 1919, 726 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-core-foundation-xlarge - rotate: false - xy: 51, 278 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-core-nucleus-large - rotate: false - xy: 543, 340 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-core-nucleus-medium - rotate: false - xy: 1324, 870 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-core-nucleus-small - rotate: false - xy: 1374, 572 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-core-nucleus-tiny - rotate: false - xy: 1108, 528 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-core-nucleus-xlarge - rotate: false - xy: 1, 178 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-core-shard-large - rotate: false - xy: 593, 474 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-core-shard-medium - rotate: false - xy: 1358, 870 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-core-shard-small - rotate: false - xy: 1400, 572 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-core-shard-tiny - rotate: false - xy: 1126, 528 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-core-shard-xlarge - rotate: false - xy: 51, 228 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-craters-large - rotate: false - xy: 585, 432 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-craters-medium - rotate: false - xy: 1392, 870 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-craters-small - rotate: false - xy: 1426, 572 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-craters-tiny - rotate: false - xy: 1144, 528 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-craters-xlarge - rotate: false - xy: 1, 128 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-crawler-factory-large - rotate: false - xy: 585, 390 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-crawler-factory-medium - rotate: false - xy: 1426, 870 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-crawler-factory-small - rotate: false - xy: 1452, 572 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-crawler-factory-tiny - rotate: false - xy: 1162, 528 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-crawler-factory-xlarge - rotate: false - xy: 51, 178 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-cryofluidmixer-large - rotate: false - xy: 585, 348 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-cryofluidmixer-medium - rotate: false - xy: 1460, 870 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-cryofluidmixer-small - rotate: false - xy: 1478, 572 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-cryofluidmixer-tiny - rotate: false - xy: 1180, 528 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-cryofluidmixer-xlarge - rotate: false - xy: 1, 78 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-cultivator-large +block-copper-wall-large rotate: false xy: 643, 524 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-cultivator-medium +block-copper-wall-large-large rotate: false - xy: 1494, 870 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-cultivator-small - rotate: false - xy: 1504, 572 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-cultivator-tiny - rotate: false - xy: 1198, 528 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-cultivator-xlarge - rotate: false - xy: 51, 128 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-cyclone-large - rotate: false - xy: 635, 482 + xy: 643, 482 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-cyclone-medium +block-copper-wall-large-medium rotate: false - xy: 1528, 870 + xy: 1051, 579 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-cyclone-small +block-copper-wall-large-small rotate: false - xy: 1530, 572 + xy: 680, 246 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-cyclone-tiny +block-copper-wall-large-tiny rotate: false - xy: 1216, 528 + xy: 1513, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-cyclone-xlarge +block-copper-wall-large-xlarge rotate: false - xy: 1, 28 + xy: 1, 228 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-dagger-factory-large +block-copper-wall-medium + rotate: false + xy: 1085, 579 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-copper-wall-small + rotate: false + xy: 654, 194 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-copper-wall-tiny + rotate: false + xy: 1435, 677 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-copper-wall-xlarge + rotate: false + xy: 51, 278 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-core-foundation-large + rotate: false + xy: 643, 440 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-core-foundation-medium + rotate: false + xy: 1119, 579 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-core-foundation-small + rotate: false + xy: 680, 220 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-core-foundation-tiny + rotate: false + xy: 1461, 714 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-core-foundation-xlarge + rotate: false + xy: 1, 178 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-core-nucleus-large rotate: false xy: 685, 532 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-dagger-factory-medium +block-core-nucleus-medium rotate: false - xy: 1562, 870 + xy: 1161, 660 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-dagger-factory-small +block-core-nucleus-small rotate: false - xy: 1556, 572 + xy: 706, 246 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-dagger-factory-tiny +block-core-nucleus-tiny rotate: false - xy: 1234, 528 + xy: 914, 154 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-dagger-factory-xlarge +block-core-nucleus-xlarge rotate: false - xy: 51, 78 + xy: 51, 228 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-dark-metal-large +block-core-shard-large + rotate: false + xy: 685, 490 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-core-shard-medium + rotate: false + xy: 1195, 660 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-core-shard-small + rotate: false + xy: 680, 194 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-core-shard-tiny + rotate: false + xy: 1367, 638 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-core-shard-xlarge + rotate: false + xy: 1, 128 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-craters-large rotate: false xy: 727, 532 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-dark-metal-medium +block-craters-medium rotate: false - xy: 1596, 870 + xy: 1979, 899 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-dark-metal-small +block-craters-small rotate: false - xy: 1582, 572 + xy: 706, 220 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-dark-metal-tiny +block-craters-tiny rotate: false - xy: 1252, 528 + xy: 1531, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-dark-metal-xlarge +block-craters-xlarge rotate: false - xy: 51, 28 + xy: 51, 178 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-dark-panel-1-large +block-crawler-factory-large + rotate: false + xy: 685, 448 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-crawler-factory-medium + rotate: false + xy: 2013, 907 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-crawler-factory-small + rotate: false + xy: 706, 194 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-crawler-factory-tiny + rotate: false + xy: 914, 136 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-crawler-factory-xlarge + rotate: false + xy: 1, 78 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-cryofluidmixer-large + rotate: false + xy: 727, 490 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-cryofluidmixer-medium + rotate: false + xy: 1363, 828 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-cryofluidmixer-small + rotate: false + xy: 550, 160 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-cryofluidmixer-tiny + rotate: false + xy: 1385, 638 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-cryofluidmixer-xlarge + rotate: false + xy: 51, 128 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-cultivator-large + rotate: false + xy: 727, 448 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-cultivator-medium + rotate: false + xy: 1397, 828 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-cultivator-small + rotate: false + xy: 576, 168 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-cultivator-tiny + rotate: false + xy: 1549, 758 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-cultivator-xlarge + rotate: false + xy: 1, 28 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-cyclone-large rotate: false xy: 393, 224 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-dark-panel-1-medium +block-cyclone-medium rotate: false - xy: 1630, 870 + xy: 1431, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-dark-panel-1-small +block-cyclone-small rotate: false - xy: 1608, 572 + xy: 602, 168 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-dark-panel-1-tiny +block-cyclone-tiny rotate: false - xy: 1270, 528 + xy: 1567, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-dark-panel-1-xlarge +block-cyclone-xlarge rotate: false - xy: 857, 975 + xy: 51, 78 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-dark-panel-2-large +block-dagger-factory-large rotate: false xy: 393, 182 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-dark-panel-2-medium +block-dagger-factory-medium rotate: false - xy: 1919, 912 + xy: 1465, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-dark-panel-2-small +block-dagger-factory-small rotate: false - xy: 2021, 863 + xy: 628, 168 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-dark-panel-2-tiny +block-dagger-factory-tiny rotate: false - xy: 1288, 528 + xy: 1585, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-dark-panel-2-xlarge +block-dagger-factory-xlarge rotate: false - xy: 907, 975 + xy: 51, 28 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-dark-panel-3-large +block-dark-metal-large rotate: false xy: 393, 140 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-dark-panel-3-medium +block-dark-metal-medium rotate: false - xy: 1953, 912 + xy: 1499, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-dark-panel-3-small +block-dark-metal-small rotate: false - xy: 929, 512 + xy: 654, 168 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-dark-panel-3-tiny +block-dark-metal-tiny rotate: false - xy: 1306, 528 + xy: 1603, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-dark-panel-3-xlarge +block-dark-metal-xlarge rotate: false - xy: 957, 975 + xy: 857, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-dark-panel-4-large +block-dark-panel-1-large rotate: false xy: 393, 98 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-dark-panel-4-medium +block-dark-panel-1-medium rotate: false - xy: 1919, 878 + xy: 1533, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-dark-panel-4-small +block-dark-panel-1-small rotate: false - xy: 1114, 546 + xy: 680, 168 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-dark-panel-4-tiny +block-dark-panel-1-tiny rotate: false - xy: 1324, 528 + xy: 1621, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-dark-panel-4-xlarge +block-dark-panel-1-xlarge rotate: false - xy: 1007, 975 + xy: 907, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-dark-panel-5-large +block-dark-panel-2-large rotate: false xy: 393, 56 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-dark-panel-5-medium +block-dark-panel-2-medium rotate: false - xy: 1953, 878 + xy: 1567, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-dark-panel-5-small +block-dark-panel-2-small rotate: false - xy: 1140, 546 + xy: 706, 168 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-dark-panel-5-tiny +block-dark-panel-2-tiny rotate: false - xy: 1342, 528 + xy: 1639, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-dark-panel-5-xlarge +block-dark-panel-2-xlarge rotate: false - xy: 1057, 975 + xy: 957, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-dark-panel-6-large +block-dark-panel-3-large rotate: false xy: 393, 14 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-dark-panel-6-medium +block-dark-panel-3-medium rotate: false - xy: 1987, 907 + xy: 1601, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-dark-panel-6-small +block-dark-panel-3-small rotate: false - xy: 1166, 546 + xy: 548, 134 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-dark-panel-6-tiny +block-dark-panel-3-tiny rotate: false - xy: 1360, 528 + xy: 1657, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-dark-panel-6-xlarge +block-dark-panel-3-xlarge rotate: false - xy: 1107, 975 + xy: 1007, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-darksand-large +block-dark-panel-4-large rotate: false xy: 443, 274 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-darksand-medium +block-dark-panel-4-medium rotate: false - xy: 1987, 873 + xy: 1635, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-darksand-small +block-dark-panel-4-small rotate: false - xy: 1192, 546 + xy: 548, 108 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-darksand-tainted-water-large +block-dark-panel-4-tiny + rotate: false + xy: 1675, 758 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-dark-panel-4-xlarge + rotate: false + xy: 1057, 975 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-dark-panel-5-large rotate: false xy: 435, 232 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-darksand-tainted-water-medium +block-dark-panel-5-medium rotate: false - xy: 1664, 865 + xy: 1669, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-darksand-tainted-water-small +block-dark-panel-5-small rotate: false - xy: 1218, 546 + xy: 548, 82 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-darksand-tainted-water-tiny +block-dark-panel-5-tiny rotate: false - xy: 1378, 528 + xy: 1693, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-darksand-tainted-water-xlarge +block-dark-panel-5-xlarge rotate: false - xy: 1157, 975 + xy: 1107, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-darksand-tiny - rotate: false - xy: 1396, 528 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-darksand-water-large +block-dark-panel-6-large rotate: false xy: 435, 190 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-darksand-water-medium +block-dark-panel-6-medium rotate: false - xy: 1698, 865 + xy: 1703, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-darksand-water-small +block-dark-panel-6-small rotate: false - xy: 1244, 546 + xy: 548, 56 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-darksand-water-tiny +block-dark-panel-6-tiny rotate: false - xy: 1414, 528 + xy: 1711, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-darksand-water-xlarge +block-dark-panel-6-xlarge rotate: false - xy: 1207, 975 + xy: 1157, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-darksand-xlarge - rotate: false - xy: 1257, 975 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-dart-mech-pad-large +block-darksand-large rotate: false xy: 435, 148 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-dart-mech-pad-medium +block-darksand-medium rotate: false - xy: 1732, 865 + xy: 1737, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-dart-mech-pad-small +block-darksand-small rotate: false - xy: 1270, 546 + xy: 548, 30 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-dart-mech-pad-tiny - rotate: false - xy: 1432, 528 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-dart-mech-pad-xlarge - rotate: false - xy: 1307, 975 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-deepwater-large +block-darksand-tainted-water-large rotate: false xy: 435, 106 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-deepwater-medium +block-darksand-tainted-water-medium rotate: false - xy: 1766, 865 + xy: 1771, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-deepwater-small +block-darksand-tainted-water-small rotate: false - xy: 1296, 546 + xy: 732, 212 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-deepwater-tiny +block-darksand-tainted-water-tiny rotate: false - xy: 1450, 528 + xy: 1729, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-deepwater-xlarge +block-darksand-tainted-water-xlarge rotate: false - xy: 1357, 975 + xy: 1207, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-delta-mech-pad-large +block-darksand-tiny + rotate: false + xy: 1747, 758 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-darksand-water-large rotate: false xy: 435, 64 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-delta-mech-pad-medium +block-darksand-water-medium rotate: false - xy: 1800, 865 + xy: 1805, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-delta-mech-pad-small +block-darksand-water-small rotate: false - xy: 1322, 546 + xy: 732, 186 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-delta-mech-pad-tiny +block-darksand-water-tiny rotate: false - xy: 1468, 528 + xy: 1765, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-delta-mech-pad-xlarge +block-darksand-water-xlarge rotate: false - xy: 1407, 975 + xy: 1257, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-differential-generator-large +block-darksand-xlarge + rotate: false + xy: 1307, 975 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-dart-ship-pad-large rotate: false xy: 435, 22 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-differential-generator-medium +block-dart-ship-pad-medium rotate: false - xy: 1834, 865 + xy: 1839, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-differential-generator-small +block-dart-ship-pad-small rotate: false - xy: 1348, 546 + xy: 758, 212 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-differential-generator-tiny +block-dart-ship-pad-tiny rotate: false - xy: 1486, 528 + xy: 1783, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-differential-generator-xlarge +block-dart-ship-pad-xlarge + rotate: false + xy: 1357, 975 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-deepwater-large + rotate: false + xy: 493, 324 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-deepwater-medium + rotate: false + xy: 1873, 828 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-deepwater-small + rotate: false + xy: 758, 186 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-deepwater-tiny + rotate: false + xy: 1801, 758 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-deepwater-xlarge + rotate: false + xy: 1407, 975 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-delta-mech-pad-large + rotate: false + xy: 485, 282 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-delta-mech-pad-medium + rotate: false + xy: 1907, 828 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-delta-mech-pad-small + rotate: false + xy: 784, 212 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-delta-mech-pad-tiny + rotate: false + xy: 1819, 758 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-delta-mech-pad-xlarge rotate: false xy: 1457, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-diode-large +block-differential-generator-large rotate: false - xy: 493, 298 + xy: 543, 374 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-diode-medium +block-differential-generator-medium rotate: false - xy: 1868, 865 + xy: 1941, 828 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-diode-small +block-differential-generator-small rotate: false - xy: 1374, 546 + xy: 784, 186 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-diode-tiny +block-differential-generator-tiny rotate: false - xy: 1504, 528 + xy: 1837, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-diode-xlarge +block-differential-generator-xlarge rotate: false xy: 1507, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-distributor-large +block-diode-large rotate: false - xy: 535, 298 + xy: 535, 332 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-distributor-medium +block-diode-medium rotate: false - xy: 859, 836 + xy: 1321, 786 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-distributor-small +block-diode-small rotate: false - xy: 1400, 546 + xy: 810, 212 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-distributor-tiny +block-diode-tiny rotate: false - xy: 1522, 528 + xy: 1855, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-distributor-xlarge +block-diode-xlarge rotate: false xy: 1557, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-door-large +block-distributor-large rotate: false - xy: 485, 256 + xy: 593, 398 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-door-large-large +block-distributor-medium rotate: false - xy: 527, 256 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-door-large-medium - rotate: false - xy: 859, 802 + xy: 1279, 744 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-door-large-small +block-distributor-small rotate: false - xy: 1426, 546 + xy: 810, 186 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-door-large-tiny +block-distributor-tiny rotate: false - xy: 1540, 528 + xy: 1873, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-door-large-xlarge +block-distributor-xlarge rotate: false xy: 1607, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-door-medium +block-door-large rotate: false - xy: 893, 836 + xy: 635, 398 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-door-large-large + rotate: false + xy: 585, 356 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-door-large-medium + rotate: false + xy: 1237, 702 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-door-small +block-door-large-small rotate: false - xy: 1452, 546 + xy: 836, 212 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-door-tiny +block-door-large-tiny rotate: false - xy: 1558, 528 + xy: 1891, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-door-xlarge +block-door-large-xlarge rotate: false xy: 1657, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-draug-factory-large +block-door-medium rotate: false - xy: 477, 214 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-draug-factory-medium - rotate: false - xy: 859, 768 + xy: 1229, 668 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-draug-factory-small +block-door-small rotate: false - xy: 1478, 546 + xy: 836, 186 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-draug-factory-tiny +block-door-tiny rotate: false - xy: 1576, 528 + xy: 1909, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-draug-factory-xlarge +block-door-xlarge rotate: false xy: 1707, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-dunerocks-large +block-draug-factory-large rotate: false - xy: 477, 172 + xy: 627, 356 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-dunerocks-medium +block-draug-factory-medium rotate: false - xy: 927, 836 + xy: 1161, 626 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-dunerocks-small +block-draug-factory-small rotate: false - xy: 1504, 546 + xy: 732, 160 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-dunerocks-tiny +block-draug-factory-tiny rotate: false - xy: 1594, 528 + xy: 1927, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-dunerocks-xlarge +block-draug-factory-xlarge rotate: false xy: 1757, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-duo-large +block-dunerocks-large rotate: false - xy: 519, 214 + xy: 577, 314 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-duo-medium +block-dunerocks-medium rotate: false - xy: 893, 802 + xy: 1195, 626 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-duo-small +block-dunerocks-small rotate: false - xy: 1530, 546 + xy: 758, 160 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-duo-tiny +block-dunerocks-tiny rotate: false - xy: 1612, 528 + xy: 1945, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-duo-xlarge +block-dunerocks-xlarge rotate: false xy: 1807, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-force-projector-large +block-duo-large rotate: false - xy: 477, 130 + xy: 619, 314 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-force-projector-medium +block-duo-medium rotate: false - xy: 859, 734 + xy: 1229, 634 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-force-projector-small +block-duo-small rotate: false - xy: 1556, 546 + xy: 784, 160 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-force-projector-tiny +block-duo-tiny rotate: false - xy: 1927, 860 + xy: 1963, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-force-projector-xlarge +block-duo-xlarge rotate: false xy: 1857, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-fortress-factory-large +block-force-projector-large rotate: false - xy: 519, 172 + xy: 535, 290 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-fortress-factory-medium +block-force-projector-medium rotate: false - xy: 961, 836 + xy: 1157, 592 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-fortress-factory-small +block-force-projector-small rotate: false - xy: 1582, 546 + xy: 810, 160 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-fortress-factory-tiny +block-force-projector-tiny rotate: false - xy: 1945, 860 + xy: 1479, 732 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-fortress-factory-xlarge +block-force-projector-xlarge rotate: false xy: 1907, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-fuse-large +block-fortress-factory-large rotate: false - xy: 477, 88 + xy: 577, 272 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-fuse-medium +block-fortress-factory-medium rotate: false - xy: 927, 802 + xy: 1191, 592 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-fuse-small +block-fortress-factory-small rotate: false - xy: 1608, 546 + xy: 836, 160 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-fuse-tiny +block-fortress-factory-tiny rotate: false - xy: 1927, 842 + xy: 1479, 714 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-fuse-xlarge +block-fortress-factory-xlarge rotate: false xy: 1957, 975 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-ghoul-factory-large +block-fuse-large rotate: false - xy: 519, 130 + xy: 619, 272 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-ghoul-factory-medium +block-fuse-medium rotate: false - xy: 893, 768 + xy: 1153, 558 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-ghoul-factory-small +block-fuse-small rotate: false - xy: 771, 2 + xy: 862, 182 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-ghoul-factory-tiny +block-fuse-tiny rotate: false - xy: 1963, 860 + xy: 896, 8 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-ghoul-factory-xlarge +block-fuse-xlarge rotate: false xy: 345, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-glaive-ship-pad-large +block-ghoul-factory-large rotate: false - xy: 477, 46 + xy: 769, 532 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-glaive-ship-pad-medium +block-ghoul-factory-medium rotate: false - xy: 859, 700 + xy: 1187, 558 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-glaive-ship-pad-small +block-ghoul-factory-small rotate: false - xy: 797, 2 + xy: 888, 182 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-glaive-ship-pad-tiny +block-ghoul-factory-tiny rotate: false - xy: 1945, 842 + xy: 1361, 620 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-glaive-ship-pad-xlarge +block-ghoul-factory-xlarge rotate: false xy: 395, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-graphite-press-large +block-glaive-ship-pad-large rotate: false - xy: 519, 88 + xy: 769, 490 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-graphite-press-medium +block-glaive-ship-pad-medium rotate: false - xy: 995, 836 + xy: 895, 550 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-graphite-press-small +block-glaive-ship-pad-small rotate: false - xy: 823, 2 + xy: 862, 156 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-graphite-press-tiny +block-glaive-ship-pad-tiny rotate: false - xy: 1927, 824 + xy: 1361, 602 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-graphite-press-xlarge +block-glaive-ship-pad-xlarge rotate: false xy: 445, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-grass-large +block-graphite-press-large rotate: false - xy: 519, 46 + xy: 769, 448 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-grass-medium +block-graphite-press-medium rotate: false - xy: 961, 802 + xy: 895, 516 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-grass-small +block-graphite-press-small rotate: false - xy: 849, 2 + xy: 888, 156 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-grass-tiny +block-graphite-press-tiny rotate: false - xy: 1963, 842 + xy: 1379, 620 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-grass-xlarge +block-graphite-press-xlarge rotate: false xy: 495, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-hail-large +block-grass-large rotate: false - xy: 477, 4 + xy: 811, 536 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-hail-medium +block-grass-medium rotate: false - xy: 927, 768 + xy: 895, 482 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-hail-small +block-grass-small rotate: false - xy: 875, 2 + xy: 576, 142 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-hail-tiny +block-grass-tiny rotate: false - xy: 1945, 824 + xy: 1379, 602 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-hail-xlarge +block-grass-xlarge rotate: false xy: 545, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-holostone-large +block-hail-large rotate: false - xy: 519, 4 + xy: 811, 494 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-holostone-medium +block-hail-medium rotate: false - xy: 893, 734 + xy: 895, 448 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-holostone-small +block-hail-small rotate: false - xy: 901, 2 + xy: 602, 142 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-holostone-tiny +block-hail-tiny rotate: false - xy: 1927, 806 + xy: 1981, 758 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-holostone-xlarge +block-hail-xlarge rotate: false xy: 595, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-hotrock-large +block-holostone-large rotate: false - xy: 627, 432 + xy: 811, 452 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-hotrock-medium +block-holostone-medium rotate: false - xy: 1029, 836 + xy: 895, 414 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-hotrock-small +block-holostone-small rotate: false - xy: 927, 2 + xy: 628, 142 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-hotrock-tiny +block-holostone-tiny rotate: false - xy: 1963, 824 + xy: 1999, 761 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-hotrock-xlarge +block-holostone-xlarge rotate: false xy: 645, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-ice-large +block-hotrock-large rotate: false - xy: 627, 390 + xy: 853, 536 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-ice-medium +block-hotrock-medium rotate: false - xy: 995, 802 + xy: 929, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-ice-small +block-hotrock-small rotate: false - xy: 953, 6 + xy: 654, 142 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-ice-snow-large +block-hotrock-tiny rotate: false - xy: 627, 348 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-ice-snow-medium - rotate: false - xy: 961, 768 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-ice-snow-small - rotate: false - xy: 979, 6 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-ice-snow-tiny - rotate: false - xy: 1945, 806 + xy: 932, 187 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-ice-snow-xlarge +block-hotrock-xlarge rotate: false xy: 695, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-ice-tiny +block-ice-large rotate: false - xy: 1927, 788 + xy: 853, 494 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-ice-medium + rotate: false + xy: 963, 545 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-ice-small + rotate: false + xy: 680, 142 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-ice-snow-large + rotate: false + xy: 853, 452 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-ice-snow-medium + rotate: false + xy: 929, 511 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-ice-snow-small + rotate: false + xy: 706, 142 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-ice-snow-tiny + rotate: false + xy: 950, 187 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-ice-xlarge +block-ice-snow-xlarge rotate: false xy: 101, 478 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-icerocks-large +block-ice-tiny rotate: false - xy: 585, 306 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-icerocks-medium - rotate: false - xy: 927, 734 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-icerocks-small - rotate: false - xy: 1005, 6 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-icerocks-tiny - rotate: false - xy: 1963, 806 + xy: 932, 169 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-icerocks-xlarge +block-ice-xlarge rotate: false xy: 101, 428 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-ignarock-large +block-icerocks-large rotate: false - xy: 627, 306 + xy: 685, 406 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-ignarock-medium +block-icerocks-medium rotate: false - xy: 893, 700 + xy: 997, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-ignarock-small +block-icerocks-small rotate: false - xy: 1634, 585 + xy: 574, 116 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-ignarock-tiny +block-icerocks-tiny rotate: false - xy: 1945, 788 + xy: 968, 187 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-ignarock-xlarge +block-icerocks-xlarge rotate: false xy: 101, 378 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-illuminator-large +block-ignarock-large rotate: false - xy: 677, 482 + xy: 727, 406 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-illuminator-medium +block-ignarock-medium rotate: false - xy: 1063, 836 + xy: 963, 511 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-illuminator-small +block-ignarock-small rotate: false - xy: 1634, 559 + xy: 574, 90 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-illuminator-tiny +block-ignarock-tiny rotate: false - xy: 1927, 770 + xy: 932, 151 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-illuminator-xlarge +block-ignarock-xlarge rotate: false xy: 101, 328 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-impact-reactor-large +block-illuminator-large rotate: false - xy: 669, 440 + xy: 769, 406 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-impact-reactor-medium +block-illuminator-medium rotate: false - xy: 1029, 802 + xy: 929, 477 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-impact-reactor-small +block-illuminator-small rotate: false - xy: 1634, 533 + xy: 600, 116 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-impact-reactor-tiny +block-illuminator-tiny rotate: false - xy: 1963, 788 + xy: 950, 169 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-impact-reactor-xlarge +block-illuminator-xlarge rotate: false xy: 101, 278 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 +block-impact-reactor-large + rotate: false + xy: 811, 410 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-impact-reactor-medium + rotate: false + xy: 1031, 545 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-impact-reactor-small + rotate: false + xy: 574, 64 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-impact-reactor-tiny + rotate: false + xy: 986, 187 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-impact-reactor-xlarge + rotate: false + xy: 101, 228 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 block-incinerator-large rotate: false - xy: 669, 398 + xy: 853, 410 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-incinerator-medium rotate: false - xy: 995, 768 + xy: 997, 511 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-incinerator-small rotate: false - xy: 1655, 611 + xy: 600, 90 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-incinerator-tiny rotate: false - xy: 1945, 770 + xy: 950, 151 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-incinerator-xlarge rotate: false - xy: 101, 228 + xy: 101, 178 size: 48, 48 orig: 48, 48 offset: 0, 0 @@ -11652,4690 +11791,4725 @@ block-inverted-sorter-large index: -1 block-inverted-sorter-medium rotate: false - xy: 961, 734 + xy: 963, 477 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-inverted-sorter-small rotate: false - xy: 1660, 585 + xy: 626, 116 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-inverted-sorter-tiny rotate: false - xy: 1927, 752 + xy: 968, 169 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-inverted-sorter-xlarge rotate: false - xy: 101, 178 + xy: 101, 128 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-item-source-large rotate: false - xy: 669, 314 + xy: 661, 314 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-item-source-medium rotate: false - xy: 927, 700 + xy: 929, 443 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-item-source-small rotate: false - xy: 1660, 559 + xy: 574, 38 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-item-source-tiny rotate: false - xy: 1963, 770 + xy: 1004, 187 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-item-source-xlarge rotate: false - xy: 101, 128 + xy: 101, 78 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-item-void-large rotate: false - xy: 719, 490 + xy: 661, 272 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-item-void-medium rotate: false - xy: 1097, 836 + xy: 1065, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-item-void-small rotate: false - xy: 1660, 533 + xy: 600, 64 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-item-void-tiny rotate: false - xy: 1945, 752 + xy: 968, 151 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-item-void-xlarge rotate: false - xy: 101, 78 + xy: 101, 28 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-javelin-ship-pad-large rotate: false - xy: 769, 532 + xy: 711, 364 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-javelin-ship-pad-medium rotate: false - xy: 1063, 802 + xy: 1031, 511 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-javelin-ship-pad-small rotate: false - xy: 1641, 839 + xy: 626, 90 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-javelin-ship-pad-tiny rotate: false - xy: 1963, 752 + xy: 986, 169 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-javelin-ship-pad-xlarge rotate: false - xy: 101, 28 + xy: 231, 608 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-junction-large rotate: false - xy: 761, 490 + xy: 753, 364 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-junction-medium rotate: false - xy: 1029, 768 + xy: 997, 477 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-junction-small rotate: false - xy: 1641, 813 + xy: 652, 116 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-junction-tiny rotate: false - xy: 1981, 855 + xy: 1022, 187 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-junction-xlarge rotate: false - xy: 231, 608 + xy: 231, 558 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-kiln-large rotate: false - xy: 811, 536 + xy: 795, 364 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-kiln-medium rotate: false - xy: 995, 734 + xy: 963, 443 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-kiln-small rotate: false - xy: 1667, 839 + xy: 600, 38 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-kiln-tiny rotate: false - xy: 1999, 855 + xy: 986, 151 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-kiln-xlarge rotate: false - xy: 231, 558 + xy: 745, 866 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-lancer-large rotate: false - xy: 853, 536 + xy: 837, 368 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-lancer-medium rotate: false - xy: 961, 700 + xy: 1099, 545 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-lancer-small rotate: false - xy: 1641, 787 + xy: 626, 64 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-lancer-tiny rotate: false - xy: 1981, 837 + xy: 1004, 169 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-lancer-xlarge rotate: false - xy: 745, 866 + xy: 151, 508 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-laser-drill-large rotate: false - xy: 569, 256 + xy: 879, 368 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-laser-drill-medium rotate: false - xy: 1131, 836 + xy: 1065, 511 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-laser-drill-small rotate: false - xy: 1693, 839 + xy: 652, 90 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-laser-drill-tiny rotate: false - xy: 1981, 819 + xy: 1040, 187 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-laser-drill-xlarge rotate: false - xy: 151, 508 + xy: 151, 458 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-launch-pad-large rotate: false - xy: 561, 214 + xy: 477, 232 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-launch-pad-large-large rotate: false - xy: 561, 172 + xy: 477, 190 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-launch-pad-large-medium rotate: false - xy: 1097, 802 + xy: 1031, 477 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-launch-pad-large-small rotate: false - xy: 1667, 813 + xy: 678, 116 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-launch-pad-large-tiny rotate: false - xy: 1999, 837 + xy: 1004, 151 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-launch-pad-large-xlarge rotate: false - xy: 151, 458 + xy: 201, 508 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-launch-pad-medium rotate: false - xy: 1063, 768 + xy: 997, 443 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-launch-pad-small rotate: false - xy: 1641, 761 + xy: 626, 38 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-launch-pad-tiny rotate: false - xy: 1981, 801 + xy: 1022, 169 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-launch-pad-xlarge rotate: false - xy: 201, 508 + xy: 151, 408 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-liquid-junction-large rotate: false - xy: 561, 130 + xy: 477, 148 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-liquid-junction-medium rotate: false - xy: 1029, 734 + xy: 1099, 511 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-junction-small rotate: false - xy: 1719, 839 + xy: 652, 64 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-liquid-junction-tiny rotate: false - xy: 1999, 819 + xy: 1058, 187 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-liquid-junction-xlarge rotate: false - xy: 151, 408 + xy: 201, 458 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-liquid-router-large rotate: false - xy: 561, 88 + xy: 477, 106 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-liquid-router-medium rotate: false - xy: 995, 700 + xy: 1065, 477 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-router-small rotate: false - xy: 1693, 813 + xy: 678, 90 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-liquid-router-tiny rotate: false - xy: 1981, 783 + xy: 1022, 151 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-liquid-router-xlarge rotate: false - xy: 201, 458 + xy: 151, 358 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-liquid-source-large rotate: false - xy: 561, 46 + xy: 477, 64 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-liquid-source-medium rotate: false - xy: 1165, 836 + xy: 1031, 443 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-source-small rotate: false - xy: 1667, 787 + xy: 704, 116 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-liquid-source-tiny rotate: false - xy: 1999, 801 + xy: 1040, 169 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-liquid-source-xlarge rotate: false - xy: 151, 358 + xy: 201, 408 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-liquid-tank-large rotate: false - xy: 561, 4 + xy: 477, 22 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-liquid-tank-medium rotate: false - xy: 1131, 802 + xy: 1099, 477 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-tank-small rotate: false - xy: 1641, 735 + xy: 652, 38 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-liquid-tank-tiny rotate: false - xy: 1981, 765 + xy: 1076, 187 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-liquid-tank-xlarge rotate: false - xy: 201, 408 + xy: 151, 308 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-liquid-void-large rotate: false - xy: 611, 264 + xy: 703, 314 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-liquid-void-medium rotate: false - xy: 1097, 768 + xy: 1065, 443 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-liquid-void-small rotate: false - xy: 1745, 839 + xy: 678, 64 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-liquid-void-tiny rotate: false - xy: 1999, 783 + xy: 1040, 151 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-liquid-void-xlarge rotate: false - xy: 151, 308 + xy: 201, 358 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-magmarock-large rotate: false - xy: 653, 264 + xy: 703, 272 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-magmarock-medium rotate: false - xy: 1063, 734 + xy: 1099, 443 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-magmarock-small rotate: false - xy: 1719, 813 + xy: 704, 90 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-magmarock-tiny rotate: false - xy: 1999, 765 + xy: 1058, 169 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-magmarock-xlarge rotate: false - xy: 201, 358 + xy: 151, 258 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-mass-driver-large rotate: false - xy: 711, 440 + xy: 745, 322 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mass-driver-medium rotate: false - xy: 1029, 700 + xy: 929, 409 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mass-driver-small rotate: false - xy: 1693, 787 + xy: 678, 38 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mass-driver-tiny rotate: false - xy: 2017, 845 + xy: 1058, 151 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-mass-driver-xlarge rotate: false - xy: 151, 258 + xy: 201, 308 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-mechanical-drill-large rotate: false - xy: 711, 398 + xy: 745, 280 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mechanical-drill-medium rotate: false - xy: 1199, 836 + xy: 963, 409 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mechanical-drill-small rotate: false - xy: 1667, 761 + xy: 704, 64 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mechanical-drill-tiny rotate: false - xy: 2017, 827 + xy: 1076, 169 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-mechanical-drill-xlarge rotate: false - xy: 201, 308 + xy: 151, 208 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-mechanical-pump-large rotate: false - xy: 711, 356 + xy: 787, 322 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mechanical-pump-medium rotate: false - xy: 1165, 802 + xy: 997, 409 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mechanical-pump-small rotate: false - xy: 1641, 709 + xy: 704, 38 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mechanical-pump-tiny rotate: false - xy: 2017, 809 + xy: 1076, 151 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-mechanical-pump-xlarge rotate: false - xy: 151, 208 + xy: 201, 258 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-meltdown-large rotate: false - xy: 711, 314 + xy: 787, 280 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-meltdown-medium rotate: false - xy: 1131, 768 + xy: 1031, 409 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-meltdown-small rotate: false - xy: 1771, 839 + xy: 732, 134 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-meltdown-tiny rotate: false - xy: 2017, 791 + xy: 932, 133 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-meltdown-xlarge rotate: false - xy: 201, 258 + xy: 151, 158 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-melter-large rotate: false - xy: 695, 272 + xy: 745, 238 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-melter-medium rotate: false - xy: 1097, 734 + xy: 1065, 409 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-melter-small rotate: false - xy: 1745, 813 + xy: 758, 134 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-melter-tiny rotate: false - xy: 2017, 773 + xy: 950, 133 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-melter-xlarge rotate: false - xy: 151, 158 + xy: 201, 208 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-mend-projector-large rotate: false - xy: 753, 448 + xy: 787, 238 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mend-projector-medium rotate: false - xy: 1063, 700 + xy: 1099, 409 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mend-projector-small rotate: false - xy: 1719, 787 + xy: 784, 134 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mend-projector-tiny rotate: false - xy: 1981, 747 + xy: 968, 133 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-mend-projector-xlarge rotate: false - xy: 201, 208 + xy: 151, 108 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-mender-large rotate: false - xy: 753, 406 + xy: 829, 322 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-mender-medium rotate: false - xy: 1233, 836 + xy: 921, 375 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-mender-small rotate: false - xy: 1693, 761 + xy: 810, 134 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-mender-tiny rotate: false - xy: 1999, 747 + xy: 986, 133 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-mender-xlarge rotate: false - xy: 151, 108 + xy: 201, 158 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-message-large rotate: false - xy: 753, 364 + xy: 829, 280 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-message-medium rotate: false - xy: 1199, 802 + xy: 955, 375 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-message-small rotate: false - xy: 1667, 735 + xy: 836, 134 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-message-tiny rotate: false - xy: 2017, 755 + xy: 1004, 133 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-message-xlarge rotate: false - xy: 201, 158 + xy: 151, 58 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-metal-floor-2-large rotate: false - xy: 753, 322 + xy: 829, 238 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-metal-floor-2-medium rotate: false - xy: 1165, 768 + xy: 989, 375 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-2-small rotate: false - xy: 1797, 839 + xy: 730, 108 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-metal-floor-2-tiny rotate: false - xy: 1937, 734 + xy: 1022, 133 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-metal-floor-2-xlarge rotate: false - xy: 151, 58 + xy: 201, 108 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-metal-floor-3-large rotate: false - xy: 737, 272 + xy: 871, 326 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-metal-floor-3-medium rotate: false - xy: 1131, 734 + xy: 1023, 375 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-3-small rotate: false - xy: 1771, 813 + xy: 730, 82 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-metal-floor-3-tiny rotate: false - xy: 1955, 734 + xy: 1040, 133 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-metal-floor-3-xlarge rotate: false - xy: 201, 108 + xy: 201, 58 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-metal-floor-5-large rotate: false - xy: 803, 490 + xy: 871, 284 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-metal-floor-5-medium rotate: false - xy: 1097, 700 + xy: 1057, 375 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-5-small rotate: false - xy: 1745, 787 + xy: 756, 108 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-metal-floor-5-tiny rotate: false - xy: 2017, 737 + xy: 1058, 133 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-metal-floor-5-xlarge rotate: false - xy: 201, 58 + xy: 251, 508 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-metal-floor-damaged-large rotate: false - xy: 795, 448 + xy: 871, 242 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-metal-floor-damaged-medium rotate: false - xy: 1267, 836 + xy: 1091, 375 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-damaged-small rotate: false - xy: 1719, 761 + xy: 730, 56 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-metal-floor-damaged-tiny rotate: false - xy: 1937, 716 + xy: 1076, 133 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-metal-floor-damaged-xlarge rotate: false - xy: 251, 508 + xy: 251, 458 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-metal-floor-large rotate: false - xy: 795, 406 + xy: 913, 326 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-metal-floor-medium rotate: false - xy: 1233, 802 + xy: 955, 341 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-metal-floor-small rotate: false - xy: 1693, 735 + xy: 756, 82 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-metal-floor-tiny rotate: false - xy: 1955, 716 + xy: 1094, 187 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-metal-floor-xlarge rotate: false - xy: 251, 458 + xy: 251, 408 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-moss-large rotate: false - xy: 795, 364 + xy: 913, 284 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-moss-medium rotate: false - xy: 1199, 768 + xy: 955, 307 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-moss-small rotate: false - xy: 1667, 709 + xy: 782, 108 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-moss-tiny rotate: false - xy: 1973, 729 + xy: 1094, 169 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-moss-xlarge rotate: false - xy: 251, 408 + xy: 251, 358 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-multi-press-large rotate: false - xy: 795, 322 + xy: 913, 242 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-multi-press-medium rotate: false - xy: 1165, 734 + xy: 989, 341 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-multi-press-small rotate: false - xy: 1823, 839 + xy: 756, 56 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-multi-press-tiny rotate: false - xy: 1991, 729 + xy: 1094, 151 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-multi-press-xlarge rotate: false - xy: 251, 358 + xy: 251, 308 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-oil-extractor-large rotate: false - xy: 845, 494 + xy: 821, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-oil-extractor-medium rotate: false - xy: 1131, 700 + xy: 955, 273 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-oil-extractor-small rotate: false - xy: 1797, 813 + xy: 782, 82 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-oil-extractor-tiny rotate: false - xy: 1973, 711 + xy: 1094, 133 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-oil-extractor-xlarge rotate: false - xy: 251, 308 + xy: 251, 258 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-omega-mech-pad-large rotate: false - xy: 779, 280 + xy: 863, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-omega-mech-pad-medium rotate: false - xy: 1301, 836 + xy: 989, 307 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-omega-mech-pad-small rotate: false - xy: 1771, 787 + xy: 808, 108 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-omega-mech-pad-tiny rotate: false - xy: 1991, 711 + xy: 1435, 659 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-omega-mech-pad-xlarge rotate: false - xy: 251, 258 + xy: 251, 208 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-ore-coal-large rotate: false - xy: 821, 280 + xy: 905, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-coal-medium rotate: false - xy: 1267, 802 + xy: 1023, 341 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-coal-small rotate: false - xy: 1745, 761 + xy: 782, 56 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-coal-tiny rotate: false - xy: 2009, 719 + xy: 1497, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-ore-coal-xlarge rotate: false - xy: 251, 208 + xy: 251, 158 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-ore-copper-large rotate: false - xy: 603, 214 + xy: 947, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-copper-medium rotate: false - xy: 1233, 768 + xy: 989, 273 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-copper-small rotate: false - xy: 1719, 735 + xy: 808, 82 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-copper-tiny rotate: false - xy: 2009, 701 + xy: 1497, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-ore-copper-xlarge rotate: false - xy: 251, 158 + xy: 251, 108 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-ore-lead-large rotate: false - xy: 603, 172 + xy: 989, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-lead-medium rotate: false - xy: 1199, 734 + xy: 1023, 307 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-lead-small rotate: false - xy: 1693, 709 + xy: 834, 108 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-lead-tiny rotate: false - xy: 2027, 719 + xy: 1515, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-ore-lead-xlarge rotate: false - xy: 251, 108 + xy: 251, 58 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-ore-scrap-large rotate: false - xy: 603, 130 + xy: 1031, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-scrap-medium rotate: false - xy: 1165, 700 + xy: 1057, 341 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-scrap-small rotate: false - xy: 1849, 839 + xy: 808, 56 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-scrap-tiny rotate: false - xy: 2027, 701 + xy: 1515, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-ore-scrap-xlarge rotate: false - xy: 251, 58 + xy: 151, 8 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-ore-thorium-large rotate: false - xy: 603, 88 + xy: 1073, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-thorium-medium rotate: false - xy: 1335, 836 + xy: 1023, 273 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-thorium-small rotate: false - xy: 1823, 813 + xy: 834, 82 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-thorium-tiny rotate: false - xy: 947, 540 + xy: 1533, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-ore-thorium-xlarge rotate: false - xy: 151, 8 + xy: 201, 8 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-ore-titanium-large rotate: false - xy: 603, 46 + xy: 1115, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ore-titanium-medium rotate: false - xy: 1301, 802 + xy: 1057, 307 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ore-titanium-small rotate: false - xy: 1797, 787 + xy: 834, 56 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ore-titanium-tiny rotate: false - xy: 965, 540 + xy: 1533, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-ore-titanium-xlarge rotate: false - xy: 201, 8 + xy: 251, 8 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-overdrive-projector-large rotate: false - xy: 603, 4 + xy: 1157, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-overdrive-projector-medium rotate: false - xy: 1267, 768 + xy: 1091, 341 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-overdrive-projector-small rotate: false - xy: 1771, 761 + xy: 862, 130 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-overdrive-projector-tiny rotate: false - xy: 983, 540 + xy: 1551, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-overdrive-projector-xlarge rotate: false - xy: 251, 8 + xy: 281, 619 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-overflow-gate-large rotate: false - xy: 645, 222 + xy: 1199, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-overflow-gate-medium rotate: false - xy: 1233, 734 + xy: 1057, 273 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-overflow-gate-small rotate: false - xy: 1745, 735 + xy: 888, 130 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-overflow-gate-tiny rotate: false - xy: 1001, 540 + xy: 1551, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-overflow-gate-xlarge rotate: false - xy: 281, 619 + xy: 281, 569 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-pebbles-large rotate: false - xy: 645, 180 + xy: 1241, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pebbles-medium rotate: false - xy: 1199, 700 + xy: 1091, 307 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pebbles-small rotate: false - xy: 1719, 709 + xy: 860, 104 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pebbles-tiny rotate: false - xy: 1019, 540 + xy: 1569, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-pebbles-xlarge rotate: false - xy: 281, 569 + xy: 301, 519 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-phantom-factory-large rotate: false - xy: 645, 138 + xy: 1283, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phantom-factory-medium rotate: false - xy: 1369, 836 + xy: 1091, 273 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phantom-factory-small rotate: false - xy: 1875, 839 + xy: 860, 78 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phantom-factory-tiny rotate: false - xy: 1037, 540 + xy: 1569, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-phantom-factory-xlarge rotate: false - xy: 301, 519 + xy: 301, 469 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-phase-conduit-large rotate: false - xy: 645, 96 + xy: 1325, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phase-conduit-medium rotate: false - xy: 1335, 802 + xy: 955, 239 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-conduit-small rotate: false - xy: 1849, 813 + xy: 886, 104 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phase-conduit-tiny rotate: false - xy: 955, 522 + xy: 1587, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-phase-conduit-xlarge rotate: false - xy: 301, 469 + xy: 301, 419 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-phase-conveyor-large rotate: false - xy: 645, 54 + xy: 1367, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phase-conveyor-medium rotate: false - xy: 1301, 768 + xy: 989, 239 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-conveyor-small rotate: false - xy: 1823, 787 + xy: 886, 78 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phase-conveyor-tiny rotate: false - xy: 973, 522 + xy: 1587, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-phase-conveyor-xlarge rotate: false - xy: 301, 419 + xy: 301, 369 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-phase-wall-large rotate: false - xy: 645, 12 + xy: 1409, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phase-wall-large-large rotate: false - xy: 695, 230 + xy: 1451, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phase-wall-large-medium rotate: false - xy: 1267, 734 + xy: 1023, 239 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-wall-large-small rotate: false - xy: 1797, 761 + xy: 860, 52 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phase-wall-large-tiny rotate: false - xy: 991, 522 + xy: 1605, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-phase-wall-large-xlarge rotate: false - xy: 301, 369 + xy: 301, 319 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-phase-wall-medium rotate: false - xy: 1233, 700 + xy: 1057, 239 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-wall-small rotate: false - xy: 1771, 735 + xy: 886, 52 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phase-wall-tiny rotate: false - xy: 1009, 522 + xy: 1605, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-phase-wall-xlarge rotate: false - xy: 301, 319 + xy: 301, 269 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-phase-weaver-large rotate: false - xy: 737, 230 + xy: 1493, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-phase-weaver-medium rotate: false - xy: 1403, 836 + xy: 1091, 239 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-phase-weaver-small rotate: false - xy: 1745, 709 + xy: 730, 30 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-phase-weaver-tiny rotate: false - xy: 1027, 522 + xy: 1623, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-phase-weaver-xlarge rotate: false - xy: 301, 269 + xy: 301, 219 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-pine-large rotate: false - xy: 779, 238 + xy: 1535, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pine-medium rotate: false - xy: 1369, 802 + xy: 1133, 524 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pine-small rotate: false - xy: 1875, 813 + xy: 756, 30 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pine-tiny rotate: false - xy: 965, 504 + xy: 1623, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-pine-xlarge rotate: false - xy: 301, 219 + xy: 301, 169 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-plastanium-compressor-large rotate: false - xy: 821, 238 + xy: 1577, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-plastanium-compressor-medium rotate: false - xy: 1335, 768 + xy: 1133, 490 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-plastanium-compressor-small rotate: false - xy: 1849, 787 + xy: 782, 30 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-plastanium-compressor-tiny rotate: false - xy: 983, 504 + xy: 1641, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-plastanium-compressor-xlarge rotate: false - xy: 301, 169 + xy: 301, 119 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-plastanium-wall-large rotate: false - xy: 687, 188 + xy: 1619, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-plastanium-wall-large-large rotate: false - xy: 687, 146 + xy: 1661, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-plastanium-wall-large-medium rotate: false - xy: 1301, 734 + xy: 1167, 524 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-plastanium-wall-large-small rotate: false - xy: 1823, 761 + xy: 808, 30 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-plastanium-wall-large-tiny rotate: false - xy: 1001, 504 + xy: 1641, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-plastanium-wall-large-xlarge rotate: false - xy: 301, 119 + xy: 301, 69 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-plastanium-wall-medium rotate: false - xy: 1267, 700 + xy: 1133, 456 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-plastanium-wall-small rotate: false - xy: 1797, 735 + xy: 834, 30 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-plastanium-wall-tiny rotate: false - xy: 1019, 504 + xy: 1659, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-plastanium-wall-xlarge rotate: false - xy: 301, 69 + xy: 301, 19 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-plated-conduit-large rotate: false - xy: 729, 188 + xy: 1703, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-plated-conduit-medium rotate: false - xy: 1437, 836 + xy: 1167, 490 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-plated-conduit-small rotate: false - xy: 1771, 709 + xy: 860, 26 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-plated-conduit-tiny rotate: false - xy: 965, 486 + xy: 1659, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-plated-conduit-xlarge rotate: false - xy: 301, 19 + xy: 795, 878 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-pneumatic-drill-large rotate: false - xy: 687, 104 + xy: 1745, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pneumatic-drill-medium rotate: false - xy: 1403, 802 + xy: 1133, 422 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pneumatic-drill-small rotate: false - xy: 1875, 787 + xy: 886, 26 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pneumatic-drill-tiny rotate: false - xy: 983, 486 + xy: 1677, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-pneumatic-drill-xlarge rotate: false - xy: 795, 878 + xy: 309, 816 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-power-node-large rotate: false - xy: 729, 146 + xy: 1787, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-power-node-large-large rotate: false - xy: 687, 62 + xy: 1829, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-power-node-large-medium rotate: false - xy: 1369, 768 + xy: 1167, 456 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-power-node-large-small rotate: false - xy: 1849, 761 + xy: 574, 12 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-power-node-large-tiny rotate: false - xy: 1001, 486 + xy: 1677, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-power-node-large-xlarge rotate: false - xy: 309, 816 + xy: 309, 766 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-power-node-medium rotate: false - xy: 1335, 734 + xy: 1167, 422 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-power-node-small rotate: false - xy: 1823, 735 + xy: 600, 12 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-power-node-tiny rotate: false - xy: 1019, 486 + xy: 1695, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-power-node-xlarge rotate: false - xy: 309, 766 + xy: 359, 816 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-power-source-large rotate: false - xy: 729, 104 + xy: 1871, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-power-source-medium rotate: false - xy: 1301, 700 + xy: 1201, 524 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-power-source-small rotate: false - xy: 1797, 709 + xy: 626, 12 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-power-source-tiny rotate: false - xy: 963, 468 + xy: 1695, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-power-source-xlarge rotate: false - xy: 359, 816 + xy: 309, 716 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-power-void-large rotate: false - xy: 687, 20 + xy: 1913, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-power-void-medium rotate: false - xy: 1471, 836 + xy: 1201, 490 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-power-void-small rotate: false - xy: 1875, 761 + xy: 652, 12 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-power-void-tiny rotate: false - xy: 963, 450 + xy: 1713, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-power-void-xlarge rotate: false - xy: 309, 716 + xy: 359, 766 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-pulse-conduit-large rotate: false - xy: 729, 62 + xy: 1955, 933 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pulse-conduit-medium rotate: false - xy: 1437, 802 + xy: 1201, 456 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pulse-conduit-small rotate: false - xy: 1849, 735 + xy: 678, 12 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pulse-conduit-tiny rotate: false - xy: 981, 468 + xy: 1713, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-pulse-conduit-xlarge rotate: false - xy: 359, 766 + xy: 409, 816 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-pulverizer-large rotate: false - xy: 729, 20 + xy: 845, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pulverizer-medium rotate: false - xy: 1403, 768 + xy: 1201, 422 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pulverizer-small rotate: false - xy: 1823, 709 + xy: 704, 12 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pulverizer-tiny rotate: false - xy: 963, 432 + xy: 1731, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-pulverizer-xlarge rotate: false - xy: 409, 816 + xy: 359, 716 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-pyratite-mixer-large rotate: false - xy: 887, 494 + xy: 887, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-pyratite-mixer-medium rotate: false - xy: 1369, 734 + xy: 1221, 558 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-pyratite-mixer-small rotate: false - xy: 1875, 735 + xy: 548, 4 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-pyratite-mixer-tiny rotate: false - xy: 999, 468 + xy: 1731, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-pyratite-mixer-xlarge rotate: false - xy: 359, 716 + xy: 409, 766 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-repair-point-large rotate: false - xy: 837, 448 + xy: 929, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-repair-point-medium rotate: false - xy: 1335, 700 + xy: 1225, 592 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-repair-point-small rotate: false - xy: 1849, 709 + xy: 730, 4 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-repair-point-tiny rotate: false - xy: 981, 450 + xy: 1749, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-repair-point-xlarge rotate: false - xy: 409, 766 + xy: 459, 816 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-revenant-factory-large rotate: false - xy: 837, 406 + xy: 971, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-revenant-factory-medium rotate: false - xy: 1505, 836 + xy: 1235, 524 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-revenant-factory-small rotate: false - xy: 1875, 709 + xy: 756, 4 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-revenant-factory-tiny rotate: false - xy: 963, 414 + xy: 1749, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-revenant-factory-xlarge rotate: false - xy: 459, 816 + xy: 409, 716 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-ripple-large rotate: false - xy: 837, 364 + xy: 1013, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-ripple-medium rotate: false - xy: 1471, 802 + xy: 1235, 490 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-ripple-small rotate: false - xy: 1658, 683 + xy: 782, 4 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-ripple-tiny rotate: false - xy: 1017, 468 + xy: 1767, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-ripple-xlarge rotate: false - xy: 409, 716 + xy: 459, 766 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-rock-large rotate: false - xy: 837, 322 + xy: 1055, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-rock-medium rotate: false - xy: 1437, 768 + xy: 1235, 456 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-rock-small rotate: false - xy: 1658, 657 + xy: 808, 4 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-rock-tiny rotate: false - xy: 999, 450 + xy: 1767, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-rock-xlarge rotate: false - xy: 459, 766 + xy: 509, 816 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-rocks-large rotate: false - xy: 879, 452 + xy: 1097, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-rocks-medium rotate: false - xy: 1403, 734 + xy: 1235, 422 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-rocks-small rotate: false - xy: 1684, 683 + xy: 834, 4 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-rocks-tiny rotate: false - xy: 981, 432 + xy: 1785, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-rocks-xlarge rotate: false - xy: 509, 816 + xy: 459, 716 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-rotary-pump-large rotate: false - xy: 879, 410 + xy: 1139, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-rotary-pump-medium rotate: false - xy: 1369, 700 + xy: 1255, 558 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-rotary-pump-small rotate: false - xy: 1710, 683 + xy: 2009, 813 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-rotary-pump-tiny rotate: false - xy: 963, 396 + xy: 1785, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-rotary-pump-xlarge rotate: false - xy: 459, 716 + xy: 509, 766 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-router-large rotate: false - xy: 879, 368 + xy: 1181, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-router-medium rotate: false - xy: 1539, 836 + xy: 1269, 524 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-router-small rotate: false - xy: 1684, 657 + xy: 1317, 760 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-router-tiny rotate: false - xy: 1017, 450 + xy: 1803, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-router-xlarge rotate: false - xy: 509, 766 + xy: 559, 816 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-rtg-generator-large rotate: false - xy: 879, 326 + xy: 1223, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-rtg-generator-medium rotate: false - xy: 1505, 802 + xy: 1269, 490 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-rtg-generator-small rotate: false - xy: 1736, 683 + xy: 1313, 734 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-rtg-generator-tiny rotate: false - xy: 999, 432 + xy: 1803, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-rtg-generator-xlarge rotate: false - xy: 559, 816 + xy: 509, 716 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-salt-large rotate: false - xy: 863, 280 + xy: 1265, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-salt-medium rotate: false - xy: 1471, 768 + xy: 1269, 456 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-salt-small rotate: false - xy: 1710, 657 + xy: 1305, 708 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-salt-tiny rotate: false - xy: 981, 414 + xy: 1821, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-salt-xlarge rotate: false - xy: 509, 716 + xy: 559, 766 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-saltrocks-large rotate: false - xy: 863, 238 + xy: 1307, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-saltrocks-medium rotate: false - xy: 1437, 734 + xy: 1269, 422 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-saltrocks-small rotate: false - xy: 1762, 683 + xy: 1343, 760 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-saltrocks-tiny rotate: false - xy: 963, 378 + xy: 1821, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-saltrocks-xlarge rotate: false - xy: 559, 766 + xy: 609, 816 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-salvo-large rotate: false - xy: 905, 284 + xy: 1349, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-salvo-medium rotate: false - xy: 1403, 700 + xy: 1133, 388 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-salvo-small rotate: false - xy: 1736, 657 + xy: 1339, 734 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-salvo-tiny rotate: false - xy: 1017, 432 + xy: 1839, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-salvo-xlarge rotate: false - xy: 609, 816 + xy: 559, 716 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-sand-boulder-large rotate: false - xy: 905, 242 + xy: 1391, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sand-boulder-medium rotate: false - xy: 1573, 836 + xy: 1167, 388 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sand-boulder-small rotate: false - xy: 1788, 683 + xy: 1331, 708 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sand-boulder-tiny rotate: false - xy: 999, 414 + xy: 1839, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-sand-boulder-xlarge rotate: false - xy: 559, 716 + xy: 609, 766 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-sand-large rotate: false - xy: 779, 196 + xy: 1433, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sand-medium rotate: false - xy: 1539, 802 + xy: 1201, 388 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sand-small rotate: false - xy: 1762, 657 + xy: 1331, 682 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sand-tiny rotate: false - xy: 981, 396 + xy: 1857, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-sand-water-large rotate: false - xy: 821, 196 + xy: 1475, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sand-water-medium rotate: false - xy: 1505, 768 + xy: 1235, 388 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sand-water-small rotate: false - xy: 1814, 683 + xy: 1331, 656 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sand-water-tiny rotate: false - xy: 963, 360 + xy: 1857, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-sand-water-xlarge rotate: false - xy: 609, 766 + xy: 659, 816 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-sand-xlarge rotate: false - xy: 659, 816 + xy: 609, 716 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-sandrocks-large rotate: false - xy: 863, 196 + xy: 1517, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sandrocks-medium rotate: false - xy: 1471, 734 + xy: 1269, 388 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sandrocks-small rotate: false - xy: 1788, 657 + xy: 1357, 708 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sandrocks-tiny rotate: false - xy: 1017, 414 + xy: 1875, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-sandrocks-xlarge rotate: false - xy: 609, 716 + xy: 659, 766 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-scatter-large rotate: false - xy: 905, 200 + xy: 1559, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scatter-medium rotate: false - xy: 1437, 700 + xy: 1125, 354 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scatter-small rotate: false - xy: 1840, 683 + xy: 1357, 682 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scatter-tiny rotate: false - xy: 999, 396 + xy: 1875, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-scatter-xlarge rotate: false - xy: 659, 766 + xy: 709, 816 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-scorch-large rotate: false - xy: 771, 154 + xy: 1601, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scorch-medium rotate: false - xy: 1607, 836 + xy: 1125, 320 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scorch-small rotate: false - xy: 1814, 657 + xy: 1357, 656 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scorch-tiny rotate: false - xy: 981, 378 + xy: 1893, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-scorch-xlarge rotate: false - xy: 709, 816 + xy: 659, 716 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-scrap-wall-gigantic-large rotate: false - xy: 771, 112 + xy: 1643, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scrap-wall-gigantic-medium rotate: false - xy: 1573, 802 + xy: 1159, 354 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-gigantic-small rotate: false - xy: 1866, 683 + xy: 1365, 734 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scrap-wall-gigantic-tiny rotate: false - xy: 963, 342 + xy: 1893, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-scrap-wall-gigantic-xlarge rotate: false - xy: 659, 716 + xy: 709, 766 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-scrap-wall-huge-large rotate: false - xy: 813, 154 + xy: 1685, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scrap-wall-huge-medium rotate: false - xy: 1539, 768 + xy: 1125, 286 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-huge-small rotate: false - xy: 1840, 657 + xy: 1383, 708 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scrap-wall-huge-tiny rotate: false - xy: 1017, 396 + xy: 1911, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-scrap-wall-huge-xlarge rotate: false - xy: 709, 766 + xy: 709, 716 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-scrap-wall-large rotate: false - xy: 771, 70 + xy: 1727, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scrap-wall-large-large rotate: false - xy: 813, 112 + xy: 1769, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-scrap-wall-large-medium rotate: false - xy: 1505, 734 + xy: 1159, 320 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-large-small rotate: false - xy: 1866, 657 + xy: 1383, 682 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scrap-wall-large-tiny rotate: false - xy: 999, 378 + xy: 1911, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-scrap-wall-large-xlarge rotate: false - xy: 709, 716 + xy: 759, 816 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-scrap-wall-medium rotate: false - xy: 1471, 700 + xy: 1193, 354 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-scrap-wall-small rotate: false - xy: 1892, 683 + xy: 1383, 656 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-scrap-wall-tiny rotate: false - xy: 981, 360 + xy: 1929, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-scrap-wall-xlarge rotate: false - xy: 759, 816 + xy: 759, 766 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-separator-large rotate: false - xy: 855, 154 + xy: 1811, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-separator-medium rotate: false - xy: 1607, 802 + xy: 1125, 252 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-separator-small rotate: false - xy: 1892, 657 + xy: 1359, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-separator-tiny rotate: false - xy: 1017, 378 + xy: 1929, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-separator-xlarge rotate: false - xy: 759, 766 + xy: 759, 716 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-shale-boulder-large rotate: false - xy: 771, 28 + xy: 1853, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-shale-boulder-medium rotate: false - xy: 1573, 768 + xy: 1159, 286 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shale-boulder-small rotate: false - xy: 1681, 631 + xy: 1385, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-shale-boulder-tiny rotate: false - xy: 999, 360 + xy: 1947, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-shale-boulder-xlarge rotate: false - xy: 759, 716 + xy: 809, 828 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-shale-large rotate: false - xy: 813, 70 + xy: 1895, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-shale-medium rotate: false - xy: 1539, 734 + xy: 1193, 320 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shale-small rotate: false - xy: 1707, 631 + xy: 1411, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-shale-tiny rotate: false - xy: 981, 342 + xy: 1947, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-shale-xlarge rotate: false - xy: 809, 828 + xy: 809, 778 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-shalerocks-large rotate: false - xy: 855, 112 + xy: 1937, 891 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-shalerocks-medium rotate: false - xy: 1505, 700 + xy: 1227, 354 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shalerocks-small rotate: false - xy: 1733, 631 + xy: 1437, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-shalerocks-tiny rotate: false - xy: 1017, 360 + xy: 1965, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-shalerocks-xlarge rotate: false - xy: 809, 778 + xy: 809, 728 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-shock-mine-large rotate: false - xy: 813, 28 + xy: 859, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-shock-mine-medium rotate: false - xy: 1607, 768 + xy: 1159, 252 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shock-mine-small rotate: false - xy: 1759, 631 + xy: 1463, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-shock-mine-tiny rotate: false - xy: 999, 342 + xy: 1965, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-shock-mine-xlarge rotate: false - xy: 809, 728 + xy: 809, 678 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-shrubs-large rotate: false - xy: 855, 70 + xy: 859, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-shrubs-medium rotate: false - xy: 1573, 734 + xy: 1193, 286 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-shrubs-small rotate: false - xy: 1785, 631 + xy: 1489, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-shrubs-tiny rotate: false - xy: 1017, 342 + xy: 1983, 740 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-shrubs-xlarge rotate: false - xy: 809, 678 + xy: 331, 666 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-silicon-smelter-large rotate: false - xy: 855, 28 + xy: 901, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-silicon-smelter-medium rotate: false - xy: 1539, 700 + xy: 1227, 320 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-silicon-smelter-small rotate: false - xy: 1811, 631 + xy: 1515, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-silicon-smelter-tiny rotate: false - xy: 1037, 504 + xy: 1983, 722 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-silicon-smelter-xlarge rotate: false - xy: 331, 666 + xy: 331, 616 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-slag-large rotate: false - xy: 921, 452 + xy: 859, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-slag-medium rotate: false - xy: 1607, 734 + xy: 1261, 354 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-slag-small rotate: false - xy: 1837, 631 + xy: 1541, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-slag-tiny rotate: false - xy: 1037, 486 + xy: 2001, 743 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-slag-xlarge rotate: false - xy: 331, 616 + xy: 381, 666 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-snow-large rotate: false - xy: 921, 410 + xy: 943, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-snow-medium rotate: false - xy: 1573, 700 + xy: 1193, 252 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snow-pine-large rotate: false - xy: 921, 368 + xy: 901, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-snow-pine-medium rotate: false - xy: 1607, 700 + xy: 1227, 286 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snow-pine-small rotate: false - xy: 1863, 631 + xy: 1567, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-snow-pine-tiny rotate: false - xy: 1035, 468 + xy: 2001, 725 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-snow-pine-xlarge rotate: false - xy: 381, 666 + xy: 381, 616 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-snow-small rotate: false - xy: 1889, 631 + xy: 1593, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-snow-tiny rotate: false - xy: 1035, 450 + xy: 1409, 648 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-snow-xlarge rotate: false - xy: 381, 616 + xy: 431, 666 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-snowrock-large rotate: false - xy: 921, 326 + xy: 859, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-snowrock-medium rotate: false - xy: 881, 666 + xy: 1261, 320 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snowrock-small rotate: false - xy: 1686, 605 + xy: 1619, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-snowrock-tiny rotate: false - xy: 1035, 432 + xy: 914, 118 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-snowrock-xlarge rotate: false - xy: 431, 666 + xy: 431, 616 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-snowrocks-large rotate: false - xy: 947, 284 + xy: 985, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-snowrocks-medium rotate: false - xy: 881, 632 + xy: 1227, 252 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-snowrocks-small rotate: false - xy: 1686, 579 + xy: 1645, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-snowrocks-tiny rotate: false - xy: 1035, 414 + xy: 912, 100 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-snowrocks-xlarge rotate: false - xy: 431, 616 + xy: 481, 666 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-solar-panel-large rotate: false - xy: 947, 242 + xy: 943, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-solar-panel-large-large rotate: false - xy: 947, 200 + xy: 901, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-solar-panel-large-medium rotate: false - xy: 915, 666 + xy: 1261, 286 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-solar-panel-large-small rotate: false - xy: 1712, 605 + xy: 1671, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-solar-panel-large-tiny rotate: false - xy: 1035, 396 + xy: 912, 82 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-solar-panel-large-xlarge rotate: false - xy: 481, 666 + xy: 481, 616 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-solar-panel-medium rotate: false - xy: 881, 598 + xy: 1261, 252 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-solar-panel-small rotate: false - xy: 1686, 553 + xy: 1697, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-solar-panel-tiny rotate: false - xy: 1035, 378 + xy: 912, 64 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-solar-panel-xlarge rotate: false - xy: 481, 616 + xy: 531, 666 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-sorter-large rotate: false - xy: 897, 154 + xy: 859, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sorter-medium rotate: false - xy: 949, 666 + xy: 1125, 218 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sorter-small rotate: false - xy: 1712, 579 + xy: 1723, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sorter-tiny rotate: false - xy: 1035, 360 + xy: 912, 46 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-sorter-xlarge rotate: false - xy: 531, 666 + xy: 531, 616 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-spawn-large rotate: false - xy: 897, 112 + xy: 1027, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-spawn-medium rotate: false - xy: 915, 632 + xy: 1159, 218 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-spawn-small rotate: false - xy: 1738, 605 + xy: 1749, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-spawn-tiny rotate: false - xy: 1035, 342 + xy: 912, 28 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-spawn-xlarge rotate: false - xy: 531, 616 + xy: 581, 666 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-spectre-large rotate: false - xy: 897, 70 + xy: 985, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-spectre-medium rotate: false - xy: 983, 666 + xy: 1193, 218 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-spectre-small rotate: false - xy: 1712, 553 + xy: 1775, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-spectre-tiny rotate: false - xy: 1055, 516 + xy: 932, 115 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-spectre-xlarge rotate: false - xy: 581, 666 + xy: 581, 616 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-spirit-factory-large rotate: false - xy: 897, 28 + xy: 943, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-spirit-factory-medium rotate: false - xy: 949, 632 + xy: 1227, 218 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-spirit-factory-small rotate: false - xy: 1738, 579 + xy: 1801, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-spirit-factory-tiny rotate: false - xy: 1055, 498 + xy: 950, 115 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-spirit-factory-xlarge rotate: false - xy: 581, 616 + xy: 631, 666 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-spore-cluster-large rotate: false - xy: 939, 158 + xy: 901, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-spore-cluster-medium rotate: false - xy: 915, 598 + xy: 1261, 218 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-spore-cluster-small rotate: false - xy: 1764, 605 + xy: 1827, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-spore-cluster-tiny rotate: false - xy: 1073, 516 + xy: 968, 115 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-spore-cluster-xlarge rotate: false - xy: 631, 666 + xy: 631, 616 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-spore-moss-large rotate: false - xy: 939, 116 + xy: 1069, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-spore-moss-medium rotate: false - xy: 1017, 666 + xy: 1979, 865 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-spore-moss-small rotate: false - xy: 1738, 553 + xy: 1853, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-spore-moss-tiny rotate: false - xy: 1073, 498 + xy: 986, 115 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-spore-moss-xlarge rotate: false - xy: 631, 616 + xy: 681, 666 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-spore-pine-large rotate: false - xy: 939, 74 + xy: 1027, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-spore-pine-medium rotate: false - xy: 983, 632 + xy: 2013, 873 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-spore-pine-small rotate: false - xy: 1764, 579 + xy: 1879, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-spore-pine-tiny rotate: false - xy: 1055, 480 + xy: 1004, 115 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-spore-pine-xlarge rotate: false - xy: 681, 666 + xy: 681, 616 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-spore-press-large rotate: false - xy: 939, 32 + xy: 985, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-spore-press-medium rotate: false - xy: 949, 598 + xy: 1975, 831 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-spore-press-small rotate: false - xy: 1790, 605 + xy: 1905, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-spore-press-tiny rotate: false - xy: 1073, 480 + xy: 1022, 115 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-spore-press-xlarge rotate: false - xy: 681, 616 + xy: 731, 666 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-sporerocks-large rotate: false - xy: 981, 158 + xy: 943, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-sporerocks-medium rotate: false - xy: 1051, 666 + xy: 1263, 668 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-sporerocks-small rotate: false - xy: 1764, 553 + xy: 1931, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-sporerocks-tiny rotate: false - xy: 1053, 462 + xy: 1040, 115 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-sporerocks-xlarge rotate: false - xy: 731, 666 + xy: 731, 616 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-stone-large rotate: false - xy: 981, 116 + xy: 901, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-stone-medium rotate: false - xy: 1017, 632 + xy: 1263, 634 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-stone-small rotate: false - xy: 1790, 579 + xy: 1957, 802 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-stone-tiny rotate: false - xy: 1053, 444 + xy: 1058, 115 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-stone-xlarge rotate: false - xy: 731, 616 + xy: 781, 628 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-surge-tower-large rotate: false - xy: 981, 74 + xy: 1111, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-surge-tower-medium rotate: false - xy: 983, 598 + xy: 1271, 702 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-surge-tower-small rotate: false - xy: 1816, 605 + xy: 1983, 805 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-surge-tower-tiny rotate: false - xy: 1071, 462 + xy: 1076, 115 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-surge-tower-xlarge rotate: false - xy: 781, 628 + xy: 831, 628 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-surge-wall-large rotate: false - xy: 981, 32 + xy: 1069, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-surge-wall-large-large rotate: false - xy: 821, 933 + xy: 1027, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-surge-wall-large-medium rotate: false - xy: 1085, 666 + xy: 1259, 600 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-surge-wall-large-small rotate: false - xy: 1790, 553 + xy: 1369, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-surge-wall-large-tiny rotate: false - xy: 1053, 426 + xy: 1094, 115 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-surge-wall-large-xlarge rotate: false - xy: 831, 628 + xy: 781, 578 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-surge-wall-medium rotate: false - xy: 1051, 632 + xy: 1295, 354 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-surge-wall-small rotate: false - xy: 1816, 579 + xy: 1395, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-surge-wall-tiny rotate: false - xy: 1071, 444 + xy: 930, 97 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-surge-wall-xlarge rotate: false - xy: 781, 578 + xy: 831, 578 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-swarmer-large rotate: false - xy: 863, 933 + xy: 985, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-swarmer-medium rotate: false - xy: 1017, 598 + xy: 1295, 320 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-swarmer-small rotate: false - xy: 1842, 605 + xy: 1421, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-swarmer-tiny rotate: false - xy: 1053, 408 + xy: 930, 79 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-swarmer-xlarge rotate: false - xy: 831, 578 + xy: 351, 566 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-tainted-water-large rotate: false - xy: 905, 933 + xy: 943, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-tainted-water-medium rotate: false - xy: 1119, 666 + xy: 1295, 286 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-tainted-water-small rotate: false - xy: 1816, 553 + xy: 1447, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-tainted-water-tiny rotate: false - xy: 1071, 426 + xy: 948, 97 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-tainted-water-xlarge rotate: false - xy: 351, 566 + xy: 351, 516 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-tar-large rotate: false - xy: 947, 933 + xy: 1153, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-tar-medium rotate: false - xy: 1085, 632 + xy: 1295, 252 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-tar-small rotate: false - xy: 1842, 579 + xy: 1473, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-tar-tiny rotate: false - xy: 1053, 390 + xy: 930, 61 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-tar-xlarge rotate: false - xy: 351, 516 + xy: 401, 566 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-tau-mech-pad-large rotate: false - xy: 989, 933 + xy: 1111, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-tau-mech-pad-medium rotate: false - xy: 1051, 598 + xy: 1295, 218 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-tau-mech-pad-small rotate: false - xy: 1868, 605 + xy: 1499, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-tau-mech-pad-tiny rotate: false - xy: 1071, 408 + xy: 948, 79 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-tau-mech-pad-xlarge rotate: false - xy: 401, 566 + xy: 351, 466 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-tendrils-large rotate: false - xy: 1031, 933 + xy: 1069, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-tendrils-medium rotate: false - xy: 1153, 666 + xy: 2013, 839 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-tendrils-small rotate: false - xy: 1842, 553 + xy: 1525, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-tendrils-tiny rotate: false - xy: 1053, 372 + xy: 966, 97 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-tendrils-xlarge rotate: false - xy: 351, 466 + xy: 401, 516 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-thermal-generator-large rotate: false - xy: 1073, 933 + xy: 1027, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-thermal-generator-medium rotate: false - xy: 1119, 632 + xy: 1297, 668 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-thermal-generator-small rotate: false - xy: 1868, 579 + xy: 1551, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-thermal-generator-tiny rotate: false - xy: 1071, 390 + xy: 930, 43 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-thermal-generator-xlarge rotate: false - xy: 401, 516 + xy: 451, 566 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-thermal-pump-large rotate: false - xy: 1115, 933 + xy: 985, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-thermal-pump-medium rotate: false - xy: 1085, 598 + xy: 1297, 634 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-thermal-pump-small rotate: false - xy: 1868, 553 + xy: 1577, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-thermal-pump-tiny rotate: false - xy: 1053, 354 + xy: 948, 61 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-thermal-pump-xlarge rotate: false - xy: 451, 566 + xy: 351, 416 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-thorium-reactor-large rotate: false - xy: 1157, 933 + xy: 1195, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-thorium-reactor-medium rotate: false - xy: 1187, 666 + xy: 1293, 600 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-thorium-reactor-small rotate: false - xy: 1894, 605 + xy: 1603, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-thorium-reactor-tiny rotate: false - xy: 1071, 372 + xy: 966, 79 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-thorium-reactor-xlarge rotate: false - xy: 351, 416 + xy: 401, 466 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-thorium-wall-large rotate: false - xy: 1199, 933 + xy: 1153, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-thorium-wall-large-large rotate: false - xy: 1241, 933 + xy: 1111, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-thorium-wall-large-medium rotate: false - xy: 1153, 632 + xy: 1289, 566 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-thorium-wall-large-small rotate: false - xy: 1894, 579 + xy: 1629, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-thorium-wall-large-tiny rotate: false - xy: 1071, 354 + xy: 984, 97 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-thorium-wall-large-xlarge rotate: false - xy: 401, 466 + xy: 451, 516 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-thorium-wall-medium rotate: false - xy: 1119, 598 + xy: 1303, 532 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-thorium-wall-small rotate: false - xy: 1894, 553 + xy: 1655, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-thorium-wall-tiny rotate: false - xy: 1053, 336 + xy: 948, 43 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-thorium-wall-xlarge rotate: false - xy: 451, 516 + xy: 501, 566 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-thruster-large rotate: false - xy: 1283, 933 + xy: 1069, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-thruster-medium rotate: false - xy: 1221, 666 + xy: 1303, 498 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-thruster-small rotate: false - xy: 1686, 527 + xy: 1681, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-thruster-tiny rotate: false - xy: 1071, 336 + xy: 966, 61 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-thruster-xlarge rotate: false - xy: 501, 566 + xy: 351, 366 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-titan-factory-large rotate: false - xy: 1325, 933 + xy: 1027, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-titan-factory-medium rotate: false - xy: 1187, 632 + xy: 1303, 464 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-titan-factory-small rotate: false - xy: 1712, 527 + xy: 1707, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-titan-factory-tiny rotate: false - xy: 1089, 462 + xy: 984, 79 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-titan-factory-xlarge rotate: false - xy: 351, 366 + xy: 401, 416 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-titanium-conveyor-large rotate: false - xy: 1367, 933 + xy: 1237, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-titanium-conveyor-medium rotate: false - xy: 1153, 598 + xy: 1303, 430 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-titanium-conveyor-small rotate: false - xy: 1738, 527 + xy: 1733, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-titanium-conveyor-tiny rotate: false - xy: 1089, 444 + xy: 1002, 97 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-titanium-conveyor-xlarge rotate: false - xy: 401, 416 + xy: 451, 466 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-titanium-wall-large rotate: false - xy: 1409, 933 + xy: 1195, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-titanium-wall-large-large rotate: false - xy: 1451, 933 + xy: 1153, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-titanium-wall-large-medium rotate: false - xy: 1255, 666 + xy: 1303, 396 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-titanium-wall-large-small rotate: false - xy: 1764, 527 + xy: 1759, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-titanium-wall-large-tiny rotate: false - xy: 1089, 426 + xy: 966, 43 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-titanium-wall-large-xlarge rotate: false - xy: 451, 466 + xy: 501, 516 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-titanium-wall-medium rotate: false - xy: 1221, 632 + xy: 1323, 566 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-titanium-wall-small rotate: false - xy: 1790, 527 + xy: 1785, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-titanium-wall-tiny rotate: false - xy: 1089, 408 + xy: 984, 61 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-titanium-wall-xlarge rotate: false - xy: 501, 516 + xy: 551, 566 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-trident-ship-pad-large rotate: false - xy: 1493, 933 + xy: 1111, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-trident-ship-pad-medium rotate: false - xy: 1187, 598 + xy: 1327, 600 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-trident-ship-pad-small rotate: false - xy: 1816, 527 + xy: 1811, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-trident-ship-pad-tiny rotate: false - xy: 1089, 390 + xy: 1002, 79 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-trident-ship-pad-xlarge rotate: false - xy: 551, 566 + xy: 351, 316 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 block-turbine-generator-large rotate: false - xy: 1535, 933 + xy: 1069, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 block-turbine-generator-medium rotate: false - xy: 1289, 666 + xy: 1337, 532 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 block-turbine-generator-small rotate: false - xy: 1842, 527 + xy: 1837, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-turbine-generator-tiny rotate: false - xy: 1089, 372 + xy: 1020, 97 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 block-turbine-generator-xlarge - rotate: false - xy: 351, 316 - size: 48, 48 - orig: 48, 48 - offset: 0, 0 - index: -1 -block-unloader-large - rotate: false - xy: 1577, 933 - size: 40, 40 - orig: 40, 40 - offset: 0, 0 - index: -1 -block-unloader-medium - rotate: false - xy: 1255, 632 - size: 32, 32 - orig: 32, 32 - offset: 0, 0 - index: -1 -block-unloader-small - rotate: false - xy: 1868, 527 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -block-unloader-tiny - rotate: false - xy: 1089, 354 - size: 16, 16 - orig: 16, 16 - offset: 0, 0 - index: -1 -block-unloader-xlarge rotate: false xy: 401, 366 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-vault-large +block-underflow-gate-large rotate: false - xy: 1619, 933 + xy: 1279, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-vault-medium +block-underflow-gate-medium rotate: false - xy: 1221, 598 + xy: 1337, 498 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-vault-small +block-underflow-gate-small rotate: false - xy: 1894, 527 + xy: 1863, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-vault-tiny +block-underflow-gate-tiny rotate: false - xy: 1089, 336 + xy: 984, 43 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-vault-xlarge +block-underflow-gate-xlarge rotate: false xy: 451, 416 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-water-extractor-large +block-unloader-large rotate: false - xy: 1661, 933 + xy: 1237, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-water-extractor-medium +block-unloader-medium rotate: false - xy: 1323, 666 + xy: 1337, 464 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-water-extractor-small +block-unloader-small rotate: false - xy: 1915, 631 + xy: 1889, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-water-extractor-tiny +block-unloader-tiny rotate: false - xy: 989, 324 + xy: 1002, 61 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-water-extractor-xlarge +block-unloader-xlarge rotate: false xy: 501, 466 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-water-large +block-vault-large rotate: false - xy: 1703, 933 + xy: 1195, 765 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-water-medium +block-vault-medium rotate: false - xy: 1289, 632 + xy: 1337, 430 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-water-small +block-vault-small rotate: false - xy: 1920, 605 + xy: 1915, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-water-tiny +block-vault-tiny rotate: false - xy: 989, 306 + xy: 1020, 79 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-water-xlarge +block-vault-xlarge rotate: false xy: 551, 516 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-wave-large +block-water-extractor-large rotate: false - xy: 1745, 933 + xy: 1153, 723 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-wave-medium +block-water-extractor-medium rotate: false - xy: 1255, 598 + xy: 1337, 396 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-wave-small +block-water-extractor-small rotate: false - xy: 1920, 579 + xy: 1941, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-wave-tiny +block-water-extractor-tiny rotate: false - xy: 1007, 324 + xy: 1038, 97 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-wave-xlarge +block-water-extractor-xlarge rotate: false xy: 601, 566 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-white-tree-dead-large +block-water-large rotate: false - xy: 1787, 933 + xy: 1111, 681 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-white-tree-dead-medium +block-water-medium rotate: false - xy: 1357, 666 + xy: 1329, 362 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-white-tree-dead-small +block-water-small rotate: false - xy: 1920, 553 + xy: 1967, 776 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-white-tree-dead-tiny +block-water-tiny rotate: false - xy: 989, 288 + xy: 1002, 43 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-white-tree-dead-xlarge +block-water-xlarge rotate: false xy: 351, 266 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-white-tree-large +block-wave-large rotate: false - xy: 1829, 933 + xy: 1321, 849 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-white-tree-medium +block-wave-medium rotate: false - xy: 1323, 632 + xy: 1329, 328 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-white-tree-small +block-wave-small rotate: false - xy: 1920, 527 + xy: 1993, 779 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-white-tree-tiny +block-wave-tiny rotate: false - xy: 1025, 324 + xy: 1020, 61 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-white-tree-xlarge +block-wave-xlarge rotate: false xy: 401, 316 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 -block-wraith-factory-large +block-white-tree-dead-large rotate: false - xy: 1871, 933 + xy: 1279, 807 size: 40, 40 orig: 40, 40 offset: 0, 0 index: -1 -block-wraith-factory-medium +block-white-tree-dead-medium rotate: false - xy: 1289, 598 + xy: 1329, 294 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 -block-wraith-factory-small +block-white-tree-dead-small rotate: false - xy: 1056, 534 + xy: 1391, 750 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 -block-wraith-factory-tiny +block-white-tree-dead-tiny rotate: false - xy: 1007, 306 + xy: 1038, 79 size: 16, 16 orig: 16, 16 offset: 0, 0 index: -1 -block-wraith-factory-xlarge +block-white-tree-dead-xlarge rotate: false xy: 451, 366 size: 48, 48 orig: 48, 48 offset: 0, 0 index: -1 +block-white-tree-large + rotate: false + xy: 1237, 765 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-white-tree-medium + rotate: false + xy: 1329, 260 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-white-tree-small + rotate: false + xy: 1417, 750 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-white-tree-tiny + rotate: false + xy: 1056, 97 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-white-tree-xlarge + rotate: false + xy: 501, 416 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 +block-wraith-factory-large + rotate: false + xy: 1195, 723 + size: 40, 40 + orig: 40, 40 + offset: 0, 0 + index: -1 +block-wraith-factory-medium + rotate: false + xy: 1329, 226 + size: 32, 32 + orig: 32, 32 + offset: 0, 0 + index: -1 +block-wraith-factory-small + rotate: false + xy: 1443, 750 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +block-wraith-factory-tiny + rotate: false + xy: 1020, 43 + size: 16, 16 + orig: 16, 16 + offset: 0, 0 + index: -1 +block-wraith-factory-xlarge + rotate: false + xy: 551, 466 + size: 48, 48 + orig: 48, 48 + offset: 0, 0 + index: -1 button rotate: false - xy: 1377, 904 + xy: 1781, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16343,7 +16517,7 @@ button index: -1 button-disabled rotate: false - xy: 1913, 946 + xy: 1153, 694 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16351,7 +16525,7 @@ button-disabled index: -1 button-down rotate: false - xy: 1951, 946 + xy: 1363, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16359,7 +16533,7 @@ button-down index: -1 button-edge-1 rotate: false - xy: 845, 904 + xy: 1321, 820 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16367,7 +16541,7 @@ button-edge-1 index: -1 button-edge-2 rotate: false - xy: 883, 904 + xy: 1279, 778 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16375,7 +16549,7 @@ button-edge-2 index: -1 button-edge-3 rotate: false - xy: 921, 904 + xy: 1237, 736 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16383,7 +16557,7 @@ button-edge-3 index: -1 button-edge-4 rotate: false - xy: 959, 904 + xy: 1191, 694 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16391,7 +16565,7 @@ button-edge-4 index: -1 button-edge-over-4 rotate: false - xy: 997, 904 + xy: 1401, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16399,7 +16573,7 @@ button-edge-over-4 index: -1 button-over rotate: false - xy: 1035, 904 + xy: 1439, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16407,7 +16581,7 @@ button-over index: -1 button-red rotate: false - xy: 1073, 904 + xy: 1477, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16415,7 +16589,7 @@ button-red index: -1 button-right rotate: false - xy: 1187, 904 + xy: 1591, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16423,7 +16597,7 @@ button-right index: -1 button-right-down rotate: false - xy: 1111, 904 + xy: 1515, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16431,7 +16605,7 @@ button-right-down index: -1 button-right-over rotate: false - xy: 1149, 904 + xy: 1553, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16439,7 +16613,7 @@ button-right-over index: -1 button-select rotate: false - xy: 1082, 534 + xy: 1469, 750 size: 24, 24 split: 4, 4, 4, 4 orig: 24, 24 @@ -16447,7 +16621,7 @@ button-select index: -1 button-square rotate: false - xy: 1301, 904 + xy: 1705, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16455,7 +16629,7 @@ button-square index: -1 button-square-down rotate: false - xy: 1225, 904 + xy: 1629, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16463,7 +16637,7 @@ button-square-down index: -1 button-square-over rotate: false - xy: 1263, 904 + xy: 1667, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16471,7 +16645,7 @@ button-square-over index: -1 button-trans rotate: false - xy: 1339, 904 + xy: 1743, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16479,42 +16653,42 @@ button-trans index: -1 check-disabled rotate: false - xy: 1391, 666 + xy: 1357, 566 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-off rotate: false - xy: 1357, 632 + xy: 1371, 532 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-on rotate: false - xy: 1323, 598 + xy: 1371, 498 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-on-disabled rotate: false - xy: 1425, 666 + xy: 1371, 464 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-on-over rotate: false - xy: 1391, 632 + xy: 1371, 430 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 check-over rotate: false - xy: 1357, 598 + xy: 1371, 396 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -16528,7 +16702,7 @@ clear index: -1 cursor rotate: false - xy: 1913, 940 + xy: 1305, 702 size: 4, 4 orig: 4, 4 offset: 0, 0 @@ -16542,7 +16716,7 @@ discord-banner index: -1 flat-down-base rotate: false - xy: 1415, 904 + xy: 1819, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16557,7 +16731,7 @@ info-banner index: -1 inventory rotate: false - xy: 1901, 823 + xy: 1409, 708 size: 24, 40 split: 10, 10, 10, 14 orig: 24, 40 @@ -16565,140 +16739,140 @@ inventory index: -1 item-blast-compound-icon rotate: false - xy: 1459, 666 + xy: 1363, 362 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-coal-icon rotate: false - xy: 1425, 632 + xy: 1363, 328 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-copper-icon rotate: false - xy: 1391, 598 + xy: 1363, 294 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-graphite-icon rotate: false - xy: 1493, 666 + xy: 1363, 260 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-lead-icon rotate: false - xy: 1459, 632 + xy: 1363, 226 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-metaglass-icon rotate: false - xy: 1425, 598 + xy: 1329, 192 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-phase-fabric-icon rotate: false - xy: 1527, 666 + xy: 1363, 192 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-plastanium-icon rotate: false - xy: 1493, 632 + xy: 1397, 362 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-pyratite-icon rotate: false - xy: 1459, 598 + xy: 1397, 328 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-sand-icon rotate: false - xy: 1561, 666 + xy: 1397, 294 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-scrap-icon rotate: false - xy: 1527, 632 + xy: 1397, 260 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-silicon-icon rotate: false - xy: 1493, 598 + xy: 1397, 226 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-spore-pod-icon rotate: false - xy: 1595, 666 + xy: 1397, 192 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-surge-alloy-icon rotate: false - xy: 1561, 632 + xy: 871, 208 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-thorium-icon rotate: false - xy: 1527, 598 + xy: 905, 208 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 item-titanium-icon rotate: false - xy: 1595, 632 + xy: 939, 205 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-cryofluid-icon rotate: false - xy: 1561, 598 + xy: 973, 205 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-oil-icon rotate: false - xy: 1595, 598 + xy: 1007, 205 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-slag-icon rotate: false - xy: 895, 564 + xy: 1041, 205 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 liquid-water-icon rotate: false - xy: 929, 564 + xy: 1075, 205 size: 32, 32 orig: 32, 32 offset: 0, 0 @@ -16719,7 +16893,7 @@ nomap index: -1 pane rotate: false - xy: 1491, 904 + xy: 1895, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16727,7 +16901,7 @@ pane index: -1 pane-2 rotate: false - xy: 1453, 904 + xy: 1857, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16735,7 +16909,7 @@ pane-2 index: -1 scroll rotate: false - xy: 1901, 744 + xy: 1435, 713 size: 24, 35 split: 10, 10, 6, 5 orig: 24, 35 @@ -16743,7 +16917,7 @@ scroll index: -1 scroll-horizontal rotate: false - xy: 845, 878 + xy: 43, 2 size: 35, 24 split: 6, 5, 10, 10 orig: 35, 24 @@ -16758,63 +16932,63 @@ scroll-knob-horizontal-black index: -1 scroll-knob-vertical-black rotate: false - xy: 1901, 781 + xy: 1409, 666 size: 24, 40 orig: 24, 40 offset: 0, 0 index: -1 scroll-knob-vertical-thin rotate: false - xy: 2035, 821 + xy: 2035, 797 size: 12, 40 orig: 12, 40 offset: 0, 0 index: -1 selection rotate: false - xy: 821, 975 + xy: 309, 866 size: 1, 1 orig: 1, 1 offset: 0, 0 index: -1 slider rotate: false - xy: 2017, 863 + xy: 259, 659 size: 1, 8 orig: 1, 8 offset: 0, 0 index: -1 slider-knob rotate: false - xy: 963, 558 + xy: 519, 242 size: 29, 38 orig: 29, 38 offset: 0, 0 index: -1 slider-knob-down rotate: false - xy: 994, 558 + xy: 519, 202 size: 29, 38 orig: 29, 38 offset: 0, 0 index: -1 slider-knob-over rotate: false - xy: 1025, 558 + xy: 519, 162 size: 29, 38 orig: 29, 38 offset: 0, 0 index: -1 slider-vertical rotate: false - xy: 309, 866 + xy: 1983, 802 size: 8, 1 orig: 8, 1 offset: 0, 0 index: -1 underline rotate: false - xy: 1643, 904 + xy: 919, 652 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16822,7 +16996,7 @@ underline index: -1 underline-2 rotate: false - xy: 1529, 904 + xy: 1933, 862 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16830,7 +17004,7 @@ underline-2 index: -1 underline-disabled rotate: false - xy: 1567, 904 + xy: 881, 652 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16838,7 +17012,7 @@ underline-disabled index: -1 underline-red rotate: false - xy: 1605, 904 + xy: 881, 623 size: 36, 27 split: 12, 12, 12, 12 orig: 36, 27 @@ -16853,7 +17027,7 @@ whiteui index: -1 window-empty rotate: false - xy: 1629, 637 + xy: 519, 23 size: 27, 61 split: 4, 4, 2, 2 orig: 27, 61 diff --git a/core/assets/sprites/sprites.png b/core/assets/sprites/sprites.png index 66cc5a04f1..10374ee696 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 8fe2b79b25..dafec12836 100644 Binary files a/core/assets/sprites/sprites2.png and b/core/assets/sprites/sprites2.png differ diff --git a/core/assets/sprites/sprites3.png b/core/assets/sprites/sprites3.png index e794484a5f..8fe2b79b25 100644 Binary files a/core/assets/sprites/sprites3.png and b/core/assets/sprites/sprites3.png differ diff --git a/core/assets/sprites/sprites4.png b/core/assets/sprites/sprites4.png index 9c08c17bf7..f5b287eabe 100644 Binary files a/core/assets/sprites/sprites4.png and b/core/assets/sprites/sprites4.png differ diff --git a/core/assets/sprites/sprites5.png b/core/assets/sprites/sprites5.png index 95bd202a59..9c08c17bf7 100644 Binary files a/core/assets/sprites/sprites5.png and b/core/assets/sprites/sprites5.png differ diff --git a/core/assets/sprites/sprites6.png b/core/assets/sprites/sprites6.png new file mode 100644 index 0000000000..f86cfd88d0 Binary files /dev/null and b/core/assets/sprites/sprites6.png differ diff --git a/core/build.gradle b/core/build.gradle index abcec6d8f6..ea07c810b3 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -1,4 +1,4 @@ apply plugin: "java" sourceCompatibility = 1.8 [compileJava, compileTestJava]*.options*.encoding = 'UTF-8' -sourceSets.main.java.srcDirs = ["src/"] \ No newline at end of file +sourceSets.main.java.srcDirs = ["src/", "$buildDir/generated/sources/annotationProcessor/java/main"] \ No newline at end of file diff --git a/core/build/generated/sources/annotationProcessor/java/main/mindustry/gen/Call.java b/core/build/generated/sources/annotationProcessor/java/main/mindustry/gen/Call.java new file mode 100644 index 0000000000..3003d832ff --- /dev/null +++ b/core/build/generated/sources/annotationProcessor/java/main/mindustry/gen/Call.java @@ -0,0 +1,1132 @@ +package mindustry.gen; + +import java.lang.String; +import java.nio.ByteBuffer; +import mindustry.entities.bullet.BulletType; +import mindustry.entities.units.BuildRequest; +import mindustry.game.Rules; +import mindustry.game.Team; +import mindustry.net.Administration; +import mindustry.net.NetConnection; +import mindustry.net.Packets; +import mindustry.type.Item; +import mindustry.world.Block; +import mindustry.world.Tile; + +/** + * Autogenerated file. Do not modify! + */ +public class Call { + private static final ByteBuffer TEMP_BUFFER = ByteBuffer.allocate(4096); + + public static synchronized void beginBreak(Team team, int x, int y) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.world.Build.beginBreak(team, x, y); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)0; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeTeam(TEMP_BUFFER, team); + TEMP_BUFFER.putInt(x); + TEMP_BUFFER.putInt(y); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void beginPlace(Team team, int x, int y, Block result, int rotation) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.world.Build.beginPlace(team, x, y, result, rotation); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)1; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeTeam(TEMP_BUFFER, team); + TEMP_BUFFER.putInt(x); + TEMP_BUFFER.putInt(y); + mindustry.io.TypeIO.writeBlock(TEMP_BUFFER, result); + TEMP_BUFFER.putInt(rotation); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void connectConfirm() { + if(mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)2; + TEMP_BUFFER.position(0); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void createBullet(BulletType type, Team team, float x, float y, + float angle, float damage, float velocityScl, float lifetimeScl) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.entities.bullet.BulletType.createBullet(type, team, x, y, angle, damage, velocityScl, lifetimeScl); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)3; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeBulletType(TEMP_BUFFER, type); + mindustry.io.TypeIO.writeTeam(TEMP_BUFFER, team); + TEMP_BUFFER.putFloat(x); + TEMP_BUFFER.putFloat(y); + TEMP_BUFFER.putFloat(angle); + TEMP_BUFFER.putFloat(damage); + TEMP_BUFFER.putFloat(velocityScl); + TEMP_BUFFER.putFloat(lifetimeScl); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.udp); + } + } + + public static synchronized void dropItem(float angle) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.input.InputHandler.dropItem(mindustry.Vars.player, angle); + } + if(mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)4; + TEMP_BUFFER.position(0); + TEMP_BUFFER.putFloat(angle); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void launchZone() { + mindustry.core.Logic.launchZone(); + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)5; + TEMP_BUFFER.position(0); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onAdminRequest(Playerc other, Packets.AdminAction action) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.core.NetServer.onAdminRequest(mindustry.Vars.player, other, action); + } + if(mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)6; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, other); + mindustry.io.TypeIO.writeAction(TEMP_BUFFER, action); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onBlockSnapshot(short amount, short dataLen, byte[] data) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)2; + packet.type = (byte)7; + TEMP_BUFFER.position(0); + TEMP_BUFFER.putShort(amount); + TEMP_BUFFER.putShort(dataLen); + mindustry.io.TypeIO.writeBytes(TEMP_BUFFER, data); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.udp); + } + } + + public static synchronized void onBlockSnapshot(NetConnection playerConnection, short amount, + short dataLen, byte[] data) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)2; + packet.type = (byte)7; + TEMP_BUFFER.position(0); + TEMP_BUFFER.putShort(amount); + TEMP_BUFFER.putShort(dataLen); + mindustry.io.TypeIO.writeBytes(TEMP_BUFFER, data); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.udp); + } + } + + public static synchronized void onClientShapshot(int snapshotID, float x, float y, float pointerX, + float pointerY, float rotation, float baseRotation, float xVelocity, float yVelocity, + Tile mining, boolean boosting, boolean shooting, boolean chatting, BuildRequest[] requests, + float viewX, float viewY, float viewWidth, float viewHeight) { + if(mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)8; + TEMP_BUFFER.position(0); + TEMP_BUFFER.putInt(snapshotID); + TEMP_BUFFER.putFloat(x); + TEMP_BUFFER.putFloat(y); + TEMP_BUFFER.putFloat(pointerX); + TEMP_BUFFER.putFloat(pointerY); + TEMP_BUFFER.putFloat(rotation); + TEMP_BUFFER.putFloat(baseRotation); + TEMP_BUFFER.putFloat(xVelocity); + TEMP_BUFFER.putFloat(yVelocity); + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, mining); + TEMP_BUFFER.put(boosting ? (byte)1 : 0); + TEMP_BUFFER.put(shooting ? (byte)1 : 0); + TEMP_BUFFER.put(chatting ? (byte)1 : 0); + mindustry.io.TypeIO.writeRequests(TEMP_BUFFER, requests); + TEMP_BUFFER.putFloat(viewX); + TEMP_BUFFER.putFloat(viewY); + TEMP_BUFFER.putFloat(viewWidth); + TEMP_BUFFER.putFloat(viewHeight); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.udp); + } + } + + public static synchronized void onConnect(NetConnection playerConnection, String ip, int port) { + if(mindustry.Vars.net.client() || !mindustry.Vars.net.active()) { + mindustry.core.NetClient.onConnect(ip, port); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)9; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, ip); + TEMP_BUFFER.putInt(port); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onConstructFinish(Tile tile, Block block, int builderID, + byte rotation, Team team, boolean skipConfig) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.world.blocks.BuildBlock.onConstructFinish(tile, block, builderID, rotation, team, skipConfig); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)10; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + mindustry.io.TypeIO.writeBlock(TEMP_BUFFER, block); + TEMP_BUFFER.putInt(builderID); + TEMP_BUFFER.put(rotation); + mindustry.io.TypeIO.writeTeam(TEMP_BUFFER, team); + TEMP_BUFFER.put(skipConfig ? (byte)1 : 0); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onDeconstructFinish(Tile tile, Block block, int builderID) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.world.blocks.BuildBlock.onDeconstructFinish(tile, block, builderID); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)11; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + mindustry.io.TypeIO.writeBlock(TEMP_BUFFER, block); + TEMP_BUFFER.putInt(builderID); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onDoorToggle(Playerc player, Tile tile, boolean open) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.world.blocks.defense.Door.onDoorToggle(player, tile, open); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)12; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + TEMP_BUFFER.put(open ? (byte)1 : 0); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onEntitySnapshot(NetConnection playerConnection, short amount, + short dataLen, byte[] data) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)2; + packet.type = (byte)13; + TEMP_BUFFER.position(0); + TEMP_BUFFER.putShort(amount); + TEMP_BUFFER.putShort(dataLen); + mindustry.io.TypeIO.writeBytes(TEMP_BUFFER, data); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.udp); + } + } + + public static synchronized void onGameOver(Team winner) { + mindustry.core.Logic.onGameOver(winner); + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)14; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeTeam(TEMP_BUFFER, winner); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onInfoMessage(String message) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)15; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, message); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onInfoMessage(NetConnection playerConnection, String message) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)15; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, message); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onInfoPopup(String message, float duration, int align, int top, + int left, int bottom, int right) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)16; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, message); + TEMP_BUFFER.putFloat(duration); + TEMP_BUFFER.putInt(align); + TEMP_BUFFER.putInt(top); + TEMP_BUFFER.putInt(left); + TEMP_BUFFER.putInt(bottom); + TEMP_BUFFER.putInt(right); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onInfoPopup(NetConnection playerConnection, String message, + float duration, int align, int top, int left, int bottom, int right) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)16; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, message); + TEMP_BUFFER.putFloat(duration); + TEMP_BUFFER.putInt(align); + TEMP_BUFFER.putInt(top); + TEMP_BUFFER.putInt(left); + TEMP_BUFFER.putInt(bottom); + TEMP_BUFFER.putInt(right); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onInfoToast(String message, float duration) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)17; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, message); + TEMP_BUFFER.putFloat(duration); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onInfoToast(NetConnection playerConnection, String message, + float duration) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)17; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, message); + TEMP_BUFFER.putFloat(duration); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onKick(NetConnection playerConnection, String reason) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)1; + packet.type = (byte)18; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, reason); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onKick(NetConnection playerConnection, + Packets.KickReason reason) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)1; + packet.type = (byte)19; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeKick(TEMP_BUFFER, reason); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onLabel(String info, float duration, float worldx, float worldy) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)20; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, info); + TEMP_BUFFER.putFloat(duration); + TEMP_BUFFER.putFloat(worldx); + TEMP_BUFFER.putFloat(worldy); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onLabel(NetConnection playerConnection, String info, + float duration, float worldx, float worldy) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)20; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, info); + TEMP_BUFFER.putFloat(duration); + TEMP_BUFFER.putFloat(worldx); + TEMP_BUFFER.putFloat(worldy); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onMechFactoryDone(Tile tile) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.world.blocks.units.MechPad.onMechFactoryDone(tile); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)21; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onMechFactoryTap(Playerc player, Tile tile) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.world.blocks.units.MechPad.onMechFactoryTap(player, tile); + } + if(mindustry.Vars.net.server() || mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)22; + TEMP_BUFFER.position(0); + if(mindustry.Vars.net.server()) { + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + } + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onPing(long time) { + if(mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)23; + TEMP_BUFFER.position(0); + TEMP_BUFFER.putLong(time); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onPingResponse(NetConnection playerConnection, long time) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)24; + TEMP_BUFFER.position(0); + TEMP_BUFFER.putLong(time); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onPlayerDisconnect(int playerid) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)25; + TEMP_BUFFER.position(0); + TEMP_BUFFER.putInt(playerid); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onPositionSet(NetConnection playerConnection, float x, float y) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)26; + TEMP_BUFFER.position(0); + TEMP_BUFFER.putFloat(x); + TEMP_BUFFER.putFloat(y); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onSetRules(Rules rules) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)27; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeRules(TEMP_BUFFER, rules); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onSetRules(NetConnection playerConnection, Rules rules) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)27; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeRules(TEMP_BUFFER, rules); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onStateSnapshot(NetConnection playerConnection, float waveTime, + int wave, int enemies, short coreDataLen, byte[] coreData) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)2; + packet.type = (byte)28; + TEMP_BUFFER.position(0); + TEMP_BUFFER.putFloat(waveTime); + TEMP_BUFFER.putInt(wave); + TEMP_BUFFER.putInt(enemies); + TEMP_BUFFER.putShort(coreDataLen); + mindustry.io.TypeIO.writeBytes(TEMP_BUFFER, coreData); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.udp); + } + } + + public static synchronized void onTileConfig(Playerc player, Tile tile, int value) { + mindustry.input.InputHandler.onTileConfig(player, tile, value); + if(mindustry.Vars.net.server() || mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)29; + TEMP_BUFFER.position(0); + if(mindustry.Vars.net.server()) { + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + } + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + TEMP_BUFFER.putInt(value); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + static synchronized void onTileConfig__forward(NetConnection exceptConnection, Playerc player, + Tile tile, int value) { + if(mindustry.Vars.net.server() || mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)29; + TEMP_BUFFER.position(0); + if(mindustry.Vars.net.server()) { + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + } + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + TEMP_BUFFER.putInt(value); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.sendExcept(exceptConnection, packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onTileDamage(Tile tile, float health) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.world.Tile.onTileDamage(tile, health); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)30; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + TEMP_BUFFER.putFloat(health); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.udp); + } + } + + public static synchronized void onTileDestroyed(Tile tile) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.world.Tile.onTileDestroyed(tile); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)31; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onTileTapped(Playerc player, Tile tile) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.input.InputHandler.onTileTapped(player, tile); + } + if(mindustry.Vars.net.server() || mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)32; + TEMP_BUFFER.position(0); + if(mindustry.Vars.net.server()) { + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + } + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + static synchronized void onTileTapped__forward(NetConnection exceptConnection, Playerc player, + Tile tile) { + if(mindustry.Vars.net.server() || mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)32; + TEMP_BUFFER.position(0); + if(mindustry.Vars.net.server()) { + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + } + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onTraceInfo(NetConnection playerConnection, Playerc player, + Administration.TraceInfo info) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)33; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + mindustry.io.TypeIO.writeTraceInfo(TEMP_BUFFER, info); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onUnitFactorySpawn(Tile tile, int spawns) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.world.blocks.units.UnitFactory.onUnitFactorySpawn(tile, spawns); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)34; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + TEMP_BUFFER.putInt(spawns); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onUnitRespawn(Tile tile, Playerc player) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.world.blocks.storage.CoreBlock.onUnitRespawn(tile, player); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)35; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onWorldDataBegin() { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)36; + TEMP_BUFFER.position(0); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void onWorldDataBegin(NetConnection playerConnection) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)36; + TEMP_BUFFER.position(0); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void removeQueueBlock(NetConnection playerConnection, int x, int y, + boolean breaking) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)37; + TEMP_BUFFER.position(0); + TEMP_BUFFER.putInt(x); + TEMP_BUFFER.putInt(y); + TEMP_BUFFER.put(breaking ? (byte)1 : 0); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void removeTile(Tile tile) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.world.Tile.removeTile(tile); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)38; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void requestItem(Playerc player, Tile tile, Item item, int amount) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.ui.fragments.BlockInventoryFragment.requestItem(player, tile, item, amount); + } + if(mindustry.Vars.net.server() || mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)39; + TEMP_BUFFER.position(0); + if(mindustry.Vars.net.server()) { + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + } + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + mindustry.io.TypeIO.writeItem(TEMP_BUFFER, item); + TEMP_BUFFER.putInt(amount); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + static synchronized void requestItem__forward(NetConnection exceptConnection, Playerc player, + Tile tile, Item item, int amount) { + if(mindustry.Vars.net.server() || mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)39; + TEMP_BUFFER.position(0); + if(mindustry.Vars.net.server()) { + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + } + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + mindustry.io.TypeIO.writeItem(TEMP_BUFFER, item); + TEMP_BUFFER.putInt(amount); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void rotateBlock(Playerc player, Tile tile, boolean direction) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.input.InputHandler.rotateBlock(player, tile, direction); + } + if(mindustry.Vars.net.server() || mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)40; + TEMP_BUFFER.position(0); + if(mindustry.Vars.net.server()) { + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + } + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + TEMP_BUFFER.put(direction ? (byte)1 : 0); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.udp); + } + } + + static synchronized void rotateBlock__forward(NetConnection exceptConnection, Playerc player, + Tile tile, boolean direction) { + if(mindustry.Vars.net.server() || mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)40; + TEMP_BUFFER.position(0); + if(mindustry.Vars.net.server()) { + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + } + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + TEMP_BUFFER.put(direction ? (byte)1 : 0); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.udp); + } + } + + public static synchronized void sendChatMessage(String message) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.core.NetClient.sendChatMessage(mindustry.Vars.player, message); + } + if(mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)41; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, message); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void sendMessage(String message) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.core.NetClient.sendMessage(message); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)42; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, message); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void sendMessage(String message, String sender, Playerc playersender) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)43; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, message); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, sender); + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, playersender); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void sendMessage(NetConnection playerConnection, String message, + String sender, Playerc playersender) { + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)43; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, message); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, sender); + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, playersender); + packet.writeLength = TEMP_BUFFER.position(); + playerConnection.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void setMessageBlockText(Playerc player, Tile tile, String text) { + mindustry.world.blocks.logic.MessageBlock.setMessageBlockText(player, tile, text); + if(mindustry.Vars.net.server() || mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)44; + TEMP_BUFFER.position(0); + if(mindustry.Vars.net.server()) { + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + } + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, text); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + static synchronized void setMessageBlockText__forward(NetConnection exceptConnection, + Playerc player, Tile tile, String text) { + if(mindustry.Vars.net.server() || mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)44; + TEMP_BUFFER.position(0); + if(mindustry.Vars.net.server()) { + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + } + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + mindustry.io.TypeIO.writeString(TEMP_BUFFER, text); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.sendExcept(exceptConnection, packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void setPlayerTeamEditor(Playerc player, Team team) { + mindustry.ui.fragments.HudFragment.setPlayerTeamEditor(player, team); + if(mindustry.Vars.net.server() || mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)45; + TEMP_BUFFER.position(0); + if(mindustry.Vars.net.server()) { + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + } + mindustry.io.TypeIO.writeTeam(TEMP_BUFFER, team); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + static synchronized void setPlayerTeamEditor__forward(NetConnection exceptConnection, + Playerc player, Team team) { + if(mindustry.Vars.net.server() || mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)45; + TEMP_BUFFER.position(0); + if(mindustry.Vars.net.server()) { + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + } + mindustry.io.TypeIO.writeTeam(TEMP_BUFFER, team); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.sendExcept(exceptConnection, packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void setTile(Tile tile, Block block, Team team, int rotation) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.world.Tile.setTile(tile, block, team, rotation); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)46; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + mindustry.io.TypeIO.writeBlock(TEMP_BUFFER, block); + mindustry.io.TypeIO.writeTeam(TEMP_BUFFER, team); + TEMP_BUFFER.putInt(rotation); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void transferInventory(Playerc player, Tile tile) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.input.InputHandler.transferInventory(player, tile); + } + if(mindustry.Vars.net.server() || mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)47; + TEMP_BUFFER.position(0); + if(mindustry.Vars.net.server()) { + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + } + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + static synchronized void transferInventory__forward(NetConnection exceptConnection, + Playerc player, Tile tile) { + if(mindustry.Vars.net.server() || mindustry.Vars.net.client()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)47; + TEMP_BUFFER.position(0); + if(mindustry.Vars.net.server()) { + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, player); + } + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.tcp); + } + } + + public static synchronized void transferItemEffect(Item item, float x, float y, Itemsc to) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.input.InputHandler.transferItemEffect(item, x, y, to); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)48; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeItem(TEMP_BUFFER, item); + TEMP_BUFFER.putFloat(x); + TEMP_BUFFER.putFloat(y); + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, to); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.udp); + } + } + + public static synchronized void transferItemTo(Item item, int amount, float x, float y, + Tile tile) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.input.InputHandler.transferItemTo(item, amount, x, y, tile); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)49; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeItem(TEMP_BUFFER, item); + TEMP_BUFFER.putInt(amount); + TEMP_BUFFER.putFloat(x); + TEMP_BUFFER.putFloat(y); + mindustry.io.TypeIO.writeTile(TEMP_BUFFER, tile); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.udp); + } + } + + public static synchronized void transferItemToUnit(Item item, float x, float y, Itemsc to) { + if(mindustry.Vars.net.server() || !mindustry.Vars.net.active()) { + mindustry.input.InputHandler.transferItemToUnit(item, x, y, to); + } + if(mindustry.Vars.net.server()) { + mindustry.net.Packets.InvokePacket packet = arc.util.pooling.Pools.obtain(mindustry.net.Packets.InvokePacket.class, mindustry.net.Packets.InvokePacket::new); + packet.writeBuffer = TEMP_BUFFER; + packet.priority = (byte)0; + packet.type = (byte)50; + TEMP_BUFFER.position(0); + mindustry.io.TypeIO.writeItem(TEMP_BUFFER, item); + TEMP_BUFFER.putFloat(x); + TEMP_BUFFER.putFloat(y); + mindustry.io.TypeIO.writeEntity(TEMP_BUFFER, to); + packet.writeLength = TEMP_BUFFER.position(); + mindustry.Vars.net.send(packet, mindustry.net.Net.SendMode.udp); + } + } +} diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java index 619c90e157..6359edea0b 100644 --- a/core/src/mindustry/Vars.java +++ b/core/src/mindustry/Vars.java @@ -13,9 +13,6 @@ import arc.util.io.*; import mindustry.ai.*; import mindustry.core.*; import mindustry.entities.*; -import mindustry.entities.effect.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; import mindustry.game.*; import mindustry.game.EventType.*; import mindustry.gen.*; @@ -24,8 +21,6 @@ import mindustry.maps.*; import mindustry.mod.*; import mindustry.net.Net; import mindustry.net.*; -import mindustry.type.Weather.*; -import mindustry.world.blocks.defense.ForceProjector.*; import java.io.*; import java.nio.charset.*; @@ -33,7 +28,6 @@ import java.util.*; import static arc.Core.settings; -@SuppressWarnings("unchecked") public class Vars implements Loadable{ /** Whether to load locales.*/ public static boolean loadLocales = true; @@ -61,7 +55,7 @@ public class Vars implements Loadable{ public static final String serverJsonURL = "https://raw.githubusercontent.com/Anuken/Mindustry/master/servers.json"; /** URL to the JSON file containing all the BE servers. Only queried in BE. */ public static final String serverJsonBeURL = "https://raw.githubusercontent.com/Anuken/Mindustry/master/servers_be.json"; - /** URL the links to the wiki's modding guide.*/ + /** URL of the github issue report template.*/ public static final String reportIssueURL = "https://github.com/Anuken/Mindustry/issues/new?template=bug_report.md"; /** list of built-in servers.*/ public static final Array defaultServers = Array.with(); @@ -79,6 +73,10 @@ public class Vars implements Loadable{ public static final float worldBounds = 100f; /** units outside of this bound will simply die instantly */ public static final float finalWorldBounds = worldBounds + 500; + /** mining range for manual miners */ + public static final float miningRange = 70f; + /** range for building */ + public static final float buildingRange = 220f; /** ticks spent out of bound until self destruct. */ public static final float boundsCountdown = 60 * 7; /** for map generator dialog */ @@ -180,19 +178,7 @@ public class Vars implements Loadable{ public static NetServer netServer; public static NetClient netClient; - public static Entities entities; - public static EntityGroup playerGroup; - public static EntityGroup tileGroup; - public static EntityGroup bulletGroup; - public static EntityGroup effectGroup; - public static EntityGroup groundEffectGroup; - public static EntityGroup shieldGroup; - public static EntityGroup puddleGroup; - public static EntityGroup fireGroup; - public static EntityGroup weatherGroup; - public static EntityGroup unitGroup; - - public static Player player; + public static Playerc player; @Override public void loadAsync(){ @@ -202,6 +188,7 @@ public class Vars implements Loadable{ public static void init(){ Serialization.init(); + Groups.init(); DefaultSerializers.typeMappings.put("mindustry.type.ContentType", "mindustry.ctype.ContentType"); if(loadLocales){ @@ -237,26 +224,6 @@ public class Vars implements Loadable{ indexer = new BlockIndexer(); pathfinder = new Pathfinder(); - entities = new Entities(); - playerGroup = entities.add(Player.class).enableMapping(); - tileGroup = entities.add(TileEntity.class, false); - bulletGroup = entities.add(Bullet.class).enableMapping(); - effectGroup = entities.add(EffectEntity.class, false); - groundEffectGroup = entities.add(DrawTrait.class, false); - puddleGroup = entities.add(Puddle.class).enableMapping(); - shieldGroup = entities.add(ShieldEntity.class, false); - fireGroup = entities.add(Fire.class).enableMapping(); - unitGroup = entities.add(BaseUnit.class).enableMapping(); - weatherGroup = entities.add(WeatherEntity.class); - - for(EntityGroup group : entities.all()){ - group.setRemoveListener(entity -> { - if(entity instanceof SyncTrait && net.client()){ - netClient.addRemovedEntity((entity).getID()); - } - }); - } - state = new GameState(); data = new GlobalData(); diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java index ff17679630..5d8380fa21 100644 --- a/core/src/mindustry/ai/BlockIndexer.java +++ b/core/src/mindustry/ai/BlockIndexer.java @@ -7,9 +7,9 @@ import arc.math.geom.*; import arc.struct.*; import arc.util.*; import mindustry.content.*; -import mindustry.entities.type.*; import mindustry.game.EventType.*; import mindustry.game.*; +import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.*; @@ -25,6 +25,7 @@ public class BlockIndexer{ /** Set of all ores that are being scanned. */ private final ObjectSet scanOres = new ObjectSet<>(); + private final IntSet intSet = new IntSet(); private final ObjectSet itemSet = new ObjectSet<>(); /** Stores all ore quadtrants on the map. */ private ObjectMap> ores = new ObjectMap<>(); @@ -121,7 +122,7 @@ public class BlockIndexer{ for(int x = 0; x < world.width(); x++){ for(int y = 0; y < world.height(); y++){ Tile tile = world.tile(x, y); - if(tile.getTeam() == team){ + if(tile.team() == team){ int quadrantX = tile.x / quadrantSize; int quadrantY = tile.y / quadrantSize; structQuadrant(team).set(quadrantX, quadrantY); @@ -145,7 +146,7 @@ public class BlockIndexer{ ObjectSet set = damagedTiles[team.id]; for(Tile tile : set){ - if((tile.entity == null || tile.entity.getTeam() != team || !tile.entity.damaged()) || tile.block() instanceof BuildBlock){ + if((tile.entity == null || tile.entity.team() != team || !tile.entity.damaged()) || tile.block() instanceof BuildBlock){ returnArray.add(tile); } } @@ -162,6 +163,39 @@ public class BlockIndexer{ return flagMap[team.id][type.ordinal()]; } + public boolean eachBlock(Teamc team, float range, Boolf pred, Cons cons){ + return eachBlock(team.team(), team.getX(), team.getY(), range, pred, cons); + } + + public boolean eachBlock(Team team, float wx, float wy, float range, Boolf pred, Cons cons){ + intSet.clear(); + + int tx = world.toTile(wx); + int ty = world.toTile(wy); + + int tileRange = (int)(range / tilesize + 1); + intSet.clear(); + boolean any = false; + + for(int x = -tileRange + tx; x <= tileRange + tx; x++){ + for(int y = -tileRange + ty; y <= tileRange + ty; y++){ + if(!Mathf.within(x * tilesize, y * tilesize, wx, wy, range)) continue; + + Tile other = world.ltile(x, y); + + if(other == null) continue; + + if(other.team() == team && !intSet.contains(other.pos()) && other.entity != null && pred.get(other)){ + cons.get(other); + any = true; + intSet.add(other.pos()); + } + } + } + + return any; + } + /** Get all enemy blocks with a flag. */ public Array getEnemy(Team team, BlockFlag type){ returnArray.clear(); @@ -178,20 +212,20 @@ public class BlockIndexer{ return returnArray; } - public void notifyTileDamaged(TileEntity entity){ - if(damagedTiles[(int)entity.getTeam().id] == null){ - damagedTiles[(int)entity.getTeam().id] = new ObjectSet<>(); + public void notifyTileDamaged(Tilec entity){ + if(damagedTiles[(int)entity.team().id] == null){ + damagedTiles[(int)entity.team().id] = new ObjectSet<>(); } - ObjectSet set = damagedTiles[(int)entity.getTeam().id]; - set.add(entity.tile); + ObjectSet set = damagedTiles[(int)entity.team().id]; + set.add(entity.tile()); } - public TileEntity findEnemyTile(Team team, float x, float y, float range, Boolf pred){ + public Tilec findEnemyTile(Team team, float x, float y, float range, Boolf pred){ for(Team enemy : activeTeams){ if(!team.isEnemy(enemy)) continue; - TileEntity entity = indexer.findTile(enemy, x, y, range, pred, true); + Tilec entity = indexer.findTile(enemy, x, y, range, pred, true); if(entity != null){ return entity; } @@ -200,12 +234,12 @@ public class BlockIndexer{ return null; } - public TileEntity findTile(Team team, float x, float y, float range, Boolf pred){ + public Tilec findTile(Team team, float x, float y, float range, Boolf pred){ return findTile(team, x, y, range, pred, false); } - public TileEntity findTile(Team team, float x, float y, float range, Boolf pred, boolean usePriority){ - TileEntity closest = null; + public Tilec findTile(Team team, float x, float y, float range, Boolf pred, boolean usePriority){ + Tilec closest = null; float dst = 0; float range2 = range*range; @@ -220,17 +254,17 @@ public class BlockIndexer{ if(other == null) continue; - if(other.entity == null || other.getTeam() != team || !pred.get(other) || !other.block().targetable) + if(other.entity == null || other.team() != team || !pred.get(other) || !other.block().targetable) continue; - TileEntity e = other.entity; + Tilec e = other.entity; - float ndst = Mathf.dst2(x, y, e.x, e.y); + float ndst = e.dst2(x, y); if(ndst < range2 && (closest == null || //this one is closer, and it is at least of equal priority - (ndst < dst && (!usePriority || closest.block.priority.ordinal() <= e.block.priority.ordinal())) || + (ndst < dst && (!usePriority || closest.block().priority.ordinal() <= e.block().priority.ordinal())) || //priority is used, and new block has higher priority regardless of range - (usePriority && closest.block.priority.ordinal() < e.block.priority.ordinal()))){ + (usePriority && closest.block().priority.ordinal() < e.block().priority.ordinal()))){ dst = ndst; closest = e; } @@ -271,8 +305,8 @@ public class BlockIndexer{ } private void process(Tile tile){ - if(tile.block().flags.size() > 0 && tile.getTeam() != Team.derelict){ - ObjectSet[] map = getFlagged(tile.getTeam()); + if(tile.block().flags.size() > 0 && tile.team() != Team.derelict){ + ObjectSet[] map = getFlagged(tile.team()); for(BlockFlag flag : tile.block().flags){ @@ -282,9 +316,9 @@ public class BlockIndexer{ map[flag.ordinal()] = arr; } - typeMap.put(tile.pos(), new TileIndex(tile.block().flags, tile.getTeam())); + typeMap.put(tile.pos(), new TileIndex(tile.block().flags, tile.team())); } - activeTeams.add(tile.getTeam()); + activeTeams.add(tile.team()); if(ores == null) return; @@ -328,7 +362,7 @@ public class BlockIndexer{ GridBits bits = structQuadrant(team); //fast-set this quadrant to 'occupied' if the tile just placed is already of this team - if(tile.getTeam() == team && tile.entity != null && tile.block().targetable){ + if(tile.team() == team && tile.entity != null && tile.block().targetable){ bits.set(quadrantX, quadrantY); continue; //no need to process futher } @@ -340,7 +374,7 @@ public class BlockIndexer{ for(int y = quadrantY * quadrantSize; y < world.height() && y < (quadrantY + 1) * quadrantSize; y++){ Tile result = world.ltile(x, y); //when a targetable block is found, mark this quadrant as occupied and stop searching - if(result.entity != null && result.getTeam() == team){ + if(result.entity != null && result.team() == team){ bits.set(quadrantX, quadrantY); break outer; } diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index a16ac8f410..b40e3543da 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -33,8 +33,7 @@ public class Pathfinder implements Runnable{ /** handles task scheduling on the update thread. */ private TaskQueue queue = new TaskQueue(); /** current pathfinding thread */ - private @Nullable - Thread thread; + private @Nullable Thread thread; public Pathfinder(){ Events.on(WorldLoadEvent.class, event -> { diff --git a/core/src/mindustry/ai/WaveSpawner.java b/core/src/mindustry/ai/WaveSpawner.java index 3bd5bc5400..ada260a51b 100644 --- a/core/src/mindustry/ai/WaveSpawner.java +++ b/core/src/mindustry/ai/WaveSpawner.java @@ -1,20 +1,16 @@ package mindustry.ai; -import arc.Events; -import arc.struct.Array; -import arc.func.Floatc2; -import arc.math.Angles; -import arc.math.Mathf; -import arc.util.Time; -import arc.util.Tmp; -import mindustry.content.Blocks; -import mindustry.content.Fx; -import mindustry.entities.Damage; -import mindustry.entities.Effects; -import mindustry.entities.type.*; -import mindustry.game.EventType.WorldLoadEvent; -import mindustry.game.SpawnGroup; -import mindustry.world.Tile; +import arc.*; +import arc.func.*; +import arc.math.*; +import arc.struct.*; +import arc.util.*; +import mindustry.content.*; +import mindustry.entities.*; +import mindustry.game.EventType.*; +import mindustry.game.*; +import mindustry.gen.*; +import mindustry.world.*; import static mindustry.Vars.*; @@ -39,7 +35,7 @@ public class WaveSpawner{ /** @return true if the player is near a ground spawn point. */ public boolean playerNear(){ - return groundSpawns.contains(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, player.x, player.y) < state.rules.dropZoneRadius); + return groundSpawns.contains(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, player.x(), player.y()) < state.rules.dropZoneRadius && player.team() != state.rules.waveTeam); } public void spawnEnemies(){ @@ -53,9 +49,10 @@ public class WaveSpawner{ eachFlyerSpawn((spawnX, spawnY) -> { for(int i = 0; i < spawned; i++){ - BaseUnit unit = group.createUnit(state.rules.waveTeam); - unit.set(spawnX + Mathf.range(spread), spawnY + Mathf.range(spread)); - unit.add(); + //TODO + //Unitc unit = group.createUnit(state.rules.waveTeam); + //unit.set(spawnX + Mathf.range(spread), spawnY + Mathf.range(spread)); + //unit.add(); } }); }else{ @@ -66,10 +63,11 @@ public class WaveSpawner{ for(int i = 0; i < spawned; i++){ Tmp.v1.rnd(spread); - BaseUnit unit = group.createUnit(state.rules.waveTeam); - unit.set(spawnX + Tmp.v1.x, spawnY + Tmp.v1.y); + //TODO + //Unitc unit = group.createUnit(state.rules.waveTeam); + //unit.set(spawnX + Tmp.v1.x, spawnY + Tmp.v1.y); - Time.run(Math.min(i * 5, 60 * 2), () -> spawnEffect(unit)); + //Time.run(Math.min(i * 5, 60 * 2), () -> spawnEffect(unit)); } }); } @@ -77,7 +75,7 @@ public class WaveSpawner{ eachGroundSpawn((spawnX, spawnY, doShockwave) -> { if(doShockwave){ - Time.run(20f, () -> Effects.effect(Fx.spawnShockwave, spawnX, spawnY, state.rules.dropZoneRadius)); + Time.run(20f, () -> Fx.spawnShockwave.at(spawnX, spawnY, state.rules.dropZoneRadius)); Time.run(40f, () -> Damage.damage(state.rules.waveTeam, spawnX, spawnY, state.rules.dropZoneRadius, 99999999f, true)); } }); @@ -91,10 +89,10 @@ public class WaveSpawner{ } if(state.rules.attackMode && state.teams.isActive(state.rules.waveTeam) && !state.teams.playerCores().isEmpty()){ - TileEntity firstCore = state.teams.playerCores().first(); - for(TileEntity core : state.rules.waveTeam.cores()){ - Tmp.v1.set(firstCore).sub(core.x, core.y).limit(coreMargin + core.block.size*tilesize); - cons.accept(core.x + Tmp.v1.x, core.y + Tmp.v1.y, false); + Tilec firstCore = state.teams.playerCores().first(); + for(Tilec core : state.rules.waveTeam.cores()){ + Tmp.v1.set(firstCore).sub(core).limit(coreMargin + core.block().size*tilesize); + cons.accept(core.x() + Tmp.v1.x, core.y() + Tmp.v1.y, false); } } } @@ -108,8 +106,8 @@ public class WaveSpawner{ } if(state.rules.attackMode && state.teams.isActive(state.rules.waveTeam)){ - for(TileEntity core : state.teams.get(state.rules.waveTeam).cores){ - cons.get(core.x, core.y); + for(Tilec core : state.teams.get(state.rules.waveTeam).cores){ + cons.get(core.x(), core.y()); } } } @@ -141,11 +139,11 @@ public class WaveSpawner{ flySpawns.add(fspawn); } - private void spawnEffect(BaseUnit unit){ - Effects.effect(Fx.unitSpawn, unit.x, unit.y, 0f, unit); + private void spawnEffect(Unitc unit){ + Fx.unitSpawn.at(unit.x(), unit.y(), 0f, unit); Time.run(30f, () -> { unit.add(); - Effects.effect(Fx.spawn, unit); + Fx.spawn.at(unit); }); } diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index 41103d219e..e6428ad0e0 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -10,7 +10,6 @@ import mindustry.*; import mindustry.ctype.*; import mindustry.entities.*; import mindustry.entities.bullet.*; -import mindustry.entities.type.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; @@ -57,7 +56,7 @@ public class Blocks implements ContentList{ scrapWall, scrapWallLarge, scrapWallHuge, scrapWallGigantic, thruster, //ok, these names are getting ridiculous, but at least I don't have humongous walls yet //transport - conveyor, titaniumConveyor, armoredConveyor, distributor, junction, itemBridge, phaseConveyor, sorter, invertedSorter, router, overflowGate, massDriver, + conveyor, titaniumConveyor, armoredConveyor, distributor, junction, itemBridge, phaseConveyor, sorter, invertedSorter, router, overflowGate, underflowGate, massDriver, //liquids mechanicalPump, rotaryPump, thermalPump, conduit, pulseConduit, platedConduit, liquidRouter, liquidTank, liquidJunction, bridgeConduit, phaseConduit, @@ -80,7 +79,7 @@ public class Blocks implements ContentList{ fortressFactory, repairPoint, //upgrades - dartPad, deltaPad, tauPad, omegaPad, javelinPad, tridentPad, glaivePad; + dartPad, alphaPad, deltaPad, tauPad, omegaPad, javelinPad, tridentPad, glaivePad; @Override public void load(){ @@ -269,13 +268,13 @@ public class Blocks implements ContentList{ }}; ice = new Floor("ice"){{ - //TODO fix drag/speed - dragMultiplier = 1f; - speedMultiplier = 1f; + dragMultiplier = 0.35f; + speedMultiplier = 0.9f; attributes.set(Attribute.water, 0.4f); }}; iceSnow = new Floor("ice-snow"){{ + dragMultiplier = 0.6f; variants = 3; attributes.set(Attribute.water, 0.3f); }}; @@ -409,12 +408,37 @@ public class Blocks implements ContentList{ //endregion //region ore - oreCopper = new OreBlock(Items.copper); - oreLead = new OreBlock(Items.lead); + oreCopper = new OreBlock(Items.copper){{ + oreDefault = true; + oreThreshold = 0.81f; + oreScale = 23.47619f; + }}; + + oreLead = new OreBlock(Items.lead){{ + oreDefault = true; + oreThreshold = 0.828f; + oreScale = 23.952381f; + }}; + oreScrap = new OreBlock(Items.scrap); - oreCoal = new OreBlock(Items.coal); - oreTitanium = new OreBlock(Items.titanium); - oreThorium = new OreBlock(Items.thorium); + + oreCoal = new OreBlock(Items.coal){{ + oreDefault = true; + oreThreshold = 0.846f; + oreScale = 24.428572f; + }}; + + oreTitanium = new OreBlock(Items.titanium){{ + oreDefault = true; + oreThreshold = 0.864f; + oreScale = 24.904762f; + }}; + + oreThorium = new OreBlock(Items.thorium){{ + oreDefault = true; + oreThreshold = 0.882f; + oreScale = 25.380953f; + }}; //endregion //region crafting @@ -573,7 +597,7 @@ public class Blocks implements ContentList{ drawIcons = () -> new TextureRegion[]{Core.atlas.find(name + "-bottom"), Core.atlas.find(name + "-top")}; drawer = tile -> { - LiquidModule mod = tile.entity.liquids; + LiquidModule mod = tile.entity.liquids(); int rotation = rotate ? tile.rotation() * 90 : 0; @@ -664,13 +688,12 @@ public class Blocks implements ContentList{ int topRegion = reg("-top"); drawIcons = () -> new TextureRegion[]{Core.atlas.find(name), Core.atlas.find(name + "-top")}; - drawer = tile -> { GenericCrafterEntity entity = tile.ent(); 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()); @@ -956,6 +979,12 @@ public class Blocks implements ContentList{ buildCostMultiplier = 3f; }}; + underflowGate = new OverflowGate("underflow-gate"){{ + requirements(Category.distribution, ItemStack.with(Items.lead, 2, Items.copper, 4)); + buildCostMultiplier = 3f; + invert = true; + }}; + massDriver = new MassDriver("mass-driver"){{ requirements(Category.distribution, ItemStack.with(Items.titanium, 125, Items.silicon, 75, Items.lead, 125, Items.thorium, 50)); size = 3; @@ -1516,25 +1545,25 @@ public class Blocks implements ContentList{ } @Override - public void init(mindustry.entities.type.Bullet b){ + public void init(Bulletc 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); + Damage.collideLine(b, b.team(), hitEffect, b.x(), b.y(), b.rotation(), rayLength - Math.abs(i - (rays / 2)) * 20f); } } @Override - public void draw(Bullet b){ + public void draw(Bulletc b){ super.draw(b); 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); + Tmp.v1.trns(b.rotation(), i * 8f); float sl = Mathf.clamp(b.fout() - 0.5f) * (80f - i * 10); - Drawf.tri(b.x + Tmp.v1.x, b.y + Tmp.v1.y, 4f, sl, b.rot() + 90); - Drawf.tri(b.x + Tmp.v1.x, b.y + Tmp.v1.y, 4f, sl, b.rot() - 90); + Drawf.tri(b.x() + Tmp.v1.x, b.y() + Tmp.v1.y, 4f, sl, b.rotation() + 90); + Drawf.tri(b.x() + Tmp.v1.x, b.y() + Tmp.v1.y, 4f, sl, b.rotation() - 90); } - Drawf.tri(b.x, b.y, 20f * b.fout(), (rayLength + 50), b.rot()); - Drawf.tri(b.x, b.y, 20f * b.fout(), 10f, b.rot() + 180f); + Drawf.tri(b.x(), b.y(), 20f * b.fout(), (rayLength + 50), b.rotation()); + Drawf.tri(b.x(), b.y(), 20f * b.fout(), 10f, b.rotation() + 180f); Draw.reset(); } }); @@ -1688,6 +1717,7 @@ public class Blocks implements ContentList{ unitType = UnitTypes.ghoul; produceTime = 1150; size = 3; + maxSpawn = 2; consumes.power(1.2f); consumes.items(new ItemStack(Items.silicon, 15), new ItemStack(Items.titanium, 10)); }}; @@ -1697,6 +1727,7 @@ public class Blocks implements ContentList{ unitType = UnitTypes.revenant; produceTime = 2000; size = 4; + maxSpawn = 2; consumes.power(3f); consumes.items(new ItemStack(Items.silicon, 40), new ItemStack(Items.titanium, 30)); }}; @@ -1749,51 +1780,58 @@ public class Blocks implements ContentList{ //endregion //region upgrades - dartPad = new MechPad("dart-mech-pad"){{ + dartPad = new MechPad("dart-ship-pad"){{ requirements(Category.upgrade, ItemStack.with(Items.lead, 100, Items.graphite, 50, Items.copper, 75)); - mech = Mechs.alpha; + mech = UnitTypes.dart; + size = 2; + consumes.power(0.5f); + }}; + + alphaPad = new MechPad("alpha-mech-pad"){{ + requirements(Category.upgrade, ItemStack.with(Items.lead, 100, Items.graphite, 50, Items.copper, 75)); + mech = UnitTypes.alpha; size = 2; consumes.power(0.5f); }}; deltaPad = new MechPad("delta-mech-pad"){{ requirements(Category.upgrade, ItemStack.with(Items.lead, 175, Items.titanium, 175, Items.copper, 200, Items.silicon, 225, Items.thorium, 150)); - mech = Mechs.delta; + mech = UnitTypes.delta; size = 2; consumes.power(0.7f); }}; tauPad = new MechPad("tau-mech-pad"){{ requirements(Category.upgrade, ItemStack.with(Items.lead, 125, Items.titanium, 125, Items.copper, 125, Items.silicon, 125)); - mech = Mechs.tau; + mech = UnitTypes.tau; size = 2; consumes.power(1f); }}; omegaPad = new MechPad("omega-mech-pad"){{ requirements(Category.upgrade, ItemStack.with(Items.lead, 225, Items.graphite, 275, Items.silicon, 325, Items.thorium, 300, Items.surgealloy, 120)); - mech = Mechs.omega; + mech = UnitTypes.omega; size = 3; consumes.power(1.2f); }}; javelinPad = new MechPad("javelin-ship-pad"){{ requirements(Category.upgrade, ItemStack.with(Items.lead, 175, Items.silicon, 225, Items.titanium, 250, Items.plastanium, 200, Items.phasefabric, 100)); - mech = Mechs.javelin; + mech = UnitTypes.javelin; size = 2; consumes.power(0.8f); }}; tridentPad = new MechPad("trident-ship-pad"){{ requirements(Category.upgrade, ItemStack.with(Items.lead, 125, Items.copper, 125, Items.silicon, 125, Items.titanium, 150, Items.plastanium, 100)); - mech = Mechs.trident; + mech = UnitTypes.trident; size = 2; consumes.power(1f); }}; glaivePad = new MechPad("glaive-ship-pad"){{ requirements(Category.upgrade, ItemStack.with(Items.lead, 225, Items.silicon, 325, Items.titanium, 350, Items.plastanium, 300, Items.surgealloy, 100)); - mech = Mechs.glaive; + mech = UnitTypes.glaive; size = 3; consumes.power(1.2f); }}; diff --git a/core/src/mindustry/content/Bullets.java b/core/src/mindustry/content/Bullets.java index 017798731c..a3c4925e19 100644 --- a/core/src/mindustry/content/Bullets.java +++ b/core/src/mindustry/content/Bullets.java @@ -4,11 +4,10 @@ import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; import arc.util.*; -import mindustry.ctype.ContentList; +import mindustry.ctype.*; import mindustry.entities.*; import mindustry.entities.bullet.*; -import mindustry.entities.effect.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.graphics.*; import mindustry.world.*; @@ -384,7 +383,7 @@ public class Bullets implements ContentList{ }}; damageLightning = new BulletType(0.0001f, 0f){{ - lifetime = Lightning.lifetime; + lifetime = Fx.lightning.lifetime; hitEffect = Fx.hitLancer; despawnEffect = Fx.none; status = StatusEffects.shocked; @@ -410,32 +409,33 @@ public class Bullets implements ContentList{ } @Override - public void init(Bullet b){ - b.velocity().setLength(0.6f + Mathf.random(2f)); + public void init(Bulletc b){ + b.vel().setLength(0.6f + Mathf.random(2f)); } @Override - public void draw(Bullet b){ + public void draw(Bulletc b){ Draw.color(Pal.lightFlame, Pal.darkFlame, Color.gray, b.fin()); - Fill.circle(b.x, b.y, 3f * b.fout()); + Fill.circle(b.x(), b.y(), 3f * b.fout()); Draw.reset(); } @Override - public void update(Bullet b){ + public void update(Bulletc b){ if(Mathf.chance(0.04 * Time.delta())){ - Tile tile = world.tileWorld(b.x, b.y); + Tile tile = world.tileWorld(b.x(), b.y()); if(tile != null){ - Fire.create(tile); + //TODO implement + //Fire.create(tile); } } if(Mathf.chance(0.1 * Time.delta())){ - Effects.effect(Fx.fireballsmoke, b.x, b.y); + Fx.fireballsmoke.at(b.x(), b.y()); } if(Mathf.chance(0.1 * Time.delta())){ - Effects.effect(Fx.ballfire, b.x, b.y); + Fx.ballfire.at(b.x(), b.y()); } } }; @@ -452,6 +452,7 @@ public class Bullets implements ContentList{ hitEffect = Fx.hitFlameSmall; despawnEffect = Fx.none; status = StatusEffects.burning; + keepVelocity = false; } @Override @@ -460,7 +461,7 @@ public class Bullets implements ContentList{ } @Override - public void draw(Bullet b){ + public void draw(Bulletc b){ } }; @@ -479,50 +480,17 @@ public class Bullets implements ContentList{ } @Override - public void draw(Bullet b){ + public void draw(Bulletc b){ } }; - lancerLaser = new BulletType(0.001f, 140){ - 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; - - { - hitEffect = Fx.hitLancer; - despawnEffect = Fx.none; - hitSize = 4; - lifetime = 16f; - pierce = true; - } - - @Override - public float range(){ - return length; - } - - @Override - public void init(Bullet b){ - Damage.collideLine(b, b.getTeam(), hitEffect, b.x, b.y, b.rot(), length); - } - - @Override - public void draw(Bullet b){ - float f = Mathf.curve(b.fin(), 0f, 0.2f); - float baseLen = length * f; - - Lines.lineAngle(b.x, b.y, b.rot(), baseLen); - for(int s = 0; s < 3; s++){ - Draw.color(colors[s]); - for(int i = 0; i < tscales.length; i++){ - Lines.stroke(7f * b.fout() * (s == 0 ? 1.5f : s == 1 ? 1f : 0.3f) * tscales[i]); - Lines.lineAngle(b.x, b.y, b.rot(), baseLen * lenscales[i]); - } - } - Draw.reset(); - } - }; + lancerLaser = new LaserBulletType(140){{ + colors = new Color[]{Pal.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Pal.lancerLaser, Color.white}; + hitEffect = Fx.hitLancer; + despawnEffect = Fx.none; + hitSize = 4; + lifetime = 16f; + }}; meltdownLaser = new BulletType(0.001f, 70){ Color tmpColor = new Color(); @@ -542,32 +510,33 @@ public class Bullets implements ContentList{ } @Override - public void update(Bullet b){ - if(b.timer.get(1, 5f)){ - Damage.collideLine(b, b.getTeam(), hitEffect, b.x, b.y, b.rot(), length, true); + public void update(Bulletc b){ + if(b.timer(1, 5f)){ + Damage.collideLine(b, b.team(), hitEffect, b.x(), b.y(), b.rotation(), length, true); } - Effects.shake(1f, 1f, b.x, b.y); + Effects.shake(1f, 1f, b.x(), b.y()); } @Override - public void hit(Bullet b, float hitx, float hity){ - Effects.effect(hitEffect, colors[2], hitx, hity); + public void hit(Bulletc b, float hitx, float hity){ + hitEffect.at(hitx, hity, colors[2]); if(Mathf.chance(0.4)){ - Fire.create(world.tileWorld(hitx + Mathf.range(5f), hity + Mathf.range(5f))); + //TODO implement + // Fire.create(world.tileWorld(hitx + Mathf.range(5f), hity + Mathf.range(5f))); } } @Override - public void draw(Bullet b){ + public void draw(Bulletc b){ float baseLen = (length) * b.fout(); - Lines.lineAngle(b.x, b.y, b.rot(), baseLen); + Lines.lineAngle(b.x(), b.y(), b.rotation(), baseLen); for(int s = 0; s < colors.length; s++){ Draw.color(tmpColor.set(colors[s]).mul(1f + Mathf.absin(Time.time(), 1f, 0.1f))); for(int i = 0; i < tscales.length; i++){ - Tmp.v1.trns(b.rot() + 180f, (lenscales[i] - 1f) * 35f); + Tmp.v1.trns(b.rotation() + 180f, (lenscales[i] - 1f) * 35f); Lines.stroke((9f + Mathf.absin(Time.time(), 0.8f, 1.5f)) * b.fout() * strokes[s] * tscales[i]); - Lines.lineAngle(b.x + Tmp.v1.x, b.y + Tmp.v1.y, b.rot(), baseLen * lenscales[i], CapStyle.none); + Lines.lineAngle(b.x() + Tmp.v1.x, b.y() + Tmp.v1.y, b.rotation(), baseLen * lenscales[i], CapStyle.none); } } Draw.reset(); @@ -613,31 +582,20 @@ public class Bullets implements ContentList{ } @Override - public void draw(Bullet b){ + public void draw(Bulletc b){ } @Override - public void init(Bullet b){ - Lightning.create(b.getTeam(), Pal.lancerLaser, damage * (b.getOwner() instanceof Player ? state.rules.playerDamageMultiplier : 1f), b.x, b.y, b.rot(), 30); + public void init(Bulletc b){ + //TODO owners are never players... + Lightning.create(b.team(), Pal.lancerLaser, damage * (b.owner() instanceof Playerc ? state.rules.playerDamageMultiplier : 1f), b.x(), b.y(), b.rotation(), 30); } }; - arc = new BulletType(0.001f, 21){ - { - lifetime = 1; - despawnEffect = Fx.none; - hitEffect = Fx.hitLancer; - } - - @Override - public void draw(Bullet b){ - } - - @Override - public void init(Bullet b){ - Lightning.create(b.getTeam(), Pal.lancerLaser, damage, b.x, b.y, b.rot(), 25); - } - }; + arc = new LightningBulletType(){{ + damage = 21; + lightningLength = 25; + }}; driverBolt = new MassDriverBolt(); @@ -678,12 +636,13 @@ public class Bullets implements ContentList{ } @Override - public void hit(Bullet b, float x, float y){ + public void hit(Bulletc b, float x, float y){ super.hit(b, x, y); for(int i = 0; i < 3; i++){ Tile tile = world.tileWorld(x + Mathf.range(8f), y + Mathf.range(8f)); - Puddle.deposit(tile, Liquids.oil, 5f); + //TODO implement + //Puddle.deposit(tile, Liquids.oil, 5f); } } }; diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index a116034e1a..22436c5154 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -4,1097 +4,1139 @@ import arc.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; +import arc.math.geom.*; +import arc.struct.*; import arc.util.*; -import mindustry.ctype.ContentList; -import mindustry.entities.Effects.*; -import mindustry.entities.effect.GroundEffectEntity.*; -import mindustry.entities.type.*; +import mindustry.entities.*; +import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; -import mindustry.ui.Cicon; +import mindustry.ui.*; +import static arc.graphics.g2d.Draw.*; +import static arc.graphics.g2d.Lines.*; +import static arc.math.Angles.*; import static mindustry.Vars.*; -public class Fx implements ContentList{ - public static Effect +public class Fx{ + public static final Effect + + none = new Effect(0, 0f, e -> {}), + + unitSpawn = new Effect(30f, e -> { + if(!(e.data instanceof Unitc)) return; + + alpha(e.fin()); + + float scl = 1f + e.fout() * 2f; + + Unitc unit = (Unitc)e.data; + rect(unit.type().region, e.x, e.y, + unit.type().region.getWidth() * Draw.scl * scl, unit.type().region.getHeight() * Draw.scl * scl, 180f); + + }), + + itemTransfer = new Effect(30f, e -> { + if(!(e.data instanceof Position)) return; + Position to = e.data(); + Tmp.v1.set(e.x, e.y).interpolate(Tmp.v2.set(to), e.fin(), Interpolation.pow3) + .add(Tmp.v2.sub(e.x, e.y).nor().rotate90(1).scl(Mathf.randomSeedRange(e.id, 1f) * e.fslope() * 10f)); + float x = Tmp.v1.x, y = Tmp.v1.y; + + stroke(e.fslope() * 2f, Pal.accent); + Lines.circle(x, y, e.fslope() * 2f); + + color(e.color); + Fill.circle(x, y, e.fslope() * 1.5f); + }), + + lightning = new Effect(10f, 500f, e -> { + if(!(e.data instanceof Array)) return; + Array lines = e.data(); + + stroke(3f * e.fout()); + color(e.color, Color.white, e.fin()); + beginLine(); + + linePoint(e.x, e.y); + lines.each(Lines::linePoint); + endLine(); + + int i = 0; + for(Vec2 p : lines){ + Fill.square(p.x, p.y, (5f - (float)i++ / lines.size * 2f) * e.fout(), 45); + } + }), + + commandSend = new Effect(28, e -> { + color(Pal.command); + stroke(e.fout() * 2f); + Lines.circle(e.x, e.y, 4f + e.finpow() * 120f); + }), + + placeBlock = new Effect(16, e -> { + color(Pal.accent); + stroke(3f - e.fin() * 2f); + Lines.square(e.x, e.y, tilesize / 2f * e.rotation + e.fin() * 3f); + }), + + tapBlock = new Effect(12, e -> { + color(Pal.accent); + stroke(3f - e.fin() * 2f); + Lines.circle(e.x, e.y, 4f + (tilesize / 1.5f * e.rotation) * e.fin()); + }), + + breakBlock = new Effect(12, e -> { + color(Pal.remove); + stroke(3f - e.fin() * 2f); + Lines.square(e.x, e.y, tilesize / 2f * e.rotation + e.fin() * 3f); + + randLenVectors(e.id, 3 + (int)(e.rotation * 3), e.rotation * 2f + (tilesize * e.rotation) * e.finpow(), (x, y) -> { + Fill.square(e.x + x, e.y + y, 1f + e.fout() * (3f + e.rotation)); + }); + }), + + select = new Effect(23, e -> { + color(Pal.accent); + stroke(e.fout() * 3f); + Lines.circle(e.x, e.y, 3f + e.fin() * 14f); + }), + + smoke = new Effect(100, e -> { + color(Color.gray, Pal.darkishGray, e.fin()); + Fill.circle(e.x, e.y, (7f - e.fin() * 7f)/2f); + }), - none, placeBlock, breakBlock, smoke, spawn, tapBlock, select, - vtolHover, unitDrop, unitPickup, unitLand, pickup, healWave, heal, landShock, reactorsmoke, nuclearsmoke, nuclearcloud, - redgeneratespark, generatespark, fuelburn, plasticburn, pulverize, pulverizeRed, pulverizeRedder, pulverizeSmall, pulverizeMedium, - producesmoke, smeltsmoke, formsmoke, blastsmoke, lava, doorclose, dooropen, dooropenlarge, doorcloselarge, purify, purifyoil, purifystone, generate, - mine, mineBig, mineHuge, smelt, teleportActivate, teleport, teleportOut, ripple, bubble, launch, - healBlock, healBlockFull, healWaveMend, overdriveWave, overdriveBlockFull, shieldBreak, hitBulletSmall, hitFuse, - hitBulletBig, hitFlameSmall, hitLiquid, hitLaser, hitLancer, hitMeltdown, despawn, flakExplosion, blastExplosion, - plasticExplosion, artilleryTrail, incendTrail, missileTrail, absorb, flakExplosionBig, plasticExplosionFlak, burning, fire, - fireSmoke, steam, fireballsmoke, ballfire, freezing, melting, wet, oily, overdriven, dropItem, shockwave, - 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, coreLand; + magmasmoke = new Effect(110, e -> { + color(Color.gray); + Fill.circle(e.x, e.y, e.fslope() * 6f); + }), - @Override - public void load(){ + spawn = new Effect(30, e -> { + stroke(2f * e.fout()); + color(Pal.accent); + Lines.poly(e.x, e.y, 4, 5f + e.fin() * 12f); + }), - none = new Effect(0, 0f, e -> {}); + padlaunch = new Effect(10, e -> { + stroke(4f * e.fout()); + color(Pal.accent); + Lines.poly(e.x, e.y, 4, 5f + e.fin() * 60f); + }), - unitSpawn = new Effect(30f, e -> { - if(!(e.data instanceof BaseUnit)) return; - - Draw.alpha(e.fin()); - - float scl = 1f + e.fout() * 2f; - - BaseUnit unit = (BaseUnit)e.data; - Draw.rect(unit.getIconRegion(), e.x, e.y, - unit.getIconRegion().getWidth() * Draw.scl * scl, unit.getIconRegion().getWidth() * Draw.scl * scl, 180f); + vtolHover = new Effect(40f, e -> { + float len = e.finpow() * 10f; + float ang = e.rotation + Mathf.randomSeedRange(e.id, 30f); + color(Pal.lightFlame, Pal.lightOrange, e.fin()); + Fill.circle(e.x + trnsx(ang, len), e.y + trnsy(ang, len), 2f * e.fout()); + }), + unitDrop = new Effect(30, e -> { + color(Pal.lightishGray); + randLenVectors(e.id, 9, 3 + 20f * e.finpow(), (x, y) -> { + Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.4f); }); + }).ground(), - commandSend = new Effect(28, e -> { - Draw.color(Pal.command); - Lines.stroke(e.fout() * 2f); - Lines.circle(e.x, e.y, 4f + e.finpow() * 120f); + unitLand = new Effect(30, e -> { + color(Tmp.c1.set(e.color).mul(1.1f)); + randLenVectors(e.id, 6, 17f * e.finpow(), (x, y) -> { + Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.3f); }); + }).ground(), - placeBlock = new Effect(16, e -> { - Draw.color(Pal.accent); - Lines.stroke(3f - e.fin() * 2f); - Lines.square(e.x, e.y, tilesize / 2f * e.rotation + e.fin() * 3f); - }); - - tapBlock = new Effect(12, e -> { - Draw.color(Pal.accent); - Lines.stroke(3f - e.fin() * 2f); - Lines.circle(e.x, e.y, 4f + (tilesize / 1.5f * e.rotation) * e.fin()); - }); + unitPickup = new Effect(18, e -> { + color(Pal.lightishGray); + stroke(e.fin() * 2f); + Lines.poly(e.x, e.y, 4, 13f * e.fout()); + }).ground(), - breakBlock = new Effect(12, e -> { - Draw.color(Pal.remove); - Lines.stroke(3f - e.fin() * 2f); - Lines.square(e.x, e.y, tilesize / 2f * e.rotation + e.fin() * 3f); + landShock = new Effect(12, e -> { + color(Pal.lancerLaser); + stroke(e.fout() * 3f); + Lines.poly(e.x, e.y, 12, 20f * e.fout()); + }).ground(), - Angles.randLenVectors(e.id, 3 + (int)(e.rotation * 3), e.rotation * 2f + (tilesize * e.rotation) * e.finpow(), (x, y) -> { - Fill.square(e.x + x, e.y + y, 1f + e.fout() * (3f + e.rotation)); - }); - }); + pickup = new Effect(18, e -> { + color(Pal.lightishGray); + stroke(e.fout() * 2f); + Lines.spikes(e.x, e.y, 1f + e.fin() * 6f, e.fout() * 4f, 6); + }), - select = new Effect(23, e -> { - Draw.color(Pal.accent); - Lines.stroke(e.fout() * 3f); - Lines.circle(e.x, e.y, 3f + e.fin() * 14f); - }); + healWave = new Effect(22, e -> { + color(Pal.heal); + stroke(e.fout() * 2f); + Lines.circle(e.x, e.y, 4f + e.finpow() * 60f); + }), - smoke = new Effect(100, e -> { - Draw.color(Color.gray, Pal.darkishGray, e.fin()); - float size = 7f - e.fin() * 7f; - Draw.rect("circle", e.x, e.y, size, size); - }); + heal = new Effect(11, e -> { + color(Pal.heal); + stroke(e.fout() * 2f); + Lines.circle(e.x, e.y, 2f + e.finpow() * 7f); + }), - magmasmoke = new Effect(110, e -> { - Draw.color(Color.gray); - Fill.circle(e.x, e.y, e.fslope() * 6f); - }); + hitBulletSmall = new Effect(14, e -> { + color(Color.white, Pal.lightOrange, e.fin()); - spawn = new Effect(30, e -> { - Lines.stroke(2f * e.fout()); - Draw.color(Pal.accent); - Lines.poly(e.x, e.y, 4, 5f + e.fin() * 12f); + e.scaled(7f, s -> { + stroke(0.5f + s.fout()); + Lines.circle(e.x, e.y, s.fin() * 5f); }); - padlaunch = new Effect(10, e -> { - Lines.stroke(4f * e.fout()); - Draw.color(Pal.accent); - Lines.poly(e.x, e.y, 4, 5f + e.fin() * 60f); - }); + stroke(0.5f + e.fout()); - vtolHover = new Effect(40f, e -> { - float len = e.finpow() * 10f; - float ang = e.rotation + Mathf.randomSeedRange(e.id, 30f); - Draw.color(Pal.lightFlame, Pal.lightOrange, e.fin()); - Fill.circle(e.x + Angles.trnsx(ang, len), e.y + Angles.trnsy(ang, len), 2f * e.fout()); + randLenVectors(e.id, 5, e.fin() * 15f, (x, y) -> { + float ang = Mathf.angle(x, y); + lineAngle(e.x + x, e.y + y, ang, e.fout() * 3 + 1f); }); + }), - unitDrop = new GroundEffect(30, e -> { - Draw.color(Pal.lightishGray); - Angles.randLenVectors(e.id, 9, 3 + 20f * e.finpow(), (x, y) -> { - Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.4f); - }); - }); + hitFuse = new Effect(14, e -> { + color(Color.white, Pal.surge, e.fin()); - unitLand = new GroundEffect(30, e -> { - Draw.color(Tmp.c1.set(e.color).mul(1.1f)); - Angles.randLenVectors(e.id, 6, 17f * e.finpow(), (x, y) -> { - Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.3f); - }); + e.scaled(7f, s -> { + stroke(0.5f + s.fout()); + Lines.circle(e.x, e.y, s.fin() * 7f); }); - unitPickup = new GroundEffect(18, e -> { - Draw.color(Pal.lightishGray); - Lines.stroke(e.fin() * 2f); - Lines.poly(e.x, e.y, 4, 13f * e.fout()); - }); + stroke(0.5f + e.fout()); - landShock = new GroundEffect(12, e -> { - Draw.color(Pal.lancerLaser); - Lines.stroke(e.fout() * 3f); - Lines.poly(e.x, e.y, 12, 20f * e.fout()); + randLenVectors(e.id, 6, e.fin() * 15f, (x, y) -> { + float ang = Mathf.angle(x, y); + lineAngle(e.x + x, e.y + y, ang, e.fout() * 3 + 1f); }); - pickup = new Effect(18, e -> { - Draw.color(Pal.lightishGray); - Lines.stroke(e.fout() * 2f); - Lines.spikes(e.x, e.y, 1f + e.fin() * 6f, e.fout() * 4f, 6); - }); + }), - healWave = new Effect(22, e -> { - Draw.color(Pal.heal); - Lines.stroke(e.fout() * 2f); - Lines.circle(e.x, e.y, 4f + e.finpow() * 60f); - }); + hitBulletBig = new Effect(13, e -> { + color(Color.white, Pal.lightOrange, e.fin()); + stroke(0.5f + e.fout() * 1.5f); - heal = new Effect(11, e -> { - Draw.color(Pal.heal); - Lines.stroke(e.fout() * 2f); - Lines.circle(e.x, e.y, 2f + e.finpow() * 7f); + randLenVectors(e.id, 8, e.finpow() * 30f, e.rotation, 50f, (x, y) -> { + float ang = Mathf.angle(x, y); + lineAngle(e.x + x, e.y + y, ang, e.fout() * 4 + 1.5f); }); + }), - hitBulletSmall = new Effect(14, e -> { - Draw.color(Color.white, Pal.lightOrange, e.fin()); - - e.scaled(7f, s -> { - Lines.stroke(0.5f + s.fout()); - Lines.circle(e.x, e.y, s.fin() * 5f); - }); - - - Lines.stroke(0.5f + e.fout()); - - Angles.randLenVectors(e.id, 5, e.fin() * 15f, (x, y) -> { - float ang = Mathf.angle(x, y); - Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 3 + 1f); - }); + hitFlameSmall = new Effect(14, e -> { + color(Pal.lightFlame, Pal.darkFlame, e.fin()); + stroke(0.5f + e.fout()); + randLenVectors(e.id, 2, e.fin() * 15f, e.rotation, 50f, (x, y) -> { + float ang = Mathf.angle(x, y); + lineAngle(e.x + x, e.y + y, ang, e.fout() * 3 + 1f); }); - hitFuse = new Effect(14, e -> { - Draw.color(Color.white, Pal.surge, e.fin()); + }), - e.scaled(7f, s -> { - Lines.stroke(0.5f + s.fout()); - Lines.circle(e.x, e.y, s.fin() * 7f); - }); - - - Lines.stroke(0.5f + e.fout()); - - Angles.randLenVectors(e.id, 6, e.fin() * 15f, (x, y) -> { - float ang = Mathf.angle(x, y); - Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 3 + 1f); - }); + hitLiquid = new Effect(16, e -> { + color(e.color); + randLenVectors(e.id, 5, e.fin() * 15f, e.rotation + 180f, 60f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, e.fout() * 2f); }); - hitBulletBig = new Effect(13, e -> { - 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) -> { - float ang = Mathf.angle(x, y); - Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 4 + 1.5f); - }); + hitLancer = new Effect(12, e -> { + color(Color.white); + stroke(e.fout() * 1.5f); + randLenVectors(e.id, 8, e.finpow() * 17f, e.rotation, 360f, (x, y) -> { + float ang = Mathf.angle(x, y); + lineAngle(e.x + x, e.y + y, ang, e.fout() * 4 + 1f); }); - hitFlameSmall = new Effect(14, e -> { - Draw.color(Pal.lightFlame, Pal.darkFlame, e.fin()); - Lines.stroke(0.5f + e.fout()); + }), - Angles.randLenVectors(e.id, 2, e.fin() * 15f, e.rotation, 50f, (x, y) -> { - float ang = Mathf.angle(x, y); - Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 3 + 1f); - }); + hitMeltdown = new Effect(12, e -> { + color(Pal.meltdownHit); + stroke(e.fout() * 2f); + randLenVectors(e.id, 6, e.finpow() * 18f, e.rotation, 360f, (x, y) -> { + float ang = Mathf.angle(x, y); + lineAngle(e.x + x, e.y + y, ang, e.fout() * 4 + 1f); }); - hitLiquid = new Effect(16, e -> { - Draw.color(e.color); - - Angles.randLenVectors(e.id, 5, e.fin() * 15f, e.rotation + 180f, 60f, (x, y) -> { - Fill.circle(e.x + x, e.y + y, e.fout() * 2f); - }); + }), - }); + hitLaser = new Effect(8, e -> { + color(Color.white, Pal.heal, e.fin()); + stroke(0.5f + e.fout()); + Lines.circle(e.x, e.y, e.fin() * 5f); + }), - hitLancer = new Effect(12, e -> { - Draw.color(Color.white); - Lines.stroke(e.fout() * 1.5f); + hitYellowLaser = new Effect(8, e -> { + color(Color.white, Pal.lightTrail, e.fin()); + stroke(0.5f + e.fout()); + Lines.circle(e.x, e.y, e.fin() * 5f); + }), - Angles.randLenVectors(e.id, 8, e.finpow() * 17f, e.rotation, 360f, (x, y) -> { - float ang = Mathf.angle(x, y); - Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 4 + 1f); - }); + despawn = new Effect(12, e -> { + color(Pal.lighterOrange, Color.gray, e.fin()); + stroke(e.fout()); + randLenVectors(e.id, 7, e.fin() * 7f, e.rotation, 40f, (x, y) -> { + float ang = Mathf.angle(x, y); + lineAngle(e.x + x, e.y + y, ang, e.fout() * 2 + 1f); }); - hitMeltdown = new Effect(12, e -> { - Draw.color(Pal.meltdownHit); - Lines.stroke(e.fout() * 2f); + }), - Angles.randLenVectors(e.id, 6, e.finpow() * 18f, e.rotation, 360f, (x, y) -> { - float ang = Mathf.angle(x, y); - Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 4 + 1f); - }); + flakExplosion = new Effect(20, e -> { + color(Pal.bulletYellow); + e.scaled(6, i -> { + stroke(3f * i.fout()); + Lines.circle(e.x, e.y, 3f + i.fin() * 10f); }); - hitLaser = new Effect(8, e -> { - Draw.color(Color.white, Pal.heal, e.fin()); - Lines.stroke(0.5f + e.fout()); - Lines.circle(e.x, e.y, e.fin() * 5f); - }); + color(Color.gray); - despawn = new Effect(12, e -> { - Draw.color(Pal.lighterOrange, Color.gray, e.fin()); - Lines.stroke(e.fout()); + randLenVectors(e.id, 5, 2f + 23f * e.finpow(), (x, y) -> { + Fill.circle(e.x + x, e.y + y, e.fout() * 3f + 0.5f); + }); - Angles.randLenVectors(e.id, 7, e.fin() * 7f, e.rotation, 40f, (x, y) -> { - float ang = Mathf.angle(x, y); - Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 2 + 1f); - }); + color(Pal.lighterOrange); + stroke(1f * e.fout()); + randLenVectors(e.id + 1, 4, 1f + 23f * e.finpow(), (x, y) -> { + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); }); - flakExplosion = new Effect(20, e -> { + }), - Draw.color(Pal.bulletYellow); - e.scaled(6, i -> { - Lines.stroke(3f * i.fout()); - Lines.circle(e.x, e.y, 3f + i.fin() * 10f); - }); + plasticExplosion = new Effect(24, e -> { - Draw.color(Color.gray); + color(Pal.plastaniumFront); + e.scaled(7, i -> { + stroke(3f * i.fout()); + Lines.circle(e.x, e.y, 3f + i.fin() * 24f); + }); - Angles.randLenVectors(e.id, 5, 2f + 23f * e.finpow(), (x, y) -> { - Fill.circle(e.x + x, e.y + y, e.fout() * 3f + 0.5f); - }); + color(Color.gray); - Draw.color(Pal.lighterOrange); - Lines.stroke(1f * e.fout()); + randLenVectors(e.id, 7, 2f + 28f * e.finpow(), (x, y) -> { + Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f); + }); - Angles.randLenVectors(e.id + 1, 4, 1f + 23f * e.finpow(), (x, y) -> { - Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); - }); + color(Pal.plastaniumBack); + stroke(1f * e.fout()); + randLenVectors(e.id + 1, 4, 1f + 25f * e.finpow(), (x, y) -> { + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); }); - plasticExplosion = new Effect(24, e -> { + }), - Draw.color(Pal.plastaniumFront); - e.scaled(7, i -> { - Lines.stroke(3f * i.fout()); - Lines.circle(e.x, e.y, 3f + i.fin() * 24f); - }); + plasticExplosionFlak = new Effect(28, e -> { - Draw.color(Color.gray); + color(Pal.plastaniumFront); + e.scaled(7, i -> { + stroke(3f * i.fout()); + Lines.circle(e.x, e.y, 3f + i.fin() * 34f); + }); - Angles.randLenVectors(e.id, 7, 2f + 28f * e.finpow(), (x, y) -> { - Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f); - }); + color(Color.gray); - Draw.color(Pal.plastaniumBack); - Lines.stroke(1f * e.fout()); + randLenVectors(e.id, 7, 2f + 30f * e.finpow(), (x, y) -> { + Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f); + }); - Angles.randLenVectors(e.id + 1, 4, 1f + 25f * e.finpow(), (x, y) -> { - Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); - }); + color(Pal.plastaniumBack); + stroke(1f * e.fout()); + randLenVectors(e.id + 1, 4, 1f + 30f * e.finpow(), (x, y) -> { + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); }); - plasticExplosionFlak = new Effect(28, e -> { + }), - Draw.color(Pal.plastaniumFront); - e.scaled(7, i -> { - Lines.stroke(3f * i.fout()); - Lines.circle(e.x, e.y, 3f + i.fin() * 34f); - }); + blastExplosion = new Effect(22, e -> { - Draw.color(Color.gray); + color(Pal.missileYellow); + e.scaled(6, i -> { + stroke(3f * i.fout()); + Lines.circle(e.x, e.y, 3f + i.fin() * 15f); + }); - Angles.randLenVectors(e.id, 7, 2f + 30f * e.finpow(), (x, y) -> { - Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f); - }); + color(Color.gray); - Draw.color(Pal.plastaniumBack); - Lines.stroke(1f * e.fout()); + randLenVectors(e.id, 5, 2f + 23f * e.finpow(), (x, y) -> { + Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f); + }); - Angles.randLenVectors(e.id + 1, 4, 1f + 30f * e.finpow(), (x, y) -> { - Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); - }); + color(Pal.missileYellowBack); + stroke(1f * e.fout()); + randLenVectors(e.id + 1, 4, 1f + 23f * e.finpow(), (x, y) -> { + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); }); - blastExplosion = new Effect(22, e -> { + }), - Draw.color(Pal.missileYellow); - e.scaled(6, i -> { - Lines.stroke(3f * i.fout()); - Lines.circle(e.x, e.y, 3f + i.fin() * 15f); - }); + artilleryTrail = new Effect(50, e -> { + color(e.color); + Fill.circle(e.x, e.y, e.rotation * e.fout()); + }), - Draw.color(Color.gray); + incendTrail = new Effect(50, e -> { + color(Pal.lightOrange); + Fill.circle(e.x, e.y, e.rotation * e.fout()); + }), - Angles.randLenVectors(e.id, 5, 2f + 23f * e.finpow(), (x, y) -> { - Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f); - }); + missileTrail = new Effect(50, e -> { + color(e.color); + Fill.circle(e.x, e.y, e.rotation * e.fout()); + }), - Draw.color(Pal.missileYellowBack); - Lines.stroke(1f * e.fout()); + absorb = new Effect(12, e -> { + color(Pal.accent); + stroke(2f * e.fout()); + Lines.circle(e.x, e.y, 5f * e.fout()); + }), - Angles.randLenVectors(e.id + 1, 4, 1f + 23f * e.finpow(), (x, y) -> { - Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); - }); + flakExplosionBig = new Effect(30, e -> { + color(Pal.bulletYellowBack); + e.scaled(6, i -> { + stroke(3f * i.fout()); + Lines.circle(e.x, e.y, 3f + i.fin() * 25f); }); - artilleryTrail = new Effect(50, e -> { - Draw.color(e.color); - Fill.circle(e.x, e.y, e.rotation * e.fout()); - }); + color(Color.gray); - incendTrail = new Effect(50, e -> { - Draw.color(Pal.lightOrange); - Fill.circle(e.x, e.y, e.rotation * e.fout()); + randLenVectors(e.id, 6, 2f + 23f * e.finpow(), (x, y) -> { + Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.5f); }); - missileTrail = new Effect(50, e -> { - Draw.color(e.color); - Fill.circle(e.x, e.y, e.rotation * e.fout()); - }); + color(Pal.bulletYellow); + stroke(1f * e.fout()); - absorb = new Effect(12, e -> { - Draw.color(Pal.accent); - Lines.stroke(2f * e.fout()); - Lines.circle(e.x, e.y, 5f * e.fout()); + randLenVectors(e.id + 1, 4, 1f + 23f * e.finpow(), (x, y) -> { + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); }); - flakExplosionBig = new Effect(30, e -> { + }), - Draw.color(Pal.bulletYellowBack); - e.scaled(6, i -> { - Lines.stroke(3f * i.fout()); - Lines.circle(e.x, e.y, 3f + i.fin() * 25f); - }); - - 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); - }); - - Draw.color(Pal.bulletYellow); - Lines.stroke(1f * e.fout()); - - Angles.randLenVectors(e.id + 1, 4, 1f + 23f * e.finpow(), (x, y) -> { - Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); - }); + burning = new Effect(35f, e -> { + color(Pal.lightFlame, Pal.darkFlame, e.fin()); + randLenVectors(e.id, 3, 2f + e.fin() * 7f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, 0.1f + e.fout() * 1.4f); }); + }), - burning = new Effect(35f, e -> { - Draw.color(Pal.lightFlame, Pal.darkFlame, e.fin()); - - Angles.randLenVectors(e.id, 3, 2f + e.fin() * 7f, (x, y) -> { - Fill.circle(e.x + x, e.y + y, 0.1f + e.fout() * 1.4f); - }); + fire = new Effect(50f, e -> { + color(Pal.lightFlame, Pal.darkFlame, e.fin()); + randLenVectors(e.id, 2, 2f + e.fin() * 9f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, 0.2f + e.fslope() * 1.5f); }); - fire = new Effect(50f, e -> { - Draw.color(Pal.lightFlame, Pal.darkFlame, e.fin()); + color(); - Angles.randLenVectors(e.id, 2, 2f + e.fin() * 9f, (x, y) -> { - Fill.circle(e.x + x, e.y + y, 0.2f + e.fslope() * 1.5f); - }); + renderer.lights.add(e.x, e.y, 20f * e.fslope(), Pal.lightFlame, 0.5f); + }), - Draw.color(); + fireSmoke = new Effect(35f, e -> { + color(Color.gray); - renderer.lights.add(e.x, e.y, 20f * e.fslope(), Pal.lightFlame, 0.5f); + randLenVectors(e.id, 1, 2f + e.fin() * 7f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, 0.2f + e.fslope() * 1.5f); }); - fireSmoke = new Effect(35f, e -> { - 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); - }); + steam = new Effect(35f, e -> { + color(Color.lightGray); + randLenVectors(e.id, 2, 2f + e.fin() * 7f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, 0.2f + e.fslope() * 1.5f); }); - steam = new Effect(35f, e -> { - 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); - }); + fireballsmoke = new Effect(25f, e -> { + color(Color.gray); + randLenVectors(e.id, 1, 2f + e.fin() * 7f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, 0.2f + e.fout() * 1.5f); }); - fireballsmoke = new Effect(25f, e -> { - 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); - }); + ballfire = new Effect(25f, e -> { + color(Pal.lightFlame, Pal.darkFlame, e.fin()); + randLenVectors(e.id, 2, 2f + e.fin() * 7f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, 0.2f + e.fout() * 1.5f); }); - ballfire = new Effect(25f, e -> { - Draw.color(Pal.lightFlame, Pal.darkFlame, e.fin()); + }), - Angles.randLenVectors(e.id, 2, 2f + e.fin() * 7f, (x, y) -> { - Fill.circle(e.x + x, e.y + y, 0.2f + e.fout() * 1.5f); - }); + freezing = new Effect(40f, e -> { + color(Liquids.cryofluid.color); + randLenVectors(e.id, 2, 1f + e.fin() * 2f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, e.fout() * 1.2f); }); - freezing = new Effect(40f, e -> { - Draw.color(Liquids.cryofluid.color); + }), - Angles.randLenVectors(e.id, 2, 1f + e.fin() * 2f, (x, y) -> { - Fill.circle(e.x + x, e.y + y, e.fout() * 1.2f); - }); + melting = new Effect(40f, e -> { + color(Liquids.slag.color, Color.white, e.fout() / 5f + Mathf.randomSeedRange(e.id, 0.12f)); + randLenVectors(e.id, 2, 1f + e.fin() * 3f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, .2f + e.fout() * 1.2f); }); - melting = new Effect(40f, e -> { - 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); - }); + wet = new Effect(40f, e -> { + color(Liquids.water.color); + randLenVectors(e.id, 2, 1f + e.fin() * 2f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, e.fout() * 1f); }); - wet = new Effect(40f, e -> { - Draw.color(Liquids.water.color); + }), - Angles.randLenVectors(e.id, 2, 1f + e.fin() * 2f, (x, y) -> { - Fill.circle(e.x + x, e.y + y, e.fout() * 1f); - }); + oily = new Effect(42f, e -> { + color(Liquids.oil.color); + randLenVectors(e.id, 2, 1f + e.fin() * 2f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, e.fout() * 1f); }); - oily = new Effect(42f, e -> { - Draw.color(Liquids.oil.color); + }), - Angles.randLenVectors(e.id, 2, 1f + e.fin() * 2f, (x, y) -> { - Fill.circle(e.x + x, e.y + y, e.fout() * 1f); - }); + overdriven = new Effect(20f, e -> { + color(Pal.accent); + randLenVectors(e.id, 2, 1f + e.fin() * 2f, (x, y) -> { + Fill.square(e.x + x, e.y + y, e.fout() * 2.3f + 0.5f); }); - overdriven = new Effect(20f, e -> { - Draw.color(Pal.accent); + }), - Angles.randLenVectors(e.id, 2, 1f + e.fin() * 2f, (x, y) -> { - Fill.square(e.x + x, e.y + y, e.fout() * 2.3f + 0.5f); - }); + dropItem = new Effect(20f, e -> { + float length = 20f * e.finpow(); + float size = 7f * e.fout(); - }); + rect(((Item)e.data).icon(Cicon.medium), e.x + trnsx(e.rotation, length), e.y + trnsy(e.rotation, length), size, size); + }), - dropItem = new Effect(20f, e -> { - float length = 20f * e.finpow(); - float size = 7f * e.fout(); + shockwave = new Effect(10f, 80f, e -> { + color(Color.white, Color.lightGray, e.fin()); + stroke(e.fout() * 2f + 0.2f); + Lines.circle(e.x, e.y, e.fin() * 28f); + }), - Draw.rect(((Item)e.data).icon(Cicon.medium), e.x + Angles.trnsx(e.rotation, length), e.y + Angles.trnsy(e.rotation, length), size, size); - }); + bigShockwave = new Effect(10f, 80f, e -> { + color(Color.white, Color.lightGray, e.fin()); + stroke(e.fout() * 3f); + Lines.circle(e.x, e.y, e.fin() * 50f); + }), + nuclearShockwave = new Effect(10f, 200f, e -> { + color(Color.white, Color.lightGray, e.fin()); + stroke(e.fout() * 3f + 0.2f); + Lines.circle(e.x, e.y, e.fin() * 140f); + }), - shockwave = new Effect(10f, 80f, e -> { - Draw.color(Color.white, Color.lightGray, e.fin()); - Lines.stroke(e.fout() * 2f + 0.2f); - Lines.circle(e.x, e.y, e.fin() * 28f); - }); + impactShockwave = new Effect(13f, 300f, e -> { + color(Pal.lighterOrange, Color.lightGray, e.fin()); + stroke(e.fout() * 4f + 0.2f); + Lines.circle(e.x, e.y, e.fin() * 200f); + }), - bigShockwave = new Effect(10f, 80f, e -> { - Draw.color(Color.white, Color.lightGray, e.fin()); - Lines.stroke(e.fout() * 3f); - Lines.circle(e.x, e.y, e.fin() * 50f); - }); + spawnShockwave = new Effect(20f, 400f, e -> { + color(Color.white, Color.lightGray, e.fin()); + stroke(e.fout() * 3f + 0.5f); + Lines.circle(e.x, e.y, e.fin() * (e.rotation + 50f)); + }), - nuclearShockwave = new Effect(10f, 200f, e -> { - Draw.color(Color.white, Color.lightGray, e.fin()); - Lines.stroke(e.fout() * 3f + 0.2f); - Lines.circle(e.x, e.y, e.fin() * 140f); + explosion = new Effect(30, e -> { + e.scaled(7, i -> { + stroke(3f * i.fout()); + Lines.circle(e.x, e.y, 3f + i.fin() * 10f); }); - impactShockwave = new Effect(13f, 300f, e -> { - Draw.color(Pal.lighterOrange, Color.lightGray, e.fin()); - Lines.stroke(e.fout() * 4f + 0.2f); - Lines.circle(e.x, e.y, e.fin() * 200f); - }); + color(Color.gray); - spawnShockwave = new Effect(20f, 400f, e -> { - 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)); + 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); }); - explosion = new Effect(30, e -> { - e.scaled(7, i -> { - Lines.stroke(3f * i.fout()); - Lines.circle(e.x, e.y, 3f + i.fin() * 10f); - }); - - 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()); - Lines.stroke(1.5f * e.fout()); - - Angles.randLenVectors(e.id + 1, 8, 1f + 23f * e.finpow(), (x, y) -> { - Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); - }); + color(Pal.lighterOrange, Pal.lightOrange, Color.gray, e.fin()); + stroke(1.5f * e.fout()); + randLenVectors(e.id + 1, 8, 1f + 23f * e.finpow(), (x, y) -> { + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); }); + }), - dynamicExplosion = new Effect(30, e -> { - float intensity = e.rotation; - - e.scaled(5 + intensity * 2, i -> { - Lines.stroke(3.1f * i.fout()); - Lines.circle(e.x, e.y, (3f + i.fin() * 14f) * intensity); - }); - - 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()); - 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) -> { - Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + out * 4 * (3f + intensity)); - }); + dynamicExplosion = new Effect(30, e -> { + float intensity = e.rotation; + e.scaled(5 + intensity * 2, i -> { + stroke(3.1f * i.fout()); + Lines.circle(e.x, e.y, (3f + i.fin() * 14f) * intensity); }); - blockExplosion = new Effect(30, e -> { - e.scaled(7, i -> { - Lines.stroke(3.1f * i.fout()); - Lines.circle(e.x, e.y, 3f + i.fin() * 14f); - }); - - 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()); - Lines.stroke(1.7f * e.fout()); - - Angles.randLenVectors(e.id + 1, 9, 1f + 23f * e.finpow(), (x, y) -> { - Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); - }); + color(Color.gray); + 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); }); - blockExplosionSmoke = new Effect(30, e -> { - Draw.color(Color.gray); + color(Pal.lighterOrange, Pal.lightOrange, Color.gray, e.fin()); + stroke((1.7f * e.fout()) * (1f + (intensity - 1f) / 2f)); - Angles.randLenVectors(e.id, 6, 4f + 30f * e.finpow(), (x, y) -> { - Fill.circle(e.x + x, e.y + y, e.fout() * 3f); - Fill.circle(e.x + x / 2f, e.y + y / 2f, e.fout() * 1f); - }); + randLenVectors(e.id + 1, e.finpow(), (int)(9 * intensity), 40f * intensity, (x, y, in, out) -> { + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + out * 4 * (3f + intensity)); + }); + }), + blockExplosion = new Effect(30, e -> { + e.scaled(7, i -> { + stroke(3.1f * i.fout()); + Lines.circle(e.x, e.y, 3f + i.fin() * 14f); }); + color(Color.gray); - shootSmall = new Effect(8, e -> { - Draw.color(Pal.lighterOrange, Pal.lightOrange, e.fin()); - float w = 1f + 5 * e.fout(); - Drawf.tri(e.x, e.y, w, 15f * e.fout(), e.rotation); - Drawf.tri(e.x, e.y, w, 3f * e.fout(), e.rotation + 180f); + 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); }); - shootHeal = new Effect(8, e -> { - Draw.color(Pal.heal); - float w = 1f + 5 * e.fout(); - Drawf.tri(e.x, e.y, w, 17f * e.fout(), e.rotation); - Drawf.tri(e.x, e.y, w, 4f * e.fout(), e.rotation + 180f); + color(Pal.lighterOrange, Pal.lightOrange, Color.gray, e.fin()); + stroke(1.7f * e.fout()); + + randLenVectors(e.id + 1, 9, 1f + 23f * e.finpow(), (x, y) -> { + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); }); - shootSmallSmoke = new Effect(20f, e -> { - 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); - }); + blockExplosionSmoke = new Effect(30, e -> { + color(Color.gray); + randLenVectors(e.id, 6, 4f + 30f * e.finpow(), (x, y) -> { + Fill.circle(e.x + x, e.y + y, e.fout() * 3f); + Fill.circle(e.x + x / 2f, e.y + y / 2f, e.fout() * 1f); }); - shootBig = new Effect(9, e -> { - Draw.color(Pal.lighterOrange, Pal.lightOrange, e.fin()); - float w = 1.2f + 7 * e.fout(); - Drawf.tri(e.x, e.y, w, 25f * e.fout(), e.rotation); - Drawf.tri(e.x, e.y, w, 4f * e.fout(), e.rotation + 180f); - }); + }), - shootBig2 = new Effect(10, e -> { - 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); - }); + shootSmall = new Effect(8, e -> { + color(Pal.lighterOrange, Pal.lightOrange, e.fin()); + float w = 1f + 5 * e.fout(); + Drawf.tri(e.x, e.y, w, 15f * e.fout(), e.rotation); + Drawf.tri(e.x, e.y, w, 3f * e.fout(), e.rotation + 180f); + }), - shootBigSmoke = new Effect(17f, e -> { - Draw.color(Pal.lighterOrange, Color.lightGray, Color.gray, e.fin()); + shootHeal = new Effect(8, e -> { + color(Pal.heal); + float w = 1f + 5 * e.fout(); + Drawf.tri(e.x, e.y, w, 17f * e.fout(), e.rotation); + Drawf.tri(e.x, e.y, w, 4f * e.fout(), e.rotation + 180f); + }), - 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); - }); + shootHealYellow = new Effect(8, e -> { + color(Pal.lightTrail); + float w = 1f + 5 * e.fout(); + Drawf.tri(e.x, e.y, w, 17f * e.fout(), e.rotation); + Drawf.tri(e.x, e.y, w, 4f * e.fout(), e.rotation + 180f); + }), - }); + shootSmallSmoke = new Effect(20f, e -> { + color(Pal.lighterOrange, Color.lightGray, Color.gray, e.fin()); - shootBigSmoke2 = new Effect(18f, e -> { - Draw.color(Pal.lightOrange, Color.lightGray, Color.gray, e.fin()); + randLenVectors(e.id, 5, e.finpow() * 6f, e.rotation, 20f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, e.fout() * 1.5f); + }); - 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); - }); + }), - }); + shootBig = new Effect(9, e -> { + color(Pal.lighterOrange, Pal.lightOrange, e.fin()); + float w = 1.2f + 7 * e.fout(); + Drawf.tri(e.x, e.y, w, 25f * e.fout(), e.rotation); + Drawf.tri(e.x, e.y, w, 4f * e.fout(), e.rotation + 180f); + }), - shootSmallFlame = new Effect(32f, e -> { - Draw.color(Pal.lightFlame, Pal.darkFlame, Color.gray, e.fin()); + shootBig2 = new Effect(10, e -> { + 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); + }), - 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); - }); + shootBigSmoke = new Effect(17f, e -> { + color(Pal.lighterOrange, Color.lightGray, Color.gray, e.fin()); + 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); }); - shootPyraFlame = new Effect(33f, e -> { - 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); - }); + shootBigSmoke2 = new Effect(18f, e -> { + color(Pal.lightOrange, Color.lightGray, Color.gray, e.fin()); + 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); }); - shootLiquid = new Effect(40f, e -> { - 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); - }); + shootSmallFlame = new Effect(32f, e -> { + color(Pal.lightFlame, Pal.darkFlame, Color.gray, e.fin()); + 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); }); - shellEjectSmall = new GroundEffect(30f, 400f, e -> { - Draw.color(Pal.lightOrange, Color.lightGray, Pal.lightishGray, e.fin()); - float rot = Math.abs(e.rotation) + 90f; - - int i = Mathf.sign(e.rotation); + }), - float len = (2f + e.finpow() * 6f) * i; - float lr = rot + e.fin() * 30f * i; - Fill.rect(e.x + Angles.trnsx(lr, len) + Mathf.randomSeedRange(e.id + i + 7, 3f * e.fin()), - e.y + Angles.trnsy(lr, len) + Mathf.randomSeedRange(e.id + i + 8, 3f * e.fin()), - 1f, 2f, rot + e.fin() * 50f * i); + shootPyraFlame = new Effect(33f, e -> { + color(Pal.lightPyraFlame, Pal.darkPyraFlame, Color.gray, e.fin()); + 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); }); - shellEjectMedium = new GroundEffect(34f, 400f, e -> { - 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; - float lr = rot + e.fin() * 20f * i; - Draw.rect(Core.atlas.find("casing"), - e.x + Angles.trnsx(lr, len) + Mathf.randomSeedRange(e.id + i + 7, 3f * e.fin()), - e.y + Angles.trnsy(lr, len) + Mathf.randomSeedRange(e.id + i + 8, 3f * e.fin()), - 2f, 3f, rot); - } - - Draw.color(Color.lightGray, Color.gray, e.fin()); + }), - for(int i : Mathf.signs){ - float ex = e.x, ey = e.y, fout = e.fout(); - Angles.randLenVectors(e.id, 4, 1f + e.finpow() * 11f, e.rotation + 90f * i, 20f, (x, y) -> { - Fill.circle(ex + x, ey + y, fout * 1.5f); - }); - } + shootLiquid = new Effect(40f, e -> { + color(e.color, Color.white, e.fout() / 6f + Mathf.randomSeedRange(e.id, 0.1f)); + 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); }); - shellEjectBig = new GroundEffect(22f, 400f, e -> { - 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; - float lr = rot + Mathf.randomSeedRange(e.id + i + 6, 20f * e.fin()) * i; - Draw.rect(Core.atlas.find("casing"), - e.x + Angles.trnsx(lr, len) + Mathf.randomSeedRange(e.id + i + 7, 3f * e.fin()), - e.y + Angles.trnsy(lr, len) + Mathf.randomSeedRange(e.id + i + 8, 3f * e.fin()), - 2.5f, 4f, - rot + e.fin() * 30f * i + Mathf.randomSeedRange(e.id + i + 9, 40f * e.fin())); - } + }), - Draw.color(Color.lightGray); + shellEjectSmall = new Effect(30f, e -> { + color(Pal.lightOrange, Color.lightGray, Pal.lightishGray, e.fin()); + float rot = Math.abs(e.rotation) + 90f; - for(int i : Mathf.signs){ - float ex = e.x, ey = e.y, fout = e.fout(); - Angles.randLenVectors(e.id, 4, -e.finpow() * 15f, e.rotation + 90f * i, 25f, (x, y) -> { - Fill.circle(ex + x, ey + y, fout * 2f); - }); - } + int i = Mathf.sign(e.rotation); - }); - - lancerLaserShoot = new Effect(21f, e -> { - Draw.color(Pal.lancerLaser); + float len = (2f + e.finpow() * 6f) * i; + float lr = rot + e.fin() * 30f * i; + Fill.rect(e.x + trnsx(lr, len) + Mathf.randomSeedRange(e.id + i + 7, 3f * e.fin()), + e.y + trnsy(lr, len) + Mathf.randomSeedRange(e.id + i + 8, 3f * e.fin()), + 1f, 2f, rot + e.fin() * 50f * i); - for(int i : Mathf.signs){ - Drawf.tri(e.x, e.y, 4f * e.fout(), 29f, e.rotation + 90f * i); - } + }).ground(400f), - }); + shellEjectMedium = new Effect(34f, e -> { + 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; + float lr = rot + e.fin() * 20f * i; + rect(Core.atlas.find("casing"), + e.x + trnsx(lr, len) + Mathf.randomSeedRange(e.id + i + 7, 3f * e.fin()), + e.y + trnsy(lr, len) + Mathf.randomSeedRange(e.id + i + 8, 3f * e.fin()), + 2f, 3f, rot); + } - lancerLaserShootSmoke = new Effect(26f, e -> { - Draw.color(Pal.lancerLaser); + color(Color.lightGray, Color.gray, e.fin()); - Angles.randLenVectors(e.id, 7, 80f, e.rotation, 0f, (x, y) -> { - Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fout() * 9f); + for(int i : Mathf.signs){ + float ex = e.x, ey = e.y, fout = e.fout(); + randLenVectors(e.id, 4, 1f + e.finpow() * 11f, e.rotation + 90f * i, 20f, (x, y) -> { + Fill.circle(ex + x, ey + y, fout * 1.5f); }); + } - }); + }).ground(400f), + + shellEjectBig = new Effect(22f, e -> { + 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; + float lr = rot + Mathf.randomSeedRange(e.id + i + 6, 20f * e.fin()) * i; + rect(Core.atlas.find("casing"), + e.x + trnsx(lr, len) + Mathf.randomSeedRange(e.id + i + 7, 3f * e.fin()), + e.y + trnsy(lr, len) + Mathf.randomSeedRange(e.id + i + 8, 3f * e.fin()), + 2.5f, 4f, + rot + e.fin() * 30f * i + Mathf.randomSeedRange(e.id + i + 9, 40f * e.fin())); + } - lancerLaserCharge = new Effect(38f, e -> { - Draw.color(Pal.lancerLaser); + color(Color.lightGray); - Angles.randLenVectors(e.id, 2, 1f + 20f * e.fout(), e.rotation, 120f, (x, y) -> { - Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fslope() * 3f + 1f); + for(int i : Mathf.signs){ + float ex = e.x, ey = e.y, fout = e.fout(); + randLenVectors(e.id, 4, -e.finpow() * 15f, e.rotation + 90f * i, 25f, (x, y) -> { + Fill.circle(ex + x, ey + y, fout * 2f); }); + } - }); + }).ground(400f), - lancerLaserChargeBegin = new Effect(71f, e -> { - Draw.color(Pal.lancerLaser); - Fill.circle(e.x, e.y, e.fin() * 3f); + lancerLaserShoot = new Effect(21f, e -> { + color(Pal.lancerLaser); - Draw.color(); - Fill.circle(e.x, e.y, e.fin() * 2f); - }); + for(int i : Mathf.signs){ + Drawf.tri(e.x, e.y, 4f * e.fout(), 29f, e.rotation + 90f * i); + } - lightningCharge = new Effect(38f, e -> { - Draw.color(Pal.lancerLaser); + }), - Angles.randLenVectors(e.id, 2, 1f + 20f * e.fout(), e.rotation, 120f, (x, y) -> { - Drawf.tri(e.x + x, e.y + y, e.fslope() * 3f + 1, e.fslope() * 3f + 1, Mathf.angle(x, y)); - }); + lancerLaserShootSmoke = new Effect(26f, e -> { + color(Color.white); + randLenVectors(e.id, 7, 70f, e.rotation, 0f, (x, y) -> { + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fout() * 9f); }); - lightningShoot = new Effect(12f, e -> { - 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) -> { - Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fin() * 5f + 2f); - }); + lancerLaserCharge = new Effect(38f, e -> { + color(Pal.lancerLaser); + randLenVectors(e.id, 2, 1f + 20f * e.fout(), e.rotation, 120f, (x, y) -> { + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fslope() * 3f + 1f); }); + }), - reactorsmoke = new Effect(17, e -> { - Angles.randLenVectors(e.id, 4, e.fin() * 8f, (x, y) -> { - float size = 1f + e.fout() * 5f; - Draw.color(Color.lightGray, Color.gray, e.fin()); - Draw.rect("circle", e.x + x, e.y + y, size, size); - }); - }); - nuclearsmoke = new Effect(40, e -> { - Angles.randLenVectors(e.id, 4, e.fin() * 13f, (x, y) -> { - float size = e.fslope() * 4f; - Draw.color(Color.lightGray, Color.gray, e.fin()); - Draw.rect("circle", e.x + x, e.y + y, size, size); - }); - }); - 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.rect("circle", e.x + x, e.y + y, size, size); - }); - }); - impactsmoke = new Effect(60, e -> { - Angles.randLenVectors(e.id, 7, e.fin() * 20f, (x, y) -> { - float size = e.fslope() * 4f; - Draw.color(Color.lightGray, Color.gray, e.fin()); - Draw.rect("circle", e.x + x, e.y + y, size, size); - }); - }); - 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.lightGray, e.fin()); - Draw.rect("circle", e.x + x, e.y + y, size, size); - }); - }); - 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.rect("circle", e.x + x, e.y + y, len, len); - }); - }); - 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.rect("circle", e.x + x, e.y + y, len, len); - }); - }); - fuelburn = new Effect(23, e -> { - Angles.randLenVectors(e.id, 5, e.fin() * 9f, (x, y) -> { - float len = e.fout() * 4f; - Draw.color(Color.lightGray, Color.gray, e.fin()); - Draw.rect("circle", e.x + x, e.y + y, len, len); - }); - }); - 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()); - Fill.circle(e.x + x, e.y + y, e.fout() * 1f); - }); - }); - pulverize = new Effect(40, e -> { - Angles.randLenVectors(e.id, 5, 3f + e.fin() * 8f, (x, y) -> { - Draw.color(Pal.stoneGray); - Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.5f, 45); - }); - }); - pulverizeRed = new Effect(40, e -> { - Angles.randLenVectors(e.id, 5, 3f + e.fin() * 8f, (x, y) -> { - Draw.color(Pal.redDust, Pal.stoneGray, e.fin()); - Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.5f, 45); - }); - }); - pulverizeRedder = new Effect(40, e -> { - Angles.randLenVectors(e.id, 5, 3f + e.fin() * 9f, (x, y) -> { - Draw.color(Pal.redderDust, Pal.stoneGray, e.fin()); - Fill.square(e.x + x, e.y + y, e.fout() * 2.5f + 0.5f, 45); - }); - }); - pulverizeSmall = new Effect(30, e -> { - Angles.randLenVectors(e.id, 3, e.fin() * 5f, (x, y) -> { - Draw.color(Pal.stoneGray); - Fill.square(e.x + x, e.y + y, e.fout() * 1f + 0.5f, 45); - }); - }); - pulverizeMedium = new Effect(30, e -> { - Angles.randLenVectors(e.id, 5, 3f + e.fin() * 8f, (x, y) -> { - Draw.color(Pal.stoneGray); - Fill.square(e.x + x, e.y + y, e.fout() * 1f + 0.5f, 45); - }); - }); - producesmoke = new Effect(12, e -> { - Angles.randLenVectors(e.id, 8, 4f + e.fin() * 18f, (x, y) -> { - Draw.color(Color.white, Pal.accent, e.fin()); - Fill.square(e.x + x, e.y + y, 1f + e.fout() * 3f, 45); - }); - }); - smeltsmoke = new Effect(15, e -> { - Angles.randLenVectors(e.id, 6, 4f + e.fin() * 5f, (x, y) -> { - Draw.color(Color.white, e.color, e.fin()); - Fill.square(e.x + x, e.y + y, 0.5f + e.fout() * 2f, 45); - }); - }); - formsmoke = new Effect(40, e -> { - Angles.randLenVectors(e.id, 6, 5f + e.fin() * 8f, (x, y) -> { - Draw.color(Pal.plasticSmoke, Color.lightGray, e.fin()); - Fill.square(e.x + x, e.y + y, 0.2f + e.fout() * 2f, 45); - }); - }); - 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.lightGray, Color.darkGray, e.fin()); - Draw.rect("circle", e.x + x, e.y + y, size, size); - }); - }); - 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.rect("circle", e.x + x, e.y + y, size, size); - }); - }); - dooropen = new Effect(10, e -> { - Lines.stroke(e.fout() * 1.6f); - Lines.square(e.x, e.y, tilesize / 2f + e.fin() * 2f); - }); - doorclose = new Effect(10, e -> { - Lines.stroke(e.fout() * 1.6f); - Lines.square(e.x, e.y, tilesize / 2f + e.fout() * 2f); - }); - dooropenlarge = new Effect(10, e -> { - Lines.stroke(e.fout() * 1.6f); - Lines.square(e.x, e.y, tilesize + e.fin() * 2f); - }); - doorcloselarge = new Effect(10, e -> { - Lines.stroke(e.fout() * 1.6f); - Lines.square(e.x, e.y, tilesize + e.fout() * 2f); - }); - purify = new Effect(10, e -> { - Draw.color(Color.royal, Color.gray, e.fin()); - Lines.stroke(2f); - Lines.spikes(e.x, e.y, e.fin() * 4f, 2, 6); - }); - purifyoil = new Effect(10, e -> { - Draw.color(Color.black, Color.gray, e.fin()); - Lines.stroke(2f); - Lines.spikes(e.x, e.y, e.fin() * 4f, 2, 6); - }); - purifystone = new Effect(10, e -> { - Draw.color(Color.orange, Color.gray, e.fin()); - Lines.stroke(2f); - Lines.spikes(e.x, e.y, e.fin() * 4f, 2, 6); - }); - generate = new Effect(11, e -> { - Draw.color(Color.orange, Color.yellow, e.fin()); - Lines.stroke(1f); - Lines.spikes(e.x, e.y, e.fin() * 5f, 2, 8); - }); - mine = new Effect(20, e -> { - Angles.randLenVectors(e.id, 6, 3f + e.fin() * 6f, (x, y) -> { - Draw.color(e.color, Color.lightGray, e.fin()); - Fill.square(e.x + x, e.y + y, e.fout() * 2f, 45); - }); - }); - mineBig = new Effect(30, e -> { - Angles.randLenVectors(e.id, 6, 4f + e.fin() * 8f, (x, y) -> { - Draw.color(e.color, Color.lightGray, e.fin()); - Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.2f, 45); - }); - }); - mineHuge = new Effect(40, e -> { - Angles.randLenVectors(e.id, 8, 5f + e.fin() * 10f, (x, y) -> { - Draw.color(e.color, Color.lightGray, e.fin()); - Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.5f, 45); - }); - }); - smelt = new Effect(20, e -> { - Angles.randLenVectors(e.id, 6, 2f + e.fin() * 5f, (x, y) -> { - Draw.color(Color.white, e.color, e.fin()); - Fill.square(e.x + x, e.y + y, 0.5f + e.fout() * 2f, 45); - }); - }); - teleportActivate = new Effect(50, e -> { - Draw.color(e.color); - - e.scaled(8f, e2 -> { - Lines.stroke(e2.fout() * 4f); - Lines.circle(e2.x, e2.y, 4f + e2.fin() * 27f); - }); + lancerLaserChargeBegin = new Effect(60f, e -> { + color(Pal.lancerLaser); + Fill.circle(e.x, e.y, e.fin() * 3f); - Lines.stroke(e.fout() * 2f); + color(); + Fill.circle(e.x, e.y, e.fin() * 2f); + }), - Angles.randLenVectors(e.id, 30, 4f + 40f * e.fin(), (x, y) -> { - Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fin() * 4f + 1f); - }); + lightningCharge = new Effect(38f, e -> { + color(Pal.lancerLaser); + randLenVectors(e.id, 2, 1f + 20f * e.fout(), e.rotation, 120f, (x, y) -> { + Drawf.tri(e.x + x, e.y + y, e.fslope() * 3f + 1, e.fslope() * 3f + 1, Mathf.angle(x, y)); }); - teleport = new Effect(60, e -> { - Draw.color(e.color); - Lines.stroke(e.fin() * 2f); - Lines.circle(e.x, e.y, 7f + e.fout() * 8f); - - Angles.randLenVectors(e.id, 20, 6f + 20f * e.fout(), (x, y) -> { - Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fin() * 4f + 1f); - }); - }); - teleportOut = new Effect(20, e -> { - Draw.color(e.color); - Lines.stroke(e.fout() * 2f); - Lines.circle(e.x, e.y, 7f + e.fin() * 8f); + }), - Angles.randLenVectors(e.id, 20, 4f + 20f * e.fin(), (x, y) -> { - Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fslope() * 4f + 1f); - }); + lightningShoot = new Effect(12f, e -> { + color(Color.white, Pal.lancerLaser, e.fin()); + stroke(e.fout() * 1.2f + 0.5f); - }); - ripple = new GroundEffect(false, 30, e -> { - Draw.color(Tmp.c1.set(e.color).mul(1.2f)); - Lines.stroke(e.fout() + 0.4f); - Lines.circle(e.x, e.y, 2f + e.fin() * 4f); + randLenVectors(e.id, 7, 25f * e.finpow(), e.rotation, 50f, (x, y) -> { + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fin() * 5f + 2f); }); - bubble = new Effect(20, e -> { - Draw.color(Tmp.c1.set(e.color).shiftValue(0.1f)); - Lines.stroke(e.fout() + 0.2f); - Angles.randLenVectors(e.id, 2, 8f, (x, y) -> { - Lines.circle(e.x + x, e.y + y, 1f + e.fin() * 3f); - }); - }); + }), - launch = new Effect(28, e -> { - Draw.color(Pal.command); - Lines.stroke(e.fout() * 2f); - Lines.circle(e.x, e.y, 4f + e.finpow() * 120f); + reactorsmoke = new Effect(17, e -> { + randLenVectors(e.id, 4, e.fin() * 8f, (x, y) -> { + float size = 1f + e.fout() * 5f; + color(Color.lightGray, Color.gray, e.fin()); + Fill.circle(e.x + x, e.y + y, size/2f); }); + }), - healWaveMend = new Effect(40, e -> { - Draw.color(e.color); - Lines.stroke(e.fout() * 2f); - Lines.circle(e.x, e.y, e.finpow() * e.rotation); + nuclearsmoke = new Effect(40, e -> { + randLenVectors(e.id, 4, e.fin() * 13f, (x, y) -> { + float size = e.fslope() * 4f; + color(Color.lightGray, Color.gray, e.fin()); + Fill.circle(e.x + x, e.y + y, size/2f); }); + }), - overdriveWave = new Effect(50, e -> { - Draw.color(e.color); - Lines.stroke(e.fout() * 1f); - Lines.circle(e.x, e.y, e.finpow() * e.rotation); + nuclearcloud = new Effect(90, 200f, e -> { + randLenVectors(e.id, 10, e.finpow() * 90f, (x, y) -> { + float size = e.fout() * 14f; + color(Color.lime, Color.gray, e.fin()); + Fill.circle(e.x + x, e.y + y, size/2f); }); + }), - healBlock = new Effect(20, e -> { - Draw.color(Pal.heal); - Lines.stroke(2f * e.fout() + 0.5f); - Lines.square(e.x, e.y, 1f + (e.fin() * e.rotation * tilesize / 2f - 1f)); + impactsmoke = new Effect(60, e -> { + randLenVectors(e.id, 7, e.fin() * 20f, (x, y) -> { + float size = e.fslope() * 4f; + color(Color.lightGray, Color.gray, e.fin()); + Fill.circle(e.x + x, e.y + y, size/2f); }); + }), - healBlockFull = new Effect(20, e -> { - Draw.color(e.color); - Draw.alpha(e.fout()); - Fill.square(e.x, e.y, e.rotation * tilesize / 2f); + impactcloud = new Effect(140, 400f, e -> { + randLenVectors(e.id, 20, e.finpow() * 160f, (x, y) -> { + float size = e.fout() * 15f; + color(Pal.lighterOrange, Color.lightGray, e.fin()); + Fill.circle(e.x + x, e.y + y, size/2f); }); + }), - overdriveBlockFull = new Effect(60, e -> { - Draw.color(e.color); - Draw.alpha(e.fslope() * 0.4f); - Fill.square(e.x, e.y, e.rotation * tilesize); + redgeneratespark = new Effect(18, e -> { + randLenVectors(e.id, 5, e.fin() * 8f, (x, y) -> { + float len = e.fout() * 4f; + color(Pal.redSpark, Color.gray, e.fin()); + Fill.circle(e.x + x, e.y + y, len/2f); }); + }), - shieldBreak = new Effect(40, e -> { - Draw.color(Pal.accent); - Lines.stroke(3f * e.fout()); - Lines.poly(e.x, e.y, 6, e.rotation + e.fin(), 90); - }); + generatespark = new Effect(18, e -> { + randLenVectors(e.id, 5, e.fin() * 8f, (x, y) -> { + float len = e.fout() * 4f; + color(Pal.orangeSpark, Color.gray, e.fin()); + Fill.circle(e.x + x, e.y + y, len/2f); + }); + }), + + fuelburn = new Effect(23, e -> { + randLenVectors(e.id, 5, e.fin() * 9f, (x, y) -> { + float len = e.fout() * 4f; + color(Color.lightGray, Color.gray, e.fin()); + Fill.circle(e.x + x, e.y + y, len/2f); + }); + }), + + plasticburn = new Effect(40, e -> { + randLenVectors(e.id, 5, 3f + e.fin() * 5f, (x, y) -> { + color(Color.valueOf("e9ead3"), Color.gray, e.fin()); + Fill.circle(e.x + x, e.y + y, e.fout() * 1f); + }); + }), + + pulverize = new Effect(40, e -> { + randLenVectors(e.id, 5, 3f + e.fin() * 8f, (x, y) -> { + color(Pal.stoneGray); + Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.5f, 45); + }); + }), + + pulverizeRed = new Effect(40, e -> { + randLenVectors(e.id, 5, 3f + e.fin() * 8f, (x, y) -> { + color(Pal.redDust, Pal.stoneGray, e.fin()); + Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.5f, 45); + }); + }), + + pulverizeRedder = new Effect(40, e -> { + randLenVectors(e.id, 5, 3f + e.fin() * 9f, (x, y) -> { + color(Pal.redderDust, Pal.stoneGray, e.fin()); + Fill.square(e.x + x, e.y + y, e.fout() * 2.5f + 0.5f, 45); + }); + }), + + pulverizeSmall = new Effect(30, e -> { + randLenVectors(e.id, 3, e.fin() * 5f, (x, y) -> { + color(Pal.stoneGray); + Fill.square(e.x + x, e.y + y, e.fout() * 1f + 0.5f, 45); + }); + }), + + pulverizeMedium = new Effect(30, e -> { + randLenVectors(e.id, 5, 3f + e.fin() * 8f, (x, y) -> { + color(Pal.stoneGray); + Fill.square(e.x + x, e.y + y, e.fout() * 1f + 0.5f, 45); + }); + }), + + producesmoke = new Effect(12, e -> { + randLenVectors(e.id, 8, 4f + e.fin() * 18f, (x, y) -> { + color(Color.white, Pal.accent, e.fin()); + Fill.square(e.x + x, e.y + y, 1f + e.fout() * 3f, 45); + }); + }), + + smeltsmoke = new Effect(15, e -> { + randLenVectors(e.id, 6, 4f + e.fin() * 5f, (x, y) -> { + color(Color.white, e.color, e.fin()); + Fill.square(e.x + x, e.y + y, 0.5f + e.fout() * 2f, 45); + }); + }), + + formsmoke = new Effect(40, e -> { + randLenVectors(e.id, 6, 5f + e.fin() * 8f, (x, y) -> { + color(Pal.plasticSmoke, Color.lightGray, e.fin()); + Fill.square(e.x + x, e.y + y, 0.2f + e.fout() * 2f, 45); + }); + }), + + blastsmoke = new Effect(26, e -> { + randLenVectors(e.id, 12, 1f + e.fin() * 23f, (x, y) -> { + float size = 2f + e.fout() * 6f; + color(Color.lightGray, Color.darkGray, e.fin()); + Fill.circle(e.x + x, e.y + y, size/2f); + }); + }), + + lava = new Effect(18, e -> { + randLenVectors(e.id, 3, 1f + e.fin() * 10f, (x, y) -> { + float size = e.fslope() * 4f; + color(Color.orange, Color.gray, e.fin()); + Fill.circle(e.x + x, e.y + y, size/2f); + }); + }), + + dooropen = new Effect(10, e -> { + stroke(e.fout() * 1.6f); + Lines.square(e.x, e.y, tilesize / 2f + e.fin() * 2f); + }), + + doorclose = new Effect(10, e -> { + stroke(e.fout() * 1.6f); + Lines.square(e.x, e.y, tilesize / 2f + e.fout() * 2f); + }), + dooropenlarge = new Effect(10, e -> { + stroke(e.fout() * 1.6f); + Lines.square(e.x, e.y, tilesize + e.fin() * 2f); + }), + doorcloselarge = new Effect(10, e -> { + stroke(e.fout() * 1.6f); + Lines.square(e.x, e.y, tilesize + e.fout() * 2f); + }), + purify = new Effect(10, e -> { + color(Color.royal, Color.gray, e.fin()); + stroke(2f); + Lines.spikes(e.x, e.y, e.fin() * 4f, 2, 6); + }), + purifyoil = new Effect(10, e -> { + color(Color.black, Color.gray, e.fin()); + stroke(2f); + Lines.spikes(e.x, e.y, e.fin() * 4f, 2, 6); + }), + purifystone = new Effect(10, e -> { + color(Color.orange, Color.gray, e.fin()); + stroke(2f); + Lines.spikes(e.x, e.y, e.fin() * 4f, 2, 6); + }), + generate = new Effect(11, e -> { + color(Color.orange, Color.yellow, e.fin()); + stroke(1f); + Lines.spikes(e.x, e.y, e.fin() * 5f, 2, 8); + }), + mine = new Effect(20, e -> { + randLenVectors(e.id, 6, 3f + e.fin() * 6f, (x, y) -> { + color(e.color, Color.lightGray, e.fin()); + Fill.square(e.x + x, e.y + y, e.fout() * 2f, 45); + }); + }), + mineBig = new Effect(30, e -> { + randLenVectors(e.id, 6, 4f + e.fin() * 8f, (x, y) -> { + color(e.color, Color.lightGray, e.fin()); + Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.2f, 45); + }); + }), + + mineHuge = new Effect(40, e -> { + randLenVectors(e.id, 8, 5f + e.fin() * 10f, (x, y) -> { + color(e.color, Color.lightGray, e.fin()); + Fill.square(e.x + x, e.y + y, e.fout() * 2f + 0.5f, 45); + }); + }), + smelt = new Effect(20, e -> { + randLenVectors(e.id, 6, 2f + e.fin() * 5f, (x, y) -> { + color(Color.white, e.color, e.fin()); + Fill.square(e.x + x, e.y + y, 0.5f + e.fout() * 2f, 45); + }); + }), + teleportActivate = new Effect(50, e -> { + color(e.color); + + e.scaled(8f, e2 -> { + stroke(e2.fout() * 4f); + Lines.circle(e2.x, e2.y, 4f + e2.fin() * 27f); + }); + + stroke(e.fout() * 2f); + + randLenVectors(e.id, 30, 4f + 40f * e.fin(), (x, y) -> { + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fin() * 4f + 1f); + }); + + }), + teleport = new Effect(60, e -> { + color(e.color); + stroke(e.fin() * 2f); + Lines.circle(e.x, e.y, 7f + e.fout() * 8f); + + randLenVectors(e.id, 20, 6f + 20f * e.fout(), (x, y) -> { + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fin() * 4f + 1f); + }); + + }), + teleportOut = new Effect(20, e -> { + color(e.color); + stroke(e.fout() * 2f); + Lines.circle(e.x, e.y, 7f + e.fin() * 8f); + + randLenVectors(e.id, 20, 4f + 20f * e.fin(), (x, y) -> { + lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fslope() * 4f + 1f); + }); + + }), + + //TODO fix false in constructor + ripple = new Effect(30, e -> { + color(Tmp.c1.set(e.color).mul(1.5f)); + stroke(e.fout() + 0.4f); + Lines.circle(e.x, e.y, 2f + e.fin() * 4f); + }).ground(), + + bubble = new Effect(20, e -> { + color(Tmp.c1.set(e.color).shiftValue(0.1f)); + stroke(e.fout() + 0.2f); + randLenVectors(e.id, 2, 8f, (x, y) -> { + Lines.circle(e.x + x, e.y + y, 1f + e.fin() * 3f); + }); + }), + + launch = new Effect(28, e -> { + color(Pal.command); + stroke(e.fout() * 2f); + Lines.circle(e.x, e.y, 4f + e.finpow() * 120f); + }), + + healWaveMend = new Effect(40, e -> { + color(e.color); + stroke(e.fout() * 2f); + Lines.circle(e.x, e.y, e.finpow() * e.rotation); + }), + + overdriveWave = new Effect(50, e -> { + color(e.color); + stroke(e.fout() * 1f); + Lines.circle(e.x, e.y, e.finpow() * e.rotation); + }), + + healBlock = new Effect(20, e -> { + color(Pal.heal); + stroke(2f * e.fout() + 0.5f); + Lines.square(e.x, e.y, 1f + (e.fin() * e.rotation * tilesize / 2f - 1f)); + }), + + healBlockFull = new Effect(20, e -> { + color(e.color); + alpha(e.fout()); + Fill.square(e.x, e.y, e.rotation * tilesize / 2f); + }), + + overdriveBlockFull = new Effect(60, e -> { + color(e.color); + alpha(e.fslope() * 0.4f); + Fill.square(e.x, e.y, e.rotation * tilesize); + }), + + shieldBreak = new Effect(40, e -> { + color(Pal.accent); + stroke(3f * e.fout()); + Lines.poly(e.x, e.y, 6, e.rotation + e.fin(), 90); + }), - coreLand = new Effect(120f, e -> { - }); - } + coreLand = new Effect(120f, e -> { + }); } diff --git a/core/src/mindustry/content/Mechs.java b/core/src/mindustry/content/Mechs.java deleted file mode 100644 index 9bbb67d51a..0000000000 --- a/core/src/mindustry/content/Mechs.java +++ /dev/null @@ -1,378 +0,0 @@ -package mindustry.content; - -import arc.*; -import arc.graphics.*; -import arc.graphics.g2d.*; -import arc.math.*; -import arc.util.*; -import mindustry.*; -import mindustry.ctype.ContentList; -import mindustry.entities.*; -import mindustry.entities.bullet.*; -import mindustry.entities.effect.*; -import mindustry.entities.type.*; -import mindustry.gen.*; -import mindustry.graphics.*; -import mindustry.type.*; - -public class Mechs implements ContentList{ - public static Mech alpha, delta, tau, omega, dart, javelin, trident, glaive; - - public static Mech starter; - - @Override - public void load(){ - - alpha = new Mech("alpha-mech", false){ - { - drillPower = 1; - mineSpeed = 1.5f; - mass = 1.2f; - speed = 0.5f; - itemCapacity = 40; - boostSpeed = 0.95f; - buildPower = 1.2f; - engineColor = Color.valueOf("ffd37f"); - health = 250f; - - weapon = new Weapon("blaster"){{ - length = 1.5f; - reload = 14f; - alternate = true; - ejectEffect = Fx.shellEjectSmall; - bullet = Bullets.standardMechSmall; - }}; - } - - @Override - public void updateAlt(Player player){ - player.healBy(Time.delta() * 0.09f); - } - - }; - - delta = new Mech("delta-mech", false){ - float cooldown = 120; - - { - drillPower = -1; - speed = 0.75f; - boostSpeed = 0.95f; - itemCapacity = 15; - mass = 0.9f; - health = 150f; - buildPower = 0.9f; - weaponOffsetX = -1; - weaponOffsetY = -1; - engineColor = Color.valueOf("d3ddff"); - - weapon = new Weapon("shockgun"){{ - shake = 2f; - length = 1f; - reload = 55f; - shotDelay = 3f; - alternate = true; - shots = 2; - inaccuracy = 0f; - ejectEffect = Fx.none; - bullet = Bullets.lightning; - shootSound = Sounds.spark; - }}; - } - - @Override - public void onLand(Player player){ - if(player.timer.get(Player.timerAbility, cooldown)){ - Effects.shake(1f, 1f, player); - Effects.effect(Fx.landShock, player); - for(int i = 0; i < 8; i++){ - Time.run(Mathf.random(8f), () -> Lightning.create(player.getTeam(), Pal.lancerLaser, 17f * Vars.state.rules.playerDamageMultiplier, player.x, player.y, Mathf.random(360f), 14)); - } - } - } - }; - - tau = new Mech("tau-mech", false){ - float healRange = 60f; - float healAmount = 10f; - float healReload = 160f; - boolean wasHealed; - - { - drillPower = 4; - mineSpeed = 3f; - itemCapacity = 70; - weaponOffsetY = -1; - weaponOffsetX = 1; - mass = 1.75f; - speed = 0.44f; - drag = 0.35f; - boostSpeed = 0.8f; - canHeal = true; - health = 200f; - buildPower = 1.6f; - engineColor = Pal.heal; - - weapon = new Weapon("heal-blaster"){{ - length = 1.5f; - reload = 24f; - alternate = false; - ejectEffect = Fx.none; - recoil = 2f; - bullet = Bullets.healBullet; - shootSound = Sounds.pew; - }}; - } - - @Override - public void updateAlt(Player player){ - - if(player.timer.get(Player.timerAbility, healReload)){ - wasHealed = false; - - Units.nearby(player.getTeam(), player.x, player.y, healRange, unit -> { - if(unit.health < unit.maxHealth()){ - Effects.effect(Fx.heal, unit); - wasHealed = true; - } - unit.healBy(healAmount); - }); - - if(wasHealed){ - Effects.effect(Fx.healWave, player); - } - } - } - }; - - omega = new Mech("omega-mech", false){ - protected TextureRegion armorRegion; - - { - drillPower = 2; - mineSpeed = 1.5f; - itemCapacity = 80; - speed = 0.36f; - boostSpeed = 0.6f; - mass = 4f; - shake = 4f; - weaponOffsetX = 1; - weaponOffsetY = 0; - engineColor = Color.valueOf("feb380"); - health = 350f; - buildPower = 1.5f; - weapon = new Weapon("swarmer"){{ - length = 1.5f; - recoil = 4f; - reload = 38f; - shots = 4; - spacing = 8f; - inaccuracy = 8f; - alternate = true; - ejectEffect = Fx.none; - shake = 3f; - bullet = Bullets.missileSwarm; - shootSound = Sounds.shootBig; - }}; - } - - @Override - public float getRotationAlpha(Player player){ - return 0.6f - player.shootHeat * 0.3f; - } - - @Override - public float spreadX(Player player){ - return player.shootHeat * 2f; - } - - @Override - public void load(){ - super.load(); - armorRegion = Core.atlas.find(name + "-armor"); - } - - @Override - public void updateAlt(Player player){ - float scl = 1f - player.shootHeat / 2f*Time.delta(); - player.velocity().scl(scl); - } - - @Override - public float getExtraArmor(Player player){ - return player.shootHeat * 30f; - } - - @Override - public void draw(Player player){ - if(player.shootHeat <= 0.01f) return; - - Shaders.build.progress = player.shootHeat; - Shaders.build.region = armorRegion; - Shaders.build.time = Time.time() / 10f; - Shaders.build.color.set(Pal.accent).a = player.shootHeat; - Draw.shader(Shaders.build); - Draw.rect(armorRegion, player.x, player.y, player.rotation); - Draw.shader(); - } - }; - - dart = new Mech("dart-ship", true){ - { - drillPower = 1; - mineSpeed = 3f; - speed = 0.5f; - drag = 0.09f; - health = 200f; - weaponOffsetX = -1; - weaponOffsetY = -1; - engineColor = Pal.lightTrail; - cellTrnsY = 1f; - buildPower = 1.1f; - weapon = new Weapon("blaster"){{ - length = 1.5f; - reload = 15f; - alternate = true; - ejectEffect = Fx.shellEjectSmall; - bullet = Bullets.standardCopper; - }}; - } - - @Override - public boolean alwaysUnlocked(){ - return true; - } - }; - - javelin = new Mech("javelin-ship", true){ - float minV = 3.6f; - float maxV = 6f; - TextureRegion shield; - - { - drillPower = -1; - speed = 0.11f; - drag = 0.01f; - mass = 2f; - health = 170f; - engineColor = Color.valueOf("d3ddff"); - cellTrnsY = 1f; - weapon = new Weapon("missiles"){{ - length = 1.5f; - reload = 70f; - shots = 4; - inaccuracy = 2f; - alternate = true; - ejectEffect = Fx.none; - velocityRnd = 0.2f; - spacing = 1f; - bullet = Bullets.missileJavelin; - shootSound = Sounds.missile; - }}; - } - - @Override - public void load(){ - super.load(); - shield = Core.atlas.find(name + "-shield"); - } - - @Override - public float getRotationAlpha(Player player){ - return 0.5f; - } - - @Override - public void updateAlt(Player player){ - float scl = scld(player); - if(Mathf.chance(Time.delta() * (0.15 * scl))){ - Effects.effect(Fx.hitLancer, Pal.lancerLaser, player.x, player.y); - Lightning.create(player.getTeam(), Pal.lancerLaser, 10f * Vars.state.rules.playerDamageMultiplier, - player.x + player.velocity().x, player.y + player.velocity().y, player.rotation, 14); - } - } - - @Override - public void draw(Player player){ - float scl = scld(player); - if(scl < 0.01f) return; - Draw.color(Pal.lancerLaser); - Draw.alpha(scl / 2f); - Draw.blend(Blending.additive); - Draw.rect(shield, player.x + Mathf.range(scl / 2f), player.y + Mathf.range(scl / 2f), player.rotation - 90); - Draw.blend(); - } - - float scld(Player player){ - return Mathf.clamp((player.velocity().len() - minV) / (maxV - minV)); - } - }; - - trident = new Mech("trident-ship", true){ - { - drillPower = 2; - speed = 0.15f; - drag = 0.034f; - mass = 2.5f; - turnCursor = false; - health = 250f; - itemCapacity = 30; - engineColor = Color.valueOf("84f491"); - cellTrnsY = 1f; - buildPower = 2.5f; - weapon = new Weapon("bomber"){{ - length = 0f; - width = 2f; - reload = 25f; - shots = 2; - shotDelay = 1f; - shots = 8; - alternate = true; - ejectEffect = Fx.none; - velocityRnd = 1f; - inaccuracy = 20f; - ignoreRotation = true; - bullet = new BombBulletType(16f, 25f, "shell"){{ - bulletWidth = 10f; - bulletHeight = 14f; - hitEffect = Fx.flakExplosion; - shootEffect = Fx.none; - smokeEffect = Fx.none; - shootSound = Sounds.artillery; - }}; - }}; - } - - @Override - public boolean canShoot(Player player){ - return player.velocity().len() > 1.2f; - } - }; - - glaive = new Mech("glaive-ship", true){ - { - drillPower = 4; - mineSpeed = 1.3f; - speed = 0.32f; - drag = 0.06f; - mass = 3f; - health = 240f; - itemCapacity = 60; - engineColor = Color.valueOf("feb380"); - cellTrnsY = 1f; - buildPower = 1.2f; - - weapon = new Weapon("bomber"){{ - length = 1.5f; - reload = 13f; - alternate = true; - ejectEffect = Fx.shellEjectSmall; - bullet = Bullets.standardGlaive; - shootSound = Sounds.shootSnap; - }}; - } - }; - - starter = dart; - } -} diff --git a/core/src/mindustry/content/StatusEffects.java b/core/src/mindustry/content/StatusEffects.java index 6672727847..a925a77be4 100644 --- a/core/src/mindustry/content/StatusEffects.java +++ b/core/src/mindustry/content/StatusEffects.java @@ -1,8 +1,8 @@ package mindustry.content; import arc.*; +import arc.graphics.*; import arc.math.Mathf; -import mindustry.entities.Effects; import mindustry.ctype.ContentList; import mindustry.game.EventType.*; import mindustry.type.StatusEffect; @@ -24,7 +24,7 @@ public class StatusEffects implements ContentList{ opposite(wet,freezing); trans(tarred, ((unit, time, newTime, result) -> { unit.damage(1f); - Effects.effect(Fx.burning, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f)); + Fx.burning.at(unit.x() + Mathf.range(unit.bounds() / 2f), unit.y() + Mathf.range(unit.bounds() / 2f)); result.set(this, Math.min(time + newTime, 300f)); })); }); @@ -41,13 +41,14 @@ public class StatusEffects implements ContentList{ }}; wet = new StatusEffect("wet"){{ + color = Color.royal; speedMultiplier = 0.9f; effect = Fx.wet; init(() -> { trans(shocked, ((unit, time, newTime, result) -> { unit.damage(20f); - if(unit.getTeam() == state.rules.waveTeam){ + if(unit.team() == state.rules.waveTeam){ Events.fire(Trigger.shock); } result.set(this, time); diff --git a/core/src/mindustry/content/TechTree.java b/core/src/mindustry/content/TechTree.java index fb9207cdda..d55eb68623 100644 --- a/core/src/mindustry/content/TechTree.java +++ b/core/src/mindustry/content/TechTree.java @@ -22,7 +22,6 @@ public class TechTree implements ContentList{ node(conveyor, () -> { node(junction, () -> { - node(itemBridge); node(router, () -> { node(launchPad, () -> { node(launchPadLarge, () -> { @@ -34,7 +33,9 @@ public class TechTree implements ContentList{ node(sorter, () -> { node(invertedSorter); node(message); - node(overflowGate); + node(overflowGate, () -> { + node(underflowGate); + }); }); node(container, () -> { node(unloader); @@ -43,16 +44,18 @@ public class TechTree implements ContentList{ }); }); - node(titaniumConveyor, () -> { - node(phaseConveyor, () -> { - node(massDriver, () -> { + node(itemBridge, () -> { + node(titaniumConveyor, () -> { + node(phaseConveyor, () -> { + node(massDriver, () -> { + + }); + }); + + node(armoredConveyor, () -> { }); }); - - node(armoredConveyor, () -> { - - }); }); }); }); @@ -100,23 +103,25 @@ public class TechTree implements ContentList{ node(copperWall, () -> { - node(copperWallLarge); - node(titaniumWall, () -> { - node(door, () -> { - node(doorLarge); - }); - node(plastaniumWall, () -> { - node(plastaniumWallLarge, () -> { + node(copperWallLarge, () -> { + node(titaniumWall, () -> { + node(titaniumWallLarge); + node(door, () -> { + node(doorLarge); }); - }); - node(titaniumWallLarge); - node(thoriumWall, () -> { - node(thoriumWallLarge); - node(surgeWall, () -> { - node(surgeWallLarge); - node(phaseWall, () -> { - node(phaseWallLarge); + node(plastaniumWall, () -> { + node(plastaniumWallLarge, () -> { + + }); + }); + node(thoriumWall, () -> { + node(thoriumWallLarge); + node(surgeWall, () -> { + node(surgeWallLarge); + node(phaseWall, () -> { + node(phaseWallLarge); + }); }); }); }); @@ -196,6 +201,8 @@ public class TechTree implements ContentList{ node(liquidRouter, () -> { node(liquidTank); + node(bridgeConduit); + node(pulseConduit, () -> { node(phaseConduit, () -> { @@ -212,7 +219,6 @@ public class TechTree implements ContentList{ }); }); }); - node(bridgeConduit); }); }); }); diff --git a/core/src/mindustry/content/TypeIDs.java b/core/src/mindustry/content/TypeIDs.java deleted file mode 100644 index b99e321e98..0000000000 --- a/core/src/mindustry/content/TypeIDs.java +++ /dev/null @@ -1,18 +0,0 @@ -package mindustry.content; - -import mindustry.entities.effect.Fire; -import mindustry.entities.effect.Puddle; -import mindustry.entities.type.Player; -import mindustry.ctype.ContentList; -import mindustry.type.TypeID; - -public class TypeIDs implements ContentList{ - public static TypeID fire, puddle, player; - - @Override - public void load(){ - fire = new TypeID("fire", Fire::new); - puddle = new TypeID("puddle", Puddle::new); - player = new TypeID("player", Player::new); - } -} diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index 1c5202ab46..fb96da5e09 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -1,23 +1,59 @@ package mindustry.content; -import arc.struct.*; -import mindustry.ctype.ContentList; -import mindustry.entities.bullet.*; -import mindustry.entities.type.*; -import mindustry.entities.type.Bullet; -import mindustry.entities.type.base.*; +import mindustry.annotations.Annotations.*; +import mindustry.ctype.*; import mindustry.gen.*; import mindustry.type.*; public class UnitTypes implements ContentList{ - public static UnitType + public static UnitDef draug, spirit, phantom, wraith, ghoul, revenant, lich, reaper, - dagger, crawler, titan, fortress, eruptor, chaosArray, eradicator; + crawler, titan, fortress, eruptor, chaosArray, eradicator; + + public static @EntityDef({Unitc.class, Legsc.class}) UnitDef dagger; + public static @EntityDef({Unitc.class, WaterMovec.class}) UnitDef vanguard; + + public static UnitDef alpha, delta, tau, omega, dart, javelin, trident, glaive; + public static UnitDef starter; + @Override public void load(){ - draug = new UnitType("draug", MinerDrone::new){{ + + dagger = new UnitDef("dagger"){{ + speed = 1f; + drag = 0.3f; + hitsize = 8f; + mass = 1.75f; + health = 130; + weapons.add(new Weapon("chain-blaster"){{ + reload = 28f; + x = 4f; + alternate = true; + ejectEffect = Fx.shellEjectSmall; + bullet = Bullets.standardCopper; + }}); + }}; + + vanguard = new UnitDef("vanguard"){{ + speed = 1.3f; + drag = 0.1f; + hitsize = 8f; + mass = 1.75f; + health = 130; + weapons.add(new Weapon("chain-blaster"){{ + reload = 10f; + x = 1.25f; + alternate = true; + rotate = true; + ejectEffect = Fx.shellEjectSmall; + bullet = Bullets.standardCopper; + }}); + }}; + + /* + draug = new UnitDef("draug", MinerDrone::new){{ flying = true; drag = 0.01f; speed = 0.3f; @@ -27,12 +63,9 @@ public class UnitTypes implements ContentList{ minePower = 0.9f; engineSize = 1.8f; engineOffset = 5.7f; - weapon = new Weapon("you have incurred my wrath. prepare to die."){{ - bullet = Bullets.lancerLaser; - }}; }}; - spirit = new UnitType("spirit", RepairDrone::new){{ + spirit = new UnitDef("spirit", RepairDrone::new){{ flying = true; drag = 0.01f; speed = 0.42f; @@ -53,7 +86,7 @@ public class UnitTypes implements ContentList{ }}; }}; - phantom = new UnitType("phantom", BuilderDrone::new){{ + phantom = new UnitDef("phantom", BuilderDrone::new){{ flying = true; drag = 0.01f; mass = 2f; @@ -76,7 +109,7 @@ public class UnitTypes implements ContentList{ }}; }}; - dagger = new UnitType("dagger", GroundUnit::new){{ + dagger = new UnitDef("dagger", GroundUnit::new){{ maxVelocity = 1.1f; speed = 0.2f; drag = 0.4f; @@ -92,7 +125,7 @@ public class UnitTypes implements ContentList{ }}; }}; - crawler = new UnitType("crawler", GroundUnit::new){{ + crawler = new UnitDef("crawler", GroundUnit::new){{ maxVelocity = 1.27f; speed = 0.285f; drag = 0.4f; @@ -103,27 +136,19 @@ public class UnitTypes implements ContentList{ reload = 12f; ejectEffect = Fx.none; shootSound = Sounds.explosion; - bullet = new BombBulletType(2f, 3f, "clear"){ - { - hitEffect = Fx.pulverize; - lifetime = 30f; - speed = 1.1f; - splashDamageRadius = 55f; - splashDamage = 30f; - } - - @Override - public void init(Bullet b){ - if(b.getOwner() instanceof Unit){ - ((Unit)b.getOwner()).kill(); - } - b.time(b.lifetime()); - } - }; + bullet = new BombBulletType(2f, 3f, "clear"){{ + hitEffect = Fx.pulverize; + lifetime = 30f; + speed = 1.1f; + splashDamageRadius = 55f; + instantDisappear = true; + splashDamage = 30f; + killShooter = true; + }}; }}; }}; - titan = new UnitType("titan", GroundUnit::new){{ + titan = new UnitDef("titan", GroundUnit::new){{ maxVelocity = 0.8f; speed = 0.22f; drag = 0.4f; @@ -137,7 +162,6 @@ public class UnitTypes implements ContentList{ shootSound = Sounds.flame; length = 1f; reload = 14f; - range = 30f; alternate = true; recoil = 1f; ejectEffect = Fx.none; @@ -145,7 +169,7 @@ public class UnitTypes implements ContentList{ }}; }}; - fortress = new UnitType("fortress", GroundUnit::new){{ + fortress = new UnitDef("fortress", GroundUnit::new){{ maxVelocity = 0.78f; speed = 0.15f; drag = 0.4f; @@ -167,7 +191,7 @@ public class UnitTypes implements ContentList{ }}; }}; - eruptor = new UnitType("eruptor", GroundUnit::new){{ + eruptor = new UnitDef("eruptor", GroundUnit::new){{ maxVelocity = 0.81f; speed = 0.16f; drag = 0.4f; @@ -189,7 +213,7 @@ public class UnitTypes implements ContentList{ }}; }}; - chaosArray = new UnitType("chaos-array", GroundUnit::new){{ + chaosArray = new UnitDef("chaos-array", GroundUnit::new){{ maxVelocity = 0.68f; speed = 0.12f; drag = 0.4f; @@ -213,7 +237,7 @@ public class UnitTypes implements ContentList{ }}; }}; - eradicator = new UnitType("eradicator", GroundUnit::new){{ + eradicator = new UnitDef("eradicator", GroundUnit::new){{ maxVelocity = 0.68f; speed = 0.12f; drag = 0.4f; @@ -238,7 +262,7 @@ public class UnitTypes implements ContentList{ }}; }}; - wraith = new UnitType("wraith", FlyingUnit::new){{ + wraith = new UnitDef("wraith", FlyingUnit::new){{ speed = 0.3f; maxVelocity = 1.9f; drag = 0.01f; @@ -257,7 +281,7 @@ public class UnitTypes implements ContentList{ }}; }}; - ghoul = new UnitType("ghoul", FlyingUnit::new){{ + ghoul = new UnitDef("ghoul", FlyingUnit::new){{ health = 220; speed = 0.2f; maxVelocity = 1.4f; @@ -281,7 +305,7 @@ public class UnitTypes implements ContentList{ }}; }}; - revenant = new UnitType("revenant", HoverUnit::new){{ + revenant = new UnitDef("revenant", HoverUnit::new){{ health = 1000; mass = 5f; hitsize = 20f; @@ -312,7 +336,7 @@ public class UnitTypes implements ContentList{ }}; }}; - lich = new UnitType("lich", HoverUnit::new){{ + lich = new UnitDef("lich", HoverUnit::new){{ health = 6000; mass = 20f; hitsize = 40f; @@ -345,7 +369,7 @@ public class UnitTypes implements ContentList{ }}; }}; - reaper = new UnitType("reaper", HoverUnit::new){{ + reaper = new UnitDef("reaper", HoverUnit::new){{ health = 11000; mass = 30f; hitsize = 56f; @@ -386,5 +410,440 @@ public class UnitTypes implements ContentList{ shootSound = Sounds.shootBig; }}; }}; + + + /* + vanguard = new UnitDef("vanguard-ship"){ + float healRange = 60f; + float healReload = 200f; + float healPercent = 10f; + + { + flying = true; + drillTier = 1; + minePower = 4f; + speed = 0.49f; + drag = 0.09f; + health = 200f; + weaponOffsetX = -1; + engineSize = 2.3f; + weaponOffsetY = -1; + engineColor = Pal.lightTrail; + cellTrnsY = 1f; + buildPower = 1.2f; + weapon = new Weapon("vanguard-blaster"){{ + length = 1.5f; + reload = 30f; + alternate = true; + inaccuracy = 6f; + velocityRnd = 0.1f; + ejectEffect = Fx.none; + bullet = new HealBulletType(){{ + healPercent = 3f; + backColor = engineColor; + homingPower = 20f; + bulletHeight = 4f; + bulletWidth = 1.5f; + damage = 3f; + speed = 4f; + lifetime = 40f; + shootEffect = Fx.shootHealYellow; + smokeEffect = hitEffect = despawnEffect = Fx.hitYellowLaser; + }}; + }}; + } + + @Override + public boolean alwaysUnlocked(){ + return true; + } + + @Override + public void update(Playerc player){ + if(player.timer.get(Playerc.timerAbility, healReload)){ + if(indexer.eachBlock(player, healRange, other -> other.entity.damaged(), other -> { + other.entity.heal(other.entity.maxHealth() * healPercent / 100f); + Fx.healBlockFull.at(other.drawx(), other.drawy(), other.block().size, Pal.heal); + })){ + Fx.healWave.at(player); + } + } + } + }; + + alpha = new UnitDef("alpha-mech", false){ + { + drillTier = -1; + speed = 0.5f; + boostSpeed = 0.95f; + itemCapacity = 15; + mass = 0.9f; + health = 150f; + buildPower = 0.9f; + weaponOffsetX = 1; + weaponOffsetY = -1; + engineColor = Pal.heal; + + weapon = new Weapon("shockgun"){{ + shake = 2f; + length = 0.5f; + reload = 70f; + alternate = true; + recoil = 4f; + width = 5f; + shootSound = Sounds.laser; + + bullet = new LaserBulletType(){{ + damage = 20f; + recoil = 1f; + sideAngle = 45f; + sideWidth = 1f; + sideLength = 70f; + colors = new Color[]{Pal.heal.cpy().a(0.4f), Pal.heal, Color.white}; + }}; + }}; + } + + @Override + public void update(Playerc player){ + player.heal(Time.delta() * 0.09f); + } + + }; + + delta = new UnitDef("delta-mech", false){ + { + drillPower = 1; + mineSpeed = 1.5f; + mass = 1.2f; + speed = 0.5f; + itemCapacity = 40; + boostSpeed = 0.95f; + buildPower = 1.2f; + engineColor = Color.valueOf("ffd37f"); + health = 250f; + weaponOffsetX = 4f; + + weapon = new Weapon("flamethrower"){{ + length = 1.5f; + reload = 30f; + width = 4f; + alternate = true; + shots = 3; + inaccuracy = 40f; + shootSound = Sounds.spark; + bullet = new LightningBulletType(){{ + damage = 5; + lightningLength = 10; + lightningColor = Pal.lightFlame; + }}; + }}; + } + }; + + tau = new UnitDef("tau-mech", false){ + float healRange = 60f; + float healAmount = 10f; + float healReload = 160f; + boolean wasHealed; + + { + drillPower = 4; + mineSpeed = 3f; + itemCapacity = 70; + weaponOffsetY = -1; + weaponOffsetX = 1; + mass = 1.75f; + speed = 0.44f; + drag = 0.35f; + boostSpeed = 0.8f; + canHeal = true; + health = 200f; + buildPower = 1.6f; + engineColor = Pal.heal; + + weapon = new Weapon("heal-blaster"){{ + length = 1.5f; + reload = 24f; + alternate = false; + ejectEffect = Fx.none; + recoil = 2f; + bullet = Bullets.healBullet; + shootSound = Sounds.pew; + }}; + } + + @Override + public void update(Playerc player){ + + if(player.timer.get(Playerc.timerAbility, healReload)){ + wasHealed = false; + + Units.nearby(player.team(), player.x, player.y, healRange, unit -> { + if(unit.health < unit.maxHealth()){ + Fx.heal.at(unit); + wasHealed = true; + } + unit.heal(healAmount); + }); + + if(wasHealed){ + Fx.healWave.at(player); + } + } + } + }; + + omega = new UnitDef("omega-mech", false){ + protected TextureRegion armorRegion; + + { + drillPower = 2; + mineSpeed = 1.5f; + itemCapacity = 80; + speed = 0.36f; + boostSpeed = 0.6f; + mass = 4f; + shake = 4f; + weaponOffsetX = 1; + weaponOffsetY = 0; + engineColor = Color.valueOf("feb380"); + health = 350f; + buildPower = 1.5f; + weapon = new Weapon("swarmer"){{ + length = 1.5f; + recoil = 4f; + reload = 38f; + shots = 4; + spacing = 8f; + inaccuracy = 8f; + alternate = true; + ejectEffect = Fx.none; + shake = 3f; + bullet = Bullets.missileSwarm; + shootSound = Sounds.shootBig; + }}; + } + + @Override + public float getRotationAlpha(Playerc player){ + return 0.6f - player.shootHeat * 0.3f; + } + + @Override + public float spreadX(Playerc player){ + return player.shootHeat * 2f; + } + + @Override + public void load(){ + super.load(); + armorRegion = Core.atlas.find(name + "-armor"); + } + + @Override + public void update(Playerc player){ + float scl = 1f - player.shootHeat / 2f*Time.delta(); + player.vel().scl(scl); + } + + @Override + public float getExtraArmor(Playerc player){ + return player.shootHeat * 30f; + } + + @Override + public void draw(Playerc player){ + if(player.shootHeat <= 0.01f) return; + + Shaders.build.progress = player.shootHeat; + Shaders.build.region = armorRegion; + Shaders.build.time = Time.time() / 10f; + Shaders.build.color.set(Pal.accent).a = player.shootHeat; + Draw.shader(Shaders.build); + Draw.rect(armorRegion, player.x, player.y, player.rotation); + Draw.shader(); + } + }; + + dart = new UnitDef("dart-ship"){ + float effectRange = 60f; + float effectReload = 60f * 5; + float effectDuration = 60f * 10f; + + { + flying = true; + drillPower = 1; + mineSpeed = 2f; + speed = 0.5f; + drag = 0.09f; + health = 200f; + weaponOffsetX = -1; + weaponOffsetY = -1; + engineColor = Pal.lightTrail; + cellTrnsY = 1f; + buildPower = 1.1f; + weapon = new Weapon("blaster"){{ + length = 1.5f; + reload = 15f; + alternate = true; + ejectEffect = Fx.shellEjectSmall; + bullet = Bullets.standardCopper; + }}; + } + + @Override + public void update(Playerc player){ + super.update(player); + + if(player.timer.get(Playerc.timerAbility, effectReload)){ + + Units.nearby(player.team(), player.x, player.y, effectRange, unit -> { + //unit.applyEffect(StatusEffects.overdrive, effectDuration); + }); + + indexer.eachBlock(player, effectRange, other -> other.entity.damaged(), other -> { + other.entity.applyBoost(1.5f, effectDuration); + Fx.healBlockFull.at(other.drawx(), other.drawy(), other.block().size, Pal.heal); + }); + + Fx.overdriveWave.at(player); + } + } + }; + + javelin = new UnitDef("javelin-ship"){ + float minV = 3.6f; + float maxV = 6f; + TextureRegion shield; + + { + flying = true; + drillPower = -1; + speed = 0.11f; + drag = 0.01f; + mass = 2f; + health = 170f; + engineColor = Color.valueOf("d3ddff"); + cellTrnsY = 1f; + weapon = new Weapon("missiles"){{ + length = 1.5f; + reload = 70f; + shots = 4; + inaccuracy = 2f; + alternate = true; + ejectEffect = Fx.none; + velocityRnd = 0.2f; + spacing = 1f; + bullet = Bullets.missileJavelin; + shootSound = Sounds.missile; + }}; + } + + @Override + public void load(){ + super.load(); + shield = Core.atlas.find(name + "-shield"); + } + + @Override + public float getRotationAlpha(Playerc player){ + return 0.5f; + } + + @Override + public void update(Playerc player){ + float scl = scld(player); + if(Mathf.chance(Time.delta() * (0.15 * scl))){ + Fx.hitLancer.at(Pal.lancerLaser, player.x, player.y); + Lightning.create(player.team(), Pal.lancerLaser, 10f * Vars.state.rules.playerDamageMultiplier, + player.x + player.vel().x, player.y + player.vel().y, player.rotation, 14); + } + } + + @Override + public void draw(Playerc player){ + float scl = scld(player); + if(scl < 0.01f) return; + Draw.color(Pal.lancerLaser); + Draw.alpha(scl / 2f); + Draw.blend(Blending.additive); + Draw.rect(shield, player.x + Mathf.range(scl / 2f), player.y + Mathf.range(scl / 2f), player.rotation - 90); + Draw.blend(); + } + + float scld(Playerc player){ + return Mathf.clamp((player.vel().len() - minV) / (maxV - minV)); + } + }; + + trident = new UnitDef("trident-ship"){ + { + flying = true; + drillPower = 2; + speed = 0.15f; + drag = 0.034f; + mass = 2.5f; + turnCursor = false; + health = 250f; + itemCapacity = 30; + engineColor = Color.valueOf("84f491"); + cellTrnsY = 1f; + buildPower = 2.5f; + weapon = new Weapon("bomber"){{ + length = 0f; + width = 2f; + reload = 25f; + shots = 2; + shotDelay = 1f; + shots = 8; + alternate = true; + ejectEffect = Fx.none; + velocityRnd = 1f; + inaccuracy = 20f; + ignoreRotation = true; + bullet = new BombBulletType(16f, 25f, "shell"){{ + bulletWidth = 10f; + bulletHeight = 14f; + hitEffect = Fx.flakExplosion; + shootEffect = Fx.none; + smokeEffect = Fx.none; + shootSound = Sounds.artillery; + }}; + }}; + } + + @Override + public boolean canShoot(Playerc player){ + return player.vel().len() > 1.2f; + } + }; + + glaive = new UnitDef("glaive-ship"){ + { + flying = true; + drillPower = 4; + mineSpeed = 1.3f; + speed = 0.32f; + drag = 0.06f; + mass = 3f; + health = 240f; + itemCapacity = 60; + engineColor = Color.valueOf("feb380"); + cellTrnsY = 1f; + buildPower = 1.2f; + + weapon = new Weapon("bomber"){{ + length = 1.5f; + reload = 13f; + alternate = true; + ejectEffect = Fx.shellEjectSmall; + bullet = Bullets.standardGlaive; + shootSound = Sounds.shootSnap; + }}; + } + }; + + starter = vanguard;*/ } } diff --git a/core/src/mindustry/core/ContentLoader.java b/core/src/mindustry/core/ContentLoader.java index 0a1d9c1db2..94cf2d80a1 100644 --- a/core/src/mindustry/core/ContentLoader.java +++ b/core/src/mindustry/core/ContentLoader.java @@ -29,12 +29,10 @@ public class ContentLoader{ private @Nullable Content lastAdded; private ObjectSet> initialization = new ObjectSet<>(); private ContentList[] content = { - new Fx(), new Items(), new StatusEffects(), new Liquids(), new Bullets(), - new Mechs(), new UnitTypes(), new Blocks(), new Loadouts(), @@ -42,7 +40,6 @@ public class ContentLoader{ new Weathers(), new Planets(), new Zones(), - new TypeIDs(), //these are not really content classes, but this makes initialization easier new LegacyColorMapper(), @@ -264,7 +261,7 @@ public class ContentLoader{ return getBy(ContentType.zone); } - public Array units(){ + public Array units(){ return getBy(ContentType.unit); } } diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java index 1965d57a23..aafb705aaa 100644 --- a/core/src/mindustry/core/Control.java +++ b/core/src/mindustry/core/Control.java @@ -3,17 +3,16 @@ package mindustry.core; import arc.*; import arc.assets.*; import arc.audio.*; -import arc.struct.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.input.*; import arc.math.geom.*; import arc.scene.ui.*; +import arc.struct.*; import arc.util.*; import mindustry.content.*; import mindustry.core.GameState.*; import mindustry.entities.*; -import mindustry.entities.type.*; import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.gen.*; @@ -63,21 +62,19 @@ public class Control implements ApplicationListener, Loadable{ }); Events.on(PlayEvent.class, event -> { - player.setTeam(netServer.assignTeam(player, playerGroup.all())); - player.setDead(true); + player.team(netServer.assignTeam(player)); player.add(); state.set(State.playing); }); Events.on(WorldLoadEvent.class, event -> { - Core.app.post(() -> Core.app.post(() -> { - if(net.active() && player.getClosestCore() != null){ - //set to closest core since that's where the player will probably respawn; prevents camera jumps - Core.camera.position.set(player.isDead() ? player.getClosestCore() : player); - }else{ - //locally, set to player position since respawning occurs immediately - Core.camera.position.set(player); + //TODO test this + app.post(() -> app.post(() -> { + //TODO 0,0 seems like a bad choice? + Tilec core = state.teams.closestCore(0, 0, player.team()); + if(core != null){ + camera.position.set(core); } })); }); @@ -118,7 +115,7 @@ public class Control implements ApplicationListener, Loadable{ if(state.rules.pvp && !net.active()){ try{ net.host(port); - player.isAdmin = true; + player.admin(true); }catch(IOException e){ ui.showException("$server.error", e); Core.app.post(() -> state.set(State.menu)); @@ -129,7 +126,7 @@ public class Control implements ApplicationListener, Loadable{ Events.on(UnlockEvent.class, e -> ui.hudfrag.showUnlock(e.content)); Events.on(BlockBuildEndEvent.class, e -> { - if(e.team == player.getTeam()){ + if(e.team == player.team()){ if(e.breaking){ state.stats.buildingsDeconstructed++; }else{ @@ -139,13 +136,13 @@ public class Control implements ApplicationListener, Loadable{ }); Events.on(BlockDestroyEvent.class, e -> { - if(e.tile.getTeam() == player.getTeam()){ + if(e.tile.team() == player.team()){ state.stats.buildingsDestroyed++; } }); Events.on(UnitDestroyEvent.class, e -> { - if(e.unit.getTeam() != player.getTeam()){ + if(e.unit.team() != player.team()){ state.stats.enemyUnitsDestroyed++; } }); @@ -163,22 +160,22 @@ public class Control implements ApplicationListener, Loadable{ }); Events.on(Trigger.newGame, () -> { - TileEntity core = player.getClosestCore(); + Tilec core = player.closestCore(); 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)); + app.post(() -> Fx.coreLand.at(core.getX(), core.getY(), 0, core.block())); Time.run(Fx.coreLand.lifetime, () -> { - Effects.effect(Fx.launch, core); + Fx.launch.at(core); Effects.shake(5f, 5f, core); }); }); Events.on(UnitDestroyEvent.class, e -> { - if(e.unit instanceof BaseUnit && world.isZone()){ - data.unlockContent(((BaseUnit)e.unit).getType()); + if(world.isZone()){ + data.unlockContent(e.unit.type()); } }); } @@ -204,11 +201,9 @@ public class Control implements ApplicationListener, Loadable{ } void createPlayer(){ - player = new Player(); - player.name = Core.settings.getString("name"); - player.color.set(Core.settings.getInt("color-0")); - player.isLocal = true; - player.isMobile = mobile; + player = PlayerEntity.create(); + player.name(Core.settings.getString("name")); + player.color().set(Core.settings.getInt("color-0")); if(mobile){ input = new MobileInput(); @@ -286,7 +281,7 @@ public class Control implements ApplicationListener, Loadable{ Geometry.circle(coreb.x, coreb.y, 10, (cx, cy) -> { Tile tile = world.ltile(cx, cy); - if(tile != null && tile.getTeam() == state.rules.defaultTeam && !(tile.block() instanceof CoreBlock)){ + if(tile != null && tile.team() == state.rules.defaultTeam && !(tile.block() instanceof CoreBlock)){ tile.remove(); } }); @@ -297,13 +292,13 @@ public class Control implements ApplicationListener, Loadable{ zone.rules.get(state.rules); state.rules.zone = zone; - for(TileEntity core : state.teams.playerCores()){ + for(Tilec core : state.teams.playerCores()){ for(ItemStack stack : zone.getStartingItems()){ - core.items.add(stack.item, stack.amount); + core.items().add(stack.item, stack.amount); } } - TileEntity core = state.teams.playerCores().first(); - core.items.clear(); + Tilec core = state.teams.playerCores().first(); + core.items().clear(); logic.play(); state.rules.waveTimer = false; @@ -426,9 +421,9 @@ public class Control implements ApplicationListener, Loadable{ input.update(); if(world.isZone()){ - for(TileEntity tile : state.teams.cores(player.getTeam())){ + for(Tilec tile : state.teams.cores(player.team())){ for(Item item : content.items()){ - if(tile.items.has(item)){ + if(tile.items().has(item)){ data.unlockContent(item); } } diff --git a/core/src/mindustry/core/GameState.java b/core/src/mindustry/core/GameState.java index 2b233789eb..f546a933f1 100644 --- a/core/src/mindustry/core/GameState.java +++ b/core/src/mindustry/core/GameState.java @@ -1,9 +1,9 @@ package mindustry.core; import arc.*; -import mindustry.entities.type.*; import mindustry.game.EventType.*; import mindustry.game.*; +import mindustry.gen.*; import static mindustry.Vars.*; @@ -25,8 +25,8 @@ public class GameState{ /** Current game state. */ private State state = State.menu; - public BaseUnit boss(){ - return unitGroup.find(u -> u.isBoss() && u.getTeam() == rules.waveTeam); + public Unitc boss(){ + return Groups.unit.find(u -> u.isBoss() && u.team() == rules.waveTeam); } public void set(State astate){ diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java index 5379cec401..f91efe799b 100644 --- a/core/src/mindustry/core/Logic.java +++ b/core/src/mindustry/core/Logic.java @@ -6,12 +6,10 @@ import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.core.GameState.*; import mindustry.ctype.*; -import mindustry.entities.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.game.Teams.*; -import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.*; @@ -33,10 +31,6 @@ public class Logic implements ApplicationListener{ public Logic(){ Events.on(WaveEvent.class, event -> { - for(Player p : playerGroup.all()){ - p.respawns = state.rules.respawns; - } - if(world.isZone()){ world.getZone().updateWave(state.wave); } @@ -62,7 +56,7 @@ public class Logic implements ApplicationListener{ } } - TeamData data = state.teams.get(tile.getTeam()); + TeamData data = state.teams.get(tile.team()); //remove existing blocks that have been placed here. //painful O(n) iteration + copy @@ -109,10 +103,10 @@ public class Logic implements ApplicationListener{ if(!world.isZone()){ for(TeamData team : state.teams.getActive()){ if(team.hasCore()){ - TileEntity entity = team.core(); - entity.items.clear(); + Tilec entity = team.core(); + entity.items().clear(); for(ItemStack stack : state.rules.loadout){ - entity.items.add(stack.item, stack.amount); + entity.items().add(stack.item, stack.amount); } } } @@ -127,10 +121,8 @@ public class Logic implements ApplicationListener{ state.rules = new Rules(); state.stats = new Stats(); - entities.clear(); + Groups.all.clear(); Time.clear(); - TileEntity.sleepingEntities = 0; - Events.fire(new ResetEvent()); } @@ -176,8 +168,8 @@ public class Logic implements ApplicationListener{ ui.hudfrag.showLaunch(); } - for(TileEntity tile : state.teams.playerCores()){ - Effects.effect(Fx.launch, tile); + for(Tilec tile : state.teams.playerCores()){ + Fx.launch.at(tile); } if(world.getZone() != null){ @@ -185,12 +177,12 @@ public class Logic implements ApplicationListener{ } Time.runTask(30f, () -> { - for(TileEntity entity : state.teams.playerCores()){ + for(Tilec entity : state.teams.playerCores()){ for(Item item : content.items()){ - data.addItem(item, entity.items.get(item)); - Events.fire(new LaunchItemEvent(item, entity.items.get(item))); + data.addItem(item, entity.items().get(item)); + Events.fire(new LaunchItemEvent(item, entity.items().get(item))); } - entity.tile.remove(); + entity.tile().remove(); } state.launched = true; state.gameOver = true; @@ -213,7 +205,8 @@ public class Logic implements ApplicationListener{ if(!state.is(State.menu)){ if(!net.client()){ - state.enemies = unitGroup.count(b -> b.getTeam() == state.rules.waveTeam && b.countsAsEnemy()); + //TODO + //state.enemies = Groups.unit.count(b -> b.team() == state.rules.waveTeam && b.countsAsEnemy()); } if(!state.isPaused()){ @@ -229,13 +222,17 @@ public class Logic implements ApplicationListener{ runWave(); } + Groups.update(); + + //TODO update groups + /* if(!headless){ effectGroup.update(); groundEffectGroup.update(); } if(!state.isEditor()){ - unitGroup.update(); + Groups.unit.update(); puddleGroup.update(); shieldGroup.update(); bulletGroup.update(); @@ -243,12 +240,12 @@ public class Logic implements ApplicationListener{ fireGroup.update(); weatherGroup.update(); }else{ - unitGroup.updateEvents(); - collisions.updatePhysics(unitGroup); + Groups.unit.updateEvents(); + collisions.updatePhysics(Groups.unit); } - playerGroup.update(); + Groups.player.update(); //effect group only contains item transfers in the headless version, update it! if(headless){ @@ -257,9 +254,8 @@ public class Logic implements ApplicationListener{ if(!state.isEditor()){ //bulletGroup - collisions.collideGroups(bulletGroup, unitGroup); - collisions.collideGroups(bulletGroup, playerGroup); - } + collisions.collideGroups(bulletGroup, Groups.unit); + }*/ } if(!net.client() && !world.isInvalidMap() && !state.isEditor() && state.rules.canGameOver){ diff --git a/core/src/mindustry/core/NetClient.java b/core/src/mindustry/core/NetClient.java index 89d2a600f8..8fb7e27a19 100644 --- a/core/src/mindustry/core/NetClient.java +++ b/core/src/mindustry/core/NetClient.java @@ -1,29 +1,23 @@ package mindustry.core; import arc.*; -import mindustry.annotations.Annotations.*; -import arc.struct.*; import arc.graphics.*; import arc.math.*; -import arc.util.CommandHandler.*; +import arc.struct.*; import arc.util.*; +import arc.util.CommandHandler.*; import arc.util.io.*; import arc.util.serialization.*; import mindustry.*; +import mindustry.annotations.Annotations.*; import mindustry.core.GameState.*; -import mindustry.ctype.ContentType; -import mindustry.entities.*; -import mindustry.entities.traits.BuilderTrait.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; -import mindustry.game.*; import mindustry.game.EventType.*; +import mindustry.game.*; import mindustry.gen.*; import mindustry.net.Administration.*; import mindustry.net.Net.*; import mindustry.net.*; import mindustry.net.Packets.*; -import mindustry.type.TypeID; import mindustry.world.*; import mindustry.world.modules.*; @@ -61,7 +55,7 @@ public class NetClient implements ApplicationListener{ net.handleClient(Connect.class, packet -> { Log.info("Connecting to server: {0}", packet.addressTCP); - player.isAdmin = false; + player.admin(false); reset(); @@ -76,11 +70,11 @@ public class NetClient implements ApplicationListener{ }); ConnectPacket c = new ConnectPacket(); - c.name = player.name; + c.name = player.name(); c.mods = mods.getModStrings(); c.mobile = mobile; c.versionType = Version.type; - c.color = Color.rgba8888(player.color); + c.color = Color.rgba8888(player.color()); c.usid = getUsid(packet.addressTCP); c.uuid = platform.getUUID(); @@ -134,14 +128,14 @@ public class NetClient implements ApplicationListener{ //called on all clients @Remote(targets = Loc.server, variants = Variant.both) - public static void sendMessage(String message, String sender, Player playersender){ + public static void sendMessage(String message, String sender, Playerc playersender){ if(Vars.ui != null){ Vars.ui.chatfrag.addMessage(message, sender); } if(playersender != null){ - playersender.lastText = message; - playersender.textFadeTime = 1f; + playersender.lastText(message); + playersender.textFadeTime(1f); } } @@ -155,7 +149,7 @@ public class NetClient implements ApplicationListener{ //called when a server recieves a chat message from a player @Remote(called = Loc.server, targets = Loc.client) - public static void sendChatMessage(Player player, String message){ + public static void sendChatMessage(Playerc player, String message){ if(message.length() > maxTextLength){ throw new ValidateException(player, "Player has sent a message above the text limit."); } @@ -172,19 +166,19 @@ public class NetClient implements ApplicationListener{ } //special case; graphical server needs to see its message - if(!headless && player == Vars.player){ - Vars.ui.chatfrag.addMessage(message, colorizeName(player.id, player.name)); + if(!headless){ + sendMessage(message, colorizeName(player.id(), player.name()), player); } //server console logging - Log.info("&y{0}: &lb{1}", player.name, message); + Log.info("&y{0}: &lb{1}", player.name(), message); //invoke event for all clients but also locally //this is required so other clients get the correct name even if they don't know who's sending it yet - Call.sendMessage(message, colorizeName(player.id, player.name), player); + Call.sendMessage(message, colorizeName(player.id(), player.name()), player); }else{ //log command to console but with brackets - Log.info("<&y{0}: &lm{1}&lg>", player.name, message); + Log.info("<&y{0}: &lm{1}&lg>", player.name(), message); //a command was sent, now get the output if(response.type != ResponseType.valid){ @@ -205,9 +199,9 @@ public class NetClient implements ApplicationListener{ } public static String colorizeName(int id, String name){ - Player player = playerGroup.getByID(id); + Playerc player = Groups.player.getByID(id); if(name == null || player == null) return null; - return "[#" + player.color.toString().toUpperCase() + "]" + name; + return "[#" + player.color().toString().toUpperCase() + "]" + name; } @Remote(called = Loc.client, variants = Variant.one) @@ -220,8 +214,8 @@ public class NetClient implements ApplicationListener{ } @Remote(targets = Loc.client) - public static void onPing(Player player, long time){ - Call.onPingResponse(player.con, time); + public static void onPing(Playerc player, long time){ + Call.onPingResponse(player.con(), time); } @Remote(variants = Variant.one) @@ -230,7 +224,7 @@ public class NetClient implements ApplicationListener{ } @Remote(variants = Variant.one) - public static void onTraceInfo(Player player, TraceInfo info){ + public static void onTraceInfo(Playerc player, TraceInfo info){ if(player != null){ ui.traces.show(player, info); } @@ -266,6 +260,32 @@ public class NetClient implements ApplicationListener{ ui.showText("", message); } + @Remote(variants = Variant.both) + public static void onInfoPopup(String message, float duration, int align, int top, int left, int bottom, int right){ + ui.showInfoPopup(message, duration, align, top, left, bottom, right); + } + + @Remote(variants = Variant.both) + public static void onLabel(String info, float duration, float worldx, float worldy){ + ui.showLabel(info, duration, worldx, worldy); + } + + /* + @Remote(variants = Variant.both, unreliable = true) + public static void onEffect(Effect effect, float x, float y, float rotation, Color color){ + effect.at(x, y, rotation, color); + } + + @Remote(variants = Variant.both) + public static void onEffectReliable(Effect effect, float x, float y, float rotation, Color color){ + effect.at(x, y, rotation, color); + }*/ + + @Remote(variants = Variant.both) + public static void onInfoToast(String message, float duration){ + ui.showInfoToast(message, duration); + } + @Remote(variants = Variant.both) public static void onSetRules(Rules rules){ state.rules = rules; @@ -273,7 +293,7 @@ public class NetClient implements ApplicationListener{ @Remote(variants = Variant.both) public static void onWorldDataBegin(){ - entities.clear(); + Groups.all.clear(); netClient.removed.clear(); logic.reset(); @@ -291,41 +311,38 @@ public class NetClient implements ApplicationListener{ @Remote(variants = Variant.one) public static void onPositionSet(float x, float y){ - player.x = x; - player.y = y; + player.set(x, y); } @Remote public static void onPlayerDisconnect(int playerid){ - playerGroup.removeByID(playerid); + Groups.player.removeByID(playerid); } @Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true) - public static void onEntitySnapshot(byte groupID, short amount, short dataLen, byte[] data){ + public static void onEntitySnapshot(short amount, short dataLen, byte[] data){ try{ netClient.byteStream.setBytes(net.decompressSnapshot(data, dataLen)); DataInputStream input = netClient.dataStream; - EntityGroup group = entities.get(groupID); - //go through each entity for(int j = 0; j < amount; j++){ int id = input.readInt(); byte typeID = input.readByte(); - SyncTrait entity = group == null ? null : (SyncTrait)group.getByID(id); + Syncc entity = Groups.sync.getByID(id); boolean add = false, created = false; - if(entity == null && id == player.id){ + if(entity == null && id == player.id()){ entity = player; add = true; } //entity must not be added yet, so create it if(entity == null){ - entity = (SyncTrait)content.getByID(ContentType.typeid, typeID).constructor.get(); - entity.resetID(id); - if(!netClient.isEntityUsed(entity.getID())){ + entity = (Syncc)EntityMapping.map(typeID).get(); + entity.id(id); + if(!netClient.isEntityUsed(entity.id())){ add = true; } created = true; @@ -334,17 +351,14 @@ public class NetClient implements ApplicationListener{ //read the entity entity.read(input); - if(created && entity.getInterpolator() != null && entity.getInterpolator().target != null){ + if(created && entity.interpolator().target != null){ //set initial starting position - entity.setNet(entity.getInterpolator().target.x, entity.getInterpolator().target.y); - if(entity instanceof Unit && entity.getInterpolator().targets.length > 0){ - ((Unit)entity).rotation = entity.getInterpolator().targets[0]; - } + entity.setNet(entity.interpolator().target.x, entity.interpolator().target.y); } if(add){ entity.add(); - netClient.addRemovedEntity(entity.getID()); + netClient.addRemovedEntity(entity.id()); } } }catch(IOException e){ @@ -365,7 +379,7 @@ public class NetClient implements ApplicationListener{ Log.warn("Missing entity at {0}. Skipping block snapshot.", tile); break; } - tile.entity.read(input, tile.entity.version()); + tile.entity.read(input); } }catch(Exception e){ e.printStackTrace(); @@ -393,7 +407,7 @@ public class NetClient implements ApplicationListener{ Tile tile = world.tile(pos); if(tile != null && tile.entity != null){ - tile.entity.items.read(input); + tile.entity.items().read(input); }else{ new ItemModule().read(input); } @@ -438,7 +452,8 @@ public class NetClient implements ApplicationListener{ connecting = false; ui.join.hide(); net.setClientLoaded(true); - Core.app.post(Call::connectConfirm); + //TODO connect confirm + //Core.app.post(Call::connectConfirm); Time.runTask(40f, platform::updateRPC); Core.app.post(() -> ui.loadfrag.hide()); } @@ -452,7 +467,7 @@ public class NetClient implements ApplicationListener{ quiet = false; lastSent = 0; - entities.clear(); + Groups.all.clear(); ui.chatfrag.clearMessages(); } @@ -486,21 +501,22 @@ public class NetClient implements ApplicationListener{ } void sync(){ - + //TODO implement + /* if(timer.get(0, playerSyncTime)){ BuildRequest[] requests; //limit to 10 to prevent buffer overflows - int usedRequests = Math.min(player.buildQueue().size, 10); + int usedRequests = Math.min(player.builder().requests().size, 10); requests = new BuildRequest[usedRequests]; for(int i = 0; i < usedRequests; i++){ - requests[i] = player.buildQueue().get(i); + requests[i] = player.builder().requests().get(i); } Call.onClientShapshot(lastSent++, player.x, player.y, player.pointerX, player.pointerY, player.rotation, player.baseRotation, - player.velocity().x, player.velocity().y, - player.getMineTile(), + player.vel().x, player.vel().y, + player.miner().mineTile(), player.isBoosting, player.isShooting, ui.chatfrag.shown(), player.isBuilding, requests, Core.camera.position.x, Core.camera.position.y, @@ -509,7 +525,7 @@ public class NetClient implements ApplicationListener{ if(timer.get(1, 60)){ Call.onPing(Time.millis()); - } + }*/ } String getUsid(String ip){ diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java index 844447e7b8..129db7855d 100644 --- a/core/src/mindustry/core/NetServer.java +++ b/core/src/mindustry/core/NetServer.java @@ -9,13 +9,8 @@ import arc.util.*; import arc.util.CommandHandler.*; import arc.util.io.*; import mindustry.annotations.Annotations.*; -import mindustry.content.*; import mindustry.core.GameState.*; -import mindustry.entities.*; -import mindustry.entities.traits.BuilderTrait.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; -import mindustry.net.Administration; +import mindustry.entities.units.*; import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.game.Teams.*; @@ -49,8 +44,8 @@ public class NetServer implements ApplicationListener{ //find team with minimum amount of players and auto-assign player to that. TeamData re = state.teams.getActive().min(data -> { int count = 0; - for(Player other : players){ - if(other.getTeam() == data.team && other != player){ + for(Playerc other : players){ + if(other.team() == data.team && other != player){ count++; } } @@ -121,7 +116,7 @@ public class NetServer implements ApplicationListener{ return; } - if(admins.getPlayerLimit() > 0 && playerGroup.size() >= admins.getPlayerLimit()){ + if(admins.getPlayerLimit() > 0 && Groups.player.size() >= admins.getPlayerLimit()){ con.kick(KickReason.playerLimit); return; } @@ -162,16 +157,14 @@ public class NetServer implements ApplicationListener{ boolean preventDuplicates = headless && netServer.admins.getStrict(); if(preventDuplicates){ - for(Player player : playerGroup.all()){ - if(player.name.trim().equalsIgnoreCase(packet.name.trim())){ - con.kick(KickReason.nameInUse); - return; - } + if(Groups.player.contains(p -> p.name().trim().equalsIgnoreCase(packet.name.trim()))){ + con.kick(KickReason.nameInUse); + return; + } - if(player.uuid != null && player.usid != null && (player.uuid.equals(packet.uuid) || player.usid.equals(packet.usid))){ - con.kick(KickReason.idInUse); - return; - } + if(Groups.player.contains(player -> player.uuid().equals(packet.uuid) || player.usid().equals(packet.usid))){ + con.kick(KickReason.idInUse); + return; } } @@ -195,17 +188,14 @@ public class NetServer implements ApplicationListener{ con.modclient = true; } - Player player = new Player(); - player.isAdmin = admins.isAdmin(uuid, packet.usid); - player.con = con; - player.usid = packet.usid; - player.name = packet.name; - player.uuid = uuid; - player.isMobile = packet.mobile; - player.dead = true; - player.setNet(player.x, player.y); - player.color.set(packet.color); - player.color.a = 1f; + Playerc player = PlayerEntity.create(); + player.admin(admins.isAdmin(uuid, packet.usid)); + player.con(con); + player.con().usid = packet.usid; + player.con().uuid = uuid; + player.con().mobile = packet.mobile; + player.name(packet.name); + player.color().set(packet.color).a(1f); try{ writeBuffer.position(0); @@ -219,7 +209,7 @@ public class NetServer implements ApplicationListener{ con.player = player; //playing in pvp mode automatically assigns players to teams - player.setTeam(assignTeam(player, playerGroup.all())); + player.team(assignTeam(player)); sendWorldData(player); @@ -234,6 +224,13 @@ public class NetServer implements ApplicationListener{ RemoteReadServer.readPacket(packet.writeBuffer, packet.type, con.player); }catch(ValidateException e){ Log.debug("Validation failed for '{0}': {1}", e.player, e.getMessage()); + }catch(RuntimeException e){ + if(e.getCause() instanceof ValidateException){ + ValidateException v = (ValidateException)e.getCause(); + Log.debug("Validation failed for '{0}': {1}", v.player, v.getMessage()); + }else{ + throw e; + } } }); @@ -246,7 +243,7 @@ public class NetServer implements ApplicationListener{ } private void registerCommands(){ - clientCommands.register("help", "[page]", "Lists all commands.", (args, player) -> { + clientCommands.register("help", "[page]", "Lists all commands.", (args, player) -> { if(args.length > 0 && !Strings.canParseInt(args[0])){ player.sendMessage("[scarlet]'page' must be a number."); return; @@ -257,7 +254,7 @@ public class NetServer implements ApplicationListener{ page --; - if(page > pages || page < 0){ + if(page >= pages || page < 0){ player.sendMessage("[scarlet]'page' must be a number between[orange] 1[] and[orange] " + pages + "[scarlet]."); return; } @@ -272,45 +269,49 @@ public class NetServer implements ApplicationListener{ player.sendMessage(result.toString()); }); - clientCommands.register("t", "", "Send a message only to your teammates.", (args, player) -> { - playerGroup.all().each(p -> p.getTeam() == player.getTeam(), o -> o.sendMessage(args[0], player, "[#" + player.getTeam().color.toString() + "]" + NetClient.colorizeName(player.id, player.name))); + clientCommands.register("t", "", "Send a message only to your teammates.", (args, player) -> { + Groups.player.each(p -> p.team() == player.team(), o -> o.sendMessage(args[0], player, "[#" + player.team().color.toString() + "]" + NetClient.colorizeName(player.id(), player.name()))); }); //duration of a a kick in seconds - int kickDuration = 15 * 60; + int kickDuration = 60 * 60; + //voting round duration in seconds + float voteDuration = 0.5f * 60; + //cooldown between votes + int voteCooldown = 60 * 1; class VoteSession{ - Player target; + Playerc target; ObjectSet voted = new ObjectSet<>(); VoteSession[] map; Timer.Task task; int votes; - public VoteSession(VoteSession[] map, Player target){ + public VoteSession(VoteSession[] map, Playerc 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)); + Call.sendMessage(Strings.format("[lightgray]Vote failed. Not enough votes to kick[orange] {0}[lightgray].", target.name())); map[0] = null; task.cancel(); } - }, 60 * 1); + }, voteDuration); } - void vote(Player player, int d){ + void vote(Playerc player, int d){ votes += d; - voted.addAll(player.uuid, admins.getInfo(player.uuid).lastIP); + 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())); + player.name(), target.name(), votes, votesRequired())); } boolean checkPass(){ if(votes >= votesRequired()){ - Call.sendMessage(Strings.format("[orange]Vote passed.[scarlet] {0}[orange] will be banned from the server for {1} minutes.", target.name, (kickDuration/60))); + Call.sendMessage(Strings.format("[orange]Vote passed.[scarlet] {0}[orange] will be banned from the server for {1} minutes.", target.name(), (kickDuration/60))); target.getInfo().lastKicked = Time.millis() + kickDuration*1000; - playerGroup.all().each(p -> p.uuid != null && p.uuid.equals(target.uuid), p -> p.con.kick(KickReason.vote)); + Groups.player.each(p -> p.uuid().equals(target.uuid()), p -> p.kick(KickReason.vote)); map[0] = null; task.cancel(); return true; @@ -319,24 +320,22 @@ public class NetServer implements ApplicationListener{ } } - //cooldown between votes - int voteTime = 60 * 3; - Timekeeper vtime = new Timekeeper(voteTime); + Timekeeper vtime = new Timekeeper(voteCooldown); //current kick sessions VoteSession[] currentlyKicking = {null}; - clientCommands.register("votekick", "[player...]", "Vote to kick a player, with a cooldown.", (args, player) -> { + clientCommands.register("votekick", "[player...]", "Vote to kick a player, with a cooldown.", (args, player) -> { if(!Config.enableVotekick.bool()){ player.sendMessage("[scarlet]Vote-kick is disabled on this server."); return; } - if(playerGroup.size() < 3){ + if(Groups.player.size() < 3){ player.sendMessage("[scarlet]At least 3 players are needed to start a votekick."); return; } - if(player.isLocal){ + if(player.isLocal()){ player.sendMessage("[scarlet]Just kick them yourself if you're the host."); return; } @@ -344,31 +343,30 @@ public class NetServer implements ApplicationListener{ if(args.length == 0){ StringBuilder builder = new StringBuilder(); builder.append("[orange]Players to kick: \n"); - for(Player p : playerGroup.all()){ - if(p.isAdmin || p.con == null || p == player) continue; - builder.append("[lightgray] ").append(p.name).append("[accent] (#").append(p.id).append(")\n"); - } + Groups.player.each(p -> !p.admin() && p.con() != null && p != player, p -> { + builder.append("[lightgray] ").append(p.name()).append("[accent] (#").append(p.id()).append(")\n"); + }); player.sendMessage(builder.toString()); }else{ - Player found; + Playerc 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.id == id); + found = Groups.player.find(p -> p.id() == id); }else{ - found = playerGroup.find(p -> p.name.equalsIgnoreCase(args[0])); + found = Groups.player.find(p -> p.name().equalsIgnoreCase(args[0])); } if(found != null){ - if(found.isAdmin){ + if(found.admin()){ player.sendMessage("[scarlet]Did you really expect to be able to kick an admin?"); - }else if(found.isLocal){ + }else if(found.isLocal()){ player.sendMessage("[scarlet]Local players cannot be kicked."); - }else if(found.getTeam() != player.getTeam()){ + }else if(found.team() != player.team()){ player.sendMessage("[scarlet]Only players on your team can be kicked."); }else{ if(!vtime.get()){ - player.sendMessage("[scarlet]You must wait " + voteTime/60 + " minutes between votekicks."); + player.sendMessage("[scarlet]You must wait " + voteCooldown/60 + " minutes between votekicks."); return; } @@ -383,17 +381,17 @@ public class NetServer implements ApplicationListener{ } }); - clientCommands.register("vote", "", "Vote to kick the current player.", (arg, player) -> { + 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(player.isLocal){ + if(player.isLocal()){ player.sendMessage("Local players can't vote. Kick the player yourself instead."); return; } //hosts can vote all they want - if(player.uuid != null && (currentlyKicking[0].voted.contains(player.uuid) || currentlyKicking[0].voted.contains(admins.getInfo(player.uuid).lastIP))){ + 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; } @@ -414,8 +412,8 @@ public class NetServer implements ApplicationListener{ }); - clientCommands.register("sync", "Re-synchronize world state.", (args, player) -> { - if(player.isLocal){ + clientCommands.register("sync", "Re-synchronize world state.", (args, player) -> { + if(player.isLocal()){ player.sendMessage("[scarlet]Re-synchronizing as the host is pointless."); }else{ if(Time.timeSinceMillis(player.getInfo().lastSyncTime) < 1000 * 5){ @@ -424,69 +422,75 @@ public class NetServer implements ApplicationListener{ } player.getInfo().lastSyncTime = Time.millis(); - Call.onWorldDataBegin(player.con); + Call.onWorldDataBegin(player.con()); netServer.sendWorldData(player); } }); } public int votesRequired(){ - return 2 + (playerGroup.size() > 4 ? 1 : 0); + return 2 + (Groups.player.size() > 4 ? 1 : 0); } - public Team assignTeam(Player current, Iterable players){ + public Team assignTeam(Playerc current){ + return assigner.assign(current, Groups.player); + } + + public Team assignTeam(Playerc current, Iterable players){ return assigner.assign(current, players); } - public void sendWorldData(Player player){ + public void sendWorldData(Playerc player){ ByteArrayOutputStream stream = new ByteArrayOutputStream(); DeflaterOutputStream def = new FastDeflaterOutputStream(stream); NetworkIO.writeWorld(player, def); WorldStream data = new WorldStream(); data.stream = new ByteArrayInputStream(stream.toByteArray()); - player.con.sendStream(data); + player.con().sendStream(data); Log.debug("Packed {0} compressed bytes of world data.", stream.size()); } - public static void onDisconnect(Player player, String reason){ + public static void onDisconnect(Playerc player, String reason){ //singleplayer multiplayer wierdness - if(player.con == null){ + if(player.con() == null){ player.remove(); return; } - if(!player.con.hasDisconnected){ - if(player.con.hasConnected){ + if(!player.con().hasDisconnected){ + if(player.con().hasConnected){ Events.fire(new PlayerLeave(player)); - if(Config.showConnectMessages.bool()) Call.sendMessage("[accent]" + player.name + "[accent] has disconnected."); - Call.onPlayerDisconnect(player.id); + if(Config.showConnectMessages.bool()) Call.sendMessage("[accent]" + player.name() + "[accent] has disconnected."); + Call.onPlayerDisconnect(player.id()); } - Log.info("&lm[{1}] &lc{0} has disconnected. &lg&fi({2})", player.name, player.uuid, reason); + if(Config.showConnectMessages.bool()) Log.info("&lm[{1}] &lc{0} has disconnected. &lg&fi({2})", player.name(), player.uuid(), reason); } player.remove(); - player.con.hasDisconnected = true; + player.con().hasDisconnected = true; } @Remote(targets = Loc.client, unreliable = true) public static void onClientShapshot( - Player player, + Playerc player, int snapshotID, float x, float y, float pointerX, float pointerY, float rotation, float baseRotation, float xVelocity, float yVelocity, Tile mining, - boolean boosting, boolean shooting, boolean chatting, boolean building, + boolean boosting, boolean shooting, boolean chatting, BuildRequest[] requests, float viewX, float viewY, float viewWidth, float viewHeight ){ - NetConnection connection = player.con; + //TODO this entire thing needs to be rewritten. + /* + NetConnection connection = player.con(); if(connection == null || snapshotID < connection.lastRecievedClientSnapshot) return; - boolean verifyPosition = !player.isDead() && netServer.admins.getStrict() && headless; + boolean verifyPosition = !player.dead() && netServer.admins.getStrict() && headless; if(connection.lastRecievedClientTime == 0) connection.lastRecievedClientTime = Time.millis() - 16; @@ -500,14 +504,14 @@ public class NetServer implements ApplicationListener{ float maxSpeed = boosting && !player.mech.flying ? player.mech.compoundSpeedBoost : player.mech.compoundSpeed; float maxMove = elapsed / 1000f * 60f * Math.min(maxSpeed, player.mech.maxSpeed) * 1.2f; - player.pointerX = pointerX; - player.pointerY = pointerY; - player.setMineTile(mining); + player.mouseX(pointerX); + player.mouseY(pointerY); + player.miner().mineTile(mining); player.isTyping = chatting; player.isBoosting = boosting; player.isShooting = shooting; player.isBuilding = building; - player.buildQueue().clear(); + player.builder().requests().clear(); for(BuildRequest req : requests){ if(req == null) continue; @@ -526,11 +530,11 @@ public class NetServer implements ApplicationListener{ action.config = req.config; })){ //force the player to remove this request if that's not the case - Call.removeQueueBlock(player.con, req.x, req.y, req.breaking); + Call.removeQueueBlock(player.con(), req.x, req.y, req.breaking); connection.rejectedRequests.add(req); continue; } - player.buildQueue().addLast(req); + player.builder().requests().addLast(req); } connection.rejectedRequests.clear(); @@ -554,7 +558,7 @@ public class NetServer implements ApplicationListener{ newx = x; newy = y; }else if(Mathf.dst(x, y, newx, newy) > correctDist){ - Call.onPositionSet(player.con, 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 @@ -563,23 +567,23 @@ public class NetServer implements ApplicationListener{ //set interpolator target to *new* position so it moves toward it player.getInterpolator().read(player.x, player.y, newx, newy, rotation, baseRotation); - player.velocity().set(xVelocity, yVelocity); //only for visual calculation purposes, doesn't actually update the player + player.vel().set(xVelocity, yVelocity); //only for visual calculation purposes, doesn't actually update the player connection.lastRecievedClientSnapshot = snapshotID; - connection.lastRecievedClientTime = Time.millis(); + connection.lastRecievedClientTime = Time.millis();*/ } @Remote(targets = Loc.client, called = Loc.server) - public static void onAdminRequest(Player player, Player other, AdminAction action){ + public static void onAdminRequest(Playerc player, Playerc other, AdminAction action){ - if(!player.isAdmin){ + if(!player.admin()){ Log.warn("ACCESS DENIED: Player {0} / {1} attempted to perform admin action without proper security access.", - player.name, player.con.address); + player.name(), player.con().address); return; } - if(other == null || ((other.isAdmin && !player.isLocal) && other != player)){ - Log.warn("{0} attempted to perform admin action on nonexistant or admin player.", player.name); + if(other == null || ((other.admin() && !player.isLocal()) && other != player)){ + Log.warn("{0} attempted to perform admin action on nonexistant or admin player.", player.name()); return; } @@ -588,31 +592,33 @@ public class NetServer implements ApplicationListener{ //not a real issue, because server owners may want to do just that state.wavetime = 0f; }else if(action == AdminAction.ban){ - netServer.admins.banPlayerIP(other.con.address); - other.con.kick(KickReason.banned); - Log.info("&lc{0} has banned {1}.", player.name, other.name); + netServer.admins.banPlayerIP(other.con().address); + other.kick(KickReason.banned); + Log.info("&lc{0} has banned {1}.", player.name(), other.name()); }else if(action == AdminAction.kick){ - other.con.kick(KickReason.kick); - Log.info("&lc{0} has kicked {1}.", player.name, other.name); + other.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, other, info); + TraceInfo info = new TraceInfo(other.con().address, other.uuid(), other.con().modclient, other.con().mobile); + if(player.con() != null){ + Call.onTraceInfo(player.con(), other, info); }else{ NetClient.onTraceInfo(other, info); } - Log.info("&lc{0} has requested trace info of {1}.", player.name, other.name); + Log.info("&lc{0} has requested trace info of {1}.", player.name(), other.name()); } } @Remote(targets = Loc.client) - public static void connectConfirm(Player player){ - if(player.con == null || player.con.hasConnected) return; + public static void connectConfirm(Playerc player){ + if(player.con() == null || player.con().hasConnected) return; player.add(); - player.con.hasConnected = true; - if(Config.showConnectMessages.bool()) Call.sendMessage("[accent]" + player.name + "[accent] has connected."); - Log.info("&lm[{1}] &y{0} has connected. ", player.name, player.uuid); + player.con().hasConnected = true; + if(Config.showConnectMessages.bool()){ + Call.sendMessage("[accent]" + player.name() + "[accent] has connected."); + Log.info("&lm[{1}] &y{0} has connected. ", player.name(), player.uuid()); + } if(!Config.motd.string().equalsIgnoreCase("off")){ player.sendMessage(Config.motd.string()); @@ -625,7 +631,7 @@ public class NetServer implements ApplicationListener{ if(state.rules.pvp){ int used = 0; for(TeamData t : state.teams.getActive()){ - if(playerGroup.count(p -> p.getTeam() == t.team) > 0){ + if(Groups.player.count(p -> p.team() == t.team) > 0){ used++; } } @@ -677,11 +683,11 @@ public class NetServer implements ApplicationListener{ syncStream.reset(); short sent = 0; - for(TileEntity entity : tileGroup.all()){ - if(!entity.block.sync) continue; + for(Tilec entity : Groups.tile){ + if(!entity.block().sync) continue; sent ++; - dataStream.writeInt(entity.tile.pos()); + dataStream.writeInt(entity.tile().pos()); entity.write(dataStream); if(syncStream.size() > maxSnapshotSize){ @@ -700,65 +706,53 @@ public class NetServer implements ApplicationListener{ } } - public void writeEntitySnapshot(Player player) throws IOException{ + public void writeEntitySnapshot(Playerc player) throws IOException{ syncStream.reset(); - Array cores = state.teams.cores(player.getTeam()); + Array cores = state.teams.cores(player.team()); dataStream.writeByte(cores.size); for(CoreEntity entity : cores){ - dataStream.writeInt(entity.tile.pos()); - entity.items.write(dataStream); + dataStream.writeInt(entity.tile().pos()); + entity.items().write(dataStream); } dataStream.close(); byte[] stateBytes = syncStream.toByteArray(); //write basic state data. - Call.onStateSnapshot(player.con, 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); + viewport.setSize(player.con().viewWidth, player.con().viewHeight).setCenter(player.con().viewX, player.con().viewY); - //check for syncable groups - for(EntityGroup group : entities.all()){ - if(group.isEmpty() || !(group.all().get(0) instanceof SyncTrait)) continue; + syncStream.reset(); - //make sure mapping is enabled for this group - if(!group.mappingEnabled()){ - throw new RuntimeException("Entity group '" + group.getType() + "' contains SyncTrait entities, yet mapping is not enabled. In order for syncing to work, you must enable mapping for this group."); - } + int sent = 0; - syncStream.reset(); + for(Syncc entity : Groups.sync){ + //write all entities now + dataStream.writeInt(entity.id()); //write id + dataStream.writeByte(entity.classId()); //write type ID + entity.write(dataStream); //write entity - int sent = 0; + sent++; - for(Entity entity : group.all()){ - SyncTrait sync = (SyncTrait)entity; - if(!sync.isSyncing()) continue; - - //write all entities now - dataStream.writeInt(entity.getID()); //write id - dataStream.writeByte(sync.getTypeID().id); //write type ID - sync.write(dataStream); //write entity - - sent++; - - if(syncStream.size() > maxSnapshotSize){ - dataStream.close(); - byte[] syncBytes = syncStream.toByteArray(); - Call.onEntitySnapshot(player.con, (byte)group.getID(), (short)sent, (short)syncBytes.length, net.compressSnapshot(syncBytes)); - sent = 0; - syncStream.reset(); - } - } - - if(sent > 0){ + if(syncStream.size() > maxSnapshotSize){ dataStream.close(); - byte[] syncBytes = syncStream.toByteArray(); - Call.onEntitySnapshot(player.con, (byte)group.getID(), (short)sent, (short)syncBytes.length, net.compressSnapshot(syncBytes)); + Call.onEntitySnapshot(player.con(), (short)sent, (short)syncBytes.length, net.compressSnapshot(syncBytes)); + sent = 0; + syncStream.reset(); } } + + if(sent > 0){ + dataStream.close(); + + byte[] syncBytes = syncStream.toByteArray(); + Call.onEntitySnapshot(player.con(), (short)sent, (short)syncBytes.length, net.compressSnapshot(syncBytes)); + } + } String fixName(String name){ @@ -814,24 +808,24 @@ public class NetServer implements ApplicationListener{ void sync(){ try{ - //iterate through each player - for(int i = 0; i < playerGroup.size(); i++){ - Player player = playerGroup.all().get(i); - if(player.isLocal) continue; - - if(player.con == null || !player.con.isConnected()){ + Groups.player.each(p -> !p.isLocal(), player -> { + if(player.con() == null || !player.con().isConnected()){ onDisconnect(player, "disappeared"); - continue; + return; } - NetConnection connection = player.con; + NetConnection connection = player.con(); - if(!player.timer.get(Player.timerSync, serverSyncTime) || !connection.hasConnected) continue; + if(!player.timer(0, serverSyncTime) || !connection.hasConnected) return; - writeEntitySnapshot(player); - } + try{ + writeEntitySnapshot(player); + }catch(IOException e){ + e.printStackTrace(); + } + }); - if(playerGroup.size() > 0 && Core.settings.getBool("blocksync") && timer.get(timerBlockSync, blockSyncTime)){ + if(Groups.player.size() > 0 && Core.settings.getBool("blocksync") && timer.get(timerBlockSync, blockSyncTime)){ writeBlockSnapshots(); } @@ -841,6 +835,6 @@ public class NetServer implements ApplicationListener{ } public interface TeamAssigner{ - Team assign(Player player, Iterable players); + Team assign(Playerc player, Iterable players); } } diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 7d5e6714b5..20c8d8607a 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -1,8 +1,6 @@ package mindustry.core; import arc.*; -import arc.files.*; -import arc.func.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.graphics.gl.*; @@ -10,19 +8,12 @@ import arc.math.*; import arc.math.geom.*; import arc.scene.ui.layout.*; import arc.util.*; -import arc.util.pooling.*; import mindustry.content.*; import mindustry.core.GameState.*; -import mindustry.entities.*; -import mindustry.entities.effect.*; -import mindustry.entities.effect.GroundEffectEntity.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; import mindustry.game.EventType.*; +import mindustry.gen.*; import mindustry.graphics.*; -import mindustry.input.*; import mindustry.ui.*; -import mindustry.world.blocks.defense.ForceProjector.*; import static arc.Core.*; import static mindustry.Vars.*; @@ -34,7 +25,7 @@ public class Renderer implements ApplicationListener{ public final LightRenderer lights = new LightRenderer(); public final Pixelator pixelator = new Pixelator(); - public FrameBuffer shieldBuffer = new FrameBuffer(2, 2); + public FrameBuffer effectBuffer = new FrameBuffer(2, 2); private Bloom bloom; private Color clearColor; private float targetscale = Scl.scl(4); @@ -48,51 +39,14 @@ public class Renderer implements ApplicationListener{ camera = new Camera(); Shaders.init(); - Effects.setScreenShakeProvider((intensity, duration) -> { - shakeIntensity = Math.max(intensity, shakeIntensity); - shaketime = Math.max(shaketime, duration); - }); - - Effects.setEffectProvider((effect, color, x, y, rotation, data) -> { - if(effect == Fx.none) return; - if(Core.settings.getBool("effects")){ - Rect view = camera.bounds(rect); - Rect pos = rect2.setSize(effect.size).setCenter(x, y); - - if(view.overlaps(pos)){ - - if(!(effect instanceof GroundEffect)){ - EffectEntity entity = Pools.obtain(EffectEntity.class, EffectEntity::new); - entity.effect = effect; - entity.color.set(color); - entity.rotation = rotation; - entity.data = data; - entity.id++; - entity.set(x, y); - if(data instanceof Entity){ - entity.setParent((Entity)data); - } - effectGroup.add(entity); - }else{ - GroundEffectEntity entity = Pools.obtain(GroundEffectEntity.class, GroundEffectEntity::new); - entity.effect = effect; - entity.color.set(color); - entity.rotation = rotation; - entity.id++; - entity.data = data; - entity.set(x, y); - if(data instanceof Entity){ - entity.setParent((Entity)data); - } - groundEffectGroup.add(entity); - } - } - } - }); - clearColor = new Color(0f, 0f, 0f, 1f); } + public void shake(float intensity, float duration){ + shakeIntensity = Math.max(shakeIntensity, intensity); + shaketime = Math.max(shaketime, duration); + } + @Override public void init(){ if(settings.getBool("bloom")){ @@ -121,8 +75,10 @@ public class Renderer implements ApplicationListener{ }else{ Vec2 position = Tmp.v3.set(player); - if(player.isDead()){ - TileEntity core = player.getClosestCore(); + //TODO camera controls should be in input + /* + if(player.dead()){ + Tilec core = player.closestCore(); if(core != null){ if(player.spawner == null){ camera.position.lerpDelta(core.x, core.y, 0.08f); @@ -132,7 +88,7 @@ public class Renderer implements ApplicationListener{ } }else if(control.input instanceof DesktopInput && !state.isPaused()){ camera.position.lerpDelta(position, 0.08f); - } + }*/ updateShake(0.75f); if(pixelator.enabled()){ @@ -150,7 +106,7 @@ public class Renderer implements ApplicationListener{ @Override public void dispose(){ minimap.dispose(); - shieldBuffer.dispose(); + effectBuffer.dispose(); blocks.dispose(); if(bloom != null){ bloom.dispose(); @@ -166,6 +122,13 @@ public class Renderer implements ApplicationListener{ } } + @Override + public void resume(){ + if(settings.getBool("bloom") && bloom != null){ + bloom.resume(); + } + } + void setupBloom(){ try{ if(bloom != null){ @@ -207,6 +170,117 @@ public class Renderer implements ApplicationListener{ } } + public void draw(){ + camera.update(); + + if(Float.isNaN(camera.position.x) || Float.isNaN(camera.position.y)){ + camera.position.set(player); + } + + graphics.clear(clearColor); + + if(!graphics.isHidden() && (Core.settings.getBool("animatedwater") || Core.settings.getBool("animatedshields")) && (effectBuffer.getWidth() != graphics.getWidth() || effectBuffer.getHeight() != graphics.getHeight())){ + effectBuffer.resize(graphics.getWidth(), graphics.getHeight()); + } + + Draw.proj(camera.projection()); + + blocks.floor.drawFloor(); + + Groups.drawFloor(); + Groups.drawFloorOver(); + + blocks.processBlocks(); + blocks.drawShadows(); + Draw.color(); + + blocks.floor.beginDraw(); + blocks.floor.drawLayer(CacheLayer.walls); + blocks.floor.endDraw(); + + blocks.drawBlocks(Layer.block); + blocks.drawFog(); + + blocks.drawDestroyed(); + + Draw.shader(Shaders.blockbuild, true); + blocks.drawBlocks(Layer.placement); + Draw.shader(); + + blocks.drawBlocks(Layer.overlay); + + Groups.drawGroundShadows(); + Groups.drawGroundUnder(); + Groups.drawGround(); + + blocks.drawBlocks(Layer.turret); + + Groups.drawFlyingShadows(); + + blocks.drawBlocks(Layer.power); + blocks.drawBlocks(Layer.lights); + + Groups.drawFlying(); + + Draw.flush(); + if(bloom != null && !pixelator.enabled()){ + bloom.capture(); + } + + Groups.drawBullets(); + Groups.drawEffects(); + + Draw.flush(); + if(bloom != null && !pixelator.enabled()){ + bloom.render(); + } + + overlays.drawBottom(); + if(player.isBuilder()){ + player.builder().drawBuildRequests(); + } + + overlays.drawTop(); + + if(!pixelator.enabled()){ + Groups.drawNames(); + } + + if(state.rules.lighting){ + lights.draw(); + } + + drawLanding(); + + Draw.color(); + Draw.flush(); + } + + private void drawLanding(){ + if(landTime > 0 && player.closestCore() != null){ + float fract = landTime / Fx.coreLand.lifetime; + Tilec entity = player.closestCore(); + + TextureRegion reg = entity.block().icon(Cicon.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.getX(), entity.getY(), s, s); + + Angles.randLenVectors(1, (1f- fract), 100, 1000f * scl * (1f-fract), (x, y, fin, fout) -> { + Lines.stroke(scl * fin); + Lines.lineAngle(entity.getX() + x, entity.getY() + y, Mathf.angle(x, y), (fin * 20 + 1f) * scl); + }); + + Draw.color(); + Draw.mixcol(Color.white, fract); + Draw.rect(reg, entity.getX(), entity.getY(), reg.getWidth() * Draw.scl * scl, reg.getHeight() * Draw.scl * scl, fract * 135f); + + Draw.reset(); + } + } +/* public void draw(){ camera.update(); @@ -217,8 +291,8 @@ public class Renderer implements ApplicationListener{ graphics.clear(clearColor); - if(!graphics.isHidden() && (Core.settings.getBool("animatedwater") || Core.settings.getBool("animatedshields")) && (shieldBuffer.getWidth() != graphics.getWidth() || shieldBuffer.getHeight() != graphics.getHeight())){ - shieldBuffer.resize(graphics.getWidth(), graphics.getHeight()); + if(!graphics.isHidden() && (Core.settings.getBool("animatedwater") || Core.settings.getBool("animatedshields")) && (effectBuffer.getWidth() != graphics.getWidth() || effectBuffer.getHeight() != graphics.getHeight())){ + effectBuffer.resize(graphics.getWidth(), graphics.getHeight()); } Draw.proj(camera.projection()); @@ -276,20 +350,20 @@ public class Renderer implements ApplicationListener{ } overlays.drawBottom(); - playerGroup.draw(p -> p.isLocal, Player::drawBuildRequests); + Groups.player.draw(p -> p.isLocal, Playerc::drawBuildRequests); if(shieldGroup.countInBounds() > 0){ if(settings.getBool("animatedshields") && Shaders.shield != null){ Draw.flush(); - shieldBuffer.begin(); + effectBuffer.begin(); graphics.clear(Color.clear); shieldGroup.draw(); shieldGroup.draw(shield -> true, ShieldEntity::drawOver); Draw.flush(); - shieldBuffer.end(); + effectBuffer.end(); Draw.shader(Shaders.shield); Draw.color(Pal.accent); - Draw.rect(Draw.wrap(shieldBuffer.getTexture()), camera.position.x, camera.position.y, camera.width, -camera.height); + Draw.rect(Draw.wrap(effectBuffer.getTexture()), camera.position.x, camera.position.y, camera.width, -camera.height); Draw.color(); Draw.shader(); }else{ @@ -299,7 +373,7 @@ public class Renderer implements ApplicationListener{ overlays.drawTop(); - playerGroup.draw(p -> !p.isDead(), Player::drawName); + Groups.player.draw(p -> !p.isDead(), Playerc::drawName); if(state.rules.lighting){ lights.draw(); @@ -312,25 +386,25 @@ public class Renderer implements ApplicationListener{ } private void drawLanding(){ - if(landTime > 0 && player.getClosestCore() != null){ + if(landTime > 0 && player.closestCore() != null){ float fract = landTime / Fx.coreLand.lifetime; - TileEntity entity = player.getClosestCore(); + Tilec entity = player.closestCore(); TextureRegion reg = entity.block.icon(Cicon.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); + Draw.rect("circle-shadow", entity.getX(), entity.getY(), 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); + Lines.lineAngle(entity.getX() + x, entity.getY() + 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.rect(reg, entity.getX(), entity.getY(), reg.getWidth() * Draw.scl * scl, reg.getHeight() * Draw.scl * scl, fract * 135f); Draw.reset(); } @@ -340,15 +414,15 @@ public class Renderer implements ApplicationListener{ Draw.color(0, 0, 0, 0.4f); float rad = 1.6f; - Cons draw = u -> { + Cons draw = u -> { float size = Math.max(u.getIconRegion().getWidth(), u.getIconRegion().getHeight()) * Draw.scl; Draw.rect("circle-shadow", u.x, u.y, size * rad, size * rad); }; - unitGroup.draw(unit -> !unit.isDead(), draw::get); + Groups.unit.draw(unit -> !unit.isDead(), draw::get); - if(!playerGroup.isEmpty()){ - playerGroup.draw(unit -> !unit.isDead(), draw::get); + if(!Groups.player.isEmpty()){ + Groups.player.draw(unit -> !unit.isDead(), draw::get); } Draw.color(); @@ -358,22 +432,22 @@ public class Renderer implements ApplicationListener{ float trnsX = -12, trnsY = -13; Draw.color(0, 0, 0, 0.22f); - unitGroup.draw(unit -> unit.isFlying() && !unit.isDead(), baseUnit -> baseUnit.drawShadow(trnsX, trnsY)); - playerGroup.draw(unit -> unit.isFlying() && !unit.isDead(), player -> player.drawShadow(trnsX, trnsY)); + Groups.unit.draw(unit -> unit.isFlying() && !unit.isDead(), baseUnit -> baseUnit.drawShadow(trnsX, trnsY)); + Groups.player.draw(unit -> unit.isFlying() && !unit.isDead(), player -> player.drawShadow(trnsX, trnsY)); Draw.color(); } private void drawAllTeams(boolean flying){ - unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawUnder); - playerGroup.draw(p -> p.isFlying() == flying && !p.isDead(), Unit::drawUnder); + Groups.unit.draw(u -> u.isFlying() == flying && !u.isDead(), Unitc::drawUnder); + Groups.player.draw(p -> p.isFlying() == flying && !p.isDead(), Unitc::drawUnder); - unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawAll); - playerGroup.draw(p -> p.isFlying() == flying, Unit::drawAll); + Groups.unit.draw(u -> u.isFlying() == flying && !u.isDead(), Unitc::drawAll); + Groups.player.draw(p -> p.isFlying() == flying, Unitc::drawAll); - unitGroup.draw(u -> u.isFlying() == flying && !u.isDead(), Unit::drawOver); - playerGroup.draw(p -> p.isFlying() == flying, Unit::drawOver); - } + Groups.unit.draw(u -> u.isFlying() == flying && !u.isDead(), Unitc::drawOver); + Groups.player.draw(p -> p.isFlying() == flying, Unitc::drawOver); + }*/ public void scaleCamera(float amount){ targetscale += amount; @@ -400,6 +474,8 @@ public class Renderer implements ApplicationListener{ } public void takeMapScreenshot(){ + //TODO uncomment + /* drawGroundShadows(); int w = world.width() * tilesize, h = world.height() * tilesize; @@ -448,7 +524,7 @@ public class Renderer implements ApplicationListener{ buffer.dispose(); Core.settings.put("animatedwater", hadWater); - Core.settings.put("animatedshields", hadShields); + Core.settings.put("animatedshields", hadShields);*/ } } diff --git a/core/src/mindustry/core/UI.java b/core/src/mindustry/core/UI.java index 1bd6d31e2a..d3c416ee31 100644 --- a/core/src/mindustry/core/UI.java +++ b/core/src/mindustry/core/UI.java @@ -9,6 +9,7 @@ import arc.graphics.*; import arc.graphics.g2d.*; import arc.input.*; import arc.math.*; +import arc.math.geom.*; import arc.scene.*; import arc.scene.actions.*; import arc.scene.event.*; @@ -289,6 +290,49 @@ public class UI implements ApplicationListener, Loadable{ Core.scene.add(table); } + /** Shows a fading label at the top of the screen. */ + public void showInfoToast(String info, float duration){ + Table table = new Table(); + table.setFillParent(true); + table.touchable(Touchable.disabled); + table.update(() -> { + if(state.is(State.menu)) table.remove(); + }); + table.actions(Actions.delay(duration * 0.9f), Actions.fadeOut(duration * 0.1f, Interpolation.fade), Actions.remove()); + table.top().table(Styles.black3, t -> t.margin(4).add(info).style(Styles.outlineLabel)).padTop(10); + Core.scene.add(table); + } + + /** Shows a label at some position on the screen. Does not fade. */ + public void showInfoPopup(String info, float duration, int align, int top, int left, int bottom, int right){ + Table table = new Table(); + table.setFillParent(true); + table.touchable(Touchable.disabled); + table.update(() -> { + if(state.is(State.menu)) table.remove(); + }); + table.actions(Actions.delay(duration), Actions.remove()); + table.align(align).table(Styles.black3, t -> t.margin(4).add(info).style(Styles.outlineLabel)).pad(top, left, bottom, right); + Core.scene.add(table); + } + + /** Shows a label in the world. This label is behind everything. Does not fade. */ + public void showLabel(String info, float duration, float worldx, float worldy){ + Table table = new Table(); + table.setFillParent(true); + table.touchable(Touchable.disabled); + table.update(() -> { + if(state.is(State.menu)) table.remove(); + }); + table.actions(Actions.delay(duration), Actions.remove()); + table.align(Align.center).table(Styles.black3, t -> t.margin(4).add(info).style(Styles.outlineLabel)).update(t -> { + Vec2 v = Core.camera.project(worldx, worldy); + t.setPosition(v.x, v.y, Align.center); + }); + //make sure it's at the back + Core.scene.root.addChildAt(0, table); + } + public void showInfo(String info){ new Dialog(""){{ getCell(cont).growX(); @@ -426,7 +470,6 @@ public class UI implements ApplicationListener, Loadable{ dialog.show(); } - public void showCustomConfirm(String title, String text, String yes, String no, Runnable confirmed, Runnable denied){ FloatingDialog dialog = new FloatingDialog(title); dialog.cont.add(text).width(mobile ? 400f : 500f).wrap().pad(4f).get().setAlignment(Align.center, Align.center); @@ -459,11 +502,11 @@ public class UI implements ApplicationListener, Loadable{ public String formatAmount(int number){ if(number >= 1000000){ - return Strings.fixed(number / 1000000f, 1) + "[gray]" + Core.bundle.getOrNull("unit.millions") + "[]"; + return Strings.fixed(number / 1000000f, 1) + "[gray]" + Core.bundle.get("unit.millions") + "[]"; }else if(number >= 10000){ - return number / 1000 + "[gray]k[]"; + return number / 1000 + "[gray]" + Core.bundle.get("unit.thousands") + "[]"; }else if(number >= 1000){ - return Strings.fixed(number / 1000f, 1) + "[gray]" + Core.bundle.getOrNull("unit.thousands") + "[]"; + return Strings.fixed(number / 1000f, 1) + "[gray]" + Core.bundle.get("unit.thousands") + "[]"; }else{ return number + ""; } diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index 04fec3d240..abaa6982d9 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -12,6 +12,7 @@ import mindustry.core.GameState.*; import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.game.Teams.*; +import mindustry.gen.*; import mindustry.io.*; import mindustry.maps.*; import mindustry.maps.filters.*; @@ -163,7 +164,7 @@ public class World{ addDarkness(tiles); } - entities.all().each(group -> group.resize(-finalWorldBounds, -finalWorldBounds, tiles.width() * tilesize + finalWorldBounds * 2, tiles.height() * tilesize + finalWorldBounds * 2)); + Groups.resize(-finalWorldBounds, -finalWorldBounds, tiles.width() * tilesize + finalWorldBounds * 2, tiles.height() * tilesize + finalWorldBounds * 2); generating = false; Events.fire(new WorldLoadEvent()); @@ -377,7 +378,7 @@ public class World{ Tile tile = tiles.getn(x, y); Block result = tile.block(); - Team team = tile.getTeam(); + Team team = tile.team(); int offsetx = -(result.size - 1) / 2; int offsety = -(result.size - 1) / 2; diff --git a/core/src/mindustry/ctype/ContentType.java b/core/src/mindustry/ctype/ContentType.java index 31061e256b..2c8faaa1ff 100644 --- a/core/src/mindustry/ctype/ContentType.java +++ b/core/src/mindustry/ctype/ContentType.java @@ -4,16 +4,16 @@ package mindustry.ctype; public enum ContentType{ item, block, - mech, + mech_UNUSED, bullet, liquid, status, unit, weather, - effect, + effect_UNUSED, zone, - loadout, - typeid, + loadout_UNUSED, + typeid_UNUSED, error, planet; diff --git a/core/src/mindustry/ctype/UnlockableContent.java b/core/src/mindustry/ctype/UnlockableContent.java index 42c9ab8251..825891c31f 100644 --- a/core/src/mindustry/ctype/UnlockableContent.java +++ b/core/src/mindustry/ctype/UnlockableContent.java @@ -1,6 +1,7 @@ package mindustry.ctype; import arc.*; +import arc.util.ArcAnnotate.*; import mindustry.annotations.Annotations.*; import arc.graphics.g2d.*; import arc.scene.ui.layout.*; @@ -10,10 +11,10 @@ import mindustry.ui.Cicon; /** Base interface for an unlockable content type. */ public abstract class UnlockableContent extends MappableContent{ - /** Localized, formal name. Never null. Set to block name if not found in bundle. */ + /** Localized, formal name. Never null. Set to internal name if not found in bundle. */ public String localizedName; /** Localized description. May be null. */ - public String description; + public @Nullable String description; /** Icons by Cicon ID.*/ protected TextureRegion[] cicons = new TextureRegion[mindustry.ui.Cicon.all.length]; @@ -24,6 +25,10 @@ public abstract class UnlockableContent extends MappableContent{ this.description = Core.bundle.getOrNull(getContentType() + "." + this.name + ".description"); } + public String displayDescription(){ + return minfo.mod == null ? description : description + "\n" + Core.bundle.format("mod.display", minfo.mod.meta.displayName()); + } + /** Generate any special icons for this content. Called asynchronously.*/ @CallSuper public void createIcons(MultiPacker packer){ diff --git a/core/src/mindustry/editor/DrawOperation.java b/core/src/mindustry/editor/DrawOperation.java index 061a7aee84..f2e9b2ff71 100755 --- a/core/src/mindustry/editor/DrawOperation.java +++ b/core/src/mindustry/editor/DrawOperation.java @@ -65,7 +65,7 @@ public class DrawOperation{ tile.setFloor((Floor)content.block(to)); }else if(type == OpType.block.ordinal()){ Block block = content.block(to); - tile.setBlock(block, tile.getTeam(), tile.rotation()); + tile.setBlock(block, tile.team(), tile.rotation()); }else if(type == OpType.rotation.ordinal()){ tile.rotation(to); }else if(type == OpType.team.ordinal()){ diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java index 01b9e987b0..aeabaed77d 100644 --- a/core/src/mindustry/editor/EditorTile.java +++ b/core/src/mindustry/editor/EditorTile.java @@ -139,10 +139,10 @@ public class EditorTile extends Tile{ if(block.hasEntity()){ entity = block.newEntity().init(this, false); - entity.cons = new ConsumeModule(entity); - if(block.hasItems) entity.items = new ItemModule(); - if(block.hasLiquids) entity.liquids = new LiquidModule(); - if(block.hasPower) entity.power = new PowerModule(); + entity.cons(new ConsumeModule(entity)); + if(block.hasItems) entity.items(new ItemModule()); + if(block.hasLiquids) entity.liquids(new LiquidModule()); + if(block.hasPower) entity.power(new PowerModule()); } } diff --git a/core/src/mindustry/editor/EditorTool.java b/core/src/mindustry/editor/EditorTool.java index 8e197bf42e..e591aa5eb3 100644 --- a/core/src/mindustry/editor/EditorTool.java +++ b/core/src/mindustry/editor/EditorTool.java @@ -138,7 +138,7 @@ public enum EditorTool{ //only fill synthetic blocks, it's meaningless otherwise if(tile.link().synthetic()){ - Team dest = tile.getTeam(); + Team dest = tile.team(); if(dest == editor.drawTeam) return; fill(editor, x, y, false, t -> t.getTeamID() == (int)dest.id && t.link().synthetic(), t -> t.setTeam(editor.drawTeam)); } @@ -166,33 +166,42 @@ public enum EditorTool{ stack.clear(); stack.add(Pos.get(x, y)); - while(stack.size > 0){ - int popped = stack.pop(); - x = Pos.x(popped); - y = Pos.y(popped); + try{ + while(stack.size > 0 && stack.size < width*height){ + int popped = stack.pop(); + x = Pos.x(popped); + y = Pos.y(popped); - x1 = x; - while(x1 >= 0 && tester.get(editor.tile(x1, y))) x1--; - x1++; - boolean spanAbove = false, spanBelow = false; - while(x1 < width && tester.get(editor.tile(x1, y))){ - filler.get(editor.tile(x1, y)); - - if(!spanAbove && y > 0 && tester.get(editor.tile(x1, y - 1))){ - stack.add(Pos.get(x1, y - 1)); - spanAbove = true; - }else if(spanAbove && !tester.get(editor.tile(x1, y - 1))){ - spanAbove = false; - } - - if(!spanBelow && y < height - 1 && tester.get(editor.tile(x1, y + 1))){ - stack.add(Pos.get(x1, y + 1)); - spanBelow = true; - }else if(spanBelow && y < height - 1 && !tester.get(editor.tile(x1, y + 1))){ - spanBelow = false; - } + x1 = x; + while(x1 >= 0 && tester.get(editor.tile(x1, y))) x1--; x1++; + boolean spanAbove = false, spanBelow = false; + while(x1 < width && tester.get(editor.tile(x1, y))){ + filler.get(editor.tile(x1, y)); + + if(!spanAbove && y > 0 && tester.get(editor.tile(x1, y - 1))){ + stack.add(Pos.get(x1, y - 1)); + spanAbove = true; + }else if(spanAbove && !tester.get(editor.tile(x1, y - 1))){ + spanAbove = false; + } + + if(!spanBelow && y < height - 1 && tester.get(editor.tile(x1, y + 1))){ + stack.add(Pos.get(x1, y + 1)); + spanBelow = true; + }else if(spanBelow && y < height - 1 && !tester.get(editor.tile(x1, y + 1))){ + spanBelow = false; + } + x1++; + } } + stack.clear(); + }catch(OutOfMemoryError e){ + //hack + stack = null; + System.gc(); + e.printStackTrace(); + stack = new IntArray(); } } } diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java index d38c6d14cc..9a2f6e1449 100644 --- a/core/src/mindustry/editor/MapEditor.java +++ b/core/src/mindustry/editor/MapEditor.java @@ -83,7 +83,7 @@ public class MapEditor{ //re-add them for(Tile tile : tiles){ if(tile.block().isMultiblock()){ - tile.set(tile.block(), tile.getTeam()); + tile.set(tile.block(), tile.team()); } } diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index 577157ff19..4088b0c1bd 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -176,7 +176,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ } platform.publish(map); - }).padTop(-3).size(swidth * 2f + 10, 60f).update(b -> b.setText(editor.getTags().containsKey("steamid") ? editor.getTags().get("author").equals(player.name) ? "$workshop.listing" : "$view.workshop" : "$editor.publish.workshop")); + }).padTop(-3).size(swidth * 2f + 10, 60f).update(b -> b.setText(editor.getTags().containsKey("steamid") ? editor.getTags().get("author").equals(player.name()) ? "$workshop.listing" : "$view.workshop" : "$editor.publish.workshop")); menu.cont.row(); } @@ -283,7 +283,8 @@ public class MapEditorDialog extends Dialog implements Disposable{ } } player.set(world.width() * tilesize/2f, world.height() * tilesize/2f); - player.setDead(false); + //TODO figure out how to kill player + //player.dead(false); logic.play(); }); } @@ -295,7 +296,8 @@ public class MapEditorDialog extends Dialog implements Disposable{ editor.getTags().put("rules", JsonIO.write(state.rules)); editor.getTags().remove("width"); editor.getTags().remove("height"); - player.dead = true; + //TODO unkill player + //player.dead = true; Map returned = null; diff --git a/core/src/mindustry/editor/MapGenerateDialog.java b/core/src/mindustry/editor/MapGenerateDialog.java index da32ad259b..7c90d10548 100644 --- a/core/src/mindustry/editor/MapGenerateDialog.java +++ b/core/src/mindustry/editor/MapGenerateDialog.java @@ -124,7 +124,7 @@ public class MapGenerateDialog extends FloatingDialog{ Tile tile = editor.tile(x, y); input.apply(x, y, tile.floor(), tile.block(), tile.overlay()); filter.apply(input); - writeTiles[x][y].set(input.floor, input.block, input.ore, tile.getTeam(), tile.rotation()); + writeTiles[x][y].set(input.floor, input.block, input.ore, tile.team(), tile.rotation()); } } @@ -424,7 +424,7 @@ public class MapGenerateDialog extends FloatingDialog{ } public GenTile set(Tile other){ - set(other.floor(), other.block(), other.overlay(), other.getTeam(), other.rotation()); + set(other.floor(), other.block(), other.overlay(), other.team(), other.rotation()); return this; } diff --git a/core/src/mindustry/editor/MapRenderer.java b/core/src/mindustry/editor/MapRenderer.java index 2bd889006c..07ef0c1c5c 100644 --- a/core/src/mindustry/editor/MapRenderer.java +++ b/core/src/mindustry/editor/MapRenderer.java @@ -111,7 +111,7 @@ public class MapRenderer implements Disposable{ IndexedRenderer mesh = chunks[x][y]; Tile tile = editor.tiles().getn(wx, wy); - Team team = tile.getTeam(); + Team team = tile.team(); Block floor = tile.floor(); Block wall = tile.block(); diff --git a/core/src/mindustry/editor/WaveInfoDialog.java b/core/src/mindustry/editor/WaveInfoDialog.java index 50ee9de42e..fd885fabf1 100644 --- a/core/src/mindustry/editor/WaveInfoDialog.java +++ b/core/src/mindustry/editor/WaveInfoDialog.java @@ -30,7 +30,7 @@ public class WaveInfoDialog extends FloatingDialog{ private Table table, preview; private int start = 0; - private UnitType lastType = UnitTypes.dagger; + private UnitDef lastType = UnitTypes.dagger; private float updateTimer, updatePeriod = 1f; public WaveInfoDialog(MapEditor editor){ @@ -221,7 +221,7 @@ public class WaveInfoDialog extends FloatingDialog{ dialog.setFillParent(true); dialog.cont.pane(p -> { int i = 0; - for(UnitType type : content.units()){ + for(UnitDef type : content.units()){ p.addButton(t -> { t.left(); t.addImage(type.icon(mindustry.ui.Cicon.medium)).size(40f).padRight(2f); @@ -256,7 +256,7 @@ public class WaveInfoDialog extends FloatingDialog{ for(int j = 0; j < spawned.length; j++){ if(spawned[j] > 0){ - UnitType type = content.getByID(ContentType.unit, j); + UnitDef type = content.getByID(ContentType.unit, j); table.addImage(type.icon(Cicon.medium)).size(8f * 4f).padRight(4); table.add(spawned[j] + "x").color(Color.lightGray).padRight(6); table.row(); diff --git a/core/src/mindustry/entities/AllEntities.java b/core/src/mindustry/entities/AllEntities.java new file mode 100644 index 0000000000..e7b4e159ca --- /dev/null +++ b/core/src/mindustry/entities/AllEntities.java @@ -0,0 +1,56 @@ +package mindustry.entities; + +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +class AllEntities{ + + @EntityDef(value = {Bulletc.class, Velc.class, Timedc.class}, pooled = true) + class BulletDef{} + + @EntityDef(value = {Tilec.class}, isFinal = false) + class TileDef{} + + @EntityDef(value = {StandardEffectc.class, Childc.class}, pooled = true) + class EffectDef{} + + @EntityDef(value = {GroundEffectc.class, Childc.class}, pooled = true) + class GroundEffectDef{} + + @EntityDef(value = {Decalc.class}, pooled = true) + class DecalDef{} + + @EntityDef({Playerc.class}) + class PlayerDef{} + + @EntityDef({Unitc.class}) + class GenericUnitDef{} + + @EntityDef(value = {Firec.class}, pooled = true) + class FireDef{} + + @GroupDef(Entityc.class) + void all(){ + + } + + @GroupDef(Playerc.class) + void player(){ + + } + + @GroupDef(value = Unitc.class, spatial = true) + void unit(){ + + } + + @GroupDef(Tilec.class) + void tile(){ + + } + + @GroupDef(Syncc.class) + void sync(){ + + } +} diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java index 335ac96385..b1a70219c1 100644 --- a/core/src/mindustry/entities/Damage.java +++ b/core/src/mindustry/entities/Damage.java @@ -1,17 +1,14 @@ package mindustry.entities; import arc.*; -import mindustry.annotations.Annotations.*; -import arc.struct.*; import arc.func.*; import arc.graphics.*; import arc.math.*; import arc.math.geom.*; +import arc.struct.*; import arc.util.*; +import mindustry.annotations.Annotations.*; import mindustry.content.*; -import mindustry.entities.Effects.*; -import mindustry.entities.effect.*; -import mindustry.entities.type.*; import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.gen.*; @@ -33,12 +30,11 @@ public class Damage{ public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, Color color){ for(int i = 0; i < Mathf.clamp(power / 20, 0, 6); i++){ int branches = 5 + Mathf.clamp((int)(power / 30), 1, 20); - Time.run(i * 2f + Mathf.random(4f), () -> Lightning.create(Team.derelict, Pal.power, 3, - x, y, Mathf.random(360f), branches + Mathf.range(2))); + Time.run(i * 2f + Mathf.random(4f), () -> Lightning.create(Team.derelict, Pal.power, 3, x, y, Mathf.random(360f), branches + Mathf.range(2))); } for(int i = 0; i < Mathf.clamp(flammability / 4, 0, 30); i++){ - Time.run(i / 2f, () -> Call.createBullet(Bullets.fireball, Team.derelict, x, y, Mathf.random(360f), 1, 1)); + Time.run(i / 2f, () -> Call.createBullet(Bullets.fireball, Team.derelict, x, y, -1f, Mathf.random(360f), 1, 1)); } int waves = Mathf.clamp((int)(explosiveness / 4), 0, 30); @@ -47,21 +43,21 @@ public class Damage{ int f = i; Time.run(i * 2f, () -> { Damage.damage(x, y, Mathf.clamp(radius + explosiveness, 0, 50f) * ((f + 1f) / waves), explosiveness / 2f); - Effects.effect(Fx.blockExplosionSmoke, x + Mathf.range(radius), y + Mathf.range(radius)); + Fx.blockExplosionSmoke.at(x + Mathf.range(radius), y + Mathf.range(radius)); }); } if(explosiveness > 15f){ - Effects.effect(Fx.shockwave, x, y); + Fx.shockwave.at(x, y); } if(explosiveness > 30f){ - Effects.effect(Fx.bigShockwave, x, y); + Fx.bigShockwave.at(x, y); } float shake = Math.min(explosiveness / 4f + 3f, 9f); Effects.shake(shake, shake, x, y); - Effects.effect(Fx.dynamicExplosion, x, y, radius / 8f); + Fx.dynamicExplosion.at(x, y, radius / 8f); } public static void createIncend(float x, float y, float range, int amount){ @@ -70,12 +66,13 @@ public class Damage{ float cy = y + Mathf.range(range); Tile tile = world.tileWorld(cx, cy); if(tile != null){ - Fire.create(tile); + //TODO uncomment + //Fire.create(tile); } } } - public static void collideLine(Bullet hitter, Team team, Effect effect, float x, float y, float angle, float length){ + public static void collideLine(Bulletc hitter, Team team, Effect effect, float x, float y, float angle, float length){ collideLine(hitter, team, effect, x, y, angle, length, false); } @@ -83,7 +80,7 @@ public class Damage{ * Damages entities in a line. * Only enemies of the specified team are damaged. */ - public static void collideLine(Bullet hitter, Team team, Effect effect, float x, float y, float angle, float length, boolean large){ + public static void collideLine(Bulletc hitter, Team team, Effect effect, float x, float y, float angle, float length, boolean large){ collidedBlocks.clear(); tr.trns(angle, length); Intc2 collider = (cx, cy) -> { @@ -91,7 +88,7 @@ public class Damage{ if(tile != null && !collidedBlocks.contains(tile.pos()) && tile.entity != null && tile.getTeamID() != team.id && tile.entity.collide(hitter)){ tile.entity.collision(hitter); collidedBlocks.add(tile.pos()); - hitter.getBulletType().hit(hitter, tile.worldx(), tile.worldy()); + hitter.type().hit(hitter, tile.worldx(), tile.worldy()); } }; @@ -125,7 +122,7 @@ public class Damage{ rect.width += expand * 2; rect.height += expand * 2; - Cons cons = e -> { + Cons cons = e -> { e.hitbox(hitrect); Rect other = hitrect; other.y -= expand; @@ -136,7 +133,7 @@ public class Damage{ Vec2 vec = Geometry.raycastRect(x, y, x2, y2, other); if(vec != null){ - Effects.effect(effect, vec.x, vec.y); + effect.at(vec.x, vec.y); e.collision(hitter, vec.x, vec.y); hitter.collision(e, vec.x, vec.y); } @@ -146,8 +143,8 @@ public class Damage{ } /** Damages all entities and blocks in a radius that are enemies of the team. */ - public static void damageUnits(Team team, float x, float y, float size, float damage, Boolf predicate, Cons acceptor){ - Cons cons = entity -> { + public static void damageUnits(Team team, float x, float y, float size, float damage, Boolf predicate, Cons acceptor){ + Cons cons = entity -> { if(!predicate.get(entity)) return; entity.hitbox(hitrect); @@ -178,15 +175,15 @@ public class Damage{ /** Damages all entities and blocks in a radius that are enemies of the team. */ public static void damage(Team team, float x, float y, float radius, float damage, boolean complete){ - Cons cons = entity -> { - if(entity.getTeam() == team || entity.dst(x, y) > radius){ + Cons cons = entity -> { + if(entity.team() == team || entity.dst(x, y) > radius){ return; } - float amount = calculateDamage(x, y, entity.x, entity.y, radius, damage); + float amount = calculateDamage(x, y, entity.getX(), entity.getY(), radius, damage); entity.damage(amount); //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())); + float dst = tr.set(entity.getX() - x, entity.getY() - y).len(); + entity.vel().add(tr.setLength((1f - dst / radius) * 2f / entity.mass())); if(complete && damage >= 9999999f && entity == player){ Events.fire(Trigger.exclusionDeath); @@ -236,9 +233,9 @@ public class Damage{ if(scaledDamage <= 0 || tile == null) continue; //apply damage to entity if needed - if(tile.entity != null && tile.getTeam() != team){ - int health = (int)tile.entity.health; - if(tile.entity.health > 0){ + if(tile.entity != null && tile.team() != team){ + int health = (int)tile.entity.health(); + if(tile.entity.health() > 0){ tile.entity.damage(scaledDamage); scaledDamage -= health; @@ -259,7 +256,7 @@ public class Damage{ for(int dx = -trad; dx <= trad; dx++){ for(int dy = -trad; dy <= trad; dy++){ Tile tile = world.tile(Math.round(x / tilesize) + dx, Math.round(y / tilesize) + dy); - if(tile != null && tile.entity != null && (team == null ||team.isEnemy(tile.getTeam())) && Mathf.dst(dx, dy) <= trad){ + if(tile != null && tile.entity != null && (team == null ||team.isEnemy(tile.team())) && Mathf.dst(dx, dy) <= trad){ tile.entity.damage(damage); } } diff --git a/core/src/mindustry/entities/Effect.java b/core/src/mindustry/entities/Effect.java new file mode 100644 index 0000000000..b1dd73ed69 --- /dev/null +++ b/core/src/mindustry/entities/Effect.java @@ -0,0 +1,118 @@ +package mindustry.entities; + +import arc.func.*; +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.math.*; +import arc.math.geom.*; + +public class Effect{ + private static final EffectContainer container = new EffectContainer(); + private static int lastid = 0; + + public final int id; + public final Cons renderer; + public final float lifetime; + /** Clip size. */ + public float size; + + public boolean ground; + public float groundDuration; + + public Effect(float life, float clipsize, Cons renderer){ + this.id = lastid++; + this.lifetime = life; + this.renderer = renderer; + this.size = clipsize; + } + + public Effect(float life, Cons renderer){ + this(life, 28f, renderer); + } + + public Effect ground(){ + ground = true; + return this; + } + + public Effect ground(float duration){ + ground = true; + this.groundDuration = duration; + return this; + } + + public void at(Position pos){ + Effects.create(this, pos.getX(), pos.getY(), 0, Color.white, null); + } + + public void at(Position pos, float rotation){ + Effects.create(this, pos.getX(), pos.getY(), rotation, Color.white, null); + } + + public void at(float x, float y){ + Effects.create(this, x, y, 0, Color.white, null); + } + + public void at(float x, float y, float rotation){ + Effects.create(this, x, y, rotation, Color.white, null); + } + + public void at(float x, float y, float rotation, Color color){ + Effects.create(this, x, y, rotation, color, null); + } + + public void at(float x, float y, Color color){ + Effects.create(this, x, y, 0, color, null); + } + + public void at(float x, float y, float rotation, Color color, Object data){ + Effects.create(this, x, y, rotation, color, data); + } + + public void at(float x, float y, float rotation, Object data){ + Effects.create(this, x, y, rotation, Color.white, data); + } + + public void render(int id, Color color, float life, float rotation, float x, float y, Object data){ + container.set(id, color, life, lifetime, rotation, x, y, data); + renderer.get(container); + Draw.reset(); + } + + public static class EffectContainer implements Scaled{ + public float x, y, time, lifetime, rotation; + public Color color; + public int id; + public Object data; + private EffectContainer innerContainer; + + public void set(int id, Color color, float life, float lifetime, float rotation, float x, float y, Object data){ + this.x = x; + this.y = y; + this.color = color; + this.time = life; + this.lifetime = lifetime; + this.id = id; + this.rotation = rotation; + this.data = data; + } + + public T data(){ + return (T)data; + } + + public void scaled(float lifetime, Cons cons){ + if(innerContainer == null) innerContainer = new EffectContainer(); + if(time <= lifetime){ + innerContainer.set(id, color, time, lifetime, rotation, x, y, data); + cons.get(innerContainer); + } + } + + @Override + public float fin(){ + return time / lifetime; + } + } + +} \ No newline at end of file diff --git a/core/src/mindustry/entities/Effects.java b/core/src/mindustry/entities/Effects.java index 6f2a04033a..911cbadb83 100644 --- a/core/src/mindustry/entities/Effects.java +++ b/core/src/mindustry/entities/Effects.java @@ -1,91 +1,24 @@ package mindustry.entities; -import arc.Core; -import arc.struct.Array; -import arc.func.Cons; -import arc.graphics.Color; +import arc.*; +import arc.graphics.*; import arc.graphics.g2d.*; -import arc.math.Mathf; -import arc.math.geom.Position; -import arc.util.pooling.Pools; -import mindustry.entities.type.EffectEntity; -import mindustry.entities.traits.ScaleTrait; +import arc.math.*; +import arc.math.geom.*; +import arc.util.*; +import mindustry.content.*; +import mindustry.gen.*; +import mindustry.graphics.*; + +import static mindustry.Vars.*; public class Effects{ - private static final EffectContainer container = new EffectContainer(); - private static Array effects = new Array<>(); - private static ScreenshakeProvider shakeProvider; - private static float shakeFalloff = 10000f; - private static EffectProvider provider = (effect, color, x, y, rotation, data) -> { - EffectEntity entity = Pools.obtain(EffectEntity.class, EffectEntity::new); - entity.effect = effect; - entity.color = color; - entity.rotation = rotation; - entity.data = data; - entity.set(x, y); - entity.add(); - }; - - public static void setEffectProvider(EffectProvider prov){ - provider = prov; - } - - public static void setScreenShakeProvider(ScreenshakeProvider provider){ - shakeProvider = provider; - } - - public static void renderEffect(int id, Effect render, Color color, float life, float rotation, float x, float y, Object data){ - container.set(id, color, life, render.lifetime, rotation, x, y, data); - render.draw.render(container); - Draw.reset(); - } - - public static Effect getEffect(int id){ - if(id >= effects.size || id < 0) - throw new IllegalArgumentException("The effect with ID \"" + id + "\" does not exist!"); - return effects.get(id); - } - - public static Array all(){ - return effects; - } - - public static void effect(Effect effect, float x, float y, float rotation){ - provider.createEffect(effect, Color.white, x, y, rotation, null); - } - - public static void effect(Effect effect, float x, float y){ - effect(effect, x, y, 0); - } - - public static void effect(Effect effect, Color color, float x, float y){ - provider.createEffect(effect, color, x, y, 0f, null); - } - - public static void effect(Effect effect, Position loc){ - 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){ - provider.createEffect(effect, color, x, y, rotation, null); - } - - public static void effect(Effect effect, Color color, float x, float y, float rotation, Object data){ - provider.createEffect(effect, color, x, y, rotation, data); - } - - public static void effect(Effect effect, float x, float y, float rotation, Object data){ - provider.createEffect(effect, Color.white, x, y, rotation, data); - } - - /** Default value is 1000. Higher numbers mean more powerful shake (less falloff). */ - public static void setShakeFalloff(float falloff){ - shakeFalloff = falloff; - } + private static final float shakeFalloff = 10000f; private static void shake(float intensity, float duration){ - if(shakeProvider == null) throw new RuntimeException("Screenshake provider is null! Set it first."); - shakeProvider.accept(intensity, duration); + if(!headless){ + renderer.shake(intensity, duration); + } } public static void shake(float intensity, float duration, float x, float y){ @@ -101,68 +34,52 @@ public class Effects{ shake(intensity, duration, loc.getX(), loc.getY()); } - public interface ScreenshakeProvider{ - void accept(float intensity, float duration); - } + public static void create(Effect effect, float x, float y, float rotation, Color color, Object data){ + if(headless || effect == Fx.none) return; + if(Core.settings.getBool("effects")){ + Rect view = Core.camera.bounds(Tmp.r1); + Rect pos = Tmp.r2.setSize(effect.size).setCenter(x, y); - public static class Effect{ - private static int lastid = 0; - public final int id; - public final EffectRenderer draw; - public final float lifetime; - /** Clip size. */ - public float size; - - public Effect(float life, float clipsize, EffectRenderer draw){ - this.id = lastid++; - this.lifetime = life; - this.draw = draw; - this.size = clipsize; - effects.add(this); - } - - public Effect(float life, EffectRenderer draw){ - this(life, 28f, draw); - } - } - - public static class EffectContainer implements ScaleTrait{ - public float x, y, time, lifetime, rotation; - public Color color; - public int id; - public Object data; - private EffectContainer innerContainer; - - public void set(int id, Color color, float life, float lifetime, float rotation, float x, float y, Object data){ - this.x = x; - this.y = y; - this.color = color; - this.time = life; - this.lifetime = lifetime; - this.id = id; - this.rotation = rotation; - this.data = data; - } - - public void scaled(float lifetime, Cons cons){ - if(innerContainer == null) innerContainer = new EffectContainer(); - if(time <= lifetime){ - innerContainer.set(id, color, time, lifetime, rotation, x, y, data); - cons.get(innerContainer); + if(view.overlaps(pos)){ + Effectc entity = effect.ground ? GroundEffectEntity.create() : EffectEntity.create(); + entity.effect(effect); + entity.rotation(rotation); + entity.data(data); + entity.lifetime(effect.lifetime); + entity.set(x, y); + entity.color().set(color); + if(data instanceof Posc) entity.parent((Posc)data); + entity.add(); } } - - @Override - public float fin(){ - return time / lifetime; - } } - public interface EffectProvider{ - void createEffect(Effect effect, Color color, float x, float y, float rotation, Object data); + public static void decal(TextureRegion region, float x, float y, float rotation, float lifetime, Color color){ + if(headless || region == null || !Core.atlas.isFound(region)) return; + + Decalc decal = DecalEntity.create(); + decal.set(x, y); + decal.rotation(rotation); + decal.lifetime(lifetime); + decal.color().set(color); + decal.region(region); + decal.add(); } - public interface EffectRenderer{ - void render(EffectContainer effect); + public static void scorch(float x, float y, int size){ + if(headless) return; + + size = Mathf.clamp(size, 0, 9); + + TextureRegion region = Core.atlas.find("scorch-" + size + "-" + Mathf.random(2)); + decal(region, x, y, Mathf.random(4) * 90, 3600, Pal.rubble); + + } + + public static void rubble(float x, float y, int blockSize){ + if(headless) return; + + TextureRegion region = Core.atlas.find("rubble-" + blockSize + "-" + (Core.atlas.has("rubble-" + blockSize + "-1") ? Mathf.random(0, 1) : "0")); + decal(region, x, y, Mathf.random(4) * 90, 3600, Pal.rubble); } } diff --git a/core/src/mindustry/entities/Entities.java b/core/src/mindustry/entities/Entities.java deleted file mode 100755 index 022af6b95d..0000000000 --- a/core/src/mindustry/entities/Entities.java +++ /dev/null @@ -1,33 +0,0 @@ -package mindustry.entities; - -import arc.struct.*; -import mindustry.entities.traits.*; - -/** Simple container for managing entity groups.*/ -public class Entities{ - private final Array> groupArray = new Array<>(); - - public void clear(){ - for(EntityGroup group : groupArray){ - group.clear(); - } - } - - public EntityGroup get(int id){ - return groupArray.get(id); - } - - public Array> all(){ - return groupArray; - } - - public EntityGroup add(Class type){ - return add(type, true); - } - - public EntityGroup add(Class type, boolean useTree){ - EntityGroup group = new EntityGroup<>(groupArray.size, type, useTree); - groupArray.add(group); - return group; - } -} diff --git a/core/src/mindustry/entities/EntityCollisions.java b/core/src/mindustry/entities/EntityCollisions.java index 72e177d71e..58820a113f 100644 --- a/core/src/mindustry/entities/EntityCollisions.java +++ b/core/src/mindustry/entities/EntityCollisions.java @@ -1,14 +1,13 @@ package mindustry.entities; -import arc.struct.Array; -import arc.math.Mathf; +import arc.math.*; import arc.math.geom.*; -import mindustry.entities.traits.Entity; -import mindustry.entities.traits.SolidTrait; -import mindustry.world.Tile; +import arc.struct.*; +import arc.util.*; +import mindustry.gen.*; +import mindustry.world.*; -import static mindustry.Vars.tilesize; -import static mindustry.Vars.world; +import static mindustry.Vars.*; public class EntityCollisions{ //range for tile collision scanning @@ -24,15 +23,19 @@ public class EntityCollisions{ private Rect r2 = new Rect(); //entity collisions - private Array arrOut = new Array<>(); + private Array arrOut = new Array<>(); - public void move(SolidTrait entity, float deltax, float deltay){ + public void move(Hitboxc entity, float deltax, float deltay){ + move(entity, deltax, deltay, EntityCollisions::solid); + } + + public void move(Hitboxc entity, float deltax, float deltay, SolidPred solidCheck){ boolean movedx = false; while(Math.abs(deltax) > 0 || !movedx){ movedx = true; - moveDelta(entity, Math.min(Math.abs(deltax), seg) * Mathf.sign(deltax), 0, true); + moveDelta(entity, Math.min(Math.abs(deltax), seg) * Mathf.sign(deltax), 0, true, solidCheck); if(Math.abs(deltax) >= seg){ deltax -= seg * Mathf.sign(deltax); @@ -45,7 +48,7 @@ public class EntityCollisions{ while(Math.abs(deltay) > 0 || !movedy){ movedy = true; - moveDelta(entity, 0, Math.min(Math.abs(deltay), seg) * Mathf.sign(deltay), false); + moveDelta(entity, 0, Math.min(Math.abs(deltay), seg) * Mathf.sign(deltay), false, solidCheck); if(Math.abs(deltay) >= seg){ deltay -= seg * Mathf.sign(deltay); @@ -55,33 +58,30 @@ public class EntityCollisions{ } } - public void moveDelta(SolidTrait entity, float deltax, float deltay, boolean x){ - - Rect rect = r1; - entity.hitboxTile(rect); + public void moveDelta(Hitboxc entity, float deltax, float deltay, boolean x, SolidPred solidCheck){ + entity.hitboxTile(r1); entity.hitboxTile(r2); - rect.x += deltax; - rect.y += deltay; + r1.x += deltax; + r1.y += deltay; - int tilex = Math.round((rect.x + rect.width / 2) / tilesize), tiley = Math.round((rect.y + rect.height / 2) / tilesize); + int tilex = Math.round((r1.x + r1.width / 2) / tilesize), tiley = Math.round((r1.y + r1.height / 2) / tilesize); for(int dx = -r; dx <= r; dx++){ for(int dy = -r; dy <= r; dy++){ int wx = dx + tilex, wy = dy + tiley; - if(solid(wx, wy) && entity.collidesGrid(wx, wy)){ + if(solidCheck.solid(wx, wy)){ tmp.setSize(tilesize).setCenter(wx * tilesize, wy * tilesize); - if(tmp.overlaps(rect)){ - Vec2 v = Geometry.overlap(rect, tmp, x); - rect.x += v.x; - rect.y += v.y; + if(tmp.overlaps(r1)){ + Vec2 v = Geometry.overlap(r1, tmp, x); + if(x) r1.x += v.x; + if(!x) r1.y += v.y; } } } } - entity.setX(entity.getX() + rect.x - r2.x); - entity.setY(entity.getY() + rect.y - r2.y); + entity.trns(r1.x - r2.x, r1.y - r2.y); } public boolean overlapsTile(Rect rect){ @@ -108,44 +108,43 @@ public class EntityCollisions{ } @SuppressWarnings("unchecked") - public void updatePhysics(EntityGroup group){ + public void updatePhysics(EntityGroup group){ QuadTree tree = group.tree(); tree.clear(); - for(Entity entity : group.all()){ - if(entity instanceof SolidTrait){ - SolidTrait s = (SolidTrait)entity; - s.lastPosition().set(s.getX(), s.getY()); - tree.insert(s); - } - } + group.each(s -> { + s.updateLastPosition(); + tree.insert(s); + }); } - private static boolean solid(int x, int y){ + public static boolean waterSolid(int x, int y){ + Tile tile = world.tile(x, y); + return tile != null && (tile.solid() || !tile.floor().isLiquid); + } + + public static boolean solid(int x, int y){ Tile tile = world.tile(x, y); return tile != null && tile.solid(); } - private void checkCollide(Entity entity, Entity other){ - - SolidTrait a = (SolidTrait)entity; - SolidTrait b = (SolidTrait)other; + private void checkCollide(Hitboxc a, Hitboxc b){ a.hitbox(this.r1); b.hitbox(this.r2); - r1.x += (a.lastPosition().x - a.getX()); - r1.y += (a.lastPosition().y - a.getY()); - r2.x += (b.lastPosition().x - b.getX()); - r2.y += (b.lastPosition().y - b.getY()); + r1.x += (a.lastX() - a.getX()); + r1.y += (a.lastY() - a.getY()); + r2.x += (b.lastX() - b.getX()); + r2.y += (b.lastY() - b.getY()); - float vax = a.getX() - a.lastPosition().x; - float vay = a.getY() - a.lastPosition().y; - float vbx = b.getX() - b.lastPosition().x; - float vby = b.getY() - b.lastPosition().y; + float vax = a.getX() - a.lastX(); + float vay = a.getY() - a.lastY(); + float vbx = b.getX() - b.lastX(); + float vby = b.getY() - b.lastY(); - if(a != b && a.collides(b) && b.collides(a)){ + if(a != b && a.collides(b)){ l1.set(a.getX(), a.getY()); boolean collide = r1.overlaps(r2) || collide(r1.x, r1.y, r1.width, r1.height, vax, vay, r2.x, r2.y, r2.width, r2.height, vbx, vby, l1); @@ -207,17 +206,12 @@ public class EntityCollisions{ } @SuppressWarnings("unchecked") - public void collideGroups(EntityGroup groupa, EntityGroup groupb){ - - for(Entity entity : groupa.all()){ - if(!(entity instanceof SolidTrait)) - continue; - - SolidTrait solid = (SolidTrait)entity; + public void collideGroups(EntityGroup groupa, EntityGroup groupb){ + groupa.each(solid -> { solid.hitbox(r1); - r1.x += (solid.lastPosition().x - solid.getX()); - r1.y += (solid.lastPosition().y - solid.getY()); + r1.x += (solid.lastX() - solid.getX()); + r1.y += (solid.lastY() - solid.getY()); solid.hitbox(r2); r2.merge(r1); @@ -225,12 +219,16 @@ public class EntityCollisions{ arrOut.clear(); groupb.tree().getIntersect(arrOut, r2); - for(SolidTrait sc : arrOut){ + for(Hitboxc sc : arrOut){ sc.hitbox(r1); if(r2.overlaps(r1)){ - checkCollide(entity, sc); + checkCollide(solid, sc); } } - } + }); + } + + public interface SolidPred{ + boolean solid(int x, int y); } } diff --git a/core/src/mindustry/entities/EntityGroup.java b/core/src/mindustry/entities/EntityGroup.java index 24c3f0e4f0..40953d1847 100644 --- a/core/src/mindustry/entities/EntityGroup.java +++ b/core/src/mindustry/entities/EntityGroup.java @@ -1,11 +1,10 @@ package mindustry.entities; import arc.*; -import arc.struct.*; import arc.func.*; -import arc.graphics.*; import arc.math.geom.*; -import mindustry.entities.traits.*; +import arc.struct.*; +import mindustry.gen.*; import java.util.*; @@ -13,128 +12,78 @@ import static mindustry.Vars.collisions; /** Represents a group of a certain type of entity.*/ @SuppressWarnings("unchecked") -public class EntityGroup implements Iterable{ - private final boolean useTree; - private final int id; - private final Class type; - private final Array entityArray = new Array<>(false, 32); - private final Array entitiesToRemove = new Array<>(false, 32); - private final Array entitiesToAdd = new Array<>(false, 32); +public class EntityGroup implements Iterable{ + private static int lastId = 0; + + private final Array array; private final Array intersectArray = new Array<>(); + private final Rect viewport = new Rect(); private final Rect intersectRect = new Rect(); private IntMap map; private QuadTree tree; - private Cons removeListener; - private Cons addListener; + private boolean clearing; - private final Rect viewport = new Rect(); - private int count = 0; + private int index; - public EntityGroup(int id, Class type, boolean useTree){ - this.useTree = useTree; - this.id = id; - this.type = type; + public static int nextId(){ + return lastId++; + } - if(useTree){ + public EntityGroup(Class type, boolean spatial, boolean mapping){ + array = new Array<>(false, 32, type); + + if(spatial){ tree = new QuadTree<>(new Rect(0, 0, 0, 0)); } + + if(mapping){ + map = new IntMap<>(); + } + } + + public void sort(Comparator comp){ + array.sort(comp); + } + + public void updatePhysics(){ + collisions.updatePhysics((EntityGroup)this); } public void update(){ - updateEvents(); + each(Entityc::update); + } - if(useTree()){ - collisions.updatePhysics(this); - } - - for(Entity e : all()){ - e.update(); + public void each(Cons cons){ + for(index = 0; index < array.size; index++){ + cons.get(array.items[index]); } } - public int countInBounds(){ - count = 0; - draw(e -> true, e -> count++); - return count; + public void each(Boolf filter, Cons cons){ + for(index = 0; index < array.size; index++){ + if(filter.get(array.items[index])) cons.get(array.items[index]); + } } - public void draw(){ - draw(e -> true); - } + public void draw(Cons cons){ + Core.camera.bounds(viewport); - public void draw(Boolf toDraw){ - draw(toDraw, t -> ((DrawTrait)t).draw()); - } - - public void draw(Boolf toDraw, Cons cons){ - Camera cam = Core.camera; - viewport.set(cam.position.x - cam.width / 2, cam.position.y - cam.height / 2, cam.width, cam.height); - - for(Entity e : all()){ - if(!(e instanceof DrawTrait) || !toDraw.get((T)e) || !e.isAdded()) continue; - DrawTrait draw = (DrawTrait)e; - - if(viewport.overlaps(draw.getX() - draw.drawSize()/2f, draw.getY() - draw.drawSize()/2f, draw.drawSize(), draw.drawSize())){ - cons.get((T)e); + each(e -> { + Drawc draw = (Drawc)e; + if(viewport.overlaps(draw.x() - draw.clipSize()/2f, draw.y() - draw.clipSize()/2f, draw.clipSize(), draw.clipSize())){ + cons.get(e); } - } + }); } public boolean useTree(){ - return useTree; - } - - public void setRemoveListener(Cons removeListener){ - this.removeListener = removeListener; - } - - public void setAddListener(Cons addListener){ - this.addListener = addListener; - } - - public EntityGroup enableMapping(){ - map = new IntMap<>(); - return this; + return map != null; } public boolean mappingEnabled(){ return map != null; } - public Class getType(){ - return type; - } - - public int getID(){ - return id; - } - - public void updateEvents(){ - - for(T e : entitiesToAdd){ - if(e == null) - continue; - entityArray.add(e); - e.added(); - - if(map != null){ - map.put(e.getID(), e); - } - } - - entitiesToAdd.clear(); - - for(T e : entitiesToRemove){ - entityArray.removeValue(e, true); - if(map != null){ - map.remove(e.getID()); - } - e.removed(); - } - - entitiesToRemove.clear(); - } - public T getByID(int id){ if(map == null) throw new RuntimeException("Mapping is not enabled for group " + id + "!"); return map.get(id); @@ -145,16 +94,6 @@ public class EntityGroup implements Iterable{ T t = map.get(id); if(t != null){ //remove if present in map already remove(t); - }else{ //maybe it's being queued? - for(T check : entitiesToAdd){ - if(check.getID() == id){ //if it is indeed queued, remove it - entitiesToAdd.removeValue(check, true); - if(removeListener != null){ - removeListener.get(check); - } - break; - } - } } } @@ -175,93 +114,73 @@ public class EntityGroup implements Iterable{ } public QuadTree tree(){ - if(!useTree) throw new RuntimeException("This group does not support quadtrees! Enable quadtrees when creating it."); + if(tree == null) throw new RuntimeException("This group does not support quadtrees! Enable quadtrees when creating it."); return tree; } /** Resizes the internal quadtree, if it is enabled.*/ public void resize(float x, float y, float w, float h){ - if(useTree){ + if(tree != null){ tree = new QuadTree<>(new Rect(x, y, w, h)); } } public boolean isEmpty(){ - return entityArray.size == 0; + return array.size == 0; } public int size(){ - return entityArray.size; + return array.size; + } + + public boolean contains(Boolf pred){ + return array.contains(pred); } public int count(Boolf pred){ - int count = 0; - for(int i = 0; i < entityArray.size; i++){ - if(pred.get(entityArray.get(i))) count++; - } - return count; + return array.count(pred); } public void add(T type){ if(type == null) throw new RuntimeException("Cannot add a null entity!"); - if(type.getGroup() != null) return; - type.setGroup(this); - entitiesToAdd.add(type); + array.add(type); if(mappingEnabled()){ - map.put(type.getID(), type); - } - - if(addListener != null){ - addListener.get(type); + map.put(type.id(), type); } } public void remove(T type){ + if(clearing) return; if(type == null) throw new RuntimeException("Cannot remove a null entity!"); - type.setGroup(null); - entitiesToRemove.add(type); + int idx = array.indexOf(type, true); + if(idx != -1){ + array.remove(idx); - if(removeListener != null){ - removeListener.get(type); + //fix iteration index when removing + if(index >= idx){ + index --; + } } } public void clear(){ - for(T entity : entityArray){ - entity.removed(); - entity.setGroup(null); - } + clearing = true; - for(T entity : entitiesToAdd) - entity.setGroup(null); - - for(T entity : entitiesToRemove) - entity.setGroup(null); - - entitiesToAdd.clear(); - entitiesToRemove.clear(); - entityArray.clear(); + array.each(Entityc::remove); + array.clear(); if(map != null) map.clear(); + + clearing = false; } public T find(Boolf pred){ - - for(int i = 0; i < entityArray.size; i++){ - if(pred.get(entityArray.get(i))) return entityArray.get(i); - } - - return null; - } - - /** Returns the array for iteration. */ - public Array all(){ - return entityArray; + return array.find(pred); } @Override public Iterator iterator(){ - return entityArray.iterator(); + return array.iterator(); } } diff --git a/core/src/mindustry/entities/Lightning.java b/core/src/mindustry/entities/Lightning.java new file mode 100644 index 0000000000..df9cdd9b61 --- /dev/null +++ b/core/src/mindustry/entities/Lightning.java @@ -0,0 +1,86 @@ +package mindustry.entities; + +import arc.graphics.*; +import arc.math.*; +import arc.math.geom.*; +import arc.struct.*; +import mindustry.content.*; +import mindustry.game.*; +import mindustry.gen.*; +import mindustry.world.*; + +import static mindustry.Vars.*; + +//TODO move into a different class +public class Lightning{ + private static final Rand random = new Rand(); + private static final Rect rect = new Rect(); + private static final Array entities = new Array<>(); + private static final IntSet hit = new IntSet(); + private static final int maxChain = 8; + private static final float hitRange = 30f; + private static boolean bhit = false; + private static int lastSeed = 0; + + /** Create a lighting branch at a location. Use Team.none to damage everyone. */ + public static void create(Team team, Color color, float damage, float x, float y, float targetAngle, int length){ + createLightingInternal(lastSeed++, team, color, damage, x, y, targetAngle, length); + } + + //TODO remote method + //@Remote(called = Loc.server, unreliable = true) + private static void createLightingInternal(int seed, Team team, Color color, float damage, float x, float y, float rotation, int length){ + random.setSeed(seed); + hit.clear(); + + Array lines = new Array<>(); + bhit = false; + + for(int i = 0; i < length / 2; i++){ + Bullets.damageLightning.create(null, team, x, y, 0f, damage, 1f, 1f, null); + lines.add(new Vec2(x + Mathf.range(3f), y + Mathf.range(3f))); + + if(lines.size > 1){ + bhit = false; + Vec2 from = lines.get(lines.size - 2); + Vec2 to = lines.get(lines.size - 1); + world.raycastEach(world.toTile(from.getX()), world.toTile(from.getY()), world.toTile(to.getX()), world.toTile(to.getY()), (wx, wy) -> { + + Tile tile = world.ltile(wx, wy); + if(tile != null && tile.block().insulated){ + bhit = true; + //snap it instead of removing + lines.get(lines.size -1).set(wx * tilesize, wy * tilesize); + return true; + } + return false; + }); + if(bhit) break; + } + + rect.setSize(hitRange).setCenter(x, y); + entities.clear(); + if(hit.size < maxChain){ + Units.nearbyEnemies(team, rect, u -> { + if(!hit.contains(u.id())){ + entities.add(u); + } + }); + } + + Unitc furthest = Geometry.findFurthest(x, y, entities); + + if(furthest != null){ + hit.add(furthest.id()); + x = furthest.x(); + y = furthest.y(); + }else{ + rotation += random.range(20f); + x += Angles.trnsx(rotation, hitRange / 2f); + y += Angles.trnsy(rotation, hitRange / 2f); + } + } + + Fx.lightning.at(x, y, rotation, color, lines); + } +} diff --git a/core/src/mindustry/entities/Predict.java b/core/src/mindustry/entities/Predict.java index c541771829..e9646a6eeb 100644 --- a/core/src/mindustry/entities/Predict.java +++ b/core/src/mindustry/entities/Predict.java @@ -3,7 +3,7 @@ package mindustry.entities; import arc.math.*; import arc.math.geom.*; import arc.util.*; -import mindustry.entities.traits.*; +import mindustry.gen.*; /** * Class for predicting shoot angles based on velocities of targets. @@ -51,11 +51,24 @@ public class Predict{ return sol; } + public static Vec2 intercept(Position src, Hitboxc dst, float v){ + return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.deltaX(), dst.deltaY(), v); + } + + public static Vec2 intercept(Position src, Position dst, float v){ + float ddx = 0, ddy = 0; + if(dst instanceof Hitboxc){ + ddx = ((Hitboxc)dst).deltaX(); + ddy = ((Hitboxc)dst).deltaY(); + } + return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), ddx, ddy, v); + } + /** * See {@link #intercept(float, float, float, float, float, float, float)}. */ - public static Vec2 intercept(TargetTrait src, TargetTrait dst, float v){ - return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.getTargetVelocityX() - src.getTargetVelocityX()/(2f*Time.delta()), dst.getTargetVelocityY() - src.getTargetVelocityY()/(2f*Time.delta()), v); + public static Vec2 intercept(Hitboxc src, Hitboxc dst, float v){ + return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), dst.deltaX() - src.deltaX()/(2f*Time.delta()), dst.deltaY() - src.deltaX()/(2f*Time.delta()), v); } private static Vec2 quad(float a, float b, float c){ diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java index 67fe01dc9e..9c8bc16f20 100644 --- a/core/src/mindustry/entities/Units.java +++ b/core/src/mindustry/entities/Units.java @@ -1,11 +1,9 @@ package mindustry.entities; import arc.func.*; -import arc.math.*; import arc.math.geom.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; import mindustry.game.*; +import mindustry.gen.*; import mindustry.world.*; import static mindustry.Vars.*; @@ -13,13 +11,13 @@ import static mindustry.Vars.*; /** Utility class for unit and team interactions.*/ public class Units{ private static Rect hitrect = new Rect(); - private static Unit result; + private static Unitc result; private static float cdist; private static boolean boolResult; /** @return whether this player can interact with a specific tile. if either of these are null, returns true.*/ - public static boolean canInteract(Player player, Tile tile){ - return player == null || tile == null || tile.interactable(player.getTeam()); + public static boolean canInteract(Playerc player, Tile tile){ + return player == null || tile == null || tile.interactable(player.team()); } /** @@ -31,18 +29,18 @@ public class Units{ * @param range The maximum distance from the target X/Y the targeter can be for it to be valid * @return whether the target is invalid */ - public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y, float range){ - return target == null || (range != Float.MAX_VALUE && !target.withinDst(x, y, range)) || target.getTeam() == team || !target.isValid(); + public static boolean invalidateTarget(Teamc target, Team team, float x, float y, float range){ + return target == null || (range != Float.MAX_VALUE && !target.withinDst(x, y, range)) || target.team() == team || (target instanceof Healthc && !((Healthc)target).isValid()); } - /** See {@link #invalidateTarget(TargetTrait, Team, float, float, float)} */ - public static boolean invalidateTarget(TargetTrait target, Team team, float x, float y){ + /** See {@link #invalidateTarget(Teamc, Team, float, float, float)} */ + public static boolean invalidateTarget(Teamc target, Team team, float x, float y){ return invalidateTarget(target, team, x, y, Float.MAX_VALUE); } - /** See {@link #invalidateTarget(TargetTrait, Team, float, float, float)} */ - public static boolean invalidateTarget(TargetTrait target, Unit targeter){ - return invalidateTarget(target, targeter.getTeam(), targeter.x, targeter.y, targeter.getWeapon().bullet.range()); + /** See {@link #invalidateTarget(Teamc, Team, float, float, float)} */ + public static boolean invalidateTarget(Teamc target, Unitc targeter, float range){ + return invalidateTarget(target, targeter.team(), targeter.x(), targeter.y(), range); } /** Returns whether there are any entities on this tile. */ @@ -56,7 +54,7 @@ public class Units{ nearby(x, y, width, height, unit -> { if(boolResult) return; - if(!unit.isFlying()){ + if(unit.isGrounded()){ unit.hitbox(hitrect); if(hitrect.overlaps(x, y, width, height)){ @@ -69,38 +67,38 @@ public class Units{ } /** Returns the neareset damaged tile. */ - public static TileEntity findDamagedTile(Team team, float x, float y){ + public static Tilec findDamagedTile(Team team, float x, float y){ Tile tile = Geometry.findClosest(x, y, indexer.getDamaged(team)); return tile == null ? null : tile.entity; } /** Returns the neareset ally tile in a range. */ - public static TileEntity findAllyTile(Team team, float x, float y, float range, Boolf pred){ + public static Tilec findAllyTile(Team team, float x, float y, float range, Boolf pred){ return indexer.findTile(team, x, y, range, pred); } /** Returns the neareset enemy tile in a range. */ - public static TileEntity findEnemyTile(Team team, float x, float y, float range, Boolf pred){ + public static Tilec findEnemyTile(Team team, float x, float y, float range, Boolf pred){ if(team == Team.derelict) return null; return indexer.findEnemyTile(team, x, y, range, pred); } /** Returns the closest target enemy. First, units are checked, then tile entities. */ - public static TargetTrait closestTarget(Team team, float x, float y, float range){ - return closestTarget(team, x, y, range, Unit::isValid); + public static Teamc closestTarget(Team team, float x, float y, float range){ + return closestTarget(team, x, y, range, Unitc::isValid); } /** Returns the closest target enemy. First, units are checked, then tile entities. */ - public static TargetTrait closestTarget(Team team, float x, float y, float range, Boolf unitPred){ + public static Teamc closestTarget(Team team, float x, float y, float range, Boolf unitPred){ return closestTarget(team, x, y, range, unitPred, t -> true); } /** Returns the closest target enemy. First, units are checked, then tile entities. */ - public static TargetTrait closestTarget(Team team, float x, float y, float range, Boolf unitPred, Boolf tilePred){ + public static Teamc closestTarget(Team team, float x, float y, float range, Boolf unitPred, Boolf tilePred){ if(team == Team.derelict) return null; - Unit unit = closestEnemy(team, x, y, range, unitPred); + Unitc unit = closestEnemy(team, x, y, range, unitPred); if(unit != null){ return unit; }else{ @@ -109,16 +107,16 @@ public class Units{ } /** Returns the closest enemy of this team. Filter by predicate. */ - public static Unit closestEnemy(Team team, float x, float y, float range, Boolf predicate){ + public static Unitc closestEnemy(Team team, float x, float y, float range, Boolf predicate){ if(team == Team.derelict) return null; result = null; cdist = 0f; nearbyEnemies(team, x - range, y - range, range*2f, range*2f, e -> { - if(e.isDead() || !predicate.get(e)) return; + if(e.dead() || !predicate.get(e)) return; - float dst2 = Mathf.dst2(e.x, e.y, x, y); + float dst2 = e.dst2(x, y); if(dst2 < range*range && (result == null || dst2 < cdist)){ result = e; cdist = dst2; @@ -129,14 +127,14 @@ public class Units{ } /** Returns the closest ally of this team. Filter by predicate. */ - public static Unit closest(Team team, float x, float y, float range, Boolf predicate){ + public static Unitc closest(Team team, float x, float y, float range, Boolf predicate){ result = null; cdist = 0f; nearby(team, x, y, range, e -> { if(!predicate.get(e)) return; - float dist = Mathf.dst2(e.x, e.y, x, y); + float dist = e.dst2(x, y); if(result == null || dist < cdist){ result = e; cdist = dist; @@ -147,73 +145,45 @@ public class Units{ } /** Iterates over all units in a rectangle. */ - public static void nearby(Team team, float x, float y, float width, float height, Cons cons){ - unitGroup.intersect(x, y, width, height, u -> { - if(u.getTeam() == team){ + public static void nearby(Team team, float x, float y, float width, float height, Cons cons){ + Groups.unit.intersect(x, y, width, height, u -> { + if(u.team() == team){ cons.get(u); } }); - playerGroup.intersect(x, y, width, height, player -> { - if(player.getTeam() == team){ - cons.get(player); - } - }); } /** Iterates over all units in a circle around this position. */ - public static void nearby(Team team, float x, float y, float radius, Cons cons){ - unitGroup.intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> { - if(unit.getTeam() == team && unit.withinDst(x, y, radius)){ - cons.get(unit); - } - }); - - playerGroup.intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> { - if(unit.getTeam() == team && unit.withinDst(x, y, radius)){ + public static void nearby(Team team, float x, float y, float radius, Cons cons){ + Groups.unit.intersect(x - radius, y - radius, radius*2f, radius*2f, unit -> { + if(unit.team() == team && unit.withinDst(x, y, radius)){ cons.get(unit); } }); } /** Iterates over all units in a rectangle. */ - public static void nearby(float x, float y, float width, float height, Cons cons){ - unitGroup.intersect(x, y, width, height, cons); - playerGroup.intersect(x, y, width, height, cons); + public static void nearby(float x, float y, float width, float height, Cons cons){ + Groups.unit.intersect(x, y, width, height, cons); } /** Iterates over all units in a rectangle. */ - public static void nearby(Rect rect, Cons cons){ + public static void nearby(Rect rect, Cons cons){ nearby(rect.x, rect.y, rect.width, rect.height, cons); } /** Iterates over all units that are enemies of this team. */ - public static void nearbyEnemies(Team team, float x, float y, float width, float height, Cons cons){ - unitGroup.intersect(x, y, width, height, u -> { - if(team.isEnemy(u.getTeam())){ + public static void nearbyEnemies(Team team, float x, float y, float width, float height, Cons cons){ + Groups.unit.intersect(x, y, width, height, u -> { + if(team.isEnemy(u.team())){ cons.get(u); } }); - - playerGroup.intersect(x, y, width, height, player -> { - if(team.isEnemy(player.getTeam())){ - cons.get(player); - } - }); } /** Iterates over all units that are enemies of this team. */ - public static void nearbyEnemies(Team team, Rect rect, Cons cons){ + public static void nearbyEnemies(Team team, Rect rect, Cons cons){ nearbyEnemies(team, rect.x, rect.y, rect.width, rect.height, cons); } - /** Iterates over all units. */ - public static void all(Cons cons){ - unitGroup.all().each(cons); - playerGroup.all().each(cons); - } - - public static void each(Team team, Cons cons){ - unitGroup.all().each(t -> t.getTeam() == team, cons); - } - } diff --git a/core/src/mindustry/entities/bullet/ArtilleryBulletType.java b/core/src/mindustry/entities/bullet/ArtilleryBulletType.java index c59dedf99a..6e43b53cee 100644 --- a/core/src/mindustry/entities/bullet/ArtilleryBulletType.java +++ b/core/src/mindustry/entities/bullet/ArtilleryBulletType.java @@ -3,8 +3,6 @@ package mindustry.entities.bullet; import arc.graphics.g2d.*; import mindustry.content.*; import mindustry.entities.*; -import mindustry.entities.Effects.*; -import mindustry.entities.type.Bullet; import mindustry.gen.*; //TODO scale velocity depending on fslope() @@ -25,25 +23,25 @@ public class ArtilleryBulletType extends BasicBulletType{ } @Override - public void update(Bullet b){ + public void update(Bulletc b){ super.update(b); - if(b.timer.get(0, 3 + b.fslope() * 2f)){ - Effects.effect(trailEffect, backColor, b.x, b.y, b.fslope() * 4f); + if(b.timer(0, 3 + b.fslope() * 2f)){ + trailEffect.at(b.x(), b.y(), b.fslope() * 4f, backColor); } } @Override - public void draw(Bullet b){ + public void draw(Bulletc b){ float baseScale = 0.7f; float scale = (baseScale + b.fslope() * (1f - baseScale)); float height = bulletHeight * ((1f - bulletShrink) + bulletShrink * b.fout()); Draw.color(backColor); - Draw.rect(backRegion, b.x, b.y, bulletWidth * scale, height * scale, b.rot() - 90); + Draw.rect(backRegion, b.x(), b.y(), bulletWidth * scale, height * scale, b.rotation() - 90); Draw.color(frontColor); - Draw.rect(frontRegion, b.x, b.y, bulletWidth * scale, height * scale, b.rot() - 90); + Draw.rect(frontRegion, b.x(), b.y(), bulletWidth * scale, height * scale, b.rotation() - 90); Draw.color(); } } diff --git a/core/src/mindustry/entities/bullet/BasicBulletType.java b/core/src/mindustry/entities/bullet/BasicBulletType.java index 44588dedf4..f4edaf3924 100644 --- a/core/src/mindustry/entities/bullet/BasicBulletType.java +++ b/core/src/mindustry/entities/bullet/BasicBulletType.java @@ -4,7 +4,7 @@ import arc.Core; import arc.graphics.Color; import arc.graphics.g2d.Draw; import arc.graphics.g2d.TextureRegion; -import mindustry.entities.type.Bullet; +import mindustry.gen.*; import mindustry.graphics.Pal; /** An extended BulletType for most ammo-based bullets shot from turrets and units. */ @@ -34,13 +34,13 @@ public class BasicBulletType extends BulletType{ } @Override - public void draw(Bullet b){ + public void draw(Bulletc b){ float height = bulletHeight * ((1f - bulletShrink) + bulletShrink * b.fout()); Draw.color(backColor); - Draw.rect(backRegion, b.x, b.y, bulletWidth, height, b.rot() - 90); + Draw.rect(backRegion, b.x(), b.y(), bulletWidth, height, b.rotation() - 90); Draw.color(frontColor); - Draw.rect(frontRegion, b.x, b.y, bulletWidth, height, b.rot() - 90); + Draw.rect(frontRegion, b.x(), b.y(), bulletWidth, height, b.rotation() - 90); Draw.color(); } } diff --git a/core/src/mindustry/entities/bullet/BulletType.java b/core/src/mindustry/entities/bullet/BulletType.java index 6c5417d0ca..e8028ce8c2 100644 --- a/core/src/mindustry/entities/bullet/BulletType.java +++ b/core/src/mindustry/entities/bullet/BulletType.java @@ -2,14 +2,13 @@ package mindustry.entities.bullet; import arc.audio.*; import arc.math.*; +import arc.util.ArcAnnotate.*; +import arc.util.*; +import mindustry.annotations.Annotations.*; import mindustry.content.*; -import mindustry.ctype.Content; -import mindustry.ctype.ContentType; +import mindustry.ctype.*; import mindustry.entities.*; -import mindustry.entities.Effects.*; -import mindustry.entities.effect.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; +import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; @@ -39,7 +38,11 @@ public abstract class BulletType extends Content{ public float reloadMultiplier = 1f; /** Recoil from shooter entities. */ public float recoil; - + /** Whether to kill the shooter when this is shot. For suicide bombers. */ + public boolean killShooter; + /** Whether to instantly make the bullet disappear. */ + public boolean instantDisappear; + /** Damage dealt in splash. 0 to disable.*/ public float splashDamage = 0f; /** Knockback in velocity. */ public float knockback; @@ -94,20 +97,20 @@ public abstract class BulletType extends Content{ return speed * lifetime * (1f - drag); } - public boolean collides(Bullet bullet, Tile tile){ + public boolean collides(Bulletc bullet, Tile tile){ return true; } - public void hitTile(Bullet b, Tile tile){ + public void hitTile(Bulletc b, Tile tile){ hit(b); } - public void hit(Bullet b){ - hit(b, b.x, b.y); + public void hit(Bulletc b){ + hit(b, b.getX(), b.getY()); } - public void hit(Bullet b, float x, float y){ - Effects.effect(hitEffect, x, y, b.rot()); + public void hit(Bulletc b, float x, float y){ + hitEffect.at(x, y, b.rotation()); hitSound.at(b); Effects.shake(hitShake, hitShake, b); @@ -116,7 +119,7 @@ public abstract class BulletType extends Content{ for(int i = 0; i < fragBullets; i++){ float len = Mathf.random(1f, 7f); float a = Mathf.random(360f); - Bullet.create(fragBullet, b, x + Angles.trnsx(a, len), y + Angles.trnsy(a, len), a, Mathf.random(fragVelocityMin, fragVelocityMax)); + fragBullet.create(b, x + Angles.trnsx(a, len), y + Angles.trnsy(a, len), a, Mathf.random(fragVelocityMin, fragVelocityMax)); } } @@ -125,12 +128,12 @@ public abstract class BulletType extends Content{ } if(splashDamageRadius > 0){ - Damage.damage(b.getTeam(), x, y, splashDamageRadius, splashDamage * b.damageMultiplier()); + Damage.damage(b.team(), x, y, splashDamageRadius, splashDamage * b.damageMultiplier()); } } - public void despawned(Bullet b){ - Effects.effect(despawnEffect, b.x, b.y, b.rot()); + public void despawned(Bulletc b){ + despawnEffect.at(b.getX(), b.getY(), b.rotation()); hitSound.at(b); if(fragBullet != null || splashDamageRadius > 0){ @@ -138,22 +141,28 @@ public abstract class BulletType extends Content{ } for(int i = 0; i < lightining; i++){ - Lightning.createLighting(Lightning.nextSeed(), b.getTeam(), Pal.surge, damage, b.x, b.y, Mathf.random(360f), lightningLength); + Lightning.create(b.team(), Pal.surge, damage, b.getX(), b.getY(), Mathf.random(360f), lightningLength); } } - public void draw(Bullet b){ + public void draw(Bulletc b){ } - public void init(Bullet b){ + public void init(Bulletc b){ + if(killShooter && b.owner() instanceof Healthc){ + ((Healthc)b.owner()).kill(); + } + + if(instantDisappear){ + b.time(lifetime); + } } - public void update(Bullet b){ - + public void update(Bulletc b){ if(homingPower > 0.0001f){ - TargetTrait target = Units.closestTarget(b.getTeam(), b.x, b.y, homingRange, e -> !e.isFlying() || collidesAir); + Teamc target = Units.closestTarget(b.team(), b.getX(), b.getY(), homingRange, e -> e.isGrounded() || collidesAir); if(target != null){ - b.velocity().setAngle(Mathf.slerpDelta(b.velocity().angle(), b.angleTo(target), 0.08f)); + b.vel().setAngle(Mathf.slerpDelta(b.rotation(), b.angleTo(target), 0.08f)); } } } @@ -162,4 +171,58 @@ public abstract class BulletType extends Content{ public ContentType getContentType(){ return ContentType.bullet; } + + //TODO change 'create' to 'at' + + public Bulletc create(Teamc owner, float x, float y, float angle){ + return create(owner, owner.team(), x, y, angle); + } + + public Bulletc create(Entityc owner, Team team, float x, float y, float angle){ + return create(owner, team, x, y, angle, 1f); + } + + public Bulletc create(Entityc owner, Team team, float x, float y, float angle, float velocityScl){ + return create(owner, team, x, y, angle, -1, velocityScl, 1f, null); + } + + public Bulletc create(Entityc owner, Team team, float x, float y, float angle, float velocityScl, float lifetimeScl){ + return create(owner, team, x, y, angle, -1, velocityScl, lifetimeScl, null); + } + + public Bulletc create(Bulletc parent, float x, float y, float angle){ + return create(parent.owner(), parent.team(), x, y, angle); + } + + public Bulletc create(Bulletc parent, float x, float y, float angle, float velocityScl){ + return create(parent.owner(), parent.team(), x, y, angle, velocityScl); + } + + public Bulletc create(@Nullable Entityc owner, Team team, float x, float y, float angle, float damage, float velocityScl, float lifetimeScl, Object data){ + Bulletc bullet = BulletEntity.create(); + bullet.type(this); + bullet.owner(owner); + bullet.team(team); + bullet.vel().trns(angle, speed * velocityScl); + bullet.set(x - bullet.vel().x * Time.delta(), y - bullet.vel().y * Time.delta()); + bullet.lifetime(lifetime * lifetimeScl); + bullet.data(data); + bullet.drag(drag); + bullet.hitSize(hitSize); + bullet.damage(damage < 0 ? this.damage : damage); + bullet.add(); + + //if(keepVelocity && owner instanceof Velc) bullet.vel().add(((Velc)owner).vel()); + return bullet; + + } + + public void createNet(Team team, float x, float y, float angle, float damage, float velocityScl, float lifetimeScl){ + Call.createBullet(this, team, x, y, damage, angle, velocityScl, lifetimeScl); + } + + @Remote(called = Loc.server, unreliable = true) + public static void createBullet(BulletType type, Team team, float x, float y, float angle, float damage, float velocityScl, float lifetimeScl){ + type.create(null, team, x, y, angle, damage, velocityScl, lifetimeScl, null); + } } diff --git a/core/src/mindustry/entities/bullet/FlakBulletType.java b/core/src/mindustry/entities/bullet/FlakBulletType.java index ead19859cc..c933485d31 100644 --- a/core/src/mindustry/entities/bullet/FlakBulletType.java +++ b/core/src/mindustry/entities/bullet/FlakBulletType.java @@ -4,7 +4,7 @@ import arc.math.geom.Rect; import arc.util.Time; import mindustry.content.Fx; import mindustry.entities.Units; -import mindustry.entities.type.Bullet; +import mindustry.gen.*; public class FlakBulletType extends BasicBulletType{ protected static Rect rect = new Rect(); @@ -24,18 +24,18 @@ public class FlakBulletType extends BasicBulletType{ } @Override - public void update(Bullet b){ + public void update(Bulletc b){ super.update(b); - if(b.getData() instanceof Integer) return; + if(b.data() instanceof Integer) return; - if(b.timer.get(2, 6)){ - Units.nearbyEnemies(b.getTeam(), rect.setSize(explodeRange * 2f).setCenter(b.x, b.y), unit -> { - if(b.getData() instanceof Float) return; + if(b.timer(2, 6)){ + Units.nearbyEnemies(b.team(), rect.setSize(explodeRange * 2f).setCenter(b.x(), b.y()), unit -> { + if(b.data() instanceof Float) return; if(unit.dst(b) < explodeRange){ - b.setData(0); + b.data(0); Time.run(5f, () -> { - if(b.getData() instanceof Integer){ + if(b.data() instanceof Integer){ b.time(b.lifetime()); } }); diff --git a/core/src/mindustry/entities/bullet/HealBulletType.java b/core/src/mindustry/entities/bullet/HealBulletType.java index 4ff0b9fefd..64f65fc1a5 100644 --- a/core/src/mindustry/entities/bullet/HealBulletType.java +++ b/core/src/mindustry/entities/bullet/HealBulletType.java @@ -3,14 +3,15 @@ package mindustry.entities.bullet; import arc.graphics.*; import arc.graphics.g2d.*; import mindustry.content.*; -import mindustry.entities.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.graphics.*; import mindustry.world.*; import mindustry.world.blocks.*; public class HealBulletType extends BulletType{ protected float healPercent = 3f; + protected float bulletHeight = 7f, bulletWidth = 2f; + protected Color backColor = Pal.heal, frontColor = Color.white; public HealBulletType(float speed, float damage){ super(speed, damage); @@ -27,28 +28,28 @@ public class HealBulletType extends BulletType{ } @Override - public boolean collides(Bullet b, Tile tile){ - return tile.getTeam() != b.getTeam() || tile.entity.healthf() < 1f; + public boolean collides(Bulletc b, Tile tile){ + return tile.team() != b.team() || tile.entity.healthf() < 1f; } @Override - public void draw(Bullet b){ - Draw.color(Pal.heal); - Lines.stroke(2f); - Lines.lineAngleCenter(b.x, b.y, b.rot(), 7f); - Draw.color(Color.white); - Lines.lineAngleCenter(b.x, b.y, b.rot(), 3f); + public void draw(Bulletc b){ + Draw.color(backColor); + Lines.stroke(bulletWidth); + Lines.lineAngleCenter(b.x(), b.y(), b.rotation(), bulletHeight); + Draw.color(frontColor); + Lines.lineAngleCenter(b.x(), b.y(), b.rotation(), bulletHeight / 2f); Draw.reset(); } @Override - public void hitTile(Bullet b, Tile tile){ + public void hitTile(Bulletc b, Tile tile){ super.hit(b); tile = tile.link(); - if(tile.entity != null && tile.getTeam() == b.getTeam() && !(tile.block() instanceof BuildBlock)){ - Effects.effect(Fx.healBlockFull, Pal.heal, tile.drawx(), tile.drawy(), tile.block().size); - tile.entity.healBy(healPercent / 100f * tile.entity.maxHealth()); + if(tile.entity != null && tile.team() == b.team() && !(tile.block() instanceof BuildBlock)){ + Fx.healBlockFull.at(tile.drawx(), tile.drawy(), tile.block().size, Pal.heal); + tile.entity.heal(healPercent / 100f * tile.entity.maxHealth()); } } } diff --git a/core/src/mindustry/entities/bullet/LaserBulletType.java b/core/src/mindustry/entities/bullet/LaserBulletType.java new file mode 100644 index 0000000000..18e4610c58 --- /dev/null +++ b/core/src/mindustry/entities/bullet/LaserBulletType.java @@ -0,0 +1,73 @@ +package mindustry.entities.bullet; + +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.math.*; +import arc.util.*; +import mindustry.content.*; +import mindustry.entities.*; +import mindustry.gen.*; +import mindustry.graphics.*; + +public class LaserBulletType extends BulletType{ + protected Color[] colors = {Pal.lancerLaser.cpy().mul(1f, 1f, 1f, 0.4f), Pal.lancerLaser, Color.white}; + protected float length = 160f; + protected float width = 15f; + protected float lengthFalloff = 0.5f; + protected float sideLength = 29f, sideWidth = 0.7f; + protected float sideAngle = 90f; + + public LaserBulletType(float damage){ + super(0.01f, damage); + + keepVelocity = false; + hitEffect = Fx.hitLancer; + despawnEffect = Fx.none; + shootEffect = Fx.hitLancer; + smokeEffect = Fx.lancerLaserShootSmoke; + hitSize = 4; + lifetime = 16f; + pierce = true; + } + + public LaserBulletType(){ + this(1f); + } + + @Override + public float range(){ + return length; + } + + @Override + public void init(Bulletc b){ + Damage.collideLine(b, b.team(), hitEffect, b.x(), b.y(), b.rotation(), length); + } + + @Override + public void draw(Bulletc b){ + float f = Mathf.curve(b.fin(), 0f, 0.2f); + float baseLen = length * f; + float cwidth = width; + float compound = 1f; + + Lines.lineAngle(b.x(), b.y(), b.rotation(), baseLen); + Lines.precise(true); + for(Color color : colors){ + Draw.color(color); + Lines.stroke((cwidth *= lengthFalloff) * b.fout()); + Lines.lineAngle(b.x(), b.y(), b.rotation(), baseLen, CapStyle.none); + Tmp.v1.trns(b.rotation(), baseLen); + Drawf.tri(b.x() + Tmp.v1.x, b.y() + Tmp.v1.y, Lines.getStroke() * 1.22f, cwidth * 2f + width / 2f, b.rotation()); + + Fill.circle(b.x(), b.y(), 1f * cwidth * b.fout()); + for(int i : Mathf.signs){ + Drawf.tri(b.x(), b.y(), sideWidth * b.fout() * cwidth, sideLength * compound, b.rotation() + sideAngle * i); + } + + compound *= lengthFalloff; + } + Lines.precise(false); + Draw.reset(); + } +} diff --git a/core/src/mindustry/entities/bullet/LightningBulletType.java b/core/src/mindustry/entities/bullet/LightningBulletType.java new file mode 100644 index 0000000000..36beb5a092 --- /dev/null +++ b/core/src/mindustry/entities/bullet/LightningBulletType.java @@ -0,0 +1,30 @@ +package mindustry.entities.bullet; + +import arc.graphics.*; +import mindustry.content.*; +import mindustry.entities.*; +import mindustry.gen.*; +import mindustry.graphics.*; + +public class LightningBulletType extends BulletType{ + protected Color lightningColor = Pal.lancerLaser; + protected int lightningLength = 25; + + public LightningBulletType(){ + super(0.0001f, 1f); + + lifetime = 1; + despawnEffect = Fx.none; + hitEffect = Fx.hitLancer; + keepVelocity = false; + } + + @Override + public void draw(Bulletc b){ + } + + @Override + public void init(Bulletc b){ + Lightning.create(b.team(), lightningColor, damage, b.x(), b.y(), b.rotation(), lightningLength); + } +} diff --git a/core/src/mindustry/entities/bullet/LiquidBulletType.java b/core/src/mindustry/entities/bullet/LiquidBulletType.java index a1039e2748..e6be46263d 100644 --- a/core/src/mindustry/entities/bullet/LiquidBulletType.java +++ b/core/src/mindustry/entities/bullet/LiquidBulletType.java @@ -5,9 +5,7 @@ import arc.graphics.g2d.*; import arc.math.geom.*; import arc.util.ArcAnnotate.*; import mindustry.content.*; -import mindustry.entities.*; -import mindustry.entities.effect.*; -import mindustry.entities.type.Bullet; +import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; @@ -45,36 +43,38 @@ public class LiquidBulletType extends BulletType{ } @Override - public void update(Bullet b){ + public void update(Bulletc b){ super.update(b); if(liquid.canExtinguish()){ - Tile tile = world.tileWorld(b.x, b.y); - if(tile != null && Fire.has(tile.x, tile.y)){ - Fire.extinguish(tile, 100f); - b.remove(); - hit(b); - } + //TODO implement + Tile tile = world.tileWorld(b.x(), b.y()); + //if(tile != null && Fire.has(tile.x, tile.y)){ + //Fire.extinguish(tile, 100f); + // b.remove(); + // hit(b); + //} } } @Override - public void draw(Bullet b){ + public void draw(Bulletc b){ Draw.color(liquid.color, Color.white, b.fout() / 100f); - Fill.circle(b.x, b.y, 0.5f + b.fout() * 2.5f); + Fill.circle(b.x(), b.y(), 0.5f + b.fout() * 2.5f); } @Override - public void hit(Bullet b, float hitx, float hity){ - Effects.effect(hitEffect, liquid.color, hitx, hity); - Puddle.deposit(world.tileWorld(hitx, hity), liquid, puddleSize); + public void hit(Bulletc b, float hitx, float hity){ + hitEffect.at(hitx, hity, liquid.color); + //TODO implement + // Puddle.deposit(world.tileWorld(hitx, hity), liquid, puddleSize); if(liquid.temperature <= 0.5f && liquid.flammability < 0.3f){ float intensity = 400f; - Fire.extinguish(world.tileWorld(hitx, hity), intensity); + //Fire.extinguish(world.tileWorld(hitx, hity), intensity); for(Point2 p : Geometry.d4){ - Fire.extinguish(world.tileWorld(hitx + p.x * tilesize, hity + p.y * tilesize), intensity); + // Fire.extinguish(world.tileWorld(hitx + p.x * tilesize, hity + p.y * tilesize), intensity); } } } diff --git a/core/src/mindustry/entities/bullet/MassDriverBolt.java b/core/src/mindustry/entities/bullet/MassDriverBolt.java index 8fbe5c77db..96fd1698f7 100644 --- a/core/src/mindustry/entities/bullet/MassDriverBolt.java +++ b/core/src/mindustry/entities/bullet/MassDriverBolt.java @@ -5,8 +5,7 @@ import arc.graphics.g2d.Draw; import arc.math.Angles; import arc.math.Mathf; import mindustry.content.Fx; -import mindustry.entities.Effects; -import mindustry.entities.type.Bullet; +import mindustry.gen.*; import mindustry.graphics.Pal; import mindustry.world.blocks.distribution.MassDriver.DriverBulletData; @@ -24,32 +23,32 @@ public class MassDriverBolt extends BulletType{ } @Override - public void draw(mindustry.entities.type.Bullet b){ + public void draw(Bulletc b){ float w = 11f, h = 13f; Draw.color(Pal.bulletYellowBack); - Draw.rect("shell-back", b.x, b.y, w, h, b.rot() + 90); + Draw.rect("shell-back", b.x(), b.y(), w, h, b.rotation() + 90); Draw.color(Pal.bulletYellow); - Draw.rect("shell", b.x, b.y, w, h, b.rot() + 90); + Draw.rect("shell", b.x(), b.y(), w, h, b.rotation() + 90); Draw.reset(); } @Override - public void update(mindustry.entities.type.Bullet b){ + public void update(Bulletc b){ //data MUST be an instance of DriverBulletData - if(!(b.getData() instanceof DriverBulletData)){ + if(!(b.data() instanceof DriverBulletData)){ hit(b); return; } float hitDst = 7f; - DriverBulletData data = (DriverBulletData)b.getData(); + DriverBulletData data = (DriverBulletData)b.data(); //if the target is dead, just keep flying until the bullet explodes - if(data.to.isDead()){ + if(data.to.dead()){ return; } @@ -68,7 +67,7 @@ public class MassDriverBolt extends BulletType{ if(Angles.near(angleTo, baseAngle, 2f)){ intersect = true; //snap bullet position back; this is used for low-FPS situations - b.set(data.to.x + Angles.trnsx(baseAngle, hitDst), data.to.y + Angles.trnsy(baseAngle, hitDst)); + b.set(data.to.x() + Angles.trnsx(baseAngle, hitDst), data.to.y() + Angles.trnsy(baseAngle, hitDst)); } } @@ -83,24 +82,24 @@ public class MassDriverBolt extends BulletType{ } @Override - public void despawned(mindustry.entities.type.Bullet b){ + public void despawned(Bulletc b){ super.despawned(b); - if(!(b.getData() instanceof DriverBulletData)) return; + if(!(b.data() instanceof DriverBulletData)) return; - DriverBulletData data = (DriverBulletData)b.getData(); + DriverBulletData data = (DriverBulletData)b.data(); for(int i = 0; i < data.items.length; i++){ 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)); + float angle = b.rotation() + Mathf.range(100f); + Fx.dropItem.at(b.x(), b.y(), angle, Color.white, content.item(i)); } } } @Override - public void hit(Bullet b, float hitx, float hity){ + public void hit(Bulletc b, float hitx, float hity){ super.hit(b, hitx, hity); despawned(b); } diff --git a/core/src/mindustry/entities/bullet/MissileBulletType.java b/core/src/mindustry/entities/bullet/MissileBulletType.java index 3c730d975a..296509c9bf 100644 --- a/core/src/mindustry/entities/bullet/MissileBulletType.java +++ b/core/src/mindustry/entities/bullet/MissileBulletType.java @@ -4,8 +4,6 @@ import arc.graphics.Color; import arc.math.Mathf; import arc.util.Time; import mindustry.content.Fx; -import mindustry.entities.Effects; -import mindustry.entities.type.Bullet; import mindustry.gen.*; import mindustry.graphics.Pal; @@ -28,15 +26,15 @@ public class MissileBulletType extends BasicBulletType{ } @Override - public void update(Bullet b){ + public void update(Bulletc b){ super.update(b); if(Mathf.chance(Time.delta() * 0.2)){ - Effects.effect(Fx.missileTrail, trailColor, b.x, b.y, 2f); + Fx.missileTrail.at(b.x(), b.y(), 2f, trailColor); } if(weaveMag > 0){ - b.velocity().rotate(Mathf.sin(Time.time() + b.id * 4422, weaveScale, weaveMag) * Time.delta()); + b.vel().rotate(Mathf.sin(Time.time() + b.id() * 442, weaveScale, weaveMag) * Time.delta()); } } } diff --git a/core/src/mindustry/entities/def/BoundedComp.java b/core/src/mindustry/entities/def/BoundedComp.java new file mode 100644 index 0000000000..da3da73fbf --- /dev/null +++ b/core/src/mindustry/entities/def/BoundedComp.java @@ -0,0 +1,36 @@ +package mindustry.entities.def; + +import arc.math.*; +import arc.math.geom.*; +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +import static mindustry.Vars.*; + +@Component +abstract class BoundedComp implements Velc, Posc, Healthc, Flyingc{ + static final float warpDst = 180f; + + transient float x, y; + transient Vec2 vel; + + @Override + public void update(){ + //repel unit out of bounds + if(x < 0) vel.x += (-x/warpDst); + if(y < 0) vel.y += (-y/warpDst); + if(x > world.unitWidth()) vel.x -= (x - world.unitWidth())/warpDst; + if(y > world.unitHeight()) vel.y -= (y - world.unitHeight())/warpDst; + + //clamp position if not flying + if(isGrounded()){ + x = Mathf.clamp(x, 0, world.width() * tilesize - tilesize); + y = Mathf.clamp(y, 0, world.height() * tilesize - tilesize); + } + + //kill when out of bounds + if(x < -finalWorldBounds || y < -finalWorldBounds || x >= world.width() * tilesize + finalWorldBounds || y >= world.height() * tilesize + finalWorldBounds){ + kill(); + } + } +} diff --git a/core/src/mindustry/entities/def/BuilderComp.java b/core/src/mindustry/entities/def/BuilderComp.java new file mode 100644 index 0000000000..480449cea0 --- /dev/null +++ b/core/src/mindustry/entities/def/BuilderComp.java @@ -0,0 +1,229 @@ +package mindustry.entities.def; + +import arc.*; +import arc.graphics.g2d.*; +import arc.math.*; +import arc.math.geom.*; +import arc.struct.*; +import arc.struct.Queue; +import arc.util.*; +import arc.util.ArcAnnotate.*; +import mindustry.*; +import mindustry.annotations.Annotations.*; +import mindustry.content.*; +import mindustry.entities.units.*; +import mindustry.game.EventType.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.world.*; +import mindustry.world.blocks.*; +import mindustry.world.blocks.BuildBlock.*; + +import java.util.*; + +import static mindustry.Vars.*; + +@Component +abstract class BuilderComp implements Unitc{ + static final Vec2[] tmptr = new Vec2[]{new Vec2(), new Vec2(), new Vec2(), new Vec2()}; + + transient float x, y, rotation; + + Queue requests = new Queue<>(); + float buildSpeed = 1f; + //boolean building; + + void updateBuilding(){ + float finalPlaceDst = state.rules.infiniteResources ? Float.MAX_VALUE : buildingRange; + + Iterator it = requests.iterator(); + while(it.hasNext()){ + BuildRequest req = it.next(); + Tile tile = world.tile(req.x, req.y); + if(tile == null || (req.breaking && tile.block() == Blocks.air) || (!req.breaking && (tile.rotation() == req.rotation || !req.block.rotate) && tile.block() == req.block)){ + it.remove(); + } + } + + Tilec core = closestCore(); + + //nothing to build. + if(buildRequest() == null) return; + + //find the next build request + if(requests.size > 1){ + int total = 0; + BuildRequest req; + while((dst((req = buildRequest()).tile()) > finalPlaceDst || shouldSkip(req, core)) && total < requests.size){ + requests.removeFirst(); + requests.addLast(req); + total++; + } + } + + BuildRequest current = buildRequest(); + + if(dst(current.tile()) > finalPlaceDst) return; + + Tile tile = world.tile(current.x, current.y); + + if(!(tile.block() instanceof BuildBlock)){ + if(!current.initialized && !current.breaking && Build.validPlace(team(), current.x, current.y, current.block, current.rotation)){ + Build.beginPlace(team(), current.x, current.y, current.block, current.rotation); + }else if(!current.initialized && current.breaking && Build.validBreak(team(), current.x, current.y)){ + Build.beginBreak(team(), current.x, current.y); + }else{ + requests.removeFirst(); + return; + } + } + + if(tile.entity instanceof BuildEntity && !current.initialized){ + Core.app.post(() -> Events.fire(new BuildSelectEvent(tile, team(), (Builderc)this, current.breaking))); + current.initialized = true; + } + + //if there is no core to build with or no build entity, stop building! + if((core == null && !state.rules.infiniteResources) || !(tile.entity instanceof BuildEntity)){ + return; + } + + //otherwise, update it. + BuildEntity entity = tile.ent(); + + if(entity == null){ + return; + } + + if(dst(tile) <= finalPlaceDst){ + rotation = Mathf.slerpDelta(rotation, angleTo(entity), 0.4f); + } + + if(current.breaking){ + entity.deconstruct(this, core, 1f / entity.buildCost * Time.delta() * buildSpeed * state.rules.buildSpeedMultiplier); + }else{ + if(entity.construct(this, core, 1f / entity.buildCost * Time.delta() * buildSpeed * state.rules.buildSpeedMultiplier, current.hasConfig)){ + if(current.hasConfig){ + Call.onTileConfig(null, tile, current.config); + } + } + } + + current.stuck = Mathf.equal(current.progress, entity.progress); + current.progress = entity.progress; + } + + + /** Draw all current build requests. Does not draw the beam effect, only the positions. */ + void drawBuildRequests(){ + + for(BuildRequest request : requests){ + if(request.progress > 0.01f || (buildRequest() == request && request.initialized && (dst(request.x * tilesize, request.y * tilesize) <= buildingRange || state.isEditor()))) continue; + + request.animScale = 1f; + if(request.breaking){ + control.input.drawBreaking(request); + }else{ + request.block.drawRequest(request, control.input.allRequests(), + Build.validPlace(team(), request.x, request.y, request.block, request.rotation) || control.input.requestMatches(request)); + } + } + + Draw.reset(); + } + + /** @return whether this request should be skipped, in favor of the next one. */ + boolean shouldSkip(BuildRequest request, @Nullable Tilec core){ + //requests that you have at least *started* are considered + if(state.rules.infiniteResources || request.breaking || !request.initialized || core == null) return false; + return request.stuck && !core.items().has(request.block.requirements); + } + + void removeBuild(int x, int y, boolean breaking){ + //remove matching request + int idx = requests.indexOf(req -> req.breaking == breaking && req.x == x && req.y == y); + if(idx != -1){ + requests.removeIndex(idx); + } + } + + /** Return whether this builder's place queue contains items. */ + boolean isBuilding(){ + return requests.size != 0; + } + + /** Clears the placement queue. */ + void clearBuilding(){ + requests.clear(); + } + + /** Add another build requests to the tail of the queue, if it doesn't exist there yet. */ + void addBuild(BuildRequest place){ + addBuild(place, true); + } + + /** Add another build requests to the queue, if it doesn't exist there yet. */ + void addBuild(BuildRequest place, boolean tail){ + BuildRequest replace = null; + for(BuildRequest request : requests){ + if(request.x == place.x && request.y == place.y){ + replace = request; + break; + } + } + if(replace != null){ + requests.remove(replace); + } + Tile tile = world.tile(place.x, place.y); + if(tile != null && tile.entity instanceof BuildEntity){ + place.progress = tile.ent().progress; + } + if(tail){ + requests.addLast(place); + }else{ + requests.addFirst(place); + } + } + + /** Return the build requests currently active, or the one at the top of the queue.*/ + @Nullable BuildRequest buildRequest(){ + return requests.size == 0 ? null : requests.first(); + } + + void drawOver(){ + if(!isBuilding()) return; + BuildRequest request = buildRequest(); + Tile tile = world.tile(request.x, request.y); + + if(dst(tile) > buildingRange && !state.isEditor()){ + return; + } + + Lines.stroke(1f, Pal.accent); + float focusLen = 3.8f + Mathf.absin(Time.time(), 1.1f, 0.6f); + float px = x + Angles.trnsx(rotation, focusLen); + float py = y + Angles.trnsy(rotation, focusLen); + + float sz = Vars.tilesize * tile.block().size / 2f; + float ang = angleTo(tile); + + tmptr[0].set(tile.drawx() - sz, tile.drawy() - sz); + tmptr[1].set(tile.drawx() + sz, tile.drawy() - sz); + tmptr[2].set(tile.drawx() - sz, tile.drawy() + sz); + tmptr[3].set(tile.drawx() + sz, tile.drawy() + sz); + + Arrays.sort(tmptr, Structs.comparingFloat(vec -> Angles.angleDist(angleTo(vec), ang))); + + float x1 = tmptr[0].x, y1 = tmptr[0].y, + x3 = tmptr[1].x, y3 = tmptr[1].y; + + Draw.alpha(1f); + + Lines.line(px, py, x1, y1); + Lines.line(px, py, x3, y3); + + Fill.circle(px, py, 1.6f + Mathf.absin(Time.time(), 0.8f, 1.5f)); + + Draw.color(); + } +} diff --git a/core/src/mindustry/entities/def/BulletComp.java b/core/src/mindustry/entities/def/BulletComp.java new file mode 100644 index 0000000000..a22a83281e --- /dev/null +++ b/core/src/mindustry/entities/def/BulletComp.java @@ -0,0 +1,115 @@ +package mindustry.entities.def; + +import arc.math.*; +import arc.util.*; +import mindustry.annotations.Annotations.*; +import mindustry.entities.bullet.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.world.*; + +import static mindustry.Vars.*; + +@Component +abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Drawc, Shielderc, Ownerc, Velc, Bulletc, Timerc, DrawLayerBulletsc{ + Object data; + BulletType type; + float damage; + + @Override + public void drawBullets(){ + type.draw(this); + } + + @Override + public void add(){ + type.init(this); + } + + @Override + public void remove(){ + type.despawned(this); + } + + @Override + public float damageMultiplier(){ + if(owner() instanceof Unitc){ + return ((Unitc)owner()).damageMultiplier(); + } + return 1f; + } + + @Override + public void absorb(){ + //TODO + remove(); + } + + @Override + public float clipSize(){ + return type.drawSize; + } + + @Override + public float damage(){ + return damage * damageMultiplier(); + } + + @Override + public void collision(Hitboxc other, float x, float y){ + if(!type.pierce) remove(); + type.hit(this, x, y); + + if(other instanceof Unitc){ + Unitc unit = (Unitc)other; + unit.vel().add(Tmp.v3.set(other.x(), other.y()).sub(x, y).setLength(type.knockback / unit.mass())); + unit.apply(type.status, type.statusDuration); + } + } + + @Override + public void update(){ + type.update(this); + + if(type.hitTiles){ + world.raycastEach(world.toTile(lastX()), world.toTile(lastY()), tileX(), tileY(), (x, y) -> { + + Tile tile = world.ltile(x, y); + if(tile == null) return false; + + if(tile.entity != null && tile.entity.collide(this) && type.collides(this, tile) && !tile.entity.dead() && (type.collidesTeam || tile.team() != team())){ + if(tile.team() != team()){ + tile.entity.collision(this); + } + + type.hitTile(this, tile); + remove(); + return true; + } + + return false; + }); + } + } + + @Override + public void draw(){ + type.draw(this); + //TODO refactor + renderer.lights.add(x(), y(), 16f, Pal.powerLight, 0.3f); + } + + /** Sets the bullet's rotation in degrees. */ + @Override + public void rotation(float angle){ + vel().setAngle(angle); + } + + /** @return the bullet's rotation. */ + @Override + public float rotation(){ + float angle = Mathf.atan2(vel().x, vel().y) * Mathf.radiansToDegrees; + if(angle < 0) angle += 360; + return angle; + } +} diff --git a/core/src/mindustry/entities/def/ChildComp.java b/core/src/mindustry/entities/def/ChildComp.java new file mode 100644 index 0000000000..e64efe6eac --- /dev/null +++ b/core/src/mindustry/entities/def/ChildComp.java @@ -0,0 +1,29 @@ +package mindustry.entities.def; + +import arc.util.ArcAnnotate.*; +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class ChildComp implements Posc{ + transient float x, y; + + @Nullable Posc parent; + float offsetX, offsetY; + + @Override + public void add(){ + if(parent != null){ + offsetX = x - parent.getX(); + offsetY = y - parent.getY(); + } + } + + @Override + public void update(){ + if(parent != null){ + x = parent.getX() + offsetX; + y = parent.getY() + offsetY; + } + } +} diff --git a/core/src/mindustry/entities/def/DamageComp.java b/core/src/mindustry/entities/def/DamageComp.java new file mode 100644 index 0000000000..2ace4db324 --- /dev/null +++ b/core/src/mindustry/entities/def/DamageComp.java @@ -0,0 +1,8 @@ +package mindustry.entities.def; + +import mindustry.annotations.Annotations.*; + +@Component +abstract class DamageComp{ + abstract float damage(); +} diff --git a/core/src/mindustry/entities/def/DecalComp.java b/core/src/mindustry/entities/def/DecalComp.java new file mode 100644 index 0000000000..d6f8ea012b --- /dev/null +++ b/core/src/mindustry/entities/def/DecalComp.java @@ -0,0 +1,29 @@ +package mindustry.entities.def; + +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.math.*; +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class DecalComp implements Drawc, Timedc, Rotc, Posc, DrawLayerFloorc{ + transient float x, y, rotation; + + Color color = new Color(1, 1, 1, 1); + TextureRegion region; + + @Override + public void drawFloor(){ + Draw.color(color); + Draw.alpha(1f - Mathf.curve(fin(), 0.98f)); + Draw.rect(region, x, y, rotation); + Draw.color(); + } + + @Override + public float clipSize(){ + return region.getWidth()*2; + } + +} diff --git a/core/src/mindustry/entities/def/DrawComp.java b/core/src/mindustry/entities/def/DrawComp.java new file mode 100644 index 0000000000..123c6a14ed --- /dev/null +++ b/core/src/mindustry/entities/def/DrawComp.java @@ -0,0 +1,9 @@ +package mindustry.entities.def; + +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class DrawComp implements Posc{ + abstract float clipSize(); +} diff --git a/core/src/mindustry/entities/def/EffectComp.java b/core/src/mindustry/entities/def/EffectComp.java new file mode 100644 index 0000000000..b090a256f2 --- /dev/null +++ b/core/src/mindustry/entities/def/EffectComp.java @@ -0,0 +1,22 @@ +package mindustry.entities.def; + +import arc.graphics.*; +import mindustry.annotations.Annotations.*; +import mindustry.entities.*; +import mindustry.gen.*; + +@Component +abstract class EffectComp implements Posc, Drawc, Timedc, Rotc, Childc{ + Color color = new Color(Color.white); + Effect effect; + Object data; + + void draw(){ + effect.render(id(), color, time(), rotation(), x(), y(), data); + } + + @Override + public float clipSize(){ + return effect.size; + } +} diff --git a/core/src/mindustry/entities/def/ElevationMoveComp.java b/core/src/mindustry/entities/def/ElevationMoveComp.java new file mode 100644 index 0000000000..079a32e9bc --- /dev/null +++ b/core/src/mindustry/entities/def/ElevationMoveComp.java @@ -0,0 +1,22 @@ +package mindustry.entities.def; + +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +import static mindustry.Vars.collisions; + +@Component +abstract class ElevationMoveComp implements Velc, Posc, Flyingc, Hitboxc{ + transient float x, y; + + @Replace + @Override + public void move(float cx, float cy){ + if(isFlying()){ + x += cx; + y += cy; + }else{ + collisions.move(this, cx, cy); + } + } +} diff --git a/core/src/mindustry/entities/def/EntityComp.java b/core/src/mindustry/entities/def/EntityComp.java new file mode 100644 index 0000000000..80c1412930 --- /dev/null +++ b/core/src/mindustry/entities/def/EntityComp.java @@ -0,0 +1,59 @@ +package mindustry.entities.def; + +import arc.func.*; +import mindustry.annotations.Annotations.*; +import mindustry.entities.*; +import mindustry.gen.*; + +import java.io.*; + +import static mindustry.Vars.player; + +@Component +@BaseComponent +abstract class EntityComp{ + private boolean added; + int id = EntityGroup.nextId(); + + boolean isAdded(){ + return added; + } + + void update(){} + + void remove(){ + added = false; + } + + void add(){ + added = true; + } + + boolean isLocal(){ + return ((Object)this) == player || ((Object)this) instanceof Unitc && ((Unitc)((Object)this)).controller() == player; + } + + boolean isNull(){ + return false; + } + + T as(Class type){ + return (T)this; + } + + T with(Cons cons){ + cons.get((T)this); + return (T)this; + } + + @InternalImpl + abstract int classId(); + + void read(DataInput input) throws IOException{ + //TODO dynamic io + } + + void write(DataOutput output) throws IOException{ + //TODO dynamic io + } +} diff --git a/core/src/mindustry/entities/def/FireComp.java b/core/src/mindustry/entities/def/FireComp.java new file mode 100644 index 0000000000..ed33341af5 --- /dev/null +++ b/core/src/mindustry/entities/def/FireComp.java @@ -0,0 +1,8 @@ +package mindustry.entities.def; + +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class FireComp implements Timedc{ +} diff --git a/core/src/mindustry/entities/def/FlyingComp.java b/core/src/mindustry/entities/def/FlyingComp.java new file mode 100644 index 0000000000..60b1dda381 --- /dev/null +++ b/core/src/mindustry/entities/def/FlyingComp.java @@ -0,0 +1,73 @@ +package mindustry.entities.def; + +import arc.math.*; +import arc.math.geom.*; +import arc.util.*; +import mindustry.annotations.Annotations.*; +import mindustry.content.*; +import mindustry.gen.*; +import mindustry.world.blocks.*; + +import static mindustry.Vars.net; + +@Component +abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{ + transient float x, y; + transient Vec2 vel; + + float elevation; + float drownTime; + float splashTimer; + + boolean isGrounded(){ + return elevation < 0.001f; + } + + boolean isFlying(){ + return elevation >= 0.001f; + } + + boolean canDrown(){ + return isGrounded(); + } + + void moveAt(Vec2 vector){ + Vec2 t = Tmp.v3.set(vector).scl(floorSpeedMultiplier()); //target vector + float mag = Tmp.v3.len(); + vel.x = Mathf.approach(vel.x, t.x, mag); + vel.y = Mathf.approach(vel.y, t.y, mag); + } + + float floorSpeedMultiplier(){ + Floor on = isFlying() ? Blocks.air.asFloor() : floorOn(); + return on.speedMultiplier; + } + + @Override + public void update(){ + Floor floor = floorOn(); + + if(isGrounded() && floor.isLiquid){ + if((splashTimer += Mathf.dst(deltaX(), deltaY())) >= 7f){ + floor.walkEffect.at(x, y, 0, floor.color); + splashTimer = 0f; + } + } + + if(canDrown() && floor.isLiquid && floor.drownTime > 0){ + drownTime += Time.delta() * 1f / floor.drownTime; + drownTime = Mathf.clamp(drownTime); + if(Mathf.chance(Time.delta() * 0.05f)){ + floor.drownUpdateEffect.at(x, y, 0f, floor.color); + } + + //TODO is the netClient check necessary? + if(drownTime >= 0.999f && !net.client()){ + kill(); + //TODO drown event! + } + }else{ + drownTime = Mathf.lerpDelta(drownTime, 0f, 0.03f); + } + } +} diff --git a/core/src/mindustry/entities/def/GroundEffectComp.java b/core/src/mindustry/entities/def/GroundEffectComp.java new file mode 100644 index 0000000000..c1a10fc11d --- /dev/null +++ b/core/src/mindustry/entities/def/GroundEffectComp.java @@ -0,0 +1,13 @@ +package mindustry.entities.def; + +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class GroundEffectComp implements Effectc, DrawLayerFloorOverc{ + + @Override + public void drawFloorOver(){ + draw(); + } +} diff --git a/core/src/mindustry/entities/def/HealthComp.java b/core/src/mindustry/entities/def/HealthComp.java new file mode 100644 index 0000000000..4a18cf67bc --- /dev/null +++ b/core/src/mindustry/entities/def/HealthComp.java @@ -0,0 +1,83 @@ +package mindustry.entities.def; + +import arc.math.*; +import arc.util.*; +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class HealthComp implements Entityc{ + static final float hitDuration = 9f; + + float health, maxHealth = 1f, hitTime; + boolean dead; + + boolean isValid(){ + return !dead && isAdded(); + } + + float healthf(){ + return health / maxHealth; + } + + @Override + public void update(){ + hitTime -= Time.delta() / hitDuration; + } + + float hitAlpha(){ + return hitTime / hitDuration; + } + + void killed(){ + //implement by other components + } + + void kill(){ + if(dead) return; + + health = 0; + dead = true; + killed(); + remove(); + } + + void heal(){ + dead = false; + health = maxHealth; + } + + boolean damaged(){ + return health <= maxHealth - 0.0001f; + } + + void damage(float amount){ + health -= amount; + if(health <= 0 && !dead){ + kill(); + } + } + + void damage(float amount, boolean withEffect){ + float pre = hitTime; + + damage(amount); + + if(!withEffect){ + hitTime = pre; + } + } + + void damageContinuous(float amount){ + damage(amount * Time.delta(), hitTime <= -20 + hitDuration); + } + + void clampHealth(){ + health = Mathf.clamp(health, 0, maxHealth); + } + + void heal(float amount){ + health += amount; + clampHealth(); + } +} diff --git a/core/src/mindustry/entities/def/HitboxComp.java b/core/src/mindustry/entities/def/HitboxComp.java new file mode 100644 index 0000000000..8814172e79 --- /dev/null +++ b/core/src/mindustry/entities/def/HitboxComp.java @@ -0,0 +1,51 @@ +package mindustry.entities.def; + +import arc.math.geom.*; +import arc.math.geom.QuadTree.*; +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class HitboxComp implements Posc, QuadTreeObject{ + transient float x, y; + + float hitSize; + float lastX, lastY; + + @Override + public void update(){ + + } + + void updateLastPosition(){ + lastX = x; + lastY = y; + } + + void collision(Hitboxc other, float x, float y){ + + } + + float deltaX(){ + return x - lastX; + } + + float deltaY(){ + return y - lastY; + } + + boolean collides(Hitboxc other){ + return Intersector.overlapsRect(x - hitSize/2f, y - hitSize/2f, hitSize, hitSize, + other.x() - other.hitSize()/2f, other.y() - other.hitSize()/2f, other.hitSize(), other.hitSize()); + } + + @Override + public void hitbox(Rect rect){ + rect.setCentered(x, y, hitSize, hitSize); + } + + public void hitboxTile(Rect rect){ + float scale = 0.66f; + rect.setCentered(x, y, hitSize * scale, hitSize * scale); + } +} diff --git a/core/src/mindustry/entities/def/ItemsComp.java b/core/src/mindustry/entities/def/ItemsComp.java new file mode 100644 index 0000000000..a471197257 --- /dev/null +++ b/core/src/mindustry/entities/def/ItemsComp.java @@ -0,0 +1,50 @@ +package mindustry.entities.def; + +import arc.math.*; +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; +import mindustry.type.*; + +@Component +abstract class ItemsComp implements Posc{ + @ReadOnly ItemStack stack = new ItemStack(); + float itemTime; + + abstract int itemCapacity(); + + @Override + public void update(){ + stack.amount = Mathf.clamp(stack.amount, 0, itemCapacity()); + itemTime = Mathf.lerpDelta(itemTime, Mathf.num(hasItem()), 0.05f); + } + + Item item(){ + return stack.item; + } + + void clearItem(){ + stack.amount = 0; + } + + boolean acceptsItem(Item item){ + return !hasItem() || item == stack.item && stack.amount + 1 <= itemCapacity(); + } + + boolean hasItem(){ + return stack.amount > 0; + } + + void addItem(Item item){ + addItem(item, 1); + } + + void addItem(Item item, int amount){ + stack.amount = stack.item == item ? stack.amount + amount : amount; + stack.item = item; + stack.amount = Mathf.clamp(stack.amount, 0, itemCapacity()); + } + + int maxAccepted(Item item){ + return stack.item != item && stack.amount > 0 ? 0 : itemCapacity() - stack.amount; + } +} diff --git a/core/src/mindustry/entities/def/LegsComp.java b/core/src/mindustry/entities/def/LegsComp.java new file mode 100644 index 0000000000..f530a1997f --- /dev/null +++ b/core/src/mindustry/entities/def/LegsComp.java @@ -0,0 +1,25 @@ +package mindustry.entities.def; + +import arc.math.*; +import arc.util.*; +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class LegsComp implements Posc, Flyingc, Hitboxc, DrawLayerGroundUnderc, Unitc, Legsc, ElevationMovec{ + transient float x, y; + + float baseRotation, walkTime; + + @Override + public void update(){ + float len = vel().len(); + baseRotation = Angles.moveToward(baseRotation, vel().angle(), type().baseRotateSpeed * Mathf.clamp(len / type().speed)); + walkTime += Time.delta()*len/1f; + } + + @Override + public void drawGroundUnder(){ + type().drawLegs(this); + } +} diff --git a/core/src/mindustry/entities/def/MassComp.java b/core/src/mindustry/entities/def/MassComp.java new file mode 100644 index 0000000000..13ec0c2b9d --- /dev/null +++ b/core/src/mindustry/entities/def/MassComp.java @@ -0,0 +1,13 @@ +package mindustry.entities.def; + +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class MassComp implements Velc{ + float mass = 1f; + + public void impulse(float x, float y){ + vel().add(x / mass, y / mass); + } +} diff --git a/core/src/mindustry/entities/def/MinerComp.java b/core/src/mindustry/entities/def/MinerComp.java new file mode 100644 index 0000000000..5c9574085e --- /dev/null +++ b/core/src/mindustry/entities/def/MinerComp.java @@ -0,0 +1,104 @@ +package mindustry.entities.def; + +import arc.*; +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.math.*; +import arc.util.*; +import arc.util.ArcAnnotate.*; +import mindustry.annotations.Annotations.*; +import mindustry.content.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.input.*; +import mindustry.type.*; +import mindustry.world.*; + +import static mindustry.Vars.*; + +@Component +abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc{ + transient float x, y, rotation; + + float mineTimer; + @Nullable Tile mineTile; + + abstract boolean canMine(Item item); + + abstract float miningSpeed(); + + abstract boolean offloadImmediately(); + + boolean mining(){ + return mineTile != null; + } + + void updateMining(){ + Tilec core = closestCore(); + + if(core != null && mineTile != null && mineTile.drop() != null && !acceptsItem(mineTile.drop()) && dst(core) < mineTransferRange){ + int accepted = core.tile().block().acceptStack(item(), stack().amount, core.tile(), this); + if(accepted > 0){ + Call.transferItemTo(item(), accepted, + mineTile.worldx() + Mathf.range(tilesize / 2f), + mineTile.worldy() + Mathf.range(tilesize / 2f), core.tile()); + clearItem(); + } + } + + if(mineTile == null || core == null || mineTile.block() != Blocks.air || dst(mineTile.worldx(), mineTile.worldy()) > miningRange + || mineTile.drop() == null || !acceptsItem(mineTile.drop()) || !canMine(mineTile.drop())){ + mineTile = null; + mineTimer = 0f; + }else{ + Item item = mineTile.drop(); + rotation(Mathf.slerpDelta(rotation(), angleTo(mineTile.worldx(), mineTile.worldy()), 0.4f)); + mineTimer += Time.delta()*miningSpeed(); + + if(mineTimer >= 50f + item.hardness*10f){ + mineTimer = 0; + + if(dst(core) < mineTransferRange && core.tile().block().acceptStack(item, 1, core.tile(), this) == 1 && offloadImmediately()){ + Call.transferItemTo(item, 1, + mineTile.worldx() + Mathf.range(tilesize / 2f), + mineTile.worldy() + Mathf.range(tilesize / 2f), core.tile()); + }else if(acceptsItem(item)){ + //this is clientside, since items are synced anyway + InputHandler.transferItemToUnit(item, + mineTile.worldx() + Mathf.range(tilesize / 2f), + mineTile.worldy() + Mathf.range(tilesize / 2f), + this); + } + } + + if(Mathf.chance(0.06 * Time.delta())){ + Fx.pulverizeSmall.at(mineTile.worldx() + Mathf.range(tilesize / 2f), mineTile.worldy() + Mathf.range(tilesize / 2f), 0f, item.color); + } + } + } + + void drawOver(){ + if(!mining()) return; + float focusLen = 4f + Mathf.absin(Time.time(), 1.1f, 0.5f); + float swingScl = 12f, swingMag = tilesize / 8f; + float flashScl = 0.3f; + + float px = x + Angles.trnsx(rotation, focusLen); + float py = y + Angles.trnsy(rotation, focusLen); + + float ex = mineTile.worldx() + Mathf.sin(Time.time() + 48, swingScl, swingMag); + float ey = mineTile.worldy() + Mathf.sin(Time.time() + 48, swingScl + 2f, swingMag); + + 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); + + //TODO hack? + if(isLocal()){ + Lines.stroke(1f, Pal.accent); + Lines.poly(mineTile.worldx(), mineTile.worldy(), 4, tilesize / 2f * Mathf.sqrt2, Time.time()); + } + + Draw.color(); + } +} diff --git a/core/src/mindustry/entities/def/OwnerComp.java b/core/src/mindustry/entities/def/OwnerComp.java new file mode 100644 index 0000000000..e5e1f9d5ae --- /dev/null +++ b/core/src/mindustry/entities/def/OwnerComp.java @@ -0,0 +1,9 @@ +package mindustry.entities.def; + +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +class OwnerComp{ + Entityc owner; +} diff --git a/core/src/mindustry/entities/def/PlayerComp.java b/core/src/mindustry/entities/def/PlayerComp.java new file mode 100644 index 0000000000..1825ccf667 --- /dev/null +++ b/core/src/mindustry/entities/def/PlayerComp.java @@ -0,0 +1,207 @@ +package mindustry.entities.def; + +import arc.*; +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.math.*; +import arc.scene.ui.layout.*; +import arc.util.*; +import arc.util.ArcAnnotate.*; +import arc.util.pooling.*; +import mindustry.annotations.Annotations.*; +import mindustry.core.*; +import mindustry.entities.units.*; +import mindustry.game.*; +import mindustry.gen.*; +import mindustry.net.*; +import mindustry.net.Administration.*; +import mindustry.net.Packets.*; +import mindustry.ui.*; + +import static mindustry.Vars.*; + +@Component +abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc{ + @NonNull + @ReadOnly Unitc unit = Nulls.unit; + + @ReadOnly Team team = Team.sharded; + String name = "noname"; + @Nullable NetConnection con; + boolean admin, typing; + Color color = new Color(); + float mouseX, mouseY; + + @Nullable String lastText; + float textFadeTime; + + public boolean isBuilder(){ + return unit instanceof Builderc; + } + + public boolean isMiner(){ + return unit instanceof Minerc; + } + + public @Nullable Tilec closestCore(){ + return state.teams.closestCore(x(), y(), team); + } + + public void reset(){ + team = state.rules.defaultTeam; + admin = typing = false; + lastText = null; + textFadeTime = 0f; + if(!dead()){ + unit.controller(unit.type().createController()); + unit = Nulls.unit; + } + } + + public void update(){ + if(unit.dead()){ + clearUnit(); + } + + if(!dead()){ + x(unit.x()); + y(unit.y()); + unit.team(team); + } + textFadeTime -= Time.delta() / (60 * 5); + } + + public void team(Team team){ + if(unit != null){ + unit.team(team); + } + } + + public void clearUnit(){ + unit(Nulls.unit); + } + + public Unitc unit(){ + return unit; + } + + public Minerc miner(){ + return !(unit instanceof Minerc) ? Nulls.miner : (Minerc)unit; + } + + public Builderc builder(){ + return !(unit instanceof Builderc) ? Nulls.builder : (Builderc)unit; + } + + public void unit(Unitc unit){ + if(unit == null) throw new IllegalArgumentException("Unit cannot be null. Use clearUnit() instead."); + if(this.unit != Nulls.unit){ + //un-control the old unit + this.unit.controller(this.unit.type().createController()); + } + this.unit = unit; + if(unit != Nulls.unit){ + unit.team(team); + unit.controller(this); + } + } + + boolean dead(){ + return unit.isNull(); + } + + String uuid(){ + return con == null ? "[LOCAL]" : con.uuid; + } + + String usid(){ + return con == null ? "[LOCAL]" : con.usid; + } + + void kick(KickReason reason){ + con.kick(reason); + } + + void kick(String reason){ + con.kick(reason); + } + + void drawName(){ + 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 / Scl.scl(1f)); + layout.setText(font, name); + + if(!isLocal()){ + Draw.color(0f, 0f, 0f, 0.3f); + Fill.rect(unit.x(), unit.y() + nameHeight - layout.height / 2, layout.width + 2, layout.height + 3); + Draw.color(); + font.setColor(color); + font.draw(name, unit.x(), unit.y() + nameHeight, 0, Align.center, false); + + if(admin){ + float s = 3f; + Draw.color(color.r * 0.5f, color.g * 0.5f, color.b * 0.5f, 1f); + Draw.rect(Icon.adminSmall.getRegion(), unit.x() + layout.width / 2f + 2 + 1, unit.y() + nameHeight - 1.5f, s, s); + Draw.color(color); + Draw.rect(Icon.adminSmall.getRegion(), unit.x() + layout.width / 2f + 2 + 1, unit.y() + nameHeight - 1f, s, s); + } + } + + if(Core.settings.getBool("playerchat") && ((textFadeTime > 0 && lastText != null) || typing)){ + String text = textFadeTime <= 0 || lastText == null ? "[LIGHT_GRAY]" + Strings.animated(Time.time(), 4, 15f, ".") : lastText; + float width = 100f; + 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); + + Draw.color(0f, 0f, 0f, 0.3f * (textFadeTime <= 0 || lastText == null ? 1f : visualFadeTime)); + Fill.rect(unit.x(), unit.y() + textHeight + layout.height - layout.height/2f, layout.width + 2, layout.height + 3); + font.draw(text, unit.x() - width/2f, unit.y() + textHeight + layout.height, width, Align.center, true); + } + + Draw.reset(); + Pools.free(layout); + font.getData().setScale(1f); + font.setColor(Color.white); + font.setUseIntegerPositions(ints); + } + + void sendMessage(String text){ + if(isLocal()){ + if(ui != null){ + ui.chatfrag.addMessage(text, null); + } + }else{ + Call.sendMessage(con, text, null, null); + } + } + + void sendMessage(String text, Playerc from){ + sendMessage(text, from, NetClient.colorizeName(from.id(), from.name())); + } + + void sendMessage(String text, Playerc from, String fromName){ + if(isLocal()){ + if(ui != null){ + ui.chatfrag.addMessage(text, fromName); + } + }else{ + Call.sendMessage(con, text, fromName, from); + } + } + + PlayerInfo getInfo(){ + if(isLocal()){ + throw new IllegalArgumentException("Local players cannot be traced and do not have info."); + }else{ + return netServer.admins.getInfo(uuid()); + } + } +} diff --git a/core/src/mindustry/entities/def/PosComp.java b/core/src/mindustry/entities/def/PosComp.java new file mode 100644 index 0000000000..00b143acc4 --- /dev/null +++ b/core/src/mindustry/entities/def/PosComp.java @@ -0,0 +1,58 @@ +package mindustry.entities.def; + +import arc.math.geom.*; +import arc.util.ArcAnnotate.*; +import mindustry.*; +import mindustry.annotations.Annotations.*; +import mindustry.content.*; +import mindustry.world.*; +import mindustry.world.blocks.*; + +import static mindustry.Vars.world; + +@Component +abstract class PosComp implements Position{ + float x, y; + + void set(float x, float y){ + this.x = x; + this.y = y; + } + + void set(Position pos){ + set(pos.getX(), pos.getY()); + } + + void trns(float x, float y){ + set(this.x + x, this.y + y); + } + + int tileX(){ + return Vars.world.toTile(x); + } + + int tileY(){ + return Vars.world.toTile(y); + } + + /** Returns air if this unit is on a non-air top block. */ + public Floor floorOn(){ + Tile tile = tileOn(); + return tile == null || tile.block() != Blocks.air ? (Floor)Blocks.air : tile.floor(); + } + + public @Nullable + Tile tileOn(){ + return world.tileWorld(x, y); + } + + @Override + public float getX(){ + return x; + } + + @Override + public float getY(){ + return y; + } +} diff --git a/core/src/mindustry/entities/def/RotComp.java b/core/src/mindustry/entities/def/RotComp.java new file mode 100644 index 0000000000..8740b78935 --- /dev/null +++ b/core/src/mindustry/entities/def/RotComp.java @@ -0,0 +1,17 @@ +package mindustry.entities.def; + +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class RotComp implements Entityc{ + float rotation; + + void interpolate(){ + Syncc sync = as(Syncc.class); + + if(sync.interpolator().values.length > 0){ + rotation = sync.interpolator().values[0]; + } + } +} diff --git a/core/src/mindustry/entities/def/ShielderComp.java b/core/src/mindustry/entities/def/ShielderComp.java new file mode 100644 index 0000000000..86a038d9fb --- /dev/null +++ b/core/src/mindustry/entities/def/ShielderComp.java @@ -0,0 +1,12 @@ +package mindustry.entities.def; + +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class ShielderComp implements Damagec, Teamc, Posc{ + + void absorb(){ + + } +} diff --git a/core/src/mindustry/entities/def/StandardEffectComp.java b/core/src/mindustry/entities/def/StandardEffectComp.java new file mode 100644 index 0000000000..4de2986f3d --- /dev/null +++ b/core/src/mindustry/entities/def/StandardEffectComp.java @@ -0,0 +1,13 @@ +package mindustry.entities.def; + +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class StandardEffectComp implements Effectc, DrawLayerEffectsc{ + + @Override + public void drawEffects(){ + draw(); + } +} diff --git a/core/src/mindustry/entities/units/Statuses.java b/core/src/mindustry/entities/def/StatusComp.java similarity index 50% rename from core/src/mindustry/entities/units/Statuses.java rename to core/src/mindustry/entities/def/StatusComp.java index 637bbf1a55..f504f6c4f0 100644 --- a/core/src/mindustry/entities/units/Statuses.java +++ b/core/src/mindustry/entities/def/StatusComp.java @@ -1,34 +1,38 @@ -package mindustry.entities.units; +package mindustry.entities.def; -import arc.struct.Bits; -import arc.struct.*; import arc.graphics.*; +import arc.math.*; +import arc.struct.*; import arc.util.*; import arc.util.pooling.*; +import mindustry.annotations.Annotations.*; import mindustry.content.*; -import mindustry.ctype.ContentType; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; +import mindustry.ctype.*; +import mindustry.entities.units.*; +import mindustry.gen.*; import mindustry.type.*; +import mindustry.world.blocks.*; import java.io.*; import static mindustry.Vars.content; -/** Class for controlling status effects on an entity. */ -public class Statuses implements Saveable{ - private static final StatusEntry globalResult = new StatusEntry(); - private static final Array removals = new Array<>(); - +@Component +abstract class StatusComp implements Posc, Flyingc{ private Array statuses = new Array<>(); private Bits applied = new Bits(content.getBy(ContentType.status).size); - private float speedMultiplier; - private float damageMultiplier; - private float armorMultiplier; + @ReadOnly float speedMultiplier; + @ReadOnly float damageMultiplier; + @ReadOnly float armorMultiplier; - public void handleApply(Unit unit, StatusEffect effect, float duration){ - if(effect == StatusEffects.none || effect == null || unit.isImmune(effect)) return; //don't apply empty or immune effects + /** @return damage taken based on status armor multipliers */ + float getShieldDamage(float amount){ + return amount * Mathf.clamp(1f - armorMultiplier / 100f); + } + + void apply(StatusEffect effect, float duration){ + if(effect == StatusEffects.none || effect == null || isImmune(effect)) return; //don't apply empty or immune effects if(statuses.size > 0){ //check for opposite effects @@ -38,12 +42,12 @@ public class Statuses implements Saveable{ entry.time = Math.max(entry.time, duration); return; }else if(entry.effect.reactsWith(effect)){ //find opposite - globalResult.effect = entry.effect; - entry.effect.getTransition(unit, effect, entry.time, duration, globalResult); - entry.time = globalResult.time; + StatusEntry.tmp.effect = entry.effect; + entry.effect.getTransition((Unitc)this, effect, entry.time, duration, StatusEntry.tmp); + entry.time = StatusEntry.tmp.time; - if(globalResult.effect != entry.effect){ - entry.effect = globalResult.effect; + if(StatusEntry.tmp.effect != entry.effect){ + entry.effect = StatusEntry.tmp.effect; } //stop looking when one is found @@ -58,70 +62,68 @@ public class Statuses implements Saveable{ statuses.add(entry); } - public Color getStatusColor(){ + boolean isBoss(){ + return hasEffect(StatusEffects.boss); + } + + abstract boolean isImmune(StatusEffect effect); + + Color statusColor(){ if(statuses.size == 0){ return Tmp.c1.set(Color.white); } - float r = 0f, g = 0f, b = 0f; + float r = 1f, g = 1f, b = 1f, total = 0f; for(StatusEntry entry : statuses){ - r += entry.effect.color.r; - g += entry.effect.color.g; - b += entry.effect.color.b; + float intensity = entry.time < 10f ? entry.time/10f : 1f; + r += entry.effect.color.r * intensity; + g += entry.effect.color.g * intensity; + b += entry.effect.color.b * intensity; + total += intensity; } - return Tmp.c1.set(r / statuses.size, g / statuses.size, b / statuses.size, 1f); + float count = statuses.size + total; + return Tmp.c1.set(r / count, g / count, b / count, 1f); } - public void clear(){ - statuses.clear(); - } + @Override + public void update(){ + Floor floor = floorOn(); + if(isGrounded() && floor.status != null){ + //apply effect + apply(floor.status, floor.statusDuration); + } - public void update(Unit unit){ applied.clear(); speedMultiplier = damageMultiplier = armorMultiplier = 1f; - if(statuses.size == 0) return; + if(statuses.isEmpty()) return; - removals.clear(); - - for(StatusEntry entry : statuses){ + statuses.eachFilter(entry -> { entry.time = Math.max(entry.time - Time.delta(), 0); applied.set(entry.effect.id); if(entry.time <= 0){ Pools.free(entry); - removals.add(entry); + return true; }else{ speedMultiplier *= entry.effect.speedMultiplier; armorMultiplier *= entry.effect.armorMultiplier; damageMultiplier *= entry.effect.damageMultiplier; - entry.effect.update(unit, entry.time); + //TODO ugly casting + entry.effect.update((Unitc)this, entry.time); } - } - if(removals.size > 0){ - statuses.removeAll(removals, true); - } + return false; + }); } - public float getSpeedMultiplier(){ - return speedMultiplier; - } - - public float getDamageMultiplier(){ - return damageMultiplier; - } - - public float getArmorMultiplier(){ - return armorMultiplier; - } - - public boolean hasEffect(StatusEffect effect){ + boolean hasEffect(StatusEffect effect){ return applied.get(effect.id); } - @Override - public void writeSave(DataOutput stream) throws IOException{ + //TODO autogen io code + + void writeSave(DataOutput stream) throws IOException{ stream.writeByte(statuses.size); for(StatusEntry entry : statuses){ stream.writeByte(entry.effect.id); @@ -129,8 +131,7 @@ public class Statuses implements Saveable{ } } - @Override - public void readSave(DataInput stream, byte version) throws IOException{ + void readSave(DataInput stream, byte version) throws IOException{ for(StatusEntry effect : statuses){ Pools.free(effect); } @@ -146,15 +147,4 @@ public class Statuses implements Saveable{ statuses.add(entry); } } - - public static class StatusEntry{ - public StatusEffect effect; - public float time; - - public StatusEntry set(StatusEffect effect, float time){ - this.effect = effect; - this.time = time; - return this; - } - } } diff --git a/core/src/mindustry/entities/def/SyncComp.java b/core/src/mindustry/entities/def/SyncComp.java new file mode 100644 index 0000000000..cbe2e6735f --- /dev/null +++ b/core/src/mindustry/entities/def/SyncComp.java @@ -0,0 +1,37 @@ +package mindustry.entities.def; + +import mindustry.*; +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; +import mindustry.net.*; + +@Component +abstract class SyncComp implements Posc{ + transient float x, y; + + Interpolator interpolator = new Interpolator(); + + void setNet(float x, float y){ + set(x, y); + + //TODO change interpolator API + interpolator.target.set(x, y); + interpolator.last.set(x, y); + interpolator.pos.set(0, 0); + interpolator.updateSpacing = 16; + interpolator.lastUpdated = 0; + } + + @Override + public void update(){ + if(Vars.net.client() && !isLocal()){ + interpolate(); + } + } + + void interpolate(){ + interpolator.update(); + x = interpolator.pos.x; + y = interpolator.pos.y; + } +} diff --git a/core/src/mindustry/entities/def/TeamComp.java b/core/src/mindustry/entities/def/TeamComp.java new file mode 100644 index 0000000000..c9c540634e --- /dev/null +++ b/core/src/mindustry/entities/def/TeamComp.java @@ -0,0 +1,20 @@ +package mindustry.entities.def; + +import arc.util.ArcAnnotate.*; +import mindustry.annotations.Annotations.*; +import mindustry.game.*; +import mindustry.gen.*; + +import static mindustry.Vars.state; + +@Component +abstract class TeamComp implements Posc{ + transient float x, y; + + Team team = Team.sharded; + + public @Nullable + Tilec closestCore(){ + return state.teams.closestCore(x, y, team); + } +} diff --git a/core/src/mindustry/entities/def/TileComp.java b/core/src/mindustry/entities/def/TileComp.java new file mode 100644 index 0000000000..697d7d44c7 --- /dev/null +++ b/core/src/mindustry/entities/def/TileComp.java @@ -0,0 +1,241 @@ +package mindustry.entities.def; + +import arc.*; +import arc.math.geom.*; +import arc.struct.*; +import arc.util.*; +import arc.util.ArcAnnotate.*; +import mindustry.annotations.Annotations.*; +import mindustry.game.*; +import mindustry.game.EventType.*; +import mindustry.gen.*; +import mindustry.world.*; +import mindustry.world.consumers.*; +import mindustry.world.modules.*; + +import static mindustry.Vars.*; + +@Component +abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc{ + static final float timeToSleep = 60f * 1; + static final ObjectSet tmpTiles = new ObjectSet<>(); + static int sleepingEntities = 0; + + Tile tile; + Block block; + Array proximity = new Array<>(8); + + PowerModule power; + ItemModule items; + LiquidModule liquids; + ConsumeModule cons; + + private float timeScale = 1f, timeScaleDuration; + + private @Nullable SoundLoop sound; + + private boolean sleeping; + private float sleepTime; + + /** Sets this tile entity data to this tile, and adds it if necessary. */ + @Override + public Tilec init(Tile tile, boolean shouldAdd){ + this.tile = tile; + this.block = tile.block(); + + set(tile.drawx(), tile.drawy()); + if(block.activeSound != Sounds.none){ + sound = new SoundLoop(block.activeSound, block.activeSoundVolume); + } + + health(block.health); + maxHealth(block.health); + timer(new Interval(block.timers)); + + if(shouldAdd){ + add(); + } + + return this; + } + + @Override + public void applyBoost(float intensity, float duration){ + timeScale = Math.max(timeScale, intensity); + timeScaleDuration = Math.max(timeScaleDuration, duration); + } + + @Override + public float timeScale(){ + return timeScale; + } + + @Override + public boolean consValid(){ + return cons.valid(); + } + + @Override + public void consume(){ + cons.trigger(); + } + + /** Scaled delta. */ + @Override + public float delta(){ + return Time.delta() * timeScale; + } + + /** Base efficiency. If this entity has non-buffered power, returns the power %, otherwise returns 1. */ + @Override + public float efficiency(){ + return power != null && (block.consumes.has(ConsumeType.power) && !block.consumes.getPower().buffered) ? power.status : 1f; + } + + /** Call when nothing is happening to the entity. This increments the internal sleep timer. */ + @Override + public void sleep(){ + sleepTime += Time.delta(); + if(!sleeping && sleepTime >= timeToSleep){ + remove(); + sleeping = true; + sleepingEntities++; + } + } + + /** Call when this entity is updating. This wakes it up. */ + @Override + public void noSleep(){ + sleepTime = 0f; + if(sleeping){ + add(); + sleeping = false; + sleepingEntities--; + } + } + + /** Returns the version of this TileEntity IO code.*/ + @Override + public byte version(){ + return 0; + } + + @Override + public boolean collide(Bulletc other){ + return true; + } + + @Override + public void collision(Bulletc other){ + block.handleBulletHit(this, other); + } + + //TODO Implement damage! + + @Override + public void removeFromProximity(){ + block.onProximityRemoved(tile); + + Point2[] nearby = Edges.getEdges(block.size); + for(Point2 point : nearby){ + Tile other = world.ltile(tile.x + point.x, tile.y + point.y); + //remove this tile from all nearby tile's proximities + if(other != null){ + other.block().onProximityUpdate(other); + + if(other.entity != null){ + other.entity.proximity().remove(tile, true); + } + } + } + } + + @Override + public void updateProximity(){ + tmpTiles.clear(); + proximity.clear(); + + Point2[] nearby = Edges.getEdges(block.size); + for(Point2 point : nearby){ + Tile other = world.ltile(tile.x + point.x, tile.y + point.y); + + if(other == null) continue; + if(other.entity == null || !(other.interactable(tile.team()))) continue; + + //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 + for(Tile tile : tmpTiles){ + proximity.add(tile); + } + + block.onProximityAdded(tile); + block.onProximityUpdate(tile); + + for(Tile other : tmpTiles){ + other.block().onProximityUpdate(other); + } + } + + @Override + public Array proximity(){ + return proximity; + } + + /** Tile configuration. Defaults to 0. Used for block rebuilding. */ + @Override + public int config(){ + return 0; + } + + @Override + public void remove(){ + if(sound != null){ + sound.stop(); + } + } + + @Override + public void killed(){ + Events.fire(new BlockDestroyEvent(tile)); + block.breakSound.at(tile); + block.onDestroyed(tile); + tile.remove(); + } + + @Override + public void update(){ + timeScaleDuration -= Time.delta(); + if(timeScaleDuration <= 0f || !block.canOverdrive){ + timeScale = 1f; + } + + if(sound != null){ + sound.update(x(), y(), block.shouldActiveSound(tile)); + } + + if(block.idleSound != Sounds.none && block.shouldIdleSound(tile)){ + loops.play(block.idleSound, this, block.idleSoundVolume); + } + + block.update(tile); + + if(liquids != null){ + liquids.update(); + } + + if(cons != null){ + cons.update(); + } + + if(power != null){ + power.graph.update(); + } + } +} diff --git a/core/src/mindustry/entities/def/TimedComp.java b/core/src/mindustry/entities/def/TimedComp.java new file mode 100644 index 0000000000..f3b5f97317 --- /dev/null +++ b/core/src/mindustry/entities/def/TimedComp.java @@ -0,0 +1,27 @@ +package mindustry.entities.def; + +import arc.math.*; +import arc.util.*; +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class TimedComp implements Entityc, Scaled{ + float time, lifetime; + + //called last so pooling and removal happens then. + @MethodPriority(100) + @Override + public void update(){ + time = Math.min(time + Time.delta(), lifetime); + + if(time >= lifetime){ + remove(); + } + } + + @Override + public float fin(){ + return time / lifetime; + } +} diff --git a/core/src/mindustry/entities/def/TimerComp.java b/core/src/mindustry/entities/def/TimerComp.java new file mode 100644 index 0000000000..a23e8e09ac --- /dev/null +++ b/core/src/mindustry/entities/def/TimerComp.java @@ -0,0 +1,13 @@ +package mindustry.entities.def; + +import arc.util.*; +import mindustry.annotations.Annotations.*; + +@Component +abstract class TimerComp{ + Interval timer = new Interval(6); + + public boolean timer(int index, float time){ + return timer.get(index, time); + } +} diff --git a/core/src/mindustry/entities/def/UnitComp.java b/core/src/mindustry/entities/def/UnitComp.java new file mode 100644 index 0000000000..1a06adad1d --- /dev/null +++ b/core/src/mindustry/entities/def/UnitComp.java @@ -0,0 +1,167 @@ +package mindustry.entities.def; + +import arc.*; +import arc.math.*; +import arc.math.geom.*; +import arc.util.*; +import mindustry.annotations.Annotations.*; +import mindustry.content.*; +import mindustry.entities.*; +import mindustry.entities.units.*; +import mindustry.game.EventType.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.type.*; +import mindustry.world.*; +import mindustry.world.blocks.*; + +import static mindustry.Vars.*; + +@Component +abstract class UnitComp implements Healthc, Velc, Statusc, Teamc, Itemsc, Hitboxc, Rotc, Massc, Unitc, Weaponsc, Drawc, + DrawLayerGroundc, DrawLayerFlyingc, DrawLayerGroundShadowsc, DrawLayerFlyingShadowsc{ + transient float x, y, rotation; + + private UnitController controller; + private UnitDef type; + + @Override + public float clipSize(){ + return type.region.getWidth() * 2f; + } + + @Override + public int itemCapacity(){ + return type.itemCapacity; + } + + @Override + public float bounds(){ + return hitSize() * 2f; + } + + @Override + public void controller(UnitController controller){ + this.controller = controller; + if(controller.unit() != this) controller.unit(this); + } + + @Override + public UnitController controller(){ + return controller; + } + + @Override + public void set(UnitDef def, UnitController controller){ + type(type); + controller(controller); + } + + @Override + public void type(UnitDef type){ + this.type = type; + maxHealth(type.health); + heal(); + drag(type.drag); + hitSize(type.hitsize); + controller(type.createController()); + setupWeapons(type); + } + + @Override + public UnitDef type(){ + return type; + } + + public void lookAt(float angle){ + rotation = Angles.moveToward(rotation, angle, type.rotateSpeed); + } + + public void lookAt(Position pos){ + lookAt(angleTo(pos)); + } + + @Override + public void update(){ + drag(type.drag * (isGrounded() ? (floorOn().dragMultiplier) : 1f)); + + //apply knockback based on spawns + //TODO move elsewhere + if(team() != state.rules.waveTeam){ + float relativeSize = state.rules.dropZoneRadius + bounds()/2f + 1f; + for(Tile spawn : spawner.getGroundSpawns()){ + if(withinDst(spawn.worldx(), spawn.worldy(), relativeSize)){ + vel().add(Tmp.v1.set(this).sub(spawn.worldx(), spawn.worldy()).setLength(0.1f + 1f - dst(spawn) / relativeSize).scl(0.45f * Time.delta())); + } + } + } + + Tile tile = tileOn(); + Floor floor = floorOn(); + + if(tile != null){ + //unit block update + tile.block().unitOn(tile, this); + + //apply damage + if(floor.damageTaken > 0f){ + damageContinuous(floor.damageTaken); + } + } + } + + @Override + public boolean isImmune(StatusEffect effect){ + return type.immunities.contains(effect); + } + + @Override + public void draw(){ + type.drawBody(this); + type.drawWeapons(this); + if(type.drawCell) type.drawCell(this); + if(type.drawItems) type.drawItems(this); + type.drawLight(this); + } + + @Override + public void drawFlyingShadows(){ + if(isFlying()) type.drawShadow(this); + } + + @Override + public void drawGroundShadows(){ + type.drawOcclusion(this); + } + + @Override + public void drawFlying(){ + if(isFlying()) draw(); + } + + @Override + public void drawGround(){ + if(isGrounded()) draw(); + } + + @Override + public void killed(){ + float explosiveness = 2f + item().explosiveness * stack().amount; + float flammability = item().flammability * stack().amount; + Damage.dynamicExplosion(x, y, flammability, explosiveness, 0f, bounds() / 2f, Pal.darkFlame); + + //TODO cleanup + //ScorchDecal.create(getX(), getY()); + Effects.scorch(x, y, (int)(hitSize() / 5)); + Fx.explosion.at(this); + Effects.shake(2f, 2f, this); + type.deathSound.at(this); + + Events.fire(new UnitDestroyEvent(this)); + + //TODO implement suicide bomb trigger + //if(explosiveness > 7f && this == player){ + // Events.fire(Trigger.suicideBomb); + //} + } +} diff --git a/core/src/mindustry/entities/def/VelComp.java b/core/src/mindustry/entities/def/VelComp.java new file mode 100644 index 0000000000..7155b804c6 --- /dev/null +++ b/core/src/mindustry/entities/def/VelComp.java @@ -0,0 +1,27 @@ +package mindustry.entities.def; + +import arc.math.geom.*; +import arc.util.*; +import mindustry.annotations.Annotations.*; +import mindustry.gen.*; + +@Component +abstract class VelComp implements Posc{ + transient float x, y; + + final Vec2 vel = new Vec2(); + float drag = 0f; + + //velocity needs to be called first, as it affects delta and lastPosition + @MethodPriority(-1) + @Override + public void update(){ + move(vel.x, vel.y); + vel.scl(1f - drag * Time.delta()); + } + + void move(float cx, float cy){ + x += cx; + y += cy; + } +} diff --git a/core/src/mindustry/entities/def/WaterMoveComp.java b/core/src/mindustry/entities/def/WaterMoveComp.java new file mode 100644 index 0000000000..a5d44f1239 --- /dev/null +++ b/core/src/mindustry/entities/def/WaterMoveComp.java @@ -0,0 +1,41 @@ +package mindustry.entities.def; + +import mindustry.annotations.Annotations.*; +import mindustry.content.*; +import mindustry.entities.*; +import mindustry.gen.*; +import mindustry.world.blocks.*; + +import static mindustry.Vars.collisions; + +//just a proof of concept +@Component +abstract class WaterMoveComp implements Posc, Velc, Hitboxc, Flyingc{ + transient float x, y; + + @Replace + @Override + public void move(float cx, float cy){ + if(isGrounded()){ + if(!EntityCollisions.waterSolid(tileX(), tileY())){ + collisions.move(this, cx, cy, EntityCollisions::waterSolid); + } + }else{ + x += cx; + y += cy; + } + } + + @Replace + @Override + public boolean canDrown(){ + return false; + } + + @Replace + public float floorSpeedMultiplier(){ + Floor on = isFlying() ? Blocks.air.asFloor() : floorOn(); + return on.isDeep() ? 1.3f : 1f; + } +} + diff --git a/core/src/mindustry/entities/def/WeaponsComp.java b/core/src/mindustry/entities/def/WeaponsComp.java new file mode 100644 index 0000000000..5012de6281 --- /dev/null +++ b/core/src/mindustry/entities/def/WeaponsComp.java @@ -0,0 +1,137 @@ +package mindustry.entities.def; + +import arc.math.*; +import arc.math.geom.*; +import arc.util.*; +import mindustry.annotations.Annotations.*; +import mindustry.entities.*; +import mindustry.entities.bullet.*; +import mindustry.entities.units.*; +import mindustry.gen.*; +import mindustry.type.*; + +@Component +abstract class WeaponsComp implements Teamc, Posc, Rotc{ + transient float x, y, rotation; + + /** minimum cursor distance from player, fixes 'cross-eyed' shooting */ + static final float minAimDst = 20f; + /** temporary weapon sequence number */ + static int sequenceNum = 0; + + /** weapon mount array, never null */ + @ReadOnly WeaponMount[] mounts = {}; + + void setupWeapons(UnitDef def){ + mounts = new WeaponMount[def.weapons.size]; + for(int i = 0; i < mounts.length; i++){ + mounts[i] = new WeaponMount(def.weapons.get(i)); + } + } + + void controlWeapons(boolean rotate, boolean shoot){ + for(WeaponMount mount : mounts){ + mount.rotate = rotate; + mount.shoot = shoot; + } + } + + void aim(Position pos){ + aim(pos.getX(), pos.getY()); + } + + /** Aim at something. This will make all mounts point at it. */ + void aim(float x, float y){ + Tmp.v1.set(x, y).sub(this.x, this.y); + if(Tmp.v1.len() < minAimDst) Tmp.v1.setLength(minAimDst); + + x = Tmp.v1.x + this.x; + y = Tmp.v1.y + this.y; + + for(WeaponMount mount : mounts){ + mount.aimX = x; + mount.aimY = y; + } + } + + /** Update shooting and rotation for this unit. */ + @Override + public void update(){ + for(WeaponMount mount : mounts){ + Weapon weapon = mount.weapon; + mount.reload = Math.max(mount.reload - Time.delta(), 0); + + //rotate if applicable + if(weapon.rotate && (mount.rotate || mount.shoot)){ + float axisXOffset = weapon.mirror ? 0f : weapon.x; + float axisX = this.x + Angles.trnsx(rotation, axisXOffset, weapon.y), + axisY = this.y + Angles.trnsy(rotation, axisXOffset, weapon.y); + + mount.rotation = Angles.moveToward(mount.rotation, Angles.angle(axisX, axisY, mount.aimX, mount.aimY) - rotation(), weapon.rotateSpeed); + } + + if(mount.shoot){ + float rotation = this.rotation - 90; + + //shoot if applicable + //TODO only shoot if angle is reached, don't shoot inaccurately + if(mount.reload <= 0.0001f){ + for(int i : (weapon.mirror && !weapon.alternate ? Mathf.signs : Mathf.one)){ + i *= Mathf.sign(weapon.flipped) * Mathf.sign(mount.side); + + //m a t h + float weaponRotation = rotation + (weapon.rotate ? mount.rotation : 0); + float mountX = this.x + Angles.trnsx(rotation, weapon.x * i, weapon.y), + mountY = this.y + Angles.trnsy(rotation, weapon.x * i, weapon.y); + float shootX = mountX + Angles.trnsx(weaponRotation, weapon.shootX * i, weapon.shootY), + shootY = mountY + Angles.trnsy(weaponRotation, weapon.shootX * i, weapon.shootY); + float shootAngle = weapon.rotate ? weaponRotation + 90 : Angles.angle(shootX, shootY, mount.aimX, mount.aimY); + + shoot(weapon, shootX, shootY, shootAngle); + } + + mount.side = !mount.side; + mount.reload = weapon.reload; + } + } + } + } + + private void shoot(Weapon weapon, float x, float y, float rotation){ + float baseX = this.x, baseY = this.y; + + weapon.shootSound.at(x, y, Mathf.random(0.8f, 1.0f)); + + sequenceNum = 0; + if(weapon.shotDelay > 0.01f){ + Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> { + Time.run(sequenceNum * weapon.shotDelay, () -> bullet(weapon, x + this.x - baseX, y + this.y - baseY, f + Mathf.range(weapon.inaccuracy))); + sequenceNum++; + }); + }else{ + Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> bullet(weapon, x, y, f + Mathf.range(weapon.inaccuracy))); + } + + BulletType ammo = weapon.bullet; + + Tmp.v1.trns(rotation + 180f, ammo.recoil); + + if(this instanceof Velc){ + //TODO apply force? + ((Velc)this).vel().add(Tmp.v1); + } + + Tmp.v1.trns(rotation, 3f); + boolean parentize = ammo.keepVelocity; + + Effects.shake(weapon.shake, weapon.shake, x, y); + weapon.ejectEffect.at(x, y, rotation); + ammo.shootEffect.at(x + Tmp.v1.x, y + Tmp.v1.y, rotation, parentize ? this : null); + ammo.smokeEffect.at(x + Tmp.v1.x, y + Tmp.v1.y, rotation, parentize ? this : null); + } + + private void bullet(Weapon weapon, float x, float y, float angle){ + Tmp.v1.trns(angle, 3f); + weapon.bullet.create(this, team(), x + Tmp.v1.x, y + Tmp.v1.y, angle, (1f - weapon.velocityRnd) + Mathf.random(weapon.velocityRnd)); + } +} diff --git a/core/src/mindustry/entities/effect/Decal.java b/core/src/mindustry/entities/effect/Decal.java deleted file mode 100644 index cbe0e8edb2..0000000000 --- a/core/src/mindustry/entities/effect/Decal.java +++ /dev/null @@ -1,36 +0,0 @@ -package mindustry.entities.effect; - -import arc.graphics.g2d.Draw; -import arc.math.Mathf; -import mindustry.entities.EntityGroup; -import mindustry.entities.type.TimedEntity; -import mindustry.entities.traits.BelowLiquidTrait; -import mindustry.entities.traits.DrawTrait; -import mindustry.graphics.Pal; - -import static mindustry.Vars.groundEffectGroup; - -/** - * Class for creating block rubble on the ground. - */ -public abstract class Decal extends TimedEntity implements BelowLiquidTrait, DrawTrait{ - - @Override - public float lifetime(){ - return 3600; - } - - @Override - public void draw(){ - Draw.color(Pal.rubble.r, Pal.rubble.g, Pal.rubble.b, 1f - Mathf.curve(fin(), 0.98f)); - drawDecal(); - Draw.color(); - } - - @Override - public EntityGroup targetGroup(){ - return groundEffectGroup; - } - - abstract void drawDecal(); -} diff --git a/core/src/mindustry/entities/effect/Fire.java b/core/src/mindustry/entities/effect/Fire.java deleted file mode 100644 index a3e15873fa..0000000000 --- a/core/src/mindustry/entities/effect/Fire.java +++ /dev/null @@ -1,229 +0,0 @@ -package mindustry.entities.effect; - -import arc.*; -import mindustry.annotations.Annotations.*; -import arc.struct.*; -import arc.math.*; -import arc.math.geom.*; -import arc.util.*; -import mindustry.content.*; -import mindustry.entities.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; -import mindustry.game.EventType.*; -import mindustry.game.*; -import mindustry.gen.*; -import mindustry.type.*; -import mindustry.world.*; - -import java.io.*; - -import static mindustry.Vars.*; - -public class Fire extends TimedEntity implements SaveTrait, SyncTrait{ - private static final IntMap map = new IntMap<>(); - private static final float baseLifetime = 1000f, spreadChance = 0.05f, fireballChance = 0.07f; - - private int loadedPosition = -1; - private Tile tile; - private Block block; - private float baseFlammability = -1, puddleFlammability; - private float lifetime; - - /** Deserialization use only! */ - public Fire(){ - } - - @Remote - public static void onRemoveFire(int fid){ - fireGroup.removeByID(fid); - } - - /** 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. - - Fire fire = map.get(tile.pos()); - - if(fire == null){ - fire = new Fire(); - fire.tile = tile; - fire.lifetime = baseLifetime; - fire.set(tile.worldx(), tile.worldy()); - fire.add(); - map.put(tile.pos(), fire); - }else{ - fire.lifetime = baseLifetime; - fire.time = 0f; - } - } - - public static boolean has(int x, int y){ - if(!Structs.inBounds(x, y, world.width(), world.height()) || !map.containsKey(Pos.get(x, y))){ - return false; - } - Fire fire = map.get(Pos.get(x, y)); - return fire.isAdded() && fire.fin() < 1f && fire.tile != null && fire.tile.x == x && fire.tile.y == y; - } - - /** - * Attempts to extinguish a fire by shortening its life. If there is no fire here, does nothing. - */ - public static void extinguish(Tile tile, float intensity){ - if(tile != null && map.containsKey(tile.pos())){ - Fire fire = map.get(tile.pos()); - fire.time += intensity * Time.delta(); - if(fire.time >= fire.lifetime()){ - Events.fire(Trigger.fireExtinguish); - } - } - } - - @Override - public TypeID getTypeID(){ - return TypeIDs.fire; - } - - @Override - public byte version(){ - return 0; - } - - @Override - public float lifetime(){ - return lifetime; - } - - @Override - public void update(){ - if(Mathf.chance(0.1 * Time.delta())){ - Effects.effect(Fx.fire, x + Mathf.range(4f), y + Mathf.range(4f)); - } - - if(Mathf.chance(0.05 * Time.delta())){ - Effects.effect(Fx.fireSmoke, x + Mathf.range(4f), y + Mathf.range(4f)); - } - - if(Mathf.chance(0.001 * Time.delta())){ - Sounds.fire.at(this); - } - - time = Mathf.clamp(time + Time.delta(), 0, lifetime()); - map.put(tile.pos(), this); - - if(net.client()){ - return; - } - - if(time >= lifetime() || tile == null){ - remove(); - return; - } - - TileEntity entity = tile.link().entity; - boolean damage = entity != null; - - float flammability = baseFlammability + puddleFlammability; - - if(!damage && flammability <= 0){ - time += Time.delta() * 8; - } - - if(baseFlammability < 0 || block != tile.block()){ - baseFlammability = tile.block().getFlammability(tile); - block = tile.block(); - } - - if(damage){ - lifetime += Mathf.clamp(flammability / 8f, 0f, 0.6f) * Time.delta(); - } - - if(flammability > 1f && Mathf.chance(spreadChance * Time.delta() * Mathf.clamp(flammability / 5f, 0.3f, 2f))){ - Point2 p = Geometry.d4[Mathf.random(3)]; - Tile other = world.tile(tile.x + p.x, tile.y + p.y); - create(other); - - if(Mathf.chance(fireballChance * Time.delta() * Mathf.clamp(flammability / 10f))){ - Call.createBullet(Bullets.fireball, Team.derelict, x, y, Mathf.random(360f), 1, 1); - } - } - - if(Mathf.chance(0.1 * Time.delta())){ - Puddle p = Puddle.getPuddle(tile); - if(p != null){ - puddleFlammability = p.getFlammability() / 3f; - }else{ - puddleFlammability = 0; - } - - if(damage){ - entity.damage(0.4f); - } - Damage.damageUnits(null, tile.worldx(), tile.worldy(), tilesize, 3f, - unit -> !unit.isFlying() && !unit.isImmune(StatusEffects.burning), - unit -> unit.applyEffect(StatusEffects.burning, 60 * 5)); - } - } - - @Override - public void writeSave(DataOutput stream) throws IOException{ - stream.writeInt(tile.pos()); - stream.writeFloat(lifetime); - stream.writeFloat(time); - } - - @Override - public void readSave(DataInput stream, byte version) throws IOException{ - this.loadedPosition = stream.readInt(); - this.lifetime = stream.readFloat(); - this.time = stream.readFloat(); - add(); - } - - @Override - public void write(DataOutput data) throws IOException{ - data.writeInt(tile.pos()); - data.writeFloat(lifetime); - } - - @Override - public void read(DataInput data) throws IOException{ - int pos = data.readInt(); - this.lifetime = data.readFloat(); - - x = Pos.x(pos) * tilesize; - y = Pos.y(pos) * tilesize; - tile = world.tile(pos); - } - - @Override - public void reset(){ - loadedPosition = -1; - tile = null; - baseFlammability = -1; - puddleFlammability = 0f; - incrementID(); - } - - @Override - public void added(){ - if(loadedPosition != -1){ - map.put(loadedPosition, this); - tile = world.tile(loadedPosition); - set(tile.worldx(), tile.worldy()); - } - } - - @Override - public void removed(){ - if(tile != null){ - Call.onRemoveFire(id); - map.remove(tile.pos()); - } - } - - @Override - public EntityGroup targetGroup(){ - return fireGroup; - } -} diff --git a/core/src/mindustry/entities/effect/GroundEffectEntity.java b/core/src/mindustry/entities/effect/GroundEffectEntity.java deleted file mode 100644 index 644757512c..0000000000 --- a/core/src/mindustry/entities/effect/GroundEffectEntity.java +++ /dev/null @@ -1,90 +0,0 @@ -package mindustry.entities.effect; - -import arc.math.Mathf; -import arc.util.Time; -import mindustry.Vars; -import mindustry.entities.Effects; -import mindustry.entities.Effects.Effect; -import mindustry.entities.Effects.EffectRenderer; -import mindustry.entities.type.EffectEntity; -import mindustry.world.Tile; - -/** - * A ground effect contains an effect that is rendered on the ground layer as opposed to the top layer. - */ -public class GroundEffectEntity extends EffectEntity{ - private boolean once; - - @Override - public void update(){ - GroundEffect effect = (GroundEffect)this.effect; - - if(effect.isStatic){ - time += Time.delta(); - - time = Mathf.clamp(time, 0, effect.staticLife); - - if(!once && time >= lifetime()){ - once = true; - time = 0f; - Tile tile = Vars.world.tileWorld(x, y); - if(tile != null && tile.floor().isLiquid){ - remove(); - } - }else if(once && time >= effect.staticLife){ - remove(); - } - }else{ - super.update(); - } - } - - @Override - public void draw(){ - GroundEffect effect = (GroundEffect)this.effect; - - if(once && effect.isStatic) - Effects.renderEffect(id, effect, color, lifetime(), rotation, x, y, data); - else - Effects.renderEffect(id, effect, color, time, rotation, x, y, data); - } - - @Override - public void reset(){ - super.reset(); - once = false; - } - - /** - * An effect that is rendered on the ground layer as opposed to the top layer. - */ - public static class GroundEffect extends Effect{ - /** - * How long this effect stays on the ground when static. - */ - public final float staticLife; - /** - * If true, this effect will stop and lie on the ground for a specific duration, - * after its initial lifetime is over. - */ - public final boolean isStatic; - - public GroundEffect(float life, float staticLife, EffectRenderer draw){ - super(life, draw); - this.staticLife = staticLife; - this.isStatic = true; - } - - public GroundEffect(boolean isStatic, float life, EffectRenderer draw){ - super(life, draw); - this.staticLife = 0f; - this.isStatic = isStatic; - } - - public GroundEffect(float life, EffectRenderer draw){ - super(life, draw); - this.staticLife = 0f; - this.isStatic = false; - } - } -} diff --git a/core/src/mindustry/entities/effect/ItemTransfer.java b/core/src/mindustry/entities/effect/ItemTransfer.java deleted file mode 100644 index 2018d15a69..0000000000 --- a/core/src/mindustry/entities/effect/ItemTransfer.java +++ /dev/null @@ -1,119 +0,0 @@ -package mindustry.entities.effect; - -import mindustry.annotations.Annotations.Loc; -import mindustry.annotations.Annotations.Remote; -import arc.graphics.g2d.*; -import arc.math.Interpolation; -import arc.math.Mathf; -import arc.math.geom.Position; -import arc.math.geom.Vec2; -import arc.util.Time; -import arc.util.pooling.Pools; -import mindustry.entities.*; -import mindustry.entities.type.TimedEntity; -import mindustry.entities.traits.DrawTrait; -import mindustry.entities.type.Unit; -import mindustry.graphics.Pal; -import mindustry.type.Item; -import mindustry.world.Tile; - -import static mindustry.Vars.*; - -public class ItemTransfer extends TimedEntity implements DrawTrait{ - private Vec2 from = new Vec2(); - private Vec2 current = new Vec2(); - private Vec2 tovec = new Vec2(); - private Item item; - private float seed; - private Position to; - private Runnable done; - - public ItemTransfer(){ - } - - @Remote(called = Loc.server, unreliable = true) - public static void transferItemEffect(Item item, float x, float y, Unit to){ - if(to == null) return; - create(item, x, y, to, () -> { - }); - } - - @Remote(called = Loc.server, unreliable = true) - public static void transferItemToUnit(Item item, float x, float y, Unit to){ - if(to == null) return; - create(item, x, y, to, () -> to.addItem(item)); - } - - @Remote(called = Loc.server, unreliable = true) - public static void transferItemTo(Item item, int amount, float x, float y, Tile tile){ - if(tile == null || tile.entity == null || tile.entity.items == null) return; - for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){ - Time.run(i * 3, () -> create(item, x, y, tile, () -> {})); - } - tile.entity.items.add(item, amount); - } - - public static void create(Item item, float fromx, float fromy, Position to, Runnable done){ - ItemTransfer tr = Pools.obtain(ItemTransfer.class, ItemTransfer::new); - tr.item = item; - tr.from.set(fromx, fromy); - tr.to = to; - tr.done = done; - tr.seed = Mathf.range(1f); - tr.add(); - } - - @Override - public float lifetime(){ - return 60; - } - - @Override - public void reset(){ - super.reset(); - item = null; - to = null; - done = null; - from.setZero(); - current.setZero(); - tovec.setZero(); - } - - @Override - public void removed(){ - if(done != null){ - done.run(); - } - Pools.free(this); - } - - @Override - public void update(){ - if(to == null){ - remove(); - return; - } - - super.update(); - current.set(from).interpolate(tovec.set(to.getX(), to.getY()), fin(), Interpolation.pow3); - current.add(tovec.set(to.getX(), to.getY()).sub(from).nor().rotate90(1).scl(seed * fslope() * 10f)); - set(current.x, current.y); - } - - @Override - public void draw(){ - Lines.stroke(fslope() * 2f, Pal.accent); - - Lines.circle(x, y, fslope() * 2f); - - Draw.color(item.color); - Fill.circle(x, y, fslope() * 1.5f); - - Draw.reset(); - } - - @Override - public EntityGroup targetGroup(){ - return effectGroup; - } -} diff --git a/core/src/mindustry/entities/effect/Lightning.java b/core/src/mindustry/entities/effect/Lightning.java deleted file mode 100644 index e4658cd1ff..0000000000 --- a/core/src/mindustry/entities/effect/Lightning.java +++ /dev/null @@ -1,160 +0,0 @@ -package mindustry.entities.effect; - -import mindustry.annotations.Annotations.Loc; -import mindustry.annotations.Annotations.Remote; -import arc.struct.Array; -import arc.struct.IntSet; -import arc.graphics.Color; -import arc.graphics.g2d.*; -import arc.math.*; -import arc.math.geom.*; -import arc.util.pooling.Pools; -import mindustry.content.Bullets; -import mindustry.entities.EntityGroup; -import mindustry.entities.Units; -import mindustry.entities.type.Bullet; -import mindustry.entities.type.TimedEntity; -import mindustry.entities.traits.DrawTrait; -import mindustry.entities.traits.TimeTrait; -import mindustry.entities.type.Unit; -import mindustry.game.Team; -import mindustry.gen.Call; -import mindustry.graphics.Pal; -import mindustry.world.Tile; - -import static mindustry.Vars.*; - -public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{ - public static final float lifetime = 10f; - - private static final Rand random = new Rand(); - private static final Rect rect = new Rect(); - private static final Array entities = new Array<>(); - private static final IntSet hit = new IntSet(); - private static final int maxChain = 8; - private static final float hitRange = 30f; - private static int lastSeed = 0; - - private Array lines = new Array<>(); - private Color color = Pal.lancerLaser; - - /** For pooling use only. Do not call directly! */ - public Lightning(){ - } - - /** Create a lighting branch at a location. Use Team.none to damage everyone. */ - public static void create(Team team, Color color, float damage, float x, float y, float targetAngle, int length){ - Call.createLighting(nextSeed(), team, color, damage, x, y, targetAngle, length); - } - - public static int nextSeed(){ - return lastSeed++; - } - - /** Do not invoke! */ - @Remote(called = Loc.server, unreliable = true) - public static void createLighting(int seed, Team team, Color color, float damage, float x, float y, float rotation, int length){ - - Lightning l = Pools.obtain(Lightning.class, Lightning::new); - Float dmg = damage; - - l.x = x; - l.y = y; - l.color = color; - l.add(); - - random.setSeed(seed); - hit.clear(); - - boolean[] bhit = {false}; - - for(int i = 0; i < length / 2; i++){ - Bullet.create(Bullets.damageLightning, l, team, x, y, 0f, 1f, 1f, dmg); - l.lines.add(new Vec2(x + Mathf.range(3f), y + Mathf.range(3f))); - - if(l.lines.size > 1){ - bhit[0] = false; - Position from = l.lines.get(l.lines.size - 2); - Position to = l.lines.get(l.lines.size - 1); - world.raycastEach(world.toTile(from.getX()), world.toTile(from.getY()), world.toTile(to.getX()), world.toTile(to.getY()), (wx, wy) -> { - - Tile tile = world.ltile(wx, wy); - if(tile != null && tile.block().insulated){ - bhit[0] = true; - //snap it instead of removing - l.lines.get(l.lines.size -1).set(wx * tilesize, wy * tilesize); - return true; - } - return false; - }); - if(bhit[0]) break; - } - - rect.setSize(hitRange).setCenter(x, y); - entities.clear(); - if(hit.size < maxChain){ - Units.nearbyEnemies(team, rect, u -> { - if(!hit.contains(u.getID())){ - entities.add(u); - } - }); - } - - Unit furthest = Geometry.findFurthest(x, y, entities); - - if(furthest != null){ - hit.add(furthest.getID()); - x = furthest.x; - y = furthest.y; - }else{ - rotation += random.range(20f); - - x += Angles.trnsx(rotation, hitRange / 2f); - y += Angles.trnsy(rotation, hitRange / 2f); - } - } - } - - @Override - public float lifetime(){ - return lifetime; - } - - @Override - public void reset(){ - super.reset(); - color = Pal.lancerLaser; - lines.clear(); - } - - @Override - public void removed(){ - super.removed(); - Pools.free(this); - } - - @Override - public void draw(){ - Lines.stroke(3f * fout()); - Draw.color(color, Color.white, fin()); - Lines.beginLine(); - - Lines.linePoint(x, y); - for(Position p : lines){ - Lines.linePoint(p.getX(), p.getY()); - } - Lines.endLine(); - - int i = 0; - - for(Position p : lines){ - Fill.square(p.getX(), p.getY(), (5f - (float)i++ / lines.size * 2f) * fout(), 45); - } - Draw.reset(); - } - - @Override - public EntityGroup targetGroup(){ - return bulletGroup; - } -} diff --git a/core/src/mindustry/entities/effect/Puddle.java b/core/src/mindustry/entities/effect/Puddle.java deleted file mode 100644 index 132c2d1379..0000000000 --- a/core/src/mindustry/entities/effect/Puddle.java +++ /dev/null @@ -1,322 +0,0 @@ -package mindustry.entities.effect; - -import mindustry.annotations.Annotations.*; -import arc.struct.*; -import arc.graphics.*; -import arc.graphics.g2d.*; -import arc.math.*; -import arc.math.geom.*; -import arc.util.*; -import arc.util.pooling.Pool.*; -import arc.util.pooling.*; -import mindustry.content.*; -import mindustry.entities.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; -import mindustry.game.*; -import mindustry.gen.*; -import mindustry.type.*; -import mindustry.world.*; - -import java.io.*; - -import static mindustry.Vars.*; - -public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrait, SyncTrait{ - private static final IntMap map = new IntMap<>(); - private static final float maxLiquid = 70f; - private static final int maxGeneration = 2; - private static final Color tmp = new Color(); - private static final Rect rect = new Rect(); - private static final Rect rect2 = new Rect(); - private static int seeds; - - private int loadedPosition = -1; - - private float updateTime; - private float lastRipple; - private Tile tile; - private Liquid liquid; - private float amount, targetAmount; - private float accepting; - private byte generation; - - /** Deserialization use only! */ - public Puddle(){ - } - - /** Deposists a puddle between tile and source. */ - public static void deposit(Tile tile, Tile source, Liquid liquid, float amount){ - deposit(tile, source, liquid, amount, 0); - } - - /** Deposists a puddle at a tile. */ - public static void deposit(Tile tile, Liquid liquid, float amount){ - deposit(tile, tile, liquid, amount, 0); - } - - /** Returns the puddle on the specified tile. May return null. */ - public static Puddle getPuddle(Tile tile){ - return map.get(tile.pos()); - } - - private static void deposit(Tile tile, Tile source, Liquid liquid, float amount, int generation){ - if(tile == null) return; - - if(tile.floor().isLiquid && !canStayOn(liquid, tile.floor().liquidDrop)){ - reactPuddle(tile.floor().liquidDrop, liquid, amount, tile, - (tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f); - - Puddle p = map.get(tile.pos()); - - if(generation == 0 && p != null && p.lastRipple <= Time.time() - 40f){ - Effects.effect(Fx.ripple, tile.floor().liquidDrop.color, - (tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f); - p.lastRipple = Time.time(); - } - return; - } - - Puddle p = map.get(tile.pos()); - if(p == null){ - if(net.client()) return; //not clientside. - - Puddle puddle = Pools.obtain(Puddle.class, Puddle::new); - puddle.tile = tile; - puddle.liquid = liquid; - puddle.amount = amount; - puddle.generation = (byte)generation; - puddle.set((tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f); - puddle.add(); - map.put(tile.pos(), puddle); - }else if(p.liquid == liquid){ - p.accepting = Math.max(amount, p.accepting); - - if(generation == 0 && p.lastRipple <= Time.time() - 40f && p.amount >= maxLiquid / 2f){ - Effects.effect(Fx.ripple, p.liquid.color, (tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f); - p.lastRipple = Time.time(); - } - }else{ - p.amount += reactPuddle(p.liquid, liquid, amount, p.tile, p.x, p.y); - } - } - - /** - * Returns whether the first liquid can 'stay' on the second one. - * Currently, the only place where this can happen is oil on water. - */ - private static boolean canStayOn(Liquid liquid, Liquid other){ - return liquid == Liquids.oil && other == Liquids.water; - } - - /** Reacts two liquids together at a location. */ - private static float reactPuddle(Liquid dest, Liquid liquid, float amount, Tile tile, float x, float y){ - if((dest.flammability > 0.3f && liquid.temperature > 0.7f) || - (liquid.flammability > 0.3f && dest.temperature > 0.7f)){ //flammable liquid + hot liquid - Fire.create(tile); - if(Mathf.chance(0.006 * amount)){ - Call.createBullet(Bullets.fireball, Team.derelict, x, y, Mathf.random(360f), 1f, 1f); - } - }else if(dest.temperature > 0.7f && liquid.temperature < 0.55f){ //cold liquid poured onto hot puddle - if(Mathf.chance(0.5f * amount)){ - Effects.effect(Fx.steam, x, y); - } - return -0.1f * amount; - }else if(liquid.temperature > 0.7f && dest.temperature < 0.55f){ //hot liquid poured onto cold puddle - if(Mathf.chance(0.8f * amount)){ - Effects.effect(Fx.steam, x, y); - } - return -0.4f * amount; - } - return 0f; - } - - @Remote(called = Loc.server) - public static void onPuddleRemoved(int puddleid){ - puddleGroup.removeByID(puddleid); - } - - public float getFlammability(){ - return liquid.flammability * amount; - } - - @Override - public TypeID getTypeID(){ - return TypeIDs.puddle; - } - - @Override - public byte version(){ - return 0; - } - - @Override - public void hitbox(Rect rect){ - rect.setCenter(x, y).setSize(tilesize); - } - - @Override - public void hitboxTile(Rect rect){ - rect.setCenter(x, y).setSize(0f); - } - - @Override - public void update(){ - - //no updating happens clientside - if(net.client()){ - amount = Mathf.lerpDelta(amount, targetAmount, 0.15f); - }else{ - //update code - float addSpeed = accepting > 0 ? 3f : 0f; - - amount -= Time.delta() * (1f - liquid.viscosity) / (5f + addSpeed); - - amount += accepting; - accepting = 0f; - - if(amount >= maxLiquid / 1.5f && generation < maxGeneration){ - float deposited = Math.min((amount - maxLiquid / 1.5f) / 4f, 0.3f) * Time.delta(); - for(Point2 point : Geometry.d4){ - Tile other = world.tile(tile.x + point.x, tile.y + point.y); - if(other != null && other.block() == Blocks.air){ - deposit(other, tile, liquid, deposited, generation + 1); - amount -= deposited / 2f; //tweak to speed up/slow down puddle propagation - } - } - } - - amount = Mathf.clamp(amount, 0, maxLiquid); - - if(amount <= 0f){ - Call.onPuddleRemoved(getID()); - } - } - - //effects-only code - if(amount >= maxLiquid / 2f && updateTime <= 0f){ - Units.nearby(rect.setSize(Mathf.clamp(amount / (maxLiquid / 1.5f)) * 10f).setCenter(x, y), unit -> { - if(unit.isFlying()) return; - - unit.hitbox(rect2); - if(!rect.overlaps(rect2)) return; - - unit.applyEffect(liquid.effect, 60 * 2); - - if(unit.velocity().len() > 0.1){ - Effects.effect(Fx.ripple, liquid.color, unit.x, unit.y); - } - }); - - if(liquid.temperature > 0.7f && (tile.link().entity != null) && Mathf.chance(0.3 * Time.delta())){ - Fire.create(tile); - } - - updateTime = 20f; - } - - updateTime -= Time.delta(); - } - - @Override - public void draw(){ - seeds = id; - boolean onLiquid = tile.floor().isLiquid; - float f = Mathf.clamp(amount / (maxLiquid / 1.5f)); - float smag = onLiquid ? 0.8f : 0f; - float sscl = 20f; - - Draw.color(tmp.set(liquid.color).shiftValue(-0.05f)); - Fill.circle(x + Mathf.sin(Time.time() + seeds * 532, sscl, smag), y + Mathf.sin(Time.time() + seeds * 53, sscl, smag), f * 8f); - Angles.randLenVectors(id, 3, f * 6f, (ex, ey) -> { - Fill.circle(x + ex + Mathf.sin(Time.time() + seeds * 532, sscl, smag), - y + ey + Mathf.sin(Time.time() + seeds * 53, sscl, smag), f * 5f); - seeds++; - }); - Draw.color(); - - if(liquid.lightColor.a > 0.001f && f > 0){ - Color color = liquid.lightColor; - float opacity = color.a * f; - renderer.lights.add(tile.drawx(), tile.drawy(), 30f * f, color, opacity * 0.8f); - } - } - - @Override - public float drawSize(){ - return 20; - } - - @Override - public void writeSave(DataOutput stream) throws IOException{ - stream.writeInt(tile.pos()); - stream.writeFloat(x); - stream.writeFloat(y); - stream.writeByte(liquid.id); - stream.writeFloat(amount); - stream.writeByte(generation); - } - - @Override - public void readSave(DataInput stream, byte version) throws IOException{ - this.loadedPosition = stream.readInt(); - this.x = stream.readFloat(); - this.y = stream.readFloat(); - this.liquid = content.liquid(stream.readByte()); - this.amount = stream.readFloat(); - this.generation = stream.readByte(); - add(); - } - - @Override - public void reset(){ - loadedPosition = -1; - tile = null; - liquid = null; - amount = 0; - generation = 0; - accepting = 0; - } - - @Override - public void added(){ - if(loadedPosition != -1){ - map.put(loadedPosition, this); - tile = world.tile(loadedPosition); - } - } - - @Override - public void removed(){ - if(tile != null){ - map.remove(tile.pos()); - } - reset(); - } - - @Override - public void write(DataOutput data) throws IOException{ - data.writeFloat(x); - data.writeFloat(y); - data.writeByte(liquid.id); - data.writeShort((short)(amount * 4)); - data.writeInt(tile.pos()); - } - - @Override - public void read(DataInput data) throws IOException{ - x = data.readFloat(); - y = data.readFloat(); - liquid = content.liquid(data.readByte()); - targetAmount = data.readShort() / 4f; - int pos = data.readInt(); - tile = world.tile(pos); - - map.put(pos, this); - } - - @Override - public EntityGroup targetGroup(){ - return puddleGroup; - } -} diff --git a/core/src/mindustry/entities/effect/RubbleDecal.java b/core/src/mindustry/entities/effect/RubbleDecal.java deleted file mode 100644 index 1d26980dc0..0000000000 --- a/core/src/mindustry/entities/effect/RubbleDecal.java +++ /dev/null @@ -1,41 +0,0 @@ -package mindustry.entities.effect; - -import arc.Core; -import arc.graphics.g2d.Draw; -import arc.graphics.g2d.TextureRegion; -import arc.math.Mathf; - -import static mindustry.Vars.headless; - -public class RubbleDecal extends Decal{ - private TextureRegion region; - - /** Creates a rubble effect at a position. Provide a block size to use. */ - public static void create(float x, float y, int size){ - if(headless) return; - - RubbleDecal decal = new RubbleDecal(); - decal.region = Core.atlas.find("rubble-" + size + "-" + Mathf.randomSeed(decal.id, 0, 1)); - - if(!Core.atlas.isFound(decal.region)){ - return; - } - - decal.set(x, y); - decal.add(); - } - - @Override - public float lifetime(){ - return 8200f; - } - - @Override - public void drawDecal(){ - if(!Core.atlas.isFound(region)){ - remove(); - return; - } - Draw.rect(region, x, y, Mathf.randomSeed(id, 0, 4) * 90); - } -} diff --git a/core/src/mindustry/entities/effect/ScorchDecal.java b/core/src/mindustry/entities/effect/ScorchDecal.java deleted file mode 100644 index e35cf7a7c0..0000000000 --- a/core/src/mindustry/entities/effect/ScorchDecal.java +++ /dev/null @@ -1,49 +0,0 @@ -package mindustry.entities.effect; - -import arc.Core; -import arc.graphics.g2d.Draw; -import arc.graphics.g2d.TextureRegion; -import arc.math.Angles; -import arc.math.Mathf; -import mindustry.world.Tile; - -import static mindustry.Vars.headless; -import static mindustry.Vars.world; - -public class ScorchDecal extends Decal{ - private static final int scorches = 5; - private static final TextureRegion[] regions = new TextureRegion[scorches]; - - public static void create(float x, float y){ - if(headless) return; - - if(regions[0] == null || regions[0].getTexture().isDisposed()){ - for(int i = 0; i < regions.length; i++){ - regions[i] = Core.atlas.find("scorch" + (i + 1)); - } - } - - Tile tile = world.tileWorld(x, y); - - if(tile == null || tile.floor().liquidDrop != null) return; - - ScorchDecal decal = new ScorchDecal(); - decal.set(x, y); - decal.add(); - } - - @Override - public void drawDecal(){ - for(int i = 0; i < 3; i++){ - TextureRegion region = regions[Mathf.randomSeed(id - i, 0, scorches - 1)]; - float rotation = Mathf.randomSeed(id + i, 0, 360); - float space = 1.5f + Mathf.randomSeed(id + i + 1, 0, 20) / 10f; - Draw.rect(region, - x + Angles.trnsx(rotation, space), - y + Angles.trnsy(rotation, space) + region.getHeight() / 2f * Draw.scl, - region.getWidth() * Draw.scl, - region.getHeight() * Draw.scl, - region.getWidth() / 2f * Draw.scl, 0, rotation - 90); - } - } -} diff --git a/core/src/mindustry/entities/traits/AbsorbTrait.java b/core/src/mindustry/entities/traits/AbsorbTrait.java deleted file mode 100644 index 2dd31c487e..0000000000 --- a/core/src/mindustry/entities/traits/AbsorbTrait.java +++ /dev/null @@ -1,13 +0,0 @@ -package mindustry.entities.traits; - -public interface AbsorbTrait extends Entity, TeamTrait, DamageTrait{ - void absorb(); - - default boolean canBeAbsorbed(){ - return true; - } - - default float getShieldDamage(){ - return damage(); - } -} diff --git a/core/src/mindustry/entities/traits/BelowLiquidTrait.java b/core/src/mindustry/entities/traits/BelowLiquidTrait.java deleted file mode 100644 index e5d54a5f58..0000000000 --- a/core/src/mindustry/entities/traits/BelowLiquidTrait.java +++ /dev/null @@ -1,7 +0,0 @@ -package mindustry.entities.traits; - -/** - * A flag interface for marking an effect as appearing below liquids. - */ -public interface BelowLiquidTrait{ -} diff --git a/core/src/mindustry/entities/traits/BuilderMinerTrait.java b/core/src/mindustry/entities/traits/BuilderMinerTrait.java deleted file mode 100644 index dff842212c..0000000000 --- a/core/src/mindustry/entities/traits/BuilderMinerTrait.java +++ /dev/null @@ -1,22 +0,0 @@ -package mindustry.entities.traits; - -/** A class for gracefully merging mining and building traits.*/ -public interface BuilderMinerTrait extends MinerTrait, BuilderTrait{ - - default void updateMechanics(){ - updateBuilding(); - - //mine only when not building - if(buildRequest() == null){ - updateMining(); - } - } - - default void drawMechanics(){ - if(isBuilding()){ - drawBuilding(); - }else{ - drawMining(); - } - } -} diff --git a/core/src/mindustry/entities/traits/BuilderTrait.java b/core/src/mindustry/entities/traits/BuilderTrait.java deleted file mode 100644 index 570f5eabf9..0000000000 --- a/core/src/mindustry/entities/traits/BuilderTrait.java +++ /dev/null @@ -1,402 +0,0 @@ -package mindustry.entities.traits; - -import arc.*; -import arc.struct.Queue; -import arc.graphics.g2d.*; -import arc.math.*; -import arc.math.geom.*; -import arc.util.ArcAnnotate.*; -import arc.util.*; -import mindustry.*; -import mindustry.content.*; -import mindustry.entities.type.*; -import mindustry.game.EventType.*; -import mindustry.gen.*; -import mindustry.graphics.*; -import mindustry.world.*; -import mindustry.world.blocks.*; -import mindustry.world.blocks.BuildBlock.*; - -import java.io.*; -import java.util.*; - -import static mindustry.Vars.*; -import static mindustry.entities.traits.BuilderTrait.BuildDataStatic.*; - -/** Interface for units that build things.*/ -public interface BuilderTrait extends Entity, TeamTrait{ - //these are not instance variables! - float placeDistance = 220f; - float mineDistance = 70f; - - /** Updates building mechanism for this unit.*/ - default void updateBuilding(){ - float finalPlaceDst = state.rules.infiniteResources ? Float.MAX_VALUE : placeDistance; - Unit unit = (Unit)this; - - Iterator it = buildQueue().iterator(); - while(it.hasNext()){ - BuildRequest req = it.next(); - Tile tile = world.tile(req.x, req.y); - if(tile == null || (req.breaking && tile.block() == Blocks.air) || (!req.breaking && (tile.rotation() == req.rotation || !req.block.rotate) && tile.block() == req.block)){ - it.remove(); - } - } - - TileEntity core = unit.getClosestCore(); - - //nothing to build. - if(buildRequest() == null) return; - - //find the next build request - if(buildQueue().size > 1){ - int total = 0; - BuildRequest req; - while((dst((req = buildRequest()).tile()) > finalPlaceDst || shouldSkip(req, core)) && total < buildQueue().size){ - buildQueue().removeFirst(); - buildQueue().addLast(req); - total++; - } - } - - BuildRequest current = buildRequest(); - - if(dst(current.tile()) > finalPlaceDst) return; - - Tile tile = world.tile(current.x, current.y); - - if(!(tile.block() instanceof BuildBlock)){ - if(!current.initialized && canCreateBlocks() && !current.breaking && Build.validPlace(getTeam(), current.x, current.y, current.block, current.rotation)){ - Build.beginPlace(getTeam(), current.x, current.y, current.block, current.rotation); - }else if(!current.initialized && canCreateBlocks() && current.breaking && Build.validBreak(getTeam(), current.x, current.y)){ - Build.beginBreak(getTeam(), current.x, current.y); - }else{ - buildQueue().removeFirst(); - return; - } - } - - if(tile.entity instanceof BuildEntity && !current.initialized){ - Core.app.post(() -> Events.fire(new BuildSelectEvent(tile, unit.getTeam(), this, current.breaking))); - current.initialized = true; - } - - //if there is no core to build with or no build entity, stop building! - if((core == null && !state.rules.infiniteResources) || !(tile.entity instanceof BuildEntity)){ - return; - } - - //otherwise, update it. - BuildEntity entity = tile.ent(); - - if(entity == null){ - return; - } - - if(unit.dst(tile) <= finalPlaceDst){ - unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(entity), 0.4f); - } - - if(current.breaking){ - entity.deconstruct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier); - }else{ - if(entity.construct(unit, core, 1f / entity.buildCost * Time.delta() * getBuildPower(tile) * state.rules.buildSpeedMultiplier, current.hasConfig)){ - if(current.hasConfig){ - Call.onTileConfig(null, tile, current.config); - } - } - } - - current.stuck = Mathf.equal(current.progress, entity.progress); - current.progress = entity.progress; - } - - /** @return whether this request should be skipped, in favor of the next one. */ - default boolean shouldSkip(BuildRequest request, @Nullable TileEntity core){ - //requests that you have at least *started* are considered - if(state.rules.infiniteResources || request.breaking || !request.initialized || core == null) return false; - return request.stuck && !core.items.has(request.block.requirements); - } - - default void removeRequest(int x, int y, boolean breaking){ - //remove matching request - int idx = player.buildQueue().indexOf(req -> req.breaking == breaking && req.x == x && req.y == y); - if(idx != -1){ - player.buildQueue().removeIndex(idx); - } - } - - /** Returns the queue for storing build requests. */ - Queue buildQueue(); - - /** Build power, can be any float. 1 = builds recipes in normal time, 0 = doesn't build at all. */ - float getBuildPower(Tile tile); - - /** Whether this type of builder can begin creating new blocks. */ - default boolean canCreateBlocks(){ - return true; - } - - default void writeBuilding(DataOutput output) throws IOException{ - BuildRequest request = buildRequest(); - - if(request != null && (request.block != null || request.breaking)){ - output.writeByte(request.breaking ? 1 : 0); - output.writeInt(Pos.get(request.x, request.y)); - output.writeFloat(request.progress); - if(!request.breaking){ - output.writeShort(request.block.id); - output.writeByte(request.rotation); - } - }else{ - output.writeByte(-1); - } - } - - default void readBuilding(DataInput input) throws IOException{ - readBuilding(input, true); - } - - default void readBuilding(DataInput input, boolean applyChanges) throws IOException{ - if(applyChanges) buildQueue().clear(); - - byte type = input.readByte(); - if(type != -1){ - int position = input.readInt(); - float progress = input.readFloat(); - BuildRequest request; - - if(type == 1){ //remove - request = new BuildRequest(Pos.x(position), Pos.y(position)); - }else{ //place - short block = input.readShort(); - byte rotation = input.readByte(); - request = new BuildRequest(Pos.x(position), Pos.y(position), rotation, content.block(block)); - } - - request.progress = progress; - - if(applyChanges){ - buildQueue().addLast(request); - }else if(isBuilding()){ - BuildRequest last = buildRequest(); - last.progress = progress; - if(last.tile() != null && last.tile().entity instanceof BuildEntity){ - ((BuildEntity)last.tile().entity).progress = progress; - } - } - } - } - - /** Return whether this builder's place queue contains items. */ - default boolean isBuilding(){ - return buildQueue().size != 0; - } - - /** Clears the placement queue. */ - default void clearBuilding(){ - buildQueue().clear(); - } - - /** Add another build requests to the tail of the queue, if it doesn't exist there yet. */ - default void addBuildRequest(BuildRequest place){ - addBuildRequest(place, true); - } - - /** Add another build requests to the queue, if it doesn't exist there yet. */ - default void addBuildRequest(BuildRequest place, boolean tail){ - BuildRequest replace = null; - for(BuildRequest request : buildQueue()){ - if(request.x == place.x && request.y == place.y){ - replace = request; - break; - } - } - if(replace != null){ - buildQueue().remove(replace); - } - Tile tile = world.tile(place.x, place.y); - if(tile != null && tile.entity instanceof BuildEntity){ - place.progress = tile.ent().progress; - } - if(tail){ - buildQueue().addLast(place); - }else{ - buildQueue().addFirst(place); - } - } - - /** - * Return the build requests currently active, or the one at the top of the queue. - * May return null. - */ - default @Nullable - BuildRequest buildRequest(){ - return buildQueue().size == 0 ? null : buildQueue().first(); - } - - //due to iOS weirdness, this is apparently required - class BuildDataStatic{ - static Vec2[] tmptr = new Vec2[]{new Vec2(), new Vec2(), new Vec2(), new Vec2()}; - } - - /** Draw placement effects for an entity. */ - default void drawBuilding(){ - if(!isBuilding()) return; - - Unit unit = (Unit)this; - BuildRequest request = buildRequest(); - Tile tile = world.tile(request.x, request.y); - - if(dst(tile) > placeDistance && !state.isEditor()){ - return; - } - - Lines.stroke(1f, Pal.accent); - float focusLen = 3.8f + Mathf.absin(Time.time(), 1.1f, 0.6f); - float px = unit.x + Angles.trnsx(unit.rotation, focusLen); - float py = unit.y + Angles.trnsy(unit.rotation, focusLen); - - float sz = Vars.tilesize * tile.block().size / 2f; - float ang = unit.angleTo(tile); - - tmptr[0].set(tile.drawx() - sz, tile.drawy() - sz); - tmptr[1].set(tile.drawx() + sz, tile.drawy() - sz); - tmptr[2].set(tile.drawx() - sz, tile.drawy() + sz); - tmptr[3].set(tile.drawx() + sz, tile.drawy() + sz); - - Arrays.sort(tmptr, (a, b) -> -Float.compare(Angles.angleDist(Angles.angle(unit.x, unit.y, a.x, a.y), ang), - Angles.angleDist(Angles.angle(unit.x, unit.y, b.x, b.y), ang))); - - float x1 = tmptr[0].x, y1 = tmptr[0].y, - x3 = tmptr[1].x, y3 = tmptr[1].y; - - Draw.alpha(1f); - - Lines.line(px, py, x1, y1); - Lines.line(px, py, x3, y3); - - Fill.circle(px, py, 1.6f + Mathf.absin(Time.time(), 0.8f, 1.5f)); - - Draw.color(); - } - - /** Class for storing build requests. Can be either a place or remove request. */ - class BuildRequest{ - /** Position and rotation of this request. */ - public int x, y, rotation; - /** Block being placed. If null, this is a breaking request.*/ - public @Nullable Block block; - /** Whether this is a break request.*/ - public boolean breaking; - /** Whether this request comes with a config int. If yes, any blocks placed with this request will not call playerPlaced.*/ - public boolean hasConfig; - /** Config int. Not used unless hasConfig is true.*/ - public int config; - /** Original position, only used in schematics.*/ - public int originalX, originalY, originalWidth, originalHeight; - - /** Last progress.*/ - public float progress; - /** Whether construction has started for this request, and other special variables.*/ - public boolean initialized, worldContext = true, stuck; - - /** Visual scale. Used only for rendering.*/ - public float animScale = 0f; - - /** This creates a build request. */ - public BuildRequest(int x, int y, int rotation, Block block){ - this.x = x; - this.y = y; - this.rotation = rotation; - this.block = block; - this.breaking = false; - } - - /** This creates a remove request. */ - public BuildRequest(int x, int y){ - this.x = x; - this.y = y; - this.rotation = -1; - this.block = world.tile(x, y).block(); - this.breaking = true; - } - - public BuildRequest(){ - - } - - public BuildRequest copy(){ - BuildRequest copy = new BuildRequest(); - copy.x = x; - copy.y = y; - copy.rotation = rotation; - copy.block = block; - copy.breaking = breaking; - copy.hasConfig = hasConfig; - copy.config = config; - copy.originalX = originalX; - copy.originalY = originalY; - copy.progress = progress; - copy.initialized = initialized; - copy.animScale = animScale; - return copy; - } - - public BuildRequest original(int x, int y, int originalWidth, int originalHeight){ - originalX = x; - originalY = y; - this.originalWidth = originalWidth; - this.originalHeight = originalHeight; - return this; - } - - public Rect bounds(Rect rect){ - if(breaking){ - return rect.set(-100f, -100f, 0f, 0f); - }else{ - return block.bounds(x, y, rect); - } - } - - public BuildRequest set(int x, int y, int rotation, Block block){ - this.x = x; - this.y = y; - this.rotation = rotation; - this.block = block; - this.breaking = false; - return this; - } - - public float drawx(){ - return x*tilesize + block.offset(); - } - - public float drawy(){ - return y*tilesize + block.offset(); - } - - public BuildRequest configure(int config){ - this.config = config; - this.hasConfig = true; - return this; - } - - public @Nullable Tile tile(){ - return world.tile(x, y); - } - - @Override - public String toString(){ - return "BuildRequest{" + - "x=" + x + - ", y=" + y + - ", rotation=" + rotation + - ", recipe=" + block + - ", breaking=" + breaking + - ", progress=" + progress + - ", initialized=" + initialized + - '}'; - } - } -} diff --git a/core/src/mindustry/entities/traits/DamageTrait.java b/core/src/mindustry/entities/traits/DamageTrait.java deleted file mode 100644 index 13feb85e6e..0000000000 --- a/core/src/mindustry/entities/traits/DamageTrait.java +++ /dev/null @@ -1,9 +0,0 @@ -package mindustry.entities.traits; - -public interface DamageTrait{ - float damage(); - - default void killed(Entity other){ - - } -} diff --git a/core/src/mindustry/entities/traits/DrawTrait.java b/core/src/mindustry/entities/traits/DrawTrait.java deleted file mode 100644 index 472b582c75..0000000000 --- a/core/src/mindustry/entities/traits/DrawTrait.java +++ /dev/null @@ -1,10 +0,0 @@ -package mindustry.entities.traits; - -public interface DrawTrait extends Entity{ - - default float drawSize(){ - return 20f; - } - - void draw(); -} diff --git a/core/src/mindustry/entities/traits/Entity.java b/core/src/mindustry/entities/traits/Entity.java deleted file mode 100644 index 5b0416b69f..0000000000 --- a/core/src/mindustry/entities/traits/Entity.java +++ /dev/null @@ -1,42 +0,0 @@ -package mindustry.entities.traits; - -import mindustry.entities.EntityGroup; - -public interface Entity extends MoveTrait{ - - int getID(); - - void resetID(int id); - - default void update(){} - - default void removed(){} - - default void added(){} - - EntityGroup targetGroup(); - - @SuppressWarnings("unchecked") - default void add(){ - if(targetGroup() != null){ - targetGroup().add(this); - } - } - - @SuppressWarnings("unchecked") - default void remove(){ - if(getGroup() != null){ - getGroup().remove(this); - } - - setGroup(null); - } - - EntityGroup getGroup(); - - void setGroup(EntityGroup group); - - default boolean isAdded(){ - return getGroup() != null; - } -} diff --git a/core/src/mindustry/entities/traits/HealthTrait.java b/core/src/mindustry/entities/traits/HealthTrait.java deleted file mode 100644 index fb241e0d1b..0000000000 --- a/core/src/mindustry/entities/traits/HealthTrait.java +++ /dev/null @@ -1,52 +0,0 @@ -package mindustry.entities.traits; - -import arc.math.Mathf; - -public interface HealthTrait{ - - void health(float health); - - float health(); - - float maxHealth(); - - boolean isDead(); - - void setDead(boolean dead); - - default void onHit(SolidTrait entity){ - } - - default void onDeath(){ - } - - default boolean damaged(){ - return health() < maxHealth() - 0.0001f; - } - - default void damage(float amount){ - health(health() - amount); - if(health() <= 0 && !isDead()){ - onDeath(); - setDead(true); - } - } - - default void clampHealth(){ - health(Mathf.clamp(health(), 0, maxHealth())); - } - - default float healthf(){ - return health() / maxHealth(); - } - - default void healBy(float amount){ - health(health() + amount); - clampHealth(); - } - - default void heal(){ - health(maxHealth()); - setDead(false); - } -} diff --git a/core/src/mindustry/entities/traits/KillerTrait.java b/core/src/mindustry/entities/traits/KillerTrait.java deleted file mode 100644 index 7be5f42882..0000000000 --- a/core/src/mindustry/entities/traits/KillerTrait.java +++ /dev/null @@ -1,5 +0,0 @@ -package mindustry.entities.traits; - -public interface KillerTrait{ - void killed(Entity other); -} diff --git a/core/src/mindustry/entities/traits/MinerTrait.java b/core/src/mindustry/entities/traits/MinerTrait.java deleted file mode 100644 index 5b3d51c21d..0000000000 --- a/core/src/mindustry/entities/traits/MinerTrait.java +++ /dev/null @@ -1,119 +0,0 @@ -package mindustry.entities.traits; - -import arc.Core; -import arc.graphics.Color; -import arc.graphics.g2d.*; -import arc.math.*; -import arc.util.Time; -import mindustry.content.*; -import mindustry.entities.Effects; -import mindustry.entities.effect.*; -import mindustry.entities.type.*; -import mindustry.gen.Call; -import mindustry.graphics.*; -import mindustry.type.Item; -import mindustry.world.Tile; - -import static mindustry.Vars.*; - -public interface MinerTrait extends Entity{ - - /** Returns the range at which this miner can mine blocks.*/ - default float getMiningRange(){ - return 70f; - } - - default boolean isMining(){ - return getMineTile() != null; - } - - /** Returns the tile this builder is currently mining. */ - Tile getMineTile(); - - /** Sets the tile this builder is currently mining. */ - void setMineTile(Tile tile); - - /** Returns the mining speed of this miner. 1 = standard, 0.5 = half speed, 2 = double speed, etc. */ - float getMinePower(); - - /** Returns whether or not this builder can mine a specific item type. */ - boolean canMine(Item item); - - /** @return whether to offload mined items immediately at the core. if false, items are collected and dropped in a burst. */ - default boolean offloadImmediately(){ - return false; - } - - default void updateMining(){ - Unit unit = (Unit)this; - Tile tile = getMineTile(); - TileEntity core = unit.getClosestCore(); - - if(core != null && tile != null && tile.drop() != null && !unit.acceptsItem(tile.drop()) && unit.dst(core) < mineTransferRange){ - int accepted = core.tile.block().acceptStack(unit.item().item, unit.item().amount, core.tile, unit); - if(accepted > 0){ - Call.transferItemTo(unit.item().item, accepted, - tile.worldx() + Mathf.range(tilesize / 2f), - tile.worldy() + Mathf.range(tilesize / 2f), core.tile); - unit.clearItem(); - } - } - - if(tile == null || core == null || tile.block() != Blocks.air || dst(tile.worldx(), tile.worldy()) > getMiningRange() - || tile.drop() == null || !unit.acceptsItem(tile.drop()) || !canMine(tile.drop())){ - setMineTile(null); - }else{ - Item item = tile.drop(); - unit.rotation = Mathf.slerpDelta(unit.rotation, unit.angleTo(tile.worldx(), tile.worldy()), 0.4f); - - if(Mathf.chance(Time.delta() * (0.06 - item.hardness * 0.01) * getMinePower())){ - - if(unit.dst(core) < mineTransferRange && core.tile.block().acceptStack(item, 1, core.tile, unit) == 1 && offloadImmediately()){ - Call.transferItemTo(item, 1, - tile.worldx() + Mathf.range(tilesize / 2f), - tile.worldy() + Mathf.range(tilesize / 2f), core.tile); - }else if(unit.acceptsItem(item)){ - //this is clientside, since items are synced anyway - ItemTransfer.transferItemToUnit(item, - tile.worldx() + Mathf.range(tilesize / 2f), - tile.worldy() + Mathf.range(tilesize / 2f), - unit); - } - } - - if(Mathf.chance(0.06 * Time.delta())){ - Effects.effect(Fx.pulverizeSmall, - tile.worldx() + Mathf.range(tilesize / 2f), - tile.worldy() + Mathf.range(tilesize / 2f), 0f, item.color); - } - } - } - - default void drawMining(){ - Unit unit = (Unit)this; - Tile tile = getMineTile(); - - if(tile == null) return; - - float focusLen = 4f + Mathf.absin(Time.time(), 1.1f, 0.5f); - float swingScl = 12f, swingMag = tilesize / 8f; - float flashScl = 0.3f; - - float px = unit.x + Angles.trnsx(unit.rotation, focusLen); - float py = unit.y + Angles.trnsy(unit.rotation, focusLen); - - 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.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); - - if(unit instanceof Player && ((Player)unit).isLocal){ - Lines.stroke(1f, Pal.accent); - Lines.poly(tile.worldx(), tile.worldy(), 4, tilesize / 2f * Mathf.sqrt2, Time.time()); - } - - Draw.color(); - } -} diff --git a/core/src/mindustry/entities/traits/MoveTrait.java b/core/src/mindustry/entities/traits/MoveTrait.java deleted file mode 100644 index f34abba24f..0000000000 --- a/core/src/mindustry/entities/traits/MoveTrait.java +++ /dev/null @@ -1,20 +0,0 @@ -package mindustry.entities.traits; - -import arc.math.geom.Position; - -public interface MoveTrait extends Position{ - - void setX(float x); - - void setY(float y); - - default void moveBy(float x, float y){ - setX(getX() + x); - setY(getY() + y); - } - - default void set(float x, float y){ - setX(x); - setY(y); - } -} diff --git a/core/src/mindustry/entities/traits/SaveTrait.java b/core/src/mindustry/entities/traits/SaveTrait.java deleted file mode 100644 index 26e923bda1..0000000000 --- a/core/src/mindustry/entities/traits/SaveTrait.java +++ /dev/null @@ -1,9 +0,0 @@ -package mindustry.entities.traits; - -/** Marks an entity as serializable. */ -public interface SaveTrait extends Entity, TypeTrait, Saveable{ - - default byte version(){ - return 0; - } -} diff --git a/core/src/mindustry/entities/traits/Saveable.java b/core/src/mindustry/entities/traits/Saveable.java deleted file mode 100644 index cdbcf07663..0000000000 --- a/core/src/mindustry/entities/traits/Saveable.java +++ /dev/null @@ -1,9 +0,0 @@ -package mindustry.entities.traits; - -import java.io.*; - -/** Marks something as saveable; not necessarily used for entities. */ -public interface Saveable{ - void writeSave(DataOutput stream) throws IOException; - void readSave(DataInput stream, byte version) throws IOException; -} diff --git a/core/src/mindustry/entities/traits/ScaleTrait.java b/core/src/mindustry/entities/traits/ScaleTrait.java deleted file mode 100644 index 2a572659b2..0000000000 --- a/core/src/mindustry/entities/traits/ScaleTrait.java +++ /dev/null @@ -1,43 +0,0 @@ -package mindustry.entities.traits; - -import arc.math.Interpolation; - -public interface ScaleTrait{ - /** 0 to 1. */ - float fin(); - - /** 1 to 0 */ - default float fout(){ - return 1f - fin(); - } - - /** 1 to 0 */ - default float fout(Interpolation i){ - return i.apply(fout()); - } - - /** 1 to 0, ending at the specified margin */ - default float fout(float margin){ - float f = fin(); - if(f >= 1f - margin){ - return 1f - (f - (1f - margin)) / margin; - }else{ - return 1f; - } - } - - /** 0 to 1 **/ - default float fin(Interpolation i){ - return i.apply(fin()); - } - - /** 0 to 1 */ - default float finpow(){ - return Interpolation.pow3Out.apply(fin()); - } - - /** 0 to 1 to 0 */ - default float fslope(){ - return (0.5f - Math.abs(fin() - 0.5f)) * 2f; - } -} diff --git a/core/src/mindustry/entities/traits/ShooterTrait.java b/core/src/mindustry/entities/traits/ShooterTrait.java deleted file mode 100644 index bb20ccc83c..0000000000 --- a/core/src/mindustry/entities/traits/ShooterTrait.java +++ /dev/null @@ -1,13 +0,0 @@ -package mindustry.entities.traits; - -import arc.util.Interval; -import mindustry.type.Weapon; - -public interface ShooterTrait extends VelocityTrait, TeamTrait{ - - Interval getTimer(); - - int getShootTimer(boolean left); - - Weapon getWeapon(); -} diff --git a/core/src/mindustry/entities/traits/SolidTrait.java b/core/src/mindustry/entities/traits/SolidTrait.java deleted file mode 100644 index afa2efd6b0..0000000000 --- a/core/src/mindustry/entities/traits/SolidTrait.java +++ /dev/null @@ -1,38 +0,0 @@ -package mindustry.entities.traits; - - -import arc.math.geom.*; -import arc.math.geom.QuadTree.QuadTreeObject; -import mindustry.Vars; - -public interface SolidTrait extends QuadTreeObject, MoveTrait, VelocityTrait, Entity, Position{ - - void hitbox(Rect rect); - - void hitboxTile(Rect rect); - - Vec2 lastPosition(); - - default boolean collidesGrid(int x, int y){ - return true; - } - - default float getDeltaX(){ - return getX() - lastPosition().x; - } - - default float getDeltaY(){ - return getY() - lastPosition().y; - } - - default boolean collides(SolidTrait other){ - return true; - } - - default void collision(SolidTrait other, float x, float y){ - } - - default void move(float x, float y){ - Vars.collisions.move(this, x, y); - } -} diff --git a/core/src/mindustry/entities/traits/SpawnerTrait.java b/core/src/mindustry/entities/traits/SpawnerTrait.java deleted file mode 100644 index 3eeee072e5..0000000000 --- a/core/src/mindustry/entities/traits/SpawnerTrait.java +++ /dev/null @@ -1,18 +0,0 @@ -package mindustry.entities.traits; - -import arc.math.geom.Position; -import mindustry.entities.type.*; -import mindustry.world.Tile; - -public interface SpawnerTrait extends TargetTrait, Position{ - Tile getTile(); - - void updateSpawning(Player unit); - - boolean hasUnit(Unit unit); - - @Override - default boolean isValid(){ - return getTile().entity instanceof SpawnerTrait; - } -} diff --git a/core/src/mindustry/entities/traits/SyncTrait.java b/core/src/mindustry/entities/traits/SyncTrait.java deleted file mode 100644 index 29da740bc0..0000000000 --- a/core/src/mindustry/entities/traits/SyncTrait.java +++ /dev/null @@ -1,48 +0,0 @@ -package mindustry.entities.traits; - -import mindustry.net.Interpolator; - -import java.io.*; - -public interface SyncTrait extends Entity, TypeTrait{ - - /** Sets the position of this entity and updated the interpolator. */ - default void setNet(float x, float y){ - set(x, y); - - if(getInterpolator() != null){ - getInterpolator().target.set(x, y); - getInterpolator().last.set(x, y); - getInterpolator().pos.set(0, 0); - getInterpolator().updateSpacing = 16; - getInterpolator().lastUpdated = 0; - } - } - - /** Interpolate entity position only. Override if you need to interpolate rotations or other values. */ - default void interpolate(){ - if(getInterpolator() == null){ - throw new RuntimeException("This entity must have an interpolator to interpolate()!"); - } - - getInterpolator().update(); - - setX(getInterpolator().pos.x); - setY(getInterpolator().pos.y); - } - - /** Return the interpolator used for smoothing the position. Optional. */ - default Interpolator getInterpolator(){ - return null; - } - - /** Whether syncing is enabled for this entity; true by default. */ - default boolean isSyncing(){ - return true; - } - - //Read and write sync data, usually position - void write(DataOutput data) throws IOException; - - void read(DataInput data) throws IOException; -} diff --git a/core/src/mindustry/entities/traits/TargetTrait.java b/core/src/mindustry/entities/traits/TargetTrait.java deleted file mode 100644 index 1544b8d057..0000000000 --- a/core/src/mindustry/entities/traits/TargetTrait.java +++ /dev/null @@ -1,35 +0,0 @@ -package mindustry.entities.traits; - -import arc.math.geom.Position; -import mindustry.game.Team; - -/** - * Base interface for targetable entities. - */ -public interface TargetTrait extends Position, VelocityTrait{ - - boolean isDead(); - - Team getTeam(); - - default float getTargetVelocityX(){ - if(this instanceof SolidTrait){ - return ((SolidTrait)this).getDeltaX(); - } - return velocity().x; - } - - default float getTargetVelocityY(){ - if(this instanceof SolidTrait){ - return ((SolidTrait)this).getDeltaY(); - } - return velocity().y; - } - - /** - * Whether this entity is a valid target. - */ - default boolean isValid(){ - return !isDead(); - } -} diff --git a/core/src/mindustry/entities/traits/TeamTrait.java b/core/src/mindustry/entities/traits/TeamTrait.java deleted file mode 100644 index f4424149af..0000000000 --- a/core/src/mindustry/entities/traits/TeamTrait.java +++ /dev/null @@ -1,7 +0,0 @@ -package mindustry.entities.traits; - -import mindustry.game.Team; - -public interface TeamTrait extends Entity{ - Team getTeam(); -} diff --git a/core/src/mindustry/entities/traits/TimeTrait.java b/core/src/mindustry/entities/traits/TimeTrait.java deleted file mode 100644 index cf89d7dca8..0000000000 --- a/core/src/mindustry/entities/traits/TimeTrait.java +++ /dev/null @@ -1,23 +0,0 @@ -package mindustry.entities.traits; - -import arc.math.Mathf; -import arc.util.Time; - -public interface TimeTrait extends ScaleTrait, Entity{ - - float lifetime(); - - void time(float time); - - float time(); - - default void updateTime(){ - time(Mathf.clamp(time() + Time.delta(), 0, lifetime())); - - if(time() >= lifetime()){ - remove(); - } - } - - //fin() is not implemented due to compiler issues with iOS/RoboVM -} diff --git a/core/src/mindustry/entities/traits/TypeTrait.java b/core/src/mindustry/entities/traits/TypeTrait.java deleted file mode 100644 index 00917194fc..0000000000 --- a/core/src/mindustry/entities/traits/TypeTrait.java +++ /dev/null @@ -1,45 +0,0 @@ -package mindustry.entities.traits; - -import mindustry.type.TypeID; - -public interface TypeTrait{ - - TypeID getTypeID(); - /* - int[] lastRegisteredID = {0}; - Array> registeredTypes = new Array<>(); - ObjectIntMap> typeToID = new ObjectIntMap<>(); - - /** - * Register and return a type ID. The supplier should return a fresh instace of that type. - - static void registerType(Class type, Supplier supplier){ - if(typeToID.get(type, -1) != -1){ - return; //already registered - } - - registeredTypes.add(supplier); - int result = lastRegisteredID[0]; - typeToID.put(type, result); - lastRegisteredID[0]++; - } - - /**Gets a syncable type by ID. - static Supplier getTypeByID(int id){ - if(id == -1){ - throw new IllegalArgumentException("Attempt to retrieve invalid entity type ID! Did you forget to set it in ContentLoader.registerTypes()?"); - } - return registeredTypes.get(id); - } - - /** - * Returns the type ID of this entity used for intstantiation. Should be < BYTE_MAX. - * Do not override! - - default int getTypeID(){ - int id = typeToID.get(getClass(), -1); - if(id == -1) - throw new RuntimeException("Class of type '" + getClass() + "' is not registered! Did you forget to register it in ContentLoader#registerTypes()?"); - return id; - }*/ -} diff --git a/core/src/mindustry/entities/traits/VelocityTrait.java b/core/src/mindustry/entities/traits/VelocityTrait.java deleted file mode 100644 index 6eb42254d7..0000000000 --- a/core/src/mindustry/entities/traits/VelocityTrait.java +++ /dev/null @@ -1,36 +0,0 @@ -package mindustry.entities.traits; - -import arc.math.geom.Vec2; -import arc.util.Time; - -public interface VelocityTrait extends MoveTrait{ - - Vec2 velocity(); - - default void applyImpulse(float x, float y){ - velocity().x += x / mass(); - velocity().y += y / mass(); - } - - default float maxVelocity(){ - return Float.MAX_VALUE; - } - - default float mass(){ - return 1f; - } - - default float drag(){ - return 0f; - } - - default void updateVelocity(){ - velocity().scl(1f - drag() * Time.delta()); - - if(this instanceof SolidTrait){ - ((SolidTrait)this).move(velocity().x * Time.delta(), velocity().y * Time.delta()); - }else{ - moveBy(velocity().x * Time.delta(), velocity().y * Time.delta()); - } - } -} diff --git a/core/src/mindustry/entities/type/BaseEntity.java b/core/src/mindustry/entities/type/BaseEntity.java deleted file mode 100755 index 6aa4f0f8b7..0000000000 --- a/core/src/mindustry/entities/type/BaseEntity.java +++ /dev/null @@ -1,75 +0,0 @@ -package mindustry.entities.type; - -import mindustry.*; -import mindustry.entities.EntityGroup; -import mindustry.entities.traits.Entity; - -public abstract class BaseEntity implements Entity{ - private static int lastid; - /** Do not modify. Used for network operations and mapping. */ - public int id; - public float x, y; - protected transient EntityGroup group; - - public BaseEntity(){ - id = lastid++; - } - - public int tileX(){ - return Vars.world.toTile(x); - } - - public int tileY(){ - return Vars.world.toTile(y); - } - - @Override - public int getID(){ - return id; - } - - @Override - public void resetID(int id){ - this.id = id; - } - - @Override - public EntityGroup getGroup(){ - return group; - } - - @Override - public void setGroup(EntityGroup group){ - this.group = group; - } - - @Override - public float getX(){ - return x; - } - - @Override - public void setX(float x){ - this.x = x; - } - - @Override - public float getY(){ - return y; - } - - @Override - public void setY(float y){ - this.y = y; - } - - @Override - public String toString(){ - return getClass() + " " + id; - } - - /** Increments this entity's ID. Used for pooled entities.*/ - public void incrementID(){ - id = lastid++; - } -} diff --git a/core/src/mindustry/entities/type/BaseUnit.java b/core/src/mindustry/entities/type/BaseUnit.java deleted file mode 100644 index 6062662e9b..0000000000 --- a/core/src/mindustry/entities/type/BaseUnit.java +++ /dev/null @@ -1,417 +0,0 @@ -package mindustry.entities.type; - -import arc.*; -import mindustry.annotations.Annotations.*; -import arc.graphics.g2d.*; -import arc.math.*; -import arc.math.geom.*; -import arc.util.*; -import arc.util.ArcAnnotate.*; -import mindustry.*; -import mindustry.content.*; -import mindustry.ctype.ContentType; -import mindustry.entities.*; -import mindustry.entities.traits.*; -import mindustry.entities.units.*; -import mindustry.game.EventType.*; -import mindustry.game.*; -import mindustry.gen.*; -import mindustry.type.*; -import mindustry.type.TypeID; -import mindustry.ui.Cicon; -import mindustry.world.*; -import mindustry.world.blocks.*; -import mindustry.world.blocks.defense.DeflectorWall.*; -import mindustry.world.blocks.units.CommandCenter.*; -import mindustry.world.blocks.units.UnitFactory.*; -import mindustry.world.meta.*; - -import java.io.*; - -import static mindustry.Vars.*; - -/** Base class for AI units. */ -public abstract class BaseUnit extends Unit implements ShooterTrait{ - protected static int timerIndex = 0; - - protected static final int timerTarget = timerIndex++; - protected static final int timerTarget2 = timerIndex++; - protected static final int timerShootLeft = timerIndex++; - protected static final int timerShootRight = timerIndex++; - - protected boolean loaded; - protected UnitType type; - protected Interval timer = new Interval(5); - protected StateMachine state = new StateMachine(); - protected TargetTrait target; - - protected int spawner = noSpawner; - - /** internal constructor used for deserialization, DO NOT USE */ - public BaseUnit(){ - } - - @Remote(called = Loc.server) - public static void onUnitDeath(BaseUnit unit){ - if(unit == null) return; - - if(net.server() || !net.active()){ - UnitDrops.dropItems(unit); - } - - unit.onSuperDeath(); - unit.type.deathSound.at(unit); - - //visual only. - if(net.client()){ - Tile tile = world.tile(unit.spawner); - if(tile != null){ - tile.block().unitRemoved(tile, unit); - } - - unit.spawner = noSpawner; - } - - //must run afterwards so the unit's group is not null when sending the removal packet - Core.app.post(unit::remove); - } - - @Override - public float drag(){ - return type.drag; - } - - @Override - public TypeID getTypeID(){ - 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); - } - - public boolean isCommanded(){ - return indexer.getAllied(team, BlockFlag.comandCenter).size != 0 && indexer.getAllied(team, BlockFlag.comandCenter).first().entity instanceof CommandCenterEntity; - } - - public @Nullable UnitCommand getCommand(){ - if(isCommanded()){ - return indexer.getAllied(team, BlockFlag.comandCenter).first().ent().command; - } - return null; - } - - /**Called when a command is recieved from the command center.*/ - public void onCommand(UnitCommand command){ - - } - - /** Initialize the type and team of this unit. Only call once! */ - public void init(UnitType type, Team team){ - if(this.type != null) throw new RuntimeException("This unit is already initialized!"); - - this.type = type; - this.team = team; - } - - /** @return whether this unit counts toward the enemy amount in the wave UI. */ - public boolean countsAsEnemy(){ - return true; - } - - public UnitType getType(){ - return type; - } - - public void setSpawner(Tile tile){ - this.spawner = tile.pos(); - } - - public void rotate(float angle){ - rotation = Mathf.slerpDelta(rotation, angle, type.rotatespeed); - } - - public boolean targetHasFlag(BlockFlag flag){ - return (target instanceof TileEntity && ((TileEntity)target).tile.block().flags.contains(flag)) || - (target instanceof Tile && ((Tile)target).block().flags.contains(flag)); - } - - public void setState(UnitState state){ - this.state.set(state); - } - - public boolean retarget(){ - return timer.get(timerTarget, 20); - } - - /** Only runs when the unit has a target. */ - public void behavior(){ - - } - - public void updateTargeting(){ - if(target == null || (target instanceof Unit && (target.isDead() || target.getTeam() == team)) - || (target instanceof TileEntity && ((TileEntity)target).tile.entity == null)){ - target = null; - } - } - - public void targetClosestAllyFlag(BlockFlag flag){ - Tile target = Geometry.findClosest(x, y, indexer.getAllied(team, flag)); - if(target != null) this.target = target.entity; - } - - public void targetClosestEnemyFlag(BlockFlag flag){ - Tile target = Geometry.findClosest(x, y, indexer.getEnemy(team, flag)); - if(target != null) this.target = target.entity; - } - - public void targetClosest(){ - TargetTrait newTarget = Units.closestTarget(team, x, y, Math.max(getWeapon().bullet.range(), type.range), u -> type.targetAir || !u.isFlying()); - if(newTarget != null){ - target = newTarget; - } - } - - public @Nullable Tile getClosest(BlockFlag flag){ - return Geometry.findClosest(x, y, indexer.getAllied(team, flag)); - } - - public @Nullable Tile getClosestSpawner(){ - return Geometry.findClosest(x, y, Vars.spawner.getGroundSpawns()); - } - - public @Nullable TileEntity getClosestEnemyCore(){ - return Vars.state.teams.closestEnemyCore(x, y, team); - } - - public UnitState getStartState(){ - return null; - } - - public boolean isBoss(){ - return hasEffect(StatusEffects.boss); - } - - @Override - public float getDamageMultipler(){ - return status.getDamageMultiplier() * Vars.state.rules.unitDamageMultiplier; - } - - @Override - public boolean isImmune(StatusEffect effect){ - return type.immunities.contains(effect); - } - - @Override - public boolean isValid(){ - return super.isValid() && isAdded(); - } - - @Override - public Interval getTimer(){ - return timer; - } - - @Override - public int getShootTimer(boolean left){ - return left ? timerShootLeft : timerShootRight; - } - - @Override - public Weapon getWeapon(){ - return type.weapon; - } - - @Override - public TextureRegion getIconRegion(){ - return type.icon(Cicon.full); - } - - @Override - public int getItemCapacity(){ - return type.itemCapacity; - } - - @Override - public void interpolate(){ - super.interpolate(); - - if(interpolator.values.length > 0){ - rotation = interpolator.values[0]; - } - } - - @Override - public float maxHealth(){ - return type.health * Vars.state.rules.unitHealthMultiplier; - } - - @Override - public float mass(){ - return type.mass; - } - - @Override - public boolean isFlying(){ - return type.flying; - } - - @Override - public void update(){ - if(isDead()){ - //dead enemies should get immediately removed - remove(); - return; - } - - hitTime -= Time.delta(); - - if(net.client()){ - interpolate(); - status.update(this); - return; - } - - if(!isFlying() && (world.tileWorld(x, y) != null && !(world.tileWorld(x, y).block() instanceof BuildBlock) && world.tileWorld(x, y).solid())){ - kill(); - } - - avoidOthers(); - - if(spawner != noSpawner && (world.tile(spawner) == null || !(world.tile(spawner).entity instanceof UnitFactoryEntity))){ - kill(); - } - - updateTargeting(); - - state.update(); - updateVelocityStatus(); - - if(target != null) behavior(); - - if(!isFlying()){ - clampPosition(); - } - } - - @Override - public void draw(){ - - } - - @Override - public float maxVelocity(){ - return type.maxVelocity; - } - - @Override - public void removed(){ - super.removed(); - Tile tile = world.tile(spawner); - if(tile != null && !net.client()){ - tile.block().unitRemoved(tile, this); - } - - spawner = noSpawner; - } - - @Override - public float drawSize(){ - return type.hitsize * 10; - } - - @Override - public void onDeath(){ - Call.onUnitDeath(this); - } - - @Override - public void added(){ - state.set(getStartState()); - - if(!loaded){ - health(maxHealth()); - } - - if(isCommanded()){ - onCommand(getCommand()); - } - } - - @Override - public void hitbox(Rect rect){ - rect.setSize(type.hitsize).setCenter(x, y); - } - - @Override - public void hitboxTile(Rect rect){ - rect.setSize(type.hitsizeTile).setCenter(x, y); - } - - @Override - public EntityGroup targetGroup(){ - return unitGroup; - } - - @Override - public byte version(){ - return 0; - } - - @Override - public void writeSave(DataOutput stream) throws IOException{ - super.writeSave(stream); - stream.writeByte(type.id); - stream.writeInt(spawner); - } - - @Override - public void readSave(DataInput stream, byte version) throws IOException{ - super.readSave(stream, version); - loaded = true; - byte type = stream.readByte(); - this.spawner = stream.readInt(); - - this.type = content.getByID(ContentType.unit, type); - add(); - } - - @Override - public void write(DataOutput data) throws IOException{ - super.writeSave(data); - data.writeByte(type.id); - data.writeInt(spawner); - } - - @Override - public void read(DataInput data) throws IOException{ - float lastx = x, lasty = y, lastrot = rotation; - - super.readSave(data, version()); - - this.type = content.getByID(ContentType.unit, data.readByte()); - this.spawner = data.readInt(); - - interpolator.read(lastx, lasty, x, y, rotation); - rotation = lastrot; - x = lastx; - y = lasty; - } - - public void onSuperDeath(){ - super.onDeath(); - } -} \ No newline at end of file diff --git a/core/src/mindustry/entities/type/Bullet.java b/core/src/mindustry/entities/type/Bullet.java deleted file mode 100644 index f7e676ecc9..0000000000 --- a/core/src/mindustry/entities/type/Bullet.java +++ /dev/null @@ -1,323 +0,0 @@ -package mindustry.entities.type; - -import mindustry.annotations.Annotations.*; -import arc.math.*; -import arc.math.geom.*; -import arc.util.*; -import arc.util.pooling.Pool.*; -import arc.util.pooling.*; -import mindustry.entities.*; -import mindustry.entities.bullet.*; -import mindustry.entities.effect.*; -import mindustry.entities.traits.*; -import mindustry.game.*; -import mindustry.graphics.*; -import mindustry.world.*; - -import static mindustry.Vars.*; - -public class Bullet extends SolidEntity implements DamageTrait, ScaleTrait, Poolable, DrawTrait, VelocityTrait, TimeTrait, TeamTrait, AbsorbTrait{ - public Interval timer = new Interval(3); - - private float lifeScl; - private Team team; - private Object data; - private boolean supressCollision, supressOnce, initialized, deflected; - - protected BulletType type; - protected Entity owner; - protected float time; - - /** Internal use only! */ - public Bullet(){ - } - - public static Bullet create(BulletType type, TeamTrait owner, float x, float y, float angle){ - return create(type, owner, owner.getTeam(), x, y, angle); - } - - public static Bullet create(BulletType type, Entity owner, Team team, float x, float y, float angle){ - return create(type, owner, team, x, y, angle, 1f); - } - - public static Bullet create(BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl){ - return create(type, owner, team, x, y, angle, velocityScl, 1f, null); - } - - public static Bullet create(BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl, float lifetimeScl){ - return create(type, owner, team, x, y, angle, velocityScl, lifetimeScl, null); - } - - public static Bullet create(BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl, float lifetimeScl, Object data){ - Bullet bullet = Pools.obtain(Bullet.class, Bullet::new); - bullet.type = type; - bullet.owner = owner; - bullet.data = data; - - bullet.velocity.set(0, type.speed).setAngle(angle).scl(velocityScl); - if(type.keepVelocity){ - bullet.velocity.add(owner instanceof VelocityTrait ? ((VelocityTrait)owner).velocity() : Vec2.ZERO); - } - - bullet.team = team; - bullet.type = type; - bullet.lifeScl = lifetimeScl; - - bullet.set(x - bullet.velocity.x * Time.delta(), y - bullet.velocity.y * Time.delta()); - bullet.add(); - - return bullet; - } - - public static Bullet create(BulletType type, Bullet parent, float x, float y, float angle){ - return create(type, parent.owner, parent.team, x, y, angle); - } - - public static Bullet create(BulletType type, Bullet parent, float x, float y, float angle, float velocityScl){ - return create(type, parent.owner, parent.team, x, y, angle, velocityScl); - } - - @Remote(called = Loc.server, unreliable = true) - public static void createBullet(BulletType type, Team team, float x, float y, float angle, float velocityScl, float lifetimeScl){ - create(type, null, team, x, y, angle, velocityScl, lifetimeScl, null); - } - - public Entity getOwner(){ - return owner; - } - - public boolean collidesTiles(){ - return type.collidesTiles; - } - - public void deflect(){ - supressCollision = true; - supressOnce = true; - deflected = true; - } - - public boolean isDeflected(){ - return deflected; - } - - public BulletType getBulletType(){ - return type; - } - - public void resetOwner(Entity entity, Team team){ - this.owner = entity; - this.team = team; - } - - public void scaleTime(float add){ - time += add; - } - - public Object getData(){ - return data; - } - - public void setData(Object data){ - this.data = data; - } - - public float damageMultiplier(){ - if(owner instanceof Unit){ - return ((Unit)owner).getDamageMultipler(); - } - return 1f; - } - - @Override - public void killed(Entity other){ - if(owner instanceof KillerTrait){ - ((KillerTrait)owner).killed(other); - } - } - - @Override - public void absorb(){ - supressCollision = true; - remove(); - } - - @Override - public float drawSize(){ - return type.drawSize; - } - - @Override - public float damage(){ - if(owner instanceof Lightning && data instanceof Float){ - return (Float)data; - } - return type.damage * damageMultiplier(); - } - - @Override - public Team getTeam(){ - return team; - } - - @Override - public float getShieldDamage(){ - return Math.max(damage(), type.splashDamage); - } - - @Override - public boolean collides(SolidTrait other){ - return type.collides && (other != owner && !(other instanceof DamageTrait)) && !supressCollision && !(other instanceof Unit && ((Unit)other).isFlying() && !type.collidesAir); - } - - @Override - public void collision(SolidTrait other, float x, float y){ - if(!type.pierce) remove(); - type.hit(this, x, y); - - if(other instanceof Unit){ - Unit unit = (Unit)other; - unit.velocity().add(Tmp.v3.set(other.getX(), other.getY()).sub(x, y).setLength(type.knockback / unit.mass())); - unit.applyEffect(type.status, type.statusDuration); - } - } - - @Override - public void update(){ - type.update(this); - - x += velocity.x * Time.delta(); - y += velocity.y * Time.delta(); - - velocity.scl(Mathf.clamp(1f - type.drag * Time.delta())); - - time += Time.delta() * 1f / (lifeScl); - time = Mathf.clamp(time, 0, type.lifetime); - - if(time >= type.lifetime){ - if(!supressCollision) type.despawned(this); - remove(); - } - - if(type.hitTiles && collidesTiles() && !supressCollision && initialized){ - world.raycastEach(world.toTile(lastPosition().x), world.toTile(lastPosition().y), world.toTile(x), world.toTile(y), (x, y) -> { - - Tile tile = world.ltile(x, y); - if(tile == null) return false; - - if(tile.entity != null && tile.entity.collide(this) && type.collides(this, tile) && !tile.entity.isDead() && (type.collidesTeam || tile.getTeam() != team)){ - if(tile.getTeam() != team){ - tile.entity.collision(this); - } - - if(!supressCollision){ - type.hitTile(this, tile); - remove(); - } - - return true; - } - - return false; - }); - } - - if(supressOnce){ - supressCollision = false; - supressOnce = false; - } - - initialized = true; - } - - @Override - public void reset(){ - type = null; - owner = null; - velocity.setZero(); - time = 0f; - timer.clear(); - lifeScl = 1f; - team = null; - data = null; - supressCollision = false; - supressOnce = false; - deflected = false; - initialized = false; - } - - @Override - public void hitbox(Rect rect){ - rect.setSize(type.hitSize).setCenter(x, y); - } - - @Override - public void hitboxTile(Rect rect){ - rect.setSize(type.hitSize).setCenter(x, y); - } - - @Override - public float lifetime(){ - return type.lifetime; - } - - @Override - public void time(float time){ - this.time = time; - } - - @Override - public float time(){ - return time; - } - - @Override - public void removed(){ - Pools.free(this); - } - - @Override - public EntityGroup targetGroup(){ - return bulletGroup; - } - - @Override - public void added(){ - type.init(this); - } - - @Override - public void draw(){ - type.draw(this); - renderer.lights.add(x, y, 16f, Pal.powerLight, 0.3f); - } - - @Override - public float fin(){ - return time / type.lifetime; - } - - @Override - public Vec2 velocity(){ - return velocity; - } - - public void velocity(float speed, float angle){ - velocity.set(0, speed).setAngle(angle); - } - - public void limit(float f){ - velocity.limit(f); - } - - /** Sets the bullet's rotation in degrees. */ - public void rot(float angle){ - velocity.setAngle(angle); - } - - /** @return the bullet's rotation. */ - public float rot(){ - float angle = Mathf.atan2(velocity.x, velocity.y) * Mathf.radiansToDegrees; - if(angle < 0) angle += 360; - return angle; - } -} diff --git a/core/src/mindustry/entities/type/DestructibleEntity.java b/core/src/mindustry/entities/type/DestructibleEntity.java deleted file mode 100644 index 99efe3b00c..0000000000 --- a/core/src/mindustry/entities/type/DestructibleEntity.java +++ /dev/null @@ -1,47 +0,0 @@ -package mindustry.entities.type; - - -import mindustry.entities.traits.*; - -public abstract class DestructibleEntity extends SolidEntity implements HealthTrait{ - public transient boolean dead; - public float health; - - @Override - public boolean collides(SolidTrait other){ - return other instanceof DamageTrait; - } - - @Override - public void collision(SolidTrait other, float x, float y){ - if(other instanceof DamageTrait){ - boolean wasDead = isDead(); - onHit(other); - damage(((DamageTrait)other).damage()); - if(!wasDead && isDead()){ - ((DamageTrait)other).killed(this); - } - } - } - - @Override - public void health(float health){ - this.health = health; - } - - @Override - public float health(){ - return health; - } - - @Override - public boolean isDead(){ - return dead; - } - - @Override - public void setDead(boolean dead){ - this.dead = dead; - } - -} diff --git a/core/src/mindustry/entities/type/EffectEntity.java b/core/src/mindustry/entities/type/EffectEntity.java deleted file mode 100644 index 95f40d8100..0000000000 --- a/core/src/mindustry/entities/type/EffectEntity.java +++ /dev/null @@ -1,81 +0,0 @@ -package mindustry.entities.type; - -import arc.graphics.Color; -import arc.util.pooling.Pool.Poolable; -import arc.util.pooling.Pools; -import mindustry.entities.Effects; -import mindustry.entities.Effects.Effect; -import mindustry.entities.EntityGroup; -import mindustry.entities.traits.DrawTrait; -import mindustry.entities.traits.Entity; - -import static mindustry.Vars.effectGroup; - -public class EffectEntity extends TimedEntity implements Poolable, DrawTrait{ - public Effect effect; - public Color color = new Color(Color.white); - public Object data; - public float rotation = 0f; - - public Entity parent; - public float poffsetx, poffsety; - - /** For pooling use only! */ - public EffectEntity(){ - } - - public void setParent(Entity parent){ - this.parent = parent; - this.poffsetx = x - parent.getX(); - this.poffsety = y - parent.getY(); - } - - @Override - public EntityGroup targetGroup(){ - //this should never actually be called - return effectGroup; - } - - @Override - public float lifetime(){ - return effect.lifetime; - } - - @Override - public float drawSize(){ - return effect.size; - } - - @Override - public void update(){ - if(effect == null){ - remove(); - return; - } - - super.update(); - if(parent != null){ - x = parent.getX() + poffsetx; - y = parent.getY() + poffsety; - } - } - - @Override - public void reset(){ - effect = null; - color.set(Color.white); - rotation = time = poffsetx = poffsety = 0f; - parent = null; - data = null; - } - - @Override - public void draw(){ - Effects.renderEffect(id, effect, color, time, rotation, x, y, data); - } - - @Override - public void removed(){ - Pools.free(this); - } -} diff --git a/core/src/mindustry/entities/type/Player.java b/core/src/mindustry/entities/type/Player.java deleted file mode 100644 index d1046031ef..0000000000 --- a/core/src/mindustry/entities/type/Player.java +++ /dev/null @@ -1,957 +0,0 @@ -package mindustry.entities.type; - -import arc.*; -import mindustry.annotations.Annotations.*; -import arc.struct.*; -import arc.graphics.*; -import arc.graphics.g2d.*; -import arc.math.*; -import arc.math.geom.*; -import arc.scene.ui.*; -import arc.scene.ui.layout.*; -import arc.util.*; -import arc.util.ArcAnnotate.*; -import arc.util.pooling.*; -import mindustry.*; -import mindustry.content.*; -import mindustry.core.*; -import mindustry.ctype.ContentType; -import mindustry.entities.*; -import mindustry.entities.traits.*; -import mindustry.game.*; -import mindustry.gen.*; -import mindustry.input.*; -import mindustry.io.*; -import mindustry.net.Administration.*; -import mindustry.net.*; -import mindustry.type.*; -import mindustry.ui.*; -import mindustry.world.*; -import mindustry.world.blocks.*; - -import java.io.*; - -import static 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; - - private static final Rect rect = new Rect(); - - //region instance variables - - public float baseRotation; - public float pointerX, pointerY; - public String name = "noname"; - public @Nullable String uuid, usid; - public boolean isAdmin, isTransferring, isShooting, isBoosting, isMobile, isTyping, isBuilding = true; - public boolean buildWasAutoPaused = false; - public float boostHeat, shootHeat, destructTime; - public boolean achievedFlight; - public Color color = new Color(); - public Mech mech = Mechs.starter; - public SpawnerTrait spawner, lastSpawner; - public int respawns; - - public @Nullable NetConnection con; - public boolean isLocal = false; - public Interval timer = new Interval(6); - public TargetTrait target; - public TargetTrait moveTarget; - - public @Nullable String lastText; - public float textFadeTime; - - private float walktime, itemtime; - private Queue placeQueue = new Queue<>(); - private Tile mining; - private Vec2 movement = new Vec2(); - private boolean moved; - - //endregion - - //region unit and event overrides, utility methods - - @Remote(targets = Loc.server, called = Loc.server) - public static void onPlayerDeath(Player player){ - if(player == null) return; - - player.dead = true; - player.placeQueue.clear(); - player.onDeath(); - } - - @Override - public float getDamageMultipler(){ - return status.getDamageMultiplier() * state.rules.playerDamageMultiplier; - } - - @Override - public void hitbox(Rect rect){ - rect.setSize(mech.hitsize).setCenter(x, y); - } - - @Override - public void hitboxTile(Rect rect){ - rect.setSize(mech.hitsize * 2f / 3f).setCenter(x, y); - } - - @Override - public void onRespawn(Tile tile){ - velocity.setZero(); - boostHeat = 1f; - achievedFlight = true; - rotation = 90f; - baseRotation = 90f; - dead = false; - spawner = null; - respawns --; - Sounds.respawn.at(tile); - - setNet(tile.drawx(), tile.drawy()); - clearItem(); - heal(); - } - - @Override - public boolean offloadImmediately(){ - return true; - } - - @Override - public TypeID getTypeID(){ - return TypeIDs.player; - } - - @Override - public void move(float x, float y){ - if(!mech.flying){ - collisions.move(this, x, y); - }else{ - moveBy(x, y); - } - } - - @Override - public float drag(){ - return mech.drag; - } - - @Override - public Interval getTimer(){ - return timer; - } - - @Override - public int getShootTimer(boolean left){ - return left ? timerShootLeft : timerShootRight; - } - - @Override - public Weapon getWeapon(){ - return mech.weapon; - } - - @Override - public float getMinePower(){ - return mech.mineSpeed; - } - - @Override - public TextureRegion getIconRegion(){ - return mech.icon(Cicon.full); - } - - @Override - public int getItemCapacity(){ - return mech.itemCapacity; - } - - @Override - public void interpolate(){ - super.interpolate(); - - if(interpolator.values.length > 1){ - baseRotation = interpolator.values[1]; - } - - if(interpolator.target.dst(interpolator.last) > 1f){ - walktime += Time.delta(); - } - } - - @Override - public float getBuildPower(Tile tile){ - return mech.buildPower; - } - - @Override - public float maxHealth(){ - return mech.health * state.rules.playerHealthMultiplier; - } - - @Override - public Tile getMineTile(){ - return mining; - } - - @Override - public void setMineTile(Tile tile){ - this.mining = tile; - } - - @Override - public boolean canMine(Item item){ - return item.hardness <= mech.drillPower; - } - - @Override - public float calculateDamage(float amount){ - return amount * Mathf.clamp(1f - (status.getArmorMultiplier() + mech.getExtraArmor(this)) / 100f); - } - - @Override - public void added(){ - baseRotation = 90f; - } - - @Override - public float mass(){ - return mech.mass; - } - - @Override - public boolean isFlying(){ - return mech.flying || boostHeat > liftoffBoost; - } - - @Override - public void damage(float amount){ - hitTime = hitDuration; - if(!net.client()){ - health -= calculateDamage(amount); - } - - if(health <= 0 && !dead){ - Call.onPlayerDeath(this); - } - } - - @Override - public void set(float x, float y){ - this.x = x; - this.y = y; - } - - @Override - public float maxVelocity(){ - return mech.maxSpeed; - } - - @Override - public Queue buildQueue(){ - return placeQueue; - } - - @Override - public String toString(){ - return "Player{" + name + ", mech=" + mech.name + ", id=" + id + ", local=" + isLocal + ", " + x + ", " + y + "}"; - } - - @Override - public EntityGroup targetGroup(){ - return playerGroup; - } - - public void setTeam(Team team){ - this.team = team; - } - - //endregion - - //region draw methods - - @Override - public float drawSize(){ - return isLocal ? Float.MAX_VALUE : 40 + placeDistance; - } - - @Override - public void drawShadow(float offsetX, float offsetY){ - float scl = mech.flying ? 1f : boostHeat / 2f; - - Draw.rect(getIconRegion(), x + offsetX * scl, y + offsetY * scl, rotation - 90); - } - - @Override - public void draw(){ - if(dead) return; - - if(!movement.isZero() && moved && !state.isPaused()){ - walktime += movement.len() * getFloorOn().speedMultiplier * 2f; - baseRotation = Mathf.slerpDelta(baseRotation, movement.angle(), 0.13f); - } - - float ft = Mathf.sin(walktime, 6f, 2f) * (1f - boostHeat); - - Floor floor = getFloorOn(); - - Draw.color(); - Draw.mixcol(Color.white, hitTime / hitDuration); - - if(!mech.flying){ - if(floor.isLiquid){ - Draw.color(Color.white, floor.color, 0.5f); - } - - float boostTrnsY = -boostHeat * 3f; - float boostTrnsX = boostHeat * 3f; - float boostAng = boostHeat * 40f; - - for(int i : Mathf.signs){ - Draw.rect(mech.legRegion, - x + Angles.trnsx(baseRotation, ft * i + boostTrnsY, -boostTrnsX * i), - y + Angles.trnsy(baseRotation, ft * i + boostTrnsY, -boostTrnsX * i), - mech.legRegion.getWidth() * i * Draw.scl, - (mech.legRegion.getHeight() - Mathf.clamp(ft * i, 0, 2)) * Draw.scl, - baseRotation - 90 + boostAng * i); - } - - Draw.rect(mech.baseRegion, x, y, baseRotation - 90); - } - - if(floor.isLiquid){ - Draw.color(Color.white, floor.color, drownTime); - }else{ - Draw.color(Color.white); - } - - Draw.rect(mech.region, x, y, rotation - 90); - - mech.draw(this); - - for(int i : Mathf.signs){ - float tra = rotation - 90, trY = -mech.weapon.getRecoil(this, i > 0) + mech.weaponOffsetY; - float w = i > 0 ? -mech.weapon.region.getWidth() : mech.weapon.region.getWidth(); - Draw.rect(mech.weapon.region, - x + Angles.trnsx(tra, (mech.weaponOffsetX + mech.spreadX(this)) * i, trY), - y + Angles.trnsy(tra, (mech.weaponOffsetX + mech.spreadX(this)) * i, trY), - w * Draw.scl, - mech.weapon.region.getHeight() * Draw.scl, - rotation - 90); - } - - Draw.reset(); - } - - public void drawBackItems(){ - drawBackItems(itemtime, isLocal); - } - - @Override - public void drawStats(){ - mech.drawStats(this); - } - - @Override - public void drawOver(){ - if(dead) return; - - if(isBuilding() && isBuilding){ - if(!state.isPaused()){ - drawBuilding(); - } - }else{ - drawMining(); - } - } - - @Override - public void drawUnder(){ - if(dead) return; - - float size = mech.engineSize * (mech.flying ? 1f : boostHeat); - Draw.color(mech.engineColor); - 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); - 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 = 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 / Scl.scl(1f)); - layout.setText(font, name); - - if(!isLocal){ - Draw.color(0f, 0f, 0f, 0.3f); - Fill.rect(x, y + nameHeight - layout.height / 2, layout.width + 2, layout.height + 3); - Draw.color(); - font.setColor(color); - font.draw(name, x, y + nameHeight, 0, Align.center, false); - - 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-badge"), x + layout.width / 2f + 2 + 1, y + nameHeight - 1.5f, s, s); - Draw.color(color); - 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)){ - String text = textFadeTime <= 0 || lastText == null ? "[LIGHT_GRAY]" + Strings.animated(Time.time(), 4, 15f, ".") : lastText; - float width = 100f; - 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); - - 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); - font.draw(text, x - width/2f, y + textHeight + layout.height, width, Align.center, true); - } - - Draw.reset(); - Pools.free(layout); - font.getData().setScale(1f); - font.setColor(Color.white); - font.setUseIntegerPositions(ints); - } - - /** Draw all current build requests. Does not draw the beam effect, only the positions. */ - public void drawBuildRequests(){ - if(!isLocal) return; - - for(BuildRequest request : buildQueue()){ - if(request.progress > 0.01f || (buildRequest() == request && request.initialized && (dst(request.x * tilesize, request.y * tilesize) <= placeDistance || state.isEditor()))) continue; - - request.animScale = 1f; - if(request.breaking){ - control.input.drawBreaking(request); - }else{ - request.block.drawRequest(request, control.input.allRequests(), - Build.validPlace(getTeam(), request.x, request.y, request.block, request.rotation) || control.input.requestMatches(request)); - } - } - - Draw.reset(); - } - - //endregion - - //region update methods - - @Override - public void updateMechanics(){ - if(isBuilding){ - updateBuilding(); - } - - //mine only when not building - if(buildRequest() == null || !isBuilding){ - updateMining(); - } - } - - @Override - public void update(){ - hitTime -= Time.delta(); - textFadeTime -= Time.delta() / (60 * 5); - itemtime = Mathf.lerpDelta(itemtime, Mathf.num(item.amount > 0), 0.1f); - - if(Float.isNaN(x) || Float.isNaN(y)){ - velocity.set(0f, 0f); - x = 0; - y = 0; - setDead(true); - } - - if(netServer.isWaitingForPlayers()){ - setDead(true); - } - - if(!isDead() && isOutOfBounds()){ - destructTime += Time.delta(); - - if(destructTime >= boundsCountdown){ - kill(); - } - }else{ - destructTime = 0f; - } - - if(!isDead() && isFlying()){ - loops.play(Sounds.thruster, this, Mathf.clamp(velocity.len() * 2f) * 0.3f); - } - - BuildRequest request = buildRequest(); - if(isBuilding() && isBuilding && request.tile() != null && (request.tile().withinDst(x, y, placeDistance) || state.isEditor())){ - loops.play(Sounds.build, request.tile(), 0.75f); - } - - if(isDead()){ - isBoosting = false; - boostHeat = 0f; - if(respawns > 0 || !state.rules.limitedRespawns){ - updateRespawning(); - } - return; - }else{ - spawner = null; - } - - if(isLocal || net.server()){ - avoidOthers(); - } - - Tile tile = world.tileWorld(x, y); - - boostHeat = Mathf.lerpDelta(boostHeat, (tile != null && tile.solid()) || (isBoosting && ((!movement.isZero() && moved) || !isLocal)) ? 1f : 0f, 0.08f); - shootHeat = Mathf.lerpDelta(shootHeat, isShooting() ? 1f : 0f, 0.06f); - mech.updateAlt(this); //updated regardless - - if(boostHeat > liftoffBoost + 0.1f){ - achievedFlight = true; - } - - if(boostHeat <= liftoffBoost + 0.05f && achievedFlight && !mech.flying){ - if(tile != null){ - if(mech.shake > 1f){ - Effects.shake(mech.shake, mech.shake, this); - } - Effects.effect(Fx.unitLand, tile.floor().color, x, y, tile.floor().isLiquid ? 1f : 0.5f); - } - mech.onLand(this); - achievedFlight = false; - } - - if(!isLocal){ - interpolate(); - updateMechanics(); //building happens even with non-locals - status.update(this); //status effect updating also happens with non locals for effect purposes - updateVelocityStatus(); //velocity too, for visual purposes - - if(net.server()){ - updateShooting(); //server simulates player shooting - } - return; - }else if(world.isZone()){ - //unlock mech when used - data.unlockContent(mech); - } - - if(control.input instanceof MobileInput){ - updateTouch(); - }else{ - updateKeyboard(); - } - - isTyping = ui.chatfrag.shown(); - - updateMechanics(); - - if(!mech.flying){ - clampPosition(); - } - } - - protected void updateKeyboard(){ - Tile tile = world.tileWorld(x, y); - boolean canMove = !Core.scene.hasKeyboard() || ui.minimapfrag.shown(); - - isBoosting = Core.input.keyDown(Binding.dash) && !mech.flying; - - //if player is in solid block - if(tile != null && tile.solid()){ - isBoosting = true; - } - - float speed = isBoosting && !mech.flying ? mech.boostSpeed : mech.speed; - - if(mech.flying){ - //prevent strafing backwards, have a penalty for doing so - float penalty = 0.2f; //when going 180 degrees backwards, reduce speed to 0.2x - speed *= Mathf.lerp(1f, penalty, Angles.angleDist(rotation, velocity.angle()) / 180f); - } - - movement.setZero(); - - float xa = Core.input.axis(Binding.move_x); - float ya = Core.input.axis(Binding.move_y); - if(!(Core.scene.getKeyboardFocus() instanceof TextField)){ - movement.y += ya * speed; - movement.x += xa * speed; - } - - if(Core.input.keyDown(Binding.mouse_move)){ - movement.x += Mathf.clamp((Core.input.mouseX() - Core.graphics.getWidth() / 2f) * 0.005f, -1, 1) * speed; - movement.y += Mathf.clamp((Core.input.mouseY() - Core.graphics.getHeight() / 2f) * 0.005f, -1, 1) * speed; - } - - Vec2 vec = Core.input.mouseWorld(control.input.getMouseX(), control.input.getMouseY()); - pointerX = vec.x; - pointerY = vec.y; - updateShooting(); - - movement.limit(speed).scl(Time.delta()); - - if(canMove){ - velocity.add(movement.x, movement.y); - }else{ - isShooting = false; - } - float prex = x, prey = y; - updateVelocityStatus(); - moved = dst(prex, prey) > 0.001f; - - if(canMove){ - float baseLerp = mech.getRotationAlpha(this); - if(!isShooting() || !mech.turnCursor){ - if(!movement.isZero()){ - rotation = Mathf.slerpDelta(rotation, mech.flying ? velocity.angle() : movement.angle(), 0.13f * baseLerp); - } - }else{ - float angle = control.input.mouseAngle(x, y); - this.rotation = Mathf.slerpDelta(this.rotation, angle, 0.1f * baseLerp); - } - } - } - - protected void updateShooting(){ - if(!state.isEditor() && isShooting() && mech.canShoot(this)){ - if(!mech.turnCursor){ - //shoot forward ignoring cursor - mech.weapon.update(this, x + Angles.trnsx(rotation, mech.weapon.targetDistance), y + Angles.trnsy(rotation, mech.weapon.targetDistance)); - }else{ - mech.weapon.update(this, pointerX, pointerY); - } - } - } - - protected void updateTouch(){ - if(Units.invalidateTarget(target, this) && - !(target instanceof TileEntity && ((TileEntity)target).damaged() && target.isValid() && target.getTeam() == team && mech.canHeal && dst(target) < getWeapon().bullet.range() && !(((TileEntity)target).block instanceof BuildBlock))){ - target = null; - } - - if(state.isEditor()){ - target = null; - } - - float targetX = Core.camera.position.x, targetY = Core.camera.position.y; - float attractDst = 15f; - float speed = isBoosting && !mech.flying ? mech.boostSpeed : mech.speed; - - if(moveTarget != null && !moveTarget.isDead()){ - targetX = moveTarget.getX(); - targetY = moveTarget.getY(); - boolean tapping = moveTarget instanceof TileEntity && moveTarget.getTeam() == team; - attractDst = 0f; - - if(tapping){ - velocity.setAngle(angleTo(moveTarget)); - } - - if(dst(moveTarget) <= 2f * Time.delta()){ - if(tapping && !isDead()){ - Tile tile = ((TileEntity)moveTarget).tile; - tile.block().tapped(tile, this); - } - - moveTarget = null; - } - }else{ - moveTarget = null; - } - - movement.set((targetX - x) / Time.delta(), (targetY - y) / Time.delta()).limit(speed); - movement.setAngle(Mathf.slerp(movement.angle(), velocity.angle(), 0.05f)); - - if(dst(targetX, targetY) < attractDst){ - movement.setZero(); - } - - float expansion = 3f; - - hitbox(rect); - rect.x -= expansion; - rect.y -= expansion; - rect.width += expansion * 2f; - rect.height += expansion * 2f; - - isBoosting = collisions.overlapsTile(rect) || dst(targetX, targetY) > 85f; - - velocity.add(movement.scl(Time.delta())); - - if(velocity.len() <= 0.2f && mech.flying){ - rotation += Mathf.sin(Time.time() + id * 99, 10f, 1f); - }else if(target == null){ - rotation = Mathf.slerpDelta(rotation, velocity.angle(), velocity.len() / 10f); - } - - float lx = x, ly = y; - updateVelocityStatus(); - moved = dst(lx, ly) > 0.001f; - - if(mech.flying){ - //hovering effect - x += Mathf.sin(Time.time() + id * 999, 25f, 0.08f); - y += Mathf.cos(Time.time() + id * 999, 25f, 0.08f); - } - - //update shooting if not building, not mining and there's ammo left - if(!isBuilding() && getMineTile() == null){ - - //autofire - if(target == null){ - isShooting = false; - if(Core.settings.getBool("autotarget")){ - target = Units.closestTarget(team, x, y, getWeapon().bullet.range(), u -> u.getTeam() != Team.derelict, u -> u.getTeam() != Team.derelict); - - if(mech.canHeal && target == null){ - target = Geometry.findClosest(x, y, indexer.getDamaged(Team.sharded)); - if(target != null && dst(target) > getWeapon().bullet.range()){ - target = null; - }else if(target != null){ - target = ((Tile)target).entity; - } - } - - if(target != null){ - setMineTile(null); - } - } - }else if(target.isValid() || (target instanceof TileEntity && ((TileEntity)target).damaged() && target.getTeam() == team && - mech.canHeal && dst(target) < getWeapon().bullet.range())){ - //rotate toward and shoot the target - if(mech.turnCursor){ - rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.2f); - } - - Vec2 intercept = Predict.intercept(this, target, getWeapon().bullet.speed); - - pointerX = intercept.x; - pointerY = intercept.y; - - updateShooting(); - isShooting = true; - } - - } - } - - //endregion - - //region utility methods - - public void sendMessage(String text){ - if(isLocal){ - if(Vars.ui != null){ - Vars.ui.chatfrag.addMessage(text, null); - } - }else{ - Call.sendMessage(con, text, null, null); - } - } - - public void sendMessage(String text, Player from){ - sendMessage(text, from, NetClient.colorizeName(from.id, from.name)); - } - - public void sendMessage(String text, Player from, String fromName){ - if(isLocal){ - if(Vars.ui != null){ - Vars.ui.chatfrag.addMessage(text, fromName); - } - }else{ - 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); - } - } - - /** Resets all values of the player. */ - public void reset(){ - resetNoAdd(); - - add(); - } - - public void resetNoAdd(){ - status.clear(); - team = Team.sharded; - item.amount = 0; - placeQueue.clear(); - dead = true; - lastText = null; - isBuilding = true; - textFadeTime = 0f; - target = null; - moveTarget = null; - isShooting = isBoosting = isTransferring = isTyping = false; - spawner = lastSpawner = null; - health = maxHealth(); - mining = null; - boostHeat = drownTime = hitTime = 0f; - mech = Mechs.starter; - placeQueue.clear(); - respawns = state.rules.respawns; - } - - public boolean isShooting(){ - return isShooting && (boostHeat < 0.1f || mech.flying) && mining == null; - } - - public void updateRespawning(){ - - if(state.isEditor()){ - //instant respawn at center of map. - set(world.width() * tilesize/2f, world.height() * tilesize/2f); - setDead(false); - }else if(spawner != null && spawner.isValid()){ - spawner.updateSpawning(this); - }else if(!netServer.isWaitingForPlayers()){ - if(!net.client()){ - if(lastSpawner != null && lastSpawner.isValid()){ - this.spawner = lastSpawner; - }else if(getClosestCore() != null){ - this.spawner = (SpawnerTrait)getClosestCore(); - } - } - }else if(getClosestCore() != null){ - set(getClosestCore().getX(), getClosestCore().getY()); - } - } - - public void beginRespawning(SpawnerTrait spawner){ - this.spawner = spawner; - this.lastSpawner = spawner; - this.dead = true; - setNet(spawner.getX(), spawner.getY()); - spawner.updateSpawning(this); - } - - //endregion - - //region read and write methods - - @Override - public byte version(){ - return 0; - } - - @Override - public void writeSave(DataOutput stream) throws IOException{ - stream.writeBoolean(isLocal); - - if(isLocal){ - stream.writeByte(mech.id); - stream.writeInt(lastSpawner == null ? noSpawner : lastSpawner.getTile().pos()); - super.writeSave(stream, false); - } - } - - @Override - public void readSave(DataInput stream, byte version) throws IOException{ - boolean local = stream.readBoolean(); - - if(local){ - byte mechid = stream.readByte(); - int spawner = stream.readInt(); - Tile stile = world.tile(spawner); - Player player = headless ? this : Vars.player; - player.readSaveSuper(stream, version); - player.mech = content.getByID(ContentType.mech, mechid); - player.dead = false; - if(stile != null && stile.entity instanceof SpawnerTrait){ - player.lastSpawner = (SpawnerTrait)stile.entity; - } - } - } - - private void readSaveSuper(DataInput stream, byte version) throws IOException{ - super.readSave(stream, version); - - add(); - } - - @Override - public void write(DataOutput buffer) throws IOException{ - super.writeSave(buffer, !isLocal); - TypeIO.writeStringData(buffer, name); - buffer.writeByte(Pack.byteValue(isAdmin) | (Pack.byteValue(dead) << 1) | (Pack.byteValue(isBoosting) << 2) | (Pack.byteValue(isTyping) << 3)| (Pack.byteValue(isBuilding) << 4)); - buffer.writeInt(Color.rgba8888(color)); - buffer.writeByte(mech.id); - buffer.writeInt(mining == null ? noSpawner : mining.pos()); - buffer.writeInt(spawner == null || !spawner.hasUnit(this) ? noSpawner : spawner.getTile().pos()); - buffer.writeShort((short)(baseRotation * 2)); - - writeBuilding(buffer); - } - - @Override - public void read(DataInput buffer) throws IOException{ - float lastx = x, lasty = y, lastrot = rotation, lastvx = velocity.x, lastvy = velocity.y; - - super.readSave(buffer, version()); - - name = TypeIO.readStringData(buffer); - byte bools = buffer.readByte(); - isAdmin = (bools & 1) != 0; - dead = (bools & 2) != 0; - boolean boosting = (bools & 4) != 0; - isTyping = (bools & 8) != 0; - boolean building = (bools & 16) != 0; - color.set(buffer.readInt()); - mech = content.getByID(ContentType.mech, buffer.readByte()); - int mine = buffer.readInt(); - int spawner = buffer.readInt(); - float baseRotation = buffer.readShort() / 2f; - - readBuilding(buffer, !isLocal); - - interpolator.read(lastx, lasty, x, y, rotation, baseRotation); - rotation = lastrot; - x = lastx; - y = lasty; - - if(isLocal){ - velocity.x = lastvx; - velocity.y = lastvy; - }else{ - mining = world.tile(mine); - isBuilding = building; - isBoosting = boosting; - } - - Tile tile = world.tile(spawner); - if(tile != null && tile.entity instanceof SpawnerTrait){ - this.spawner = (SpawnerTrait)tile.entity; - }else{ - this.spawner = null; - } - } - - //endregion -} diff --git a/core/src/mindustry/entities/type/SolidEntity.java b/core/src/mindustry/entities/type/SolidEntity.java deleted file mode 100644 index d3d0685f3f..0000000000 --- a/core/src/mindustry/entities/type/SolidEntity.java +++ /dev/null @@ -1,19 +0,0 @@ -package mindustry.entities.type; - -import arc.math.geom.Vec2; -import mindustry.entities.traits.SolidTrait; - -public abstract class SolidEntity extends BaseEntity implements SolidTrait{ - protected transient Vec2 velocity = new Vec2(0f, 0.0001f); - private transient Vec2 lastPosition = new Vec2(); - - @Override - public Vec2 lastPosition(){ - return lastPosition; - } - - @Override - public Vec2 velocity(){ - return velocity; - } -} diff --git a/core/src/mindustry/entities/type/TileEntity.java b/core/src/mindustry/entities/type/TileEntity.java deleted file mode 100644 index cf5a2f4bdb..0000000000 --- a/core/src/mindustry/entities/type/TileEntity.java +++ /dev/null @@ -1,356 +0,0 @@ -package mindustry.entities.type; - -import arc.math.*; -import mindustry.annotations.Annotations.*; -import arc.Events; -import arc.struct.Array; -import arc.struct.ObjectSet; -import arc.math.geom.Point2; -import arc.math.geom.Vec2; -import arc.util.*; -import arc.util.ArcAnnotate.*; -import mindustry.entities.EntityGroup; -import mindustry.entities.traits.HealthTrait; -import mindustry.entities.traits.TargetTrait; -import mindustry.game.*; -import mindustry.game.EventType.BlockDestroyEvent; -import mindustry.gen.*; -import mindustry.world.*; -import mindustry.world.consumers.*; -import mindustry.world.modules.*; - -import java.io.*; - -import static mindustry.Vars.*; - -public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ - public static final float timeToSleep = 60f * 4; //4 seconds to fall asleep - private static final ObjectSet tmpTiles = new ObjectSet<>(); - /** This value is only used for debugging. */ - public static int sleepingEntities = 0; - - public Tile tile; - public Block block; - public Interval timer; - public float health; - public float timeScale = 1f, timeScaleDuration; - - public PowerModule power; - public ItemModule items; - public LiquidModule liquids; - public @Nullable ConsumeModule cons; - - /** List of (cached) tiles with entities in proximity, used for outputting to */ - private Array proximity = new Array<>(8); - private boolean dead = false; - private boolean sleeping; - private float sleepTime; - private @Nullable SoundLoop sound; - - @Remote(called = Loc.server, unreliable = true) - public static void onTileDamage(Tile tile, float health){ - if(tile.entity != null){ - tile.entity.health = health; - - if(tile.entity.damaged()){ - indexer.notifyTileDamaged(tile.entity); - } - } - } - - @Remote(called = Loc.server) - public static void onTileDestroyed(Tile tile){ - if(tile.entity == null) return; - tile.entity.onDeath(); - } - - /** Sets this tile entity data to this tile, and adds it if necessary. */ - public TileEntity init(Tile tile, boolean shouldAdd){ - this.tile = tile; - x = tile.drawx(); - y = tile.drawy(); - block = tile.block(); - if(block.activeSound != Sounds.none){ - sound = new SoundLoop(block.activeSound, block.activeSoundVolume); - } - - health = block.health; - timer = new Interval(block.timers); - - if(shouldAdd){ - add(); - } - - return this; - } - - /** Scaled delta. */ - public float delta(){ - return Time.delta() * timeScale; - } - - /** Base efficiency. If this entity has non-buffered power, returns the power %, otherwise returns 1. */ - public float efficiency(){ - return power != null && (block.consumes.has(ConsumeType.power) && !block.consumes.getPower().buffered) ? power.status : 1f; - } - - /** Call when nothing is happening to the entity. This increments the internal sleep timer. */ - public void sleep(){ - sleepTime += Time.delta(); - if(!sleeping && sleepTime >= timeToSleep){ - remove(); - sleeping = true; - sleepingEntities++; - } - } - - /** Call when this entity is updating. This wakes it up. */ - public void noSleep(){ - sleepTime = 0f; - if(sleeping){ - add(); - sleeping = false; - sleepingEntities--; - } - } - - public boolean isSleeping(){ - return sleeping; - } - - public boolean isDead(){ - return dead || tile.entity != this; - } - - @CallSuper - public void write(DataOutput stream) throws IOException{ - stream.writeShort((short)health); - stream.writeByte(Pack.byteByte((byte)8, tile.rotation())); //rotation + marker to indicate that team is moved (8 isn't valid) - stream.writeByte(tile.getTeamID()); - if(items != null) items.write(stream); - if(power != null) power.write(stream); - if(liquids != null) liquids.write(stream); - if(cons != null) cons.write(stream); - } - - @CallSuper - public void read(DataInput stream, byte revision) throws IOException{ - health = stream.readUnsignedShort(); - byte packedrot = stream.readByte(); - byte team = Pack.leftByte(packedrot) == 8 ? stream.readByte() : Pack.leftByte(packedrot); - byte rotation = Pack.rightByte(packedrot); - - tile.setTeam(Team.get(team)); - tile.rotation(rotation); - - if(items != null) items.read(stream); - if(power != null) power.read(stream); - if(liquids != null) liquids.read(stream); - if(cons != null) cons.read(stream); - } - - /** Returns the version of this TileEntity IO code.*/ - public byte version(){ - return 0; - } - - public boolean collide(Bullet other){ - return true; - } - - public void collision(Bullet other){ - block.handleBulletHit(this, other); - } - - public void kill(){ - Call.onTileDestroyed(tile); - } - - @Override - public void damage(float damage){ - if(dead) return; - - if(Mathf.zero(state.rules.blockHealthMultiplier)){ - damage = health + 1; - }else{ - damage /= state.rules.blockHealthMultiplier; - } - - float preHealth = health; - - Call.onTileDamage(tile, health - block.handleDamage(tile, damage)); - - if(health <= 0){ - Call.onTileDestroyed(tile); - } - - if(preHealth >= maxHealth() - 0.00001f && health < maxHealth() && world != null){ //when just damaged - indexer.notifyTileDamaged(this); - } - } - - public Tile getTile(){ - return tile; - } - - public void removeFromProximity(){ - block.onProximityRemoved(tile); - - Point2[] nearby = Edges.getEdges(block.size); - for(Point2 point : nearby){ - Tile other = world.ltile(tile.x + point.x, tile.y + point.y); - //remove this tile from all nearby tile's proximities - if(other != null){ - other.block().onProximityUpdate(other); - - if(other.entity != null){ - other.entity.proximity.removeValue(tile, true); - } - } - } - } - - public void updateProximity(){ - tmpTiles.clear(); - proximity.clear(); - - Point2[] nearby = Edges.getEdges(block.size); - for(Point2 point : nearby){ - Tile other = world.ltile(tile.x + point.x, tile.y + point.y); - - if(other == null) continue; - if(other.entity == null || !(other.interactable(tile.getTeam()))) continue; - - //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 - for(Tile tile : tmpTiles){ - proximity.add(tile); - } - - block.onProximityAdded(tile); - block.onProximityUpdate(tile); - - for(Tile other : tmpTiles){ - other.block().onProximityUpdate(other); - } - } - - public Array proximity(){ - return proximity; - } - - /** Tile configuration. Defaults to 0. Used for block rebuilding. */ - public int config(){ - return 0; - } - - @Override - public void removed(){ - if(sound != null){ - sound.stop(); - } - } - - @Override - public void health(float health){ - this.health = health; - } - - @Override - public float health(){ - return health; - } - - @Override - public float maxHealth(){ - return block.health; - } - - @Override - public void setDead(boolean dead){ - this.dead = dead; - } - - @Override - public void onDeath(){ - if(!dead){ - dead = true; - - Events.fire(new BlockDestroyEvent(tile)); - block.breakSound.at(tile); - block.onDestroyed(tile); - tile.remove(); - remove(); - } - } - - @Override - public Team getTeam(){ - return tile.getTeam(); - } - - @Override - public Vec2 velocity(){ - return Vec2.ZERO; - } - - @Override - public void update(){ - timeScaleDuration -= Time.delta(); - if(timeScaleDuration <= 0f || !block.canOverdrive){ - timeScale = 1f; - } - - if(health <= 0){ - onDeath(); - return; //no need to update anymore - } - - if(sound != null){ - sound.update(x, y, block.shouldActiveSound(tile)); - } - - if(block.idleSound != Sounds.none && block.shouldIdleSound(tile)){ - loops.play(block.idleSound, this, block.idleSoundVolume); - } - - block.update(tile); - - if(liquids != null){ - liquids.update(); - } - - if(cons != null){ - cons.update(); - } - - if(power != null){ - power.graph.update(); - } - } - - @Override - public boolean isValid(){ - return !isDead() && tile.entity == this; - } - - @Override - public EntityGroup targetGroup(){ - return tileGroup; - } - - @Override - public String toString(){ - return "TileEntity{" + - "tile=" + tile + - ", health=" + health + - '}'; - } -} diff --git a/core/src/mindustry/entities/type/TimedEntity.java b/core/src/mindustry/entities/type/TimedEntity.java deleted file mode 100644 index 413b1c3fd5..0000000000 --- a/core/src/mindustry/entities/type/TimedEntity.java +++ /dev/null @@ -1,34 +0,0 @@ -package mindustry.entities.type; - -import arc.util.pooling.Pool.Poolable; -import mindustry.entities.traits.ScaleTrait; -import mindustry.entities.traits.TimeTrait; - -public abstract class TimedEntity extends BaseEntity implements ScaleTrait, TimeTrait, Poolable{ - public float time; - - @Override - public void time(float time){ - this.time = time; - } - - @Override - public float time(){ - return time; - } - - @Override - public void update(){ - updateTime(); - } - - @Override - public void reset(){ - time = 0f; - } - - @Override - public float fin(){ - return time() / lifetime(); - } -} diff --git a/core/src/mindustry/entities/type/Unit.java b/core/src/mindustry/entities/type/Unit.java deleted file mode 100644 index 05dd89a4d6..0000000000 --- a/core/src/mindustry/entities/type/Unit.java +++ /dev/null @@ -1,464 +0,0 @@ -package mindustry.entities.type; - -import arc.*; -import arc.graphics.*; -import arc.graphics.g2d.*; -import arc.math.*; -import arc.math.geom.*; -import arc.scene.ui.layout.*; -import arc.struct.*; -import arc.util.*; -import arc.util.ArcAnnotate.*; -import mindustry.content.*; -import mindustry.entities.*; -import mindustry.entities.effect.*; -import mindustry.entities.traits.*; -import mindustry.entities.units.*; -import mindustry.game.EventType.*; -import mindustry.game.*; -import mindustry.gen.*; -import mindustry.graphics.*; -import mindustry.net.*; -import mindustry.type.*; -import mindustry.ui.*; -import mindustry.world.*; -import mindustry.world.blocks.*; - -import java.io.*; - -import static mindustry.Vars.*; - -public abstract class Unit extends DestructibleEntity implements SaveTrait, TargetTrait, SyncTrait, DrawTrait, TeamTrait{ - /** Total duration of hit flash effect */ - public static final float hitDuration = 9f; - /** Percision divisor of velocity, used when writing. For example a value of '2' would mean the percision is 1/2 = 0.5-size chunks. */ - public static final float velocityPercision = 8f; - /** Maximum absolute value of a velocity vector component. */ - public static final float maxAbsVelocity = 127f / velocityPercision; - public static final int noSpawner = Pos.get(-1, 1); - - private static final Vec2 moveVector = new Vec2(); - - public float rotation; - - protected final Interpolator interpolator = new Interpolator(); - protected final Statuses status = new Statuses(); - protected final ItemStack item = new ItemStack(content.item(0), 0); - - protected Team team = Team.sharded; - protected float drownTime, hitTime; - - @Override - public boolean collidesGrid(int x, int y){ - return !isFlying(); - } - - @Override - public Team getTeam(){ - return team; - } - - @Override - public void interpolate(){ - interpolator.update(); - - x = interpolator.pos.x; - y = interpolator.pos.y; - - if(interpolator.values.length > 0){ - rotation = interpolator.values[0]; - } - } - - @Override - public Interpolator getInterpolator(){ - return interpolator; - } - - @Override - public void damage(float amount){ - if(!net.client()){ - super.damage(calculateDamage(amount)); - } - hitTime = hitDuration; - } - - @Override - public boolean collides(SolidTrait other){ - if(isDead()) return false; - - if(other instanceof DamageTrait){ - return other instanceof TeamTrait && (((TeamTrait)other).getTeam()).isEnemy(team); - }else{ - return other instanceof Unit && ((Unit)other).isFlying() == isFlying(); - } - } - - @Override - public void onDeath(){ - float explosiveness = 2f + item.item.explosiveness * item.amount; - float flammability = item.item.flammability * item.amount; - Damage.dynamicExplosion(x, y, flammability, explosiveness, 0f, getSize() / 2f, Pal.darkFlame); - - ScorchDecal.create(x, y); - Effects.effect(Fx.explosion, this); - Effects.shake(2f, 2f, this); - - Sounds.bang.at(this); - item.amount = 0; - drownTime = 0f; - status.clear(); - Events.fire(new UnitDestroyEvent(this)); - - if(explosiveness > 7f && this == player){ - Events.fire(Trigger.suicideBomb); - } - } - - @Override - public Vec2 velocity(){ - return velocity; - } - - @Override - public void move(float x, float y){ - if(!isFlying()){ - super.move(x, y); - }else{ - moveBy(x, y); - } - } - - @Override - public boolean isValid(){ - return !isDead() && isAdded(); - } - - @Override - public void writeSave(DataOutput stream) throws IOException{ - writeSave(stream, false); - } - - @Override - public void readSave(DataInput stream, byte version) throws IOException{ - byte team = stream.readByte(); - boolean dead = stream.readBoolean(); - float x = stream.readFloat(); - float y = stream.readFloat(); - byte xv = stream.readByte(); - byte yv = stream.readByte(); - float rotation = stream.readShort() / 2f; - int health = stream.readShort(); - byte itemID = stream.readByte(); - short itemAmount = stream.readShort(); - - this.status.readSave(stream, version); - this.item.amount = itemAmount; - this.item.item = content.item(itemID); - this.dead = dead; - this.team = Team.get(team); - this.health = health; - this.x = x; - this.y = y; - this.velocity.set(xv / velocityPercision, yv / velocityPercision); - this.rotation = rotation; - } - - public void writeSave(DataOutput stream, boolean net) throws IOException{ - if(item.item == null) item.item = Items.copper; - - stream.writeByte(team.id); - stream.writeBoolean(isDead()); - stream.writeFloat(net ? interpolator.target.x : x); - stream.writeFloat(net ? interpolator.target.y : y); - stream.writeByte((byte)(Mathf.clamp(velocity.x, -maxAbsVelocity, maxAbsVelocity) * velocityPercision)); - stream.writeByte((byte)(Mathf.clamp(velocity.y, -maxAbsVelocity, maxAbsVelocity) * velocityPercision)); - stream.writeShort((short)(rotation * 2)); - stream.writeShort((short)health); - stream.writeByte(item.item.id); - stream.writeShort((short)item.amount); - status.writeSave(stream); - } - - protected void clampPosition(){ - x = Mathf.clamp(x, 0, world.width() * tilesize - tilesize); - y = Mathf.clamp(y, 0, world.height() * tilesize - tilesize); - } - - public void kill(){ - health = -1; - damage(1); - } - - public boolean isImmune(StatusEffect effect){ - return false; - } - - public boolean isOutOfBounds(){ - return x < -worldBounds || y < -worldBounds || x > world.width() * tilesize + worldBounds || y > world.height() * tilesize + worldBounds; - } - - public float calculateDamage(float amount){ - return amount * Mathf.clamp(1f - status.getArmorMultiplier() / 100f); - } - - public float getDamageMultipler(){ - return status.getDamageMultiplier(); - } - - public boolean hasEffect(StatusEffect effect){ - return status.hasEffect(effect); - } - - public void avoidOthers(){ - float radScl = 1.5f; - float fsize = getSize() / radScl; - moveVector.setZero(); - float cx = x - fsize/2f, cy = y - fsize/2f; - avoid(unitGroup.intersect(cx, cy, fsize, fsize)); - if(!(this instanceof Player)){ - avoid(playerGroup.intersect(cx, cy, fsize, fsize)); - } - velocity.add(moveVector.x / mass() * Time.delta(), moveVector.y / mass() * Time.delta()); - } - - private void avoid(Array arr){ - float radScl = 1.5f; - - for(Unit en : arr){ - if(en.isFlying() != isFlying() || (en instanceof Player && en.getTeam() != getTeam()) || (this instanceof Player && en.isFlying())) continue; - float dst = dst(en); - float scl = Mathf.clamp(1f - dst / (getSize()/(radScl*2f) + en.getSize()/(radScl*2f))); - moveVector.add(Tmp.v1.set((x - en.x) * scl, (y - en.y) * scl).limit(0.4f)); - } - } - - public @Nullable TileEntity getClosestCore(){ - return state.teams.closestCore(x, y, team); - } - - public Floor getFloorOn(){ - Tile tile = world.tileWorld(x, y); - return tile == null ? (Floor)Blocks.air : tile.floor(); - } - - public @Nullable Tile tileOn(){ - return world.tileWorld(x, y); - } - - public void onRespawn(Tile tile){ - } - - /** Updates velocity and status effects. */ - public void updateVelocityStatus(){ - Floor floor = getFloorOn(); - - Tile tile = world.tileWorld(x, y); - - status.update(this); - item.amount = Mathf.clamp(this.item.amount, 0, getItemCapacity()); - - velocity.limit(maxVelocity()).scl(1f + (status.getSpeedMultiplier() - 1f) * Time.delta()); - - if(x < -finalWorldBounds || y < -finalWorldBounds || x >= world.width() * tilesize + finalWorldBounds || y >= world.height() * tilesize + finalWorldBounds){ - kill(); - } - - //apply knockback based on spawns - if(getTeam() != state.rules.waveTeam){ - float relativeSize = state.rules.dropZoneRadius + getSize()/2f + 1f; - for(Tile spawn : spawner.getGroundSpawns()){ - if(withinDst(spawn.worldx(), spawn.worldy(), relativeSize)){ - velocity.add(Tmp.v1.set(this).sub(spawn.worldx(), spawn.worldy()).setLength(0.1f + 1f - dst(spawn) / relativeSize).scl(0.45f * Time.delta())); - } - } - } - - //repel player out of bounds - final float warpDst = 180f; - - if(x < 0) velocity.x += (-x/warpDst); - if(y < 0) velocity.y += (-y/warpDst); - if(x > world.unitWidth()) velocity.x -= (x - world.unitWidth())/warpDst; - if(y > world.unitHeight()) velocity.y -= (y - world.unitHeight())/warpDst; - - - if(isFlying()){ - drownTime = 0f; - move(velocity.x * Time.delta(), velocity.y * Time.delta()); - }else{ - boolean onLiquid = floor.isLiquid; - - if(tile != null){ - tile.block().unitOn(tile, this); - if(tile.block() != Blocks.air){ - onLiquid = false; - } - } - - if(onLiquid && velocity.len() > 0.4f && Mathf.chance((velocity.len() * floor.speedMultiplier) * 0.06f * Time.delta())){ - Effects.effect(floor.walkEffect, floor.color, x, y); - } - - if(onLiquid){ - status.handleApply(this, floor.status, floor.statusDuration); - - if(floor.damageTaken > 0f){ - damagePeriodic(floor.damageTaken); - } - } - - if(onLiquid && floor.drownTime > 0){ - drownTime += Time.delta() * 1f / floor.drownTime; - if(Mathf.chance(Time.delta() * 0.05f)){ - Effects.effect(floor.drownUpdateEffect, floor.color, x, y); - } - }else{ - drownTime = Mathf.lerpDelta(drownTime, 0f, 0.03f); - } - - drownTime = Mathf.clamp(drownTime); - - if(drownTime >= 0.999f && !net.client()){ - damage(health + 1); - if(this == player){ - Events.fire(Trigger.drown); - } - } - - float px = x, py = y; - move(velocity.x * floor.speedMultiplier * Time.delta(), velocity.y * floor.speedMultiplier * Time.delta()); - if(Math.abs(px - x) <= 0.0001f) velocity.x = 0f; - if(Math.abs(py - y) <= 0.0001f) velocity.y = 0f; - } - - velocity.scl(Mathf.clamp(1f - drag() * (isFlying() ? 1f : floor.dragMultiplier) * Time.delta())); - } - - public boolean acceptsItem(Item item){ - return this.item.amount <= 0 || (this.item.item == item && this.item.amount <= getItemCapacity()); - } - - public void addItem(Item item){ - addItem(item, 1); - } - - public void addItem(Item item, int amount){ - this.item.amount = this.item.item == item ? this.item.amount + amount : amount; - this.item.item = item; - this.item.amount = Mathf.clamp(this.item.amount, 0, getItemCapacity()); - } - - public void clearItem(){ - item.amount = 0; - } - - public ItemStack item(){ - return item; - } - - public int maxAccepted(Item item){ - return this.item.item != item && this.item.amount > 0 ? 0 : getItemCapacity() - this.item.amount; - } - - public void applyEffect(StatusEffect effect, float duration){ - if(dead || net.client()) return; //effects are synced and thus not applied through clients - status.handleApply(this, effect, duration); - } - - public void damagePeriodic(float amount){ - damage(amount * Time.delta(), hitTime <= -20 + hitDuration); - } - - public void damage(float amount, boolean withEffect){ - float pre = hitTime; - - damage(amount); - - if(!withEffect){ - hitTime = pre; - } - } - - public void drawUnder(){ - } - - public void drawOver(){ - } - - public void drawStats(){ - 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(); - - drawBackItems(item.amount > 0 ? 1f : 0f, false); - - drawLight(); - } - - public void drawLight(){ - renderer.lights.add(x, y, 50f, Pal.powerLight, 0.6f); - } - - public void drawBackItems(float itemtime, boolean number){ - //draw back items - if(itemtime > 0.01f && item.item != null){ - float backTrns = 5f; - float size = (itemSize + Mathf.absin(Time.time(), 5f, 1f)) * itemtime; - - Draw.mixcol(Pal.accent, Mathf.absin(Time.time(), 5f, 0.5f)); - Draw.rect(item.item.icon(Cicon.medium), - x + Angles.trnsx(rotation + 180f, backTrns), - y + Angles.trnsy(rotation + 180f, backTrns), - size, size, rotation); - - Draw.mixcol(); - - Lines.stroke(1f, Pal.accent); - Lines.circle( - x + Angles.trnsx(rotation + 180f, backTrns), - y + Angles.trnsy(rotation + 180f, backTrns), - (3f + Mathf.absin(Time.time(), 5f, 1f)) * itemtime); - - if(number){ - Fonts.outline.draw(item.amount + "", - x + Angles.trnsx(rotation + 180f, backTrns), - y + Angles.trnsy(rotation + 180f, backTrns) - 3, - Pal.accent, 0.25f * itemtime / Scl.scl(1f), false, Align.center - ); - } - } - - Draw.reset(); - } - - public TextureRegion getPowerCellRegion(){ - return Core.atlas.find("power-cell"); - } - - public void drawAll(){ - if(!isDead()){ - draw(); - drawStats(); - } - } - - public void drawShadow(float offsetX, float offsetY){ - Draw.rect(getIconRegion(), x + offsetX, y + offsetY, rotation - 90); - } - - public float getSize(){ - hitbox(Tmp.r1); - return Math.max(Tmp.r1.width, Tmp.r1.height) * 2f; - } - - public abstract TextureRegion getIconRegion(); - - public abstract Weapon getWeapon(); - - public abstract int getItemCapacity(); - - public abstract float mass(); - - public abstract boolean isFlying(); -} diff --git a/core/src/mindustry/entities/type/base/BaseDrone.java b/core/src/mindustry/entities/type/base/BaseDrone.java deleted file mode 100644 index 02a8fd9d32..0000000000 --- a/core/src/mindustry/entities/type/base/BaseDrone.java +++ /dev/null @@ -1,67 +0,0 @@ -package mindustry.entities.type.base; - -import arc.math.Mathf; -import arc.math.geom.Geometry; -import mindustry.entities.units.*; -import mindustry.world.Tile; -import mindustry.world.meta.BlockFlag; - -import static mindustry.Vars.*; - -public abstract class BaseDrone extends FlyingUnit{ - public final UnitState retreat = new UnitState(){ - public void entered(){ - target = null; - } - - public void update(){ - if(health >= maxHealth()){ - state.set(getStartState()); - }else if(!targetHasFlag(BlockFlag.repair)){ - if(retarget()){ - Tile repairPoint = Geometry.findClosest(x, y, indexer.getAllied(team, BlockFlag.repair)); - if(repairPoint != null){ - target = repairPoint; - }else{ - setState(getStartState()); - } - } - }else{ - circle(40f); - } - } - }; - - public boolean countsAsEnemy(){ - return false; - } - - @Override - public void onCommand(UnitCommand command){ - //do nothing, normal commands are not applicable here - } - - @Override - protected void updateRotation(){ - if(target != null && shouldRotate() && target.dst(this) < type.range){ - rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.3f); - }else{ - rotation = Mathf.slerpDelta(rotation, velocity.angle(), 0.3f); - } - } - - @Override - public void behavior(){ - if(health <= maxHealth() * type.retreatPercent && !state.is(retreat) && Geometry.findClosest(x, y, indexer.getAllied(team, BlockFlag.repair)) != null){ - setState(retreat); - } - } - - public boolean shouldRotate(){ - return state.is(getStartState()); - } - - @Override - public abstract UnitState getStartState(); - -} diff --git a/core/src/mindustry/entities/type/base/BuilderDrone.java b/core/src/mindustry/entities/type/base/BuilderDrone.java deleted file mode 100644 index 336be7be6e..0000000000 --- a/core/src/mindustry/entities/type/base/BuilderDrone.java +++ /dev/null @@ -1,239 +0,0 @@ -package mindustry.entities.type.base; - -import arc.*; -import arc.math.*; -import arc.struct.*; -import arc.util.*; -import mindustry.entities.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; -import mindustry.entities.units.*; -import mindustry.game.EventType.*; -import mindustry.game.Teams.*; -import mindustry.world.*; -import mindustry.world.blocks.*; -import mindustry.world.blocks.BuildBlock.*; - -import java.io.*; - -import static mindustry.Vars.*; - -public class BuilderDrone extends BaseDrone implements BuilderTrait{ - private static final StaticReset reset = new StaticReset(); - private static final IntIntMap totals = new IntIntMap(); - - protected Queue placeQueue = new Queue<>(); - protected BuildRequest lastFound; - protected boolean isBreaking; - protected Player playerTarget; - - public final UnitState - - build = new UnitState(){ - - public void entered(){ - if(!(target instanceof BuildEntity)){ - target = null; - } - } - - public void update(){ - BuildEntity entity = (BuildEntity)target; - TileEntity core = getClosestCore(); - - if(isBuilding() && entity == null && canRebuild()){ - target = world.tile(buildRequest().x, buildRequest().y); - circle(placeDistance * 0.7f); - target = null; - - BuildRequest request = buildRequest(); - - if(world.tile(request.x, request.y).entity instanceof BuildEntity){ - target = world.tile(request.x, request.y).entity; - } - }else if(entity != null && core != null && (entity.progress < 1f || entity.progress > 0f) && entity.tile.block() instanceof BuildBlock){ //building is valid - if(!isBuilding() && dst(target) < placeDistance * 0.9f){ //within distance, begin placing - if(isBreaking){ - buildQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y)); - }else{ - buildQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.rotation(), entity.cblock)); - if(lastFound != null && lastFound.hasConfig){ - buildQueue().last().configure(lastFound.config); - } - } - } - - circle(placeDistance * 0.7f); - velocity.scl(0.74f); - }else{ //else, building isn't valid, follow a player - target = null; - - if(playerTarget == null || playerTarget.getTeam() != team || !playerTarget.isValid()){ - playerTarget = null; - - if(retarget()){ - float minDst = Float.POSITIVE_INFINITY; - int minDrones = Integer.MAX_VALUE; - - //find player with min amount of drones - for(Player player : playerGroup.all()){ - if(player.getTeam() == team){ - int drones = getDrones(player); - float dst = dst2(player); - - if(playerTarget == null || drones < minDrones || (drones == minDrones && dst < minDst)){ - minDrones = drones; - minDst = dst; - playerTarget = player; - } - } - } - } - - if(getSpawner() != null){ - target = getSpawner(); - circle(40f); - target = null; - } - }else{ - incDrones(playerTarget); - TargetTrait prev = target; - target = playerTarget; - float dst = 90f + (id % 10)*3; - float tdst = dst(target); - float scale = (Mathf.lerp(1f, 0.2f, 1f - Mathf.clamp((tdst - dst) / dst))); - circle(dst); - velocity.scl(scale); - target = prev; - } - } - } - }; - - public BuilderDrone(){ - if(reset.check()){ - Events.on(BuildSelectEvent.class, event -> { - if(!(event.tile.entity instanceof BuildEntity)) return; - - for(BaseUnit unit : unitGroup.all()){ - if(unit instanceof BuilderDrone && unit.getTeam() == getTeam()){ - BuilderDrone drone = (BuilderDrone)unit; - if(drone.isBuilding()){ - //stop building if opposite building begins. - BuildRequest req = drone.buildRequest(); - if(req.breaking != event.breaking && req.x == event.tile.x && req.y == event.tile.y){ - drone.clearBuilding(); - drone.target = null; - } - } - } - } - }); - } - } - - int getDrones(Player player){ - return Pack.leftShort(totals.get(player.id, 0)); - } - - void incDrones(Player player){ - int num = totals.get(player.id, 0); - int amount = Pack.leftShort(num), frame = Pack.rightShort(num); - short curFrame = (short)(Core.graphics.getFrameId() % Short.MAX_VALUE); - - if(frame != curFrame){ - totals.put(player.id, Pack.shortInt((short)1, curFrame)); - }else{ - totals.put(player.id, Pack.shortInt((short)(amount + 1), curFrame)); - } - } - - boolean canRebuild(){ - return true; - } - - @Override - public float getBuildPower(Tile tile){ - return type.buildPower; - } - - @Override - public Queue buildQueue(){ - return placeQueue; - } - - @Override - public void update(){ - super.update(); - - if(!isBuilding() && timer.get(timerTarget2, 15)){ - for(Player player : playerGroup.all()){ - if(player.getTeam() == team && player.buildRequest() != null){ - BuildRequest req = player.buildRequest(); - Tile tile = world.tile(req.x, req.y); - if(tile != null && tile.entity instanceof BuildEntity){ - BuildEntity b = tile.ent(); - float dist = Math.min(b.dst(x, y) - placeDistance, 0); - if(dist / type.maxVelocity < b.buildCost * 0.9f){ - lastFound = req; - target = b; - this.isBreaking = req.breaking; - setState(build); - break; - } - } - } - } - - if(timer.get(timerTarget, 80) && Units.closestEnemy(getTeam(), x, y, 100f, u -> !(u instanceof BaseDrone)) == null && !isBuilding()){ - TeamData data = team.data(); - if(!data.brokenBlocks.isEmpty()){ - BrokenBlock block = data.brokenBlocks.removeLast(); - if(Build.validPlace(getTeam(), block.x, block.y, content.block(block.block), block.rotation)){ - placeQueue.addFirst(new BuildRequest(block.x, block.y, block.rotation, content.block(block.block)).configure(block.config)); - setState(build); - } - } - } - } - - updateBuilding(); - } - - @Override - public boolean shouldRotate(){ - return isBuilding(); - } - - @Override - public UnitState getStartState(){ - return build; - } - - @Override - public void drawOver(){ - drawBuilding(); - } - - @Override - public float drawSize(){ - return isBuilding() ? placeDistance * 2f : 30f; - } - - @Override - public boolean canCreateBlocks(){ - return true; - } - - @Override - public void write(DataOutput data) throws IOException{ - super.write(data); - writeBuilding(data); - } - - @Override - public void read(DataInput data) throws IOException{ - super.read(data); - readBuilding(data); - } -} diff --git a/core/src/mindustry/entities/type/base/FlyingUnit.java b/core/src/mindustry/entities/type/base/FlyingUnit.java deleted file mode 100644 index 35473b7a4e..0000000000 --- a/core/src/mindustry/entities/type/base/FlyingUnit.java +++ /dev/null @@ -1,256 +0,0 @@ -package mindustry.entities.type.base; - -import arc.graphics.*; -import arc.graphics.g2d.*; -import arc.math.*; -import arc.math.geom.*; -import arc.util.*; -import mindustry.*; -import mindustry.entities.*; -import mindustry.entities.bullet.*; -import mindustry.entities.type.*; -import mindustry.entities.units.*; -import mindustry.graphics.*; -import mindustry.world.*; -import mindustry.world.meta.*; - -import static mindustry.Vars.*; - -public class FlyingUnit extends BaseUnit{ - protected float[] weaponAngles = {0,0}; - - protected final UnitState - - attack = new UnitState(){ - public void entered(){ - target = null; - } - - public void update(){ - - if(Units.invalidateTarget(target, team, x, y)){ - target = null; - } - - if(retarget()){ - targetClosest(); - - if(target == null) targetClosestEnemyFlag(BlockFlag.producer); - if(target == null) targetClosestEnemyFlag(BlockFlag.turret); - - if(target == null && isCommanded() && getCommand() != UnitCommand.attack){ - onCommand(getCommand()); - } - } - - if(getClosestSpawner() == null && getSpawner() != null && target == null){ - target = getSpawner(); - circle(80f + Mathf.randomSeed(id) * 120); - }else if(target != null){ - attack(type.attackLength); - - if((Angles.near(angleTo(target), rotation, type.shootCone) || getWeapon().ignoreRotation) //bombers and such don't care about rotation - && dst(target) < getWeapon().bullet.range()){ - BulletType ammo = getWeapon().bullet; - - if(type.rotateWeapon){ - for(boolean left : Mathf.booleans){ - int wi = Mathf.num(left); - float wx = x + Angles.trnsx(rotation - 90, getWeapon().width * Mathf.sign(left)); - float wy = y + Angles.trnsy(rotation - 90, getWeapon().width * Mathf.sign(left)); - - weaponAngles[wi] = Mathf.slerpDelta(weaponAngles[wi], Angles.angle(wx, wy, target.getX(), target.getY()), 0.1f); - - Tmp.v2.trns(weaponAngles[wi], getWeapon().length); - getWeapon().update(FlyingUnit.this, wx + Tmp.v2.x, wy + Tmp.v2.y, weaponAngles[wi], left); - } - }else{ - Vec2 to = Predict.intercept(FlyingUnit.this, target, ammo.speed); - getWeapon().update(FlyingUnit.this, to.x, to.y); - } - } - }else{ - target = getClosestSpawner(); - moveTo(Vars.state.rules.dropZoneRadius + 120f); - } - } - }, - rally = new UnitState(){ - public void update(){ - if(retarget()){ - targetClosestAllyFlag(BlockFlag.rally); - targetClosest(); - - if(target != null && !Units.invalidateTarget(target, team, x, y)){ - setState(attack); - return; - } - - if(target == null) target = getSpawner(); - } - - if(target != null){ - circle(65f + Mathf.randomSeed(id) * 100); - } - } - }, - retreat = new UnitState(){ - public void entered(){ - target = null; - } - - public void update(){ - if(retarget()){ - target = getSpawner(); - - Tile repair = Geometry.findClosest(x, y, indexer.getAllied(team, BlockFlag.repair)); - if(repair != null && damaged()) FlyingUnit.this.target = repair.entity; - if(target == null) target = getClosestCore(); - } - - circle(targetHasFlag(BlockFlag.repair) ? 20f : 60f + Mathf.randomSeed(id) * 50, 0.65f * type.speed); - } - };; - - @Override - public void onCommand(UnitCommand command){ - state.set(command == UnitCommand.retreat ? retreat : - command == UnitCommand.attack ? attack : - command == UnitCommand.rally ? rally : - null); - } - - @Override - public void move(float x, float y){ - moveBy(x, y); - } - - @Override - public void update(){ - super.update(); - - if(!net.client()){ - updateRotation(); - } - wobble(); - } - - @Override - public void drawUnder(){ - drawEngine(); - } - - @Override - public void draw(){ - Draw.mixcol(Color.white, hitTime / hitDuration); - Draw.rect(type.region, x, y, rotation - 90); - - drawWeapons(); - - Draw.mixcol(); - } - - public void drawWeapons(){ - for(int i : Mathf.signs){ - float tra = rotation - 90, trY = -type.weapon.getRecoil(this, i > 0) + type.weaponOffsetY; - float w = -i * type.weapon.region.getWidth() * Draw.scl; - Draw.rect(type.weapon.region, - x + Angles.trnsx(tra, getWeapon().width * i, trY), - y + Angles.trnsy(tra, getWeapon().width * i, trY), w, type.weapon.region.getHeight() * Draw.scl, rotation - 90); - } - } - - public void drawEngine(){ - Draw.color(Pal.engine); - 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); - 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(); - } - - @Override - public void behavior(){ - - if(Units.invalidateTarget(target, this)){ - for(boolean left : Mathf.booleans){ - int wi = Mathf.num(left); - weaponAngles[wi] = Mathf.slerpDelta(weaponAngles[wi], rotation, 0.1f); - } - } - } - - @Override - public UnitState getStartState(){ - return attack; - } - - protected void wobble(){ - 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(); - - if(velocity.len() <= 0.05f){ - //rotation += Mathf.sin(Time.time() + id * 99, 10f, 2f * type.speed)*Time.delta(); - } - } - - protected void updateRotation(){ - rotation = velocity.angle(); - } - - protected void circle(float circleLength){ - circle(circleLength, type.speed); - } - - protected void circle(float circleLength, float speed){ - if(target == null) return; - - Tmp.v1.set(target.getX() - x, target.getY() - y); - - if(Tmp.v1.len() < circleLength){ - Tmp.v1.rotate((circleLength - Tmp.v1.len()) / circleLength * 180f); - } - - Tmp.v1.setLength(speed * Time.delta()); - - velocity.add(Tmp.v1); - } - - protected void moveTo(float circleLength){ - if(target == null) return; - - Tmp.v1.set(target.getX() - x, target.getY() - y); - - float length = circleLength <= 0.001f ? 1f : Mathf.clamp((dst(target) - circleLength) / 100f, -1f, 1f); - - Tmp.v1.setLength(type.speed * Time.delta() * length); - if(length < -0.5f){ - Tmp.v1.rotate(180f); - }else if(length < 0){ - Tmp.v1.setZero(); - } - - velocity.add(Tmp.v1); - } - - protected void attack(float circleLength){ - Tmp.v1.set(target.getX() - x, target.getY() - y); - - float ang = angleTo(target); - float diff = Angles.angleDist(ang, rotation); - - if(diff > 100f && Tmp.v1.len() < circleLength){ - Tmp.v1.setAngle(velocity.angle()); - }else{ - Tmp.v1.setAngle(Mathf.slerpDelta(velocity.angle(), Tmp.v1.angle(), 0.44f)); - } - - Tmp.v1.setLength(type.speed * Time.delta()); - - velocity.add(Tmp.v1); - } -} diff --git a/core/src/mindustry/entities/type/base/GroundUnit.java b/core/src/mindustry/entities/type/base/GroundUnit.java deleted file mode 100644 index 56ba404a30..0000000000 --- a/core/src/mindustry/entities/type/base/GroundUnit.java +++ /dev/null @@ -1,266 +0,0 @@ -package mindustry.entities.type.base; - -import arc.graphics.*; -import arc.graphics.g2d.*; -import arc.math.*; -import arc.math.geom.*; -import arc.util.*; -import mindustry.*; -import mindustry.ai.Pathfinder.*; -import mindustry.entities.*; -import mindustry.entities.bullet.*; -import mindustry.entities.type.*; -import mindustry.entities.units.*; -import mindustry.game.*; -import mindustry.type.*; -import mindustry.world.*; -import mindustry.world.blocks.*; -import mindustry.world.meta.*; - -import static mindustry.Vars.*; - -public class GroundUnit extends BaseUnit{ - protected static Vec2 vec = new Vec2(); - - protected float walkTime; - protected float stuckTime; - protected float baseRotation; - - public final UnitState - - attack = new UnitState(){ - public void entered(){ - target = null; - } - - public void update(){ - TileEntity core = getClosestEnemyCore(); - - if(core == null){ - Tile closestSpawn = getClosestSpawner(); - if(closestSpawn == null || !withinDst(closestSpawn, Vars.state.rules.dropZoneRadius + 85f)){ - moveToCore(PathTarget.enemyCores); - } - }else{ - - float dst = dst(core); - - if(dst < getWeapon().bullet.range() / 1.1f){ - target = core; - } - - if(dst > getWeapon().bullet.range() * 0.5f){ - moveToCore(PathTarget.enemyCores); - } - } - } - }, - rally = new UnitState(){ - public void update(){ - Tile target = getClosest(BlockFlag.rally); - - if(target != null && dst(target) > 80f){ - moveToCore(PathTarget.rallyPoints); - } - } - }, - retreat = new UnitState(){ - public void entered(){ - target = null; - } - - public void update(){ - moveAwayFromCore(); - } - }; - - @Override - public void onCommand(UnitCommand command){ - state.set(command == UnitCommand.retreat ? retreat : - command == UnitCommand.attack ? attack : - command == UnitCommand.rally ? rally : - null); - } - - @Override - public void interpolate(){ - super.interpolate(); - - if(interpolator.values.length > 1){ - baseRotation = interpolator.values[1]; - } - } - - @Override - public void move(float x, float y){ - float dst = Mathf.dst(x, y); - if(dst > 0.01f){ - baseRotation = Mathf.slerp(baseRotation, Mathf.angle(x, y), type.baseRotateSpeed * (dst / type.speed)); - } - super.move(x, y); - } - - @Override - public UnitState getStartState(){ - return attack; - } - - @Override - public void update(){ - super.update(); - - stuckTime = !vec.set(x, y).sub(lastPosition()).isZero(0.0001f) ? 0f : stuckTime + Time.delta(); - - if(!velocity.isZero()){ - baseRotation = Mathf.slerpDelta(baseRotation, velocity.angle(), 0.05f); - } - - if(stuckTime < 1f){ - walkTime += Time.delta(); - } - } - - @Override - public Weapon getWeapon(){ - return type.weapon; - } - - @Override - public void draw(){ - 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); - } - - for(int i : Mathf.signs){ - Draw.rect(type.legRegion, - x + Angles.trnsx(baseRotation, ft * i), - y + Angles.trnsy(baseRotation, ft * i), - type.legRegion.getWidth() * i * Draw.scl, type.legRegion.getHeight() * Draw.scl - Mathf.clamp(ft * i, 0, 2), baseRotation - 90); - } - - if(floor.isLiquid){ - Draw.color(Color.white, floor.color, drownTime * 0.4f); - }else{ - Draw.color(Color.white); - } - - Draw.rect(type.baseRegion, x, y, baseRotation - 90); - - Draw.rect(type.region, x, y, rotation - 90); - - for(int i : Mathf.signs){ - float tra = rotation - 90, trY = -type.weapon.getRecoil(this, i > 0) + type.weaponOffsetY; - float w = -i * type.weapon.region.getWidth() * Draw.scl; - Draw.rect(type.weapon.region, - x + Angles.trnsx(tra, getWeapon().width * i, trY), - y + Angles.trnsy(tra, getWeapon().width * i, trY), w, type.weapon.region.getHeight() * Draw.scl, rotation - 90); - } - - Draw.mixcol(); - } - - @Override - public void behavior(){ - - if(!Units.invalidateTarget(target, this)){ - if(dst(target) < getWeapon().bullet.range()){ - rotate(angleTo(target)); - - if(Angles.near(angleTo(target), rotation, 13f)){ - BulletType ammo = getWeapon().bullet; - - Vec2 to = Predict.intercept(GroundUnit.this, target, ammo.speed); - - getWeapon().update(GroundUnit.this, to.x, to.y); - } - } - } - } - - @Override - public void updateTargeting(){ - super.updateTargeting(); - - if(Units.invalidateTarget(target, team, x, y, Float.MAX_VALUE)){ - target = null; - } - - if(retarget()){ - targetClosest(); - } - } - - protected void patrol(){ - vec.trns(baseRotation, type.speed * Time.delta()); - velocity.add(vec.x, vec.y); - vec.trns(baseRotation, type.hitsizeTile * 5); - Tile tile = world.tileWorld(x + vec.x, y + vec.y); - if((tile == null || tile.solid() || tile.floor().drownTime > 0 || tile.floor().isLiquid) || stuckTime > 10f){ - baseRotation += Mathf.sign(id % 2 - 0.5f) * Time.delta() * 3f; - } - - rotation = Mathf.slerpDelta(rotation, velocity.angle(), type.rotatespeed); - } - - protected void circle(float circleLength){ - if(target == null) return; - - vec.set(target.getX() - x, target.getY() - y); - - if(vec.len() < circleLength){ - vec.rotate((circleLength - vec.len()) / circleLength * 180f); - } - - vec.setLength(type.speed * Time.delta()); - - velocity.add(vec); - } - - protected void moveToCore(PathTarget path){ - Tile tile = world.tileWorld(x, y); - if(tile == null) return; - Tile targetTile = pathfinder.getTargetTile(tile, team, path); - - if(tile == targetTile) return; - - velocity.add(vec.trns(angleTo(targetTile), type.speed * Time.delta())); - if(Units.invalidateTarget(target, this)){ - rotation = Mathf.slerpDelta(rotation, baseRotation, type.rotatespeed); - } - } - - protected void moveAwayFromCore(){ - Team enemy = null; - for(Team team : team.enemies()){ - if(team.active()){ - enemy = team; - break; - } - } - - if(enemy == null){ - for(Team team : team.enemies()){ - enemy = team; - break; - } - } - - if(enemy == null) return; - - Tile tile = world.tileWorld(x, y); - if(tile == null) return; - Tile targetTile = pathfinder.getTargetTile(tile, enemy, PathTarget.enemyCores); - TileEntity core = getClosestCore(); - - if(tile == targetTile || core == null || dst(core) < 120f) return; - - velocity.add(vec.trns(angleTo(targetTile), type.speed * Time.delta())); - rotation = Mathf.slerpDelta(rotation, baseRotation, type.rotatespeed); - } -} diff --git a/core/src/mindustry/entities/type/base/HoverUnit.java b/core/src/mindustry/entities/type/base/HoverUnit.java deleted file mode 100644 index a1dfd25819..0000000000 --- a/core/src/mindustry/entities/type/base/HoverUnit.java +++ /dev/null @@ -1,34 +0,0 @@ -package mindustry.entities.type.base; - -import arc.graphics.g2d.Draw; -import arc.math.Angles; -import arc.math.Mathf; -import mindustry.entities.Units; - -public class HoverUnit extends FlyingUnit{ - - @Override - public void drawWeapons(){ - for(int i : Mathf.signs){ - float tra = rotation - 90, trY = -getWeapon().getRecoil(this, i > 0) + type.weaponOffsetY; - float w = i > 0 ? -12 : 12; - float wx = x + Angles.trnsx(tra, getWeapon().width * i, trY), wy = y + Angles.trnsy(tra, getWeapon().width * i, trY); - int wi = (i + 1) / 2; - Draw.rect(getWeapon().region, wx, wy, w, 12, weaponAngles[wi] - 90); - } - } - - @Override - protected void attack(float circleLength){ - moveTo(circleLength); - } - - @Override - protected void updateRotation(){ - if(!Units.invalidateTarget(target, this)){ - rotation = Mathf.slerpDelta(rotation, angleTo(target), type.rotatespeed); - }else{ - rotation = Mathf.slerpDelta(rotation, velocity.angle(), type.baseRotateSpeed); - } - } -} diff --git a/core/src/mindustry/entities/type/base/MinerDrone.java b/core/src/mindustry/entities/type/base/MinerDrone.java deleted file mode 100644 index 5c10983577..0000000000 --- a/core/src/mindustry/entities/type/base/MinerDrone.java +++ /dev/null @@ -1,179 +0,0 @@ -package mindustry.entities.type.base; - -import arc.math.Mathf; -import arc.util.Structs; -import mindustry.content.Blocks; -import mindustry.entities.traits.MinerTrait; -import mindustry.entities.type.TileEntity; -import mindustry.entities.units.UnitState; -import mindustry.gen.Call; -import mindustry.type.Item; -import mindustry.type.ItemType; -import mindustry.world.Pos; -import mindustry.world.Tile; - -import java.io.*; - -import static mindustry.Vars.*; - -/** A drone that only mines.*/ -public class MinerDrone extends BaseDrone implements MinerTrait{ - protected Item targetItem; - protected Tile mineTile; - - public final UnitState - - mine = new UnitState(){ - public void entered(){ - target = null; - } - - public void update(){ - TileEntity entity = getClosestCore(); - - if(entity == null) return; - - findItem(); - - //core full of the target item, do nothing - if(targetItem != null && entity.block.acceptStack(targetItem, 1, entity.tile, MinerDrone.this) == 0){ - MinerDrone.this.clearItem(); - return; - } - - //if inventory is full, drop it off. - if(item.amount >= getItemCapacity() || (targetItem != null && !acceptsItem(targetItem))){ - setState(drop); - }else{ - if(retarget() && targetItem != null){ - target = indexer.findClosestOre(x, y, targetItem); - } - - if(target instanceof Tile){ - moveTo(type.range / 1.5f); - - if(dst(target) < type.range && mineTile != target){ - setMineTile((Tile)target); - } - - if(((Tile)target).block() != Blocks.air){ - setState(drop); - } - }else{ - //nothing to mine anymore, core full: circle spawnpoint - if(getSpawner() != null){ - target = getSpawner(); - - circle(40f); - } - } - } - } - - public void exited(){ - setMineTile(null); - } - }, - - drop = new UnitState(){ - public void entered(){ - target = null; - } - - public void update(){ - if(item.amount == 0 || item.item.type != ItemType.material){ - clearItem(); - setState(mine); - return; - } - - target = getClosestCore(); - - if(target == null) return; - - TileEntity tile = (TileEntity)target; - - if(dst(target) < type.range){ - if(tile.tile.block().acceptStack(item.item, item.amount, tile.tile, MinerDrone.this) > 0){ - Call.transferItemTo(item.item, item.amount, x, y, tile.tile); - } - - clearItem(); - setState(mine); - } - - circle(type.range / 1.8f); - } - }; - - @Override - public UnitState getStartState(){ - return mine; - } - - @Override - public void update(){ - super.update(); - - updateMining(); - } - - @Override - protected void updateRotation(){ - if(mineTile != null && shouldRotate() && mineTile.dst(this) < type.range){ - rotation = Mathf.slerpDelta(rotation, angleTo(mineTile), 0.3f); - }else{ - rotation = Mathf.slerpDelta(rotation, velocity.angle(), 0.3f); - } - } - - @Override - public boolean shouldRotate(){ - return isMining(); - } - - @Override - public void drawOver(){ - drawMining(); - } - - @Override - public boolean canMine(Item item){ - return type.toMine.contains(item); - } - - @Override - public float getMinePower(){ - return type.minePower; - } - - @Override - public Tile getMineTile(){ - return mineTile; - } - - @Override - public void setMineTile(Tile tile){ - mineTile = tile; - } - - @Override - public void write(DataOutput data) throws IOException{ - super.write(data); - data.writeInt(mineTile == null || !state.is(mine) ? Pos.invalid : mineTile.pos()); - } - - @Override - public void read(DataInput data) throws IOException{ - super.read(data); - mineTile = world.tile(data.readInt()); - } - - protected void findItem(){ - TileEntity entity = getClosestCore(); - if(entity == null){ - return; - } - targetItem = Structs.findMin(type.toMine, indexer::hasOre, (a, b) -> -Integer.compare(entity.items.get(a), entity.items.get(b))); - } -} diff --git a/core/src/mindustry/entities/type/base/RepairDrone.java b/core/src/mindustry/entities/type/base/RepairDrone.java deleted file mode 100644 index a796d6eddc..0000000000 --- a/core/src/mindustry/entities/type/base/RepairDrone.java +++ /dev/null @@ -1,73 +0,0 @@ -package mindustry.entities.type.base; - -import mindustry.entities.Units; -import mindustry.entities.type.TileEntity; -import mindustry.entities.units.UnitState; -import mindustry.world.Pos; -import mindustry.world.Tile; -import mindustry.world.blocks.*; - -import java.io.*; - -import static mindustry.Vars.world; - -public class RepairDrone extends BaseDrone{ - public final UnitState repair = new UnitState(){ - - public void entered(){ - target = null; - } - - public void update(){ - - if(retarget()){ - target = Units.findDamagedTile(team, x, y); - } - - if(target instanceof TileEntity && ((TileEntity)target).block instanceof BuildBlock){ - target = null; - } - - if(target != null){ - if(target.dst(RepairDrone.this) > type.range){ - circle(type.range * 0.9f); - }else{ - getWeapon().update(RepairDrone.this, target.getX(), target.getY()); - } - }else{ - //circle spawner if there's nothing to repair - if(getSpawner() != null){ - target = getSpawner(); - circle(type.range * 1.5f, type.speed/2f); - target = null; - } - } - } - }; - - @Override - public boolean shouldRotate(){ - return target != null; - } - - @Override - public UnitState getStartState(){ - return repair; - } - - @Override - public void write(DataOutput data) throws IOException{ - super.write(data); - data.writeInt(state.is(repair) && target instanceof TileEntity ? ((TileEntity)target).tile.pos() : Pos.invalid); - } - - @Override - public void read(DataInput data) throws IOException{ - super.read(data); - Tile repairing = world.tile(data.readInt()); - - if(repairing != null){ - target = repairing.entity; - } - } -} diff --git a/core/src/mindustry/entities/units/AIController.java b/core/src/mindustry/entities/units/AIController.java new file mode 100644 index 0000000000..a08058f86d --- /dev/null +++ b/core/src/mindustry/entities/units/AIController.java @@ -0,0 +1,17 @@ +package mindustry.entities.units; + +import mindustry.gen.*; + +public class AIController implements UnitController{ + protected Unitc unit; + + @Override + public void unit(Unitc unit){ + this.unit = unit; + } + + @Override + public Unitc unit(){ + return unit; + } +} diff --git a/core/src/mindustry/entities/units/BuildRequest.java b/core/src/mindustry/entities/units/BuildRequest.java new file mode 100644 index 0000000000..740da58163 --- /dev/null +++ b/core/src/mindustry/entities/units/BuildRequest.java @@ -0,0 +1,126 @@ +package mindustry.entities.units; + +import arc.math.geom.*; +import arc.util.ArcAnnotate.*; +import mindustry.world.*; + +import static mindustry.Vars.*; + +/** Class for storing build requests. Can be either a place or remove request. */ +public class BuildRequest{ + /** Position and rotation of this request. */ + public int x, y, rotation; + /** Block being placed. If null, this is a breaking request.*/ + public @Nullable Block block; + /** Whether this is a break request.*/ + public boolean breaking; + /** Whether this request comes with a config int. If yes, any blocks placed with this request will not call playerPlaced.*/ + public boolean hasConfig; + /** Config int. Not used unless hasConfig is true.*/ + public int config; + /** Original position, only used in schematics.*/ + public int originalX, originalY, originalWidth, originalHeight; + + /** Last progress.*/ + public float progress; + /** Whether construction has started for this request, and other special variables.*/ + public boolean initialized, worldContext = true, stuck; + + /** Visual scale. Used only for rendering.*/ + public float animScale = 0f; + + /** This creates a build request. */ + public BuildRequest(int x, int y, int rotation, Block block){ + this.x = x; + this.y = y; + this.rotation = rotation; + this.block = block; + this.breaking = false; + } + + /** This creates a remove request. */ + public BuildRequest(int x, int y){ + this.x = x; + this.y = y; + this.rotation = -1; + this.block = world.tile(x, y).block(); + this.breaking = true; + } + + public BuildRequest(){ + + } + + public BuildRequest copy(){ + BuildRequest copy = new BuildRequest(); + copy.x = x; + copy.y = y; + copy.rotation = rotation; + copy.block = block; + copy.breaking = breaking; + copy.hasConfig = hasConfig; + copy.config = config; + copy.originalX = originalX; + copy.originalY = originalY; + copy.progress = progress; + copy.initialized = initialized; + copy.animScale = animScale; + return copy; + } + + public BuildRequest original(int x, int y, int originalWidth, int originalHeight){ + originalX = x; + originalY = y; + this.originalWidth = originalWidth; + this.originalHeight = originalHeight; + return this; + } + + public Rect bounds(Rect rect){ + if(breaking){ + return rect.set(-100f, -100f, 0f, 0f); + }else{ + return block.bounds(x, y, rect); + } + } + + public BuildRequest set(int x, int y, int rotation, Block block){ + this.x = x; + this.y = y; + this.rotation = rotation; + this.block = block; + this.breaking = false; + return this; + } + + public float drawx(){ + return x*tilesize + block.offset(); + } + + public float drawy(){ + return y*tilesize + block.offset(); + } + + public BuildRequest configure(int config){ + this.config = config; + this.hasConfig = true; + return this; + } + + public @Nullable Tile tile(){ + return world.tile(x, y); + } + + @Override + public String toString(){ + return "BuildRequest{" + + "x=" + x + + ", y=" + y + + ", rotation=" + rotation + + ", recipe=" + block + + ", breaking=" + breaking + + ", progress=" + progress + + ", initialized=" + initialized + + '}'; + } +} diff --git a/core/src/mindustry/entities/units/StateMachine.java b/core/src/mindustry/entities/units/StateMachine.java index 18255cec1b..9181df106e 100644 --- a/core/src/mindustry/entities/units/StateMachine.java +++ b/core/src/mindustry/entities/units/StateMachine.java @@ -21,4 +21,15 @@ public class StateMachine{ public boolean is(UnitState state){ return this.state == state; } + + public interface UnitState{ + default void entered(){ + } + + default void exited(){ + } + + default void update(){ + } + } } diff --git a/core/src/mindustry/entities/units/StatusEntry.java b/core/src/mindustry/entities/units/StatusEntry.java new file mode 100644 index 0000000000..1c1f07f9b7 --- /dev/null +++ b/core/src/mindustry/entities/units/StatusEntry.java @@ -0,0 +1,16 @@ +package mindustry.entities.units; + +import mindustry.type.*; + +public class StatusEntry{ + public static final StatusEntry tmp = new StatusEntry(); + + public StatusEffect effect; + public float time; + + public StatusEntry set(StatusEffect effect, float time){ + this.effect = effect; + this.time = time; + return this; + } +} diff --git a/core/src/mindustry/entities/units/UnitController.java b/core/src/mindustry/entities/units/UnitController.java new file mode 100644 index 0000000000..4f691066b6 --- /dev/null +++ b/core/src/mindustry/entities/units/UnitController.java @@ -0,0 +1,13 @@ +package mindustry.entities.units; + +import mindustry.gen.*; + +//TODO rename +public interface UnitController{ + void unit(Unitc unit); + Unitc unit(); + + default void command(UnitCommand command){ + + } +} diff --git a/core/src/mindustry/entities/units/UnitDrops.java b/core/src/mindustry/entities/units/UnitDrops.java deleted file mode 100644 index f57ff0a75d..0000000000 --- a/core/src/mindustry/entities/units/UnitDrops.java +++ /dev/null @@ -1,48 +0,0 @@ -package mindustry.entities.units; - -import arc.math.Mathf; -import mindustry.Vars; -import mindustry.content.Items; -import mindustry.entities.type.BaseUnit; -import mindustry.entities.type.TileEntity; -import mindustry.gen.Call; -import mindustry.type.Item; -import static mindustry.Vars.*; - -public class UnitDrops{ - private static Item[] dropTable; - - public static void dropItems(BaseUnit unit){ - //items only dropped in waves for enemy team - if(unit.getTeam() != state.rules.waveTeam || !Vars.state.rules.unitDrops){ - return; - } - - TileEntity core = unit.getClosestEnemyCore(); - - if(core == null || core.dst(unit) > Vars.mineTransferRange){ - return; - } - - if(dropTable == null){ - dropTable = new Item[]{Items.titanium, Items.silicon, Items.lead, Items.copper}; - } - - for(int i = 0; i < 3; i++){ - for(Item item : dropTable){ - //only drop unlocked items - if(!Vars.headless && !Vars.data.isUnlocked(item)){ - continue; - } - - if(Mathf.chance(0.03)){ - int amount = Mathf.random(20, 40); - amount = core.tile.block().acceptStack(item, amount, core.tile, null); - if(amount > 0){ - Call.transferItemTo(item, amount, unit.x + Mathf.range(2f), unit.y + Mathf.range(2f), core.tile); - } - } - } - } - } -} diff --git a/core/src/mindustry/entities/units/UnitState.java b/core/src/mindustry/entities/units/UnitState.java deleted file mode 100644 index d64dd49446..0000000000 --- a/core/src/mindustry/entities/units/UnitState.java +++ /dev/null @@ -1,12 +0,0 @@ -package mindustry.entities.units; - -public interface UnitState{ - default void entered(){ - } - - default void exited(){ - } - - default void update(){ - } -} diff --git a/core/src/mindustry/entities/units/WeaponMount.java b/core/src/mindustry/entities/units/WeaponMount.java new file mode 100644 index 0000000000..35858de595 --- /dev/null +++ b/core/src/mindustry/entities/units/WeaponMount.java @@ -0,0 +1,24 @@ +package mindustry.entities.units; + +import mindustry.type.*; + +public class WeaponMount{ + /** weapon associated with this mount */ + public final Weapon weapon; + /** reload in frames; 0 means ready to fire */ + public float reload; + /** rotation relative to the unit this mount is on */ + public float rotation; + /** aiming position in world coordinates */ + public float aimX, aimY; + /** side that's being shot - only valid for mirrors */ + public boolean side; + /** whether to shoot right now */ + public boolean shoot = false; + /** whether to rotate to face the target right now */ + public boolean rotate = false; + + public WeaponMount(Weapon weapon){ + this.weapon = weapon; + } +} diff --git a/core/src/mindustry/game/Difficulty.java b/core/src/mindustry/game/Difficulty.java deleted file mode 100644 index 7c2e20e15f..0000000000 --- a/core/src/mindustry/game/Difficulty.java +++ /dev/null @@ -1,28 +0,0 @@ -package mindustry.game; - -import arc.Core; - -/** Presets for time between waves. Currently unused.*/ -public enum Difficulty{ - easy(1.4f), - normal(1f), - hard(0.5f), - insane(0.25f); - - /** Multiplier of the time between waves. */ - public final float waveTime; - - private String value; - - Difficulty(float waveTime){ - this.waveTime = waveTime; - } - - @Override - public String toString(){ - if(value == null){ - value = Core.bundle.get("setting.difficulty." + name()); - } - return value; - } -} diff --git a/core/src/mindustry/game/EventType.java b/core/src/mindustry/game/EventType.java index 365e8f2b7c..148eb57276 100644 --- a/core/src/mindustry/game/EventType.java +++ b/core/src/mindustry/game/EventType.java @@ -1,13 +1,13 @@ package mindustry.game; import arc.util.ArcAnnotate.*; -import mindustry.core.GameState.State; -import mindustry.ctype.UnlockableContent; -import mindustry.entities.traits.BuilderTrait; -import mindustry.entities.type.*; +import mindustry.core.GameState.*; +import mindustry.ctype.*; +import mindustry.gen.*; import mindustry.entities.units.*; +import mindustry.gen.*; import mindustry.type.*; -import mindustry.world.Tile; +import mindustry.world.*; public class EventType{ @@ -62,10 +62,10 @@ public class EventType{ } public static class PlayerChatEvent{ - public final Player player; + public final Playerc player; public final String message; - public PlayerChatEvent(Player player, String message){ + public PlayerChatEvent(Playerc player, String message){ this.player = player; this.message = message; } @@ -144,11 +144,11 @@ public class EventType{ /** Called when the player withdraws items from a block. */ public static class WithdrawEvent{ public final Tile tile; - public final Player player; + public final Playerc player; public final Item item; public final int amount; - public WithdrawEvent(Tile tile, Player player, Item item, int amount){ + public WithdrawEvent(Tile tile, Playerc player, Item item, int amount){ this.tile = tile; this.player = player; this.item = item; @@ -159,11 +159,11 @@ public class EventType{ /** Called when a player deposits items to a block.*/ public static class DepositEvent{ public final Tile tile; - public final Player player; + public final Playerc player; public final Item item; public final int amount; - public DepositEvent(Tile tile, Player player, Item item, int amount){ + public DepositEvent(Tile tile, Playerc player, Item item, int amount){ this.tile = tile; this.player = player; this.item = item; @@ -174,9 +174,9 @@ public class EventType{ /** Called when the player taps a block. */ public static class TapEvent{ public final Tile tile; - public final Player player; + public final Playerc player; - public TapEvent(Tile tile, Player player){ + public TapEvent(Tile tile, Playerc player){ this.tile = tile; this.player = player; } @@ -185,10 +185,10 @@ public class EventType{ /** Called when the player sets a specific block. */ public static class TapConfigEvent{ public final Tile tile; - public final Player player; + public final Playerc player; public final int value; - public TapConfigEvent(Tile tile, Player player, int value){ + public TapConfigEvent(Tile tile, Playerc player, int value){ this.tile = tile; this.player = player; this.value = value; @@ -262,10 +262,10 @@ public class EventType{ public final Tile tile; public final Team team; public final @Nullable - Player player; + Playerc player; public final boolean breaking; - public BlockBuildEndEvent(Tile tile, @Nullable Player player, Team team, boolean breaking){ + public BlockBuildEndEvent(Tile tile, @Nullable Playerc player, Team team, boolean breaking){ this.tile = tile; this.team = team; this.player = player; @@ -280,10 +280,10 @@ public class EventType{ public static class BuildSelectEvent{ public final Tile tile; public final Team team; - public final BuilderTrait builder; + public final Builderc builder; public final boolean breaking; - public BuildSelectEvent(Tile tile, Team team, BuilderTrait builder, boolean breaking){ + public BuildSelectEvent(Tile tile, Team team, Builderc builder, boolean breaking){ this.tile = tile; this.team = team; this.builder = builder; @@ -302,17 +302,17 @@ public class EventType{ } public static class UnitDestroyEvent{ - public final Unit unit; + public final Unitc unit; - public UnitDestroyEvent(Unit unit){ + public UnitDestroyEvent(Unitc unit){ this.unit = unit; } } public static class UnitCreateEvent{ - public final BaseUnit unit; + public final Unitc unit; - public UnitCreateEvent(BaseUnit unit){ + public UnitCreateEvent(Unitc unit){ this.unit = unit; } } @@ -321,11 +321,12 @@ public class EventType{ } + //TODO rename public static class MechChangeEvent{ - public final Player player; - public final Mech mech; + public final Playerc player; + public final UnitDef mech; - public MechChangeEvent(Player player, Mech mech){ + public MechChangeEvent(Playerc player, UnitDef mech){ this.player = player; this.mech = mech; } @@ -333,42 +334,42 @@ public class EventType{ /** Called after connecting; when a player recieves world data and is ready to play.*/ public static class PlayerJoin{ - public final Player player; + public final Playerc player; - public PlayerJoin(Player player){ + public PlayerJoin(Playerc 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 final Playerc player; - public PlayerConnect(Player player){ + public PlayerConnect(Playerc player){ this.player = player; } } public static class PlayerLeave{ - public final Player player; + public final Playerc player; - public PlayerLeave(Player player){ + public PlayerLeave(Playerc player){ this.player = player; } } public static class PlayerBanEvent{ - public final Player player; + public final Playerc player; - public PlayerBanEvent(Player player){ + public PlayerBanEvent(Playerc player){ this.player = player; } } public static class PlayerUnbanEvent{ - public final Player player; + public final Playerc player; - public PlayerUnbanEvent(Player player){ + public PlayerUnbanEvent(Playerc player){ this.player = player; } } diff --git a/core/src/mindustry/game/MusicControl.java b/core/src/mindustry/game/MusicControl.java index 05624dab15..dc1eda2591 100644 --- a/core/src/mindustry/game/MusicControl.java +++ b/core/src/mindustry/game/MusicControl.java @@ -83,7 +83,7 @@ public class MusicControl{ /** Whether to play dark music.*/ private boolean isDark(){ - if(state.teams.get(player.getTeam()).hasCore() && state.teams.get(player.getTeam()).core().healthf() < 0.85f){ + if(state.teams.get(player.team()).hasCore() && state.teams.get(player.team()).core().healthf() < 0.85f){ //core damaged -> dark return true; } diff --git a/core/src/mindustry/game/Saves.java b/core/src/mindustry/game/Saves.java index cd3389d1f0..09f09f122a 100644 --- a/core/src/mindustry/game/Saves.java +++ b/core/src/mindustry/game/Saves.java @@ -311,7 +311,7 @@ public class Saves{ public void delete(){ file.delete(); - saves.removeValue(this, true); + saves.remove(this, true); if(this == current){ current = null; } diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java index 7a96ed672b..2f03916d1c 100644 --- a/core/src/mindustry/game/Schematics.java +++ b/core/src/mindustry/game/Schematics.java @@ -14,7 +14,7 @@ import arc.util.serialization.*; import mindustry.*; import mindustry.content.*; import mindustry.ctype.ContentType; -import mindustry.entities.traits.BuilderTrait.*; +import mindustry.entities.units.*; import mindustry.game.EventType.*; import mindustry.game.Schematic.*; import mindustry.input.*; @@ -315,7 +315,7 @@ public class Schematics implements Loadable{ for(int cy = y; cy <= y2; cy++){ Tile linked = world.ltile(cx, cy); - if(linked != null && linked.entity != null && linked.entity.block.isVisible() && !(linked.block() instanceof BuildBlock)){ + if(linked != null && linked.entity != null && linked.entity.block().isVisible() && !(linked.block() instanceof BuildBlock)){ int top = linked.block().size/2; int bot = linked.block().size % 2 == 1 ? -linked.block().size/2 : -(linked.block().size - 1)/2; minx = Math.min(linked.x + bot, minx); @@ -344,7 +344,7 @@ public class Schematics implements Loadable{ Tile tile = world.ltile(cx, cy); if(tile != null && tile.entity != null && !counted.contains(tile.pos()) && !(tile.block() instanceof BuildBlock) - && (tile.entity.block.isVisible() || (tile.entity.block instanceof CoreBlock && Core.settings.getBool("coreselect")))){ + && (tile.entity.block().isVisible() || (tile.entity.block() instanceof CoreBlock && Core.settings.getBool("coreselect")))){ int config = tile.entity.config(); if(tile.block().posConfig){ config = Pos.get(Pos.x(config) + offsetX, Pos.y(config) + offsetY); diff --git a/core/src/mindustry/game/SpawnGroup.java b/core/src/mindustry/game/SpawnGroup.java index c0a08d2661..5a9dba9a24 100644 --- a/core/src/mindustry/game/SpawnGroup.java +++ b/core/src/mindustry/game/SpawnGroup.java @@ -5,7 +5,7 @@ import arc.util.serialization.Json.Serializable; import arc.util.serialization.JsonValue; import mindustry.content.*; import mindustry.ctype.ContentType; -import mindustry.entities.type.BaseUnit; +import mindustry.gen.*; import mindustry.type.*; import static mindustry.Vars.content; @@ -19,7 +19,7 @@ public class SpawnGroup implements Serializable{ public static final int never = Integer.MAX_VALUE; /** The unit type spawned */ - public UnitType type; + public UnitDef type; /** When this spawn should end */ public int end = never; /** When this spawn should start */ @@ -37,7 +37,7 @@ public class SpawnGroup implements Serializable{ /** Items this unit spawns with. Null to disable. */ public ItemStack items; - public SpawnGroup(UnitType type){ + public SpawnGroup(UnitDef type){ this.type = type; } @@ -57,11 +57,11 @@ public class SpawnGroup implements Serializable{ * Creates a unit, and assigns correct values based on this group's data. * This method does not add() the unit. */ - public BaseUnit createUnit(Team team){ - BaseUnit unit = type.create(team); + public Unitc createUnit(Team team){ + Unitc unit = type.create(team); if(effect != null){ - unit.applyEffect(effect, 999999f); + unit.apply(effect, 999999f); } if(items != null){ diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java index e4fa1f1ef3..d07b1060ca 100644 --- a/core/src/mindustry/game/Teams.java +++ b/core/src/mindustry/game/Teams.java @@ -5,7 +5,7 @@ import arc.math.geom.*; import arc.struct.*; import arc.util.ArcAnnotate.*; import arc.util.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.world.blocks.storage.CoreBlock.*; import static mindustry.Vars.*; @@ -17,6 +17,10 @@ public class Teams{ /** Active teams. */ private Array active = new Array<>(); + public Teams(){ + active.add(get(Team.crux)); + } + public @Nullable CoreEntity closestEnemyCore(float x, float y, Team team){ for(TeamData data : active){ if(areEnemies(team, data.team)){ @@ -50,10 +54,10 @@ public class Teams{ return false; } - public void eachEnemyCore(Team team, Cons ret){ + public void eachEnemyCore(Team team, Cons ret){ for(TeamData data : active){ if(areEnemies(team, data.team)){ - for(TileEntity tile : data.cores){ + for(Tilec tile : data.cores){ ret.get(tile); } } @@ -85,7 +89,6 @@ public class Teams{ /** Returns whether {@param other} is an enemy of {@param #team}. */ public boolean areEnemies(Team team, Team other){ - //todo what about derelict? return team != other; } @@ -99,7 +102,7 @@ public class Teams{ } public void registerCore(CoreEntity core){ - TeamData data = get(core.getTeam()); + TeamData data = get(core.team()); //add core if not present if(!data.cores.contains(core)){ data.cores.add(core); @@ -114,7 +117,7 @@ public class Teams{ } public void unregisterCore(CoreEntity entity){ - TeamData data = get(entity.getTeam()); + TeamData data = get(entity.team()); //remove core data.cores.remove(entity); //unregister in active list @@ -125,7 +128,7 @@ public class Teams{ } private void updateEnemies(){ - if(!active.contains(get(state.rules.waveTeam))){ + if(state.rules.waves && !active.contains(get(state.rules.waveTeam))){ active.add(get(state.rules.waveTeam)); } diff --git a/core/src/mindustry/game/Tutorial.java b/core/src/mindustry/game/Tutorial.java index 4b344bc945..1480751020 100644 --- a/core/src/mindustry/game/Tutorial.java +++ b/core/src/mindustry/game/Tutorial.java @@ -10,7 +10,7 @@ import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.*; import mindustry.content.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.game.EventType.*; import mindustry.graphics.*; import mindustry.type.*; @@ -162,7 +162,7 @@ public class Tutorial{ }, withdraw(() -> event("withdraw")){ void begin(){ - state.teams.playerCores().first().items.add(Items.copper, 10); + state.teams.playerCores().first().items().add(Items.copper, 10); } }, deposit(() -> event("deposit")), @@ -240,18 +240,18 @@ public class Tutorial{ //utility static void placeBlocks(){ - TileEntity core = state.teams.playerCores().first(); + Tilec core = state.teams.playerCores().first(); for(int i = 0; i < blocksToBreak; i++){ - world.ltile(core.tile.x + blockOffset, core.tile.y + i).remove(); - world.tile(core.tile.x + blockOffset, core.tile.y + i).setBlock(Blocks.scrapWall, state.rules.defaultTeam); + world.ltile(core.tile().x + blockOffset, core.tile().y + i).remove(); + world.tile(core.tile().x + blockOffset, core.tile().y + i).setBlock(Blocks.scrapWall, state.rules.defaultTeam); } } static boolean blocksBroken(){ - TileEntity core = state.teams.playerCores().first(); + Tilec core = state.teams.playerCores().first(); for(int i = 0; i < blocksToBreak; i++){ - if(world.tile(core.tile.x + blockOffset, core.tile.y + i).block() == Blocks.scrapWall){ + if(world.tile(core.tile().x + blockOffset, core.tile().y + i).block() == Blocks.scrapWall){ return false; } } @@ -271,7 +271,7 @@ public class Tutorial{ } static int item(Item item){ - return state.rules.defaultTeam.data().noCores() ? 0 : state.rules.defaultTeam.core().items.get(item); + return state.rules.defaultTeam.data().noCores() ? 0 : state.rules.defaultTeam.core().items().get(item); } static boolean toggled(String name){ diff --git a/core/src/mindustry/graphics/BlockRenderer.java b/core/src/mindustry/graphics/BlockRenderer.java index 41274e0349..01f3e78082 100644 --- a/core/src/mindustry/graphics/BlockRenderer.java +++ b/core/src/mindustry/graphics/BlockRenderer.java @@ -134,7 +134,7 @@ public class BlockRenderer implements Disposable{ } if(brokenFade > 0.001f){ - for(BrokenBlock block : state.teams.get(player.getTeam()).brokenBlocks){ + for(BrokenBlock block : state.teams.get(player.team()).brokenBlocks){ Block b = content.block(block.block); if(!camera.bounds(Tmp.r1).grow(tilesize * 2f).overlaps(Tmp.r2.setSize(b.size * tilesize).setCenter(block.x * tilesize + b.offset(), block.y * tilesize + b.offset()))) continue; @@ -233,7 +233,7 @@ public class BlockRenderer implements Disposable{ addRequest(tile, block.layer2); } - if(tile.entity != null && tile.entity.power != null && tile.entity.power.links.size > 0){ + if(tile.entity != null && tile.entity.power() != null && tile.entity.power().links.size > 0){ for(Tile other : block.getPowerConnections(tile, outArray)){ if(other.block().layer == Layer.power){ addRequest(other, Layer.power); @@ -275,7 +275,7 @@ public class BlockRenderer implements Disposable{ if(request.tile.entity != null && request.tile.entity.damaged()){ block.drawCracks(request.tile); } - if(block.synthetic() && request.tile.getTeam() != player.getTeam()){ + if(block.synthetic() && request.tile.team() != player.team()){ block.drawTeam(request.tile); } diff --git a/core/src/mindustry/graphics/Bloom.java b/core/src/mindustry/graphics/Bloom.java deleted file mode 100644 index 1b7b8f89f9..0000000000 --- a/core/src/mindustry/graphics/Bloom.java +++ /dev/null @@ -1,382 +0,0 @@ -package mindustry.graphics; - -import arc.Core; -import arc.graphics.*; -import arc.graphics.Pixmap.Format; -import arc.graphics.VertexAttributes.Usage; -import arc.graphics.gl.FrameBuffer; -import arc.graphics.gl.Shader; - -/** - * Bloomlib allow easy but efficient way to add bloom effect as post process - * effect - * - * @author kalle_h - */ -public class Bloom{ - /** - * To use implement bloom more like a glow. Texture alpha channel can be - * used as mask which part are glowing and which are not. see more info at: - * http://www.gamasutra.com/view/feature/2107/realtime_glow.php - *

- * NOTE: need to be set before bloom instance is created. After that this - * does nothing. - */ - public static boolean useAlphaChannelAsMask = false; - - /** how many blur pass */ - public int blurPasses = 1; - - private Shader tresholdShader; - private Shader bloomShader; - - private Mesh fullScreenQuad; - - private Texture pingPongTex1; - private Texture pingPongTex2; - private Texture original; - - private FrameBuffer frameBuffer; - private FrameBuffer pingPongBuffer1; - private FrameBuffer pingPongBuffer2; - - private Shader blurShader; - - private float bloomIntensity; - private float originalIntensity; - private float threshold; - private int w; - private int h; - private boolean blending = false; - private boolean capturing = false; - private float r = 0f; - private float g = 0f; - private float b = 0f; - private float a = 1f; - private boolean disposeFBO = true; - - /** - * IMPORTANT NOTE CALL THIS WHEN RESUMING - */ - public void resume(){ - bloomShader.begin(); - bloomShader.setUniformi("u_texture0", 0); - bloomShader.setUniformi("u_texture1", 1); - bloomShader.end(); - - setSize(w, h); - setThreshold(threshold); - setBloomIntesity(bloomIntensity); - setOriginalIntesity(originalIntensity); - - original = frameBuffer.getTexture(); - pingPongTex1 = pingPongBuffer1.getTexture(); - pingPongTex2 = pingPongBuffer2.getTexture(); - } - - /** - * Initialize bloom class that capsulate original scene capturate, - * tresholding, gaussian blurring and blending. Default values: depth = true - * blending = false 32bits = true - */ - public Bloom(){ - initialize(Core.graphics.getWidth() / 4, Core.graphics.getHeight() / 4, null, false, false, true); - } - - public Bloom(boolean useBlending){ - initialize(Core.graphics.getWidth() / 4, Core.graphics.getHeight() / 4, null, false, useBlending, true); - } - - /** - * Initialize bloom class that capsulate original scene capturate, - * tresholding, gaussian blurring and blending. - * - * @param FBO_W - * @param FBO_H how big fbo is used for bloom texture, smaller = more blur and - * lot faster but aliasing can be problem - * @param hasDepth do rendering need depth buffer - * @param useBlending does fbo need alpha channel and is blending enabled when final - * image is rendered. This allow to combine background graphics - * and only do blooming on certain objects param use32bitFBO does - * fbo use higher precision than 16bits. - */ - public Bloom(int FBO_W, int FBO_H, boolean hasDepth, boolean useBlending, boolean use32bitFBO){ - initialize(FBO_W, FBO_H, null, hasDepth, useBlending, use32bitFBO); - - } - - /** - * EXPERT FUNCTIONALITY. no error checking. Use this only if you know what - * you are doing. Remember that bloom.capture() clear the screen so use - * continue instead if that is a problem. - *

- * Initialize bloom class that capsulate original scene capturate, - * tresholding, gaussian blurring and blending. - *

- * * @param sceneIsCapturedHere diposing is user responsibility. - * - * @param FBO_W - * @param FBO_H how big fbo is used for bloom texture, smaller = more blur and - * lot faster but aliasing can be problem - * @param useBlending does fbo need alpha channel and is blending enabled when final - * image is rendered. This allow to combine background graphics - * and only do blooming on certain objects param use32bitFBO does - * fbo use higher precision than 16bits. - */ - public Bloom(int FBO_W, int FBO_H, FrameBuffer sceneIsCapturedHere, boolean useBlending, boolean use32bitFBO){ - initialize(FBO_W, FBO_H, sceneIsCapturedHere, false, useBlending, use32bitFBO); - disposeFBO = false; - } - - private void initialize(int FBO_W, int FBO_H, FrameBuffer fbo, boolean hasDepth, boolean useBlending, boolean use32bitFBO){ - blending = useBlending; - Format format; - - if(use32bitFBO){ - if(useBlending){ - format = Format.RGBA8888; - }else{ - format = Format.RGB888; - } - - }else{ - if(useBlending){ - format = Format.RGBA4444; - }else{ - format = Format.RGB565; - } - } - if(fbo == null){ - frameBuffer = new FrameBuffer(format, Core.graphics.getWidth(), Core.graphics.getHeight(), hasDepth); - }else{ - frameBuffer = fbo; - } - - pingPongBuffer1 = new FrameBuffer(format, FBO_W, FBO_H, false); - - pingPongBuffer2 = new FrameBuffer(format, FBO_W, FBO_H, false); - - original = frameBuffer.getTexture(); - pingPongTex1 = pingPongBuffer1.getTexture(); - pingPongTex2 = pingPongBuffer2.getTexture(); - - fullScreenQuad = createFullScreenQuad(); - final String alpha = useBlending ? "alpha_" : ""; - - bloomShader = createShader("screenspace", alpha + "bloom"); - - if(useAlphaChannelAsMask){ - tresholdShader = createShader("screenspace", "maskedtreshold"); - }else{ - tresholdShader = createShader("screenspace", alpha + "threshold"); - } - - blurShader = createShader("blurspace", alpha + "gaussian"); - - setSize(FBO_W, FBO_H); - setBloomIntesity(2.5f); - setOriginalIntesity(0.8f); - setThreshold(0.5f); - - bloomShader.begin(); - bloomShader.setUniformi("u_texture0", 0); - bloomShader.setUniformi("u_texture1", 1); - bloomShader.end(); - } - - /** - * Set clearing color for capturing buffer - * - * @param r - * @param g - * @param b - * @param a - */ - public void setClearColor(float r, float g, float b, float a){ - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } - - /** - * Call this before rendering scene. - */ - public void capture(){ - if(!capturing){ - capturing = true; - frameBuffer.begin(); - Gl.clearColor(r, g, b, a); - Gl.clear(Gl.colorBufferBit); - - } - } - - /** - * Pause capturing to fbo. - */ - public void capturePause(){ - if(capturing){ - capturing = false; - frameBuffer.end(); - } - } - - /** Start capturing again after pause, no clearing is done to framebuffer */ - public void captureContinue(){ - if(!capturing){ - capturing = true; - frameBuffer.begin(); - } - } - - /** - * Call this after scene. Renders the bloomed scene. - */ - public void render(){ - if(capturing){ - capturing = false; - frameBuffer.end(); - } - - Gl.disable(Gl.blend); - Gl.disable(Gl.depthTest); - Gl.depthMask(false); - - gaussianBlur(); - - if(blending){ - Gl.enable(Gl.blend); - Gl.blendFunc(Gl.srcAlpha, Gl.oneMinusSrcAlpha); - } - - pingPongTex1.bind(1); - original.bind(0); - - bloomShader.begin(); - fullScreenQuad.render(bloomShader, Gl.triangleFan); - bloomShader.end(); - - } - - private void gaussianBlur(){ - - // cut bright areas of the picture and blit to smaller fbo - - original.bind(0); - pingPongBuffer1.begin(); - tresholdShader.begin(); - fullScreenQuad.render(tresholdShader, Gl.triangleFan, 0, 4); - tresholdShader.end(); - pingPongBuffer1.end(); - - for(int i = 0; i < blurPasses; i++){ - - pingPongTex1.bind(0); - - // horizontal - pingPongBuffer2.begin(); - blurShader.begin(); - blurShader.setUniformf("dir", 1f, 0f); - fullScreenQuad.render(blurShader, Gl.triangleFan, 0, 4); - blurShader.end(); - pingPongBuffer2.end(); - - pingPongTex2.bind(0); - // vertical - pingPongBuffer1.begin(); - blurShader.begin(); - blurShader.setUniformf("dir", 0f, 1f); - fullScreenQuad.render(blurShader, Gl.triangleFan, 0, 4); - blurShader.end(); - pingPongBuffer1.end(); - } - } - - /** - * set intensity for bloom. higher mean more brightening for spots that are - * over threshold - * - * @param intensity multiplier for blurred texture in combining phase. must be - * positive. - */ - public void setBloomIntesity(float intensity){ - bloomIntensity = intensity; - bloomShader.begin(); - bloomShader.setUniformf("BloomIntensity", intensity); - bloomShader.end(); - } - - /** - * set intensity for original scene. under 1 mean darkening and over 1 means - * lightening - * - * @param intensity multiplier for captured texture in combining phase. must be - * positive. - */ - public void setOriginalIntesity(float intensity){ - originalIntensity = intensity; - bloomShader.begin(); - bloomShader.setUniformf("OriginalIntensity", intensity); - bloomShader.end(); - } - - /** - * Treshold for bright parts. everything under threshold is clamped to 0 - * - * @param threshold must be in range 0..1 - */ - public void setThreshold(float threshold){ - this.threshold = threshold; - tresholdShader.begin(); - tresholdShader.setUniformf("threshold", threshold, 1f / (1 - threshold)); - tresholdShader.end(); - } - - private void setSize(int FBO_W, int FBO_H){ - w = FBO_W; - h = FBO_H; - blurShader.begin(); - blurShader.setUniformf("size", FBO_W, FBO_H); - blurShader.end(); - } - - /** - * Call this when application is exiting. - */ - public void dispose(){ - try{ - if(disposeFBO) frameBuffer.dispose(); - - fullScreenQuad.dispose(); - - pingPongBuffer1.dispose(); - pingPongBuffer2.dispose(); - - blurShader.dispose(); - bloomShader.dispose(); - tresholdShader.dispose(); - }catch(Throwable ignored){ - - } - } - - private static Mesh createFullScreenQuad(){ - float[] verts = {-1, -1, 0, 0, 1, -1, 1, 0, 1, 1, 1, 1, -1, 1, 0, 1}; - Mesh tmpMesh = new Mesh(true, 4, 0, - new VertexAttribute(Usage.position, 2, "a_position"), - new VertexAttribute(Usage.textureCoordinates, 2, "a_texCoord0") - ); - - tmpMesh.setVertices(verts); - return tmpMesh; - - } - - private static Shader createShader(String vertexName, String fragmentName){ - String vertexShader = Core.files.internal("bloomshaders/" + vertexName + ".vertex.glsl").readString(); - String fragmentShader = Core.files.internal("bloomshaders/" + fragmentName + ".fragment.glsl").readString(); - return new Shader(vertexShader, fragmentShader); - } - -} diff --git a/core/src/mindustry/graphics/CacheLayer.java b/core/src/mindustry/graphics/CacheLayer.java index 4f886d4001..08ed1b8c2d 100644 --- a/core/src/mindustry/graphics/CacheLayer.java +++ b/core/src/mindustry/graphics/CacheLayer.java @@ -57,7 +57,7 @@ public enum CacheLayer{ if(!Core.settings.getBool("animatedwater")) return; renderer.blocks.floor.endc(); - renderer.shieldBuffer.begin(); + renderer.effectBuffer.begin(); Core.graphics.clear(Color.clear); renderer.blocks.floor.beginc(); } @@ -66,10 +66,10 @@ public enum CacheLayer{ if(!Core.settings.getBool("animatedwater")) return; renderer.blocks.floor.endc(); - renderer.shieldBuffer.end(); + renderer.effectBuffer.end(); Draw.shader(shader); - Draw.rect(Draw.wrap(renderer.shieldBuffer.getTexture()), camera.position.x, camera.position.y, camera.width, -camera.height); + Draw.rect(Draw.wrap(renderer.effectBuffer.getTexture()), camera.position.x, camera.position.y, camera.width, -camera.height); Draw.shader(); renderer.blocks.floor.beginc(); diff --git a/core/src/mindustry/graphics/Drawf.java b/core/src/mindustry/graphics/Drawf.java index 2fd9b48087..f3a31369da 100644 --- a/core/src/mindustry/graphics/Drawf.java +++ b/core/src/mindustry/graphics/Drawf.java @@ -43,6 +43,10 @@ public class Drawf{ } public static void arrow(float x, float y, float x2, float y2, float length, float radius){ + arrow(x, y, x2, y2, length, radius, Pal.accent); + } + + public static void arrow(float x, float y, float x2, float y2, float length, float radius, Color color){ float angle = Angles.angle(x, y, x2, y2); float space = 2f; Tmp.v1.set(x2, y2).sub(x, y).limit(length); @@ -50,7 +54,7 @@ public class Drawf{ Draw.color(Pal.gray); Fill.poly(vx, vy, 3, radius + space, angle); - Draw.color(Pal.accent); + Draw.color(color); Fill.poly(vx, vy, 3, radius, angle); Draw.color(); } diff --git a/core/src/mindustry/graphics/LightRenderer.java b/core/src/mindustry/graphics/LightRenderer.java index 0c0f94e02c..510a375274 100644 --- a/core/src/mindustry/graphics/LightRenderer.java +++ b/core/src/mindustry/graphics/LightRenderer.java @@ -24,6 +24,10 @@ public class LightRenderer{ lights.add(run); } + public void add(Position pos, float radius, Color color, float opacity){ + add(pos.getX(), pos.getY(), radius, color, opacity); + } + public void add(float x, float y, float radius, Color color, float opacity){ if(!enabled()) return; diff --git a/core/src/mindustry/graphics/MenuRenderer.java b/core/src/mindustry/graphics/MenuRenderer.java index 3576c66543..df5d591102 100644 --- a/core/src/mindustry/graphics/MenuRenderer.java +++ b/core/src/mindustry/graphics/MenuRenderer.java @@ -1,24 +1,20 @@ package mindustry.graphics; -import arc.Core; -import arc.struct.Array; -import arc.func.Floatc2; -import arc.graphics.Camera; -import arc.graphics.Color; +import arc.*; +import arc.func.*; +import arc.graphics.*; import arc.graphics.g2d.*; -import arc.graphics.gl.FrameBuffer; +import arc.graphics.gl.*; import arc.math.*; -import arc.scene.ui.layout.Scl; +import arc.scene.ui.layout.*; +import arc.struct.*; import arc.util.*; -import arc.util.noise.RidgedPerlin; -import arc.util.noise.Simplex; -import mindustry.content.Blocks; -import mindustry.content.UnitTypes; -import mindustry.type.UnitType; -import mindustry.ui.Cicon; +import arc.util.noise.*; +import mindustry.content.*; +import mindustry.type.*; +import mindustry.ui.*; import mindustry.world.*; -import mindustry.world.blocks.Floor; -import mindustry.world.blocks.OreBlock; +import mindustry.world.blocks.*; import static mindustry.Vars.*; @@ -34,7 +30,7 @@ public class MenuRenderer implements Disposable{ private float time = 0f; private float flyerRot = 45f; private int flyers = Mathf.chance(0.2) ? Mathf.random(35) : Mathf.random(15); - private UnitType flyerType = Structs.select(UnitTypes.wraith, UnitTypes.wraith, UnitTypes.ghoul, UnitTypes.phantom, UnitTypes.phantom, UnitTypes.revenant); + private UnitDef flyerType = Structs.select(UnitTypes.wraith, UnitTypes.wraith, UnitTypes.ghoul, UnitTypes.phantom, UnitTypes.phantom, UnitTypes.revenant); public MenuRenderer(){ Time.mark(); @@ -251,6 +247,8 @@ public class MenuRenderer implements Disposable{ } private void drawFlyers(){ + //TODO fix + if(true) return; Draw.color(0f, 0f, 0f, 0.4f); TextureRegion icon = flyerType.icon(Cicon.full); diff --git a/core/src/mindustry/graphics/MinimapRenderer.java b/core/src/mindustry/graphics/MinimapRenderer.java index c34bb246ec..db4059cb4a 100644 --- a/core/src/mindustry/graphics/MinimapRenderer.java +++ b/core/src/mindustry/graphics/MinimapRenderer.java @@ -12,7 +12,7 @@ import arc.util.*; import arc.util.ArcAnnotate.*; import arc.util.pooling.*; import mindustry.entities.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.game.EventType.*; import mindustry.io.*; import mindustry.ui.*; @@ -22,7 +22,7 @@ import static mindustry.Vars.*; public class MinimapRenderer implements Disposable{ private static final float baseSize = 16f; - private final Array units = new Array<>(); + private final Array units = new Array<>(); private Pixmap pixmap; private Texture texture; private TextureRegion region; @@ -76,7 +76,7 @@ public class MinimapRenderer implements Disposable{ updateUnitArray(); }else{ units.clear(); - Units.all(units::add); + Groups.unit.each(units::add); } float sz = baseSize * zoom; @@ -87,21 +87,20 @@ public class MinimapRenderer implements Disposable{ rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize); - for(Unit unit : units){ - if(unit.isDead()) continue; - float rx = !withLabels ? (unit.x - rect.x) / rect.width * w : unit.x / (world.width() * tilesize) * w; - float ry = !withLabels ? (unit.y - rect.y) / rect.width * h : unit.y / (world.height() * tilesize) * h; + for(Unitc unit : units){ + float rx = !withLabels ? (unit.x() - rect.x) / rect.width * w : unit.x() / (world.width() * tilesize) * w; + float ry = !withLabels ? (unit.y() - rect.y) / rect.width * h : unit.y() / (world.height() * tilesize) * h; - Draw.mixcol(unit.getTeam().color, 1f); + Draw.mixcol(unit.team().color, 1f); float scale = Scl.scl(1f) / 2f * scaling * 32f; - Draw.rect(unit.getIconRegion(), x + rx, y + ry, scale, scale, unit.rotation - 90); + Draw.rect(unit.type().region, x + rx, y + ry, scale, scale, unit.rotation() - 90); Draw.reset(); - if(withLabels && unit instanceof Player){ - Player pl = (Player) unit; - if(!pl.isLocal){ + if(withLabels && unit instanceof Playerc){ + Playerc pl = (Playerc) unit; + if(!pl.isLocal()){ // Only display names for other players. - drawLabel(x + rx, y + ry, pl.name, unit.getTeam().color); + drawLabel(x + rx, y + ry, pl.name(), unit.team().color); } } } @@ -162,7 +161,7 @@ public class MinimapRenderer implements Disposable{ if(bc != 0){ return bc; } - return Tmp.c1.set(MapIO.colorFor(tile.floor(), tile.block(), tile.overlay(), tile.getTeam())).mul(tile.block().cacheLayer == CacheLayer.walls ? 1f - tile.rotation() / 4f : 1f).rgba(); + return Tmp.c1.set(MapIO.colorFor(tile.floor(), tile.block(), tile.overlay(), tile.team())).mul(tile.block().cacheLayer == CacheLayer.walls ? 1f - tile.rotation() / 4f : 1f).rgba(); } @Override diff --git a/core/src/mindustry/graphics/OverlayRenderer.java b/core/src/mindustry/graphics/OverlayRenderer.java index 6cb4348c23..f40afc7c2e 100644 --- a/core/src/mindustry/graphics/OverlayRenderer.java +++ b/core/src/mindustry/graphics/OverlayRenderer.java @@ -8,8 +8,7 @@ import arc.math.geom.*; import arc.util.*; import mindustry.*; import mindustry.content.*; -import mindustry.entities.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.input.*; import mindustry.type.*; import mindustry.ui.*; @@ -28,7 +27,7 @@ public class OverlayRenderer{ public void drawBottom(){ InputHandler input = control.input; - if(player.isDead()) return; + if(player.dead()) return; input.drawBottom(); } @@ -36,32 +35,32 @@ public class OverlayRenderer{ public void drawTop(){ if(Core.settings.getBool("indicators")){ - for(Player player : playerGroup.all()){ - if(Vars.player != player && Vars.player.getTeam() == player.getTeam()){ + for(Playerc player : Groups.player){ + if(Vars.player != player && Vars.player.team() == player.team()){ if(!rect.setSize(Core.camera.width * 0.9f, Core.camera.height * 0.9f) - .setCenter(Core.camera.position.x, Core.camera.position.y).contains(player.x, player.y)){ + .setCenter(Core.camera.position.x, Core.camera.position.y).contains(player.x(), player.y())){ - Tmp.v1.set(player.x, player.y).sub(Core.camera.position.x, Core.camera.position.y).setLength(indicatorLength); + Tmp.v1.set(player.x(), player.y()).sub(Core.camera.position.x, Core.camera.position.y).setLength(indicatorLength); - Lines.stroke(2f, player.getTeam().color); + Lines.stroke(2f, player.team().color); Lines.lineAngle(Core.camera.position.x + Tmp.v1.x, Core.camera.position.y + Tmp.v1.y, Tmp.v1.angle(), 4f); Draw.reset(); } } } - Units.all(unit -> { - if(unit != player && unit.getTeam() != player.getTeam() && !rect.setSize(Core.camera.width * 0.9f, Core.camera.height * 0.9f).setCenter(Core.camera.position.x, Core.camera.position.y).contains(unit.x, unit.y)){ - Tmp.v1.set(unit.x, unit.y).sub(Core.camera.position.x, Core.camera.position.y).setLength(indicatorLength); + Groups.unit.each(unit -> { + if(unit != player && unit.team() != player.team() && !rect.setSize(Core.camera.width * 0.9f, Core.camera.height * 0.9f).setCenter(Core.camera.position.x, Core.camera.position.y).contains(unit.x(), unit.y())){ + Tmp.v1.set(unit.x(), unit.y()).sub(Core.camera.position.x, Core.camera.position.y).setLength(indicatorLength); - Lines.stroke(1f, unit.getTeam().color); - Lines.lineAngle(Core.camera.position.x + Tmp.v1.x, Core.camera.position.y + Tmp.v1.y, Tmp.v1.angle(), 3f); - Draw.reset(); - } - }); + Lines.stroke(1f, unit.team().color); + Lines.lineAngle(Core.camera.position.x + Tmp.v1.x, Core.camera.position.y + Tmp.v1.y, Tmp.v1.angle(), 3f); + Draw.reset(); + } + }); if(ui.hudfrag.blockfrag.currentCategory == Category.upgrade){ - for(Tile mechpad : indexer.getAllied(player.getTeam(), BlockFlag.mechPad)){ + for(Tile mechpad : indexer.getAllied(player.team(), BlockFlag.mechPad)){ if(!(mechpad.block() instanceof MechPad)) continue; if(!rect.setSize(Core.camera.width * 0.9f, Core.camera.height * 0.9f) .setCenter(Core.camera.position.x, Core.camera.position.y).contains(mechpad.drawx(), mechpad.drawy())){ @@ -76,7 +75,7 @@ public class OverlayRenderer{ } } - if(player.isDead()) return; //dead players don't draw + if(player.dead()) return; //dead players don't draw InputHandler input = control.input; @@ -94,13 +93,13 @@ public class OverlayRenderer{ Lines.stroke(buildFadeTime * 2f); if(buildFadeTime > 0.005f){ - state.teams.eachEnemyCore(player.getTeam(), core -> { + state.teams.eachEnemyCore(player.team(), core -> { float dst = core.dst(player); if(dst < state.rules.enemyCoreBuildRadius * 2.2f){ Draw.color(Color.darkGray); - Lines.circle(core.x, core.y - 2, state.rules.enemyCoreBuildRadius); - Draw.color(Pal.accent, core.getTeam().color, 0.5f + Mathf.absin(Time.time(), 10f, 0.5f)); - Lines.circle(core.x, core.y, state.rules.enemyCoreBuildRadius); + Lines.circle(core.x(), core.y() - 2, state.rules.enemyCoreBuildRadius); + Draw.color(Pal.accent, core.team().color, 0.5f + Mathf.absin(Time.time(), 10f, 0.5f)); + Lines.circle(core.x(), core.y(), state.rules.enemyCoreBuildRadius); } }); } @@ -109,7 +108,7 @@ public class OverlayRenderer{ 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)){ + if(tile.withinDst(player.x(), player.y(), state.rules.dropZoneRadius + spawnerMargin)){ Draw.alpha(Mathf.clamp(1f - (player.dst(tile) - state.rules.dropZoneRadius) / spawnerMargin)); Lines.dashCircle(tile.worldx(), tile.worldy(), state.rules.dropZoneRadius); } @@ -122,10 +121,10 @@ public class OverlayRenderer{ Vec2 vec = Core.input.mouseWorld(input.getMouseX(), input.getMouseY()); Tile tile = world.ltileWorld(vec.x, vec.y); - if(tile != null && tile.block() != Blocks.air && tile.getTeam() == player.getTeam()){ + if(tile != null && tile.block() != Blocks.air && tile.team() == player.team()){ tile.block().drawSelect(tile); - if(Core.input.keyDown(Binding.rotateplaced) && tile.block().rotate){ + if(Core.input.keyDown(Binding.rotateplaced) && tile.block().rotate && tile.interactable(player.team())){ control.input.drawArrow(tile.block(), tile.x, tile.y, tile.rotation(), true); Draw.color(Pal.accent, 0.3f + Mathf.absin(4f, 0.2f)); Fill.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize/2f); @@ -138,13 +137,13 @@ public class OverlayRenderer{ if(input.isDroppingItem()){ Vec2 v = Core.input.mouseWorld(input.getMouseX(), input.getMouseY()); float size = 8; - Draw.rect(player.item().item.icon(Cicon.medium), v.x, v.y, size, size); + Draw.rect(player.unit().item().icon(Cicon.medium), v.x, v.y, size, size); Draw.color(Pal.accent); Lines.circle(v.x, v.y, 6 + Mathf.absin(Time.time(), 5f, 1f)); Draw.reset(); Tile tile = world.ltileWorld(v.x, v.y); - if(tile != null && tile.interactable(player.getTeam()) && tile.block().acceptStack(player.item().item, player.item().amount, tile, player) > 0){ + if(tile != null && tile.interactable(player.team()) && tile.block().acceptStack(player.unit().item(), player.unit().stack().amount, tile, player.unit()) > 0){ Lines.stroke(3f, Pal.gray); Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize / 2f + 3 + Mathf.absin(Time.time(), 5f, 1f)); Lines.stroke(1f, Pal.place); diff --git a/core/src/mindustry/graphics/Pixelator.java b/core/src/mindustry/graphics/Pixelator.java index f746ca69e3..405a1f43e1 100644 --- a/core/src/mindustry/graphics/Pixelator.java +++ b/core/src/mindustry/graphics/Pixelator.java @@ -1,16 +1,14 @@ package mindustry.graphics; -import arc.Core; -import arc.graphics.Blending; -import arc.graphics.Texture.TextureFilter; -import arc.graphics.g2d.Draw; -import arc.graphics.gl.FrameBuffer; -import arc.util.Disposable; -import mindustry.entities.type.Player; +import arc.*; +import arc.graphics.*; +import arc.graphics.Texture.*; +import arc.graphics.g2d.*; +import arc.graphics.gl.*; +import arc.util.*; +import mindustry.gen.*; -import static arc.Core.camera; -import static arc.Core.graphics; -import static mindustry.Vars.playerGroup; +import static arc.Core.*; import static mindustry.Vars.renderer; public class Pixelator implements Disposable{ @@ -55,7 +53,7 @@ public class Pixelator implements Disposable{ Draw.rect(Draw.wrap(buffer.getTexture()), Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height); Draw.blend(); - playerGroup.draw(p -> !p.isDead(), Player::drawName); + Groups.drawNames(); Core.camera.position.set(px, py); Core.settings.put("animatedwater", hadWater); diff --git a/core/src/mindustry/graphics/ScorchGenerator.java b/core/src/mindustry/graphics/ScorchGenerator.java new file mode 100644 index 0000000000..547b7e5c00 --- /dev/null +++ b/core/src/mindustry/graphics/ScorchGenerator.java @@ -0,0 +1,33 @@ +package mindustry.graphics; + +import arc.graphics.*; +import arc.math.*; +import arc.util.noise.*; + +/** Generates a scorch pixmap based on parameters. Thread safe, unless multiple scorch generators are running in parallel. */ +public class ScorchGenerator{ + private static final Simplex sim = new Simplex(); + + public int size = 80, seed = 0, color = Color.white.rgba(); + public double scale = 18, pow = 2, octaves = 4, pers = 0.4, add = 2, nscl = 4.5f; + + public Pixmap generate(){ + Pixmap pix = new Pixmap(size, size); + sim.setSeed(seed); + + pix.each((x, y) -> { + double dst = Mathf.dst(x, y, size/2, size/2) / (size / 2f); + double scaled = Math.abs(dst - 0.5f) * 5f + add; + scaled -= noise(Angles.angle(x, y, size/2, size/2))*nscl; + boolean present = scaled < 1.5f; + + if(present) pix.draw(x, y, color); + }); + + return pix; + } + + private double noise(float angle){ + return Math.pow(sim.octaveNoise2D(octaves, pers, 1 / scale, Angles.trnsx(angle, size/2f) + size/2f, Angles.trnsy(angle, size/2f) + size/2f), pow); + } +} diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index 0776d9e33e..88d9608321 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -5,6 +5,7 @@ import arc.Graphics.*; import arc.Graphics.Cursor.*; import arc.graphics.g2d.*; import arc.math.*; +import arc.math.geom.*; import arc.scene.*; import arc.scene.event.*; import arc.scene.ui.*; @@ -13,7 +14,8 @@ import arc.util.ArcAnnotate.*; import arc.util.*; import mindustry.*; import mindustry.core.GameState.*; -import mindustry.entities.traits.BuilderTrait.*; +import mindustry.entities.*; +import mindustry.entities.units.*; import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.gen.*; @@ -44,12 +46,12 @@ public class DesktopInput extends InputHandler{ @Override public void buildUI(Group group){ group.fill(t -> { - t.bottom().update(() -> t.getColor().a = Mathf.lerpDelta(t.getColor().a, player.isBuilding() ? 1f : 0f, 0.15f)); + t.bottom().update(() -> t.getColor().a = Mathf.lerpDelta(t.getColor().a, player.builder().isBuilding() ? 1f : 0f, 0.15f)); t.visible(() -> Core.settings.getBool("hints") && selectRequests.isEmpty()); t.touchable(() -> t.getColor().a < 0.1f ? Touchable.disabled : Touchable.childrenOnly); t.table(Styles.black6, b -> { b.defaults().left(); - b.label(() -> Core.bundle.format(!player.isBuilding ? "resumebuilding" : "pausebuilding", Core.keybinds.get(Binding.pause_building).key.toString())).style(Styles.outlineLabel); + b.label(() -> Core.bundle.format(!isBuilding ? "resumebuilding" : "pausebuilding", Core.keybinds.get(Binding.pause_building).key.toString())).style(Styles.outlineLabel); b.row(); b.label(() -> Core.bundle.format("cancelbuilding", Core.keybinds.get(Binding.clear_building).key.toString())).style(Styles.outlineLabel); b.row(); @@ -132,11 +134,13 @@ public class DesktopInput extends InputHandler{ @Override public void update(){ + super.update(); + if(net.active() && Core.input.keyTap(Binding.player_list)){ ui.listfrag.toggle(); } - if(((player.getClosestCore() == null && player.isDead()) || state.isPaused()) && !ui.chatfrag.shown()){ + if((player.dead() || state.isPaused()) && !ui.chatfrag.shown()){ //move camera around float camSpeed = !Core.input.keyDown(Binding.dash) ? 3f : 8f; Core.camera.position.add(Tmp.v1.setZero().add(Core.input.axis(Binding.move_x), Core.input.axis(Binding.move_y)).nor().scl(Time.delta() * camSpeed)); @@ -145,10 +149,27 @@ public class DesktopInput extends InputHandler{ Core.camera.position.x += Mathf.clamp((Core.input.mouseX() - Core.graphics.getWidth() / 2f) * 0.005f, -1, 1) * camSpeed; Core.camera.position.y += Mathf.clamp((Core.input.mouseY() - Core.graphics.getHeight() / 2f) * 0.005f, -1, 1) * camSpeed; } + }else if(!player.dead()){ + Core.camera.position.lerpDelta(player, 0.08f); + } + + //TODO remove: debug unit possession + if(Core.input.keyTap(Binding.select)){ + Unitc unit = Units.closest(state.rules.defaultTeam, Core.input.mouseWorld().x, Core.input.mouseWorld().y, 40f, u -> true); + if(unit != null){ + unit.hitbox(Tmp.r1); + if(Tmp.r1.contains(Core.input.mouseWorld())){ + player.unit(unit); + } + } + } + + if(!player.dead() && !state.isPaused() && !(Core.scene.getKeyboardFocus() instanceof TextField)){ + updateMovement(player.unit()); } if(Core.input.keyRelease(Binding.select)){ - player.isShooting = false; + isShooting = false; } if(!state.is(State.menu) && Core.input.keyTap(Binding.minimap) && !scene.hasDialog() && !(scene.getKeyboardFocus() instanceof TextField)){ @@ -158,11 +179,12 @@ public class DesktopInput extends InputHandler{ if(state.is(State.menu) || Core.scene.hasDialog()) return; //zoom camera - if((!Core.scene.hasScroll() || Core.input.keyDown(Binding.diagonal_placement)) && !ui.chatfrag.shown() && Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && !Core.input.keyDown(Binding.rotateplaced) && (Core.input.keyDown(Binding.diagonal_placement) || ((!isPlacing() || !block.rotate) && selectRequests.isEmpty()))){ + if((!Core.scene.hasScroll() || Core.input.keyDown(Binding.diagonal_placement)) && !ui.chatfrag.shown() && Math.abs(Core.input.axisTap(Binding.zoom)) > 0 + && !Core.input.keyDown(Binding.rotateplaced) && (Core.input.keyDown(Binding.diagonal_placement) || ((!isPlacing() || !block.rotate) && selectRequests.isEmpty()))){ renderer.scaleCamera(Core.input.axisTap(Binding.zoom)); } - if(player.isDead()){ + if(player.dead()){ cursorType = SystemCursor.arrow; return; } @@ -174,8 +196,8 @@ public class DesktopInput extends InputHandler{ mode = none; } - if(player.isShooting && !canShoot()){ - player.isShooting = false; + if(isShooting && !canShoot()){ + isShooting = false; } if(isPlacing()){ @@ -222,7 +244,7 @@ public class DesktopInput extends InputHandler{ cursorType = ui.unloadCursor; } - if(!isPlacing() && Math.abs(Core.input.axisTap(Binding.rotate)) > 0 && Core.input.keyDown(Binding.rotateplaced) && cursor.block().rotate){ + if(cursor.interactable(player.team()) && !isPlacing() && Math.abs(Core.input.axisTap(Binding.rotate)) > 0 && Core.input.keyDown(Binding.rotateplaced) && cursor.block().rotate){ Call.rotateBlock(player, cursor, Core.input.axisTap(Binding.rotate) > 0); } } @@ -270,9 +292,9 @@ public class DesktopInput extends InputHandler{ int rawCursorX = world.toTile(Core.input.mouseWorld().x), rawCursorY = world.toTile(Core.input.mouseWorld().y); // automatically pause building if the current build queue is empty - if(Core.settings.getBool("buildautopause") && player.isBuilding && !player.isBuilding()){ - player.isBuilding = false; - player.buildWasAutoPaused = true; + if(Core.settings.getBool("buildautopause") && isBuilding && !player.builder().isBuilding()){ + isBuilding = false; + buildWasAutoPaused = true; } if(!selectRequests.isEmpty()){ @@ -288,11 +310,11 @@ public class DesktopInput extends InputHandler{ } if(Core.input.keyTap(Binding.deselect)){ - player.setMineTile(null); + player.miner().mineTile(null); } if(Core.input.keyTap(Binding.clear_building)){ - player.clearBuilding(); + player.builder().clearBuilding(); } if(Core.input.keyTap(Binding.schematic_select) && !Core.scene.hasKeyboard()){ @@ -344,8 +366,8 @@ public class DesktopInput extends InputHandler{ } if(Core.input.keyTap(Binding.pause_building)){ - player.isBuilding = !player.isBuilding; - player.buildWasAutoPaused = false; + isBuilding = !isBuilding; + buildWasAutoPaused = false; } if((cursorX != lastLineX || cursorY != lastLineY) && isPlacing() && mode == placing){ @@ -374,12 +396,12 @@ public class DesktopInput extends InputHandler{ deleting = true; }else if(selected != null){ //only begin shooting if there's no cursor event - if(!tileTapped(selected) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && (player.buildQueue().size == 0 || !player.isBuilding) && !droppingItem && - !tryBeginMine(selected) && player.getMineTile() == null && !Core.scene.hasKeyboard()){ - player.isShooting = true; + if(!tileTapped(selected) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && (player.builder().requests().size == 0 || !player.builder().isBuilding()) && !droppingItem && + !tryBeginMine(selected) && player.miner().mineTile() == null && !Core.scene.hasKeyboard()){ + isShooting = true; } }else if(!Core.scene.hasKeyboard()){ //if it's out of bounds, shooting is just fine - player.isShooting = true; + isShooting = true; } }else if(Core.input.keyTap(Binding.deselect) && isPlacing()){ block = null; @@ -398,7 +420,7 @@ public class DesktopInput extends InputHandler{ if(Core.input.keyDown(Binding.select) && mode == none && !isPlacing() && deleting){ BuildRequest req = getRequest(cursorX, cursorY); if(req != null && req.breaking){ - player.buildQueue().remove(req); + player.builder().requests().remove(req); } }else{ deleting = false; @@ -429,7 +451,7 @@ public class DesktopInput extends InputHandler{ if(sreq != null){ if(getRequest(sreq.x, sreq.y, sreq.block.size, sreq) != null){ - player.buildQueue().remove(sreq, true); + player.builder().requests().remove(sreq, true); } sreq = null; } @@ -472,4 +494,86 @@ public class DesktopInput extends InputHandler{ selectRequests.clear(); } } + + protected void updateMovement(Unitc unit){ + boolean omni = !(unit instanceof WaterMovec); + float speed = unit.type().speed; + float xa = Core.input.axis(Binding.move_x); + float ya = Core.input.axis(Binding.move_y); + + Vec2 movement = Tmp.v1.set(speed * xa, speed * ya).limit(speed); + + if(omni){ + unit.moveAt(movement); + unit.lookAt(Angles.mouseAngle(unit.x(), unit.y())); + }else{ + if(!unit.vel().isZero(0.01f)) unit.rotation(unit.vel().angle()); + unit.moveAt(Tmp.v2.trns(unit.rotation(), movement.len())); + if(!movement.isZero()) unit.vel().rotateTo(movement.angle(), unit.type().rotateSpeed * Time.delta()); + } + + unit.aim(Core.input.mouseWorld()); + unit.controlWeapons(true, isShooting); + /* + Tile tile = unit.tileOn(); + boolean canMove = !Core.scene.hasKeyboard() || ui.minimapfrag.shown(); + + //TODO implement + boolean isBoosting = Core.input.keyDown(Binding.dash) && !mech.flying; + + //if player is in solid block + if(tile != null && tile.solid()){ + isBoosting = true; + } + + float speed = isBoosting && unit.type().flying ? mech.boostSpeed : mech.speed; + + if(mech.flying){ + //prevent strafing backwards, have a penalty for doing so + float penalty = 0.2f; //when going 180 degrees backwards, reduce speed to 0.2x + speed *= Mathf.lerp(1f, penalty, Angles.angleDist(rotation, velocity.angle()) / 180f); + } + + movement.setZero(); + + float xa = Core.input.axis(Binding.move_x); + float ya = Core.input.axis(Binding.move_y); + if(!(Core.scene.getKeyboardFocus() instanceof TextField)){ + movement.y += ya * speed; + movement.x += xa * speed; + } + + if(Core.input.keyDown(Binding.mouse_move)){ + movement.x += Mathf.clamp((Core.input.mouseX() - Core.graphics.getWidth() / 2f) * 0.005f, -1, 1) * speed; + movement.y += Mathf.clamp((Core.input.mouseY() - Core.graphics.getHeight() / 2f) * 0.005f, -1, 1) * speed; + } + + Vec2 vec = Core.input.mouseWorld(control.input.getMouseX(), control.input.getMouseY()); + pointerX = vec.x; + pointerY = vec.y; + updateShooting(); + + movement.limit(speed).scl(Time.delta()); + + if(canMove){ + velocity.add(movement.x, movement.y); + }else{ + isShooting = false; + } + float prex = x, prey = y; + updateVelocityStatus(); + moved = dst(prex, prey) > 0.001f; + + if(canMove){ + float baseLerp = mech.getRotationAlpha(this); + if(!isShooting() || !mech.faceTarget){ + if(!movement.isZero()){ + rotation = Mathf.slerpDelta(rotation, mech.flying ? velocity.angle() : movement.angle(), 0.13f * baseLerp); + } + }else{ + float angle = control.input.mouseAngle(x, y); + this.rotation = Mathf.slerpDelta(this.rotation, angle, 0.1f * baseLerp); + } + }*/ + } } diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index 8000fc4e19..f9e72b5a12 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -17,17 +17,15 @@ import arc.util.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.entities.*; -import mindustry.entities.effect.*; -import mindustry.entities.traits.BuilderTrait.*; -import mindustry.entities.type.*; +import mindustry.entities.units.*; import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.game.Teams.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.input.Placement.*; -import mindustry.net.*; import mindustry.net.Administration.*; +import mindustry.net.*; import mindustry.type.*; import mindustry.ui.fragments.*; import mindustry.world.*; @@ -56,6 +54,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public int rotation; public boolean droppingItem; public Group uiGroup; + public boolean isShooting, isBuilding = true, buildWasAutoPaused = false; protected @Nullable Schematic lastSchematic; protected GestureDetector detector; @@ -67,23 +66,51 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ //methods to override + @Remote(called = Loc.server, unreliable = true) + public static void transferItemEffect(Item item, float x, float y, Itemsc to){ + if(to == null) return; + createItemTransfer(item, x, y, to, null); + } + + @Remote(called = Loc.server, unreliable = true) + public static void transferItemToUnit(Item item, float x, float y, Itemsc to){ + if(to == null) return; + createItemTransfer(item, x, y, to, () -> to.addItem(item)); + } + + @Remote(called = Loc.server, unreliable = true) + public static void transferItemTo(Item item, int amount, float x, float y, Tile tile){ + if(tile == null || tile.entity == null || tile.entity.items() == null) return; + for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){ + Time.run(i * 3, () -> createItemTransfer(item, x, y, tile, () -> {})); + } + tile.entity.items().add(item, amount); + } + + public static void createItemTransfer(Item item, float x, float y, Position to, Runnable done){ + Fx.itemTransfer.at(x, y, 0, item.color, to); + if(done != null){ + Time.run(Fx.itemTransfer.lifetime, done); + } + } + @Remote(variants = Variant.one) public static void removeQueueBlock(int x, int y, boolean breaking){ - player.removeRequest(x, y, breaking); + player.builder().removeBuild(x, y, breaking); } @Remote(targets = Loc.client, called = Loc.server) - public static void dropItem(Player player, float angle){ - if(net.server() && player.item().amount <= 0){ + public static void dropItem(Playerc player, float angle){ + if(net.server() && player.unit().stack().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); - player.clearItem(); + Fx.dropItem.at(player.x(), player.y(), angle, Color.white, player.unit().item()); + player.unit().clearItem(); } @Remote(targets = Loc.both, called = Loc.server, forward = true, unreliable = true) - public static void rotateBlock(Player player, Tile tile, boolean direction){ + public static void rotateBlock(Playerc player, Tile tile, boolean direction){ if(net.server() && (!Units.canInteract(player, tile) || !netServer.admins.allowAction(player, ActionType.rotate, tile, action -> action.rotation = Mathf.mod(tile.rotation() + Mathf.sign(direction), 4)))){ throw new ValidateException(player, "Player cannot rotate a block."); @@ -98,61 +125,42 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } @Remote(targets = Loc.both, forward = true, called = Loc.server) - public static void transferInventory(Player player, Tile tile){ - if(player == null || player.timer == null) return; - if(net.server() && (player.item().amount <= 0 || player.isTransferring|| !Units.canInteract(player, tile) || + public static void transferInventory(Playerc player, Tile tile){ + if(player == null) return; + if(net.server() && (player.unit().stack().amount <= 0 || !Units.canInteract(player, tile) || !netServer.admins.allowAction(player, ActionType.depositItem, tile, action -> { - action.itemAmount = player.item().amount; - action.item = player.item().item; + action.itemAmount = player.unit().stack().amount; + action.item = player.unit().item(); }))){ throw new ValidateException(player, "Player cannot transfer an item."); } if(tile.entity == null) return; - player.isTransferring = true; - - Item item = player.item().item; - int amount = player.item().amount; - int accepted = tile.block().acceptStack(item, amount, tile, player); - player.item().amount -= accepted; + Item item = player.unit().item(); + int amount = player.unit().stack().amount; + int accepted = tile.block().acceptStack(item, amount, tile, player.unit()); + player.unit().stack().amount -= accepted; int sent = Mathf.clamp(accepted / 4, 1, 8); - int removed = accepted / sent; - int[] remaining = {accepted, accepted}; Block block = tile.block(); Core.app.post(() -> Events.fire(new DepositEvent(tile, player, item, accepted))); for(int i = 0; i < sent; i++){ - boolean end = i == sent - 1; - Time.run(i * 3, () -> { - tile.block().getStackOffset(item, tile, stackTrns); + tile.block().getStackOffset(item, tile, stackTrns); - ItemTransfer.create(item, - player.x + Angles.trnsx(player.rotation + 180f, backTrns), player.y + Angles.trnsy(player.rotation + 180f, backTrns), - new Vec2(tile.drawx() + stackTrns.x, tile.drawy() + stackTrns.y), () -> { - if(tile.block() != block || tile.entity == null || tile.entity.items == null) return; + createItemTransfer(item, player.x() + Angles.trnsx(player.unit().rotation() + 180f, backTrns), player.y() + Angles.trnsy(player.unit().rotation() + 180f, backTrns), + new Vec2(tile.drawx() + stackTrns.x, tile.drawy() + stackTrns.y), () -> { + if(tile.block() != block || tile.entity == null || tile.entity.items() == null) return; - tile.block().handleStack(item, removed, tile, player); - remaining[1] -= removed; - - if(end && remaining[1] > 0){ - tile.block().handleStack(item, remaining[1], tile, player); - } - }); - - remaining[0] -= removed; - - if(end){ - player.isTransferring = false; - } + tile.block().handleStack(item, accepted, tile, player.unit()); }); } } @Remote(targets = Loc.both, called = Loc.server, forward = true) - public static void onTileTapped(Player player, Tile tile){ + public static void onTileTapped(Playerc player, Tile tile){ if(tile == null || player == null) return; if(net.server() && (!Units.canInteract(player, tile) || !netServer.admins.allowAction(player, ActionType.tapTile, tile, action -> {}))) throw new ValidateException(player, "Player cannot tap a tile."); @@ -161,7 +169,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } @Remote(targets = Loc.both, called = Loc.both, forward = true) - public static void onTileConfig(Player player, Tile tile, int value){ + public static void onTileConfig(Playerc player, Tile tile, int value){ if(tile == null) return; if(net.server() && (!Units.canInteract(player, tile) || @@ -172,7 +180,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public Eachable allRequests(){ return cons -> { - for(BuildRequest request : player.buildQueue()) cons.get(request); + for(BuildRequest request : player.builder().requests()) cons.get(request); for(BuildRequest request : selectRequests) cons.get(request); for(BuildRequest request : lineRequests) cons.get(request); }; @@ -183,7 +191,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } public void update(){ - + player.typing(ui.chatfrag.shown()); } public float getMouseX(){ @@ -248,7 +256,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } public void useSchematic(Schematic schem){ - selectRequests.addAll(schematics.toRequests(schem, world.toTile(player.x), world.toTile(player.y))); + selectRequests.addAll(schematics.toRequests(schem, player.tileX(), player.tileY())); } protected void showSchematicSave(){ @@ -374,7 +382,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ return r2.overlaps(r1); }; - for(BuildRequest req : player.buildQueue()){ + for(BuildRequest req : player.builder().requests()){ if(test.get(req)) return req; } @@ -403,7 +411,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ Draw.color(Pal.remove); Lines.stroke(1f); - for(BuildRequest req : player.buildQueue()){ + for(BuildRequest req : player.builder().requests()){ if(req.breaking) continue; if(req.bounds(Tmp.r2).overlaps(Tmp.r1)){ drawBreaking(req); @@ -417,7 +425,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } } - for(BrokenBlock req : player.getTeam().data().brokenBlocks){ + for(BrokenBlock req : player.team().data().brokenBlocks){ Block block = content.block(req.block); if(block.bounds(req.x, req.y, Tmp.r2).overlaps(Tmp.r1)){ drawSelected(req.x, req.y, content.block(req.block), Pal.remove); @@ -464,7 +472,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ if(copy.hasConfig && copy.block.posConfig){ copy.config = Pos.get(Pos.x(copy.config) + copy.x - copy.originalX, Pos.y(copy.config) + copy.y - copy.originalY); } - player.addBuildRequest(copy); + player.builder().addBuild(copy); } } } @@ -508,7 +516,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ //remove build requests Tmp.r1.set(result.x * tilesize, result.y * tilesize, (result.x2 - result.x) * tilesize, (result.y2 - result.y) * tilesize); - Iterator it = player.buildQueue().iterator(); + Iterator it = player.builder().requests().iterator(); while(it.hasNext()){ BuildRequest req = it.next(); if(!req.breaking && req.bounds(Tmp.r2).overlaps(Tmp.r1)){ @@ -525,7 +533,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } //remove blocks to rebuild - Iterator broken = state.teams.get(player.getTeam()).brokenBlocks.iterator(); + Iterator broken = state.teams.get(player.team()).brokenBlocks.iterator(); while(broken.hasNext()){ BrokenBlock req = broken.next(); Block block = content.block(req.block); @@ -565,7 +573,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ boolean consumed = false, showedInventory = false; //check if tapped block is configurable - if(tile.block().configurable && tile.interactable(player.getTeam())){ + if(tile.block().configurable && tile.interactable(player.team())){ consumed = true; if(((!frag.config.isShown() && tile.block().shouldShowConfigure(tile, player)) //if the config fragment is hidden, show //alternatively, the current selected block can 'agree' to switch config tiles @@ -587,15 +595,15 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } //call tapped event - if(!consumed && tile.interactable(player.getTeam())){ + if(!consumed && tile.interactable(player.team())){ Call.onTileTapped(player, tile); } //consume tap event if necessary - if(tile.interactable(player.getTeam()) && tile.block().consumesTap){ + if(tile.interactable(player.team()) && tile.block().consumesTap){ consumed = true; - }else if(tile.interactable(player.getTeam()) && tile.block().synthetic() && !consumed){ - if(tile.block().hasItems && tile.entity.items.total() > 0){ + }else if(tile.interactable(player.team()) && tile.block().synthetic() && !consumed){ + if(tile.block().hasItems && tile.entity.items().total() > 0){ frag.inv.showFor(tile); consumed = true; showedInventory = true; @@ -619,14 +627,14 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } boolean canTapPlayer(float x, float y){ - return Mathf.dst(x, y, player.x, player.y) <= playerSelectRange && player.item().amount > 0; + return player.within(x, y, playerSelectRange) && player.unit().stack().amount > 0; } /** Tries to begin mining a tile, returns true if successful. */ boolean tryBeginMine(Tile tile){ if(canMine(tile)){ //if a block is clicked twice, reset it - player.setMineTile(player.getMineTile() == tile ? null : tile); + player.miner().mineTile(player.miner().mineTile() == tile ? null : tile); return true; } return false; @@ -634,10 +642,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ boolean canMine(Tile tile){ return !Core.scene.hasMouse() - && tile.drop() != null && tile.drop().hardness <= player.mech.drillPower + && tile.drop() != null && player.miner().canMine(tile.drop()) && !(tile.floor().playerUnmineable && tile.overlay().itemDrop == null) - && player.acceptsItem(tile.drop()) - && tile.block() == Blocks.air && player.dst(tile.worldx(), tile.worldy()) <= Player.mineDistance; + && player.unit().acceptsItem(tile.drop()) + && tile.block() == Blocks.air && player.dst(tile.worldx(), tile.worldy()) <= miningRange; } /** Returns the tile at the specified MOUSE coordinates. */ @@ -704,7 +712,8 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } public void add(){ - Core.input.addProcessor(detector = new GestureDetector(20, 0.5f, 0.4f, 0.15f, this)); + Core.input.getInputProcessors().remove(i -> i instanceof InputHandler || (i instanceof GestureDetector && ((GestureDetector)i).getListener() instanceof InputHandler)); + Core.input.addProcessor(detector = new GestureDetector(20, 0.5f, 0.3f, 0.15f, this)); Core.input.addProcessor(this); if(Core.scene != null){ Table table = (Table)Core.scene.find("inputTable"); @@ -721,10 +730,6 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ frag.add(); } - - if(player != null){ - player.isBuilding = true; - } } public boolean canShoot(){ @@ -740,16 +745,16 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } public void tryDropItems(Tile tile, float x, float y){ - if(!droppingItem || player.item().amount <= 0 || canTapPlayer(x, y) || state.isPaused() ){ + if(!droppingItem || player.unit().stack().amount <= 0 || canTapPlayer(x, y) || state.isPaused() ){ droppingItem = false; return; } droppingItem = false; - ItemStack stack = player.item(); + ItemStack stack = player.unit().stack(); - 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())){ + if(tile.block().acceptStack(stack.item, stack.amount, tile, player.unit()) > 0 && tile.interactable(player.team()) && tile.block().hasItems && player.unit().stack().amount > 0 && tile.interactable(player.team())){ Call.transferInventory(player, tile); }else{ Call.dropItem(player.angleTo(x, y)); @@ -773,7 +778,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } public boolean validPlace(int x, int y, Block type, int rotation, BuildRequest ignore){ - for(BuildRequest req : player.buildQueue()){ + for(BuildRequest req : player.builder().requests()){ if(req != ignore && !req.breaking && req.block.bounds(req.x, req.y, Tmp.r1).overlaps(type.bounds(x, y, Tmp.r2)) @@ -781,24 +786,24 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ return false; } } - return Build.validPlace(player.getTeam(), x, y, type, rotation); + return Build.validPlace(player.team(), x, y, type, rotation); } public boolean validBreak(int x, int y){ - return Build.validBreak(player.getTeam(), x, y); + return Build.validBreak(player.team(), x, y); } public void placeBlock(int x, int y, Block block, int rotation){ BuildRequest req = getRequest(x, y); if(req != null){ - player.buildQueue().remove(req); + player.builder().requests().remove(req); } - player.addBuildRequest(new BuildRequest(x, y, rotation, block)); + player.builder().addBuild(new BuildRequest(x, y, rotation, block)); } public void breakBlock(int x, int y){ Tile tile = world.ltile(x, y); - player.addBuildRequest(new BuildRequest(tile.x, tile.y)); + player.builder().addBuild(new BuildRequest(tile.x, tile.y)); } public void drawArrow(Block block, int x, int y, int rotation){ @@ -896,4 +901,192 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public int x, y, rotation; public boolean last; } + + //TODO implement all of this! + /* + protected void updateKeyboard(){ + Tile tile = world.tileWorld(x, y); + boolean canMove = !Core.scene.hasKeyboard() || ui.minimapfrag.shown(); + + isBoosting = Core.input.keyDown(Binding.dash) && !mech.flying; + + //if player is in solid block + if(tile != null && tile.solid()){ + isBoosting = true; + } + + float speed = isBoosting && !mech.flying ? mech.boostSpeed : mech.speed; + + if(mech.flying){ + //prevent strafing backwards, have a penalty for doing so + float penalty = 0.2f; //when going 180 degrees backwards, reduce speed to 0.2x + speed *= Mathf.lerp(1f, penalty, Angles.angleDist(rotation, velocity.angle()) / 180f); + } + + movement.setZero(); + + float xa = Core.input.axis(Binding.move_x); + float ya = Core.input.axis(Binding.move_y); + if(!(Core.scene.getKeyboardFocus() instanceof TextField)){ + movement.y += ya * speed; + movement.x += xa * speed; + } + + if(Core.input.keyDown(Binding.mouse_move)){ + movement.x += Mathf.clamp((Core.input.mouseX() - Core.graphics.getWidth() / 2f) * 0.005f, -1, 1) * speed; + movement.y += Mathf.clamp((Core.input.mouseY() - Core.graphics.getHeight() / 2f) * 0.005f, -1, 1) * speed; + } + + Vec2 vec = Core.input.mouseWorld(control.input.getMouseX(), control.input.getMouseY()); + pointerX = vec.x; + pointerY = vec.y; + updateShooting(); + + movement.limit(speed).scl(Time.delta()); + + if(canMove){ + velocity.add(movement.x, movement.y); + }else{ + isShooting = false; + } + float prex = x, prey = y; + updateVelocityStatus(); + moved = dst(prex, prey) > 0.001f; + + if(canMove){ + float baseLerp = mech.getRotationAlpha(this); + if(!isShooting() || !mech.faceTarget){ + if(!movement.isZero()){ + rotation = Mathf.slerpDelta(rotation, mech.flying ? velocity.angle() : movement.angle(), 0.13f * baseLerp); + } + }else{ + float angle = control.input.mouseAngle(x, y); + this.rotation = Mathf.slerpDelta(this.rotation, angle, 0.1f * baseLerp); + } + } + } + + protected void updateShooting(){ + if(!state.isEditor() && isShooting() && mech.canShoot(this)){ + weapons.update(this); + //if(!mech.turnCursor){ + //shoot forward ignoring cursor + //mech.weapon.update(this, x + Angles.trnsx(rotation, mech.weapon.targetDistance), y + Angles.trnsy(rotation, mech.weapon.targetDistance)); + //}else{ + //mech.weapon.update(this, pointerX, pointerY); + //} + } + } + + protected void updateTouch(){ + if(Units.invalidateTarget(target, this) && + !(target instanceof Tilec && ((Tilec)target).damaged() && target.isValid() && target.team() == team && mech.canHeal && dst(target) < mech.range && !(((Tilec)target).block instanceof BuildBlock))){ + target = null; + } + + if(state.isEditor()){ + target = null; + } + + float targetX = Core.camera.position.x, targetY = Core.camera.position.y; + float attractDst = 15f; + float speed = isBoosting && !mech.flying ? mech.boostSpeed : mech.speed; + + if(moveTarget != null && !moveTarget.dead()){ + targetX = moveTarget.getX(); + targetY = moveTarget.getY(); + boolean tapping = moveTarget instanceof Tilec && moveTarget.team() == team; + attractDst = 0f; + + if(tapping){ + velocity.setAngle(angleTo(moveTarget)); + } + + if(dst(moveTarget) <= 2f * Time.delta()){ + if(tapping && !dead()){ + Tile tile = ((Tilec)moveTarget).tile; + tile.block().tapped(tile, this); + } + + moveTarget = null; + } + }else{ + moveTarget = null; + } + + movement.set((targetX - x) / Time.delta(), (targetY - y) / Time.delta()).limit(speed); + movement.setAngle(Mathf.slerp(movement.angle(), velocity.angle(), 0.05f)); + + if(dst(targetX, targetY) < attractDst){ + movement.setZero(); + } + + float expansion = 3f; + + hitbox(rect); + rect.x -= expansion; + rect.y -= expansion; + rect.width += expansion * 2f; + rect.height += expansion * 2f; + + isBoosting = collisions.overlapsTile(rect) || dst(targetX, targetY) > 85f; + + velocity.add(movement.scl(Time.delta())); + + if(velocity.len() <= 0.2f && mech.flying){ + rotation += Mathf.sin(Time.time() + id * 99, 10f, 1f); + }else if(target == null){ + rotation = Mathf.slerpDelta(rotation, velocity.angle(), velocity.len() / 10f); + } + + float lx = x, ly = y; + updateVelocityStatus(); + moved = dst(lx, ly) > 0.001f; + + if(mech.flying){ + //hovering effect + x += Mathf.sin(Time.time() + id * 999, 25f, 0.08f); + y += Mathf.cos(Time.time() + id * 999, 25f, 0.08f); + } + + //update shooting if not building, not mining and there's ammo left + if(!isBuilding() && mineTile() == null){ + + //autofire + if(target == null){ + isShooting = false; + if(Core.settings.getBool("autotarget")){ + target = Units.closestTarget(team, x, y, mech.range, u -> u.team() != Team.derelict, u -> u.team() != Team.derelict); + + if(mech.canHeal && target == null){ + target = Geometry.findClosest(x, y, indexer.getDamaged(Team.sharded)); + if(target != null && dst(target) > mech.range){ + target = null; + }else if(target != null){ + target = ((Tile)target).entity; + } + } + + if(target != null){ + mineTile(null); + } + } + }else if(target.isValid() || (target instanceof Tilec && ((Tilec)target).damaged() && target.team() == team && mech.canHeal && dst(target) < mech.range)){ + //rotate toward and shoot the target + if(mech.faceTarget){ + rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.2f); + } + + Vec2 intercept = Predict.intercept(this, target, getWeapon().bullet.speed); + + pointerX = intercept.x; + pointerY = intercept.y; + + updateShooting(); + isShooting = true; + } + + } + } + */ } diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java index 8e0ed53d06..81a6cccd9c 100644 --- a/core/src/mindustry/input/MobileInput.java +++ b/core/src/mindustry/input/MobileInput.java @@ -16,12 +16,10 @@ import mindustry.*; import mindustry.content.*; import mindustry.core.GameState.*; import mindustry.entities.*; -import mindustry.entities.traits.BuilderTrait.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; +import mindustry.gen.*; +import mindustry.entities.units.*; import mindustry.game.EventType.*; import mindustry.game.*; -import mindustry.gen.*; import mindustry.graphics.*; import mindustry.ui.*; import mindustry.world.*; @@ -46,7 +44,7 @@ public class MobileInput extends InputHandler implements GestureListener{ private float lineScale; /** Animation data for crosshair. */ private float crosshairScale; - private TargetTrait lastTarget; + private Teamc lastTarget; /** Used for shifting build requests. */ private float shiftDeltaX, shiftDeltaY; @@ -65,26 +63,29 @@ public class MobileInput extends InputHandler implements GestureListener{ /** Down tracking for panning.*/ private boolean down = false; + private Teamc target; + //region utility methods /** Check and assign targets for a specific position. */ void checkTargets(float x, float y){ - Unit unit = Units.closestEnemy(player.getTeam(), x, y, 20f, u -> !u.isDead()); + Unitc unit = Units.closestEnemy(player.team(), x, y, 20f, u -> !u.dead()); if(unit != null){ - player.setMineTile(null); - player.target = unit; + player.miner().mineTile(null); + target = unit; }else{ Tile tile = world.ltileWorld(x, y); - if(tile != null && tile.synthetic() && player.getTeam().isEnemy(tile.getTeam())){ - TileEntity entity = tile.entity; - player.setMineTile(null); - player.target = entity; - }else if(tile != null && player.mech.canHeal && tile.entity != null && tile.getTeam() == player.getTeam() && tile.entity.damaged()){ - player.setMineTile(null); - player.target = tile.entity; - } + if(tile != null && tile.synthetic() && player.team().isEnemy(tile.team())){ + Tilec entity = tile.entity; + player.miner().mineTile(null); + target = entity; + //TODO implement healing + }//else if(tile != null && player.unit().canHeal && tile.entity != null && tile.team() == player.team() && tile.entity.damaged()){ + /// player.miner().mineTile(null); + // target = tile.entity; + // } } } @@ -111,7 +112,7 @@ public class MobileInput extends InputHandler implements GestureListener{ } } - for(BuildRequest req : player.buildQueue()){ + for(BuildRequest req : player.builder().requests()){ Tile other = world.tile(req.x, req.y); if(other == null || req.breaking) continue; @@ -156,7 +157,7 @@ public class MobileInput extends InputHandler implements GestureListener{ } void removeRequest(BuildRequest request){ - selectRequests.removeValue(request, true); + selectRequests.remove(request, true); if(!request.breaking){ removals.add(request); } @@ -226,10 +227,10 @@ public class MobileInput extends InputHandler implements GestureListener{ } if(other == null){ - player.addBuildRequest(copy); + player.builder().addBuild(copy); }else if(!other.breaking && other.x == request.x && other.y == request.y && other.block.size == request.block.size){ - player.buildQueue().remove(other); - player.addBuildRequest(copy); + player.builder().requests().remove(other); + player.builder().addBuild(copy); } } @@ -252,13 +253,13 @@ public class MobileInput extends InputHandler implements GestureListener{ Boolp schem = () -> lastSchematic != null && !selectRequests.isEmpty(); group.fill(t -> { - t.bottom().left().visible(() -> (player.isBuilding() || block != null || mode == breaking || !selectRequests.isEmpty()) && !schem.get()); + t.bottom().left().visible(() -> (player.builder().isBuilding() || block != null || mode == breaking || !selectRequests.isEmpty()) && !schem.get()); t.addImageTextButton("$cancel", Icon.cancel, () -> { - player.clearBuilding(); + player.builder().clearBuilding(); selectRequests.clear(); mode = none; block = null; - }).width(155f); + }).width(155f).margin(12f); }); group.fill(t -> { @@ -377,8 +378,6 @@ public class MobileInput extends InputHandler implements GestureListener{ } } - TargetTrait target = player.target; - //draw targeting crosshair if(target != null && !state.isEditor()){ if(target != lastTarget){ @@ -433,7 +432,7 @@ public class MobileInput extends InputHandler implements GestureListener{ @Override public void useSchematic(Schematic schem){ selectRequests.clear(); - selectRequests.addAll(schematics.toRequests(schem, world.toTile(player.x), world.toTile(player.y))); + selectRequests.addAll(schematics.toRequests(schem, player.tileX(), player.tileY())); lastSchematic = schem; } @@ -443,7 +442,7 @@ public class MobileInput extends InputHandler implements GestureListener{ down = true; - if(player.isDead()) return false; + if(player.dead()) return false; //get tile on cursor Tile cursor = tileAt(screenX, screenY); @@ -469,7 +468,7 @@ public class MobileInput extends InputHandler implements GestureListener{ lastLineY = tileY; }else if(!tryTapPlayer(worldx, worldy) && Core.settings.getBool("keyboard")){ //shoot on touch down when in keyboard mode - player.isShooting = true; + isShooting = true; } } @@ -520,7 +519,7 @@ public class MobileInput extends InputHandler implements GestureListener{ @Override public boolean longPress(float x, float y){ - if(state.is(State.menu) || mode == none || player.isDead()) return false; + if(state.is(State.menu) || mode == none || player.dead()) return false; //get tile on cursor Tile cursor = tileAt(x, y); @@ -537,10 +536,10 @@ public class MobileInput extends InputHandler implements GestureListener{ lineMode = true; if(mode == breaking){ - Effects.effect(Fx.tapBlock, cursor.worldx(), cursor.worldy(), 1f); + Fx.tapBlock.at(cursor.worldx(), cursor.worldy(), 1f); }else if(block != null){ updateLine(lineStartX, lineStartY, cursor.x, cursor.y); - Effects.effect(Fx.tapBlock, cursor.worldx() + block.offset(), cursor.worldy() + block.offset(), block.size); + Fx.tapBlock.at(cursor.worldx() + block.offset(), cursor.worldy() + block.offset(), block.size); } return false; @@ -579,13 +578,15 @@ public class MobileInput extends InputHandler implements GestureListener{ @Override public void update(){ + super.update(); + if(state.is(State.menu) ){ selectRequests.clear(); removals.clear(); mode = none; } - if(player.isDead()){ + if(player.dead()){ mode = none; } @@ -602,11 +603,11 @@ public class MobileInput extends InputHandler implements GestureListener{ if(Core.settings.getBool("keyboard")){ if(Core.input.keyRelease(Binding.select)){ - player.isShooting = false; + isShooting = false; } - if(player.isShooting && !canShoot()){ - player.isShooting = false; + if(isShooting && !canShoot()){ + isShooting = false; } } diff --git a/core/src/mindustry/io/MapIO.java b/core/src/mindustry/io/MapIO.java index 0ffe03d777..3187b791b6 100644 --- a/core/src/mindustry/io/MapIO.java +++ b/core/src/mindustry/io/MapIO.java @@ -19,7 +19,6 @@ import java.util.zip.*; import static mindustry.Vars.*; /** Reads and writes map files. */ -//TODO does this class even need to exist??? move to Maps? public class MapIO{ private static final int[] pngHeader = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; @@ -81,7 +80,7 @@ public class MapIO{ @Override public void setBlock(Block type){ super.setBlock(type); - int c = colorFor(Blocks.air, block(), Blocks.air, getTeam()); + int c = colorFor(Blocks.air, block(), Blocks.air, team()); if(c != black){ walls.draw(x, floors.getHeight() - 1 - y, c); floors.draw(x, floors.getHeight() - 1 - y + 1, shade); @@ -138,7 +137,7 @@ public class MapIO{ for(int x = 0; x < pixmap.getWidth(); x++){ for(int y = 0; y < pixmap.getHeight(); y++){ Tile tile = tiles.getn(x, y); - pixmap.draw(x, pixmap.getHeight() - 1 - y, colorFor(tile.floor(), tile.block(), tile.overlay(), tile.getTeam())); + pixmap.draw(x, pixmap.getHeight() - 1 - y, colorFor(tile.floor(), tile.block(), tile.overlay(), tile.team())); } } return pixmap; diff --git a/core/src/mindustry/io/SaveFileReader.java b/core/src/mindustry/io/SaveFileReader.java index c324e78fdb..2cc2e27a90 100644 --- a/core/src/mindustry/io/SaveFileReader.java +++ b/core/src/mindustry/io/SaveFileReader.java @@ -14,7 +14,9 @@ public abstract class SaveFileReader{ protected final DataOutputStream dataBytes = new DataOutputStream(byteOutput); protected final ReusableByteOutStream byteOutputSmall = new ReusableByteOutStream(); protected final DataOutputStream dataBytesSmall = new DataOutputStream(byteOutputSmall); - protected final ObjectMap fallback = ObjectMap.of(); + protected final ObjectMap fallback = ObjectMap.of( + "dart-mech-pad", "dart-ship-pad" + ); protected void region(String name, DataInput stream, CounterInputStream counter, IORunner cons) throws IOException{ counter.resetCount(); diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java index 06c75bc878..621545889f 100644 --- a/core/src/mindustry/io/SaveVersion.java +++ b/core/src/mindustry/io/SaveVersion.java @@ -6,13 +6,10 @@ import arc.util.io.*; import mindustry.content.*; import mindustry.core.*; import mindustry.ctype.*; -import mindustry.ctype.ContentType; -import mindustry.entities.*; -import mindustry.entities.traits.*; import mindustry.game.*; import mindustry.game.Teams.*; +import mindustry.gen.*; import mindustry.maps.*; -import mindustry.type.*; import mindustry.world.*; import java.io.*; @@ -189,10 +186,7 @@ public abstract class SaveVersion extends SaveFileReader{ if(tile.entity != null){ try{ - readChunk(stream, true, in -> { - byte version = in.readByte(); - tile.entity.read(in, version); - }); + readChunk(stream, true, in -> tile.entity.read(in)); }catch(Exception e){ throw new IOException("Failed to read tile entity of block: " + block, e); } @@ -228,30 +222,12 @@ public abstract class SaveVersion extends SaveFileReader{ } } - //write entity chunk - int groups = 0; - - for(EntityGroup group : entities.all()){ - if(!group.isEmpty() && group.all().get(0) instanceof SaveTrait){ - groups++; - } - } - - stream.writeByte(groups); - - for(EntityGroup group : entities.all()){ - if(!group.isEmpty() && group.all().get(0) instanceof SaveTrait){ - stream.writeInt(group.size()); - for(Entity entity : group.all()){ - SaveTrait save = (SaveTrait)entity; - //each entity is a separate chunk. - writeChunk(stream, true, out -> { - out.writeByte(save.getTypeID().id); - out.writeByte(save.version()); - save.writeSave(out); - }); - } - } + stream.writeInt(Groups.sync.size()); + for(Syncc entity : Groups.sync){ + writeChunk(stream, true, out -> { + out.writeByte(entity.classId()); + entity.write(out); + }); } } @@ -266,19 +242,14 @@ public abstract class SaveVersion extends SaveFileReader{ } } - byte groups = stream.readByte(); - for(int i = 0; i < groups; i++){ - int amount = stream.readInt(); - for(int j = 0; j < amount; j++){ - //TODO throw exception on read fail - readChunk(stream, true, in -> { - byte typeid = in.readByte(); - byte version = in.readByte(); - SaveTrait trait = (SaveTrait)content.getByID(ContentType.typeid, typeid).constructor.get(); - trait.readSave(in, version); - }); - } + int amount = stream.readInt(); + for(int j = 0; j < amount; j++){ + readChunk(stream, true, in -> { + byte typeid = in.readByte(); + Syncc sync = (Syncc)EntityMapping.map(typeid).get(); + sync.read(in); + }); } } diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java index 5095ce396a..5ab5a6b832 100644 --- a/core/src/mindustry/io/TypeIO.java +++ b/core/src/mindustry/io/TypeIO.java @@ -1,26 +1,19 @@ package mindustry.io; -import mindustry.annotations.Annotations.ReadClass; -import mindustry.annotations.Annotations.WriteClass; -import arc.graphics.Color; -import mindustry.ctype.ContentType; -import mindustry.entities.Effects; -import mindustry.entities.Effects.Effect; -import mindustry.entities.type.Bullet; -import mindustry.entities.bullet.BulletType; -import mindustry.entities.traits.BuilderTrait.BuildRequest; -import mindustry.entities.traits.ShooterTrait; -import mindustry.entities.type.*; +import arc.graphics.*; +import mindustry.annotations.Annotations.*; +import mindustry.ctype.*; +import mindustry.entities.bullet.*; import mindustry.entities.units.*; import mindustry.game.*; -import mindustry.net.Administration.TraceInfo; -import mindustry.net.Packets.AdminAction; -import mindustry.net.Packets.KickReason; +import mindustry.gen.*; +import mindustry.net.Administration.*; +import mindustry.net.Packets.*; import mindustry.type.*; import mindustry.world.*; import java.io.*; -import java.nio.ByteBuffer; +import java.nio.*; import static mindustry.Vars.*; @@ -28,74 +21,14 @@ import static mindustry.Vars.*; @SuppressWarnings("unused") public class TypeIO{ - @WriteClass(Player.class) - public static void writePlayer(ByteBuffer buffer, Player player){ - if(player == null){ - buffer.putInt(-1); - }else{ - buffer.putInt(player.id); - } + @WriteClass(Entityc.class) + public static void writeEntity(ByteBuffer buffer, Entityc entity){ + buffer.putInt(entity == null ? -1 : entity.id()); } - @ReadClass(Player.class) - public static Player readPlayer(ByteBuffer buffer){ - int id = buffer.getInt(); - return id == -1 ? null : playerGroup.getByID(id); - } - - @WriteClass(Unit.class) - public static void writeUnit(ByteBuffer buffer, Unit unit){ - if(unit.getGroup() == null){ - buffer.put((byte)-1); - return; - } - buffer.put((byte)unit.getGroup().getID()); - buffer.putInt(unit.getID()); - } - - @ReadClass(Unit.class) - public static Unit readUnit(ByteBuffer buffer){ - byte gid = buffer.get(); - if(gid == -1) return null; - int id = buffer.getInt(); - return (Unit)entities.get(gid).getByID(id); - } - - @WriteClass(ShooterTrait.class) - public static void writeShooter(ByteBuffer buffer, ShooterTrait trait){ - buffer.put((byte)trait.getGroup().getID()); - buffer.putInt(trait.getID()); - } - - @ReadClass(ShooterTrait.class) - public static ShooterTrait readShooter(ByteBuffer buffer){ - byte gid = buffer.get(); - int id = buffer.getInt(); - return (ShooterTrait)entities.get(gid).getByID(id); - } - - @WriteClass(Bullet.class) - public static void writeBullet(ByteBuffer buffer, Bullet bullet){ - buffer.putInt(bullet.getID()); - } - - @ReadClass(Bullet.class) - public static Bullet readBullet(ByteBuffer buffer){ - int id = buffer.getInt(); - return bulletGroup.getByID(id); - } - - @WriteClass(BaseUnit.class) - public static void writeBaseUnit(ByteBuffer buffer, BaseUnit unit){ - buffer.put((byte) (int)unit.getTeam().id); - buffer.putInt(unit.getID()); - } - - @ReadClass(BaseUnit.class) - public static BaseUnit readBaseUnit(ByteBuffer buffer){ - byte tid = buffer.get(); - int id = buffer.getInt(); - return unitGroup.getByID(id); + @ReadClass(Entityc.class) + public static T readEntity(ByteBuffer buffer){ + return (T)Groups.all.getByID(buffer.getInt()); } @WriteClass(Tile.class) @@ -222,23 +155,13 @@ public class TypeIO{ return AdminAction.values()[buffer.get()]; } - @WriteClass(Effect.class) - public static void writeEffect(ByteBuffer buffer, Effect effect){ - buffer.putShort((short)effect.id); - } - - @ReadClass(Effect.class) - public static Effect readEffect(ByteBuffer buffer){ - return Effects.getEffect(buffer.getShort()); - } - - @WriteClass(UnitType.class) - public static void writeUnitType(ByteBuffer buffer, UnitType effect){ + @WriteClass(UnitDef.class) + public static void writeUnitDef(ByteBuffer buffer, UnitDef effect){ buffer.putShort(effect.id); } - @ReadClass(UnitType.class) - public static UnitType readUnitType(ByteBuffer buffer){ + @ReadClass(UnitDef.class) + public static UnitDef readUnitDef(ByteBuffer buffer){ return content.getByID(ContentType.unit, buffer.getShort()); } @@ -252,16 +175,6 @@ public class TypeIO{ return new Color(buffer.getInt()); } - @WriteClass(Mech.class) - public static void writeMech(ByteBuffer buffer, Mech mech){ - buffer.put((byte)mech.id); - } - - @ReadClass(Mech.class) - public static Mech readMech(ByteBuffer buffer){ - return content.getByID(ContentType.mech, buffer.get()); - } - @WriteClass(Liquid.class) public static void writeLiquid(ByteBuffer buffer, Liquid liquid){ buffer.putShort(liquid == null ? -1 : liquid.id); diff --git a/core/src/mindustry/io/versions/LegacyTypeTable.java b/core/src/mindustry/io/versions/LegacyTypeTable.java index 2aeb8c8d66..36b184f93f 100644 --- a/core/src/mindustry/io/versions/LegacyTypeTable.java +++ b/core/src/mindustry/io/versions/LegacyTypeTable.java @@ -1,11 +1,5 @@ package mindustry.io.versions; -import arc.func.Prov; -import mindustry.entities.type.Bullet; -import mindustry.entities.effect.*; -import mindustry.entities.type.Player; -import mindustry.entities.type.base.*; - /* Latest data: [build 81] @@ -77,9 +71,9 @@ public class LegacyTypeTable{ 11 = Wraith 12 = Ghoul 13 = Revenant - */ + private static final Prov[] build81Table = { - Player::new, + Playerc::new, Fire::new, Puddle::new, MinerDrone::new, @@ -96,7 +90,7 @@ public class LegacyTypeTable{ }; private static final Prov[] build80Table = { - Player::new, + Playerc::new, Fire::new, Puddle::new, Bullet::new, @@ -115,7 +109,7 @@ public class LegacyTypeTable{ }; private static final Prov[] build79Table = { - Player::new, + Playerc::new, Fire::new, Puddle::new, Bullet::new, @@ -141,5 +135,5 @@ public class LegacyTypeTable{ }else{ return build79Table; } - } + }*/ } diff --git a/core/src/mindustry/io/versions/Save1.java b/core/src/mindustry/io/versions/Save1.java index 446fe8e80b..613b116446 100644 --- a/core/src/mindustry/io/versions/Save1.java +++ b/core/src/mindustry/io/versions/Save1.java @@ -1,8 +1,5 @@ package mindustry.io.versions; -import arc.func.*; -import mindustry.entities.traits.*; - import java.io.*; public class Save1 extends Save2{ @@ -13,7 +10,8 @@ public class Save1 extends Save2{ @Override public void readEntities(DataInput stream) throws IOException{ - Prov[] table = LegacyTypeTable.getTable(lastReadBuild); + //TODO implement + //Prov[] table = LegacyTypeTable.getTable(lastReadBuild); byte groups = stream.readByte(); @@ -23,8 +21,8 @@ public class Save1 extends Save2{ readChunk(stream, true, in -> { byte typeid = in.readByte(); byte version = in.readByte(); - SaveTrait trait = (SaveTrait)table[typeid].get(); - trait.readSave(in, version); + //SaveTrait trait = (SaveTrait)table[typeid].get(); + //trait.readSave(in, version); }); } } diff --git a/core/src/mindustry/io/versions/Save2.java b/core/src/mindustry/io/versions/Save2.java index 497289ed71..3467e369fb 100644 --- a/core/src/mindustry/io/versions/Save2.java +++ b/core/src/mindustry/io/versions/Save2.java @@ -1,14 +1,9 @@ package mindustry.io.versions; -import mindustry.ctype.ContentType; -import mindustry.entities.traits.*; import mindustry.io.*; -import mindustry.type.TypeID; import java.io.*; -import static mindustry.Vars.content; - public class Save2 extends SaveVersion{ public Save2(){ @@ -17,6 +12,7 @@ public class Save2 extends SaveVersion{ @Override public void readEntities(DataInput stream) throws IOException{ + //TODO implement byte groups = stream.readByte(); for(int i = 0; i < groups; i++){ @@ -26,8 +22,8 @@ public class Save2 extends SaveVersion{ readChunk(stream, true, in -> { byte typeid = in.readByte(); byte version = in.readByte(); - SaveTrait trait = (SaveTrait)content.getByID(ContentType.typeid, typeid).constructor.get(); - trait.readSave(in, version); + //SaveTrait trait = (SaveTrait)content.getByID(ContentType.typeid, typeid).constructor.get(); + //trait.readSave(in, version); }); } } diff --git a/core/src/mindustry/maps/Map.java b/core/src/mindustry/maps/Map.java index 90bb4f2f87..296180680b 100644 --- a/core/src/mindustry/maps/Map.java +++ b/core/src/mindustry/maps/Map.java @@ -203,7 +203,7 @@ public class Map implements Comparable, Publishable{ @Override public boolean prePublish(){ - tags.put("author", player.name); + tags.put("author", player.name()); ui.editor.editor.getTags().put("author", tags.get("author")); ui.editor.save(); diff --git a/core/src/mindustry/maps/Maps.java b/core/src/mindustry/maps/Maps.java index d7522e5166..4279ebc765 100644 --- a/core/src/mindustry/maps/Maps.java +++ b/core/src/mindustry/maps/Maps.java @@ -338,11 +338,11 @@ public class Maps{ } public void addDefaultOres(Array filters){ - int index = 0; - for(Block block : new Block[]{Blocks.oreCopper, Blocks.oreLead, Blocks.oreCoal, Blocks.oreTitanium, Blocks.oreThorium}){ + Array ores = content.blocks().select(b -> b.isOverlay() && b.asFloor().oreDefault); + for(Block block : ores){ OreFilter filter = new OreFilter(); - filter.threshold += index ++ * 0.018f; - filter.scl += index/2.1f; + filter.threshold = block.asFloor().oreThreshold; + filter.scl = block.asFloor().oreScale; filter.ore = block; filters.add(filter); } diff --git a/core/src/mindustry/maps/filters/CoreSpawnFilter.java b/core/src/mindustry/maps/filters/CoreSpawnFilter.java index 8386c5cfa9..1f1c5aefae 100644 --- a/core/src/mindustry/maps/filters/CoreSpawnFilter.java +++ b/core/src/mindustry/maps/filters/CoreSpawnFilter.java @@ -23,7 +23,7 @@ public class CoreSpawnFilter extends GenerateFilter{ public void apply(Tiles tiles, GenerateInput in){ IntArray spawns = new IntArray(); for(Tile tile : tiles){ - if(tile.getTeam() == state.rules.defaultTeam && tile.block() instanceof CoreBlock){ + if(tile.team() == state.rules.defaultTeam && tile.block() instanceof CoreBlock){ spawns.add(tile.pos()); } } diff --git a/core/src/mindustry/maps/filters/FilterOption.java b/core/src/mindustry/maps/filters/FilterOption.java index 41698c0674..a91d471a82 100644 --- a/core/src/mindustry/maps/filters/FilterOption.java +++ b/core/src/mindustry/maps/filters/FilterOption.java @@ -8,7 +8,8 @@ import arc.scene.ui.*; import arc.scene.ui.layout.*; import mindustry.*; import mindustry.content.*; -import mindustry.ui.Cicon; +import mindustry.gen.*; +import mindustry.ui.*; import mindustry.ui.dialogs.*; import mindustry.world.*; import mindustry.world.blocks.*; @@ -88,14 +89,14 @@ public abstract class FilterOption{ @Override public void build(Table table){ table.addButton(b -> b.addImage(supplier.get().icon(Cicon.small)).update(i -> ((TextureRegionDrawable)i.getDrawable()) - .setRegion(supplier.get() == Blocks.air ? Core.atlas.find("Icon.none") : supplier.get().icon(Cicon.small))).size(8 * 3), () -> { + .setRegion(supplier.get() == Blocks.air ? Icon.block.getRegion() : supplier.get().icon(Cicon.small))).size(8 * 3), () -> { FloatingDialog dialog = new FloatingDialog(""); dialog.setFillParent(false); int i = 0; for(Block block : Vars.content.blocks()){ if(!filter.get(block)) continue; - dialog.cont.addImage(block == Blocks.air ? Core.atlas.find("Icon.none-") : block.icon(Cicon.medium)).size(8 * 4).pad(3).get().clicked(() -> { + dialog.cont.addImage(block == Blocks.air ? Icon.block.getRegion() : block.icon(Cicon.medium)).size(8 * 4).pad(3).get().clicked(() -> { consumer.get(block); dialog.hide(); changed.run(); diff --git a/core/src/mindustry/maps/filters/RandomItemFilter.java b/core/src/mindustry/maps/filters/RandomItemFilter.java index d4f163d6db..dc20cd6ace 100644 --- a/core/src/mindustry/maps/filters/RandomItemFilter.java +++ b/core/src/mindustry/maps/filters/RandomItemFilter.java @@ -21,7 +21,7 @@ public class RandomItemFilter extends GenerateFilter{ if(tile.block() instanceof StorageBlock && !(tile.block() instanceof CoreBlock)){ for(ItemStack stack : drops){ if(Mathf.chance(chance)){ - tile.entity.items.add(stack.item, Math.min(Mathf.random(stack.amount), tile.block().itemCapacity)); + tile.entity.items().add(stack.item, Math.min(Mathf.random(stack.amount), tile.block().itemCapacity)); } } } diff --git a/core/src/mindustry/maps/generators/MapGenerator.java b/core/src/mindustry/maps/generators/MapGenerator.java index db54ba7c34..5269f2b7a8 100644 --- a/core/src/mindustry/maps/generators/MapGenerator.java +++ b/core/src/mindustry/maps/generators/MapGenerator.java @@ -50,7 +50,7 @@ public class MapGenerator extends Generator{ if(tile.block() instanceof StorageBlock && !(tile.block() instanceof CoreBlock) && world.getZone() != null){ for(Item item : world.getZone().resources){ if(Mathf.chance(0.3)){ - tile.entity.items.add(item, Math.min(Mathf.random(500), tile.block().itemCapacity)); + tile.entity.items().add(item, Math.min(Mathf.random(500), tile.block().itemCapacity)); } } } @@ -68,7 +68,7 @@ public class MapGenerator extends Generator{ }); } - if(tile.block() instanceof CoreBlock && tile.getTeam() == state.rules.defaultTeam){ + if(tile.block() instanceof CoreBlock && tile.team() == state.rules.defaultTeam){ schematics.placeLoadout(loadout, tile.x, tile.y); anyCores = true; } diff --git a/core/src/mindustry/mod/ClassAccess.java b/core/src/mindustry/mod/ClassAccess.java deleted file mode 100644 index 7046227686..0000000000 --- a/core/src/mindustry/mod/ClassAccess.java +++ /dev/null @@ -1,7 +0,0 @@ -package mindustry.mod; - -import arc.struct.*; -//obviously autogenerated, do not touch -public class ClassAccess{ - public static final ObjectSet allowedClassNames = ObjectSet.with("arc.Core", "arc.func.Boolc", "arc.func.Boolf", "arc.func.Boolf2", "arc.func.Boolp", "arc.func.Cons", "arc.func.Cons2", "arc.func.Floatc", "arc.func.Floatc2", "arc.func.Floatc4", "arc.func.Floatf", "arc.func.Floatp", "arc.func.Func", "arc.func.Func2", "arc.func.Func3", "arc.func.Intc", "arc.func.Intc2", "arc.func.Intc4", "arc.func.Intf", "arc.func.Intp", "arc.func.Prov", "arc.graphics.Color", "arc.graphics.Pixmap", "arc.graphics.Texture", "arc.graphics.TextureData", "arc.graphics.g2d.Draw", "arc.graphics.g2d.Fill", "arc.graphics.g2d.Lines", "arc.graphics.g2d.TextureAtlas", "arc.graphics.g2d.TextureAtlas$AtlasRegion", "arc.graphics.g2d.TextureRegion", "arc.math.Affine2", "arc.math.Angles", "arc.math.Angles", "arc.math.Angles$ParticleConsumer", "arc.math.CumulativeDistribution", "arc.math.CumulativeDistribution$CumulativeValue", "arc.math.DelaunayTriangulator", "arc.math.EarClippingTriangulator", "arc.math.Extrapolator", "arc.math.FloatCounter", "arc.math.Interpolation", "arc.math.Interpolation$Bounce", "arc.math.Interpolation$BounceIn", "arc.math.Interpolation$BounceOut", "arc.math.Interpolation$Elastic", "arc.math.Interpolation$ElasticIn", "arc.math.Interpolation$ElasticOut", "arc.math.Interpolation$Exp", "arc.math.Interpolation$ExpIn", "arc.math.Interpolation$ExpOut", "arc.math.Interpolation$Pow", "arc.math.Interpolation$PowIn", "arc.math.Interpolation$PowOut", "arc.math.Interpolation$Swing", "arc.math.Interpolation$SwingIn", "arc.math.Interpolation$SwingOut", "arc.math.Mathf", "arc.math.Mathf", "arc.math.Matrix3", "arc.math.WindowedMean", "arc.math.geom.BSpline", "arc.math.geom.Bezier", "arc.math.geom.Bresenham2", "arc.math.geom.CatmullRomSpline", "arc.math.geom.Circle", "arc.math.geom.ConvexHull", "arc.math.geom.Ellipse", "arc.math.geom.FixedPosition", "arc.math.geom.Geometry", "arc.math.geom.Geometry$Raycaster", "arc.math.geom.Geometry$SolidChecker", "arc.math.geom.Intersector", "arc.math.geom.Intersector$MinimumTranslationVector", "arc.math.geom.Path", "arc.math.geom.Point2", "arc.math.geom.Point3", "arc.math.geom.Polygon", "arc.math.geom.Polyline", "arc.math.geom.Position", "arc.math.geom.QuadTree", "arc.math.geom.QuadTree$QuadTreeObject", "arc.math.geom.Rect", "arc.math.geom.Shape2D", "arc.math.geom.Spring1D", "arc.math.geom.Spring2D", "arc.math.geom.Vec2", "arc.math.geom.Vec3", "arc.math.geom.Vector", "arc.scene.Action", "arc.scene.Element", "arc.scene.Group", "arc.scene.Scene", "arc.scene.actions.Actions", "arc.scene.actions.AddAction", "arc.scene.actions.AddListenerAction", "arc.scene.actions.AfterAction", "arc.scene.actions.AlphaAction", "arc.scene.actions.ColorAction", "arc.scene.actions.DelayAction", "arc.scene.actions.DelegateAction", "arc.scene.actions.FloatAction", "arc.scene.actions.IntAction", "arc.scene.actions.LayoutAction", "arc.scene.actions.MoveByAction", "arc.scene.actions.MoveToAction", "arc.scene.actions.OriginAction", "arc.scene.actions.ParallelAction", "arc.scene.actions.RelativeTemporalAction", "arc.scene.actions.RemoveAction", "arc.scene.actions.RemoveActorAction", "arc.scene.actions.RemoveListenerAction", "arc.scene.actions.RepeatAction", "arc.scene.actions.RotateByAction", "arc.scene.actions.RotateToAction", "arc.scene.actions.RunnableAction", "arc.scene.actions.ScaleByAction", "arc.scene.actions.ScaleToAction", "arc.scene.actions.SequenceAction", "arc.scene.actions.SizeByAction", "arc.scene.actions.SizeToAction", "arc.scene.actions.TemporalAction", "arc.scene.actions.TimeScaleAction", "arc.scene.actions.TouchableAction", "arc.scene.actions.TranslateByAction", "arc.scene.actions.VisibleAction", "arc.scene.event.ChangeListener", "arc.scene.event.ChangeListener$ChangeEvent", "arc.scene.event.ClickListener", "arc.scene.event.DragListener", "arc.scene.event.DragScrollListener", "arc.scene.event.ElementGestureListener", "arc.scene.event.EventListener", "arc.scene.event.FocusListener", "arc.scene.event.FocusListener$FocusEvent", "arc.scene.event.FocusListener$FocusEvent$Type", "arc.scene.event.HandCursorListener", "arc.scene.event.IbeamCursorListener", "arc.scene.event.InputEvent", "arc.scene.event.InputEvent$Type", "arc.scene.event.InputListener", "arc.scene.event.SceneEvent", "arc.scene.event.Touchable", "arc.scene.event.VisibilityEvent", "arc.scene.event.VisibilityListener", "arc.scene.style.BaseDrawable", "arc.scene.style.Drawable", "arc.scene.style.NinePatchDrawable", "arc.scene.style.ScaledNinePatchDrawable", "arc.scene.style.Style", "arc.scene.style.TextureRegionDrawable", "arc.scene.style.TiledDrawable", "arc.scene.style.TransformDrawable", "arc.scene.ui.Button", "arc.scene.ui.Button$ButtonStyle", "arc.scene.ui.ButtonGroup", "arc.scene.ui.CheckBox", "arc.scene.ui.CheckBox$CheckBoxStyle", "arc.scene.ui.ColorImage", "arc.scene.ui.Dialog", "arc.scene.ui.Dialog$DialogStyle", "arc.scene.ui.Image", "arc.scene.ui.ImageButton", "arc.scene.ui.ImageButton$ImageButtonStyle", "arc.scene.ui.KeybindDialog", "arc.scene.ui.KeybindDialog$KeybindDialogStyle", "arc.scene.ui.Label", "arc.scene.ui.Label$LabelStyle", "arc.scene.ui.ProgressBar", "arc.scene.ui.ProgressBar$ProgressBarStyle", "arc.scene.ui.ScrollPane", "arc.scene.ui.ScrollPane$ScrollPaneStyle", "arc.scene.ui.SettingsDialog", "arc.scene.ui.SettingsDialog$SettingsTable", "arc.scene.ui.SettingsDialog$SettingsTable$CheckSetting", "arc.scene.ui.SettingsDialog$SettingsTable$Setting", "arc.scene.ui.SettingsDialog$SettingsTable$SliderSetting", "arc.scene.ui.SettingsDialog$StringProcessor", "arc.scene.ui.Slider", "arc.scene.ui.Slider$SliderStyle", "arc.scene.ui.TextArea", "arc.scene.ui.TextArea$TextAreaListener", "arc.scene.ui.TextButton", "arc.scene.ui.TextButton$TextButtonStyle", "arc.scene.ui.TextField", "arc.scene.ui.TextField$DefaultOnscreenKeyboard", "arc.scene.ui.TextField$OnscreenKeyboard", "arc.scene.ui.TextField$TextFieldClickListener", "arc.scene.ui.TextField$TextFieldFilter", "arc.scene.ui.TextField$TextFieldListener", "arc.scene.ui.TextField$TextFieldStyle", "arc.scene.ui.TextField$TextFieldValidator", "arc.scene.ui.Tooltip", "arc.scene.ui.Tooltip$Tooltips", "arc.scene.ui.Touchpad", "arc.scene.ui.Touchpad$TouchpadStyle", "arc.scene.ui.TreeElement", "arc.scene.ui.TreeElement$Node", "arc.scene.ui.TreeElement$TreeStyle", "arc.scene.ui.layout.Cell", "arc.scene.ui.layout.Collapser", "arc.scene.ui.layout.HorizontalGroup", "arc.scene.ui.layout.Scl", "arc.scene.ui.layout.Stack", "arc.scene.ui.layout.Table", "arc.scene.ui.layout.Table$DrawRect", "arc.scene.ui.layout.VerticalGroup", "arc.scene.ui.layout.WidgetGroup", "arc.scene.utils.ArraySelection", "arc.scene.utils.Cullable", "arc.scene.utils.Disableable", "arc.scene.utils.DragAndDrop", "arc.scene.utils.DragAndDrop$Payload", "arc.scene.utils.DragAndDrop$Source", "arc.scene.utils.DragAndDrop$Target", "arc.scene.utils.Elements", "arc.scene.utils.Layout", "arc.scene.utils.Selection", "arc.struct.Array", "arc.struct.Array$ArrayIterable", "arc.struct.ArrayMap", "arc.struct.ArrayMap$Entries", "arc.struct.ArrayMap$Keys", "arc.struct.ArrayMap$Values", "arc.struct.AtomicQueue", "arc.struct.BinaryHeap", "arc.struct.BinaryHeap$Node", "arc.struct.Bits", "arc.struct.BooleanArray", "arc.struct.ByteArray", "arc.struct.CharArray", "arc.struct.ComparableTimSort", "arc.struct.DelayedRemovalArray", "arc.struct.EnumSet", "arc.struct.EnumSet$EnumSetIterator", "arc.struct.FloatArray", "arc.struct.GridBits", "arc.struct.GridMap", "arc.struct.IdentityMap", "arc.struct.IdentityMap$Entries", "arc.struct.IdentityMap$Entry", "arc.struct.IdentityMap$Keys", "arc.struct.IdentityMap$Values", "arc.struct.IntArray", "arc.struct.IntFloatMap", "arc.struct.IntFloatMap$Entries", "arc.struct.IntFloatMap$Entry", "arc.struct.IntFloatMap$Keys", "arc.struct.IntFloatMap$Values", "arc.struct.IntIntMap", "arc.struct.IntIntMap$Entries", "arc.struct.IntIntMap$Entry", "arc.struct.IntIntMap$Keys", "arc.struct.IntIntMap$Values", "arc.struct.IntMap", "arc.struct.IntMap$Entries", "arc.struct.IntMap$Entry", "arc.struct.IntMap$Keys", "arc.struct.IntMap$Values", "arc.struct.IntQueue", "arc.struct.IntSet", "arc.struct.IntSet$IntSetIterator", "arc.struct.LongArray", "arc.struct.LongMap", "arc.struct.LongMap$Entries", "arc.struct.LongMap$Entry", "arc.struct.LongMap$Keys", "arc.struct.LongMap$Values", "arc.struct.LongQueue", "arc.struct.ObjectFloatMap", "arc.struct.ObjectFloatMap$Entries", "arc.struct.ObjectFloatMap$Entry", "arc.struct.ObjectFloatMap$Keys", "arc.struct.ObjectFloatMap$Values", "arc.struct.ObjectIntMap", "arc.struct.ObjectIntMap$Entries", "arc.struct.ObjectIntMap$Entry", "arc.struct.ObjectIntMap$Keys", "arc.struct.ObjectIntMap$Values", "arc.struct.ObjectMap", "arc.struct.ObjectMap$Entries", "arc.struct.ObjectMap$Entry", "arc.struct.ObjectMap$Keys", "arc.struct.ObjectMap$Values", "arc.struct.ObjectSet", "arc.struct.ObjectSet$ObjectSetIterator", "arc.struct.OrderedMap", "arc.struct.OrderedMap$OrderedMapEntries", "arc.struct.OrderedMap$OrderedMapKeys", "arc.struct.OrderedMap$OrderedMapValues", "arc.struct.OrderedSet", "arc.struct.OrderedSet$OrderedSetIterator", "arc.struct.PooledLinkedList", "arc.struct.PooledLinkedList$Item", "arc.struct.Queue", "arc.struct.Queue$QueueIterable", "arc.struct.ShortArray", "arc.struct.SnapshotArray", "arc.struct.Sort", "arc.struct.SortedIntList", "arc.struct.SortedIntList$Iterator", "arc.struct.SortedIntList$Node", "arc.struct.StringMap", "arc.struct.TimSort", "arc.util.I18NBundle", "arc.util.Interval", "arc.util.Time", "java.io.DataInput", "java.io.DataInputStream", "java.io.DataOutput", "java.io.DataOutputStream", "java.io.PrintStream", "java.lang.Boolean", "java.lang.Byte", "java.lang.Character", "java.lang.Double", "java.lang.Float", "java.lang.Integer", "java.lang.Long", "java.lang.Object", "java.lang.Runnable", "java.lang.Short", "java.lang.String", "java.lang.System", "mindustry.Vars", "mindustry.ai.BlockIndexer", "mindustry.ai.Pathfinder", "mindustry.ai.Pathfinder$PathData", "mindustry.ai.Pathfinder$PathTarget", "mindustry.ai.Pathfinder$PathTileStruct", "mindustry.ai.WaveSpawner", "mindustry.content.Blocks", "mindustry.content.Bullets", "mindustry.content.Fx", "mindustry.content.Items", "mindustry.content.Liquids", "mindustry.content.Loadouts", "mindustry.content.Mechs", "mindustry.content.StatusEffects", "mindustry.content.TechTree", "mindustry.content.TechTree$TechNode", "mindustry.content.TypeIDs", "mindustry.content.UnitTypes", "mindustry.content.Zones", "mindustry.core.ContentLoader", "mindustry.core.Control", "mindustry.core.FileTree", "mindustry.core.GameState", "mindustry.core.GameState$State", "mindustry.core.Logic", "mindustry.core.NetServer$TeamAssigner", "mindustry.core.Platform", "mindustry.core.Renderer", "mindustry.core.UI", "mindustry.core.Version", "mindustry.core.World", "mindustry.core.World$Raycaster", "mindustry.ctype.Content", "mindustry.ctype.Content$ModContentInfo", "mindustry.ctype.ContentList", "mindustry.ctype.ContentType", "mindustry.ctype.MappableContent", "mindustry.ctype.UnlockableContent", "mindustry.editor.DrawOperation", "mindustry.editor.DrawOperation$OpType", "mindustry.editor.DrawOperation$TileOpStruct", "mindustry.editor.EditorTile", "mindustry.editor.EditorTool", "mindustry.editor.MapEditor", "mindustry.editor.MapEditor$Context", "mindustry.editor.MapEditorDialog", "mindustry.editor.MapGenerateDialog", "mindustry.editor.MapInfoDialog", "mindustry.editor.MapLoadDialog", "mindustry.editor.MapRenderer", "mindustry.editor.MapResizeDialog", "mindustry.editor.MapSaveDialog", "mindustry.editor.MapView", "mindustry.editor.OperationStack", "mindustry.editor.WaveInfoDialog", "mindustry.entities.Damage", "mindustry.entities.Damage$PropCellStruct", "mindustry.entities.Effects", "mindustry.entities.Effects$Effect", "mindustry.entities.Effects$EffectContainer", "mindustry.entities.Effects$EffectProvider", "mindustry.entities.Effects$EffectRenderer", "mindustry.entities.Effects$ScreenshakeProvider", "mindustry.entities.Entities", "mindustry.entities.EntityCollisions", "mindustry.entities.EntityGroup", "mindustry.entities.Predict", "mindustry.entities.TargetPriority", "mindustry.entities.Units", "mindustry.entities.bullet.ArtilleryBulletType", "mindustry.entities.bullet.BasicBulletType", "mindustry.entities.bullet.BombBulletType", "mindustry.entities.bullet.BulletType", "mindustry.entities.bullet.FlakBulletType", "mindustry.entities.bullet.HealBulletType", "mindustry.entities.bullet.LiquidBulletType", "mindustry.entities.bullet.MassDriverBolt", "mindustry.entities.bullet.MissileBulletType", "mindustry.entities.effect.Decal", "mindustry.entities.effect.Fire", "mindustry.entities.effect.GroundEffectEntity", "mindustry.entities.effect.GroundEffectEntity$GroundEffect", "mindustry.entities.effect.ItemTransfer", "mindustry.entities.effect.Lightning", "mindustry.entities.effect.Puddle", "mindustry.entities.effect.RubbleDecal", "mindustry.entities.effect.ScorchDecal", "mindustry.entities.traits.AbsorbTrait", "mindustry.entities.traits.BelowLiquidTrait", "mindustry.entities.traits.BuilderMinerTrait", "mindustry.entities.traits.BuilderTrait", "mindustry.entities.traits.BuilderTrait$BuildDataStatic", "mindustry.entities.traits.BuilderTrait$BuildRequest", "mindustry.entities.traits.DamageTrait", "mindustry.entities.traits.DrawTrait", "mindustry.entities.traits.Entity", "mindustry.entities.traits.HealthTrait", "mindustry.entities.traits.KillerTrait", "mindustry.entities.traits.MinerTrait", "mindustry.entities.traits.MoveTrait", "mindustry.entities.traits.SaveTrait", "mindustry.entities.traits.Saveable", "mindustry.entities.traits.ScaleTrait", "mindustry.entities.traits.ShooterTrait", "mindustry.entities.traits.SolidTrait", "mindustry.entities.traits.SpawnerTrait", "mindustry.entities.traits.SyncTrait", "mindustry.entities.traits.TargetTrait", "mindustry.entities.traits.TeamTrait", "mindustry.entities.traits.TimeTrait", "mindustry.entities.traits.TypeTrait", "mindustry.entities.traits.VelocityTrait", "mindustry.entities.type.BaseEntity", "mindustry.entities.type.BaseUnit", "mindustry.entities.type.Bullet", "mindustry.entities.type.DestructibleEntity", "mindustry.entities.type.EffectEntity", "mindustry.entities.type.Player", "mindustry.entities.type.SolidEntity", "mindustry.entities.type.TileEntity", "mindustry.entities.type.TimedEntity", "mindustry.entities.type.Unit", "mindustry.entities.type.base.BaseDrone", "mindustry.entities.type.base.BuilderDrone", "mindustry.entities.type.base.FlyingUnit", "mindustry.entities.type.base.GroundUnit", "mindustry.entities.type.base.HoverUnit", "mindustry.entities.type.base.MinerDrone", "mindustry.entities.type.base.RepairDrone", "mindustry.entities.units.StateMachine", "mindustry.entities.units.Statuses", "mindustry.entities.units.Statuses$StatusEntry", "mindustry.entities.units.UnitCommand", "mindustry.entities.units.UnitDrops", "mindustry.entities.units.UnitState", "mindustry.game.DefaultWaves", "mindustry.game.Difficulty", "mindustry.game.EventType", "mindustry.game.EventType$BlockBuildBeginEvent", "mindustry.game.EventType$BlockBuildEndEvent", "mindustry.game.EventType$BlockDestroyEvent", "mindustry.game.EventType$BlockInfoEvent", "mindustry.game.EventType$BuildSelectEvent", "mindustry.game.EventType$ClientLoadEvent", "mindustry.game.EventType$CommandIssueEvent", "mindustry.game.EventType$ContentReloadEvent", "mindustry.game.EventType$CoreItemDeliverEvent", "mindustry.game.EventType$DepositEvent", "mindustry.game.EventType$DisposeEvent", "mindustry.game.EventType$GameOverEvent", "mindustry.game.EventType$LaunchEvent", "mindustry.game.EventType$LaunchItemEvent", "mindustry.game.EventType$LineConfirmEvent", "mindustry.game.EventType$LoseEvent", "mindustry.game.EventType$MapMakeEvent", "mindustry.game.EventType$MapPublishEvent", "mindustry.game.EventType$MechChangeEvent", "mindustry.game.EventType$PlayEvent", "mindustry.game.EventType$PlayerBanEvent", "mindustry.game.EventType$PlayerChatEvent", "mindustry.game.EventType$PlayerConnect", "mindustry.game.EventType$PlayerIpBanEvent", "mindustry.game.EventType$PlayerIpUnbanEvent", "mindustry.game.EventType$PlayerJoin", "mindustry.game.EventType$PlayerLeave", "mindustry.game.EventType$PlayerUnbanEvent", "mindustry.game.EventType$ResearchEvent", "mindustry.game.EventType$ResetEvent", "mindustry.game.EventType$ResizeEvent", "mindustry.game.EventType$ServerLoadEvent", "mindustry.game.EventType$StateChangeEvent", "mindustry.game.EventType$TapConfigEvent", "mindustry.game.EventType$TapEvent", "mindustry.game.EventType$TileChangeEvent", "mindustry.game.EventType$Trigger", "mindustry.game.EventType$TurretAmmoDeliverEvent", "mindustry.game.EventType$UnitCreateEvent", "mindustry.game.EventType$UnitDestroyEvent", "mindustry.game.EventType$UnlockEvent", "mindustry.game.EventType$WaveEvent", "mindustry.game.EventType$WinEvent", "mindustry.game.EventType$WithdrawEvent", "mindustry.game.EventType$WorldLoadEvent", "mindustry.game.EventType$ZoneConfigureCompleteEvent", "mindustry.game.EventType$ZoneRequireCompleteEvent", "mindustry.game.Gamemode", "mindustry.game.GlobalData", "mindustry.game.LoopControl", "mindustry.game.MusicControl", "mindustry.game.Objective", "mindustry.game.Objectives", "mindustry.game.Objectives$Launched", "mindustry.game.Objectives$Unlock", "mindustry.game.Objectives$Wave", "mindustry.game.Objectives$ZoneObjective", "mindustry.game.Objectives$ZoneWave", "mindustry.game.Rules", "mindustry.game.Saves", "mindustry.game.Saves$SaveSlot", "mindustry.game.Schematic", "mindustry.game.Schematic$Stile", "mindustry.game.Schematics", "mindustry.game.SoundLoop", "mindustry.game.SpawnGroup", "mindustry.game.Stats", "mindustry.game.Stats$Rank", "mindustry.game.Stats$RankResult", "mindustry.game.Team", "mindustry.game.Teams", "mindustry.game.Teams$BrokenBlock", "mindustry.game.Teams$TeamData", "mindustry.game.Tutorial", "mindustry.game.Tutorial$TutorialStage", "mindustry.gen.BufferItem", "mindustry.gen.Call", "mindustry.gen.Call", "mindustry.gen.Icon", "mindustry.gen.Icon", "mindustry.gen.MethodHash", "mindustry.gen.Musics", "mindustry.gen.Musics", "mindustry.gen.PathTile", "mindustry.gen.PropCell", "mindustry.gen.RemoteReadClient", "mindustry.gen.RemoteReadServer", "mindustry.gen.Serialization", "mindustry.gen.Sounds", "mindustry.gen.Sounds", "mindustry.gen.Tex", "mindustry.gen.Tex", "mindustry.gen.TileOp", "mindustry.graphics.BlockRenderer", "mindustry.graphics.Bloom", "mindustry.graphics.CacheLayer", "mindustry.graphics.Drawf", "mindustry.graphics.FloorRenderer", "mindustry.graphics.IndexedRenderer", "mindustry.graphics.Layer", "mindustry.graphics.LightRenderer", "mindustry.graphics.MenuRenderer", "mindustry.graphics.MinimapRenderer", "mindustry.graphics.MultiPacker", "mindustry.graphics.MultiPacker$PageType", "mindustry.graphics.OverlayRenderer", "mindustry.graphics.Pal", "mindustry.graphics.Pixelator", "mindustry.graphics.Shaders", "mindustry.input.Binding", "mindustry.input.DesktopInput", "mindustry.input.InputHandler", "mindustry.input.InputHandler$PlaceLine", "mindustry.input.MobileInput", "mindustry.input.PlaceMode", "mindustry.input.Placement", "mindustry.input.Placement$DistanceHeuristic", "mindustry.input.Placement$NormalizeDrawResult", "mindustry.input.Placement$NormalizeResult", "mindustry.input.Placement$TileHueristic", "mindustry.maps.Map", "mindustry.maps.Maps", "mindustry.maps.Maps$MapProvider", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.Maps$ShuffleMode", "mindustry.maps.filters.BlendFilter", "mindustry.maps.filters.ClearFilter", "mindustry.maps.filters.DistortFilter", "mindustry.maps.filters.FilterOption", "mindustry.maps.filters.FilterOption$BlockOption", "mindustry.maps.filters.FilterOption$SliderOption", "mindustry.maps.filters.GenerateFilter", "mindustry.maps.filters.GenerateFilter$GenerateInput", "mindustry.maps.filters.GenerateFilter$GenerateInput$TileProvider", "mindustry.maps.filters.MedianFilter", "mindustry.maps.filters.MirrorFilter", "mindustry.maps.filters.NoiseFilter", "mindustry.maps.filters.OreFilter", "mindustry.maps.filters.OreMedianFilter", "mindustry.maps.filters.RiverNoiseFilter", "mindustry.maps.filters.ScatterFilter", "mindustry.maps.filters.TerrainFilter", "mindustry.maps.generators.BasicGenerator", "mindustry.maps.generators.BasicGenerator$DistanceHeuristic", "mindustry.maps.generators.BasicGenerator$TileHueristic", "mindustry.maps.generators.Generator", "mindustry.maps.generators.MapGenerator", "mindustry.maps.generators.MapGenerator$Decoration", "mindustry.maps.generators.RandomGenerator", "mindustry.maps.zonegen.DesertWastesGenerator", "mindustry.maps.zonegen.OvergrowthGenerator", "mindustry.type.Category", "mindustry.type.ErrorContent", "mindustry.type.Item", "mindustry.type.ItemStack", "mindustry.type.ItemType", "mindustry.type.Liquid", "mindustry.type.LiquidStack", "mindustry.type.Mech", "mindustry.type.Publishable", "mindustry.type.StatusEffect", "mindustry.type.StatusEffect$TransitionHandler", "mindustry.type.TypeID", "mindustry.type.UnitType", "mindustry.type.Weapon", "mindustry.type.WeatherEvent", "mindustry.type.Zone", "mindustry.ui.Bar", "mindustry.ui.BorderImage", "mindustry.ui.Cicon", "mindustry.ui.ContentDisplay", "mindustry.ui.Fonts", "mindustry.ui.GridImage", "mindustry.ui.IconSize", "mindustry.ui.IntFormat", "mindustry.ui.ItemDisplay", "mindustry.ui.ItemImage", "mindustry.ui.ItemsDisplay", "mindustry.ui.Links", "mindustry.ui.Links$LinkEntry", "mindustry.ui.LiquidDisplay", "mindustry.ui.Minimap", "mindustry.ui.MobileButton", "mindustry.ui.MultiReqImage", "mindustry.ui.ReqImage", "mindustry.ui.Styles", "mindustry.ui.dialogs.AboutDialog", "mindustry.ui.dialogs.AdminsDialog", "mindustry.ui.dialogs.BansDialog", "mindustry.ui.dialogs.ColorPicker", "mindustry.ui.dialogs.ContentInfoDialog", "mindustry.ui.dialogs.ControlsDialog", "mindustry.ui.dialogs.CustomGameDialog", "mindustry.ui.dialogs.CustomRulesDialog", "mindustry.ui.dialogs.DatabaseDialog", "mindustry.ui.dialogs.DeployDialog", "mindustry.ui.dialogs.DeployDialog$View", "mindustry.ui.dialogs.DeployDialog$ZoneNode", "mindustry.ui.dialogs.DiscordDialog", "mindustry.ui.dialogs.FileChooser", "mindustry.ui.dialogs.FileChooser$FileHistory", "mindustry.ui.dialogs.FloatingDialog", "mindustry.ui.dialogs.GameOverDialog", "mindustry.ui.dialogs.HostDialog", "mindustry.ui.dialogs.JoinDialog", "mindustry.ui.dialogs.JoinDialog$Server", "mindustry.ui.dialogs.LanguageDialog", "mindustry.ui.dialogs.LoadDialog", "mindustry.ui.dialogs.LoadoutDialog", "mindustry.ui.dialogs.MapPlayDialog", "mindustry.ui.dialogs.MapsDialog", "mindustry.ui.dialogs.MinimapDialog", "mindustry.ui.dialogs.ModsDialog", "mindustry.ui.dialogs.PaletteDialog", "mindustry.ui.dialogs.PausedDialog", "mindustry.ui.dialogs.SaveDialog", "mindustry.ui.dialogs.SchematicsDialog", "mindustry.ui.dialogs.SchematicsDialog$SchematicImage", "mindustry.ui.dialogs.SchematicsDialog$SchematicInfoDialog", "mindustry.ui.dialogs.SettingsMenuDialog", "mindustry.ui.dialogs.TechTreeDialog", "mindustry.ui.dialogs.TechTreeDialog$LayoutNode", "mindustry.ui.dialogs.TechTreeDialog$TechTreeNode", "mindustry.ui.dialogs.TechTreeDialog$View", "mindustry.ui.dialogs.TraceDialog", "mindustry.ui.dialogs.ZoneInfoDialog", "mindustry.ui.fragments.BlockConfigFragment", "mindustry.ui.fragments.BlockInventoryFragment", "mindustry.ui.fragments.ChatFragment", "mindustry.ui.fragments.FadeInFragment", "mindustry.ui.fragments.Fragment", "mindustry.ui.fragments.HudFragment", "mindustry.ui.fragments.LoadingFragment", "mindustry.ui.fragments.MenuFragment", "mindustry.ui.fragments.MinimapFragment", "mindustry.ui.fragments.OverlayFragment", "mindustry.ui.fragments.PlacementFragment", "mindustry.ui.fragments.PlayerListFragment", "mindustry.ui.fragments.ScriptConsoleFragment", "mindustry.ui.layout.BranchTreeLayout", "mindustry.ui.layout.BranchTreeLayout$TreeAlignment", "mindustry.ui.layout.BranchTreeLayout$TreeLocation", "mindustry.ui.layout.RadialTreeLayout", "mindustry.ui.layout.TreeLayout", "mindustry.ui.layout.TreeLayout$TreeNode", "mindustry.world.Block", "mindustry.world.BlockStorage", "mindustry.world.Build", "mindustry.world.CachedTile", "mindustry.world.DirectionalItemBuffer", "mindustry.world.DirectionalItemBuffer$BufferItemStruct", "mindustry.world.Edges", "mindustry.world.ItemBuffer", "mindustry.world.LegacyColorMapper", "mindustry.world.LegacyColorMapper$LegacyBlock", "mindustry.world.Pos", "mindustry.world.StaticTree", "mindustry.world.Tile", "mindustry.world.WorldContext", "mindustry.world.blocks.Attributes", "mindustry.world.blocks.Autotiler", "mindustry.world.blocks.Autotiler$AutotilerHolder", "mindustry.world.blocks.BlockPart", "mindustry.world.blocks.BuildBlock", "mindustry.world.blocks.BuildBlock$BuildEntity", "mindustry.world.blocks.DoubleOverlayFloor", "mindustry.world.blocks.Floor", "mindustry.world.blocks.ItemSelection", "mindustry.world.blocks.LiquidBlock", "mindustry.world.blocks.OreBlock", "mindustry.world.blocks.OverlayFloor", "mindustry.world.blocks.PowerBlock", "mindustry.world.blocks.RespawnBlock", "mindustry.world.blocks.Rock", "mindustry.world.blocks.StaticWall", "mindustry.world.blocks.TreeBlock", "mindustry.world.blocks.defense.DeflectorWall", "mindustry.world.blocks.defense.DeflectorWall$DeflectorEntity", "mindustry.world.blocks.defense.Door", "mindustry.world.blocks.defense.Door$DoorEntity", "mindustry.world.blocks.defense.ForceProjector", "mindustry.world.blocks.defense.ForceProjector$ForceEntity", "mindustry.world.blocks.defense.ForceProjector$ShieldEntity", "mindustry.world.blocks.defense.MendProjector", "mindustry.world.blocks.defense.MendProjector$MendEntity", "mindustry.world.blocks.defense.OverdriveProjector", "mindustry.world.blocks.defense.OverdriveProjector$OverdriveEntity", "mindustry.world.blocks.defense.ShockMine", "mindustry.world.blocks.defense.SurgeWall", "mindustry.world.blocks.defense.Wall", "mindustry.world.blocks.defense.turrets.ArtilleryTurret", "mindustry.world.blocks.defense.turrets.BurstTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret", "mindustry.world.blocks.defense.turrets.ChargeTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.CooledTurret", "mindustry.world.blocks.defense.turrets.DoubleTurret", "mindustry.world.blocks.defense.turrets.ItemTurret", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemEntry", "mindustry.world.blocks.defense.turrets.ItemTurret$ItemTurretEntity", "mindustry.world.blocks.defense.turrets.LaserTurret", "mindustry.world.blocks.defense.turrets.LaserTurret$LaserTurretEntity", "mindustry.world.blocks.defense.turrets.LiquidTurret", "mindustry.world.blocks.defense.turrets.PowerTurret", "mindustry.world.blocks.defense.turrets.Turret", "mindustry.world.blocks.defense.turrets.Turret$AmmoEntry", "mindustry.world.blocks.defense.turrets.Turret$TurretEntity", "mindustry.world.blocks.distribution.ArmoredConveyor", "mindustry.world.blocks.distribution.BufferedItemBridge", "mindustry.world.blocks.distribution.BufferedItemBridge$BufferedItemBridgeEntity", "mindustry.world.blocks.distribution.Conveyor", "mindustry.world.blocks.distribution.Conveyor$ConveyorEntity", "mindustry.world.blocks.distribution.Conveyor$ItemPos", "mindustry.world.blocks.distribution.ExtendingItemBridge", "mindustry.world.blocks.distribution.ItemBridge", "mindustry.world.blocks.distribution.ItemBridge$ItemBridgeEntity", "mindustry.world.blocks.distribution.Junction", "mindustry.world.blocks.distribution.Junction$JunctionEntity", "mindustry.world.blocks.distribution.MassDriver", "mindustry.world.blocks.distribution.MassDriver$DriverBulletData", "mindustry.world.blocks.distribution.MassDriver$DriverState", "mindustry.world.blocks.distribution.MassDriver$MassDriverEntity", "mindustry.world.blocks.distribution.OverflowGate", "mindustry.world.blocks.distribution.OverflowGate$OverflowGateEntity", "mindustry.world.blocks.distribution.Router", "mindustry.world.blocks.distribution.Router$RouterEntity", "mindustry.world.blocks.distribution.Sorter", "mindustry.world.blocks.distribution.Sorter$SorterEntity", "mindustry.world.blocks.liquid.ArmoredConduit", "mindustry.world.blocks.liquid.Conduit", "mindustry.world.blocks.liquid.Conduit$ConduitEntity", "mindustry.world.blocks.liquid.LiquidBridge", "mindustry.world.blocks.liquid.LiquidExtendingBridge", "mindustry.world.blocks.liquid.LiquidJunction", "mindustry.world.blocks.liquid.LiquidOverflowGate", "mindustry.world.blocks.liquid.LiquidRouter", "mindustry.world.blocks.liquid.LiquidTank", "mindustry.world.blocks.logic.LogicBlock", "mindustry.world.blocks.logic.MessageBlock", "mindustry.world.blocks.logic.MessageBlock$MessageBlockEntity", "mindustry.world.blocks.power.Battery", "mindustry.world.blocks.power.BurnerGenerator", "mindustry.world.blocks.power.ConditionalConsumePower", "mindustry.world.blocks.power.DecayGenerator", "mindustry.world.blocks.power.ImpactReactor", "mindustry.world.blocks.power.ImpactReactor$FusionReactorEntity", "mindustry.world.blocks.power.ItemLiquidGenerator", "mindustry.world.blocks.power.ItemLiquidGenerator$ItemLiquidGeneratorEntity", "mindustry.world.blocks.power.LightBlock", "mindustry.world.blocks.power.LightBlock$LightEntity", "mindustry.world.blocks.power.NuclearReactor", "mindustry.world.blocks.power.NuclearReactor$NuclearReactorEntity", "mindustry.world.blocks.power.PowerDiode", "mindustry.world.blocks.power.PowerDistributor", "mindustry.world.blocks.power.PowerGenerator", "mindustry.world.blocks.power.PowerGenerator$GeneratorEntity", "mindustry.world.blocks.power.PowerGraph", "mindustry.world.blocks.power.PowerNode", "mindustry.world.blocks.power.SingleTypeGenerator", "mindustry.world.blocks.power.SolarGenerator", "mindustry.world.blocks.power.ThermalGenerator", "mindustry.world.blocks.production.Cultivator", "mindustry.world.blocks.production.Cultivator$CultivatorEntity", "mindustry.world.blocks.production.Drill", "mindustry.world.blocks.production.Drill$DrillEntity", "mindustry.world.blocks.production.Fracker", "mindustry.world.blocks.production.Fracker$FrackerEntity", "mindustry.world.blocks.production.GenericCrafter", "mindustry.world.blocks.production.GenericCrafter$GenericCrafterEntity", "mindustry.world.blocks.production.GenericSmelter", "mindustry.world.blocks.production.Incinerator", "mindustry.world.blocks.production.Incinerator$IncineratorEntity", "mindustry.world.blocks.production.LiquidConverter", "mindustry.world.blocks.production.Pump", "mindustry.world.blocks.production.Separator", "mindustry.world.blocks.production.SolidPump", "mindustry.world.blocks.production.SolidPump$SolidPumpEntity", "mindustry.world.blocks.sandbox.ItemSource", "mindustry.world.blocks.sandbox.ItemSource$ItemSourceEntity", "mindustry.world.blocks.sandbox.ItemVoid", "mindustry.world.blocks.sandbox.LiquidSource", "mindustry.world.blocks.sandbox.LiquidSource$LiquidSourceEntity", "mindustry.world.blocks.sandbox.PowerSource", "mindustry.world.blocks.sandbox.PowerVoid", "mindustry.world.blocks.storage.CoreBlock", "mindustry.world.blocks.storage.CoreBlock$CoreEntity", "mindustry.world.blocks.storage.LaunchPad", "mindustry.world.blocks.storage.StorageBlock", "mindustry.world.blocks.storage.StorageBlock$StorageBlockEntity", "mindustry.world.blocks.storage.Unloader", "mindustry.world.blocks.storage.Unloader$UnloaderEntity", "mindustry.world.blocks.storage.Vault", "mindustry.world.blocks.units.CommandCenter", "mindustry.world.blocks.units.CommandCenter$CommandCenterEntity", "mindustry.world.blocks.units.MechPad", "mindustry.world.blocks.units.MechPad$MechFactoryEntity", "mindustry.world.blocks.units.RallyPoint", "mindustry.world.blocks.units.RepairPoint", "mindustry.world.blocks.units.RepairPoint$RepairPointEntity", "mindustry.world.blocks.units.UnitFactory", "mindustry.world.blocks.units.UnitFactory$UnitFactoryEntity", "mindustry.world.consumers.Consume", "mindustry.world.consumers.ConsumeItemFilter", "mindustry.world.consumers.ConsumeItems", "mindustry.world.consumers.ConsumeLiquid", "mindustry.world.consumers.ConsumeLiquidBase", "mindustry.world.consumers.ConsumeLiquidFilter", "mindustry.world.consumers.ConsumePower", "mindustry.world.consumers.ConsumeType", "mindustry.world.consumers.Consumers", "mindustry.world.meta.Attribute", "mindustry.world.meta.BlockBars", "mindustry.world.meta.BlockFlag", "mindustry.world.meta.BlockGroup", "mindustry.world.meta.BlockStat", "mindustry.world.meta.BlockStats", "mindustry.world.meta.BuildVisibility", "mindustry.world.meta.PowerType", "mindustry.world.meta.Producers", "mindustry.world.meta.StatCategory", "mindustry.world.meta.StatUnit", "mindustry.world.meta.StatValue", "mindustry.world.meta.values.AmmoListValue", "mindustry.world.meta.values.BooleanValue", "mindustry.world.meta.values.BoosterListValue", "mindustry.world.meta.values.ItemFilterValue", "mindustry.world.meta.values.ItemListValue", "mindustry.world.meta.values.LiquidFilterValue", "mindustry.world.meta.values.LiquidValue", "mindustry.world.meta.values.NumberValue", "mindustry.world.meta.values.StringValue", "mindustry.world.modules.BlockModule", "mindustry.world.modules.ConsumeModule", "mindustry.world.modules.ItemModule", "mindustry.world.modules.ItemModule$ItemCalculator", "mindustry.world.modules.ItemModule$ItemConsumer", "mindustry.world.modules.LiquidModule", "mindustry.world.modules.LiquidModule$LiquidCalculator", "mindustry.world.modules.LiquidModule$LiquidConsumer", "mindustry.world.modules.PowerModule", "mindustry.world.producers.Produce", "mindustry.world.producers.ProduceItem"); -} \ No newline at end of file diff --git a/core/src/mindustry/mod/ContentParser.java b/core/src/mindustry/mod/ContentParser.java index aa6048d833..9d610512df 100644 --- a/core/src/mindustry/mod/ContentParser.java +++ b/core/src/mindustry/mod/ContentParser.java @@ -4,11 +4,11 @@ import arc.*; import arc.assets.*; import arc.audio.*; import arc.audio.mock.*; -import arc.struct.Array; -import arc.struct.*; import arc.files.*; import arc.func.*; import arc.graphics.*; +import arc.struct.Array; +import arc.struct.*; import arc.util.ArcAnnotate.*; import arc.util.*; import arc.util.serialization.*; @@ -18,9 +18,8 @@ import mindustry.*; import mindustry.content.*; import mindustry.content.TechTree.*; import mindustry.ctype.*; -import mindustry.entities.Effects.*; +import mindustry.entities.*; import mindustry.entities.bullet.*; -import mindustry.entities.type.*; import mindustry.game.*; import mindustry.game.Objectives.*; import mindustry.gen.*; @@ -275,13 +274,14 @@ public class ContentParser{ return block; }, - ContentType.unit, (TypeParser)(mod, name, value) -> { + ContentType.unit, (TypeParser)(mod, name, value) -> { readBundle(ContentType.unit, name, value); - UnitType unit; + //TODO fix + UnitDef unit; if(locate(ContentType.unit, name) == null){ - Class type = resolve(legacyUnitMap.get(Strings.capitalize(getType(value)), getType(value)), "mindustry.entities.type.base"); - unit = new UnitType(mod + "-" + name, supply(type)); + Class type = resolve(legacyUnitMap.get(Strings.capitalize(getType(value)), getType(value)), "mindustry.entities.type.base"); + unit = new UnitDef(mod + "-" + name); }else{ unit = locate(ContentType.unit, name); } @@ -293,7 +293,6 @@ public class ContentParser{ }, ContentType.item, parser(ContentType.item, Item::new), ContentType.liquid, parser(ContentType.liquid, Liquid::new), - ContentType.mech, parser(ContentType.mech, Mech::new), ContentType.zone, parser(ContentType.zone, Zone::new) ); diff --git a/core/src/mindustry/mod/Mods.java b/core/src/mindustry/mod/Mods.java index fd24040542..1ef88311c5 100644 --- a/core/src/mindustry/mod/Mods.java +++ b/core/src/mindustry/mod/Mods.java @@ -78,7 +78,7 @@ public class Mods implements Loadable{ public void importMod(Fi file) throws IOException{ Fi dest = modDirectory.child(file.name()); if(dest.exists()){ - throw new IOException("A mod with the same filename already exists!"); + throw new IOException("A file with the same name already exists in the mod folder!"); } file.copyTo(dest); @@ -246,7 +246,7 @@ public class Mods implements Loadable{ try{ LoadedMod mod = loadMod(file); mods.add(mod); - }catch(Exception e){ + }catch(Throwable e){ Log.err("Failed to load mod file {0}. Skipping.", file); Log.err(e); } @@ -258,7 +258,7 @@ public class Mods implements Loadable{ LoadedMod mod = loadMod(file); mods.add(mod); mod.addSteamID(file.name()); - }catch(Exception e){ + }catch(Throwable e){ Log.err("Failed to load mod workshop file {0}. Skipping.", file); Log.err(e); } @@ -354,7 +354,7 @@ public class Mods implements Loadable{ for(Fi file : bundles.getOr(locale, Array::new)){ try{ PropertiesUtils.load(bundle.getProperties(), file.reader()); - }catch(Exception e){ + }catch(Throwable e){ Log.err("Error loading bundle: " + file + "/" + locale, e); } } diff --git a/core/src/mindustry/mod/Scripts.java b/core/src/mindustry/mod/Scripts.java index 19a94fca36..94acd92eb4 100644 --- a/core/src/mindustry/mod/Scripts.java +++ b/core/src/mindustry/mod/Scripts.java @@ -10,7 +10,10 @@ import mindustry.mod.Mods.*; import org.mozilla.javascript.*; public class Scripts implements Disposable{ - private final Array blacklist = Array.with("net", "classaccess", ".io", "io.", "files", "reflect"); + private final Array blacklist = Array.with("net", "files", "reflect", "javax", "rhino", "file", "channels", "jdk", + "runtime", "util.os", "rmi", "security", "org.", "sun.", "beans", "sql", "http", "exec", "compiler", "process", "system", + ".awt", "socket", "classloader", "oracle", "invoke"); + private final Array whitelist = Array.with("mindustry.net"); private final Context context; private final String wrapper; private Scriptable scope; @@ -20,7 +23,7 @@ public class Scripts implements Disposable{ Time.mark(); context = Vars.platform.getScriptContext(); - context.setClassShutter(type -> !blacklist.contains(type.toLowerCase()::contains) || type.contains("mindustry.net")); + context.setClassShutter(type -> !blacklist.contains(type.toLowerCase()::contains) || whitelist.contains(type.toLowerCase()::contains)); context.getWrapFactory().setJavaPrimitiveWrap(false); scope = new ImporterTopLevel(context); diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java index ca5a30f5c4..8da95c14cc 100644 --- a/core/src/mindustry/net/Administration.java +++ b/core/src/mindustry/net/Administration.java @@ -5,11 +5,11 @@ import arc.func.*; import arc.struct.*; import arc.util.ArcAnnotate.*; import arc.util.*; -import arc.util.pooling.*; import arc.util.pooling.Pool.*; +import arc.util.pooling.*; import mindustry.*; import mindustry.annotations.Annotations.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; @@ -31,7 +31,7 @@ public class Administration{ //anti-spam addChatFilter((player, message) -> { long resetTime = Config.messageRateLimit.num() * 1000; - if(Config.antiSpam.bool() && !player.isLocal && !player.isAdmin){ + if(Config.antiSpam.bool() && !player.isLocal() && !player.admin()){ //prevent people from spamming messages quickly if(resetTime > 0 && Time.timeSinceMillis(player.getInfo().lastMessageTime) < resetTime){ //supress message @@ -39,9 +39,8 @@ public class Administration{ player.getInfo().messageInfractions ++; //kick player for spamming and prevent connection if they've done this several times if(player.getInfo().messageInfractions >= Config.messageSpamKick.num() && Config.messageSpamKick.num() != 0){ - player.con.kick("You have been kicked for spamming.", 1000 * 60 * 2); + player.con().kick("You have been kicked for spamming.", 1000 * 60 * 2); } - player.getInfo().lastSentMessage = message; return null; }else{ player.getInfo().messageInfractions = 0; @@ -87,7 +86,7 @@ public class Administration{ } /** Filters out a chat message. */ - public @Nullable String filterMessage(Player player, String message){ + public @Nullable String filterMessage(Playerc player, String message){ String current = message; for(ChatFilter f : chatFilters){ current = f.filter(player, message); @@ -102,7 +101,7 @@ public class Administration{ } /** @return whether this action is allowed by the action filters. */ - public boolean allowAction(Player player, ActionType type, Tile tile, Cons setter){ + public boolean allowAction(Playerc player, ActionType type, Tile tile, Cons setter){ PlayerAction act = Pools.obtain(PlayerAction.class, PlayerAction::new); setter.get(act.set(player, type, tile)); for(ActionFilter filter : actionFilters){ @@ -173,7 +172,7 @@ public class Administration{ getCreateInfo(id).banned = true; save(); - Events.fire(new PlayerBanEvent(Vars.playerGroup.find(p -> id.equals(p.uuid)))); + Events.fire(new PlayerBanEvent(Groups.player.find(p -> id.equals(p.uuid())))); return true; } @@ -191,7 +190,7 @@ public class Administration{ } } - bannedIPs.removeValue(ip, false); + bannedIPs.remove(ip, false); if(found){ save(); @@ -213,7 +212,7 @@ public class Administration{ info.banned = false; bannedIPs.removeAll(info.ips, false); save(); - Events.fire(new PlayerUnbanEvent(Vars.playerGroup.find(p -> id.equals(p.uuid)))); + Events.fire(new PlayerUnbanEvent(Groups.player.find(p -> id.equals(p.uuid())))); return true; } @@ -420,7 +419,7 @@ public class Administration{ crashReport("Whether to send crash reports.", false, "crashreport"), logging("Whether to log everything to files.", true), strict("Whether strict mode is on - corrects positions and prevents duplicate UUIDs.", true), - antiSpam("Whether spammers are automatically kicked and rate-limited.", true), + antiSpam("Whether spammers are automatically kicked and rate-limited.", headless), messageRateLimit("Message rate limit in seconds. 0 to disable.", 0), messageSpamKick("How many times a player must send a message before the cooldown to get kicked. 0 to disable.", 3), socketInput("Allows a local application to control this server through a local TCP socket.", false, "socket", () -> Events.fire(Trigger.socketConfigChanged)), @@ -516,7 +515,7 @@ public class Administration{ /** Handles chat messages from players and changes their contents. */ public interface ChatFilter{ /** @return the filtered message; a null string signals that the message should not be sent. */ - @Nullable String filter(Player player, String message); + @Nullable String filter(Playerc player, String message); } /** Allows or disallows player actions. */ @@ -540,7 +539,7 @@ public class Administration{ /** Defines a (potentially dangerous) action that a player has done in the world. * These objects are pooled; do not cache them! */ public static class PlayerAction implements Poolable{ - public @NonNull Player player; + public @NonNull Playerc player; public @NonNull ActionType type; public @NonNull Tile tile; @@ -555,7 +554,7 @@ public class Administration{ public @Nullable Item item; public int itemAmount; - public PlayerAction set(Player player, ActionType type, Tile tile){ + public PlayerAction set(Playerc player, ActionType type, Tile tile){ this.player = player; this.type = type; this.tile = tile; diff --git a/core/src/mindustry/net/CrashSender.java b/core/src/mindustry/net/CrashSender.java index bcc25cea43..184c7b96ec 100644 --- a/core/src/mindustry/net/CrashSender.java +++ b/core/src/mindustry/net/CrashSender.java @@ -12,6 +12,7 @@ import arc.util.serialization.JsonValue.*; import arc.util.serialization.JsonWriter.*; import mindustry.*; import mindustry.core.*; +import mindustry.gen.*; import java.io.*; import java.text.*; @@ -118,7 +119,7 @@ public class CrashSender{ ex(() -> value.addChild("revision", new JsonValue(Version.revision))); ex(() -> value.addChild("net", new JsonValue(fn))); ex(() -> value.addChild("server", new JsonValue(fs))); - ex(() -> value.addChild("players", new JsonValue(Vars.playerGroup.size()))); + ex(() -> value.addChild("players", new JsonValue(Groups.player.size()))); ex(() -> value.addChild("state", new JsonValue(Vars.state.getState().name()))); ex(() -> value.addChild("os", new JsonValue(System.getProperty("os.name") + "x" + (OS.is64Bit ? "64" : "32")))); ex(() -> value.addChild("trace", new JsonValue(parseException(exception)))); diff --git a/core/src/mindustry/net/NetConnection.java b/core/src/mindustry/net/NetConnection.java index 6555957b5b..36555b4ac7 100644 --- a/core/src/mindustry/net/NetConnection.java +++ b/core/src/mindustry/net/NetConnection.java @@ -3,8 +3,7 @@ package mindustry.net; import arc.struct.*; import arc.util.ArcAnnotate.*; import arc.util.*; -import mindustry.entities.traits.BuilderTrait.*; -import mindustry.entities.type.*; +import mindustry.entities.units.*; import mindustry.gen.*; import mindustry.net.Administration.*; import mindustry.net.Net.*; @@ -16,8 +15,9 @@ import static mindustry.Vars.netServer; public abstract class NetConnection{ public final String address; + public String uuid = "AAAAAAAA", usid = uuid; public boolean mobile, modclient; - public @Nullable Player player; + public @Nullable Playerc player; /** ID of last recieved client snapshot. */ public int lastRecievedClientSnapshot = -1; @@ -37,8 +37,8 @@ public abstract class NetConnection{ 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); + if((reason == KickReason.kick || reason == KickReason.banned || reason == KickReason.vote)){ + PlayerInfo info = netServer.admins.getInfo(uuid); info.timesKicked++; info.lastKicked = Math.max(Time.millis() + 30 * 1000, info.lastKicked); } @@ -59,11 +59,9 @@ public abstract class NetConnection{ public void kick(String reason, int kickDuration){ Log.info("Kicking connection {0}; Reason: {1}", address, reason.replace("\n", " ")); - if(player != null && player.uuid != null){ - PlayerInfo info = netServer.admins.getInfo(player.uuid); - info.timesKicked++; - info.lastKicked = Math.max(Time.millis() + kickDuration, info.lastKicked); - } + PlayerInfo info = netServer.admins.getInfo(uuid); + info.timesKicked++; + info.lastKicked = Math.max(Time.millis() + kickDuration, info.lastKicked); Call.onKick(this, reason); diff --git a/core/src/mindustry/net/NetworkIO.java b/core/src/mindustry/net/NetworkIO.java index 27811fed9f..10504e9143 100644 --- a/core/src/mindustry/net/NetworkIO.java +++ b/core/src/mindustry/net/NetworkIO.java @@ -2,7 +2,7 @@ package mindustry.net; import arc.util.*; import mindustry.core.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.game.*; import mindustry.io.*; import mindustry.maps.Map; @@ -16,7 +16,7 @@ import static mindustry.Vars.*; public class NetworkIO{ - public static void writeWorld(Player player, OutputStream os){ + public static void writeWorld(Playerc player, OutputStream os){ try(DataOutputStream stream = new DataOutputStream(os)){ stream.writeUTF(JsonIO.write(state.rules)); @@ -25,7 +25,7 @@ public class NetworkIO{ stream.writeInt(state.wave); stream.writeFloat(state.wavetime); - stream.writeInt(player.id); + stream.writeInt(player.id()); player.write(stream); SaveIO.getSaveWriter().writeContentHeader(stream); @@ -45,11 +45,11 @@ public class NetworkIO{ state.wave = stream.readInt(); state.wavetime = stream.readFloat(); - entities.clear(); + Groups.all.clear(); int id = stream.readInt(); - player.resetNoAdd(); + player.reset(); player.read(stream); - player.resetID(id); + player.id(id); player.add(); SaveIO.getSaveWriter().readContentHeader(stream); @@ -62,7 +62,7 @@ public class NetworkIO{ } public static ByteBuffer writeServerData(){ - String name = (headless ? Config.name.string() : player.name); + String name = (headless ? Config.name.string() : player.name()); String description = headless && !Config.desc.string().equals("off") ? Config.desc.string() : ""; String map = world.getMap() == null ? "None" : world.getMap().name(); @@ -71,7 +71,7 @@ public class NetworkIO{ writeString(buffer, name, 100); writeString(buffer, map); - buffer.putInt(playerGroup.size()); + buffer.putInt(Groups.player.size()); buffer.putInt(state.wave); buffer.putInt(Version.build); writeString(buffer, Version.type); diff --git a/core/src/mindustry/net/ValidateException.java b/core/src/mindustry/net/ValidateException.java index f1291212ab..12a4ae4bdc 100644 --- a/core/src/mindustry/net/ValidateException.java +++ b/core/src/mindustry/net/ValidateException.java @@ -1,14 +1,14 @@ package mindustry.net; -import mindustry.entities.type.Player; +import mindustry.gen.*; /** * Thrown when a client sends invalid information. */ public class ValidateException extends RuntimeException{ - public final Player player; + public final Playerc player; - public ValidateException(Player player, String s){ + public ValidateException(Playerc player, String s){ super(s); this.player = player; } diff --git a/core/src/mindustry/type/ItemStack.java b/core/src/mindustry/type/ItemStack.java index 7fc4d113fa..e229e21447 100644 --- a/core/src/mindustry/type/ItemStack.java +++ b/core/src/mindustry/type/ItemStack.java @@ -5,7 +5,7 @@ import mindustry.content.Items; public class ItemStack implements Comparable{ public Item item; - public int amount = 1; + public int amount = 0; public ItemStack(Item item, int amount){ if(item == null) item = Items.copper; diff --git a/core/src/mindustry/type/Mech.java b/core/src/mindustry/type/Mech.java deleted file mode 100644 index d9ac986df2..0000000000 --- a/core/src/mindustry/type/Mech.java +++ /dev/null @@ -1,141 +0,0 @@ -package mindustry.type; - -import arc.Core; -import arc.graphics.Color; -import arc.graphics.g2d.*; -import arc.math.*; -import arc.scene.ui.layout.Table; -import arc.util.ArcAnnotate.*; -import arc.util.Time; -import mindustry.ctype.ContentType; -import mindustry.entities.type.Player; -import mindustry.ctype.UnlockableContent; -import mindustry.graphics.Pal; -import mindustry.ui.ContentDisplay; - -public class Mech extends UnlockableContent{ - public boolean flying; - public float speed = 1.1f; - public float maxSpeed = 10f; - public float boostSpeed = 0.75f; - public float drag = 0.4f; - public float mass = 1f; - public float shake = 0f; - public float health = 200f; - - public float hitsize = 6f; - public float cellTrnsY = 0f; - public float mineSpeed = 1f; - public int drillPower = -1; - public float buildPower = 1f; - public Color engineColor = Pal.boostTo; - public int itemCapacity = 30; - public boolean turnCursor = true; - public boolean canHeal = false; - public float compoundSpeed, compoundSpeedBoost; - - /** draw the health and team indicator */ - public boolean drawCell = true; - /** draw the items on its back */ - public boolean drawItems = true; - /** draw the engine light if it's flying/boosting */ - public boolean drawLight = true; - - public float weaponOffsetX, weaponOffsetY, engineOffset = 5f, engineSize = 2.5f; - public @NonNull Weapon weapon; - - public TextureRegion baseRegion, legRegion, region; - - public Mech(String name, boolean flying){ - super(name); - this.flying = flying; - } - - public Mech(String name){ - this(name, false); - } - - public void updateAlt(Player player){ - } - - public void draw(Player player){ - } - - public void drawStats(Player player){ - if(drawCell){ - float health = player.healthf(); - Draw.color(Color.black, player.getTeam().color, health + Mathf.absin(Time.time(), health * 5f, 1f - health)); - Draw.rect(player.getPowerCellRegion(), - player.x + Angles.trnsx(player.rotation, cellTrnsY, 0f), - player.y + Angles.trnsy(player.rotation, cellTrnsY, 0f), - player.rotation - 90); - Draw.reset(); - } - if(drawItems){ - player.drawBackItems(); - } - if(drawLight){ - player.drawLight(); - } - } - - public float getExtraArmor(Player player){ - return 0f; - } - - public float spreadX(Player player){ - return 0f; - } - - public float getRotationAlpha(Player player){ - return 1f; - } - - public boolean canShoot(Player player){ - return true; - } - - public void onLand(Player player){ - } - - @Override - public void init(){ - super.init(); - - for(int i = 0; i < 500; i++){ - compoundSpeed *= (1f - drag); - compoundSpeed += speed; - } - - for(int i = 0; i < 500; i++){ - compoundSpeedBoost *= (1f - drag); - compoundSpeedBoost += boostSpeed; - } - } - - @Override - public void displayInfo(Table table){ - ContentDisplay.displayMech(table, this); - } - - @Override - public ContentType getContentType(){ - return ContentType.mech; - } - - @Override - public void load(){ - weapon.load(); - if(!flying){ - legRegion = Core.atlas.find(name + "-leg"); - baseRegion = Core.atlas.find(name + "-base"); - } - - region = Core.atlas.find(name); - } - - @Override - public String toString(){ - return localizedName; - } -} diff --git a/core/src/mindustry/type/Sector.java b/core/src/mindustry/type/Sector.java index 3ebe6af7eb..d1fbff354a 100644 --- a/core/src/mindustry/type/Sector.java +++ b/core/src/mindustry/type/Sector.java @@ -5,7 +5,6 @@ import arc.util.*; import mindustry.graphics.PlanetGrid.*; /** A small section of a planet. */ -//TODO should this be content? public class Sector{ public final SectorRect rect; public final Planet planet; diff --git a/core/src/mindustry/type/StatusEffect.java b/core/src/mindustry/type/StatusEffect.java index 1ade3af60f..e7aacc1c41 100644 --- a/core/src/mindustry/type/StatusEffect.java +++ b/core/src/mindustry/type/StatusEffect.java @@ -1,16 +1,14 @@ package mindustry.type; -import arc.struct.*; import arc.graphics.*; import arc.math.*; +import arc.struct.*; import arc.util.*; import mindustry.content.*; import mindustry.ctype.*; -import mindustry.ctype.ContentType; import mindustry.entities.*; -import mindustry.entities.Effects.*; -import mindustry.entities.type.*; -import mindustry.entities.units.Statuses.*; +import mindustry.entities.units.*; +import mindustry.gen.*; public class StatusEffect extends MappableContent{ /** Damage dealt by the unit with the effect. */ @@ -44,15 +42,15 @@ public class StatusEffect extends MappableContent{ } /** Runs every tick on the affected unit while time is greater than 0. */ - public void update(Unit unit, float time){ + public void update(Unitc unit, float time){ if(damage > 0){ - unit.damagePeriodic(damage); + unit.damageContinuous(damage); }else if(damage < 0){ //heal unit - unit.healBy(damage * Time.delta()); + unit.heal(damage * Time.delta()); } if(effect != Fx.none && Mathf.chance(Time.delta() * 0.15f)){ - Effects.effect(effect, unit.x + Mathf.range(unit.getSize() / 2f), unit.y + Mathf.range(unit.getSize() / 2f)); + effect.at(unit.getX() + Mathf.range(unit.bounds() / 2f), unit.getY() + Mathf.range(unit.bounds() / 2f)); } } @@ -83,7 +81,7 @@ public class StatusEffect extends MappableContent{ * @param time The current status effect time * @param newTime The time that the new status effect will last */ - public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result){ + public StatusEntry getTransition(Unitc unit, StatusEffect to, float time, float newTime, StatusEntry result){ if(transitions.containsKey(to)){ transitions.get(to).handle(unit, time, newTime, result); return result; @@ -98,6 +96,6 @@ public class StatusEffect extends MappableContent{ } public interface TransitionHandler{ - void handle(Unit unit, float time, float newTime, StatusEntry result); + void handle(Unitc unit, float time, float newTime, StatusEntry result); } } diff --git a/core/src/mindustry/type/TypeID.java b/core/src/mindustry/type/TypeID.java deleted file mode 100644 index 8630dfa219..0000000000 --- a/core/src/mindustry/type/TypeID.java +++ /dev/null @@ -1,20 +0,0 @@ -package mindustry.type; - -import arc.func.*; -import mindustry.ctype.*; -import mindustry.ctype.ContentType; -import mindustry.entities.traits.*; - -public class TypeID extends MappableContent{ - public final Prov constructor; - - public TypeID(String name, Prov constructor){ - super(name); - this.constructor = constructor; - } - - @Override - public ContentType getContentType(){ - return ContentType.typeid; - } -} diff --git a/core/src/mindustry/type/UnitDef.java b/core/src/mindustry/type/UnitDef.java new file mode 100644 index 0000000000..26113ac210 --- /dev/null +++ b/core/src/mindustry/type/UnitDef.java @@ -0,0 +1,228 @@ +package mindustry.type; + +import arc.*; +import arc.audio.*; +import arc.func.*; +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.math.*; +import arc.scene.ui.layout.*; +import arc.struct.*; +import arc.util.ArcAnnotate.*; +import arc.util.*; +import mindustry.annotations.Annotations.*; +import mindustry.ctype.*; +import mindustry.entities.units.*; +import mindustry.game.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.ui.*; +import mindustry.world.blocks.*; + +import static mindustry.Vars.*; + +//TODO change to UnitType or Shell or something +public class UnitDef extends UnlockableContent{ + static final float shadowTX = -12, shadowTY = -13, shadowColor = Color.toFloatBits(0, 0, 0, 0.22f); + + public @NonNull Prov defaultController = AIController::new; + public @NonNull Prov constructor; + public boolean flying; + public float speed = 1.1f, boostSpeed = 0.75f, rotateSpeed = 10f, baseRotateSpeed = 10f; + public float drag = 0.3f, mass = 1f, accel = 0.1f; + public float health = 200f, range = -1; + public boolean targetAir = false, targetGround = false; + public boolean faceTarget = true; + + public int itemCapacity = 30; + public int drillTier = -1; + public float buildPower = 1f, minePower = 1f; + + public Color engineColor = Pal.boostTo; + public float engineOffset = 5f, engineSize = 2.5f; + + public float hitsize = 6f; + public float itemOffsetY = 3f; + public float lightRadius = 60f, lightOpacity = 0.6f; + public Color lightColor = Pal.powerLight; + public boolean drawCell = true, drawItems = true; + + public ObjectSet immunities = new ObjectSet<>(); + public Sound deathSound = Sounds.bang; + + public Array weapons = new Array<>(); + public TextureRegion baseRegion, legRegion, region, cellRegion, occlusionRegion; + + public UnitDef(String name){ + super(name); + + if(EntityMapping.map(name) != null){ + constructor = EntityMapping.map(name); + }else{ + constructor = () -> Nulls.unit; + } + } + + public UnitController createController(){ + return defaultController.get(); + } + + public Unitc create(Team team){ + Unitc unit = constructor.get(); + unit.team(team); + unit.type(this); + return unit; + } + + @Override + public void displayInfo(Table table){ + ContentDisplay.displayUnit(table, this); + } + + @CallSuper + @Override + public void init(){ + //set up default range + if(range < 0){ + for(Weapon weapon : weapons){ + range = Math.max(range, weapon.bullet.range()); + } + } + } + + @CallSuper + @Override + public void load(){ + weapons.each(Weapon::load); + region = Core.atlas.find(name); + legRegion = Core.atlas.find(name + "-leg"); + baseRegion = Core.atlas.find(name + "-base"); + cellRegion = Core.atlas.find(name + "-cell", Core.atlas.find("power-cell")); + occlusionRegion = Core.atlas.find("circle-shadow"); + } + + @Override + public ContentType getContentType(){ + return ContentType.unit; + } + + //region drawing + + public void drawShadow(Unitc unit){ + Draw.color(shadowColor); + Draw.rect(region, unit.x() + shadowTX * unit.elevation(), unit.y() + shadowTY * unit.elevation(), unit.rotation() - 90); + Draw.color(); + } + + public void drawOcclusion(Unitc unit){ + Draw.color(0, 0, 0, 0.4f); + float rad = 1.6f; + float size = Math.max(region.getWidth(), region.getHeight()) * Draw.scl; + Draw.rect(occlusionRegion, unit, size * rad, size * rad); + Draw.color(); + } + + public void drawItems(Unitc unit){ + + //draw back items + if(unit.hasItem() && unit.itemTime() > 0.01f){ + float size = (itemSize + Mathf.absin(Time.time(), 5f, 1f)) * unit.itemTime(); + + Draw.mixcol(Pal.accent, Mathf.absin(Time.time(), 5f, 0.5f)); + Draw.rect(unit.item().icon(Cicon.medium), + unit.x() + Angles.trnsx(unit.rotation() + 180f, itemOffsetY), + unit.y() + Angles.trnsy(unit.rotation() + 180f, itemOffsetY), + size, size, unit.rotation()); + + Draw.mixcol(); + + Lines.stroke(1f, Pal.accent); + Lines.circle( + unit.x() + Angles.trnsx(unit.rotation() + 180f, itemOffsetY), + unit.y() + Angles.trnsy(unit.rotation() + 180f, itemOffsetY), + (3f + Mathf.absin(Time.time(), 5f, 1f)) * unit.itemTime()); + + if(unit.isLocal()){ + Fonts.outline.draw(unit.stack().amount + "", + unit.x() + Angles.trnsx(unit.rotation() + 180f, itemOffsetY), + unit.y() + Angles.trnsy(unit.rotation() + 180f, itemOffsetY) - 3, + Pal.accent, 0.25f * unit.itemTime() / Scl.scl(1f), false, Align.center + ); + } + + Draw.reset(); + } + } + + public void drawWeapons(Unitc unit){ + for(WeaponMount mount : unit.mounts()){ + Weapon weapon = mount.weapon; + + for(int i : (weapon.mirror ? Mathf.signs : Mathf.one)){ + i *= Mathf.sign(weapon.flipped); + + float rotation = unit.rotation() - 90 + (weapon.rotate ? mount.rotation : 0); + float trY = weapon.y - (mount.reload / weapon.reload * weapon.recoil) * (weapon.alternate ? Mathf.num(i == Mathf.sign(mount.side)) : 1); + float width = i > 0 ? -weapon.region.getWidth() : weapon.region.getWidth(); + + Draw.rect(weapon.region, + unit.x() + Angles.trnsx(rotation, weapon.x * i, trY), + unit.y() + Angles.trnsy(rotation, weapon.x * i, trY), + width * Draw.scl, + weapon.region.getHeight() * Draw.scl, + rotation); + } + } + } + + public void drawBody(Unitc unit){ + Draw.mixcol(Color.white, unit.hitAlpha()); + + Draw.rect(region, unit, unit.rotation() - 90); + + Draw.reset(); + } + + public void drawCell(Unitc unit){ + Draw.color(Color.black, unit.team().color, unit.healthf() + Mathf.absin(Time.time(), Math.max(unit.healthf() * 5f, 1f), 1f - unit.healthf())); + Draw.rect(cellRegion, unit, unit.rotation() - 90); + Draw.color(); + } + + public void drawLight(Unitc unit){ + if(lightRadius > 0){ + renderer.lights.add(unit, lightRadius, lightColor, lightOpacity); + } + } + + public void drawLegs(Legsc unit){ + Draw.mixcol(Color.white, unit.hitAlpha()); + + float ft = Mathf.sin(unit.walkTime(), 6f, 2f + unit.hitSize() / 15f); + + Floor floor = unit.floorOn(); + + if(floor.isLiquid){ + Draw.color(Color.white, floor.color, 0.5f); + } + + for(int i : Mathf.signs){ + Draw.rect(legRegion, + unit.x() + Angles.trnsx(unit.baseRotation(), ft * i), + unit.y() + Angles.trnsy(unit.baseRotation(), ft * i), + legRegion.getWidth() * i * Draw.scl, legRegion.getHeight() * Draw.scl - Mathf.clamp(ft * i, 0, 2), unit.baseRotation() - 90); + } + + if(floor.isLiquid){ + Draw.color(Color.white, floor.color, unit.drownTime() * 0.4f); + }else{ + Draw.color(Color.white); + } + + Draw.rect(baseRegion, unit, unit.baseRotation() - 90); + + Draw.mixcol(); + } + + //endregion +} diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java deleted file mode 100644 index af0e8d5746..0000000000 --- a/core/src/mindustry/type/UnitType.java +++ /dev/null @@ -1,85 +0,0 @@ -package mindustry.type; - -import arc.*; -import arc.audio.*; -import arc.struct.*; -import arc.func.*; -import arc.graphics.g2d.*; -import arc.scene.ui.layout.*; -import arc.util.ArcAnnotate.*; -import mindustry.content.*; -import mindustry.ctype.ContentType; -import mindustry.ctype.UnlockableContent; -import mindustry.entities.type.*; -import mindustry.game.*; -import mindustry.gen.*; -import mindustry.ui.*; - -public class UnitType extends UnlockableContent{ - public @NonNull TypeID typeID; - public @NonNull Prov constructor; - - public float health = 60; - public float hitsize = 7f; - public float hitsizeTile = 4f; - public float speed = 0.4f; - public float range = 0, attackLength = 150f; - public float rotatespeed = 0.2f; - public float baseRotateSpeed = 0.1f; - public float shootCone = 15f; - public float mass = 1f; - public boolean flying; - public boolean targetAir = true; - public boolean rotateWeapon = false; - public float drag = 0.1f; - public float maxVelocity = 5f; - public float retreatPercent = 0.6f; - public int itemCapacity = 30; - public ObjectSet toMine = ObjectSet.with(Items.lead, Items.copper); - public float buildPower = 0.3f, minePower = 0.7f; - public @NonNull Weapon weapon; - public float weaponOffsetY, engineOffset = 6f, engineSize = 2f; - public ObjectSet immunities = new ObjectSet<>(); - public Sound deathSound = Sounds.bang; - - public TextureRegion legRegion, baseRegion, region; - - public UnitType(String name, Prov mainConstructor){ - this(name); - create(mainConstructor); - } - - public UnitType(String name){ - super(name); - } - - public void create(Prov mainConstructor){ - this.constructor = mainConstructor; - this.description = Core.bundle.getOrNull("unit." + name + ".description"); - this.typeID = new TypeID(name, mainConstructor); - } - - @Override - public void displayInfo(Table table){ - ContentDisplay.displayUnit(table, this); - } - - @Override - public void load(){ - weapon.load(); - region = Core.atlas.find(name); - legRegion = Core.atlas.find(name + "-leg"); - baseRegion = Core.atlas.find(name + "-base"); - } - - @Override - public ContentType getContentType(){ - return ContentType.unit; - } - - public BaseUnit create(Team team){ - BaseUnit unit = constructor.get(); - unit.init(this, team); - return unit; - } -} diff --git a/core/src/mindustry/type/Weapon.java b/core/src/mindustry/type/Weapon.java index 175abd1d24..f5b9d1e1e1 100644 --- a/core/src/mindustry/type/Weapon.java +++ b/core/src/mindustry/type/Weapon.java @@ -1,34 +1,31 @@ package mindustry.type; import arc.*; -import mindustry.annotations.Annotations.*; import arc.audio.*; import arc.graphics.g2d.*; -import arc.math.*; -import arc.util.*; import arc.util.ArcAnnotate.*; -import mindustry.*; import mindustry.content.*; import mindustry.entities.*; -import mindustry.entities.Effects.*; import mindustry.entities.bullet.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; -import mindustry.entities.type.Bullet; import mindustry.gen.*; -import static mindustry.Vars.net; - public class Weapon{ + /** displayed weapon region */ public String name; - - /** minimum cursor distance from player, fixes 'cross-eyed' shooting. */ - protected static float minPlayerDist = 20f; - protected static int sequenceNum = 0; /** bullet shot */ public @NonNull BulletType bullet; /** shell ejection effect */ public Effect ejectEffect = Fx.none; + /** whether to mirror the weapon (draw two of them, which is the default) */ + public boolean mirror = true; + /** whether to flip the weapon's position/side on the ship (only valid when mirror is false) */ + public boolean flipped = false; + /** whether to shoot the weapons in different arms one after another, rather than all at once; only valid when mirror = true */ + public boolean alternate = false; + /** whether to rotate toward the target independently of unit */ + public boolean rotate = false; + /** rotation speed of weapon when rotation is enabled, in degrees/t*/ + public float rotateSpeed = 20f; /** weapon reload in frames */ public float reload; /** amount of shots per fire */ @@ -41,14 +38,12 @@ public class Weapon{ public float shake = 0f; /** visual weapon knockback. */ public float recoil = 1.5f; - /** shoot barrel y offset */ - public float length = 3f; - /** shoot barrel x offset. */ - public float width = 4f; + /** projectile/effect offsets from center of weapon */ + public float shootX = 0f, shootY = 3f; + /** offsets of weapon position on unit */ + public float x = 5f, y = 0f; /** fraction of velocity that is random */ public float velocityRnd = 0f; - /** whether to shoot the weapons in different arms one after another, rather than all at once */ - public boolean alternate = false; /** randomization of shot length */ public float lengthRand = 0f; /** delay in ticks between shots */ @@ -57,124 +52,21 @@ public class Weapon{ public boolean ignoreRotation = false; /** if turnCursor is false for a mech, how far away will the weapon target. */ public float targetDistance = 1f; - + /** sound used for shooting */ public Sound shootSound = Sounds.pew; - + /** displayed region (autoloaded) */ public TextureRegion region; - protected Weapon(String name){ + public Weapon(String name){ this.name = name; } public Weapon(){ - //no region - this.name = ""; - } - - @Remote(targets = Loc.server, called = Loc.both, unreliable = true) - public static void onPlayerShootWeapon(Player player, float x, float y, float rotation, boolean left){ - - 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){ - return; - } - - shootDirect(player, x, y, rotation, left); - } - - @Remote(targets = Loc.server, called = Loc.both, unreliable = true) - public static void onGenericShootWeapon(ShooterTrait shooter, float x, float y, float rotation, boolean left){ - if(shooter == null) return; - shootDirect(shooter, x, y, rotation, left); - } - - public static void shootDirect(ShooterTrait shooter, float offsetX, float offsetY, float rotation, boolean left){ - float x = shooter.getX() + offsetX; - float y = shooter.getY() + offsetY; - float baseX = shooter.getX(), baseY = shooter.getY(); - - Weapon weapon = shooter.getWeapon(); - weapon.shootSound.at(x, y, Mathf.random(0.8f, 1.0f)); - - sequenceNum = 0; - if(weapon.shotDelay > 0.01f){ - Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> { - Time.run(sequenceNum * weapon.shotDelay, () -> weapon.bullet(shooter, x + shooter.getX() - baseX, y + shooter.getY() - baseY, f + Mathf.range(weapon.inaccuracy))); - sequenceNum++; - }); - }else{ - Angles.shotgun(weapon.shots, weapon.spacing, rotation, f -> weapon.bullet(shooter, x, y, f + Mathf.range(weapon.inaccuracy))); - } - - BulletType ammo = weapon.bullet; - - Tmp.v1.trns(rotation + 180f, ammo.recoil); - - shooter.velocity().add(Tmp.v1); - - Tmp.v1.trns(rotation, 3f); - - Effects.shake(weapon.shake, weapon.shake, x, y); - Effects.effect(weapon.ejectEffect, x, y, rotation * -Mathf.sign(left)); - Effects.effect(ammo.shootEffect, x + Tmp.v1.x, y + Tmp.v1.y, rotation, shooter); - Effects.effect(ammo.smokeEffect, x + Tmp.v1.x, y + Tmp.v1.y, rotation, shooter); - - //reset timer for remote players - shooter.getTimer().get(shooter.getShootTimer(left), weapon.reload); + this(""); } public void load(){ region = Core.atlas.find(name + "-equip", Core.atlas.find(name, Core.atlas.find("clear"))); } - public void update(ShooterTrait shooter, float pointerX, float pointerY){ - for(boolean left : Mathf.booleans){ - Tmp.v1.set(pointerX, pointerY).sub(shooter.getX(), shooter.getY()); - if(Tmp.v1.len() < minPlayerDist) Tmp.v1.setLength(minPlayerDist); - - float cx = Tmp.v1.x + shooter.getX(), cy = Tmp.v1.y + shooter.getY(); - - float ang = Tmp.v1.angle(); - Tmp.v1.trns(ang - 90, width * Mathf.sign(left), length + Mathf.range(lengthRand)); - - update(shooter, shooter.getX() + Tmp.v1.x, shooter.getY() + Tmp.v1.y, Angles.angle(shooter.getX() + Tmp.v1.x, shooter.getY() + Tmp.v1.y, cx, cy), left); - } - } - - public void update(ShooterTrait shooter, float mountX, float mountY, float angle, boolean left){ - if(shooter.getTimer().get(shooter.getShootTimer(left), reload)){ - if(alternate){ - shooter.getTimer().reset(shooter.getShootTimer(!left), reload / 2f); - } - - shoot(shooter, mountX - shooter.getX(), mountY - shooter.getY(), angle, left); - } - } - - public float getRecoil(ShooterTrait player, boolean left){ - return (1f - Mathf.clamp(player.getTimer().getTime(player.getShootTimer(left)) / reload)) * recoil; - } - - public void shoot(ShooterTrait p, float x, float y, float angle, boolean left){ - if(net.client()){ - //call it directly, don't invoke on server - shootDirect(p, x, y, angle, left); - }else{ - if(p instanceof Player){ //players need special weapon handling logic - Call.onPlayerShootWeapon((Player)p, x, y, angle, left); - }else{ - Call.onGenericShootWeapon(p, x, y, angle, left); - } - } - } - - void bullet(ShooterTrait owner, float x, float y, float angle){ - if(owner == null) return; - - Tmp.v1.trns(angle, 3f); - Bullet.create(bullet, - owner, owner.getTeam(), x + Tmp.v1.x, y + Tmp.v1.y, angle, (1f - velocityRnd) + Mathf.random(velocityRnd)); - } } diff --git a/core/src/mindustry/type/Weather.java b/core/src/mindustry/type/Weather.java index b83be04262..fac723177b 100644 --- a/core/src/mindustry/type/Weather.java +++ b/core/src/mindustry/type/Weather.java @@ -1,81 +1,22 @@ package mindustry.type; -import arc.util.ArcAnnotate.*; -import mindustry.annotations.Annotations.*; import mindustry.ctype.*; -import mindustry.entities.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; -import mindustry.type.Weather.*; -import java.io.*; - -import static mindustry.Vars.*; - -public abstract class Weather extends MappableContent{ +public abstract class Weather extends MappableContent{ protected float duration = 100f; public Weather(String name){ super(name); } - public abstract void update(T entity); + public abstract void update(); - public abstract void draw(T entity); + public abstract void draw(); @Override public ContentType getContentType(){ return ContentType.weather; } - /** Represents the in-game state of a weather event. */ - @SuppressWarnings("unchecked") - public static class WeatherEntity extends BaseEntity implements SaveTrait, DrawTrait{ - /** How long this event has been occuring in ticks. */ - protected float life; - /** Type of weather that is being simulated. */ - protected @NonNull - Weather weather; - - public WeatherEntity(Weather weather){ - this.weather = weather; - } - - @Override - public void update(){ - weather.update(this); - } - - @Override - public void draw(){ - weather.draw(this); - } - - @CallSuper - @Override - public void writeSave(DataOutput stream) throws IOException{ - stream.writeShort(weather.id); - } - - @CallSuper - @Override - public void readSave(DataInput stream, byte version) throws IOException{ - weather = content.getByID(ContentType.weather, stream.readShort()); - } - - @Override - public byte version(){ - return 0; - } - - @Override - public TypeID getTypeID(){ - return null; - } - - @Override - public EntityGroup targetGroup(){ - return weatherGroup; - } - } + //TODO implement } diff --git a/core/src/mindustry/ui/ContentDisplay.java b/core/src/mindustry/ui/ContentDisplay.java index b3e49040e0..c2ab37ba1f 100644 --- a/core/src/mindustry/ui/ContentDisplay.java +++ b/core/src/mindustry/ui/ContentDisplay.java @@ -28,7 +28,7 @@ public class ContentDisplay{ table.row(); if(block.description != null){ - table.add(block.description).padLeft(5).padRight(5).width(400f).wrap().fillX(); + table.add(block.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX(); table.row(); table.addImage().height(3).color(Color.lightGray).pad(8).padLeft(0).padRight(0).fillX(); @@ -76,7 +76,7 @@ public class ContentDisplay{ table.row(); if(item.description != null){ - table.add(item.description).padLeft(5).padRight(5).width(400f).wrap().fillX(); + table.add(item.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX(); table.row(); table.addImage().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); @@ -110,7 +110,7 @@ public class ContentDisplay{ table.row(); if(liquid.description != null){ - table.add(liquid.description).padLeft(5).padRight(5).width(400f).wrap().fillX(); + table.add(liquid.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX(); table.row(); table.addImage().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); @@ -131,55 +131,7 @@ public class ContentDisplay{ table.row(); } - public static void displayMech(Table table, Mech mech){ - table.table(title -> { - title.addImage(mech.icon(Cicon.xlarge)).size(8 * 6); - title.add("[accent]" + mech.localizedName).padLeft(5); - }); - table.left().defaults().left(); - - table.row(); - - table.addImage().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); - - table.row(); - - if(mech.description != null){ - table.add(mech.description).padLeft(5).padRight(5).width(400f).wrap().fillX(); - table.row(); - - table.addImage().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); - table.row(); - } - - table.left().defaults().fillX(); - - if(Core.bundle.has("mech." + mech.name + ".weapon")){ - table.add(Core.bundle.format("mech.weapon", Core.bundle.get("mech." + mech.name + ".weapon"))); - table.row(); - } - if(Core.bundle.has("mech." + mech.name + ".ability")){ - table.add(Core.bundle.format("mech.ability", Core.bundle.get("mech." + mech.name + ".ability"))); - table.row(); - } - - table.add(Core.bundle.format("mech.buildspeed", (int)(mech.buildPower * 100f))); - table.row(); - - table.add(Core.bundle.format("mech.health", (int)mech.health)); - table.row(); - table.add(Core.bundle.format("mech.itemcapacity", mech.itemCapacity)); - table.row(); - - if(mech.drillPower > 0){ - table.add(Core.bundle.format("mech.minespeed", (int)(mech.mineSpeed * 100f))); - table.row(); - table.add(Core.bundle.format("mech.minepower", mech.drillPower)); - table.row(); - } - } - - public static void displayUnit(Table table, UnitType unit){ + public static void displayUnit(Table table, UnitDef unit){ table.table(title -> { title.addImage(unit.icon(Cicon.xlarge)).size(8 * 6); title.add("[accent]" + unit.localizedName).padLeft(5); @@ -192,7 +144,7 @@ public class ContentDisplay{ table.row(); if(unit.description != null){ - table.add(unit.description).padLeft(5).padRight(5).width(400f).wrap().fillX(); + table.add(unit.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX(); table.row(); table.addImage().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX(); diff --git a/core/src/mindustry/ui/Fonts.java b/core/src/mindustry/ui/Fonts.java index 1c4cfe7d56..7c847c0838 100644 --- a/core/src/mindustry/ui/Fonts.java +++ b/core/src/mindustry/ui/Fonts.java @@ -54,8 +54,9 @@ public class Fonts{ 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; Core.assets.load("icon", BitmapFont.class, new FreeTypeFontLoaderParameter("fonts/icon.ttf", new FreeTypeFontParameter(){{ - size = (int)(Scl.scl(30f)); + size = 30; incremental = true; + characters = "\0"; }})).loaded = f -> Fonts.icon = (BitmapFont)f; } @@ -73,7 +74,10 @@ public class Fonts{ int ch = Integer.parseInt(character); TextureRegion region = Core.atlas.find(texture); - if(region.getTexture() != uitex) throw new IllegalArgumentException("Font icon '" + texture + "' is not in the UI texture."); + if(region.getTexture() != uitex){ + continue; + //throw new IllegalArgumentException("Font icon '" + texture + "' is not in the UI texture."); + } unicodeIcons.put(nametex[0], ch); @@ -104,12 +108,19 @@ public class Fonts{ FileHandleResolver resolver = new InternalFileHandleResolver(); Core.assets.setLoader(FreeTypeFontGenerator.class, new FreeTypeFontGeneratorLoader(resolver)); Core.assets.setLoader(BitmapFont.class, null, new FreetypeFontLoader(resolver){ + ObjectSet scaled = new ObjectSet<>(); + @Override public BitmapFont loadSync(AssetManager manager, String fileName, Fi file, FreeTypeFontLoaderParameter parameter){ if(fileName.equals("outline")){ parameter.fontParameters.borderWidth = Scl.scl(2f); parameter.fontParameters.spaceX -= parameter.fontParameters.borderWidth; } + if(!scaled.contains(parameter.fontParameters)){ + parameter.fontParameters.size = (int)(Scl.scl(parameter.fontParameters.size)); + scaled.add(parameter.fontParameters); + } + parameter.fontParameters.magFilter = TextureFilter.Linear; parameter.fontParameters.minFilter = TextureFilter.Linear; parameter.fontParameters.packer = UI.packer; @@ -119,8 +130,8 @@ public class Fonts{ FreeTypeFontParameter param = new FreeTypeFontParameter(){{ borderColor = Color.darkGray; - size = (int)(Scl.scl(18f)); incremental = true; + size = 18; }}; Core.assets.load("outline", BitmapFont.class, new FreeTypeFontLoaderParameter("fonts/font.ttf", param)).loaded = t -> Fonts.outline = (BitmapFont)t; @@ -162,7 +173,6 @@ public class Fonts{ if(g == null) throw new IllegalArgumentException("No glyph: " + glyph + " (" + (int)glyph + ")"); float size = Math.max(g.width, g.height); - float aspect = (float)g.height / g.width; TextureRegionDrawable draw = new TextureRegionDrawable(new TextureRegion(font.getRegion().getTexture(), g.u, g.v2, g.u2, g.v)){ @Override public void draw(float x, float y, float width, float height){ @@ -173,6 +183,19 @@ public class Fonts{ Draw.rect(region, cx + g.width/2f, cy + g.height/2f, g.width, g.height); } + @Override + public void draw(float x, float y, float originX, float originY, float width, float height, float scaleX, float scaleY, float rotation){ + width *= scaleX; + height *= scaleY; + Draw.color(Tmp.c1.set(tint).mul(Draw.getColor()).toFloatBits()); + float cx = x + width/2f - g.width/2f, cy = y + height/2f - g.height/2f; + cx = (int)cx; + cy = (int)cy; + originX = g.width/2f; + originY = g.height/2f; + Draw.rect(region, cx + g.width/2f, cy + g.height/2f, g.width, g.height, originX, originY, rotation); + } + @Override public float imageSize(){ return size; @@ -186,7 +209,7 @@ public class Fonts{ static FreeTypeFontParameter fontParameter(){ return new FreeTypeFontParameter(){{ - size = (int)(Scl.scl(18f)); + size = 18; shadowColor = Color.darkGray; shadowOffsetY = 2; incremental = true; diff --git a/core/src/mindustry/ui/ItemsDisplay.java b/core/src/mindustry/ui/ItemsDisplay.java index d59a579c16..53d2ed2970 100644 --- a/core/src/mindustry/ui/ItemsDisplay.java +++ b/core/src/mindustry/ui/ItemsDisplay.java @@ -1,6 +1,7 @@ package mindustry.ui; import arc.graphics.*; +import arc.scene.ui.*; import arc.scene.ui.layout.*; import mindustry.core.GameState.*; import mindustry.gen.*; @@ -21,27 +22,40 @@ public class ItemsDisplay extends Table{ top().left(); margin(0); - table(Tex.button,t -> { - t.margin(10).marginLeft(15).marginTop(15f); - t.label(() -> state.is(State.menu) ? "$launcheditems" : "$launchinfo").colspan(3).padBottom(4).left().colspan(3).width(210f).wrap(); - t.row(); - for(Item item : content.items()){ - if(item.type == ItemType.material && data.isUnlocked(item)){ - t.label(() -> format(item)).left(); - t.addImage(item.icon(Cicon.small)).size(8 * 3).padLeft(4).padRight(4); - t.add(item.localizedName).color(Color.lightGray).left(); - t.row(); + table(Tex.button, c -> { + c.margin(10).marginLeft(12).marginTop(15f); + c.marginRight(12f); + c.left(); + + Collapser col = new Collapser(base -> base.pane(t -> { + t.marginRight(30f); + t.left(); + for(Item item : content.items()){ + if(item.type == ItemType.material && data.isUnlocked(item)){ + t.label(() -> format(item)).left(); + t.addImage(item.icon(Cicon.small)).size(8 * 3).padLeft(4).padRight(4); + t.add(item.localizedName).color(Color.lightGray).left(); + t.row(); + } } - } + }).get().setScrollingDisabled(true, false), false).setDuration(0.3f); + + c.addImageTextButton("$launcheditems", Icon.downOpen, Styles.clearTogglet, col::toggle).update(t -> { + t.setText(state.is(State.menu) ? "$launcheditems" : "$launchinfo"); + t.setChecked(col.isCollapsed()); + ((Image)t.getChildren().get(1)).setDrawable(col.isCollapsed() ? Icon.upOpen : Icon.downOpen); + }).padBottom(4).left().fillX().margin(12f); + c.row(); + c.add(col); }); } private String format(Item item){ builder.setLength(0); builder.append(ui.formatAmount(data.items().get(item, 0))); - if(!state.is(State.menu) && player.getTeam().data().hasCore() && player.getTeam().core().items.get(item) > 0){ + if(!state.is(State.menu) && player.team().data().hasCore() && player.team().core().items().get(item) > 0){ builder.append(" [unlaunched]+ "); - builder.append(ui.formatAmount(state.teams.get(player.getTeam()).core().items.get(item))); + builder.append(ui.formatAmount(state.teams.get(player.team()).core().items().get(item))); } return builder.toString(); } diff --git a/core/src/mindustry/ui/dialogs/AdminsDialog.java b/core/src/mindustry/ui/dialogs/AdminsDialog.java index 4b9d23816d..870dc31111 100644 --- a/core/src/mindustry/ui/dialogs/AdminsDialog.java +++ b/core/src/mindustry/ui/dialogs/AdminsDialog.java @@ -41,9 +41,9 @@ public class AdminsDialog extends FloatingDialog{ res.addImageButton(Icon.cancel, () -> { ui.showConfirm("$confirm", "$confirmunadmin", () -> { netServer.admins.unAdminPlayer(info.id); - playerGroup.all().each(player -> { - if(player != null && player.uuid != null && player.uuid.equals(info.id)){ - player.isAdmin = false; + Groups.player.each(player -> { + if(player != null && !player.isLocal() && player.uuid().equals(info.id)){ + player.admin(false); } }); setup(); diff --git a/core/src/mindustry/ui/dialogs/CustomGameDialog.java b/core/src/mindustry/ui/dialogs/CustomGameDialog.java index fdc5077821..03ec05961e 100644 --- a/core/src/mindustry/ui/dialogs/CustomGameDialog.java +++ b/core/src/mindustry/ui/dialogs/CustomGameDialog.java @@ -3,6 +3,7 @@ package mindustry.ui.dialogs; import arc.*; import arc.graphics.g2d.*; import arc.math.*; +import arc.scene.style.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.*; @@ -59,8 +60,9 @@ public class CustomGameDialog extends FloatingDialog{ image.table(t -> { t.left(); for(Gamemode mode : Gamemode.all){ - if(mode.valid(map) && Core.atlas.has("icon-mode-" + mode.name())){ - t.addImage(Core.atlas.drawable("icon-mode-" + mode.name())).size(16f).pad(4f); + TextureRegionDrawable icon = Vars.ui.getIcon("mode" + Strings.capitalize(mode.name()) + "Small"); + if(mode.valid(map) && Core.atlas.isFound(icon.getRegion())){ + t.addImage(icon).size(16f).pad(4f); } } }).left(); diff --git a/core/src/mindustry/ui/dialogs/GameOverDialog.java b/core/src/mindustry/ui/dialogs/GameOverDialog.java index 486b90eb8e..27d4066522 100644 --- a/core/src/mindustry/ui/dialogs/GameOverDialog.java +++ b/core/src/mindustry/ui/dialogs/GameOverDialog.java @@ -22,7 +22,7 @@ public class GameOverDialog extends FloatingDialog{ public void show(Team winner){ this.winner = winner; show(); - if(winner == player.getTeam()){ + if(winner == player.team()){ Events.fire(new WinEvent()); }else{ Events.fire(new LoseEvent()); @@ -62,6 +62,10 @@ public class GameOverDialog extends FloatingDialog{ t.row(); t.add(Core.bundle.format("stat.deconstructed", state.stats.buildingsDeconstructed)); t.row(); + if(control.saves.getCurrent() != null){ + t.add(Core.bundle.format("stat.playtime", control.saves.getCurrent().getPlayTime())); + t.row(); + } if(world.isZone() && !state.stats.itemsDelivered.isEmpty()){ t.add("$stat.delivered"); t.row(); diff --git a/core/src/mindustry/ui/dialogs/HostDialog.java b/core/src/mindustry/ui/dialogs/HostDialog.java index 196f93d63f..4cb2ba0f45 100644 --- a/core/src/mindustry/ui/dialogs/HostDialog.java +++ b/core/src/mindustry/ui/dialogs/HostDialog.java @@ -24,7 +24,7 @@ public class HostDialog extends FloatingDialog{ cont.table(t -> { t.add("$name").padRight(10); t.addField(Core.settings.getString("name"), text -> { - player.name = text; + player.name(text); Core.settings.put("name", text); Core.settings.save(); ui.listfrag.rebuild(); @@ -32,12 +32,12 @@ public class HostDialog extends FloatingDialog{ ImageButton button = t.addImageButton(Tex.whiteui, Styles.clearFulli, 40, () -> { new PaletteDialog().show(color -> { - player.color.set(color); + player.color().set(color); Core.settings.put("color-0", Color.rgba8888(color)); Core.settings.save(); }); }).size(54f).get(); - button.update(() -> button.getStyle().imageUpColor = player.color); + button.update(() -> button.getStyle().imageUpColor = player.color()); }).width(w).height(70f).pad(4).colspan(3); cont.row(); @@ -67,7 +67,7 @@ public class HostDialog extends FloatingDialog{ Time.runTask(5f, () -> { try{ net.host(Vars.port); - player.isAdmin = true; + player.admin(true); if(steam){ Core.app.post(() -> Core.settings.getBoolOnce("steampublic2", () -> { diff --git a/core/src/mindustry/ui/dialogs/JoinDialog.java b/core/src/mindustry/ui/dialogs/JoinDialog.java index 397fee4f64..65b34ac697 100644 --- a/core/src/mindustry/ui/dialogs/JoinDialog.java +++ b/core/src/mindustry/ui/dialogs/JoinDialog.java @@ -95,11 +95,16 @@ public class JoinDialog extends FloatingDialog{ } }); - onResize(this::setup); + onResize(() -> { + setup(); + refreshLocal(); + refreshRemote(); + }); } void setupRemote(){ remote.clear(); + for(Server server : servers){ //why are java lambdas this bad TextButton[] buttons = {null}; @@ -152,7 +157,7 @@ public class JoinDialog extends FloatingDialog{ inner.addImageButton(Icon.trash, Styles.emptyi, () -> { ui.showConfirm("$confirm", "$server.delete", () -> { - servers.removeValue(server, true); + servers.remove(server, true); saveServers(); setupRemote(); refreshRemote(); @@ -243,22 +248,22 @@ public class JoinDialog extends FloatingDialog{ t.add("$name").padRight(10); if(!steam){ t.addField(Core.settings.getString("name"), text -> { - player.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); + t.add(player.name()).update(l -> l.setColor(player.color())).grow().pad(8); } ImageButton button = t.addImageButton(Tex.whiteui, Styles.clearFulli, 40, () -> { new PaletteDialog().show(color -> { - player.color.set(color); + player.color().set(color); Core.settings.put("color-0", Color.rgba8888(color)); Core.settings.save(); }); }).size(54f).get(); - button.update(() -> button.getStyle().imageUpColor = player.color); + button.update(() -> button.getStyle().imageUpColor = player.color()); }).width(w).height(70f).pad(4); cont.row(); cont.add(pane).width(w + 38).pad(0); @@ -266,7 +271,7 @@ public class JoinDialog extends FloatingDialog{ cont.addCenteredImageTextButton("$server.add", Icon.add, () -> { renaming = null; add.show(); - }).marginLeft(6).width(w).height(80f).update(button -> { + }).marginLeft(10).width(w).height(80f).update(button -> { float pw = w; float pad = 0f; if(pane.getChildren().first().getPrefHeight() > pane.getHeight()){ @@ -330,7 +335,7 @@ public class JoinDialog extends FloatingDialog{ } public void connect(String ip, int port){ - if(player.name.trim().isEmpty()){ + if(player.name().trim().isEmpty()){ ui.showInfo("$noname"); return; } @@ -363,7 +368,7 @@ public class JoinDialog extends FloatingDialog{ } float targetWidth(){ - return Core.graphics.isPortrait() ? 350f : 500f; + return Math.min(Core.graphics.getWidth() / Scl.scl() * 0.9f, 500f);//Core.graphics.isPortrait() ? 350f : 500f; } @SuppressWarnings("unchecked") diff --git a/core/src/mindustry/ui/dialogs/ModsDialog.java b/core/src/mindustry/ui/dialogs/ModsDialog.java index 8320c9eab9..ca89f3a6a6 100644 --- a/core/src/mindustry/ui/dialogs/ModsDialog.java +++ b/core/src/mindustry/ui/dialogs/ModsDialog.java @@ -87,7 +87,7 @@ public class ModsDialog extends FloatingDialog{ void modError(Throwable error){ ui.loadfrag.hide(); - if(Strings.getCauses(error).contains(t -> t.getMessage() != null && (t.getMessage().contains("SSL") || t.getMessage().contains("protocol")))){ + if(Strings.getCauses(error).contains(t -> t.getMessage() != null && (t.getMessage().contains("trust anchor") || t.getMessage().contains("SSL") || t.getMessage().contains("protocol")))){ ui.showErrorMessage("$feature.unsupported"); }else{ ui.showException(error); diff --git a/core/src/mindustry/ui/dialogs/PaletteDialog.java b/core/src/mindustry/ui/dialogs/PaletteDialog.java index 876d88b925..5f86276686 100644 --- a/core/src/mindustry/ui/dialogs/PaletteDialog.java +++ b/core/src/mindustry/ui/dialogs/PaletteDialog.java @@ -29,7 +29,7 @@ public class PaletteDialog extends Dialog{ cons.get(color); hide(); }).size(48).get(); - button.setChecked(player.color.equals(color)); + button.setChecked(player.color().equals(color)); button.getStyle().imageUpColor = color; if(i % 4 == 3){ diff --git a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java index df13b270ec..2b4e336d67 100644 --- a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -1,7 +1,6 @@ package mindustry.ui.dialogs; import arc.*; -import arc.struct.*; import arc.files.*; import arc.graphics.*; import arc.graphics.Texture.*; @@ -12,6 +11,7 @@ import arc.scene.ui.*; import arc.scene.ui.SettingsDialog.SettingsTable.*; import arc.scene.ui.TextButton.*; import arc.scene.ui.layout.*; +import arc.struct.*; import arc.util.*; import mindustry.core.GameState.*; import mindustry.core.*; @@ -144,7 +144,7 @@ public class SettingsMenuDialog extends SettingsDialog{ } }))); - if(!ios){ + if(!mobile){ t.row(); t.addImageTextButton("$data.openfolder", Icon.folder, style, () -> Core.app.openFolder(Core.settings.getDataDirectory().absolutePath())); } @@ -240,10 +240,17 @@ public class SettingsMenuDialog extends SettingsDialog{ game.checkPref("buildautopause", false); } - if(steam && !Version.modifier.contains("beta")){ - game.checkPref("publichost", false, i -> { + if(steam){ + game.sliderPref("playerlimit", 16, 2, 32, i -> { platform.updateLobby(); + return i + ""; }); + + if(!Version.modifier.contains("beta")){ + game.checkPref("publichost", false, i -> { + platform.updateLobby(); + }); + } } game.pref(new Setting(){ diff --git a/core/src/mindustry/ui/dialogs/TechTreeDialog.java b/core/src/mindustry/ui/dialogs/TechTreeDialog.java index 3a166c3995..0c942c7647 100644 --- a/core/src/mindustry/ui/dialogs/TechTreeDialog.java +++ b/core/src/mindustry/ui/dialogs/TechTreeDialog.java @@ -1,6 +1,7 @@ package mindustry.ui.dialogs; import arc.*; +import arc.scene.ui.layout.Stack; import arc.struct.*; import arc.graphics.*; import arc.graphics.g2d.*; @@ -25,6 +26,8 @@ import mindustry.ui.Cicon; import mindustry.ui.layout.*; import mindustry.ui.layout.TreeLayout.*; +import java.util.*; + import static mindustry.Vars.*; public class TechTreeDialog extends FloatingDialog{ @@ -110,9 +113,25 @@ public class TechTreeDialog extends FloatingDialog{ } void treeLayout(){ - RadialTreeLayout layout = new RadialTreeLayout(); + float spacing = 20f; LayoutNode node = new LayoutNode(root, null); - layout.layout(node); + LayoutNode[] children = node.children; + LayoutNode[] leftHalf = Arrays.copyOfRange(node.children, 0, Mathf.ceil(node.children.length/2f)); + LayoutNode[] rightHalf = Arrays.copyOfRange(node.children, Mathf.ceil(node.children.length/2f), node.children.length); + node.children = leftHalf; + new BranchTreeLayout(){{ + gapBetweenLevels = gapBetweenNodes = spacing; + rootLocation = TreeLocation.top; + }}.layout(node); + node.children = rightHalf; + + new BranchTreeLayout(){{ + gapBetweenLevels = gapBetweenNodes = spacing; + rootLocation = TreeLocation.bottom; + }}.layout(node); + + node.children = children; + float minx = 0f, miny = 0f, maxx = 0f, maxy = 0f; copyInfo(node); @@ -252,7 +271,7 @@ public class TechTreeDialog extends FloatingDialog{ button.setPosition(node.x + panX + width / 2f, node.y + panY + height / 2f + offset, Align.center); 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(Cicon.medium) : Core.atlas.find("icon-locked")); + .setRegion(node.visible ? node.node.block.icon(Cicon.medium) : Icon.lock.getRegion()); button.getImage().setColor(!locked(node.node) ? Color.white : Color.gray); }); addChild(button); @@ -358,7 +377,7 @@ public class TechTreeDialog extends FloatingDialog{ infoTable.row(); if(node.block.description != null){ - infoTable.table(t -> t.margin(3f).left().labelWrap(node.block.description).color(Color.lightGray).growX()).fillX(); + infoTable.table(t -> t.margin(3f).left().labelWrap(node.block.displayDescription()).color(Color.lightGray).growX()).fillX(); } addChild(infoTable); @@ -378,7 +397,12 @@ public class TechTreeDialog extends FloatingDialog{ 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); + if(Mathf.equal(Math.abs(node.y - child.y), Math.abs(node.x - child.x), 1f) && Mathf.dstm(node.x, node.y, child.x, child.y) <= node.width*3){ + Lines.line(node.x + offsetX, node.y + offsetY, child.x + offsetX, child.y + offsetY); + }else{ + Lines.line(node.x + offsetX, node.y + offsetY, child.x + offsetX, node.y + offsetY); + Lines.line(child.x + offsetX, node.y + offsetY, child.x + offsetX, child.y + offsetY); + } } } diff --git a/core/src/mindustry/ui/dialogs/TraceDialog.java b/core/src/mindustry/ui/dialogs/TraceDialog.java index 9d31780501..0857f2b50e 100644 --- a/core/src/mindustry/ui/dialogs/TraceDialog.java +++ b/core/src/mindustry/ui/dialogs/TraceDialog.java @@ -2,7 +2,7 @@ package mindustry.ui.dialogs; import arc.Core; import arc.scene.ui.layout.Table; -import mindustry.entities.type.Player; +import mindustry.gen.*; import mindustry.gen.*; import mindustry.net.Administration.TraceInfo; @@ -15,7 +15,7 @@ public class TraceDialog extends FloatingDialog{ setFillParent(false); } - public void show(Player player, TraceInfo info){ + public void show(Playerc player, TraceInfo info){ cont.clear(); Table table = new Table(Tex.clear); @@ -23,7 +23,7 @@ public class TraceDialog extends FloatingDialog{ table.defaults().pad(1); table.defaults().left(); - table.add(Core.bundle.format("trace.playername", player.name)); + table.add(Core.bundle.format("trace.playername", player.name())); table.row(); table.add(Core.bundle.format("trace.ip", info.ip)); table.row(); diff --git a/core/src/mindustry/ui/fragments/BlockInventoryFragment.java b/core/src/mindustry/ui/fragments/BlockInventoryFragment.java index 926c56460a..4f53e2fd75 100644 --- a/core/src/mindustry/ui/fragments/BlockInventoryFragment.java +++ b/core/src/mindustry/ui/fragments/BlockInventoryFragment.java @@ -16,7 +16,6 @@ import arc.util.*; import mindustry.annotations.Annotations.*; import mindustry.core.GameState.*; import mindustry.entities.*; -import mindustry.entities.type.*; import mindustry.game.EventType.*; import mindustry.gen.*; import mindustry.net.Administration.*; @@ -37,9 +36,9 @@ public class BlockInventoryFragment extends Fragment{ private Item lastItem; @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 || !tile.interactable(player.getTeam())) return; - amount = Mathf.clamp(amount, 0, player.getItemCapacity()); + public static void requestItem(Playerc player, Tile tile, Item item, int amount){ + if(player == null || tile == null || !tile.interactable(player.team())) return; + amount = Mathf.clamp(amount, 0, player.unit().itemCapacity()); int fa = amount; if(net.server() && (!Units.canInteract(player, tile) || @@ -50,10 +49,10 @@ public class BlockInventoryFragment extends Fragment{ int removed = tile.block().removeStack(tile, item, amount); - player.addItem(item, removed); + player.unit().addItem(item, removed); Events.fire(new WithdrawEvent(tile, player, item, amount)); for(int j = 0; j < Mathf.clamp(removed / 3, 1, 8); j++){ - Time.run(j * 3f, () -> Call.transferItemEffect(item, tile.drawx(), tile.drawy(), player)); + Time.run(j * 3f, () -> Call.transferItemEffect(item, tile.drawx(), tile.drawy(), player.unit())); } } @@ -71,7 +70,7 @@ public class BlockInventoryFragment extends Fragment{ return; } this.tile = t; - if(tile == null || tile.entity == null || !tile.block().isAccessible() || tile.entity.items.total() == 0) + if(tile == null || tile.entity == null || !tile.block().isAccessible() || tile.entity.items().total() == 0) return; rebuild(true); } @@ -98,14 +97,14 @@ public class BlockInventoryFragment extends Fragment{ table.touchable(Touchable.enabled); table.update(() -> { - if(state.is(State.menu) || tile == null || tile.entity == null || !tile.block().isAccessible() || tile.entity.items.total() == 0){ + if(state.is(State.menu) || tile == null || tile.entity == null || !tile.block().isAccessible() || tile.entity.items().total() == 0){ hide(); }else{ if(holding && lastItem != null){ holdTime += Time.delta(); if(holdTime >= holdWithdraw){ - int amount = Math.min(tile.entity.items.get(lastItem), player.maxAccepted(lastItem)); + int amount = Math.min(tile.entity.items().get(lastItem), player.unit().maxAccepted(lastItem)); Call.requestItem(player, tile, lastItem, amount); holding = false; holdTime = 0f; @@ -117,7 +116,7 @@ public class BlockInventoryFragment extends Fragment{ updateTablePosition(); if(tile.block().hasItems){ for(int i = 0; i < content.items().size; i++){ - boolean has = tile.entity.items.has(content.item(i)); + boolean has = tile.entity.items().has(content.item(i)); if(has != container.contains(i)){ rebuild(false); } @@ -136,11 +135,11 @@ public class BlockInventoryFragment extends Fragment{ for(int i = 0; i < content.items().size; i++){ Item item = content.item(i); - if(!tile.entity.items.has(item)) continue; + if(!tile.entity.items().has(item)) continue; container.add(i); - Boolp canPick = () -> player.acceptsItem(item) && !state.isPaused(); + Boolp canPick = () -> player.unit().acceptsItem(item) && !state.isPaused(); HandCursorListener l = new HandCursorListener(); l.setEnabled(canPick); @@ -149,15 +148,15 @@ public class BlockInventoryFragment extends Fragment{ if(tile == null || tile.entity == null){ return ""; } - return round(tile.entity.items.get(item)); + return round(tile.entity.items().get(item)); }); image.addListener(l); image.addListener(new InputListener(){ @Override public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){ - if(!canPick.get() || tile == null || tile.entity == null || tile.entity.items == null || !tile.entity.items.has(item)) return false; - int amount = Math.min(1, player.maxAccepted(item)); + if(!canPick.get() || tile == null || tile.entity == null || tile.entity.items() == null || !tile.entity.items().has(item)) return false; + int amount = Math.min(1, player.unit().maxAccepted(item)); if(amount > 0){ Call.requestItem(player, tile, item, amount); lastItem = item; diff --git a/core/src/mindustry/ui/fragments/HudFragment.java b/core/src/mindustry/ui/fragments/HudFragment.java index e3a7e3a227..52b6cfc80b 100644 --- a/core/src/mindustry/ui/fragments/HudFragment.java +++ b/core/src/mindustry/ui/fragments/HudFragment.java @@ -1,35 +1,27 @@ package mindustry.ui.fragments; import arc.*; -import mindustry.annotations.Annotations.*; -import arc.struct.*; import arc.graphics.*; -import arc.graphics.g2d.*; import arc.input.*; import arc.math.*; -import arc.math.geom.*; import arc.scene.*; import arc.scene.actions.*; import arc.scene.event.*; -import arc.scene.style.*; import arc.scene.ui.*; import arc.scene.ui.ImageButton.*; import arc.scene.ui.layout.*; +import arc.struct.*; import arc.util.*; +import mindustry.annotations.Annotations.*; import mindustry.core.GameState.*; -import mindustry.ctype.ContentType; -import mindustry.ctype.UnlockableContent; -import mindustry.entities.*; -import mindustry.entities.type.*; -import mindustry.game.*; +import mindustry.ctype.*; import mindustry.game.EventType.*; +import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.input.*; import mindustry.net.Packets.*; -import mindustry.type.*; import mindustry.ui.*; -import mindustry.ui.Cicon; import mindustry.ui.dialogs.*; import static mindustry.Vars.*; @@ -75,7 +67,7 @@ public class HudFragment extends Fragment{ } }).name("pause").update(i -> { if(net.active()){ - i.getStyle().imageUp = Icon.user; + i.getStyle().imageUp = Icon.players; }else{ i.setDisabled(false); i.getStyle().imageUp = state.is(State.paused) ? Icon.play : Icon.pause; @@ -173,66 +165,13 @@ public class HudFragment extends Fragment{ .size(50f).margin(6f).get(); button.getImageCell().grow(); button.getStyle().imageUpColor = team.color; - button.update(() -> button.setChecked(player.getTeam() == team)); + button.update(() -> button.setChecked(player.team() == team)); if(++i % 3 == 0){ teams.row(); } } }).left(); - - if(enableUnitEditing){ - - t.row(); - 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(Tex.whiteui, 8 * 6f, () -> { - Call.spawnUnitEditor(player, type); - dialog.hide(); - }).get().getStyle().imageUp = new TextureRegionDrawable(type.icon(Cicon.xlarge)); - if(++i % 4 == 0) dialog.cont.row(); - } - dialog.addCloseButton(); - dialog.setFillParent(false); - dialog.show(); - }).fillX(); - - float[] size = {0}; - float[] position = {0, 0}; - - t.row(); - t.addImageTextButton("$editor.removeunit", Icon.cancel, Styles.togglet, () -> {}).fillX().update(b -> { - boolean[] found = {false}; - if(b.isChecked()){ - Element e = Core.scene.hit(Core.input.mouseX(), Core.input.mouseY(), true); - if(e == null){ - Vec2 world = Core.input.mouseWorld(); - Units.nearby(world.x, world.y, 1f, 1f, unit -> { - if(!found[0] && unit instanceof BaseUnit){ - if(Core.input.keyTap(KeyCode.MOUSE_LEFT)){ - Call.removeUnitEditor(player, (BaseUnit)unit); - } - found[0] = true; - unit.hitbox(Tmp.r1); - size[0] = Mathf.lerpDelta(size[0], Tmp.r1.width * 2f + Mathf.absin(Time.time(), 10f, 5f), 0.1f); - position[0] = unit.x; - position[1] = unit.y; - } - }); - } - } - - Draw.color(Pal.accent, Color.white, Mathf.absin(Time.time(), 8f, 1f)); - Lines.poly(position[0], position[1], 4, size[0] / 2f); - Draw.reset(); - - if(!found[0]){ - size[0] = Mathf.lerpDelta(size[0], 0f, 0.2f); - } - }); - } }).width(dsize * 5 + 4f); editorMain.visible(() -> shown && state.isEditor()); } @@ -256,7 +195,7 @@ public class HudFragment extends Fragment{ t.add(new Minimap()); t.row(); //position - t.label(() -> world.toTile(player.x) + "," + world.toTile(player.y)) + t.label(() -> player.tileX() + "," + player.tileY()) .visible(() -> Core.settings.getBool("position") && !state.rules.tutorial); t.top().right(); }); @@ -287,7 +226,7 @@ public class HudFragment extends Fragment{ }); t.top().visible(() -> { - if(state.is(State.menu) || !state.teams.get(player.getTeam()).hasCore()){ + if(state.is(State.menu) || !state.teams.get(player.team()).hasCore()){ coreAttackTime[0] = 0f; return false; } @@ -345,26 +284,9 @@ public class HudFragment extends Fragment{ } @Remote(targets = Loc.both, forward = true, called = Loc.both) - public static void setPlayerTeamEditor(Player player, Team team){ + public static void setPlayerTeamEditor(Playerc player, Team team){ if(state.isEditor() && player != null){ - player.setTeam(team); - } - } - - @Remote(targets = Loc.both, called = Loc.server) - public static void spawnUnitEditor(Player player, UnitType type){ - if(state.isEditor()){ - BaseUnit unit = type.create(player.getTeam()); - unit.set(player.x, player.y); - unit.rotation = player.rotation; - unit.add(); - } - } - - @Remote(targets = Loc.both, called = Loc.server, forward = true) - public static void removeUnitEditor(Player player, BaseUnit unit){ - if(state.isEditor() && unit != null){ - unit.remove(); + player.team(team); } } @@ -646,12 +568,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.admin()) || !net.active()) && state.enemies == 0 && !spawner.isSpawning() && !state.rules.tutorial; } private void addPlayButton(Table table){ table.right().addImageButton(Icon.play, Styles.righti, 30f, () -> { - if(net.client() && player.isAdmin){ + if(net.client() && player.admin()){ Call.onAdminRequest(player, AdminAction.wave); }else if(inLaunchWave()){ ui.showConfirm("$confirm", "$launch.skip.confirm", () -> !canSkipWave(), () -> state.wavetime = 0f); diff --git a/core/src/mindustry/ui/fragments/MenuFragment.java b/core/src/mindustry/ui/fragments/MenuFragment.java index 3425de4a55..6642847ab5 100644 --- a/core/src/mindustry/ui/fragments/MenuFragment.java +++ b/core/src/mindustry/ui/fragments/MenuFragment.java @@ -171,7 +171,7 @@ public class MenuFragment extends Fragment{ new Buttoni("$loadgame", Icon.download, () -> checkPlay(ui.load::show)), new Buttoni("$tutorial", Icon.info, () -> checkPlay(control::playTutorial)) ), - new Buttoni("$editor", Icon.terrain, () -> checkPlay(ui.maps::show)), steam ? new Buttoni("$workshop", Icon.save, platform::openWorkshop) : null, + new Buttoni("$editor", Icon.terrain, () -> checkPlay(ui.maps::show)), steam ? new Buttoni("$workshop", Icon.book, platform::openWorkshop) : null, new Buttoni(Core.bundle.get("mods"), Icon.bookOpen, ui.mods::show), //not enough space for this button //new Buttoni("$schematics", Icon.paste, ui.schematics::show), diff --git a/core/src/mindustry/ui/fragments/PlacementFragment.java b/core/src/mindustry/ui/fragments/PlacementFragment.java index cf454a288f..9a08993fa3 100644 --- a/core/src/mindustry/ui/fragments/PlacementFragment.java +++ b/core/src/mindustry/ui/fragments/PlacementFragment.java @@ -12,10 +12,9 @@ import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; import mindustry.content.*; -import mindustry.entities.traits.BuilderTrait.*; -import mindustry.entities.type.*; -import mindustry.game.EventType.*; import mindustry.gen.*; +import mindustry.entities.units.*; +import mindustry.game.EventType.*; import mindustry.graphics.*; import mindustry.input.*; import mindustry.type.*; @@ -31,11 +30,13 @@ public class PlacementFragment extends Fragment{ Array returnArray = new Array<>(); Array returnCatArray = new Array<>(); boolean[] categoryEmpty = new boolean[Category.all.length]; - ObjectMap selectedBlocks = new ObjectMap(); + ObjectMap selectedBlocks = new ObjectMap<>(); + ObjectFloatMap scrollPositions = new ObjectFloatMap<>(); Block hovered, lastDisplay; Tile lastHover; Tile hoverTile; Table blockTable, toggler, topTable; + ScrollPane blockPane; boolean lastGround; boolean blockSelectEnd; int blockSelectSeq; @@ -86,11 +87,13 @@ public class PlacementFragment extends Fragment{ } boolean gridUpdate(InputHandler input){ - if(Core.input.keyDown(Binding.pick)){ //mouse eyedropper select + scrollPositions.put(currentCategory, blockPane.getScrollY()); + + if(Core.input.keyDown(Binding.pick) && player.isBuilder()){ //mouse eyedropper select Tile tile = world.ltileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y); Block tryRecipe = tile == null ? null : tile.block(); - for(BuildRequest req : player.buildQueue()){ + for(BuildRequest req : player.builder().requests()){ if(!req.breaking && req.block.bounds(req.x, req.y, Tmp.r1).contains(Core.input.mouseWorld())){ tryRecipe = req.block; break; @@ -216,8 +219,8 @@ public class PlacementFragment extends Fragment{ button.resizeImage(Cicon.medium.size); button.update(() -> { //color unplacable things gray - TileEntity core = player.getClosestCore(); - Color color = state.rules.infiniteResources || (core != null && (core.items.has(block.requirements, state.rules.buildCostMultiplier) || state.rules.infiniteResources)) ? Color.white : Color.gray; + Tilec core = player.closestCore(); + Color color = (state.rules.infiniteResources || (core != null && (core.items().has(block.requirements, state.rules.buildCostMultiplier) || state.rules.infiniteResources))) && player.isBuilder() ? Color.white : Color.gray; button.forEach(elem -> elem.setColor(color)); button.setChecked(control.input.block == block); @@ -240,6 +243,12 @@ public class PlacementFragment extends Fragment{ } } blockTable.act(0f); + blockPane.setScrollYForce(scrollPositions.get(currentCategory, 0)); + Core.app.post(() -> { + blockPane.setScrollYForce(scrollPositions.get(currentCategory, 0)); + blockPane.act(0f); + blockPane.layout(); + }); }; //top table with hover info @@ -298,10 +307,10 @@ public class PlacementFragment extends Fragment{ line.addImage(stack.item.icon(Cicon.small)).size(8 * 2); line.add(stack.item.localizedName).maxWidth(140f).fillX().color(Color.lightGray).padLeft(2).left().get().setEllipsis(true); line.labelWrap(() -> { - TileEntity core = player.getClosestCore(); + Tilec core = player.closestCore(); if(core == null || state.rules.infiniteResources) return "*/*"; - int amount = core.items.get(stack.item); + int amount = core.items().get(stack.item); int stackamount = Math.round(stack.amount * state.rules.buildCostMultiplier); String color = (amount < stackamount / 2f ? "[red]" : amount < stackamount ? "[accent]" : "[white]"); @@ -312,11 +321,11 @@ public class PlacementFragment extends Fragment{ } }).growX().left().margin(3); - if(state.rules.bannedBlocks.contains(lastDisplay)){ + if(state.rules.bannedBlocks.contains(lastDisplay) || !player.isBuilder()){ topTable.row(); topTable.table(b -> { b.addImage(Icon.cancel).padRight(2).color(Color.scarlet); - b.add("$banned"); + b.add(!player.isBuilder() ? "$unit.nobuild" : "$banned"); b.left(); }).padTop(2).left(); } @@ -328,7 +337,7 @@ public class PlacementFragment extends Fragment{ t.add(new Image(lastDisplay.getDisplayIcon(hoverTile))).size(8 * 4); t.labelWrap(lastDisplay.getDisplayName(hoverTile)).left().width(190f).padLeft(5); }).growX().left(); - if(hoverTile.getTeam() == player.getTeam()){ + if(hoverTile.team() == player.team()){ topTable.row(); topTable.table(t -> { t.left().defaults().left(); @@ -343,14 +352,15 @@ public class PlacementFragment extends Fragment{ frame.row(); frame.table(Tex.pane2, blocksSelect -> { blocksSelect.margin(4).marginTop(0); - blocksSelect.pane(blocks -> blockTable = blocks).height(194f).update(pane -> { + blockPane = blocksSelect.pane(blocks -> blockTable = blocks).height(194f).update(pane -> { if(pane.hasScroll()){ Element result = Core.scene.hit(Core.input.mouseX(), Core.input.mouseY(), true); if(result == null || !result.isDescendantOf(pane)){ Core.scene.setScrollFocus(null); } } - }).grow().get().setStyle(Styles.smallPane); + }).grow().get(); + blockPane.setStyle(Styles.smallPane); blocksSelect.row(); blocksSelect.table(control.input::buildPlacementUI).name("inputTable").growX(); }).fillY().bottom().touchable(Touchable.enabled); diff --git a/core/src/mindustry/ui/fragments/PlayerListFragment.java b/core/src/mindustry/ui/fragments/PlayerListFragment.java index 7a29b7ffb0..e96fae02fe 100644 --- a/core/src/mindustry/ui/fragments/PlayerListFragment.java +++ b/core/src/mindustry/ui/fragments/PlayerListFragment.java @@ -8,7 +8,6 @@ import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.*; import mindustry.core.GameState.*; -import mindustry.entities.type.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.net.*; @@ -42,7 +41,7 @@ public class PlayerListFragment extends Fragment{ }); cont.table(Tex.buttonTrans, pane -> { - pane.label(() -> Core.bundle.format(playerGroup.size() == 1 ? "players.single" : "players", playerGroup.size())); + pane.label(() -> Core.bundle.format(Groups.player.size() == 1 ? "players.single" : "players", Groups.player.size())); pane.row(); pane.pane(content).grow().get().setScrollingDisabled(true, false); pane.row(); @@ -66,11 +65,11 @@ public class PlayerListFragment extends Fragment{ float h = 74f; - playerGroup.all().sort(Structs.comparing(Unit::getTeam)); - playerGroup.all().each(user -> { - NetConnection connection = user.con; + Groups.player.sort(Structs.comparing(Playerc::team)); + Groups.player.each(user -> { + NetConnection connection = user.con(); - if(connection == null && net.server() && !user.isLocal) return; + if(connection == null && net.server() && !user.isLocal()) return; Table button = new Table(); button.left(); @@ -88,15 +87,16 @@ public class PlayerListFragment extends Fragment{ } }; table.margin(8); - table.add(new Image(user.getIconRegion()).setScaling(Scaling.none)).grow(); + //TODO dead players should have no region + table.add(new Image(user.unit().type().region).setScaling(Scaling.none)).grow(); button.add(table).size(h); - button.labelWrap("[#" + user.color.toString().toUpperCase() + "]" + user.name).width(170f).pad(10); + button.labelWrap("[#" + user.color().toString().toUpperCase() + "]" + user.name()).width(170f).pad(10); button.add().grow(); - button.addImage(Icon.admin).visible(() -> user.isAdmin && !(!user.isLocal && net.server())).padRight(5).get().updateVisibility(); + button.addImage(Icon.admin).visible(() -> user.admin() && !(!user.isLocal() && net.server())).padRight(5).get().updateVisibility(); - if((net.server() || player.isAdmin) && !user.isLocal && (!user.isAdmin || net.server())){ + if((net.server() || player.admin()) && !user.isLocal() && (!user.admin() || net.server())){ button.add().growY(); float bs = (h) / 2f; @@ -114,32 +114,32 @@ public class PlayerListFragment extends Fragment{ t.addImageButton(Icon.admin, Styles.clearTogglePartiali, () -> { if(net.client()) return; - String id = user.uuid; + String id = user.uuid(); if(netServer.admins.isAdmin(id, connection.address)){ ui.showConfirm("$confirm", "$confirmunadmin", () -> netServer.admins.unAdminPlayer(id)); }else{ - ui.showConfirm("$confirm", "$confirmadmin", () -> netServer.admins.adminPlayer(id, user.usid)); + ui.showConfirm("$confirm", "$confirmadmin", () -> netServer.admins.adminPlayer(id, user.usid())); } }) - .update(b -> b.setChecked(user.isAdmin)) + .update(b -> b.setChecked(user.admin())) .disabled(b -> net.client()) .touchable(() -> net.client() ? Touchable.disabled : Touchable.enabled) - .checked(user.isAdmin); + .checked(user.admin()); t.addImageButton(Icon.zoom, Styles.clearPartiali, () -> Call.onAdminRequest(user, AdminAction.trace)); }).padRight(12).size(bs + 10f, bs); - }else if(!user.isLocal && !user.isAdmin && net.client() && playerGroup.size() >= 3 && player.getTeam() == user.getTeam()){ //votekick + }else if(!user.isLocal() && !user.admin() && net.client() && Groups.player.size() >= 3 && player.team() == user.team()){ //votekick button.add().growY(); button.addImageButton(Icon.hammer, Styles.clearPartiali, - () -> ui.showConfirm("$confirm", "$confirmvotekick", () -> Call.sendChatMessage("/votekick " + user.name))).size(h); + () -> ui.showConfirm("$confirm", "$confirmvotekick", () -> Call.sendChatMessage("/votekick " + user.name()))).size(h); } content.add(button).padBottom(-6).width(350f).maxHeight(h + 14); content.row(); - content.addImage().height(4f).color(state.rules.pvp ? user.getTeam().color : Pal.gray).growX(); + content.addImage().height(4f).color(state.rules.pvp ? user.team().color : Pal.gray).growX(); content.row(); }); diff --git a/core/src/mindustry/ui/layout/BranchTreeLayout.java b/core/src/mindustry/ui/layout/BranchTreeLayout.java index 07c3fb5497..15dbe4ae6f 100644 --- a/core/src/mindustry/ui/layout/BranchTreeLayout.java +++ b/core/src/mindustry/ui/layout/BranchTreeLayout.java @@ -148,8 +148,7 @@ public class BranchTreeLayout implements TreeLayout{ wPlus.mode = wPlus.mode + shift; } - private TreeNode apportion(TreeNode v, TreeNode defaultAncestor, - TreeNode leftSibling, TreeNode parentOfV){ + private TreeNode apportion(TreeNode v, TreeNode defaultAncestor, TreeNode leftSibling, TreeNode parentOfV){ if(leftSibling == null){ return defaultAncestor; } diff --git a/core/src/mindustry/ui/layout/RadialTreeLayout.java b/core/src/mindustry/ui/layout/RadialTreeLayout.java index 65096e86f6..88b13a5efa 100644 --- a/core/src/mindustry/ui/layout/RadialTreeLayout.java +++ b/core/src/mindustry/ui/layout/RadialTreeLayout.java @@ -12,7 +12,7 @@ public class RadialTreeLayout implements TreeLayout{ @Override public void layout(TreeNode root){ startRadius = root.height * 2.4f; - delta = root.height * 2.4f; + delta = root.height * 20.4f; bfs(root, true); diff --git a/core/src/mindustry/ui/layout/RowTreeLayout.java b/core/src/mindustry/ui/layout/RowTreeLayout.java new file mode 100644 index 0000000000..58fa8596e4 --- /dev/null +++ b/core/src/mindustry/ui/layout/RowTreeLayout.java @@ -0,0 +1,36 @@ +package mindustry.ui.layout; + +import arc.struct.*; + +public class RowTreeLayout implements TreeLayout{ + + @Override + public void layout(TreeNode root){ + layout(root, 0, new IntArray()); + + /* + def minimum_ws(tree, depth=0): + tree.x = nexts[depth] + tree.y = depth + nexts[depth] += 1 + for c in tree.children: + minimum_ws(tree, c) + */ + } + + void layout(TreeNode node, int depth, IntArray nexts){ + float size = node.height * 5f; + + if(nexts.size < depth + 1){ + nexts.ensureCapacity(depth + 1); + nexts.size = depth + 1; + } + + node.x = size * nexts.get(depth); + node.y = size * depth; + nexts.incr(depth, 1); + for(TreeNode child : node.children){ + layout(child, depth + 1, nexts); + } + } +} diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index a0294013ad..e8f679cfa4 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -1,12 +1,9 @@ package mindustry.world; import arc.*; -import mindustry.annotations.Annotations.*; import arc.Graphics.*; import arc.Graphics.Cursor.*; import arc.audio.*; -import arc.struct.EnumSet; -import arc.struct.*; import arc.func.*; import arc.graphics.*; import arc.graphics.g2d.*; @@ -14,15 +11,15 @@ import arc.graphics.g2d.TextureAtlas.*; import arc.math.*; import arc.math.geom.*; import arc.scene.ui.layout.*; +import arc.struct.EnumSet; +import arc.struct.*; import arc.util.*; import arc.util.ArcAnnotate.*; import arc.util.pooling.*; +import mindustry.annotations.Annotations.*; import mindustry.ctype.*; -import mindustry.ctype.ContentType; import mindustry.entities.*; -import mindustry.entities.effect.*; -import mindustry.entities.traits.BuilderTrait.*; -import mindustry.entities.type.*; +import mindustry.entities.units.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.graphics.MultiPacker.*; @@ -145,7 +142,7 @@ public class Block extends BlockStorage{ protected TextureRegion[] cacheRegions = {}; protected Array cacheRegionStrings = new Array<>(); - protected Prov entityType = TileEntity::new; + protected Prov entityType = TileEntity::create; protected Array tempTiles = new Array<>(); protected TextureRegion[] generatedIcons; @@ -177,7 +174,7 @@ public class Block extends BlockStorage{ } public void onProximityRemoved(Tile tile){ - if(tile.entity.power != null){ + if(tile.entity.power() != null){ tile.block().powerGraphRemoved(tile); } } @@ -187,49 +184,49 @@ public class Block extends BlockStorage{ } protected void updatePowerGraph(Tile tile){ - TileEntity entity = tile.ent(); + Tilec entity = tile.ent(); for(Tile other : getPowerConnections(tile, tempTiles)){ - if(other.entity.power != null){ - other.entity.power.graph.add(entity.power.graph); + if(other.entity.power() != null){ + other.entity.power().graph.add(entity.power().graph); } } } protected void powerGraphRemoved(Tile tile){ - if(tile.entity == null || tile.entity.power == null){ + if(tile.entity == null || tile.entity.power() == null){ return; } - tile.entity.power.graph.remove(tile); - for(int i = 0; i < tile.entity.power.links.size; i++){ - Tile other = world.tile(tile.entity.power.links.get(i)); - if(other != null && other.entity != null && other.entity.power != null){ - other.entity.power.links.removeValue(tile.pos()); + tile.entity.power().graph.remove(tile); + for(int i = 0; i < tile.entity.power().links.size; i++){ + Tile other = world.tile(tile.entity.power().links.get(i)); + if(other != null && other.entity != null && other.entity.power() != null){ + other.entity.power().links.removeValue(tile.pos()); } } } public Array getPowerConnections(Tile tile, Array out){ out.clear(); - if(tile == null || tile.entity == null || tile.entity.power == null) return out; + if(tile == null || tile.entity == null || tile.entity.power() == null) return out; for(Tile other : tile.entity.proximity()){ - if(other != null && other.entity != null && other.entity.power != null + if(other != null && other.entity != null && other.entity.power() != null && !(consumesPower && other.block().consumesPower && !outputsPower && !other.block().outputsPower) - && !tile.entity.power.links.contains(other.pos())){ + && !tile.entity.power().links.contains(other.pos())){ out.add(other); } } - for(int i = 0; i < tile.entity.power.links.size; i++){ - Tile link = world.tile(tile.entity.power.links.get(i)); - if(link != null && link.entity != null && link.entity.power != null) out.add(link); + for(int i = 0; i < tile.entity.power().links.size; i++){ + Tile link = world.tile(tile.entity.power().links.get(i)); + if(link != null && link.entity != null && link.entity.power() != null) out.add(link); } return out; } - protected float getProgressIncrease(TileEntity entity, float baseTime){ + protected float getProgressIncrease(Tilec entity, float baseTime){ return 1f / baseTime * entity.delta() * entity.efficiency(); } @@ -301,8 +298,8 @@ public class Block extends BlockStorage{ } public void drawLight(Tile tile){ - if(tile.entity != null && hasLiquids && drawLiquidLight && tile.entity.liquids.current().lightColor.a > 0.001f){ - drawLiquidLight(tile, tile.entity.liquids.current(), tile.entity.liquids.smoothAmount()); + if(tile.entity != null && hasLiquids && drawLiquidLight && tile.entity.liquids().current().lightColor.a > 0.001f){ + drawLiquidLight(tile, tile.entity.liquids().current(), tile.entity.liquids().smoothAmount()); } } @@ -318,7 +315,7 @@ public class Block extends BlockStorage{ } public void drawTeam(Tile tile){ - Draw.color(tile.getTeam().color); + Draw.color(tile.team().color); Draw.rect("block-border", tile.drawx() - size * tilesize / 2f + 4, tile.drawy() - size * tilesize / 2f + 4); Draw.color(); } @@ -340,14 +337,14 @@ public class Block extends BlockStorage{ Geometry.circle(tile.x, tile.y, range, (x, y) -> { Tile other = world.ltile(x, y); if(other != null && other.block instanceof PowerNode && ((PowerNode)other.block).linkValid(other, tile) && !PowerNode.insulated(other, tile) && !other.entity.proximity().contains(tile) && - !(outputsPower && tile.entity.proximity().contains(p -> p.entity != null && p.entity.power != null && p.entity.power.graph == other.entity.power.graph))){ + !(outputsPower && tile.entity.proximity().contains(p -> p.entity != null && p.entity.power() != null && p.entity.power().graph == other.entity.power().graph))){ tempTiles.add(other); } }); tempTiles.sort(Structs.comparingFloat(t -> t.dst2(tile))); if(!tempTiles.isEmpty()){ Tile toLink = tempTiles.first(); - if(!toLink.entity.power.links.contains(tile.pos())){ + if(!toLink.entity.power().links.contains(tile.pos())){ toLink.configureAny(tile.pos()); } } @@ -358,11 +355,11 @@ public class Block extends BlockStorage{ } /** Called every frame a unit is on this tile. */ - public void unitOn(Tile tile, Unit unit){ + public void unitOn(Tile tile, Unitc unit){ } /** Called when a unit that spawned at this tile is removed. */ - public void unitRemoved(Tile tile, Unit unit){ + public void unitRemoved(Tile tile, Unitc unit){ } /** Returns whether ot not this block can be place on the specified tile. */ @@ -373,7 +370,7 @@ public class Block extends BlockStorage{ /** Call when some content is produced. This unlocks the content if it is applicable. */ public void useContent(Tile tile, UnlockableContent content){ //only unlocks content in zones - if(!headless && tile.getTeam() == player.getTeam() && world.isZone()){ + if(!headless && tile.team() == player.team() && world.isZone()){ logic.handleContent(content); } } @@ -468,12 +465,12 @@ public class Block extends BlockStorage{ } /** Called when the block is tapped. */ - public void tapped(Tile tile, Player player){ + public void tapped(Tile tile, Playerc player){ } /** Called when arbitrary configuration is applied to a tile. */ - public void configured(Tile tile, @Nullable Player player, int value){ + public void configured(Tile tile, @Nullable Playerc player, int value){ } @@ -504,12 +501,12 @@ public class Block extends BlockStorage{ } /** Returns whether this config menu should show when the specified player taps it. */ - public boolean shouldShowConfigure(Tile tile, Player player){ + public boolean shouldShowConfigure(Tile tile, Playerc player){ return true; } /** Whether this configuration should be hidden now. Called every frame the config is open. */ - public boolean shouldHideConfigure(Tile tile, Player player){ + public boolean shouldHideConfigure(Tile tile, Playerc player){ return false; } @@ -543,15 +540,15 @@ public class Block extends BlockStorage{ bars.add("health", entity -> new Bar("blocks.health", Pal.health, entity::healthf).blink(Color.white)); if(hasLiquids){ - Func current; + Func current; if(consumes.has(ConsumeType.liquid) && consumes.get(ConsumeType.liquid) instanceof ConsumeLiquid){ Liquid liquid = consumes.get(ConsumeType.liquid).liquid; current = entity -> liquid; }else{ - current = entity -> entity.liquids.current(); + current = entity -> entity.liquids().current(); } - bars.add("liquid", entity -> new Bar(() -> entity.liquids.get(current.get(entity)) <= 0.001f ? Core.bundle.get("bar.liquid") : current.get(entity).localizedName, - () -> current.get(entity).barColor(), () -> entity.liquids.get(current.get(entity)) / liquidCapacity)); + bars.add("liquid", entity -> new Bar(() -> entity.liquids().get(current.get(entity)) <= 0.001f ? Core.bundle.get("bar.liquid") : current.get(entity).localizedName, + () -> current.get(entity).barColor(), () -> entity.liquids().get(current.get(entity)) / liquidCapacity)); } if(hasPower && consumes.hasPower()){ @@ -559,12 +556,12 @@ public class Block extends BlockStorage{ boolean buffered = cons.buffered; float capacity = cons.capacity; - bars.add("power", entity -> new Bar(() -> buffered ? Core.bundle.format("bar.poweramount", Float.isNaN(entity.power.status * capacity) ? "" : (int)(entity.power.status * capacity)) : - Core.bundle.get("bar.power"), () -> Pal.powerBar, () -> Mathf.zero(cons.requestedPower(entity)) && entity.power.graph.getPowerProduced() + entity.power.graph.getBatteryStored() > 0f ? 1f : entity.power.status)); + bars.add("power", entity -> new Bar(() -> buffered ? Core.bundle.format("bar.poweramount", Float.isNaN(entity.power().status * capacity) ? "" : (int)(entity.power().status * capacity)) : + Core.bundle.get("bar.power"), () -> Pal.powerBar, () -> Mathf.zero(cons.requestedPower(entity)) && entity.power().graph.getPowerProduced() + entity.power().graph.getBatteryStored() > 0f ? 1f : entity.power().status)); } if(hasItems && configurable){ - bars.add("items", entity -> new Bar(() -> Core.bundle.format("bar.items", entity.items.total()), () -> Pal.items, () -> (float)entity.items.total() / itemCapacity)); + bars.add("items", entity -> new Bar(() -> Core.bundle.format("bar.items", entity.items().total()), () -> Pal.items, () -> (float)entity.items().total() / itemCapacity)); } } @@ -589,7 +586,7 @@ public class Block extends BlockStorage{ return amount; } - public void handleBulletHit(TileEntity entity, Bullet bullet){ + public void handleBulletHit(Tilec entity, Bulletc bullet){ entity.damage(bullet.damage()); } @@ -609,31 +606,32 @@ public class Block extends BlockStorage{ if(hasItems){ for(Item item : content.items()){ - int amount = tile.entity.items.get(item); + int amount = tile.entity.items().get(item); explosiveness += item.explosiveness * amount; flammability += item.flammability * amount; } } if(hasLiquids){ - flammability += tile.entity.liquids.sum((liquid, amount) -> liquid.explosiveness * amount / 2f); - explosiveness += tile.entity.liquids.sum((liquid, amount) -> liquid.flammability * amount / 2f); + flammability += tile.entity.liquids().sum((liquid, amount) -> liquid.explosiveness * amount / 2f); + explosiveness += tile.entity.liquids().sum((liquid, amount) -> liquid.flammability * amount / 2f); } if(consumes.hasPower() && consumes.getPower().buffered){ - power += tile.entity.power.status * consumes.getPower().capacity; + power += tile.entity.power().status * consumes.getPower().capacity; } if(hasLiquids){ - tile.entity.liquids.each((liquid, amount) -> { + tile.entity.liquids().each((liquid, amount) -> { float splash = Mathf.clamp(amount / 4f, 0f, 10f); for(int i = 0; i < Mathf.clamp(amount / 5, 0, 30); i++){ Time.run(i / 2f, () -> { Tile other = world.tile(tile.x + Mathf.range(size / 2), tile.y + Mathf.range(size / 2)); if(other != null){ - Puddle.deposit(other, liquid, splash); + //TODO puddle + //Puddle.deposit(other, liquid, splash); } }); } @@ -642,7 +640,7 @@ public class Block extends BlockStorage{ Damage.dynamicExplosion(x, y, flammability, explosiveness * 3.5f, power, tilesize * size / 2f, Pal.darkFlame); if(!tile.floor().solid && !tile.floor().isLiquid){ - RubbleDecal.create(tile.drawx(), tile.drawy(), size); + Effects.rubble(tile.drawx(), tile.drawy(), size); } } @@ -657,10 +655,10 @@ public class Block extends BlockStorage{ } return 0; }else{ - float result = tile.entity.items.sum((item, amount) -> item.flammability * amount); + float result = tile.entity.items().sum((item, amount) -> item.flammability * amount); if(hasLiquids){ - result += tile.entity.liquids.sum((liquid, amount) -> liquid.flammability * amount / 3f); + result += tile.entity.liquids().sum((liquid, amount) -> liquid.flammability * amount / 3f); } return result; @@ -676,7 +674,7 @@ public class Block extends BlockStorage{ } public void display(Tile tile, Table table){ - TileEntity entity = tile.entity; + Tilec entity = tile.entity; if(entity != null){ table.table(bars -> { @@ -702,7 +700,7 @@ public class Block extends BlockStorage{ } public void displayBars(Tile tile, Table table){ - for(Func bar : bars.list()){ + for(Func bar : bars.list()){ table.add(bar.get(tile.entity)).growX(); table.row(); } @@ -857,7 +855,7 @@ public class Block extends BlockStorage{ return destructible || update; } - public final TileEntity newEntity(){ + public final Tilec newEntity(){ return entityType.get(); } diff --git a/core/src/mindustry/world/BlockStorage.java b/core/src/mindustry/world/BlockStorage.java index 20c1ca8f98..9807952b88 100644 --- a/core/src/mindustry/world/BlockStorage.java +++ b/core/src/mindustry/world/BlockStorage.java @@ -1,21 +1,16 @@ package mindustry.world; -import arc.struct.Array; -import arc.math.Mathf; -import arc.math.geom.Vec2; +import arc.math.*; +import arc.math.geom.*; +import arc.struct.*; import arc.util.*; -import mindustry.Vars; -import mindustry.content.Fx; -import mindustry.entities.Effects; -import mindustry.entities.effect.Puddle; -import mindustry.entities.type.TileEntity; -import mindustry.entities.type.Unit; -import mindustry.ctype.UnlockableContent; -import mindustry.type.Item; -import mindustry.type.Liquid; -import mindustry.world.consumers.Consumers; -import mindustry.world.meta.BlockBars; -import mindustry.world.meta.BlockStats; +import mindustry.*; +import mindustry.content.*; +import mindustry.ctype.*; +import mindustry.gen.*; +import mindustry.type.*; +import mindustry.world.consumers.*; +import mindustry.world.meta.*; public abstract class BlockStorage extends UnlockableContent{ public boolean hasItems; @@ -51,9 +46,9 @@ public abstract class BlockStorage extends UnlockableContent{ } /** Returns the amount of items this block can accept. */ - public int acceptStack(Item item, int amount, Tile tile, Unit source){ - if(acceptItem(item, tile, tile) && hasItems && (source == null || source.getTeam() == tile.getTeam())){ - return Math.min(getMaximumAccepted(tile, item) - tile.entity.items.get(item), amount); + public int acceptStack(Item item, int amount, Tile tile, Teamc source){ + if(acceptItem(item, tile, tile) && hasItems && (source == null || source.team() == tile.team())){ + return Math.min(getMaximumAccepted(tile, item) - tile.entity.items().get(item), amount); }else{ return 0; } @@ -65,17 +60,17 @@ public abstract class BlockStorage extends UnlockableContent{ /** Remove a stack from this inventory, and return the amount removed. */ public int removeStack(Tile tile, Item item, int amount){ - if(tile.entity == null || tile.entity.items == null) return 0; - amount = Math.min(amount, tile.entity.items.get(item)); + if(tile.entity == null || tile.entity.items() == null) return 0; + amount = Math.min(amount, tile.entity.items().get(item)); tile.entity.noSleep(); - tile.entity.items.remove(item, amount); + tile.entity.items().remove(item, amount); return amount; } /** Handle a stack input. */ - public void handleStack(Item item, int amount, Tile tile, Unit source){ + public void handleStack(Item item, int amount, Tile tile, Teamc source){ tile.entity.noSleep(); - tile.entity.items.add(item, amount); + tile.entity.items().add(item, amount); } public boolean outputsItems(){ @@ -92,19 +87,19 @@ public abstract class BlockStorage extends UnlockableContent{ } public void handleItem(Item item, Tile tile, Tile source){ - tile.entity.items.add(item, 1); + tile.entity.items().add(item, 1); } public boolean acceptItem(Item item, Tile tile, Tile source){ - return consumes.itemFilters.get(item.id) && tile.entity.items.get(item) < getMaximumAccepted(tile, item); + return consumes.itemFilters.get(item.id) && tile.entity.items().get(item) < getMaximumAccepted(tile, item); } public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - return hasLiquids && tile.entity.liquids.get(liquid) + amount < liquidCapacity && consumes.liquidfilters.get(liquid.id); + return hasLiquids && tile.entity.liquids().get(liquid) + amount < liquidCapacity && consumes.liquidfilters.get(liquid.id); } public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - tile.entity.liquids.add(liquid, amount); + tile.entity.liquids().add(liquid, amount); } public void tryDumpLiquid(Tile tile, Liquid liquid){ @@ -118,9 +113,9 @@ public abstract class BlockStorage extends UnlockableContent{ other = other.block().getLiquidDestination(other, in, liquid); - if(other != null && other.getTeam() == tile.getTeam() && other.block().hasLiquids && canDumpLiquid(tile, other, liquid) && other.entity.liquids != null){ - float ofract = other.entity.liquids.get(liquid) / other.block().liquidCapacity; - float fract = tile.entity.liquids.get(liquid) / liquidCapacity; + if(other != null && other.team() == tile.team() && other.block().hasLiquids && canDumpLiquid(tile, other, liquid) && other.entity.liquids() != null){ + float ofract = other.entity.liquids().get(liquid) / other.block().liquidCapacity; + float fract = tile.entity.liquids().get(liquid) / liquidCapacity; if(ofract < fract) tryMoveLiquid(tile, in, other, (fract - ofract) * liquidCapacity / 2f, liquid); } @@ -133,11 +128,11 @@ public abstract class BlockStorage extends UnlockableContent{ } public void tryMoveLiquid(Tile tile, Tile tileSource, Tile next, float amount, Liquid liquid){ - float flow = Math.min(next.block().liquidCapacity - next.entity.liquids.get(liquid) - 0.001f, amount); + float flow = Math.min(next.block().liquidCapacity - next.entity.liquids().get(liquid) - 0.001f, amount); if(next.block().acceptLiquid(next, tileSource, liquid, flow)){ next.block().handleLiquid(next, tileSource, liquid, flow); - tile.entity.liquids.remove(liquid, flow); + tile.entity.liquids().remove(liquid, flow); } } @@ -151,38 +146,39 @@ public abstract class BlockStorage extends UnlockableContent{ next = next.link(); next = next.block().getLiquidDestination(next, tile, liquid); - if(next.getTeam() == tile.getTeam() && next.block().hasLiquids && tile.entity.liquids.get(liquid) > 0f){ + if(next.team() == tile.team() && next.block().hasLiquids && tile.entity.liquids().get(liquid) > 0f){ if(next.block().acceptLiquid(next, tile, liquid, 0f)){ - float ofract = next.entity.liquids.get(liquid) / next.block().liquidCapacity; - float fract = tile.entity.liquids.get(liquid) / liquidCapacity * liquidPressure; - float flow = Math.min(Mathf.clamp((fract - ofract) * (1f)) * (liquidCapacity), tile.entity.liquids.get(liquid)); - flow = Math.min(flow, next.block().liquidCapacity - next.entity.liquids.get(liquid) - 0.001f); + float ofract = next.entity.liquids().get(liquid) / next.block().liquidCapacity; + float fract = tile.entity.liquids().get(liquid) / liquidCapacity * liquidPressure; + float flow = Math.min(Mathf.clamp((fract - ofract) * (1f)) * (liquidCapacity), tile.entity.liquids().get(liquid)); + flow = Math.min(flow, next.block().liquidCapacity - next.entity.liquids().get(liquid) - 0.001f); if(flow > 0f && ofract <= fract && next.block().acceptLiquid(next, tile, liquid, flow)){ next.block().handleLiquid(next, tile, liquid, flow); - tile.entity.liquids.remove(liquid, flow); + tile.entity.liquids().remove(liquid, flow); return flow; }else if(ofract > 0.1f && fract > 0.1f){ - Liquid other = next.entity.liquids.current(); + Liquid other = next.entity.liquids().current(); if((other.flammability > 0.3f && liquid.temperature > 0.7f) || (liquid.flammability > 0.3f && other.temperature > 0.7f)){ tile.entity.damage(1 * Time.delta()); next.entity.damage(1 * Time.delta()); if(Mathf.chance(0.1 * Time.delta())){ - Effects.effect(Fx.fire, (tile.worldx() + next.worldx()) / 2f, (tile.worldy() + next.worldy()) / 2f); + Fx.fire.at((tile.worldx() + next.worldx()) / 2f, (tile.worldy() + next.worldy()) / 2f); } }else if((liquid.temperature > 0.7f && other.temperature < 0.55f) || (other.temperature > 0.7f && liquid.temperature < 0.55f)){ - tile.entity.liquids.remove(liquid, Math.min(tile.entity.liquids.get(liquid), 0.7f * Time.delta())); + tile.entity.liquids().remove(liquid, Math.min(tile.entity.liquids().get(liquid), 0.7f * Time.delta())); if(Mathf.chance(0.2f * Time.delta())){ - Effects.effect(Fx.steam, (tile.worldx() + next.worldx()) / 2f, (tile.worldy() + next.worldy()) / 2f); + Fx.steam.at((tile.worldx() + next.worldx()) / 2f, (tile.worldy() + next.worldy()) / 2f); } } } } }else if(leakResistance != 100f && !next.block().solid && !next.block().hasLiquids){ - float leakAmount = tile.entity.liquids.get(liquid) / leakResistance; - Puddle.deposit(next, tile, liquid, leakAmount); - tile.entity.liquids.remove(liquid, leakAmount); + float leakAmount = tile.entity.liquids().get(liquid) / leakResistance; + //TODO deposit puddle + //Puddle.deposit(next, tile, liquid, leakAmount); + tile.entity.liquids().remove(liquid, leakAmount); } return 0; } @@ -203,7 +199,7 @@ public abstract class BlockStorage extends UnlockableContent{ incrementDump(tile, proximity.size); Tile other = proximity.get((i + dump) % proximity.size); Tile in = Edges.getFacingEdge(tile, other); - if(other.getTeam() == tile.getTeam() && other.block().acceptItem(item, other, in) && canDump(tile, other, item)){ + if(other.team() == tile.team() && other.block().acceptItem(item, other, in) && canDump(tile, other, item)){ other.block().handleItem(item, other, in); return; } @@ -222,8 +218,8 @@ public abstract class BlockStorage extends UnlockableContent{ * @param todump Item to dump. Can be null to dump anything. */ public boolean tryDump(Tile tile, Item todump){ - TileEntity entity = tile.entity; - if(entity == null || !hasItems || tile.entity.items.total() == 0 || (todump != null && !entity.items.has(todump))) + Tilec entity = tile.entity; + if(entity == null || !hasItems || tile.entity.items().total() == 0 || (todump != null && !entity.items().has(todump))) return false; Array proximity = entity.proximity(); @@ -240,18 +236,18 @@ public abstract class BlockStorage extends UnlockableContent{ for(int ii = 0; ii < Vars.content.items().size; ii++){ Item item = Vars.content.item(ii); - if(other.getTeam() == tile.getTeam() && entity.items.has(item) && other.block().acceptItem(item, other, in) && canDump(tile, other, item)){ + if(other.team() == tile.team() && entity.items().has(item) && other.block().acceptItem(item, other, in) && canDump(tile, other, item)){ other.block().handleItem(item, other, in); - tile.entity.items.remove(item, 1); + tile.entity.items().remove(item, 1); incrementDump(tile, proximity.size); return true; } } }else{ - if(other.getTeam() == tile.getTeam() && other.block().acceptItem(todump, other, in) && canDump(tile, other, todump)){ + if(other.team() == tile.team() && other.block().acceptItem(todump, other, in) && canDump(tile, other, todump)){ other.block().handleItem(todump, other, in); - tile.entity.items.remove(todump, 1); + tile.entity.items().remove(todump, 1); incrementDump(tile, proximity.size); return true; } @@ -274,9 +270,8 @@ public abstract class BlockStorage extends UnlockableContent{ /** Try offloading an item to a nearby container in its facing direction. Returns true if success. */ public boolean offloadDir(Tile tile, Item item){ - Tile other = tile.getNearby(tile.rotation()); - if(other != null) other = other.link(); - if(other != null && other.getTeam() == tile.getTeam() && other.block().acceptItem(item, other, tile)){ + Tile other = tile.front(); + if(other != null && other.team() == tile.team() && other.block().acceptItem(item, other, tile)){ other.block().handleItem(item, other, tile); return true; } diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index 1e20da65e8..0cafd2b416 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -38,7 +38,7 @@ public class Build{ tile.set(sub, team, rotation); tile.ent().setDeconstruct(previous); - tile.entity.health = tile.entity.maxHealth() * prevPercent; + tile.entity.health(tile.entity.maxHealth() * prevPercent); Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, true))); } @@ -78,7 +78,7 @@ public class Build{ return false; } - if(state.teams.eachEnemyCore(team, core -> Mathf.dst(x * tilesize + type.offset(), y * tilesize + type.offset(), core.x, core.y) < state.rules.enemyCoreBuildRadius + type.size * tilesize / 2f)){ + if(state.teams.eachEnemyCore(team, core -> Mathf.dst(x * tilesize + type.offset(), y * tilesize + type.offset(), core.x(), core.y()) < state.rules.enemyCoreBuildRadius + type.size * tilesize / 2f)){ return false; } diff --git a/core/src/mindustry/world/CachedTile.java b/core/src/mindustry/world/CachedTile.java index 281828dcd7..4d2466f6e7 100644 --- a/core/src/mindustry/world/CachedTile.java +++ b/core/src/mindustry/world/CachedTile.java @@ -1,6 +1,6 @@ package mindustry.world; -import mindustry.entities.type.TileEntity; +import mindustry.gen.*; import mindustry.game.Team; import mindustry.world.modules.*; @@ -15,7 +15,7 @@ public class CachedTile extends Tile{ } @Override - public Team getTeam(){ + public Team team(){ return Team.get(getTeamID()); } @@ -32,13 +32,13 @@ public class CachedTile extends Tile{ Block block = block(); if(block.hasEntity()){ - TileEntity n = block.newEntity(); - n.cons = new ConsumeModule(entity); - n.tile = this; - n.block = block; - if(block.hasItems) n.items = new ItemModule(); - if(block.hasLiquids) n.liquids = new LiquidModule(); - if(block.hasPower) n.power = new PowerModule(); + Tilec n = block.newEntity(); + n.cons(new ConsumeModule(entity)); + n.tile(this); + n.block(block); + if(block.hasItems) n.items(new ItemModule()); + if(block.hasLiquids) n.liquids(new LiquidModule()); + if(block.hasPower) n.power(new PowerModule()); entity = n; } } diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java index c48f167dd8..58b1ddc1a4 100644 --- a/core/src/mindustry/world/Tile.java +++ b/core/src/mindustry/world/Tile.java @@ -7,8 +7,6 @@ import arc.struct.*; import arc.util.ArcAnnotate.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; import mindustry.game.*; import mindustry.gen.*; import mindustry.type.*; @@ -17,11 +15,11 @@ import mindustry.world.modules.*; import static mindustry.Vars.*; -public class Tile implements Position, TargetTrait{ +public class Tile implements Position{ /** Tile traversal cost. */ public byte cost = 1; /** Tile entity, usually null. */ - public TileEntity entity; + public Tilec entity; public short x, y; protected Block block; protected Floor floor; @@ -145,8 +143,7 @@ public class Tile implements Position, TargetTrait{ return (T)block; } - @Override - public Team getTeam(){ + public Team team(){ return Team.get(link().team); } @@ -284,7 +281,7 @@ public class Tile implements Position, TargetTrait{ } public boolean isEnemyCheat(){ - return getTeam() == state.rules.waveTeam && state.rules.enemyCheat; + return team() == state.rules.waveTeam && state.rules.enemyCheat; } public boolean isLinked(){ @@ -388,7 +385,7 @@ public class Tile implements Position, TargetTrait{ } public boolean interactable(Team team){ - return state.teams.canInteract(team, getTeam()); + return state.teams.canInteract(team, team()); } public @Nullable Item drop(){ @@ -461,12 +458,12 @@ public class Tile implements Position, TargetTrait{ if(block.hasEntity()){ entity = block.newEntity().init(this, block.update); - entity.cons = new ConsumeModule(entity); - if(block.hasItems) entity.items = new ItemModule(); - if(block.hasLiquids) entity.liquids = new LiquidModule(); + entity.cons(new ConsumeModule(entity)); + if(block.hasItems) entity.items(new ItemModule()); + if(block.hasLiquids) entity.liquids(new LiquidModule()); if(block.hasPower){ - entity.power = new PowerModule(); - entity.power.graph.add(this); + entity.power(new PowerModule()); + entity.power().graph.add(this); } if(!world.isGenerating()){ @@ -487,39 +484,19 @@ public class Tile implements Position, TargetTrait{ world.notifyChanged(this); } - @Override - public boolean isDead(){ - return entity == null; - } - - @Override - public Vec2 velocity(){ - return Vec2.ZERO; - } - @Override public float getX(){ return drawx(); } - @Override - public void setX(float x){ - throw new IllegalArgumentException("Tile position cannot change."); - } - @Override public float getY(){ return drawy(); } - @Override - public void setY(float y){ - throw new IllegalArgumentException("Tile position cannot change."); - } - @Override public String toString(){ - return floor.name + ":" + block.name + ":" + overlay + "[" + x + "," + y + "] " + "entity=" + (entity == null ? "null" : (entity.getClass())) + ":" + getTeam(); + return floor.name + ":" + block.name + ":" + overlay + "[" + x + "," + y + "] " + "entity=" + (entity == null ? "null" : (entity.getClass())) + ":" + team(); } //remote utility methods @@ -533,4 +510,21 @@ public class Tile implements Position, TargetTrait{ public static void setTile(Tile tile, Block block, Team team, int rotation){ tile.set(block, team, rotation); } + + @Remote(called = Loc.server, unreliable = true) + public static void onTileDamage(Tile tile, float health){ + if(tile.entity != null){ + tile.entity.health(health); + + if(tile.entity.damaged()){ + indexer.notifyTileDamaged(tile.entity); + } + } + } + + @Remote(called = Loc.server) + public static void onTileDestroyed(Tile tile){ + if(tile.entity == null) return; + tile.entity.killed(); + } } diff --git a/core/src/mindustry/world/TileData.java b/core/src/mindustry/world/TileData.java new file mode 100644 index 0000000000..cf34d5ef60 --- /dev/null +++ b/core/src/mindustry/world/TileData.java @@ -0,0 +1,4 @@ +package mindustry.world; + +public class TileData{ +} diff --git a/core/src/mindustry/world/blocks/Autotiler.java b/core/src/mindustry/world/blocks/Autotiler.java index 4c25ca170d..dfcecf4a7d 100644 --- a/core/src/mindustry/world/blocks/Autotiler.java +++ b/core/src/mindustry/world/blocks/Autotiler.java @@ -4,7 +4,7 @@ import arc.math.*; import arc.math.geom.*; import arc.util.*; import arc.util.ArcAnnotate.*; -import mindustry.entities.traits.BuilderTrait.*; +import mindustry.entities.units.*; import mindustry.world.*; import java.util.*; diff --git a/core/src/mindustry/world/blocks/BuildBlock.java b/core/src/mindustry/world/blocks/BuildBlock.java index 14187850ba..7f40261a5a 100644 --- a/core/src/mindustry/world/blocks/BuildBlock.java +++ b/core/src/mindustry/world/blocks/BuildBlock.java @@ -1,18 +1,15 @@ package mindustry.world.blocks; import arc.*; -import mindustry.annotations.Annotations.*; import arc.Graphics.*; import arc.Graphics.Cursor.*; import arc.graphics.g2d.*; import arc.math.*; import arc.util.ArcAnnotate.*; import arc.util.*; +import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.entities.*; -import mindustry.entities.effect.*; -import mindustry.entities.traits.BuilderTrait.*; -import mindustry.entities.type.*; import mindustry.game.EventType.*; import mindustry.game.*; import mindustry.gen.*; @@ -55,10 +52,10 @@ public class BuildBlock extends Block{ @Remote(called = Loc.server) public static void onDeconstructFinish(Tile tile, Block block, int builderID){ - Team team = tile.getTeam(); - Effects.effect(Fx.breakBlock, tile.drawx(), tile.drawy(), block.size); + Team team = tile.team(); + Fx.breakBlock.at(tile.drawx(), tile.drawy(), block.size); + Events.fire(new BlockBuildEndEvent(tile, Groups.player.getByID(builderID), team, true)); tile.remove(); - Events.fire(new BlockBuildEndEvent(tile, playerGroup.getByID(builderID), team, true)); if(shouldPlay()) Sounds.breaks.at(tile, calcPitch(false)); } @@ -68,15 +65,15 @@ public class BuildBlock extends Block{ float healthf = tile.entity == null ? 1f : tile.entity.healthf(); tile.set(block, team, rotation); if(tile.entity != null){ - tile.entity.health = block.health * healthf; + tile.entity.health(block.health * healthf); } //last builder was this local client player, call placed() - if(!headless && builderID == player.id){ + if(!headless && builderID == player.id()){ if(!skipConfig){ tile.block().playerPlaced(tile); } } - Effects.effect(Fx.placeBlock, tile.drawx(), tile.drawy(), block.size); + Fx.placeBlock.at(tile.drawx(), tile.drawy(), block.size); } static boolean shouldPlay(){ @@ -107,7 +104,7 @@ public class BuildBlock extends Block{ Call.onConstructFinish(tile, block, builderID, rotation, team, skipConfig); tile.block().placed(tile); - Events.fire(new BlockBuildEndEvent(tile, playerGroup.getByID(builderID), team, false)); + Events.fire(new BlockBuildEndEvent(tile, Groups.player.getByID(builderID), team, false)); if(shouldPlay()) Sounds.place.at(tile, calcPitch(true)); } @@ -140,25 +137,27 @@ public class BuildBlock extends Block{ } @Override - public void tapped(Tile tile, Player player){ + public void tapped(Tile tile, Playerc player){ BuildEntity entity = tile.ent(); + //TODO building + /* //if the target is constructible, begin constructing if(entity.cblock != null){ if(player.buildWasAutoPaused && !player.isBuilding){ player.isBuilding = true; } //player.clearBuilding(); - player.addBuildRequest(new BuildRequest(tile.x, tile.y, tile.rotation(), entity.cblock), false); - } + player.builder().addBuild(new BuildRequest(tile.x, tile.y, tile.rotation(), entity.cblock), false); + }*/ } @Override public void onDestroyed(Tile tile){ - Effects.effect(Fx.blockExplosionSmoke, tile); + Fx.blockExplosionSmoke.at(tile); if(!tile.floor().solid && !tile.floor().isLiquid){ - RubbleDecal.create(tile.drawx(), tile.drawy(), size); + Effects.rubble(tile.drawx(), tile.drawy(), size); } } @@ -218,7 +217,7 @@ public class BuildBlock extends Block{ private float[] accumulator; private float[] totalAccumulator; - public boolean construct(Unit builder, @Nullable TileEntity core, float amount, boolean configured){ + public boolean construct(Unitc builder, @Nullable Tilec core, float amount, boolean configured){ if(cblock == null){ kill(); return false; @@ -228,7 +227,7 @@ public class BuildBlock extends Block{ setConstruct(previous, cblock); } - float maxProgress = core == null ? amount : checkRequired(core.items, amount, false); + float maxProgress = core == null ? amount : checkRequired(core.items(), amount, false); for(int i = 0; i < cblock.requirements.length; i++){ int reqamount = Math.round(state.rules.buildCostMultiplier * cblock.requirements[i].amount); @@ -236,22 +235,19 @@ public class BuildBlock extends Block{ totalAccumulator[i] = Math.min(totalAccumulator[i] + reqamount * maxProgress, reqamount); } - maxProgress = core == null ? maxProgress : checkRequired(core.items, maxProgress, true); + maxProgress = core == null ? maxProgress : checkRequired(core.items(), maxProgress, true); progress = Mathf.clamp(progress + maxProgress); - - if(builder instanceof Player){ - builderID = builder.getID(); - } + builderID = builder.id(); if(progress >= 1f || state.rules.infiniteResources){ - constructed(tile, cblock, builderID, tile.rotation(), builder.getTeam(), configured); + constructed(tile, cblock, builderID, tile.rotation(), builder.team(), configured); return true; } return false; } - public void deconstruct(Unit builder, @Nullable TileEntity core, float amount){ + public void deconstruct(Unitc builder, @Nullable Tilec core, float amount){ float deconstructMultiplier = 0.5f; if(cblock != null){ @@ -272,8 +268,8 @@ public class BuildBlock extends Block{ if(clampedAmount > 0 && accumulated > 0){ //if it's positive, add it to the core if(core != null){ - int accepting = core.tile.block().acceptStack(requirements[i].item, accumulated, core.tile, builder); - core.tile.block().handleStack(requirements[i].item, accepting, core.tile, builder); + int accepting = core.tile().block().acceptStack(requirements[i].item, accumulated, core.tile(), builder); + core.tile().block().handleStack(requirements[i].item, accepting, core.tile(), builder); accumulator[i] -= accepting; }else{ accumulator[i] -= accumulated; @@ -284,8 +280,8 @@ public class BuildBlock extends Block{ progress = Mathf.clamp(progress - amount); - if(builder instanceof Player){ - builderID = builder.getID(); + if(builder instanceof Playerc){ + builderID = builder.id(); } if(progress <= 0 || state.rules.infiniteResources){ @@ -369,8 +365,8 @@ public class BuildBlock extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); progress = stream.readFloat(); short pid = stream.readShort(); short rid = stream.readShort(); diff --git a/core/src/mindustry/world/blocks/Floor.java b/core/src/mindustry/world/blocks/Floor.java index 3fe5cf71a8..35a6990287 100644 --- a/core/src/mindustry/world/blocks/Floor.java +++ b/core/src/mindustry/world/blocks/Floor.java @@ -1,15 +1,15 @@ package mindustry.world.blocks; import arc.*; -import arc.struct.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.graphics.g2d.TextureAtlas.*; import arc.math.*; import arc.math.geom.*; import arc.util.ArcAnnotate.*; +import arc.struct.*; import mindustry.content.*; -import mindustry.entities.Effects.*; +import mindustry.entities.*; import mindustry.graphics.*; import mindustry.graphics.MultiPacker.*; import mindustry.type.*; @@ -53,6 +53,10 @@ public class Floor extends Block{ public Effect updateEffect = Fx.none; /** Array of affinities to certain things. */ public Attributes attributes = new Attributes(); + /** Whether this ore generates in maps by default. */ + public boolean oreDefault = false; + /** Ore generation params. */ + public float oreScale = 24f, oreThreshold = 0.828f; protected TextureRegion[][] edges; protected byte eq = 0; diff --git a/core/src/mindustry/world/blocks/LiquidBlock.java b/core/src/mindustry/world/blocks/LiquidBlock.java index 91cb843283..9b8c45842f 100644 --- a/core/src/mindustry/world/blocks/LiquidBlock.java +++ b/core/src/mindustry/world/blocks/LiquidBlock.java @@ -36,7 +36,7 @@ public class LiquidBlock extends Block{ @Override public void draw(Tile tile){ - LiquidModule mod = tile.entity.liquids; + LiquidModule mod = tile.entity.liquids(); int rotation = rotate ? tile.rotation() * 90 : 0; diff --git a/core/src/mindustry/world/blocks/RespawnBlock.java b/core/src/mindustry/world/blocks/RespawnBlock.java index b27b0af621..123cdb71c5 100644 --- a/core/src/mindustry/world/blocks/RespawnBlock.java +++ b/core/src/mindustry/world/blocks/RespawnBlock.java @@ -2,7 +2,7 @@ package mindustry.world.blocks; import arc.graphics.g2d.*; import arc.math.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; import mindustry.ui.*; @@ -12,7 +12,7 @@ import static mindustry.Vars.net; public class RespawnBlock{ - public static void drawRespawn(Tile tile, float heat, float progress, float time, Player player, Mech to){ + public static void drawRespawn(Tile tile, float heat, float progress, float time, Playerc player, UnitDef to){ progress = Mathf.clamp(progress); Draw.color(Pal.darkMetal); @@ -67,7 +67,7 @@ public class RespawnBlock{ Draw.reset(); if(net.active() && player != null){ - tile.block().drawPlaceText(player.name, tile.x, tile.y - (Math.max((tile.block().size-1)/2, 0)), true); + tile.block().drawPlaceText(player.name(), tile.x, tile.y - (Math.max((tile.block().size-1)/2, 0)), true); } } } diff --git a/core/src/mindustry/world/blocks/defense/DeflectorWall.java b/core/src/mindustry/world/blocks/defense/DeflectorWall.java index ae535ca8a6..0273ca981a 100644 --- a/core/src/mindustry/world/blocks/defense/DeflectorWall.java +++ b/core/src/mindustry/world/blocks/defense/DeflectorWall.java @@ -5,8 +5,7 @@ import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; import arc.util.*; -import mindustry.entities.type.*; -import mindustry.entities.type.Bullet; +import mindustry.gen.*; import mindustry.world.*; import static mindustry.Vars.tilesize; @@ -42,33 +41,36 @@ public class DeflectorWall extends Wall{ } @Override - public void handleBulletHit(TileEntity entity, Bullet bullet){ + public void handleBulletHit(Tilec entity, Bulletc bullet){ super.handleBulletHit(entity, bullet); + //TODO fix and test //doesn't reflect powerful bullets - if(bullet.damage() > maxDamageDeflect || bullet.isDeflected()) return; + if(bullet.damage() > maxDamageDeflect) return; - float penX = Math.abs(entity.x - bullet.x), penY = Math.abs(entity.y - bullet.y); + float penX = Math.abs(entity.getX() - bullet.x()), penY = Math.abs(entity.getY() - bullet.y()); bullet.hitbox(rect2); - Vec2 position = Geometry.raycastRect(bullet.x - bullet.velocity().x*Time.delta(), bullet.y - bullet.velocity().y*Time.delta(), bullet.x + bullet.velocity().x*Time.delta(), bullet.y + bullet.velocity().y*Time.delta(), - rect.setSize(size * tilesize + rect2.width*2 + rect2.height*2).setCenter(entity.x, entity.y)); + Vec2 position = Geometry.raycastRect(bullet.x() - bullet.vel().x*Time.delta(), bullet.y() - bullet.vel().y*Time.delta(), bullet.x() + bullet.vel().x*Time.delta(), bullet.y() + bullet.vel().y*Time.delta(), + rect.setSize(size * tilesize + rect2.width*2 + rect2.height*2).setCenter(entity.getX(), entity.getY())); if(position != null){ bullet.set(position.x, position.y); } if(penX > penY){ - bullet.velocity().x *= -1; + bullet.vel().x *= -1; }else{ - bullet.velocity().y *= -1; + bullet.vel().y *= -1; } //bullet.updateVelocity(); - bullet.resetOwner(entity, entity.getTeam()); - bullet.scaleTime(1f); - bullet.deflect(); + bullet.owner(entity); + bullet.team(entity.team()); + bullet.time(bullet.time() + 1f); + //TODO deflect + //bullet.deflect(); ((DeflectorEntity)entity).hit = 1f; } diff --git a/core/src/mindustry/world/blocks/defense/Door.java b/core/src/mindustry/world/blocks/defense/Door.java index df75416207..020311c2f0 100644 --- a/core/src/mindustry/world/blocks/defense/Door.java +++ b/core/src/mindustry/world/blocks/defense/Door.java @@ -8,8 +8,7 @@ import arc.graphics.g2d.*; import arc.math.geom.*; import mindustry.content.*; import mindustry.entities.*; -import mindustry.entities.Effects.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.gen.*; import mindustry.world.*; @@ -35,7 +34,7 @@ public class Door extends Wall{ } @Remote(called = Loc.server) - public static void onDoorToggle(Player player, Tile tile, boolean open){ + public static void onDoorToggle(Playerc player, Tile tile, boolean open){ DoorEntity entity = tile.ent(); if(entity != null){ entity.open = open; @@ -43,9 +42,9 @@ public class Door extends Wall{ pathfinder.updateTile(tile); if(!entity.open){ - Effects.effect(door.openfx, tile.drawx(), tile.drawy()); + door.openfx.at(tile.drawx(), tile.drawy()); }else{ - Effects.effect(door.closefx, tile.drawx(), tile.drawy()); + door.closefx.at(tile.drawx(), tile.drawy()); } Sounds.door.at(tile); } @@ -80,10 +79,10 @@ public class Door extends Wall{ } @Override - public void tapped(Tile tile, Player player){ + public void tapped(Tile tile, Playerc player){ DoorEntity entity = tile.ent(); - if((Units.anyEntities(tile) && entity.open) || !tile.entity.timer.get(timerToggle, 30f)){ + if((Units.anyEntities(tile) && entity.open) || !tile.entity.timer(timerToggle, 30f)){ return; } @@ -100,8 +99,8 @@ public class Door extends Wall{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); open = stream.readBoolean(); } } diff --git a/core/src/mindustry/world/blocks/defense/ForceProjector.java b/core/src/mindustry/world/blocks/defense/ForceProjector.java index 36ed812b5d..85c2ca226e 100644 --- a/core/src/mindustry/world/blocks/defense/ForceProjector.java +++ b/core/src/mindustry/world/blocks/defense/ForceProjector.java @@ -8,10 +8,7 @@ import arc.math.*; import arc.math.geom.*; import arc.util.*; import mindustry.content.*; -import mindustry.entities.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; -import mindustry.entities.type.BaseEntity; +import mindustry.gen.*; import mindustry.graphics.*; import mindustry.world.*; import mindustry.world.consumers.*; @@ -19,7 +16,7 @@ import mindustry.world.meta.*; import java.io.*; -import static mindustry.Vars.*; +import static mindustry.Vars.tilesize; public class ForceProjector extends Block{ public final int timerUse = timers++; @@ -37,12 +34,12 @@ public class ForceProjector extends Block{ private static Tile paramTile; private static ForceProjector paramBlock; private static ForceEntity paramEntity; - private static Cons shieldConsumer = trait -> { - if(trait.canBeAbsorbed() && trait.getTeam() != paramTile.getTeam() && Intersector.isInsideHexagon(trait.getX(), trait.getY(), paramBlock.realRadius(paramEntity) * 2f, paramTile.drawx(), paramTile.drawy())){ + private static Cons shieldConsumer = trait -> { + if(trait.team() != paramTile.team() && Intersector.isInsideHexagon(trait.x(), trait.y(), paramBlock.realRadius(paramEntity) * 2f, paramTile.drawx(), paramTile.drawy())){ trait.absorb(); - Effects.effect(Fx.absorb, trait); + Fx.absorb.at(trait); paramEntity.hit = 1f; - paramEntity.buildup += trait.getShieldDamage() * paramEntity.warmup; + paramEntity.buildup += trait.damage() * paramEntity.warmup; } }; @@ -92,22 +89,23 @@ public class ForceProjector extends Block{ ForceEntity entity = tile.ent(); if(entity.shield == null){ - entity.shield = new ShieldEntity(tile); - entity.shield.add(); + //TODO implement + //entity.shield = new ShieldEntity(tile); + //entity.shield.add(); } boolean phaseValid = consumes.get(ConsumeType.item).valid(tile.entity); entity.phaseHeat = Mathf.lerpDelta(entity.phaseHeat, Mathf.num(phaseValid), 0.1f); - if(phaseValid && !entity.broken && entity.timer.get(timerUse, phaseUseTime) && entity.efficiency() > 0){ - entity.cons.trigger(); + if(phaseValid && !entity.broken && entity.timer(timerUse, phaseUseTime) && entity.efficiency() > 0){ + entity.consume(); } entity.radscl = Mathf.lerpDelta(entity.radscl, entity.broken ? 0f : entity.warmup, 0.05f); if(Mathf.chance(Time.delta() * entity.buildup / breakage * 0.1f)){ - Effects.effect(Fx.reactorsmoke, tile.drawx() + Mathf.range(tilesize / 2f), tile.drawy() + Mathf.range(tilesize / 2f)); + Fx.reactorsmoke.at(tile.drawx() + Mathf.range(tilesize / 2f), tile.drawy() + Mathf.range(tilesize / 2f)); } entity.warmup = Mathf.lerpDelta(entity.warmup, entity.efficiency(), 0.1f); @@ -117,7 +115,7 @@ public class ForceProjector extends Block{ ConsumeLiquidFilter cons = consumes.get(ConsumeType.liquid); if(cons.valid(entity)){ cons.update(entity); - scale *= (cooldownLiquid * (1f + (entity.liquids.current().heatCapacity - 0.4f) * 0.9f)); + scale *= (cooldownLiquid * (1f + (entity.liquids().current().heatCapacity - 0.4f) * 0.9f)); } entity.buildup -= Time.delta() * scale; @@ -130,7 +128,7 @@ public class ForceProjector extends Block{ if(entity.buildup >= breakage && !entity.broken){ entity.broken = true; entity.buildup = breakage; - Effects.effect(Fx.shieldBreak, tile.drawx(), tile.drawy(), radius); + Fx.shieldBreak.at(tile.drawx(), tile.drawy(), radius); } if(entity.hit > 0f){ @@ -142,7 +140,8 @@ public class ForceProjector extends Block{ paramTile = tile; paramEntity = entity; paramBlock = this; - bulletGroup.intersect(tile.drawx() - realRadius, tile.drawy() - realRadius, realRadius*2f, realRadius * 2f, shieldConsumer); + //TODO fix + //bulletGroup.intersect(tile.drawx() - realRadius, tile.drawy() - realRadius, realRadius*2f, realRadius * 2f, shieldConsumer); } float realRadius(ForceEntity entity){ @@ -183,8 +182,8 @@ public class ForceProjector extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); broken = stream.readBoolean(); buildup = stream.readFloat(); radscl = stream.readFloat(); @@ -193,6 +192,14 @@ public class ForceProjector extends Block{ } } + //TODO fix + class ShieldEntity{ + + } + /* + //@EntityDef({Drawc.class}) + //class ShieldDef{} + public class ShieldEntity extends BaseEntity implements DrawTrait{ final ForceEntity entity; @@ -247,5 +254,5 @@ public class ForceProjector extends Block{ public EntityGroup targetGroup(){ return shieldGroup; } - } + }*/ } diff --git a/core/src/mindustry/world/blocks/defense/MendProjector.java b/core/src/mindustry/world/blocks/defense/MendProjector.java index 30ea5fbda7..03f42fcced 100644 --- a/core/src/mindustry/world/blocks/defense/MendProjector.java +++ b/core/src/mindustry/world/blocks/defense/MendProjector.java @@ -7,8 +7,7 @@ import arc.graphics.g2d.*; import arc.math.Mathf; import arc.util.*; import mindustry.content.Fx; -import mindustry.entities.Effects; -import mindustry.entities.type.TileEntity; +import mindustry.gen.*; import mindustry.graphics.*; import mindustry.world.*; import mindustry.world.meta.*; @@ -65,37 +64,23 @@ public class MendProjector extends Block{ @Override public void update(Tile tile){ MendEntity entity = tile.ent(); - entity.heat = Mathf.lerpDelta(entity.heat, entity.cons.valid() || tile.isEnemyCheat() ? 1f : 0f, 0.08f); + entity.heat = Mathf.lerpDelta(entity.heat, entity.consValid() || tile.isEnemyCheat() ? 1f : 0f, 0.08f); entity.charge += entity.heat * entity.delta(); - entity.phaseHeat = Mathf.lerpDelta(entity.phaseHeat, Mathf.num(entity.cons.optionalValid()), 0.1f); + entity.phaseHeat = Mathf.lerpDelta(entity.phaseHeat, Mathf.num(entity.cons().optionalValid()), 0.1f); - if(entity.cons.optionalValid() && entity.timer.get(timerUse, useTime) && entity.efficiency() > 0){ - entity.cons.trigger(); + if(entity.cons().optionalValid() && entity.timer(timerUse, useTime) && entity.efficiency() > 0){ + entity.consume(); } if(entity.charge >= reload){ float realRange = range + entity.phaseHeat * phaseRangeBoost; entity.charge = 0f; - int tileRange = (int)(realRange / tilesize + 1); - healed.clear(); - - for(int x = -tileRange + tile.x; x <= tileRange + tile.x; x++){ - for(int y = -tileRange + tile.y; y <= tileRange + tile.y; y++){ - if(!Mathf.within(x * tilesize, y * tilesize, tile.drawx(), tile.drawy(), realRange)) continue; - - Tile other = world.ltile(x, y); - - if(other == null) continue; - - if(other.getTeamID() == tile.getTeamID() && !healed.contains(other.pos()) && other.entity != null && other.entity.health < other.entity.maxHealth()){ - other.entity.healBy(other.entity.maxHealth() * (healPercent + entity.phaseHeat * phaseBoost) / 100f * entity.efficiency()); - Effects.effect(Fx.healBlockFull, Tmp.c1.set(baseColor).lerp(phaseColor, entity.phaseHeat), other.drawx(), other.drawy(), other.block().size); - healed.add(other.pos()); - } - } - } + indexer.eachBlock(entity, realRange, other -> other.entity.damaged(), other -> { + other.entity.heal(other.entity.maxHealth() * (healPercent + entity.phaseHeat * phaseBoost) / 100f * entity.efficiency()); + Fx.healBlockFull.at(other.drawx(), other.drawy(), other.block().size, Tmp.c1.set(baseColor).lerp(phaseColor, entity.phaseHeat)); + }); } } @@ -121,9 +106,7 @@ public class MendProjector extends Block{ Draw.color(baseColor, phaseColor, entity.phaseHeat); Draw.alpha(entity.heat * Mathf.absin(Time.time(), 10f, 1f) * 0.5f); - //Draw.blend(Blending.additive); Draw.rect(topRegion, tile.drawx(), tile.drawy()); - //Draw.blend(); Draw.alpha(1f); Lines.stroke((2f * f + 0.2f) * entity.heat); @@ -150,8 +133,8 @@ public class MendProjector extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); heat = stream.readFloat(); phaseHeat = stream.readFloat(); } diff --git a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java index 945aeb3602..482cb640e6 100644 --- a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java +++ b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java @@ -6,7 +6,7 @@ import arc.graphics.Color; import arc.graphics.g2d.*; import arc.math.Mathf; import arc.util.Time; -import mindustry.entities.type.TileEntity; +import mindustry.gen.*; import mindustry.graphics.*; import mindustry.world.*; import mindustry.world.meta.*; @@ -75,13 +75,13 @@ public class OverdriveProjector extends Block{ @Override public void update(Tile tile){ OverdriveEntity entity = tile.ent(); - entity.heat = Mathf.lerpDelta(entity.heat, entity.cons.valid() ? 1f : 0f, 0.08f); + entity.heat = Mathf.lerpDelta(entity.heat, entity.consValid() ? 1f : 0f, 0.08f); entity.charge += entity.heat * Time.delta(); - entity.phaseHeat = Mathf.lerpDelta(entity.phaseHeat, Mathf.num(entity.cons.optionalValid()), 0.1f); + entity.phaseHeat = Mathf.lerpDelta(entity.phaseHeat, Mathf.num(entity.cons().optionalValid()), 0.1f); - if(entity.timer.get(timerUse, useTime) && entity.efficiency() > 0){ - entity.cons.trigger(); + if(entity.timer(timerUse, useTime) && entity.efficiency() > 0){ + entity.consume(); } if(entity.charge >= reload){ @@ -89,27 +89,7 @@ public class OverdriveProjector extends Block{ float realBoost = (speedBoost + entity.phaseHeat * speedBoostPhase) * entity.efficiency(); entity.charge = 0f; - - int tileRange = (int)(realRange / tilesize + 1); - healed.clear(); - - for(int x = -tileRange + tile.x; x <= tileRange + tile.x; x++){ - for(int y = -tileRange + tile.y; y <= tileRange + tile.y; y++){ - if(!Mathf.within(x * tilesize, y * tilesize, tile.drawx(), tile.drawy(), realRange)) continue; - - Tile other = world.ltile(x, y); - - if(other == null) continue; - - if(other.getTeamID() == tile.getTeamID() && !healed.contains(other.pos()) && other.entity != null){ - if(other.entity.timeScale <= realBoost){ - other.entity.timeScaleDuration = Math.max(other.entity.timeScaleDuration, reload + 1f); - other.entity.timeScale = Math.max(other.entity.timeScale, realBoost); - } - healed.add(other.pos()); - } - } - } + indexer.eachBlock(entity, realRange, other -> other.entity.timeScale() <= realBoost, other -> other.entity.applyBoost(realBoost, reload + 1f)); } } @@ -151,8 +131,8 @@ public class OverdriveProjector extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); heat = stream.readFloat(); phaseHeat = stream.readFloat(); } diff --git a/core/src/mindustry/world/blocks/defense/ShockMine.java b/core/src/mindustry/world/blocks/defense/ShockMine.java index 61864556b8..8a1426d7ac 100644 --- a/core/src/mindustry/world/blocks/defense/ShockMine.java +++ b/core/src/mindustry/world/blocks/defense/ShockMine.java @@ -1,14 +1,11 @@ package mindustry.world.blocks.defense; -import arc.graphics.g2d.Draw; -import arc.graphics.g2d.Fill; -import arc.math.Mathf; -import mindustry.entities.effect.Lightning; -import mindustry.entities.type.Unit; -import mindustry.graphics.Layer; -import mindustry.graphics.Pal; -import mindustry.world.Block; -import mindustry.world.Tile; +import arc.graphics.g2d.*; +import arc.math.*; +import mindustry.entities.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.world.*; public class ShockMine extends Block{ public final int timerDamage = timers++; @@ -32,7 +29,7 @@ public class ShockMine extends Block{ @Override public void drawLayer(Tile tile){ super.draw(tile); - Draw.color(tile.getTeam().color); + Draw.color(tile.team().color); Draw.alpha(0.22f); Fill.rect(tile.drawx(), tile.drawy(), 2f, 2f); Draw.color(); @@ -49,10 +46,10 @@ public class ShockMine extends Block{ } @Override - public void unitOn(Tile tile, Unit unit){ - if(unit.getTeam() != tile.getTeam() && tile.entity.timer.get(timerDamage, cooldown)){ + public void unitOn(Tile tile, Unitc unit){ + if(unit.team() != tile.team() && tile.entity.timer(timerDamage, cooldown)){ for(int i = 0; i < tendrils; i++){ - Lightning.create(tile.getTeam(), Pal.lancerLaser, damage, tile.drawx(), tile.drawy(), Mathf.random(360f), length); + Lightning.create(tile.team(), Pal.lancerLaser, damage, tile.drawx(), tile.drawy(), Mathf.random(360f), length); } tile.entity.damage(tileDamage); } diff --git a/core/src/mindustry/world/blocks/defense/SurgeWall.java b/core/src/mindustry/world/blocks/defense/SurgeWall.java index d679169c8b..efc49331c5 100644 --- a/core/src/mindustry/world/blocks/defense/SurgeWall.java +++ b/core/src/mindustry/world/blocks/defense/SurgeWall.java @@ -1,10 +1,9 @@ package mindustry.world.blocks.defense; -import arc.math.Mathf; -import mindustry.entities.type.Bullet; -import mindustry.entities.effect.Lightning; -import mindustry.entities.type.TileEntity; -import mindustry.graphics.Pal; +import arc.math.*; +import mindustry.entities.*; +import mindustry.gen.*; +import mindustry.graphics.*; public class SurgeWall extends Wall{ public float lightningChance = 0.05f; @@ -16,10 +15,10 @@ public class SurgeWall extends Wall{ } @Override - public void handleBulletHit(TileEntity entity, Bullet bullet){ + public void handleBulletHit(Tilec entity, Bulletc bullet){ super.handleBulletHit(entity, bullet); if(Mathf.chance(lightningChance)){ - Lightning.create(entity.getTeam(), Pal.surge, lightningDamage, bullet.x, bullet.y, bullet.rot() + 180f, lightningLength); + Lightning.create(entity.team(), Pal.surge, lightningDamage, bullet.x(), bullet.y(), bullet.rotation() + 180f, lightningLength); } } } diff --git a/core/src/mindustry/world/blocks/defense/turrets/ArtilleryTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ArtilleryTurret.java index a74e4abf94..730718068d 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/ArtilleryTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/ArtilleryTurret.java @@ -3,7 +3,6 @@ package mindustry.world.blocks.defense.turrets; import arc.math.Mathf; import arc.math.geom.Vec2; import mindustry.entities.Predict; -import mindustry.entities.type.Bullet; import mindustry.entities.bullet.BulletType; import mindustry.world.Tile; @@ -37,7 +36,7 @@ public class ArtilleryTurret extends ItemTurret{ float maxTraveled = type.lifetime * type.speed; for(int i = 0; i < shots; i++){ - Bullet.create(ammo, tile.entity, tile.getTeam(), tile.drawx() + tr.x, tile.drawy() + tr.y, + ammo.create(tile.entity, tile.team(), tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation + Mathf.range(inaccuracy + type.inaccuracy), 1f + Mathf.range(velocityInaccuracy), (dst / maxTraveled)); } diff --git a/core/src/mindustry/world/blocks/defense/turrets/ChargeTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ChargeTurret.java index 9f4b3c8ee2..831a4602d1 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/ChargeTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/ChargeTurret.java @@ -30,13 +30,13 @@ public class ChargeTurret extends PowerTurret{ useAmmo(tile); tr.trns(entity.rotation, size * tilesize / 2); - Effects.effect(chargeBeginEffect, tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); + chargeBeginEffect.at(tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); for(int i = 0; i < chargeEffects; i++){ Time.run(Mathf.random(chargeMaxDelay), () -> { if(!isTurret(tile)) return; tr.trns(entity.rotation, size * tilesize / 2); - Effects.effect(chargeEffect, tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); + chargeEffect.at(tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); }); } diff --git a/core/src/mindustry/world/blocks/defense/turrets/CooledTurret.java b/core/src/mindustry/world/blocks/defense/turrets/CooledTurret.java index 078e626009..1ec02cc07b 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/CooledTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/CooledTurret.java @@ -5,7 +5,6 @@ import arc.math.*; import arc.util.*; import mindustry.content.*; import mindustry.entities.*; -import mindustry.entities.Effects.*; import mindustry.game.EventType.*; import mindustry.type.*; import mindustry.world.*; @@ -37,7 +36,7 @@ public class CooledTurret extends Turret{ @Override public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - if(tile.entity.liquids.currentAmount() <= 0.001f){ + if(tile.entity.liquids().currentAmount() <= 0.001f){ Events.fire(Trigger.turretCool); } @@ -51,14 +50,14 @@ public class CooledTurret extends Turret{ float maxUsed = consumes.get(ConsumeType.liquid).amount; TurretEntity entity = tile.ent(); - Liquid liquid = entity.liquids.current(); + Liquid liquid = entity.liquids().current(); - float used = Math.min(Math.min(entity.liquids.get(liquid), maxUsed * Time.delta()), Math.max(0, ((reload - entity.reload) / coolantMultiplier) / liquid.heatCapacity)) * baseReloadSpeed(tile); + float used = Math.min(Math.min(entity.liquids().get(liquid), maxUsed * Time.delta()), Math.max(0, ((reload - entity.reload) / coolantMultiplier) / liquid.heatCapacity)) * baseReloadSpeed(tile); entity.reload += used * liquid.heatCapacity * coolantMultiplier; - entity.liquids.remove(liquid, used); + entity.liquids().remove(liquid, used); if(Mathf.chance(0.06 * used)){ - Effects.effect(coolEffect, tile.drawx() + Mathf.range(size * tilesize / 2f), tile.drawy() + Mathf.range(size * tilesize / 2f)); + coolEffect.at(tile.drawx() + Mathf.range(size * tilesize / 2f), tile.drawy() + Mathf.range(size * tilesize / 2f)); } } } diff --git a/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java index b40b8d58b6..151891b4c1 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java @@ -6,7 +6,7 @@ import arc.scene.ui.layout.*; import mindustry.*; import mindustry.content.*; import mindustry.entities.bullet.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.game.EventType.*; import mindustry.graphics.*; import mindustry.type.*; @@ -53,7 +53,7 @@ public class ItemTurret extends CooledTurret{ } @Override - public boolean valid(TileEntity entity){ + public boolean valid(Tilec entity){ //valid when there's any ammo in the turret return !((ItemTurretEntity)entity).ammo.isEmpty(); } @@ -86,7 +86,7 @@ public class ItemTurret extends CooledTurret{ } @Override - public int acceptStack(Item item, int amount, Tile tile, Unit source){ + public int acceptStack(Item item, int amount, Tile tile, Teamc source){ TurretEntity entity = tile.ent(); BulletType type = ammo.get(item); @@ -97,7 +97,7 @@ public class ItemTurret extends CooledTurret{ } @Override - public void handleStack(Item item, int amount, Tile tile, Unit source){ + public void handleStack(Item item, int amount, Tile tile, Teamc source){ for(int i = 0; i < amount; i++){ handleItem(item, tile, null); } @@ -162,8 +162,8 @@ public class ItemTurret extends CooledTurret{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); byte amount = stream.readByte(); for(int i = 0; i < amount; i++){ Item item = Vars.content.item(stream.readByte()); diff --git a/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java b/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java index 7a37c7af2b..c028b503cb 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java @@ -2,9 +2,8 @@ package mindustry.world.blocks.defense.turrets; import arc.math.*; import arc.util.*; -import mindustry.entities.*; import mindustry.entities.bullet.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.consumers.*; @@ -45,7 +44,7 @@ public class LaserTurret extends PowerTurret{ if(entity.bulletLife > 0 && entity.bullet != null){ tr.trns(entity.rotation, size * tilesize / 2f, 0f); - entity.bullet.rot(entity.rotation); + entity.bullet.rotation(entity.rotation); entity.bullet.set(tile.drawx() + tr.x, tile.drawy() + tr.y); entity.bullet.time(0f); entity.heat = 1f; @@ -65,22 +64,22 @@ public class LaserTurret extends PowerTurret{ return; } - if(entity.reload >= reload && (entity.cons.valid() || tile.isEnemyCheat())){ + if(entity.reload >= reload && (entity.consValid() || tile.isEnemyCheat())){ BulletType type = peekAmmo(tile); shoot(tile, type); entity.reload = 0f; }else{ - Liquid liquid = entity.liquids.current(); + Liquid liquid = entity.liquids().current(); float maxUsed = consumes.get(ConsumeType.liquid).amount; - float used = baseReloadSpeed(tile) * (tile.isEnemyCheat() ? maxUsed : Math.min(entity.liquids.get(liquid), maxUsed * Time.delta())) * liquid.heatCapacity * coolantMultiplier; + float used = baseReloadSpeed(tile) * (tile.isEnemyCheat() ? maxUsed : Math.min(entity.liquids().get(liquid), maxUsed * Time.delta())) * liquid.heatCapacity * coolantMultiplier; entity.reload += used; - entity.liquids.remove(liquid, used); + entity.liquids().remove(liquid, used); if(Mathf.chance(0.06 * used)){ - Effects.effect(coolEffect, tile.drawx() + Mathf.range(size * tilesize / 2f), tile.drawy() + Mathf.range(size * tilesize / 2f)); + coolEffect.at(tile.drawx() + Mathf.range(size * tilesize / 2f), tile.drawy() + Mathf.range(size * tilesize / 2f)); } } } @@ -96,7 +95,7 @@ public class LaserTurret extends PowerTurret{ protected void bullet(Tile tile, BulletType type, float angle){ LaserTurretEntity entity = tile.ent(); - entity.bullet = Bullet.create(type, tile.entity, tile.getTeam(), tile.drawx() + tr.x, tile.drawy() + tr.y, angle); + entity.bullet = type.create(tile.entity, tile.team(), tile.drawx() + tr.x, tile.drawy() + tr.y, angle); entity.bulletLife = shootDuration; } @@ -108,7 +107,7 @@ public class LaserTurret extends PowerTurret{ } class LaserTurretEntity extends TurretEntity{ - Bullet bullet; + Bulletc bullet; float bulletLife; } } diff --git a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java index 42336ea1d9..6515512697 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java @@ -5,8 +5,6 @@ import arc.graphics.g2d.*; import arc.struct.*; import mindustry.entities.*; import mindustry.entities.bullet.*; -import mindustry.entities.effect.*; -import mindustry.entities.type.*; import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; @@ -38,8 +36,8 @@ public class LiquidTurret extends Turret{ TurretEntity entity = tile.ent(); if(Core.atlas.isFound(reg(liquidRegion))){ - Draw.color(entity.liquids.current().color); - Draw.alpha(entity.liquids.total() / liquidCapacity); + Draw.color(entity.liquids().current().color); + Draw.alpha(entity.liquids().total() / liquidCapacity); Draw.rect(reg(liquidRegion), tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); Draw.color(); } @@ -52,7 +50,7 @@ public class LiquidTurret extends Turret{ stats.add(BlockStat.ammo, new AmmoListValue<>(ammo)); consumes.add(new ConsumeLiquidFilter(i -> ammo.containsKey(i), 1f){ @Override - public boolean valid(TileEntity entity){ + public boolean valid(Tilec entity){ return !((TurretEntity)entity).ammo.isEmpty(); } @@ -72,8 +70,9 @@ public class LiquidTurret extends Turret{ @Override protected boolean validateTarget(Tile tile){ TurretEntity entity = tile.ent(); - if(entity.liquids.current().canExtinguish() && entity.target instanceof Tile){ - return Fire.has(((Tile)entity.target).x, ((Tile)entity.target).y); + if(entity.liquids().current().canExtinguish() && entity.target instanceof Tile){ + //TODO fix + //return Fire.has(((Tile)entity.target).x, ((Tile)entity.target).y); } return super.validateTarget(tile); } @@ -81,14 +80,14 @@ public class LiquidTurret extends Turret{ @Override protected void findTarget(Tile tile){ TurretEntity entity = tile.ent(); - if(entity.liquids.current().canExtinguish()){ + if(entity.liquids().current().canExtinguish()){ int tr = (int)(range / tilesize); for(int x = -tr; x <= tr; x++){ for(int y = -tr; y <= tr; y++){ - if(Fire.has(x + tile.x, y + tile.y)){ - entity.target = world.tile(x + tile.x, y + tile.y); - return; - } + //if(Fire.has(x + tile.x, y + tile.y)){ + // entity.target = world.tile(x + tile.x, y + tile.y); + // return; + //} } } } @@ -102,8 +101,8 @@ public class LiquidTurret extends Turret{ TurretEntity entity = tile.ent(); - Effects.effect(type.shootEffect, entity.liquids.current().color, tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); - Effects.effect(type.smokeEffect, entity.liquids.current().color, tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); + type.shootEffect.at(tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation, entity.liquids().current().color); + type.smokeEffect.at(tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation, entity.liquids().current().color); //shootSound.at(tile); if(shootShake > 0){ @@ -116,21 +115,21 @@ public class LiquidTurret extends Turret{ @Override public BulletType useAmmo(Tile tile){ TurretEntity entity = tile.ent(); - if(tile.isEnemyCheat()) return ammo.get(entity.liquids.current()); - BulletType type = ammo.get(entity.liquids.current()); - entity.liquids.remove(entity.liquids.current(), type.ammoMultiplier); + if(tile.isEnemyCheat()) return ammo.get(entity.liquids().current()); + BulletType type = ammo.get(entity.liquids().current()); + entity.liquids().remove(entity.liquids().current(), type.ammoMultiplier); return type; } @Override public BulletType peekAmmo(Tile tile){ - return ammo.get(tile.entity.liquids.current()); + return ammo.get(tile.entity.liquids().current()); } @Override public boolean hasAmmo(Tile tile){ TurretEntity entity = tile.ent(); - return ammo.get(entity.liquids.current()) != null && entity.liquids.total() >= ammo.get(entity.liquids.current()).ammoMultiplier; + return ammo.get(entity.liquids().current()) != null && entity.liquids().total() >= ammo.get(entity.liquids().current()).ammoMultiplier; } @Override @@ -141,7 +140,7 @@ public class LiquidTurret extends Turret{ @Override public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ return ammo.get(liquid) != null - && (tile.entity.liquids.current() == liquid || (ammo.containsKey(tile.entity.liquids.current()) && tile.entity.liquids.get(tile.entity.liquids.current()) <= ammo.get(tile.entity.liquids.current()).ammoMultiplier + 0.001f)); + && (tile.entity.liquids().current() == liquid || (ammo.containsKey(tile.entity.liquids().current()) && tile.entity.liquids().get(tile.entity.liquids().current()) <= ammo.get(tile.entity.liquids().current()).ammoMultiplier + 0.001f)); } } diff --git a/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java b/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java index 35b11319b8..c9f6c93bd6 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java @@ -47,6 +47,6 @@ public class PowerTurret extends CooledTurret{ @Override protected float baseReloadSpeed(Tile tile){ - return tile.isEnemyCheat() ? 1f : tile.entity.power.status; + return tile.isEnemyCheat() ? 1f : tile.entity.power().status; } } diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java index 75ca4bcf2d..53a2e4c06f 100644 --- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java @@ -14,17 +14,15 @@ import arc.math.geom.Vec2; import arc.util.Time; import mindustry.content.Fx; import mindustry.entities.*; -import mindustry.entities.Effects.Effect; -import mindustry.entities.type.Bullet; import mindustry.entities.bullet.BulletType; -import mindustry.entities.traits.TargetTrait; -import mindustry.entities.type.TileEntity; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.world.Block; import mindustry.world.Tile; import mindustry.world.meta.*; +import java.io.*; + import static mindustry.Vars.tilesize; public abstract class Turret extends Block{ @@ -133,7 +131,7 @@ public abstract class Turret extends Block{ @Override public void drawSelect(Tile tile){ - Drawf.dashCircle(tile.drawx(), tile.drawy(), range, tile.getTeam().color); + Drawf.dashCircle(tile.drawx(), tile.drawy(), range, tile.team().color); } @Override @@ -152,7 +150,7 @@ public abstract class Turret extends Block{ if(hasAmmo(tile)){ - if(entity.timer.get(timerTarget, targetInterval)){ + if(entity.timer(timerTarget, targetInterval)){ findTarget(tile); } @@ -186,16 +184,16 @@ public abstract class Turret extends Block{ protected boolean validateTarget(Tile tile){ TurretEntity entity = tile.ent(); - return !Units.invalidateTarget(entity.target, tile.getTeam(), tile.drawx(), tile.drawy()); + return !Units.invalidateTarget(entity.target, tile.team(), tile.drawx(), tile.drawy()); } protected void findTarget(Tile tile){ TurretEntity entity = tile.ent(); if(targetAir && !targetGround){ - entity.target = Units.closestEnemy(tile.getTeam(), tile.drawx(), tile.drawy(), range, e -> !e.isDead() && e.isFlying()); + entity.target = Units.closestEnemy(tile.team(), tile.drawx(), tile.drawy(), range, e -> !e.dead() && !e.isGrounded()); }else{ - entity.target = Units.closestTarget(tile.getTeam(), tile.drawx(), tile.drawy(), range, e -> !e.isDead() && (!e.isFlying() || targetAir) && (e.isFlying() || targetGround)); + entity.target = Units.closestTarget(tile.team(), tile.drawx(), tile.drawy(), range, e -> !e.dead() && (e.isGrounded() || targetAir) && (!e.isGrounded() || targetGround)); } } @@ -269,7 +267,7 @@ public abstract class Turret extends Block{ } protected void bullet(Tile tile, BulletType type, float angle){ - Bullet.create(type, tile.entity, tile.getTeam(), tile.drawx() + tr.x, tile.drawy() + tr.y, angle); + type.create(tile.entity, tile.team(), tile.drawx() + tr.x, tile.drawy() + tr.y, angle); } protected void effects(Tile tile){ @@ -278,8 +276,8 @@ public abstract class Turret extends Block{ TurretEntity entity = tile.ent(); - Effects.effect(shootEffect, tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); - Effects.effect(smokeEffect, tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); + shootEffect.at(tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); + smokeEffect.at(tile.drawx() + tr.x, tile.drawy() + tr.y, entity.rotation); shootSound.at(tile, Mathf.random(0.9f, 1.1f)); if(shootShake > 0){ @@ -293,7 +291,7 @@ public abstract class Turret extends Block{ if(!isTurret(tile)) return; TurretEntity entity = tile.ent(); - Effects.effect(ammoUseEffect, tile.drawx() - Angles.trnsx(entity.rotation, ammoEjectBack), + ammoUseEffect.at(tile.drawx() - Angles.trnsx(entity.rotation, ammoEjectBack), tile.drawy() - Angles.trnsy(entity.rotation, ammoEjectBack), entity.rotation); } @@ -319,6 +317,25 @@ public abstract class Turret extends Block{ public float recoil = 0f; public float heat; public int shots; - public TargetTrait target; + public Teamc target; + + @Override + public void write(DataOutput stream) throws IOException{ + super.write(stream); + stream.writeFloat(reload); + stream.writeFloat(rotation); + } + + @Override + public void read(DataInput stream) throws IOException{ + super.read(stream); + reload = stream.readFloat(); + rotation = stream.readFloat(); + } + + @Override + public byte version(){ + return 1; + } } } diff --git a/core/src/mindustry/world/blocks/distribution/BufferedItemBridge.java b/core/src/mindustry/world/blocks/distribution/BufferedItemBridge.java index 3809fea966..caac4aa7cf 100644 --- a/core/src/mindustry/world/blocks/distribution/BufferedItemBridge.java +++ b/core/src/mindustry/world/blocks/distribution/BufferedItemBridge.java @@ -23,12 +23,12 @@ public class BufferedItemBridge extends ExtendingItemBridge{ public void updateTransport(Tile tile, Tile other){ BufferedItemBridgeEntity entity = tile.ent(); - if(entity.buffer.accepts() && entity.items.total() > 0){ - entity.buffer.accept(entity.items.take()); + if(entity.buffer.accepts() && entity.items().total() > 0){ + entity.buffer.accept(entity.items().take()); } Item item = entity.buffer.poll(); - if(entity.timer.get(timerAccept, 4) && item != null && other.block().acceptItem(item, other, tile)){ + if(entity.timer(timerAccept, 4) && item != null && other.block().acceptItem(item, other, tile)){ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 4f, 0.05f); other.block().handleItem(item, other, tile); entity.buffer.remove(); @@ -47,8 +47,8 @@ public class BufferedItemBridge extends ExtendingItemBridge{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); buffer.read(stream); } } diff --git a/core/src/mindustry/world/blocks/distribution/Conveyor.java b/core/src/mindustry/world/blocks/distribution/Conveyor.java index ea81cdbb48..4f60d5a319 100644 --- a/core/src/mindustry/world/blocks/distribution/Conveyor.java +++ b/core/src/mindustry/world/blocks/distribution/Conveyor.java @@ -1,16 +1,16 @@ package mindustry.world.blocks.distribution; import arc.*; -import arc.struct.*; import arc.func.*; import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; +import arc.struct.*; +import arc.util.ArcAnnotate.*; import arc.util.*; import mindustry.content.*; -import mindustry.entities.traits.BuilderTrait.*; -import mindustry.entities.type.*; import mindustry.gen.*; +import mindustry.entities.units.*; import mindustry.graphics.*; import mindustry.type.*; import mindustry.ui.*; @@ -24,10 +24,8 @@ import static mindustry.Vars.*; public class Conveyor extends Block implements Autotiler{ private static final float itemSpace = 0.4f; - private static final float minmove = 1f / (Short.MAX_VALUE - 2); - private static ItemPos drawpos = new ItemPos(); - private static ItemPos pos1 = new ItemPos(); - private static ItemPos pos2 = new ItemPos(); + private static final int capacity = 4; + private final Vec2 tr1 = new Vec2(); private final Vec2 tr2 = new Vec2(); private TextureRegion[][] regions = new TextureRegion[7][4]; @@ -51,12 +49,6 @@ public class Conveyor extends Block implements Autotiler{ unloadable = false; } - private static int compareItems(long a, long b){ - pos1.set(a, ItemPos.packShorts); - pos2.set(b, ItemPos.packShorts); - return Float.compare(pos1.y, pos2.y); - } - @Override public void setStats(){ super.setStats(); @@ -80,7 +72,7 @@ public class Conveyor extends Block implements Autotiler{ ConveyorEntity entity = tile.ent(); byte rotation = tile.rotation(); - int frame = entity.clogHeat <= 0.5f ? (int)(((Time.time() * speed * 8f * entity.timeScale)) % 4) : 0; + int frame = entity.clogHeat <= 0.5f ? (int)(((Time.time() * speed * 8f * entity.timeScale())) % 4) : 0; Draw.rect(regions[Mathf.clamp(entity.blendbits, 0, regions.length - 1)][Mathf.clamp(frame, 0, regions[0].length - 1)], tile.drawx(), tile.drawy(), tilesize * entity.blendsclx, tilesize * entity.blendscly, rotation * 90); } @@ -100,6 +92,12 @@ public class Conveyor extends Block implements Autotiler{ entity.blendbits = bits[0]; entity.blendsclx = bits[1]; entity.blendscly = bits[2]; + + if(tile.front() != null && tile.front().entity != null){ + entity.next = tile.front().entity; + entity.nextc = entity.next instanceof ConveyorEntity && entity.next.team() == tile.team() ? (ConveyorEntity)entity.next : null; + entity.aligned = entity.nextc != null && tile.rotation() == entity.next.tile().rotation(); + } } @Override @@ -124,32 +122,22 @@ public class Conveyor extends Block implements Autotiler{ @Override public void drawLayer(Tile tile){ - ConveyorEntity entity = tile.ent(); - + ConveyorEntity e = tile.ent(); byte rotation = tile.rotation(); - try{ + for(int i = 0; i < e.len; i++){ + Item item = e.ids[i]; + tr1.trns(rotation * 90, tilesize, 0); + tr2.trns(rotation * 90, -tilesize / 2f, e.xs[i] * tilesize / 2f); - for(int i = 0; i < entity.convey.size; i++){ - ItemPos pos = drawpos.set(entity.convey.get(i), ItemPos.drawShorts); - - if(pos.item == null) continue; - - tr1.trns(rotation * 90, tilesize, 0); - tr2.trns(rotation * 90, -tilesize / 2f, pos.x * tilesize / 2f); - - Draw.rect(pos.item.icon(Cicon.medium), - (tile.x * tilesize + tr1.x * pos.y + tr2.x), - (tile.y * tilesize + tr1.y * pos.y + tr2.y), itemSize, itemSize); - } - - }catch(IndexOutOfBoundsException e){ - Log.err(e); + Draw.rect(item.icon(Cicon.medium), + (tile.x * tilesize + tr1.x * e.ys[i] + tr2.x), + (tile.y * tilesize + tr1.y * e.ys[i] + tr2.y), itemSize, itemSize); } } @Override - public void unitOn(Tile tile, Unit unit){ + public void unitOn(Tile tile, Unitc unit){ ConveyorEntity entity = tile.ent(); if(entity.clogHeat > 0.5f){ @@ -166,86 +154,63 @@ public class Conveyor extends Block implements Autotiler{ float centerx = 0f, centery = 0f; if(Math.abs(tx) > Math.abs(ty)){ - centery = Mathf.clamp((tile.worldy() - unit.y) / centerDstScl, -centerSpeed, centerSpeed); - if(Math.abs(tile.worldy() - unit.y) < 1f) centery = 0f; + centery = Mathf.clamp((tile.worldy() - unit.y()) / centerDstScl, -centerSpeed, centerSpeed); + if(Math.abs(tile.worldy() - unit.y()) < 1f) centery = 0f; }else{ - centerx = Mathf.clamp((tile.worldx() - unit.x) / centerDstScl, -centerSpeed, centerSpeed); - if(Math.abs(tile.worldx() - unit.x) < 1f) centerx = 0f; + centerx = Mathf.clamp((tile.worldx() - unit.x()) / centerDstScl, -centerSpeed, centerSpeed); + if(Math.abs(tile.worldx() - unit.x()) < 1f) centerx = 0f; } - if(entity.convey.size * itemSpace < 0.9f){ - unit.applyImpulse((tx * speed + centerx) * entity.delta(), (ty * speed + centery) * entity.delta()); + if(entity.len * itemSpace < 0.9f){ + unit.impulse((tx * speed + centerx) * entity.delta(), (ty * speed + centery) * entity.delta()); } } @Override public void update(Tile tile){ - ConveyorEntity entity = tile.ent(); - entity.minitem = 1f; - Tile next = tile.getNearby(tile.rotation()); - if(next != null) next = next.link(); + ConveyorEntity e = tile.ent(); + e.minitem = 1f; + e.mid = 0; - float nextMax = next != null && next.block() instanceof Conveyor && next.block().acceptItem(null, next, tile) ? 1f - Math.max(itemSpace - next.ent().minitem, 0) : 1f; - int minremove = Integer.MAX_VALUE; + //skip updates if possible + if(e.len == 0){ + e.clogHeat = 0f; + e.sleep(); + return; + } - for(int i = entity.convey.size - 1; i >= 0; i--){ - long value = entity.convey.get(i); - ItemPos pos = pos1.set(value, ItemPos.updateShorts); + float nextMax = e.aligned ? 1f - Math.max(itemSpace - e.nextc.minitem, 0) : 1f; - //..this should never happen, but in case it does, remove it and stop here - if(pos.item == null){ - entity.convey.removeValue(value); - break; - } + for(int i = e.len - 1; i >= 0; i--){ + float nextpos = (i == e.len - 1 ? 100f : e.ys[i + 1]) - itemSpace; + float maxmove = Mathf.clamp(nextpos - e.ys[i], 0, speed * e.delta()); - float nextpos = (i == entity.convey.size - 1 ? 100f : pos2.set(entity.convey.get(i + 1), ItemPos.updateShorts).y) - itemSpace; - float maxmove = Math.min(nextpos - pos.y, speed * entity.delta()); + e.ys[i] += maxmove; - if(maxmove > minmove){ - pos.y += maxmove; - if(Mathf.equal(pos.x, 0, 0.1f)){ - pos.x = 0f; + if(e.ys[i] > nextMax) e.ys[i] = nextMax; + if(e.ys[i] > 0.5 && i > 0) e.mid = i - 1; + e.xs[i] = Mathf.approachDelta(e.xs[i], 0, speed*2); + + if(e.ys[i] >= 1f && offloadDir(tile, e.ids[i])){ + //align X position if passing forwards + if(e.aligned){ + e.nextc.xs[e.nextc.lastInserted] = e.xs[i]; } - pos.x = Mathf.lerpDelta(pos.x, 0, 0.1f); - } - - pos.y = Mathf.clamp(pos.y, 0, nextMax); - - if(pos.y >= 0.9999f && offloadDir(tile, pos.item)){ - if(next != null && next.block() instanceof Conveyor){ - ConveyorEntity othere = next.ent(); - - ItemPos ni = pos2.set(othere.convey.get(othere.lastInserted), ItemPos.updateShorts); - - if(next.rotation() == tile.rotation()){ - ni.x = pos.x; - } - othere.convey.set(othere.lastInserted, ni.pack()); - } - minremove = Math.min(i, minremove); - tile.entity.items.remove(pos.item, 1); - }else{ - value = pos.pack(); - - if(pos.y < entity.minitem) - entity.minitem = pos.y; - entity.convey.set(i, value); + //remove last item + e.items().remove(e.ids[i], e.len - i); + e.len = Math.min(i, e.len); + }else if(e.ys[i] < e.minitem){ + e.minitem = e.ys[i]; } } - if(entity.minitem < itemSpace){ - entity.clogHeat = Mathf.lerpDelta(entity.clogHeat, 1f, 0.02f); + if(e.minitem < itemSpace + (e.blendbits == 1 ? 0.3f : 0f)){ + e.clogHeat = Mathf.lerpDelta(e.clogHeat, 1f, 0.02f); }else{ - entity.clogHeat = Mathf.lerpDelta(entity.clogHeat, 0f, 1f); + e.clogHeat = 0f; } - if(entity.items.total() == 0){ - entity.sleep(); - }else{ - entity.noSleep(); - } - - if(minremove != Integer.MAX_VALUE) entity.convey.truncate(minremove); + e.noSleep(); } @Override @@ -265,22 +230,22 @@ public class Conveyor extends Block implements Autotiler{ @Override public int removeStack(Tile tile, Item item, int amount){ - ConveyorEntity entity = tile.ent(); - entity.noSleep(); + ConveyorEntity e = tile.ent(); + e.noSleep(); int removed = 0; for(int j = 0; j < amount; j++){ - for(int i = 0; i < entity.convey.size; i++){ - long val = entity.convey.get(i); - ItemPos pos = pos1.set(val, ItemPos.drawShorts); - if(pos.item == item){ - entity.convey.removeValue(val); - entity.items.remove(item, 1); - removed++; + for(int i = 0; i < e.len; i++){ + if(e.ids[i] == item){ + e.remove(i); + removed ++; break; } } } + + e.items().remove(item, removed); + return removed; } @@ -290,65 +255,73 @@ public class Conveyor extends Block implements Autotiler{ } @Override - public int acceptStack(Item item, int amount, Tile tile, Unit source){ + public int acceptStack(Item item, int amount, Tile tile, Teamc source){ ConveyorEntity entity = tile.ent(); return Math.min((int)(entity.minitem / itemSpace), amount); } @Override - public void handleStack(Item item, int amount, Tile tile, Unit source){ - ConveyorEntity entity = tile.ent(); + public void handleStack(Item item, int amount, Tile tile, Teamc source){ + ConveyorEntity e = tile.ent(); for(int i = amount - 1; i >= 0; i--){ - long result = ItemPos.packItem(item, 0f, i * itemSpace); - entity.convey.insert(0, result); - entity.items.add(item, 1); + e.add(0); + e.xs[0] = 0; + e.ys[0] = i * itemSpace; + e.ids[0] = item; + e.items().add(item, 1); } - entity.noSleep(); + e.noSleep(); } @Override public boolean acceptItem(Item item, Tile tile, Tile source){ + ConveyorEntity e = tile.ent(); + if(e.len >= capacity) return false; int direction = source == null ? 0 : Math.abs(source.relativeTo(tile.x, tile.y) - tile.rotation()); - float minitem = tile.ent().minitem; - return (((direction == 0) && minitem > itemSpace) || - ((direction % 2 == 1) && minitem > 0.52f)) && (source == null || !(source.block().rotate && (source.rotation() + 2) % 4 == tile.rotation())); + return (((direction == 0) && e.minitem >= itemSpace) || ((direction % 2 == 1) && e.minitem > 0.7f)) && (source == null || !(source.block().rotate && (source.rotation() + 2) % 4 == tile.rotation())); } @Override public void handleItem(Item item, Tile tile, Tile source){ - byte rotation = tile.rotation(); + ConveyorEntity e = tile.ent(); + if(e.len >= capacity) return; - int ch = Math.abs(source.relativeTo(tile.x, tile.y) - rotation); - int ang = ((source.relativeTo(tile.x, tile.y) - rotation)); + byte r = tile.rotation(); + int ang = ((source.relativeTo(tile.x, tile.y) - r)); + float x = (ang == -1 || ang == 3) ? 1 : (ang == 1 || ang == -3) ? -1 : 0; - float pos = ch == 0 ? 0 : ch % 2 == 1 ? 0.5f : 1f; - float y = (ang == -1 || ang == 3) ? 1 : (ang == 1 || ang == -3) ? -1 : 0; + e.noSleep(); + e.items().add(item, 1); - ConveyorEntity entity = tile.ent(); - entity.noSleep(); - long result = ItemPos.packItem(item, y * 0.9f, pos); - - tile.entity.items.add(item, 1); - - for(int i = 0; i < entity.convey.size; i++){ - if(compareItems(result, entity.convey.get(i)) < 0){ - entity.convey.insert(i, result); - entity.lastInserted = (byte)i; - return; - } + if(Math.abs(source.relativeTo(tile.x, tile.y) - r) == 0){ //idx = 0 + e.add(0); + e.xs[0] = x; + e.ys[0] = 0; + e.ids[0] = item; + }else{ //idx = mid + e.add(e.mid); + e.xs[e.mid] = x; + e.ys[e.mid] = 0.5f; + e.ids[e.mid] = item; } - - //this item must be greater than anything there... - entity.convey.add(result); - entity.lastInserted = (byte)(entity.convey.size - 1); } public static class ConveyorEntity extends TileEntity{ + //parallel array data + Item[] ids = new Item[capacity]; + float[] xs = new float[capacity]; + float[] ys = new float[capacity]; + //amount of items, always < capacity + int len = 0; + //next entity + @Nullable Tilec next; + @Nullable ConveyorEntity nextc; + //whether the next conveyor's rotation == tile rotation + boolean aligned; - LongArray convey = new LongArray(); - byte lastInserted; + int lastInserted, mid; float minitem = 1; int blendbits; @@ -356,96 +329,53 @@ public class Conveyor extends Block implements Autotiler{ float clogHeat = 0f; + final void add(int o){ + for(int i = Math.max(o + 1, len); i > o; i--){ + ids[i] = ids[i - 1]; + xs[i] = xs[i - 1]; + ys[i] = ys[i - 1]; + } + + len++; + } + + final void remove(int o){ + for(int i = o; i < len - 1; i++){ + ids[i] = ids[i + 1]; + xs[i] = xs[i + 1]; + ys[i] = ys[i + 1]; + } + + len--; + } + @Override public void write(DataOutput stream) throws IOException{ super.write(stream); - stream.writeInt(convey.size); + stream.writeInt(len); - for(int i = 0; i < convey.size; i++){ - stream.writeInt(ItemPos.toInt(convey.get(i))); + for(int i = 0; i < len; i++){ + stream.writeInt(Pack.intBytes((byte)ids[i].id, (byte)(xs[i] * 127), (byte)(ys[i] * 255 - 128), (byte)0)); } } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); - convey.clear(); + public void read(DataInput stream) throws IOException{ + super.read(stream); int amount = stream.readInt(); - convey.ensureCapacity(Math.min(amount, 10)); + len = Math.min(amount, capacity); for(int i = 0; i < amount; i++){ - convey.add(ItemPos.toLong(stream.readInt())); + int val = stream.readInt(); + byte id = (byte)(val >> 24); + float x = (float)((byte)(val >> 16)) / 127f; + float y = ((float)((byte)(val >> 8)) + 128f) / 255f; + if(i < capacity){ + ids[i] = content.item(id); + xs[i] = x; + ys[i] = y; + } } } } - - //Container class. Do not instantiate. - static class ItemPos{ - private static short[] writeShort = new short[4]; - private static byte[] writeByte = new byte[4]; - - private static short[] packShorts = new short[4]; - private static short[] drawShorts = new short[4]; - private static short[] updateShorts = new short[4]; - - Item item; - float x, y; - - private ItemPos(){ - } - - static long packItem(Item item, float x, float y){ - short[] shorts = packShorts; - shorts[0] = (short)item.id; - shorts[1] = (short)(x * Short.MAX_VALUE); - shorts[2] = (short)((y - 1f) * Short.MAX_VALUE); - return Pack.longShorts(shorts); - } - - static int toInt(long value){ - short[] values = Pack.shorts(value, writeShort); - - short itemid = values[0]; - float x = values[1] / (float)Short.MAX_VALUE; - float y = ((float)values[2]) / Short.MAX_VALUE + 1f; - - byte[] bytes = writeByte; - bytes[0] = (byte)itemid; - bytes[1] = (byte)(x * 127); - bytes[2] = (byte)(y * 255 - 128); - - return Pack.intBytes(bytes); - } - - static long toLong(int value){ - byte[] values = Pack.bytes(value, writeByte); - - short itemid = content.item(values[0]).id; - float x = values[1] / 127f; - float y = ((int)values[2] + 128) / 255f; - - short[] shorts = writeShort; - shorts[0] = itemid; - shorts[1] = (short)(x * Short.MAX_VALUE); - shorts[2] = (short)((y - 1f) * Short.MAX_VALUE); - return Pack.longShorts(shorts); - } - - ItemPos set(long lvalue, short[] values){ - Pack.shorts(lvalue, values); - - if(values[0] >= content.items().size || values[0] < 0) - item = null; - else - item = content.items().get(values[0]); - - x = values[1] / (float)Short.MAX_VALUE; - y = ((float)values[2]) / Short.MAX_VALUE + 1f; - return this; - } - - long pack(){ - return packItem(item, x, y); - } - } } \ No newline at end of file diff --git a/core/src/mindustry/world/blocks/distribution/ItemBridge.java b/core/src/mindustry/world/blocks/distribution/ItemBridge.java index 5d16ec69ee..59ce04d733 100644 --- a/core/src/mindustry/world/blocks/distribution/ItemBridge.java +++ b/core/src/mindustry/world/blocks/distribution/ItemBridge.java @@ -8,8 +8,8 @@ import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; import arc.util.*; -import mindustry.entities.traits.BuilderTrait.*; -import mindustry.entities.type.*; +import mindustry.gen.*; +import mindustry.entities.units.*; import mindustry.graphics.*; import mindustry.type.*; import mindustry.world.*; @@ -45,7 +45,7 @@ public class ItemBridge extends Block{ } @Override - public void configured(Tile tile, Player player, int value){ + public void configured(Tile tile, Playerc player, int value){ tile.ent().link = value; } @@ -187,7 +187,7 @@ public class ItemBridge extends Block{ }else{ ((ItemBridgeEntity)world.tile(entity.link).entity).incoming.add(tile.pos()); - if(entity.cons.valid() && Mathf.zero(1f - entity.efficiency())){ + if(entity.consValid() && Mathf.zero(1f - entity.efficiency())){ entity.uptime = Mathf.lerpDelta(entity.uptime, 1f, 0.04f); }else{ entity.uptime = Mathf.lerpDelta(entity.uptime, 0f, 0.02f); @@ -200,14 +200,14 @@ public class ItemBridge extends Block{ public void updateTransport(Tile tile, Tile other){ ItemBridgeEntity entity = tile.ent(); - if(entity.uptime >= 0.5f && entity.timer.get(timerTransport, transportTime)){ - Item item = entity.items.take(); + if(entity.uptime >= 0.5f && entity.timer(timerTransport, transportTime)){ + Item item = entity.items().take(); if(item != null && other.block().acceptItem(item, other, tile)){ other.block().handleItem(item, other, tile); entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 4f, 0.05f); }else{ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 1f, 0.01f); - if(item != null) entity.items.add(item, 1); + if(item != null) entity.items().add(item, 1); } } } @@ -255,7 +255,7 @@ public class ItemBridge extends Block{ @Override public boolean acceptItem(Item item, Tile tile, Tile source){ - if(tile.getTeam() != source.getTeam()) return false; + if(tile.team() != source.team()) return false; ItemBridgeEntity entity = tile.ent(); Tile other = world.tile(entity.link); @@ -266,10 +266,10 @@ public class ItemBridge extends Block{ if(rel == rel2) return false; }else{ - return source.block() instanceof ItemBridge && source.ent().link == tile.pos() && tile.entity.items.total() < itemCapacity; + return source.block() instanceof ItemBridge && source.ent().link == tile.pos() && tile.entity.items().total() < itemCapacity; } - return tile.entity.items.total() < itemCapacity; + return tile.entity.items().total() < itemCapacity; } @@ -301,7 +301,7 @@ public class ItemBridge extends Block{ @Override public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - if(tile.getTeam() != source.getTeam() || !hasLiquids) return false; + if(tile.team() != source.team() || !hasLiquids) return false; ItemBridgeEntity entity = tile.ent(); Tile other = world.tile(entity.link); @@ -315,7 +315,7 @@ public class ItemBridge extends Block{ return false; } - return tile.entity.liquids.get(liquid) + amount < liquidCapacity && (tile.entity.liquids.current() == liquid || tile.entity.liquids.get(tile.entity.liquids.current()) < 0.2f); + return tile.entity.liquids().get(liquid) + amount < liquidCapacity && (tile.entity.liquids().current() == liquid || tile.entity.liquids().get(tile.entity.liquids().current()) < 0.2f); } @Override @@ -389,8 +389,8 @@ public class ItemBridge extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); link = stream.readInt(); uptime = stream.readFloat(); byte links = stream.readByte(); diff --git a/core/src/mindustry/world/blocks/distribution/Junction.java b/core/src/mindustry/world/blocks/distribution/Junction.java index 99c22057e1..eeb2b69376 100644 --- a/core/src/mindustry/world/blocks/distribution/Junction.java +++ b/core/src/mindustry/world/blocks/distribution/Junction.java @@ -1,8 +1,7 @@ package mindustry.world.blocks.distribution; import arc.util.Time; -import mindustry.entities.type.TileEntity; -import mindustry.entities.type.Unit; +import mindustry.gen.*; import mindustry.gen.BufferItem; import mindustry.type.Item; import mindustry.world.Block; @@ -31,7 +30,7 @@ public class Junction extends Block{ } @Override - public int acceptStack(Item item, int amount, Tile tile, Unit source){ + public int acceptStack(Item item, int amount, Tile tile, Teamc source){ return 0; } @@ -58,7 +57,7 @@ public class Junction extends Block{ if(dest != null) dest = dest.link(); //skip blocks that don't want the item, keep waiting until they do - if(dest == null || !dest.block().acceptItem(item, dest, tile) || dest.getTeam() != tile.getTeam()){ + if(dest == null || !dest.block().acceptItem(item, dest, tile) || dest.team() != tile.team()){ continue; } @@ -84,7 +83,7 @@ public class Junction extends Block{ if(entity == null || relative == -1 || !entity.buffer.accepts(relative)) return false; Tile to = tile.getNearby(relative); - return to != null && to.link().entity != null && to.getTeam() == tile.getTeam(); + return to != null && to.link().entity != null && to.team() == tile.team(); } class JunctionEntity extends TileEntity{ @@ -97,8 +96,8 @@ public class Junction extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); buffer.read(stream); } } diff --git a/core/src/mindustry/world/blocks/distribution/MassDriver.java b/core/src/mindustry/world/blocks/distribution/MassDriver.java index eacef7d0eb..47710572a3 100644 --- a/core/src/mindustry/world/blocks/distribution/MassDriver.java +++ b/core/src/mindustry/world/blocks/distribution/MassDriver.java @@ -9,8 +9,7 @@ import arc.util.pooling.Pool.*; import arc.util.pooling.*; import mindustry.content.*; import mindustry.entities.*; -import mindustry.entities.Effects.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; import mindustry.world.*; @@ -46,7 +45,7 @@ public class MassDriver extends Block{ } @Override - public void configured(Tile tile, Player player, int value){ + public void configured(Tile tile, Playerc player, int value){ tile.ent().link = value; } @@ -81,7 +80,7 @@ public class MassDriver extends Block{ //switch states if(entity.state == DriverState.idle){ //start accepting when idle and there's space - if(!entity.waitingShooters.isEmpty() && (itemCapacity - entity.items.total() >= minDistribute)){ + if(!entity.waitingShooters.isEmpty() && (itemCapacity - entity.items().total() >= minDistribute)){ entity.state = DriverState.accepting; }else if(hasLink){ //switch to shooting if there's a valid link. entity.state = DriverState.shooting; @@ -94,13 +93,13 @@ public class MassDriver extends Block{ } //skip when there's no power - if(!entity.cons.valid()){ + if(!entity.consValid()){ return; } if(entity.state == DriverState.accepting){ //if there's nothing shooting at this, bail - OR, items full - if(entity.currentShooter() == null || (itemCapacity - entity.items.total() < minDistribute)){ + if(entity.currentShooter() == null || (itemCapacity - entity.items().total() < minDistribute)){ entity.state = DriverState.idle; return; } @@ -109,7 +108,7 @@ public class MassDriver extends Block{ entity.rotation = Mathf.slerpDelta(entity.rotation, tile.angleTo(entity.currentShooter()), rotateSpeed * entity.efficiency()); }else if(entity.state == DriverState.shooting){ //if there's nothing to shoot at OR someone wants to shoot at this thing, bail - if(!hasLink || (!entity.waitingShooters.isEmpty() && (itemCapacity - entity.items.total() >= minDistribute))){ + if(!hasLink || (!entity.waitingShooters.isEmpty() && (itemCapacity - entity.items().total() >= minDistribute))){ entity.state = DriverState.idle; return; } @@ -117,8 +116,8 @@ public class MassDriver extends Block{ float targetRotation = tile.angleTo(link); if( - tile.entity.items.total() >= minDistribute && //must shoot minimum amount of items - link.block().itemCapacity - link.entity.items.total() >= minDistribute //must have minimum amount of space + tile.entity.items().total() >= minDistribute && //must shoot minimum amount of items + link.block().itemCapacity - link.entity.items().total() >= minDistribute //must have minimum amount of space ){ MassDriverEntity other = link.ent(); other.waitingShooters.add(tile); @@ -192,6 +191,11 @@ public class MassDriver extends Block{ MassDriverEntity entity = tile.ent(); + for(Tile shooter : entity.waitingShooters){ + Drawf.circles(shooter.drawx(), shooter.drawy(), (tile.block().size / 2f + 1) * tilesize + sin - 2f, Pal.place); + Drawf.arrow(shooter.drawx(), shooter.drawy(), tile.drawx(), tile.drawy(), size * tilesize + sin, 4f + sin, Pal.place); + } + if(linkValid(tile)){ Tile target = world.tile(entity.link); Drawf.circles(target.drawx(), target.drawy(), (target.block().size / 2f + 1) * tilesize + sin - 2f, Pal.place); @@ -210,7 +214,7 @@ public class MassDriver extends Block{ if(entity.link == other.pos()){ tile.configure(-1); return false; - }else if(other.block() instanceof MassDriver && other.dst(tile) <= range && other.getTeam() == tile.getTeam()){ + }else if(other.block() instanceof MassDriver && other.dst(tile) <= range && other.team() == tile.team()){ tile.configure(other.pos()); return false; } @@ -221,7 +225,7 @@ public class MassDriver extends Block{ @Override public boolean acceptItem(Item item, Tile tile, Tile source){ //mass drivers that ouput only cannot accept items - return tile.entity.items.total() < itemCapacity && linkValid(tile); + return tile.entity.items().total() < itemCapacity && linkValid(tile); } protected void fire(Tile tile, Tile target){ @@ -236,34 +240,34 @@ public class MassDriver extends Block{ data.to = other; int totalUsed = 0; for(int i = 0; i < content.items().size; i++){ - int maxTransfer = Math.min(entity.items.get(content.item(i)), ((MassDriver)tile.block()).itemCapacity - totalUsed); + int maxTransfer = Math.min(entity.items().get(content.item(i)), ((MassDriver)tile.block()).itemCapacity - totalUsed); data.items[i] = maxTransfer; totalUsed += maxTransfer; - entity.items.remove(content.item(i), maxTransfer); + entity.items().remove(content.item(i), maxTransfer); } float angle = tile.angleTo(target); - Bullet.create(Bullets.driverBolt, entity, entity.getTeam(), + Bullets.driverBolt.create(entity, entity.team(), tile.drawx() + Angles.trnsx(angle, translation), tile.drawy() + Angles.trnsy(angle, translation), - angle, 1f, 1f, data); + angle, -1f, 1f, 1f, data); - Effects.effect(shootEffect, tile.drawx() + Angles.trnsx(angle, translation), + shootEffect.at(tile.drawx() + Angles.trnsx(angle, translation), tile.drawy() + Angles.trnsy(angle, translation), angle); - Effects.effect(smokeEffect, tile.drawx() + Angles.trnsx(angle, translation), + smokeEffect.at(tile.drawx() + Angles.trnsx(angle, translation), tile.drawy() + Angles.trnsy(angle, translation), angle); Effects.shake(shake, shake, entity); } - protected void handlePayload(MassDriverEntity entity, Bullet bullet, DriverBulletData data){ - int totalItems = entity.items.total(); + protected void handlePayload(MassDriverEntity entity, Bulletc bullet, DriverBulletData data){ + int totalItems = entity.items().total(); //add all the items possible for(int i = 0; i < data.items.length; i++){ int maxAdd = Math.min(data.items[i], itemCapacity * 2 - totalItems); - entity.items.add(content.item(i), maxAdd); + entity.items().add(content.item(i), maxAdd); data.items[i] -= maxAdd; totalItems += maxAdd; @@ -273,7 +277,7 @@ public class MassDriver extends Block{ } Effects.shake(shake, shake, entity); - Effects.effect(recieveEffect, bullet); + recieveEffect.at(bullet); entity.reload = 1f; bullet.remove(); @@ -293,7 +297,7 @@ public class MassDriver extends Block{ if(entity == null || entity.link == -1) return false; Tile link = world.tile(entity.link); - return link != null && link.block() instanceof MassDriver && link.getTeam() == tile.getTeam() && tile.dst(link) <= range; + return link != null && link.block() instanceof MassDriver && link.team() == tile.team() && tile.dst(link) <= range; } public static class DriverBulletData implements Poolable{ @@ -318,8 +322,8 @@ public class MassDriver extends Block{ return waitingShooters.isEmpty() ? null : waitingShooters.first(); } - public void handlePayload(Bullet bullet, DriverBulletData data){ - ((MassDriver)block).handlePayload(this, bullet, data); + public void handlePayload(Bulletc bullet, DriverBulletData data){ + ((MassDriver)block()).handlePayload(this, bullet, data); } @Override @@ -336,8 +340,8 @@ public class MassDriver extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); link = stream.readInt(); rotation = stream.readFloat(); state = DriverState.values()[stream.readByte()]; diff --git a/core/src/mindustry/world/blocks/distribution/OverflowGate.java b/core/src/mindustry/world/blocks/distribution/OverflowGate.java index b07ae8c7be..781561b517 100644 --- a/core/src/mindustry/world/blocks/distribution/OverflowGate.java +++ b/core/src/mindustry/world/blocks/distribution/OverflowGate.java @@ -1,16 +1,15 @@ package mindustry.world.blocks.distribution; -import arc.math.Mathf; -import arc.util.Time; -import mindustry.entities.type.TileEntity; -import mindustry.type.Item; +import arc.math.*; +import arc.util.*; +import mindustry.gen.*; +import mindustry.type.*; import mindustry.world.*; -import mindustry.world.meta.BlockGroup; - -import java.io.*; +import mindustry.world.meta.*; public class OverflowGate extends Block{ public float speed = 1f; + public boolean invert = false; public OverflowGate(String name){ super(name); @@ -41,8 +40,8 @@ public class OverflowGate extends Block{ public void update(Tile tile){ OverflowGateEntity entity = tile.ent(); - if(entity.lastItem == null && entity.items.total() > 0){ - entity.items.clear(); + if(entity.lastItem == null && entity.items().total() > 0){ + entity.items().clear(); } if(entity.lastItem != null){ @@ -52,7 +51,7 @@ public class OverflowGate extends Block{ if(target != null && (entity.time >= 1f)){ getTileTarget(tile, entity.lastItem, entity.lastInput, true); target.block().handleItem(entity.lastItem, target, Edges.getFacingEdge(tile, target)); - entity.items.remove(entity.lastItem, 1); + entity.items().remove(entity.lastItem, 1); entity.lastItem = null; } } @@ -62,33 +61,36 @@ public class OverflowGate extends Block{ public boolean acceptItem(Item item, Tile tile, Tile source){ OverflowGateEntity entity = tile.ent(); - return tile.getTeam() == source.getTeam() && entity.lastItem == null && entity.items.total() == 0; + return tile.team() == source.team() && entity.lastItem == null && entity.items().total() == 0; } @Override public void handleItem(Item item, Tile tile, Tile source){ OverflowGateEntity entity = tile.ent(); - entity.items.add(item, 1); + entity.items().add(item, 1); entity.lastItem = item; entity.time = 0f; entity.lastInput = source; + + update(tile); } - Tile getTileTarget(Tile tile, Item item, Tile src, boolean flip){ + public Tile getTileTarget(Tile tile, Item item, Tile src, boolean flip){ int from = tile.relativeTo(src.x, src.y); if(from == -1) return null; Tile to = tile.getNearby((from + 2) % 4); if(to == null) return null; Tile edge = Edges.getFacingEdge(tile, to); + boolean canForward = to.block().acceptItem(item, to, edge) && to.team() == tile.team() && !(to.block() instanceof OverflowGate); - if(!to.block().acceptItem(item, to, edge) || to.getTeam() != tile.getTeam() || (to.block() instanceof OverflowGate)){ + if(!canForward || invert){ Tile a = tile.getNearby(Mathf.mod(from - 1, 4)); Tile b = tile.getNearby(Mathf.mod(from + 1, 4)); - boolean ac = a != null && a.block().acceptItem(item, a, edge) && !(a.block() instanceof OverflowGate) && a.getTeam() == tile.getTeam(); - boolean bc = b != null && b.block().acceptItem(item, b, edge) && !(b.block() instanceof OverflowGate) && b.getTeam() == tile.getTeam(); + boolean ac = a != null && a.block().acceptItem(item, a, edge) && !(a.block() instanceof OverflowGate) && a.team() == tile.team(); + boolean bc = b != null && b.block().acceptItem(item, b, edge) && !(b.block() instanceof OverflowGate) && b.team() == tile.team(); if(!ac && !bc){ - return null; + return invert && canForward ? to : null; } if(ac && !bc){ @@ -113,23 +115,5 @@ public class OverflowGate extends Block{ Item lastItem; Tile lastInput; float time; - - @Override - public byte version(){ - return 2; - } - - @Override - public void write(DataOutput stream) throws IOException{ - super.write(stream); - } - - @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); - if(revision == 1){ - new DirectionalItemBuffer(25, 50f).read(stream); - } - } } } diff --git a/core/src/mindustry/world/blocks/distribution/Router.java b/core/src/mindustry/world/blocks/distribution/Router.java index 8cfa4525d0..6058d80de7 100644 --- a/core/src/mindustry/world/blocks/distribution/Router.java +++ b/core/src/mindustry/world/blocks/distribution/Router.java @@ -3,7 +3,7 @@ package mindustry.world.blocks.distribution; import arc.struct.Array; import arc.util.Time; import mindustry.content.*; -import mindustry.entities.type.TileEntity; +import mindustry.gen.*; import mindustry.type.Item; import mindustry.world.*; import mindustry.world.meta.BlockGroup; @@ -26,8 +26,8 @@ public class Router extends Block{ public void update(Tile tile){ RouterEntity entity = tile.ent(); - if(entity.lastItem == null && entity.items.total() > 0){ - entity.items.clear(); + if(entity.lastItem == null && entity.items().total() > 0){ + entity.items().clear(); } if(entity.lastItem != null){ @@ -37,7 +37,7 @@ public class Router extends Block{ if(target != null && (entity.time >= 1f || !(target.block() instanceof Router))){ getTileTarget(tile, entity.lastItem, entity.lastInput, true); target.block().handleItem(entity.lastItem, target, Edges.getFacingEdge(tile, target)); - entity.items.remove(entity.lastItem, 1); + entity.items().remove(entity.lastItem, 1); entity.lastItem = null; } } @@ -47,13 +47,13 @@ public class Router extends Block{ public boolean acceptItem(Item item, Tile tile, Tile source){ RouterEntity entity = tile.ent(); - return tile.getTeam() == source.getTeam() && entity.lastItem == null && entity.items.total() == 0; + return tile.team() == source.team() && entity.lastItem == null && entity.items().total() == 0; } @Override public void handleItem(Item item, Tile tile, Tile source){ RouterEntity entity = tile.ent(); - entity.items.add(item, 1); + entity.items().add(item, 1); entity.lastItem = item; entity.time = 0f; entity.lastInput = source; diff --git a/core/src/mindustry/world/blocks/distribution/Sorter.java b/core/src/mindustry/world/blocks/distribution/Sorter.java index 1df5fe75e5..a011929cec 100644 --- a/core/src/mindustry/world/blocks/distribution/Sorter.java +++ b/core/src/mindustry/world/blocks/distribution/Sorter.java @@ -3,10 +3,10 @@ package mindustry.world.blocks.distribution; import arc.graphics.g2d.*; import arc.math.*; import arc.scene.ui.layout.*; -import arc.util.*; import arc.util.ArcAnnotate.*; -import mindustry.entities.traits.BuilderTrait.*; -import mindustry.entities.type.*; +import arc.util.*; +import mindustry.gen.*; +import mindustry.entities.units.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.*; @@ -44,7 +44,7 @@ public class Sorter extends Block{ } @Override - public void configured(Tile tile, Player player, int value){ + public void configured(Tile tile, Playerc player, int value){ tile.ent().sortItem = content.item(value); } @@ -74,7 +74,7 @@ public class Sorter extends Block{ public boolean acceptItem(Item item, Tile tile, Tile source){ Tile to = getTileTarget(item, tile, source, false); - return to != null && to.block().acceptItem(item, to, tile) && to.getTeam() == tile.getTeam(); + return to != null && to.block().acceptItem(item, to, tile) && to.team() == tile.team(); } @Override @@ -85,7 +85,8 @@ public class Sorter extends Block{ } boolean isSame(Tile tile, Tile other){ - return other != null && other.block() instanceof Sorter; + //uncomment comment below to prevent sorter/gate chaining (hacky) + return other != null && (other.block() instanceof Sorter/* || other.block() instanceof OverflowGate */); } Tile getTileTarget(Item item, Tile dest, Tile source, boolean flip){ @@ -158,12 +159,9 @@ public class Sorter extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); sortItem = content.item(stream.readShort()); - if(revision == 1){ - new DirectionalItemBuffer(20, 45f).read(stream); - } } } } diff --git a/core/src/mindustry/world/blocks/liquid/ArmoredConduit.java b/core/src/mindustry/world/blocks/liquid/ArmoredConduit.java index 82fe515f0f..da8c442706 100644 --- a/core/src/mindustry/world/blocks/liquid/ArmoredConduit.java +++ b/core/src/mindustry/world/blocks/liquid/ArmoredConduit.java @@ -28,7 +28,7 @@ public class ArmoredConduit extends Conduit{ // draw the cap when a conduit would normally leak Tile next = tile.front(); - if(next != null && next.getTeam() == tile.getTeam() && next.block().hasLiquids) return; + if(next != null && next.team() == tile.team() && next.block().hasLiquids) return; Draw.rect(capRegion, tile.drawx(), tile.drawy(), tile.rotation() * 90); } diff --git a/core/src/mindustry/world/blocks/liquid/Conduit.java b/core/src/mindustry/world/blocks/liquid/Conduit.java index eb5511891e..b605e06cb5 100644 --- a/core/src/mindustry/world/blocks/liquid/Conduit.java +++ b/core/src/mindustry/world/blocks/liquid/Conduit.java @@ -8,8 +8,8 @@ import arc.math.geom.*; import arc.struct.*; import arc.util.*; import mindustry.content.*; -import mindustry.entities.traits.BuilderTrait.*; -import mindustry.entities.type.*; +import mindustry.entities.units.*; +import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.*; @@ -96,7 +96,7 @@ public class Conduit extends LiquidBlock implements Autotiler{ Draw.colorl(0.34f); Draw.rect(botRegions[entity.blendbits], tile.drawx(), tile.drawy(), rotation); - Draw.color(tile.entity.liquids.current().color); + Draw.color(tile.entity.liquids().current().color); Draw.alpha(entity.smoothLiquid); Draw.rect(botRegions[entity.blendbits], tile.drawx(), tile.drawy(), rotation); Draw.color(); @@ -107,10 +107,10 @@ public class Conduit extends LiquidBlock implements Autotiler{ @Override public void update(Tile tile){ ConduitEntity entity = tile.ent(); - entity.smoothLiquid = Mathf.lerpDelta(entity.smoothLiquid, entity.liquids.currentAmount() / liquidCapacity, 0.05f); + entity.smoothLiquid = Mathf.lerpDelta(entity.smoothLiquid, entity.liquids().currentAmount() / liquidCapacity, 0.05f); - if(tile.entity.liquids.total() > 0.001f && tile.entity.timer.get(timerFlow, 1)){ - tryMoveLiquid(tile, tile.getNearby(tile.rotation()), leakResistance, tile.entity.liquids.current()); + if(tile.entity.liquids().total() > 0.001f && tile.entity.timer(timerFlow, 1)){ + tryMoveLiquid(tile, tile.getNearby(tile.rotation()), leakResistance, tile.entity.liquids().current()); entity.noSleep(); }else{ entity.sleep(); @@ -125,7 +125,7 @@ public class Conduit extends LiquidBlock implements Autotiler{ @Override public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ tile.entity.noSleep(); - return tile.entity.liquids.get(liquid) + amount < liquidCapacity && (tile.entity.liquids.current() == liquid || tile.entity.liquids.get(tile.entity.liquids.current()) < 0.2f) + return tile.entity.liquids().get(liquid) + amount < liquidCapacity && (tile.entity.liquids().current() == liquid || tile.entity.liquids().get(tile.entity.liquids().current()) < 0.2f) && ((source.absoluteRelativeTo(tile.x, tile.y) + 2) % 4 != tile.rotation()); } diff --git a/core/src/mindustry/world/blocks/liquid/LiquidBridge.java b/core/src/mindustry/world/blocks/liquid/LiquidBridge.java index b1a790b491..2f43129858 100644 --- a/core/src/mindustry/world/blocks/liquid/LiquidBridge.java +++ b/core/src/mindustry/world/blocks/liquid/LiquidBridge.java @@ -28,11 +28,11 @@ public class LiquidBridge extends ItemBridge{ Tile other = world.tile(entity.link); if(!linkValid(tile, other)){ - tryDumpLiquid(tile, entity.liquids.current()); + tryDumpLiquid(tile, entity.liquids().current()); }else{ ((ItemBridgeEntity)world.tile(entity.link).entity).incoming.add(tile.pos()); - if(entity.cons.valid()){ + if(entity.consValid()){ float alpha = 0.04f; if(hasPower){ alpha *= entity.efficiency(); // Exceed boot time unless power is at max. @@ -44,7 +44,7 @@ public class LiquidBridge extends ItemBridge{ if(entity.uptime >= 0.5f){ - if(tryMoveLiquid(tile, other, false, entity.liquids.current()) > 0.1f){ + if(tryMoveLiquid(tile, other, false, entity.liquids().current()) > 0.1f){ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 4f, 0.05f); }else{ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 1f, 0.01f); diff --git a/core/src/mindustry/world/blocks/liquid/LiquidExtendingBridge.java b/core/src/mindustry/world/blocks/liquid/LiquidExtendingBridge.java index 8b7840e9ad..99cdec27ab 100644 --- a/core/src/mindustry/world/blocks/liquid/LiquidExtendingBridge.java +++ b/core/src/mindustry/world/blocks/liquid/LiquidExtendingBridge.java @@ -28,11 +28,11 @@ public class LiquidExtendingBridge extends ExtendingItemBridge{ Tile other = world.tile(entity.link); if(!linkValid(tile, other)){ - tryDumpLiquid(tile, entity.liquids.current()); + tryDumpLiquid(tile, entity.liquids().current()); }else{ ((ItemBridgeEntity)world.tile(entity.link).entity).incoming.add(tile.pos()); - if(entity.cons.valid()){ + if(entity.consValid()){ entity.uptime = Mathf.lerpDelta(entity.uptime, 1f, 0.04f); }else{ entity.uptime = Mathf.lerpDelta(entity.uptime, 0f, 0.02f); @@ -40,7 +40,7 @@ public class LiquidExtendingBridge extends ExtendingItemBridge{ if(entity.uptime >= 0.5f){ - if(tryMoveLiquid(tile, other, false, entity.liquids.current()) > 0.1f){ + if(tryMoveLiquid(tile, other, false, entity.liquids().current()) > 0.1f){ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 4f, 0.05f); }else{ entity.cycleSpeed = Mathf.lerpDelta(entity.cycleSpeed, 1f, 0.01f); diff --git a/core/src/mindustry/world/blocks/liquid/LiquidRouter.java b/core/src/mindustry/world/blocks/liquid/LiquidRouter.java index 35f7e09ea8..3f787d1ef2 100644 --- a/core/src/mindustry/world/blocks/liquid/LiquidRouter.java +++ b/core/src/mindustry/world/blocks/liquid/LiquidRouter.java @@ -13,13 +13,13 @@ public class LiquidRouter extends LiquidBlock{ @Override public void update(Tile tile){ - if(tile.entity.liquids.total() > 0.01f){ - tryDumpLiquid(tile, tile.entity.liquids.current()); + if(tile.entity.liquids().total() > 0.01f){ + tryDumpLiquid(tile, tile.entity.liquids().current()); } } @Override public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - return tile.entity.liquids.get(liquid) + amount < liquidCapacity && (tile.entity.liquids.current() == liquid || tile.entity.liquids.get(tile.entity.liquids.current()) < 0.2f); + return tile.entity.liquids().get(liquid) + amount < liquidCapacity && (tile.entity.liquids().current() == liquid || tile.entity.liquids().get(tile.entity.liquids().current()) < 0.2f); } } diff --git a/core/src/mindustry/world/blocks/logic/MessageBlock.java b/core/src/mindustry/world/blocks/logic/MessageBlock.java index 697dda9401..7bd04a7e49 100644 --- a/core/src/mindustry/world/blocks/logic/MessageBlock.java +++ b/core/src/mindustry/world/blocks/logic/MessageBlock.java @@ -11,7 +11,7 @@ import arc.scene.ui.layout.*; import arc.util.*; import arc.util.pooling.*; import mindustry.entities.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.gen.*; import mindustry.net.*; import mindustry.ui.*; @@ -35,7 +35,7 @@ public class MessageBlock extends Block{ } @Remote(targets = Loc.both, called = Loc.both, forward = true) - public static void setMessageBlockText(Player player, Tile tile, String text){ + public static void setMessageBlockText(Playerc player, Tile tile, String text){ if(!Units.canInteract(player, tile)) return; if(net.server() && text.length() > maxTextLength){ throw new ValidateException(player, "Player has gone above text limit."); @@ -157,8 +157,8 @@ public class MessageBlock extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); message = stream.readUTF(); } } diff --git a/core/src/mindustry/world/blocks/power/ConditionalConsumePower.java b/core/src/mindustry/world/blocks/power/ConditionalConsumePower.java index fa94ea64cc..35e3b08514 100644 --- a/core/src/mindustry/world/blocks/power/ConditionalConsumePower.java +++ b/core/src/mindustry/world/blocks/power/ConditionalConsumePower.java @@ -1,20 +1,20 @@ package mindustry.world.blocks.power; import arc.func.Boolf; -import mindustry.entities.type.TileEntity; +import mindustry.gen.*; import mindustry.world.consumers.ConsumePower; /** A power consumer that only activates sometimes. */ public class ConditionalConsumePower extends ConsumePower{ - private final Boolf consume; + private final Boolf consume; - public ConditionalConsumePower(float usage, Boolf consume){ + public ConditionalConsumePower(float usage, Boolf consume){ super(usage, 0, false); this.consume = consume; } @Override - public float requestedPower(TileEntity entity){ + public float requestedPower(Tilec entity){ return consume.get(entity) ? usage : 0f; } } diff --git a/core/src/mindustry/world/blocks/power/ImpactReactor.java b/core/src/mindustry/world/blocks/power/ImpactReactor.java index 2c47bdf465..060518016a 100644 --- a/core/src/mindustry/world/blocks/power/ImpactReactor.java +++ b/core/src/mindustry/world/blocks/power/ImpactReactor.java @@ -53,7 +53,7 @@ public class ImpactReactor extends PowerGenerator{ bars.add("poweroutput", entity -> new Bar(() -> Core.bundle.format("bar.poweroutput", - Strings.fixed(Math.max(entity.block.getPowerProduction(entity.tile) - consumes.getPower().usage, 0) * 60 * entity.timeScale, 1)), + Strings.fixed(Math.max(entity.block().getPowerProduction(entity.tile()) - consumes.getPower().usage, 0) * 60 * entity.timeScale(), 1)), () -> Pal.powerBar, () -> ((GeneratorEntity)entity).productionEfficiency)); } @@ -71,7 +71,7 @@ public class ImpactReactor extends PowerGenerator{ public void update(Tile tile){ FusionReactorEntity entity = tile.ent(); - if(entity.cons.valid() && entity.power.status >= 0.99f){ + if(entity.consValid() && entity.power().status >= 0.99f){ boolean prevOut = getPowerProduction(tile) <= consumes.getPower().requestedPower(entity); entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, warmupSpeed); @@ -83,8 +83,8 @@ public class ImpactReactor extends PowerGenerator{ Events.fire(Trigger.impactPower); } - if(entity.timer.get(timerUse, itemDuration / entity.timeScale)){ - entity.cons.trigger(); + if(entity.timer(timerUse, itemDuration / entity.timeScale())){ + entity.consume(); } }else{ entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, 0.01f); @@ -138,9 +138,9 @@ public class ImpactReactor extends PowerGenerator{ Sounds.explosionbig.at(tile); Effects.shake(6f, 16f, tile.worldx(), tile.worldy()); - Effects.effect(Fx.impactShockwave, tile.worldx(), tile.worldy()); + Fx.impactShockwave.at(tile.worldx(), tile.worldy()); for(int i = 0; i < 6; i++){ - Time.run(Mathf.random(80), () -> Effects.effect(Fx.impactcloud, tile.worldx(), tile.worldy())); + Time.run(Mathf.random(80), () -> Fx.impactcloud.at(tile.worldx(), tile.worldy())); } Damage.damage(tile.worldx(), tile.worldy(), explosionRadius * tilesize, explosionDamage * 4); @@ -149,14 +149,14 @@ public class ImpactReactor extends PowerGenerator{ for(int i = 0; i < 20; i++){ Time.run(Mathf.random(80), () -> { Tmp.v1.rnd(Mathf.random(40f)); - Effects.effect(Fx.explosion, Tmp.v1.x + tile.worldx(), Tmp.v1.y + tile.worldy()); + Fx.explosion.at(Tmp.v1.x + tile.worldx(), Tmp.v1.y + tile.worldy()); }); } for(int i = 0; i < 70; i++){ Time.run(Mathf.random(90), () -> { Tmp.v1.rnd(Mathf.random(120f)); - Effects.effect(Fx.impactsmoke, Tmp.v1.x + tile.worldx(), Tmp.v1.y + tile.worldy()); + Fx.impactsmoke.at(Tmp.v1.x + tile.worldx(), Tmp.v1.y + tile.worldy()); }); } } @@ -171,8 +171,8 @@ public class ImpactReactor extends PowerGenerator{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); warmup = stream.readFloat(); } } diff --git a/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java b/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java index 1eb1cf6033..32dbab21c7 100644 --- a/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java +++ b/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java @@ -7,7 +7,6 @@ import arc.math.*; import arc.util.*; import mindustry.content.*; import mindustry.entities.*; -import mindustry.entities.Effects.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.consumers.*; @@ -99,14 +98,14 @@ public class ItemLiquidGenerator extends PowerGenerator{ //Power amount is delta'd by PowerGraph class already. float calculationDelta = entity.delta(); - if(!entity.cons.valid()){ + if(!entity.consValid()){ entity.productionEfficiency = 0.0f; return; } Liquid liquid = null; for(Liquid other : content.liquids()){ - if(hasLiquids && entity.liquids.get(other) >= 0.001f && getLiquidEfficiency(other) >= minLiquidEfficiency){ + if(hasLiquids && entity.liquids().get(other) >= 0.001f && getLiquidEfficiency(other) >= minLiquidEfficiency){ liquid = other; break; } @@ -115,35 +114,35 @@ public class ItemLiquidGenerator extends PowerGenerator{ entity.heat = Mathf.lerpDelta(entity.heat, entity.generateTime >= 0.001f ? 1f : 0f, 0.05f); //liquid takes priority over solids - if(hasLiquids && liquid != null && entity.liquids.get(liquid) >= 0.001f){ + if(hasLiquids && liquid != null && entity.liquids().get(liquid) >= 0.001f){ float baseLiquidEfficiency = getLiquidEfficiency(liquid); float maximumPossible = maxLiquidGenerate * calculationDelta; - float used = Math.min(entity.liquids.get(liquid) * calculationDelta, maximumPossible); + float used = Math.min(entity.liquids().get(liquid) * calculationDelta, maximumPossible); - entity.liquids.remove(liquid, used * entity.power.graph.getUsageFraction()); + entity.liquids().remove(liquid, used * entity.power().graph.getUsageFraction()); entity.productionEfficiency = baseLiquidEfficiency * used / maximumPossible; if(used > 0.001f && Mathf.chance(0.05 * entity.delta())){ - Effects.effect(generateEffect, tile.drawx() + Mathf.range(3f), tile.drawy() + Mathf.range(3f)); + generateEffect.at(tile.drawx() + Mathf.range(3f), tile.drawy() + Mathf.range(3f)); } }else if(hasItems){ // No liquids accepted or none supplied, try using items if accepted - if(entity.generateTime <= 0f && entity.items.total() > 0){ - Effects.effect(generateEffect, tile.worldx() + Mathf.range(3f), tile.worldy() + Mathf.range(3f)); - Item item = entity.items.take(); + if(entity.generateTime <= 0f && entity.items().total() > 0){ + generateEffect.at(tile.worldx() + Mathf.range(3f), tile.worldy() + Mathf.range(3f)); + Item item = entity.items().take(); entity.productionEfficiency = getItemEfficiency(item); entity.explosiveness = item.explosiveness; entity.generateTime = 1f; } if(entity.generateTime > 0f){ - entity.generateTime -= Math.min(1f / itemDuration * entity.delta() * entity.power.graph.getUsageFraction(), entity.generateTime); + entity.generateTime -= Math.min(1f / itemDuration * entity.delta() * entity.power().graph.getUsageFraction(), entity.generateTime); if(randomlyExplode && state.rules.reactorExplosions && Mathf.chance(entity.delta() * 0.06 * Mathf.clamp(entity.explosiveness - 0.5f))){ //this block is run last so that in the event of a block destruction, no code relies on the block type Core.app.post(() -> { entity.damage(Mathf.random(11f)); - Effects.effect(explodeEffect, tile.worldx() + Mathf.range(size * tilesize / 2f), tile.worldy() + Mathf.range(size * tilesize / 2f)); + explodeEffect.at(tile.worldx() + Mathf.range(size * tilesize / 2f), tile.worldy() + Mathf.range(size * tilesize / 2f)); }); } }else{ @@ -166,8 +165,8 @@ public class ItemLiquidGenerator extends PowerGenerator{ } if(hasLiquids){ - Draw.color(entity.liquids.current().color); - Draw.alpha(entity.liquids.currentAmount() / liquidCapacity); + Draw.color(entity.liquids().current().color); + Draw.alpha(entity.liquids().currentAmount() / liquidCapacity); Draw.rect(liquidRegion, tile.drawx(), tile.drawy()); Draw.color(); } diff --git a/core/src/mindustry/world/blocks/power/LightBlock.java b/core/src/mindustry/world/blocks/power/LightBlock.java index 82637dd410..8601914af8 100644 --- a/core/src/mindustry/world/blocks/power/LightBlock.java +++ b/core/src/mindustry/world/blocks/power/LightBlock.java @@ -4,7 +4,7 @@ import arc.graphics.*; import arc.graphics.g2d.*; import arc.scene.ui.layout.*; import arc.util.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.world.*; @@ -62,7 +62,7 @@ public class LightBlock extends Block{ } @Override - public void configured(Tile tile, Player player, int value){ + public void configured(Tile tile, Playerc player, int value){ tile.ent().color = value; } @@ -87,8 +87,8 @@ public class LightBlock extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); color = stream.readInt(); } } diff --git a/core/src/mindustry/world/blocks/power/NuclearReactor.java b/core/src/mindustry/world/blocks/power/NuclearReactor.java index b583b3cfdf..c250f28ab5 100644 --- a/core/src/mindustry/world/blocks/power/NuclearReactor.java +++ b/core/src/mindustry/world/blocks/power/NuclearReactor.java @@ -79,30 +79,30 @@ public class NuclearReactor extends PowerGenerator{ ConsumeLiquid cliquid = consumes.get(ConsumeType.liquid); Item item = consumes.get(ConsumeType.item).items[0].item; - int fuel = entity.items.get(item); + int fuel = entity.items().get(item); float fullness = (float)fuel / itemCapacity; entity.productionEfficiency = fullness; if(fuel > 0){ entity.heat += fullness * heating * Math.min(entity.delta(), 4f); - if(entity.timer.get(timerFuel, itemDuration / entity.timeScale)){ - entity.cons.trigger(); + if(entity.timer(timerFuel, itemDuration / entity.timeScale())){ + entity.consume(); } } Liquid liquid = cliquid.liquid; if(entity.heat > 0){ - float maxUsed = Math.min(entity.liquids.get(liquid), entity.heat / coolantPower); + float maxUsed = Math.min(entity.liquids().get(liquid), entity.heat / coolantPower); entity.heat -= maxUsed * coolantPower; - entity.liquids.remove(liquid, maxUsed); + entity.liquids().remove(liquid, maxUsed); } if(entity.heat > smokeThreshold){ float smoke = 1.0f + (entity.heat - smokeThreshold) / (1f - smokeThreshold); //ranges from 1.0 to 2.0 if(Mathf.chance(smoke / 20.0 * entity.delta())){ - Effects.effect(Fx.reactorsmoke, tile.worldx() + Mathf.range(size * tilesize / 2f), + Fx.reactorsmoke.at(tile.worldx() + Mathf.range(size * tilesize / 2f), tile.worldy() + Mathf.random(size * tilesize / 2f)); } } @@ -123,14 +123,14 @@ public class NuclearReactor extends PowerGenerator{ NuclearReactorEntity entity = tile.ent(); - int fuel = entity.items.get(consumes.get(ConsumeType.item).items[0].item); + int fuel = entity.items().get(consumes.get(ConsumeType.item).items[0].item); if((fuel < 5 && entity.heat < 0.5f) || !state.rules.reactorExplosions) return; Effects.shake(6f, 16f, tile.worldx(), tile.worldy()); - Effects.effect(Fx.nuclearShockwave, tile.worldx(), tile.worldy()); + Fx.nuclearShockwave.at(tile.worldx(), tile.worldy()); for(int i = 0; i < 6; i++){ - Time.run(Mathf.random(40), () -> Effects.effect(Fx.nuclearcloud, tile.worldx(), tile.worldy())); + Time.run(Mathf.random(40), () -> Fx.nuclearcloud.at(tile.worldx(), tile.worldy())); } Damage.damage(tile.worldx(), tile.worldy(), explosionRadius * tilesize, explosionDamage * 4); @@ -138,14 +138,14 @@ public class NuclearReactor extends PowerGenerator{ for(int i = 0; i < 20; i++){ Time.run(Mathf.random(50), () -> { tr.rnd(Mathf.random(40f)); - Effects.effect(Fx.explosion, tr.x + tile.worldx(), tr.y + tile.worldy()); + Fx.explosion.at(tr.x + tile.worldx(), tr.y + tile.worldy()); }); } for(int i = 0; i < 70; i++){ Time.run(Mathf.random(80), () -> { tr.rnd(Mathf.random(120f)); - Effects.effect(Fx.nuclearsmoke, tr.x + tile.worldx(), tr.y + tile.worldy()); + Fx.nuclearsmoke.at(tr.x + tile.worldx(), tr.y + tile.worldy()); }); } } @@ -166,8 +166,8 @@ public class NuclearReactor extends PowerGenerator{ Draw.color(coolColor, hotColor, entity.heat); Fill.rect(tile.drawx(), tile.drawy(), size * tilesize, size * tilesize); - Draw.color(entity.liquids.current().color); - Draw.alpha(entity.liquids.currentAmount() / liquidCapacity); + Draw.color(entity.liquids().current().color); + Draw.alpha(entity.liquids().currentAmount() / liquidCapacity); Draw.rect(topRegion, tile.drawx(), tile.drawy()); if(entity.heat > flashThreshold){ @@ -192,8 +192,8 @@ public class NuclearReactor extends PowerGenerator{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); heat = stream.readFloat(); } } diff --git a/core/src/mindustry/world/blocks/power/PowerDiode.java b/core/src/mindustry/world/blocks/power/PowerDiode.java index eea5b46d72..267fb727d0 100644 --- a/core/src/mindustry/world/blocks/power/PowerDiode.java +++ b/core/src/mindustry/world/blocks/power/PowerDiode.java @@ -2,6 +2,7 @@ package mindustry.world.blocks.power; import arc.Core; import arc.math.Mathf; +import mindustry.entities.units.*; import mindustry.ui.Bar; import arc.util.Eachable; import mindustry.ui.Cicon; @@ -10,7 +11,6 @@ import mindustry.world.Block; import arc.graphics.g2d.Draw; import mindustry.graphics.Pal; import arc.graphics.g2d.TextureRegion; -import mindustry.entities.traits.BuilderTrait; public class PowerDiode extends Block{ public TextureRegion arrow; @@ -27,10 +27,10 @@ public class PowerDiode extends Block{ public void update(Tile tile){ super.update(tile); - if(tile.front() == null || tile.back() == null || !tile.back().block().hasPower || !tile.front().block().hasPower || tile.back().getTeam() != tile.front().getTeam()) return; + if(tile.front() == null || tile.back() == null || !tile.back().block().hasPower || !tile.front().block().hasPower || tile.back().team() != tile.front().team()) return; - PowerGraph backGraph = tile.back().entity.power.graph; - PowerGraph frontGraph = tile.front().entity.power.graph; + PowerGraph backGraph = tile.back().entity.power().graph; + PowerGraph frontGraph = tile.front().entity.power().graph; if(backGraph == frontGraph) return; // 0f - 1f of battery capacity in use @@ -51,15 +51,15 @@ public class PowerDiode extends Block{ // battery % of the graph on either side, defaults to zero public float bar(Tile tile){ - return (tile != null && tile.block().hasPower) ? tile.entity.power.graph.getBatteryStored() / tile.entity.power.graph.getTotalBatteryCapacity() : 0f; + return (tile != null && tile.block().hasPower) ? tile.entity.power().graph.getBatteryStored() / tile.entity.power().graph.getTotalBatteryCapacity() : 0f; } @Override public void setBars(){ super.setBars(); - bars.add("back", entity -> new Bar("bar.input", Pal.powerBar, () -> bar(entity.tile.back()))); - bars.add("front", entity -> new Bar("bar.output", Pal.powerBar, () -> bar(entity.tile.front()))); + bars.add("back", entity -> new Bar("bar.input", Pal.powerBar, () -> bar(entity.tile().back()))); + bars.add("front", entity -> new Bar("bar.output", Pal.powerBar, () -> bar(entity.tile().front()))); } @Override @@ -75,7 +75,7 @@ public class PowerDiode extends Block{ } @Override - public void drawRequestRegion(BuilderTrait.BuildRequest req, Eachable list) { + public void drawRequestRegion(BuildRequest req, Eachable list) { TextureRegion reg = icon(Cicon.full); Draw.rect(icon(Cicon.full), req.drawx(), req.drawy(), reg.getWidth() * req.animScale * Draw.scl, diff --git a/core/src/mindustry/world/blocks/power/PowerGenerator.java b/core/src/mindustry/world/blocks/power/PowerGenerator.java index b7cff15bd7..39b8271bdf 100644 --- a/core/src/mindustry/world/blocks/power/PowerGenerator.java +++ b/core/src/mindustry/world/blocks/power/PowerGenerator.java @@ -3,7 +3,7 @@ package mindustry.world.blocks.power; import arc.Core; import arc.struct.EnumSet; import arc.util.Strings; -import mindustry.entities.type.TileEntity; +import mindustry.gen.*; import mindustry.graphics.Pal; import mindustry.ui.Bar; import mindustry.world.Tile; @@ -37,7 +37,7 @@ public class PowerGenerator extends PowerDistributor{ if(hasPower && outputsPower && !consumes.hasPower()){ bars.add("power", entity -> new Bar(() -> Core.bundle.format("bar.poweroutput", - Strings.fixed(entity.block.getPowerProduction(entity.tile) * 60 * entity.timeScale, 1)), + Strings.fixed(entity.block().getPowerProduction(entity.tile()) * 60 * entity.timeScale(), 1)), () -> Pal.powerBar, () -> ((GeneratorEntity)entity).productionEfficiency)); } @@ -65,8 +65,8 @@ public class PowerGenerator extends PowerDistributor{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); productionEfficiency = stream.readFloat(); } } diff --git a/core/src/mindustry/world/blocks/power/PowerGraph.java b/core/src/mindustry/world/blocks/power/PowerGraph.java index be5d593797..c3ea54ad9e 100644 --- a/core/src/mindustry/world/blocks/power/PowerGraph.java +++ b/core/src/mindustry/world/blocks/power/PowerGraph.java @@ -88,7 +88,7 @@ public class PowerGraph{ for(Tile battery : batteries){ Consumers consumes = battery.block().consumes; if(consumes.hasPower()){ - totalAccumulator += battery.entity.power.status * consumes.getPower().capacity; + totalAccumulator += battery.entity.power().status * consumes.getPower().capacity; } } return totalAccumulator; @@ -99,7 +99,7 @@ public class PowerGraph{ for(Tile battery : batteries){ if(battery.block().consumes.hasPower()){ ConsumePower power = battery.block().consumes.getPower(); - totalCapacity += (1f - battery.entity.power.status) * power.capacity; + totalCapacity += (1f - battery.entity.power().status) * power.capacity; } } return totalCapacity; @@ -124,7 +124,7 @@ public class PowerGraph{ for(Tile battery : batteries){ Consumers consumes = battery.block().consumes; if(consumes.hasPower()){ - battery.entity.power.status *= (1f-consumedPowerPercentage); + battery.entity.power().status *= (1f-consumedPowerPercentage); } } return used; @@ -141,7 +141,7 @@ public class PowerGraph{ if(consumes.hasPower()){ ConsumePower consumePower = consumes.getPower(); if(consumePower.capacity > 0f){ - battery.entity.power.status += (1f-battery.entity.power.status) * chargedPercent; + battery.entity.power().status += (1f-battery.entity.power().status) * chargedPercent; } } } @@ -159,17 +159,17 @@ public class PowerGraph{ if(!Mathf.zero(consumePower.capacity)){ // Add an equal percentage of power to all buffers, based on the global power coverage in this graph float maximumRate = consumePower.requestedPower(consumer.entity) * coverage * consumer.entity.delta(); - consumer.entity.power.status = Mathf.clamp(consumer.entity.power.status + maximumRate / consumePower.capacity); + consumer.entity.power().status = Mathf.clamp(consumer.entity.power().status + maximumRate / consumePower.capacity); } }else{ //valid consumers get power as usual if(otherConsumersAreValid(consumer, consumePower)){ - consumer.entity.power.status = coverage; + consumer.entity.power().status = coverage; }else{ //invalid consumers get an estimate, if they were to activate - consumer.entity.power.status = Math.min(1, produced / (needed + consumePower.usage * consumer.entity.delta())); + consumer.entity.power().status = Math.min(1, produced / (needed + consumePower.usage * consumer.entity.delta())); //just in case - if(Float.isNaN(consumer.entity.power.status)){ - consumer.entity.power.status = 0f; + if(Float.isNaN(consumer.entity.power().status)){ + consumer.entity.power().status = 0f; } } } @@ -183,7 +183,7 @@ public class PowerGraph{ }else if(!consumers.isEmpty() && consumers.first().isEnemyCheat()){ //when cheating, just set status to 1 for(Tile tile : consumers){ - tile.entity.power.status = 1f; + tile.entity.power().status = 1f; } lastPowerNeeded = lastPowerProduced = lastUsageFraction = 1f; @@ -230,8 +230,8 @@ public class PowerGraph{ } public void add(Tile tile){ - if(tile.entity == null || tile.entity.power == null) return; - tile.entity.power.graph = this; + if(tile.entity == null || tile.entity.power() == null) return; + tile.entity.power().graph = this; all.add(tile); if(tile.block().outputsPower && tile.block().consumesPower && !tile.block().consumes.getPower().buffered){ @@ -277,7 +277,7 @@ public class PowerGraph{ //go through all the connections of this tile for(Tile other : tile.block().getPowerConnections(tile, outArray1)){ //a graph has already been assigned to this tile from a previous call, skip it - if(other.entity.power.graph != this) continue; + if(other.entity.power().graph != this) continue; //create graph for this branch PowerGraph graph = new PowerGraph(); @@ -296,7 +296,7 @@ public class PowerGraph{ for(Tile next : child.block().getPowerConnections(child, outArray2)){ //make sure it hasn't looped back, and that the new graph being assigned hasn't already been assigned //also skip closed tiles - if(next != tile && next.entity.power.graph != graph && !closedSet.contains(next.pos())){ + if(next != tile && next.entity.power().graph != graph && !closedSet.contains(next.pos())){ queue.addLast(next); closedSet.add(next.pos()); } diff --git a/core/src/mindustry/world/blocks/power/PowerNode.java b/core/src/mindustry/world/blocks/power/PowerNode.java index 7a267abeef..a1c277a150 100644 --- a/core/src/mindustry/world/blocks/power/PowerNode.java +++ b/core/src/mindustry/world/blocks/power/PowerNode.java @@ -9,7 +9,7 @@ import arc.math.*; import arc.math.geom.*; import arc.util.*; import arc.util.ArcAnnotate.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.graphics.*; import mindustry.ui.*; import mindustry.world.*; @@ -38,41 +38,41 @@ public class PowerNode extends PowerBlock{ } @Override - public void configured(Tile tile, Player player, int value){ - TileEntity entity = tile.entity; + public void configured(Tile tile, Playerc player, int value){ + Tilec entity = tile.entity; Tile other = world.tile(value); - boolean contains = entity.power.links.contains(value), valid = other != null && other.entity != null && other.entity.power != null; + boolean contains = entity.power().links.contains(value), valid = other != null && other.entity != null && other.entity.power() != null; if(contains){ //unlink - entity.power.links.removeValue(value); - if(valid) other.entity.power.links.removeValue(tile.pos()); + entity.power().links.removeValue(value); + if(valid) other.entity.power().links.removeValue(tile.pos()); PowerGraph newgraph = new PowerGraph(); //reflow from this point, covering all tiles on this side newgraph.reflow(tile); - if(valid && other.entity.power.graph != newgraph){ + if(valid && other.entity.power().graph != newgraph){ //create new graph for other end PowerGraph og = new PowerGraph(); //reflow from other end og.reflow(other); } - }else if(linkValid(tile, other) && valid && entity.power.links.size < maxNodes){ + }else if(linkValid(tile, other) && valid && entity.power().links.size < maxNodes){ - if(!entity.power.links.contains(other.pos())){ - entity.power.links.add(other.pos()); + if(!entity.power().links.contains(other.pos())){ + entity.power().links.add(other.pos()); } if(other.getTeamID() == tile.getTeamID()){ - if(!other.entity.power.links.contains(tile.pos())){ - other.entity.power.links.add(tile.pos()); + if(!other.entity.power().links.contains(tile.pos())){ + other.entity.power().links.add(tile.pos()); } } - entity.power.graph.add(other.entity.power.graph); + entity.power().graph.add(other.entity.power().graph); } } @@ -89,15 +89,15 @@ public class PowerNode extends PowerBlock{ super.setBars(); bars.add("power", entity -> new Bar(() -> Core.bundle.format("bar.powerbalance", - ((entity.power.graph.getPowerBalance() >= 0 ? "+" : "") + Strings.fixed(entity.power.graph.getPowerBalance() * 60, 1))), + ((entity.power().graph.getPowerBalance() >= 0 ? "+" : "") + Strings.fixed(entity.power().graph.getPowerBalance() * 60, 1))), () -> Pal.powerBar, - () -> Mathf.clamp(entity.power.graph.getLastPowerProduced() / entity.power.graph.getLastPowerNeeded()))); + () -> Mathf.clamp(entity.power().graph.getLastPowerProduced() / entity.power().graph.getLastPowerNeeded()))); bars.add("batteries", entity -> new Bar(() -> Core.bundle.format("bar.powerstored", - (ui.formatAmount((int)entity.power.graph.getBatteryStored())), ui.formatAmount((int)entity.power.graph.getTotalBatteryCapacity())), + (ui.formatAmount((int)entity.power().graph.getBatteryStored())), ui.formatAmount((int)entity.power().graph.getTotalBatteryCapacity())), () -> Pal.powerBar, - () -> Mathf.clamp(entity.power.graph.getBatteryStored() / entity.power.graph.getTotalBatteryCapacity()))); + () -> Mathf.clamp(entity.power().graph.getBatteryStored() / entity.power().graph.getTotalBatteryCapacity()))); } @Override @@ -105,7 +105,7 @@ public class PowerNode extends PowerBlock{ if(net.client()) return; Boolf valid = other -> other != null && other != tile && ((!other.block().outputsPower && other.block().consumesPower) || (other.block().outputsPower && !other.block().consumesPower) || other.block() instanceof PowerNode) && linkValid(tile, other) - && !other.entity.proximity().contains(tile) && other.entity.power.graph != tile.entity.power.graph; + && !other.entity.proximity().contains(tile) && other.entity.power().graph != tile.entity.power().graph; tempTiles.clear(); Geometry.circle(tile.x, tile.y, (int)(laserRange + 2), (x, y) -> { @@ -123,7 +123,7 @@ public class PowerNode extends PowerBlock{ return Float.compare(a.dst2(tile), b.dst2(tile)); }); tempTiles.each(valid, other -> { - if(!tile.entity.power.links.contains(other.pos())){ + if(!tile.entity.power().links.contains(other.pos())){ tile.configureAny(other.pos()); } }); @@ -132,10 +132,10 @@ public class PowerNode extends PowerBlock{ } private void getPotentialLinks(Tile tile, Cons others){ - Boolf valid = other -> other != null && other != tile && other.entity != null && other.entity.power != null && + Boolf valid = other -> other != null && other != tile && other.entity != null && other.entity.power() != null && ((!other.block().outputsPower && other.block().consumesPower) || (other.block().outputsPower && !other.block().consumesPower) || other.block() instanceof PowerNode) && - overlaps(tile.x * tilesize + offset(), tile.y * tilesize + offset(), other, laserRange * tilesize) && other.getTeam() == player.getTeam() - && !other.entity.proximity().contains(tile) && !graphs.contains(other.entity.power.graph); + overlaps(tile.x * tilesize + offset(), tile.y * tilesize + offset(), other, laserRange * tilesize) && other.team() == player.team() + && !other.entity.proximity().contains(tile) && !graphs.contains(other.entity.power().graph); tempTiles.clear(); graphs.clear(); @@ -152,7 +152,7 @@ public class PowerNode extends PowerBlock{ return Float.compare(a.dst2(tile), b.dst2(tile)); }); tempTiles.each(valid, t -> { - graphs.add(t.entity.power.graph); + graphs.add(t.entity.power().graph); others.get(t); }); } @@ -167,12 +167,12 @@ public class PowerNode extends PowerBlock{ @Override public void update(Tile tile){ - tile.entity.power.graph.update(); + tile.entity.power().graph.update(); } @Override public boolean onConfigureTileTapped(Tile tile, Tile other){ - TileEntity entity = tile.ent(); + Tilec entity = tile.ent(); other = other.link(); if(linkValid(tile, other)){ @@ -181,13 +181,16 @@ public class PowerNode extends PowerBlock{ } if(tile == other){ - if(other.entity.power.links.size == 0){ + if(other.entity.power().links.size == 0){ + int[] total = {0}; getPotentialLinks(tile, link -> { - if(!insulated(tile, link)) tile.configure(link.pos()); + if(!insulated(tile, link) && total[0]++ < maxNodes){ + tile.configure(link.pos()); + } }); }else{ - while(entity.power.links.size > 0){ - tile.configure(entity.power.links.get(0)); + while(entity.power().links.size > 0){ + tile.configure(entity.power().links.get(0)); } } return false; @@ -262,10 +265,10 @@ public class PowerNode extends PowerBlock{ public void drawLayer(Tile tile){ if(Core.settings.getInt("lasersopacity") == 0) return; - TileEntity entity = tile.ent(); + Tilec entity = tile.ent(); - for(int i = 0; i < entity.power.links.size; i++){ - Tile link = world.tile(entity.power.links.get(i)); + for(int i = 0; i < entity.power().links.size; i++){ + Tile link = world.tile(entity.power().links.get(i)); if(!linkValid(tile, link)) continue; @@ -278,7 +281,7 @@ public class PowerNode extends PowerBlock{ } protected boolean linked(Tile tile, Tile other){ - return tile.entity.power.links.contains(other.pos()); + return tile.entity.power().links.contains(other.pos()); } public boolean linkValid(Tile tile, Tile link){ @@ -286,11 +289,11 @@ public class PowerNode extends PowerBlock{ } public boolean linkValid(Tile tile, Tile link, boolean checkMaxNodes){ - if(tile == link || link == null || link.entity == null || tile.entity == null || !link.block().hasPower || tile.getTeam() != link.getTeam()) return false; + if(tile == link || link == null || link.entity == null || tile.entity == null || !link.block().hasPower || tile.team() != link.team()) return false; if(overlaps(tile, link, laserRange * tilesize) || (link.block() instanceof PowerNode && overlaps(link, tile, link.cblock().laserRange * tilesize))){ if(checkMaxNodes && link.block() instanceof PowerNode){ - return link.entity.power.links.size < link.cblock().maxNodes || link.entity.power.links.contains(tile.pos()); + return link.entity.power().links.size < link.cblock().maxNodes || link.entity.power().links.contains(tile.pos()); } return true; } @@ -328,7 +331,7 @@ public class PowerNode extends PowerBlock{ x2 += t2.x; y2 += t2.y; - float fract = 1f - tile.entity.power.graph.getSatisfaction(); + float fract = 1f - tile.entity.power().graph.getSatisfaction(); Draw.color(Color.white, Pal.powerLight, fract * 0.86f + Mathf.absin(3f, 0.1f)); Draw.alpha(opacity); diff --git a/core/src/mindustry/world/blocks/power/ThermalGenerator.java b/core/src/mindustry/world/blocks/power/ThermalGenerator.java index 6c1debe03b..5e0059a05f 100644 --- a/core/src/mindustry/world/blocks/power/ThermalGenerator.java +++ b/core/src/mindustry/world/blocks/power/ThermalGenerator.java @@ -13,23 +13,31 @@ import static mindustry.Vars.renderer; public class ThermalGenerator extends PowerGenerator{ public Effect generateEffect = Fx.none; + public Attribute attribute = Attribute.heat; public ThermalGenerator(String name){ super(name); } + @Override + public void setStats(){ + super.setStats(); + + stats.add(BlockStat.tiles, attribute); + } + @Override public void update(Tile tile){ GeneratorEntity entity = tile.ent(); if(entity.productionEfficiency > 0.1f && Mathf.chance(0.05 * entity.delta())){ - Effects.effect(generateEffect, tile.drawx() + Mathf.range(3f), tile.drawy() + Mathf.range(3f)); + generateEffect.at(tile.drawx() + Mathf.range(3f), tile.drawy() + Mathf.range(3f)); } } @Override public void drawPlace(int x, int y, int rotation, boolean valid){ - drawPlaceText(Core.bundle.formatFloat("bar.efficiency", sumAttribute(Attribute.heat, x, y) * 100, 1), x, y, valid); + drawPlaceText(Core.bundle.formatFloat("bar.efficiency", sumAttribute(attribute, x, y) * 100, 1), x, y, valid); } @Override @@ -43,7 +51,7 @@ public class ThermalGenerator extends PowerGenerator{ super.onProximityAdded(tile); GeneratorEntity entity = tile.ent(); - entity.productionEfficiency = sumAttribute(Attribute.heat, tile.x, tile.y); + entity.productionEfficiency = sumAttribute(attribute, tile.x, tile.y); } @Override @@ -56,6 +64,6 @@ public class ThermalGenerator extends PowerGenerator{ @Override public boolean canPlaceOn(Tile tile){ //make sure there's heat at this location - return tile.getLinkedTilesAs(this, tempTiles).sumf(other -> other.floor().attributes.get(Attribute.heat)) > 0.01f; + return tile.getLinkedTilesAs(this, tempTiles).sumf(other -> other.floor().attributes.get(attribute)) > 0.01f; } } diff --git a/core/src/mindustry/world/blocks/production/Cultivator.java b/core/src/mindustry/world/blocks/production/Cultivator.java index 3d924c1dbf..06186b6ea1 100644 --- a/core/src/mindustry/world/blocks/production/Cultivator.java +++ b/core/src/mindustry/world/blocks/production/Cultivator.java @@ -1,17 +1,16 @@ package mindustry.world.blocks.production; -import arc.Core; -import arc.graphics.Color; +import arc.*; +import arc.graphics.*; import arc.graphics.g2d.*; -import arc.math.Mathf; -import arc.math.Rand; -import arc.util.Time; -import mindustry.content.Fx; -import mindustry.entities.type.TileEntity; -import mindustry.graphics.Pal; -import mindustry.ui.Bar; -import mindustry.world.Tile; -import mindustry.world.meta.Attribute; +import arc.math.*; +import arc.util.*; +import mindustry.content.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.ui.*; +import mindustry.world.*; +import mindustry.world.meta.*; import java.io.*; @@ -44,7 +43,7 @@ public class Cultivator extends GenericCrafter{ super.update(tile); CultivatorEntity entity = tile.ent(); - entity.warmup = Mathf.lerpDelta(entity.warmup, entity.cons.valid() ? 1f : 0f, 0.015f); + entity.warmup = Mathf.lerpDelta(entity.warmup, entity.consValid() ? 1f : 0f, 0.015f); } @Override @@ -57,6 +56,13 @@ public class Cultivator extends GenericCrafter{ () -> ((CultivatorEntity)entity).warmup)); } + @Override + public void setStats(){ + super.setStats(); + + stats.add(BlockStat.affinities, attribute); + } + @Override public void drawPlace(int x, int y, int rotation, boolean valid){ drawPlaceText(Core.bundle.formatFloat("bar.efficiency", (1 + sumAttribute(attribute, x, y)) * 100, 1), x, y, valid); @@ -104,7 +110,7 @@ public class Cultivator extends GenericCrafter{ } @Override - protected float getProgressIncrease(TileEntity entity, float baseTime){ + protected float getProgressIncrease(Tilec entity, float baseTime){ CultivatorEntity c = (CultivatorEntity)entity; return super.getProgressIncrease(entity, baseTime) * (1f + c.boost); } @@ -120,8 +126,8 @@ public class Cultivator extends GenericCrafter{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); warmup = stream.readFloat(); } } diff --git a/core/src/mindustry/world/blocks/production/Drill.java b/core/src/mindustry/world/blocks/production/Drill.java index 0a9975e69f..0840ef4aec 100644 --- a/core/src/mindustry/world/blocks/production/Drill.java +++ b/core/src/mindustry/world/blocks/production/Drill.java @@ -8,8 +8,6 @@ import arc.math.*; import arc.util.*; import mindustry.content.*; import mindustry.entities.*; -import mindustry.entities.Effects.*; -import mindustry.entities.type.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; @@ -77,7 +75,7 @@ public class Drill extends Block{ bars.add("drillspeed", e -> { DrillEntity entity = (DrillEntity)e; - return new Bar(() -> Core.bundle.format("bar.drillspeed", Strings.fixed(entity.lastDrillSpeed * 60 * entity.timeScale, 2)), () -> Pal.ammo, () -> entity.warmup); + return new Bar(() -> Core.bundle.format("bar.drillspeed", Strings.fixed(entity.lastDrillSpeed * 60 * entity.timeScale(), 2)), () -> Pal.ammo, () -> entity.warmup); }); } @@ -129,7 +127,7 @@ public class Drill extends Block{ @Override public boolean shouldConsume(Tile tile){ - return tile.entity.items.total() < itemCapacity; + return tile.entity.items().total() < itemCapacity; } @Override @@ -247,17 +245,17 @@ public class Drill extends Block{ entity.dominantItems = returnCount; } - if(entity.timer.get(timerDump, dumpTime)){ + if(entity.timer(timerDump, dumpTime)){ tryDump(tile, entity.dominantItem); } entity.drillTime += entity.warmup * entity.delta(); - if(entity.items.total() < itemCapacity && entity.dominantItems > 0 && entity.cons.valid()){ + if(entity.items().total() < itemCapacity && entity.dominantItems > 0 && entity.consValid()){ float speed = 1f; - if(entity.cons.optionalValid()){ + if(entity.cons().optionalValid()){ speed = liquidBoostIntensity; } @@ -269,14 +267,14 @@ public class Drill extends Block{ * entity.dominantItems * speed * entity.warmup; if(Mathf.chance(Time.delta() * updateEffectChance * entity.warmup)) - Effects.effect(updateEffect, entity.x + Mathf.range(size * 2f), entity.y + Mathf.range(size * 2f)); + updateEffect.at(entity.getX() + Mathf.range(size * 2f), entity.getY() + Mathf.range(size * 2f)); }else{ entity.lastDrillSpeed = 0f; entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, warmupSpeed); return; } - if(entity.dominantItems > 0 && entity.progress >= drillTime + hardnessDrillMultiplier * entity.dominantItem.hardness && tile.entity.items.total() < itemCapacity){ + if(entity.dominantItems > 0 && entity.progress >= drillTime + hardnessDrillMultiplier * entity.dominantItem.hardness && tile.entity.items().total() < itemCapacity){ offloadNear(tile, entity.dominantItem); @@ -285,8 +283,7 @@ public class Drill extends Block{ entity.index++; entity.progress = 0f; - Effects.effect(drillEffect, entity.dominantItem.color, - entity.x + Mathf.range(size), entity.y + Mathf.range(size)); + drillEffect.at(entity.getX() + Mathf.range(size), entity.getY() + Mathf.range(size), entity.dominantItem.color); } } diff --git a/core/src/mindustry/world/blocks/production/Fracker.java b/core/src/mindustry/world/blocks/production/Fracker.java index 5642830c2e..e8ce36dff8 100644 --- a/core/src/mindustry/world/blocks/production/Fracker.java +++ b/core/src/mindustry/world/blocks/production/Fracker.java @@ -44,7 +44,7 @@ public class Fracker extends SolidPump{ @Override public boolean shouldConsume(Tile tile){ - return tile.entity.liquids.get(result) < liquidCapacity - 0.01f; + return tile.entity.liquids().get(result) < liquidCapacity - 0.01f; } @Override @@ -55,7 +55,7 @@ public class Fracker extends SolidPump{ super.drawCracks(tile); Draw.color(result.color); - Draw.alpha(tile.entity.liquids.get(result) / liquidCapacity); + Draw.alpha(tile.entity.liquids().get(result) / liquidCapacity); Draw.rect(liquidRegion, tile.drawx(), tile.drawy()); Draw.color(); @@ -72,9 +72,9 @@ public class Fracker extends SolidPump{ public void update(Tile tile){ FrackerEntity entity = tile.ent(); - if(entity.cons.valid()){ + if(entity.consValid()){ if(entity.accumulator >= itemUseTime){ - entity.cons.trigger(); + entity.consume(); entity.accumulator -= itemUseTime; } @@ -87,7 +87,7 @@ public class Fracker extends SolidPump{ @Override public float typeLiquid(Tile tile){ - return tile.entity.liquids.get(result); + return tile.entity.liquids().get(result); } public static class FrackerEntity extends SolidPumpEntity{ diff --git a/core/src/mindustry/world/blocks/production/GenericCrafter.java b/core/src/mindustry/world/blocks/production/GenericCrafter.java index ee0e9a3c30..8db6b86df1 100644 --- a/core/src/mindustry/world/blocks/production/GenericCrafter.java +++ b/core/src/mindustry/world/blocks/production/GenericCrafter.java @@ -6,8 +6,6 @@ import arc.math.*; import arc.util.*; import mindustry.content.*; import mindustry.entities.*; -import mindustry.entities.Effects.*; -import mindustry.entities.type.*; import mindustry.gen.*; import mindustry.type.*; import mindustry.world.*; @@ -61,7 +59,7 @@ public class GenericCrafter extends Block{ @Override public boolean shouldIdleSound(Tile tile){ - return tile.entity.cons.valid(); + return tile.entity.cons().valid(); } @Override @@ -88,21 +86,21 @@ public class GenericCrafter extends Block{ public void update(Tile tile){ GenericCrafterEntity entity = tile.ent(); - if(entity.cons.valid()){ + if(entity.consValid()){ entity.progress += getProgressIncrease(entity, craftTime); entity.totalProgress += entity.delta(); entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, 0.02f); if(Mathf.chance(Time.delta() * updateEffectChance)){ - Effects.effect(updateEffect, entity.x + Mathf.range(size * 4f), entity.y + Mathf.range(size * 4)); + updateEffect.at(entity.getX() + Mathf.range(size * 4f), entity.getY() + Mathf.range(size * 4)); } }else{ entity.warmup = Mathf.lerp(entity.warmup, 0f, 0.02f); } if(entity.progress >= 1f){ - entity.cons.trigger(); + entity.consume(); if(outputItem != null){ useContent(tile, outputItem.item); @@ -116,11 +114,11 @@ public class GenericCrafter extends Block{ handleLiquid(tile, tile, outputLiquid.liquid, outputLiquid.amount); } - Effects.effect(craftEffect, tile.drawx(), tile.drawy()); + craftEffect.at(tile.drawx(), tile.drawy()); entity.progress = 0f; } - if(outputItem != null && tile.entity.timer.get(timerDump, dumpTime)){ + if(outputItem != null && tile.entity.timer(timerDump, dumpTime)){ tryDump(tile, outputItem.item); } @@ -134,14 +132,12 @@ public class GenericCrafter extends Block{ return outputItem != null; } - - @Override public boolean shouldConsume(Tile tile){ - if(outputItem != null && tile.entity.items.get(outputItem.item) >= itemCapacity){ + if(outputItem != null && tile.entity.items().get(outputItem.item) >= itemCapacity){ return false; } - return outputLiquid == null || !(tile.entity.liquids.get(outputLiquid.liquid) >= liquidCapacity); + return outputLiquid == null || !(tile.entity.liquids().get(outputLiquid.liquid) >= liquidCapacity); } @Override @@ -162,8 +158,8 @@ public class GenericCrafter extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); progress = stream.readFloat(); warmup = stream.readFloat(); } diff --git a/core/src/mindustry/world/blocks/production/Incinerator.java b/core/src/mindustry/world/blocks/production/Incinerator.java index 61d5d05ee8..5064d61702 100644 --- a/core/src/mindustry/world/blocks/production/Incinerator.java +++ b/core/src/mindustry/world/blocks/production/Incinerator.java @@ -6,9 +6,8 @@ import arc.graphics.g2d.Fill; import arc.math.Mathf; import arc.util.Time; import mindustry.content.Fx; -import mindustry.entities.Effects; -import mindustry.entities.Effects.Effect; -import mindustry.entities.type.TileEntity; +import mindustry.entities.*; +import mindustry.gen.*; import mindustry.type.Item; import mindustry.type.Liquid; import mindustry.world.Block; @@ -31,7 +30,7 @@ public class Incinerator extends Block{ public void update(Tile tile){ IncineratorEntity entity = tile.ent(); - if(entity.cons.valid()){ + if(entity.consValid()){ entity.heat = Mathf.lerpDelta(entity.heat, 1f, 0.04f); }else{ entity.heat = Mathf.lerpDelta(entity.heat, 0f, 0.02f); @@ -62,7 +61,7 @@ public class Incinerator extends Block{ @Override public void handleItem(Item item, Tile tile, Tile source){ if(Mathf.chance(0.3)){ - Effects.effect(effect, tile.drawx(), tile.drawy()); + effect.at(tile.drawx(), tile.drawy()); } } @@ -75,7 +74,7 @@ public class Incinerator extends Block{ @Override public void handleLiquid(Tile tile, Tile source, Liquid liquid, float amount){ if(Mathf.chance(0.02)){ - Effects.effect(effect, tile.drawx(), tile.drawy()); + effect.at(tile.drawx(), tile.drawy()); } } diff --git a/core/src/mindustry/world/blocks/production/LiquidConverter.java b/core/src/mindustry/world/blocks/production/LiquidConverter.java index b604867434..0704e6a08f 100644 --- a/core/src/mindustry/world/blocks/production/LiquidConverter.java +++ b/core/src/mindustry/world/blocks/production/LiquidConverter.java @@ -35,7 +35,7 @@ public class LiquidConverter extends GenericCrafter{ @Override public void drawLight(Tile tile){ if(hasLiquids && drawLiquidLight && outputLiquid.liquid.lightColor.a > 0.001f){ - drawLiquidLight(tile, outputLiquid.liquid, tile.entity.liquids.get(outputLiquid.liquid)); + drawLiquidLight(tile, outputLiquid.liquid, tile.entity.liquids().get(outputLiquid.liquid)); } } @@ -44,14 +44,14 @@ public class LiquidConverter extends GenericCrafter{ GenericCrafterEntity entity = tile.ent(); ConsumeLiquidBase cl = consumes.get(ConsumeType.liquid); - if(tile.entity.cons.valid()){ - float use = Math.min(cl.amount * entity.delta(), liquidCapacity - entity.liquids.get(outputLiquid.liquid)) * entity.efficiency(); + if(tile.entity.cons().valid()){ + float use = Math.min(cl.amount * entity.delta(), liquidCapacity - entity.liquids().get(outputLiquid.liquid)) * entity.efficiency(); useContent(tile, outputLiquid.liquid); entity.progress += use / cl.amount / craftTime; - entity.liquids.add(outputLiquid.liquid, use); + entity.liquids().add(outputLiquid.liquid, use); if(entity.progress >= 1f){ - entity.cons.trigger(); + entity.consume(); entity.progress = 0f; } } diff --git a/core/src/mindustry/world/blocks/production/Pump.java b/core/src/mindustry/world/blocks/production/Pump.java index 010e7cb041..7eabecdb41 100644 --- a/core/src/mindustry/world/blocks/production/Pump.java +++ b/core/src/mindustry/world/blocks/production/Pump.java @@ -48,8 +48,8 @@ public class Pump extends LiquidBlock{ public void draw(Tile tile){ Draw.rect(name, tile.drawx(), tile.drawy()); - Draw.color(tile.entity.liquids.current().color); - Draw.alpha(tile.entity.liquids.total() / liquidCapacity); + Draw.color(tile.entity.liquids().current().color); + Draw.alpha(tile.entity.liquids().total() / liquidCapacity); Draw.rect(liquidRegion, tile.drawx(), tile.drawy()); Draw.color(); } @@ -118,16 +118,16 @@ public class Pump extends LiquidBlock{ liquidDrop = tile.floor().liquidDrop; } - if(tile.entity.cons.valid() && liquidDrop != null){ - float maxPump = Math.min(liquidCapacity - tile.entity.liquids.total(), tiles * pumpAmount * tile.entity.delta() / size / size) * tile.entity.efficiency(); - tile.entity.liquids.add(liquidDrop, maxPump); + if(tile.entity.cons().valid() && liquidDrop != null){ + float maxPump = Math.min(liquidCapacity - tile.entity.liquids().total(), tiles * pumpAmount * tile.entity.delta() / size / size) * tile.entity.efficiency(); + tile.entity.liquids().add(liquidDrop, maxPump); } - if(tile.entity.liquids.currentAmount() > 0f && tile.entity.timer.get(timerContentCheck, 10)){ - useContent(tile, tile.entity.liquids.current()); + if(tile.entity.liquids().currentAmount() > 0f && tile.entity.timer(timerContentCheck, 10)){ + useContent(tile, tile.entity.liquids().current()); } - tryDumpLiquid(tile, tile.entity.liquids.current()); + tryDumpLiquid(tile, tile.entity.liquids().current()); } protected boolean isValid(Tile tile){ diff --git a/core/src/mindustry/world/blocks/production/Separator.java b/core/src/mindustry/world/blocks/production/Separator.java index 7361b8f4bb..c6f750595a 100644 --- a/core/src/mindustry/world/blocks/production/Separator.java +++ b/core/src/mindustry/world/blocks/production/Separator.java @@ -54,7 +54,7 @@ public class Separator extends Block{ @Override public boolean shouldConsume(Tile tile){ - return tile.entity.items.total() < itemCapacity; + return tile.entity.items().total() < itemCapacity; } @Override @@ -63,8 +63,8 @@ public class Separator extends Block{ GenericCrafterEntity entity = tile.ent(); - Draw.color(tile.entity.liquids.current().color); - Draw.alpha(tile.entity.liquids.total() / liquidCapacity); + Draw.color(tile.entity.liquids().current().color); + Draw.alpha(tile.entity.liquids().total() / liquidCapacity); Draw.rect(reg(liquidRegion), tile.drawx(), tile.drawy()); Draw.reset(); @@ -79,7 +79,7 @@ public class Separator extends Block{ entity.totalProgress += entity.warmup * entity.delta(); - if(entity.cons.valid()){ + if(entity.consValid()){ entity.progress += getProgressIncrease(entity, craftTime); entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, 0.02f); }else{ @@ -104,14 +104,14 @@ public class Separator extends Block{ count += stack.amount; } - entity.cons.trigger(); + entity.consume(); - if(item != null && entity.items.get(item) < itemCapacity){ + if(item != null && entity.items().get(item) < itemCapacity){ offloadNear(tile, item); } } - if(entity.timer.get(timerDump, dumpTime)){ + if(entity.timer(timerDump, dumpTime)){ tryDump(tile); } } diff --git a/core/src/mindustry/world/blocks/production/SolidPump.java b/core/src/mindustry/world/blocks/production/SolidPump.java index ac199c7b27..5675d2302b 100644 --- a/core/src/mindustry/world/blocks/production/SolidPump.java +++ b/core/src/mindustry/world/blocks/production/SolidPump.java @@ -5,11 +5,11 @@ import arc.graphics.g2d.Draw; import arc.graphics.g2d.TextureRegion; import arc.math.Mathf; import arc.util.*; +import arc.util.ArcAnnotate.*; import mindustry.content.Fx; import mindustry.content.Liquids; -import mindustry.entities.Effects; -import mindustry.entities.Effects.Effect; -import mindustry.entities.type.TileEntity; +import mindustry.entities.*; +import mindustry.gen.*; import mindustry.graphics.Pal; import mindustry.type.Liquid; import mindustry.ui.Bar; @@ -26,7 +26,7 @@ public class SolidPump extends Pump{ public float updateEffectChance = 0.02f; public float rotateSpeed = 1f; /** Attribute that is checked when calculating output. */ - public Attribute attribute; + public @Nullable Attribute attribute; public SolidPump(String name){ super(name); @@ -64,6 +64,9 @@ public class SolidPump extends Pump{ stats.remove(BlockStat.output); stats.add(BlockStat.output, result, 60f * pumpAmount, true); + if(attribute != null){ + stats.add(BlockStat.affinities, attribute); + } } @Override @@ -71,8 +74,8 @@ public class SolidPump extends Pump{ SolidPumpEntity entity = tile.ent(); Draw.rect(region, tile.drawx(), tile.drawy()); - Draw.color(tile.entity.liquids.current().color); - Draw.alpha(tile.entity.liquids.total() / liquidCapacity); + Draw.color(tile.entity.liquids().current().color); + Draw.alpha(tile.entity.liquids().total() / liquidCapacity); Draw.rect(liquidRegion, tile.drawx(), tile.drawy()); Draw.color(); Draw.rect(name + "-rotator", tile.drawx(), tile.drawy(), entity.pumpTime * rotateSpeed); @@ -102,13 +105,13 @@ public class SolidPump extends Pump{ fraction += entity.boost; - if(tile.entity.cons.valid() && typeLiquid(tile) < liquidCapacity - 0.001f){ + if(tile.entity.cons().valid() && typeLiquid(tile) < liquidCapacity - 0.001f){ float maxPump = Math.min(liquidCapacity - typeLiquid(tile), pumpAmount * entity.delta() * fraction * entity.efficiency()); - tile.entity.liquids.add(result, maxPump); + tile.entity.liquids().add(result, maxPump); entity.lastPump = maxPump; entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, 0.02f); if(Mathf.chance(entity.delta() * updateEffectChance)) - Effects.effect(updateEffect, entity.x + Mathf.range(size * 2f), entity.y + Mathf.range(size * 2f)); + updateEffect.at(entity.getX() + Mathf.range(size * 2f), entity.getY() + Mathf.range(size * 2f)); }else{ entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, 0.02f); entity.lastPump = 0f; @@ -149,7 +152,7 @@ public class SolidPump extends Pump{ } public float typeLiquid(Tile tile){ - return tile.entity.liquids.total(); + return tile.entity.liquids().total(); } public static class SolidPumpEntity extends TileEntity{ diff --git a/core/src/mindustry/world/blocks/sandbox/ItemSource.java b/core/src/mindustry/world/blocks/sandbox/ItemSource.java index 2ff49b70d8..4e6755b283 100644 --- a/core/src/mindustry/world/blocks/sandbox/ItemSource.java +++ b/core/src/mindustry/world/blocks/sandbox/ItemSource.java @@ -4,8 +4,8 @@ import arc.*; import arc.graphics.g2d.*; import arc.scene.ui.layout.*; import arc.util.*; -import mindustry.entities.traits.BuilderTrait.*; -import mindustry.entities.type.*; +import mindustry.gen.*; +import mindustry.entities.units.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.*; @@ -29,7 +29,7 @@ public class ItemSource extends Block{ } @Override - public void configured(Tile tile, Player player, int value){ + public void configured(Tile tile, Playerc player, int value){ tile.ent().outputItem = content.item(value); } @@ -73,9 +73,9 @@ public class ItemSource extends Block{ ItemSourceEntity entity = tile.ent(); if(entity.outputItem == null) return; - entity.items.set(entity.outputItem, 1); + entity.items().set(entity.outputItem, 1); tryDump(tile, entity.outputItem); - entity.items.set(entity.outputItem, 0); + entity.items().set(entity.outputItem, 0); } @Override @@ -107,8 +107,8 @@ public class ItemSource extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); outputItem = content.item(stream.readShort()); } } diff --git a/core/src/mindustry/world/blocks/sandbox/LiquidSource.java b/core/src/mindustry/world/blocks/sandbox/LiquidSource.java index d1ff0be0dd..73f89e0668 100644 --- a/core/src/mindustry/world/blocks/sandbox/LiquidSource.java +++ b/core/src/mindustry/world/blocks/sandbox/LiquidSource.java @@ -8,9 +8,9 @@ import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.util.*; import arc.util.ArcAnnotate.*; -import mindustry.entities.traits.BuilderTrait.*; -import mindustry.entities.type.*; import mindustry.gen.*; +import mindustry.gen.*; +import mindustry.entities.units.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.ui.Cicon; @@ -53,9 +53,9 @@ public class LiquidSource extends Block{ LiquidSourceEntity entity = tile.ent(); if(entity.source == null){ - tile.entity.liquids.clear(); + tile.entity.liquids().clear(); }else{ - tile.entity.liquids.add(entity.source, liquidCapacity); + tile.entity.liquids().add(entity.source, liquidCapacity); tryDumpLiquid(tile, entity.source); } } @@ -108,7 +108,7 @@ public class LiquidSource extends Block{ } @Override - public void configured(Tile tile, Player player, int value){ + public void configured(Tile tile, Playerc player, int value){ tile.ent().source = value == -1 ? null : content.liquid(value); } @@ -127,8 +127,8 @@ public class LiquidSource extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); byte id = stream.readByte(); source = id == -1 ? null : content.liquid(id); } diff --git a/core/src/mindustry/world/blocks/storage/CoreBlock.java b/core/src/mindustry/world/blocks/storage/CoreBlock.java index 4a8f500d77..6bf1cad182 100644 --- a/core/src/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/mindustry/world/blocks/storage/CoreBlock.java @@ -8,11 +8,9 @@ import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; import mindustry.content.*; -import mindustry.entities.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; -import mindustry.game.EventType.*; import mindustry.gen.*; +import mindustry.gen.*; +import mindustry.game.EventType.*; import mindustry.graphics.*; import mindustry.type.*; import mindustry.ui.*; @@ -24,7 +22,7 @@ import mindustry.world.modules.*; import static mindustry.Vars.*; public class CoreBlock extends StorageBlock{ - public Mech mech = Mechs.starter; + public UnitDef mech = UnitTypes.starter; public CoreBlock(String name){ super(name); @@ -40,15 +38,16 @@ public class CoreBlock extends StorageBlock{ } @Remote(called = Loc.server) - public static void onUnitRespawn(Tile tile, Player player){ + public static void onUnitRespawn(Tile tile, Playerc player){ if(player == null || tile.entity == null) return; CoreEntity entity = tile.ent(); - Effects.effect(Fx.spawn, entity); + Fx.spawn.at(entity); entity.progress = 0; entity.spawnPlayer = player; - entity.spawnPlayer.onRespawn(tile); - entity.spawnPlayer.applyImpulse(0, 8f); + //TODO fix + //entity.spawnPlayer.onRespawn(tile); + //entity.spawnPlayer.applyImpulse(0, 8f); entity.spawnPlayer = null; } @@ -60,7 +59,7 @@ public class CoreBlock extends StorageBlock{ new Bar( () -> Core.bundle.format("bar.capacity", ui.formatAmount(((CoreEntity)e).storageCapacity)), () -> Pal.items, - () -> e.items.total() / (float)(((CoreEntity)e).storageCapacity * content.items().count(i -> i.type == ItemType.material)) + () -> e.items().total() / (float)(((CoreEntity)e).storageCapacity * content.items().count(i -> i.type == ItemType.material)) )); } @@ -71,7 +70,7 @@ public class CoreBlock extends StorageBlock{ @Override public boolean acceptItem(Item item, Tile tile, Tile source){ - return tile.entity.items.get(item) < getMaximumAccepted(tile, item); + return tile.entity.items().get(item) < getMaximumAccepted(tile, item); } @Override @@ -84,31 +83,31 @@ public class CoreBlock extends StorageBlock{ public void onProximityUpdate(Tile tile){ CoreEntity entity = tile.ent(); - for(TileEntity other : state.teams.cores(tile.getTeam())){ - if(other.tile != tile){ - entity.items = other.items; + for(Tilec other : state.teams.cores(tile.team())){ + if(other.tile() != tile){ + entity.items(other.items()); } } state.teams.registerCore(entity); entity.storageCapacity = itemCapacity + entity.proximity().sum(e -> isContainer(e) ? e.block().itemCapacity : 0); entity.proximity().each(this::isContainer, t -> { - t.entity.items = entity.items; + t.entity.items(entity.items()); t.ent().linkedCore = tile; }); - for(TileEntity other : state.teams.cores(tile.getTeam())){ - if(other.tile == tile) continue; - entity.storageCapacity += other.block.itemCapacity + entity.proximity().sum(e -> isContainer(e) ? e.block().itemCapacity : 0); + for(Tilec other : state.teams.cores(tile.team())){ + if(other.tile() == tile) continue; + entity.storageCapacity += other.block().itemCapacity + other.proximity().sum(e -> isContainer(e) ? e.block().itemCapacity : 0); } if(!world.isGenerating()){ for(Item item : content.items()){ - entity.items.set(item, Math.min(entity.items.get(item), entity.storageCapacity)); + entity.items().set(item, Math.min(entity.items().get(item), entity.storageCapacity)); } } - for(CoreEntity other : state.teams.cores(tile.getTeam())){ + for(CoreEntity other : state.teams.cores(tile.team())){ other.storageCapacity = entity.storageCapacity; } } @@ -123,10 +122,10 @@ public class CoreBlock extends StorageBlock{ Draw.rect("block-select", t.drawx() + offset * p.x, t.drawy() + offset * p.y, i * 90); } }; - if(tile.entity.proximity().contains(e -> isContainer(e) && e.entity.items == tile.entity.items)){ + if(tile.entity.proximity().contains(e -> isContainer(e) && e.entity.items() == tile.entity.items())){ outline.get(tile); } - tile.entity.proximity().each(e -> isContainer(e) && e.entity.items == tile.entity.items, outline); + tile.entity.proximity().each(e -> isContainer(e) && e.entity.items() == tile.entity.items(), outline); Draw.reset(); } @@ -137,9 +136,10 @@ public class CoreBlock extends StorageBlock{ @Override public float handleDamage(Tile tile, float amount){ - if(player != null && tile.getTeam() == player.getTeam()){ - Events.fire(Trigger.teamCoreDamage); - } + //TODO implement + //if(player != null && tile.team() == player.team()){ + // Events.fire(Trigger.teamCoreDamage); + //} return amount; } @@ -151,27 +151,27 @@ public class CoreBlock extends StorageBlock{ @Override public void removed(Tile tile){ CoreEntity entity = tile.ent(); - int total = tile.entity.proximity().count(e -> e.entity != null && e.entity.items != null && e.entity.items == tile.entity.items); - float fract = 1f / total / state.teams.cores(tile.getTeam()).size; + int total = tile.entity.proximity().count(e -> e.entity != null && e.entity.items() != null && e.entity.items() == tile.entity.items()); + float fract = 1f / total / state.teams.cores(tile.team()).size; - tile.entity.proximity().each(e -> isContainer(e) && e.entity.items == tile.entity.items, t -> { + tile.entity.proximity().each(e -> isContainer(e) && e.entity.items() == tile.entity.items(), t -> { StorageBlockEntity ent = (StorageBlockEntity)t.entity; ent.linkedCore = null; - ent.items = new ItemModule(); + ent.items(new ItemModule()); for(Item item : content.items()){ - ent.items.set(item, (int)(fract * tile.entity.items.get(item))); + ent.items().set(item, (int)(fract * tile.entity.items().get(item))); } }); state.teams.unregisterCore(entity); - int max = itemCapacity * state.teams.cores(tile.getTeam()).size; + int max = itemCapacity * state.teams.cores(tile.team()).size; for(Item item : content.items()){ - tile.entity.items.set(item, Math.min(tile.entity.items.get(item), max)); + tile.entity.items().set(item, Math.min(tile.entity.items().get(item), max)); } - for(CoreEntity other : state.teams.cores(tile.getTeam())){ - other.block.onProximityUpdate(other.tile); + for(CoreEntity other : state.teams.cores(tile.team())){ + other.block().onProximityUpdate(other.tile()); } } @@ -187,7 +187,8 @@ public class CoreBlock extends StorageBlock{ CoreEntity entity = tile.ent(); if(entity.heat > 0.001f){ - RespawnBlock.drawRespawn(tile, entity.heat, entity.progress, entity.time, entity.spawnPlayer, mech); + //TODO implement + //RespawnBlock.drawRespawn(tile, entity.heat, entity.progress, entity.time, entity.spawnPlayer, mech); } } @@ -205,8 +206,10 @@ public class CoreBlock extends StorageBlock{ public void update(Tile tile){ CoreEntity entity = tile.ent(); + //TODO implement + /* if(entity.spawnPlayer != null){ - if(!entity.spawnPlayer.isDead() || !entity.spawnPlayer.isAdded()){ + if(!entity.spawnPlayer.dead() || !entity.spawnPlayer.isAdded()){ entity.spawnPlayer = null; return; } @@ -221,7 +224,7 @@ public class CoreBlock extends StorageBlock{ } }else{ entity.heat = Mathf.lerpDelta(entity.heat, 0f, 0.1f); - } + }*/ } @Override @@ -231,26 +234,11 @@ public class CoreBlock extends StorageBlock{ return entity.spawnPlayer != null; } - public class CoreEntity extends TileEntity implements SpawnerTrait{ - protected Player spawnPlayer; + public class CoreEntity extends TileEntity{ + protected Playerc spawnPlayer; protected float progress; protected float time; protected float heat; protected int storageCapacity; - - @Override - public boolean hasUnit(Unit unit){ - return unit == spawnPlayer; - } - - @Override - public void updateSpawning(Player player){ - if(!netServer.isWaitingForPlayers() && spawnPlayer == null){ - spawnPlayer = player; - progress = 0f; - player.mech = mech; - player.beginRespawning(this); - } - } } } diff --git a/core/src/mindustry/world/blocks/storage/LaunchPad.java b/core/src/mindustry/world/blocks/storage/LaunchPad.java index 02cb9bbd29..899cd1fd79 100644 --- a/core/src/mindustry/world/blocks/storage/LaunchPad.java +++ b/core/src/mindustry/world/blocks/storage/LaunchPad.java @@ -7,8 +7,7 @@ import arc.math.Mathf; import arc.util.Time; import mindustry.Vars; import mindustry.content.Fx; -import mindustry.entities.Effects; -import mindustry.entities.type.TileEntity; +import mindustry.gen.*; import mindustry.game.EventType.*; import mindustry.graphics.Pal; import mindustry.type.Item; @@ -41,14 +40,15 @@ public class LaunchPad extends StorageBlock{ @Override public boolean acceptItem(Item item, Tile tile, Tile source){ - return item.type == ItemType.material && tile.entity.items.total() < itemCapacity; + return item.type == ItemType.material && tile.entity.items().total() < itemCapacity; } @Override public void draw(Tile tile){ super.draw(tile); - float progress = Mathf.clamp(Mathf.clamp((tile.entity.items.total() / (float)itemCapacity)) * ((tile.entity.timer.getTime(timerLaunch) / (launchTime / tile.entity.timeScale)))); + //TODO broken + float progress = Mathf.clamp(Mathf.clamp((tile.entity.items().total() / (float)itemCapacity)) * ((tile.entity.timer().getTime(timerLaunch) / (launchTime / tile.entity.timeScale())))); float scale = size / 3f; Lines.stroke(2f); @@ -57,7 +57,7 @@ public class LaunchPad extends StorageBlock{ Draw.color(Pal.accent); - if(tile.entity.cons.valid()){ + if(tile.entity.cons().valid()){ for(int i = 0; i < 3; i++){ float f = (Time.time() / 200f + i * 0.5f) % 1f; @@ -71,15 +71,15 @@ public class LaunchPad extends StorageBlock{ @Override public void update(Tile tile){ - TileEntity entity = tile.entity; + Tilec entity = tile.entity; - if(world.isZone() && entity.cons.valid() && entity.items.total() >= itemCapacity && entity.timer.get(timerLaunch, launchTime / entity.timeScale)){ + if(world.isZone() && entity.consValid() && entity.items().total() >= itemCapacity && entity.timer(timerLaunch, launchTime / entity.timeScale())){ for(Item item : Vars.content.items()){ Events.fire(Trigger.itemLaunch); - Effects.effect(Fx.padlaunch, tile); - int used = Math.min(entity.items.get(item), itemCapacity); + Fx.padlaunch.at(tile); + int used = Math.min(entity.items().get(item), itemCapacity); data.addItem(item, used); - entity.items.remove(item, used); + entity.items().remove(item, used); Events.fire(new LaunchItemEvent(item, used)); } } diff --git a/core/src/mindustry/world/blocks/storage/StorageBlock.java b/core/src/mindustry/world/blocks/storage/StorageBlock.java index 29aa7860b5..297bee427e 100644 --- a/core/src/mindustry/world/blocks/storage/StorageBlock.java +++ b/core/src/mindustry/world/blocks/storage/StorageBlock.java @@ -1,7 +1,7 @@ package mindustry.world.blocks.storage; import arc.util.ArcAnnotate.*; -import mindustry.entities.type.TileEntity; +import mindustry.gen.*; import mindustry.type.Item; import mindustry.world.Block; import mindustry.world.Tile; @@ -17,7 +17,7 @@ public abstract class StorageBlock extends Block{ @Override public boolean acceptItem(Item item, Tile tile, Tile source){ StorageBlockEntity entity = tile.ent(); - return entity.linkedCore != null ? entity.linkedCore.block().acceptItem(item, entity.linkedCore, source) : tile.entity.items.get(item) < getMaximumAccepted(tile, item); + return entity.linkedCore != null ? entity.linkedCore.block().acceptItem(item, entity.linkedCore, source) : tile.entity.items().get(item) < getMaximumAccepted(tile, item); } @Override @@ -43,13 +43,13 @@ public abstract class StorageBlock extends Block{ * Returns null if no items are there. */ public Item removeItem(Tile tile, Item item){ - TileEntity entity = tile.entity; + Tilec entity = tile.entity; if(item == null){ - return entity.items.take(); + return entity.items().take(); }else{ - if(entity.items.has(item)){ - entity.items.remove(item, 1); + if(entity.items().has(item)){ + entity.items().remove(item, 1); return item; } @@ -62,11 +62,11 @@ public abstract class StorageBlock extends Block{ * If the item is null, it should return whether it has ANY items. */ public boolean hasItem(Tile tile, Item item){ - TileEntity entity = tile.entity; + Tilec entity = tile.entity; if(item == null){ - return entity.items.total() > 0; + return entity.items().total() > 0; }else{ - return entity.items.has(item); + return entity.items().has(item); } } diff --git a/core/src/mindustry/world/blocks/storage/Unloader.java b/core/src/mindustry/world/blocks/storage/Unloader.java index b63e7a04bb..b1f5644515 100644 --- a/core/src/mindustry/world/blocks/storage/Unloader.java +++ b/core/src/mindustry/world/blocks/storage/Unloader.java @@ -4,8 +4,8 @@ import arc.graphics.*; import arc.graphics.g2d.*; import arc.scene.ui.layout.*; import arc.util.*; -import mindustry.entities.traits.BuilderTrait.*; -import mindustry.entities.type.*; +import mindustry.gen.*; +import mindustry.entities.units.*; import mindustry.type.*; import mindustry.world.*; import mindustry.world.blocks.*; @@ -54,8 +54,8 @@ public class Unloader extends Block{ } @Override - public void configured(Tile tile, Player player, int value){ - tile.entity.items.clear(); + public void configured(Tile tile, Playerc player, int value){ + tile.entity.items().clear(); tile.ent().sortItem = content.item(value); } @@ -63,16 +63,16 @@ public class Unloader extends Block{ public void update(Tile tile){ UnloaderEntity entity = tile.ent(); - if(tile.entity.timer.get(timerUnload, speed / entity.timeScale) && tile.entity.items.total() == 0){ + if(tile.entity.timer(timerUnload, speed / entity.timeScale()) && tile.entity.items().total() == 0){ for(Tile other : tile.entity.proximity()){ - if(other.interactable(tile.getTeam()) && other.block().unloadable && other.block().hasItems && entity.items.total() == 0 && - ((entity.sortItem == null && other.entity.items.total() > 0) || hasItem(other, entity.sortItem))){ + if(other.interactable(tile.team()) && other.block().unloadable && other.block().hasItems && entity.items().total() == 0 && + ((entity.sortItem == null && other.entity.items().total() > 0) || hasItem(other, entity.sortItem))){ offloadNear(tile, removeItem(other, entity.sortItem)); } } } - if(entity.items.total() > 0){ + if(entity.items().total() > 0){ tryDump(tile); } } @@ -82,13 +82,13 @@ public class Unloader extends Block{ * Returns null if no items are there. */ private Item removeItem(Tile tile, Item item){ - TileEntity entity = tile.entity; + Tilec entity = tile.entity; if(item == null){ - return entity.items.take(); + return entity.items().take(); }else{ - if(entity.items.has(item)){ - entity.items.remove(item, 1); + if(entity.items().has(item)){ + entity.items().remove(item, 1); return item; } @@ -101,11 +101,11 @@ public class Unloader extends Block{ * If the item is null, it should return whether it has ANY items. */ private boolean hasItem(Tile tile, Item item){ - TileEntity entity = tile.entity; + Tilec entity = tile.entity; if(item == null){ - return entity.items.total() > 0; + return entity.items().total() > 0; }else{ - return entity.items.has(item); + return entity.items().has(item); } } @@ -144,8 +144,8 @@ public class Unloader extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); byte id = stream.readByte(); sortItem = id == -1 ? null : content.items().get(id); } diff --git a/core/src/mindustry/world/blocks/units/CommandCenter.java b/core/src/mindustry/world/blocks/units/CommandCenter.java index 6676ebf9c8..c18af1d855 100644 --- a/core/src/mindustry/world/blocks/units/CommandCenter.java +++ b/core/src/mindustry/world/blocks/units/CommandCenter.java @@ -3,14 +3,14 @@ package mindustry.world.blocks.units; import arc.*; import arc.graphics.*; import arc.graphics.g2d.*; +import arc.scene.style.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; import mindustry.content.*; import mindustry.entities.*; -import mindustry.entities.Effects.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.entities.units.*; import mindustry.game.EventType.*; import mindustry.graphics.*; @@ -20,10 +20,10 @@ import mindustry.world.meta.*; import java.io.*; -import static mindustry.Vars.indexer; +import static mindustry.Vars.*; public class CommandCenter extends Block{ - protected TextureRegion[] commandRegions = new TextureRegion[UnitCommand.all.length]; + protected TextureRegionDrawable[] commandRegions = new TextureRegionDrawable[UnitCommand.all.length]; protected Color topColor = Pal.command; protected Color bottomColor = Color.valueOf("5e5e5e"); protected Effect effect = Fx.commandSend; @@ -41,7 +41,7 @@ public class CommandCenter extends Block{ @Override public void placed(Tile tile){ super.placed(tile); - ObjectSet set = indexer.getAllied(tile.getTeam(), BlockFlag.comandCenter); + ObjectSet set = indexer.getAllied(tile.team(), BlockFlag.comandCenter); if(set.size > 0){ CommandCenterEntity entity = tile.ent(); @@ -54,10 +54,10 @@ public class CommandCenter extends Block{ public void removed(Tile tile){ super.removed(tile); - ObjectSet set = indexer.getAllied(tile.getTeam(), BlockFlag.comandCenter); + ObjectSet set = indexer.getAllied(tile.team(), BlockFlag.comandCenter); if(set.size == 1){ - Units.each(tile.getTeam(), u -> u.onCommand(UnitCommand.all[0])); + Groups.unit.each(t -> t.team() == tile.team(), u -> u.controller().command(UnitCommand.all[0])); } } @@ -65,8 +65,10 @@ public class CommandCenter extends Block{ public void load(){ super.load(); - for(UnitCommand cmd : UnitCommand.all){ - commandRegions[cmd.ordinal()] = Core.atlas.find("Icon.command-" + cmd.name() + "-"); + if(ui != null){ + for(UnitCommand cmd : UnitCommand.all){ + commandRegions[cmd.ordinal()] = ui.getIcon("command" + Strings.capitalize(cmd.name())); + } } } @@ -75,12 +77,12 @@ public class CommandCenter extends Block{ CommandCenterEntity entity = tile.ent(); super.draw(tile); - float size = IconSize.small.size/4f; + float size = 6f; Draw.color(bottomColor); - Draw.rect(commandRegions[entity.command.ordinal()], tile.drawx(), tile.drawy() - 1, size, size); + Draw.rect(commandRegions[entity.command.ordinal()].getRegion(), tile.drawx(), tile.drawy() - 1, size, size); Draw.color(topColor); - Draw.rect(commandRegions[entity.command.ordinal()], tile.drawx(), tile.drawy(), size, size); + Draw.rect(commandRegions[entity.command.ordinal()].getRegion(), tile.drawx(), tile.drawy(), size, size); Draw.color(); } @@ -91,7 +93,7 @@ public class CommandCenter extends Block{ Table buttons = new Table(); for(UnitCommand cmd : UnitCommand.all){ - buttons.addImageButton(Core.atlas.drawable("Icon.command-" + cmd.name() + "-"), Styles.clearToggleTransi, () -> tile.configure(cmd.ordinal())) + buttons.addImageButton(commandRegions[cmd.ordinal()], Styles.clearToggleTransi, () -> tile.configure(cmd.ordinal())) .size(44).group(group).update(b -> b.setChecked(entity.command == cmd)); } table.add(buttons); @@ -100,18 +102,18 @@ public class CommandCenter extends Block{ } @Override - public void configured(Tile tile, Player player, int value){ + public void configured(Tile tile, Playerc player, int value){ UnitCommand command = UnitCommand.all[value]; - Effects.effect(((CommandCenter)tile.block()).effect, tile); + ((CommandCenter)tile.block()).effect.at(tile); - for(Tile center : indexer.getAllied(tile.getTeam(), BlockFlag.comandCenter)){ + for(Tile center : indexer.getAllied(tile.team(), BlockFlag.comandCenter)){ if(center.block() instanceof CommandCenter){ CommandCenterEntity entity = center.ent(); entity.command = command; } } - Units.each(tile.getTeam(), u -> u.onCommand(command)); + Groups.unit.each(t -> t.team() == tile.team(), u -> u.controller().command(command)); Events.fire(new CommandIssueEvent(tile, command)); } @@ -130,8 +132,8 @@ public class CommandCenter extends Block{ } @Override - public void read(DataInput stream, byte version) throws IOException{ - super.read(stream, version); + public void read(DataInput stream) throws IOException{ + super.read(stream); command = UnitCommand.all[stream.readByte()]; } } diff --git a/core/src/mindustry/world/blocks/units/MechPad.java b/core/src/mindustry/world/blocks/units/MechPad.java index 0dadebc018..5cdf5ac535 100644 --- a/core/src/mindustry/world/blocks/units/MechPad.java +++ b/core/src/mindustry/world/blocks/units/MechPad.java @@ -1,31 +1,26 @@ package mindustry.world.blocks.units; -import arc.*; -import mindustry.annotations.Annotations.*; -import arc.struct.EnumSet; import arc.graphics.g2d.*; import arc.math.*; import arc.math.geom.*; -import arc.util.*; +import arc.struct.*; import arc.util.ArcAnnotate.*; +import arc.util.*; +import mindustry.annotations.Annotations.*; import mindustry.content.*; -import mindustry.entities.*; -import mindustry.entities.traits.*; -import mindustry.entities.type.*; -import mindustry.game.EventType.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; import mindustry.world.*; -import mindustry.world.blocks.*; import mindustry.world.meta.*; import java.io.*; import static mindustry.Vars.*; +//TODO remove public class MechPad extends Block{ - public @NonNull Mech mech; + public @NonNull UnitDef mech; public float buildTime = 60 * 5; public MechPad(String name){ @@ -46,13 +41,13 @@ public class MechPad extends Block{ } @Remote(targets = Loc.both, called = Loc.server) - public static void onMechFactoryTap(Player player, Tile tile){ + public static void onMechFactoryTap(Playerc player, Tile tile){ if(player == null || tile == null || !(tile.block() instanceof MechPad) || !checkValidTap(tile, player)) return; MechFactoryEntity entity = tile.ent(); - if(!entity.cons.valid()) return; - player.beginRespawning(entity); + if(!entity.consValid()) return; + //player.beginRespawning(entity); entity.sameMech = false; } @@ -62,27 +57,27 @@ public class MechPad extends Block{ MechFactoryEntity entity = tile.ent(); - Effects.effect(Fx.spawn, entity); + Fx.spawn.at(entity); if(entity.player == null) return; - Mech mech = ((MechPad)tile.block()).mech; - boolean resetSpawner = !entity.sameMech && entity.player.mech == mech; - entity.player.mech = !entity.sameMech && entity.player.mech == mech ? Mechs.starter : mech; + //Mech mech = ((MechPad)tile.block()).mech; + //boolean resetSpawner = !entity.sameMech && entity.player.mech == mech; + //entity.player.mech = !entity.sameMech && entity.player.mech == mech ? UnitTypes.starter : mech; - Player player = entity.player; + Playerc player = entity.player; - entity.progress = 0; - entity.player.onRespawn(tile); - if(resetSpawner) entity.player.lastSpawner = null; - entity.player = null; + //entity.progress = 0; + //entity.player.onRespawn(tile); + //if(resetSpawner) entity.player.lastSpawner = null; + //entity.player = null; - Events.fire(new MechChangeEvent(player, player.mech)); + //Events.fire(new MechChangeEvent(player, player.mech)); } - protected static boolean checkValidTap(Tile tile, Player player){ + protected static boolean checkValidTap(Tile tile, Playerc player){ MechFactoryEntity entity = tile.ent(); - return !player.isDead() && tile.interactable(player.getTeam()) && Math.abs(player.x - tile.drawx()) <= tile.block().size * tilesize && - Math.abs(player.y - tile.drawy()) <= tile.block().size * tilesize && entity.cons.valid() && entity.player == null; + return false;//!player.dead() && tile.interactable(player.team()) && Math.abs(player.x - tile.drawx()) <= tile.block().size * tilesize && + //Math.abs(player.y - tile.drawy()) <= tile.block().size * tilesize && entity.consValid() && entity.player == null; } @Override @@ -96,14 +91,15 @@ public class MechPad extends Block{ } @Override - public void tapped(Tile tile, Player player){ + public void tapped(Tile tile, Playerc player){ MechFactoryEntity entity = tile.ent(); if(checkValidTap(tile, player)){ Call.onMechFactoryTap(player, tile); - }else if(player.isLocal && mobile && !player.isDead() && entity.cons.valid() && entity.player == null){ + }else if(player.isLocal() && mobile && !player.dead() && entity.consValid() && entity.player == null){ //deselect on double taps - player.moveTarget = player.moveTarget == tile.entity ? null : tile.entity; + //TODO remove + //player.moveTarget = player.moveTarget == tile.entity ? null : tile.entity; } } @@ -112,7 +108,8 @@ public class MechPad extends Block{ MechFactoryEntity entity = tile.ent(); if(entity.player != null){ - RespawnBlock.drawRespawn(tile, entity.heat, entity.progress, entity.time, entity.player, (!entity.sameMech && entity.player.mech == mech ? Mechs.starter : mech)); + //TODO remove + //RespawnBlock.drawRespawn(tile, entity.heat, entity.progress, entity.time, entity.player, (!entity.sameMech && entity.player.mech == mech ? UnitTypes.starter : mech)); } } @@ -135,29 +132,13 @@ public class MechPad extends Block{ } } - public class MechFactoryEntity extends TileEntity implements SpawnerTrait{ - Player player; + public class MechFactoryEntity extends TileEntity{ + Playerc player; boolean sameMech; float progress; float time; float heat; - @Override - public boolean hasUnit(Unit unit){ - return unit == player; - } - - @Override - public void updateSpawning(Player unit){ - if(player == null){ - progress = 0f; - player = unit; - sameMech = true; - - player.beginRespawning(this); - } - } - @Override public void write(DataOutput stream) throws IOException{ super.write(stream); @@ -167,8 +148,8 @@ public class MechPad extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); progress = stream.readFloat(); time = stream.readFloat(); heat = stream.readFloat(); diff --git a/core/src/mindustry/world/blocks/units/RallyPoint.java b/core/src/mindustry/world/blocks/units/RallyPoint.java deleted file mode 100644 index c79e08e3e4..0000000000 --- a/core/src/mindustry/world/blocks/units/RallyPoint.java +++ /dev/null @@ -1,14 +0,0 @@ -package mindustry.world.blocks.units; - -import arc.struct.*; -import mindustry.world.*; -import mindustry.world.meta.*; - -public class RallyPoint extends Block{ - - public RallyPoint(String name){ - super(name); - update = solid = true; - flags = EnumSet.of(BlockFlag.rally); - } -} diff --git a/core/src/mindustry/world/blocks/units/RepairPoint.java b/core/src/mindustry/world/blocks/units/RepairPoint.java index a17fffe1b1..547b1ceb63 100644 --- a/core/src/mindustry/world/blocks/units/RepairPoint.java +++ b/core/src/mindustry/world/blocks/units/RepairPoint.java @@ -9,8 +9,7 @@ import arc.math.Mathf; import arc.math.geom.Rect; import arc.util.Time; import mindustry.entities.Units; -import mindustry.entities.type.TileEntity; -import mindustry.entities.type.Unit; +import mindustry.gen.*; import mindustry.graphics.*; import mindustry.world.Block; import mindustry.world.Tile; @@ -96,7 +95,7 @@ public class RepairPoint extends Block{ Draw.color(Color.valueOf("e8ffd7")); Drawf.laser(laser, laserEnd, tile.drawx() + Angles.trnsx(ang, len), tile.drawy() + Angles.trnsy(ang, len), - entity.target.x, entity.target.y, entity.strength); + entity.target.x(), entity.target.y(), entity.strength); Draw.color(); } } @@ -111,11 +110,10 @@ public class RepairPoint extends Block{ RepairPointEntity entity = tile.ent(); boolean targetIsBeingRepaired = false; - if(entity.target != null && (entity.target.isDead() || entity.target.dst(tile) > repairRadius || entity.target.health >= entity.target.maxHealth())){ + if(entity.target != null && (entity.target.dead() || entity.target.dst(tile) > repairRadius || entity.target.health() >= entity.target.maxHealth())){ entity.target = null; - }else if(entity.target != null && entity.cons.valid()){ - entity.target.health += repairSpeed * Time.delta() * entity.strength * entity.efficiency(); - entity.target.clampHealth(); + }else if(entity.target != null && entity.consValid()){ + entity.target.heal(repairSpeed * Time.delta() * entity.strength * entity.efficiency()); entity.rotation = Mathf.slerpDelta(entity.rotation, entity.angleTo(entity.target), 0.5f); targetIsBeingRepaired = true; } @@ -126,10 +124,9 @@ public class RepairPoint extends Block{ entity.strength = Mathf.lerpDelta(entity.strength, 0f, 0.07f * Time.delta()); } - if(entity.timer.get(timerTarget, 20)){ + if(entity.timer(timerTarget, 20)){ rect.setSize(repairRadius * 2).setCenter(tile.drawx(), tile.drawy()); - entity.target = Units.closest(tile.getTeam(), tile.drawx(), tile.drawy(), repairRadius, - unit -> unit.health < unit.maxHealth()); + entity.target = Units.closest(tile.team(), tile.drawx(), tile.drawy(), repairRadius, Unitc::damaged); } } @@ -141,7 +138,7 @@ public class RepairPoint extends Block{ } public class RepairPointEntity extends TileEntity{ - public Unit target; + public Unitc target; public float strength, rotation = 90; } } diff --git a/core/src/mindustry/world/blocks/units/UnitFactory.java b/core/src/mindustry/world/blocks/units/UnitFactory.java index ac3e20f0bb..df8c50d81a 100644 --- a/core/src/mindustry/world/blocks/units/UnitFactory.java +++ b/core/src/mindustry/world/blocks/units/UnitFactory.java @@ -1,33 +1,27 @@ package mindustry.world.blocks.units; import arc.*; -import mindustry.annotations.Annotations.Loc; -import mindustry.annotations.Annotations.Remote; -import arc.struct.EnumSet; import arc.graphics.g2d.*; -import arc.math.Mathf; -import mindustry.Vars; -import mindustry.content.Fx; -import mindustry.entities.Effects; -import mindustry.entities.type.*; -import mindustry.game.EventType.*; -import mindustry.gen.Call; -import mindustry.graphics.Pal; -import mindustry.graphics.Shaders; +import arc.math.*; +import arc.struct.*; +import mindustry.*; +import mindustry.annotations.Annotations.*; +import mindustry.content.*; +import mindustry.entities.*; +import mindustry.gen.*; +import mindustry.graphics.*; import mindustry.type.*; -import mindustry.ui.Bar; -import mindustry.ui.Cicon; -import mindustry.world.Block; -import mindustry.world.Tile; -import mindustry.world.consumers.ConsumeItems; -import mindustry.world.consumers.ConsumeType; +import mindustry.ui.*; +import mindustry.world.*; +import mindustry.world.consumers.*; import mindustry.world.meta.*; import java.io.*; -import static mindustry.Vars.*; + +import static mindustry.Vars.net; public class UnitFactory extends Block{ - public UnitType unitType; + public UnitDef unitType; public float produceTime = 1000f; public float launchVelocity = 0f; public TextureRegion topRegion; @@ -55,15 +49,17 @@ public class UnitFactory extends Block{ entity.spawned = spawns; Effects.shake(2f, 3f, entity); - Effects.effect(Fx.producesmoke, tile.drawx(), tile.drawy()); + Fx.producesmoke.at(tile.drawx(), tile.drawy()); if(!net.client()){ - BaseUnit unit = factory.unitType.create(tile.getTeam()); + //TODO create the unit + /* + Unitc unit = factory.unitType.create(tile.team()); unit.setSpawner(tile); unit.set(tile.drawx() + Mathf.range(4), tile.drawy() + Mathf.range(4)); unit.add(); - unit.velocity().y = factory.launchVelocity; - Events.fire(new UnitCreateEvent(unit)); + unit.vel().y = factory.launchVelocity; + Events.fire(new UnitCreateEvent(unit));*/ } } @@ -109,7 +105,7 @@ public class UnitFactory extends Block{ } @Override - public void unitRemoved(Tile tile, Unit unit){ + public void unitRemoved(Tile tile, Unitc unit){ UnitFactoryEntity entity = tile.ent(); entity.spawned--; entity.spawned = Math.max(entity.spawned, 0); @@ -159,7 +155,7 @@ public class UnitFactory extends Block{ return; } - if(entity.cons.valid() || tile.isEnemyCheat()){ + if(entity.consValid() || tile.isEnemyCheat()){ entity.time += entity.delta() * entity.speedScl * Vars.state.rules.unitBuildSpeedMultiplier * entity.efficiency(); entity.buildTime += entity.delta() * entity.efficiency() * Vars.state.rules.unitBuildSpeedMultiplier; entity.speedScl = Mathf.lerpDelta(entity.speedScl, 1f, 0.05f); @@ -173,7 +169,7 @@ public class UnitFactory extends Block{ Call.onUnitFactorySpawn(tile, entity.spawned + 1); useContent(tile, unitType); - entity.cons.trigger(); + entity.consume(); } } @@ -202,8 +198,8 @@ public class UnitFactory extends Block{ } @Override - public void read(DataInput stream, byte revision) throws IOException{ - super.read(stream, revision); + public void read(DataInput stream) throws IOException{ + super.read(stream); buildTime = stream.readFloat(); spawned = stream.readInt(); } diff --git a/core/src/mindustry/world/consumers/Consume.java b/core/src/mindustry/world/consumers/Consume.java index b419f68d13..76827379d6 100644 --- a/core/src/mindustry/world/consumers/Consume.java +++ b/core/src/mindustry/world/consumers/Consume.java @@ -2,7 +2,7 @@ package mindustry.world.consumers; import arc.struct.*; import arc.scene.ui.layout.Table; -import mindustry.entities.type.TileEntity; +import mindustry.gen.*; import mindustry.world.Tile; import mindustry.world.meta.BlockStats; @@ -62,15 +62,15 @@ public abstract class Consume{ public abstract void build(Tile tile, Table table); /** Called when a consumption is triggered manually. */ - public void trigger(TileEntity entity){ + public void trigger(Tilec entity){ } public abstract String getIcon(); - public abstract void update(TileEntity entity); + public abstract void update(Tilec entity); - public abstract boolean valid(TileEntity entity); + public abstract boolean valid(Tilec entity); public abstract void display(BlockStats stats); } diff --git a/core/src/mindustry/world/consumers/ConsumeItemFilter.java b/core/src/mindustry/world/consumers/ConsumeItemFilter.java index 2dcab1a841..8e2079edae 100644 --- a/core/src/mindustry/world/consumers/ConsumeItemFilter.java +++ b/core/src/mindustry/world/consumers/ConsumeItemFilter.java @@ -4,7 +4,7 @@ import arc.struct.*; import arc.func.*; import arc.scene.ui.layout.*; import arc.util.ArcAnnotate.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.ui.Cicon; @@ -35,7 +35,7 @@ public class ConsumeItemFilter extends Consume{ @Override public void build(Tile tile, Table table){ MultiReqImage image = new MultiReqImage(); - content.items().each(i -> filter.get(i) && (!world.isZone() || data.isUnlocked(i)), item -> image.add(new ReqImage(new ItemImage(item.icon(Cicon.medium), 1), () -> tile.entity != null && tile.entity.items != null && tile.entity.items.has(item)))); + content.items().each(i -> filter.get(i) && (!world.isZone() || data.isUnlocked(i)), item -> image.add(new ReqImage(new ItemImage(item.icon(Cicon.medium), 1), () -> tile.entity != null && tile.entity.items() != null && tile.entity.items().has(item)))); table.add(image).size(8 * 4); } @@ -46,26 +46,26 @@ public class ConsumeItemFilter extends Consume{ } @Override - public void update(TileEntity entity){ + public void update(Tilec entity){ } @Override - public void trigger(TileEntity entity){ + public void trigger(Tilec entity){ for(int i = 0; i < content.items().size; i++){ Item item = content.item(i); - if(entity.items != null && entity.items.has(item) && this.filter.get(item)){ - entity.items.remove(item, 1); + if(entity.items() != null && entity.items().has(item) && this.filter.get(item)){ + entity.items().remove(item, 1); break; } } } @Override - public boolean valid(TileEntity entity){ + public boolean valid(Tilec entity){ for(int i = 0; i < content.items().size; i++){ Item item = content.item(i); - if(entity.items != null && entity.items.has(item) && this.filter.get(item)){ + if(entity.items() != null && entity.items().has(item) && this.filter.get(item)){ return true; } } diff --git a/core/src/mindustry/world/consumers/ConsumeItems.java b/core/src/mindustry/world/consumers/ConsumeItems.java index c5f904bfeb..aa604ff969 100644 --- a/core/src/mindustry/world/consumers/ConsumeItems.java +++ b/core/src/mindustry/world/consumers/ConsumeItems.java @@ -3,7 +3,7 @@ package mindustry.world.consumers; import arc.struct.*; import arc.scene.ui.layout.*; import arc.util.ArcAnnotate.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.ui.Cicon; @@ -38,7 +38,7 @@ public class ConsumeItems extends Consume{ @Override public void build(Tile tile, Table table){ for(ItemStack stack : items){ - table.add(new ReqImage(new ItemImage(stack.item.icon(Cicon.medium), stack.amount), () -> tile.entity != null && tile.entity.items != null && tile.entity.items.has(stack.item, stack.amount))).size(8 * 4).padRight(5); + table.add(new ReqImage(new ItemImage(stack.item.icon(Cicon.medium), stack.amount), () -> tile.entity != null && tile.entity.items() != null && tile.entity.items().has(stack.item, stack.amount))).size(8 * 4).padRight(5); } } @@ -48,20 +48,20 @@ public class ConsumeItems extends Consume{ } @Override - public void update(TileEntity entity){ + public void update(Tilec entity){ } @Override - public void trigger(TileEntity entity){ + public void trigger(Tilec entity){ for(ItemStack stack : items){ - entity.items.remove(stack); + entity.items().remove(stack); } } @Override - public boolean valid(TileEntity entity){ - return entity.items != null && entity.items.has(items); + public boolean valid(Tilec entity){ + return entity.items() != null && entity.items().has(items); } @Override diff --git a/core/src/mindustry/world/consumers/ConsumeLiquid.java b/core/src/mindustry/world/consumers/ConsumeLiquid.java index dcb318150a..a4de0a3b52 100644 --- a/core/src/mindustry/world/consumers/ConsumeLiquid.java +++ b/core/src/mindustry/world/consumers/ConsumeLiquid.java @@ -3,7 +3,7 @@ package mindustry.world.consumers; import arc.struct.*; import arc.scene.ui.layout.*; import arc.util.ArcAnnotate.*; -import mindustry.entities.type.*; +import mindustry.gen.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.ui.Cicon; @@ -38,13 +38,13 @@ public class ConsumeLiquid extends ConsumeLiquidBase{ } @Override - public void update(TileEntity entity){ - entity.liquids.remove(liquid, Math.min(use(entity), entity.liquids.get(liquid))); + public void update(Tilec entity){ + entity.liquids().remove(liquid, Math.min(use(entity), entity.liquids().get(liquid))); } @Override - public boolean valid(TileEntity entity){ - return entity != null && entity.liquids != null && entity.liquids.get(liquid) >= use(entity); + public boolean valid(Tilec entity){ + return entity != null && entity.liquids() != null && entity.liquids().get(liquid) >= use(entity); } @Override diff --git a/core/src/mindustry/world/consumers/ConsumeLiquidBase.java b/core/src/mindustry/world/consumers/ConsumeLiquidBase.java index 229121863d..867d2fe0fd 100644 --- a/core/src/mindustry/world/consumers/ConsumeLiquidBase.java +++ b/core/src/mindustry/world/consumers/ConsumeLiquidBase.java @@ -1,6 +1,6 @@ package mindustry.world.consumers; -import mindustry.entities.type.TileEntity; +import mindustry.gen.*; public abstract class ConsumeLiquidBase extends Consume{ /** amount used per frame */ @@ -22,7 +22,7 @@ public abstract class ConsumeLiquidBase extends Consume{ return ConsumeType.liquid; } - protected float use(TileEntity entity){ - return Math.min(amount * entity.delta(), entity.block.liquidCapacity); + protected float use(Tilec entity){ + return Math.min(amount * entity.delta(), entity.block().liquidCapacity); } } diff --git a/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java b/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java index 9d8450cfb8..2fb844a827 100644 --- a/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java +++ b/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java @@ -3,7 +3,7 @@ package mindustry.world.consumers; import arc.struct.*; import arc.func.Boolf; import arc.scene.ui.layout.Table; -import mindustry.entities.type.TileEntity; +import mindustry.gen.*; import mindustry.type.Liquid; import mindustry.ui.Cicon; import mindustry.ui.MultiReqImage; @@ -32,7 +32,7 @@ public class ConsumeLiquidFilter extends ConsumeLiquidBase{ public void build(Tile tile, Table table){ Array list = content.liquids().select(l -> !l.isHidden() && filter.get(l)); MultiReqImage image = new MultiReqImage(); - list.each(liquid -> image.add(new ReqImage(liquid.icon(Cicon.medium), () -> tile.entity != null && tile.entity.liquids != null && tile.entity.liquids.get(liquid) >= use(tile.entity)))); + list.each(liquid -> image.add(new ReqImage(liquid.icon(Cicon.medium), () -> tile.entity != null && tile.entity.liquids() != null && tile.entity.liquids().get(liquid) >= use(tile.entity)))); table.add(image).size(8 * 4); } @@ -43,13 +43,13 @@ public class ConsumeLiquidFilter extends ConsumeLiquidBase{ } @Override - public void update(TileEntity entity){ - entity.liquids.remove(entity.liquids.current(), use(entity)); + public void update(Tilec entity){ + entity.liquids().remove(entity.liquids().current(), use(entity)); } @Override - public boolean valid(TileEntity entity){ - return entity != null && entity.liquids != null && filter.get(entity.liquids.current()) && entity.liquids.currentAmount() >= use(entity); + public boolean valid(Tilec entity){ + return entity != null && entity.liquids() != null && filter.get(entity.liquids().current()) && entity.liquids().currentAmount() >= use(entity); } @Override diff --git a/core/src/mindustry/world/consumers/ConsumePower.java b/core/src/mindustry/world/consumers/ConsumePower.java index 5df011349a..630add2ca7 100644 --- a/core/src/mindustry/world/consumers/ConsumePower.java +++ b/core/src/mindustry/world/consumers/ConsumePower.java @@ -2,7 +2,7 @@ package mindustry.world.consumers; import arc.math.Mathf; import arc.scene.ui.layout.Table; -import mindustry.entities.type.TileEntity; +import mindustry.gen.*; import mindustry.world.Tile; import mindustry.world.meta.*; @@ -41,16 +41,16 @@ public class ConsumePower extends Consume{ } @Override - public void update(TileEntity entity){ - // Nothing to do since PowerGraph directly updates entity.power.status + public void update(Tilec entity){ + // Nothing to do since PowerGraph directly updates entity.power().status } @Override - public boolean valid(TileEntity entity){ + public boolean valid(Tilec entity){ if(buffered){ return true; }else{ - return entity.power.status > 0f; + return entity.power().status > 0f; } } @@ -68,13 +68,13 @@ public class ConsumePower extends Consume{ * @param entity The entity which contains the power module. * @return The amount of power which is requested per tick. */ - public float requestedPower(TileEntity entity){ - if(entity.tile.entity == null) return 0f; + public float requestedPower(Tilec entity){ + if(entity.tile().entity == null) return 0f; if(buffered){ - return (1f-entity.power.status)*capacity; + return (1f-entity.power().status)*capacity; }else{ try{ - return usage * Mathf.num(entity.block.shouldConsume(entity.tile)); + return usage * Mathf.num(entity.block().shouldConsume(entity.tile())); }catch(Exception e){ //HACK an error will only happen with a bar that is checking its requested power, and the entity is null/a different class return 0; diff --git a/core/src/mindustry/world/consumers/Consumers.java b/core/src/mindustry/world/consumers/Consumers.java index b6ebd7391a..4f0df357dc 100644 --- a/core/src/mindustry/world/consumers/Consumers.java +++ b/core/src/mindustry/world/consumers/Consumers.java @@ -4,7 +4,7 @@ import arc.struct.*; import arc.func.Boolf; import arc.util.Structs; import mindustry.Vars; -import mindustry.entities.type.TileEntity; +import mindustry.gen.*; import mindustry.type.*; import mindustry.world.blocks.power.ConditionalConsumePower; import mindustry.world.meta.BlockStats; @@ -48,7 +48,7 @@ public class Consumers{ } /** Creates a consumer which only consumes power when the condition is met. */ - public ConsumePower powerCond(float usage, Boolf cons){ + public ConsumePower powerCond(float usage, Boolf cons){ return add(new ConditionalConsumePower(usage, cons)); } diff --git a/core/src/mindustry/world/meta/BlockBars.java b/core/src/mindustry/world/meta/BlockBars.java index 5b319332ce..ec47b7ae47 100644 --- a/core/src/mindustry/world/meta/BlockBars.java +++ b/core/src/mindustry/world/meta/BlockBars.java @@ -2,13 +2,13 @@ package mindustry.world.meta; import arc.struct.OrderedMap; import arc.func.Func; -import mindustry.entities.type.TileEntity; +import mindustry.gen.*; import mindustry.ui.Bar; public class BlockBars{ - private OrderedMap> bars = new OrderedMap<>(); + private OrderedMap> bars = new OrderedMap<>(); - public void add(String name, Func sup){ + public void add(String name, Func sup){ bars.put(name, sup); } @@ -18,7 +18,7 @@ public class BlockBars{ bars.remove(name); } - public Iterable> list(){ + public Iterable> list(){ return bars.values(); } } diff --git a/core/src/mindustry/world/meta/BlockStat.java b/core/src/mindustry/world/meta/BlockStat.java index 162df3dd37..089ad53e45 100644 --- a/core/src/mindustry/world/meta/BlockStat.java +++ b/core/src/mindustry/world/meta/BlockStat.java @@ -24,6 +24,7 @@ public enum BlockStat{ powerConnections(StatCategory.power), basePowerGeneration(StatCategory.power), + tiles(StatCategory.crafting), input(StatCategory.crafting), output(StatCategory.crafting), productionTime(StatCategory.crafting), @@ -45,7 +46,8 @@ public enum BlockStat{ ammo(StatCategory.shooting), booster(StatCategory.optional), - boostEffect(StatCategory.optional); + boostEffect(StatCategory.optional), + affinities(StatCategory.optional); public final StatCategory category; diff --git a/core/src/mindustry/world/meta/BlockStats.java b/core/src/mindustry/world/meta/BlockStats.java index 931482a49a..d91e25bc31 100644 --- a/core/src/mindustry/world/meta/BlockStats.java +++ b/core/src/mindustry/world/meta/BlockStats.java @@ -1,9 +1,11 @@ package mindustry.world.meta; -import arc.struct.Array; -import arc.struct.ObjectMap.Entry; -import arc.struct.OrderedMap; +import arc.math.*; +import arc.struct.*; +import arc.struct.ObjectMap.*; +import mindustry.*; import mindustry.type.*; +import mindustry.world.*; import mindustry.world.meta.values.*; /** Hold and organizes a list of block stats. */ @@ -36,6 +38,13 @@ public class BlockStats{ add(stat, new LiquidValue(liquid, amount, perSecond)); } + public void add(BlockStat stat, Attribute attr){ + for(Block block : Vars.content.blocks()){ + if(!block.isFloor() || Mathf.zero(block.asFloor().attributes.get(attr))) continue; + add(stat, new FloorValue(block.asFloor())); + } + } + /** Adds a single string value with this stat. */ public void add(BlockStat stat, String format, Object... args){ add(stat, new StringValue(format, args)); diff --git a/core/src/mindustry/world/meta/values/FloorValue.java b/core/src/mindustry/world/meta/values/FloorValue.java new file mode 100644 index 0000000000..7993a60eb0 --- /dev/null +++ b/core/src/mindustry/world/meta/values/FloorValue.java @@ -0,0 +1,21 @@ +package mindustry.world.meta.values; + +import arc.scene.ui.*; +import arc.scene.ui.layout.*; +import mindustry.ui.*; +import mindustry.world.blocks.*; +import mindustry.world.meta.*; + +public class FloorValue implements StatValue{ + private final Floor floor; + + public FloorValue(Floor floor){ + this.floor = floor; + } + + @Override + public void display(Table table){ + table.add(new Image(floor.icon(Cicon.small))).padRight(3); + table.add(floor.localizedName).padRight(3); + } +} \ No newline at end of file diff --git a/core/src/mindustry/world/modules/ConsumeModule.java b/core/src/mindustry/world/modules/ConsumeModule.java index 44f8d471d4..efbc7bec17 100644 --- a/core/src/mindustry/world/modules/ConsumeModule.java +++ b/core/src/mindustry/world/modules/ConsumeModule.java @@ -1,21 +1,21 @@ package mindustry.world.modules; -import mindustry.entities.type.TileEntity; +import mindustry.gen.*; import mindustry.world.consumers.Consume; import java.io.*; public class ConsumeModule extends BlockModule{ private boolean valid, optionalValid; - private final TileEntity entity; + private final Tilec entity; - public ConsumeModule(TileEntity entity){ + public ConsumeModule(Tilec entity){ this.entity = entity; } public void update(){ //everything is valid here - if(entity.tile.isEnemyCheat()){ + if(entity.tile().isEnemyCheat()){ valid = optionalValid = true; return; } @@ -23,9 +23,9 @@ public class ConsumeModule extends BlockModule{ boolean prevValid = valid(); valid = true; optionalValid = true; - boolean docons = entity.block.shouldConsume(entity.tile) && entity.block.productionValid(entity.tile); + boolean docons = entity.block().shouldConsume(entity.tile()) && entity.block().productionValid(entity.tile()); - for(Consume cons : entity.block.consumes.all()){ + for(Consume cons : entity.block().consumes.all()){ if(cons.isOptional()) continue; if(docons && cons.isUpdate() && prevValid && cons.valid(entity)){ @@ -35,7 +35,7 @@ public class ConsumeModule extends BlockModule{ valid &= cons.valid(entity); } - for(Consume cons : entity.block.consumes.optionals()){ + for(Consume cons : entity.block().consumes.optionals()){ if(docons && cons.isUpdate() && prevValid && cons.valid(entity)){ cons.update(entity); } @@ -45,13 +45,13 @@ public class ConsumeModule extends BlockModule{ } public void trigger(){ - for(Consume cons : entity.block.consumes.all()){ + for(Consume cons : entity.block().consumes.all()){ cons.trigger(entity); } } public boolean valid(){ - return valid && entity.block.shouldConsume(entity.tile); + return valid && entity.block().shouldConsume(entity.tile()); } public boolean optionalValid(){ diff --git a/core/src/mindustry/world/modules/ItemModule.java b/core/src/mindustry/world/modules/ItemModule.java index 8fc338dcbd..cd30730d2d 100644 --- a/core/src/mindustry/world/modules/ItemModule.java +++ b/core/src/mindustry/world/modules/ItemModule.java @@ -12,6 +12,9 @@ public class ItemModule extends BlockModule{ private int[] items = new int[content.items().size]; private int total; + // Make the take() loop persistent so it does not return the same item twice in a row unless there is nothing else to return. + protected int takeRotation; + public void forEach(ItemConsumer cons){ for(int i = 0; i < items.length; i++){ if(items[i] > 0){ @@ -68,10 +71,13 @@ public class ItemModule extends BlockModule{ public Item take(){ for(int i = 0; i < items.length; i++){ - if(items[i] > 0){ - items[i]--; - total--; - return content.item(i); + int index = (i + takeRotation); + if(index >= items.length) index -= items.length; //conditional instead of mod + if(items[index] > 0){ + items[index] --; + total --; + takeRotation = index + 1; + return content.item(index % items.length); } } return null; diff --git a/core/src/mindustry/world/modules/LiquidModule.java b/core/src/mindustry/world/modules/LiquidModule.java index 19ad109341..eaaa22a07f 100644 --- a/core/src/mindustry/world/modules/LiquidModule.java +++ b/core/src/mindustry/world/modules/LiquidModule.java @@ -102,6 +102,7 @@ public class LiquidModule extends BlockModule{ @Override public void read(DataInput stream) throws IOException{ Arrays.fill(liquids, 0); + total = 0f; byte count = stream.readByte(); for(int j = 0; j < count; j++){ diff --git a/desktop/src/mindustry/desktop/DesktopLauncher.java b/desktop/src/mindustry/desktop/DesktopLauncher.java index f3161ec1ba..71689d40be 100644 --- a/desktop/src/mindustry/desktop/DesktopLauncher.java +++ b/desktop/src/mindustry/desktop/DesktopLauncher.java @@ -17,6 +17,7 @@ import mindustry.core.GameState.*; import mindustry.core.*; import mindustry.desktop.steam.*; import mindustry.game.EventType.*; +import mindustry.gen.*; import mindustry.net.*; import mindustry.net.Net.*; import mindustry.type.*; @@ -136,9 +137,9 @@ public class DesktopLauncher extends ClientLauncher{ boolean[] isShutdown = {false}; Events.on(ClientLoadEvent.class, event -> { - player.name = SVars.net.friends.getPersonaName(); + player.name(SVars.net.friends.getPersonaName()); Core.settings.defaults("name", SVars.net.friends.getPersonaName()); - Core.settings.put("name", player.name); + Core.settings.put("name", player.name()); Core.settings.save(); //update callbacks Core.app.addListener(new ApplicationListener(){ @@ -242,36 +243,65 @@ public class DesktopLauncher extends ClientLauncher{ @Override public void updateRPC(){ - if(!useDiscord) return; + //if we're using neither discord nor steam, do no work + if(!useDiscord && !steam) return; - DiscordRichPresence presence = new DiscordRichPresence(); + //common elements they each share + boolean inGame = !state.is(State.menu); + String gameMapWithWave = "Unknown Map"; + String gameMode = ""; + String gamePlayersSuffix = ""; + String uiState = ""; - if(!state.is(State.menu)){ - String map = world.getMap() == null ? "Unknown Map" : world.isZone() ? world.getZone().localizedName : Strings.capitalize(world.getMap().name()); - String mode = state.rules.pvp ? "PvP" : state.rules.attackMode ? "Attack" : "Survival"; - String players = net.active() && playerGroup.size() > 1 ? " | " + playerGroup.size() + " Players" : ""; - - presence.state = mode + players; - - if(!state.rules.waves){ - presence.details = map; - }else{ - presence.details = map + " | Wave " + state.wave; - presence.largeImageText = "Wave " + state.wave; + if(inGame){ + if(world.getMap() != null){ + gameMapWithWave = world.isZone() ? world.getZone().localizedName : Strings.capitalize(world.getMap().name()); + } + if(state.rules.waves){ + gameMapWithWave += " | Wave " + state.wave; + } + gameMode = state.rules.pvp ? "PvP" : state.rules.attackMode ? "Attack" : "Survival"; + if(net.active() && Groups.player.size() > 1){ + gamePlayersSuffix = " | " + Groups.player.size() + " Players"; } }else{ if(ui.editor != null && ui.editor.isShown()){ - presence.state = "In Editor"; + uiState = "In Editor"; }else if(ui.planet != null && ui.planet.isShown()){ - presence.state = "In Launch Selection"; + uiState = "In Launch Selection"; }else{ - presence.state = "In Menu"; + uiState = "In Menu"; } } - presence.largeImageKey = "logo"; + if(useDiscord){ + DiscordRichPresence presence = new DiscordRichPresence(); - DiscordRPC.INSTANCE.Discord_UpdatePresence(presence); + if(inGame){ + presence.state = gameMode + gamePlayersSuffix; + presence.details = gameMapWithWave; + if(state.rules.waves){ + presence.largeImageText = "Wave " + state.wave; + } + }else{ + presence.state = uiState; + } + + presence.largeImageKey = "logo"; + + DiscordRPC.INSTANCE.Discord_UpdatePresence(presence); + } + + if(steam){ + //Steam mostly just expects us to give it a nice string, but it apparently expects "steam_display" to always be a loc token, so I've uploaded this one which just passes through 'steam_status' raw. + SVars.net.friends.setRichPresence("steam_display", "#steam_status_raw"); + + if(inGame){ + SVars.net.friends.setRichPresence("steam_status", gameMapWithWave); + }else{ + SVars.net.friends.setRichPresence("steam_status", uiState); + } + } } @Override diff --git a/desktop/src/mindustry/desktop/steam/SNet.java b/desktop/src/mindustry/desktop/steam/SNet.java index 579b2b39c6..ff52cde8ce 100644 --- a/desktop/src/mindustry/desktop/steam/SNet.java +++ b/desktop/src/mindustry/desktop/steam/SNet.java @@ -172,7 +172,7 @@ public class SNet implements SteamNetworkingCallback, SteamMatchmakingCallback, @Override public void hostServer(int port) throws IOException{ provider.hostServer(port); - smat.createLobby(Core.settings.getBool("publichost") ? LobbyType.Public : LobbyType.FriendsOnly, 16); + smat.createLobby(Core.settings.getBool("publichost") ? LobbyType.Public : LobbyType.FriendsOnly, Core.settings.getInt("playerlimit")); Core.app.post(() -> Core.app.post(() -> Core.app.post(() -> Log.info("Server: {0}\nClient: {1}\nActive: {2}", net.server(), net.client(), net.active())))); } @@ -180,6 +180,7 @@ public class SNet implements SteamNetworkingCallback, SteamMatchmakingCallback, public void updateLobby(){ if(currentLobby != null && net.server()){ smat.setLobbyType(currentLobby, Core.settings.getBool("publichost") ? LobbyType.Public : LobbyType.FriendsOnly); + smat.setLobbyMemberLimit(currentLobby, Core.settings.getInt("playerlimit")); } } @@ -347,7 +348,7 @@ public class SNet implements SteamNetworkingCallback, SteamMatchmakingCallback, if(result == SteamResult.OK){ currentLobby = steamID; - smat.setLobbyData(steamID, "name", player.name); + smat.setLobbyData(steamID, "name", player.name()); smat.setLobbyData(steamID, "mapname", world.getMap() == null ? "Unknown" : state.rules.zone == null ? world.getMap().name() : state.rules.zone.localizedName); smat.setLobbyData(steamID, "version", Version.build + ""); smat.setLobbyData(steamID, "versionType", Version.type); diff --git a/desktop/src/mindustry/desktop/steam/SStats.java b/desktop/src/mindustry/desktop/steam/SStats.java index 950bffc249..78f89172ea 100644 --- a/desktop/src/mindustry/desktop/steam/SStats.java +++ b/desktop/src/mindustry/desktop/steam/SStats.java @@ -6,10 +6,10 @@ import arc.util.*; import com.codedisaster.steamworks.*; import mindustry.*; import mindustry.content.*; -import mindustry.entities.type.*; import mindustry.entities.units.*; import mindustry.game.EventType.*; import mindustry.game.Stats.*; +import mindustry.gen.*; import mindustry.type.*; import static mindustry.Vars.*; @@ -54,18 +54,18 @@ public class SStats implements SteamUserStatsCallback{ private void checkUpdate(){ if(campaign()){ - SStat.maxUnitActive.max(unitGroup.count(t -> t.getTeam() == player.getTeam())); + SStat.maxUnitActive.max(Groups.unit.count(t -> t.team() == player.team())); - if(unitGroup.count(u -> u.getType() == UnitTypes.phantom && u.getTeam() == player.getTeam()) >= 10){ + if(Groups.unit.count(u -> u.type() == UnitTypes.phantom && u.team() == player.team()) >= 10){ active10Phantoms.complete(); } - if(unitGroup.count(u -> u.getType() == UnitTypes.crawler && u.getTeam() == player.getTeam()) >= 50){ + if(Groups.unit.count(u -> u.type() == UnitTypes.crawler && u.team() == player.team()) >= 50){ active50Crawlers.complete(); } - for(TileEntity entity : player.getTeam().cores()){ - if(!content.items().contains(i -> i.type == ItemType.material && entity.items.get(i) < entity.block.itemCapacity)){ + for(Tilec entity : player.team().cores()){ + if(!content.items().contains(i -> i.type == ItemType.material && entity.items().get(i) < entity.block().itemCapacity)){ fillCoreAllCampaign.complete(); break; } @@ -76,10 +76,10 @@ public class SStats implements SteamUserStatsCallback{ private void registerEvents(){ Events.on(UnitDestroyEvent.class, e -> { if(ncustom()){ - if(e.unit.getTeam() != Vars.player.getTeam()){ + if(e.unit.team() != Vars.player.team()){ SStat.unitsDestroyed.add(); - if(e.unit instanceof BaseUnit && ((BaseUnit)e.unit).isBoss()){ + if(e.unit instanceof Unitc && ((Unitc)e.unit).isBoss()){ SStat.bossesDefeated.add(); } } @@ -93,7 +93,7 @@ public class SStats implements SteamUserStatsCallback{ }); Events.on(Trigger.newGame, () -> Core.app.post(() -> { - if(campaign() && player.getClosestCore() != null && player.getClosestCore().items.total() >= 10 * 1000){ + if(campaign() && player.closestCore() != null && player.closestCore().items().total() >= 10 * 1000){ drop10kitems.complete(); } })); @@ -133,7 +133,7 @@ public class SStats implements SteamUserStatsCallback{ }); Events.on(BlockDestroyEvent.class, e -> { - if(campaign() && e.tile.getTeam() != player.getTeam()){ + if(campaign() && e.tile.team() != player.team()){ SStat.blocksDestroyed.add(); } }); @@ -180,7 +180,7 @@ public class SStats implements SteamUserStatsCallback{ trigger(Trigger.itemLaunch, launchItemPad); Events.on(UnitCreateEvent.class, e -> { - if(campaign() && e.unit.getTeam() == player.getTeam()){ + if(campaign() && e.unit.team() == player.team()){ SStat.unitsBuilt.add(); } }); @@ -217,7 +217,7 @@ public class SStats implements SteamUserStatsCallback{ Events.on(PlayerJoin.class, e -> { if(Vars.net.server()){ - SStat.maxPlayersServer.max(Vars.playerGroup.size()); + SStat.maxPlayersServer.max(Groups.player.size()); } }); @@ -283,7 +283,7 @@ public class SStats implements SteamUserStatsCallback{ if(result != SteamResult.OK){ Log.err("Failed to recieve steam stats: {0}", result); }else{ - Log.err("Recieved steam stats."); + Log.info("Recieved steam stats."); } } diff --git a/fastlane/metadata/android/cs-CZ/changelogs/102.1.txt b/fastlane/metadata/android/cs-CZ/changelogs/102.1.txt new file mode 100644 index 0000000000..01760ded80 --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/102.1.txt @@ -0,0 +1,5 @@ +- Přidán nový pohled na mapu s rolováním a posouváním +- Přidáno pravidlo pro zdraví bloku +- Přidáno více interních týmů pro různé herní režimy +- Přidána vylepšená podpora pro modifikace +- Hlavní vnitřní změna: programový balík se teď jmenuje "mindustry" namísto dosavadního "io.anuke.mindustry" (toto rozbije staré pluginy) diff --git a/fastlane/metadata/android/cs-CZ/changelogs/102.2.txt b/fastlane/metadata/android/cs-CZ/changelogs/102.2.txt new file mode 100644 index 0000000000..01760ded80 --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/102.2.txt @@ -0,0 +1,5 @@ +- Přidán nový pohled na mapu s rolováním a posouváním +- Přidáno pravidlo pro zdraví bloku +- Přidáno více interních týmů pro různé herní režimy +- Přidána vylepšená podpora pro modifikace +- Hlavní vnitřní změna: programový balík se teď jmenuje "mindustry" namísto dosavadního "io.anuke.mindustry" (toto rozbije staré pluginy) diff --git a/fastlane/metadata/android/cs-CZ/changelogs/102.txt b/fastlane/metadata/android/cs-CZ/changelogs/102.txt new file mode 100644 index 0000000000..01760ded80 --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/changelogs/102.txt @@ -0,0 +1,5 @@ +- Přidán nový pohled na mapu s rolováním a posouváním +- Přidáno pravidlo pro zdraví bloku +- Přidáno více interních týmů pro různé herní režimy +- Přidána vylepšená podpora pro modifikace +- Hlavní vnitřní změna: programový balík se teď jmenuje "mindustry" namísto dosavadního "io.anuke.mindustry" (toto rozbije staré pluginy) diff --git a/fastlane/metadata/android/cs-CZ/full_description.txt b/fastlane/metadata/android/cs-CZ/full_description.txt new file mode 100644 index 0000000000..112ccaf515 --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/full_description.txt @@ -0,0 +1,43 @@ +Vytvoř propracovaný výrobní řetězec dopravníků, abys naládoval munici do věží, vyrobil materiály pro stavění a ubránil své stavby před vlnami nepřátel. Hraj s Tvými přáteli kooperačně napříč platformami, nebo je vyzvi v týmové hře hráčů proti sobě. + +Hra: +- Vytvoř vrty a dopravníky pro přesun zdrojů do Tvého jádra. +- Použij výrobní bloky pro vytvoření pokročilých materiálů. +- Postav drony pro automatické těžení zdrojů, pomoc se stavěním a vybudování a ochraně své základny. +- Rozváděj kapaliny a bojuj s požárem. +- Posilni výrobu dodatečným chlazením a promaž obranné i výrobní bloky. + +Kampaň: +- Projdi skrz 12 znovuhratelných předpřipravených zón s náhodným místem startu. +- Sesbírej a vyšli zpět ze zón materiál. +- Vynalezni nové bloky, abys rozjel výrobu. +- Konfiguruj předměty, se kterými se vyšleš do zóny, abys byl lépe připraven. +- V jednotlivých zónách plň rozdílné cíle mise. +- Pozvi kamarády pro společné dokončení mise. +- 120+ technologických bloků, dokážeš je všechny využít? +- 19 různých typů dronů, mechů and lodí! + +Herní módy: +- Přežití: Postav věže k obraně Tvého jádra před nepřátelskými jednotkami. Přežij tak dlouho, jak jen dokážeš, a ideálně ještě odešli své jádro zpět se sesbíranými surovinami pro zaplacení výzkumu. Připrav svou základnu pro střídavý útok vzdušného Záporáka. +- Útok: Postav továrny na jednotky pro zničení nepřátelského jádra, zatímco zároveň ochraňuj svoji základnu před vlnami nepřátelských jednotek. Vytvoř různé typy podpůrných a obranných jednotek pro dosažení tohoto cíle. +- Hráči proti sobě: Soupeř s jinými hráči v až 4 různých týmech, s cílem zničit ostatní jádra. Vytvoř jednotky nebo útoč na cizí jádro rovnou ve svém mechu. +- Pískoviště: Vyzkoušej si hru s nekonečnými zdroji surovin a bez nepřátelských hrozeb. Použij bloky dostupné pouze v pískovišti aby sis otestoval svůj nový nápad a pokud budeš chtít, můžeš si na vyžádání nechat seslat nepřátelské jednotky. + +Vlastní hra a podpora napříč herními platformami: +- 12 vestavěných map pro vlastní hry, navíc ke kampani +- Hraj kooperativně, proti sobě nebo na pískovišti +- Připoj se k veřejnému serveru nebo pozvi přátele do svého vlastního soukromého sezení +- Nastavitelná herní pravidla: Změn cenu bloků, nepřátelské statistiky, počáteční předměty, časování vln atd. +- Mix herních režimů: Smíchej dohromady hru hráčů proti sobě (PvP) a hráčů proti prostředí (PvE) + +Editor map: +- Nakresli si novou mapu s vestavěným editorem +- Upravuj a dej si náhled staveb přímo ve hře +- Konfigurovatelné nástroje: Změň, jak se každý nástroj chová +- Silný systém pro generování map, s mnoha různými typy filtrů pro procedurální manipulaci s terénem - vytvoř úžasnou mapu za 5 minut! +- Přidej zašumění, zkreslení, vyhlazení, prolnutí, zrcadlení, rozptýlení, generování rud a náhodného terénu do svých map +- Konfiguruj náhodné generování rudy, řek a surovin +- Konfiguruj rozestavění nepřátelských vln +- Sdílej vyexportované mapy v dílně Steamu +- Nastav pravidla pro základní mapy +- Použij 75+ různých bloků diff --git a/fastlane/metadata/android/cs-CZ/short_description.txt b/fastlane/metadata/android/cs-CZ/short_description.txt new file mode 100644 index 0000000000..706cd5e9c8 --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/short_description.txt @@ -0,0 +1 @@ +Hra typu tower-defense s otevřeným koncem, zaměřená na řízení zdrojů. diff --git a/fastlane/metadata/android/cs-CZ/summary.txt b/fastlane/metadata/android/cs-CZ/summary.txt new file mode 100644 index 0000000000..706cd5e9c8 --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/summary.txt @@ -0,0 +1 @@ +Hra typu tower-defense s otevřeným koncem, zaměřená na řízení zdrojů. diff --git a/fastlane/metadata/android/cs-CZ/title.txt b/fastlane/metadata/android/cs-CZ/title.txt new file mode 100644 index 0000000000..2beb939017 --- /dev/null +++ b/fastlane/metadata/android/cs-CZ/title.txt @@ -0,0 +1 @@ +Mindustry \ No newline at end of file diff --git a/fastlane/metadata/android/en-US/changelogs/103.1.txt b/fastlane/metadata/android/en-US/changelogs/103.1.txt new file mode 100644 index 0000000000..fa41c882ac --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/103.1.txt @@ -0,0 +1,9 @@ +- Added new icons w/ smooth scaling +- Added liquid void (Contributed by @GioIacca9) +- Added bridge opacity slider (Contributed by @Quezler) +- Added "underflow" gate (opposite of overflow gate) +- Added "emojis" for most blocks and items into the font +- Added new tech tree layout w/ better mod support +- Added game log file, stored in data folder +- Added new separator sprite/animation +- Added list of affinity tiles to stats of certain blocks diff --git a/fastlane/metadata/android/en-US/changelogs/103.2.txt b/fastlane/metadata/android/en-US/changelogs/103.2.txt new file mode 100644 index 0000000000..fa41c882ac --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/103.2.txt @@ -0,0 +1,9 @@ +- Added new icons w/ smooth scaling +- Added liquid void (Contributed by @GioIacca9) +- Added bridge opacity slider (Contributed by @Quezler) +- Added "underflow" gate (opposite of overflow gate) +- Added "emojis" for most blocks and items into the font +- Added new tech tree layout w/ better mod support +- Added game log file, stored in data folder +- Added new separator sprite/animation +- Added list of affinity tiles to stats of certain blocks diff --git a/fastlane/metadata/android/en-US/changelogs/103.3.txt b/fastlane/metadata/android/en-US/changelogs/103.3.txt new file mode 100644 index 0000000000..fa41c882ac --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/103.3.txt @@ -0,0 +1,9 @@ +- Added new icons w/ smooth scaling +- Added liquid void (Contributed by @GioIacca9) +- Added bridge opacity slider (Contributed by @Quezler) +- Added "underflow" gate (opposite of overflow gate) +- Added "emojis" for most blocks and items into the font +- Added new tech tree layout w/ better mod support +- Added game log file, stored in data folder +- Added new separator sprite/animation +- Added list of affinity tiles to stats of certain blocks diff --git a/fastlane/metadata/android/en-US/changelogs/103.txt b/fastlane/metadata/android/en-US/changelogs/103.txt new file mode 100644 index 0000000000..fa41c882ac --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/103.txt @@ -0,0 +1,9 @@ +- Added new icons w/ smooth scaling +- Added liquid void (Contributed by @GioIacca9) +- Added bridge opacity slider (Contributed by @Quezler) +- Added "underflow" gate (opposite of overflow gate) +- Added "emojis" for most blocks and items into the font +- Added new tech tree layout w/ better mod support +- Added game log file, stored in data folder +- Added new separator sprite/animation +- Added list of affinity tiles to stats of certain blocks diff --git a/fastlane/metadata/android/en-US/changelogs/29584.txt b/fastlane/metadata/android/en-US/changelogs/29584.txt new file mode 100644 index 0000000000..fa41c882ac --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29584.txt @@ -0,0 +1,9 @@ +- Added new icons w/ smooth scaling +- Added liquid void (Contributed by @GioIacca9) +- Added bridge opacity slider (Contributed by @Quezler) +- Added "underflow" gate (opposite of overflow gate) +- Added "emojis" for most blocks and items into the font +- Added new tech tree layout w/ better mod support +- Added game log file, stored in data folder +- Added new separator sprite/animation +- Added list of affinity tiles to stats of certain blocks diff --git a/fastlane/metadata/android/en-US/changelogs/29586.txt b/fastlane/metadata/android/en-US/changelogs/29586.txt new file mode 100644 index 0000000000..fa41c882ac --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29586.txt @@ -0,0 +1,9 @@ +- Added new icons w/ smooth scaling +- Added liquid void (Contributed by @GioIacca9) +- Added bridge opacity slider (Contributed by @Quezler) +- Added "underflow" gate (opposite of overflow gate) +- Added "emojis" for most blocks and items into the font +- Added new tech tree layout w/ better mod support +- Added game log file, stored in data folder +- Added new separator sprite/animation +- Added list of affinity tiles to stats of certain blocks diff --git a/fastlane/metadata/android/en-US/changelogs/29589.txt b/fastlane/metadata/android/en-US/changelogs/29589.txt new file mode 100644 index 0000000000..fa41c882ac --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29589.txt @@ -0,0 +1,9 @@ +- Added new icons w/ smooth scaling +- Added liquid void (Contributed by @GioIacca9) +- Added bridge opacity slider (Contributed by @Quezler) +- Added "underflow" gate (opposite of overflow gate) +- Added "emojis" for most blocks and items into the font +- Added new tech tree layout w/ better mod support +- Added game log file, stored in data folder +- Added new separator sprite/animation +- Added list of affinity tiles to stats of certain blocks diff --git a/fastlane/metadata/android/en-US/changelogs/29591.txt b/fastlane/metadata/android/en-US/changelogs/29591.txt new file mode 100644 index 0000000000..fa41c882ac --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29591.txt @@ -0,0 +1,9 @@ +- Added new icons w/ smooth scaling +- Added liquid void (Contributed by @GioIacca9) +- Added bridge opacity slider (Contributed by @Quezler) +- Added "underflow" gate (opposite of overflow gate) +- Added "emojis" for most blocks and items into the font +- Added new tech tree layout w/ better mod support +- Added game log file, stored in data folder +- Added new separator sprite/animation +- Added list of affinity tiles to stats of certain blocks diff --git a/fastlane/metadata/android/en-US/changelogs/29594.txt b/fastlane/metadata/android/en-US/changelogs/29594.txt new file mode 100644 index 0000000000..fa41c882ac --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29594.txt @@ -0,0 +1,9 @@ +- Added new icons w/ smooth scaling +- Added liquid void (Contributed by @GioIacca9) +- Added bridge opacity slider (Contributed by @Quezler) +- Added "underflow" gate (opposite of overflow gate) +- Added "emojis" for most blocks and items into the font +- Added new tech tree layout w/ better mod support +- Added game log file, stored in data folder +- Added new separator sprite/animation +- Added list of affinity tiles to stats of certain blocks diff --git a/fastlane/metadata/android/en-US/changelogs/29597.txt b/fastlane/metadata/android/en-US/changelogs/29597.txt new file mode 100644 index 0000000000..fa41c882ac --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29597.txt @@ -0,0 +1,9 @@ +- Added new icons w/ smooth scaling +- Added liquid void (Contributed by @GioIacca9) +- Added bridge opacity slider (Contributed by @Quezler) +- Added "underflow" gate (opposite of overflow gate) +- Added "emojis" for most blocks and items into the font +- Added new tech tree layout w/ better mod support +- Added game log file, stored in data folder +- Added new separator sprite/animation +- Added list of affinity tiles to stats of certain blocks diff --git a/fastlane/metadata/android/pt-PT/changelogs/102.txt b/fastlane/metadata/android/pt-PT/changelogs/102.txt new file mode 100644 index 0000000000..784f53ea20 --- /dev/null +++ b/fastlane/metadata/android/pt-PT/changelogs/102.txt @@ -0,0 +1,5 @@ +- Adicionado nova forma de ver mapas. Com panorâmica e rolagem +- Foi adicionada regra de integridade do bloco +- Adicionado mais equipes internas para modos de jogo alternativos +- Adicionado recursos para melhorar a modificação do servidor +-Grande mudança interna: o pacote agora é "mindustry" em vez de "io.anuke.mindustry" (irá quebrar os plugins) \ No newline at end of file diff --git a/fastlane/metadata/android/pt-PT/full_description.txt b/fastlane/metadata/android/pt-PT/full_description.txt new file mode 100644 index 0000000000..07cf8233b3 --- /dev/null +++ b/fastlane/metadata/android/pt-PT/full_description.txt @@ -0,0 +1,14 @@ +Cria e elabora e fornece correntes de correias transportadoras para aumentar a munição das tuas torretas, produz materiais para usar em construções, e defende as tuas estruturas de ondas de inimigos. Joga com os teus amigos em multiplataforma multijogador jogos cooperativos, ou desafia eles em batalhas em equipa modo PvP. + +Recursos incluidos: +- 24 mapas integrados +- Uma campanha completa com uma estrutura tecnológica em árvore e áreas para desbloquear +- 4 ondas de chefes poderosas para derrotar +- Sistema de transporte de Energias, Líquidos e Itens +- 19 tipos diferentes de drones, mechas e navios +- Mais de 120 blocos de tecnologia para dominar +- Mais de 75 diferentes blocos de ambiente +- Multijogador multiplataforma através de redes locais ou servidores dedicados +- Regras personalizadas do jogo: altere os custos de bloqueio, estatísticas do inimigo, itens iniciais, tempo das ondas e muito mais +- Um editor poderoso, com ferramentas para gerar aleatoriamente minérios, terrenos, decoração e aplicar simetria a mapas +- Layouts de rondas de mapa personalizáveis \ No newline at end of file diff --git a/fastlane/metadata/android/pt-PT/short_description.txt b/fastlane/metadata/android/pt-PT/short_description.txt new file mode 100644 index 0000000000..6ecbaf697a --- /dev/null +++ b/fastlane/metadata/android/pt-PT/short_description.txt @@ -0,0 +1 @@ +Um jogo de defesa de torre de sandbox baseado em construção. diff --git a/fastlane/metadata/android/pt-PT/summary.txt b/fastlane/metadata/android/pt-PT/summary.txt new file mode 100644 index 0000000000..24b4edd83d --- /dev/null +++ b/fastlane/metadata/android/pt-PT/summary.txt @@ -0,0 +1 @@ +Um jogo de defesa de torre de sandbox baseado em construção. \ No newline at end of file diff --git a/fastlane/metadata/android/pt-PT/title.txt b/fastlane/metadata/android/pt-PT/title.txt new file mode 100644 index 0000000000..2beb939017 --- /dev/null +++ b/fastlane/metadata/android/pt-PT/title.txt @@ -0,0 +1 @@ +Mindustry \ No newline at end of file diff --git a/fastlane/metadata/steam/czech/achievements.vdf b/fastlane/metadata/steam/czech/achievements.vdf new file mode 100644 index 0000000000..e7e80c47f2 --- /dev/null +++ b/fastlane/metadata/steam/czech/achievements.vdf @@ -0,0 +1,109 @@ +"lang" +{ + "Language" "czech" + "Tokens" + { + "NEW_ACHIEVEMENT_20_0_NAME" "Ověřen" + "NEW_ACHIEVEMENT_20_0_DESC" "Dokončena výuka." + "NEW_ACHIEVEMENT_20_1_NAME" "Šroťák" + "NEW_ACHIEVEMENT_20_1_DESC" "Znič 1000 nepřátelských jednotek." + "NEW_ACHIEVEMENT_20_2_NAME" "Čistič" + "NEW_ACHIEVEMENT_20_2_DESC" "Znič 100,000 nepřátelských jednotek." + "NEW_ACHIEVEMENT_20_3_NAME" "Přesun do atmosféry" + "NEW_ACHIEVEMENT_20_3_DESC" "Vyšli zpět celkem 10.000 předmětů." + "NEW_ACHIEVEMENT_20_5_NAME" "Nekonečné dodávky" + "NEW_ACHIEVEMENT_20_5_DESC" "Vyšli zpět celkem 1.000.000 předmětů." + "NEW_ACHIEVEMENT_20_6_NAME" "Dobyvatel" + "NEW_ACHIEVEMENT_20_6_DESC" "Vyhraj 10 zápasů v herním režimu Útok." + "NEW_ACHIEVEMENT_20_7_NAME" "Šampión" + "NEW_ACHIEVEMENT_20_7_DESC" "Vyhraj 10 zápasů v herním režimu Hráči proti sobě." + "NEW_ACHIEVEMENT_20_8_NAME" "Blesk" + "NEW_ACHIEVEMENT_20_8_DESC" "Znič nepřátelské jádro v útočné zóně v průběhu prvních 5 vln." + "NEW_ACHIEVEMENT_20_9_NAME" "Prší jádra" + "NEW_ACHIEVEMENT_20_9_DESC" "Vyšli Tvoje jádro do mapy 30x." + "NEW_ACHIEVEMENT_20_10_NAME" "Houževnatý" + "NEW_ACHIEVEMENT_20_10_DESC" "Přežij 100 vln." + "NEW_ACHIEVEMENT_20_11_NAME" "Neposkvrněný" + "NEW_ACHIEVEMENT_20_11_DESC" "Přežij 500 vln." + "NEW_ACHIEVEMENT_20_12_NAME" "Výzkumník" + "NEW_ACHIEVEMENT_20_12_DESC" "Vyzkoumej všechno." + "NEW_ACHIEVEMENT_20_13_NAME" "Měňavec" + "NEW_ACHIEVEMENT_20_13_DESC" "Odemkni každého mecha ve hře a transformuj se do něj." + "NEW_ACHIEVEMENT_20_14_NAME" "Přetížení" + "NEW_ACHIEVEMENT_20_14_DESC" "Zasáhni nepřítele pokrytého vodou energetickou zbraní." + "NEW_ACHIEVEMENT_20_15_NAME" "Odražení" + "NEW_ACHIEVEMENT_20_15_DESC" "Znič jednotku její vlastní odraženou kulkou." + "NEW_ACHIEVEMENT_20_17_NAME" "Distributor v zácviku" + "NEW_ACHIEVEMENT_20_17_DESC" "Vynalezni Směrovač." + "NEW_ACHIEVEMENT_20_18_NAME" "Stvořitel" + "NEW_ACHIEVEMENT_20_18_DESC" "Umísti 10.000 bloků." + "NEW_ACHIEVEMENT_20_19_NAME" "Viktor čistič" + "NEW_ACHIEVEMENT_20_19_DESC" "Znič 1.000 nepřátelských bloků." + "NEW_ACHIEVEMENT_20_20_NAME" "Velkolepá chyba" + "NEW_ACHIEVEMENT_20_20_DESC" "Způsob přetížení Thoriového reaktoru, následované explozí." + "NEW_ACHIEVEMENT_20_21_NAME" "Kartograf" + "NEW_ACHIEVEMENT_20_21_DESC" "Vytvoř 10 nových map." + "NEW_ACHIEVEMENT_20_22_NAME" "Sosač" + "NEW_ACHIEVEMENT_20_22_DESC" "Stáhni mapu z dílny." + "NEW_ACHIEVEMENT_20_23_NAME" "Tvůrce" + "NEW_ACHIEVEMENT_20_23_DESC" "Publikuj mapu do dílny." + "NEW_ACHIEVEMENT_20_24_NAME" "Řezník" + "NEW_ACHIEVEMENT_20_24_DESC" "Poraž Záporáka." + "NEW_ACHIEVEMENT_20_25_NAME" "Průzkumník" + "NEW_ACHIEVEMENT_20_25_DESC" "Odemkni všechny zóny v kampani." + "NEW_ACHIEVEMENT_20_26_NAME" "Perfekcionalista" + "NEW_ACHIEVEMENT_20_26_DESC" "Dosáhni požadavku pro vlastní výbavu ve všech zónách v kampani." + "NEW_ACHIEVEMENT_20_29_NAME" "Materiály II" + "NEW_ACHIEVEMENT_20_29_DESC" "Odemkni Thorium." + "NEW_ACHIEVEMENT_20_31_NAME" "Materiály I" + "NEW_ACHIEVEMENT_20_31_DESC" "Odemkni Titan." + "NEW_ACHIEVEMENT_21_0_NAME" "Kamikaze" + "NEW_ACHIEVEMENT_21_0_DESC" "Naplň svého mecha výbušným materiálem a zemři v explozi ." + "NEW_ACHIEVEMENT_21_1_NAME" "A tak to začíná" + "NEW_ACHIEVEMENT_21_1_DESC" "Vytvoř továrnu na mecha Dýka." + "NEW_ACHIEVEMENT_21_2_NAME" "Přímý útok" + "NEW_ACHIEVEMENT_21_2_DESC" "Vyšli příkaz k útoku z řídícího střediska." + "NEW_ACHIEVEMENT_21_3_NAME" "Roj" + "NEW_ACHIEVEMENT_21_3_DESC" "Měj v jeden ukamžil 100 aktivních jednotek." + "NEW_ACHIEVEMENT_21_4_NAME" "Stádo" + "NEW_ACHIEVEMENT_21_4_DESC" "Měj v jeden okamžik 10 aktivních dronů Fantóm ." + "NEW_ACHIEVEMENT_21_5_NAME" "Proměnlivá armáda" + "NEW_ACHIEVEMENT_21_5_DESC" "Měj v jeden okamžik 50 aktivních jednotek Slídič." + "NEW_ACHIEVEMENT_21_6_NAME" "Legie" + "NEW_ACHIEVEMENT_21_6_DESC" "Postav celkem 1.000 jednotek." + "NEW_ACHIEVEMENT_21_7_NAME" "Super" + "NEW_ACHIEVEMENT_21_7_DESC" "Dosáhni hodnocení S v jakékoliv zóně." + "NEW_ACHIEVEMENT_21_8_NAME" "Super Super" + "NEW_ACHIEVEMENT_21_8_DESC" "Dosáhni hodnocení SS v jakékoliv zóně." + "NEW_ACHIEVEMENT_21_9_NAME" "Měl jsi líp poslouchat" + "NEW_ACHIEVEMENT_21_9_DESC" "Zemři v zóně pro vylíhnutí nepřátelských jednotek." + "NEW_ACHIEVEMENT_21_10_NAME" "Prostě zmáčkni Shift" + "NEW_ACHIEVEMENT_21_10_DESC" "Nějak se utop." + "NEW_ACHIEVEMENT_21_11_NAME" "Sběratel" + "NEW_ACHIEVEMENT_21_11_DESC" "Naplň jádro do maximální kapacity každým typem materiálu." + "NEW_ACHIEVEMENT_21_12_NAME" "Dav" + "NEW_ACHIEVEMENT_21_12_DESC" "Hostuj server s aspoň 10 hráči." + "NEW_ACHIEVEMENT_21_13_NAME" "Nezranitelný" + "NEW_ACHIEVEMENT_21_13_DESC" "Postav drony Meltdown a Spectre." + "NEW_ACHIEVEMENT_21_14_NAME" "Odlet" + "NEW_ACHIEVEMENT_21_14_DESC" "Použij Vysílací plošinu." + "NEW_ACHIEVEMENT_21_15_NAME" "Samolibost" + "NEW_ACHIEVEMENT_21_15_DESC" "Přeskoč vyslání zpět dvakrát a pak si nech zničit jádro nepřítelem." + "NEW_ACHIEVEMENT_21_16_NAME" "Kacířství" + "NEW_ACHIEVEMENT_21_16_DESC" "Postav dva směrovače vedle sebe." + "NEW_ACHIEVEMENT_21_17_NAME" "Osamělý strážce" + "NEW_ACHIEVEMENT_21_17_DESC" "Přežij 10 vln v jakékoliv zóně bez položení bloku." + "NEW_ACHIEVEMENT_21_18_NAME" "Zpopelnění" + "NEW_ACHIEVEMENT_21_18_DESC" "Použij ve střílně pyratit." + "NEW_ACHIEVEMENT_21_19_NAME" "Účinnost" + "NEW_ACHIEVEMENT_21_19_DESC" "Chlaď střílnu vodou nebo chladící kapalinou." + "NEW_ACHIEVEMENT_21_20_NAME" "Klasický režim" + "NEW_ACHIEVEMENT_21_20_DESC" "Zapni rozpixlování." + "NEW_ACHIEVEMENT_21_21_NAME" "Školák" + "NEW_ACHIEVEMENT_21_21_DESC" "Otevři Wiki Mindustry ze hry." + "NEW_ACHIEVEMENT_21_22_NAME" "Náskok" + "NEW_ACHIEVEMENT_21_22_DESC" "Vyšli se do zóny s nejméně 10.000 předměty." + "NEW_ACHIEVEMENT_21_23_NAME" "Zážeh" + "NEW_ACHIEVEMENT_21_23_DESC" "Zažehni rázový reaktor." + } +} diff --git a/fastlane/metadata/steam/czech/description.txt b/fastlane/metadata/steam/czech/description.txt new file mode 100644 index 0000000000..7a7ac632ff --- /dev/null +++ b/fastlane/metadata/steam/czech/description.txt @@ -0,0 +1,61 @@ +Vytvoř propracovaný výrobní řetězec dopravníků, abys naládoval munici do věží, vyrobil materiály pro stavění a ubránil své stavby před vlnami nepřátel. Hraj s Tvými přáteli kooperačně napříč platformami, nebo je vyzvi v týmové hře hráčů proti sobě. + +[img]{STEAM_APP_IMAGE}/extras/ezgif-4-0e70c282f775.gif[/img] + +[h2]Hra[/h2] + +[list] +[*] Vytvoř vrty a dopravníky pro přesun zdrojů do Tvého jádra. +[*] Použij výrobní bloky pro vytvoření pokročilých materiálů. +[*] Postav drony pro automatické těžení zdrojů, pomoc se stavěním a vybudování a ochraně své základny. +[*] Rozváděj kapaliny a bojuj s požárem. +[*] Posilni výrobu dodatečným chlazením a promaž obranné i výrobní bloky. +[/list] + +[h2]Kampaň[/h2] + +[list] +[*] Projdi skrz 12 znovuhratelných předpřipravených zón s náhodným místem startu. +[*] Sesbírej a vyšli zpět ze zón materiál. +[*] Vynalezni nové bloky, abys rozjel výrobu. +[*] Konfiguruj předměty, se kterými se vyšleš do zóny, abys byl lépe připraven. +[*] V jednotlivých zónách plň rozdílné cíle mise. +[*] Pozvi kamarády pro společné dokončení mise. +[*] 120+ technologických bloků, dokážeš je všechny využít? +[*] 19 různých typů dronů, mechů and lodí! +[*] 50+ achievementů! +[/list] + +[h2][h2]Herní módy[/h2][/h2] + +[list] +[*] [b]Přežití[/b]: Postav věže k obraně Tvého jádra před nepřátelskými jednotkami. Přežij tak dlouho, jak jen dokážeš, a ideálně ještě odešli své jádro zpět se sesbíranými surovinami pro zaplacení výzkumu. Připrav svou základnu pro střídavý útok vzdušného Záporáka. +[*] [b]Útok[/b]: Postav továrny na jednotky pro zničení nepřátelského jádra, zatímco zároveň ochraňuj svoji základnu před vlnami nepřátelských jednotek. Vytvoř různé typy podpůrných a obranných jednotek pro dosažení tohoto cíle. +[*] [b]Hráči proti sobě[/b]: Soupeř s jinými hráči v až 4 různých týmech, s cílem zničit ostatní jádra. Vytvoř jednotky nebo útoč na cizí jádro rovnou ve svém mechu. +[*] [b]Pískoviště[/b]: Vyzkoušej si hru s nekonečnými zdroji surovin a bez nepřátelských hrozeb. Použij bloky dostupné pouze v pískovišti aby sis otestoval svůj nový nápad a pokud budeš chtít, můžeš si na vyžádání nechat seslat nepřátelské jednotky. +[/list] + +[h2]Vlastní hra a podpora napříč herními platformami[/h2] + +[list] +[*] 12 vestavěných map pro vlastní hry, navíc ke kampani +[*] Hraj kooperativně, proti sobě nebo na pískovišti +[*] Připoj se k veřejnému serveru nebo pozvi přátele do svého vlastního soukromého sezení +[*] Nastavitelná herní pravidla: Změn cenu bloků, nepřátelské statistiky, počáteční předměty, časování vln atd. +[*] Mix herních režimů: Smíchej dohromady hru hráčů proti sobě (PvP) a hráčů proti prostředí (PvE) +[/list] + +[h2]Editor map[/h2] + +[list] +[*] Nakresli si novou mapu s vestavěným editorem +[*] Upravuj a dej si náhled staveb přímo ve hře +[*] Konfigurovatelné nástroje: Změň, jak se každý nástroj chová +[*] Silný systém pro generování map, s mnoha různými typy filtrů pro procedurální manipulaci s terénem - vytvoř úžasnou mapu za 5 minut! +[*] Přidej zašumění, zkreslení, vyhlazení, prolnutí, zrcadlení, rozptýlení, generování rud a náhodného terénu do svých map +[*] Konfiguruj náhodné generování rudy, řek a surovin +[*] Konfiguruj rozestavění nepřátelských vln +[*] Sdílej vyexportované mapy v dílně Steamu +[*] Nastav pravidla pro základní mapy +[*] Použij 75+ různých bloků +[/list] diff --git a/fastlane/metadata/steam/czech/short-description.txt b/fastlane/metadata/steam/czech/short-description.txt new file mode 100644 index 0000000000..252ae989db --- /dev/null +++ b/fastlane/metadata/steam/czech/short-description.txt @@ -0,0 +1 @@ +Hra typu tower-defense s otevřeným koncem, zaměřená na řízení zdrojů. diff --git a/fastlane/metadata/steam/portuguese-brazil/description.txt b/fastlane/metadata/steam/portuguese-brazil/description.txt index 0efa240dc0..add86a6a2c 100644 --- a/fastlane/metadata/steam/portuguese-brazil/description.txt +++ b/fastlane/metadata/steam/portuguese-brazil/description.txt @@ -5,7 +5,7 @@ Crie correntes de suprimentos elaboradas com correias transportadoras para alime [h2]Gameplay[/h2] [list] -[*] Crie brocas e correntes transportadoras para mover recursos para o seu Núcleo. +[*] Crie brocas e esteiras transportadoras para mover recursos para o seu Núcleo. [*] Use blocos de produção para criar materiais avançados. [*] Construa drones para minerar recursos automaticamente, ajudar na construção e proteger a sua base. [*] Distribua líquidos e enfrente surtos de fogo. diff --git a/fastlane/metadata/steam/portuguese/achievements.vdf b/fastlane/metadata/steam/portuguese/achievements.vdf new file mode 100644 index 0000000000..caa3a26319 --- /dev/null +++ b/fastlane/metadata/steam/portuguese/achievements.vdf @@ -0,0 +1,109 @@ +"lang" +{ + "Language" "portuguese-brazil" + "Tokens" + { + "NEW_ACHIEVEMENT_20_0_NAME" "Verificado" + "NEW_ACHIEVEMENT_20_0_DESC" "Complete o tutorial" + "NEW_ACHIEVEMENT_20_1_NAME" "Sucateiro" + "NEW_ACHIEVEMENT_20_1_DESC" "Destrua 1000 unidades inimigas." + "NEW_ACHIEVEMENT_20_2_NAME" "Expurgo" + "NEW_ACHIEVEMENT_20_2_DESC" "Destrua 100.000 unidades inimigas." + "NEW_ACHIEVEMENT_20_3_NAME" "Transporte atmosférico" + "NEW_ACHIEVEMENT_20_3_DESC" "Lance 10.000 itens no total." + "NEW_ACHIEVEMENT_20_5_NAME" "Transportes Sem Fim" + "NEW_ACHIEVEMENT_20_5_DESC" "Lance 1.000.000 itens no total." + "NEW_ACHIEVEMENT_20_6_NAME" "Conquistador" + "NEW_ACHIEVEMENT_20_6_DESC" "Vença 10 partidas no modo de ataque." + "NEW_ACHIEVEMENT_20_7_NAME" "Campeão" + "NEW_ACHIEVEMENT_20_7_DESC" "Vença 10 partidas PvP multi-jogador." + "NEW_ACHIEVEMENT_20_8_NAME" "Blitz" + "NEW_ACHIEVEMENT_20_8_DESC" "Destrua o núcleo inimigo na zona de ataque em 5 hordas ou menos." + "NEW_ACHIEVEMENT_20_9_NAME" "Chuva de núcleos" + "NEW_ACHIEVEMENT_20_9_DESC" "Lance seu núcleo em uma zona 10 vezes." + "NEW_ACHIEVEMENT_20_10_NAME" "Persistente" + "NEW_ACHIEVEMENT_20_10_DESC" "Sobreviva 100 hordas" + "NEW_ACHIEVEMENT_20_11_NAME" "Invicto" + "NEW_ACHIEVEMENT_20_11_DESC" "Sobreviva 500 hordas." + "NEW_ACHIEVEMENT_20_12_NAME" "Pesquisador" + "NEW_ACHIEVEMENT_20_12_DESC" "Pesquise tudo." + "NEW_ACHIEVEMENT_20_13_NAME" "Metamorfose Ambulante" + "NEW_ACHIEVEMENT_20_13_DESC" "Desbloqueie e transforme-se em todos os mechas no jogo." + "NEW_ACHIEVEMENT_20_14_NAME" "Sobrecarga" + "NEW_ACHIEVEMENT_20_14_DESC" "Atinja um inimigo coberto de água com eletricidade." + "NEW_ACHIEVEMENT_20_15_NAME" "Deflexão" + "NEW_ACHIEVEMENT_20_15_DESC" "Destrua uma unidade com suas proprias balas refletidas." + "NEW_ACHIEVEMENT_20_17_NAME" "Um Erro Grave" + "NEW_ACHIEVEMENT_20_17_DESC" "Pesquise o roteador." + "NEW_ACHIEVEMENT_20_18_NAME" "Crie" + "NEW_ACHIEVEMENT_20_18_DESC" "Coloque 10.000 blocos." + "NEW_ACHIEVEMENT_20_19_NAME" "Arraso" + "NEW_ACHIEVEMENT_20_19_DESC" "Destrua 1.000 blocos inimigos." + "NEW_ACHIEVEMENT_20_20_NAME" "Um desastre espetacular." + "NEW_ACHIEVEMENT_20_20_DESC" "Faça com que um reator de tório superaqueça e exploda." + "NEW_ACHIEVEMENT_20_21_NAME" "Cartógrafo" + "NEW_ACHIEVEMENT_20_21_DESC" "Faça um mapa novo 10 vezes." + "NEW_ACHIEVEMENT_20_22_NAME" "Navegador" + "NEW_ACHIEVEMENT_20_22_DESC" "Baixe um mapa da Oficina." + "NEW_ACHIEVEMENT_20_23_NAME" "Criador" + "NEW_ACHIEVEMENT_20_23_DESC" "Publique um mapa na Oficina." + "NEW_ACHIEVEMENT_20_24_NAME" "Matador" + "NEW_ACHIEVEMENT_20_24_DESC" "Derrote um chefe." + "NEW_ACHIEVEMENT_20_25_NAME" "Explorador" + "NEW_ACHIEVEMENT_20_25_DESC" "Desbloqueie todas as zonas na campanha." + "NEW_ACHIEVEMENT_20_26_NAME" "Completador" + "NEW_ACHIEVEMENT_20_26_DESC" "Alcance a horda requerida para configuração em todas as zonas." + "NEW_ACHIEVEMENT_20_29_NAME" "Material II" + "NEW_ACHIEVEMENT_20_29_DESC" "Desbloqueie Tório." + "NEW_ACHIEVEMENT_20_31_NAME" "Material I" + "NEW_ACHIEVEMENT_20_31_DESC" "Desbloqueie Titânio." + "NEW_ACHIEVEMENT_21_0_NAME" "Kamikaze" + "NEW_ACHIEVEMENT_21_0_DESC" "Encha o seu mecha com materiais explosivos e morra, criando uma explosão." + "NEW_ACHIEVEMENT_21_1_NAME" "Assim Começa" + "NEW_ACHIEVEMENT_21_1_DESC" "Construa uma fábrica de Dagger." + "NEW_ACHIEVEMENT_21_2_NAME" "Ataque direto" + "NEW_ACHIEVEMENT_21_2_DESC" "Emita o comando de Ataque usando o Centro de Comando." + "NEW_ACHIEVEMENT_21_3_NAME" "Enchame" + "NEW_ACHIEVEMENT_21_3_DESC" "Tenha 100 unidades ativas ao mesmo tempo." + "NEW_ACHIEVEMENT_21_4_NAME" "Rebanho" + "NEW_ACHIEVEMENT_21_4_DESC" "Tenha 10 drones Phantom ativos ao mesmo tempo." + "NEW_ACHIEVEMENT_21_5_NAME" "Exército Volátil" + "NEW_ACHIEVEMENT_21_5_DESC" "Tenha 50 unidades Crawler ativas ao mesmo tempo." + "NEW_ACHIEVEMENT_21_6_NAME" "Legiões" + "NEW_ACHIEVEMENT_21_6_DESC" "Construa 1000 unidades no total." + "NEW_ACHIEVEMENT_21_7_NAME" "Super" + "NEW_ACHIEVEMENT_21_7_DESC" "Conquiste o rank S em qualquer zona." + "NEW_ACHIEVEMENT_21_8_NAME" "Super Super" + "NEW_ACHIEVEMENT_21_8_DESC" "Conquiste o rank SS em qualquer zona." + "NEW_ACHIEVEMENT_21_9_NAME" "Você Devia Ter Escutado" + "NEW_ACHIEVEMENT_21_9_DESC" "Morra na zona de exclusão do ponto de spawn." + "NEW_ACHIEVEMENT_21_10_NAME" "Só Aperte Shift" + "NEW_ACHIEVEMENT_21_10_DESC" "Afogue, de algum modo." + "NEW_ACHIEVEMENT_21_11_NAME" "Colecionador" + "NEW_ACHIEVEMENT_21_11_DESC" "Encha o núcleo até a capacidade máxima com todos os tipos de materiais." + "NEW_ACHIEVEMENT_21_12_NAME" "Galera" + "NEW_ACHIEVEMENT_21_12_DESC" "Hospede um servidor com 10 pessoas nele." + "NEW_ACHIEVEMENT_21_13_NAME" "Invulnerável" + "NEW_ACHIEVEMENT_21_13_DESC" "Construa o Meltdown e o Spectre." + "NEW_ACHIEVEMENT_21_14_NAME" "Decolagem" + "NEW_ACHIEVEMENT_21_14_DESC" "Use a Plataforma de Lançamento." + "NEW_ACHIEVEMENT_21_15_NAME" "Complacência" + "NEW_ACHIEVEMENT_21_15_DESC" "Pule o lançamento duas vezes, então tenha o seu núcleo destruído pelo inimigo." + "NEW_ACHIEVEMENT_21_16_NAME" "Heresia" + "NEW_ACHIEVEMENT_21_16_DESC" "Construa dois roteadores, um do lado do outro." + "NEW_ACHIEVEMENT_21_17_NAME" "Guardião Solitário" + "NEW_ACHIEVEMENT_21_17_DESC" "Sobreviva 10 hordas em qualquer zona, sem colocar qualquer bloco." + "NEW_ACHIEVEMENT_21_18_NAME" "Incinere" + "NEW_ACHIEVEMENT_21_18_DESC" "Use Piratita em qualquer torreta." + "NEW_ACHIEVEMENT_21_19_NAME" "Eficiência" + "NEW_ACHIEVEMENT_21_19_DESC" "Refirgere uma torreta com água ou crio fluido." + "NEW_ACHIEVEMENT_21_20_NAME" "Modo Clássico" + "NEW_ACHIEVEMENT_21_20_DESC" "Habilite pixelização." + "NEW_ACHIEVEMENT_21_21_NAME" "Sábio" + "NEW_ACHIEVEMENT_21_21_DESC" "Abra a Wiki do jogo." + "NEW_ACHIEVEMENT_21_22_NAME" "Vantagem" + "NEW_ACHIEVEMENT_21_22_DESC" "Entre em uma zona com 10.000 itens ou mais já configurados." + "NEW_ACHIEVEMENT_21_23_NAME" "Ignição" + "NEW_ACHIEVEMENT_21_23_DESC" "Ligue um Reator de Impacto." + } +} diff --git a/fastlane/metadata/steam/portuguese/description.txt b/fastlane/metadata/steam/portuguese/description.txt new file mode 100644 index 0000000000..0efa240dc0 --- /dev/null +++ b/fastlane/metadata/steam/portuguese/description.txt @@ -0,0 +1,61 @@ +Crie correntes de suprimentos elaboradas com correias transportadoras para alimentar suas torretas com munição, produza minerais para usar em construção, e defenda suas estruturas de hordas inimigas. Jogue com seus amigos em jogos cooperativos multi-jogadores multi-plataformas, ou desafie-os em partidas PvP de times. + +[img]{STEAM_APP_IMAGE}/extras/ezgif-4-0e70c282f775.gif[/img] + +[h2]Gameplay[/h2] + +[list] +[*] Crie brocas e correntes transportadoras para mover recursos para o seu Núcleo. +[*] Use blocos de produção para criar materiais avançados. +[*] Construa drones para minerar recursos automaticamente, ajudar na construção e proteger a sua base. +[*] Distribua líquidos e enfrente surtos de fogo. +[*] Melhore a produção suprimindo refrigerantes e lubrificantes opcionais para os seus blocos de defesa e produção. +[/list] + +[h2]Campanha[/h2] + +[list] +[*] Avance através de 12 zonas re-jogáveis com pontos de spawn aleatórios +[*] Colete e lance recursos +[*] Pesquise novos blocos para abastecer o progresso +[*] Configure loadout antes do lançamento para levar recursos para cada zona +[*] Variedade de missões com objetivos e metas +[*] Convide seus amigos para completar missões juntos +[*] Mais de 120 blocos de tecnologia para dominar +[*] 19 tipos de drones, mechas e naves diferentes +[*] Mais de 50 conquistas para completar +[/list] + +[h2][h2]Modos de jogo[/h2][/h2] + +[list] +[*] [b]Sobrevivência[/b]: Construa torretas para defender de inimigos no gameplay de tower-defense. Sobreviva o máximo possível, opcionalmente lançando o seu núcleo para usar os recursos coletados para pesquisa. Prepare a sua base para ataques intermitentes de chefes aéreos. +[*] [b]Ataque[/b]: Construa fábricas para unidades destruírem núcleos inimidos, enquanto simultaneamente defendendo sua base de hordas de unidades inimigas. Crie uma variedade de tipos diferentes de unidades de suporte o defesa para auxiliar você em seus objetivos. +[*] [b]PvP[/b]: Dispute com outros jogadores em até 4 times diferentes, para destruir o núcleo dos outros. Crie unidades, ou ataque outras bases diretamente com seus mechas. +[*] [b]Sandbox[/b]: Brinque com recursos infinitos e sem ameaça inimiga. Use itens específicos do modo e fontes de líquidos para testar designs, e sumone inimigos à vontade. +[/list] + +[h2]Jogos Personalizados & Multi-jogador Multi-plataforma[/h2] + +[list] +[*] 12 mapas embutidos para jogos personalizados, além da campanha +[*] Jogue Cooperativo, PvP, ou sandbox +[*] Entre em um servidor público dedicado, ou convide amigos para a sua própria sessão privada +[*] Regras do jogo personalizáveis: Mude custo dos blocos, estatísticas de inimigos, itens iniciais, tempo entre as hordas e mais +[*] Misture modos de jogo: Combine modos de jogo PvP e PvE +[/list] + +[h2]Editor de mapa[/h2] + +[list] +[*] Pinte terreno com um editor +[*] Edite e visualize estruturas em jogo +[*] Modos de ferramentas configuráveis: Mude como cada ferramenta funciona +[*] Sistema gerador de mapa poderoso, com muitos tipos diferentes de filtros para manipulação procedural de terreno +[*] Aplique ruído, distorção, suavização, erosão, simetria, geração de minérios e terreno aleatório aos seus mapas +[*] Aleatorize e configure geração de minérios, assim como localização de rios e recursos +[*] Configure o layout de hordas inimigas +[*] Compartilhe mapas exportados na Oficina da Steam +[*] Modifique regras básicas do mapa +[*] Use mais de 75 blocos de ambientação diferentes +[/list] diff --git a/fastlane/metadata/steam/portuguese/short-description.txt b/fastlane/metadata/steam/portuguese/short-description.txt new file mode 100644 index 0000000000..c6ad92da31 --- /dev/null +++ b/fastlane/metadata/steam/portuguese/short-description.txt @@ -0,0 +1 @@ +Um jogo de fim aberto de tower-defense com um foco em gerenciamento de recursos. diff --git a/gradle.properties b/gradle.properties index b74ceb8844..3fead25b94 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=e287fdce0449a87fb15599c67b5167ac0273bcb6 +archash=68b2451bd0f8c6252ccf2c065a1c4b4896605183 diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java index 566656b4a5..9cf3015466 100644 --- a/server/src/mindustry/server/ServerControl.java +++ b/server/src/mindustry/server/ServerControl.java @@ -15,7 +15,7 @@ import mindustry.*; import mindustry.core.GameState.*; import mindustry.core.*; import mindustry.entities.*; -import mindustry.entities.type.*; +import mindustry.entities.type.Playerc; import mindustry.game.*; import mindustry.game.EventType.*; import mindustry.gen.*; @@ -296,7 +296,7 @@ public class ServerControl implements ApplicationListener{ if(playerGroup.size() > 0){ info(" &lyPlayers: {0}", playerGroup.size()); - for(Player p : playerGroup.all()){ + for(Playerc p : playerGroup.all()){ info(" &y{0} / {1}", p.name, p.uuid); } }else{ @@ -346,15 +346,6 @@ public class ServerControl implements ApplicationListener{ info("&lyServer: &lb{0}", arg[0]); }); - handler.register("difficulty", "", "Set game difficulty.", arg -> { - try{ - state.rules.waveSpacing = Difficulty.valueOf(arg[0]).waveTime * 60 * 60 * 2; - info("Difficulty set to '{0}'.", arg[0]); - }catch(IllegalArgumentException e){ - err("No difficulty with name '{0}' found.", arg[0]); - } - }); - handler.register("rules", "[remove/add] [name] [value...]", "List, remove or add global rules. These will apply regardless of map.", arg -> { String rules = Core.settings.getString("globalrules"); JsonValue base = JsonIO.json().fromJson(null, rules); @@ -585,7 +576,7 @@ public class ServerControl implements ApplicationListener{ return; } - Player target = playerGroup.find(p -> p.name.equals(arg[0])); + Playerc target = playerGroup.find(p -> p.name.equals(arg[0])); if(target != null){ Call.sendMessage("[scarlet] " + target.name + "[scarlet] has been kicked by the server."); @@ -601,7 +592,7 @@ public class ServerControl implements ApplicationListener{ netServer.admins.banPlayerID(arg[1]); info("Banned."); }else if(arg[0].equals("name")){ - Player target = playerGroup.find(p -> p.name.equalsIgnoreCase(arg[1])); + Playerc target = playerGroup.find(p -> p.name.equalsIgnoreCase(arg[1])); if(target != null){ netServer.admins.banPlayer(target.uuid); info("Banned."); @@ -615,7 +606,7 @@ public class ServerControl implements ApplicationListener{ err("Invalid type."); } - for(Player player : playerGroup.all()){ + for(Playerc player : playerGroup.all()){ if(netServer.admins.isIDBanned(player.uuid)){ Call.sendMessage("[scarlet] " + player.name + " has been banned."); player.con.kick(KickReason.banned); @@ -653,18 +644,10 @@ public class ServerControl implements ApplicationListener{ }); handler.register("unban", "", "Completely unban a person by IP or ID.", arg -> { - if(arg[0].contains(".")){ - if(netServer.admins.unbanPlayerIP(arg[0])){ - info("Unbanned player by IP: {0}.", arg[0]); - }else{ - err("That IP is not banned!"); - } + if(netServer.admins.unbanPlayerIP(arg[0]) || netServer.admins.unbanPlayerID(arg[0])){ + info("Unbanned player.", arg[0]); }else{ - if(netServer.admins.unbanPlayerID(arg[0])){ - info("Unbanned player by ID: {0}.", arg[0]); - }else{ - err("That ID is not banned!"); - } + err("That IP/ID is not banned!"); } }); @@ -674,7 +657,7 @@ public class ServerControl implements ApplicationListener{ return; } - Player target = playerGroup.find(p -> p.name.equals(arg[0])); + Playerc target = playerGroup.find(p -> p.name.equals(arg[0])); if(target != null){ netServer.admins.adminPlayer(target.uuid, target.usid); @@ -691,7 +674,7 @@ public class ServerControl implements ApplicationListener{ return; } - Player target = playerGroup.find(p -> p.name.equals(arg[0])); + Playerc target = playerGroup.find(p -> p.name.equals(arg[0])); if(target != null){ netServer.admins.unAdminPlayer(target.uuid); @@ -829,7 +812,6 @@ public class ServerControl implements ApplicationListener{ }); mods.eachClass(p -> p.registerServerCommands(handler)); - mods.eachClass(p -> p.registerClientCommands(netServer.clientCommands)); } private void readCommands(){ @@ -872,10 +854,10 @@ public class ServerControl implements ApplicationListener{ private void play(boolean wait, Runnable run){ inExtraRound = true; Runnable r = () -> { - Array players = new Array<>(); - for(Player p : playerGroup.all()){ + Array players = new Array<>(); + for(Playerc p : playerGroup.all()){ players.add(p); - p.setDead(true); + p.dead(true); } logic.reset(); @@ -885,12 +867,12 @@ public class ServerControl implements ApplicationListener{ state.rules = world.getMap().applyRules(lastMode); logic.play(); - for(Player p : players){ + for(Playerc p : players){ if(p.con == null) continue; p.reset(); if(state.rules.pvp){ - p.setTeam(netServer.assignTeam(p, new ArrayIterable<>(players))); + p.team(netServer.assignTeam(p, new ArrayIterable<>(players))); } netServer.sendWorldData(p); } diff --git a/servers.json b/servers.json index 81ea4bf021..8f6e4d3491 100644 --- a/servers.json +++ b/servers.json @@ -1,5 +1,26 @@ [ { "address": "mindustry.us.to" + }, + { + "address": "mindustry.ecansol.com:6597" + }, + { + "address": "mindustry.ecansol.com:6499" + }, + { + "address": "mindustry.ru" + }, + { + "address": "mindustry.io" + }, + { + "address": "mindustry.io:1000" + }, + { + "address": "mindustry.io:2000" + }, + { + "address": "mindustry.io:3000" } ] diff --git a/settings.gradle b/settings.gradle index 2b49093a42..a7356fd3c9 100644 --- a/settings.gradle +++ b/settings.gradle @@ -31,7 +31,6 @@ if(!hasProperty("release")){ use(':Arc:extensions:g3d') use(':Arc:backends') use(':Arc:backends:backend-sdl') - use(':Arc:backends:backend-lwjgl3') use(':Arc:backends:backend-android') use(':Arc:backends:backend-robovm') use(':Arc:backends:backend-headless') diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index 9c57eff95a..26d4168c2a 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -1,25 +1,22 @@ -import arc.ApplicationCore; -import arc.Core; -import arc.backend.headless.HeadlessApplication; +import arc.*; +import arc.backend.headless.*; +import arc.math.geom.*; import arc.struct.*; -import arc.math.geom.Point2; -import arc.util.Log; -import arc.util.Time; -import mindustry.Vars; +import arc.util.*; +import mindustry.*; import mindustry.content.*; -import mindustry.core.GameState.State; import mindustry.core.*; -import mindustry.entities.traits.BuilderTrait.BuildRequest; -import mindustry.entities.type.BaseUnit; +import mindustry.core.GameState.*; +import mindustry.ctype.*; import mindustry.entities.type.base.*; -import mindustry.game.Team; -import mindustry.io.SaveIO; -import mindustry.maps.Map; -import mindustry.net.*; -import mindustry.ctype.ContentType; -import mindustry.type.Item; +import mindustry.entities.units.*; +import mindustry.game.*; +import mindustry.io.*; +import mindustry.maps.*; +import mindustry.net.Net; +import mindustry.type.*; import mindustry.world.*; -import mindustry.world.blocks.BlockPart; +import mindustry.world.blocks.*; import org.junit.jupiter.api.*; import static mindustry.Vars.*; @@ -125,7 +122,7 @@ public class ApplicationTests{ int bx = 4; int by = 4; world.tile(bx, by).set(Blocks.coreShard, Team.sharded); - assertEquals(world.tile(bx, by).getTeam(), Team.sharded); + assertEquals(world.tile(bx, by).team(), Team.sharded); for(int x = bx - 1; x <= bx + 1; x++){ for(int y = by - 1; y <= by + 1; y++){ if(x == bx && by == y){ @@ -141,12 +138,12 @@ public class ApplicationTests{ void blockInventories(){ multiblock(); Tile tile = world.tile(4, 4); - tile.entity.items.add(Items.coal, 5); - tile.entity.items.add(Items.titanium, 50); - assertEquals(tile.entity.items.total(), 55); - tile.entity.items.remove(Items.phasefabric, 10); - tile.entity.items.remove(Items.titanium, 10); - assertEquals(tile.entity.items.total(), 45); + tile.entity.items().add(Items.coal, 5); + tile.entity.items().add(Items.titanium, 50); + assertEquals(tile.entity.items().total(), 55); + tile.entity.items().remove(Items.phasefabric, 10); + tile.entity.items().remove(Items.titanium, 10); + assertEquals(tile.entity.items().total(), 45); } @Test @@ -212,6 +209,49 @@ public class ApplicationTests{ assertTrue(state.teams.playerCores().size > 0); } + @Test + void conveyorBench(){ + int[] items = {0}; + + world.loadMap(testMap); + state.set(State.playing); + int length = 128; + world.tile(0, 0).setBlock(Blocks.itemSource); + world.tile(0, 0).configureAny(Items.copper.id); + + Array entities = Array.with(world.tile(0, 0).entity); + + for(int i = 0; i < length; i++){ + world.tile(i + 1, 0).setBlock(Blocks.conveyor); + world.tile(i + 1, 0).rotation(0); + entities.add(world.tile(i + 1, 0).entity); + } + + world.tile(length + 1, 0).setBlock(new Block("___"){ + @Override + public void handleItem(Item item, Tile tile, Tile source){ + items[0] ++; + } + + @Override + public boolean acceptItem(Item item, Tile tile, Tile source){ + return true; + } + }); + + //warmup + for(int i = 0; i < 100000; i++){ + entities.each(Tilec::update); + } + + Time.mark(); + for(int i = 0; i < 200000; i++){ + entities.each(Tilec::update); + } + Log.info(Time.elapsed() + "ms to process " + items[0] + " items"); + assertTrue(items[0] > 0); + } + @Test void load77Save(){ resetWorld(); @@ -377,14 +417,14 @@ public class ApplicationTests{ Tile core = world.tile(5, 5); core.set(Blocks.coreShard, Team.sharded); for(Item item : content.items()){ - core.entity.items.set(item, 3000); + core.entity.items().set(item, 3000); } assertEquals(core.entity, state.teams.get(Team.sharded).core()); } void depositTest(Block block, Item item){ - BaseUnit unit = UnitTypes.spirit.create(Team.derelict); + Unitc unit = UnitTypes.spirit.create(Team.derelict); Tile tile = new Tile(0, 0, Blocks.air, Blocks.air, block); int capacity = tile.block().itemCapacity; @@ -394,12 +434,12 @@ public class ApplicationTests{ assertEquals(capacity - 1, deposited); tile.block().handleStack(item, capacity - 1, tile, unit); - assertEquals(tile.entity.items.get(item), capacity - 1); + assertEquals(tile.entity.items().get(item), capacity - 1); int overflow = tile.block().acceptStack(item, 10, tile, unit); assertEquals(1, overflow); tile.block().handleStack(item, 1, tile, unit); - assertEquals(capacity, tile.entity.items.get(item)); + assertEquals(capacity, tile.entity.items().get(item)); } } \ No newline at end of file diff --git a/tests/src/test/java/ZoneTests.java b/tests/src/test/java/ZoneTests.java index 2181de1cda..cca493ac9d 100644 --- a/tests/src/test/java/ZoneTests.java +++ b/tests/src/test/java/ZoneTests.java @@ -54,7 +54,7 @@ public class ZoneTests{ if(tile.drop() != null){ resources.add(tile.drop()); } - if(tile.block() instanceof CoreBlock && tile.getTeam() == state.rules.defaultTeam){ + if(tile.block() instanceof CoreBlock && tile.team() == state.rules.defaultTeam){ hasSpawnPoint = true; } } diff --git a/tests/src/test/java/power/DirectConsumerTests.java b/tests/src/test/java/power/DirectConsumerTests.java index 19933045fe..938be40a50 100644 --- a/tests/src/test/java/power/DirectConsumerTests.java +++ b/tests/src/test/java/power/DirectConsumerTests.java @@ -37,8 +37,8 @@ public class DirectConsumerTests extends PowerTestFixture{ consumes.power(requestedPower); consumes.items(new ItemStack(Items.silicon, 30), new ItemStack(Items.lead, 30)); }}); - consumerTile.entity.items.add(Items.silicon, siliconAmount); - consumerTile.entity.items.add(Items.lead, leadAmount); + consumertile.entity.items().add(Items.silicon, siliconAmount); + consumertile.entity.items().add(Items.lead, leadAmount); Tile producerTile = createFakeTile(2, 0, createFakeProducerBlock(producedPower)); producerTile.ent().productionEfficiency = 1f; @@ -50,6 +50,6 @@ public class DirectConsumerTests extends PowerTestFixture{ consumerTile.entity.update(); graph.update(); - assertEquals(expectedSatisfaction, consumerTile.entity.power.status); + assertEquals(expectedSatisfaction, consumertile.entity.power().status); } } diff --git a/tests/src/test/java/power/ItemLiquidGeneratorTests.java b/tests/src/test/java/power/ItemLiquidGeneratorTests.java index 7111c79658..fe01e49dca 100644 --- a/tests/src/test/java/power/ItemLiquidGeneratorTests.java +++ b/tests/src/test/java/power/ItemLiquidGeneratorTests.java @@ -87,13 +87,13 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{ createGenerator(inputType); assertTrue(generator.acceptLiquid(tile, null, liquid, availableLiquidAmount), inputType + " | " + parameterDescription + ": Liquids which will be declined by the generator don't need to be tested - The code won't be called for those cases."); - entity.liquids.add(liquid, availableLiquidAmount); - entity.cons.update(); + entity.liquids().add(liquid, availableLiquidAmount); + entity.cons().update(); // Perform an update on the generator once - This should use up any resource up to the maximum liquid usage generator.update(tile); - assertEquals(expectedRemainingLiquidAmount, entity.liquids.get(liquid), inputType + " | " + parameterDescription + ": Remaining liquid amount mismatch."); + assertEquals(expectedRemainingLiquidAmount, entity.liquids().get(liquid), inputType + " | " + parameterDescription + ": Remaining liquid amount mismatch."); assertEquals(expectedEfficiency, entity.productionEfficiency, inputType + " | " + parameterDescription + ": Efficiency mismatch."); } @@ -130,15 +130,15 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{ assertTrue(generator.acceptItem(item, tile, null), inputType + " | " + parameterDescription + ": Items which will be declined by the generator don't need to be tested - The code won't be called for those cases."); if(amount > 0){ - entity.items.add(item, amount); + entity.items().add(item, amount); } - entity.cons.update(); + entity.cons().update(); // Perform an update on the generator once - This should use up one or zero items - dependent on if the item is accepted and available or not. try{ generator.update(tile); - assertEquals(expectedRemainingItemAmount, entity.items.get(item), inputType + " | " + parameterDescription + ": Remaining item amount mismatch."); + assertEquals(expectedRemainingItemAmount, entity.items().get(item), inputType + " | " + parameterDescription + ": Remaining item amount mismatch."); assertEquals(expectedEfficiency, entity.productionEfficiency, inputType + " | " + parameterDescription + ": Efficiency mismatch."); }catch(NullPointerException e){ e.printStackTrace(); @@ -162,8 +162,8 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{ createGenerator(inputType); // Burn a single coal and test for the duration - entity.items.add(Items.coal, 1); - entity.cons.update(); + entity.items().add(Items.coal, 1); + entity.cons().update(); generator.update(tile); float expectedEfficiency = entity.productionEfficiency; diff --git a/tests/src/test/java/power/PowerTestFixture.java b/tests/src/test/java/power/PowerTestFixture.java index e5735052f5..459d26aa9a 100644 --- a/tests/src/test/java/power/PowerTestFixture.java +++ b/tests/src/test/java/power/PowerTestFixture.java @@ -87,19 +87,19 @@ public class PowerTestFixture{ // Simulate the "changed" method. Calling it through reflections would require half the game to be initialized. tile.entity = block.newEntity().init(tile, false); - tile.entity.cons = new ConsumeModule(tile.entity); - if(block.hasItems) tile.entity.items = new ItemModule(); - if(block.hasLiquids) tile.entity.liquids = new LiquidModule(); + tile.entity.cons() = new ConsumeModule(tile.entity); + if(block.hasItems) tile.entity.items() = new ItemModule(); + if(block.hasLiquids) tile.entity.liquids() = new LiquidModule(); if(block.hasPower){ - tile.entity.power = new PowerModule(); - tile.entity.power.graph = new PowerGraph(){ + tile.entity.power() = new PowerModule(); + tile.entity.power().graph = new PowerGraph(){ //assume there's always something consuming power @Override public float getUsageFraction(){ return 1f; } }; - tile.entity.power.graph.add(tile); + tile.entity.power().graph.add(tile); } // Assign incredibly high health so the block does not get destroyed on e.g. burning Blast Compound diff --git a/tests/src/test/java/power/PowerTests.java b/tests/src/test/java/power/PowerTests.java index 6815f2e880..509900b6f3 100644 --- a/tests/src/test/java/power/PowerTests.java +++ b/tests/src/test/java/power/PowerTests.java @@ -66,7 +66,7 @@ public class PowerTests extends PowerTestFixture{ // Update and check for the expected power status of the consumer powerGraph.update(); - assertEquals(expectedSatisfaction, directConsumerTile.entity.power.status, Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Satisfaction of direct consumer did not match"); + assertEquals(expectedSatisfaction, directConsumertile.entity.power().status, Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Satisfaction of direct consumer did not match"); } /** @@ -104,14 +104,14 @@ public class PowerTests extends PowerTestFixture{ } float maxCapacity = 100f; Tile batteryTile = createFakeTile(0, 2, createFakeBattery(maxCapacity)); - batteryTile.entity.power.status = initialBatteryCapacity / maxCapacity; + batterytile.entity.power().status = initialBatteryCapacity / maxCapacity; powerGraph.add(batteryTile); powerGraph.update(); - assertEquals(expectedBatteryCapacity / maxCapacity, batteryTile.entity.power.status, Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Expected battery status did not match"); + assertEquals(expectedBatteryCapacity / maxCapacity, batterytile.entity.power().status, Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Expected battery status did not match"); if(directConsumerTile != null){ - assertEquals(expectedSatisfaction, directConsumerTile.entity.power.status, Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Satisfaction of direct consumer did not match"); + assertEquals(expectedSatisfaction, directConsumertile.entity.power().status, Mathf.FLOAT_ROUNDING_ERROR, parameterDescription + ": Satisfaction of direct consumer did not match"); } } @@ -127,13 +127,13 @@ public class PowerTests extends PowerTestFixture{ powerGraph.add(consumerTile); powerGraph.update(); - assertEquals(1.0f, consumerTile.entity.power.status, Mathf.FLOAT_ROUNDING_ERROR); + assertEquals(1.0f, consumertile.entity.power().status, Mathf.FLOAT_ROUNDING_ERROR); powerGraph.remove(producerTile); powerGraph.add(consumerTile); powerGraph.update(); - assertEquals(0.0f, consumerTile.entity.power.status, Mathf.FLOAT_ROUNDING_ERROR); + assertEquals(0.0f, consumertile.entity.power().status, Mathf.FLOAT_ROUNDING_ERROR); if(consumerTile.block().consumes.hasPower()){ ConsumePower consumePower = consumerTile.block().consumes.getPower(); assertFalse(consumePower.valid(consumerTile.ent())); diff --git a/tools/build.gradle b/tools/build.gradle index fa4c1ca32b..959121fcda 100644 --- a/tools/build.gradle +++ b/tools/build.gradle @@ -3,12 +3,9 @@ apply plugin: "java" sourceCompatibility = 1.8 sourceSets.main.java.srcDirs = ["src/"] - -import com.badlogic.gdx.graphics.Color -import com.badlogic.gdx.tools.texturepacker.TexturePacker -import com.badlogic.gdx.utils.IntArray -import com.badlogic.gdx.utils.IntIntMap -import com.badlogic.gdx.utils.IntMap +import arc.struct.* +import arc.graphics.* +import arc.packer.* import javax.imageio.ImageIO import java.awt.* @@ -16,7 +13,7 @@ import java.awt.image.BufferedImage import java.util.List import java.util.concurrent.ExecutorService import java.util.concurrent.Executors -import java.util.concurrent.TimeUnit +import java.util.concurrent.TimeUnit def genFolder = "../core/assets-raw/sprites_out/generated/" def doAntialias = !project.hasProperty("disableAntialias") @@ -87,7 +84,8 @@ def antialias = { File file -> suma.a += color.a } - suma.mul(suma.a <= 0.001f ? 0f : (float) (1f / suma.a)) + float fm = suma.a <= 0.001f ? 0f : (float) (1f / suma.a) + suma.mul(fm, fm, fm, fm) float total = 0 sum.set(0) @@ -103,7 +101,8 @@ def antialias = { File file -> total += 1f } - sum.mul((float) (1f / total)) + fm = (float)(1f / total) + sum.mul(fm, fm, fm, fm) int result = Color.argb8888(sum) out.setRGB(x, y, result) sum.set(0) diff --git a/tools/src/mindustry/tools/FontGenerator.java b/tools/src/mindustry/tools/FontGenerator.java index 32bbc121cf..2ebb8fd2a0 100644 --- a/tools/src/mindustry/tools/FontGenerator.java +++ b/tools/src/mindustry/tools/FontGenerator.java @@ -46,7 +46,8 @@ public class FontGenerator{ Log.info("Merge..."); - OS.exec("fontforge", "-script", "core/assets-raw/fontgen/merge.pe"); + //don't merge since it breaks the font + //OS.exec("fontforge", "-script", "core/assets-raw/fontgen/merge.pe"); Log.info("Done."); } diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java index 271166f3a2..b63a056495 100644 --- a/tools/src/mindustry/tools/Generators.java +++ b/tools/src/mindustry/tools/Generators.java @@ -1,13 +1,15 @@ package mindustry.tools; -import arc.struct.*; import arc.files.*; import arc.graphics.*; import arc.graphics.g2d.*; import arc.math.*; +import arc.struct.*; import arc.util.*; import arc.util.noise.*; import mindustry.ctype.*; +import mindustry.gen.*; +import mindustry.graphics.*; import mindustry.tools.ImagePacker.*; import mindustry.type.*; import mindustry.ui.*; @@ -184,47 +186,30 @@ public class Generators{ } }); - ImagePacker.generate("mech-icons", () -> { - for(Mech mech : content.getBy(ContentType.mech)){ - mech.load(); - mech.weapon.load(); - - Image image = ImagePacker.get(mech.region); - - if(!mech.flying){ - image.drawCenter(mech.baseRegion); - image.drawCenter(mech.legRegion); - image.drawCenter(mech.legRegion, true, false); - image.drawCenter(mech.region); - } - - int off = image.width / 2 - mech.weapon.region.getWidth() / 2; - - for(int i : Mathf.signs){ - image.draw(mech.weapon.region, i * (int)mech.weaponOffsetX*4 + off, -(int)mech.weaponOffsetY*4 + off, i > 0, false); - } - - image.save("mech-" + mech.name + "-full"); - } - }); - ImagePacker.generate("unit-icons", () -> { - content.getBy(ContentType.unit).each(type -> !type.flying, type -> { + content.units().each(type -> !type.flying, type -> { type.load(); - type.weapon.load(); Image image = ImagePacker.get(type.region); - image.draw(type.baseRegion); - image.draw(type.legRegion); - image.draw(type.legRegion, true, false); + if(type.constructor.get() instanceof Legsc){ + image.draw(type.baseRegion); + image.draw(type.legRegion); + image.draw(type.legRegion, true, false); + } image.draw(type.region); - for(boolean b : Mathf.booleans){ - image.draw(type.weapon.region, - (int)(Mathf.sign(b) * type.weapon.width / Draw.scl + image.width / 2 - type.weapon.region.getWidth() / 2), - (int)(type.weaponOffsetY / Draw.scl + image.height / 2f - type.weapon.region.getHeight() / 2f), - b, false); + for(Weapon weapon : type.weapons){ + weapon.load(); + + for(int i : (weapon.mirror ? Mathf.signs : Mathf.one)){ + i *= Mathf.sign(weapon.flipped); + + image.draw(weapon.region, + (int)(i * weapon.x / Draw.scl + image.width / 2 - weapon.region.getWidth() / 2), + (int)(weapon.y / Draw.scl + image.height / 2f - weapon.region.getHeight() / 2f), + i > 0, false); + } } image.save("unit-" + type.name + "-full"); @@ -291,6 +276,33 @@ public class Generators{ }catch(Exception ignored){} }); }); + + ImagePacker.generate("scorches", () -> { + for(int size = 0; size < 10; size++){ + for(int i = 0; i < 3; i++){ + ScorchGenerator gen = new ScorchGenerator(); + double multiplier = 30; + double ss = size * multiplier / 20.0; + + gen.seed = Mathf.random(100000); + gen.size += size*multiplier; + gen.scale = gen.size / 80f * 18f; + //gen.nscl -= size * 0.2f; + gen.octaves += ss/3.0; + gen.pers += ss/10.0/5.0; + + gen.scale += Mathf.range(3f); + gen.scale -= ss*2f; + gen.nscl -= Mathf.random(1f); + + Pixmap out = gen.generate(); + Pixmap median = Pixmaps.median(out, 2, 0.75); + Fi.get("../rubble/scorch-" + size + "-" + i + ".png").writePNG(median); + out.dispose(); + median.dispose(); + } + } + }); } } diff --git a/tools/src/mindustry/tools/ImagePacker.java b/tools/src/mindustry/tools/ImagePacker.java index 2ba0a6ee68..2cdfb04415 100644 --- a/tools/src/mindustry/tools/ImagePacker.java +++ b/tools/src/mindustry/tools/ImagePacker.java @@ -25,6 +25,7 @@ public class ImagePacker{ public static void main(String[] args) throws Exception{ Vars.headless = true; + ArcNativesLoader.load(); Log.setLogger(new NoopLogHandler()); Vars.content = new ContentLoader();