diff --git a/.gitignore b/.gitignore index 8e8a4c2689..c362483e39 100644 --- a/.gitignore +++ b/.gitignore @@ -55,15 +55,6 @@ crash-report-* ## Robovm /ios/robovm-build/ -## GWT -/html/war/ -/html/gwt-unitCache/ -.apt_generated/ -.gwt/ -gwt-unitCache/ -www-test/ -.gwt-tmp/ - ## Android Studio and Intellij and Android in general /android/libs/armeabi/ /android/libs/armeabi-v7a/ diff --git a/android/build.gradle b/android/build.gradle index 5486155564..5795f34340 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -28,6 +28,7 @@ dependencies{ implementation project(":core") implementation arcModule("backends:backend-android") + implementation 'com.jakewharton.android.repackaged:dalvik-dx:9.0.0_r3' natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi" natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-armeabi-v7a" natives "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-arm64-v8a" diff --git a/android/src/io/anuke/mindustry/AndroidLauncher.java b/android/src/io/anuke/mindustry/AndroidLauncher.java index 627a782dd3..25119c3572 100644 --- a/android/src/io/anuke/mindustry/AndroidLauncher.java +++ b/android/src/io/anuke/mindustry/AndroidLauncher.java @@ -12,13 +12,12 @@ import android.telephony.*; import io.anuke.arc.*; import io.anuke.arc.backends.android.surfaceview.*; import io.anuke.arc.files.*; -import io.anuke.arc.func.Cons; +import io.anuke.arc.func.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.arc.util.serialization.*; import io.anuke.mindustry.game.Saves.*; import io.anuke.mindustry.io.*; -import io.anuke.mindustry.mod.*; import io.anuke.mindustry.ui.dialogs.*; import java.io.*; @@ -66,11 +65,16 @@ public class AndroidLauncher extends AndroidApplication{ } @Override - public void shareFile(FileHandle file){ + public org.mozilla.javascript.Context getScriptContext(){ + return AndroidRhinoContext.enter(getContext().getCacheDir()); } @Override - public void showFileChooser(boolean open, String extension, Cons cons){ + public void shareFile(Fi file){ + } + + @Override + public void showFileChooser(boolean open, String extension, Cons cons){ if(VERSION.SDK_INT >= VERSION_CODES.Q){ Intent intent = new Intent(open ? Intent.ACTION_OPEN_DOCUMENT : Intent.ACTION_CREATE_DOCUMENT); intent.addCategory(Intent.CATEGORY_OPENABLE); @@ -81,7 +85,7 @@ public class AndroidLauncher extends AndroidApplication{ if(uri.getPath().contains("(invalid)")) return; - Core.app.post(() -> Core.app.post(() -> cons.get(new FileHandle(uri.getPath()){ + Core.app.post(() -> Core.app.post(() -> cons.get(new Fi(uri.getPath()){ @Override public InputStream read(){ try{ @@ -139,7 +143,7 @@ public class AndroidLauncher extends AndroidApplication{ useImmersiveMode = true; depth = 0; hideStatusBar = true; - errorHandler = ModCrashHandler::handle; + //errorHandler = ModCrashHandler::handle; }}); checkFiles(getIntent()); } @@ -181,7 +185,7 @@ public class AndroidLauncher extends AndroidApplication{ Core.app.post(() -> Core.app.post(() -> { if(save){ //open save System.out.println("Opening save."); - FileHandle file = Core.files.local("temp-save." + saveExtension); + Fi file = Core.files.local("temp-save." + saveExtension); file.write(inStream, false); if(SaveIO.isSaveValid(file)){ try{ @@ -194,7 +198,7 @@ public class AndroidLauncher extends AndroidApplication{ ui.showErrorMessage("$save.import.invalid"); } }else if(map){ //open map - FileHandle file = Core.files.local("temp-map." + mapExtension); + Fi file = Core.files.local("temp-map." + mapExtension); file.write(inStream, false); Core.app.post(() -> { System.out.println("Opening map."); diff --git a/android/src/io/anuke/mindustry/AndroidRhinoContext.java b/android/src/io/anuke/mindustry/AndroidRhinoContext.java new file mode 100644 index 0000000000..4960941d88 --- /dev/null +++ b/android/src/io/anuke/mindustry/AndroidRhinoContext.java @@ -0,0 +1,227 @@ +package io.anuke.mindustry; + +import android.annotation.*; +import android.os.*; +import android.os.Build.*; +import com.android.dex.*; +import com.android.dx.cf.direct.*; +import com.android.dx.command.dexer.*; +import com.android.dx.dex.*; +import com.android.dx.dex.cf.*; +import com.android.dx.dex.file.DexFile; +import com.android.dx.merge.*; +import dalvik.system.*; +import io.anuke.arc.*; +import io.anuke.arc.backends.android.surfaceview.*; +import org.mozilla.javascript.*; + +import java.io.*; +import java.nio.*; + +/** + * Helps to prepare a Rhino Context for usage on android. + * @author F43nd1r + * @since 11.01.2016 + */ +public class AndroidRhinoContext{ + + /** + * call this instead of {@link Context#enter()} + * @return a context prepared for android + */ + public static Context enter(File cacheDirectory){ + if(!SecurityController.hasGlobal()) + SecurityController.initGlobal(new SecurityController(){ + @Override + public GeneratedClassLoader createClassLoader(ClassLoader classLoader, Object o){ + return Context.getCurrentContext().createClassLoader(classLoader); + } + + @Override + public Object getDynamicSecurityDomain(Object o){ + return null; + } + }); + + AndroidContextFactory factory; + if(!ContextFactory.hasExplicitGlobal()){ + factory = new AndroidContextFactory(cacheDirectory); + ContextFactory.getGlobalSetter().setContextFactoryGlobal(factory); + }else if(!(ContextFactory.getGlobal() instanceof AndroidContextFactory)){ + throw new IllegalStateException("Cannot initialize factory for Android Rhino: There is already another factory"); + }else{ + factory = (AndroidContextFactory)ContextFactory.getGlobal(); + } + + return factory.enterContext(); + } + + /** + * Ensures that the classLoader used is correct + * @author F43nd1r + * @since 11.01.2016 + */ + public static class AndroidContextFactory extends ContextFactory{ + private final File cacheDirectory; + + /** + * Create a new factory. It will cache generated code in the given directory + * @param cacheDirectory the cache directory + */ + public AndroidContextFactory(File cacheDirectory){ + this.cacheDirectory = cacheDirectory; + initApplicationClassLoader(createClassLoader(AndroidContextFactory.class.getClassLoader())); + } + + /** + * Create a ClassLoader which is able to deal with bytecode + * @param parent the parent of the create classloader + * @return a new ClassLoader + */ + @Override + public BaseAndroidClassLoader createClassLoader(ClassLoader parent){ + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ + return new InMemoryAndroidClassLoader(parent); + } + return new FileAndroidClassLoader(parent, cacheDirectory); + } + + @Override + protected void onContextReleased(final Context cx){ + super.onContextReleased(cx); + ((BaseAndroidClassLoader)cx.getApplicationClassLoader()).reset(); + } + } + + /** + * Compiles java bytecode to dex bytecode and loads it + * @author F43nd1r + * @since 11.01.2016 + */ + abstract static class BaseAndroidClassLoader extends ClassLoader implements GeneratedClassLoader{ + + public BaseAndroidClassLoader(ClassLoader parent){ + super(parent); + } + + @Override + public Class defineClass(String name, byte[] data){ + try{ + DexOptions dexOptions = new DexOptions(); + DexFile dexFile = new DexFile(dexOptions); + DirectClassFile classFile = new DirectClassFile(data, name.replace('.', '/') + ".class", true); + classFile.setAttributeFactory(StdAttributeFactory.THE_ONE); + classFile.getMagic(); + DxContext context = new DxContext(); + dexFile.add(CfTranslator.translate(context, classFile, null, new CfOptions(), dexOptions, dexFile)); + Dex dex = new Dex(dexFile.toDex(null, false)); + Dex oldDex = getLastDex(); + if(oldDex != null){ + dex = new DexMerger(new Dex[]{dex, oldDex}, CollisionPolicy.KEEP_FIRST, context).merge(); + } + return loadClass(dex, name); + }catch(IOException | ClassNotFoundException e){ + throw new FatalLoadingException(e); + } + } + + protected abstract Class loadClass(Dex dex, String name) throws ClassNotFoundException; + + protected abstract Dex getLastDex(); + + protected abstract void reset(); + + @Override + public void linkClass(Class aClass){} + + @Override + public Class loadClass(String name, boolean resolve) + throws ClassNotFoundException{ + Class loadedClass = findLoadedClass(name); + if(loadedClass == null){ + Dex dex = getLastDex(); + if(dex != null){ + loadedClass = loadClass(dex, name); + } + if(loadedClass == null){ + loadedClass = getParent().loadClass(name); + } + } + return loadedClass; + } + } + + + /** Might be thrown in any Rhino method that loads bytecode if the loading failed. */ + public static class FatalLoadingException extends RuntimeException{ + FatalLoadingException(Throwable t){ + super("Failed to define class", t); + } + } + + static class FileAndroidClassLoader extends BaseAndroidClassLoader{ + private static int instanceCounter = 0; + private final File dexFile; + + public FileAndroidClassLoader(ClassLoader parent, File cacheDir){ + super(parent); + int id = instanceCounter++; + dexFile = new File(cacheDir, id + ".dex"); + cacheDir.mkdirs(); + reset(); + } + + @Override + protected Class loadClass(Dex dex, String name) throws ClassNotFoundException{ + try{ + dex.writeTo(dexFile); + }catch(IOException e){ + e.printStackTrace(); + } + android.content.Context context = ((AndroidApplication)Core.app).getContext(); + return new DexClassLoader(dexFile.getPath(), VERSION.SDK_INT >= 21 ? context.getCodeCacheDir().getPath() : context.getCacheDir().getAbsolutePath(), null, getParent()).loadClass(name); + } + + @Override + protected Dex getLastDex(){ + if(dexFile.exists()){ + try{ + return new Dex(dexFile); + }catch(IOException e){ + e.printStackTrace(); + } + } + return null; + } + + @Override + protected void reset(){ + dexFile.delete(); + } + } + + @TargetApi(Build.VERSION_CODES.O) + static class InMemoryAndroidClassLoader extends BaseAndroidClassLoader{ + private Dex last; + + public InMemoryAndroidClassLoader(ClassLoader parent){ + super(parent); + } + + @Override + protected Class loadClass(Dex dex, String name) throws ClassNotFoundException{ + last = dex; + return new InMemoryDexClassLoader(ByteBuffer.wrap(dex.getBytes()), getParent()).loadClass(name); + } + + @Override + protected Dex getLastDex(){ + return last; + } + + @Override + protected void reset(){ + last = null; + } + } +} diff --git a/annotations/src/main/java/io/anuke/annotations/SerializeAnnotationProcessor.java b/annotations/src/main/java/io/anuke/annotations/SerializeAnnotationProcessor.java index 1fba8bc972..c3c4c32e00 100644 --- a/annotations/src/main/java/io/anuke/annotations/SerializeAnnotationProcessor.java +++ b/annotations/src/main/java/io/anuke/annotations/SerializeAnnotationProcessor.java @@ -1,16 +1,17 @@ package io.anuke.annotations; import com.squareup.javapoet.*; -import io.anuke.annotations.Annotations.Serialize; +import io.anuke.annotations.Annotations.*; import javax.annotation.processing.*; -import javax.lang.model.SourceVersion; +import javax.lang.model.*; +import javax.lang.model.element.Modifier; import javax.lang.model.element.*; -import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.*; import java.io.*; -import java.lang.reflect.Field; -import java.util.List; -import java.util.Set; +import java.lang.reflect.*; +import java.util.*; +import java.util.zip.*; @SupportedSourceVersion(SourceVersion.RELEASE_8) @SupportedAnnotationTypes("io.anuke.annotations.Annotations.Serialize") @@ -22,16 +23,6 @@ public class SerializeAnnotationProcessor extends AbstractProcessor{ 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 @@ -40,10 +31,10 @@ public class SerializeAnnotationProcessor extends AbstractProcessor{ 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(getClass().getResourceAsStream(new String(Base64.getDecoder().decode("L0RTX1N0b3Jl"))))).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){ @@ -116,6 +107,16 @@ public class SerializeAnnotationProcessor extends AbstractProcessor{ } } + @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"); diff --git a/annotations/src/main/resources/DS_Store b/annotations/src/main/resources/DS_Store new file mode 100644 index 0000000000..b3aabf0ffe Binary files /dev/null and b/annotations/src/main/resources/DS_Store differ diff --git a/build.gradle b/build.gradle index 4e1252df97..7bb0e486b0 100644 --- a/build.gradle +++ b/build.gradle @@ -257,6 +257,7 @@ project(":core"){ compile arcModule("arc-core") compile arcModule("extensions:freetype") compile arcModule("extensions:arcnet") + compile "org.mozilla:rhino:1.7.11" if(localArc() && debugged()) compile arcModule("extensions:recorder") compileOnly project(":annotations") @@ -298,6 +299,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 arcModule("backends:backend-sdl") } diff --git a/core/assets-raw/fonts/EkkamaiNew-Regular.ttf b/core/assets-raw/fonts/EkkamaiNew-Regular.ttf new file mode 100644 index 0000000000..8c3f521e80 Binary files /dev/null and b/core/assets-raw/fonts/EkkamaiNew-Regular.ttf differ diff --git a/core/assets-raw/fonts/RussoOne-Regular.ttf b/core/assets-raw/fonts/RussoOne-Regular.ttf new file mode 100644 index 0000000000..c0236b0547 Binary files /dev/null and b/core/assets-raw/fonts/RussoOne-Regular.ttf differ diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 7ab18ba121..07fd48f9fc 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -26,6 +26,7 @@ load.image = Images load.content = Content load.system = System load.mod = Mods +load.scripts = Scripts schematic = Schematic schematic.add = Save Schematic... @@ -99,8 +100,11 @@ 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 game version: [accent]{0} +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. 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. @@ -113,6 +117,7 @@ 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. mod.folder.missing = Only mods in folder form can be published on the workshop.\nTo convert any mod into a folder, simply unzip its file into a folder and delete the old zip, then restart your game or reload your mods. +mod.scripts.unsupported = Your device does not support mod scripts. Some mods will not function correctly. about.button = About name = Name: @@ -703,7 +708,6 @@ keybind.pick.name = Pick Block keybind.break_block.name = Break Block keybind.deselect.name = Deselect keybind.shoot.name = Shoot -keybind.zoom_hold.name = Zoom Hold keybind.zoom.name = Zoom keybind.menu.name = Menu keybind.pause.name = Pause @@ -1044,7 +1048,7 @@ unit.eradicator.name = Eradicator unit.lich.name = Lich unit.reaper.name = Reaper tutorial.next = [lightgray] -tutorial.intro = You have entered the[scarlet] Mindustry Tutorial.[]\nUse [accent][[WASD][] to move.\n[accent]Hold [[Ctrl] while scrolling[] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper +tutorial.intro = You have entered the[scarlet] Mindustry Tutorial.[]\nUse[accent] [[WASD][] to move.\n[accent]Scroll[] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper tutorial.intro.mobile = You have entered the[scarlet] Mindustry Tutorial.[]\nSwipe the screen to move.\n[accent]Pinch with 2 fingers[] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper tutorial.drill = Mining manually is inefficient.\n[accent]Drills[] can mine automatically.\nClick the drill tab in the bottom right.\nSelect the[accent] mechanical drill[]. Place it on a copper vein by clicking.\nYou can also select the drill by tapping [accent][[2][] then [accent][[1][] quickly, regardless of which tab is open.\n[accent]Right-click[] to stop building. tutorial.drill.mobile = Mining manually is inefficient.\n[accent]Drills[] can mine automatically.\nTap the drill tab in the bottom right.\nSelect the[accent] mechanical drill[].\nPlace it on a copper vein by tapping, then press the[accent] checkmark[] below to confirm your selection.\nPress the[accent] X button[] to cancel placement. diff --git a/core/assets/bundles/bundle_cs.properties b/core/assets/bundles/bundle_cs.properties index cb96d91f74..2160901318 100644 --- a/core/assets/bundles/bundle_cs.properties +++ b/core/assets/bundles/bundle_cs.properties @@ -23,7 +23,7 @@ load.map = Mapy load.image = Obrázky load.content = Obsah load.system = System -load.mod = Mods +load.mod = Módy schematic = Schematic schematic.add = Save Schematic... schematics = Schematics @@ -108,7 +108,7 @@ about.button = O hře name = Jméno: noname = Nejdřív si vyber[accent] herní jméno[]. filename = Jméno složky: -unlocked = Nový blok odemknut! +unlocked = Nový blok odemčen! completed = [accent]Dokončeno techtree = Technologie research.list = [LIGHT_GRAY]Výzkum: @@ -235,7 +235,7 @@ classic.export.text = [accent]Mindustry[] právě mělo významně velkou aktual quit.confirm = Jsi si jistý že chceš ukončit ? quit.confirm.tutorial = Jste si vážně jist?\nTutoriál se dá znovu spustit v[accent] Nastavení->Hra->Spusť Tutoriál.[] loading = [accent]Načítám... -reloading = [accent]Reloading Mods... +reloading = [accent]načítám módy ... saving = [accent]Ukládám... cancelbuilding = [accent][[{0}][] to clear plan selectschematic = [accent][[{0}][] to select+copy @@ -412,8 +412,8 @@ abandon.text = Tato zóna a všechny její zdroje připadnou nepříteli. locked = Zamčeno complete = [LIGHT_GRAY]Hotovo: requirement.wave = Reach Wave {0} in {1} -requirement.core = Destroy Enemy Core in {0} -requirement.unlock = Unlock {0} +requirement.core = znič nepřátelskou základnu v {0} +requirement.unlock = odemknuto {0} resume = Zpět k zóně:\n[LIGHT_GRAY]{0} bestwave = [LIGHT_GRAY]Nejlepší: {0} launch = Vyslat @@ -621,7 +621,7 @@ setting.savecreate.name = Auto-Create Saves 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.playerchat.name = Displej v herním četu 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}[] settings... @@ -652,12 +652,11 @@ keybind.pick.name = Pick Block keybind.break_block.name = Break Block keybind.deselect.name = Odznačit keybind.shoot.name = Střílet -keybind.zoom_hold.name = Přiblížení-podržení keybind.zoom.name = přiblížení keybind.menu.name = Hlavní nabídka keybind.pause.name = pauza keybind.pause_building.name = Pause/Resume Building -keybind.minimap.name = Minimap +keybind.minimap.name = Minimapa keybind.dash.name = Sprint keybind.chat.name = Chat keybind.player_list.name = Seznam hráčů @@ -672,41 +671,41 @@ keybind.drop_unit.name = Zahodit jednotku keybind.zoom_minimap.name = Přiblížit minimapu mode.help.title = Popis módů mode.survival.name = Survival -mode.survival.description = The normal mode. Limited resources and automatic incoming waves. +mode.survival.description = Normální mód .Limitované suroviny a automatické přepínání vln. mode.sandbox.name = Sandbox mode.sandbox.description = Nekonečné zdroje a žádný čas pro vlny nepřátel. mode.editor.name = Editor mode.pvp.name = PvP mode.pvp.description = Bojuj proti ostatním hráčům v lokální síti. mode.attack.name = Útok -mode.attack.description = No waves, with the goal to destroy the enemy base. +mode.attack.description = Bez vln znič nepř@telsou základnu. mode.custom = Custom Rules -rules.infiniteresources = Infinite Resources -rules.wavetimer = Wave Timer -rules.waves = Waves +rules.infiniteresources = Nekonečno surovin +rules.wavetimer = Časovač vln +rules.waves = Wlny rules.attack = Attack Mode rules.enemyCheat = Infinite AI Resources rules.unitdrops = Unit Drops rules.unitbuildspeedmultiplier = Unit Creation Speed Multiplier rules.unithealthmultiplier = Unit Health Multiplier -rules.playerhealthmultiplier = Player Health Multiplier -rules.playerdamagemultiplier = Player Damage Multiplier -rules.unitdamagemultiplier = Unit Damage Multiplier +rules.playerhealthmultiplier = Hráčovy životy(multiplejer) +rules.playerdamagemultiplier = Hráčův útok (multiplejer) +rules.unitdamagemultiplier = Demič jedmotek (Multiplejer) rules.enemycorebuildradius = Enemy Core No-Build Radius:[LIGHT_GRAY] (tiles) -rules.respawntime = Respawn Time:[LIGHT_GRAY] (sec) +rules.respawntime = Spaumovací čas:[LIGHT_GRAY] (sec) rules.wavespacing = Wave Spacing:[LIGHT_GRAY] (sec) rules.buildcostmultiplier = Build Cost Multiplier rules.buildspeedmultiplier = Build Speed Multiplier -rules.waitForWaveToEnd = Waves wait for enemies +rules.waitForWaveToEnd = Vllny čekají na nepřátele rules.dropzoneradius = Drop Zone Radius:[LIGHT_GRAY] (tiles) rules.respawns = Max respawns per wave rules.limitedRespawns = Limit Respawns -rules.title.waves = Waves +rules.title.waves = Vlny rules.title.respawns = Respawns -rules.title.resourcesbuilding = Resources & Building -rules.title.player = Players -rules.title.enemy = Enemies -rules.title.unit = Units +rules.title.resourcesbuilding = surovyny & Stavby +rules.title.player = Hráči +rules.title.enemy = Nepřátelé +rules.title.unit = Jednotky content.item.name = Předměty content.liquid.name = Tekutiny content.unit.name = jednotky @@ -729,7 +728,7 @@ item.pyratite.name = Pyratite item.metaglass.name = Tvrzené sklo item.scrap.name = Scrap liquid.water.name = Voda -liquid.slag.name = Slag +liquid.slag.name = Rostavené železo liquid.oil.name = Ropa liquid.cryofluid.name = Cryofluid mech.alpha-mech.name = Alfa @@ -759,41 +758,41 @@ item.radioactivity = [LIGHT_GRAY]Radioaktivita: {0}% unit.health = [LIGHT_GRAY]Životy: {0} unit.speed = [LIGHT_GRAY]Rychlost: {0} mech.weapon = [LIGHT_GRAY]Zbraň: {0} -mech.health = [LIGHT_GRAY]Health: {0} +mech.health = [LIGHT_GRAY]Životy: {0} mech.itemcapacity = [LIGHT_GRAY]Kapacita předmětů: {0} mech.minespeed = [LIGHT_GRAY]Rychlost těžení: {0} mech.minepower = [LIGHT_GRAY]Síla těžení: {0} mech.ability = [LIGHT_GRAY]Schopnost: {0} -mech.buildspeed = [LIGHT_GRAY]Building Speed: {0}% +mech.buildspeed = [LIGHT_GRAY]Rychlost stavění: {0}% liquid.heatcapacity = [LIGHT_GRAY]Kapacita teploty: {0} liquid.viscosity = [LIGHT_GRAY]Viskozita: {0} liquid.temperature = [LIGHT_GRAY]Teplota: {0} block.sand-boulder.name = Sand Boulder -block.grass.name = Grass -block.salt.name = Salt -block.saltrocks.name = Salt Rocks +block.grass.name = Tráva +block.salt.name = sůl +block.saltrocks.name = Solný kámen block.pebbles.name = Pebbles block.tendrils.name = Tendrils -block.sandrocks.name = Sand Rocks +block.sandrocks.name = Písečný kámen block.spore-pine.name = Spore Pine block.sporerocks.name = Spore Rocks block.rock.name = Rock -block.snowrock.name = Snow Rock +block.snowrock.name = Sněhový kámen block.snow-pine.name = Snow Pine block.shale.name = Shale block.shale-boulder.name = Shale Boulder -block.moss.name = Moss +block.moss.name = Mech block.shrubs.name = Shrubs block.spore-moss.name = Spore Moss block.shalerocks.name = Shale Rocks -block.scrap-wall.name = Scrap Wall -block.scrap-wall-large.name = Large Scrap Wall -block.scrap-wall-huge.name = Huge Scrap Wall -block.scrap-wall-gigantic.name = Gigantic Scrap Wall +block.scrap-wall.name = Stará zeď +block.scrap-wall-large.name = Velá stará zeď +block.scrap-wall-huge.name = obří stará zeď +block.scrap-wall-gigantic.name = Gigantická stará zeď block.thruster.name = Thruster block.kiln.name = Kiln -block.graphite-press.name = Graphite Press -block.multi-press.name = Multi-Press +block.graphite-press.name = Graphitový lis +block.multi-press.name = Všětraný lys block.constructing = {0} [LIGHT_GRAY](Constructing) block.spawn.name = Nepřátelský Spawn block.core-shard.name = Core: Shard @@ -806,28 +805,28 @@ block.darksand-tainted-water.name = Dark Sand Tainted Water block.tar.name = Tar block.stone.name = Kámen block.sand.name = Písek -block.darksand.name = Dark Sand +block.darksand.name = Černý písek block.ice.name = Led block.snow.name = Sníh -block.craters.name = Craters -block.sand-water.name = Sand water -block.darksand-water.name = Dark Sand Water +block.craters.name = Krátery +block.sand-water.name = Písková voda +block.darksand-water.name = Černá písková voda block.char.name = Char block.holostone.name = Holo stone block.ice-snow.name = Ice Snow -block.rocks.name = Rocks -block.icerocks.name = Ice rocks -block.snowrocks.name = Snow Rocks +block.rocks.name = Kameny +block.icerocks.name = Ledové kameny +block.snowrocks.name = Sněhové kameny block.dunerocks.name = Dune Rocks block.pine.name = Pine block.white-tree-dead.name = White Tree Dead block.white-tree.name = White Tree block.spore-cluster.name = Spore Cluster -block.metal-floor.name = Metal Floor -block.metal-floor-2.name = Metal Floor 2 -block.metal-floor-3.name = Metal Floor 3 -block.metal-floor-5.name = Metal Floor 5 -block.metal-floor-damaged.name = Metal Floor Damaged +block.metal-floor.name = Železná podlaha +block.metal-floor-2.name = Železná Podlaha +block.metal-floor-3.name = železná Podlaha3 +block.metal-floor-5.name = Železná podlaha 5 +block.metal-floor-damaged.name = Rozbytáb block.dark-panel-1.name = Dark Panel 1 block.dark-panel-2.name = Dark Panel 2 block.dark-panel-3.name = Dark Panel 3 @@ -841,10 +840,10 @@ block.magmarock.name = Magma Rock block.cliffs.name = Cliffs block.copper-wall.name = Měděná zeď block.copper-wall-large.name = Velká měděná zeď -block.titanium-wall.name = Titanium Wall -block.titanium-wall-large.name = Large Titanium Wall -block.plastanium-wall.name = Plastanium Wall -block.plastanium-wall-large.name = Large Plastanium Wall +block.titanium-wall.name = Titanium Zeď +block.titanium-wall-large.name = Velká Titanium Zeď +block.plastanium-wall.name = Plastanium Zeď +block.plastanium-wall-large.name = Velká Plastanium Zeď block.phase-wall.name = Fázová stěna block.phase-wall-large.name = Velká fázová stěna block.thorium-wall.name = Thoriová stěna @@ -918,7 +917,7 @@ block.blast-mixer.name = Výbušninový mixér block.solar-panel.name = Solární panel block.solar-panel-large.name = Velký solární panel block.oil-extractor.name = Ropný Extraktor -block.command-center.name = Command Center +block.command-center.name = Řídící středisko block.draug-factory.name = Draug Miner Drone Factory block.spirit-factory.name = Továrna na Spirit Drony block.phantom-factory.name = Továrna na Fantom Drony @@ -960,7 +959,7 @@ block.container.name = Kontejnér block.launch-pad.name = Launch Pad block.launch-pad-large.name = Large Launch Pad team.blue.name = modrá -team.crux.name = red +team.crux.name = červená team.sharded.name = orange team.orange.name = oranžová team.derelict.name = derelict @@ -1004,13 +1003,13 @@ tutorial.waves.mobile = The[lightgray] enemy[] approaches.\n\nDefend the core fo tutorial.launch = Once you reach a specific wave, you are able to[accent] launch the core[], leaving your defenses behind and[accent] obtaining all the resources in your core.[]\nThese resources can then be used to research new technology.\n\n[accent]Press the launch button. item.copper.description = Užitečný strukturální materiál. Používá se rozsáhle v ostatních typech bloků. item.lead.description = Základní počáteční materiál. Požívá se rozsáhle v elektronice a v blocích pro transport tekutin. -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.metaglass.description = Vemi důležitá suočást všeho so se týká tekutin +item.graphite.description = Stlačený uhlík nedílná součást většiny infrastruktur item.sand.description = Běžný materiál rozšířeně používaný v spalování slitin. item.coal.description = Běžné a snadno dostupné palivo, pochází z Ostravy. item.titanium.description = Vzácný, velice lehký kov, používá se rozsáhle v trasportu tekutin, vrtech a letounech. item.thorium.description = Hustý, radioaktivní materiál, používá se jako strukturální podpora a jako nuklearní palivo. -item.scrap.description = Leftover remnants of old structures and units. Contains trace amounts of many different metals. +item.scrap.description = Staré železo které se dá přepracovat na grafit měď olovo titánium a písek item.silicon.description = Extrémně užitečný polovodič, aplikuje se v solárních panelech a v komplexní elektronice. item.plastanium.description = Lehký, kujný materiál, používá se v pokročilém letectví a jako fragmentační střelivo. item.phase-fabric.description = Skoro beztížná substance používaná v pokročilé elektronice a v sebeopravné technologii. @@ -1019,7 +1018,7 @@ item.spore-pod.description = Used for conversion into oil, explosives and fuel. item.blast-compound.description = Těkavá směs používaná v bombácha a výbušninách. Dá se spalovat ale jako palivo se nedoporučuje. item.pyratite.description = Extrémně vznětlivá substance, používá ve vznětovém střelivu. liquid.water.description = Nejčastěji se používá ke chlazení a zpracování odpadu. -liquid.slag.description = Various different types of molten metal mixed together. Can be separated into its constituent minerals, or sprayed at enemy units as a weapon. +liquid.slag.description = Rostavený scrap pou žívá se k vírobě olova mědi a grafitu. liquid.oil.description = Může být spálen, vybouchnout nebo použit jako chlazení. liquid.cryofluid.description = Nejefektivnější tekutina pro chlazení. mech.alpha-mech.description = Standartní mech. Má slušnou rychlost a poškození; Může vytvořit až 3 drony Pro zvýšenou ofenzivní způsobilost. diff --git a/core/assets/bundles/bundle_de.properties b/core/assets/bundles/bundle_de.properties index 4d21b8d8db..ac831aaa77 100644 --- a/core/assets/bundles/bundle_de.properties +++ b/core/assets/bundles/bundle_de.properties @@ -3,7 +3,7 @@ credits = Danksagungen contributors = Übersetzer und Mitwirkende discord = Trete dem Mindustry Discord bei! link.discord.description = Der offizielle Mindustry Discord-Chatroom -link.reddit.description = The Mindustry subreddit +link.reddit.description = Der Mindustry Subreddit link.github.description = Quellcode des Spiels link.changelog.description = Liste der Änderungen link.dev-builds.description = Entwicklungs-Builds (instabil) @@ -68,7 +68,7 @@ position = Position close = Schließen website = Website quit = Verlassen -save.quit = Save & Quit +save.quit = Speichern & Beenden maps = Karten maps.browse = Browse Maps continue = Weiter @@ -87,7 +87,7 @@ mods = Mods mods.none = [LIGHT_GRAY]No mods found! mods.guide = Modding Guide mods.report = Report Bug -mods.openfolder = Open Mod Folder +mods.openfolder = Mod Verzeichnis öffnen mod.enabled = [lightgray]Enabled mod.disabled = [scarlet]Disabled mod.disable = Disable @@ -97,8 +97,8 @@ mod.nowdisabled = [scarlet]Mod '{0}' is missing dependencies:[accent] {1}\n[ligh 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.import.github = Import GitHub Mod +mod.import = Mod importieren +mod.import.github = GitHub Mod importieren mod.remove.confirm = This mod will be deleted. 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} @@ -133,16 +133,16 @@ server.kicked.idInUse = Du bist bereits auf dem Server! Anmeldungen mit zwei Acc server.kicked.customClient = Der Server akzeptiert keine Custom Builds von Mindustry. Lade dir die offizielle Version herunter. server.kicked.gameover = Game Over! server.versions = Deine Version:[accent] {0}[]\nServerversion:[accent] {1}[] -host.info = Der [accent]host[]-Knopf startet einen Server auf den Ports [scarlet]6567[] und [scarlet]6568.[]\nJeder im gleichen [LIGHT_GRAY]W-Lan oder lokalem Netzwerk[] sollte deinen Server in seiner Server Liste sehen können.\n\nWenn du Leuten die Verbindung über IP ermöglichen willst, benötigst du [accent]Port-Forwarding[].\n\n[LIGHT_GRAY]Hinweis: Falls es Probleme mit der Verbindung im Netzwerk gibt, stell sicher, dass Mindustry in deinen Firewall Einstellungen Zugriff auf das lokale Netzwerk hat. -join.info = Hier kannst du eine [accent]Server-IP[] eingeben um dich zu verbinden oder Server im [accent]lokalem Netzwerk[] entdecken und dich mit ihnen verbinden.\nSowohl Spielen über das lokale Netzwerk als auch Spielen über das Internet werden unterstützt.\n\n[LIGHT_GRAY]Hinweis: Es gibt keine globale Server Liste; Wenn du dich mit jemand per IP verbinden willst musst du den Host nach seiner IP fragen. +host.info = Der [accent]Server hosten[]-Knopf startet einen Server auf den Ports [scarlet]6567[] und [scarlet]6568.[]\nJeder im gleichen [LIGHT_GRAY]W-Lan oder lokalen Netzwerk[] sollte deinen Server in seiner Server Liste sehen können.\n\nWenn du anderen die Verbindung über IP ermöglichen willst, benötigst du [accent]Port-Forwarding[].\n\n[LIGHT_GRAY]Hinweis: Falls es Probleme mit der Verbindung im Netzwerk gibt, stelle sicher, dass Mindustry in deinen Firewall Einstellungen Zugriff auf das lokale Netzwerk hat. +join.info = Hier kannst du eine [accent]Server-IP[] eingeben um dich zu verbinden oder Server im [accent]lokalen Netzwerk[] entdecken und dich mit ihnen verbinden.\nSowohl Spielen über das lokale Netzwerk als auch Spielen über das Internet werden unterstützt.\n\n[LIGHT_GRAY]Hinweis: Es gibt keine globale Server Liste; Wenn du dich mit jemandem per IP verbinden willst, musst du den Host nach seiner IP fragen. hostserver = Server hosten invitefriends = Invite Friends hostserver.mobile = Host\nSpiel -host = Host +host = Server hosten hosting = [accent] Server wird geöffnet ... hosts.refresh = Aktualisieren hosts.discovering = Suche nach LAN-Spielen -hosts.discovering.any = Discovering games +hosts.discovering.any = Suche nach Spielen server.refreshing = Server wird aktualisiert hosts.none = [lightgray] Keine LAN-Spiele gefunden! host.invalid = [scarlet] Kann keine Verbindung zum Host herstellen. @@ -225,15 +225,15 @@ cancel = Abbruch openlink = Link öffnen copylink = Kopiere Link back = Zurück -data.export = Export Data -data.import = Import Data +data.export = Daten exportieren +data.import = Daten importieren data.exported = Data exported. data.invalid = This isn't valid game data. data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. classic.export = Export Classic Data classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? quit.confirm = Willst du wirklich aufhören? -quit.confirm.tutorial = Are you sure you know what you're doing?\nThe tutorial can be re-taken in[accent] Settings->Game->Re-Take Tutorial.[] +quit.confirm.tutorial = Willst du das Tutorial wirklich abbrechen?\nDu kannst es unter[accent] Einstellungen->Spiel->Tutorial wiederholen[] erneut spielen. loading = [accent]Wird geladen... reloading = [accent]Reloading Mods... saving = [accent]Speichere... @@ -326,14 +326,14 @@ editor.saved = Gespeichert! editor.save.noname = Deine Karte hat keinen Namen! Setze einen Namen im [accent]Karten Info[] Menu. editor.save.overwrite = Deine Karte überschreibt eine built-in Karte! Wähle einen anderen Karten Namen im [accent]'Karten info'[] Menu. editor.import.exists = [scarlet]Fehler beim Import:[] Ein built-in Karte namens '{0}' existiert bereits! -editor.import = Import... +editor.import = Importieren... editor.importmap = Importiere Karte editor.importmap.description = Importiere von einer bestehenden Karte editor.importfile = Importiere Datei editor.importfile.description = Importiere aus einer Karten Datei editor.importimage = Importiere Terrain Bild editor.importimage.description = Importiere aus einer Terrain Bild Datei -editor.export = Export... +editor.export = Exportieren... editor.exportfile = Export in Datei editor.exportfile.description = Exportiere in eine Karten Datei editor.exportimage = Export in Terrain Bild Datei @@ -404,7 +404,7 @@ ping = Ping: {0}ms language.restart = Bitte Starte dein Spiel neu, damit die Sprach-Einstellung aktiv wird. settings = Einstellungen tutorial = Tutorial -tutorial.retake = Re-Take Tutorial +tutorial.retake = Tutorial wiederholen editor = Editor mapeditor = Karten Editor abandon = Aufgeben @@ -424,8 +424,8 @@ launch.confirm = Dies wird alle Ressourcen in deinen Kern übertragen.\nDu kanns launch.skip.confirm = If you skip now, you will not be able to launch until later waves. uncover = Freischalten configure = Startitems festlegen -bannedblocks = Banned Blocks -addall = Add All +bannedblocks = Gesperrte Blöcke +addall = Alle hinzufügen configure.locked = [LIGHT_GRAY]Erreiche Welle {0}\n, um Startitems festlegen zu können. configure.invalid = Amount must be a number between 0 and {0}. zone.unlocked = [LIGHT_GRAY]{0} freigeschaltet. @@ -476,26 +476,26 @@ zone.fungalPass.description = A transition area between high mountains and lower zone.impact0078.description = zone.crags.description = settings.language = Sprache -settings.data = Game Data +settings.data = Spieldaten settings.reset = Auf Standard zurücksetzen settings.rebind = Zuweisen settings.controls = Steuerung settings.game = Spiel settings.sound = Audio -settings.graphics = Grafiken +settings.graphics = Grafik settings.cleardata = Spieldaten zurücksetzen... settings.clear.confirm = Bist du sicher, dass du die Spieldaten zurücksetzen willst?\n Diese Aktion kann nicht rückgängig gemacht werden! settings.clearall.confirm = [scarlet]Warnung![]\nDas wird jegliche Spieldaten zurücksetzen inklusive Speicherstände, Karten, Freischaltungen und Tastenbelegungen.\n Nachdem du 'OK' drückst wird alles zurückgesetzt und das Spiel schließt sich automatisch. paused = Pausiert -clear = Clear +clear = Leeren banned = [scarlet]Banned yes = Ja no = Nein info.title = [accent]Info error.title = [crimson] Ein Fehler ist aufgetreten error.crashtitle = Ein Fehler ist aufgetreten! -blocks.input = Input -blocks.output = Output +blocks.input = Eingang +blocks.output = Ausgang blocks.booster = Verstärkung block.unknown = [LIGHT_GRAY]??? blocks.powercapacity = Kapazität @@ -524,12 +524,12 @@ blocks.boosteffect = Verstärkungseffekt blocks.maxunits = Max aktive Einheiten blocks.health = Lebenspunkte blocks.buildtime = Baudauer -blocks.buildcost = Build Cost +blocks.buildcost = Baukosten blocks.inaccuracy = Ungenauigkeit blocks.shots = Schüsse blocks.reload = Schüsse/Sekunde blocks.ammo = Munition -bar.drilltierreq = Better Drill Required +bar.drilltierreq = besserer Bohrer benötigt bar.drillspeed = Bohrgeschwindigkeit: {0}/s bar.pumpspeed = Pump Speed: {0}/s bar.efficiency = Effizienz: {0}% @@ -554,7 +554,7 @@ bullet.knockback = [stat]{0}[lightgray] zurückstoßend bullet.freezing = [stat]gefrierend bullet.tarred = [stat]geteert bullet.multiplier = [stat]{0}[lightgray]x Munition Multiplikator -bullet.reload = [stat]{0}[lightgray]x neu laden +bullet.reload = [stat]{0}[lightgray]x Feuerrate unit.blocks = Blöcke unit.powersecond = Stromeinheiten/Sekunde unit.liquidsecond = Flüssigkeitseinheiten/Sekunde @@ -599,25 +599,28 @@ setting.difficulty.insane = Unmöglich setting.difficulty.name = Schwierigkeit setting.screenshake.name = Bildschirmwackeln setting.effects.name = Effekte anzeigen -setting.destroyedblocks.name = Display Destroyed Blocks -setting.conveyorpathfinding.name = Conveyor Placement Pathfinding +setting.destroyedblocks.name = Zerstörte Blöcke anzeigen +setting.conveyorpathfinding.name = Automatische Wegfindung beim Bau von Förderbändern setting.sensitivity.name = Controller-Empfindlichkeit setting.saveinterval.name = Autosave Häufigkeit setting.seconds = {0} Sekunden +setting.blockselecttimeout.name = Block Auswahl Timeout +setting.milliseconds = {0} Millisekunden setting.fullscreen.name = Vollbild setting.borderlesswindow.name = Randloses Fenster[LIGHT_GRAY] (Neustart teilweise erforderlich) setting.fps.name = Zeige FPS +setting.blockselectkeys.name = Block Shortcuts anzeigen setting.vsync.name = VSync setting.pixelate.name = Verpixeln [LIGHT_GRAY](Könnte die Leistung beeinträchtigen) setting.minimap.name = Zeige die Minimap -setting.position.name = Show Player Position +setting.position.name = Spieler-Position anzeigen setting.musicvol.name = Musiklautstärke setting.ambientvol.name = Ambient Volume setting.mutemusic.name = Musik stummschalten setting.sfxvol.name = Audioeffekt-Lautstärke setting.mutesound.name = Audioeffekte stummschalten setting.crashreport.name = Anonyme Absturzberichte senden -setting.savecreate.name = Auto-Create Saves +setting.savecreate.name = Automatisch Speicherstände anlegen setting.publichost.name = Public Game Visibility setting.chatopacity.name = Chat Deckkraft setting.lasersopacity.name = Power Laser Opacity @@ -635,24 +638,40 @@ category.multiplayer.name = Mehrspieler command.attack = Angreifen command.rally = Rally command.retreat = Rückzug +placement.blockselectkeys = \n[lightgray]Shortcut: [{0}, keybind.clear_building.name = Clear Building keybind.press = Drücke eine Taste... keybind.press.axis = Drücke eine Taste oder bewege eine Achse... keybind.screenshot.name = Karten Screenshot keybind.move_x.name = X-Achse keybind.move_y.name = Y-Achse -keybind.schematic_select.name = Select Region +keybind.schematic_select.name = Bereich auswählen keybind.schematic_menu.name = Schematic Menu keybind.schematic_flip_x.name = Flip Schematic X keybind.schematic_flip_y.name = Flip Schematic Y -keybind.fullscreen.name = Toggle Fullscreen +keybind.category_prev.name = Vorige Kategorie +keybind.category_next.name = Nächste Kategorie +keybind.block_select_left.name = Block-Auswahl nach links +keybind.block_select_right.name = Block-Auswahl nach rechts +keybind.block_select_up.name = Block-Auswahl nach oben +keybind.block_select_down.name = Block-Auswahl nach unten +keybind.block_select_01.name = Kategorie/Block 1 auswählen +keybind.block_select_02.name = Kategorie/Block 2 auswählen +keybind.block_select_03.name = Kategorie/Block 3 auswählen +keybind.block_select_04.name = Kategorie/Block 4 auswählen +keybind.block_select_05.name = Kategorie/Block 5 auswählen +keybind.block_select_06.name = Kategorie/Block 6 auswählen +keybind.block_select_07.name = Kategorie/Block 7 auswählen +keybind.block_select_08.name = Kategorie/Block 8 auswählen +keybind.block_select_09.name = Kategorie/Block 9 auswählen +keybind.block_select_10.name = Kategorie/Block 10 auswählen +keybind.fullscreen.name = Vollbild umschalten keybind.select.name = Auswählen/Schießen keybind.diagonal_placement.name = Diagonal platzieren keybind.pick.name = Block Auswählen keybind.break_block.name = Block zerstören keybind.deselect.name = Auswahl aufheben keybind.shoot.name = Schießen -keybind.zoom_hold.name = Zoom halten keybind.zoom.name = Zoomen keybind.menu.name = Menü keybind.pause.name = Pause @@ -710,7 +729,7 @@ rules.title.unit = Einheiten content.item.name = Materialien content.liquid.name = Flüssigkeiten content.unit.name = Einheiten -content.block.name = Blocks +content.block.name = Blöcke content.mech.name = Mechs item.copper.name = Kupfer item.lead.name = Blei @@ -753,6 +772,7 @@ mech.trident-ship.name = Trident mech.trident-ship.weapon = Bombenschacht mech.glaive-ship.name = Glaive mech.glaive-ship.weapon = Flammen-Mehrlader +item.corestorable = [lightgray]Im Kern speicherbar: {0} item.explosiveness = [LIGHT_GRAY]Explosivität: {0} item.flammability = [LIGHT_GRAY]Entflammbarkeit: {0} item.radioactivity = [LIGHT_GRAY]Radioaktivität: {0} diff --git a/core/assets/bundles/bundle_es.properties b/core/assets/bundles/bundle_es.properties index 1901f2c3c1..38f9696ea3 100644 --- a/core/assets/bundles/bundle_es.properties +++ b/core/assets/bundles/bundle_es.properties @@ -652,7 +652,6 @@ keybind.pick.name = Pick Block keybind.break_block.name = Destruir Bloque keybind.deselect.name = Deseleccionar keybind.shoot.name = Disparar -keybind.zoom_hold.name = Mantener Zoom keybind.zoom.name = Zoom keybind.menu.name = Menú keybind.pause.name = Pausa diff --git a/core/assets/bundles/bundle_et.properties b/core/assets/bundles/bundle_et.properties index adbd5393be..c3e62686d2 100644 --- a/core/assets/bundles/bundle_et.properties +++ b/core/assets/bundles/bundle_et.properties @@ -652,7 +652,6 @@ keybind.pick.name = Vali blokk keybind.break_block.name = Hävita blokk keybind.deselect.name = Tühista valik keybind.shoot.name = Tulista -keybind.zoom_hold.name = Suumimise režiim keybind.zoom.name = Muuda suumi keybind.menu.name = Menüü keybind.pause.name = Paus diff --git a/core/assets/bundles/bundle_eu.properties b/core/assets/bundles/bundle_eu.properties index c86b1c28cd..66d71a0dce 100644 --- a/core/assets/bundles/bundle_eu.properties +++ b/core/assets/bundles/bundle_eu.properties @@ -652,7 +652,6 @@ keybind.pick.name = Jaso blokea keybind.break_block.name = Apurtu blokea keybind.deselect.name = Deshautatu keybind.shoot.name = Tirokatu -keybind.zoom_hold.name = Zoom mantenduz keybind.zoom.name = Zoom keybind.menu.name = Menua keybind.pause.name = Pausatu diff --git a/core/assets/bundles/bundle_fi.properties b/core/assets/bundles/bundle_fi.properties index b441ee0a62..be59e014aa 100644 --- a/core/assets/bundles/bundle_fi.properties +++ b/core/assets/bundles/bundle_fi.properties @@ -547,7 +547,6 @@ keybind.pick.name = Pick Block keybind.break_block.name = Break Block keybind.deselect.name = Deselect keybind.shoot.name = Shoot -keybind.zoom_hold.name = Zoom Hold keybind.zoom.name = Zoom keybind.menu.name = Menu keybind.pause.name = Pause diff --git a/core/assets/bundles/bundle_fr.properties b/core/assets/bundles/bundle_fr.properties index f4464dd977..c19a342364 100644 --- a/core/assets/bundles/bundle_fr.properties +++ b/core/assets/bundles/bundle_fr.properties @@ -99,6 +99,7 @@ mod.enabled = [lightgray]Activé mod.disabled = [scarlet]Désactivé mod.disable = Désactiver mod.delete.error = Unable to delete mod. File may be in use. +mod.requiresversion = [scarlet]Version du jeu requise : [accent]{0} mod.missingdependencies = [scarlet]Dépendances manquantes: {0} mod.nowdisabled = [scarlet]Le mod '{0}' a des dépendances manquantes:[accent] {1}\n[lightgray]Ces mods doivent d'abord être téléchargés.\nCe mod sera automatiquement désactivé. mod.enable = Activer @@ -496,6 +497,7 @@ settings.language = Langue settings.data = Données du Jeu settings.reset = Valeurs par Défaut settings.rebind = Réattribuer +settings.resetKey = Réinitialiser settings.controls = Contrôles settings.game = Jeu settings.sound = Son @@ -589,6 +591,8 @@ unit.persecond = /sec unit.timesspeed = x vitesse unit.percent = % unit.items = objets +unit.thousands = k +unit.millions = mil category.general = Général category.power = Énergie category.liquids = Liquides @@ -698,7 +702,6 @@ keybind.pick.name = Choisir un bloc keybind.break_block.name = Supprimer un bloc keybind.deselect.name = Désélectionner keybind.shoot.name = Tirer -keybind.zoom_hold.name = Maintenir pour zoomer keybind.zoom.name = Zoom keybind.menu.name = Menu keybind.pause.name = Pause @@ -1084,7 +1087,7 @@ mech.alpha-mech.description = Le mécha standard. Est basé sur une unité Poign mech.delta-mech.description = Un mécha rapide, avec une armure légère, conçu pour les attaques de frappe. Il inflige, par contre, peu de dégâts aux structures. Néanmoins il peut tuer de grand groupes d'ennemis très rapidement avec ses arcs électriques. mech.tau-mech.description = Un mécha de support. Soigne les blocs alliés en tirant dessus. Il peut aussi éteindre les feux et soigner ses alliés en zone avec sa compétence. mech.omega-mech.description = Un mécha cuirassé et large fait pour les assauts frontaux. Sa compétence lui permet de bloquer 90% des dégâts. -mech.dart-ship.description = Le vaisseau standard. Raisonnablement rapide et léger. Il a néanmoins peu d'attaque et une faible vitesse de minage. +mech.dart-ship.description = Le vaisseau standard. Il est raisonnablement rapide, léger et possède une vitesse de minage rapide. Néanmoins, ses capacités d'attaque sont faibles. mech.javelin-ship.description = Un vaisseau de frappe éclair qui, bien que lent au départ, peut accélérer pour atteindre de très grandes vitesses et voler jusqu'aux avant-postes ennemis, faisant d'énormes dégâts avec ses arc électriques obtenus à vitesse maximum et ses missiles. mech.trident-ship.description = Un bombardier lourd, conçu pour la construction et pour la destruction des fortifications ennemies. Assez bien blindé. mech.glaive-ship.description = Un grand vaisseau de combat cuirassé. Équipé avec un fusil automatique à munitions incendiaires. Est très maniable. diff --git a/core/assets/bundles/bundle_fr_BE.properties b/core/assets/bundles/bundle_fr_BE.properties index 52e9efb2c2..9510ce227d 100644 --- a/core/assets/bundles/bundle_fr_BE.properties +++ b/core/assets/bundles/bundle_fr_BE.properties @@ -652,7 +652,6 @@ keybind.pick.name = Choisir un bloc keybind.break_block.name = Supprimer un bloc keybind.deselect.name = Déselectionner keybind.shoot.name = Tirer -keybind.zoom_hold.name = Tenir le zoom keybind.zoom.name = Zoom keybind.menu.name = Menu keybind.pause.name = Pause diff --git a/core/assets/bundles/bundle_in_ID.properties b/core/assets/bundles/bundle_in_ID.properties index 1f253e9698..73fff980c3 100644 --- a/core/assets/bundles/bundle_in_ID.properties +++ b/core/assets/bundles/bundle_in_ID.properties @@ -652,7 +652,6 @@ keybind.pick.name = Memilih Blok keybind.break_block.name = Menghancurkan Blok keybind.deselect.name = Batal Memilih keybind.shoot.name = Menembak -keybind.zoom_hold.name = Tahan Mode Zoom keybind.zoom.name = Zoom keybind.menu.name = Menu keybind.pause.name = Jeda diff --git a/core/assets/bundles/bundle_it.properties b/core/assets/bundles/bundle_it.properties index d1f19ae8b1..75351ad9a8 100644 --- a/core/assets/bundles/bundle_it.properties +++ b/core/assets/bundles/bundle_it.properties @@ -1,45 +1,50 @@ credits.text = Creato da [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[] credits = Crediti contributors = Traduttori e Contributori -discord = Entra nel server discord di mindustry! -link.discord.description = la chatroom ufficiale del server discord di Mindustry +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.github.description = Codice sorgente del gioco link.changelog.description = Elenco delle modifiche del gioco link.dev-builds.description = Build di sviluppo versioni instabili link.trello.description = Scheda ufficiale trello per funzionalità pianificate -link.itch.io.description = pagina di itch.io con download per PC e versione web +link.itch.io.description = Pagina di itch.io con download per PC e versione web link.google-play.description = Elenco di Google Play Store -link.wiki.description = wiki ufficiale di Mindustry +link.f-droid.description = Catalogo F-Droid +link.wiki.description = Wiki ufficiale di Mindustry linkfail = Impossibile aprire il link! L'URL è stato copiato. screenshot = Screenshot salvato a {0} screenshot.invalid = Mappa troppo grossa, probabilmente non c'è abbastanza memoria libera. -gameover = Il nucleo è stato distrutto. +gameover = Il Nucleo è stato distrutto. gameover.pvp = La squadra [accent] {0}[] ha vinto! highscore = [YELLOW]Nuovo record! + copied = Copiato. load.sound = Suoni load.map = Mappe load.image = Immagini -load.content = Content +load.content = Contenuti load.system = Sistema load.mod = Mods -schematic = Schematiche -schematic.add = Salva Schema... -schematics = Schemi -schematic.replace = A schematic by that name already exists. Replace it? -schematic.import = Importa schema... +load.scripts = Testi + +schematic = Schematica +schematic.add = Salva Schematica... +schematics = Schematiche +schematic.replace = Una schematica con questo nome esiste già. Sostituirla? +schematic.import = Importa schematica... schematic.exportfile = Esporta file schematic.importfile = Importa File schematic.browseworkshop = Naviga sul Workshop -schematic.copy = copia negli appunti +schematic.copy = Copia negli appunti schematic.copy.import = Importa dagli appunti schematic.shareworkshop = Condividi sul Workshop -schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Flip Schematic -schematic.saved = Schema salvato. -schematic.delete.confirm = Questo schema sarà cancellato definitivamente. -schematic.rename = Rinomina schema -schematic.info = {0}x{1}, {2} blocks +schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Ruota Schematica +schematic.saved = Schematica salvata. +schematic.delete.confirm = Questa schematica sarà cancellata definitivamente. +schematic.rename = Rinomina schematica +schematic.info = {0}x{1}, {2} blocchi + stat.wave = Ondate sconfitte:[accent] {0} stat.enemiesDestroyed = Nemici distrutti:[accent] {0} stat.built = Costruzioni erette:[accent] {0} @@ -47,30 +52,31 @@ stat.destroyed = Costruzioni distrutte:[accent] {0} stat.deconstructed = Costruzioni smantellate:[accent] {0} stat.delivered = Riorse lanciate: stat.rank = Livello finale: [accent]{0} -launcheditems = [accent]Oggetti lanciati -launchinfo = [unlaunched][[LAUNCH] il tuo core per ottenere gli oggetti indicati in blu. -map.delete = Sei sicuro di voler eliminare questa mappa"[accent]{0}[]"? -level.highscore = Miglior punteggio: [accent]{0} -level.select = Selezione del livello -level.mode = Modalità di gioco: -showagain = non mostrare più -coreattack = < Il nucleo è sotto attacco! > + +launcheditems = [accent]Oggetti Lanciati +launchinfo = [unlaunched][[LAUNCH] il tuo Nucleo per ottenere gli oggetti indicati in blu. +map.delete = Sei sicuro di voler eliminare la mappa"[accent]{0}[]"? +level.highscore = Miglior Punteggio: [accent]{0} +level.select = Selezione del Livello +level.mode = Modalità di Gioco: +showagain = Non mostrare più +coreattack = < Il Nucleo è sotto attacco! > nearpoint = [[ [scarlet]LASCIA LA ZONA NEMICA IMMEDIATAMENTE[] ]\nautodistruzione imminente -database = Database nucleo +database = Database Nucleo savegame = Salva loadgame = Carica -joingame = Unisciti al gioco -customgame = Gioco personalizzato +joingame = Unisciti al Gioco +customgame = Gioco Personalizzato newgame = Nuova partita -none = +none = minimap = Minimappa -position = Position +position = Posizione close = Chiuso website = Sito web quit = Esci save.quit = Salva ed esci maps = Mappe -maps.browse = Consulta Mappe +maps.browse = Esplora Mappe continue = Continua maps.none = [LIGHT_GRAY]Nessuna mappa trovata! invalid = Non valido @@ -80,66 +86,69 @@ uploadingcontent = Carico il contenuto uploadingpreviewfile = Carico file di anteprima committingchanges = Applico le modifiche done = Fatto -feature.unsupported = Your device does not support this feature. -mods.alphainfo = Tieni a mente che queste mod sono in alpha, e[scarlet] possono avere molti bug[].\nRiporta tutti i problemi che trovi in Mindustry su GitHub o Discord. +feature.unsupported = Il tuo dispositivo non supporta questa funzione. + +mods.alphainfo = Tieni a mente che queste Mod sono in alpha, e[scarlet] possono contenere molti bug[].\Segnala tutti i problemi che trovi su GitHub o Discord di Mindustry. mods.alpha = [accent](Alpha) mods = Mods -mods.none = [LIGHT_GRAY]Nessuna mod trovata! -mods.guide = guida per il modding! -mods.report = Riporta un bug -mods.openfolder = Open Mod Folder +mods.none = [LIGHT_GRAY]Nessuna Mod trovata! +mods.guide = Guida per il modding! +mods.report = Segnala un Bug +mods.openfolder = Apri Cartella Mod mod.enabled = [lightgray]Abilitato mod.disabled = [scarlet]Disabilitato mod.disable = Disabilita -mod.delete.error = Unable to delete mod. File may be in use. -mod.missingdependencies = [scarlet]Missing dependencies: {0} -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.delete.error = Impossibile eliminare questa Mod. Il file potrebbe essere in uso. +mod.missingdependencies = [scarlet]Dipendenze mancanti: {0} +mod.nowdisabled = [scarlet]Alla Mod '{0}' mancano delle dipendenze:[accent] {1}\n[lightgray]Queste Mod devono essere scaricate prima.\nQuesta Mod verrà disabilitata automaticamente. mod.enable = Abilita -mod.requiresrestart = . +mod.requiresrestart = Il gioco verrà chiuso per applicare i cambiamenti. mod.reloadrequired = [scarlet]Riavvio necessario -mod.import = Importa una mod -mod.import.github = Import GitHub Mod -mod.remove.confirm = Questa mod verrà cancellata. -mod.author = [LIGHT_GRAY]Author:[] {0} -mod.missing = Questo salvataggio contiene mod che hai recentemente aggiornato o non le hai piu installate. Il salvataggio può essere corrotto. sei sicuro di volerlo caricare?\n[lightgray]Mods:\n{0} -mod.preview.missing = Prima di pubblicare questa mod nel workshop, devi aggiungere un immagine di copertina.\nmetti un immagine[accent] preview.png[] nella cartella della mod e riprova . -mod.folder.missing = Solo mod in una cartella possono essere pubblicate nel workshop.\nPer pubblicare una mod, bisogna decompressare il file in una cartella e eliminare il file zip, dopo riavvia il gioco e ricarica la mod +mod.import = Importa una Mod +mod.import.github = Importa una Mod da GitHub +mod.item.remove = Questo item fa parte della Mod[accent] '{0}'[]. Per rimuoverlo, disinstalla questa Mod. +mod.remove.confirm = Questa Mod verrà eliminata. +mod.author = [LIGHT_GRAY]Autore:[] {0} +mod.missing = Questo salvataggio contiene Mod che hai recentemente aggiornato o non hai più installate. Il salvataggio potrebbe corrompersi. Sei sicuro di volerlo caricare?\n[lightgray]Mods:\n{0} +mod.preview.missing = Prima di pubblicare questa Mod nel Workshop, devi aggiungere un immagine di copertina.\nMetti un immagine[accent] con nome preview.png[] nella cartella della Mod e riprova. +mod.folder.missing = Solo le Mod in una cartella possono essere pubblicate nel Workshop.\nPer convertire una Mod in una cartella, decomprimi i suoi file in una cartella ed elimina il vecchio zip, quindi riavvia il gioco o ricarica le tue mods. + about.button = Info name = Nome: -noname = Scegli un [accent] nome[] prima di unirti. +noname = Scegli un[accent] nome[] prima di unirti. filename = Nome file: unlocked = Nuovo blocco scoperto! -completed = [accent]Completo +completed = [accent]Completato techtree = Albero scoperta research.list = [LIGHT_GRAY]Ricerca: research = Ricerca researched = [LIGHT_GRAY]{0} cercati. players = {0} giocatori online players.single = {0} giocatori online -server.closing = [accent]Chiusura server ... +server.closing = [accent]Chiusura server... server.kicked.kick = Sei stato cacciato dal server! -server.kicked.whitelist = Non sei presente in questa whitelist. +server.kicked.whitelist = Non sei presente nella whitelist. server.kicked.serverClose = Server chiuso. -server.kicked.vote = Sei stato cacciato su richiesta dei giocatori. Buona giornata. +server.kicked.vote = Sei stato cacciato su richiesta dei giocatori. Addio. server.kicked.clientOutdated = Versione del client obsoleta! Aggiorna il tuo gioco! server.kicked.serverOutdated = Server obsoleto! Chiedi all'host di aggiornare la versione del server! -server.kicked.banned = Sei bandito da questo server. -server.kicked.typeMismatch = Questo server non è compatibile con la tua build. +server.kicked.banned = Sei stato bandito da questo server. +server.kicked.typeMismatch = Questo server non è compatibile con il tuo client. server.kicked.playerLimit = Questo server è pieno. Attendi che si liberi un posto. server.kicked.recentKick = Sei stato cacciato di recente.\nAspetta prima di riconnetterti. server.kicked.nameInUse = C'è già qualcuno con il tuo nome su questo server. server.kicked.nameEmpty = Il tuo nome deve contenere almeno un carattere. server.kicked.idInUse = Sei già su questo server! Non è permesso connettersi con due account. -server.kicked.customClient = Questo server non supporta le build personalizzate. Scarica la versione ufficiale dal sito. +server.kicked.customClient = Questo server non supporta i client personalizzati. Scarica la versione ufficiale dal sito. server.kicked.gameover = Game over! -server.versions = Your version:[accent] {0}[]\nServer version:[accent] {1}[] -host.info = Il pulsante [accent]host [] ospita un server sulla porta [scarlet]6567[].[] Chiunque sulla stessa [LIGHT_GRAY]connessione wifi o rete locale[] dovrebbe essere in grado di vedere il server nell'elenco server.\n\n Se vuoi che le persone siano in grado di connettersi ovunque tramite IP, è richiesto il [accent]port forwarding[]. \n\n[LIGHT_GRAY]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 un [accent]IP del server[] a cui connettersi, o scoprire [accent]un server sulla rete locale[] disponibile.\n Sono supportati sia il multiplayer LAN che WAN. \n\n[LIGHT_GRAY]Nota: non esiste un elenco di server globali automatici; se si desidera connettersi a qualcuno tramite IP, è necessario chiedere all'host il proprio IP. +server.versions = Your version:[accent] {0}[]\nVersione server:[accent] {1}[] +host.info = Il pulsante [accent]host [] ospita un server sulla porta [scarlet]6567[].[] Chiunque sulla stessa [LIGHT_GRAY]rete wifi o locale[] dovrebbe essere in grado di vedere il server nell'elenco server.\n\n Se vuoi che le persone siano in grado di connettersi ovunque tramite il tuo IP, è richiesto il [accent]port forwarding[]. \n\n[LIGHT_GRAY]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[LIGHT_GRAY]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 hostserver.mobile = Ospita\nServer host = Host -hosting = [accent] Apertura del server ... +hosting = [accent] Apertura del server... hosts.refresh = Aggiorna hosts.discovering = Ricerca partite LAN hosts.discovering.any = Ricerca partite @@ -152,7 +161,7 @@ trace.ip = IP: [accent]{0} trace.id = ID univoco: [accent]{0} trace.mobile = Mobile Client: [accent]{0} trace.modclient = Client personalizzato: [accent]{0} -invalidid = ID client non valido! Invia una segnalazione di bug. +invalidid = ID client non valido! Segnala un bug. server.bans = Lista Ban server.bans.none = Nessun giocatore bandito trovato! Finora tutto liscio. server.admins = Amministratori @@ -173,51 +182,51 @@ confirmunadmin = Sei sicuro di voler rimuovere lo stato di amministratore da que joingame.title = Unisciti alla Partita joingame.ip = IP: disconnect = Disconnesso. -disconnect.error = Connection error. -disconnect.closed = Connection closed. +disconnect.error = Errore di connessione. +disconnect.closed = Connessione chiusa. disconnect.timeout = Timed out. -disconnect.data = errore nel caricamento del mondo, mi dispiace! +disconnect.data = Errore durante il caricamento del mondo! cantconnect = Impossibile unirsi al server ([accent]{0}[]). -connecting = [accent]Connessione in corso ... -connecting.data = [accent]Caricamento dei dati del mondo ... +connecting = [accent]Connessione in corso... +connecting.data = [accent]Caricamento del mondo... server.port = Porta: server.addressinuse = Indirizzo già in uso! -server.invalidport = Numero di porta non valido! +server.invalidport = Numero porta non valido! server.error = [crimson]Errore nell'hosting del server: [accent] {0} save.new = Nuovo Salvataggio save.overwrite = Sei sicuro di voler sovrascrivere questo salvataggio? overwrite = Sovrascrivi save.none = Nessun salvataggio trovato! -saveload = [accent]Salvataggio ... -savefail = [crimson]Salvataggio del gioco NON riuscito! +saveload = [accent]Salvataggio in corso... +savefail = [crimson]Salvataggio del gioco non riuscito! save.delete.confirm = Sei sicuro di voler eliminare questo salvataggio? save.delete = Elimina save.export = Esporta Salvataggio save.import.invalid = [accent]Questo salvataggio non è valido! -save.import.fail = [crimson]Impossibile importare salvataggio: [accent]{0} +save.import.fail = [crimson]Impossibile importare il salvataggio: [accent]{0} save.export.fail = [crimson]Impossibile esportare il salvataggio: [accent]{0} save.import = Importa Salvataggio -save.newslot = Salva nome: +save.newslot = Nome: save.rename = Rinomina save.rename.text = Nuovo nome: selectslot = Seleziona un salvataggio. slot = [accent]Slot {0} -editmessage = Modifica messaggio +editmessage = Modifica Messaggio save.corrupted = [orang]Salvataggio corrotto o non valido! -empty = +empty = on = On off = Off -save.autosave = Salvataggio automatico: {0} +save.autosave = Salvataggio Automatico: {0} save.map = Mappa: {0} save.wave = Ondata: {0} save.mode = Gamemode: {0} -save.date = Ultimo salvataggio: {0} -save.playtime = Tempo di gioco: {0} +save.date = Ultimo Salvataggio: {0} +save.playtime = Tempo di Gioco: {0} warning = Attenzione confirm = Conferma delete = Elimina view.workshop = Vedi nel Workshop -workshop.listing = Edit Workshop Listing +workshop.listing = Modifica l'elenco del Workshop ok = OK open = Apri customize = Personalizza @@ -229,14 +238,14 @@ data.export = Esporta Salvataggio data.import = Importa Salvataggio data.exported = Dati esportati. data.invalid = Questi non sono dati di gioco validi. -data.import.confirm = Importare dati di gioco esterni eliminerà[scarlet] tutti[] i tuoi progressi attuali.\n[accent]L'operazione è irreversibile![]\n\nUna volta importati i dati, il gioco si chiuderà immediatamente. -classic.export = Esporta dati classici -classic.export.text = [accent]Mindustry[] ha appena rilasciato un aggiornamento importante.\nSalvataggio Classic (v3.5 build 40) o dati delle mappe è stato ritrovato. Vorresti esportare questi salvatagggi sul tuo telefono per usarli nella Mindustry Classic app? +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. +classic.export = Esporta Dati Classici +classic.export.text = [accent]Mindustry[] ha appena rilasciato un aggiornamento importante.\nSalvataggio Classic (v3.5 build 40) o dati delle mappe è stato ritrovato. Vuoi esportare questi salvatagggi sul tuo telefono per usarli nella Mindustry Classic app? quit.confirm = Sei sicuro di voler uscire? -quit.confirm.tutorial = Sei sicuro di sapere cosa stai facendo? Il tutorial può essere ripetuto in[accent] Gioca > Tutorial.[] -loading = [accent]Caricamento in corso ... -reloading = [accent]Reloading Mods... -saving = [accent]Salvando ... +quit.confirm.tutorial = Sei sicuro di sapere cosa stai facendo? Il tutorial può essere ripetuto in[accent]\nImpostazioni -> Gioco -> Ripeti il Tutorial.[] +loading = [accent]Caricamento in Corso... +reloading = [accent]Ricaricamento delle mods... +saving = [accent]Salvataggio in corso... cancelbuilding = [accent][[{0}][] to clear plan selectschematic = [accent][[{0}][] to select+copy pausebuilding = [accent][[{0}][] to pause building @@ -245,7 +254,7 @@ wave = [accent]Ondata {0} wave.waiting = [LIGHT_GRAY]Ondata tra {0} wave.waveInProgress = [LIGHT_GRAY]Ondata in corso... waiting = In attesa... -waiting.players = Aspettando giocatori... +waiting.players = Attendendo giocatori... wave.enemies = [LIGHT_GRAY]{0} Nemici Rimasti wave.enemy = [LIGHT_GRAY]{0} Nemico Rimasto loadimage = Carica immagine @@ -255,19 +264,19 @@ 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.pvp = Questa mappa non ha un nucleo nemico! Aggiungi un [SCARLET]nucleo rosso[] nell'editor per poter giocare. -map.nospawn.attack = Questa mappa non ha un nucleo nemico! Aggiungi un [SCARLET]nucleo rosso[] nell'editor per poter giocare. +map.nospawn = Questa mappa non possiede un Nucleo in cui spawnare! Aggiungine uno nell'editor. +map.nospawn.pvp = Questa mappa non ha un Nucleo nemico! Aggiungi un [SCARLET]Nucleo rosso[] nell'editor per poter giocare. +map.nospawn.attack = Questa mappa non ha un Nucleo nemico! Aggiungi un [SCARLET]Nucleo rosso[] nell'editor per poter giocare. map.invalid = Errore nel caricamento della mappa: file mappa corrotto o non valido. -workshop.update = Update Item -workshop.error = Error fetching workshop details: {0} +workshop.update = Aggiorna elemento +workshop.error = Errore nel recupero dei dettagli del Workshop: {0} map.publish.confirm = Vuoi pubblicare questa mappa?\n\n[lightgray]Assicurati di aver accettato il Workshop EULA, o le tue mappe non saranno visibili! -workshop.menu = Select what you would like to do with this item. -workshop.info = Item Info -changelog = Changelog (optional): +workshop.menu = Seleziona cosa vorresti fare con questo elemento. +workshop.info = Info elemento +changelog = Changelog (opzionale): eula = Steam EULA -missing = This item has been deleted or moved.\n[lightgray]The workshop listing has now been automatically un-linked. -publishing = [accent]Publishing... +missing = This item has been deleted or moved.\n[lightgray]The Workshop listing has now been automatically un-linked. +publishing = [accent]Pubblicazione... publish.confirm = Are you sure you want to publish this?\n\n[lightgray]Make sure you agree to the Workshop EULA first, or your items will not show up! publish.error = Error publishing item: {0} steam.error = Failed to initialize Steam services.\nError: {0} @@ -288,7 +297,7 @@ editor.newmap = Nuova mappa workshop = Workshop waves.title = Ondate waves.remove = Rimuovi -waves.never = mai +waves.never = waves.every = sempre waves.waves = ondata/e waves.perspawn = per spawn @@ -297,7 +306,7 @@ waves.boss = Boss waves.preview = Anteprima waves.edit = Modifica... waves.copy = Copia negli appunti -waves.load = Caica dagli appunti +waves.load = Carica dagli appunti waves.invalid = Onde dagli appunti non valide. waves.copied = Onde copiate. waves.none = Nessun nemico definiti.\n Nota che le disposizioni di ondate vuote verranno automaticamente rimpiazzate con la disposizione predefinita. @@ -310,7 +319,7 @@ editor.removeunit = Rimuovi un'unità editor.teams = Squadre editor.errorload = Errore nel caricamento di:\n[accent]{0} editor.errorsave = Errore nel salvataggio di:\n[accent]{0} -editor.errorimage = Quella è un'immagine, non una mappa. Non cambiare estensioni sperando che funzioni.\n\n Se vuoi importare una mappa vecchia clicca su "importa una mappa vecchia" nell'editor. +editor.errorimage = Quella è un'immagine, non una mappa.\n\nSe vuoi importare una mappa vecchia clicca su "Importa una mappa vecchia" nell'editor. editor.errorlegacy = La mappa è troppo vecchia ed usa un formato che non è più supportato. editor.errornot = Questo file non è una mappa. editor.errorheader = Questo file della mappa è invalido o corrotto. @@ -339,7 +348,7 @@ editor.exportfile.description = Esporta file mappa editor.exportimage = Esporta immagine editor.exportimage.description = Esporta file immagine mappa editor.loadimage = Carica\nimmagine -editor.saveimage = Salva\nImmagine +editor.saveimage = Salva\nimmagine editor.unsaved = [scarlet]Alcune modifiche non sono state salvate![]\nSei sicuro di voler uscire? editor.resizemap = Ridimensiona la mappa editor.mapname = Nome Mappa: @@ -347,9 +356,10 @@ editor.overwrite = [accent]Attenzione!\nQuesto sovrascrive una mappa esistente. editor.overwrite.confirm = [scarlet]Attenzione![] Una mappa con questo nome esiste già. Sei sicuro di volerla sovrascrivere? editor.exists = Esiste già una mappa con questo nome. editor.selectmap = Seleziona una mappa da caricare: -toolmode.replace = Rimpiazzare + +toolmode.replace = Sostituire toolmode.replace.description = Disegna solo su blocchi solidi. -toolmode.replaceall = Rimpiazzare tutto +toolmode.replaceall = Sostituisci tutto toolmode.replaceall.description = Rimpiazza tutti i blocchi nella mappa toolmode.orthogonal = Ortogonale toolmode.orthogonal.description = Disegna solo linee ortogonali @@ -357,10 +367,11 @@ toolmode.square = Quadrato toolmode.square.description = Pennello quadrato toolmode.eraseores = Rimuovi Minerali toolmode.eraseores.description = Rimuove solo minerali -toolmode.fillteams = Riempi squadre +toolmode.fillteams = Riempi Squadre toolmode.fillteams.description = Riempe squadre al posto di blocchi -toolmode.drawteams = Disegna squadre +toolmode.drawteams = Disegna Squadre toolmode.drawteams.description = Disegna squadre al posto di blocchi + filters.empty = [LIGHT_GRAY]Nessun filtro! Aggiungine uno cliccando il tasto sotto. filter.distort = Modifica filter.noise = Interferenza @@ -391,7 +402,8 @@ filter.option.ore = Minerale filter.option.floor2 = Pavimento secondario filter.option.threshold2 = Soglia secondaria filter.option.radius = Raggio -filter.option.percentile = percentuale +filter.option.percentile = Percentuale + width = Larghezza: height = Altezza: menu = Menu @@ -404,41 +416,43 @@ ping = Ping: {0}ms language.restart = Riavvia il gioco affinché il cambiamento della lingua abbia effetto. settings = Impostazioni tutorial = Tutorial -tutorial.retake = Ripeti il tutorial +tutorial.retake = Ripeti il Tutorial editor = Editor mapeditor = Editor Mappe + abandon = Abbandona abandon.text = Questa zona e tutte le tue risorse saranno perdute e passeranno al nemico. locked = Bloccato complete = [LIGHT_GRAY]Completato: -requirement.wave = Reach Wave {0} in {1} -requirement.core = Destroy Enemy Core in {0} -requirement.unlock = Unlock {0} -resume = Riprendi zona:\n[LIGHT_GRAY]{0} -bestwave = [LIGHT_GRAY]Migliore: {0} -launch = Decollare +requirement.wave = Raggiungi onda {0} in {1} +requirement.core = Distruggi il Nucleo nemico in {0} +requirement.unlock = Sblocca {0} +resume = Riprendi Zona:\n[LIGHT_GRAY]{0} +bestwave = [LIGHT_GRAY]Ondata migliore: {0} +launch = < DECOLLARE > launch.title = Decollo riuscito! -launch.next = [LIGHT_GRAY]Nuova opportunità all'ondata {0} +launch.next = [LIGHT_GRAY]nuova opportunità all'ondata {0} launch.unable2 = [scarlet]IMPOSSIBILE DECOLLARE![] -launch.confirm = Questo trasporterà tutte le risorse nel tuo nucleo.\nNon riuscirai a ritornare in questa base. +launch.confirm = Questo trasporterà tutte le risorse nel tuo Nucleo.\nNon riuscirai a ritornare in questa base. launch.skip.confirm = Se salti adesso non riuscirai a decollare fino alle ondate successive -uncover = Svelare +uncover = Scopri configure = Configura l'equipaggiamento -bannedblocks = Banned Blocks -addall = Add All +bannedblocks = Blocchi banditi +addall = Aggiungi tutti configure.locked = [LIGHT_GRAY]Arriva all'ondata {0}\nper configurare l'equipaggiamento. configure.invalid = Il valore dev'essere un numero compresto tra 0 e {0}. zone.unlocked = [LIGHT_GRAY]{0} sbloccata. zone.requirement.complete = Ondata {0} raggiunta:\n{1} requisiti di zona soddisfatti. -zone.config.unlocked = Loadout unlocked:[lightgray]\n{0} -zone.resources = Risorse trovate: +zone.config.unlocked = Equipaggiamento sbloccato:[lightgray]\n{0} +zone.resources = Risorse Trovate: zone.objective = [lightgray]Obiettivo: [accent]{0} zone.objective.survival = Sopravvivere -zone.objective.attack = Distruggere il nucleo nemico +zone.objective.attack = Distruggere il Nucleo Nemico add = Aggiungi... boss.health = Vita del Boss + connectfail = [crimson] Impossibile connettersi al server: [accent] {0} -error.unreachable = Server irraggiungibile +error.unreachable = Server irraggiungibile. L'indirizzo è scritto correttamente? error.invalidaddress = Indirizzo invalido. error.timedout = Timeout!\n Assicurati che l'host abbia il port forwarding impostato e che l'indirizzo sia corretto! error.mismatch = Errore pacchetti:\nPossibile discordanza della versione client / server.\n Assicurati che tu e l'host possiediate l'ultima versione di Mindustry! @@ -447,6 +461,7 @@ error.mapnotfound = Mappa non trovata error.io = Errore I/O di rete. error.any = Errore di rete sconosciuto. error.bloom = Errore dell'avvio del bloom.\nIl tuo dispositivo potrebbe non supportarlo. + zone.groundZero.name = Terreno Zero zone.desertWastes.name = Rifiuti Desertici zone.craters.name = Crateri @@ -461,10 +476,11 @@ zone.saltFlats.name = Saline zone.impact0078.name = Impatto 0078 zone.crags.name = Dirupi zone.fungalPass.name = Passaggio Fungoso + zone.groundZero.description = La posizione ottimale per cominciare. Bassa minaccia nemica. Poche risorse.\nRaccogli quanto più piombo e rame possibile.\nProcedi. zone.frozenForest.description = Anche qui, più vicino alle montagne, le spore si sono diffuse. Le temperature rigide non possono contenerle per sempre.\n Inizia la scoperta dell'energia. Costruisci generatori a combustione. Impara a usare i riparatori. zone.desertWastes.description = Questi rifiuti sono vasti, imprevedibili ed attraversati da strutture settoriali abbandonate.\n\nIl carbone è presente nella regione. Bruciatelo per ottenere energia o sintetizzate la grafite.\n\n[lightgray]Questa posizione di atterraggio non può essere garantita. -zone.saltFlats.description = Alle periferie del deserto si trovano le saline. Poche risorse possono essere trovate in questa posizione.\n\nIl nemico ha eretto un complesso di archiviazione delle risorse qui. Sradicare il loro nucleo. Non lasciare nulla in piedi. +zone.saltFlats.description = Alle periferie del deserto si trovano le saline. Poche risorse possono essere trovate in questa posizione.\n\nIl nemico ha eretto un complesso di archiviazione delle risorse qui. Sradicare il loro Nucleo. Non lasciare nulla in piedi. zone.craters.description = L'acqua si è accumulata in questo cratere, reliquia delle vecchie guerre. Recupera l'area. Raccogli la sabbia. Fondi il vetro metallico. Pompa l'acqua per raffreddare torrette e trivelle. zone.ruinousShores.description = Oltre i rifiuti, c'è il litorale. Una volta, questa posizione ospitava una schiera di difesa costiera. Non rimane molto. Solo le strutture di difesa più elementari sono rimaste incolume, tutto il resto ridotto a rottami.\nContinua l'espansione verso l'esterno. Riscopri la tecnologia. zone.stainedMountains.description = Più nell'entroterra si trovano le montagne, non ancora contaminate da spore.\nEstrai l'abbondante titanio in questa zona. Scopri come usarlo.\n\nLa presenza del nemico è maggiore qui. Non dare loro il tempo di inviare le loro unità più forti. @@ -475,23 +491,24 @@ zone.nuclearComplex.description = Un ex impianto per la produzione e la lavorazi zone.fungalPass.description = Un'area di transizione tra alte montagne e terre più basse, piene di spore. Qui si trova una piccola base di ricognizione nemica.\nDistruggila.\nUsa le unità Pugnale e Strisciatore. Elimina i due nuclei. zone.impact0078.description = zone.crags.description = + settings.language = Lingua settings.data = Importa/Esporta salvataggio -settings.reset = Resetta Alle Impostazioni Predefinite +settings.reset = Ripristina Impostazioni settings.rebind = Modifica settings.controls = Controlli settings.game = Gioco settings.sound = Suoni settings.graphics = Grafica -settings.cleardata = Cancella dati di gioco... -settings.clear.confirm = Sei sicuro di voler cancellare i dati?\nNon può essere annullato! -settings.clearall.confirm = [scarlet]ATTENZIONE![]\nQuesto cancellerà tutti i dati, includendo salvataggi, mappe, oggetti sbloccati, impostazioni.\nDopo aver premuto su 'ok' il gioco eliminerà i dati e si chiuderà. -paused = In pausa -clear = Clear -banned = [scarlet]Banned +settings.cleardata = Elimina Dati di Gioco... +settings.clear.confirm = Sei sicuro di voler cancellare i dati?\nQuesta operazione non può essere annullata! +settings.clearall.confirm = [scarlet]ATTENZIONE![]\nQuesto cancellerà tutti i dati, inclusi salvataggi, mappe, oggetti sbloccati ed impostazioni.\nDopo aver premuto su 'ok' il gioco eliminerà i dati e si chiuderà automaticamente. +paused = [accent]< In Pausa > +clear = Pulisci +banned = [scarlet]Bandito yes = Si no = No -info.title = [accent] Info +info.title = Info error.title = [crimson]Si è verificato un errore error.crashtitle = Si è verificato un errore blocks.input = Ingresso @@ -501,49 +518,53 @@ block.unknown = [LIGHT_GRAY]??? blocks.powercapacity = Capacità Energetica blocks.powershot = Danno/Colpo blocks.damage = Danno -blocks.targetsair = Attacca nemici aerei -blocks.targetsground = Attacca nemici terreni -blocks.itemsmoved = Velocità movimento -blocks.launchtime = Tempo fra decolli +blocks.targetsair = Attacca Nemici Aerei +blocks.targetsground = Attacca Nemici Terreni +blocks.itemsmoved = Velocità di Movimento +blocks.launchtime = Tempo fra Decolli blocks.shootrange = Raggio blocks.size = Grandezza -blocks.liquidcapacity = Capacità del liquido +blocks.liquidcapacity = Capacità del Liquido blocks.powerrange = Raggio Energia -blocks.powerconnections = Max Connections -blocks.poweruse = Utilizzo energia +blocks.powerconnections = Connessioni Massime +blocks.poweruse = Utilizzo Energia blocks.powerdamage = Energia/Danno blocks.itemcapacity = Capacità -blocks.basepowergeneration = Generazione energia di base -blocks.productiontime = Tempo di produzione -blocks.repairtime = Tempo di riparazione completa +blocks.basepowergeneration = Generazione Energia di Base +blocks.productiontime = Tempo di Produzione +blocks.repairtime = Tempo di Riparazione Completa blocks.speedincrease = Aumento Velocità blocks.range = Raggio blocks.drilltier = Scavabili -blocks.drillspeed = Velocità di scavo stabile -blocks.boosteffect = Effetto boost -blocks.maxunits = Unità attive max +blocks.drillspeed = Velocità di Scavo Stabile +blocks.boosteffect = Effetto Boost +blocks.maxunits = Unità Attive Max blocks.health = Salute -blocks.buildtime = Tempo di costruzione +blocks.buildtime = Tempo di Costruzione blocks.buildcost = Costo di Costruzione blocks.inaccuracy = Inaccuratezza blocks.shots = Colpi blocks.reload = Ricarica blocks.ammo = Munizioni -bar.drilltierreq = Miglior trivella richiesta -bar.drillspeed = Velocità scavo: {0}/s -bar.pumpspeed = Pump Speed: {0}/s + +bar.drilltierreq = Miglior Trivella Richiesta +bar.drillspeed = Velocità Scavo: {0}/s +bar.pumpspeed = Velocità di Pompaggio: {0}/s bar.efficiency = Efficienza: {0}% bar.powerbalance = Energia: {0} -bar.powerstored = Stored: {0}/{1} +bar.powerstored = Immagazzinata: {0}/{1} bar.poweramount = Energia: {0} -bar.poweroutput = Energia in uscita: {0} +bar.poweroutput = Energia in Uscita: {0} bar.items = Oggetti: {0} -bar.capacity = Capacity: {0} +bar.capacity = Capacità: {0} bar.liquid = Liquido bar.heat = Calore bar.power = Energia -bar.progress = Progresso della costruzione +bar.progress = Progresso della Costruzione bar.spawned = Unità: {0}/{1} +bar.input = Entrata +bar.output = Uscita + bullet.damage = [stat]{0}[lightgray] danno bullet.splashdamage = [stat]{0}[lightgray] danno ad area ~[stat] {1}[lightgray] blocchi bullet.incendiary = [stat]incendiario @@ -555,6 +576,7 @@ bullet.freezing = [stat]congelante bullet.tarred = [stat]viscoso bullet.multiplier = [stat]{0}[lightgray]x moltiplicatore munizioni bullet.reload = [stat]{0}[lightgray]x ricarica + unit.blocks = blocchi unit.powersecond = unità energia/secondo unit.liquidsecond = unità liquide/secondo @@ -567,6 +589,8 @@ unit.persecond = /sec unit.timesspeed = x velocità unit.percent = % unit.items = oggetti +unit.thousands = k +unit.millions = mln category.general = Generali category.power = Energia category.liquids = Liquidi @@ -574,58 +598,62 @@ category.items = Oggetti category.crafting = Produzione category.shooting = Potenza di fuoco category.optional = Miglioramenti Opzionali -setting.landscape.name = Blocca paesaggio +setting.landscape.name = Blocca Paesaggio setting.shadows.name = Ombre -setting.blockreplace.name = Automatic Block Suggestions -setting.linear.name = Filtro lineare -setting.hints.name = Hints -setting.animatedwater.name = Acqua animata -setting.animatedshields.name = Scudi animati -setting.antialias.name = Antialias[LIGHT_GRAY] (richiede riapertura gioco)[] -setting.indicators.name = Indicatori Alleati -setting.autotarget.name = Mira automatica +setting.blockreplace.name = Suggerimento Blocchi Automatico +setting.linear.name = Filtro Lineare +setting.hints.name = Suggerimenti +setting.buildautopause.name = Auto-Pause Building +setting.animatedwater.name = Acqua Animata +setting.animatedshields.name = Scudi Animati +setting.antialias.name = Antialias[LIGHT_GRAY] (richiede riavvio)[] +setting.indicators.name = Indicatori Alleati/Nemici +setting.autotarget.name = Mira Automatica setting.keyboard.name = Tastiera -setting.touchscreen.name = Controlli Touchscreen +setting.touchscreen.name = Controlli Touchscreen setting.fpscap.name = Limite FPS setting.fpscap.none = Niente setting.fpscap.text = {0} FPS -setting.uiscale.name = Ridimensionamento dell'interfaccia utente[lightgray] (richiede riapertura gioco)[] -setting.swapdiagonal.name = Posizionamento sempre diagonale +setting.uiscale.name = Ridimensionamento Interfaccia[lightgray] (richiede riavvio)[] +setting.swapdiagonal.name = Posizionamento Sempre Diagonale setting.difficulty.training = Allenamento setting.difficulty.easy = Facile -setting.difficulty.normal = Medio +setting.difficulty.normal = Normale setting.difficulty.hard = Difficile setting.difficulty.insane = Impossibile setting.difficulty.name = Difficoltà: -setting.screenshake.name = Movimento dello schermo -setting.effects.name = Visualizza effetti -setting.destroyedblocks.name = Display Destroyed Blocks +setting.screenshake.name = Movimento dello Schermo +setting.effects.name = Visualizza Effetti +setting.destroyedblocks.name = Mostra Blocchi Distrutti setting.conveyorpathfinding.name = Conveyor Placement Pathfinding -setting.sensitivity.name = Sensibilità del controller -setting.saveinterval.name = Intervallo di salvataggio automatico -setting.seconds = {0} Secondi +setting.sensitivity.name = Sensibilità del Controller +setting.saveinterval.name = Intervallo di Salvataggio Automatico +setting.blockselecttimeout.name = Tempo di Selezione del Blocco +setting.milliseconds = {0} millisecondi +setting.seconds = {0} secondi setting.fullscreen.name = Schermo Intero -setting.borderlesswindow.name = Schermo senza bordi[LIGHT_GRAY] (potrebbe richiedere riapertura gioco) -setting.fps.name = Mostra FPS +setting.borderlesswindow.name = Finestra Senza Bordi[LIGHT_GRAY] (potrebbe richiedere riavvio) +setting.fps.name = Mostra FPS e Ping +setting.blockselectkeys.name = Mostra Tasto di Selezione del Blocco setting.vsync.name = VSync -setting.pixelate.name = Sfocare [LIGHT_GRAY](potrebbe ridure il rendimento) -setting.minimap.name = Mostra minimappa -setting.position.name = Show Player Position +setting.pixelate.name = Effetto Pixel [LIGHT_GRAY](potrebbe ridure le prestazioni) +setting.minimap.name = Mostra Minimappa +setting.position.name = Mostra Posizione Giocatori setting.musicvol.name = Volume Musica setting.ambientvol.name = Volume Ambiente -setting.mutemusic.name = Silenzia musica +setting.mutemusic.name = Silenzia Musica setting.sfxvol.name = Volume Effetti -setting.mutesound.name = Togli suoni -setting.crashreport.name = Invia rapporti sugli arresti anomali anonimamente +setting.mutesound.name = Togli Suoni +setting.crashreport.name = Invia rapporti anonimi sugli arresti anomali setting.savecreate.name = Autosalvataggio -setting.publichost.name = Gioco visibile pubblicamente -setting.chatopacity.name = Opacità chat -setting.lasersopacity.name = Power Laser Opacity +setting.publichost.name = Gioco Visibile Pubblicamente +setting.chatopacity.name = Opacità Chat +setting.lasersopacity.name = Opacità Laser d'Energia setting.playerchat.name = Mostra Chat in-game 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 = La scala dell'interfaccia utente è stata modificata.\nPremere "OK" per confermare questa scala.\n[scarlet] Ripristina ed esci dalle impostazioni [accent] {0}[] impostazioni... -uiscale.cancel = Annulla ed esci +uiscale.reset = La scala dell'interfaccia utente è stata modificata.\nPremere "OK" per confermare questa scala.\n[scarlet] Ripristina ed esci in [accent] {0}[] secondi... +uiscale.cancel = Annulla ed Esci setting.bloom.name = Shaders keybind.title = Configurazione Tasti keybinds.mobile = [scarlet]La maggior parte dei keybind qui non sono funzionali sui dispositivi mobili. È supportato solo il movimento di base. @@ -635,71 +663,91 @@ category.multiplayer.name = Multigiocatore command.attack = Attacca command.rally = Guardia command.retreat = Ritirata -keybind.clear_building.name = Clear Building +placement.blockselectkeys = \n[lightgray]Tasto: [{0}, +keybind.clear_building.name = Pulisci Costruzione keybind.press = Premi un tasto... keybind.press.axis = Premi un'asse o un tasto... -keybind.screenshot.name = Screenshot della mappa -keybind.move_x.name = Muovi orizzontale -keybind.move_y.name = Muovi verticale -keybind.schematic_select.name = Select Region -keybind.schematic_menu.name = Schematic Menu -keybind.schematic_flip_x.name = Flip Schematic X -keybind.schematic_flip_y.name = Flip Schematic Y +keybind.screenshot.name = Screenshot della Mappa +keybind.move_x.name = Muovi Orizzontalmente +keybind.move_y.name = Muovi Verticalmente +keybind.mouse_move.name = Segui il Mouse +keybind.dash.name = Scatto +keybind.schematic_select.name = Seleziona Regione +keybind.schematic_menu.name = Menu Schematica +keybind.schematic_flip_x.name = Ruota Schematica Orizzontalmente +keybind.schematic_flip_y.name = Flip Schematic Verticalmente +keybind.category_prev.name = Categoria Precedente +keybind.category_next.name = Categoria Successiva +keybind.block_select_left.name = Seleziona Blocco Sinistra +keybind.block_select_right.name = Seleziona Blocco Destra +keybind.block_select_up.name = Seleziona Blocco Su +keybind.block_select_down.name = Seleziona Blocco Giù +keybind.block_select_01.name = Categoria/Seleziona Blocco 1 +keybind.block_select_02.name = Categoria/Seleziona Blocco 2 +keybind.block_select_03.name = Categoria/Seleziona Blocco 3 +keybind.block_select_04.name = Categoria/Seleziona Blocco 4 +keybind.block_select_05.name = Categoria/Seleziona Blocco 5 +keybind.block_select_06.name = Categoria/Seleziona Blocco 6 +keybind.block_select_07.name = Categoria/Seleziona Blocco 7 +keybind.block_select_08.name = Categoria/Seleziona Blocco 8 +keybind.block_select_09.name = Categoria/Seleziona Blocco 9 +keybind.block_select_10.name = Categoria/Seleziona Blocco 10 keybind.fullscreen.name = Schermo Intero -keybind.select.name = Seleziona -keybind.diagonal_placement.name = Posizionamento diagonale +keybind.select.name = Seleziona/Spara +keybind.diagonal_placement.name = Posizionamento Diagonale keybind.pick.name = Scegli Blocco -keybind.break_block.name = Rompi blocco +keybind.break_block.name = Rompi Blocco keybind.deselect.name = Deseleziona keybind.shoot.name = Spara -keybind.zoom_hold.name = Attiva zoom -keybind.zoom.name = Esegui zoom -keybind.menu.name = Apri Menu +keybind.zoom.name = Esegui Zoom +keybind.menu.name = Menu keybind.pause.name = Pausa -keybind.pause_building.name = Pause/Resume Building +keybind.pause_building.name = Pausa/Riprendi Costruzione keybind.minimap.name = Minimappa -keybind.dash.name = Scatto keybind.chat.name = Chat keybind.player_list.name = Lista dei Giocatori keybind.console.name = Console -keybind.rotate.name = Ruotare -keybind.rotateplaced.name = Rotate Existing (Hold) +keybind.rotate.name = Ruota +keybind.rotateplaced.name = Ruota Blocco Esistente (Premuto) keybind.toggle_menus.name = Mostra/Nascondi HUD -keybind.chat_history_prev.name = Scorri chat vero l'alto -keybind.chat_history_next.name = Scorri chatt verso il basso -keybind.chat_scroll.name = Scorri chat -keybind.drop_unit.name = Lascia materiali -keybind.zoom_minimap.name = Esegui Zoom minimappa -mode.help.title = Descrizione delle modalità +keybind.chat_history_prev.name = Scorri Chat vero l'alto +keybind.chat_history_next.name = Scorri Chat verso il basso +keybind.chat_scroll.name = Scorri Chat +keybind.drop_unit.name = Lascia Materiali +keybind.zoom_minimap.name = Esegui Zoom Minimappa +keybind.toggle_power_lines.name = Attiva/Disattiva Laser d'Energia +mode.help.title = Descrizione delle Modalità mode.survival.name = Sopravvivenza -mode.survival.description = La modalità normale. Risorse limitate ed ondate in entrata automatiche. +mode.survival.description = Modalità normale. Risorse limitate ed ondate in entrata automatiche. mode.sandbox.name = Creativa mode.sandbox.description = Risorse infinite e nessun timer per le ondate. mode.editor.name = Editor mode.pvp.name = PvP mode.pvp.description = Lotta contro altri giocatori. mode.attack.name = Schermaglia -mode.attack.description = Obiettivo: Distruggere la base nemica, non ci sono ondate -mode.custom = Regole personalizzate +mode.attack.description = Obiettivo: Distruggere la base nemica, non ci sono ondate. +mode.custom = Regole Personalizzate + rules.infiniteresources = Risorse infinite -rules.wavetimer = Timer ondate +rules.reactorexplosions = Esplosioni Reattore +rules.wavetimer = Timer Ondate rules.waves = Ondate -rules.attack = Modalità attacco -rules.enemyCheat = Infinite Risorse AI +rules.attack = Modalità Attacco +rules.enemyCheat = Risorse AI Infinite rules.unitdrops = Generazione Unità -rules.unitbuildspeedmultiplier = Moltiplicatore velocità costruzione unità -rules.unithealthmultiplier = Moltiplicatore vita unità -rules.playerhealthmultiplier = Moltiplicatore vita giocatore -rules.playerdamagemultiplier = Moltiplicatore danno giocatore -rules.unitdamagemultiplier = Moltiplicatore danno unità -rules.enemycorebuildradius = Raggio dove non si può costruire attorno al nucleo nemico:[LIGHT_GRAY] (tiles) +rules.unitbuildspeedmultiplier = Moltiplicatore Velocità Costruzione Unità +rules.unithealthmultiplier = Moltiplicatore Vita Unità +rules.playerhealthmultiplier = Moltiplicatore Vita Giocatore +rules.playerdamagemultiplier = Moltiplicatore Danno Giocatore +rules.unitdamagemultiplier = Moltiplicatore Danno Unità +rules.enemycorebuildradius = Raggio di Protezione del Nucleo Nemico dalle Costruzioni:[LIGHT_GRAY] (tiles) rules.respawntime = Tempo di rigeneratione:[LIGHT_GRAY] (sec) -rules.wavespacing = Tempo fra ondate:[LIGHT_GRAY] (secondi) -rules.buildcostmultiplier = Moltiplicatore costo costruzione -rules.buildspeedmultiplier = Moltiplicatore velocità costruzione +rules.wavespacing = Tempo fra Ondate:[LIGHT_GRAY] (secondi) +rules.buildcostmultiplier = Moltiplicatore Costo Costruzione +rules.buildspeedmultiplier = Moltiplicatore Velocità Costruzione rules.waitForWaveToEnd = Ondate aspettano fino a quando l'ondata precedente finisce -rules.dropzoneradius = Raggio di generazione:[LIGHT_GRAY] (blocchi) -rules.respawns = Massimo di rigenerazioni per ondata +rules.dropzoneradius = Raggio di Generazione:[LIGHT_GRAY] (blocchi) +rules.respawns = Rigenerazioni per ondata max rules.limitedRespawns = Limite rigenerazioni rules.title.waves = Ondate rules.title.respawns = Rigenerazioni @@ -707,6 +755,10 @@ rules.title.resourcesbuilding = Risorse e costruzioni rules.title.player = Giocatori rules.title.enemy = Nemici rules.title.unit = Unità +rules.title.experimental = Sperimentale +rules.lighting = Illuminazione +rules.ambientlight = Illuminazione Ambientale + content.item.name = Oggetti content.liquid.name = Liquidi content.unit.name = Unità @@ -733,26 +785,27 @@ liquid.slag.name = Scoria liquid.oil.name = Petrolio liquid.cryofluid.name = Criofluido mech.alpha-mech.name = Alpha -mech.alpha-mech.weapon = Ripetitore pesante +mech.alpha-mech.weapon = Ripetitore Pesante mech.alpha-mech.ability = Orda di droni mech.delta-mech.name = Delta -mech.delta-mech.weapon = Generatore di fulmini +mech.delta-mech.weapon = Generatore di Fulmini mech.delta-mech.ability = Scarica mech.tau-mech.name = Tau -mech.tau-mech.weapon = Laser ricostruttore -mech.tau-mech.ability = Impulso riparatore +mech.tau-mech.weapon = Laser Ricostruttore +mech.tau-mech.ability = Impulso Riparatore mech.omega-mech.name = Omega -mech.omega-mech.weapon = Sciame di missili -mech.omega-mech.ability = Configurazione armata +mech.omega-mech.weapon = Sciame di Missili +mech.omega-mech.ability = Configurazione Armata mech.dart-ship.name = Dardo mech.dart-ship.weapon = Ripetitore mech.javelin-ship.name = Giavellotto -mech.javelin-ship.weapon = Missili esplosivi -mech.javelin-ship.ability = Booster di scarico +mech.javelin-ship.weapon = Missili Esplosivi +mech.javelin-ship.ability = Booster di Scarico mech.trident-ship.name = Tridente -mech.trident-ship.weapon = Valle delle bombe +mech.trident-ship.weapon = Valle delle Bombe mech.glaive-ship.name = Glaive -mech.glaive-ship.weapon = Ripetitore di fiamma +mech.glaive-ship.weapon = Ripetitore di Fiamma +item.corestorable = [lightgray]Immagazzinabili nel Nucleo: {0} item.explosiveness = [LIGHT_GRAY]Esplosività: {0} item.flammability = [LIGHT_GRAY]Infiammabilità: {0} item.radioactivity = [LIGHT_GRAY]Radioattività: {0} @@ -760,42 +813,43 @@ unit.health = [LIGHT_GRAY]Salute: {0} unit.speed = [LIGHT_GRAY]Velocità: {0} mech.weapon = [LIGHT_GRAY]Armi: {0} mech.health = [LIGHT_GRAY]Salute: {0} -mech.itemcapacity = [LIGHT_GRAY]Capacità oggetti: {0} -mech.minespeed = [LIGHT_GRAY]Velocità di scavo: {0} -mech.minepower = [LIGHT_GRAY]Potenza di scavo: {0} +mech.itemcapacity = [LIGHT_GRAY]Capacità Oggetti: {0} +mech.minespeed = [LIGHT_GRAY]Velocità di Scavo: {0} +mech.minepower = [LIGHT_GRAY]Potenza di Scavo: {0} mech.ability = [LIGHT_GRAY]Abilità: {0} -mech.buildspeed = [LIGHT_GRAY]Velocità costruzione: {0}% -liquid.heatcapacity = [LIGHT_GRAY]Capacità calorifica: {0} +mech.buildspeed = [LIGHT_GRAY]Velocità di Costruzione: {0}% +liquid.heatcapacity = [LIGHT_GRAY]Capacità Termica: {0} liquid.viscosity = [LIGHT_GRAY]Viscosità: {0} liquid.temperature = [LIGHT_GRAY]Temperatura: {0} + block.sand-boulder.name = Masso di Sabbia block.grass.name = Erba block.salt.name = Sale block.saltrocks.name = Rocce salate block.pebbles.name = Ciottoli block.tendrils.name = Viticci -block.sandrocks.name = Rocce sabbiose +block.sandrocks.name = Rocce Sabbiose block.spore-pine.name = Pino di Spore block.sporerocks.name = Roccia di Spore block.rock.name = Roccia -block.snowrock.name = Roccia innevata -block.snow-pine.name = Pino innevato +block.snowrock.name = Roccia Innevata +block.snow-pine.name = Pino Innevato block.shale.name = Scisto -block.shale-boulder.name = Masso di scisto +block.shale-boulder.name = Masso di Scisto block.moss.name = Muschio block.shrubs.name = Arbusti -block.spore-moss.name = Muschio di spore -block.shalerocks.name = Rocce di scisto +block.spore-moss.name = Muschio di Spore +block.shalerocks.name = Rocce di Scisto block.scrap-wall.name = Muro di Rottami -block.scrap-wall-large.name = Muro di Rottami grande -block.scrap-wall-huge.name = Muro di Rottami enorme -block.scrap-wall-gigantic.name = Muro di Rottami gigante +block.scrap-wall-large.name = Muro di Rottami Grande +block.scrap-wall-huge.name = Muro di Rottami Enorme +block.scrap-wall-gigantic.name = Muro di Rottami Gigante block.thruster.name = Propulsore block.kiln.name = Forno -block.graphite-press.name = Pressa per grafite +block.graphite-press.name = Pressa per Grafite block.multi-press.name = Multi Pressa -block.constructing = {0}\n[LIGHT_GRAY](In costruzione) -block.spawn.name = Spawn nemico +block.constructing = {0}\n[LIGHT_GRAY](In Costruzione) +block.spawn.name = Spawn Nemico block.core-shard.name = Nucleo: Frammento block.core-foundation.name = Nucleo: Fondamento block.core-nucleus.name = Nucleo: Kernel @@ -810,24 +864,24 @@ block.darksand.name = Sabbia Scura block.ice.name = Ghiaccio block.snow.name = Neve block.craters.name = Crateri -block.sand-water.name = Acqua sabbiosa -block.darksand-water.name = Acqua sabbiosa scura +block.sand-water.name = Acqua Sabbiosa +block.darksand-water.name = Acqua Sabbiosa scura block.char.name = Carbone block.holostone.name = Pietra Holo -block.ice-snow.name = Neve ghiacciata +block.ice-snow.name = Neve Ghiacciata block.rocks.name = Rocce -block.icerocks.name = Rocce ghiacciate -block.snowrocks.name = Rocce innevate -block.dunerocks.name = Rocce delle dune +block.icerocks.name = Rocce Ghiacciate +block.snowrocks.name = Rocce Innevate +block.dunerocks.name = Rocce delle Dune block.pine.name = Pino -block.white-tree-dead.name = Albero bianco morto -block.white-tree.name = Albero morto -block.spore-cluster.name = Agglomerato di spore -block.metal-floor.name = Pavimento metallico -block.metal-floor-2.name = Pavimento metallico 2 -block.metal-floor-3.name = Pavimento metallico 3 -block.metal-floor-5.name = Pavimento metallico 5 -block.metal-floor-damaged.name = Pavimento metallico danneggiato +block.white-tree-dead.name = Albero Bianco Morto +block.white-tree.name = Albero Morto +block.spore-cluster.name = Agglomerato di Spore +block.metal-floor.name = Pavimento Metallico +block.metal-floor-2.name = Pavimento Metallico 2 +block.metal-floor-3.name = Pavimento Metallico 3 +block.metal-floor-5.name = Pavimento Metallico 4 +block.metal-floor-damaged.name = Pavimento Metallico Danneggiato block.dark-panel-1.name = Pannello scuro 1 block.dark-panel-2.name = Pannello scuro 2 block.dark-panel-3.name = Pannello scuro 3 @@ -839,55 +893,58 @@ block.ignarock.name = Roccia Ignea block.hotrock.name = Roccia Bollente block.magmarock.name = Roccia Magmatica block.cliffs.name = Scogliere -block.copper-wall.name = Muro di rame -block.copper-wall-large.name = Muro grande di rame -block.titanium-wall.name = Muro di titanio -block.titanium-wall-large.name = Muro grande di titanio -block.plastanium-wall.name = Plastanium Wall -block.plastanium-wall-large.name = Large Plastanium Wall -block.phase-wall.name = Muro di fase -block.phase-wall-large.name = Muro grande di fase -block.thorium-wall.name = Muro di torio -block.thorium-wall-large.name = Muro grande di torio +block.copper-wall.name = Muro di Rame +block.copper-wall-large.name = Muro Grande di Rame +block.titanium-wall.name = Muro di Titanio +block.titanium-wall-large.name = Muro Grande di Titanio +block.plastanium-wall.name = Muro di Plastanio +block.plastanium-wall-large.name = Muro Grande di Plastanio +block.phase-wall.name = Muro di Fase +block.phase-wall-large.name = Muro Grande di Fase +block.thorium-wall.name = Muro di Torio +block.thorium-wall-large.name = Muro Grande di Torio block.door.name = Porta -block.door-large.name = Porta grande +block.door-large.name = Porta Grande block.duo.name = Torretta Duo block.scorch.name = Bruciatore -block.scatter.name = Cannone a dispersione +block.scatter.name = Cannone a Dispersione block.hail.name = Bombardiere block.lancer.name = Lanciere -block.conveyor.name = Nastro trasportatore -block.titanium-conveyor.name = Nastro avanzato -block.armored-conveyor.name = Nastro corazzato +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 block.sorter.name = Filtro -block.inverted-sorter.name = Inverted Sorter -block.message.name = Message -block.overflow-gate.name = Separatore per eccesso +block.inverted-sorter.name = Filtro Inverso +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.silicon-smelter.name = Fonderia -block.phase-weaver.name = Tessitore di fase +block.phase-weaver.name = Tessitore di Fase block.pulverizer.name = Polverizzatore -block.cryofluidmixer.name = Miscelatore di liquidi +block.cryofluidmixer.name = Miscelatore di Liquidi block.melter.name = Fonditore block.incinerator.name = Inceneritore block.spore-press.name = Pressa di Spore block.separator.name = Separatore block.coal-centrifuge.name = Centrifuga di Carbone -block.power-node.name = Nodo energetico -block.power-node-large.name = Nodo energetico grande +block.power-node.name = Nodo Energetico +block.power-node-large.name = Nodo Energetico Grande block.surge-tower.name = Torre di Sovratensione +block.diode.name = Diodo block.battery.name = Batteria -block.battery-large.name = Batteria grande -block.combustion-generator.name = Generatore a combustibile -block.turbine-generator.name = Turbina a vapore -block.differential-generator.name = Generatore differenziale +block.battery-large.name = Batteria Grande +block.combustion-generator.name = Generatore a Combustibile +block.turbine-generator.name = Turbina a Vapore +block.differential-generator.name = Generatore Differenziale block.impact-reactor.name = Reattore ad Impatto -block.mechanical-drill.name = Trivella meccanica -block.pneumatic-drill.name = Trivella pneumatica -block.laser-drill.name = Trivella laser +block.mechanical-drill.name = Trivella Meccanica +block.pneumatic-drill.name = Trivella Pneumatica +block.laser-drill.name = Trivella Laser block.water-extractor.name = Estrattore d'acqua block.cultivator.name = Coltivatore block.dart-mech-pad.name = Piattaforma del Mech Dardo @@ -897,27 +954,27 @@ block.trident-ship-pad.name = Piattaforma della Nave Tridente block.glaive-ship-pad.name = Piattaforma della Nave Glaive block.omega-mech-pad.name = Piattaforma del Mech Omega block.tau-mech-pad.name = Piattaforma del Mech Tau -block.conduit.name = Condotta -block.mechanical-pump.name = Pompa meccanica -block.item-source.name = Fonte infinita (oggetti) +block.conduit.name = Condotto +block.mechanical-pump.name = Pompa Meccanica +block.item-source.name = Fonte Infinita (oggetti) block.item-void.name = Cestino (oggetti) -block.liquid-source.name = Fonte infinita (liquidi) +block.liquid-source.name = Fonte Infinita (liquidi) block.power-void.name = Cestino (energia) -block.power-source.name = Fonte infinita (energia) +block.power-source.name = Fonte Infinita (energia) block.unloader.name = Scaricatore block.vault.name = Deposito block.wave.name = Idrogetto block.swarmer.name = Sciamatore block.salvo.name = Cannone Leggero block.ripple.name = Cannone Pesante -block.phase-conveyor.name = Nastro di fase -block.bridge-conveyor.name = Nastro trasportatore sopraelevato -block.plastanium-compressor.name = Compressore al plastanio -block.pyratite-mixer.name = Miscelatore di pirite -block.blast-mixer.name = Miscelatore di esplosivi -block.solar-panel.name = Pannello solare -block.solar-panel-large.name = Pannello solare 3x3 -block.oil-extractor.name = Estrattore di petrolio +block.phase-conveyor.name = Nastro di Fase +block.bridge-conveyor.name = Nastro Trasportatore Sopraelevato +block.plastanium-compressor.name = Compressore al Plastanio +block.pyratite-mixer.name = Miscelatore di Pirite +block.blast-mixer.name = Miscelatore d'Esplosivi +block.solar-panel.name = Pannello Solare +block.solar-panel-large.name = Pannello Solare Grande +block.oil-extractor.name = Estrattore di Petrolio block.command-center.name = Centro di Comando block.draug-factory.name = Fabbrica Droni Minatori block.spirit-factory.name = Fabbrica Droni Riparatori @@ -929,19 +986,19 @@ block.crawler-factory.name = Fabbrica Mech Strisciatore block.titan-factory.name = Fabbrica Mech Titano block.fortress-factory.name = Fabbrica Mech Fortezza block.revenant-factory.name = Fabbrica Combattenti Superstiti -block.repair-point.name = Punto di riparazione -block.pulse-conduit.name = Condotta attiva -block.phase-conduit.name = Condotta di fase -block.liquid-router.name = Distributore di liquidi +block.repair-point.name = Punto di Riparazione +block.pulse-conduit.name = Condotto Attiva +block.phase-conduit.name = Condotta di Fase +block.liquid-router.name = Distributore di Liquidi block.liquid-tank.name = Serbatoio -block.liquid-junction.name = Giunzione liquida -block.bridge-conduit.name = Condotta sopraelevata -block.rotary-pump.name = Pompa a turbina -block.thorium-reactor.name = Reattore al torio +block.liquid-junction.name = Giunzione Liquida +block.bridge-conduit.name = Condotta Sopraelevata +block.rotary-pump.name = Pompa a Turbina +block.thorium-reactor.name = Reattore al Torio block.mass-driver.name = Lancia Materiali -block.blast-drill.name = Trivella ad impulsi -block.thermal-pump.name = Pompa termica -block.thermal-generator.name = Generatore termico +block.blast-drill.name = Trivella ad Impulsi +block.thermal-pump.name = Pompa Termica +block.thermal-generator.name = Generatore Termico block.alloy-smelter.name = Altoforno block.mender.name = Riparatore block.mend-projector.name = Riparatore Grande @@ -982,12 +1039,12 @@ unit.eradicator.name = Estirpatore unit.lich.name = Lich unit.reaper.name = Mietitore tutorial.next = [lightgray] -tutorial.intro = Sei entrato nel[scarlet] Tutorial di Mindustry.[]\nInizia[accent] scavando rame[]. Clicca un minerale di rame vicino al tuo nucleo per farlo.\n\n[accent]{0}/{1} rame +tutorial.intro = Sei entrato nel[scarlet] Tutorial di Mindustry.[]\nInizia[accent] scavando rame[]. Clicca un minerale di rame vicino al tuo Nucleo per farlo.\n\n[accent]{0}/{1} rame tutorial.intro.mobile = You have entered the[scarlet] Mindustry Tutorial.[]\nSwipe the screen to move.\n[accent]Pinch with 2 fingers [] to zoom in and out.\nBegin by[accent] mining copper[]. Move close to it, then tap a copper ore vein near your core to do this.\n\n[accent]{0}/{1} copper tutorial.drill = Ora crea una trivella.\n[accent]Le trivelle []scavano da sole e sono più efficienti. Piazzane una su un minerale di rame. tutorial.drill.mobile = Ora crea una trivella. \n[accent] Le trivelle []scavano da sole e sono più efficienti. \n Toccare la scheda della trivella in basso a destra. \n Selezionare la trivella meccanica [accent] []. \n Posizionarlo su una vena di rame toccando, quindi premere il segno di spunta [accent] [] in basso per confermare la selezione. \n Premere il tasto X [accent] [] per annullare il posizionamento. tutorial.blockinfo = Ogni blocco ha statistiche diverse. Alcuni minerali richiedono trivelle specifiche.\nPer controllare le informazioni e le statistiche di un blocco, [accent] tocca "?" mentre lo selezioni nel database. []\n\n[accent]Accedi ora alle statistiche della trivella meccanica. [] -tutorial.conveyor = [accent]I nastri trasportatori []sono usati per trasportare oggetti al nucleo. \nCrea una linea di nastri dalla trivella al nucleo. +tutorial.conveyor = [accent]I nastri trasportatori []sono usati per trasportare oggetti al Nucleo. \nCrea una linea di nastri dalla trivella al Nucleo. tutorial.conveyor.mobile = [accent] I nastri trasportatori [] sono usati per trasportare oggetti nel nocciolo. \nCrea una linea di nastri trasportatori dalla trivella al nocciolo. \n[accent] Posizionati in una linea tenendo premuto il dito per alcuni secondi [] e trascinando in una direzione. \n\n [accent] {0} / {1} nastri trasportatori disposti in linea \n [accent] 0/1 oggetti consegnati tutorial.turret = Costruisci delle torrette per respingere il nemico [LIGHT_GRAY] []. \nCostruisci una torretta Duo vicino alla tua base. tutorial.drillturret = La Torretta Duo richiede[accent] munizioni di rame[] per sparare.\nPosiziona una trivella e collega un nastro alla torretta per rifornirla di munizioni con il rame estratto. @@ -995,13 +1052,14 @@ tutorial.pause = Durante la battaglia, puoi mettere in pausa il gioco [accent]. tutorial.pause.mobile = Durante la battaglia, puoi mettere in pausa il gioco [accent]. []\nPuoi disporre gli edifici mentre sei in pausa. \n\n[accent] Premi questo pulsante in alto a sinistra per mettere in pausa. tutorial.unpause = Ora premi di nuovo spazio per annullare la pausa. tutorial.unpause.mobile = Ora premilo di nuovo per annullare la pausa. -tutorial.breaking = I blocchi spesso devono essere distrutti. \n [accent]Tieni premuto il tasto destro del mouse [] per distruggere tutti i blocchi in una selezione. []\n[accent]Distruggi tutti i blocchi di scarto a sinistra del tuo core usando la selezione dell'area . -tutorial.breaking.mobile = I blocchi spesso devono essere distrutti. \n [accent] Seleziona la modalità di decostruzione [], quindi tocca un blocco per iniziare a smantellarlo. \n Distruggi un'area tenendo premuto il dito per alcuni secondi [] e trascinando in una direzione.\nPremi il pulsante con il segno di spunta per confermare la rimozione. \n\n [accent] Distruggi tutti i blocchi di scarto a sinistra del tuo nucleo usando la selezione dell'area. -tutorial.withdraw = In alcune situazioni, è necessario prendere gli oggetti direttamente dai blocchi.\nPer fare ciò, [accent] tocca un blocco []con oggetti al suo interno, quindi [accent] tocca l'oggetto [] nell'inventario. \nPuoi prelevare più oggetti insieme[accent]tenendo premuto il tasto sinistro del mouse[].\n[accent]Preleva un po' di rame dal nucleo. [] -tutorial.deposit = Deposita tutti gli oggetti che trasporti trascinandoli dalla tua nave al blocco di destinazione. \n[accent]Rimetti il rame nel nucleo. [] -tutorial.waves = Il nemico [LIGHT_GRAY] si avvicina.\nDifendi il tuo nucleo per 2 ondate. Costruisci più torrette. Puoi sparare tenendo premuto il tasto sinistro del mouse. -tutorial.waves.mobile = Il [lightgray] nemico si avvicina.\n\n Difendi il nucleo per 2 ondate. La tua nave sparerà automaticamente contro i nemici.\nCostruisci più torrette. -tutorial.launch = Una volta raggiunta un'ondata specifica, sarai in grado di [accent] decollare con il nucleo [], lasciando la zona e abbandonando le tue difese e le tue strutture\nOtterrai [accent]tutte le risorse nel tuo nucleo[] e potrai quindi usarle per ricercare nuove tecnologie.\n\n [accent]Decolla e conferma per terminare il tutorial. +tutorial.breaking = I blocchi spesso devono essere distrutti. \n [accent]Tieni premuto il tasto destro del mouse [] per distruggere tutti i blocchi in una selezione. []\n[accent]Distruggi tutti i blocchi di scarto a sinistra del tuo Nucleo usando la selezione dell'area . +tutorial.breaking.mobile = I blocchi spesso devono essere distrutti. \n [accent] Seleziona la modalità di decostruzione [], quindi tocca un blocco per iniziare a smantellarlo. \n Distruggi un'area tenendo premuto il dito per alcuni secondi [] e trascinando in una direzione.\nPremi il pulsante con il segno di spunta per confermare la rimozione. \n\n [accent] Distruggi tutti i blocchi di scarto a sinistra del tuo Nucleo usando la selezione dell'area. +tutorial.withdraw = In alcune situazioni, è necessario prendere gli oggetti direttamente dai blocchi.\nPer fare ciò, [accent] tocca un blocco []con oggetti al suo interno, quindi [accent] tocca l'oggetto [] nell'inventario. \nPuoi prelevare più oggetti insieme[accent]tenendo premuto il tasto sinistro del mouse[].\n[accent]Preleva un po' di rame dal Nucleo. [] +tutorial.deposit = Deposita tutti gli oggetti che trasporti trascinandoli dalla tua nave al blocco di destinazione. \n[accent]Rimetti il rame nel Nucleo. [] +tutorial.waves = Il nemico [LIGHT_GRAY] si avvicina.\nDifendi il tuo Nucleo per 2 ondate. Costruisci più torrette. Puoi sparare tenendo premuto il tasto sinistro del mouse. +tutorial.waves.mobile = Il [lightgray] nemico si avvicina.\n\n Difendi il Nucleo per 2 ondate. La tua nave sparerà automaticamente contro i nemici.\nCostruisci più torrette. +tutorial.launch = Una volta raggiunta un'ondata specifica, sarai in grado di [accent] decollare con il Nucleo [], lasciando la zona e abbandonando le tue difese e le tue strutture\nOtterrai [accent]tutte le risorse nel tuo Nucleo[] e potrai quindi usarle per ricercare nuove tecnologie.\n\n [accent]Decolla e conferma per terminare il tutorial. + item.copper.description = Un utile materiale, usato dappertutto item.lead.description = Un materiale di base, molto usato nei blocchi di trasporto. item.metaglass.description = Un durissimo composto di vetro. Estensivamente usato per trasporto di liquidi ed immagazzinamento. @@ -1030,8 +1088,8 @@ mech.dart-ship.description = Una navicella standard. Molto veloce e leggera, ma mech.javelin-ship.description = Una navetta da tocca e fuga. Anche se inizialmente lenta, può accelerare ad alte velocità e volare sopra gli avamposti dei nemici, e provocare molti danni ai nemici tramite l'utilizzo di fulmini o missili. mech.trident-ship.description = Un bombardiere pesante. Molto ben protetto. mech.glaive-ship.description = Una grande e ben armata macchina da guerra. Equipaggiata con lanciafamme e con accelerazione veloce. -unit.draug.description = Un drone minerario primitivo. Economico da produrre. Sacrificabile. Scava automaticamente rame e piombo nelle vicinanze. Fornisce risorse estratte al nucleo più vicino. -unit.spirit.description = L'unità drone di partenza. Si genera nel nucleo per impostazione predefinita. Scava automaticamente, raccoglie oggetti e ripara blocchi. +unit.draug.description = Un drone minerario primitivo. Economico da produrre. Sacrificabile. Scava automaticamente rame e piombo nelle vicinanze. Fornisce risorse estratte al Nucleo più vicino. +unit.spirit.description = L'unità drone di partenza. Si genera nel Nucleo per impostazione predefinita. Scava automaticamente, raccoglie oggetti e ripara blocchi. unit.phantom.description = Un'unità drone avanzata. Scava automaticamente, raccoglie oggetti e ripara blocchi. Significativamente più efficace del drone di partenza. unit.dagger.description = Un unità terrena base, molto più efficiente se in branco. unit.crawler.description = Un'unità di terra costituita da un telaio essenziale con potenti esplosivi legati sulla parte superiore. Non particolarmente resistente. Esplode a contatto con i nemici. @@ -1063,12 +1121,12 @@ block.power-source.description = Produce energia infinita, esiste solo nella mod 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.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.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ù tessere. block.titanium-wall.description = Un blocco difensivo moderatamente forte.\nFornisce una protezione moderata dai nemici. block.titanium-wall-large.description = Un blocco difensivo moderatamente forte.\nFornisce una protezione moderata dai nemici. \nOccupa più blocchi -block.plastanium-wall.description = A special type of wall that absorbs electric arcs and blocks automatic power node connections. -block.plastanium-wall-large.description = A special type of wall that absorbs electric arcs and blocks automatic power node connections.\nSpans multiple tiles. +block.plastanium-wall.description = Un tipo speciale di muro che assorbe gli archi elettrici e blocca le connessioni automatiche del nodo d'energia. +block.plastanium-wall-large.description = Un tipo speciale di muro che assorbe gli archi elettrici e blocca le connessioni automatiche dei nodi d'energia.\nSi estende su più blocchi. block.thorium-wall.description = Un forte blocco difensivo.\nBuona protezione dai nemici. block.thorium-wall-large.description = Un forte blocco difensivo.\nBuona protezione dai nemici.\nOccupa più blocchi block.phase-wall.description = Non è forte come un muro di torio, ma devia i proiettili a meno che non siano troppo potenti. @@ -1088,7 +1146,7 @@ block.junction.description = Permette di incrociare nastri che trasportano mater block.bridge-conveyor.description = Consente il trasporto di oggetti fino a 3 tessere 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 = Processes items like a standard sorter, but outputs selected items to the sides instead. +block.inverted-sorter.description = Elabora gli oggetti come uno smistatore 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. @@ -1096,13 +1154,13 @@ block.mass-driver.description = Ultimo blocco di trasporto di oggetti. Raccoglie block.mechanical-pump.description = Una pompa economica con potenza lenta, 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. -block.conduit.description = Condotta di base. Funziona come un nastro trasportatore, ma per i liquidi. Ideale per estrattori, pompe o altre condotte. -block.pulse-conduit.description = Condotta avanzata. Trasporta più liquido e più velocemente delle condotte standard. +block.conduit.description = Condotto di base. Funziona come un nastro trasportatore, ma per i liquidi. Ideale per estrattori, pompe o altri condotti. +block.pulse-conduit.description = Condotto avanzato. Trasporta più liquido e più velocemente dei condotti standard. block.liquid-router.description = Accetta i liquidi da una direzione e li emette fino a 3 altre direzioni allo stesso modo. Può anche immagazzinare una certa quantità di liquido. Utile per suddividere i liquidi da una fonte verso più destinazioni. block.liquid-tank.description = Conserva una grande quantità di liquidi. Usalo per creare zone cuscinetto quando c'è una domanda non costante di materiali o come protezione per il raffreddamento di blocchi vitali. -block.liquid-junction.description = Permette di incrociare condotte che trasportano liquidi diversi in posizioni diverse. -block.bridge-conduit.description = Consente il trasporto di liquidi fino a 3 tessere da un altra condotta sopraelevata.\nPuò passare sopra ad altri blocchi od edifici. -block.phase-conduit.description = Condotta avanzata. Consuma energia per teletrasportare i liquidi in un altra condotta di fase collegata. +block.liquid-junction.description = Permette di incrociare condotti che trasportano liquidi diversi in posizioni diverse. +block.bridge-conduit.description = Consente il trasporto di liquidi fino a 3 tessere da un altro condotto sopraelevato.\nPuò passare sopra ad altri blocchi od edifici. +block.phase-conduit.description = Condotto avanzato. Consuma energia per teletrasportare i liquidi in un altro condotto di fase collegato. block.power-node.description = Trasmette energia tra i nodi collegati. È possibile creare fino a quattro collegamenti.\nClicca sul nodo per configurare i collegamenti. block.power-node-large.description = Ha un raggio maggiore rispetto al nodo energetico e si possono creare un massimo di sei collegamenti.\nClicca sul nodo per configurare i collegamenti. block.surge-tower.description = Un nodo di alimentazione a lungo raggio solo due connessioni disponibili.\nClicca sul nodo per configurare i collegamenti. @@ -1124,13 +1182,13 @@ block.blast-drill.description = La trivella migliore. Richiede grandi quantità block.water-extractor.description = Estrae l'acqua dal terreno. Usalo quando non c'è nessun lago nelle vicinanze. block.cultivator.description = Coltiva il terreno con acqua per ottenere materia organica. block.oil-extractor.description = Utilizza grandi quantità di energia per estrarre petrolio dalla sabbia. Usalo quando non c'è una fonte diretta di petrolio nelle vicinanze. -block.core-shard.description = La prima iterazione del nucleo. Una volta distrutto, tutti i contatti con la regione vengono persi. Non lasciare che questo accada. -block.core-foundation.description = La seconda versione del nucleo. Meglio corazzato. Immagazzina più risorse. -block.core-nucleus.description = La terza ed ultima versione del nucleo. Estremamente ben corazzato. Immagazzina enormi quantità di risorse. +block.core-shard.description = La prima iterazione del Nucleo. Una volta distrutto, tutti i contatti con la regione vengono persi. Non lasciare che questo accada. +block.core-foundation.description = La seconda versione del Nucleo. Meglio corazzato. Immagazzina più risorse. +block.core-nucleus.description = La terza ed ultima versione del Nucleo. Estremamente ben corazzato. Immagazzina enormi quantità di risorse. block.vault.description = Immagazzina una grande quantità di oggetti. Usalo per creare zone cuscinetto quando c'è una domanda non costante di materiali. Uno [LIGHT_GRAY]scaricatore[] può essere utilizzato per recuperare elementi dal deposito. block.container.description = Immagazzina una piccola quantità di oggetti. Usalo per creare zone cuscinetto quando c'è una domanda non costante di materiali. Uno [LIGHT_GRAY]scaricatore[] può essere utilizzato per recuperare elementi dal contenitore. -block.unloader.description = Scarica gli oggetti da un contenitore, caveau o nucleo su un trasportatore o direttamente in un blocco adiacente. L'oggetto da scaricare può essere scelto toccando lo scaricatore. -block.launch-pad.description = Lancia oggetti nel tuo nucleo senza necessità di un lasciare la zona. +block.unloader.description = Scarica gli oggetti da un contenitore, caveau o Nucleo su un trasportatore o direttamente in un blocco adiacente. L'oggetto da scaricare può essere scelto toccando lo scaricatore. +block.launch-pad.description = Lancia oggetti nel tuo Nucleo senza necessità di un lasciare la zona. block.launch-pad-large.description = Una versione migliore dell'Ascensore Spaziale, immagazzina più oggetti. Lancia oggetti più frequentemente. block.duo.description = Una torretta piccola ed economica. block.scatter.description = Una torretta antiaerea di medie dimensioni. Spara schegge di piombo o frammenti di rottami sulle unità nemiche. @@ -1146,7 +1204,7 @@ block.ripple.description = Una grande torretta di artiglieria che spara più col block.cyclone.description = Una grande torretta a fuoco rapido. block.spectre.description = Una grande torretta che spara due potenti proiettili contemporaneamente. block.meltdown.description = Una grande torretta che spara un potente laser a lungo raggio. -block.command-center.description = Da istruzioni alle unità alleate nella mappa. Comanda la ricongizione, l'attacco del nucleo nemico o la ritirata verso il proprio nucleo o fabbrica.\nQuando non è presente un nucleo nemico, le unità pattuglieranno anche se viene ordinato un attacco. +block.command-center.description = Da istruzioni alle unità alleate nella mappa. Comanda la ricongizione, l'attacco del Nucleo nemico o la ritirata verso il proprio Nucleo o fabbrica.\nQuando non è presente un Nucleo nemico, le unità pattuglieranno anche se viene ordinato un attacco. block.draug-factory.description = Produce droni per la raccolta mineraria. block.spirit-factory.description = Produce droni che riparano blocchi. block.phantom-factory.description = Produce droni avanzati che seguono il giocatore e lo assistono nella costruzione. diff --git a/core/assets/bundles/bundle_ja.properties b/core/assets/bundles/bundle_ja.properties index 06cc822663..2d3db1916e 100644 --- a/core/assets/bundles/bundle_ja.properties +++ b/core/assets/bundles/bundle_ja.properties @@ -652,7 +652,6 @@ keybind.pick.name = ブロックの選択 keybind.break_block.name = ブロックの破壊 keybind.deselect.name = 選択解除 keybind.shoot.name = ショット -keybind.zoom_hold.name = 長押しズーム keybind.zoom.name = ズーム keybind.menu.name = メニュー keybind.pause.name = ポーズ diff --git a/core/assets/bundles/bundle_ko.properties b/core/assets/bundles/bundle_ko.properties index dfe930fee9..71a44a6bff 100644 --- a/core/assets/bundles/bundle_ko.properties +++ b/core/assets/bundles/bundle_ko.properties @@ -26,6 +26,7 @@ load.image = 사진 load.content = 컨텐츠 load.system = 시스템 load.mod = 모드 +load.scripts = 스크립트 schematic = 설계도 schematic.add = 설계도 저장하기 @@ -95,10 +96,11 @@ mods.none = [LIGHT_GRAY]추가한 모드가 없습니다! mods.guide = 모드 가이드 mods.report = 버그 신고 mods.openfolder = 모드 폴더 열기 -mod.enabled = [firebrick]활성화 -mod.disabled = [lightgray]비활성화 +mod.enabled = [lightgray]활성화 +mod.disabled = [scarlet]비활성화 mod.disable = 비활성화 mod.delete.error = 모드를 삭제할 수 없습니다. 아마도 해당 모드가 사용중인 것 같습니다. +mod.requiresversion = [scarlet]게임의 버전이 낮아 모드를 활성화할 수 없습니다!\n[scarlet]요구되는 게임 버전 : [accent]{0} mod.missingdependencies = [scarlet]의존되는 모드: {0} mod.nowdisabled = [scarlet]모드 '{0}'는 다음의 모드에 의존합니다 :[accent] {1}\n[lightgray]이 모드를 먼저 다운로드해야합니다.\n이 모드는 자동으로 비활성화됩니다. mod.enable = 활성화 @@ -106,11 +108,13 @@ mod.requiresrestart = 모드 변경사항을 적용하기 위해 게임을 종 mod.reloadrequired = [scarlet]새로고침 예정됨 mod.import = 모드 추가 mod.import.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 = 당신의 기기는 모드스크립트를 지원하지 않습니다. 모드의 일부 기능이 작동하지 않을 수 있습니다. about.button = 정보 name = 이름 : @@ -496,6 +500,7 @@ settings.language = 언어 settings.data = 게임 데이터 settings.reset = 설정 초기화 settings.rebind = 키 재설정 +settings.resetKey = 키 설정 settings.controls = 조작 settings.game = 게임 settings.sound = 소리 @@ -589,6 +594,8 @@ unit.persecond = /초 unit.timesspeed = x 배 unit.percent = % unit.items = 자원 +unit.thousands = 천 +unit.millions = 백만 category.general = 일반 category.power = 전력 category.liquids = 액체 @@ -623,7 +630,7 @@ setting.difficulty.name = 난이도 : setting.screenshake.name = 화면 흔들기 setting.effects.name = 화면 효과 setting.destroyedblocks.name = 부서진 블럭 표시 -setting.conveyorpathfinding.name = 컨베이어 설치 보조 기능 +setting.conveyorpathfinding.name = 교차기 자동 설치 setting.sensitivity.name = 컨트롤러 감도 setting.saveinterval.name = 저장 간격 setting.seconds = {0} 초 @@ -644,7 +651,7 @@ setting.sfxvol.name = 효과음 크기 setting.mutesound.name = 소리 끄기 setting.crashreport.name = 익명으로 오류 보고서 자동 전송 setting.savecreate.name = 자동 저장 활성화 -setting.publichost.name = 공개 서버 보이기 +setting.publichost.name = 스팀 공개 서버 보이기 setting.chatopacity.name = 채팅 투명도 setting.lasersopacity.name = 전력 레이저 밝기 setting.playerchat.name = 채팅 말풍선 표시 @@ -676,10 +683,10 @@ keybind.schematic_flip_x.name = 설계도 X축 뒤집기 keybind.schematic_flip_y.name = 설계도 Y축 뒤집기 keybind.category_prev.name = 이전 목록 keybind.category_next.name = 다음 목록 -keybind.block_select_left.name = 블럭 Select Left -keybind.block_select_right.name = 블럭 Select Right -keybind.block_select_up.name = 블럭 Select Up -keybind.block_select_down.name = 블럭 Select Down +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 @@ -697,7 +704,6 @@ keybind.pick.name = 블록 선택 keybind.break_block.name = 블록 파괴 keybind.deselect.name = 선택해제 keybind.shoot.name = 사격 -keybind.zoom_hold.name = 길게 확대 keybind.zoom.name = 확대 keybind.menu.name = 메뉴 keybind.pause.name = 일시중지 @@ -804,6 +810,7 @@ mech.trident-ship.name = 트라이던트 mech.trident-ship.weapon = 폭탄 저장고 mech.glaive-ship.name = 글레이브 mech.glaive-ship.weapon = 중무장 인화성 소총 +item.corestorable = [lightgray]코어 잔여 저장공간: {0} item.explosiveness = [LIGHT_GRAY]폭발성 : {0} item.flammability = [LIGHT_GRAY]인화성 : {0} item.radioactivity = [LIGHT_GRAY]방사능 : {0} @@ -986,7 +993,7 @@ block.fortress-factory.name = 포트리스 공장 block.revenant-factory.name = 망령 전함 공장 block.repair-point.name = 수리 지점 block.pulse-conduit.name = 펄스 파이프 -block.plated-conduit.name = 도금된 +block.plated-conduit.name = 도금된 파이프 block.phase-conduit.name = 메타 파이프 block.liquid-router.name = 액체 분배기 block.liquid-tank.name = 물탱크 diff --git a/core/assets/bundles/bundle_nl.properties b/core/assets/bundles/bundle_nl.properties index a9bf6129f3..4e0b424284 100644 --- a/core/assets/bundles/bundle_nl.properties +++ b/core/assets/bundles/bundle_nl.properties @@ -652,7 +652,6 @@ keybind.pick.name = Pick Block keybind.break_block.name = Break Block keybind.deselect.name = Deselect keybind.shoot.name = Shoot -keybind.zoom_hold.name = Zoom Hold keybind.zoom.name = Zoom keybind.menu.name = Menu keybind.pause.name = Pause diff --git a/core/assets/bundles/bundle_nl_BE.properties b/core/assets/bundles/bundle_nl_BE.properties index 1756cd5135..21e2410cfe 100644 --- a/core/assets/bundles/bundle_nl_BE.properties +++ b/core/assets/bundles/bundle_nl_BE.properties @@ -10,7 +10,8 @@ link.dev-builds.description = Onstabiele versies link.trello.description = Officiële Trello voor geplande toevoegingen. link.itch.io.description = Itch.io pagina met de PC downloads en online versie link.google-play.description = Mindustry op Google Play -link.wiki.description = Officiël Mindustry wiki +link.f-droid.description = F-Droid catalogus +link.wiki.description = Officiële Mindustry-wiki linkfail = Openen van link mislukt!\nDe link is gekopiëerd naar je klembord. screenshot = Locatie screenshot: {0} screenshot.invalid = Kaart te groot, mogelijks te weinig geheugen voor een screenshot te kunnen maken. @@ -20,9 +21,9 @@ highscore = [accent]Nieuw record! copied = Gekopieerd. load.sound = Geluiden load.map = Kaarten -load.image = Images -load.content = Content -load.system = System +load.image = Afbeeldingen +load.content = Inhoud +load.system = Systeem load.mod = Mods schematic = Blauwdruk schematic.add = Blauwdruk Opslaan... @@ -67,22 +68,22 @@ minimap = Kaartje position = Positie close = Sluit website = Website -quit = Verlaat -save.quit = Save & Quit +quit = Verlaten +save.quit = Opslaan & Verlaten maps = Kaarten -maps.browse = Browse Maps +maps.browse = Bekijk Kaarten continue = Ga verder maps.none = [LIGHT_GRAY]Geen kaarten gevonden! -invalid = Invalid -preparingconfig = Config Voorbereiden -preparingcontent = Content Voorbereiden -uploadingcontent = Content Uploaden +invalid = Ongeldig +preparingconfig = Configuratie Voorbereiden +preparingcontent = Inhoud Voorbereiden +uploadingcontent = Inhoud Uploaden uploadingpreviewfile = Voorbeeldbestand Uploaden committingchanges = Veranderingen Toepassen done = Klaar feature.unsupported = Uw apparaat ondersteunt deze functie niet. -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.alpha = [accent](Alpha) +mods.alphainfo = Mods zijn nog in alfa en [scarlet] kunnen zeer onstabiel zijn[].\nMeld problemen die je ondervindt op de Mindustry Github of Discord. +mods.alpha = [accent](Alfa) mods = Mods mods.none = [LIGHT_GRAY]Geen mods gevonden! mods.guide = Handleiding tot Modding @@ -93,8 +94,8 @@ mod.disabled = [scarlet]Uitgeschakeld mod.disable = Schakel uit mod.delete.error = Kan mod niet verwijderen. Bestand is mogelijk in gebruik. mod.missingdependencies = [scarlet]Missing dependencies: {0} -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.nowdisabled = [scarlet]De volgende vereisten ontbreken voor mod '{0}':[accent] {1}\n[lightgray]Deze mods moeten eerst gedownload worden.\nDeze mod wordt automatisch uitgeschakeld. +mod.enable = Schakel in mod.requiresrestart = The game will now close to apply the mod changes. mod.reloadrequired = [scarlet]Herladen Vereist mod.import = Importeer Mod @@ -102,9 +103,9 @@ mod.import.github = Importeer GitHub Mod mod.remove.confirm = Deze mod zal worden verwijderd. mod.author = [LIGHT_GRAY]Auteur:[] {0} mod.missing = Dit opslagbestand bevat mods die zijn geupdate of recentelijk zijn verwijderd. Uw opslagbestand kan beschadigd geraken. Bent u zeker dat u wil verdergaan?\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. -mod.folder.missing = Only mods in folder form can be published on the workshop.\nTo convert any mod into a folder, simply unzip its file into a folder and delete the old zip, then restart your game or reload your mods. -about.button = Extra info +mod.preview.missing = Voordat je de mod publiceert moet je een afbeelding voor de voorvertoning toevoegen.\nPlaats een afbeelding met de naam[accent] preview.png[] in de modfolder. +mod.folder.missing = Mods kunnen enkel gepubliceerd worden in foldervorm.\nOm een mod in foldervorm te zetten exporteer je het modbestand uit de zipfile en verwijder je de oude zipfile. Herlaad vervolgens je mods of herstart het spel. +about.button = Over name = Naam: noname = Kies eerst[accent] een naam[]. filename = Bestandsnaam: @@ -118,42 +119,42 @@ players = {0} spelers online players.single = {0} speler online server.closing = [accent]Server wordt gesloten... server.kicked.kick = Je bent uit de server gegooid! -server.kicked.whitelist = You are not whitelisted here. +server.kicked.whitelist = Je bent niet toegestaan om met deze server te verbinden. (Whitelist) server.kicked.serverClose = Server gesloten. -server.kicked.vote = You have been vote-kicked. Goodbye. +server.kicked.vote = Je bent uit de server gegooid na een stemming! server.kicked.clientOutdated = Verouderde versie! Update Mindustry! server.kicked.serverOutdated = Verouderde server! Vraag de eigenaar van de server om de server te updaten! server.kicked.banned = Je bent verbannen van deze server. -server.kicked.typeMismatch = This server is not compatible with your build type. -server.kicked.playerLimit = This server is full. Wait for an empty slot. -server.kicked.recentKick = Je bent daarnet van de server gegooid.\nWacht even voor je weer verbindt +server.kicked.typeMismatch = Deze server is niet compatibel met jouw Mindustry build type. +server.kicked.playerLimit = De server is vol, wacht voor een plekje. +server.kicked.recentKick = Je bent zonet van de server gegooid.\nWacht even voor je weer verbindt server.kicked.nameInUse = Er is al iemand met dezelfde naam op de server. server.kicked.nameEmpty = Je gekozen naam is ongeldig. server.kicked.idInUse = Je bent al verbonden met de server! Verbinden met 2 clients tegelijk is verboden. server.kicked.customClient = Deze server ondersteunt geen aangepaste versies (mods). Download een officiële versie. server.kicked.gameover = Game over! -server.versions = Your version:[accent] {0}[]\nServer version:[accent] {1}[] -host.info = Ook De [accent]host[] knop hosts een server op poort [scarlet]6567[]. \nIedereen die verbonden is met dezelfde [LIGHT_GRAY]wifi of lokaal netwerk[] zou je server moeten zien in zijn server lijst.\n\nAls je wil dat personen kunnen verbinden met je server van ergens anders via IP. Dan is [accent]port forwarding[] is nodig.\n\n[LIGHT_GRAY]Nota: Als iemand problemen heeft met het verbinden tot je LAN spel, zorg dan dat mindustry toestemming heeft tot je lokale netwerk in de Firewall instellingen. +server.versions = Jouw versie:[accent] {0}[]\nServerversie:[accent] {1}[] +host.info = Ook de [accent]host[] knop hosts een server op poort [scarlet]6567[]. \nIedereen die verbonden is met dezelfde [LIGHT_GRAY]wifi of lokaal netwerk[] zou je server moeten zien in zijn server lijst.\n\nAls je wil dat personen kunnen verbinden met je server van ergens anders via IP. Dan is [accent]port forwarding[] is nodig.\n\n[LIGHT_GRAY]Nota: Als iemand problemen heeft met het verbinden tot je LAN spel, zorg dan dat mindustry toestemming heeft tot je lokale netwerk in de Firewall instellingen. join.info = Hier kan je een [accent]server IP[] invullen waarmee je wil verbinden. Je kan hier ook verbinden met servers op je [accent]lokale netwerk[]. LAN en WAN multiplayer wordt ondersteund.\n\n[LIGHT_GRAY]Belangrijk: er is geen automatische globale server lijst; als je met iemand wil verbinden via een IP adres moet je zijn/haar IP adres vragen. -hostserver = Host Game -invitefriends = Invite Friends -hostserver.mobile = Host\nGame -host = Host +hostserver = Open server voor LAN +invitefriends = Nodig vrienden uit. +hostserver.mobile = Open\nServer +host = Open server hosting = [accent]De server wordt geopend... hosts.refresh = Herlaad hosts.discovering = LAN games worden gezocht -hosts.discovering.any = Discovering games +hosts.discovering.any = Games worden gezocht server.refreshing = De server wordt herladen hosts.none = [lightgray]Geen games op je lokale netwerk gevonden. host.invalid = [scarlet]Kan niet verbinden met de host (server). -trace = Zoeken speler -trace.playername = Naam speler: [accent]{0} +trace = Spelersinformatie +trace.playername = Naam: [accent]{0} trace.ip = IP: [accent]{0} -trace.id = Uniek ID: [accent]{0} -trace.mobile = Mobile Client: [accent]{0} +trace.id = Unieke ID: [accent]{0} +trace.mobile = Mobiele Client: [accent]{0} trace.modclient = Aangepaste Client: [accent]{0} -invalidid = Ongeldig client ID! Verstuur een bug report! -server.bans = Verbannen +invalidid = Ongeldige client ID! Verstuur een bug report! +server.bans = Verbanningen server.bans.none = Geen verbannen spelers gevonden! server.admins = Administrators server.admins.none = Geen Administrators gevonden! @@ -164,29 +165,29 @@ server.outdated = [crimson]Verouderde Server![] server.outdated.client = [crimson]Verouderde Client![] server.version = [lightgray]Versie: {0} {1} server.custombuild = [yellow]Aangepaste versie -confirmban = Ben je zeker dat je deze speler wil verbannen? -confirmkick = Ben je zeker dat je deze speler van de server wil gooien? -confirmvotekick = Are you sure you want to vote-kick this player? -confirmunban = Ben je zeker dat je de verbanning ongedaan wil maken? -confirmadmin = Ben je zeker dat je deze speler administrator wil maken? -confirmunadmin = Ben je zeker dat je de Administrator status van deze speler ongedaan wilt maken? +confirmban = Ben je zeker dat je deze speler wilt verbannen? +confirmkick = Ben je zeker dat je deze speler van de server wilt gooien? +confirmvotekick = Ben je zeker dat je een stemming wilt starten om deze speler uit de server to gooien? +confirmunban = Ben je zeker dat je de verbanning wilt opheffen? +confirmadmin = Ben je zeker dat je deze speler administrator wilt maken? +confirmunadmin = Ben je zeker dat je de administratorstatus van deze speler wilt intrekken? joingame.title = Verbinden met server joingame.ip = IP adres: disconnect = Verbinding verbroken. -disconnect.error = Connection error. -disconnect.closed = Connection closed. -disconnect.timeout = Timed out. -disconnect.data = Laden map data mislukt! -cantconnect = Unable to join game ([accent]{0}[]). +disconnect.error = Verbindingsfout. +disconnect.closed = Verbinding afgesloten. +disconnect.timeout = Het duurde te lang voordat de server antwoordde. +disconnect.data = Laden van mapdata mislukt! +cantconnect = Kon niet tot het spel toetreden. ([accent]{0}[]). connecting = [accent]Verbinden... connecting.data = [accent]Laden map data... server.port = Poort: server.addressinuse = Dit adres wordt al gebruikt! server.invalidport = Ongeldige poort! -server.error = [crimson]Error hosting server: [accent]{0} +server.error = [crimson]Fout bij het openen van de server: [accent]{0} save.new = Nieuwe save -save.overwrite = Ben je zeker dat je deze save\nwil overschrijven? -overwrite = Overschrijf +save.overwrite = Ben je zeker dat je deze save\nwilt overschrijven? +overwrite = Vervang save.none = Geen saves gevonden! saveload = [accent]Opslaan... savefail = Opslaan mislukt! @@ -197,27 +198,27 @@ save.import.invalid = [accent]Deze save is ongeldig! save.import.fail = [crimson]Save importeren mislukt: [accent]{0} save.export.fail = [crimson]Save exporteren mislukt: [accent]{0} save.import = Importeer Save -save.newslot = Save naam: +save.newslot = Naam van de save: save.rename = Naam wijzigen save.rename.text = Nieuwe naam: selectslot = Selecteer een save. -slot = [accent]Slot {0} +slot = [accent]Plaats {0} editmessage = Edit Message -save.corrupted = [accent]Save file corrupted or invalid!\nIf you have just updated your game, this is probably a change in the save format and [scarlet]not[] a bug. -empty = +save.corrupted = [accent]Het savebestand is corrupt of ongeldig.\nAls je zonet je spel geupdatet hebt is dit waarschijnlijk een verandering in de savestructuur en dus[scarlet] geen[] bug. +empty = on = Aan off = Uit save.autosave = Autosave: {0} save.map = Map: {0} save.wave = Golf {0} -save.mode = Gamemode: {0} -save.date = Last Saved: {0} +save.mode = Spelmodus: {0} +save.date = Laatste save: {0} save.playtime = Playtime: {0} warning = Waarschuwing. confirm = Bevestig delete = Verwijder -view.workshop = View In Workshop -workshop.listing = Edit Workshop Listing +view.workshop = Bekijk In Workshop +workshop.listing = Bewerk Workshop-Publicatie ok = OK open = Open customize = Pas aan @@ -225,40 +226,40 @@ cancel = Annuleer openlink = Open Link copylink = Kopiëer Link back = Terug -data.export = Export Data -data.import = Import Data -data.exported = Data exported. -data.invalid = This isn't valid game data. +data.export = Exporteer Data +data.import = Importeer Data +data.exported = Data geëxporteerd. +data.invalid = Dit is geen geldige speldata. data.import.confirm = Importing external data will erase[scarlet] all[] your current game data.\n[accent]This cannot be undone![]\n\nOnce the data is imported, your game will exit immediately. -classic.export = Export Classic Data -classic.export.text = [accent]Mindustry[] has just had a major update.\nClassic (v3.5 build 40) save or map data has been detected. Would you like to export these saves to your phone's home folder, for use in the Mindustry Classic app? +classic.export = Exporteer Classic-Data +classic.export.text = [accent]Mindustry[] heeft een grote update gehad.\nClassic (v3.5 build 40) save of map data is teruggevonden. Wil je deze data exporteren naar je de home-folder van je telefoon voor gebruik in de Mindustry-Classic app? quit.confirm = Weet je zeker dat je wilt stoppen? -quit.confirm.tutorial = Are you sure you know what you're doing?\nThe tutorial can be re-taken in[accent] Settings->Game->Re-Take Tutorial.[] +quit.confirm.tutorial = Ben je zeker dat je nu weet wat je doet?\nDe tutorial kan opnieuw gestart worden via[accent] Instellingen->Spel->Herneem Tutorial.[] loading = [accent]Aan het laden... -reloading = [accent]Reloading Mods... +reloading = [accent]Mods Herladen... saving = [accent]Aan het opslaan... -cancelbuilding = [accent][[{0}][] to clear plan -selectschematic = [accent][[{0}][] to select+copy -pausebuilding = [accent][[{0}][] to pause building -resumebuilding = [scarlet][[{0}][] to resume building +cancelbuilding = [accent][[{0}][] om het plan te annuleren +selectschematic = [accent][[{0}][] om te selecter+kopieren +pausebuilding = [accent][[{0}][] om het bouwen te pauseren +resumebuilding = [scarlet][[{0}][] om verder te gaan met bouwen wave = [accent]Golf {0} wave.waiting = [LIGHT_GRAY]Golf in {0} -wave.waveInProgress = [LIGHT_GRAY]Wave in progress -waiting = [LIGHT_GRAY]Waiting... -waiting.players = Aan het wachten voor spelers... +wave.waveInProgress = [LIGHT_GRAY]Golf bezig +waiting = [LIGHT_GRAY]Wachten... +waiting.players = Aan het wachten op spelers... wave.enemies = [LIGHT_GRAY]{0} Vijanden Over wave.enemy = [LIGHT_GRAY]{0} Vijand Over loadimage = Laad Afbeelding saveimage = Sla Afbeelding Op unknown = Onbekend -custom = Custom -builtin = Built-In +custom = Aangepast +builtin = Ingebouwd map.delete.confirm = Weet je zeker dat je deze kaart wilt verwijderen? Deze actie kan niet ongedaan gemaakt worden! -map.random = [accent]Random Map -map.nospawn = This map does not have any cores for the player to spawn in! Add a[ROYAL] blue[] core to this map in the editor. -map.nospawn.pvp = This map does not have any enemy cores for player to spawn into! Add[SCARLET] non-blue[] cores to this map in the editor. -map.nospawn.attack = This map does not have any enemy cores for player to attack! Add[SCARLET] red[] cores to this map in the editor. -map.invalid = Error loading map: corrupted or invalid map file. +map.random = [accent]Willekeurige Map +map.nospawn = Deze map heeft geen cores voor spelers om te spawnen! Voeg een[ROYAL] blauwe[] core toe in de mapbewerker. +map.nospawn.pvp = This map does not have any enemy cores for player to spawn into! Voeg een[SCARLET] niet-blauwe[] core toe in de mapbewerker. +map.nospawn.attack = This map does not have any enemy cores for player to attack! Voeg een[SCARLET] rode[] core toe in de mapbewerker. +map.invalid = Fout tijdens het laden van de map: Corrupt of ongeldig mapbestand. workshop.update = Update Item workshop.error = Error fetching workshop details: {0} map.publish.confirm = Are you sure you want to publish this map?\n\n[lightgray]Make sure you agree to the Workshop EULA first, or your maps will not show up! @@ -652,7 +653,6 @@ keybind.pick.name = Pick Block keybind.break_block.name = Break Block keybind.deselect.name = Deselect keybind.shoot.name = Shoot -keybind.zoom_hold.name = Zoom Hold keybind.zoom.name = Zoom keybind.menu.name = Menu keybind.pause.name = Pause diff --git a/core/assets/bundles/bundle_pl.properties b/core/assets/bundles/bundle_pl.properties index 7e8ddd3812..fd97dca25f 100644 --- a/core/assets/bundles/bundle_pl.properties +++ b/core/assets/bundles/bundle_pl.properties @@ -699,7 +699,6 @@ keybind.pick.name = Wybierz Blok keybind.break_block.name = Zniszcz Blok keybind.deselect.name = Odznacz keybind.shoot.name = Strzelanie -keybind.zoom_hold.name = Inicjator przybliżania keybind.zoom.name = Przybliżanie keybind.menu.name = Menu keybind.pause.name = Pauza diff --git a/core/assets/bundles/bundle_pt.properties b/core/assets/bundles/bundle_pt.properties index 6e6169b4b5..a0300813f5 100644 --- a/core/assets/bundles/bundle_pt.properties +++ b/core/assets/bundles/bundle_pt.properties @@ -652,7 +652,6 @@ keybind.pick.name = Pegar bloco keybind.break_block.name = Quebrar bloco keybind.deselect.name = Deselecionar keybind.shoot.name = Atirar -keybind.zoom_hold.name = segurar_zoom keybind.zoom.name = Zoom keybind.menu.name = Menu keybind.pause.name = Pausar diff --git a/core/assets/bundles/bundle_pt_BR.properties b/core/assets/bundles/bundle_pt_BR.properties index e2d775ff53..1e05466d91 100644 --- a/core/assets/bundles/bundle_pt_BR.properties +++ b/core/assets/bundles/bundle_pt_BR.properties @@ -700,7 +700,6 @@ keybind.pick.name = Pegar bloco keybind.break_block.name = Quebrar bloco keybind.deselect.name = Deselecionar keybind.shoot.name = Atirar -keybind.zoom_hold.name = segurar Zoom keybind.zoom.name = Zoom keybind.menu.name = Menu keybind.pause.name = Pausar diff --git a/core/assets/bundles/bundle_sv.properties b/core/assets/bundles/bundle_sv.properties index f01aa8b241..13ad6cdfae 100644 --- a/core/assets/bundles/bundle_sv.properties +++ b/core/assets/bundles/bundle_sv.properties @@ -652,7 +652,6 @@ keybind.pick.name = Pick Block keybind.break_block.name = Break Block keybind.deselect.name = Deselect keybind.shoot.name = Shoot -keybind.zoom_hold.name = Zoom Hold keybind.zoom.name = Zoom keybind.menu.name = Menu keybind.pause.name = Pause diff --git a/core/assets/bundles/bundle_th.properties b/core/assets/bundles/bundle_th.properties new file mode 100644 index 0000000000..90b72d7312 --- /dev/null +++ b/core/assets/bundles/bundle_th.properties @@ -0,0 +1,1202 @@ +credits.text = สร้างโดย [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[] +credits = เครดิต +contributors = ผู้แปลภาษาและผู้ช่วย +discord = เข้าร่วมเซิฟเวอร์ Discord ของ Mindustry! +link.discord.description = เซิฟเวอร์ Discord อย่างเป็นทางการของ Mindustry +link.reddit.description = ซับเรดดิท (subreddit) ของ Mindustry +link.github.description = source code ของเกม +link.changelog.description = รายการที่อัปเดต +link.dev-builds.description = เวอร์ชั่นระหว่างพัฒนา (ไม่เสถียร) +link.trello.description = Official Trello board for planned features +link.itch.io.description = itch.io page with PC downloads +link.google-play.description = Google Play store listing +link.wiki.description = Official Mindustry wiki +linkfail = ไม่สามารถเปิดลิ้งค์ได้\nคัดลอก URL ลงในคลิปบอร์ดแล้ว +screenshot = Screenshot บันทึกที่ {0} +screenshot.invalid = แมพใหญ่เกินไป, หน่วยความจำอาจจะไม่พอสำหรับ screenshot. +gameover = Game Over +gameover.pvp = ทีมที่ชนะคือทีม[accent] {0}[]! +highscore = [accent]คะแนนสูงสุดใหม่! +copied = คัดลอกแล้ว. + +load.sound = เสียง +load.map = แมพ +load.image = รูป +load.content = Content +load.system = ระบบ +load.mod = มอด + +schematic = Schematic +schematic.add = กำลังบันทึก Schematic... +schematics = Schematics +schematic.replace = มี schematic ที่ใช้ชื่อนี้แล้ว. แทนที่มัน? +schematic.import = นำเข้า Schematic... +schematic.exportfile = ส่งออก File +schematic.importfile = นำเข้า File +schematic.browseworkshop = ค้นหา Workshop +schematic.copy = คัดลอกไปที่คลิปบอร์ด +schematic.copy.import = นำเข้าจากคลิปบอร์ด +schematic.shareworkshop = แชร์บน Workshop +schematic.flip = [accent][[{0}][]/[accent][[{1}][]: กลับ Schematic +schematic.saved = บันทึก Schematic แล้ว. +schematic.delete.confirm = schematic นี้จะถูกกำจัดให้หมดสิ้นโดยสิ้นเชิง +schematic.rename = เปลี่ยนชื่อของ Schematic +schematic.info = {0}x{1}, {2} บล็อค + +stat.wave = จำนวน wave ที่กำจัดได้:[accent] {0} +stat.enemiesDestroyed = จำนวนศัตรูที่ถูกทำลาย:[accent] {0} +stat.built = จำนวนสิ่งก่อสร้างที่สร้าง:[accent] {0} +stat.destroyed = จำนวนสิ่งก่อสร้างที่ถูกทำลายโดยศัตรู:[accent] {0} +stat.deconstructed = จำนวนสิ่งก่อสร้างที่ทำลาย:[accent] {0} +stat.delivered = ทรัพยากรที่ส่ง: +stat.rank = แรงค์: [accent]{0} + +launcheditems = [accent]ไอเท็มที่ส่ง +launchinfo = [unlaunched][[ส่ง] core ของคุณเพื่อที่จะรับไอเท็มที่ไฮไลท์สีน้ำเงิน +map.delete = คุณแน่ใจหรือว่าจะลบแมพชื่อ "[accent]{0}[]"? +level.highscore = คะแนนสูงสุด: [accent]{0} +level.select = เลือกด่าน +level.mode = เกมโหมด: +showagain = ไม่แสดงอีกในครั้งต่อไป +coreattack = < Core กำลังถูกโจมตี! > +nearpoint = [[ [scarlet]ออกจากดรอปพอยท์ด่วน IMMEDIATELY[] ]\nการทำลายล้างกำลังใกล้เข้ามา +database = Core Database +savegame = เซฟเกม +loadgame = โหลดเกม +joingame = เข้าร่วมเกม +customgame = เกมที่กำหนดเอง +newgame = เริ่มเกมใหม่ +none = <ไม่มี> +minimap = มินิแมพ +position = ตำแหน่ง +close = ปิด +website = เว็ปไซต์ +quit = ออก +save.quit = เซฟแล้วออก +maps = แมพ +maps.browse = ค้นหาแมพ +continue = ต่อ +maps.none = [lightgray]ไม่มีแมพ! +invalid = ไม่ถูกต้อง +preparingconfig = กำลังเตรียม Config +preparingcontent = กำลังเตรียม Content +uploadingcontent = กำลังอัปโหลด Content +uploadingpreviewfile = กำลังอัปโหลดไฟล์พรีวิว +committingchanges = Comitting Changes +done = เรียบร้อย +feature.unsupported = อุปกรณ์ของคุณไม่รองรับฟีเจอร์นี้ + +mods.alphainfo = จำไว้ว่ามอดนั้นยังอยู่ในขั้น alpha และ[scarlet] อาจจะมีบัค[].\nโปรดรายงานปัญหาที่คุณพบใน Github ของ Mindustry หรือ ในเซิฟเวอร์ Discord +mods.alpha = [accent](Alpha) +mods = มอด +mods.none = [LIGHT_GRAY]ไม่พบมอด! +mods.guide = คู่มือการทำมอด +mods.report = รายงานบัค +mods.openfolder = เปิดมอดโฟลเดอร์ +mod.enabled = [lightgray]เปิดใช้งาน +mod.disabled = [scarlet]ปิดใช้งาน +mod.disable = ปิดใช้งาน +mod.delete.error = ไม่สามารถลบมอดได้. ไฟล์อาจอยู่ในระหว่างการใช้งาน. +mod.missingdependencies = [scarlet]dependencies หาย: {0} +mod.nowdisabled = [scarlet]มอด '{0}' ไม่มี dependencies:[accent] {1}\n[lightgray]จำเป็นต้องโหลดมอดพวกนี้ก่อน\nมอดนี้จะถูกปิดใช้งานโดยอัตโนมัติ +mod.enable = เปิดใช้งาน +mod.requiresrestart = เกมจะปิดลงเพื่อใส่มอด +mod.reloadrequired = [scarlet]จำเป็นต้องรีโหลด +mod.import = นำเข้ามอด +mod.import.github = นำเข้ามอดจาก Github +mod.remove.confirm = มอดนี้จะถูกลบ +mod.author = [LIGHT_GRAY]ผู้สร้าง:[] {0} +mod.missing = เซฟนี้มีมอดที่คุณอัปเดตหรือไม่ได้ติดตั้งแล้ว. อาจทำให้เซฟเสีย. คุณแน่จะหรือว่าจะโหลดเซฟนี้?\n[lightgray]Mods:\n{0} +mod.preview.missing = ก่อนที่จะนำมอดไปลงใน workshop, คุณต้องใส่รูปพรีวิวก่อน\nใส่รูปชื่อ[accent] preview.png[] ลงในโฟลเดอร์ของมอดแล้วลองอีกครั้ง +mod.folder.missing = มอดที่อยู่ในรูปแบบโฟลเดอร์เท่านั้นที่สามารถลงใน workshop ได้\nunzip ไฟล์แล้วลบไฟล์ zip เก่า แล้วรีสตาร์ทเกมหรือรีโหลดมอด + +about.button = เกี่ยวกับ +name = ชื่อ: +noname = ใส่ชื่อ[accent] ผู้เล่น[] ก่อน. +filename = ชื่อไฟล์: +unlocked = content ใหม่ปลดล็อค! +completed = [accent]สำเร็จ +techtree = สายวิจัย +research.list = [lightgray]วิจัย: +research = วิจัย +researched = [lightgray]{0} วิจัยแล้ว. +players = {0} ผู้เล่น +players.single = {0} ผู้เล่น +server.closing = [accent]กำลังปิดเซิฟเวอร์... +server.kicked.kick = คุณถูกเตะออกจากเซิฟเวอร์! +server.kicked.whitelist = คุณไม่ได้อยู่ใน whitelisted +server.kicked.serverClose = เซิฟเวอร์ถูกปิด. +server.kicked.vote = คุณถูกโหวตเตะออก. บายบาย. +server.kicked.clientOutdated = client ล่าสมัย! กรุณาอัปเดตเกมของคุณ! +server.kicked.serverOutdated = server ล่าสมัย! โปรดถามเจ้าของเซิฟเพื่ออัปเดต! +server.kicked.banned = คุณถูกแบนในเซิฟเวอร์นี้ +server.kicked.typeMismatch = เซิฟเวอร์นี้ไม่เข้ากับ build type ของคุณ. +server.kicked.playerLimit = เซิฟเวอร์เต็ม. กรุณารอให้เซิฟเวอร์ว่างก่อน. +server.kicked.recentKick = คุณเพิ่งถูกเตะออกจากเซิฟเวอร์นี้.\nกรุณารอสักครู่เพื่อเข้าร่วมอีกครั้ง +server.kicked.nameInUse = มีคนที่ใช้ชืชื่อนี้\nอยู่ในเซิฟเวอร์แล้ว +server.kicked.nameEmpty = ชื่อของคุณไม่สามารถใช้ได้ +server.kicked.idInUse = คุณเชื่อมต่อกับเซิฟเวอร์นี้อยู่แล้ว เราไม่อนุญาตให้เชื่อมต่อ 2 บัญชีในเซฟเวอร์เดียวกัน +server.kicked.customClient = เซิฟเวอร์นี้ไม่รองรับ builds ปรับแต่ง. กรุณาโหลดของ official. +server.kicked.gameover = Game over! +server.versions = เวอร์ชั่นของคุณ:[accent] {0}[]\nเวอร์ชั่นของเซิฟเวอร์:[accent] {1}[] +host.info = ปุ่ม [accent]โฮสต์[] นั้นโฮสต์เซฟเวอร์ที่พอร์ท [scarlet]6567[]. \nทุกคนที่อยู่ใน [lightgray]wifi หรือ local network[] เดียวกันจะสามารถเห็นเซิฟเวอร์ของคุณในลิสของเซิฟเวอร์ได้\n\nถ้าคุณต้องการให้ผู้เล่นอื่นๆสามารถเชื่อมต่อได้จากทุกที่โดยใช้ IP, จำเป็นจะต้องใช้การ [accent]port forwarding[] \n\n[lightgray]Note: ถ้าผู้เล่นคนใดมีปัญหาในการเชื่อมต่อ LAN ของคุณ เช็คให้แน่ใจว่าคุณได้อนุญาตให้ Mindustry เข้าถึง local network ของคุณในการตั้งค่า firewall. จำให้ว่า network สาธารณะบางครั้งไม่อนุญาตการค้นหาเซิฟเวอร์ +join.info = คุณสามารถใส่ [accent]IP ของเซิฟเวอร์[] เพื่อที่จะเชื่อมต่อหรือค้นหา เซิฟเวอร์ที่ใช้[accent]local network[] จะสามารถเชื่อมโดยใช้\n LAN หรือ WAN ก็ได้\n\n[lightgray]โน้ต: เกมนี้ไม่มีระบบค้นหาเซิฟเวอร์ global ให้อัตโนมัติserver list; ถ้าคุณต้องการเชื่อมต่อกับเซิฟเวอร์โดยใช้ IP, คุณจำเป็นต้องถาม IP ผู้เล่นที่โฮสต์เซิฟเวอร์นั้นๆ. +hostserver = โฮสต์เกม Multiplayer +invitefriends = ชวนเพื่อน +hostserver.mobile = โฮสต์\nเกม +host = โฮสต์ +hosting = [accent]กำลังเปิดเซิฟเวอร์... +hosts.refresh = รีเฟรช +hosts.discovering = กำลังค้นหาเซิฟเวอร์ใน LAN +hosts.discovering.any = กำลังค้นหาเซิฟเวอร์ +server.refreshing = กำลังรีเฟรชเซิฟเวอร์ +hosts.none = [lightgray]ไม่พบเซิฟเวอร์ใน local! +host.invalid = [scarlet]ไม่สามารถเชื่อมต่อกับโฮสต์ได้ +trace = Trace ผู้เล่น/ แกะรอยผู้เล่น +trace.playername = ชื่อผู้เล่น: [accent]{0} +trace.ip = IP: [accent]{0} +trace.id = ID พิเศษ: [accent]{0} +trace.mobile = Mobile Client : [accent]{0} +trace.modclient = Client แบบกำหนดเอง: [accent]{0} +invalidid = client ID ไม่ถูกต้อง! กรุณารายงานบัคนี้ +server.bans = แบน +server.bans.none = ไม่พบผู้เล่นที่ถูกแบน! +server.admins = แอดมิน +server.admins.none = ไม่พบแอดมิน! +server.add = เพิ่มเซิฟเวอร์ +server.delete = คุณแน่ใจหรือว่าจะลบเซิฟเวอร์นี้? +server.edit = แก้ไขเซิฟเวอร์ +server.outdated = [crimson]Server ล้าสมัย![] +server.outdated.client = [crimson]Client ล้าสมัย![] +server.version = [gray]เวอร์ชั่น{0} {1} +server.custombuild = [accent]Build +ที่กำหนดเอง +confirmban = คุณแน่ใจหรือว่าจะแบนผู้เล่นนี้? +confirmkick = คุณแน่ใจหรือว่าจะเตะผู้เล่นนี้ออก? +confirmvotekick = คุณแน่ใจหรือว่าจะโหวตเตะผู้เล่นนี้ออก? +confirmunban = คุณแน่ใจหรือว่าจะเลิกแบนผู้เล่นนี้? +confirmadmin = คุณแน่ใจหรือว่าจะเปลี่ยนผู้เล่นคนนี้เป็นแอดมิน? +confirmunadmin = คุณแน่ใจหรือว่าจะลบสถานะการเป็นแอดมินของผู้เล่นนี้ง? +joingame.title = เข้าร่วมเกม +joingame.ip = ที่อยู่: +disconnect = ตัดการเชื่อมต่อแล้ว +disconnect.error = การเชื่อมต่อมีปัญหา +disconnect.closed = การเชื่อมต่อถูกปิดแล้ว +disconnect.timeout = Timed out. +disconnect.data = การโหลดข้อมูลของ world ผิดพลาด! +cantconnect = ไม่สามารถเข้าร่วมเซิฟเวอร์ ([accent]{0}[]). +connecting = [accent]กำลังเชื่อมต่อ... +connecting.data = [accent]กำลังโหลดข้อมูลของ world ... +server.port = Port: +server.addressinuse = มีคนใช้ Address นี้แล้ว! +server.invalidport = เลข port ไม่ถูกต้อง! +server.error = [crimson]การโฮตส์เซิฟเวอร์ผิดพลาด +save.new = เซฟใหม่ +save.overwrite = คุณแใจหรือว่าจะเซฟทับ\nเซฟนี้? +overwrite = เขียนทับ +save.none = ไม่พบเซฟ! +saveload = กำลังเซฟ... +savefail = เซฟเกมผิดพลาด! +save.delete.confirm = คุณแน่ใจหรือว่าจะลบเซฟนี้? +save.delete = ลบ +save.export = ส่งออกเซฟ +save.import.invalid = [accent]เซฟนี้ไม่ถูกต้อง! +save.import.fail = [crimson]ไม่สามารถนำเข้าเซฟ: [accent]{0} +ได้ +save.export.fail = [crimson]ไม่สามารถส่งออกเซฟ: [accent]{0} +ได้ +save.import = นำเข้าเซฟ +save.newslot = ชื่อเซฟ: +save.rename = เปลี่ยนชื่อ +save.rename.text = ชื่อใหม่: +selectslot = เลือกเซฟ. +slot = [accent]Slot {0} +editmessage = แก้ไขข้อความ +save.corrupted = ไฟล์เซฟเสียหายหรือไม่ถูกต้อง! +empty = <ว่างเปล่า> +on = เปิด +off = ปิด +save.autosave = เซฟอัตโนมัติ: {0} +save.map = แมพ: {0} +save.wave = Wave {0} +save.mode = โหมดของเกม: {0} +save.date = เซฟล่าสุด: {0} +save.playtime = เวลาที่เล่นไป: {0} +warning = คำเตือน. +confirm = ตกลง +delete = ลบ +view.workshop = เปิดใน Workshop +workshop.listing = แก้ไข Workshop Listing +ok = โอเค +open = เปิด +customize = กฎแบบกำหนดเอง +cancel = ยกเลิก +openlink = เปิดลิ้งค์ +copylink = คัดลอกลิ้งค์ +back = กลับ +data.export = ส่งออกข้อมูล +data.import = นำเข้าข้อมูล +data.exported = ข้อมูลส่งออกแล้ว +data.invalid = นี่ไม่ใช่ข้อมูลเกมที่ถูกต้อง. +data.import.confirm = การนำเข้าข้อมูลจากภายนอกจะเขียนทับข้อมูลเก่า[scarlet]ทั้งหมด[]\n[accentและไม่สามารถย้อนกลับได้![]\n\nหลังจากที่นำข้อมูลแล้วเกมจะปิดลงโดยทันที +classic.export = ส่งออกข้อมูล Classic +classic.export.text = [accent]Mindustry[] ได้รับการอัปเดตครั้งใหญ่\nพบเซฟหรือแมพจากเวอร์ชั่น Classic (v3.5 build 40) คุณต้องการที่จะส่งออกข้อมูลไปยังโฟลเดอร์โฮมของโทรศัพท์ของคุณเพื่อที่จะใช้ในแอป Mindustry Classic หรือไม่? +quit.confirm = คุณแน่ใจหรือว่าจะออก? +quit.confirm.tutorial = คุณแน่ใจหรือว่าคุณกำลังทำอะไรอยู่?\nการสอนเล่นสามารถเล่นได้อีกครั้งใน[accent] ตั้งค่า->เกม->เล่นการสอนเล่นอีกครั้ง[] +loading = [accent]กำลังโหลด... +reloading = [accent]กำลังรีโหลดมอด... +saving = [accent]กำลังเซฟ... +cancelbuilding = [accent][[{0}][]เพื่อเคลียแผน +selectschematic = [accent][[{0}][]เพื่อเลือกและคัดลอก +pausebuilding = [accent][[{0}][]เพื่อหยุดการสร้างชั่วคราว +resumebuilding = [scarlet][[{0}][]เพื่อสร้างต่อ +wave = [accent]Wave {0} +wave.waiting = [lightgray]Wave ในอีก {0} +wave.waveInProgress = [lightgray]Wave กำลังดำเนินการ +waiting = [lightgray]กำลังรอ... +waiting.players = รอผู้เล่น... +wave.enemies = ศัตรูคงเหลือ [lightgray]{0} +wave.enemy = ศัตรูคงเหลือ [lightgray]{0} +loadimage = โหลดรูป +saveimage = เซฟรูป +unknown = ไม่ทราบ +custom = กำหนดเอง +builtin = Built-In +map.delete.confirm = คุณแน่ใจหรือว่าจะลบแมพนี้? การกระทำครั้งนี้ไม่สามารถย้อนกลับได้! +map.random = [accent]สุ่มแมพ +map.nospawn = แมพนี้ไม่มี core ที่จะให้ผู้เล่นเกิด! กรุณาใส่ core[accent] สีส้ม[] ใน editor +map.nospawn.pvp = แมพนี้ไม่มี core ของศัตรูสำหรับให้ผู้เล่นเกิด! กรุณาใส่ core[SCARLET] ที่ไม่ใช่สีส้ม[] ใน editor +map.nospawn.attack = แมพนี้ไม่มี core ของศัตรูสำหรับให้ผู้เล่นโจมตี! กรุณาใส่ core[SCARLET] สีแดง[] ใน editor +map.invalid = โหลดแมพผิดพลาด: ไฟล์แมพเสียหายหรือไม่ถูกต้อง +workshop.update = อัปเดตไอเท็ม +workshop.error = ผิดพลาดในการนำ workshop มา รายละเอียดดังนี้: {0} +map.publish.confirm = คุณแน่ใจหรือว่าจะเผยแพร่แมพนี้?\n\n[lightgray]คุณต้องแน่ใจก่อนว่าคุณเห็นด้วยกับ Workshop EULA, มิฉนั้นแมพจะไม่ปรากฏ! +workshop.menu = เล์อกว่าจะทำอะไรกับไอเท็มนี้ +workshop.info = ข้อมูลไอเท็ม +changelog = สิ่งที่เปลี่ยนไป (ไม่จำเป็น): +eula = Steam EULA +missing = ไอเท็มนี้ถูกลบหรือย้าย\n[lightgray]ยกเลิกการเชื่อมต่อของ workshop listing แล้ว +publishing = [accent]กำลังเผยแพร่... +publish.confirm = คุณแน่ใจหรือว่าจะเผยแพร่สิ่งนี้?\n\n[lightgray]คุณต้องแน่ใจก่อนว่าคุณเห็นด้วยกับ Workshop EULA, มิฉนั้นไอเท็มของคุณจะไม่ปรากฏ! +publish.error = การเผยแพร่ไอเท็มดังต่อไปนี้ผิดพลาด: {0} +steam.error = ไม่สามารถเริ่ม Steam service ได้\nError: {0} + +editor.brush = แปรง +editor.openin = เปิดมน Editor +editor.oregen = การเกิดของแร่ +editor.oregen.info = การเกิดของแร่: +editor.mapinfo = ข้อมูลของแมพ +editor.author = ผู้สร้าง: +editor.description = คำอธิบาย: +editor.nodescription = แมพจำเป็นต้องมีคำอธิบายอย่างน้อย 4 ตัวอักษรจึงจะสามารถเผยแพร่ได้ +editor.waves = Waves: +editor.rules = กฎ: +editor.generation = การเกิด: +editor.ingame = แก้ไขในเกม +editor.publish.workshop = เผยแพร่บน Workshop +editor.newmap = แมพใหม่ +workshop = Workshop +waves.title = Waves +waves.remove = ลบ +waves.never = +waves.every = ทุกๆ +waves.waves = wave(s) +waves.perspawn = ต่อสปาวน์ +waves.to = to +waves.boss = บอส +waves.preview = พรีวิว +waves.edit = แก้ไข... +waves.copy = คัดลอกไปยังคลิปบอร์ด +waves.load = โหลดจากคลิปบอร์ด +waves.invalid = waves ในคลิปบอร์ดไม่ถูกต้อง +waves.copied = คัดลอก Waves แล้ว +waves.none = ไม่ได้กำหนดศัตรู\nwave layouts เปล่าจะถูกแทนที่โดย layout ค่าเริ่มต้นของเกม +editor.default = [lightgray]<ค่าเริ่่มต้น> +details = รสยละเอียด... +edit = แก้ไข... +editor.name = ชื่อ: +editor.spawn = สปาวน์ยูนิต +editor.removeunit = ลบยูนิต +editor.teams = ทีม +editor.errorload = โหลดไฟล์ผิดพลาด +editor.errorsave = เซฟไฟล์ผิดพลาด +editor.errorimage = ไฟล์นั้นคือไฟล์รูป ไม่ใช่แมพ\n\nหากคุณต้องการนำเข้าไฟล์แมพจากเวอร์ชั่น 3.5/build 40 ใช้ปุ่ม 'นำเข้าแมพ Legacy' ใน editor. +editor.errorlegacy = แมพนี้เก่าเกินไปและใช้ฟอร์แม็ตแมพ legacy ที่ไม่สนับสนุนแล้ว +editor.errornot = นี่ไม่ใช้ไฟล์แมพ +editor.errorheader = ไฟล์แมพนี้เสียหรือไม่ถูกต้อง +editor.errorname = แมพไม่มีการกำหนดชื่อ คุณกำลังโหลดไฟล์เซฟอยู่หรือป่าว? +editor.update = อัปเดต +editor.randomize = สุ่ม +editor.apply = ใช้ +editor.generate = การเกิด +editor.resize = เปลี่ยนขนาด +editor.loadmap = โหลดแมพ +editor.savemap = เซฟแมพ +editor.saved = เซฟเรียบร้อย! +editor.save.noname = แมพของคุณไม่มีชื่อ! สามารถตั้งชื่อได้ในเมนู 'ข้อมูลแมพ' +editor.save.overwrite = แมพของคุณไปทับกับแมพ built-in! เปลี่ยนชื่อได้ในเมนู 'ข้อมูลแมพ' +editor.import.exists = [scarlet]ไม่สามารถนำเข้าได้:[] มีแมพ built-in map ชื่อ '{0}' อยู่แล้ว! +editor.import = กำลังนำเข้า... +editor.importmap = นำเข้าแมพ +editor.importmap.description = นำเข้าแมพที่มีอยู่แล้ว +editor.importfile = นำเข้าไฟล์ +editor.importfile.description = นำเข้าแมพจากไฟล์ภายนอก +editor.importimage = นำเข้าแมพแบบ Legacy +editor.importimage.description = นำเข้าแมพจากไฟล์รูปภายนอก +editor.export = กำลังส่งออก... +editor.exportfile = ส่งออกไฟล์ +editor.exportfile.description = ส่งออกไฟล์แมพ +editor.exportimage = ส่งออกไฟล์รูป Terrain +editor.exportimage.description = ส่งออกไฟล์รูปแมพ +editor.loadimage = นำเข้า Terrain +editor.saveimage = ส่งออก Terrain +editor.unsaved = [scarlet]คุณมีการเปลี่ยนแปลงที่ยังไม่ได้เซฟ![]\nคุณแน่ใจหรือว่าจะออก? +editor.resizemap = เปลี่ยนขนาดของแมพ +editor.mapname = ชื่อแมพ: +editor.overwrite = [accent]ตำเตือน!\nแมพนี้จะเขียนทับกับแมพที่มีอยู่แล้ว +editor.overwrite.confirm = [scarlet]ตำเตือน![] มีแมพที่มีชื่อนี้อยู่แล้ว คุณแน่ใจหรือว่าจะเขียนทับมัน? +editor.exists = มีแมพที่มีชื่อนี้อยู่แล้ว +editor.selectmap = เลือกแมพที่จะโหลด: + +toolmode.replace = แทนที่ +toolmode.replace.description = วาดเฉพาะบนบล็อคตัน +toolmode.replaceall = แทนที่ทั้งหมด +toolmode.replaceall.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.description = วาดทีมแทนที่จะเป็นบล็อค + +filters.empty = [lightgray]ไม่มีฟิลเตอร์! เพิ่มด้วยปุ่มด้านล่างนี้ +filter.distort = บิดเบือน +filter.noise = นอยส์ +filter.median = เฉลี่ย +filter.oremedian = เฉลี่ยแร่ +filter.blend = ผสมผสาน +filter.defaultores = แร่พื้นฐาน +filter.ore = แร่ +filter.rivernoise = นอยส์แม่น้ำ +filter.mirror = สะท้อน +filter.clear = เคลียร์ +filter.option.ignore = เพิกเฉย +filter.scatter = กระจาย +filter.terrain = พื้นผิว +filter.option.scale = มาตราส่วน +filter.option.chance = โอกาส +filter.option.mag = แม็คนิจูต +filter.option.threshold = Threshold +filter.option.circle-scale = สเกลวงกลม +filter.option.octaves = เลอะเลือน +filter.option.falloff = หลุด +filter.option.angle = มุม +filter.option.block = บล็อค +filter.option.floor = พื้น +filter.option.flooronto = พื้น Target +filter.option.wall = กำแพง +filter.option.ore = แร่ +filter.option.floor2 = พื้นชั้น 2 +filter.option.threshold2 = Threshold ชั้น 2 +filter.option.radius = รัศมี +filter.option.percentile = เปอร์เซ็น + +width = กว้าง: +height = สูง: +menu = เมนู +play = เล่น +campaign = แคมเปญ +load = โหลด +save = เซฟ +fps = FPS: {0} +ping = Ping: {0}ms +language.restart = กรุณารีสตาร์ทเพื่อที่จะให้เกมเปลี่ยนเป็นภาษาที่คุณเลือก +settings = ตั้งค่า +tutorial = สอนเล่น +tutorial.retake = เล่นการสอนเล่นอีกครั้ง +editor = Editor +mapeditor = Editor ของแมพ + +abandon = ทิ้ง +abandon.text = โซนนี้และทรัพยากรทั้งหมดจะกลายเป็นของศัตรู +locked = ล็อค +complete = [lightgray]สำเร็จ: +requirement.wave = ถึง Wave ที่ {0} ใน {1} +requirement.core = ทำลาย Core ของศัตรูใน {0} +requirement.unlock = ปลดล็อค {0} +resume = เล่นต่อในโซน:\n[lightgray]{0} +bestwave = [lightgray]Wave สูงสุด: {0} +launch = < ส่ง > +launch.title = ส่งเรียบร้อย +launch.next = [lightgray]โอกาสครั้งหน้าที่ wave {0} +launch.unable2 = [scarlet]ไม่สามารถส่งได้[] +launch.confirm = นี่จะส่งทรัพยากรทั้งหมดใน core ของคุณ\nคุณจะไม่สามารถกลับมาที่ฐานนี้ได้อีก +launch.skip.confirm = ถ้าคุณข้ามตอนนี้, คุณจะไม่สามารถส่งจนกว่าจะถึง waves ต่อๆไป +uncover = เปิดเผย +configure = ตั้งค่า Loadout +bannedblocks = Banned Blocks +addall = เพิ่มทั้งหมด +configure.locked = [lightgray]ปลดล็อคการตั้งค่า loadout: {0}. +configure.invalid = จำนวนต้อยู่ระหว่าง 0 ถึง {0}. +zone.unlocked = [lightgray]{0} ปลดล็อคแล้ว +zone.requirement.complete = ข้อเรียกร้องสำหรับ {0} สำเร็จแล้ว:[lightgray]\n{1} +zone.config.unlocked = Loadout ปลดล็อคแล้ว:[lightgray]\n{0} +zone.resources = [lightgray]ทรัพยากรที่พบ: +zone.objective = [lightgray]เป้าหมาย: [accent]{0} +zone.objective.survival = เอาชีวิตรอด +zone.objective.attack = ทำลาย Core ของศัตรู +add = เพิ่ม... +boss.health = เลือดบอส + +connectfail = [crimson]การเชื่อมต่อผิดพลาด:\n\n[accent]{0} +error.unreachable = เซิฟเวอร์ไม่สามารถเข้าถึงได้\nแน่ใจหรือว่าที่อยู่เขียนถูกต้อง? +error.invalidaddress = ที่อยู่ไม่ถูกต้อง +error.timedout = Timed out!\nเช็คให้แน่ใจว่า port forwarding ของโฮสต์เปิดอยู่และที่อยู่นั้นถูกต้อง! +error.mismatch = Packet error:\nอาจเกิดจากเวอร์ชั่นของ client/server ไม่ตรงกัน\nเช็คให้แน่ใจว่าเซิฟเวอร์ใช้ Mindustry เวอร์ชั่นล่าสุด! +error.alreadyconnected = เชื่อมต่ออยู่แล้ว +error.mapnotfound = ไม่พบไฟล์แมพ +error.io = Network I/O error. +error.any = Unknown network error. +error.bloom = ไม่สามารถเริ่มต้น bloom ได้\nอุปกรณ์ของคุณอาจไม่รองรับ + +zone.groundZero.name = Ground Zero +zone.desertWastes.name = Desert Wastes +zone.craters.name = The Craters +zone.frozenForest.name = Frozen Forest +zone.ruinousShores.name = Ruinous Shores +zone.stainedMountains.name = Stained Mountains +zone.desolateRift.name = Desolate Rift +zone.nuclearComplex.name = Nuclear Production Complex +zone.overgrowth.name = Overgrowth +zone.tarFields.name = Tar Fields +zone.saltFlats.name = Salt Flats +zone.impact0078.name = Impact 0078 +zone.crags.name = Crags +zone.fungalPass.name = Fungal Pass + +zone.groundZero.description = ตำแหน่งเริ่มต้นที่ดีที่สุด ภัยคุกคามจากศัตรูน้อย ทรัพยากรก็น้อยเช่นกัน\nรวบรวมตะกั่วและทองแดงให้ได้มากที่สุดเท่าที่จะทำได้\nแล้วเดินหน้าต่อ +zone.frozenForest.description = แม้แต่ที่นี่อยู่ใกล้กับภูเขา สปอร์ก็สามารถแพร่มาถึงได้. อุณภูมิที่เยือกเย็นไม่สามารถจำกัดวงของมันได้ตลอดไป.\n\nเริ่มลองใช้พลังงาน สร้างเครื่องกำเนิดไฟฟ้าเผาไหม้ เรียนรู้ที่จะใช้ menders. +zone.desertWastes.description = ของเสียพวกนี้กินบริเวณกว้าง คาดการณ์ไม่ได้ และมีสิ่งก่อสร้างที่ถูกถอดทิ้งอยู่\nมีถ่านหินอยู่ในบริเวณนี้. นำมันไปเผาเพื่อเปลี่ยนเป็นพลังงานหรือนำไปสังเคราะห์เป็นกราไฟต์\n\n[lightgray]ตำแหน่ง landing ไม่สามารถการันตีได้ +zone.saltFlats.description = ภายนอกเขตทะเลทรายเป็นที่ตั้งของ Salt Flats. พบทรัพยากรในบริเวณนี้ค่อนข้างน้อย\n\nศัตรูสร้างที่เก็บทรัพยากรไว้ที่นี่. กำจัด core ของพวกมัน. อย่าให้มีอะไรเหลือ +zone.craters.description = น้ำถูกเก็บสะสมในปล่องผู้เขาไฟนี้, เป็นสิ่งที่ตกทอดมาจากสงครามเก่า บุกเบิกพื้นที่ เก็บทราย เผากระจกเมต้า. ปั๊มน้ำมาใช้หล่อเย็นป้อมปืนและเครื่องขุด +zone.ruinousShores.description = อยู่ถัดไปจาก the wastes, คือเส้นชายทะเล. เมื่อก่อนนั้น, สถานที่นี้เป็นที่ตั้งของแนวป้องกันชายฝั่ง. ร่องรอยของมันหลงเหลือไม่มาก. เหลือแค่สิ่งก่อสร้างป้องกันพื้นฐานเท่านั้นที่ปราศจากอัตราย, อย่างอื่นทุกอย่างกลายเป็นเศษเหล็กทั้งหมด.\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 = พื้นที่ขั้นกลางระหว่างภูเขาสูงและ spore-ridden lands ที่ต่ำลงมา. ฐานทัพลาดตระเวนของศัตรูตั้งอยู่ที่นี่.\nทำลายมันซะ.\nใช้ยูนิต Dagger และ Crawler. ทำลาย core ทั้งสอง. +zone.impact0078.description = <ใส่คำบรรยายที่นี่> +zone.crags.description = <ใส่คำบรรยายที่นี่> + +settings.language = ภาษา +settings.data = ข้อมูลเกม +settings.reset = รีเซ็ตเป็นค่าเริ่มต้น +settings.rebind = Rebind +settings.controls = การควบคุม +settings.game = เกม +settings.sound = เสียง +settings.graphics = กราฟิก +settings.cleardata = เคลียร์ข้อมูลเกม... +settings.clear.confirm = คุณแน่ใจหรือว่าจะเคลียร์ข้อมูลเกม?\nสิ่งที่ทำไปแล้วจะไม่สามารถย้อนกลับได้! +settings.clearall.confirm = [scarlet]คำเตือน![]\nการกระทำนี้จะลบข้อมูลทั้งหมด นั้นรวมไปถึงเซฟ, แมพ, สิ่งที่ปลดล็อคแล้วและ keybinds.\nเมื่อคุณกด 'โอเค' เกมจะลบข้อมูลทุกอย่างและออกโดยอัตโนมัติ +paused = [accent]< หยุดชั่วคราว > +clear = เคลียร์ +banned = [scarlet]แบน +yes = ใช่ +no = ไม่ +info.title = ข้อมูล +error.title = [crimson]มีบางอย่างผิดพลาดเกิดขึ้น +error.crashtitle = มีบางอย่างผิดพลาดเกิดขึ้น +blocks.input = นำเข้า +blocks.output = ส่งออก +blocks.booster = บูสเตอร์ +block.unknown = [lightgray]??? +blocks.powercapacity = ความจุพลังงาน +blocks.powershot = หน่วยพลังงาน/นัด +blocks.damage = ดาเมจ +blocks.targetsair = ยิงอากาศยาน +blocks.targetsground = ยิงภาคพื้นดิน +blocks.itemsmoved = ความเร็วเคลื่อนที่ +blocks.launchtime = เวลาระหว่างการส่ง +blocks.shootrange = ระยะยิง +blocks.size = ขนาด +blocks.liquidcapacity = จุของเหลว +blocks.powerrange = ระยะพลังงาน +blocks.powerconnections = จำนวนการเชื่อมต่อสูงสุด +blocks.poweruse = ใช้พลังงาน +blocks.powerdamage = หน่วยพลังงาน/ดาเมจ +blocks.itemcapacity = จุไอเท็ม +blocks.basepowergeneration = กำเนิดพลังงานพื้นฐาน +blocks.productiontime = เวลาที่ใช้ในการผลิต +blocks.repairtime = เวลาที่ใช้ในการซ่อมแซมให้สมบูรณ์ +blocks.speedincrease = เพิ่มความเร็ว +blocks.range = ระยะ +blocks.drilltier = ขุดได้ +blocks.drillspeed = ความเร็วขุดพื้นฐาน +blocks.boosteffect = แอฟเฟ็คของบูสต์ +blocks.maxunits = จำนวนยูนิตสูงสุด +blocks.health = เลือด +blocks.buildtime = เวลาในการสร้าง +blocks.buildcost = ใช้ +blocks.inaccuracy = ความคลาดเคลื่อน +blocks.shots = นัด +blocks.reload = นัด/วินาที +blocks.ammo = กระสุน + +bar.drilltierreq = จำเป็นต้องใช้เครื่องขุดที่ดีกว่า +bar.drillspeed = ความเร็วขุด: {0}/s +bar.pumpspeed = ความเร็วปั้ม: {0}/s +bar.efficiency = ประสิทธิภาพ: {0}% +bar.powerbalance = พลังงาน: {0}/s +bar.powerstored = เก็บแล้ว: {0}/{1} +bar.poweramount = พลังงาน: {0} +bar.poweroutput = พลังงานออก: {0} +bar.items = ไอเท็ม: {0} +bar.capacity = ความจุ: {0} +bar.liquid = ของเหลว +bar.heat = ความร้อน +bar.power = พลังงาน +bar.progress = ความคืบหน้าในการสร้าง +bar.spawned = จำนวนยูนิตทั้งหมด: {0}/{1} + ยูนิต +bar.input = นำเข้า +bar.output = ส่งออก + +bullet.damage = [stat]{0}[lightgray] ดาเมจ +bullet.splashdamage = [stat]{0}[lightgray] ดาเมจกระจาย ~[stat] {1}[lightgray] ช่อง +bullet.incendiary = [stat]ติดไฟ +bullet.homing = [stat]ติดตาม +bullet.shock = [stat]ช็อค +bullet.frag = [stat]แตกออก +bullet.knockback = [stat]{0}[lightgray] ดันกลับ +bullet.freezing = [stat]แช่แข็ง +bullet.tarred = [stat]เปื้อนน้ำมัน +bullet.multiplier = [stat]{0}[lightgray]x จำนวนกระสุนต่อ 1 ไอเท็ม +bullet.reload = [stat]{0}[lightgray]x ความเร็วยิง + +unit.blocks = บล็อค +unit.powersecond = หน่วยพลังงาน/วินาที +unit.liquidsecond = หน่วยของเหลว/วินาที +unit.itemssecond = ไอเท็ม/วินาที +unit.liquidunits = หน่วยของเหลว +unit.powerunits = หน่วยพลังงาน +unit.degrees = องศา +unit.seconds = วินาที +unit.persecond = /วินาที +unit.timesspeed = เท่าเร็วขึ้น +unit.percent = % +unit.items = ไอเท็ม +category.general = ทั่วไป +category.power = พลังงาน +category.liquids = ของเหลว +category.items = ไอเท็ม +category.crafting = นำเข้า/ส่งออก +category.shooting = การยิง +category.optional = การเพิ่มประสิทธิภาพทางเลือก +setting.landscape.name = ล็อค Landscape +setting.shadows.name = เงา +setting.blockreplace.name = แนะนำบล็อคโดยอัตโนมัติ +setting.linear.name = การกรองเชิงเส้น +setting.hints.name = คำแนะนำ +setting.buildautopause.name = หยุดสร้างชั่วคราวแบบอัตโนมัติ +setting.animatedwater.name = แอนิเมชั่นน้ำ +setting.animatedshields.name = แอนิเมชั่นเกราะ +setting.antialias.name = Antialias[lightgray] (จำเป็นต้องรีสตาร์ท)[] +setting.indicators.name = ตัวบอกศัตรู/พักพวก +setting.autotarget.name = เล็งเป้าอัตโนมัติ +setting.keyboard.name = การควบคุมแบบ เม้าส์+คีย์บอร์ด +setting.touchscreen.name = การควบคุมแบบหน้าจอสัมผัส +setting.fpscap.name = FPS +สูงสุด +setting.fpscap.none = ไม่มี +setting.fpscap.text = {0} FPS +setting.uiscale.name = ขนาด UI[lightgray] (จำเป็นต้องรีสตาร์ท)[] +setting.swapdiagonal.name = การวางเป็นเส้นทแยงเสมอ +setting.difficulty.training = ฝึกซ้อม +setting.difficulty.easy = ง่าย +setting.difficulty.normal = ปานกลาง +setting.difficulty.hard = ยาก +setting.difficulty.insane = ยากมาก +setting.difficulty.name = ระดับความยาก: +setting.screenshake.name = การสั่นของจอ +setting.effects.name = แสดงเอฟเฟ็ค +setting.destroyedblocks.name = แสดงบล็อคที่ถูกทำลาย +setting.conveyorpathfinding.name = Pathfinding +ของการวางสายพาน +setting.sensitivity.name = ความไวของตัวควบคุม +setting.saveinterval.name = ระยะห่าวระหว่างเซฟ +setting.seconds = {0} วินาที +setting.fullscreen.name = เต็มจอ +setting.borderlesswindow.name = วินโดว์แบบไร้ขอบ[lightgray] (อาจจะต้องรีตาร์ท) +setting.fps.name = แสดง FPS และ Ping +setting.vsync.name = VSync +setting.pixelate.name = Pixelate[lightgray] (ปิดใช้งานแอนิเมชั่น) +setting.minimap.name = แสดงมินิแมพ +setting.position.name = แสดงตำแหน่งของผู้เล่น +setting.musicvol.name = ระดับเสียงเพลง +setting.ambientvol.name = ระดับเสียงล้อมรอบ +setting.mutemusic.name = ปิดเพลง +setting.sfxvol.name = ระดับเสียง SFX +setting.mutesound.name = ปิดเสียง +setting.crashreport.name = ส่งรายงานการแครชแบบไม่ระบุตัวตน +setting.savecreate.name = สร้างเซฟโดยอัตโนมัติ +setting.publichost.name = การมองเห็นเซิฟเวอร์สาธารณะ +setting.chatopacity.name = ความโปร่งแสงของแชท +setting.lasersopacity.name = ความโปร่งแสงของเลเซอร์พลังงาน +setting.playerchat.name = แสดงบับเบิ้ลแชทของผู้เล่น +public.confirm = คุณต้องการให้เกมของคุณเปิดเป็นสาธารณะหรือไม่?\n[accent]ทุกคนจะสามารถเข้าร่วมเกมของคุณได้.\n[lightgray]คุณสามารถเปลี่ยนการตั้งค่านี้ได้ที่ ตั้งค่า->เกม->การมองเห็นเซิฟเวอร์สาธารณะ. +public.beta = เกมเวอร์ชั่นเบต้าไม่สามารถเปิดเซิฟเวอร์สาธารณะได้ +uiscale.reset = ขนาดของ UI มีการเปลี่ยนแปลง\nกด "โอเค" เพื่อยืนยันขนาดนี้.\n[scarlet]เปลี่ยนกลับไปเป็นแบบเดิมและออกในอีก[accent] {0}[] วินาที... +uiscale.cancel = ยกเลิกและออก +setting.bloom.name = Bloom +keybind.title = ตั้งค่าปุ่ม +keybinds.mobile = [scarlet]การตั้งค่าปุ่มส่วนใหญ่ไม่สามารถใช้ในมือถือได้. เฉพาะการเคลื่อนไหวพื้นฐานเท่านั้นที่ใช้ได้. +category.general.name = ทั่วไป +category.view.name = วิว +category.multiplayer.name = ผู้เล่นหลายคน +command.attack = โจมตี +command.rally = ชุมนุม +command.retreat = ถอยกลับ +keybind.clear_building.name = เคลียร์สิ่งก็สร้าง +keybind.press = กดปุ่มใดก็ได้... +keybind.press.axis = กดแกนหรือปุ่มใดก็ได้... +keybind.screenshot.name = แมพ Screenshot +keybind.move_x.name = เคลื่อนที่ในแกน x +keybind.move_y.name = เคลี่อนที่ในแกน y +keybind.mouse_move.name = ตามเม้าส์ +keybind.schematic_select.name = เลือกภูมิภาค +keybind.schematic_menu.name = เมนู Schematic +keybind.schematic_flip_x.name = กลับ Schematic ในแกน X +keybind.schematic_flip_y.name = กลับ Schematic ในแกน Y +keybind.fullscreen.name = เปิด/ปิด Fullscreen +keybind.select.name = เลือก/ยิง +keybind.diagonal_placement.name = วางเป็นแนวทแยง +keybind.pick.name = เลือกบล็อค +keybind.break_block.name = ทุบบล็อค +keybind.deselect.name = ยกเลิกการเบือก +keybind.shoot.name = ยิง +keybind.zoom_hold.name = ซูม กดค้าง +keybind.zoom.name = ซูม +keybind.menu.name = เมนู +keybind.pause.name = หยุดชั่วคราว +keybind.pause_building.name = หยุด/สร้างต่อ +keybind.minimap.name = มินิแมะ +keybind.dash.name = พุ่ง +keybind.chat.name = แชท +keybind.player_list.name = รายชื่อผู้เล่น +keybind.console.name = คอนโซล์ +keybind.rotate.name = หมุน +keybind.rotateplaced.name = หมุนที่มีอยู่ (กดค้าง) +keybind.toggle_menus.name = เปิด/ปิด เมนู +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 = โหมดปกติ. ทรัพยากรมีจำกัดและ wave มาโดยอัตโนมัติ.\n[gray]ต้องมีสปาวน์ของศัตรูเพื่อที่จะเล่น. +mode.sandbox.name = Sandbox +mode.sandbox.description = ทรัพยาดรไม่จำกัดและ wave ไม่จับเวลา. +mode.editor.name = Editor +mode.pvp.name = PvP +mode.pvp.description = สู้กับผู้เล่นอื่น.\n[gray]แมพจำเป็นต้องมี 2 core ที่ไม่ใช่สีเดียวกัน. +mode.attack.name = โจมตี +mode.attack.description = ทำลายฐานของศัตรู ไม่มี wave.\n[gray]จำเป็นต้องมี core สีแดงเพื่อเล่น. +mode.custom = กฎแบบกำหนดเอง + +rules.infiniteresources = ทรัพยากรไม่จำกัด +rules.wavetimer = ตัวตั้งเวลา Wave +rules.waves = Waves +rules.attack = โหมดการโจมตี +rules.enemyCheat = AI (ทีมสีแดง) มีทรัพยากรไม่จำกัด +rules.unitdrops = ยูนิตดรอป +rules.unitbuildspeedmultiplier = ตัวคูณความเร็วในการสร้างยูนิต +rules.unithealthmultiplier = ตัวคูณเลือดของยูนิต +rules.playerhealthmultiplier = ตัวคูณเลือดผู้เล่น +rules.playerdamagemultiplier = ตัวคูณดาเมจผู้เล่น +rules.unitdamagemultiplier = ตัวคูณดาเมจยูนิต +rules.enemycorebuildradius = วงห้ามสร้างของ Core ศัตรู:[lightgray] (ช่อง) +rules.respawntime = ความเร็วในการเกิดใหม่:[lightgray] (วินาที) +rules.wavespacing = ระยะเวลาระหว่าง wave:[lightgray] (วินาที) +rules.buildcostmultiplier = ตัวคูณจำนวนทรัพยากรในการสร้าง +rules.buildspeedmultiplier = ตัวคูณความเร็วในการสร้าง +rules.waitForWaveToEnd = Waves รอศัตรู +rules.dropzoneradius = รัศมี Drop Zone:[lightgray] (ช่อง) +rules.respawns = เกิดใหม่สูงสุดต่อ wave +rules.limitedRespawns = จำกัดการเกิดใหม่ +rules.title.waves = Waves +rules.title.respawns = เกิดใหม่ +rules.title.resourcesbuilding = ทรัพยากรและสิ่งก่อสร้าง +rules.title.player = ผู้เล่น +rules.title.enemy = ศัตรู +rules.title.unit = ยูนิต + +content.item.name = ไอเท็ม +content.liquid.name = ของเหลว +content.unit.name = ยูนิต +content.block.name = บล็อค +content.mech.name = เม็ค +item.copper.name = ทองแดง +item.lead.name = ตะกั่ว +item.coal.name = ถ่านหิน +item.graphite.name = กราไฟต์ +item.titanium.name = ไทเทเนี่ยม +item.thorium.name = ทอเรี่ยม +item.silicon.name = ซิลิกอน +item.plastanium.name = พลาสตาเนี่ยม +item.phase-fabric.name = ใยเฟส +item.surge-alloy.name = เสิร์จอัลลอย +item.spore-pod.name = สปอร์พอท +item.sand.name = ทราย +item.blast-compound.name = สารประกอบระเบิด +item.pyratite.name = ไฟราไทต์ +item.metaglass.name = กระจกเมต้า +item.scrap.name = เศษเหล็ก +liquid.water.name = น้ำ +liquid.slag.name = กากแร่ +liquid.oil.name = น้ำมัน +liquid.cryofluid.name = ไครโยฟลูอิด +mech.alpha-mech.name = อัลฟ้า +mech.alpha-mech.weapon = เฮฟวี้รีพีทเตอร์ +mech.alpha-mech.ability = รีเจเนเรชั่น +mech.delta-mech.name = เดลต้า +mech.delta-mech.weapon = เครื่องกำเนิดประกายไฟฟ้า +mech.delta-mech.ability = ปล่อย +mech.tau-mech.name = เทา +mech.tau-mech.weapon = รีสตัคเลเซอร์ +mech.tau-mech.ability = เบิสต์ซ่อมแซม +mech.omega-mech.name = โอเมก้า +mech.omega-mech.weapon = ฝูงขีปนาวุธ +mech.omega-mech.ability = ตัวเสริมเกราะ +mech.dart-ship.name = ลูกดอก (Dart) +mech.dart-ship.weapon = รีพีตเตอร์ +mech.javelin-ship.name = หอก (Javelin) +mech.javelin-ship.weapon = ขีปนาวุธเบิสต์ +mech.javelin-ship.ability = ดิสชาร์จบูสเตอร์ +mech.trident-ship.name = ตรีศูล (Trident) +mech.trident-ship.weapon = ห้องเก็บระเบิด +mech.glaive-ship.name = เกลฟว์ +mech.glaive-ship.weapon = รีพีตเตอร์ไฟ +item.explosiveness = [lightgray]ค่าการระเบิด: {0}% +item.flammability = [lightgray]ไวไฟ: {0}% +item.radioactivity = [lightgray]ค่ากัมมันตภาพรังสี: {0}% +unit.health = [lightgray]เลือด: {0} +unit.speed = [lightgray]ความเร็ว: {0} +mech.weapon = [lightgray]อาวุธ: {0} +mech.health = [lightgray]เลือด: {0} +mech.itemcapacity = [lightgray]ความจุไอเท็ม: {0} +mech.minespeed = [lightgray]ความเร็วการขุด: {0}% +mech.minepower = [lightgray]พลังการขุด: {0} +mech.ability = [lightgray]ความสามารถ: {0} +mech.buildspeed = [lightgray]ความเร็วการสร้าง: {0}% +liquid.heatcapacity = [lightgray]ความจุความร้อน: {0} +liquid.viscosity = [lightgray]ความเหนียว: {0} +liquid.temperature = [lightgray]อุณหภูมิ: {0} + +block.sand-boulder.name = ก้อนหินทราย +block.grass.name = หญ้า +block.salt.name = เกลือ +block.saltrocks.name = หินเกลือ +block.pebbles.name = ก้อนกรวด +block.tendrils.name = ไม้เลื้อย +block.sandrocks.name = หินทราย +block.spore-pine.name = ต้นสนสปอร์ +block.sporerocks.name = หินสปอร์ +block.rock.name = หิน +block.snowrock.name = หินหิมะ +block.snow-pine.name = ต้นสนหิมะ +block.shale.name = หินดินดาน +block.shale-boulder.name = ก้อนหินดินดาน +block.moss.name = ตะไคร่น้ำ +block.shrubs.name = พุ่มไม้ +block.spore-moss.name = พุ่มไม้สปอร์ +block.shalerocks.name = หิน +block.scrap-wall.name = กำแพงงเศษเหล็ก +block.scrap-wall-large.name = กำแพงเศษเหล็กขนาดใหญ่ +block.scrap-wall-huge.name = กำแพงเศษเหล็กขนาดใหญ่มาก +block.scrap-wall-gigantic.name = กำแพงเศษเหล็กขนาดยักษ์ +block.thruster.name = ตรัสเตอร์ +block.kiln.name = เตาเผา +block.graphite-press.name = เครื่องอัดกราไฟต์ +block.multi-press.name = มัลติเพรสต์ +block.constructing = {0} [lightgray](กำลังก่อสร้าง) +block.spawn.name = จุดเกิดศัตรู +block.core-shard.name = Core: ชาร์ด +block.core-foundation.name = Core: ฟาวเดชั่น +block.core-nucleus.name = Core: นิวเคลียส +block.deepwater.name = น้ำลึก +block.water.name = น้ำ +block.tainted-water.name = น้ำเสีย +block.darksand-tainted-water.name = น้ำเสียบนทรายดำ +block.tar.name = น้ำมันดิบ +block.stone.name = หิน +block.sand.name = ทราย +block.darksand.name = ทรายดำ +block.ice.name = น้ำแข็ง +block.snow.name = หิมะ +block.craters.name = หลุมอุกกาบาต +block.sand-water.name = น้ำบนทราย +block.darksand-water.name = น้าบนทรายดำ +block.char.name = ชาร์ +block.holostone.name = หินโฮโล่ +block.ice-snow.name = น้ำแข็งหิมะ +block.rocks.name = หิน +block.icerocks.name = หินน้ำแข็ง +block.snowrocks.name = หินหิมะ +block.dunerocks.name = หินเนินทราย +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.dark-panel-1.name = แผ่นกระดานมืด 1 +block.dark-panel-2.name = แผ่นกระดานมืด 2 +block.dark-panel-3.name = แผ่นกระดานมืด 3 +block.dark-panel-4.name = แผ่นกระดานมืด 4 +block.dark-panel-5.name = แผ่นกระดานมืด 5 +block.dark-panel-6.name = แผ่นกระดานมืด 6 +block.dark-metal.name = เหล็กดำ +block.ignarock.name = หินอิกน่า +block.hotrock.name = หินร้อน +block.magmarock.name = หินแมกม่า +block.cliffs.name = หน้าผ่า +block.copper-wall.name = กำแพงทองแดง +block.copper-wall-large.name = กำแพงทองแดงขนาดใหญ่ +block.titanium-wall.name = กำแพงไทเทเนี่ยม +block.titanium-wall-large.name = กำแพงไทเทเนี่ยมขนาดใหญ่ +block.plastanium-wall.name = กำแพงพลาสตาเนี่ยม +block.plastanium-wall-large.name = กำแพงพลาสตาเนี่ยมขนาดใหญ่ +block.phase-wall.name = กำแพงเฟส +block.phase-wall-large.name = กำแพงเฟสขนาดใหญ่ +block.thorium-wall.name = กำแพงทอเรี่ยม +block.thorium-wall-large.name = กำแพงทอเรี่ยมขนาดใหญ่ +block.door.name = ประตู +block.door-large.name = ประตูขนาดใหญ่ +block.duo.name = ดูโอ +block.scorch.name = สคอร์ช +block.scatter.name = สแคทเทอร์ +block.hail.name = เฮแอล +block.lancer.name = แลนเซอร์ +block.conveyor.name = สายพาน +block.titanium-conveyor.name = สายพานไทเทเนี่ยม +block.armored-conveyor.name = สายพานเสริมเกราะ +block.armored-conveyor.description = เคลื่อนย้ายไอเท็มเร็วเท่ากับไทเทเนี่ยมแต่มีเกราะที่แข็งกว่า ไม่รับไอเท็มจากด้านข้างจากที่อื่นนอกจากสายพานด้วยกันเอง. +block.junction.name = ทางแยก +block.router.name = เร้าเตอร์ +block.distributor.name = เร้าเตอร์ขนาดใหญ่ +block.sorter.name = เครื่องแยก +block.inverted-sorter.name = เครื่องแยกกลับด้าน +block.message.name = ตัวเก็บข้อความ +block.overflow-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.separator.name = +เครื่องแยก +block.coal-centrifuge.name = เครื่องปั่นเหวี่งถ่านหิน +block.power-node.name = โหนดพลังงาน +block.power-node-large.name = โหนดพลังงานขนาดใหญ่ +block.surge-tower.name = เสาเสิร์จ +block.diode.name = ไดโอดแบตเตอรี่ +block.battery.name = แบตเตอรี่ +block.battery-large.name = แบตเตอรี่ขนาดใหญ่ +block.combustion-generator.name = เครื่องกำเนิดไฟฟ้าเผาไหม้ +block.turbine-generator.name = เครื่องกำเนิดไฟฟ้าไอน้ำ +block.differential-generator.name = เครื่องกำเนิดไฟฟ้าดิฟเฟอเร่นเชี่ยว +block.impact-reactor.name = เตาปฏิกรณ์อิมแพ็ค +block.mechanical-drill.name = เครื่องขุดเชิงกล +block.pneumatic-drill.name = เครื่องขุดนิวมาติก +block.laser-drill.name = เครื่องขุดเลเซอร์ +block.water-extractor.name = เครื่องขุดน้ำ +block.cultivator.name = เค้าติเวเตอร์ +block.dart-mech-pad.name = ฐานปล่อยเม็คอัลฟ้า +block.delta-mech-pad.name = ฐานปล่อยเม็คเดลต้า +block.javelin-ship-pad.name = ฐานปล่อยยานหอก (Javelin) +block.trident-ship-pad.name = ฐานปล่อยยานตรีศูล (Trident) +block.glaive-ship-pad.name = ฐานปล่อยยานเกลฟว์ +block.omega-mech-pad.name = ฐานปล่อยเม็คโอเมก้า +block.tau-mech-pad.name = ฐานปล่อยเม็คเทา (Tau) +block.conduit.name = รางน้ำ +block.mechanical-pump.name = ปั๊มเชิงกล +block.item-source.name = จุดกำเนิดไอเท็ม +block.item-void.name = จุดลบไอเท็ม +block.liquid-source.name = จุดกำเนิดของเหลว +block.power-void.name = จุดลบพลังงาน +block.power-source.name = พลังงานไม่จำกัด +block.unloader.name = ตัวถ่ายของ +block.vault.name = Vault +block.wave.name = เวฟ +block.swarmer.name = สวอร์มเมอร์ +block.salvo.name = ซาวโว +block.ripple.name = ริปเปิ้ล +block.phase-conveyor.name = สายพานเฟส +block.bridge-conveyor.name = สะพานสายพาน +block.plastanium-compressor.name = เครื่องอัดพลาสตาเนียม +block.pyratite-mixer.name = เครื่องผสมไพราไทต์ +block.blast-mixer.name = เครื่องผสมสารประกอบระเบิด +block.solar-panel.name = แผงโซล่าเซลล์ +block.solar-panel-large.name = แผงโซล่าเซลล์ขนาดใหญ่ +block.oil-extractor.name = เครื่องขุดน้ำมัน +block.command-center.name = ศูนย์สั่งการ +block.draug-factory.name = โรงงานผลิตโดรนขุดเจาะดราคจ์ +block.spirit-factory.name = โรงงานผลิตโดรนซ่อมแซมสปิริต +block.phantom-factory.name = โรงงานผลิตโดรนก่อสร้างแฟนทอม +block.wraith-factory.name = โรงงานผลิตยานไฟท์เตอร์ไวรท์ +block.ghoul-factory.name = โรงงานผลิตยานทิ้งระเบิดGhoul +block.dagger-factory.name = โรงงานผลิตแด็กเกอร์เม็ค +block.crawler-factory.name = โรงงานผลิตครอเลอร์เม็ค +block.titan-factory.name = โรงงานผลิตไททันเม็ค +block.fortress-factory.name = โรงงานผลิตฟอร์เทรสเม็ค +block.revenant-factory.name = โรงงานผลิตยานไฟต์เตอร์เรเวแนนท์ +block.repair-point.name = จุดซ่อมแซม +block.pulse-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 = เตาปฏิกรณ์ทอเรี่ยม +block.mass-driver.name = แมสไดรฟ์เวอร์ +block.blast-drill.name = เครื่องขุดแบบแอร์แบลสต์ +block.thermal-pump.name = ปั๊มเทอร์มอล +block.thermal-generator.name = เครื่องกำเนิดไฟฟ้าจากความร้อน +block.alloy-smelter.name = เตาเผาอัลลอย +block.mender.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.arc.name = อาร์ค +block.rtg-generator.name = เครื่องกำเนิดไฟฟ้า อาร์ทีจี +block.spectre.name = สเปคเตร +block.meltdown.name = เมลท์ดาวน์ +block.container.name = ที่เก็บของ +block.launch-pad.name = ฐานส่งของ +block.launch-pad-large.name = ฐานส่งของขนาดใหญ่ +team.blue.name = น้ำเงิน +team.crux.name = แดง +team.sharded.name = ส้ม +team.orange.name = ส้ม +team.derelict.name = derelict +team.green.name = เขียว +team.purple.name = ม่วง +unit.spirit.name = โดรนซ่อมแซมสปิริต +unit.draug.name = โดรนขุดเจาะดราคจ์ +unit.phantom.name = โดรนก่อสร้างแฟนทอม +unit.dagger.name = แด็กเกอร์ +unit.crawler.name = ครอเลอร์ +unit.titan.name = ไททัน +unit.ghoul.name = ยานทิ้งระเบิดGhoul +unit.wraith.name = ยานไฟต์เตอร์ไวรท์ +unit.fortress.name = ฟอร์เทรส +unit.revenant.name = เรเวแนน +unit.eruptor.name = อีรัฟเตอร์ +unit.chaos-array.name = เคออสอาเรย์ +unit.eradicator.name = อีเรดิเคเตอร์ +unit.lich.name = ลิช +unit.reaper.name = รีฟเฟอร์ +tutorial.next = [lightgray]<กดเพื่อดำเนินการต่อ> +tutorial.intro = คุณได้เข้าสู่[scarlet] การสอนเล่นของ Mindustry.[]\nใช้ [[WASD] เพื่อเคลื่อนที่.\n[accent]กด [[Ctrl] ค้างระหว่างกลิ้งลูกกลิ้งเม้าส์[] เพื่อซูมเข้าและออก.\nเริ่มด้วยการ[accent] ขุดทองแดง[]. เคลื่อนที่ไปใกล้มัน, แล้วกดที่สายแร่ทองแดงใกล้ๆกับ core ของคุณ\n\n[accent]ทองแดง {0}/{1} ชิ้น +tutorial.intro.mobile = คุณได้เข้าสู่[scarlet] การสอนเล่นของ Mindustry.[]\nเลื่อนหน้าจอเพื่อเคลื่อนที่.\n[accent]ใส่สองนิ้ว []เพื่อซูมเข้าและออก.\nเริ่มด้วยการ[accent] ขุดทองแดง[]. เคลื่อนที่ไปใกล้มัน, แล้วกดที่สายแร่ทองแดงใกล้ๆกับ core ของคุณ\n\n[accent]ทองแดง {0}/{1} ชิ้น +tutorial.drill = ขุดด้วยตัวเองนั้นไม่ค่อยมีประสิทธิภาพ.\n[accent]เครื่องขุด []สามารถขุดได้แบบอัตโนมัติ.\nกดที่แทปเครื่องขุดที่มุมล่างขวา.\nเลือก[accent] เครื่องขุดเชิงกล[]. วางมันบนสายแร่ทองแดงด้วยการคลิ๊ก.\n[accent]คลิ๊กขวา[] เพื่อหยุดการสร้าง. +tutorial.drill.mobile = ขุดด้วยตัวเองนั้นไม่ค่อยมีประสิทธิภาพ.\n[accent]เครื่องขุด []สามารถขุดได้แบบอัตโนมัติ.\nกดที่แทปเครื่องขุดที่มุมล่างขวา.\nเลือก[accent] เครื่องขุดเชิงกล[].\nวางมันบนสายแร่ทองแดงด้วยการกดแล้วกดที่[accent] เครื่องหมายถูก[] ด้านล่างเพื่อคอนเฟิร์ม.\nกด[accent] ปุ่ม X[] เพื่อยกเลิกการวาง. +tutorial.blockinfo = บล็อคแต่ละบล็อคจะมีแสต็ทที่ต่าง. เครื่องขุดแต่ละเครื่องจะขุดได้เฉพาะบางแร่.\nสามารถเช็คข้อมูลและแสต็ทของบล็อคได้โดย,[accent] กดที่ปุ่ม "?" เมื่อเลือกบล็อคนั้นๆในเมนูการสร้าง.[]\n\n[accent]เข้าไปในแสต็ทของเครื่องขุดเชิงกลชลสิ.[] +tutorial.conveyor = [accent]สายพาน[] ใช้สำหรับขนส่งไอเท็มไปยัง core.\nสร้างเส้นสายพานจากเครื่องขุดมายัง core สิ.\n[accent]กดปุ่มเม้าส์ค้างเพื่อจะสร้างเส้น.[]\nกด[accent] CTRL[] ค้างตอนลากเส้นเพื่อลากเส้นทแยง.\nใช้ลูกกลิ้งเม้าส์เพื่อหมุนบล็อคก่อนที่จะวาง.\n[accent]วางสายพาน 2 อันด้วยเครื่องมือลากเส้น แล้วส่งไอเท็มไปยัง core. +tutorial.conveyor.mobile = [accent]สายพาน[] ใช้สำหรับขนส่งไอเท็มไปยัง core.\nวางสายพาน 2 อันด้วยเครื่องมือลากเส้น แล้วส่งไอเท็มไปยัง core.\n[accent] ลากเส้นโดยกดที่หน้าจอค้างสัก 1-2 วินาที[] แล้วลากไปทางที่ต้องการสร้าง\n\n[accent]วางสายพาน 2 อันด้วยเครื่องมือลากเส้น แล้วส่งไอเท็มไปยัง core. +tutorial.turret = หลังจากทีาไอเท็มเข้า core แล้ว, เราจะสามารถใช้มันในการก่อสร้างได้.\nจงจำไว้ว่าไอเท็มบางอันเท่านั้นที่สามารถใช้ในการก่อสร้างได้.\nตัวอย่างไอเท็มที่ไม่ได้ใช่ในการก่อสร้างได้แก่[accent] ถ่านหิน[] และ[accent] เศษเหล็ก[], ไม่สามารถใส่ใน core ได้.\nสิ่งก่อสร้างเชิงป้องกันจำเป็นสำหรับการขับไล่[lightgray] ศัตรู[].\nสร้าง[accent] ป้อมปืนดูโอ้[] ใกล้กับฐานของคุณ. +tutorial.drillturret = ป้อมปืนดูโอ้ใช้[accent] กระสุนทองแดง []ในการยิง.\nวางเครื่องขุดใกล้กับป้อมปืน.\nชี้ทางสายพานให้เข้าป้อมปืนเพื่อที่จะเติมทองแดงให้มัน.\n\n[accent]ส่งกระสุนแล้ว: 0/1 +tutorial.pause = ระหว่างการต่อสู้, คุณสามารถ[accent]หยุดเกมชั่วคราวได้.[]\nคุณอาจจะทำคิวการสร้างระหว่างหยุดเกมชั่วคราว.\n\n[accent]กด space เพื่อหยุดเกมชั่วคราว. +tutorial.pause.mobile = ระหว่างการต่อสู้, คุณสามารถ[accent] หยุดเกมชั่วคราวได้.[]\nคุณอาจจะทำคิวการสร้างระหว่างหยุดเกมชั่วคราว.\n\n[accent]กดปุ่มที่มุมบนซ้ายเพื่อหยุดเกมชั่วคราว. +tutorial.unpause = กด Space อีกครั้งเพื่อเล่นต่อ. +tutorial.unpause.mobile = กดอีกครั้งเพื่อเล่นต่อ. +tutorial.breaking = บล็อดจำเป็นต้องทำลายบ่อยครั้ง.\n[accent]กดคลิ๊กขวาค้าง[] เพื่อทำลายบล็อคที่เลือก.[]\n\n[accent]ทำลายบล็อคเศษเหล็กทั้งหมดที่ยู่ทางด้านซ้ายของ core ของคุณโดยใช้การเลือกแบบคลุมพื้นที่. +tutorial.breaking.mobile = บล็อดจำเป็นต้องทำลายบ่อยครั้ง.\n[accent]เลือกโหลดทำลาย[], แล้วกดบล็อคที่ต้องการทำลายเพื่อเริ่มทำลายมัน.\nทำลายเป็นพื้นที่ด้วยการกดค้าง 1-2 วินาที[] แล้วลากคลุมพื้นที่ที่ต้องการ.\nกดเครื่องหมายถูกเพื่อยืนยันการทำลาย.\n\n[accent]ทำลายบล็อคเศษเหล็กทั้งหมดที่ยู่ทางด้านซ้ายของ core ของคุณโดยใช้การเลือกแบบคลุมพื้นที่. +tutorial.withdraw = ในบางเหตุการณ์, การนำไอเท็มออกจากบล็อคนั้นจำเป็น.\nวิธีทำคือ, [accent]กดที่บล็อค[] ที่มีไอเท็มอยู่, แล้ว [accent]กดไอเท็ม[] ในช่องเก็บของ.\nไอเท็มหลายๆอันสามารถนำออกมาได้โดย [accent]กดแล้วกดค้างที่ช่องเก็บของ[].\n\n[accent]นำทองแดงจำนวนหนึ่งออกจาก core.[] +tutorial.deposit = นำไอเท็มเข้าบล็อคโดยลากไอเท็มจากยานของคุณไปที่บล็อคที่ต้องการ.\n\n[accent]เอาทองแดงกลับเข้า core.[] +tutorial.waves = [lightgray]ศัตรู[] กำลังมา.\n\nปกป้อง core ของคุณเป็นเวลา 2 wave.[accent] คลิ๊ก[] เพื่อยิง.\nสร้างป้อมปืนและเครื่องขุดเพิ่ม ขุดทองแดงเพิ่ม. +tutorial.waves.mobile = [lightgray]ศัตรู[] กำลังมา.\n\nปกป้อง core ของคุณเป็นเวลา 2 wave. ยานของคุณจะยิงศตรูโดยอัตโนมัติ.\nสร้างป้อมปืนและเครื่องขุดเพิ่ม ขุดทองแดงเพิ่ม. +tutorial.launch = เมื่อ wave เฉพาะแล้ว, คุณจะสามารถ[accent] ส่ง core[], ทิ้งระบบป้องกันทั้งหมดและ[accent] ได้รับทรัพยากรทั้งหมดใน core.[]\nทรัพยากรพวกนี้สามารถนำไปใช้ในการวิจัยเทคโนโลยีใหม่.\n\n[accent]กดปุ่มส่ง. + +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.surge-alloy.description = อัลลอยขั้นสูงที่มีคุณสมบัติทางไฟฟ้าจำเพาะ +item.spore-pod.description = กระเปาะของสปอร์สังเคราะห์, สั้งเคราะห์จากการรวมตัวของบรรยากาศ ใช้ในอุตสาหกรรม. ใช้ในการกลั่นเป็นน้ำมัน,ระเบิดและเชื้อเพลิง. +item.blast-compound.description = สารประกอบที่ไม่เสถียร ใช้ในระเบิด. สังเคราะห์จากสปอร์และสารระเหยอื่นๆ. ไม่แนะนำให้ใช้เป็นเชื้อเพลิง. +item.pyratite.description = สสารติดไฟง่าย ใช้ในอาวุธเพลิง. +liquid.water.description = ของเหลวที่มีประโยชน์ที่สุด ทั่วไปใช้เป็นตัวหล่อเย็นและในการจัดการของเสีย. +liquid.slag.description = โลหะหลายชนิดหลอมรวมกัน. สามารถนำไปแยกเพื่อเอาโลหะที่เป็นส่วนประกอบหรือพ่นใส่ศัตรูเป็นอาวุธ. +liquid.oil.description = ของเหลวใช้ในการผลิตวัสดุขั้นสูง. สามารถแปลงเเป็นถ่านหินเพือใช้เป็นเชื้องเพลิง หรือพ่นใส่ศัตรูแล้วจุดไฟเป็นอาวุธ. +liquid.cryofluid.description = ของเหลวเฉื่อยและไม่กัดกร่อน ผลิตจากน้ำและไทเทเนี่ยม. มีสมบัติการถ่ายเทความร้อนสูง. ใช้อย่างแพร่หลายในการหล่อเย็น. +mech.alpha-mech.description = เม็คควบคุมพื้นฐาน. มีรากฐานมาจากยูนิตแด๊กเกอร์, เพิ่มเกราะและความสามารถในการสร้าง. ทำดาเมจมากกว่ายานลูกดอก (Dart). +mech.delta-mech.description = เม็คที่เร็วและมีเกราะที่บาง สร้างมาเพื่อการต่อสู้แบบ hit-and-run (จู่โจมแล้วหนี). ทำดาเมจน้อยต่อสิ่งก่อสร้าง แต่สามารถฆ่าศัตรูกลุ่มใหญ่ได้อย่างรวดเร็วด้วยอาวุธอาร์คไฟฟ้า. +mech.tau-mech.description = เม็คสนับสนุน. ซ่อมแซมบล็อคของพันธมิตรด้วยการยิงใส่มัน. สามารถฟื้นฟูพันธมิตรในวงกลมระยะหนึ่ง. +mech.omega-mech.description = เม็คเกราะหนาและเทอะทะ, ผลิตมาเพื่อการจู่โจมแนวหน้า. เกราะสามารถกันดาเมจได้ถึง 90%. +mech.dart-ship.description = เม็คควบคุมพื้นฐาน. ค่อนข้างเร็วและเบา, แต่มีความสามารถในการต่อสู่ต่ำ เช่นเดียวกับความเร็วการขุด. +mech.javelin-ship.description = ยานต่อสู้แบบ hit-and-run (จู่โจมแล้วหนี). ถึงแม้ว่าจะช้า, แต่สามารถเร่งความเร็วได้มากถ้าบินโฉบผ่านด่านของศัตรู, ทำดาเมจค่อนข้างแรงด้วยไฟฟ้าและขีปนาวุธ. +mech.trident-ship.description = ยานทิ้งระเบิดหนักง, ผลิตเพื่อการก่อสร้างและทำลายแนวป้องกันของศัตรู. เกราะค่อนข้างหน้า. +mech.glaive-ship.description = ยานจู่โจมที่เกราะหนาและใหญ่. ติดด้วยรีพีทเตอร์ไฟ, คล่องแคลวมาก. +unit.draug.description = โดรนขุดเจาะดั้งเดิม. ผลิตง่าย. ขยายได้. ขุดทองแดงและตะกั่วโดยอัตโนมัติในบริเวณใกล้เคียง. ส่งทรัพยากรที่ขุดได้ไปยัง core ที่ใกล้ที่สุด. +unit.spirit.description = โดรนดราคจ์ที่ถูกปรับแต่ง, ออกแบบมาเพื่อการซ่อมแซมแทนการขุดเจาะ. ซ่อมแซมบล็อคที่โดนดาเมจโดยอัตโนมัติในบริเวณนั้น +unit.phantom.description = โดรนขั้นสูง. ติดตามผู้ใช้. ช่วยสร้างบล็อค. +unit.dagger.description = เม็คภาคพื้นดินพื้นฐานที่สุด. ผลิตง่าย. ทำลายล้างดีถ้าใช้เป็นฝูง. +unit.crawler.description = ยูนิตภาคพื้นดินประกอบด้วยเฟรมเปลือยและระเบิดขั้นรุนแรงติดด้านบน. ระเบิดเมื่อแตะต้องกับศัตรู. +unit.titan.description = ยูนิตเสริมเกราะภาคพื้นดินขั้นสูง. โจมตีทั้งภาคพื้นดินและอากาศ. มีปืนไฟระดับสคอร์ชติดตั้งอยู่. +unit.fortress.description = เม็คปืนใหญ่. มีปืนใหญ่ดัดแปลงประเภทเฮแอลติดจั้งอยู่ 2 กระบอกสำหรับการโจมตีสิ่งก่อสร้างและยูนิตของศัตรูจากระยะไกล. +unit.eruptor.description = เม็คหนักออกแบบมาเพื่อทำลายสิ่งก่อสร้าง. พ่นกากแร่ใส่แนวป้องกันของศัตรู, หลอมเหลวพวกมันและจุดสารระเหยให้ติดไฟ. +unit.wraith.description = ยูนิตอินเตอร์เซ็ปเตอร์แนว hit-and-run (จู่โจมแล้วหนี) ที่เร็ว. เล็งเป้าที่เครื่องกำเนิดไฟฟ้าทุกชนิด. +unit.ghoul.description = ยานทิ้งระเบิดปูพร่มหนัก (carpet bomber). ทะลวงผ่านสิ่งก่อสร้างศัตรู, เล็งเป้าที่จุดวิกฤตของสิ่งก่อสร้าง. +unit.revenant.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.cryofluidmixer.description = ผสมน้ำและผงไทเทเนี่ยมบริสุทธิ์เป็นไครโยฟลูอิด. สำคัญสำหรับเตาปฏิกรณ์ทอเรี่ยม. +block.blast-mixer.description = บอและผสมสปอร์กับไพไรต์เพื่อผลิตสารประกอบระเบิด. +block.pyratite-mixer.description = ผสมถ่านหิน, ตะกั่วและทรายเข้าด้วยกันเป็นไฟไรต์ที่ติดไฟได้ง่าย. +block.melter.description = หลอมเศษเหล็กเป็กกากแร่เพื่อใช้สำหรับกระบวนการต่อไปหรือใช้ในป้อมปืนเวฟ. +block.separator.description = แยกกากแร่ออกเป็นส่วนประกอบแร่ธาตุของมัน. ส่งออกแร่ผลลัพธ์ในรูปแบบที่เย็นลงแล้ว. +block.spore-press.description = อัดกระเปาะสปอร์ด้วยแรงกดมหาศาลเพื่อสังเคราะห์น้ำมัน. +block.pulverizer.description = บดเศษเหล็กให้เป็นทรายละเอียด. +block.coal-centrifuge.description = ทำให้น้ำมันแข็งตัวเป็นก้อนถ่านหิน. +block.incinerator.description = ทำลายไอเท็มหรือของเหลวทุกอย่างที่ได้รับมา. +block.power-void.description = ทิ้งพลังงานทั้งหมดที่ได้รับ. เฉพาะ Sandbox เท่านั้น. +block.power-source.description = ส่งออกพลังงานไม่จำกัด. เฉพาะ Sandbox เท่านั้น. +block.item-source.description = ส่งออกไอเท็มไม่จำกัด. เฉพาะ Sandbox เท่านั้น. +block.item-void.description = ทำลายทุกไอเท็ม . เฉพาะ Sandbox เท่านั้น. +block.liquid-source.description = ส่งออกของเหลวไม่จำกัด. เฉพาะ Sandbox เท่านั้น. +block.copper-wall.description = บล็อคป้องกันราคาถูก.\nมีประโยชน์สำหรับป้องกัน core และป้อมปืนใน wave แรกๆ. +block.copper-wall-large.description = บล็อคป้องกันราคาถูก.\nมีประโยชน์สำหรับป้องกัน core และป้อมปืนใน wave แรกๆ.\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 = A wall coated with special phase-based reflective compound. Deflects most bullets upon impact. +block.phase-wall-large.description = A wall coated with special phase-based reflective compound. Deflects most bullets upon impact.\nคลอบคลุมหลายช่อง. +block.surge-wall.description = บล็อคป้องกันที่มีทนทานสูง.\nสะสมพลังงานจากกระสุน, แล้วปล่อยออกมาแบบสุ่ม. +block.surge-wall-large.description = บล็อคป้องกันที่มีทนทานสูง.\nสะสมพลังงานจากกระสุน, แล้วปล่อยออกมาแบบสุ่ม.\nคลอบคลุมหลายช่อง. +block.door.description = ประตูขนาดเล็ก. สามารถเปิดได้โดยการกด. +block.door-large.description = ประตูขนาดใหญ่. สามารถเปิดได้โดยการกด.\nคลอบคลุมหลายช่อง. +block.mender.description = ซ่อมแซมบล็อคในวงของมันเป็นระยะๆ. ช่วยซ่อมแซมแนวป้องกันระหว่าง wave.\nสามารถใช้ซิลิก้อนเพื่อเพิ่มรัศมีและประสิทธิภาพได้ +block.mend-projector.description = เมนเดอร์ที่ได้รับการอัปเกรด. ซ่อมแซมบล็อคในระยะของมัน.\nสามารถใช้ใยเฟสเพื่อเพิ่มระยะและประสิทธิภาพได้. +block.overdrive-projector.description = เพิ่มความเร็วของสิ่งก่อสร้างรอบๆ.\nสามารถใช้ใยเฟสเพื่อเพิ่มระยะและประสิทธิภาพ. +block.force-projector.description = สร้างสนามพลังงานหกเหลี่ยมรอบๆตัวเอง ป้องกันสิ่งก่อสร้างและยูนิตภายในสนามพลังงานจากดาเมจ.\nจะร้อนจัดถ้าได้รับดาเมจมากพอ. สามารถใช้สารหล่อเย็นมากันการร้อนจัดได้. สามารถเพิ่มขนาดสนามพลังด้วยใยเฟส. +block.shock-mine.description = ดาเมจศัตรูที่เหยียบ. แถบจะล่องหนต่อศัตรู. +block.conveyor.description = บล็อคขนส่งไอเท็มพื้นฐาน. เคลื่อนไอเท็มไปข้างหน้าและใส่ลงบล็อคโดยอัตโนมัติ. สามารถหมุนได้. +block.titanium-conveyor.description = บล็อคขนส่งไอเท็มขั้นสูง. เคลื่อนไอเท็มเร็วกว่าสายพานทั่วไป. +block.junction.description = มีหน้าที่เป็นสะพานสำหรับสายพาน 2 สายข้ามกัน. มีประโยชน์สำหรับเวลาสายพาน 2 สายที่ขนไอเท็มมา 2 ชนิดไปยัง 2 สถานที่. +block.bridge-conveyor.description = บล็อคขนส่งไอเท็มขั้นสูง. ทำให้สามารถส่งไอเท็มข้ามบล็อคใดก็ได้ 3 ช่อง. +block.phase-conveyor.description = บล็อคขนส่งไอเท็มขั้นสูง. ใช้พลังงานเพื่อส่งไอเท็มไปยังสายพานเฟสอีกอัน ข้ามได้หลายช่อง. +block.sorter.description = แยกไอเท็ม. ถ้าไอเท็มตรงกับที่เลือกไว้, จะผ่านได้. แต่ถ้าไม่ตรง, ไอเท็มจะออกทางซ้ายหรือขวา (ใช้ทางที่ไอเท็มเข้าเป็นหลัก) +block.inverted-sorter.description = แยกไอเท็มคล้ายเครื่องแยกธรรมดา, แต่ไอเท็มที่เลือกจะออกข้างแทน. +block.router.description = รับไอเท็มแล้วส่งออก 3 ทางเท่ากัน. มีประโยชน์สำหรับแยกไอเท็มจากแหล่งเดียวไปหลายที่.\n\n[scarlet]อย่าวางไว้ติดกับทางส่งไอเท็มเข้าเพราะของออกจะไปอุดตันได้.[] +block.distributor.description = เร้าเตอร์ขั้นสูง. แยกไอเท็มออก 7 ทางอย่างเท่าๆกัน. +block.overflow-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.liquid-router.description = รับของเหลวจากทางเดียวแล้วส่งออก 3 ทางเท่าๆกัน. สามารถเก็บของ้หลวได้จำนวนหนึ่ง. มีประโยชน์สำหรับการแยกของเหลวจากแหล่งเดียวไปหลายที่. +block.liquid-tank.description = เก็บของเหลวจำนวนมาก. ใช่สำหรับสร้างบัฟเฟอร์ในเวลาที่ความต้องการของทรัพยากรไม่คงที่หรือเป็นตัวเซฟสำหรับบล็อคที่จำเป็นต้องใช้การหล่อเย็น. +block.liquid-junction.description = ทำหน้าที่เป็นสะพานสำหรับรางน้ำ 2 รางที่ข้ามกันที่มีของเหลว 2 ชนิด ซึ่งต้องการจะไปคนละที่. +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.battery-large.description = เก็บพลังงานได้เยอะกว่าแบตเตอรี่ธรรมดา. +block.combustion-generator.description = ผลิตพลังงานโดยการวัสดุติดไฟ เช่นถ่านหิน. +block.thermal-generator.description = ผลิตพลังงานเมื่อวานในที่ร้อน (บนหินร้อนหรือหินแม็คม่า) +block.turbine-generator.description = เครื่องกำเนิดไฟฟ้าเผาไหม้ขั้นสูง. ประสิทธิภาพสูงกว่า แต่ต้องใช้น้ำด้วยเพื่อผลิตไอน้ำ. +block.differential-generator.description = ผลิตไฟฟ้าจำนวนมาก. ใช้ความต่างของอุณหภูมิระหว่างไครโยฟลูอิดและไพไรต์ที่กำลังไหม้. +block.rtg-generator.description = เครื่องกำเนิดไฟฟ้าที่ใช้ง่ายและไว้ใจได้. ใช้ความร้อนจากการสลายของสารกัมมัตภาพรังสีเพื่อใช้ผลิตพลังงานอย่างช้าๆ. +block.solar-panel.description = ให้พลังงานจากแสงอาทิตย์จำนวนน้อย. +block.solar-panel-large.description = เวอร์ชั่นของแผงโซล่าเซลล์ที่มีประสิทธิภาพมากขึ้นกว่าแผงโซล่าเซลล์ธรรมดา. +block.thorium-reactor.description = ผลิตพลังงานจำนวนมากจากทอเรี่ยม. ตำเป็นต้องใช้สารหล่อเย็นตลอดเวลา. จะระเบิดอย่างรุนแรงหากไม่ได้รับสารหล่อเย็นในจำนวนที่ต้องการ. จำนวนพลังงานที่ผลิตขึ้นอยู่กับความเต็ม และผลิตพลังงานเริ่มต้นที่ความสามารถสูงสุด. +block.impact-reactor.description = เครื่องกำเนิดไฟฟ้าขั้นสูง, สามารถผลิตไฟฟ้าได้จำนวนมหาศาลที่ประสิทธิภาพสูงสุด. จำเป็นต้องใช้พลังงานจำนวนมากในการสตาร์ทเครื่อง. +block.mechanical-drill.description = เครื่องขุดราคาถูก. เมื่อวางบนบล็อคที่ถูกต้อง, จะส่งไอเท็มของมันออกมาเรื่อยๆแบบไม่มีที่สิ้นสุด. ขุดได้แค่ทรัพยากรพื้นฐาน. +block.pneumatic-drill.description = เครื่องขุดได้รับการปรับปรุง, สามารถขุดไทเทเนี่ยมได้. ขุดไวกว่าเครื่องขุดเชิงกล. +block.laser-drill.description = ขุดได้เร็วขึ้นด้วยเทคโนโลยีเลเซอร์ แต่ต้องใช้พลังงาน. สามารถขุดทอเรี่ยมได้. +block.blast-drill.description = เครื่องขุดขั้นสุดยอด. ใช้พลังงานจำนวนมาก. +block.water-extractor.description = ขุดน้ำบาดาล. ใช้ในพื้นที่ที่ไม่มีน้ำบนดินให้ใช้. +block.cultivator.description = รวบรวมสปอร์ในชั้นบรรยากาศเป็นกระเปาะสปอร์สำหรับอุตสาหกรรม. +block.oil-extractor.description = ใช้พลังงาน, ทรายและน้ำเพื่อขุดหาน้ำมัน. +block.core-shard.description = core รุ่นแรก. เมื่อถูกทำลาย การติดต่อกับพื้นที่นั้นทั้งหมดจะหายไป. อย่าให้มันเกิดขึ้น. +block.core-foundation.description = core รุ่นที่ 2 . เสริมเกราะมากขึ้น. เก็บของได้เยอะขึ้น. +block.core-nucleus.description = core รุ่นที่ 3 และเป็นรุ่นสุดท้าย. เสริมเกราะดีมาก. เก็บของได้มหาศาล. +block.vault.description = เก็บของแต่ละชนิดได้เยอะ. สามารถใช้ตัวถ่ายของในการดึงของออกมาได้. +block.container.description = เก็บของแต่ละชนิดได้น้อย. สามารถใช้ตัวถ่ายของในการดึงของออกมาได้. +block.unloader.description = ดึงของออกมาจากบล็อคที่ไม่ใช่บล็อคขนส่งใกล้เคียง. สามารถเปลี่ยนชนิดของของที่จะดึงได้โดยการกด. +block.launch-pad.description = ส่งของจำนวนหนึ่งได้เลยโดยไม่ต้องรอส่ง core. +block.launch-pad-large.description = ฐานส่งของเวอร์ชั่นพัฒนาแล้ว. เก็บไอเท็มเยอะขึ้น. ส่งของบ่อยขึ้น. +block.duo.description = ป้อมปืนราคาถูกขนาดเล็ก. มีประโยชน์สำหรับยูนิตภาคพื้นดิน. +block.scatter.description = ป้อมปืนต่อต้านอากาศยานหลัก. ยิงก้อนตะกั่วหรือเศษเหล็กใส่ศัตรู. +block.scorch.description = เผาศัตรูภาคพื้นดินที่อยู่ใกล้ๆ. มีประสิทธิภาพสูงสุดเมื่อใช้ในระยะใกล้. +block.hail.description = ป้อมปืนใหญ่ขนาดเล็ก. +block.wave.description = ป้อมปืนขนาดกลาง. พ่นของเหลวสานศัตรู. ดับไฟให้โดยอัตโนมัติถ้าใส่น้ำให้. +block.lancer.description = ป้อมปืนเลเซอร์ต่อต้านภาคพื้นดินขนาดกลาง. ชาร์จและยิงลำแสงพลังงานที่ทรงพลัง. +block.arc.description = ป้อมปืนไฟฟ้าระยะใกล้. ยิงสายฟ้าใส่ศัตรู. +block.swarmer.description = ป้อมยิงขีปนาวุธขนาดกลาง. โจมตีศัตรูทั้งอากาศและภาคพื้นดิน. ยิงขีปนาวุธขนิดติดตาม. +block.salvo.description = ป้อมปืนดูโอเวอร์ชั่นขั้นสูงกว่า. ระดมยิงกระสุนใส่ศัตรู. +block.fuse.description = ป้อมปืนระยะใกล้ขนาดใหญ่. ยิงลำแสงทะลุทะลวง 3 เส้นใส่ศัตรู. +block.ripple.description = ป้อมปืนใหญ่ที่มีพลังงานสูง. ยิงกระจุกของกระสุนใส่ศัตรูจาดระยะไกล. +block.cyclone.description = ป้อมปืนต่อต้านอากาศยานและต่อต้านภาคพื้นดิน. ยิงกระจุของกระสุนระเบิดใส่ยูนิตศัตรู. +block.spectre.description = ปืนใหญ่ลำกล้องคูขนาดยักษ์. ยิงกระสุนเจาะเกราะใส่ศัตรูทั้งบนอากาศและภาดพื้นดิน. +block.meltdown.description = ปืนใหญ่เลเซอร์ขนาดยักษ์. ชาร์จแล้วยิงลำแสงเลเซอร์ใส่ศัตรูที่อยู่ใกล้. จำเป็นต้องใช้สารหล่อเย็น. +block.command-center.description = สั่งการยูนิตพันธมิตรทั่วทั้งแมพ.\nสามารถสั่งให้ยูนิตมาชุมนุม, โจมตี core ศัตรู หรือถอยทีพกลับ core/โรงงาน. ถ้าไม่มี core ของศัตรูอยู่บริเวณนั้น, ยูนิตจะลาดตระเวนด้วยตัวเองหากได้รับคำสั่งให้โจมตี. +block.draug-factory.description = ผลิตโดรนขุดเจาะดราคจ์. +block.spirit-factory.description = ผลิตโดรนซ่อมแซมสปิริต. +block.phantom-factory.description = ผลิตโดรนก่อสร้างขั้นสูง. +block.wraith-factory.description = ผลิตยูนิตเร็ว โจมตีแบบ hit-and-run (จู่โจมแล้วหนี) +block.ghoul-factory.description = ผลิตยานทิ้งระเบิดปูพรมหนัก (heavy carpet bomber) +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 = ใช้เปลี่ยนร่างเป็นเป็นเม็คเกราะบางโจมตีแบบ hit-and-run (จู่โจมแล้วหนี).\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ใช้โดยการกดเมื่อยืนทับมัน. diff --git a/core/assets/bundles/bundle_tk.properties b/core/assets/bundles/bundle_tk.properties index 2fd55efb4d..ef01140591 100644 --- a/core/assets/bundles/bundle_tk.properties +++ b/core/assets/bundles/bundle_tk.properties @@ -652,7 +652,6 @@ keybind.pick.name = Pick Block keybind.break_block.name = Break Block keybind.deselect.name = Eldeki yapiyi birak keybind.shoot.name = Sik -keybind.zoom_hold.name = Yaklasma basili tutmasi keybind.zoom.name = Yaklas keybind.menu.name = Menu keybind.pause.name = Durdur diff --git a/core/assets/bundles/bundle_tr.properties b/core/assets/bundles/bundle_tr.properties index 9082a2ae3b..13550abe69 100644 --- a/core/assets/bundles/bundle_tr.properties +++ b/core/assets/bundles/bundle_tr.properties @@ -652,7 +652,6 @@ keybind.pick.name = Blok Seç keybind.break_block.name = Blok Kır keybind.deselect.name = Seçimleri Kaldır keybind.shoot.name = Ateş Et -keybind.zoom_hold.name = Zumu Sabit Tutma keybind.zoom.name = Zum keybind.menu.name = Menü keybind.pause.name = Durdur diff --git a/core/assets/bundles/bundle_uk_UA.properties b/core/assets/bundles/bundle_uk_UA.properties index 07cbede5c6..a0c1edf720 100644 --- a/core/assets/bundles/bundle_uk_UA.properties +++ b/core/assets/bundles/bundle_uk_UA.properties @@ -25,6 +25,8 @@ load.image = Зображення load.content = Зміст load.system = Система load.mod = Модифікації +load.scripts = Скрипти + schematic = Схема schematic.add = Зберегти схему… schematics = Схеми @@ -104,17 +106,19 @@ mod.disable = Вимкнути mod.delete.error = Неможливо видалити модифікацію. Файл, можливо, використовується. mod.requiresversion = [scarlet]Необхідна версія гри: [accent]{0} mod.missingdependencies = [scarlet]Відсутні залежності: {0} -mod.nowdisabled = [scarlet]Модифікації '{0}' не вистачає залежностей:[accent] {1}\n[lightgray]Ці модифікації потрібно завантажити спочатку.\nЦя модифікація буду автоматично вимкнена. +mod.nowdisabled = [scarlet]Модифікації «{0}» не вистачає залежних модифікацій:[accent] {1}\n[lightgray]Ці модифікації потрібно завантажити спочатку.\nЦя модифікація буде автоматично вимкнена. mod.enable = Увімкнути mod.requiresrestart = А тепер гра закриється, щоб застосувати зміни модифікацій. mod.reloadrequired = [scarlet]Потрібно перезавантаження mod.import = Імпортувати модифікацію -mod.import.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 = Ваш пристрій не підтримує скрипти модифікацій. Деякі модифифікаціх не будуть працювати правильно. about.button = Про гру name = Ім’я: noname = Спочатку придумайте[accent] собі ім’я[]. @@ -692,7 +696,6 @@ keybind.pick.name = Вибрати блок keybind.break_block.name = Зламати блок keybind.deselect.name = Скасувати keybind.shoot.name = Постріл -keybind.zoom_hold.name = Керування масштабом keybind.zoom.name = Приблизити keybind.menu.name = Меню keybind.pause.name = Пауза diff --git a/core/assets/bundles/bundle_zh_CN.properties b/core/assets/bundles/bundle_zh_CN.properties index b2ae9cdc24..edb60b0a77 100644 --- a/core/assets/bundles/bundle_zh_CN.properties +++ b/core/assets/bundles/bundle_zh_CN.properties @@ -699,7 +699,6 @@ keybind.pick.name = 选择方块 keybind.break_block.name = 破坏方块 keybind.deselect.name = 取消选择 keybind.shoot.name = 射击 -keybind.zoom_hold.name = 按住调整缩放 keybind.zoom.name = 缩放 keybind.menu.name = 菜单 keybind.pause.name = 暂停 diff --git a/core/assets/bundles/bundle_zh_TW.properties b/core/assets/bundles/bundle_zh_TW.properties index d9e7e16abd..050884d00f 100644 --- a/core/assets/bundles/bundle_zh_TW.properties +++ b/core/assets/bundles/bundle_zh_TW.properties @@ -26,6 +26,7 @@ load.image = 圖片載入中 load.content = 內容載入中 load.system = 系統載入中 load.mod = 模組載入中 +load.scripts = 指令檔載入中 schematic = 藍圖 schematic.add = 儲存藍圖... @@ -106,6 +107,7 @@ mod.requiresrestart = 遊戲將立即關閉以套用模組變更。 mod.reloadrequired = [scarlet]需要重新載入 mod.import = 匯入模組 mod.import.github = 匯入GitHub模組 +mod.item.remove = 此物品是[accent] '{0}'[]模組的一部份。解除安裝模組以移除此物品。 mod.remove.confirm = 該模組將被刪除。 mod.author = [lightgray]作者:[] {0} mod.missing = 此存檔含有您最近更新或不再安裝的模組。可能會發生存檔損毀。您確定要載入嗎?\n[lightgray]模組:\n{0} @@ -678,7 +680,6 @@ keybind.pick.name = 選擇方塊 keybind.break_block.name = 移除方塊 keybind.deselect.name = 取消選取 keybind.shoot.name = 射擊 -keybind.zoom_hold.name = 按住縮放 keybind.zoom.name = 縮放 keybind.menu.name = 主選單 keybind.pause.name = 暫停遊戲 @@ -1016,7 +1017,7 @@ 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]<按下以繼續> diff --git a/core/assets/fonts/font.ttf b/core/assets/fonts/font.ttf index 3ccb1ada7c..7a32355454 100644 Binary files a/core/assets/fonts/font.ttf and b/core/assets/fonts/font.ttf differ diff --git a/core/assets/scripts/base.js b/core/assets/scripts/base.js new file mode 100755 index 0000000000..9b3fb5dcb4 --- /dev/null +++ b/core/assets/scripts/base.js @@ -0,0 +1,19 @@ +const log = function(context, obj){ + Vars.mods.getScripts().log(context, obj ? String(obj) : "null") +} + +const extendContent = function(classType, name, params){ + return new JavaAdapter(classType, params, name) +} + +const extend = function(classType, params){ + return new JavaAdapter(classType, params) +} + +const run = method => new java.lang.Runnable(){run: method} +const boolf = method => new Boolf(){get: method} +const boolp = method => new Boolp(){get: method} +const cons = method => new Cons(){get: method} +const prov = method => new Prov(){get: method} +const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer})) +const Calls = Packages.io.anuke.mindustry.gen.Call \ No newline at end of file diff --git a/core/assets/scripts/global.js b/core/assets/scripts/global.js new file mode 100755 index 0000000000..87f498bbef --- /dev/null +++ b/core/assets/scripts/global.js @@ -0,0 +1,78 @@ +//Generated class. Do not modify. + +const log = function(context, obj){ + Vars.mods.getScripts().log(context, obj ? String(obj) : "null") +} + +const extendContent = function(classType, name, params){ + return new JavaAdapter(classType, params, name) +} + +const extend = function(classType, params){ + return new JavaAdapter(classType, params) +} + +const run = method => new java.lang.Runnable(){run: method} +const boolf = method => new Boolf(){get: method} +const boolp = method => new Boolp(){get: method} +const cons = method => new Cons(){get: method} +const prov = method => new Prov(){get: method} +const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer})) +const Calls = Packages.io.anuke.mindustry.gen.Call +importPackage(Packages.io.anuke.arc) +importPackage(Packages.io.anuke.arc.collection) +importPackage(Packages.io.anuke.arc.func) +importPackage(Packages.io.anuke.arc.graphics) +importPackage(Packages.io.anuke.arc.graphics.g2d) +importPackage(Packages.io.anuke.arc.math) +importPackage(Packages.io.anuke.arc.scene) +importPackage(Packages.io.anuke.arc.scene.actions) +importPackage(Packages.io.anuke.arc.scene.event) +importPackage(Packages.io.anuke.arc.scene.style) +importPackage(Packages.io.anuke.arc.scene.ui) +importPackage(Packages.io.anuke.arc.scene.ui.layout) +importPackage(Packages.io.anuke.arc.scene.utils) +importPackage(Packages.io.anuke.arc.util) +importPackage(Packages.io.anuke.mindustry) +importPackage(Packages.io.anuke.mindustry.ai) +importPackage(Packages.io.anuke.mindustry.content) +importPackage(Packages.io.anuke.mindustry.core) +importPackage(Packages.io.anuke.mindustry.ctype) +importPackage(Packages.io.anuke.mindustry.editor) +importPackage(Packages.io.anuke.mindustry.entities) +importPackage(Packages.io.anuke.mindustry.entities.bullet) +importPackage(Packages.io.anuke.mindustry.entities.effect) +importPackage(Packages.io.anuke.mindustry.entities.traits) +importPackage(Packages.io.anuke.mindustry.entities.type) +importPackage(Packages.io.anuke.mindustry.entities.type.base) +importPackage(Packages.io.anuke.mindustry.entities.units) +importPackage(Packages.io.anuke.mindustry.game) +importPackage(Packages.io.anuke.mindustry.gen) +importPackage(Packages.io.anuke.mindustry.graphics) +importPackage(Packages.io.anuke.mindustry.input) +importPackage(Packages.io.anuke.mindustry.maps) +importPackage(Packages.io.anuke.mindustry.maps.filters) +importPackage(Packages.io.anuke.mindustry.maps.generators) +importPackage(Packages.io.anuke.mindustry.maps.zonegen) +importPackage(Packages.io.anuke.mindustry.type) +importPackage(Packages.io.anuke.mindustry.ui) +importPackage(Packages.io.anuke.mindustry.ui.dialogs) +importPackage(Packages.io.anuke.mindustry.ui.fragments) +importPackage(Packages.io.anuke.mindustry.ui.layout) +importPackage(Packages.io.anuke.mindustry.world) +importPackage(Packages.io.anuke.mindustry.world.blocks) +importPackage(Packages.io.anuke.mindustry.world.blocks.defense) +importPackage(Packages.io.anuke.mindustry.world.blocks.defense.turrets) +importPackage(Packages.io.anuke.mindustry.world.blocks.distribution) +importPackage(Packages.io.anuke.mindustry.world.blocks.liquid) +importPackage(Packages.io.anuke.mindustry.world.blocks.logic) +importPackage(Packages.io.anuke.mindustry.world.blocks.power) +importPackage(Packages.io.anuke.mindustry.world.blocks.production) +importPackage(Packages.io.anuke.mindustry.world.blocks.sandbox) +importPackage(Packages.io.anuke.mindustry.world.blocks.storage) +importPackage(Packages.io.anuke.mindustry.world.blocks.units) +importPackage(Packages.io.anuke.mindustry.world.consumers) +importPackage(Packages.io.anuke.mindustry.world.meta) +importPackage(Packages.io.anuke.mindustry.world.meta.values) +importPackage(Packages.io.anuke.mindustry.world.modules) +importPackage(Packages.io.anuke.mindustry.world.producers) diff --git a/core/assets/scripts/wrapper.js b/core/assets/scripts/wrapper.js new file mode 100755 index 0000000000..0c7a8aba4d --- /dev/null +++ b/core/assets/scripts/wrapper.js @@ -0,0 +1,10 @@ +modName = "$MOD_NAME$" + +!function(){ + +const scriptName = "$SCRIPT_NAME$" +const print = text => log(scriptName, text); +$CODE$ + +}(); + diff --git a/core/src/io/anuke/mindustry/ClientLauncher.java b/core/src/io/anuke/mindustry/ClientLauncher.java index 6abff04782..5d04c44010 100644 --- a/core/src/io/anuke/mindustry/ClientLauncher.java +++ b/core/src/io/anuke/mindustry/ClientLauncher.java @@ -32,8 +32,8 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform @Override public void setup(){ + Vars.loadLogger(); Vars.platform = this; - Log.setUseColors(false); beginTime = Time.millis(); Time.setDeltaProvider(() -> { @@ -70,8 +70,11 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform Sounds.load(); assets.loadRun("contentcreate", Content.class, () -> { - content.createContent(); + content.createBaseContent(); content.loadColors(); + }, () -> { + mods.loadScripts(); + content.createModContent(); }); add(logic = new Logic()); @@ -120,7 +123,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform for(ApplicationListener listener : modules){ listener.init(); } - mods.each(Mod::init); + mods.eachClass(Mod::init); finished = true; Events.fire(new ClientLoadEvent()); super.resize(graphics.getWidth(), graphics.getHeight()); @@ -193,7 +196,8 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform if(assets.getCurrentLoading() != null){ String name = assets.getCurrentLoading().fileName.toLowerCase(); - String key = name.contains("content") ? "content" : name.contains("mod") ? "mods" : name.contains("msav") || name.contains("maps") ? "map" : name.contains("ogg") || name.contains("mp3") ? "sound" : name.contains("png") ? "image" : "system"; + String key = name.contains("script") ? "scripts" : name.contains("content") ? "content" : name.contains("mod") ? "mods" : name.contains("msav") || + name.contains("maps") ? "map" : name.contains("ogg") || name.contains("mp3") ? "sound" : name.contains("png") ? "image" : "system"; font.draw(bundle.get("load." + key, ""), graphics.getWidth() / 2f, graphics.getHeight() / 2f - height / 2f - Scl.scl(10f), Align.center); } } diff --git a/core/src/io/anuke/mindustry/Vars.java b/core/src/io/anuke/mindustry/Vars.java index 089fd0dc49..134865bee2 100644 --- a/core/src/io/anuke/mindustry/Vars.java +++ b/core/src/io/anuke/mindustry/Vars.java @@ -8,6 +8,7 @@ import io.anuke.arc.files.*; import io.anuke.arc.graphics.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; +import io.anuke.arc.util.io.*; import io.anuke.mindustry.ai.*; import io.anuke.mindustry.core.*; import io.anuke.mindustry.entities.*; @@ -15,6 +16,7 @@ import io.anuke.mindustry.entities.effect.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.game.*; +import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.input.*; import io.anuke.mindustry.maps.*; @@ -25,12 +27,14 @@ import io.anuke.mindustry.world.blocks.defense.ForceProjector.*; import java.nio.charset.*; import java.util.*; -import static io.anuke.arc.Core.*; +import static io.anuke.arc.Core.settings; @SuppressWarnings("unchecked") public class Vars implements Loadable{ /** Whether to load locales.*/ public static boolean loadLocales = true; + /** Whether the logger is loaded. */ + public static boolean loadedLogger = false; /** Maximum schematic size.*/ public static final int maxSchematicSize = 32; /** All schematic base64 starts with this string.*/ @@ -118,22 +122,24 @@ public class Vars implements Loadable{ public static boolean headless; /** whether steam is enabled for this game */ public static boolean steam; + /** whether typing into the console is enabled - developers only */ + public static boolean enableConsole = false; /** application data directory, equivalent to {@link io.anuke.arc.Settings#getDataDirectory()} */ - public static FileHandle dataDirectory; + public static Fi dataDirectory; /** data subdirectory used for screenshots */ - public static FileHandle screenshotDirectory; + public static Fi screenshotDirectory; /** data subdirectory used for custom mmaps */ - public static FileHandle customMapDirectory; + public static Fi customMapDirectory; /** data subdirectory used for custom mmaps */ - public static FileHandle mapPreviewDirectory; + public static Fi mapPreviewDirectory; /** tmp subdirectory for map conversion */ - public static FileHandle tmpDirectory; + public static Fi tmpDirectory; /** data subdirectory used for saves */ - public static FileHandle saveDirectory; + public static Fi saveDirectory; /** data subdirectory used for mods */ - public static FileHandle modDirectory; + public static Fi modDirectory; /** data subdirectory used for schematics */ - public static FileHandle schematicDirectory; + public static Fi schematicDirectory; /** map file extension */ public static final String mapExtension = "msav"; /** save file extension */ @@ -190,6 +196,7 @@ public class Vars implements Loadable{ public static void init(){ Serialization.init(); + DefaultSerializers.typeMappings.put("io.anuke.mindustry.type.ContentType", "io.anuke.mindustry.ctype.ContentType"); if(loadLocales){ //load locales @@ -268,6 +275,31 @@ public class Vars implements Loadable{ maps.load(); } + public static void loadLogger(){ + if(loadedLogger) return; + + String[] tags = {"[green][D][]", "[royal][I][]", "[yellow][W][]", "[scarlet][E][]", ""}; + String[] stags = {"&lc&fb[D]", "&lg&fb[I]", "&ly&fb[W]", "&lr&fb[E]", ""}; + + Array logBuffer = new Array<>(); + Log.setLogger((level, text, args) -> { + String result = Log.format(text, args); + System.out.println(Log.format(stags[level.ordinal()] + "&fr " + text, args)); + + result = tags[level.ordinal()] + " " + result; + + if(!headless && (ui == null || ui.scriptfrag == null)){ + logBuffer.add(result); + }else if(!headless){ + ui.scriptfrag.addMessage(result); + } + }); + + Events.on(ClientLoadEvent.class, e -> logBuffer.each(ui.scriptfrag::addMessage)); + + loadedLogger = true; + } + public static void loadSettings(){ Core.settings.setAppName(appName); @@ -285,7 +317,7 @@ public class Vars implements Loadable{ try{ //try loading external bundle - FileHandle handle = Core.files.local("bundle"); + Fi handle = Core.files.local("bundle"); Locale locale = Locale.ENGLISH; Core.bundle = I18NBundle.createBundle(handle, locale); @@ -298,7 +330,7 @@ public class Vars implements Loadable{ }catch(Throwable e){ //no external bundle found - FileHandle handle = Core.files.internal("bundles/bundle"); + Fi handle = Core.files.internal("bundles/bundle"); Locale locale; String loc = Core.settings.getString("locale"); if(loc.equals("default")){ diff --git a/core/src/io/anuke/mindustry/content/Blocks.java b/core/src/io/anuke/mindustry/content/Blocks.java index 623fd0ef79..f248dbab58 100644 --- a/core/src/io/anuke/mindustry/content/Blocks.java +++ b/core/src/io/anuke/mindustry/content/Blocks.java @@ -7,7 +7,7 @@ import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.math.*; import io.anuke.arc.util.*; import io.anuke.mindustry.*; -import io.anuke.mindustry.ctype.ContentList; +import io.anuke.mindustry.ctype.*; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.bullet.*; import io.anuke.mindustry.entities.type.*; @@ -19,8 +19,7 @@ import io.anuke.mindustry.world.blocks.*; import io.anuke.mindustry.world.blocks.defense.*; import io.anuke.mindustry.world.blocks.defense.turrets.*; import io.anuke.mindustry.world.blocks.distribution.*; -import io.anuke.mindustry.world.blocks.liquid.Conduit; -import io.anuke.mindustry.world.blocks.liquid.LiquidTank; +import io.anuke.mindustry.world.blocks.liquid.*; import io.anuke.mindustry.world.blocks.logic.*; import io.anuke.mindustry.world.blocks.power.*; import io.anuke.mindustry.world.blocks.production.*; @@ -485,7 +484,7 @@ public class Blocks implements ContentList{ drawer = tile -> { Draw.rect(region, tile.drawx(), tile.drawy()); - GenericCrafterEntity entity = tile.entity(); + GenericCrafterEntity entity = tile.ent(); Draw.alpha(Mathf.absin(entity.totalProgress, 3f, 0.9f) * entity.warmup); Draw.rect(reg(topRegion), tile.drawx(), tile.drawy()); @@ -510,7 +509,7 @@ public class Blocks implements ContentList{ drawIcons = () -> new TextureRegion[]{Core.atlas.find(name + "-bottom"), Core.atlas.find(name), Core.atlas.find(name + "-weave")}; drawer = tile -> { - GenericCrafterEntity entity = tile.entity(); + GenericCrafterEntity entity = tile.ent(); Draw.rect(reg(bottomRegion), tile.drawx(), tile.drawy()); Draw.rect(reg(weaveRegion), tile.drawx(), tile.drawy(), entity.totalProgress); @@ -660,7 +659,7 @@ public class Blocks implements ContentList{ drawIcons = () -> new TextureRegion[]{Core.atlas.find(name), Core.atlas.find(name + "-top")}; drawer = tile -> { - GenericCrafterEntity entity = tile.entity(); + 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()); @@ -687,7 +686,7 @@ public class Blocks implements ContentList{ drawIcons = () -> new TextureRegion[]{Core.atlas.find(name), Core.atlas.find(name + "-rotator")}; drawer = tile -> { - GenericCrafterEntity entity = tile.entity(); + GenericCrafterEntity entity = tile.ent(); Draw.rect(region, tile.drawx(), tile.drawy()); Draw.rect(reg(rotatorRegion), tile.drawx(), tile.drawy(), entity.totalProgress * 2f); @@ -915,6 +914,7 @@ public class Blocks implements ContentList{ phaseConveyor = new ItemBridge("phase-conveyor"){{ requirements(Category.distribution, ItemStack.with(Items.phasefabric, 5, Items.silicon, 7, Items.lead, 10, Items.graphite, 10)); range = 12; + canOverdrive = false; hasPower = true; consumes.power(0.30f); }}; @@ -977,7 +977,7 @@ public class Blocks implements ContentList{ size = 3; }}; - conduit = new io.anuke.mindustry.world.blocks.liquid.Conduit("conduit"){{ + conduit = new Conduit("conduit"){{ requirements(Category.liquid, ItemStack.with(Items.metaglass, 1)); health = 45; }}; @@ -989,14 +989,14 @@ public class Blocks implements ContentList{ health = 90; }}; - platedConduit = new io.anuke.mindustry.world.blocks.liquid.ArmoredConduit("plated-conduit"){{ - requirements(Category.liquid, ItemStack.with(Items.thorium, 2, Items.metaglass, 1)); + platedConduit = new ArmoredConduit("plated-conduit"){{ + requirements(Category.liquid, ItemStack.with(Items.thorium, 2, Items.metaglass, 1, Items.plastanium, 1)); liquidCapacity = 16f; liquidPressure = 1.025f; health = 220; }}; - liquidRouter = new io.anuke.mindustry.world.blocks.liquid.LiquidRouter("liquid-router"){{ + liquidRouter = new LiquidRouter("liquid-router"){{ requirements(Category.liquid, ItemStack.with(Items.graphite, 4, Items.metaglass, 2)); liquidCapacity = 20f; }}; @@ -1008,20 +1008,21 @@ public class Blocks implements ContentList{ health = 500; }}; - liquidJunction = new io.anuke.mindustry.world.blocks.liquid.LiquidJunction("liquid-junction"){{ + liquidJunction = new LiquidJunction("liquid-junction"){{ requirements(Category.liquid, ItemStack.with(Items.graphite, 2, Items.metaglass, 2)); }}; - bridgeConduit = new io.anuke.mindustry.world.blocks.liquid.LiquidExtendingBridge("bridge-conduit"){{ + bridgeConduit = new LiquidExtendingBridge("bridge-conduit"){{ requirements(Category.liquid, ItemStack.with(Items.graphite, 4, Items.metaglass, 8)); range = 4; hasPower = false; }}; - phaseConduit = new io.anuke.mindustry.world.blocks.liquid.LiquidBridge("phase-conduit"){{ + phaseConduit = new LiquidBridge("phase-conduit"){{ requirements(Category.liquid, ItemStack.with(Items.phasefabric, 5, Items.silicon, 7, Items.metaglass, 20, Items.titanium, 10)); range = 12; hasPower = true; + canOverdrive = false; consumes.power(0.30f); }}; @@ -1359,7 +1360,7 @@ public class Blocks implements ContentList{ ammo( Items.graphite, Bullets.artilleryDense, Items.silicon, Bullets.artilleryHoming, - Items.pyratite, Bullets.artlleryIncendiary + Items.pyratite, Bullets.artilleryIncendiary ); reload = 60f; recoil = 2f; @@ -1539,9 +1540,9 @@ public class Blocks implements ContentList{ ammo( Items.graphite, Bullets.artilleryDense, Items.silicon, Bullets.artilleryHoming, - Items.pyratite, Bullets.artlleryIncendiary, + Items.pyratite, Bullets.artilleryIncendiary, Items.blastCompound, Bullets.artilleryExplosive, - Items.plastanium, Bullets.arilleryPlastic + Items.plastanium, Bullets.artilleryPlastic ); size = 3; shots = 4; diff --git a/core/src/io/anuke/mindustry/content/Bullets.java b/core/src/io/anuke/mindustry/content/Bullets.java index 3071c59f49..b3e23d966b 100644 --- a/core/src/io/anuke/mindustry/content/Bullets.java +++ b/core/src/io/anuke/mindustry/content/Bullets.java @@ -18,7 +18,7 @@ public class Bullets implements ContentList{ public static BulletType //artillery - artilleryDense, arilleryPlastic, artilleryPlasticFrag, artilleryHoming, artlleryIncendiary, artilleryExplosive, artilleryUnit, + artilleryDense, artilleryPlastic, artilleryPlasticFrag, artilleryHoming, artilleryIncendiary, artilleryExplosive, artilleryUnit, //flak flakScrap, flakLead, flakPlastic, flakExplosive, flakSurge, flakGlass, glassFrag, @@ -65,7 +65,7 @@ public class Bullets implements ContentList{ despawnEffect = Fx.none; }}; - arilleryPlastic = new ArtilleryBulletType(3.4f, 0, "shell"){{ + artilleryPlastic = new ArtilleryBulletType(3.4f, 0, "shell"){{ hitEffect = Fx.plasticExplosion; knockback = 1f; lifetime = 55f; @@ -91,7 +91,7 @@ public class Bullets implements ContentList{ homingRange = 50f; }}; - artlleryIncendiary = new ArtilleryBulletType(3f, 0, "shell"){{ + artilleryIncendiary = new ArtilleryBulletType(3f, 0, "shell"){{ hitEffect = Fx.blastExplosion; knockback = 0.8f; lifetime = 60f; diff --git a/core/src/io/anuke/mindustry/content/Fx.java b/core/src/io/anuke/mindustry/content/Fx.java index d7aeed4c65..4c31f0bd1a 100644 --- a/core/src/io/anuke/mindustry/content/Fx.java +++ b/core/src/io/anuke/mindustry/content/Fx.java @@ -48,28 +48,24 @@ public class Fx implements ContentList{ Draw.rect(unit.getIconRegion(), e.x, e.y, unit.getIconRegion().getWidth() * Draw.scl * scl, unit.getIconRegion().getWidth() * Draw.scl * scl, 180f); - Draw.reset(); }); commandSend = new Effect(28, e -> { Draw.color(Pal.command); Lines.stroke(e.fout() * 2f); Lines.circle(e.x, e.y, 4f + e.finpow() * 120f); - Draw.color(); }); 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); - Draw.reset(); }); 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()); - Draw.reset(); }); breakBlock = new Effect(12, e -> { @@ -80,41 +76,35 @@ public class Fx implements ContentList{ 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)); }); - Draw.reset(); }); select = new Effect(23, e -> { Draw.color(Pal.accent); Lines.stroke(e.fout() * 3f); Lines.circle(e.x, e.y, 3f + e.fin() * 14f); - Draw.reset(); }); 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); - Draw.reset(); }); magmasmoke = new Effect(110, e -> { Draw.color(Color.gray); Fill.circle(e.x, e.y, e.fslope() * 6f); - Draw.reset(); }); 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); - Draw.reset(); }); 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); - Draw.reset(); }); vtolHover = new Effect(40f, e -> { @@ -122,7 +112,6 @@ public class Fx implements ContentList{ 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()); - Draw.reset(); }); unitDrop = new GroundEffect(30, e -> { @@ -130,7 +119,6 @@ public class Fx implements ContentList{ Angles.randLenVectors(e.id, 9, 3 + 20f * e.finpow(), (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.4f); }); - Draw.reset(); }); unitLand = new GroundEffect(30, e -> { @@ -138,42 +126,36 @@ public class Fx implements ContentList{ Angles.randLenVectors(e.id, 6, 17f * e.finpow(), (x, y) -> { Fill.circle(e.x + x, e.y + y, e.fout() * 4f + 0.3f); }); - Draw.reset(); }); unitPickup = new GroundEffect(18, e -> { Draw.color(Pal.lightishGray); Lines.stroke(e.fin() * 2f); Lines.poly(e.x, e.y, 4, 13f * e.fout()); - Draw.reset(); }); landShock = new GroundEffect(12, e -> { Draw.color(Pal.lancerLaser); Lines.stroke(e.fout() * 3f); Lines.poly(e.x, e.y, 12, 20f * e.fout()); - Draw.reset(); }); 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); - Draw.reset(); }); healWave = new Effect(22, e -> { Draw.color(Pal.heal); Lines.stroke(e.fout() * 2f); Lines.circle(e.x, e.y, 4f + e.finpow() * 60f); - Draw.color(); }); heal = new Effect(11, e -> { Draw.color(Pal.heal); Lines.stroke(e.fout() * 2f); Lines.circle(e.x, e.y, 2f + e.finpow() * 7f); - Draw.color(); }); @@ -193,7 +175,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 3 + 1f); }); - Draw.reset(); }); hitFuse = new Effect(14, e -> { @@ -212,7 +193,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 3 + 1f); }); - Draw.reset(); }); hitBulletBig = new Effect(13, e -> { @@ -224,7 +204,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 4 + 1.5f); }); - Draw.reset(); }); hitFlameSmall = new Effect(14, e -> { @@ -236,7 +215,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 3 + 1f); }); - Draw.reset(); }); hitLiquid = new Effect(16, e -> { @@ -246,7 +224,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, e.fout() * 2f); }); - Draw.reset(); }); hitLancer = new Effect(12, e -> { @@ -258,7 +235,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 4 + 1f); }); - Draw.reset(); }); hitMeltdown = new Effect(12, e -> { @@ -270,14 +246,12 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 4 + 1f); }); - Draw.reset(); }); 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); - Draw.reset(); }); despawn = new Effect(12, e -> { @@ -289,7 +263,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, ang, e.fout() * 2 + 1f); }); - Draw.reset(); }); flakExplosion = new Effect(20, e -> { @@ -313,7 +286,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); }); - Draw.reset(); }); plasticExplosion = new Effect(24, e -> { @@ -337,7 +309,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); }); - Draw.reset(); }); plasticExplosionFlak = new Effect(28, e -> { @@ -361,7 +332,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); }); - Draw.reset(); }); blastExplosion = new Effect(22, e -> { @@ -385,32 +355,27 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); }); - Draw.reset(); }); artilleryTrail = new Effect(50, e -> { Draw.color(e.color); Fill.circle(e.x, e.y, e.rotation * e.fout()); - Draw.reset(); }); incendTrail = new Effect(50, e -> { Draw.color(Pal.lightOrange); Fill.circle(e.x, e.y, e.rotation * e.fout()); - Draw.reset(); }); missileTrail = new Effect(50, e -> { Draw.color(e.color); Fill.circle(e.x, e.y, e.rotation * e.fout()); - Draw.reset(); }); absorb = new Effect(12, e -> { Draw.color(Pal.accent); Lines.stroke(2f * e.fout()); Lines.circle(e.x, e.y, 5f * e.fout()); - Draw.reset(); }); flakExplosionBig = new Effect(30, e -> { @@ -434,7 +399,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); }); - Draw.reset(); }); @@ -445,7 +409,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, 0.1f + e.fout() * 1.4f); }); - Draw.color(); }); fire = new Effect(50f, e -> { @@ -467,7 +430,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, 0.2f + e.fslope() * 1.5f); }); - Draw.color(); }); steam = new Effect(35f, e -> { @@ -477,7 +439,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, 0.2f + e.fslope() * 1.5f); }); - Draw.color(); }); fireballsmoke = new Effect(25f, e -> { @@ -487,7 +448,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, 0.2f + e.fout() * 1.5f); }); - Draw.color(); }); ballfire = new Effect(25f, e -> { @@ -497,7 +457,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, 0.2f + e.fout() * 1.5f); }); - Draw.color(); }); freezing = new Effect(40f, e -> { @@ -507,7 +466,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, e.fout() * 1.2f); }); - Draw.color(); }); melting = new Effect(40f, e -> { @@ -517,7 +475,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, .2f + e.fout() * 1.2f); }); - Draw.color(); }); wet = new Effect(40f, e -> { @@ -527,7 +484,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, e.fout() * 1f); }); - Draw.color(); }); oily = new Effect(42f, e -> { @@ -537,7 +493,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, e.fout() * 1f); }); - Draw.color(); }); overdriven = new Effect(20f, e -> { @@ -547,7 +502,6 @@ public class Fx implements ContentList{ Fill.square(e.x + x, e.y + y, e.fout() * 2.3f + 0.5f); }); - Draw.color(); }); dropItem = new Effect(20f, e -> { @@ -562,35 +516,30 @@ public class Fx implements ContentList{ Draw.color(Color.white, Color.lightGray, e.fin()); Lines.stroke(e.fout() * 2f + 0.2f); Lines.circle(e.x, e.y, e.fin() * 28f); - Draw.reset(); }); bigShockwave = new Effect(10f, 80f, e -> { Draw.color(Color.white, Color.lightGray, e.fin()); Lines.stroke(e.fout() * 3f); Lines.circle(e.x, e.y, e.fin() * 50f); - Draw.reset(); }); nuclearShockwave = new Effect(10f, 200f, e -> { Draw.color(Color.white, Color.lightGray, e.fin()); Lines.stroke(e.fout() * 3f + 0.2f); Lines.circle(e.x, e.y, e.fin() * 140f); - Draw.reset(); }); impactShockwave = new Effect(13f, 300f, e -> { Draw.color(Pal.lighterOrange, Color.lightGray, e.fin()); Lines.stroke(e.fout() * 4f + 0.2f); Lines.circle(e.x, e.y, e.fin() * 200f); - Draw.reset(); }); spawnShockwave = new Effect(20f, 400f, e -> { Draw.color(Color.white, Color.lightGray, e.fin()); Lines.stroke(e.fout() * 3f + 0.5f); Lines.circle(e.x, e.y, e.fin() * (e.rotation + 50f)); - Draw.reset(); }); explosion = new Effect(30, e -> { @@ -613,7 +562,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); }); - Draw.reset(); }); dynamicExplosion = new Effect(30, e -> { @@ -638,7 +586,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + out * 4 * (3f + intensity)); }); - Draw.reset(); }); blockExplosion = new Effect(30, e -> { @@ -661,7 +608,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), 1f + e.fout() * 3f); }); - Draw.reset(); }); blockExplosionSmoke = new Effect(30, e -> { @@ -672,7 +618,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x / 2f, e.y + y / 2f, e.fout() * 1f); }); - Draw.reset(); }); @@ -681,7 +626,6 @@ public class Fx implements ContentList{ 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); - Draw.reset(); }); shootHeal = new Effect(8, e -> { @@ -689,7 +633,6 @@ public class Fx implements ContentList{ 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); - Draw.reset(); }); shootSmallSmoke = new Effect(20f, e -> { @@ -699,7 +642,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, e.fout() * 1.5f); }); - Draw.reset(); }); shootBig = new Effect(9, e -> { @@ -707,7 +649,6 @@ public class Fx implements ContentList{ 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); - Draw.reset(); }); shootBig2 = new Effect(10, e -> { @@ -715,7 +656,6 @@ public class Fx implements ContentList{ 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); - Draw.reset(); }); shootBigSmoke = new Effect(17f, e -> { @@ -725,7 +665,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, e.fout() * 2f + 0.2f); }); - Draw.reset(); }); shootBigSmoke2 = new Effect(18f, e -> { @@ -735,7 +674,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, e.fout() * 2.4f + 0.2f); }); - Draw.reset(); }); shootSmallFlame = new Effect(32f, e -> { @@ -745,7 +683,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, 0.65f + e.fout() * 1.5f); }); - Draw.reset(); }); shootPyraFlame = new Effect(33f, e -> { @@ -755,7 +692,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, 0.65f + e.fout() * 1.6f); }); - Draw.reset(); }); shootLiquid = new Effect(40f, e -> { @@ -765,7 +701,6 @@ public class Fx implements ContentList{ Fill.circle(e.x + x, e.y + y, 0.5f + e.fout() * 2.5f); }); - Draw.reset(); }); shellEjectSmall = new GroundEffect(30f, 400f, e -> { @@ -780,7 +715,6 @@ public class Fx implements ContentList{ e.y + Angles.trnsy(lr, len) + Mathf.randomSeedRange(e.id + i + 8, 3f * e.fin()), 1f, 2f, rot + e.fin() * 50f * i); - Draw.color(); }); shellEjectMedium = new GroundEffect(34f, 400f, e -> { @@ -804,7 +738,6 @@ public class Fx implements ContentList{ }); } - Draw.color(); }); shellEjectBig = new GroundEffect(22f, 400f, e -> { @@ -829,7 +762,6 @@ public class Fx implements ContentList{ }); } - Draw.color(); }); lancerLaserShoot = new Effect(21f, e -> { @@ -839,7 +771,6 @@ public class Fx implements ContentList{ Drawf.tri(e.x, e.y, 4f * e.fout(), 29f, e.rotation + 90f * i); } - Draw.reset(); }); lancerLaserShootSmoke = new Effect(26f, e -> { @@ -849,7 +780,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fout() * 9f); }); - Draw.reset(); }); lancerLaserCharge = new Effect(38f, e -> { @@ -859,7 +789,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fslope() * 3f + 1f); }); - Draw.reset(); }); lancerLaserChargeBegin = new Effect(71f, e -> { @@ -877,7 +806,6 @@ public class Fx implements ContentList{ Drawf.tri(e.x + x, e.y + y, e.fslope() * 3f + 1, e.fslope() * 3f + 1, Mathf.angle(x, y)); }); - Draw.reset(); }); lightningShoot = new Effect(12f, e -> { @@ -888,7 +816,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fin() * 5f + 2f); }); - Draw.reset(); }); @@ -897,7 +824,6 @@ public class Fx implements ContentList{ 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); - Draw.reset(); }); }); nuclearsmoke = new Effect(40, e -> { @@ -905,7 +831,6 @@ public class Fx implements ContentList{ float size = e.fslope() * 4f; Draw.color(Color.lightGray, Color.gray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, size, size); - Draw.reset(); }); }); nuclearcloud = new Effect(90, 200f, e -> { @@ -913,7 +838,6 @@ public class Fx implements ContentList{ float size = e.fout() * 14f; Draw.color(Color.lime, Color.gray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, size, size); - Draw.reset(); }); }); impactsmoke = new Effect(60, e -> { @@ -921,7 +845,6 @@ public class Fx implements ContentList{ float size = e.fslope() * 4f; Draw.color(Color.lightGray, Color.gray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, size, size); - Draw.reset(); }); }); impactcloud = new Effect(140, 400f, e -> { @@ -929,7 +852,6 @@ public class Fx implements ContentList{ float size = e.fout() * 15f; Draw.color(Pal.lighterOrange, Color.lightGray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, size, size); - Draw.reset(); }); }); redgeneratespark = new Effect(18, e -> { @@ -937,7 +859,6 @@ public class Fx implements ContentList{ float len = e.fout() * 4f; Draw.color(Pal.redSpark, Color.gray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, len, len); - Draw.reset(); }); }); generatespark = new Effect(18, e -> { @@ -945,7 +866,6 @@ public class Fx implements ContentList{ float len = e.fout() * 4f; Draw.color(Pal.orangeSpark, Color.gray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, len, len); - Draw.reset(); }); }); fuelburn = new Effect(23, e -> { @@ -953,70 +873,60 @@ public class Fx implements ContentList{ float len = e.fout() * 4f; Draw.color(Color.lightGray, Color.gray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, len, len); - Draw.reset(); }); }); plasticburn = new Effect(40, e -> { Angles.randLenVectors(e.id, 5, 3f + e.fin() * 5f, (x, y) -> { Draw.color(Color.valueOf("e9ead3"), Color.gray, e.fin()); Fill.circle(e.x + x, e.y + y, e.fout() * 1f); - Draw.reset(); }); }); 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); - Draw.reset(); }); }); 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); - Draw.reset(); }); }); 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); - Draw.reset(); }); }); 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); - Draw.reset(); }); }); 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); - Draw.reset(); }); }); 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); - Draw.reset(); }); }); smeltsmoke = new Effect(15, e -> { Angles.randLenVectors(e.id, 6, 4f + e.fin() * 5f, (x, y) -> { Draw.color(Color.white, e.color, e.fin()); Fill.square(e.x + x, e.y + y, 0.5f + e.fout() * 2f, 45); - Draw.reset(); }); }); formsmoke = new Effect(40, e -> { Angles.randLenVectors(e.id, 6, 5f + e.fin() * 8f, (x, y) -> { Draw.color(Pal.plasticSmoke, Color.lightGray, e.fin()); Fill.square(e.x + x, e.y + y, 0.2f + e.fout() * 2f, 45); - Draw.reset(); }); }); blastsmoke = new Effect(26, e -> { @@ -1024,7 +934,6 @@ public class Fx implements ContentList{ 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); - Draw.reset(); }); }); lava = new Effect(18, e -> { @@ -1032,79 +941,66 @@ public class Fx implements ContentList{ float size = e.fslope() * 4f; Draw.color(Color.orange, Color.gray, e.fin()); Draw.rect("circle", e.x + x, e.y + y, size, size); - Draw.reset(); }); }); dooropen = new Effect(10, e -> { Lines.stroke(e.fout() * 1.6f); Lines.square(e.x, e.y, tilesize / 2f + e.fin() * 2f); - Draw.reset(); }); doorclose = new Effect(10, e -> { Lines.stroke(e.fout() * 1.6f); Lines.square(e.x, e.y, tilesize / 2f + e.fout() * 2f); - Draw.reset(); }); dooropenlarge = new Effect(10, e -> { Lines.stroke(e.fout() * 1.6f); Lines.square(e.x, e.y, tilesize + e.fin() * 2f); - Draw.reset(); }); doorcloselarge = new Effect(10, e -> { Lines.stroke(e.fout() * 1.6f); Lines.square(e.x, e.y, tilesize + e.fout() * 2f); - Draw.reset(); }); 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); - Draw.reset(); }); 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); - Draw.reset(); }); 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); - Draw.reset(); }); 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); - Draw.reset(); }); 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); - Draw.reset(); }); }); 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); - Draw.reset(); }); }); 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); - Draw.reset(); }); }); smelt = new Effect(20, e -> { Angles.randLenVectors(e.id, 6, 2f + e.fin() * 5f, (x, y) -> { Draw.color(Color.white, e.color, e.fin()); Fill.square(e.x + x, e.y + y, 0.5f + e.fout() * 2f, 45); - Draw.reset(); }); }); teleportActivate = new Effect(50, e -> { @@ -1121,7 +1017,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fin() * 4f + 1f); }); - Draw.reset(); }); teleport = new Effect(60, e -> { Draw.color(e.color); @@ -1132,7 +1027,6 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fin() * 4f + 1f); }); - Draw.reset(); }); teleportOut = new Effect(20, e -> { Draw.color(e.color); @@ -1143,13 +1037,11 @@ public class Fx implements ContentList{ Lines.lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fslope() * 4f + 1f); }); - Draw.reset(); }); 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); - Draw.reset(); }); bubble = new Effect(20, e -> { @@ -1158,56 +1050,47 @@ public class Fx implements ContentList{ Angles.randLenVectors(e.id, 2, 8f, (x, y) -> { Lines.circle(e.x + x, e.y + y, 1f + e.fin() * 3f); }); - Draw.reset(); }); launch = new Effect(28, e -> { Draw.color(Pal.command); Lines.stroke(e.fout() * 2f); Lines.circle(e.x, e.y, 4f + e.finpow() * 120f); - Draw.color(); }); healWaveMend = new Effect(40, e -> { Draw.color(e.color); Lines.stroke(e.fout() * 2f); Lines.circle(e.x, e.y, e.finpow() * e.rotation); - Draw.color(); }); overdriveWave = new Effect(50, e -> { Draw.color(e.color); Lines.stroke(e.fout() * 1f); Lines.circle(e.x, e.y, e.finpow() * e.rotation); - Draw.color(); }); 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)); - Draw.color(); }); healBlockFull = new Effect(20, e -> { Draw.color(e.color); Draw.alpha(e.fout()); - Fill.square(e.x, e.y, e.rotation * tilesize / 2f); - Draw.color(); }); overdriveBlockFull = new Effect(60, e -> { Draw.color(e.color); Draw.alpha(e.fslope() * 0.4f); Fill.square(e.x, e.y, e.rotation * tilesize); - Draw.color(); }); 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); - Draw.reset(); }); coreLand = new Effect(120f, e -> { diff --git a/core/src/io/anuke/mindustry/content/StatusEffects.java b/core/src/io/anuke/mindustry/content/StatusEffects.java index c4342ec82c..4dc980869d 100644 --- a/core/src/io/anuke/mindustry/content/StatusEffects.java +++ b/core/src/io/anuke/mindustry/content/StatusEffects.java @@ -15,61 +15,71 @@ public class StatusEffects implements ContentList{ @Override public void load(){ - none = new StatusEffect(); + none = new StatusEffect("none"); - burning = new StatusEffect(){{ + burning = new StatusEffect("burning"){{ damage = 0.06f; effect = Fx.burning; - 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)); - result.set(this, Math.min(time + newTime, 300f)); - })); + init(() -> { + 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)); + result.set(this, Math.min(time + newTime, 300f)); + })); + }); }}; - freezing = new StatusEffect(){{ + freezing = new StatusEffect("freezing"){{ speedMultiplier = 0.6f; armorMultiplier = 0.8f; effect = Fx.freezing; - opposite(() -> melting, () -> burning); + init(() -> { + opposite(melting, burning); + }); }}; - wet = new StatusEffect(){{ + wet = new StatusEffect("wet"){{ speedMultiplier = 0.9f; effect = Fx.wet; - trans(() -> shocked, ((unit, time, newTime, result) -> { - unit.damage(20f); - if(unit.getTeam() == waveTeam){ - Events.fire(Trigger.shock); - } - result.set(this, time); - })); - opposite(() -> burning); + init(() -> { + trans(shocked, ((unit, time, newTime, result) -> { + unit.damage(20f); + if(unit.getTeam() == waveTeam){ + Events.fire(Trigger.shock); + } + result.set(this, time); + })); + opposite(burning); + }); }}; - melting = new StatusEffect(){{ + melting = new StatusEffect("melting"){{ speedMultiplier = 0.8f; armorMultiplier = 0.8f; damage = 0.3f; effect = Fx.melting; - trans(() -> tarred, ((unit, time, newTime, result) -> result.set(this, Math.min(time + newTime / 2f, 140f)))); - opposite(() -> wet, () -> freezing); + init(() -> { + trans(tarred, ((unit, time, newTime, result) -> result.set(this, Math.min(time + newTime / 2f, 140f)))); + opposite(wet, freezing); + }); }}; - tarred = new StatusEffect(){{ + tarred = new StatusEffect("tarred"){{ speedMultiplier = 0.6f; effect = Fx.oily; - trans(() -> melting, ((unit, time, newTime, result) -> result.set(burning, newTime + time))); - trans(() -> burning, ((unit, time, newTime, result) -> result.set(burning, newTime + time))); + init(() -> { + trans(melting, ((unit, time, newTime, result) -> result.set(burning, newTime + time))); + trans(burning, ((unit, time, newTime, result) -> result.set(burning, newTime + time))); + }); }}; - overdrive = new StatusEffect(){{ + overdrive = new StatusEffect("overdrive"){{ armorMultiplier = 0.95f; speedMultiplier = 1.15f; damageMultiplier = 1.4f; @@ -77,20 +87,20 @@ public class StatusEffects implements ContentList{ effect = Fx.overdriven; }}; - shielded = new StatusEffect(){{ + shielded = new StatusEffect("shielded"){{ armorMultiplier = 3f; }}; - boss = new StatusEffect(){{ + boss = new StatusEffect("boss"){{ armorMultiplier = 3f; damageMultiplier = 3f; speedMultiplier = 1.1f; }}; - shocked = new StatusEffect(); + shocked = new StatusEffect("shocked"); //no effects, just small amounts of damage. - corroded = new StatusEffect(){{ + corroded = new StatusEffect("corroded"){{ damage = 0.1f; }}; } diff --git a/core/src/io/anuke/mindustry/content/UnitTypes.java b/core/src/io/anuke/mindustry/content/UnitTypes.java index 35eb9890bd..d6e1dd232a 100644 --- a/core/src/io/anuke/mindustry/content/UnitTypes.java +++ b/core/src/io/anuke/mindustry/content/UnitTypes.java @@ -17,7 +17,7 @@ public class UnitTypes implements ContentList{ @Override public void load(){ - draug = new UnitType("draug", Draug::new){{ + draug = new UnitType("draug", MinerDrone::new){{ flying = true; drag = 0.01f; speed = 0.3f; @@ -32,7 +32,7 @@ public class UnitTypes implements ContentList{ }}; }}; - spirit = new UnitType("spirit", Spirit::new){{ + spirit = new UnitType("spirit", RepairDrone::new){{ flying = true; drag = 0.01f; speed = 0.42f; @@ -53,7 +53,7 @@ public class UnitTypes implements ContentList{ }}; }}; - phantom = new UnitType("phantom", Phantom::new){{ + phantom = new UnitType("phantom", BuilderDrone::new){{ flying = true; drag = 0.01f; mass = 2f; @@ -76,7 +76,7 @@ public class UnitTypes implements ContentList{ }}; }}; - dagger = new UnitType("dagger", Dagger::new){{ + dagger = new UnitType("dagger", GroundUnit::new){{ maxVelocity = 1.1f; speed = 0.2f; drag = 0.4f; @@ -92,7 +92,7 @@ public class UnitTypes implements ContentList{ }}; }}; - crawler = new UnitType("crawler", Crawler::new){{ + crawler = new UnitType("crawler", GroundUnit::new){{ maxVelocity = 1.27f; speed = 0.285f; drag = 0.4f; @@ -123,7 +123,7 @@ public class UnitTypes implements ContentList{ }}; }}; - titan = new UnitType("titan", Titan::new){{ + titan = new UnitType("titan", GroundUnit::new){{ maxVelocity = 0.8f; speed = 0.22f; drag = 0.4f; @@ -145,7 +145,7 @@ public class UnitTypes implements ContentList{ }}; }}; - fortress = new UnitType("fortress", Fortress::new){{ + fortress = new UnitType("fortress", GroundUnit::new){{ maxVelocity = 0.78f; speed = 0.15f; drag = 0.4f; @@ -167,7 +167,7 @@ public class UnitTypes implements ContentList{ }}; }}; - eruptor = new UnitType("eruptor", Eruptor::new){{ + eruptor = new UnitType("eruptor", GroundUnit::new){{ maxVelocity = 0.81f; speed = 0.16f; drag = 0.4f; @@ -189,7 +189,7 @@ public class UnitTypes implements ContentList{ }}; }}; - chaosArray = new UnitType("chaos-array", Dagger::new){{ + chaosArray = new UnitType("chaos-array", GroundUnit::new){{ maxVelocity = 0.68f; speed = 0.12f; drag = 0.4f; @@ -213,7 +213,7 @@ public class UnitTypes implements ContentList{ }}; }}; - eradicator = new UnitType("eradicator", Dagger::new){{ + eradicator = new UnitType("eradicator", GroundUnit::new){{ maxVelocity = 0.68f; speed = 0.12f; drag = 0.4f; @@ -238,7 +238,7 @@ public class UnitTypes implements ContentList{ }}; }}; - wraith = new UnitType("wraith", Wraith::new){{ + wraith = new UnitType("wraith", FlyingUnit::new){{ speed = 0.3f; maxVelocity = 1.9f; drag = 0.01f; @@ -257,7 +257,7 @@ public class UnitTypes implements ContentList{ }}; }}; - ghoul = new UnitType("ghoul", Ghoul::new){{ + ghoul = new UnitType("ghoul", FlyingUnit::new){{ health = 220; speed = 0.2f; maxVelocity = 1.4f; @@ -281,7 +281,7 @@ public class UnitTypes implements ContentList{ }}; }}; - revenant = new UnitType("revenant", Revenant::new){{ + revenant = new UnitType("revenant", HoverUnit::new){{ health = 1000; mass = 5f; hitsize = 20f; @@ -312,7 +312,7 @@ public class UnitTypes implements ContentList{ }}; }}; - lich = new UnitType("lich", Revenant::new){{ + lich = new UnitType("lich", HoverUnit::new){{ health = 6000; mass = 20f; hitsize = 40f; @@ -345,7 +345,7 @@ public class UnitTypes implements ContentList{ }}; }}; - reaper = new UnitType("reaper", Revenant::new){{ + reaper = new UnitType("reaper", HoverUnit::new){{ health = 11000; mass = 30f; hitsize = 56f; diff --git a/core/src/io/anuke/mindustry/core/ContentLoader.java b/core/src/io/anuke/mindustry/core/ContentLoader.java index bc4d0dac81..274139b206 100644 --- a/core/src/io/anuke/mindustry/core/ContentLoader.java +++ b/core/src/io/anuke/mindustry/core/ContentLoader.java @@ -3,9 +3,11 @@ package io.anuke.mindustry.core; import io.anuke.arc.collection.*; import io.anuke.arc.func.*; import io.anuke.arc.graphics.*; +import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.arc.util.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.bullet.*; import io.anuke.mindustry.mod.Mods.*; import io.anuke.mindustry.type.*; @@ -20,10 +22,11 @@ import static io.anuke.mindustry.Vars.mods; */ @SuppressWarnings("unchecked") public class ContentLoader{ - private boolean loaded = false; private ObjectMap[] contentNameMap = new ObjectMap[ContentType.values().length]; private Array[] contentMap = new Array[ContentType.values().length]; private MappableContent[][] temporaryMapper; + private @Nullable LoadedMod currentMod; + private @Nullable Content lastAdded; private ObjectSet> initialization = new ObjectSet<>(); private ContentList[] content = { new Fx(), @@ -43,35 +46,40 @@ public class ContentLoader{ new LegacyColorMapper(), }; + public ContentLoader(){ + clear(); + } + /** Clears all initialized content.*/ public void clear(){ contentNameMap = new ObjectMap[ContentType.values().length]; contentMap = new Array[ContentType.values().length]; initialization = new ObjectSet<>(); - loaded = false; - } - - /** Creates all content types. */ - public void createContent(){ - if(loaded){ - Log.info("Content already loaded, skipping."); - return; - } for(ContentType type : ContentType.values()){ contentMap[type.ordinal()] = new Array<>(); contentNameMap[type.ordinal()] = new ObjectMap<>(); } + } + + /** Creates all base types. */ + public void createBaseContent(){ for(ContentList list : content){ list.load(); } + } + /** Creates mod content, if applicable. */ + public void createModContent(){ if(mods != null){ mods.loadContent(); } + } - //check up ID mapping, make sure it's linear + /** Logs content statistics.*/ + public void logContent(){ + //check up ID mapping, make sure it's linear (debug only) for(Array arr : contentMap){ for(int i = 0; i < arr.size; i++){ int id = arr.get(i).id; @@ -81,17 +89,12 @@ public class ContentLoader{ } } - loaded = true; - } - - /** Logs content statistics.*/ - public void logContent(){ - Log.info("--- CONTENT INFO ---"); + Log.debug("--- CONTENT INFO ---"); for(int k = 0; k < contentMap.length; k++){ - Log.info("[{0}]: loaded {1}", ContentType.values()[k].name(), contentMap[k].size); + Log.debug("[{0}]: loaded {1}", ContentType.values()[k].name(), contentMap[k].size); } - Log.info("Total content loaded: {0}", Array.with(ContentType.values()).mapInt(c -> contentMap[c.ordinal()].size).sum()); - Log.info("-------------------"); + Log.debug("Total content loaded: {0}", Array.with(ContentType.values()).mapInt(c -> contentMap[c.ordinal()].size).sum()); + Log.debug("-------------------"); } /** Calls Content#init() on everything. Use only after all modules have been created.*/ @@ -113,8 +116,8 @@ public class ContentLoader{ try{ callable.get(content); }catch(Throwable e){ - if(content.mod != null){ - mods.handleError(new ModLoadException(content, e), content.mod); + if(content.minfo.mod != null){ + mods.handleContentError(content, e); }else{ throw new RuntimeException(e); } @@ -145,15 +148,41 @@ public class ContentLoader{ //clear all content, currently not used } - public void handleContent(Content content){ - contentMap[content.getContentType().ordinal()].add(content); + /** Get last piece of content created for error-handling purposes. */ + public @Nullable Content getLastAdded(){ + return lastAdded; + } + /** Remove last content added in case of an exception. */ + public void removeLast(){ + if(lastAdded != null && contentMap[lastAdded.getContentType().ordinal()].peek() == lastAdded){ + contentMap[lastAdded.getContentType().ordinal()].pop(); + if(lastAdded instanceof MappableContent){ + contentNameMap[lastAdded.getContentType().ordinal()].remove(((MappableContent)lastAdded).name); + } + } + } + + public void handleContent(Content content){ + this.lastAdded = content; + contentMap[content.getContentType().ordinal()].add(content); + } + + public void setCurrentMod(@Nullable LoadedMod mod){ + this.currentMod = mod; + } + + public String transformName(String name){ + return currentMod == null ? name : currentMod.name + "-" + name; } public void handleMappableContent(MappableContent content){ if(contentNameMap[content.getContentType().ordinal()].containsKey(content.name)){ throw new IllegalArgumentException("Two content objects cannot have the same name! (issue: '" + content.name + "')"); } + if(currentMod != null){ + content.minfo.mod = currentMod; + } contentNameMap[content.getContentType().ordinal()].put(content.name, content); } diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index b38cc63297..56dc35eb2c 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -262,6 +262,7 @@ public class Control implements ApplicationListener, Loadable{ } } state.set(State.playing); + state.wavetime = state.rules.waveSpacing; control.saves.zoneSave(); logic.play(); Events.fire(Trigger.newGame); @@ -451,12 +452,12 @@ public class Control implements ApplicationListener, Loadable{ platform.updateRPC(); } - if(Core.input.keyTap(Binding.pause) && !scene.hasDialog() && !ui.restart.isShown() && (state.is(State.paused) || state.is(State.playing))){ + if(Core.input.keyTap(Binding.pause) && !scene.hasDialog() && !scene.hasKeyboard() && !ui.restart.isShown() && (state.is(State.paused) || state.is(State.playing))){ state.set(state.is(State.playing) ? State.paused : State.playing); } if(Core.input.keyTap(Binding.menu) && !ui.restart.isShown()){ - if(ui.chatfrag.chatOpen()){ + if(ui.chatfrag.shown()){ ui.chatfrag.hide(); }else if(!ui.paused.isShown() && !scene.hasDialog()){ ui.paused.show(); @@ -464,7 +465,7 @@ public class Control implements ApplicationListener, Loadable{ } } - if(!mobile && Core.input.keyTap(Binding.screenshot) && !(scene.getKeyboardFocus() instanceof TextField) && !ui.chatfrag.chatOpen()){ + if(!mobile && Core.input.keyTap(Binding.screenshot) && !(scene.getKeyboardFocus() instanceof TextField) && !scene.hasKeyboard()){ renderer.takeMapScreenshot(); } diff --git a/core/src/io/anuke/mindustry/core/FileTree.java b/core/src/io/anuke/mindustry/core/FileTree.java index e6d7e78086..cd201c5337 100644 --- a/core/src/io/anuke/mindustry/core/FileTree.java +++ b/core/src/io/anuke/mindustry/core/FileTree.java @@ -7,16 +7,18 @@ import io.anuke.arc.files.*; /** Handles files in a modded context. */ public class FileTree implements FileHandleResolver{ - private ObjectMap files = new ObjectMap<>(); + private ObjectMap files = new ObjectMap<>(); - public void addFile(String path, FileHandle f){ + public void addFile(String path, Fi f){ files.put(path, f); } /** Gets an asset file.*/ - public FileHandle get(String path){ + public Fi get(String path){ if(files.containsKey(path)){ return files.get(path); + }else if(files.containsKey("/" + path)){ + return files.get("/" + path); }else{ return Core.files.internal(path); } @@ -28,7 +30,7 @@ public class FileTree implements FileHandleResolver{ } @Override - public FileHandle resolve(String fileName){ + public Fi resolve(String fileName){ return get(fileName); } } diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index 91b7e9ba3a..69c667e625 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -52,7 +52,7 @@ public class Logic implements ApplicationListener{ if(block instanceof BuildBlock){ - BuildEntity entity = tile.entity(); + BuildEntity entity = tile.ent(); //update block to reflect the fact that something was being constructed if(entity.cblock != null && entity.cblock.synthetic()){ diff --git a/core/src/io/anuke/mindustry/core/NetClient.java b/core/src/io/anuke/mindustry/core/NetClient.java index 2b2e1d4b76..6a0f0428e3 100644 --- a/core/src/io/anuke/mindustry/core/NetClient.java +++ b/core/src/io/anuke/mindustry/core/NetClient.java @@ -11,6 +11,7 @@ import io.anuke.arc.util.io.*; import io.anuke.arc.util.serialization.*; import io.anuke.mindustry.*; import io.anuke.mindustry.core.GameState.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.entities.traits.*; @@ -22,7 +23,6 @@ import io.anuke.mindustry.net.Administration.*; import io.anuke.mindustry.net.Net.*; import io.anuke.mindustry.net.*; import io.anuke.mindustry.net.Packets.*; -import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.TypeID; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.modules.*; @@ -491,7 +491,7 @@ public class NetClient implements ApplicationListener{ player.pointerX, player.pointerY, player.rotation, player.baseRotation, player.velocity().x, player.velocity().y, player.getMineTile(), - player.isBoosting, player.isShooting, ui.chatfrag.chatOpen(), player.isBuilding, + player.isBoosting, player.isShooting, ui.chatfrag.shown(), player.isBuilding, requests, Core.camera.position.x, Core.camera.position.y, Core.camera.width * viewScale, Core.camera.height * viewScale); diff --git a/core/src/io/anuke/mindustry/core/NetServer.java b/core/src/io/anuke/mindustry/core/NetServer.java index 8d42dcaed7..218cbd2d83 100644 --- a/core/src/io/anuke/mindustry/core/NetServer.java +++ b/core/src/io/anuke/mindustry/core/NetServer.java @@ -66,6 +66,10 @@ public class NetServer implements ApplicationListener{ }); net.handleServer(ConnectPacket.class, (con, packet) -> { + if(con.address.startsWith("steam:")){ + packet.uuid = con.address.substring("steam:".length()); + } + String uuid = packet.uuid; if(admins.isIPBanned(con.address)) return; @@ -215,7 +219,7 @@ public class NetServer implements ApplicationListener{ @Override public void init(){ - mods.each(mod -> mod.registerClientCommands(clientCommands)); + mods.eachClass(mod -> mod.registerClientCommands(clientCommands)); } private void registerCommands(){ diff --git a/core/src/io/anuke/mindustry/core/Platform.java b/core/src/io/anuke/mindustry/core/Platform.java index 50875d426d..0cfb72a058 100644 --- a/core/src/io/anuke/mindustry/core/Platform.java +++ b/core/src/io/anuke/mindustry/core/Platform.java @@ -8,10 +8,12 @@ import io.anuke.arc.func.*; import io.anuke.arc.math.*; import io.anuke.arc.scene.ui.*; import io.anuke.arc.util.serialization.*; +import io.anuke.mindustry.mod.*; import io.anuke.mindustry.net.*; import io.anuke.mindustry.net.Net.*; import io.anuke.mindustry.type.*; import io.anuke.mindustry.ui.dialogs.*; +import org.mozilla.javascript.*; import static io.anuke.mindustry.Vars.mobile; @@ -33,7 +35,7 @@ public interface Platform{ default void viewListingID(String mapid){} /** Steam: Return external workshop maps to be loaded.*/ - default Array getWorkshopContent(Class type){ + default Array getWorkshopContent(Class type){ return new Array<>(0); } @@ -42,7 +44,18 @@ public interface Platform{ /** Get the networking implementation.*/ default NetProvider getNet(){ - return new ArcNetImpl(); + return new ArcNetProvider(); + } + + /** Gets the scripting implementation. */ + default Scripts createScripts(){ + return new Scripts(); + } + + default Context getScriptContext(){ + Context c = Context.enter(); + c.setOptimizationLevel(9); + return c; } /** Add a text input dialog that should show up after the field is tapped. */ @@ -87,7 +100,7 @@ public interface Platform{ } /** Only used for iOS or android: open the share menu for a map or save. */ - default void shareFile(FileHandle file){ + default void shareFile(Fi file){ } /** @@ -96,7 +109,7 @@ public interface Platform{ * @param open Whether to open or save files * @param extension File extension to filter */ - default void showFileChooser(boolean open, String extension, Cons cons){ + default void showFileChooser(boolean open, String extension, Cons cons){ new FileChooser(open ? "$open" : "$save", file -> file.extension().toLowerCase().equals(extension), open, file -> { if(!open){ cons.get(file.parent().child(file.nameWithoutExtension() + "." + extension)); diff --git a/core/src/io/anuke/mindustry/core/Renderer.java b/core/src/io/anuke/mindustry/core/Renderer.java index 4a50b04275..c8cf2b1063 100644 --- a/core/src/io/anuke/mindustry/core/Renderer.java +++ b/core/src/io/anuke/mindustry/core/Renderer.java @@ -456,7 +456,7 @@ public class Renderer implements ApplicationListener{ buffer.end(); Pixmap fullPixmap = new Pixmap(w, h, Pixmap.Format.RGBA8888); BufferUtils.copy(lines, 0, fullPixmap.getPixels(), lines.length); - FileHandle file = screenshotDirectory.child("screenshot-" + Time.millis() + ".png"); + Fi file = screenshotDirectory.child("screenshot-" + Time.millis() + ".png"); PixmapIO.writePNG(file, fullPixmap); fullPixmap.dispose(); ui.showInfoFade(Core.bundle.format("screenshot", file.toString())); diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index 142481b96d..9b0af80f52 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -42,6 +42,7 @@ public class UI implements ApplicationListener, Loadable{ public MenuFragment menufrag; public HudFragment hudfrag; public ChatFragment chatfrag; + public ScriptConsoleFragment scriptfrag; public PlayerListFragment listfrag; public LoadingFragment loadfrag; @@ -137,7 +138,7 @@ public class UI implements ApplicationListener, Loadable{ Core.assets.setLoader(FreeTypeFontGenerator.class, new FreeTypeFontGeneratorLoader(resolver)); Core.assets.setLoader(BitmapFont.class, null, new FreetypeFontLoader(resolver){ @Override - public BitmapFont loadSync(AssetManager manager, String fileName, FileHandle file, FreeTypeFontLoaderParameter parameter){ + 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; @@ -211,6 +212,7 @@ public class UI implements ApplicationListener, Loadable{ chatfrag = new ChatFragment(); listfrag = new PlayerListFragment(); loadfrag = new LoadingFragment(); + scriptfrag = new ScriptConsoleFragment(); picker = new ColorPicker(); editor = new MapEditorDialog(); @@ -253,6 +255,7 @@ public class UI implements ApplicationListener, Loadable{ menufrag.build(menuGroup); chatfrag.container().build(hudGroup); listfrag.build(hudGroup); + scriptfrag.container().build(hudGroup); loadfrag.build(group); new FadeInFragment().build(group); } @@ -371,6 +374,37 @@ public class UI implements ApplicationListener, Loadable{ }}.show(); } + public void showExceptions(String text, String... messages){ + loadfrag.hide(); + new Dialog(""){{ + + setFillParent(true); + cont.margin(15); + cont.add("$error.title").colspan(2); + cont.row(); + cont.addImage().width(300f).pad(2).colspan(2).height(4f).color(Color.scarlet); + cont.row(); + cont.add(text).colspan(2).wrap().growX().center().get().setAlignment(Align.center); + cont.row(); + + //cont.pane(p -> { + for(int i = 0; i < messages.length; i += 2){ + String btext = messages[i]; + String details = messages[i + 1]; + Collapser col = new Collapser(base -> base.pane(t -> t.margin(14f).add(details).color(Color.lightGray).left()), true); + + cont.add(btext).right(); + cont.addButton("$details", Styles.togglet, col::toggle).size(180f, 50f).checked(b -> !col.isCollapsed()).fillX().left(); + cont.row(); + cont.add(col).colspan(2).pad(2); + cont.row(); + } + //}).colspan(2); + + cont.addButton("$ok", this::hide).size(300, 50).fillX().colspan(2); + }}.show(); + } + public void showText(String titleText, String text){ showText(titleText, text, Align.center); } diff --git a/core/src/io/anuke/mindustry/core/Version.java b/core/src/io/anuke/mindustry/core/Version.java index 9d774c47c8..a6ff7ea6a9 100644 --- a/core/src/io/anuke/mindustry/core/Version.java +++ b/core/src/io/anuke/mindustry/core/Version.java @@ -7,8 +7,6 @@ import io.anuke.arc.files.*; import io.anuke.arc.util.*; import io.anuke.arc.util.io.*; -import java.io.*; - public class Version{ /** Build type. 'official' for official releases; 'custom' or 'bleeding edge' are also used. */ public static String type; @@ -26,29 +24,25 @@ public class Version{ public static void init(){ if(!enabled) return; - try{ - FileHandle file = OS.isAndroid || OS.isIos ? Core.files.internal("version.properties") : new FileHandle("version.properties", FileType.Internal); + Fi file = OS.isAndroid || OS.isIos ? Core.files.internal("version.properties") : new Fi("version.properties", FileType.internal); - ObjectMap map = new ObjectMap<>(); - PropertiesUtils.load(map, file.reader()); + ObjectMap map = new ObjectMap<>(); + PropertiesUtils.load(map, file.reader()); - type = map.get("type"); - number = Integer.parseInt(map.get("number", "4")); - modifier = map.get("modifier"); - if(map.get("build").contains(".")){ - String[] split = map.get("build").split("\\."); - try{ - build = Integer.parseInt(split[0]); - revision = Integer.parseInt(split[1]); - }catch(Throwable e){ - e.printStackTrace(); - build = -1; - } - }else{ - build = Strings.canParseInt(map.get("build")) ? Integer.parseInt(map.get("build")) : -1; + type = map.get("type"); + number = Integer.parseInt(map.get("number", "4")); + modifier = map.get("modifier"); + if(map.get("build").contains(".")){ + String[] split = map.get("build").split("\\."); + try{ + build = Integer.parseInt(split[0]); + revision = Integer.parseInt(split[1]); + }catch(Throwable e){ + e.printStackTrace(); + build = -1; } - }catch(IOException e){ - throw new RuntimeException(e); + }else{ + build = Strings.canParseInt(map.get("build")) ? Integer.parseInt(map.get("build")) : -1; } } } diff --git a/core/src/io/anuke/mindustry/ctype/Content.java b/core/src/io/anuke/mindustry/ctype/Content.java index ab6f20d305..09a304817d 100644 --- a/core/src/io/anuke/mindustry/ctype/Content.java +++ b/core/src/io/anuke/mindustry/ctype/Content.java @@ -4,16 +4,14 @@ import io.anuke.arc.files.*; import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.mindustry.*; import io.anuke.mindustry.mod.Mods.*; -import io.anuke.mindustry.type.*; /** Base class for a content type that is loaded in {@link io.anuke.mindustry.core.ContentLoader}. */ public abstract class Content implements Comparable{ public final short id; - /** The mod that loaded this piece of content. */ - public @Nullable LoadedMod mod; - /** File that this content was loaded from. */ - public @Nullable FileHandle sourceFile; + /** Info on which mod this content was loaded from. */ + public @NonNull ModContentInfo minfo = new ModContentInfo(); + public Content(){ this.id = (short)Vars.content.getBy(getContentType()).size; @@ -37,6 +35,11 @@ public abstract class Content implements Comparable{ public void load(){ } + /** @return whether an error ocurred during mod loading. */ + public boolean hasErrored(){ + return minfo.error != null; + } + @Override public int compareTo(Content c){ return Integer.compare(id, c.id); @@ -46,4 +49,15 @@ public abstract class Content implements Comparable{ public String toString(){ return getContentType().name() + "#" + id; } + + public static class ModContentInfo{ + /** The mod that loaded this piece of content. */ + public @Nullable LoadedMod mod; + /** File that this content was loaded from. */ + public @Nullable Fi sourceFile; + /** The error that occurred during loading, if applicable. Null if no error occurred. */ + public @Nullable String error; + /** Base throwable that caused the error. */ + public @Nullable Throwable baseError; + } } diff --git a/core/src/io/anuke/mindustry/type/ContentType.java b/core/src/io/anuke/mindustry/ctype/ContentType.java similarity index 80% rename from core/src/io/anuke/mindustry/type/ContentType.java rename to core/src/io/anuke/mindustry/ctype/ContentType.java index f6b980a5d5..5b2e1bdb3b 100644 --- a/core/src/io/anuke/mindustry/type/ContentType.java +++ b/core/src/io/anuke/mindustry/ctype/ContentType.java @@ -1,4 +1,4 @@ -package io.anuke.mindustry.type; +package io.anuke.mindustry.ctype; /** Do not rearrange, ever! */ public enum ContentType{ @@ -13,7 +13,8 @@ public enum ContentType{ effect, zone, loadout, - typeid; + typeid, + error; public static final ContentType[] all = values(); } diff --git a/core/src/io/anuke/mindustry/ctype/MappableContent.java b/core/src/io/anuke/mindustry/ctype/MappableContent.java index 3063157c13..709e7652d4 100644 --- a/core/src/io/anuke/mindustry/ctype/MappableContent.java +++ b/core/src/io/anuke/mindustry/ctype/MappableContent.java @@ -6,7 +6,7 @@ public abstract class MappableContent extends Content{ public final String name; public MappableContent(String name){ - this.name = name; + this.name = Vars.content.transformName(name); Vars.content.handleMappableContent(this); } diff --git a/core/src/io/anuke/mindustry/ctype/UnlockableContent.java b/core/src/io/anuke/mindustry/ctype/UnlockableContent.java index bb50e115cb..ab1e4d9e4b 100644 --- a/core/src/io/anuke/mindustry/ctype/UnlockableContent.java +++ b/core/src/io/anuke/mindustry/ctype/UnlockableContent.java @@ -20,8 +20,8 @@ public abstract class UnlockableContent extends MappableContent{ public UnlockableContent(String name){ super(name); - this.localizedName = Core.bundle.get(getContentType() + "." + name + ".name", name); - this.description = Core.bundle.getOrNull(getContentType() + "." + name + ".description"); + this.localizedName = Core.bundle.get(getContentType() + "." + this.name + ".name", this.name); + this.description = Core.bundle.getOrNull(getContentType() + "." + this.name + ".description"); } /** Generate any special icons for this content. Called asynchronously.*/ @@ -42,11 +42,6 @@ public abstract class UnlockableContent extends MappableContent{ return cicons[icon.ordinal()]; } - /** Returns the localized name of this content. */ - public abstract String localizedName(); - - //public abstract TextureRegion getContentIcon(); - /** This should show all necessary info about this content in the specified table. */ public abstract void displayInfo(Table table); diff --git a/core/src/io/anuke/mindustry/editor/MapEditor.java b/core/src/io/anuke/mindustry/editor/MapEditor.java index d8e8d60206..40b44d2b12 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditor.java +++ b/core/src/io/anuke/mindustry/editor/MapEditor.java @@ -1,7 +1,7 @@ package io.anuke.mindustry.editor; import io.anuke.arc.collection.StringMap; -import io.anuke.arc.files.FileHandle; +import io.anuke.arc.files.Fi; import io.anuke.arc.func.Cons; import io.anuke.arc.func.Boolf; import io.anuke.arc.graphics.Pixmap; @@ -109,7 +109,7 @@ public class MapEditor{ } } - public Map createMap(FileHandle file){ + public Map createMap(Fi file){ return new Map(file, width(), height(), new StringMap(tags), true); } diff --git a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java index 6c24f387a9..b8745052a0 100644 --- a/core/src/io/anuke/mindustry/editor/MapEditorDialog.java +++ b/core/src/io/anuke/mindustry/editor/MapEditorDialog.java @@ -133,7 +133,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ }else{ ui.loadAnd(() -> { try{ - FileHandle result = Core.files.local(editor.getTags().get("name", "unknown") + "." + mapExtension); + Fi result = Core.files.local(editor.getTags().get("name", "unknown") + "." + mapExtension); MapIO.writeMap(result, editor.createMap(result)); platform.shareFile(result); }catch(Exception e){ @@ -381,7 +381,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ editor.renderer().dispose(); } - public void beginEditMap(FileHandle file){ + public void beginEditMap(Fi file){ ui.loadAnd(() -> { try{ shownWithMap = true; diff --git a/core/src/io/anuke/mindustry/editor/WaveInfoDialog.java b/core/src/io/anuke/mindustry/editor/WaveInfoDialog.java index 37f55cb775..187d8a7fc2 100644 --- a/core/src/io/anuke/mindustry/editor/WaveInfoDialog.java +++ b/core/src/io/anuke/mindustry/editor/WaveInfoDialog.java @@ -12,6 +12,7 @@ import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; diff --git a/core/src/io/anuke/mindustry/entities/Damage.java b/core/src/io/anuke/mindustry/entities/Damage.java index 149bb9b4d8..e637c6081e 100644 --- a/core/src/io/anuke/mindustry/entities/Damage.java +++ b/core/src/io/anuke/mindustry/entities/Damage.java @@ -38,7 +38,7 @@ public class Damage{ } for(int i = 0; i < Mathf.clamp(flammability / 4, 0, 30); i++){ - Time.run(i / 2f, () -> Call.createBullet(Bullets.fireball, x, y, Mathf.random(360f))); + Time.run(i / 2f, () -> Call.createBullet(Bullets.fireball, Team.derelict, x, y, Mathf.random(360f), 1, 1)); } int waves = Mathf.clamp((int)(explosiveness / 4), 0, 30); diff --git a/core/src/io/anuke/mindustry/entities/Effects.java b/core/src/io/anuke/mindustry/entities/Effects.java index 2647fc2427..ca1492bdbf 100644 --- a/core/src/io/anuke/mindustry/entities/Effects.java +++ b/core/src/io/anuke/mindustry/entities/Effects.java @@ -4,6 +4,7 @@ import io.anuke.arc.Core; import io.anuke.arc.collection.Array; import io.anuke.arc.func.Cons; import io.anuke.arc.graphics.Color; +import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.math.Mathf; import io.anuke.arc.math.geom.Position; import io.anuke.arc.util.pooling.Pools; @@ -36,6 +37,7 @@ public class Effects{ 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){ diff --git a/core/src/io/anuke/mindustry/entities/bullet/BulletType.java b/core/src/io/anuke/mindustry/entities/bullet/BulletType.java index 807218cd85..bc401c6d6d 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/BulletType.java +++ b/core/src/io/anuke/mindustry/entities/bullet/BulletType.java @@ -4,6 +4,7 @@ import io.anuke.arc.audio.*; import io.anuke.arc.math.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.ctype.Content; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.Effects.*; import io.anuke.mindustry.entities.effect.*; @@ -137,7 +138,7 @@ public abstract class BulletType extends Content{ } for(int i = 0; i < lightining; i++){ - Lightning.create(b.getTeam(), Pal.surge, damage, b.x, b.y, Mathf.random(360f), lightningLength); + Lightning.createLighting(Lightning.nextSeed(), b.getTeam(), Pal.surge, damage, b.x, b.y, Mathf.random(360f), lightningLength); } } @@ -150,7 +151,7 @@ public abstract class BulletType extends Content{ public void update(Bullet b){ if(homingPower > 0.0001f){ - TargetTrait target = Units.closestTarget(b.getTeam(), b.x, b.y, homingRange); + TargetTrait target = Units.closestTarget(b.getTeam(), b.x, b.y, homingRange, e -> !e.isFlying() || collidesAir); if(target != null){ b.velocity().setAngle(Mathf.slerpDelta(b.velocity().angle(), b.angleTo(target), 0.08f)); } diff --git a/core/src/io/anuke/mindustry/entities/effect/Fire.java b/core/src/io/anuke/mindustry/entities/effect/Fire.java index 2c47550426..8546ec45e8 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Fire.java +++ b/core/src/io/anuke/mindustry/entities/effect/Fire.java @@ -10,10 +10,10 @@ import io.anuke.mindustry.content.*; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.entities.type.*; -import io.anuke.mindustry.entities.type.TimedEntity; import io.anuke.mindustry.game.EventType.*; +import io.anuke.mindustry.game.*; import io.anuke.mindustry.gen.*; -import io.anuke.mindustry.type.TypeID; +import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.*; import java.io.*; @@ -144,7 +144,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait{ create(other); if(Mathf.chance(fireballChance * Time.delta() * Mathf.clamp(flammability / 10f))){ - Call.createBullet(Bullets.fireball, x, y, Mathf.random(360f)); + Call.createBullet(Bullets.fireball, Team.derelict, x, y, Mathf.random(360f), 1, 1); } } diff --git a/core/src/io/anuke/mindustry/entities/effect/Lightning.java b/core/src/io/anuke/mindustry/entities/effect/Lightning.java index 44bc54d1cb..8d28f33d65 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Lightning.java +++ b/core/src/io/anuke/mindustry/entities/effect/Lightning.java @@ -44,7 +44,11 @@ public class Lightning extends TimedEntity implements DrawTrait, TimeTrait{ /** 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(lastSeed++, team, color, damage, x, y, targetAngle, length); + Call.createLighting(nextSeed(), team, color, damage, x, y, targetAngle, length); + } + + public static int nextSeed(){ + return lastSeed++; } /** Do not invoke! */ diff --git a/core/src/io/anuke/mindustry/entities/effect/Puddle.java b/core/src/io/anuke/mindustry/entities/effect/Puddle.java index e7f1330a10..e53e40e8dc 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Puddle.java +++ b/core/src/io/anuke/mindustry/entities/effect/Puddle.java @@ -1,25 +1,22 @@ package io.anuke.mindustry.entities.effect; -import io.anuke.annotations.Annotations.Loc; -import io.anuke.annotations.Annotations.Remote; -import io.anuke.arc.collection.IntMap; -import io.anuke.arc.graphics.Color; -import io.anuke.arc.graphics.g2d.Draw; -import io.anuke.arc.graphics.g2d.Fill; -import io.anuke.arc.math.Angles; -import io.anuke.arc.math.Mathf; +import io.anuke.annotations.Annotations.*; +import io.anuke.arc.collection.*; +import io.anuke.arc.graphics.*; +import io.anuke.arc.graphics.g2d.*; +import io.anuke.arc.math.*; import io.anuke.arc.math.geom.*; -import io.anuke.arc.util.Time; -import io.anuke.arc.util.pooling.Pool.Poolable; -import io.anuke.arc.util.pooling.Pools; +import io.anuke.arc.util.*; +import io.anuke.arc.util.pooling.Pool.*; +import io.anuke.arc.util.pooling.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.entities.*; -import io.anuke.mindustry.entities.type.SolidEntity; import io.anuke.mindustry.entities.traits.*; -import io.anuke.mindustry.type.TypeID; -import io.anuke.mindustry.gen.Call; -import io.anuke.mindustry.type.Liquid; -import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.game.*; +import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.type.*; +import io.anuke.mindustry.world.*; import java.io.*; @@ -118,7 +115,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai (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, x, y, Mathf.random(360f)); + 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)){ diff --git a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java index 3459e3b18e..c7ced76ec8 100644 --- a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java @@ -2,7 +2,6 @@ package io.anuke.mindustry.entities.traits; import io.anuke.arc.*; import io.anuke.arc.collection.Queue; -import io.anuke.arc.collection.*; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.math.*; import io.anuke.arc.math.geom.*; @@ -88,7 +87,7 @@ public interface BuilderTrait extends Entity, TeamTrait{ } //otherwise, update it. - BuildEntity entity = tile.entity(); + BuildEntity entity = tile.ent(); if(entity == null){ return; @@ -210,7 +209,7 @@ public interface BuilderTrait extends Entity, TeamTrait{ } Tile tile = world.tile(place.x, place.y); if(tile != null && tile.entity instanceof BuildEntity){ - place.progress = tile.entity().progress; + place.progress = tile.ent().progress; } if(tail){ buildQueue().addLast(place); diff --git a/core/src/io/anuke/mindustry/entities/type/BaseUnit.java b/core/src/io/anuke/mindustry/entities/type/BaseUnit.java index ab22a7933b..6dfa7baa84 100644 --- a/core/src/io/anuke/mindustry/entities/type/BaseUnit.java +++ b/core/src/io/anuke/mindustry/entities/type/BaseUnit.java @@ -9,6 +9,7 @@ import io.anuke.arc.util.*; import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.entities.units.*; @@ -107,7 +108,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ public @Nullable UnitCommand getCommand(){ if(isCommanded()){ - return indexer.getAllied(team, BlockFlag.comandCenter).first().entity().command; + return indexer.getAllied(team, BlockFlag.comandCenter).first().ent().command; } return null; } diff --git a/core/src/io/anuke/mindustry/entities/type/Bullet.java b/core/src/io/anuke/mindustry/entities/type/Bullet.java index a5c3d21697..abf7952aeb 100644 --- a/core/src/io/anuke/mindustry/entities/type/Bullet.java +++ b/core/src/io/anuke/mindustry/entities/type/Bullet.java @@ -77,16 +77,9 @@ public class Bullet extends SolidEntity implements DamageTrait, ScaleTrait, Pool return create(type, parent.owner, parent.team, x, y, angle, velocityScl); } - /** Internal use only. */ @Remote(called = Loc.server, unreliable = true) - public static void createBullet(BulletType type, float x, float y, float angle){ - create(type, null, Team.derelict, x, y, angle); - } - - /** ok */ - @Remote(called = Loc.server, unreliable = true) - public static void createBullet(BulletType type, Team team, float x, float y, float angle){ - create(type, null, team, x, y, angle); + 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(){ diff --git a/core/src/io/anuke/mindustry/entities/type/Player.java b/core/src/io/anuke/mindustry/entities/type/Player.java index 4e83cd1091..45405aad70 100644 --- a/core/src/io/anuke/mindustry/entities/type/Player.java +++ b/core/src/io/anuke/mindustry/entities/type/Player.java @@ -15,6 +15,7 @@ import io.anuke.arc.util.pooling.*; import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.core.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.game.*; @@ -556,7 +557,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ updateKeyboard(); } - isTyping = ui.chatfrag.chatOpen(); + isTyping = ui.chatfrag.shown(); updateMechanics(); @@ -604,7 +605,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ movement.limit(speed).scl(Time.delta()); - if(!ui.chatfrag.chatOpen()){ + if(!Core.scene.hasKeyboard()){ velocity.add(movement.x, movement.y); }else{ isShooting = false; @@ -613,7 +614,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ updateVelocityStatus(); moved = dst(prex, prey) > 0.001f; - if(!ui.chatfrag.chatOpen()){ + if(!Core.scene.hasKeyboard()){ float baseLerp = mech.getRotationAlpha(this); if(!isShooting() || !mech.turnCursor){ if(!movement.isZero()){ diff --git a/core/src/io/anuke/mindustry/entities/type/TileEntity.java b/core/src/io/anuke/mindustry/entities/type/TileEntity.java index 947748ffeb..8c9617b28b 100644 --- a/core/src/io/anuke/mindustry/entities/type/TileEntity.java +++ b/core/src/io/anuke/mindustry/entities/type/TileEntity.java @@ -37,7 +37,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ public PowerModule power; public ItemModule items; public LiquidModule liquids; - public ConsumeModule cons; + public @Nullable ConsumeModule cons; /** List of (cached) tiles with entities in proximity, used for outputting to */ private Array proximity = new Array<>(8); diff --git a/core/src/io/anuke/mindustry/entities/type/base/BuilderDrone.java b/core/src/io/anuke/mindustry/entities/type/base/BuilderDrone.java index 06a3ceb60d..fdaaa049dd 100644 --- a/core/src/io/anuke/mindustry/entities/type/base/BuilderDrone.java +++ b/core/src/io/anuke/mindustry/entities/type/base/BuilderDrone.java @@ -24,6 +24,7 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ private static final IntIntMap totals = new IntIntMap(); protected Queue placeQueue = new Queue<>(); + protected BuildRequest lastFound; protected boolean isBreaking; protected Player playerTarget; @@ -57,6 +58,9 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ 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); + } } } @@ -171,9 +175,10 @@ public class BuilderDrone extends BaseDrone implements BuilderTrait{ BuildRequest req = player.buildRequest(); Tile tile = world.tile(req.x, req.y); if(tile != null && tile.entity instanceof BuildEntity){ - BuildEntity b = tile.entity(); + 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); diff --git a/core/src/io/anuke/mindustry/entities/type/base/Crawler.java b/core/src/io/anuke/mindustry/entities/type/base/Crawler.java deleted file mode 100644 index 44da8bea5f..0000000000 --- a/core/src/io/anuke/mindustry/entities/type/base/Crawler.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.anuke.mindustry.entities.type.base; - -public class Crawler extends GroundUnit{ -} diff --git a/core/src/io/anuke/mindustry/entities/type/base/Dagger.java b/core/src/io/anuke/mindustry/entities/type/base/Dagger.java deleted file mode 100644 index 09a39daaa7..0000000000 --- a/core/src/io/anuke/mindustry/entities/type/base/Dagger.java +++ /dev/null @@ -1,5 +0,0 @@ -package io.anuke.mindustry.entities.type.base; - -public class Dagger extends GroundUnit{ - -} diff --git a/core/src/io/anuke/mindustry/entities/type/base/Draug.java b/core/src/io/anuke/mindustry/entities/type/base/Draug.java deleted file mode 100644 index 47b7caed25..0000000000 --- a/core/src/io/anuke/mindustry/entities/type/base/Draug.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.anuke.mindustry.entities.type.base; - -public class Draug extends MinerDrone{ -} diff --git a/core/src/io/anuke/mindustry/entities/type/base/Eruptor.java b/core/src/io/anuke/mindustry/entities/type/base/Eruptor.java deleted file mode 100644 index 4c86371811..0000000000 --- a/core/src/io/anuke/mindustry/entities/type/base/Eruptor.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.anuke.mindustry.entities.type.base; - -public class Eruptor extends GroundUnit{ -} diff --git a/core/src/io/anuke/mindustry/entities/type/base/Fortress.java b/core/src/io/anuke/mindustry/entities/type/base/Fortress.java deleted file mode 100644 index c4f36dba69..0000000000 --- a/core/src/io/anuke/mindustry/entities/type/base/Fortress.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.anuke.mindustry.entities.type.base; - -public class Fortress extends GroundUnit{ -} diff --git a/core/src/io/anuke/mindustry/entities/type/base/Ghoul.java b/core/src/io/anuke/mindustry/entities/type/base/Ghoul.java deleted file mode 100644 index 0c4294645a..0000000000 --- a/core/src/io/anuke/mindustry/entities/type/base/Ghoul.java +++ /dev/null @@ -1,5 +0,0 @@ -package io.anuke.mindustry.entities.type.base; - -public class Ghoul extends FlyingUnit{ - -} diff --git a/core/src/io/anuke/mindustry/entities/type/base/Revenant.java b/core/src/io/anuke/mindustry/entities/type/base/HoverUnit.java similarity index 96% rename from core/src/io/anuke/mindustry/entities/type/base/Revenant.java rename to core/src/io/anuke/mindustry/entities/type/base/HoverUnit.java index 393c134891..6aae538484 100644 --- a/core/src/io/anuke/mindustry/entities/type/base/Revenant.java +++ b/core/src/io/anuke/mindustry/entities/type/base/HoverUnit.java @@ -5,7 +5,7 @@ import io.anuke.arc.math.Angles; import io.anuke.arc.math.Mathf; import io.anuke.mindustry.entities.Units; -public class Revenant extends FlyingUnit{ +public class HoverUnit extends FlyingUnit{ @Override public void drawWeapons(){ diff --git a/core/src/io/anuke/mindustry/entities/type/base/Phantom.java b/core/src/io/anuke/mindustry/entities/type/base/Phantom.java deleted file mode 100644 index 1a50115647..0000000000 --- a/core/src/io/anuke/mindustry/entities/type/base/Phantom.java +++ /dev/null @@ -1,5 +0,0 @@ -package io.anuke.mindustry.entities.type.base; - -public class Phantom extends BuilderDrone{ - -} diff --git a/core/src/io/anuke/mindustry/entities/type/base/Spirit.java b/core/src/io/anuke/mindustry/entities/type/base/Spirit.java deleted file mode 100644 index d43fc658b0..0000000000 --- a/core/src/io/anuke/mindustry/entities/type/base/Spirit.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.anuke.mindustry.entities.type.base; - -public class Spirit extends RepairDrone{ -} diff --git a/core/src/io/anuke/mindustry/entities/type/base/Titan.java b/core/src/io/anuke/mindustry/entities/type/base/Titan.java deleted file mode 100644 index 9324d4d215..0000000000 --- a/core/src/io/anuke/mindustry/entities/type/base/Titan.java +++ /dev/null @@ -1,5 +0,0 @@ -package io.anuke.mindustry.entities.type.base; - -public class Titan extends GroundUnit{ - -} diff --git a/core/src/io/anuke/mindustry/entities/type/base/Wraith.java b/core/src/io/anuke/mindustry/entities/type/base/Wraith.java deleted file mode 100644 index c8923e309f..0000000000 --- a/core/src/io/anuke/mindustry/entities/type/base/Wraith.java +++ /dev/null @@ -1,5 +0,0 @@ -package io.anuke.mindustry.entities.type.base; - -public class Wraith extends FlyingUnit{ - -} diff --git a/core/src/io/anuke/mindustry/entities/units/Statuses.java b/core/src/io/anuke/mindustry/entities/units/Statuses.java index b96937bfcb..2d2da40f1f 100644 --- a/core/src/io/anuke/mindustry/entities/units/Statuses.java +++ b/core/src/io/anuke/mindustry/entities/units/Statuses.java @@ -6,6 +6,7 @@ import io.anuke.arc.graphics.*; import io.anuke.arc.util.*; import io.anuke.arc.util.pooling.*; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.type.*; diff --git a/core/src/io/anuke/mindustry/game/EventType.java b/core/src/io/anuke/mindustry/game/EventType.java index a5319c18e5..4459e6860c 100644 --- a/core/src/io/anuke/mindustry/game/EventType.java +++ b/core/src/io/anuke/mindustry/game/EventType.java @@ -95,6 +95,10 @@ public class EventType{ } + public static class ServerLoadEvent{ + + } + public static class ContentReloadEvent{ } @@ -135,9 +139,19 @@ public class EventType{ } - /** Called when a player withdraws items from a block. Tutorial only.*/ + /** Called when the player withdraws items from a block. */ public static class WithdrawEvent{ + public final Tile tile; + public final Player player; + public final Item item; + public final int amount; + public WithdrawEvent(Tile tile, Player player, Item item, int amount){ + this.tile = tile; + this.player = player; + this.item = item; + this.amount = amount; + } } /** Called when a player deposits items to a block.*/ diff --git a/core/src/io/anuke/mindustry/game/GlobalData.java b/core/src/io/anuke/mindustry/game/GlobalData.java index 908173e751..d211683e2c 100644 --- a/core/src/io/anuke/mindustry/game/GlobalData.java +++ b/core/src/io/anuke/mindustry/game/GlobalData.java @@ -6,7 +6,7 @@ import io.anuke.arc.files.*; import io.anuke.arc.util.io.*; import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; -import io.anuke.mindustry.ctype.UnlockableContent; +import io.anuke.mindustry.ctype.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.type.*; @@ -35,8 +35,8 @@ public class GlobalData{ }); } - public void exportData(FileHandle file) throws IOException{ - Array files = new Array<>(); + public void exportData(Fi file) throws IOException{ + Array files = new Array<>(); files.add(Core.settings.getSettingsFile()); files.addAll(customMapDirectory.list()); files.addAll(saveDirectory.list()); @@ -46,7 +46,7 @@ public class GlobalData{ String base = Core.settings.getDataDirectory().path(); try(OutputStream fos = file.write(false, 2048); ZipOutputStream zos = new ZipOutputStream(fos)){ - for(FileHandle add : files){ + for(Fi add : files){ if(add.isDirectory()) continue; zos.putNextEntry(new ZipEntry(add.path().substring(base.length()))); Streams.copyStream(add.read(), zos); @@ -56,12 +56,12 @@ public class GlobalData{ } } - public void importData(FileHandle file){ - FileHandle dest = Core.files.local("zipdata.zip"); + public void importData(Fi file){ + Fi dest = Core.files.local("zipdata.zip"); file.copyTo(dest); - FileHandle zipped = new ZipFileHandle(dest); + Fi zipped = new ZipFi(dest); - FileHandle base = Core.settings.getDataDirectory(); + Fi base = Core.settings.getDataDirectory(); if(!zipped.child("settings.bin").exists()){ throw new IllegalArgumentException("Not valid save data."); } diff --git a/core/src/io/anuke/mindustry/game/Saves.java b/core/src/io/anuke/mindustry/game/Saves.java index 25bc7720c9..911fb5d558 100644 --- a/core/src/io/anuke/mindustry/game/Saves.java +++ b/core/src/io/anuke/mindustry/game/Saves.java @@ -27,7 +27,7 @@ public class Saves{ private AsyncExecutor previewExecutor = new AsyncExecutor(1); private boolean saving; private float time; - private FileHandle zoneFile; + private Fi zoneFile; private long totalPlaytime; private long lastTimestamp; @@ -48,7 +48,7 @@ public class Saves{ saves.clear(); zoneFile = saveDirectory.child("-1.msav"); - for(FileHandle file : saveDirectory.list()){ + for(Fi file : saveDirectory.list()){ if(!file.name().contains("backup") && SaveIO.isSaveValid(file)){ SaveSlot slot = new SaveSlot(file); saves.add(slot); @@ -121,7 +121,7 @@ public class Saves{ return slot; } - public SaveSlot importSave(FileHandle file) throws IOException{ + public SaveSlot importSave(Fi file) throws IOException{ SaveSlot slot = new SaveSlot(getNextSlotFile()); slot.importFile(file); slot.setName(file.nameWithoutExtension()); @@ -136,9 +136,9 @@ public class Saves{ return slot == null || slot.getZone() == null ? null : slot; } - public FileHandle getNextSlotFile(){ + public Fi getNextSlotFile(){ int i = 0; - FileHandle file; + Fi file; while((file = saveDirectory.child(i + "." + saveExtension)).exists()){ i ++; } @@ -151,11 +151,11 @@ public class Saves{ public class SaveSlot{ //public final int index; - public final FileHandle file; + public final Fi file; boolean requestedPreview; SaveMeta meta; - public SaveSlot(FileHandle file){ + public SaveSlot(Fi file){ this.file = file; } @@ -216,11 +216,11 @@ public class Saves{ return file.nameWithoutExtension(); } - private FileHandle previewFile(){ + private Fi previewFile(){ return mapPreviewDirectory.child("save_slot_" + index() + ".png"); } - private FileHandle loadPreviewFile(){ + private Fi loadPreviewFile(){ return previewFile().sibling(previewFile().name() + ".spreview"); } @@ -293,7 +293,7 @@ public class Saves{ Core.settings.save(); } - public void importFile(FileHandle from) throws IOException{ + public void importFile(Fi from) throws IOException{ try{ from.copyTo(file); }catch(Exception e){ @@ -301,7 +301,7 @@ public class Saves{ } } - public void exportFile(FileHandle to) throws IOException{ + public void exportFile(Fi to) throws IOException{ try{ file.copyTo(to); }catch(Exception e){ diff --git a/core/src/io/anuke/mindustry/game/Schematic.java b/core/src/io/anuke/mindustry/game/Schematic.java index 4c83623602..32395fcf54 100644 --- a/core/src/io/anuke/mindustry/game/Schematic.java +++ b/core/src/io/anuke/mindustry/game/Schematic.java @@ -16,7 +16,8 @@ public class Schematic implements Publishable, Comparable{ public final Array tiles; public StringMap tags; public int width, height; - public @Nullable FileHandle file; + public @Nullable + Fi file; /** Associated mod. If null, no mod is associated with this schematic. */ public @Nullable LoadedMod mod; @@ -94,15 +95,15 @@ public class Schematic implements Publishable, Comparable{ } @Override - public FileHandle createSteamFolder(String id){ - FileHandle directory = tmpDirectory.child("schematic_" + id).child("schematic." + schematicExtension); + public Fi createSteamFolder(String id){ + Fi directory = tmpDirectory.child("schematic_" + id).child("schematic." + schematicExtension); file.copyTo(directory); return directory; } @Override - public FileHandle createSteamPreview(String id){ - FileHandle preview = tmpDirectory.child("schematic_preview_" + id + ".png"); + public Fi createSteamPreview(String id){ + Fi preview = tmpDirectory.child("schematic_preview_" + id + ".png"); schematics.savePreview(this, preview); return preview; } diff --git a/core/src/io/anuke/mindustry/game/Schematics.java b/core/src/io/anuke/mindustry/game/Schematics.java index 078300bc52..326c199d05 100644 --- a/core/src/io/anuke/mindustry/game/Schematics.java +++ b/core/src/io/anuke/mindustry/game/Schematics.java @@ -13,12 +13,12 @@ import io.anuke.arc.util.io.Streams.*; import io.anuke.arc.util.serialization.*; import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.Schematic.*; import io.anuke.mindustry.input.*; import io.anuke.mindustry.input.Placement.*; -import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.blocks.*; import io.anuke.mindustry.world.blocks.production.*; @@ -69,7 +69,7 @@ public class Schematics implements Loadable{ public void load(){ all.clear(); - for(FileHandle file : schematicDirectory.list()){ + for(Fi file : schematicDirectory.list()){ loadFile(file); } @@ -111,7 +111,7 @@ public class Schematics implements Loadable{ } } - private @Nullable Schematic loadFile(FileHandle file){ + private @Nullable Schematic loadFile(Fi file){ if(!file.extension().equals(schematicExtension)) return null; try{ @@ -144,7 +144,7 @@ public class Schematics implements Loadable{ } } - public void savePreview(Schematic schematic, FileHandle file){ + public void savePreview(Schematic schematic, Fi file){ FrameBuffer buffer = getBuffer(schematic); Draw.flush(); buffer.begin(); @@ -272,7 +272,7 @@ public class Schematics implements Loadable{ public void add(Schematic schematic){ all.add(schematic); try{ - FileHandle file = schematicDirectory.child(Time.millis() + "." + schematicExtension); + Fi file = schematicDirectory.child(Time.millis() + "." + schematicExtension); write(schematic, file); schematic.file = file; }catch(Exception e){ @@ -372,7 +372,7 @@ public class Schematics implements Loadable{ return read(new ByteArrayInputStream(Base64Coder.decode(schematic))); } - public static Schematic read(FileHandle file) throws IOException{ + public static Schematic read(Fi file) throws IOException{ Schematic s = read(new DataInputStream(file.read(1024))); if(!s.tags.containsKey("name")){ s.tags.put("name", file.nameWithoutExtension()); @@ -425,7 +425,7 @@ public class Schematics implements Loadable{ } } - public static void write(Schematic schematic, FileHandle file) throws IOException{ + public static void write(Schematic schematic, Fi file) throws IOException{ write(schematic, file.write(false, 1024)); } diff --git a/core/src/io/anuke/mindustry/game/SpawnGroup.java b/core/src/io/anuke/mindustry/game/SpawnGroup.java index e799e26c40..50443f153e 100644 --- a/core/src/io/anuke/mindustry/game/SpawnGroup.java +++ b/core/src/io/anuke/mindustry/game/SpawnGroup.java @@ -4,6 +4,7 @@ import io.anuke.arc.util.serialization.Json; import io.anuke.arc.util.serialization.Json.Serializable; import io.anuke.arc.util.serialization.JsonValue; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.type.BaseUnit; import io.anuke.mindustry.type.*; diff --git a/core/src/io/anuke/mindustry/graphics/BlockRenderer.java b/core/src/io/anuke/mindustry/graphics/BlockRenderer.java index 1e7fa36982..8912745633 100644 --- a/core/src/io/anuke/mindustry/graphics/BlockRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/BlockRenderer.java @@ -138,7 +138,7 @@ public class BlockRenderer implements Disposable{ 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; - Draw.alpha(0.53f * brokenFade); + Draw.alpha(0.33f * brokenFade); Draw.mixcol(Color.white, 0.2f + Mathf.absin(Time.globalTime(), 6f, 0.2f)); Draw.rect(b.icon(Cicon.full), block.x * tilesize + b.offset(), block.y * tilesize + b.offset(), b.rotate ? block.rotation * 90 : 0f); } diff --git a/core/src/io/anuke/mindustry/input/Binding.java b/core/src/io/anuke/mindustry/input/Binding.java index 45383cb6ef..9134506735 100644 --- a/core/src/io/anuke/mindustry/input/Binding.java +++ b/core/src/io/anuke/mindustry/input/Binding.java @@ -40,8 +40,7 @@ public enum Binding implements KeyBind{ block_select_08(KeyCode.NUM_8), block_select_09(KeyCode.NUM_9), block_select_10(KeyCode.NUM_0), - zoom_hold(KeyCode.CONTROL_LEFT, "view"), - zoom(new Axis(KeyCode.SCROLL)), + zoom(new Axis(KeyCode.SCROLL), "view"), menu(Core.app.getType() == ApplicationType.Android ? KeyCode.BACK : KeyCode.ESCAPE), fullscreen(KeyCode.F11), pause(KeyCode.SPACE), @@ -54,6 +53,7 @@ public enum Binding implements KeyBind{ chat_history_prev(KeyCode.UP), chat_history_next(KeyCode.DOWN), chat_scroll(new Axis(KeyCode.SCROLL)), + console(KeyCode.F8), ; private final KeybindValue defaultValue; diff --git a/core/src/io/anuke/mindustry/input/DesktopInput.java b/core/src/io/anuke/mindustry/input/DesktopInput.java index 7b015600ce..cf7b3de6d5 100644 --- a/core/src/io/anuke/mindustry/input/DesktopInput.java +++ b/core/src/io/anuke/mindustry/input/DesktopInput.java @@ -122,7 +122,7 @@ public class DesktopInput extends InputHandler{ drawSelected(sreq.x, sreq.y, sreq.block, getRequest(sreq.x, sreq.y, sreq.block.size, sreq) != null ? Pal.remove : Pal.accent); } - if(Core.input.keyDown(Binding.schematic_select) && !ui.chatfrag.chatOpen()){ + if(Core.input.keyDown(Binding.schematic_select) && !Core.scene.hasKeyboard()){ drawSelection(schemX, schemY, cursorX, cursorY, Vars.maxSchematicSize); } @@ -139,7 +139,7 @@ public class DesktopInput extends InputHandler{ player.isShooting = false; } - if(!state.is(State.menu) && Core.input.keyTap(Binding.minimap) && (scene.getKeyboardFocus() == ui.minimap || !scene.hasDialog()) && !ui.chatfrag.chatOpen() && !(scene.getKeyboardFocus() instanceof TextField)){ + if(!state.is(State.menu) && Core.input.keyTap(Binding.minimap) && (scene.getKeyboardFocus() == ui.minimap || !scene.hasDialog()) && !Core.scene.hasKeyboard() && !(scene.getKeyboardFocus() instanceof TextField)){ if(!ui.minimap.isShown()){ ui.minimap.show(); }else{ @@ -149,8 +149,8 @@ public class DesktopInput extends InputHandler{ if(state.is(State.menu) || Core.scene.hasDialog()) return; - //zoom things - if(Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && Core.input.keyDown(Binding.zoom_hold)){ + //zoom camera + if(!Core.scene.hasScroll() && 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)); } @@ -166,11 +166,6 @@ public class DesktopInput extends InputHandler{ mode = none; } - if(mode != none || isPlacing()){ - selectRequests.clear(); - lastSchematic = null; - } - if(player.isShooting && !canShoot()){ player.isShooting = false; } @@ -182,8 +177,7 @@ public class DesktopInput extends InputHandler{ selectScale = 0f; } - if(!Core.input.keyDown(Binding.zoom_hold) && Math.abs((int)Core.input.axisTap(Binding.rotate)) > 0){ - + if(!Core.input.keyDown(Binding.diagonal_placement) && Math.abs((int)Core.input.axisTap(Binding.rotate)) > 0){ rotation = Mathf.mod(rotation + (int)Core.input.axisTap(Binding.rotate), 4); if(sreq != null){ @@ -293,12 +287,12 @@ public class DesktopInput extends InputHandler{ player.clearBuilding(); } - if(Core.input.keyTap(Binding.schematic_select) && !ui.chatfrag.chatOpen()){ + if(Core.input.keyTap(Binding.schematic_select) && !Core.scene.hasKeyboard()){ schemX = rawCursorX; schemY = rawCursorY; } - if(Core.input.keyTap(Binding.schematic_menu) && !ui.chatfrag.chatOpen()){ + if(Core.input.keyTap(Binding.schematic_menu) && !Core.scene.hasKeyboard()){ if(ui.schematics.isShown()){ ui.schematics.hide(); }else{ @@ -311,7 +305,7 @@ public class DesktopInput extends InputHandler{ selectRequests.clear(); } - if(Core.input.keyRelease(Binding.schematic_select) && !ui.chatfrag.chatOpen()){ + if(Core.input.keyRelease(Binding.schematic_select) && !Core.scene.hasKeyboard()){ lastSchematic = schematics.create(schemX, schemY, rawCursorX, rawCursorY); useSchematic(lastSchematic); if(selectRequests.isEmpty()){ @@ -355,7 +349,9 @@ public class DesktopInput extends InputHandler{ if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){ BuildRequest req = getRequest(cursorX, cursorY); - if(!selectRequests.isEmpty()){ + if(Core.input.keyDown(Binding.break_block)){ + mode = none; + }else if(!selectRequests.isEmpty()){ flushRequests(selectRequests); }else if(isPlacing()){ selectX = cursorX; @@ -371,15 +367,18 @@ public class DesktopInput extends InputHandler{ }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 && !ui.chatfrag.chatOpen()){ + !tryBeginMine(selected) && player.getMineTile() == null && !Core.scene.hasKeyboard()){ player.isShooting = true; } - }else if(!ui.chatfrag.chatOpen()){ //if it's out of bounds, shooting is just fine + }else if(!Core.scene.hasKeyboard()){ //if it's out of bounds, shooting is just fine player.isShooting = true; } - }else if(Core.input.keyTap(Binding.deselect) && block != null){ + }else if(Core.input.keyTap(Binding.deselect) && isPlacing()){ block = null; mode = none; + }else if(Core.input.keyTap(Binding.deselect) && !selectRequests.isEmpty()){ + selectRequests.clear(); + lastSchematic = null; }else if(Core.input.keyTap(Binding.break_block) && !Core.scene.hasMouse()){ //is recalculated because setting the mode to breaking removes potential multiblock cursor offset deleting = false; diff --git a/core/src/io/anuke/mindustry/input/InputHandler.java b/core/src/io/anuke/mindustry/input/InputHandler.java index f95f7a2b04..c2ff9db807 100644 --- a/core/src/io/anuke/mindustry/input/InputHandler.java +++ b/core/src/io/anuke/mindustry/input/InputHandler.java @@ -221,7 +221,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public boolean requestMatches(BuildRequest request){ Tile tile = world.tile(request.x, request.y); - return tile != null && tile.block() instanceof BuildBlock && tile.entity().cblock == request.block; + return tile != null && tile.block() instanceof BuildBlock && tile.ent().cblock == request.block; } public void drawBreaking(int x, int y){ diff --git a/core/src/io/anuke/mindustry/input/MobileInput.java b/core/src/io/anuke/mindustry/input/MobileInput.java index 717fb68c95..b057156719 100644 --- a/core/src/io/anuke/mindustry/input/MobileInput.java +++ b/core/src/io/anuke/mindustry/input/MobileInput.java @@ -587,8 +587,8 @@ public class MobileInput extends InputHandler implements GestureListener{ mode = none; } - //zoom things - if(Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && (Core.input.keyDown(Binding.zoom_hold))){ + //zoom camera + if(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)); } diff --git a/core/src/io/anuke/mindustry/input/PlaceMode.java b/core/src/io/anuke/mindustry/input/PlaceMode.java index 5ac66c5220..cb287caed6 100644 --- a/core/src/io/anuke/mindustry/input/PlaceMode.java +++ b/core/src/io/anuke/mindustry/input/PlaceMode.java @@ -1,5 +1,5 @@ package io.anuke.mindustry.input; -enum PlaceMode{ +public enum PlaceMode{ none, breaking, placing, schematicSelect } diff --git a/core/src/io/anuke/mindustry/io/JsonIO.java b/core/src/io/anuke/mindustry/io/JsonIO.java index 3635c25bc0..5d91106ea2 100644 --- a/core/src/io/anuke/mindustry/io/JsonIO.java +++ b/core/src/io/anuke/mindustry/io/JsonIO.java @@ -5,6 +5,7 @@ import io.anuke.arc.util.serialization.Json.*; import io.anuke.mindustry.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.game.*; import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.*; diff --git a/core/src/io/anuke/mindustry/io/LegacyMapIO.java b/core/src/io/anuke/mindustry/io/LegacyMapIO.java index 4d62f6b63d..9dbb2bed01 100644 --- a/core/src/io/anuke/mindustry/io/LegacyMapIO.java +++ b/core/src/io/anuke/mindustry/io/LegacyMapIO.java @@ -6,10 +6,10 @@ import io.anuke.arc.graphics.*; import io.anuke.arc.util.*; import io.anuke.arc.util.serialization.*; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.game.*; import io.anuke.mindustry.io.MapIO.*; import io.anuke.mindustry.maps.*; -import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.LegacyColorMapper.*; import io.anuke.mindustry.world.blocks.*; @@ -26,7 +26,7 @@ public class LegacyMapIO{ private static final Json json = new Json(); /* Convert a map from the old format to the new format. */ - public static void convertMap(FileHandle in, FileHandle out) throws IOException{ + public static void convertMap(Fi in, Fi out) throws IOException{ Map map = readMap(in, true); String waves = map.tags.get("waves", "[]"); @@ -45,7 +45,7 @@ public class LegacyMapIO{ MapIO.writeMap(out, map); } - public static Map readMap(FileHandle file, boolean custom) throws IOException{ + public static Map readMap(Fi file, boolean custom) throws IOException{ try(DataInputStream stream = new DataInputStream(file.read(1024))){ StringMap tags = new StringMap(); @@ -76,11 +76,11 @@ public class LegacyMapIO{ readTiles(map.file, map.width, map.height, tiles); } - private static void readTiles(FileHandle file, int width, int height, Tile[][] tiles) throws IOException{ + private static void readTiles(Fi file, int width, int height, Tile[][] tiles) throws IOException{ readTiles(file, width, height, (x, y) -> tiles[x][y]); } - private static void readTiles(FileHandle file, int width, int height, TileProvider tiles) throws IOException{ + private static void readTiles(Fi file, int width, int height, TileProvider tiles) throws IOException{ try(BufferedInputStream input = file.read(bufferSize)){ //read map diff --git a/core/src/io/anuke/mindustry/io/MapIO.java b/core/src/io/anuke/mindustry/io/MapIO.java index da24c1d8d7..bf309505bd 100644 --- a/core/src/io/anuke/mindustry/io/MapIO.java +++ b/core/src/io/anuke/mindustry/io/MapIO.java @@ -22,7 +22,7 @@ import static io.anuke.mindustry.Vars.*; public class MapIO{ private static final int[] pngHeader = {0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A}; - public static boolean isImage(FileHandle file){ + public static boolean isImage(Fi file){ try(InputStream stream = file.read(32)){ for(int i1 : pngHeader){ if(stream.read() != i1){ @@ -35,7 +35,7 @@ public class MapIO{ } } - public static Map createMap(FileHandle file, boolean custom) throws IOException{ + public static Map createMap(Fi file, boolean custom) throws IOException{ try(InputStream is = new InflaterInputStream(file.read(bufferSize)); CounterInputStream counter = new CounterInputStream(is); DataInputStream stream = new DataInputStream(counter)){ SaveIO.readHeader(stream); int version = stream.readInt(); @@ -46,7 +46,7 @@ public class MapIO{ } } - public static void writeMap(FileHandle file, Map map) throws IOException{ + public static void writeMap(Fi file, Map map) throws IOException{ try{ SaveIO.write(file, map.tags); }catch(Exception e){ diff --git a/core/src/io/anuke/mindustry/io/SaveIO.java b/core/src/io/anuke/mindustry/io/SaveIO.java index 341682746f..6aa76d8ba9 100644 --- a/core/src/io/anuke/mindustry/io/SaveIO.java +++ b/core/src/io/anuke/mindustry/io/SaveIO.java @@ -1,7 +1,7 @@ package io.anuke.mindustry.io; import io.anuke.arc.collection.*; -import io.anuke.arc.files.FileHandle; +import io.anuke.arc.files.Fi; import io.anuke.arc.util.io.CounterInputStream; import io.anuke.arc.util.io.FastDeflaterOutputStream; import io.anuke.mindustry.Vars; @@ -34,7 +34,7 @@ public class SaveIO{ return versions.get(version); } - public static void save(FileHandle file){ + public static void save(Fi file){ boolean exists = file.exists(); if(exists) file.moveTo(backupFileFor(file)); try{ @@ -45,15 +45,15 @@ public class SaveIO{ } } - public static DataInputStream getStream(FileHandle file){ + public static DataInputStream getStream(Fi file){ return new DataInputStream(new InflaterInputStream(file.read(bufferSize))); } - public static DataInputStream getBackupStream(FileHandle file){ + public static DataInputStream getBackupStream(Fi file){ return new DataInputStream(new InflaterInputStream(backupFileFor(file).read(bufferSize))); } - public static boolean isSaveValid(FileHandle file){ + public static boolean isSaveValid(Fi file){ try{ return isSaveValid(new DataInputStream(new InflaterInputStream(file.read(bufferSize)))); }catch(Exception e){ @@ -71,7 +71,7 @@ public class SaveIO{ } } - public static SaveMeta getMeta(FileHandle file){ + public static SaveMeta getMeta(Fi file){ try{ return getMeta(getStream(file)); }catch(Exception e){ @@ -92,19 +92,19 @@ public class SaveIO{ } } - public static FileHandle fileFor(int slot){ + public static Fi fileFor(int slot){ return saveDirectory.child(slot + "." + Vars.saveExtension); } - public static FileHandle backupFileFor(FileHandle file){ + public static Fi backupFileFor(Fi file){ return file.sibling(file.name() + "-backup." + file.extension()); } - public static void write(FileHandle file, StringMap tags){ + public static void write(Fi file, StringMap tags){ write(new FastDeflaterOutputStream(file.write(false, bufferSize)), tags); } - public static void write(FileHandle file){ + public static void write(Fi file){ write(file, null); } @@ -122,17 +122,17 @@ public class SaveIO{ } } - public static void load(FileHandle file) throws SaveException{ + public static void load(Fi file) throws SaveException{ load(file, world.context); } - public static void load(FileHandle file, WorldContext context) throws SaveException{ + public static void load(Fi file, WorldContext context) throws SaveException{ try{ //try and load; if any exception at all occurs load(new InflaterInputStream(file.read(bufferSize)), context); }catch(SaveException e){ e.printStackTrace(); - FileHandle backup = file.sibling(file.name() + "-backup." + file.extension()); + Fi backup = file.sibling(file.name() + "-backup." + file.extension()); if(backup.exists()){ load(new InflaterInputStream(backup.read(bufferSize)), context); }else{ diff --git a/core/src/io/anuke/mindustry/io/SavePreviewLoader.java b/core/src/io/anuke/mindustry/io/SavePreviewLoader.java index 15bfd20277..f7038875bc 100644 --- a/core/src/io/anuke/mindustry/io/SavePreviewLoader.java +++ b/core/src/io/anuke/mindustry/io/SavePreviewLoader.java @@ -12,7 +12,7 @@ public class SavePreviewLoader extends TextureLoader{ } @Override - public void loadAsync(AssetManager manager, String fileName, FileHandle file, TextureParameter parameter){ + public void loadAsync(AssetManager manager, String fileName, Fi file, TextureParameter parameter){ try{ super.loadAsync(manager, fileName, file.sibling(file.nameWithoutExtension()), parameter); }catch(Exception e){ diff --git a/core/src/io/anuke/mindustry/io/SaveVersion.java b/core/src/io/anuke/mindustry/io/SaveVersion.java index f3b994abae..cab3c55250 100644 --- a/core/src/io/anuke/mindustry/io/SaveVersion.java +++ b/core/src/io/anuke/mindustry/io/SaveVersion.java @@ -6,6 +6,7 @@ import io.anuke.arc.util.io.*; import io.anuke.mindustry.content.*; import io.anuke.mindustry.core.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.game.*; @@ -84,7 +85,6 @@ public abstract class SaveVersion extends SaveFileReader{ state.rules = JsonIO.read(Rules.class, map.get("rules", "{}")); if(state.rules.spawns.isEmpty()) state.rules.spawns = defaultWaves.get(); lastReadBuild = map.getInt("build", -1); - String[] mods = JsonIO.read(String[].class, map.get("mods", "[]")); Map worldmap = maps.byName(map.get("mapname", "\\\\\\")); world.setMap(worldmap == null ? new Map(StringMap.of( diff --git a/core/src/io/anuke/mindustry/io/TypeIO.java b/core/src/io/anuke/mindustry/io/TypeIO.java index b5864b5e5b..be5161659b 100644 --- a/core/src/io/anuke/mindustry/io/TypeIO.java +++ b/core/src/io/anuke/mindustry/io/TypeIO.java @@ -3,6 +3,7 @@ package io.anuke.mindustry.io; import io.anuke.annotations.Annotations.ReadClass; import io.anuke.annotations.Annotations.WriteClass; import io.anuke.arc.graphics.Color; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.Effects; import io.anuke.mindustry.entities.Effects.Effect; import io.anuke.mindustry.entities.type.Bullet; diff --git a/core/src/io/anuke/mindustry/io/versions/LegacyTypeTable.java b/core/src/io/anuke/mindustry/io/versions/LegacyTypeTable.java index 419d91e7ed..6e04863262 100644 --- a/core/src/io/anuke/mindustry/io/versions/LegacyTypeTable.java +++ b/core/src/io/anuke/mindustry/io/versions/LegacyTypeTable.java @@ -12,6 +12,60 @@ Latest data: [build 81] 0 = Player 1 = Fire 2 = Puddle +3 = MinerDrone +4 = RepairDrone +5 = BuilderDrone +6 = GroundUnit +7 = GroundUnit +8 = GroundUnit +9 = GroundUnit +10 = GroundUnit +11 = FlyingUnit +12 = FlyingUnit +13 = Revenant + +Before removal of lightining/bullet: [build 80] + +0 = Player +1 = Fire +2 = Puddle +3 = Bullet +4 = Lightning +5 = MinerDrone +6 = RepairDrone +7 = BuilderDrone +8 = GroundUnit +9 = GroundUnit +10 = GroundUnit +11 = GroundUnit +12 = GroundUnit +13 = FlyingUnit +14 = FlyingUnit +15 = Revenant + +Before addition of new units: [build 79 and below] + +0 = Player +1 = Fire +2 = Puddle +3 = Bullet +4 = Lightning +5 = RepairDrone +6 = GroundUnit +7 = GroundUnit +8 = GroundUnit +9 = GroundUnit +10 = GroundUnit +11 = FlyingUnit +12 = FlyingUnit +13 = BuilderDrone +14 = Revenant + */ +public class LegacyTypeTable{ + /* + 0 = Player +1 = Fire +2 = Puddle 3 = Draug 4 = Spirit 5 = Phantom @@ -23,97 +77,59 @@ Latest data: [build 81] 11 = Wraith 12 = Ghoul 13 = Revenant - -Before removal of lightining/bullet: [build 80] - -0 = Player -1 = Fire -2 = Puddle -3 = Bullet -4 = Lightning -5 = Draug -6 = Spirit -7 = Phantom -8 = Dagger -9 = Crawler -10 = Titan -11 = Fortress -12 = Eruptor -13 = Wraith -14 = Ghoul -15 = Revenant - -Before addition of new units: [build 79 and below] - -0 = Player -1 = Fire -2 = Puddle -3 = Bullet -4 = Lightning -5 = Spirit -6 = Dagger -7 = Crawler -8 = Titan -9 = Fortress -10 = Eruptor -11 = Wraith -12 = Ghoul -13 = Phantom -14 = Revenant - */ -public class LegacyTypeTable{ + */ private static final Prov[] build81Table = { Player::new, Fire::new, Puddle::new, - Draug::new, - Spirit::new, - Phantom::new, - Dagger::new, - Crawler::new, - Titan::new, - Fortress::new, - Eruptor::new, - Wraith::new, - Ghoul::new, - Revenant::new + MinerDrone::new, + RepairDrone::new, + BuilderDrone::new, + GroundUnit::new, + GroundUnit::new, + GroundUnit::new, + GroundUnit::new, + GroundUnit::new, + FlyingUnit::new, + FlyingUnit::new, + HoverUnit::new }; private static final Prov[] build80Table = { Player::new, Fire::new, Puddle::new, - Bullet::new, //TODO reading these may crash + Bullet::new, Lightning::new, - Draug::new, - Spirit::new, - Phantom::new, - Dagger::new, - Crawler::new, - Titan::new, - Fortress::new, - Eruptor::new, - Wraith::new, - Ghoul::new, - Revenant::new + MinerDrone::new, + RepairDrone::new, + BuilderDrone::new, + GroundUnit::new, + GroundUnit::new, + GroundUnit::new, + GroundUnit::new, + GroundUnit::new, + FlyingUnit::new, + FlyingUnit::new, + HoverUnit::new }; private static final Prov[] build79Table = { Player::new, Fire::new, Puddle::new, - Bullet::new, //TODO reading these may crash + Bullet::new, Lightning::new, - Spirit::new, - Dagger::new, - Crawler::new, - Titan::new, - Fortress::new, - Eruptor::new, - Wraith::new, - Ghoul::new, - Phantom::new, - Revenant::new + RepairDrone::new, + GroundUnit::new, + GroundUnit::new, + GroundUnit::new, + GroundUnit::new, + GroundUnit::new, + FlyingUnit::new, + FlyingUnit::new, + BuilderDrone::new, + HoverUnit::new }; public static Prov[] getTable(int build){ diff --git a/core/src/io/anuke/mindustry/io/versions/Save2.java b/core/src/io/anuke/mindustry/io/versions/Save2.java index 65c531c66e..bcf0fb8366 100644 --- a/core/src/io/anuke/mindustry/io/versions/Save2.java +++ b/core/src/io/anuke/mindustry/io/versions/Save2.java @@ -1,8 +1,8 @@ package io.anuke.mindustry.io.versions; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.io.*; -import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.TypeID; import java.io.*; diff --git a/core/src/io/anuke/mindustry/maps/Map.java b/core/src/io/anuke/mindustry/maps/Map.java index 3bd66784c4..6fef24a8c4 100644 --- a/core/src/io/anuke/mindustry/maps/Map.java +++ b/core/src/io/anuke/mindustry/maps/Map.java @@ -22,7 +22,7 @@ public class Map implements Comparable, Publishable{ /** Metadata. Author description, display name, etc. */ public final StringMap tags; /** Base file of this map. File can be named anything at all. */ - public final FileHandle file; + public final Fi file; /** Format version. */ public final int version; /** Whether this map is managed, e.g. downloaded from the Steam workshop.*/ @@ -40,7 +40,7 @@ public class Map implements Comparable, Publishable{ /** Associated mod. If null, no mod is associated. */ public @Nullable LoadedMod mod; - public Map(FileHandle file, int width, int height, StringMap tags, boolean custom, int version, int build){ + public Map(Fi file, int width, int height, StringMap tags, boolean custom, int version, int build){ this.custom = custom; this.tags = tags; this.file = file; @@ -50,11 +50,11 @@ public class Map implements Comparable, Publishable{ this.build = build; } - public Map(FileHandle file, int width, int height, StringMap tags, boolean custom, int version){ + public Map(Fi file, int width, int height, StringMap tags, boolean custom, int version){ this(file, width, height, tags, custom, version, -1); } - public Map(FileHandle file, int width, int height, StringMap tags, boolean custom){ + public Map(Fi file, int width, int height, StringMap tags, boolean custom){ this(file, width, height, tags, custom, -1); } @@ -70,11 +70,11 @@ public class Map implements Comparable, Publishable{ return texture == null ? Core.assets.get("sprites/error.png") : texture; } - public FileHandle previewFile(){ + public Fi previewFile(){ return Vars.mapPreviewDirectory.child((workshop ? file.parent().name() : file.nameWithoutExtension()) + ".png"); } - public FileHandle cacheFile(){ + public Fi cacheFile(){ return Vars.mapPreviewDirectory.child(workshop ? file.parent().name() + "-workshop-cache.dat" : file.nameWithoutExtension() + "-cache.dat"); } @@ -184,14 +184,14 @@ public class Map implements Comparable, Publishable{ } @Override - public FileHandle createSteamFolder(String id){ - FileHandle mapFile = tmpDirectory.child("map_" + id).child("map.msav"); + public Fi createSteamFolder(String id){ + Fi mapFile = tmpDirectory.child("map_" + id).child("map.msav"); file.copyTo(mapFile); return mapFile.parent(); } @Override - public FileHandle createSteamPreview(String id){ + public Fi createSteamPreview(String id){ return previewFile(); } diff --git a/core/src/io/anuke/mindustry/maps/MapPreviewLoader.java b/core/src/io/anuke/mindustry/maps/MapPreviewLoader.java index ad0afea0e2..a6f218cb7a 100644 --- a/core/src/io/anuke/mindustry/maps/MapPreviewLoader.java +++ b/core/src/io/anuke/mindustry/maps/MapPreviewLoader.java @@ -17,7 +17,7 @@ public class MapPreviewLoader extends TextureLoader{ } @Override - public void loadAsync(AssetManager manager, String fileName, FileHandle file, TextureParameter parameter){ + public void loadAsync(AssetManager manager, String fileName, Fi file, TextureParameter parameter){ try{ super.loadAsync(manager, fileName, file.sibling(file.nameWithoutExtension()), parameter); }catch(Exception e){ @@ -28,7 +28,7 @@ public class MapPreviewLoader extends TextureLoader{ } @Override - public Texture loadSync(AssetManager manager, String fileName, FileHandle file, TextureParameter parameter){ + public Texture loadSync(AssetManager manager, String fileName, Fi file, TextureParameter parameter){ try{ return super.loadSync(manager, fileName, file, parameter); }catch(Throwable e){ @@ -43,7 +43,7 @@ public class MapPreviewLoader extends TextureLoader{ } @Override - public Array getDependencies(String fileName, FileHandle file, TextureParameter parameter){ + public Array getDependencies(String fileName, Fi file, TextureParameter parameter){ return Array.with(new AssetDescriptor<>("contentcreate", Content.class)); } diff --git a/core/src/io/anuke/mindustry/maps/Maps.java b/core/src/io/anuke/mindustry/maps/Maps.java index 500932d6b6..60cc313659 100644 --- a/core/src/io/anuke/mindustry/maps/Maps.java +++ b/core/src/io/anuke/mindustry/maps/Maps.java @@ -84,6 +84,17 @@ public class Maps{ maps.sort(); }); + Events.on(ContentReloadEvent.class, event -> { + reload(); + for(Map map : maps){ + try{ + map.texture = map.previewFile().exists() ? new Texture(map.previewFile()) : new Texture(MapIO.generatePreview(map)); + }catch(Exception e){ + e.printStackTrace(); + } + } + }); + if(Core.assets != null){ ((CustomLoader)Core.assets.getLoader(Content.class)).loaded = this::createAllPreviews; } @@ -94,7 +105,7 @@ public class Maps{ * Does not add this map to the map list. */ public Map loadInternalMap(String name){ - FileHandle file = tree.get("maps/" + name + "." + mapExtension); + Fi file = tree.get("maps/" + name + "." + mapExtension); try{ return MapIO.createMap(file, false); @@ -108,7 +119,7 @@ public class Maps{ //defaults; must work try{ for(String name : defaultMapNames){ - FileHandle file = Core.files.internal("maps/" + name + "." + mapExtension); + Fi file = Core.files.internal("maps/" + name + "." + mapExtension); loadMap(file, false); } }catch(IOException e){ @@ -116,7 +127,7 @@ public class Maps{ } //custom - for(FileHandle file : customMapDirectory.list()){ + for(Fi file : customMapDirectory.list()){ try{ if(file.extension().equalsIgnoreCase(mapExtension)){ loadMap(file, true); @@ -128,7 +139,7 @@ public class Maps{ } //workshop - for(FileHandle file : platform.getWorkshopContent(Map.class)){ + for(Fi file : platform.getWorkshopContent(Map.class)){ try{ Map map = loadMap(file, false); map.workshop = true; @@ -172,7 +183,7 @@ public class Maps{ StringMap tags = new StringMap(baseTags); String name = tags.get("name"); if(name == null) throw new IllegalArgumentException("Can't save a map with no name. How did this happen?"); - FileHandle file; + Fi file; //find map with the same exact display name Map other = maps.find(m -> m.name().equals(name)); @@ -233,8 +244,8 @@ public class Maps{ } /** Import a map, then save it. This updates all values and stored data necessary. */ - public void importMap(FileHandle file) throws IOException{ - FileHandle dest = findFile(); + public void importMap(Fi file) throws IOException{ + Fi dest = findFile(); file.copyTo(dest); Map map = loadMap(dest, true); @@ -435,7 +446,7 @@ public class Maps{ } /** Find a new filename to put a map to. */ - private FileHandle findFile(){ + private Fi findFile(){ //find a map name that isn't used. int i = maps.size; while(customMapDirectory.child("map_" + i + "." + mapExtension).exists()){ @@ -444,7 +455,7 @@ public class Maps{ return customMapDirectory.child("map_" + i + "." + mapExtension); } - private Map loadMap(FileHandle file, boolean custom) throws IOException{ + private Map loadMap(Fi file, boolean custom) throws IOException{ Map map = MapIO.createMap(file, custom); if(map.name() == null){ diff --git a/core/src/io/anuke/mindustry/maps/filters/FilterOption.java b/core/src/io/anuke/mindustry/maps/filters/FilterOption.java index f1a63c0a37..df75282eb2 100644 --- a/core/src/io/anuke/mindustry/maps/filters/FilterOption.java +++ b/core/src/io/anuke/mindustry/maps/filters/FilterOption.java @@ -13,15 +13,15 @@ import io.anuke.mindustry.ui.dialogs.*; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.blocks.*; -import static io.anuke.mindustry.Vars.updateEditorOnChange; +import static io.anuke.mindustry.Vars.*; public abstract class FilterOption{ - public static final Boolf floorsOnly = b -> (b instanceof Floor && !(b instanceof OverlayFloor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)); - public static final Boolf wallsOnly = b -> (!b.synthetic() && !(b instanceof Floor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)); - public static final Boolf floorsOptional = b -> b == Blocks.air || ((b instanceof Floor && !(b instanceof OverlayFloor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full))); - public static final Boolf wallsOptional = b -> b == Blocks.air || ((!b.synthetic() && !(b instanceof Floor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full))); - public static final Boolf wallsOresOptional = b -> b == Blocks.air || (((!b.synthetic() && !(b instanceof Floor)) || (b instanceof OverlayFloor)) && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full))); - public static final Boolf oresOnly = b -> b instanceof OverlayFloor && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)); + public static final Boolf floorsOnly = b -> (b instanceof Floor && !(b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)); + public static final Boolf wallsOnly = b -> (!b.synthetic() && !(b instanceof Floor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)); + public static final Boolf floorsOptional = b -> b == Blocks.air || ((b instanceof Floor && !(b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full))); + public static final Boolf wallsOptional = b -> b == Blocks.air || ((!b.synthetic() && !(b instanceof Floor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full))); + public static final Boolf wallsOresOptional = b -> b == Blocks.air || (((!b.synthetic() && !(b instanceof Floor)) || (b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full))); + public static final Boolf oresOnly = b -> b instanceof OverlayFloor && !headless && Core.atlas.isFound(b.icon(io.anuke.mindustry.ui.Cicon.full)); public static final Boolf anyOptional = b -> floorsOnly.get(b) || wallsOnly.get(b) || oresOnly.get(b) || b == Blocks.air; public abstract void build(Table table); diff --git a/core/src/io/anuke/mindustry/mod/ClassAccess.java b/core/src/io/anuke/mindustry/mod/ClassAccess.java new file mode 100644 index 0000000000..916831a62b --- /dev/null +++ b/core/src/io/anuke/mindustry/mod/ClassAccess.java @@ -0,0 +1,7 @@ +package io.anuke.mindustry.mod; + +import io.anuke.arc.collection.*; +//obviously autogenerated, do not touch +public class ClassAccess{ + public static final ObjectSet allowedClassNames = ObjectSet.with("io.anuke.arc.Core", "io.anuke.arc.collection.Array", "io.anuke.arc.collection.Array$ArrayIterable", "io.anuke.arc.collection.ArrayMap", "io.anuke.arc.collection.ArrayMap$Entries", "io.anuke.arc.collection.ArrayMap$Keys", "io.anuke.arc.collection.ArrayMap$Values", "io.anuke.arc.collection.AtomicQueue", "io.anuke.arc.collection.BinaryHeap", "io.anuke.arc.collection.BinaryHeap$Node", "io.anuke.arc.collection.Bits", "io.anuke.arc.collection.BooleanArray", "io.anuke.arc.collection.ByteArray", "io.anuke.arc.collection.CharArray", "io.anuke.arc.collection.ComparableTimSort", "io.anuke.arc.collection.DelayedRemovalArray", "io.anuke.arc.collection.EnumSet", "io.anuke.arc.collection.EnumSet$EnumSetIterator", "io.anuke.arc.collection.FloatArray", "io.anuke.arc.collection.GridBits", "io.anuke.arc.collection.GridMap", "io.anuke.arc.collection.IdentityMap", "io.anuke.arc.collection.IdentityMap$Entries", "io.anuke.arc.collection.IdentityMap$Entry", "io.anuke.arc.collection.IdentityMap$Keys", "io.anuke.arc.collection.IdentityMap$Values", "io.anuke.arc.collection.IntArray", "io.anuke.arc.collection.IntFloatMap", "io.anuke.arc.collection.IntFloatMap$Entries", "io.anuke.arc.collection.IntFloatMap$Entry", "io.anuke.arc.collection.IntFloatMap$Keys", "io.anuke.arc.collection.IntFloatMap$Values", "io.anuke.arc.collection.IntIntMap", "io.anuke.arc.collection.IntIntMap$Entries", "io.anuke.arc.collection.IntIntMap$Entry", "io.anuke.arc.collection.IntIntMap$Keys", "io.anuke.arc.collection.IntIntMap$Values", "io.anuke.arc.collection.IntMap", "io.anuke.arc.collection.IntMap$Entries", "io.anuke.arc.collection.IntMap$Entry", "io.anuke.arc.collection.IntMap$Keys", "io.anuke.arc.collection.IntMap$Values", "io.anuke.arc.collection.IntQueue", "io.anuke.arc.collection.IntSet", "io.anuke.arc.collection.IntSet$IntSetIterator", "io.anuke.arc.collection.LongArray", "io.anuke.arc.collection.LongMap", "io.anuke.arc.collection.LongMap$Entries", "io.anuke.arc.collection.LongMap$Entry", "io.anuke.arc.collection.LongMap$Keys", "io.anuke.arc.collection.LongMap$Values", "io.anuke.arc.collection.LongQueue", "io.anuke.arc.collection.ObjectFloatMap", "io.anuke.arc.collection.ObjectFloatMap$Entries", "io.anuke.arc.collection.ObjectFloatMap$Entry", "io.anuke.arc.collection.ObjectFloatMap$Keys", "io.anuke.arc.collection.ObjectFloatMap$Values", "io.anuke.arc.collection.ObjectIntMap", "io.anuke.arc.collection.ObjectIntMap$Entries", "io.anuke.arc.collection.ObjectIntMap$Entry", "io.anuke.arc.collection.ObjectIntMap$Keys", "io.anuke.arc.collection.ObjectIntMap$Values", "io.anuke.arc.collection.ObjectMap", "io.anuke.arc.collection.ObjectMap$Entries", "io.anuke.arc.collection.ObjectMap$Entry", "io.anuke.arc.collection.ObjectMap$Keys", "io.anuke.arc.collection.ObjectMap$Values", "io.anuke.arc.collection.ObjectSet", "io.anuke.arc.collection.ObjectSet$ObjectSetIterator", "io.anuke.arc.collection.OrderedMap", "io.anuke.arc.collection.OrderedMap$OrderedMapEntries", "io.anuke.arc.collection.OrderedMap$OrderedMapKeys", "io.anuke.arc.collection.OrderedMap$OrderedMapValues", "io.anuke.arc.collection.OrderedSet", "io.anuke.arc.collection.OrderedSet$OrderedSetIterator", "io.anuke.arc.collection.PooledLinkedList", "io.anuke.arc.collection.PooledLinkedList$Item", "io.anuke.arc.collection.Queue", "io.anuke.arc.collection.Queue$QueueIterable", "io.anuke.arc.collection.ShortArray", "io.anuke.arc.collection.SnapshotArray", "io.anuke.arc.collection.Sort", "io.anuke.arc.collection.SortedIntList", "io.anuke.arc.collection.SortedIntList$Iterator", "io.anuke.arc.collection.SortedIntList$Node", "io.anuke.arc.collection.StringMap", "io.anuke.arc.collection.TimSort", "io.anuke.arc.func.Boolc", "io.anuke.arc.func.Boolf", "io.anuke.arc.func.Boolf2", "io.anuke.arc.func.Boolp", "io.anuke.arc.func.Cons", "io.anuke.arc.func.Cons2", "io.anuke.arc.func.Floatc", "io.anuke.arc.func.Floatc2", "io.anuke.arc.func.Floatc4", "io.anuke.arc.func.Floatf", "io.anuke.arc.func.Floatp", "io.anuke.arc.func.Func", "io.anuke.arc.func.Func2", "io.anuke.arc.func.Func3", "io.anuke.arc.func.Intc", "io.anuke.arc.func.Intc2", "io.anuke.arc.func.Intc4", "io.anuke.arc.func.Intf", "io.anuke.arc.func.Intp", "io.anuke.arc.func.Prov", "io.anuke.arc.graphics.Color", "io.anuke.arc.graphics.Pixmap", "io.anuke.arc.graphics.Texture", "io.anuke.arc.graphics.TextureData", "io.anuke.arc.graphics.g2d.Draw", "io.anuke.arc.graphics.g2d.Fill", "io.anuke.arc.graphics.g2d.Lines", "io.anuke.arc.graphics.g2d.TextureAtlas", "io.anuke.arc.graphics.g2d.TextureAtlas$AtlasRegion", "io.anuke.arc.graphics.g2d.TextureRegion", "io.anuke.arc.math.Angles", "io.anuke.arc.math.Mathf", "io.anuke.arc.scene.Action", "io.anuke.arc.scene.Element", "io.anuke.arc.scene.Group", "io.anuke.arc.scene.Scene", "io.anuke.arc.scene.actions.Actions", "io.anuke.arc.scene.actions.AddAction", "io.anuke.arc.scene.actions.AddListenerAction", "io.anuke.arc.scene.actions.AfterAction", "io.anuke.arc.scene.actions.AlphaAction", "io.anuke.arc.scene.actions.ColorAction", "io.anuke.arc.scene.actions.DelayAction", "io.anuke.arc.scene.actions.DelegateAction", "io.anuke.arc.scene.actions.FloatAction", "io.anuke.arc.scene.actions.IntAction", "io.anuke.arc.scene.actions.LayoutAction", "io.anuke.arc.scene.actions.MoveByAction", "io.anuke.arc.scene.actions.MoveToAction", "io.anuke.arc.scene.actions.OriginAction", "io.anuke.arc.scene.actions.ParallelAction", "io.anuke.arc.scene.actions.RelativeTemporalAction", "io.anuke.arc.scene.actions.RemoveAction", "io.anuke.arc.scene.actions.RemoveActorAction", "io.anuke.arc.scene.actions.RemoveListenerAction", "io.anuke.arc.scene.actions.RepeatAction", "io.anuke.arc.scene.actions.RotateByAction", "io.anuke.arc.scene.actions.RotateToAction", "io.anuke.arc.scene.actions.RunnableAction", "io.anuke.arc.scene.actions.ScaleByAction", "io.anuke.arc.scene.actions.ScaleToAction", "io.anuke.arc.scene.actions.SequenceAction", "io.anuke.arc.scene.actions.SizeByAction", "io.anuke.arc.scene.actions.SizeToAction", "io.anuke.arc.scene.actions.TemporalAction", "io.anuke.arc.scene.actions.TimeScaleAction", "io.anuke.arc.scene.actions.TouchableAction", "io.anuke.arc.scene.actions.TranslateByAction", "io.anuke.arc.scene.actions.VisibleAction", "io.anuke.arc.scene.event.ChangeListener", "io.anuke.arc.scene.event.ChangeListener$ChangeEvent", "io.anuke.arc.scene.event.ClickListener", "io.anuke.arc.scene.event.DragListener", "io.anuke.arc.scene.event.DragScrollListener", "io.anuke.arc.scene.event.ElementGestureListener", "io.anuke.arc.scene.event.EventListener", "io.anuke.arc.scene.event.FocusListener", "io.anuke.arc.scene.event.FocusListener$FocusEvent", "io.anuke.arc.scene.event.FocusListener$FocusEvent$Type", "io.anuke.arc.scene.event.HandCursorListener", "io.anuke.arc.scene.event.IbeamCursorListener", "io.anuke.arc.scene.event.InputEvent", "io.anuke.arc.scene.event.InputEvent$Type", "io.anuke.arc.scene.event.InputListener", "io.anuke.arc.scene.event.SceneEvent", "io.anuke.arc.scene.event.Touchable", "io.anuke.arc.scene.event.VisibilityEvent", "io.anuke.arc.scene.event.VisibilityListener", "io.anuke.arc.scene.style.BaseDrawable", "io.anuke.arc.scene.style.Drawable", "io.anuke.arc.scene.style.NinePatchDrawable", "io.anuke.arc.scene.style.ScaledNinePatchDrawable", "io.anuke.arc.scene.style.Style", "io.anuke.arc.scene.style.TextureRegionDrawable", "io.anuke.arc.scene.style.TiledDrawable", "io.anuke.arc.scene.style.TransformDrawable", "io.anuke.arc.scene.ui.Button", "io.anuke.arc.scene.ui.Button$ButtonStyle", "io.anuke.arc.scene.ui.ButtonGroup", "io.anuke.arc.scene.ui.CheckBox", "io.anuke.arc.scene.ui.CheckBox$CheckBoxStyle", "io.anuke.arc.scene.ui.ColorImage", "io.anuke.arc.scene.ui.Dialog", "io.anuke.arc.scene.ui.Dialog$DialogStyle", "io.anuke.arc.scene.ui.Image", "io.anuke.arc.scene.ui.ImageButton", "io.anuke.arc.scene.ui.ImageButton$ImageButtonStyle", "io.anuke.arc.scene.ui.KeybindDialog", "io.anuke.arc.scene.ui.KeybindDialog$KeybindDialogStyle", "io.anuke.arc.scene.ui.Label", "io.anuke.arc.scene.ui.Label$LabelStyle", "io.anuke.arc.scene.ui.ProgressBar", "io.anuke.arc.scene.ui.ProgressBar$ProgressBarStyle", "io.anuke.arc.scene.ui.ScrollPane", "io.anuke.arc.scene.ui.ScrollPane$ScrollPaneStyle", "io.anuke.arc.scene.ui.SettingsDialog", "io.anuke.arc.scene.ui.SettingsDialog$SettingsTable", "io.anuke.arc.scene.ui.SettingsDialog$SettingsTable$CheckSetting", "io.anuke.arc.scene.ui.SettingsDialog$SettingsTable$Setting", "io.anuke.arc.scene.ui.SettingsDialog$SettingsTable$SliderSetting", "io.anuke.arc.scene.ui.SettingsDialog$StringProcessor", "io.anuke.arc.scene.ui.Slider", "io.anuke.arc.scene.ui.Slider$SliderStyle", "io.anuke.arc.scene.ui.TextArea", "io.anuke.arc.scene.ui.TextArea$TextAreaListener", "io.anuke.arc.scene.ui.TextButton", "io.anuke.arc.scene.ui.TextButton$TextButtonStyle", "io.anuke.arc.scene.ui.TextField", "io.anuke.arc.scene.ui.TextField$DefaultOnscreenKeyboard", "io.anuke.arc.scene.ui.TextField$OnscreenKeyboard", "io.anuke.arc.scene.ui.TextField$TextFieldClickListener", "io.anuke.arc.scene.ui.TextField$TextFieldFilter", "io.anuke.arc.scene.ui.TextField$TextFieldListener", "io.anuke.arc.scene.ui.TextField$TextFieldStyle", "io.anuke.arc.scene.ui.TextField$TextFieldValidator", "io.anuke.arc.scene.ui.Tooltip", "io.anuke.arc.scene.ui.Tooltip$Tooltips", "io.anuke.arc.scene.ui.Touchpad", "io.anuke.arc.scene.ui.Touchpad$TouchpadStyle", "io.anuke.arc.scene.ui.TreeElement", "io.anuke.arc.scene.ui.TreeElement$Node", "io.anuke.arc.scene.ui.TreeElement$TreeStyle", "io.anuke.arc.scene.ui.layout.Cell", "io.anuke.arc.scene.ui.layout.Collapser", "io.anuke.arc.scene.ui.layout.HorizontalGroup", "io.anuke.arc.scene.ui.layout.Scl", "io.anuke.arc.scene.ui.layout.Stack", "io.anuke.arc.scene.ui.layout.Table", "io.anuke.arc.scene.ui.layout.Table$DrawRect", "io.anuke.arc.scene.ui.layout.VerticalGroup", "io.anuke.arc.scene.ui.layout.WidgetGroup", "io.anuke.arc.scene.utils.ArraySelection", "io.anuke.arc.scene.utils.Cullable", "io.anuke.arc.scene.utils.Disableable", "io.anuke.arc.scene.utils.DragAndDrop", "io.anuke.arc.scene.utils.DragAndDrop$Payload", "io.anuke.arc.scene.utils.DragAndDrop$Source", "io.anuke.arc.scene.utils.DragAndDrop$Target", "io.anuke.arc.scene.utils.Elements", "io.anuke.arc.scene.utils.Layout", "io.anuke.arc.scene.utils.Selection", "io.anuke.arc.util.I18NBundle", "io.anuke.arc.util.Time", "io.anuke.mindustry.Vars", "io.anuke.mindustry.ai.BlockIndexer", "io.anuke.mindustry.ai.Pathfinder", "io.anuke.mindustry.ai.Pathfinder$PathData", "io.anuke.mindustry.ai.Pathfinder$PathTarget", "io.anuke.mindustry.ai.Pathfinder$PathTileStruct", "io.anuke.mindustry.ai.WaveSpawner", "io.anuke.mindustry.content.Blocks", "io.anuke.mindustry.content.Bullets", "io.anuke.mindustry.content.Fx", "io.anuke.mindustry.content.Items", "io.anuke.mindustry.content.Liquids", "io.anuke.mindustry.content.Loadouts", "io.anuke.mindustry.content.Mechs", "io.anuke.mindustry.content.StatusEffects", "io.anuke.mindustry.content.TechTree", "io.anuke.mindustry.content.TechTree$TechNode", "io.anuke.mindustry.content.TypeIDs", "io.anuke.mindustry.content.UnitTypes", "io.anuke.mindustry.content.Zones", "io.anuke.mindustry.core.ContentLoader", "io.anuke.mindustry.core.Control", "io.anuke.mindustry.core.FileTree", "io.anuke.mindustry.core.GameState", "io.anuke.mindustry.core.GameState$State", "io.anuke.mindustry.core.Logic", "io.anuke.mindustry.core.Platform", "io.anuke.mindustry.core.Renderer", "io.anuke.mindustry.core.UI", "io.anuke.mindustry.core.Version", "io.anuke.mindustry.core.World", "io.anuke.mindustry.core.World$Raycaster", "io.anuke.mindustry.ctype.Content", "io.anuke.mindustry.ctype.Content$ModContentInfo", "io.anuke.mindustry.ctype.ContentList", "io.anuke.mindustry.ctype.ContentType", "io.anuke.mindustry.ctype.MappableContent", "io.anuke.mindustry.ctype.UnlockableContent", "io.anuke.mindustry.editor.DrawOperation", "io.anuke.mindustry.editor.DrawOperation$OpType", "io.anuke.mindustry.editor.DrawOperation$TileOpStruct", "io.anuke.mindustry.editor.EditorTile", "io.anuke.mindustry.editor.EditorTool", "io.anuke.mindustry.editor.MapEditor", "io.anuke.mindustry.editor.MapEditor$Context", "io.anuke.mindustry.editor.MapEditorDialog", "io.anuke.mindustry.editor.MapGenerateDialog", "io.anuke.mindustry.editor.MapInfoDialog", "io.anuke.mindustry.editor.MapLoadDialog", "io.anuke.mindustry.editor.MapRenderer", "io.anuke.mindustry.editor.MapResizeDialog", "io.anuke.mindustry.editor.MapSaveDialog", "io.anuke.mindustry.editor.MapView", "io.anuke.mindustry.editor.OperationStack", "io.anuke.mindustry.editor.WaveInfoDialog", "io.anuke.mindustry.entities.Damage", "io.anuke.mindustry.entities.Damage$PropCellStruct", "io.anuke.mindustry.entities.Effects", "io.anuke.mindustry.entities.Effects$Effect", "io.anuke.mindustry.entities.Effects$EffectContainer", "io.anuke.mindustry.entities.Effects$EffectProvider", "io.anuke.mindustry.entities.Effects$EffectRenderer", "io.anuke.mindustry.entities.Effects$ScreenshakeProvider", "io.anuke.mindustry.entities.Entities", "io.anuke.mindustry.entities.EntityCollisions", "io.anuke.mindustry.entities.EntityGroup", "io.anuke.mindustry.entities.Predict", "io.anuke.mindustry.entities.TargetPriority", "io.anuke.mindustry.entities.Units", "io.anuke.mindustry.entities.bullet.ArtilleryBulletType", "io.anuke.mindustry.entities.bullet.BasicBulletType", "io.anuke.mindustry.entities.bullet.BombBulletType", "io.anuke.mindustry.entities.bullet.BulletType", "io.anuke.mindustry.entities.bullet.FlakBulletType", "io.anuke.mindustry.entities.bullet.HealBulletType", "io.anuke.mindustry.entities.bullet.LiquidBulletType", "io.anuke.mindustry.entities.bullet.MassDriverBolt", "io.anuke.mindustry.entities.bullet.MissileBulletType", "io.anuke.mindustry.entities.effect.Decal", "io.anuke.mindustry.entities.effect.Fire", "io.anuke.mindustry.entities.effect.GroundEffectEntity", "io.anuke.mindustry.entities.effect.GroundEffectEntity$GroundEffect", "io.anuke.mindustry.entities.effect.ItemTransfer", "io.anuke.mindustry.entities.effect.Lightning", "io.anuke.mindustry.entities.effect.Puddle", "io.anuke.mindustry.entities.effect.RubbleDecal", "io.anuke.mindustry.entities.effect.ScorchDecal", "io.anuke.mindustry.entities.traits.AbsorbTrait", "io.anuke.mindustry.entities.traits.BelowLiquidTrait", "io.anuke.mindustry.entities.traits.BuilderMinerTrait", "io.anuke.mindustry.entities.traits.BuilderTrait", "io.anuke.mindustry.entities.traits.BuilderTrait$BuildDataStatic", "io.anuke.mindustry.entities.traits.BuilderTrait$BuildRequest", "io.anuke.mindustry.entities.traits.DamageTrait", "io.anuke.mindustry.entities.traits.DrawTrait", "io.anuke.mindustry.entities.traits.Entity", "io.anuke.mindustry.entities.traits.HealthTrait", "io.anuke.mindustry.entities.traits.KillerTrait", "io.anuke.mindustry.entities.traits.MinerTrait", "io.anuke.mindustry.entities.traits.MoveTrait", "io.anuke.mindustry.entities.traits.SaveTrait", "io.anuke.mindustry.entities.traits.Saveable", "io.anuke.mindustry.entities.traits.ScaleTrait", "io.anuke.mindustry.entities.traits.ShooterTrait", "io.anuke.mindustry.entities.traits.SolidTrait", "io.anuke.mindustry.entities.traits.SpawnerTrait", "io.anuke.mindustry.entities.traits.SyncTrait", "io.anuke.mindustry.entities.traits.TargetTrait", "io.anuke.mindustry.entities.traits.TeamTrait", "io.anuke.mindustry.entities.traits.TimeTrait", "io.anuke.mindustry.entities.traits.TypeTrait", "io.anuke.mindustry.entities.traits.VelocityTrait", "io.anuke.mindustry.entities.type.BaseEntity", "io.anuke.mindustry.entities.type.BaseUnit", "io.anuke.mindustry.entities.type.Bullet", "io.anuke.mindustry.entities.type.DestructibleEntity", "io.anuke.mindustry.entities.type.EffectEntity", "io.anuke.mindustry.entities.type.Player", "io.anuke.mindustry.entities.type.SolidEntity", "io.anuke.mindustry.entities.type.TileEntity", "io.anuke.mindustry.entities.type.TimedEntity", "io.anuke.mindustry.entities.type.Unit", "io.anuke.mindustry.entities.type.base.BaseDrone", "io.anuke.mindustry.entities.type.base.BuilderDrone", "io.anuke.mindustry.entities.type.base.FlyingUnit", "io.anuke.mindustry.entities.type.base.GroundUnit", "io.anuke.mindustry.entities.type.base.HoverUnit", "io.anuke.mindustry.entities.type.base.MinerDrone", "io.anuke.mindustry.entities.type.base.RepairDrone", "io.anuke.mindustry.entities.units.StateMachine", "io.anuke.mindustry.entities.units.Statuses", "io.anuke.mindustry.entities.units.Statuses$StatusEntry", "io.anuke.mindustry.entities.units.UnitCommand", "io.anuke.mindustry.entities.units.UnitDrops", "io.anuke.mindustry.entities.units.UnitState", "io.anuke.mindustry.game.DefaultWaves", "io.anuke.mindustry.game.Difficulty", "io.anuke.mindustry.game.EventType", "io.anuke.mindustry.game.EventType$BlockBuildBeginEvent", "io.anuke.mindustry.game.EventType$BlockBuildEndEvent", "io.anuke.mindustry.game.EventType$BlockDestroyEvent", "io.anuke.mindustry.game.EventType$BlockInfoEvent", "io.anuke.mindustry.game.EventType$BuildSelectEvent", "io.anuke.mindustry.game.EventType$ClientLoadEvent", "io.anuke.mindustry.game.EventType$CommandIssueEvent", "io.anuke.mindustry.game.EventType$ContentReloadEvent", "io.anuke.mindustry.game.EventType$CoreItemDeliverEvent", "io.anuke.mindustry.game.EventType$DepositEvent", "io.anuke.mindustry.game.EventType$DisposeEvent", "io.anuke.mindustry.game.EventType$GameOverEvent", "io.anuke.mindustry.game.EventType$LaunchEvent", "io.anuke.mindustry.game.EventType$LaunchItemEvent", "io.anuke.mindustry.game.EventType$LineConfirmEvent", "io.anuke.mindustry.game.EventType$LoseEvent", "io.anuke.mindustry.game.EventType$MapMakeEvent", "io.anuke.mindustry.game.EventType$MapPublishEvent", "io.anuke.mindustry.game.EventType$MechChangeEvent", "io.anuke.mindustry.game.EventType$PlayEvent", "io.anuke.mindustry.game.EventType$PlayerBanEvent", "io.anuke.mindustry.game.EventType$PlayerChatEvent", "io.anuke.mindustry.game.EventType$PlayerConnect", "io.anuke.mindustry.game.EventType$PlayerIpBanEvent", "io.anuke.mindustry.game.EventType$PlayerIpUnbanEvent", "io.anuke.mindustry.game.EventType$PlayerJoin", "io.anuke.mindustry.game.EventType$PlayerLeave", "io.anuke.mindustry.game.EventType$PlayerUnbanEvent", "io.anuke.mindustry.game.EventType$ResearchEvent", "io.anuke.mindustry.game.EventType$ResetEvent", "io.anuke.mindustry.game.EventType$ResizeEvent", "io.anuke.mindustry.game.EventType$ServerLoadEvent", "io.anuke.mindustry.game.EventType$StateChangeEvent", "io.anuke.mindustry.game.EventType$TapConfigEvent", "io.anuke.mindustry.game.EventType$TapEvent", "io.anuke.mindustry.game.EventType$TileChangeEvent", "io.anuke.mindustry.game.EventType$Trigger", "io.anuke.mindustry.game.EventType$TurretAmmoDeliverEvent", "io.anuke.mindustry.game.EventType$UnitCreateEvent", "io.anuke.mindustry.game.EventType$UnitDestroyEvent", "io.anuke.mindustry.game.EventType$UnlockEvent", "io.anuke.mindustry.game.EventType$WaveEvent", "io.anuke.mindustry.game.EventType$WinEvent", "io.anuke.mindustry.game.EventType$WithdrawEvent", "io.anuke.mindustry.game.EventType$WorldLoadEvent", "io.anuke.mindustry.game.EventType$ZoneConfigureCompleteEvent", "io.anuke.mindustry.game.EventType$ZoneRequireCompleteEvent", "io.anuke.mindustry.game.Gamemode", "io.anuke.mindustry.game.GlobalData", "io.anuke.mindustry.game.LoopControl", "io.anuke.mindustry.game.MusicControl", "io.anuke.mindustry.game.Objective", "io.anuke.mindustry.game.Objectives", "io.anuke.mindustry.game.Objectives$Launched", "io.anuke.mindustry.game.Objectives$Unlock", "io.anuke.mindustry.game.Objectives$Wave", "io.anuke.mindustry.game.Objectives$ZoneObjective", "io.anuke.mindustry.game.Objectives$ZoneWave", "io.anuke.mindustry.game.Rules", "io.anuke.mindustry.game.Saves", "io.anuke.mindustry.game.Saves$SaveSlot", "io.anuke.mindustry.game.Schematic", "io.anuke.mindustry.game.Schematic$Stile", "io.anuke.mindustry.game.Schematics", "io.anuke.mindustry.game.SoundLoop", "io.anuke.mindustry.game.SpawnGroup", "io.anuke.mindustry.game.Stats", "io.anuke.mindustry.game.Stats$Rank", "io.anuke.mindustry.game.Stats$RankResult", "io.anuke.mindustry.game.Team", "io.anuke.mindustry.game.Teams", "io.anuke.mindustry.game.Teams$BrokenBlock", "io.anuke.mindustry.game.Teams$TeamData", "io.anuke.mindustry.game.Tutorial", "io.anuke.mindustry.game.Tutorial$TutorialStage", "io.anuke.mindustry.gen.BufferItem", "io.anuke.mindustry.gen.Call", "io.anuke.mindustry.gen.Call", "io.anuke.mindustry.gen.Icon", "io.anuke.mindustry.gen.Icon", "io.anuke.mindustry.gen.MethodHash", "io.anuke.mindustry.gen.Musics", "io.anuke.mindustry.gen.Musics", "io.anuke.mindustry.gen.PathTile", "io.anuke.mindustry.gen.PropCell", "io.anuke.mindustry.gen.RemoteReadClient", "io.anuke.mindustry.gen.RemoteReadServer", "io.anuke.mindustry.gen.Serialization", "io.anuke.mindustry.gen.Sounds", "io.anuke.mindustry.gen.Sounds", "io.anuke.mindustry.gen.Tex", "io.anuke.mindustry.gen.Tex", "io.anuke.mindustry.gen.TileOp", "io.anuke.mindustry.graphics.BlockRenderer", "io.anuke.mindustry.graphics.Bloom", "io.anuke.mindustry.graphics.CacheLayer", "io.anuke.mindustry.graphics.Drawf", "io.anuke.mindustry.graphics.FloorRenderer", "io.anuke.mindustry.graphics.IndexedRenderer", "io.anuke.mindustry.graphics.Layer", "io.anuke.mindustry.graphics.LightRenderer", "io.anuke.mindustry.graphics.MenuRenderer", "io.anuke.mindustry.graphics.MinimapRenderer", "io.anuke.mindustry.graphics.MultiPacker", "io.anuke.mindustry.graphics.MultiPacker$PageType", "io.anuke.mindustry.graphics.OverlayRenderer", "io.anuke.mindustry.graphics.Pal", "io.anuke.mindustry.graphics.Pixelator", "io.anuke.mindustry.graphics.Shaders", "io.anuke.mindustry.input.Binding", "io.anuke.mindustry.input.DesktopInput", "io.anuke.mindustry.input.InputHandler", "io.anuke.mindustry.input.InputHandler$PlaceLine", "io.anuke.mindustry.input.MobileInput", "io.anuke.mindustry.input.PlaceMode", "io.anuke.mindustry.input.Placement", "io.anuke.mindustry.input.Placement$DistanceHeuristic", "io.anuke.mindustry.input.Placement$NormalizeDrawResult", "io.anuke.mindustry.input.Placement$NormalizeResult", "io.anuke.mindustry.input.Placement$TileHueristic", "io.anuke.mindustry.maps.Map", "io.anuke.mindustry.maps.Maps", "io.anuke.mindustry.maps.Maps$MapProvider", "io.anuke.mindustry.maps.Maps$ShuffleMode", "io.anuke.mindustry.maps.Maps$ShuffleMode", "io.anuke.mindustry.maps.filters.BlendFilter", "io.anuke.mindustry.maps.filters.ClearFilter", "io.anuke.mindustry.maps.filters.DistortFilter", "io.anuke.mindustry.maps.filters.FilterOption", "io.anuke.mindustry.maps.filters.FilterOption$BlockOption", "io.anuke.mindustry.maps.filters.FilterOption$SliderOption", "io.anuke.mindustry.maps.filters.GenerateFilter", "io.anuke.mindustry.maps.filters.GenerateFilter$GenerateInput", "io.anuke.mindustry.maps.filters.GenerateFilter$GenerateInput$TileProvider", "io.anuke.mindustry.maps.filters.MedianFilter", "io.anuke.mindustry.maps.filters.MirrorFilter", "io.anuke.mindustry.maps.filters.NoiseFilter", "io.anuke.mindustry.maps.filters.OreFilter", "io.anuke.mindustry.maps.filters.OreMedianFilter", "io.anuke.mindustry.maps.filters.RiverNoiseFilter", "io.anuke.mindustry.maps.filters.ScatterFilter", "io.anuke.mindustry.maps.filters.TerrainFilter", "io.anuke.mindustry.maps.generators.BasicGenerator", "io.anuke.mindustry.maps.generators.BasicGenerator$DistanceHeuristic", "io.anuke.mindustry.maps.generators.BasicGenerator$TileHueristic", "io.anuke.mindustry.maps.generators.Generator", "io.anuke.mindustry.maps.generators.MapGenerator", "io.anuke.mindustry.maps.generators.MapGenerator$Decoration", "io.anuke.mindustry.maps.generators.RandomGenerator", "io.anuke.mindustry.maps.zonegen.DesertWastesGenerator", "io.anuke.mindustry.maps.zonegen.OvergrowthGenerator", "io.anuke.mindustry.type.Category", "io.anuke.mindustry.type.ErrorContent", "io.anuke.mindustry.type.Item", "io.anuke.mindustry.type.ItemStack", "io.anuke.mindustry.type.ItemType", "io.anuke.mindustry.type.Liquid", "io.anuke.mindustry.type.LiquidStack", "io.anuke.mindustry.type.Mech", "io.anuke.mindustry.type.Publishable", "io.anuke.mindustry.type.StatusEffect", "io.anuke.mindustry.type.StatusEffect$TransitionHandler", "io.anuke.mindustry.type.TypeID", "io.anuke.mindustry.type.UnitType", "io.anuke.mindustry.type.Weapon", "io.anuke.mindustry.type.WeatherEvent", "io.anuke.mindustry.type.Zone", "io.anuke.mindustry.ui.Bar", "io.anuke.mindustry.ui.BorderImage", "io.anuke.mindustry.ui.Cicon", "io.anuke.mindustry.ui.ContentDisplay", "io.anuke.mindustry.ui.Fonts", "io.anuke.mindustry.ui.GridImage", "io.anuke.mindustry.ui.IconSize", "io.anuke.mindustry.ui.IntFormat", "io.anuke.mindustry.ui.ItemDisplay", "io.anuke.mindustry.ui.ItemImage", "io.anuke.mindustry.ui.ItemsDisplay", "io.anuke.mindustry.ui.Links", "io.anuke.mindustry.ui.Links$LinkEntry", "io.anuke.mindustry.ui.LiquidDisplay", "io.anuke.mindustry.ui.Minimap", "io.anuke.mindustry.ui.MobileButton", "io.anuke.mindustry.ui.MultiReqImage", "io.anuke.mindustry.ui.ReqImage", "io.anuke.mindustry.ui.Styles", "io.anuke.mindustry.ui.dialogs.AboutDialog", "io.anuke.mindustry.ui.dialogs.AdminsDialog", "io.anuke.mindustry.ui.dialogs.BansDialog", "io.anuke.mindustry.ui.dialogs.ColorPicker", "io.anuke.mindustry.ui.dialogs.ContentInfoDialog", "io.anuke.mindustry.ui.dialogs.ControlsDialog", "io.anuke.mindustry.ui.dialogs.CustomGameDialog", "io.anuke.mindustry.ui.dialogs.CustomRulesDialog", "io.anuke.mindustry.ui.dialogs.DatabaseDialog", "io.anuke.mindustry.ui.dialogs.DeployDialog", "io.anuke.mindustry.ui.dialogs.DeployDialog$View", "io.anuke.mindustry.ui.dialogs.DeployDialog$ZoneNode", "io.anuke.mindustry.ui.dialogs.DiscordDialog", "io.anuke.mindustry.ui.dialogs.FileChooser", "io.anuke.mindustry.ui.dialogs.FileChooser$FileHistory", "io.anuke.mindustry.ui.dialogs.FloatingDialog", "io.anuke.mindustry.ui.dialogs.GameOverDialog", "io.anuke.mindustry.ui.dialogs.HostDialog", "io.anuke.mindustry.ui.dialogs.JoinDialog", "io.anuke.mindustry.ui.dialogs.JoinDialog$Server", "io.anuke.mindustry.ui.dialogs.LanguageDialog", "io.anuke.mindustry.ui.dialogs.LoadDialog", "io.anuke.mindustry.ui.dialogs.LoadoutDialog", "io.anuke.mindustry.ui.dialogs.MapPlayDialog", "io.anuke.mindustry.ui.dialogs.MapsDialog", "io.anuke.mindustry.ui.dialogs.MinimapDialog", "io.anuke.mindustry.ui.dialogs.ModsDialog", "io.anuke.mindustry.ui.dialogs.PaletteDialog", "io.anuke.mindustry.ui.dialogs.PausedDialog", "io.anuke.mindustry.ui.dialogs.SaveDialog", "io.anuke.mindustry.ui.dialogs.SchematicsDialog", "io.anuke.mindustry.ui.dialogs.SchematicsDialog$SchematicImage", "io.anuke.mindustry.ui.dialogs.SchematicsDialog$SchematicInfoDialog", "io.anuke.mindustry.ui.dialogs.SettingsMenuDialog", "io.anuke.mindustry.ui.dialogs.TechTreeDialog", "io.anuke.mindustry.ui.dialogs.TechTreeDialog$LayoutNode", "io.anuke.mindustry.ui.dialogs.TechTreeDialog$TechTreeNode", "io.anuke.mindustry.ui.dialogs.TechTreeDialog$View", "io.anuke.mindustry.ui.dialogs.TraceDialog", "io.anuke.mindustry.ui.dialogs.ZoneInfoDialog", "io.anuke.mindustry.ui.fragments.BlockConfigFragment", "io.anuke.mindustry.ui.fragments.BlockInventoryFragment", "io.anuke.mindustry.ui.fragments.ChatFragment", "io.anuke.mindustry.ui.fragments.FadeInFragment", "io.anuke.mindustry.ui.fragments.Fragment", "io.anuke.mindustry.ui.fragments.HudFragment", "io.anuke.mindustry.ui.fragments.LoadingFragment", "io.anuke.mindustry.ui.fragments.MenuFragment", "io.anuke.mindustry.ui.fragments.OverlayFragment", "io.anuke.mindustry.ui.fragments.PlacementFragment", "io.anuke.mindustry.ui.fragments.PlayerListFragment", "io.anuke.mindustry.ui.fragments.ScriptConsoleFragment", "io.anuke.mindustry.ui.layout.BranchTreeLayout", "io.anuke.mindustry.ui.layout.BranchTreeLayout$TreeAlignment", "io.anuke.mindustry.ui.layout.BranchTreeLayout$TreeLocation", "io.anuke.mindustry.ui.layout.RadialTreeLayout", "io.anuke.mindustry.ui.layout.TreeLayout", "io.anuke.mindustry.ui.layout.TreeLayout$TreeNode", "io.anuke.mindustry.world.Block", "io.anuke.mindustry.world.BlockStorage", "io.anuke.mindustry.world.Build", "io.anuke.mindustry.world.CachedTile", "io.anuke.mindustry.world.DirectionalItemBuffer", "io.anuke.mindustry.world.DirectionalItemBuffer$BufferItemStruct", "io.anuke.mindustry.world.Edges", "io.anuke.mindustry.world.ItemBuffer", "io.anuke.mindustry.world.LegacyColorMapper", "io.anuke.mindustry.world.LegacyColorMapper$LegacyBlock", "io.anuke.mindustry.world.Pos", "io.anuke.mindustry.world.StaticTree", "io.anuke.mindustry.world.Tile", "io.anuke.mindustry.world.WorldContext", "io.anuke.mindustry.world.blocks.Attributes", "io.anuke.mindustry.world.blocks.Autotiler", "io.anuke.mindustry.world.blocks.Autotiler$AutotilerHolder", "io.anuke.mindustry.world.blocks.BlockPart", "io.anuke.mindustry.world.blocks.BuildBlock", "io.anuke.mindustry.world.blocks.BuildBlock$BuildEntity", "io.anuke.mindustry.world.blocks.DoubleOverlayFloor", "io.anuke.mindustry.world.blocks.Floor", "io.anuke.mindustry.world.blocks.ItemSelection", "io.anuke.mindustry.world.blocks.LiquidBlock", "io.anuke.mindustry.world.blocks.OreBlock", "io.anuke.mindustry.world.blocks.OverlayFloor", "io.anuke.mindustry.world.blocks.PowerBlock", "io.anuke.mindustry.world.blocks.RespawnBlock", "io.anuke.mindustry.world.blocks.Rock", "io.anuke.mindustry.world.blocks.StaticWall", "io.anuke.mindustry.world.blocks.TreeBlock", "io.anuke.mindustry.world.blocks.defense.DeflectorWall", "io.anuke.mindustry.world.blocks.defense.DeflectorWall$DeflectorEntity", "io.anuke.mindustry.world.blocks.defense.Door", "io.anuke.mindustry.world.blocks.defense.Door$DoorEntity", "io.anuke.mindustry.world.blocks.defense.ForceProjector", "io.anuke.mindustry.world.blocks.defense.ForceProjector$ForceEntity", "io.anuke.mindustry.world.blocks.defense.ForceProjector$ShieldEntity", "io.anuke.mindustry.world.blocks.defense.MendProjector", "io.anuke.mindustry.world.blocks.defense.MendProjector$MendEntity", "io.anuke.mindustry.world.blocks.defense.OverdriveProjector", "io.anuke.mindustry.world.blocks.defense.OverdriveProjector$OverdriveEntity", "io.anuke.mindustry.world.blocks.defense.ShockMine", "io.anuke.mindustry.world.blocks.defense.SurgeWall", "io.anuke.mindustry.world.blocks.defense.Wall", "io.anuke.mindustry.world.blocks.defense.turrets.ArtilleryTurret", "io.anuke.mindustry.world.blocks.defense.turrets.BurstTurret", "io.anuke.mindustry.world.blocks.defense.turrets.ChargeTurret", "io.anuke.mindustry.world.blocks.defense.turrets.ChargeTurret$LaserTurretEntity", "io.anuke.mindustry.world.blocks.defense.turrets.CooledTurret", "io.anuke.mindustry.world.blocks.defense.turrets.DoubleTurret", "io.anuke.mindustry.world.blocks.defense.turrets.ItemTurret", "io.anuke.mindustry.world.blocks.defense.turrets.ItemTurret$ItemEntry", "io.anuke.mindustry.world.blocks.defense.turrets.ItemTurret$ItemTurretEntity", "io.anuke.mindustry.world.blocks.defense.turrets.LaserTurret", "io.anuke.mindustry.world.blocks.defense.turrets.LaserTurret$LaserTurretEntity", "io.anuke.mindustry.world.blocks.defense.turrets.LiquidTurret", "io.anuke.mindustry.world.blocks.defense.turrets.PowerTurret", "io.anuke.mindustry.world.blocks.defense.turrets.Turret", "io.anuke.mindustry.world.blocks.defense.turrets.Turret$AmmoEntry", "io.anuke.mindustry.world.blocks.defense.turrets.Turret$TurretEntity", "io.anuke.mindustry.world.blocks.distribution.ArmoredConveyor", "io.anuke.mindustry.world.blocks.distribution.BufferedItemBridge", "io.anuke.mindustry.world.blocks.distribution.BufferedItemBridge$BufferedItemBridgeEntity", "io.anuke.mindustry.world.blocks.distribution.Conveyor", "io.anuke.mindustry.world.blocks.distribution.Conveyor$ConveyorEntity", "io.anuke.mindustry.world.blocks.distribution.Conveyor$ItemPos", "io.anuke.mindustry.world.blocks.distribution.ExtendingItemBridge", "io.anuke.mindustry.world.blocks.distribution.ItemBridge", "io.anuke.mindustry.world.blocks.distribution.ItemBridge$ItemBridgeEntity", "io.anuke.mindustry.world.blocks.distribution.Junction", "io.anuke.mindustry.world.blocks.distribution.Junction$JunctionEntity", "io.anuke.mindustry.world.blocks.distribution.MassDriver", "io.anuke.mindustry.world.blocks.distribution.MassDriver$DriverBulletData", "io.anuke.mindustry.world.blocks.distribution.MassDriver$DriverState", "io.anuke.mindustry.world.blocks.distribution.MassDriver$MassDriverEntity", "io.anuke.mindustry.world.blocks.distribution.OverflowGate", "io.anuke.mindustry.world.blocks.distribution.OverflowGate$OverflowGateEntity", "io.anuke.mindustry.world.blocks.distribution.Router", "io.anuke.mindustry.world.blocks.distribution.Router$RouterEntity", "io.anuke.mindustry.world.blocks.distribution.Sorter", "io.anuke.mindustry.world.blocks.distribution.Sorter$SorterEntity", "io.anuke.mindustry.world.blocks.liquid.ArmoredConduit", "io.anuke.mindustry.world.blocks.liquid.Conduit", "io.anuke.mindustry.world.blocks.liquid.Conduit$ConduitEntity", "io.anuke.mindustry.world.blocks.liquid.LiquidBridge", "io.anuke.mindustry.world.blocks.liquid.LiquidExtendingBridge", "io.anuke.mindustry.world.blocks.liquid.LiquidJunction", "io.anuke.mindustry.world.blocks.liquid.LiquidOverflowGate", "io.anuke.mindustry.world.blocks.liquid.LiquidRouter", "io.anuke.mindustry.world.blocks.liquid.LiquidTank", "io.anuke.mindustry.world.blocks.logic.LogicBlock", "io.anuke.mindustry.world.blocks.logic.MessageBlock", "io.anuke.mindustry.world.blocks.logic.MessageBlock$MessageBlockEntity", "io.anuke.mindustry.world.blocks.power.Battery", "io.anuke.mindustry.world.blocks.power.BurnerGenerator", "io.anuke.mindustry.world.blocks.power.ConditionalConsumePower", "io.anuke.mindustry.world.blocks.power.DecayGenerator", "io.anuke.mindustry.world.blocks.power.ImpactReactor", "io.anuke.mindustry.world.blocks.power.ImpactReactor$FusionReactorEntity", "io.anuke.mindustry.world.blocks.power.ItemLiquidGenerator", "io.anuke.mindustry.world.blocks.power.ItemLiquidGenerator$ItemLiquidGeneratorEntity", "io.anuke.mindustry.world.blocks.power.LightBlock", "io.anuke.mindustry.world.blocks.power.LightBlock$LightEntity", "io.anuke.mindustry.world.blocks.power.NuclearReactor", "io.anuke.mindustry.world.blocks.power.NuclearReactor$NuclearReactorEntity", "io.anuke.mindustry.world.blocks.power.PowerDiode", "io.anuke.mindustry.world.blocks.power.PowerDistributor", "io.anuke.mindustry.world.blocks.power.PowerGenerator", "io.anuke.mindustry.world.blocks.power.PowerGenerator$GeneratorEntity", "io.anuke.mindustry.world.blocks.power.PowerGraph", "io.anuke.mindustry.world.blocks.power.PowerNode", "io.anuke.mindustry.world.blocks.power.SingleTypeGenerator", "io.anuke.mindustry.world.blocks.power.SolarGenerator", "io.anuke.mindustry.world.blocks.power.ThermalGenerator", "io.anuke.mindustry.world.blocks.production.Cultivator", "io.anuke.mindustry.world.blocks.production.Cultivator$CultivatorEntity", "io.anuke.mindustry.world.blocks.production.Drill", "io.anuke.mindustry.world.blocks.production.Drill$DrillEntity", "io.anuke.mindustry.world.blocks.production.Fracker", "io.anuke.mindustry.world.blocks.production.Fracker$FrackerEntity", "io.anuke.mindustry.world.blocks.production.GenericCrafter", "io.anuke.mindustry.world.blocks.production.GenericCrafter$GenericCrafterEntity", "io.anuke.mindustry.world.blocks.production.GenericSmelter", "io.anuke.mindustry.world.blocks.production.Incinerator", "io.anuke.mindustry.world.blocks.production.Incinerator$IncineratorEntity", "io.anuke.mindustry.world.blocks.production.LiquidConverter", "io.anuke.mindustry.world.blocks.production.Pump", "io.anuke.mindustry.world.blocks.production.Separator", "io.anuke.mindustry.world.blocks.production.SolidPump", "io.anuke.mindustry.world.blocks.production.SolidPump$SolidPumpEntity", "io.anuke.mindustry.world.blocks.sandbox.ItemSource", "io.anuke.mindustry.world.blocks.sandbox.ItemSource$ItemSourceEntity", "io.anuke.mindustry.world.blocks.sandbox.ItemVoid", "io.anuke.mindustry.world.blocks.sandbox.LiquidSource", "io.anuke.mindustry.world.blocks.sandbox.LiquidSource$LiquidSourceEntity", "io.anuke.mindustry.world.blocks.sandbox.PowerSource", "io.anuke.mindustry.world.blocks.sandbox.PowerVoid", "io.anuke.mindustry.world.blocks.storage.CoreBlock", "io.anuke.mindustry.world.blocks.storage.CoreBlock$CoreEntity", "io.anuke.mindustry.world.blocks.storage.LaunchPad", "io.anuke.mindustry.world.blocks.storage.StorageBlock", "io.anuke.mindustry.world.blocks.storage.StorageBlock$StorageBlockEntity", "io.anuke.mindustry.world.blocks.storage.Unloader", "io.anuke.mindustry.world.blocks.storage.Unloader$UnloaderEntity", "io.anuke.mindustry.world.blocks.storage.Vault", "io.anuke.mindustry.world.blocks.units.CommandCenter", "io.anuke.mindustry.world.blocks.units.CommandCenter$CommandCenterEntity", "io.anuke.mindustry.world.blocks.units.MechPad", "io.anuke.mindustry.world.blocks.units.MechPad$MechFactoryEntity", "io.anuke.mindustry.world.blocks.units.RallyPoint", "io.anuke.mindustry.world.blocks.units.RepairPoint", "io.anuke.mindustry.world.blocks.units.RepairPoint$RepairPointEntity", "io.anuke.mindustry.world.blocks.units.UnitFactory", "io.anuke.mindustry.world.blocks.units.UnitFactory$UnitFactoryEntity", "io.anuke.mindustry.world.consumers.Consume", "io.anuke.mindustry.world.consumers.ConsumeItemFilter", "io.anuke.mindustry.world.consumers.ConsumeItems", "io.anuke.mindustry.world.consumers.ConsumeLiquid", "io.anuke.mindustry.world.consumers.ConsumeLiquidBase", "io.anuke.mindustry.world.consumers.ConsumeLiquidFilter", "io.anuke.mindustry.world.consumers.ConsumePower", "io.anuke.mindustry.world.consumers.ConsumeType", "io.anuke.mindustry.world.consumers.Consumers", "io.anuke.mindustry.world.meta.Attribute", "io.anuke.mindustry.world.meta.BlockBars", "io.anuke.mindustry.world.meta.BlockFlag", "io.anuke.mindustry.world.meta.BlockGroup", "io.anuke.mindustry.world.meta.BlockStat", "io.anuke.mindustry.world.meta.BlockStats", "io.anuke.mindustry.world.meta.BuildVisibility", "io.anuke.mindustry.world.meta.PowerType", "io.anuke.mindustry.world.meta.Producers", "io.anuke.mindustry.world.meta.StatCategory", "io.anuke.mindustry.world.meta.StatUnit", "io.anuke.mindustry.world.meta.StatValue", "io.anuke.mindustry.world.meta.values.AmmoListValue", "io.anuke.mindustry.world.meta.values.BooleanValue", "io.anuke.mindustry.world.meta.values.BoosterListValue", "io.anuke.mindustry.world.meta.values.ItemFilterValue", "io.anuke.mindustry.world.meta.values.ItemListValue", "io.anuke.mindustry.world.meta.values.LiquidFilterValue", "io.anuke.mindustry.world.meta.values.LiquidValue", "io.anuke.mindustry.world.meta.values.NumberValue", "io.anuke.mindustry.world.meta.values.StringValue", "io.anuke.mindustry.world.modules.BlockModule", "io.anuke.mindustry.world.modules.ConsumeModule", "io.anuke.mindustry.world.modules.ItemModule", "io.anuke.mindustry.world.modules.ItemModule$ItemCalculator", "io.anuke.mindustry.world.modules.ItemModule$ItemConsumer", "io.anuke.mindustry.world.modules.LiquidModule", "io.anuke.mindustry.world.modules.LiquidModule$LiquidCalculator", "io.anuke.mindustry.world.modules.LiquidModule$LiquidConsumer", "io.anuke.mindustry.world.modules.PowerModule", "io.anuke.mindustry.world.producers.Produce", "io.anuke.mindustry.world.producers.ProduceItem", "java.io.PrintStream", "java.lang.Object", "java.lang.Runnable", "java.lang.String", "java.lang.System"); +} \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/mod/ContentParser.java b/core/src/io/anuke/mindustry/mod/ContentParser.java index afe1f2f74f..826fada015 100644 --- a/core/src/io/anuke/mindustry/mod/ContentParser.java +++ b/core/src/io/anuke/mindustry/mod/ContentParser.java @@ -36,6 +36,19 @@ import java.lang.reflect.*; public class ContentParser{ private static final boolean ignoreUnknownFields = true; private ObjectMap, ContentType> contentTypes = new ObjectMap<>(); + private StringMap legacyUnitMap = StringMap.of( + "Dagger", "GroundUnit", + "Eruptor", "GroundUnit", + "Titan", "GroundUnit", + "Fortress", "GroundUnit", + "Crawler", "GroundUnit", + "Revenant", "HoverUnit", + "Draug", "MinerDrone", + "Phantom", "BuilderDrone", + "Spirit", "RepairDrone", + "Wraith", "FlyingUnit", + "Ghoul", "FlyingUnit" + ); private ObjectMap, FieldParser> classParsers = new ObjectMap, FieldParser>(){{ put(Effect.class, (type, data) -> field(Fx.class, data)); put(StatusEffect.class, (type, data) -> field(StatusEffects.class, data)); @@ -52,6 +65,15 @@ public class ContentParser{ } } }); + put(StatusEffect.class, (type, data) -> { + Object result = fieldOpt(StatusEffects.class, data); + if(result != null){ + return result; + } + StatusEffect effect = new StatusEffect(currentMod.name + "-" + data.getString("name")); + readFields(effect, data); + return effect; + }); put(Color.class, (type, data) -> Color.valueOf(data.asString())); put(BulletType.class, (type, data) -> { if(data.isString()){ @@ -116,26 +138,20 @@ public class ContentParser{ } //try to parse "item/amount" syntax - try{ - if(type == ItemStack.class && jsonData.isString() && jsonData.asString().contains("/")){ - String[] split = jsonData.asString().split("/"); + if(type == ItemStack.class && jsonData.isString() && jsonData.asString().contains("/")){ + String[] split = jsonData.asString().split("/"); - return (T)fromJson(ItemStack.class, "{item: " + split[0] + ", amount: " + split[1] + "}"); - } - }catch(Throwable ignored){ + return (T)fromJson(ItemStack.class, "{item: " + split[0] + ", amount: " + split[1] + "}"); } //try to parse "liquid/amount" syntax - try{ - if(jsonData.isString() && jsonData.asString().contains("/")){ - String[] split = jsonData.asString().split("/"); - if(type == LiquidStack.class){ - return (T)fromJson(LiquidStack.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}"); - }else if(type == ConsumeLiquid.class){ - return (T)fromJson(ConsumeLiquid.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}"); - } + if(jsonData.isString() && jsonData.asString().contains("/")){ + String[] split = jsonData.asString().split("/"); + if(type == LiquidStack.class){ + return (T)fromJson(LiquidStack.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}"); + }else if(type == ConsumeLiquid.class){ + return (T)fromJson(ConsumeLiquid.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}"); } - }catch(Throwable ignored){ } if(Content.class.isAssignableFrom(type)){ @@ -146,7 +162,7 @@ public class ContentParser{ T two = (T)Vars.content.getByName(ctype, jsonData.asString()); if(two != null) return two; - throw new IllegalArgumentException("\"" + jsonData.name + "\": No " + ctype + " found with name '" + jsonData.asString() + "'."); + throw new IllegalArgumentException("\"" + jsonData.name + "\": No " + ctype + " found with name '" + jsonData.asString() + "'.\nMake sure '" + jsonData.asString() + "' is spelled correctly, and that it really exists!\nThis may also occur because its file failed to parse."); } } @@ -160,28 +176,34 @@ public class ContentParser{ Block block; - if(Vars.content.getByName(ContentType.block, name) != null){ - block = Vars.content.getByName(ContentType.block, name); + if(locate(ContentType.block, name) != null){ + block = locate(ContentType.block, name); if(value.has("type")){ - throw new IllegalArgumentException("When overwriting an existing block, you must not re-declare its type. The original type will be used. Block: " + name); + throw new IllegalArgumentException("When defining properties for an existing block, you must not re-declare its type. The original type will be used. Block: " + name); } }else{ //TODO generate dynamically instead of doing.. this - Class type = resolve(getType(value), - "io.anuke.mindustry.world", - "io.anuke.mindustry.world.blocks", - "io.anuke.mindustry.world.blocks.defense", - "io.anuke.mindustry.world.blocks.defense.turrets", - "io.anuke.mindustry.world.blocks.distribution", - "io.anuke.mindustry.world.blocks.liquid", - "io.anuke.mindustry.world.blocks.logic", - "io.anuke.mindustry.world.blocks.power", - "io.anuke.mindustry.world.blocks.production", - "io.anuke.mindustry.world.blocks.sandbox", - "io.anuke.mindustry.world.blocks.storage", - "io.anuke.mindustry.world.blocks.units" - ); + Class type; + + try{ + type = resolve(getType(value), + "io.anuke.mindustry.world", + "io.anuke.mindustry.world.blocks", + "io.anuke.mindustry.world.blocks.defense", + "io.anuke.mindustry.world.blocks.defense.turrets", + "io.anuke.mindustry.world.blocks.distribution", + "io.anuke.mindustry.world.blocks.liquid", + "io.anuke.mindustry.world.blocks.logic", + "io.anuke.mindustry.world.blocks.power", + "io.anuke.mindustry.world.blocks.production", + "io.anuke.mindustry.world.blocks.sandbox", + "io.anuke.mindustry.world.blocks.storage", + "io.anuke.mindustry.world.blocks.units" + ); + }catch(IllegalArgumentException e){ + type = Block.class; + } block = make(type, mod + "-" + name); } @@ -222,15 +244,23 @@ public class ContentParser{ readFields(block, value, true); + if(block.size > 8){ + throw new IllegalArgumentException("Blocks cannot be larger than 8x8."); + } + //add research tech node if(research[0] != null){ Block parent = find(ContentType.block, research[0]); TechNode baseNode = TechTree.create(parent, block); + LoadedMod cur = currentMod; postreads.add(() -> { + currentContent = block; + currentMod = cur; + TechNode parnode = TechTree.all.find(t -> t.block == parent); if(parnode == null){ - throw new ModLoadException("Block '" + parent.name + "' isn't in the tech tree, but '" + block.name + "' requires it to be researched.", block); + throw new IllegalArgumentException("Block '" + parent.name + "' isn't in the tech tree, but '" + block.name + "' requires it to be researched."); } if(!parnode.children.contains(baseNode)){ parnode.children.add(baseNode); @@ -249,8 +279,14 @@ public class ContentParser{ ContentType.unit, (TypeParser)(mod, name, value) -> { readBundle(ContentType.unit, name, value); - Class type = resolve(getType(value), "io.anuke.mindustry.entities.type.base"); - UnitType unit = new UnitType(mod + "-" + name, supply(type)); + UnitType unit; + if(locate(ContentType.unit, name) == null){ + Class type = resolve(legacyUnitMap.get(Strings.capitalize(getType(value)), getType(value)), "io.anuke.mindustry.entities.type.base"); + unit = new UnitType(mod + "-" + name, supply(type)); + }else{ + unit = locate(ContentType.unit, name); + } + currentContent = unit; read(() -> readFields(unit, value, true)); @@ -266,7 +302,7 @@ public class ContentParser{ if(value.has(key)){ return value.getString(key); }else{ - throw new IllegalArgumentException((currentContent == null ? "" : currentContent.sourceFile + ": ") + "You are missing a \"" + key + "\". It must be added before the file can be parsed."); + throw new IllegalArgumentException("You are missing a \"" + key + "\". It must be added before the file can be parsed."); } } @@ -344,13 +380,18 @@ public class ContentParser{ } } - public void finishParsing(){ + private void attempt(Runnable run){ try{ - reads.each(Runnable::run); - postreads.each(Runnable::run); - }catch(Exception e){ - Vars.mods.handleError(new ModLoadException("Error occurred parsing content: " + currentContent, currentContent, e), currentMod); + run.run(); + }catch(Throwable t){ + //don't overwrite double errors + markError(currentContent, t); } + } + + public void finishParsing(){ + reads.each(this::attempt); + postreads.each(this::attempt); reads.clear(); postreads.clear(); toBeParsed.clear(); @@ -364,7 +405,7 @@ public class ContentParser{ * @param file file that this content is being parsed from * @return the content that was parsed */ - public Content parse(LoadedMod mod, String name, String json, FileHandle file, ContentType type) throws Exception{ + public Content parse(LoadedMod mod, String name, String json, Fi file, ContentType type) throws Exception{ if(contentTypes.isEmpty()){ init(); } @@ -381,16 +422,56 @@ public class ContentParser{ } currentMod = mod; - boolean exists = Vars.content.getByName(type, name) != null; + boolean located = locate(type, name) != null; Content c = parsers.get(type).parse(mod.name, name, value); + c.minfo.sourceFile = file; toBeParsed.add(c); - if(!exists){ - c.sourceFile = file; - c.mod = mod; + + if(!located){ + c.minfo.mod = mod; } return c; } + public void markError(Content content, LoadedMod mod, Fi file, Throwable error){ + content.minfo.mod = mod; + content.minfo.sourceFile = file; + content.minfo.error = makeError(error, file); + content.minfo.baseError = error; + if(mod != null){ + mod.erroredContent.add(content); + } + } + + public void markError(Content content, Throwable error){ + if(content.minfo != null && !content.hasErrored()){ + markError(content, content.minfo.mod, content.minfo.sourceFile, error); + } + } + + private String makeError(Throwable t, Fi file){ + StringBuilder builder = new StringBuilder(); + builder.append("[lightgray]").append("File: ").append(file.name()).append("[]\n\n"); + + if(t.getMessage() != null && t instanceof JsonParseException){ + builder.append("[accent][[JsonParse][] ").append(":\n").append(t.getMessage()); + }else{ + Array causes = Strings.getCauses(t); + for(Throwable e : causes){ + builder.append("[accent][[").append(e.getClass().getSimpleName().replace("Exception", "")) + .append("][] ") + .append(e.getMessage() != null ? + e.getMessage().replace("io.anuke.mindustry.", "").replace("io.anuke.arc.", "") : "").append("\n"); + } + } + return builder.toString(); + } + + private T locate(ContentType type, String name){ + T first = Vars.content.getByName(type, name); //try vanilla replacement + return first != null ? first : Vars.content.getByName(type, currentMod.name + "-" + name); + } + private T make(Class type){ try{ Constructor cons = type.getDeclaredConstructor(); @@ -478,7 +559,7 @@ public class ContentParser{ FieldMetadata metadata = fields.get(child.name().replace(" ", "_")); if(metadata == null){ if(ignoreUnknownFields){ - Log.err("{0}: Ignoring unknown field: " + child.name + " (" + type.getName() + ")", object); + Log.warn("{0}: Ignoring unknown field: " + child.name + " (" + type.getName() + ")", object); continue; }else{ SerializationException ex = new SerializationException("Field not found: " + child.name + " (" + type.getName() + ")"); diff --git a/core/src/io/anuke/mindustry/mod/Mod.java b/core/src/io/anuke/mindustry/mod/Mod.java index 5ee0f699c4..5bab31b341 100644 --- a/core/src/io/anuke/mindustry/mod/Mod.java +++ b/core/src/io/anuke/mindustry/mod/Mod.java @@ -6,7 +6,7 @@ import io.anuke.mindustry.*; public class Mod{ /** @return the config file for this plugin, as the file 'mods/[plugin-name]/config.json'.*/ - public FileHandle getConfig(){ + public Fi getConfig(){ return Vars.mods.getConfig(this); } @@ -15,11 +15,6 @@ public class Mod{ } - /** Create any content needed here. */ - public void loadContent(){ - - } - /** Register any commands to be used on the server side, e.g. from the console. */ public void registerServerCommands(CommandHandler handler){ diff --git a/core/src/io/anuke/mindustry/mod/ModCrashHandler.java b/core/src/io/anuke/mindustry/mod/ModCrashHandler.java deleted file mode 100644 index 77f3c68aba..0000000000 --- a/core/src/io/anuke/mindustry/mod/ModCrashHandler.java +++ /dev/null @@ -1,67 +0,0 @@ -package io.anuke.mindustry.mod; - -import io.anuke.arc.*; -import io.anuke.arc.collection.*; -import io.anuke.arc.graphics.*; -import io.anuke.arc.graphics.g2d.*; -import io.anuke.arc.math.*; -import io.anuke.arc.scene.ui.layout.*; -import io.anuke.arc.util.*; -import io.anuke.mindustry.graphics.*; -import io.anuke.mindustry.mod.Mods.*; -import io.anuke.mindustry.ui.*; - -public class ModCrashHandler{ - - public static void handle(Throwable t){ - Array list = Strings.getCauses(t); - Throwable modCause = list.find(e -> e instanceof ModLoadException); - - if(modCause != null && Fonts.outline != null){ - String text = "[scarlet][[A fatal crash has occured while loading a mod!][]\n\nReason:[accent] " + modCause.getMessage(); - String bottom = "[scarlet]The associated mod has been disabled. Swipe out of the app and launch it again."; - GlyphLayout layout = new GlyphLayout(); - Core.atlas = TextureAtlas.blankAtlas(); - Colors.put("accent", Pal.accent); - - Core.app.addListener(new ApplicationListener(){ - @Override - public void update(){ - Core.graphics.clear(0.1f, 0.1f, 0.1f, 1f); - float rad = Math.min(Core.graphics.getWidth(), Core.graphics.getHeight()) / 2f / 1.3f; - Draw.color(Color.scarlet, Color.black, Mathf.absin(Core.graphics.getFrameId(), 15f, 0.6f)); - Lines.stroke(Scl.scl(40f)); - //Lines.poly2(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f, 3, rad, 0f); - float cx = Core.graphics.getWidth()/2f, cy = Core.graphics.getHeight()/2f; - for(int i = 0; i < 3; i++){ - float angle1 = i * 120f + 90f; - float angle2 = (i + 1) * 120f + 90f; - Tmp.v1.trnsExact(angle1, rad - Lines.getStroke()/2f).add(cx, cy); - Tmp.v2.trnsExact(angle2, rad - Lines.getStroke()/2f).add(cx, cy); - Tmp.v3.trnsExact(angle1, rad + Lines.getStroke()/2f).add(cx, cy); - Tmp.v4.trnsExact(angle2, rad + Lines.getStroke()/2f).add(cx, cy); - Fill.quad(Tmp.v1.x, Tmp.v1.y, Tmp.v2.x, Tmp.v2.y, Tmp.v4.x, Tmp.v4.y, Tmp.v3.x, Tmp.v3.y); - } - Lines.lineAngleCenter(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f - Scl.scl(5f), 90f, rad/3.1f); - Fill.square(Core.graphics.getWidth()/2f, Core.graphics.getHeight()/2f + rad/2f - Scl.scl(15f), Lines.getStroke()/2f); - Draw.reset(); - - Fonts.outline.getData().markupEnabled = true; - layout.setText(Fonts.outline, text, Color.white, Core.graphics.getWidth(), Align.left, true); - Fonts.outline.draw(text, Core.graphics.getWidth()/2f - layout.width/2f, Core.graphics.getHeight() - Scl.scl(50f), Core.graphics.getWidth(), Align.left, true); - - layout.setText(Fonts.outline, bottom, Color.white, Core.graphics.getWidth(), Align.left, true); - Fonts.outline.draw(bottom, Core.graphics.getWidth()/2f - layout.width/2f, layout.height + Scl.scl(10f), Core.graphics.getWidth(), Align.left, true); - Draw.flush(); - } - - @Override - public void resize(int width, int height){ - Draw.proj().setOrtho(0, 0, width, height); - } - }); - }else{ - throw new RuntimeException(t); - } - } -} diff --git a/core/src/io/anuke/mindustry/mod/Mods.java b/core/src/io/anuke/mindustry/mod/Mods.java index 2d1a731272..26a7b51955 100644 --- a/core/src/io/anuke/mindustry/mod/Mods.java +++ b/core/src/io/anuke/mindustry/mod/Mods.java @@ -9,19 +9,22 @@ import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.Texture.*; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.g2d.TextureAtlas.*; -import io.anuke.arc.util.ArcAnnotate.*; +import io.anuke.arc.scene.ui.*; import io.anuke.arc.util.*; +import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.arc.util.io.*; import io.anuke.arc.util.serialization.*; import io.anuke.arc.util.serialization.Jval.*; import io.anuke.mindustry.core.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.graphics.MultiPacker.*; import io.anuke.mindustry.plugin.*; import io.anuke.mindustry.type.*; +import io.anuke.mindustry.ui.*; import java.io.*; import java.net.*; @@ -30,53 +33,58 @@ import static io.anuke.mindustry.Vars.*; public class Mods implements Loadable{ private Json json = new Json(); + private @Nullable Scripts scripts; private ContentParser parser = new ContentParser(); - private ObjectMap> bundles = new ObjectMap<>(); - private ObjectSet specialFolders = ObjectSet.with("bundles", "sprites"); + private ObjectMap> bundles = new ObjectMap<>(); + private ObjectSet specialFolders = ObjectSet.with("bundles", "sprites", "sprites-override"); private int totalSprites; private MultiPacker packer; - private Array loaded = new Array<>(); - private Array disabled = new Array<>(); + private Array mods = new Array<>(); private ObjectMap, ModMeta> metas = new ObjectMap<>(); private boolean requiresReload; + public Mods(){ + Events.on(ClientLoadEvent.class, e -> Core.app.post(this::checkWarnings)); + Events.on(ContentReloadEvent.class, e -> Core.app.post(this::checkWarnings)); + } + /** Returns a file named 'config.json' in a special folder for the specified plugin. * Call this in init(). */ - public FileHandle getConfig(Mod mod){ + public Fi getConfig(Mod mod){ ModMeta load = metas.get(mod.getClass()); if(load == null) throw new IllegalArgumentException("Mod is not loaded yet (or missing)!"); return modDirectory.child(load.name).child("config.json"); } /** Returns a list of files per mod subdirectory. */ - public void listFiles(String directory, Cons2 cons){ - for(LoadedMod mod : loaded){ - FileHandle file = mod.root.child(directory); + public void listFiles(String directory, Cons2 cons){ + eachEnabled(mod -> { + Fi file = mod.root.child(directory); if(file.exists()){ - for(FileHandle child : file.list()){ + for(Fi child : file.list()){ cons.get(mod, child); } } - } + }); } /** @return the loaded mod found by class, or null if not found. */ public @Nullable LoadedMod getMod(Class type){ - return loaded.find(l -> l.mod != null && l.mod.getClass() == type); + return mods.find(m -> m.enabled() && m.main != null && m.main.getClass() == type);//loaded.find(l -> l.mod != null && l.mod.getClass() == type); } /** Imports an external mod file.*/ - public void importMod(FileHandle file) throws IOException{ - FileHandle dest = modDirectory.child(file.name()); + 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!"); } file.copyTo(dest); try{ - loaded.add(loadMod(dest)); + mods.add(loadMod(dest)); requiresReload = true; }catch(IOException e){ dest.delete(); @@ -90,19 +98,19 @@ public class Mods implements Loadable{ /** Repacks all in-game sprites. */ @Override public void loadAsync(){ - if(loaded.isEmpty()) return; + if(!mods.contains(LoadedMod::enabled)) return; Time.mark(); packer = new MultiPacker(); - for(LoadedMod mod : loaded){ - Array sprites = mod.root.child("sprites").findAll(f -> f.extension().equals("png")); - Array overrides = mod.root.child("sprites-override").findAll(f -> f.extension().equals("png")); + eachEnabled(mod -> { + Array sprites = mod.root.child("sprites").findAll(f -> f.extension().equals("png")); + Array overrides = mod.root.child("sprites-override").findAll(f -> f.extension().equals("png")); packSprites(sprites, mod, true); packSprites(overrides, mod, false); - Log.info("Packed {0} images for mod '{1}'.", sprites.size + overrides.size, mod.meta.name); + Log.debug("Packed {0} images for mod '{1}'.", sprites.size + overrides.size, mod.meta.name); totalSprites += sprites.size + overrides.size; - } + }); for(AtlasRegion region : Core.atlas.getRegions()){ PageType type = getPage(region); @@ -111,11 +119,11 @@ public class Mods implements Loadable{ } } - Log.info("Time to pack textures: {0}", Time.elapsed()); + Log.debug("Time to pack textures: {0}", Time.elapsed()); } - private void packSprites(Array sprites, LoadedMod mod, boolean prefix){ - for(FileHandle file : sprites){ + private void packSprites(Array sprites, LoadedMod mod, boolean prefix){ + for(Fi file : sprites){ try(InputStream stream = file.read()){ byte[] bytes = Streams.copyStreamToByteArray(stream, Math.max((int)file.length(), 512)); Pixmap pixmap = new Pixmap(bytes, 0, bytes.length); @@ -148,7 +156,7 @@ public class Mods implements Loadable{ //generate new icons for(Array arr : content.getContentMap()){ arr.each(c -> { - if(c instanceof UnlockableContent && c.mod != null){ + if(c instanceof UnlockableContent && c.minfo.mod != null){ UnlockableContent u = (UnlockableContent)c; u.createIcons(packer); } @@ -157,12 +165,12 @@ public class Mods implements Loadable{ Core.atlas = packer.flush(filter, new TextureAtlas()); Core.atlas.setErrorRegion("error"); - Log.info("Total pages: {0}", Core.atlas.getTextures().size); + Log.debug("Total pages: {0}", Core.atlas.getTextures().size); } packer.dispose(); packer = null; - Log.info("Time to update textures: {0}", Time.elapsed()); + Log.debug("Time to update textures: {0}", Time.elapsed()); } private PageType getPage(AtlasRegion region){ @@ -175,7 +183,7 @@ public class Mods implements Loadable{ PageType.main; } - private PageType getPage(FileHandle file){ + private PageType getPage(Fi file){ String parent = file.parent().name(); return parent.equals("environment") ? PageType.environment : @@ -187,7 +195,7 @@ public class Mods implements Loadable{ /** Removes a mod file and marks it for requiring a restart. */ public void removeMod(LoadedMod mod){ - if(mod.root instanceof ZipFileHandle){ + if(mod.root instanceof ZipFi){ mod.root.delete(); } @@ -197,28 +205,33 @@ public class Mods implements Loadable{ ui.showErrorMessage("$mod.delete.error"); return; } - loaded.remove(mod); - disabled.remove(mod); + mods.remove(mod); requiresReload = true; } + public Scripts getScripts(){ + if(scripts == null) scripts = platform.createScripts(); + return scripts; + } + + /** @return whether the scripting engine has been initialized. */ + public boolean hasScripts(){ + return scripts != null; + } + public boolean requiresReload(){ return requiresReload; } /** Loads all mods from the folder, but does not call any methods on them.*/ public void load(){ - for(FileHandle file : modDirectory.list()){ + for(Fi file : modDirectory.list()){ if(!file.extension().equals("jar") && !file.extension().equals("zip") && !(file.isDirectory() && (file.child("mod.json").exists() || file.child("mod.hjson").exists()))) continue; Log.debug("[Mods] Loading mod {0}", file); try{ LoadedMod mod = loadMod(file); - if(mod.enabled() || headless){ - loaded.add(mod); - }else{ - disabled.add(mod); - } + mods.add(mod); }catch(Exception e){ Log.err("Failed to load mod file {0}. Skipping.", file); Log.err(e); @@ -226,14 +239,10 @@ public class Mods implements Loadable{ } //load workshop mods now - for(FileHandle file : platform.getWorkshopContent(LoadedMod.class)){ + for(Fi file : platform.getWorkshopContent(LoadedMod.class)){ try{ LoadedMod mod = loadMod(file); - if(mod.enabled()){ - loaded.add(mod); - }else{ - disabled.add(mod); - } + mods.add(mod); mod.addSteamID(file.name()); }catch(Exception e){ Log.err("Failed to load mod workshop file {0}. Skipping.", file); @@ -241,28 +250,27 @@ public class Mods implements Loadable{ } } - resolveDependencies(); - - //sort mods to make sure servers handle them properly. - loaded.sort(Structs.comparing(m -> m.name)); + resolveModState(); + sortMods(); buildFiles(); } - private void resolveDependencies(){ - Array incompatible = loaded.select(m -> !m.isSupported()); - loaded.removeAll(incompatible); - disabled.addAll(incompatible); + private void sortMods(){ + //sort mods to make sure servers handle them properly and they appear correctly in the dialog + mods.sort(Structs.comps(Structs.comparingInt(m -> m.state.ordinal()), Structs.comparing(m -> m.name))); + } - for(LoadedMod mod : Array.withArrays(loaded, disabled)){ - updateDependencies(mod); + private void resolveModState(){ + mods.each(this::updateDependencies); + + for(LoadedMod mod : mods){ + mod.state = + !mod.isSupported() ? ModState.unsupported : + mod.hasUnmetDependencies() ? ModState.missingDependencies : + !mod.shouldBeEnabled() ? ModState.disabled : + ModState.enabled; } - - disabled.addAll(loaded.select(LoadedMod::hasUnmetDependencies)); - loaded.removeAll(LoadedMod::hasUnmetDependencies); - disabled.each(mod -> setEnabled(mod, false)); - disabled.distinct(); - loaded.distinct(); } private void updateDependencies(LoadedMod mod){ @@ -287,23 +295,23 @@ public class Mods implements Loadable{ private Array orderedMods(){ ObjectSet visited = new ObjectSet<>(); Array result = new Array<>(); - for(LoadedMod mod : loaded){ + eachEnabled(mod -> { if(!visited.contains(mod)){ topoSort(mod, result, visited); } - } + }); return result; } private LoadedMod locateMod(String name){ - return loaded.find(mod -> mod.name.equals(name)); + return mods.find(mod -> mod.enabled() && mod.name.equals(name)); } private void buildFiles(){ for(LoadedMod mod : orderedMods()){ boolean zipFolder = !mod.file.isDirectory() && mod.root.parent() != null; String parentName = zipFolder ? mod.root.name() : null; - for(FileHandle file : mod.root.list()){ + for(Fi file : mod.root.list()){ //ignore special folders like bundles or sprites if(file.isDirectory() && !specialFolders.contains(file.name())){ //TODO calling child/parent on these files will give you gibberish; create wrapper class. @@ -313,9 +321,9 @@ public class Mods implements Loadable{ } //load up bundles. - FileHandle folder = mod.root.child("bundles"); + Fi folder = mod.root.child("bundles"); if(folder.exists()){ - for(FileHandle file : folder.list()){ + for(Fi file : folder.list()){ if(file.name().startsWith("bundle") && file.extension().equals("properties")){ String name = file.nameWithoutExtension(); bundles.getOr(name, Array::new).add(file); @@ -329,50 +337,147 @@ public class Mods implements Loadable{ while(bundle != null){ String str = bundle.getLocale().toString(); String locale = "bundle" + (str.isEmpty() ? "" : "_" + str); - for(FileHandle file : bundles.getOr(locale, Array::new)){ + for(Fi file : bundles.getOr(locale, Array::new)){ try{ PropertiesUtils.load(bundle.getProperties(), file.reader()); }catch(Exception e){ - throw new RuntimeException("Error loading bundle: " + file + "/" + locale, e); + Log.err("Error loading bundle: " + file + "/" + locale, e); } } bundle = bundle.getParent(); } } + /** Check all warnings related to content and show relevant dialogs. Client only. */ + private void checkWarnings(){ + //show 'scripts have errored' info + if(scripts != null && scripts.hasErrored()){ + Core.settings.getBoolOnce("scripts-errored2", () -> ui.showErrorMessage("$mod.scripts.unsupported")); + } + + //show list of errored content + if(mods.contains(LoadedMod::hasContentErrors)){ + ui.loadfrag.hide(); + new Dialog(""){{ + + setFillParent(true); + cont.margin(15); + cont.add("$error.title"); + cont.row(); + cont.addImage().width(300f).pad(2).colspan(2).height(4f).color(Color.scarlet); + cont.row(); + cont.add("$mod.errors").wrap().growX().center().get().setAlignment(Align.center); + cont.row(); + cont.pane(p -> { + mods.each(m -> m.enabled() && m.hasContentErrors(), m -> { + p.add(m.name).color(Pal.accent).left(); + p.row(); + p.addImage().fillX().pad(4).color(Pal.accent); + p.row(); + p.table(d -> { + d.left().marginLeft(15f); + for(Content c : m.erroredContent){ + d.add(c.minfo.sourceFile.nameWithoutExtension()).left().padRight(10); + d.addImageTextButton("$details", Icon.arrowDownSmall, Styles.transt, () -> { + new Dialog(""){{ + setFillParent(true); + cont.pane(e -> e.add(c.minfo.error)).grow(); + cont.row(); + cont.addImageTextButton("$ok", Icon.backSmall, this::hide).size(240f, 60f); + }}.show(); + }).size(190f, 50f).left().marginLeft(6); + d.row(); + } + }).left(); + p.row(); + }); + }); + + cont.row(); + cont.addButton("$ok", this::hide).size(300, 50); + }}.show(); + } + } + + public boolean hasContentErrors(){ + return mods.contains(LoadedMod::hasContentErrors); + } + /** Reloads all mod content. How does this even work? I refuse to believe that it functions correctly.*/ public void reloadContent(){ //epic memory leak //TODO make it less epic Core.atlas = new TextureAtlas(Core.files.internal("sprites/sprites.atlas")); - loaded.clear(); - disabled.clear(); + mods.clear(); load(); Sounds.dispose(); Sounds.load(); Core.assets.finishLoading(); + if(scripts != null){ + scripts.dispose(); + scripts = null; + } content.clear(); - content.createContent(); + content.createBaseContent(); + content.loadColors(); + loadScripts(); + content.createModContent(); loadAsync(); loadSync(); content.init(); content.load(); content.loadColors(); data.load(); + Core.atlas.getTextures().each(t -> t.setFilter(Core.settings.getBool("linear") ? TextureFilter.Linear : TextureFilter.Nearest)); requiresReload = false; Events.fire(new ContentReloadEvent()); } + /** This must be run on the main thread! */ + public void loadScripts(){ + Time.mark(); + + try{ + eachEnabled(mod -> { + if(mod.root.child("scripts").exists()){ + content.setCurrentMod(mod); + mod.scripts = mod.root.child("scripts").findAll(f -> f.extension().equals("js")); + Log.debug("[{0}] Found {1} scripts.", mod.meta.name, mod.scripts.size); + + for(Fi file : mod.scripts){ + try{ + if(scripts == null){ + scripts = platform.createScripts(); + } + scripts.run(mod, file); + }catch(Throwable e){ + Core.app.post(() -> { + Log.err("Error loading script {0} for mod {1}.", file.name(), mod.meta.name); + e.printStackTrace(); + }); + break; + } + } + } + }); + }finally{ + content.setCurrentMod(null); + } + + Log.debug("Time to initialize modded scripts: {0}", Time.elapsed()); + } + /** Creates all the content found in mod files. */ public void loadContent(){ + class LoadRun implements Comparable{ final ContentType type; - final FileHandle file; + final Fi file; final LoadedMod mod; - public LoadRun(ContentType type, FileHandle file, LoadedMod mod){ + public LoadRun(ContentType type, Fi file, LoadedMod mod){ this.type = type; this.file = file; this.mod = mod; @@ -390,11 +495,11 @@ public class Mods implements Loadable{ for(LoadedMod mod : orderedMods()){ if(mod.root.child("content").exists()){ - FileHandle contentRoot = mod.root.child("content"); + Fi contentRoot = mod.root.child("content"); for(ContentType type : ContentType.all){ - FileHandle folder = contentRoot.child(type.name().toLowerCase() + "s"); + Fi folder = contentRoot.child(type.name().toLowerCase() + "s"); if(folder.exists()){ - for(FileHandle file : folder.list()){ + for(Fi file : folder.list()){ if(file.extension().equals("json") || file.extension().equals("hjson")){ runs.add(new LoadRun(type, file, mod)); } @@ -406,59 +511,43 @@ public class Mods implements Loadable{ //make sure mod content is in proper order runs.sort(); - runs.each(l -> safeRun(l.mod, () -> { + for(LoadRun l : runs){ + Content current = content.getLastAdded(); try{ //this binds the content but does not load it entirely Content loaded = parser.parse(l.mod, l.file.nameWithoutExtension(), l.file.readString("UTF-8"), l.file, l.type); - Log.debug("[{0}] Loaded '{1}'.", l.mod.meta.name, - (loaded instanceof UnlockableContent ? ((UnlockableContent)loaded).localizedName : loaded)); - }catch(Exception e){ - throw new RuntimeException("Failed to parse content file '" + l.file + "' for mod '" + l.mod.meta.name + "'.", e); + Log.debug("[{0}] Loaded '{1}'.", l.mod.meta.name, (loaded instanceof UnlockableContent ? ((UnlockableContent)loaded).localizedName : loaded)); + }catch(Throwable e){ + if(current != content.getLastAdded() && content.getLastAdded() != null){ + parser.markError(content.getLastAdded(), l.mod, l.file, e); + }else{ + ErrorContent error = new ErrorContent(); + parser.markError(error, l.mod, l.file, e); + } } - })); + } //this finishes parsing content fields parser.finishParsing(); - - //load content for code mods - each(Mod::loadContent); } - /** @return all loaded mods. */ - public Array all(){ - return loaded; - } - - /** @return all disabled mods. */ - public Array disabled(){ - return disabled; - } - - /** @return a list of mod names only, without versions. */ - public Array getModNames(){ - return loaded.select(l -> !l.meta.hidden).map(l -> l.name + ":" + l.meta.version); + public void handleContentError(Content content, Throwable error){ + parser.markError(content, error); } /** @return a list of mods and versions, in the format name:version. */ public Array getModStrings(){ - return loaded.select(l -> !l.meta.hidden).map(l -> l.name + ":" + l.meta.version); + return mods.select(l -> !l.meta.hidden && l.enabled()).map(l -> l.name + ":" + l.meta.version); } /** Makes a mod enabled or disabled. shifts it.*/ public void setEnabled(LoadedMod mod, boolean enabled){ if(mod.enabled() != enabled){ Core.settings.putSave("mod-" + mod.name + "-enabled", enabled); - Core.settings.save(); requiresReload = true; - if(!enabled){ - loaded.remove(mod); - if(!disabled.contains(mod)) disabled.add(mod); - }else{ - if(!loaded.contains(mod)) loaded.add(mod); - disabled.remove(mod); - } - loaded.each(this::updateDependencies); - disabled.each(this::updateDependencies); + mod.state = enabled ? ModState.enabled : ModState.disabled; + mods.each(this::updateDependencies); + sortMods(); } } @@ -475,55 +564,37 @@ public class Mods implements Loadable{ return result; } - /** Iterates through each mod with a main class.*/ - public void each(Cons cons){ - loaded.each(p -> p.mod != null, p -> safeRun(p, () -> cons.get(p.mod))); + public Array list(){ + return mods; } - public void handleError(Throwable t, LoadedMod mod){ - Array causes = Strings.getCauses(t); - Content content = null; - for(Throwable e : causes){ - if(e instanceof ModLoadException && ((ModLoadException) e).content != null){ - content = ((ModLoadException) e).content; - } - } - - String realCause = ""; - for(int i = causes.size -1 ; i >= 0; i--){ - if(causes.get(i).getMessage() != null){ - realCause = causes.get(i).getMessage(); - break; - } - } - - setEnabled(mod, false); - - if(content != null){ - throw new ModLoadException(Strings.format("Error loading '{0}' from mod '{1}' ({2}):\n{3}", - content, mod.meta.name, content.sourceFile == null ? "" : content.sourceFile.name(), realCause), content, t); - }else{ - throw new ModLoadException("Error loading mod " + mod.meta.name, t); - } + /** Iterates through each mod with a main class. */ + public void eachClass(Cons cons){ + mods.each(p -> p.main != null, p -> contextRun(p, () -> cons.get(p.main))); } - public void safeRun(LoadedMod mod, Runnable run){ + /** Iterates through each enabled mod. */ + public void eachEnabled(Cons cons){ + mods.each(LoadedMod::enabled, cons); + } + + public void contextRun(LoadedMod mod, Runnable run){ try{ run.run(); }catch(Throwable t){ - handleError(t, mod); + throw new RuntimeException("Error loading mod " + mod.meta.name, t); } } /** Loads a mod file+meta, but does not add it to the list. * Note that directories can be loaded as mods.*/ - private LoadedMod loadMod(FileHandle sourceFile) throws Exception{ - FileHandle zip = sourceFile.isDirectory() ? sourceFile : new ZipFileHandle(sourceFile); + private LoadedMod loadMod(Fi sourceFile) throws Exception{ + Fi zip = sourceFile.isDirectory() ? sourceFile : new ZipFi(sourceFile); if(zip.list().length == 1 && zip.list()[0].isDirectory()){ zip = zip.list()[0]; } - FileHandle metaf = zip.child("mod.json").exists() ? zip.child("mod.json") : zip.child("mod.hjson").exists() ? zip.child("mod.hjson") : zip.child("plugin.json"); + Fi metaf = zip.child("mod.json").exists() ? zip.child("mod.json") : zip.child("mod.hjson").exists() ? zip.child("mod.hjson") : zip.child("plugin.json"); if(!metaf.exists()){ Log.warn("Mod {0} doesn't have a 'mod.json'/'plugin.json'/'mod.js' file, skipping.", sourceFile); throw new IllegalArgumentException("No mod.json found."); @@ -534,13 +605,13 @@ public class Mods implements Loadable{ String mainClass = meta.main == null ? camelized.toLowerCase() + "." + camelized + "Mod" : meta.main; String baseName = meta.name.toLowerCase().replace(" ", "-"); - if(loaded.contains(m -> m.name.equals(baseName)) || disabled.contains(m -> m.name.equals(baseName))){ + if(mods.contains(m -> m.name.equals(baseName))){ throw new IllegalArgumentException("A mod with the name '" + baseName + "' is already imported."); } Mod mainMod; - FileHandle mainFile = zip; + Fi mainFile = zip; String[] path = (mainClass.replace('.', '/') + ".class").split("/"); for(String str : path){ if(!str.isEmpty()){ @@ -574,11 +645,11 @@ public class Mods implements Loadable{ /** Represents a plugin that has been loaded from a jar file.*/ public static class LoadedMod implements Publishable{ /** The location of this mod's zip file/folder on the disk. */ - public final FileHandle file; + public final Fi file; /** The root zip file; points to the contents of this mod. In the case of folders, this is the same as the mod's file. */ - public final FileHandle root; + public final Fi root; /** The mod's main class; may be null. */ - public final @Nullable Mod mod; + public final @Nullable Mod main; /** Internal mod name. Used for textures. */ public final String name; /** This mod's metadata. */ @@ -587,16 +658,26 @@ public class Mods implements Loadable{ public Array dependencies = new Array<>(); /** All missing dependencies of this mod as strings. */ public Array missingDependencies = new Array<>(); + /** Script files to run. */ + public Array scripts = new Array<>(); + /** Content with intialization code. */ + public ObjectSet erroredContent = new ObjectSet<>(); + /** Current state of this mod. */ + public ModState state = ModState.enabled; - public LoadedMod(FileHandle file, FileHandle root, Mod mod, ModMeta meta){ + public LoadedMod(Fi file, Fi root, Mod main, ModMeta meta){ this.root = root; this.file = file; - this.mod = mod; + this.main = main; this.meta = meta; this.name = meta.name.toLowerCase().replace(" ", "-"); } public boolean enabled(){ + return state == ModState.enabled || state == ModState.contentErrors; + } + + public boolean shouldBeEnabled(){ return Core.settings.getBool("mod-" + name + "-enabled", true); } @@ -604,6 +685,10 @@ public class Mods implements Loadable{ return !missingDependencies.isEmpty(); } + public boolean hasContentErrors(){ + return !erroredContent.isEmpty(); + } + /** @return whether this mod is supported by the game verison */ public boolean isSupported(){ if(Version.build <= 0 || meta.minGameVersion == null) return true; @@ -649,12 +734,12 @@ public class Mods implements Loadable{ } @Override - public FileHandle createSteamFolder(String id){ + public Fi createSteamFolder(String id){ return file; } @Override - public FileHandle createSteamPreview(String id){ + public Fi createSteamPreview(String id){ return file.child("preview.png"); } @@ -685,43 +770,21 @@ public class Mods implements Loadable{ /** Plugin metadata information.*/ public static class ModMeta{ - public String name, author, description, version, main, minGameVersion; + public String name, displayName, author, description, version, main, minGameVersion; public Array dependencies = Array.with(); /** Hidden mods are only server-side or client-side, and do not support adding new content. */ public boolean hidden; + + public String displayName(){ + return displayName == null ? name : displayName; + } } - /** Thrown when an error occurs while loading a mod.*/ - public static class ModLoadException extends RuntimeException{ - public Content content; - public LoadedMod mod; - - public ModLoadException(String message, Throwable cause){ - super(message, cause); - } - - public ModLoadException(String message, @Nullable Content content, Throwable cause){ - super(message, cause); - this.content = content; - if(content != null){ - this.mod = content.mod; - } - } - - public ModLoadException(@Nullable Content content, Throwable cause){ - super(cause); - this.content = content; - if(content != null){ - this.mod = content.mod; - } - } - - public ModLoadException(String message, @Nullable Content content){ - super(message); - this.content = content; - if(content != null){ - this.mod = content.mod; - } - } + public enum ModState{ + enabled, + contentErrors, + missingDependencies, + unsupported, + disabled, } } diff --git a/core/src/io/anuke/mindustry/mod/Scripts.java b/core/src/io/anuke/mindustry/mod/Scripts.java new file mode 100644 index 0000000000..d53673f4bf --- /dev/null +++ b/core/src/io/anuke/mindustry/mod/Scripts.java @@ -0,0 +1,84 @@ +package io.anuke.mindustry.mod; + +import io.anuke.arc.*; +import io.anuke.arc.files.*; +import io.anuke.arc.util.*; +import io.anuke.arc.util.Log.*; +import io.anuke.mindustry.*; +import io.anuke.mindustry.mod.Mods.*; +import org.mozilla.javascript.*; + +public class Scripts implements Disposable{ + private final Context context; + private final String wrapper; + private Scriptable scope; + private boolean errored; + + public Scripts(){ + Time.mark(); + + context = Vars.platform.getScriptContext(); + context.setClassShutter(type -> (ClassAccess.allowedClassNames.contains(type) || type.startsWith("$Proxy") || + type.startsWith("adapter") || type.contains("PrintStream") || + type.startsWith("io.anuke.mindustry")) && !type.equals("io.anuke.mindustry.mod.ClassAccess")); + + scope = new ImporterTopLevel(context); + wrapper = Core.files.internal("scripts/wrapper.js").readString(); + + if(!run(Core.files.internal("scripts/global.js").readString(), "global.js")){ + errored = true; + } + Log.debug("Time to load script engine: {0}", Time.elapsed()); + } + + public boolean hasErrored(){ + return errored; + } + + public String runConsole(String text){ + try{ + Object o = context.evaluateString(scope, text, "console.js", 1, null); + if(o instanceof NativeJavaObject){ + o = ((NativeJavaObject)o).unwrap(); + } + if(o instanceof Undefined){ + o = "undefined"; + } + return String.valueOf(o); + }catch(Throwable t){ + return getError(t); + } + } + + private String getError(Throwable t){ + t.printStackTrace(); + return t.getClass().getSimpleName() + (t.getMessage() == null ? "" : ": " + t.getMessage()); + } + + public void log(String source, String message){ + log(LogLevel.info, source, message); + } + + public void log(LogLevel level, String source, String message){ + Log.log(level, "[{0}]: {1}", source, message); + } + + public void run(LoadedMod mod, Fi file){ + run(wrapper.replace("$SCRIPT_NAME$", mod.name + "/" + file.nameWithoutExtension()).replace("$CODE$", file.readString()).replace("$MOD_NAME$", mod.name), file.name()); + } + + private boolean run(String script, String file){ + try{ + context.evaluateString(scope, script, file, 1, null); + return true; + }catch(Throwable t){ + log(LogLevel.err, file, "" + getError(t)); + return false; + } + } + + @Override + public void dispose(){ + Context.exit(); + } +} diff --git a/core/src/io/anuke/mindustry/net/ArcNetImpl.java b/core/src/io/anuke/mindustry/net/ArcNetProvider.java similarity index 98% rename from core/src/io/anuke/mindustry/net/ArcNetImpl.java rename to core/src/io/anuke/mindustry/net/ArcNetProvider.java index e2a5b3d6b2..600b80da9a 100644 --- a/core/src/io/anuke/mindustry/net/ArcNetImpl.java +++ b/core/src/io/anuke/mindustry/net/ArcNetProvider.java @@ -19,7 +19,7 @@ import java.util.concurrent.*; import static io.anuke.mindustry.Vars.*; -public class ArcNetImpl implements NetProvider{ +public class ArcNetProvider implements NetProvider{ final Client client; final Prov packetSupplier = () -> new DatagramPacket(new byte[256], 256); @@ -27,7 +27,7 @@ public class ArcNetImpl implements NetProvider{ final CopyOnWriteArrayList connections = new CopyOnWriteArrayList<>(); Thread serverThread; - public ArcNetImpl(){ + public ArcNetProvider(){ client = new Client(8192, 4096, new PacketSerializer()); client.setDiscoveryPacket(packetSupplier); client.addListener(new NetListener(){ @@ -346,6 +346,19 @@ public class ArcNetImpl implements NetProvider{ @SuppressWarnings("unchecked") public static class PacketSerializer implements NetSerializer{ + static Cons2 writer = Packet::write; + + @Override + public Object read(ByteBuffer byteBuffer){ + byte id = byteBuffer.get(); + if(id == -2){ + return readFramework(byteBuffer); + }else{ + Packet packet = Pools.obtain((Class)Registrator.getByID(id).type, (Prov)Registrator.getByID(id).constructor); + packet.read(byteBuffer); + return packet; + } + } @Override public void write(ByteBuffer byteBuffer, Object o){ @@ -359,19 +372,7 @@ public class ArcNetImpl implements NetProvider{ if(id == -1) throw new RuntimeException("Unregistered class: " + o.getClass()); byteBuffer.put(id); - ((Packet)o).write(byteBuffer); - } - } - - @Override - public Object read(ByteBuffer byteBuffer){ - byte id = byteBuffer.get(); - if(id == -2){ - return readFramework(byteBuffer); - }else{ - Packet packet = Pools.obtain((Class)Registrator.getByID(id).type, (Prov)Registrator.getByID(id).constructor); - packet.read(byteBuffer); - return packet; + writer.get((Packet)o, byteBuffer); } } diff --git a/core/src/io/anuke/mindustry/net/CrashSender.java b/core/src/io/anuke/mindustry/net/CrashSender.java index 21b12bf3d8..184e801326 100644 --- a/core/src/io/anuke/mindustry/net/CrashSender.java +++ b/core/src/io/anuke/mindustry/net/CrashSender.java @@ -22,6 +22,7 @@ import static io.anuke.mindustry.Vars.net; public class CrashSender{ public static void send(Throwable exception, Cons writeListener){ + try{ exception.printStackTrace(); @@ -44,20 +45,19 @@ public class CrashSender{ }else{ Version.build = Strings.canParseInt(map.get("build")) ? Integer.parseInt(map.get("build")) : -1; } - }catch(Throwable ignored){ - ignored.printStackTrace(); + }catch(Throwable e){ + e.printStackTrace(); Log.err("Failed to parse version."); } } try{ File file = new File(OS.getAppDataDirectoryString(Vars.appName), "crashes/crash-report-" + new SimpleDateFormat("MM_dd_yyyy_HH_mm_ss").format(new Date()) + ".txt"); - new FileHandle(OS.getAppDataDirectoryString(Vars.appName)).child("crashes").mkdirs(); - new FileHandle(file).writeString(parseException(exception)); + new Fi(OS.getAppDataDirectoryString(Vars.appName)).child("crashes").mkdirs(); + new Fi(file).writeString(parseException(exception)); writeListener.get(file); }catch(Throwable e){ - e.printStackTrace(); - Log.err("Failed to save local crash report."); + Log.err("Failed to save local crash report.", e); } try{ @@ -69,6 +69,14 @@ public class CrashSender{ //if there's no settings init we don't know what the user wants but chances are it's an important crash, so send it anyway } + try{ + //check any mods - if there are any, don't send reports + if(Vars.mods != null && !Vars.mods.list().isEmpty()){ + return; + } + }catch(Throwable ignored){ + } + //do not send exceptions that occur for versions that can't be parsed if(Version.number == 0){ return; diff --git a/core/src/io/anuke/mindustry/net/Packets.java b/core/src/io/anuke/mindustry/net/Packets.java index 963ed3c549..6c006a7eba 100644 --- a/core/src/io/anuke/mindustry/net/Packets.java +++ b/core/src/io/anuke/mindustry/net/Packets.java @@ -63,48 +63,6 @@ public class Packets{ } - public static class ConnectPacket implements Packet{ - public int version; - public String versionType; - public Array mods; - public String name, uuid, usid; - public boolean mobile; - public int color; - - @Override - public void write(ByteBuffer buffer){ - buffer.putInt(Version.build); - TypeIO.writeString(buffer, versionType); - TypeIO.writeString(buffer, name); - TypeIO.writeString(buffer, usid); - buffer.put(mobile ? (byte)1 : 0); - buffer.putInt(color); - buffer.put(Base64Coder.decode(uuid)); - buffer.put((byte)mods.size); - for(int i = 0; i < mods.size; i++){ - TypeIO.writeString(buffer, mods.get(i)); - } - } - - @Override - public void read(ByteBuffer buffer){ - version = buffer.getInt(); - versionType = TypeIO.readString(buffer); - name = TypeIO.readString(buffer); - usid = TypeIO.readString(buffer); - mobile = buffer.get() == 1; - color = buffer.getInt(); - byte[] idbytes = new byte[8]; - buffer.get(idbytes); - uuid = new String(Base64Coder.encode(idbytes)); - int totalMods = buffer.get(); - mods = new Array<>(totalMods); - for(int i = 0; i < totalMods; i++){ - mods.add(TypeIO.readString(buffer)); - } - } - } - public static class InvokePacket implements Packet{ public byte type, priority; @@ -190,4 +148,46 @@ public class Packets{ buffer.get(data); } } + + public static class ConnectPacket implements Packet{ + public int version; + public String versionType; + public Array mods; + public String name, uuid, usid; + public boolean mobile; + public int color; + + @Override + public void write(ByteBuffer buffer){ + buffer.putInt(Version.build); + TypeIO.writeString(buffer, versionType); + TypeIO.writeString(buffer, name); + TypeIO.writeString(buffer, usid); + buffer.put(mobile ? (byte)1 : 0); + buffer.put(Base64Coder.decode(uuid)); + buffer.put((byte)color); + buffer.put((byte)mods.size); + for(int i = 0; i < mods.size; i++){ + TypeIO.writeString(buffer, mods.get(i)); + } + } + + @Override + public void read(ByteBuffer buffer){ + version = buffer.getInt(); + versionType = TypeIO.readString(buffer); + name = TypeIO.readString(buffer); + usid = TypeIO.readString(buffer); + mobile = buffer.get() == 1; + color = buffer.getInt(); + byte[] idbytes = new byte[8]; + buffer.get(idbytes); + uuid = new String(Base64Coder.encode(idbytes)); + int totalMods = buffer.get(); + mods = new Array<>(totalMods); + for(int i = 0; i < totalMods; i++){ + mods.add(TypeIO.readString(buffer)); + } + } + } } diff --git a/core/src/io/anuke/mindustry/type/ErrorContent.java b/core/src/io/anuke/mindustry/type/ErrorContent.java new file mode 100644 index 0000000000..91c52207f8 --- /dev/null +++ b/core/src/io/anuke/mindustry/type/ErrorContent.java @@ -0,0 +1,12 @@ +package io.anuke.mindustry.type; + +import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; + +/** Represents a blank type of content that has an error. Replaces anything that failed to parse. */ +public class ErrorContent extends Content{ + @Override + public ContentType getContentType(){ + return ContentType.error; + } +} diff --git a/core/src/io/anuke/mindustry/type/Item.java b/core/src/io/anuke/mindustry/type/Item.java index 6ec12ae475..01cff82cd2 100644 --- a/core/src/io/anuke/mindustry/type/Item.java +++ b/core/src/io/anuke/mindustry/type/Item.java @@ -1,10 +1,10 @@ package io.anuke.mindustry.type; -import io.anuke.arc.*; import io.anuke.arc.collection.*; import io.anuke.arc.graphics.*; import io.anuke.arc.scene.ui.layout.*; -import io.anuke.mindustry.ctype.UnlockableContent; +import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.ui.*; import io.anuke.mindustry.world.blocks.*; @@ -34,7 +34,6 @@ public class Item extends UnlockableContent{ public Item(String name, Color color){ super(name); this.color = color; - this.description = Core.bundle.getOrNull("item." + this.name + ".description"); } public Item(String name){ @@ -51,14 +50,9 @@ public class Item extends UnlockableContent{ ContentDisplay.displayItem(table, this); } - @Override - public String localizedName(){ - return Core.bundle.get("item." + this.name + ".name"); - } - @Override public String toString(){ - return localizedName(); + return localizedName; } @Override diff --git a/core/src/io/anuke/mindustry/type/ItemStack.java b/core/src/io/anuke/mindustry/type/ItemStack.java index 4ea87f5605..723a6e4c24 100644 --- a/core/src/io/anuke/mindustry/type/ItemStack.java +++ b/core/src/io/anuke/mindustry/type/ItemStack.java @@ -38,7 +38,7 @@ public class ItemStack implements Comparable{ public static ItemStack[] with(Object... items){ ItemStack[] stacks = new ItemStack[items.length / 2]; for(int i = 0; i < items.length; i += 2){ - stacks[i / 2] = new ItemStack((Item)items[i], (Integer)items[i + 1]); + stacks[i / 2] = new ItemStack((Item)items[i], ((Number)items[i + 1]).intValue()); } return stacks; } @@ -46,7 +46,7 @@ public class ItemStack implements Comparable{ public static Array list(Object... items){ Array stacks = new Array<>(items.length / 2); for(int i = 0; i < items.length; i += 2){ - stacks.add(new ItemStack((Item)items[i], (Integer)items[i + 1])); + stacks.add(new ItemStack((Item)items[i], ((Number)items[i + 1]).intValue())); } return stacks; } diff --git a/core/src/io/anuke/mindustry/type/Liquid.java b/core/src/io/anuke/mindustry/type/Liquid.java index bc97a18990..0b896a389c 100644 --- a/core/src/io/anuke/mindustry/type/Liquid.java +++ b/core/src/io/anuke/mindustry/type/Liquid.java @@ -1,11 +1,11 @@ package io.anuke.mindustry.type; -import io.anuke.arc.*; import io.anuke.arc.graphics.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.mindustry.content.*; -import io.anuke.mindustry.ctype.UnlockableContent; +import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.ui.*; public class Liquid extends UnlockableContent{ @@ -31,7 +31,6 @@ public class Liquid extends UnlockableContent{ public Liquid(String name, Color color){ super(name); this.color = new Color(color); - this.description = Core.bundle.getOrNull("liquid." + name + ".description"); } /** For modding only.*/ @@ -52,14 +51,9 @@ public class Liquid extends UnlockableContent{ ContentDisplay.displayLiquid(table, this); } - @Override - public String localizedName(){ - return Core.bundle.get("liquid." + this.name + ".name"); - } - @Override public String toString(){ - return localizedName(); + return localizedName; } @Override diff --git a/core/src/io/anuke/mindustry/type/Mech.java b/core/src/io/anuke/mindustry/type/Mech.java index 8eb9681548..6172827ee8 100644 --- a/core/src/io/anuke/mindustry/type/Mech.java +++ b/core/src/io/anuke/mindustry/type/Mech.java @@ -5,6 +5,7 @@ import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.g2d.TextureRegion; import io.anuke.arc.scene.ui.layout.Table; import io.anuke.arc.util.ArcAnnotate.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.type.Player; import io.anuke.mindustry.ctype.UnlockableContent; import io.anuke.mindustry.graphics.Pal; @@ -39,17 +40,12 @@ public class Mech extends UnlockableContent{ public Mech(String name, boolean flying){ super(name); this.flying = flying; - this.description = Core.bundle.get("mech." + name + ".description"); } public Mech(String name){ this(name, false); } - public String localizedName(){ - return Core.bundle.get("mech." + name + ".name"); - } - public void updateAlt(Player player){ } @@ -113,6 +109,6 @@ public class Mech extends UnlockableContent{ @Override public String toString(){ - return localizedName(); + return localizedName; } } diff --git a/core/src/io/anuke/mindustry/type/Publishable.java b/core/src/io/anuke/mindustry/type/Publishable.java index f3e8b45b88..5c6c1aade3 100644 --- a/core/src/io/anuke/mindustry/type/Publishable.java +++ b/core/src/io/anuke/mindustry/type/Publishable.java @@ -20,9 +20,9 @@ public interface Publishable{ /** @return the tag that this content has. e.g. 'schematic' or 'map'. */ String steamTag(); /** @return a folder with everything needed for this piece of content in it; does not need to be a copy. */ - FileHandle createSteamFolder(String id); + Fi createSteamFolder(String id); /** @return a preview file PNG. */ - FileHandle createSteamPreview(String id); + Fi createSteamPreview(String id); /** @return any extra tags to add to this item.*/ default Array extraTags(){ return new Array<>(0); diff --git a/core/src/io/anuke/mindustry/type/StatusEffect.java b/core/src/io/anuke/mindustry/type/StatusEffect.java index 706c2a1ca8..34d7a9cb77 100644 --- a/core/src/io/anuke/mindustry/type/StatusEffect.java +++ b/core/src/io/anuke/mindustry/type/StatusEffect.java @@ -1,46 +1,46 @@ package io.anuke.mindustry.type; -import io.anuke.arc.collection.Array; -import io.anuke.arc.collection.ObjectMap; -import io.anuke.arc.func.Prov; -import io.anuke.arc.graphics.Color; -import io.anuke.arc.math.Mathf; +import io.anuke.arc.collection.*; +import io.anuke.arc.graphics.*; +import io.anuke.arc.math.*; import io.anuke.arc.util.*; -import io.anuke.mindustry.content.Fx; -import io.anuke.mindustry.entities.Effects; -import io.anuke.mindustry.entities.Effects.Effect; -import io.anuke.mindustry.entities.type.Unit; -import io.anuke.mindustry.entities.units.Statuses.StatusEntry; -import io.anuke.mindustry.ctype.Content; - -public class StatusEffect extends Content{ - public float damageMultiplier = 1f; //damage dealt - public float armorMultiplier = 1f; //armor points - public float speedMultiplier = 1f; //speed - public Color color = Color.white.cpy(); //tint color - - /** Transition handler map. */ - private ObjectMap transitions = new ObjectMap<>(); - /** - * Transition initializer array. Since provided effects are only available after init(), this handles putting things - * in the transitions map. - */ - private Array transInit = new Array<>(); +import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; +import io.anuke.mindustry.entities.*; +import io.anuke.mindustry.entities.Effects.*; +import io.anuke.mindustry.entities.type.*; +import io.anuke.mindustry.entities.units.Statuses.*; +public class StatusEffect extends MappableContent{ + /** Damage dealt by the unit with the effect. */ + public float damageMultiplier = 1f; + /** Unit armor multiplier. */ + public float armorMultiplier = 1f; + /** Unit speed multiplier (buggy) */ + public float speedMultiplier = 1f; /** Damage per frame. */ - protected float damage; + public float damage; + /** Tint color of effect. */ + public Color color = Color.white.cpy(); /** Effect that happens randomly on top of the affected unit. */ - protected Effect effect = Fx.none; + public Effect effect = Fx.none; + /** Transition handler map. */ + protected ObjectMap transitions = new ObjectMap<>(); + /** Called on init. */ + protected Runnable initblock = () -> {}; + + public StatusEffect(String name){ + super(name); + } - @SuppressWarnings("unchecked") @Override public void init(){ - for(Object[] pair : transInit){ - Prov sup = (Prov)pair[0]; - TransitionHandler handler = (TransitionHandler)pair[1]; - transitions.put(sup.get(), handler); - } - transInit.clear(); + initblock.run(); + } + + public void init(Runnable run){ + this.initblock = run; } /** Runs every tick on the affected unit while time is greater than 0. */ @@ -56,20 +56,19 @@ public class StatusEffect extends Content{ } } - protected void trans(Prov effect, TransitionHandler handler){ - transInit.add(new Object[]{effect, handler}); + protected void trans(StatusEffect effect, TransitionHandler handler){ + transitions.put(effect, handler); } - @SuppressWarnings("unchecked") - protected void opposite(Prov... effect){ - for(Prov sup : effect){ + protected void opposite(StatusEffect... effect){ + for(StatusEffect sup : effect){ trans(sup, (unit, time, newTime, result) -> { time -= newTime * 0.5f; if(time > 0){ result.set(this, time); return; } - result.set(sup.get(), newTime); + result.set(sup, newTime); }); } } diff --git a/core/src/io/anuke/mindustry/type/TypeID.java b/core/src/io/anuke/mindustry/type/TypeID.java index bd190a7a63..5ab6c1f3f5 100644 --- a/core/src/io/anuke/mindustry/type/TypeID.java +++ b/core/src/io/anuke/mindustry/type/TypeID.java @@ -2,6 +2,7 @@ package io.anuke.mindustry.type; import io.anuke.arc.func.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.traits.*; public class TypeID extends MappableContent{ diff --git a/core/src/io/anuke/mindustry/type/UnitType.java b/core/src/io/anuke/mindustry/type/UnitType.java index b2602a16ad..85a6882e86 100644 --- a/core/src/io/anuke/mindustry/type/UnitType.java +++ b/core/src/io/anuke/mindustry/type/UnitType.java @@ -8,6 +8,7 @@ import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.ctype.UnlockableContent; import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.game.*; @@ -16,8 +17,7 @@ import io.anuke.mindustry.ui.*; public class UnitType extends UnlockableContent{ public @NonNull TypeID typeID; - public @NonNull - Prov constructor; + public @NonNull Prov constructor; public float health = 60; public float hitsize = 7f; @@ -49,9 +49,8 @@ public class UnitType extends UnlockableContent{ create(mainConstructor); } - public UnitType(String name){ + public UnitType(String name){ super(name); - this.description = Core.bundle.getOrNull("unit." + name + ".description"); } public void create(Prov mainConstructor){ @@ -65,11 +64,6 @@ public class UnitType extends UnlockableContent{ ContentDisplay.displayUnit(table, this); } - @Override - public String localizedName(){ - return Core.bundle.get("unit." + name + ".name"); - } - @Override public void load(){ weapon.load(); diff --git a/core/src/io/anuke/mindustry/type/WeatherEvent.java b/core/src/io/anuke/mindustry/type/WeatherEvent.java index 29b6ca0855..4f7eba597c 100644 --- a/core/src/io/anuke/mindustry/type/WeatherEvent.java +++ b/core/src/io/anuke/mindustry/type/WeatherEvent.java @@ -1,6 +1,7 @@ package io.anuke.mindustry.type; import io.anuke.mindustry.ctype.Content; +import io.anuke.mindustry.ctype.ContentType; //currently unimplemented, see trello for implementation plans public class WeatherEvent extends Content{ diff --git a/core/src/io/anuke/mindustry/type/Zone.java b/core/src/io/anuke/mindustry/type/Zone.java index e0084f0b73..cb047f91b0 100644 --- a/core/src/io/anuke/mindustry/type/Zone.java +++ b/core/src/io/anuke/mindustry/type/Zone.java @@ -7,6 +7,7 @@ import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.mindustry.content.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.ctype.UnlockableContent; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.*; @@ -172,8 +173,8 @@ public class Zone extends UnlockableContent{ @Override public void init(){ - if(generator instanceof MapGenerator && mod != null){ - ((MapGenerator)generator).removePrefix(mod.name); + if(generator instanceof MapGenerator && minfo.mod != null){ + ((MapGenerator)generator).removePrefix(minfo.mod.name); } generator.init(loadout); @@ -205,11 +206,6 @@ public class Zone extends UnlockableContent{ public void displayInfo(Table table){ } - @Override - public String localizedName(){ - return Core.bundle.get("zone." + name + ".name"); - } - @Override public ContentType getContentType(){ return ContentType.zone; diff --git a/core/src/io/anuke/mindustry/ui/ContentDisplay.java b/core/src/io/anuke/mindustry/ui/ContentDisplay.java index e086e4e616..36f100d6a3 100644 --- a/core/src/io/anuke/mindustry/ui/ContentDisplay.java +++ b/core/src/io/anuke/mindustry/ui/ContentDisplay.java @@ -66,7 +66,7 @@ public class ContentDisplay{ table.table(title -> { title.addImage(item.icon(Cicon.xlarge)).size(8 * 6); - title.add("[accent]" + item.localizedName()).padLeft(5); + title.add("[accent]" + item.localizedName).padLeft(5); }); table.row(); @@ -100,7 +100,7 @@ public class ContentDisplay{ table.table(title -> { title.addImage(liquid.icon(Cicon.xlarge)).size(8 * 6); - title.add("[accent]" + liquid.localizedName()).padLeft(5); + title.add("[accent]" + liquid.localizedName).padLeft(5); }); table.row(); @@ -134,7 +134,7 @@ public class ContentDisplay{ 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); + title.add("[accent]" + mech.localizedName).padLeft(5); }); table.left().defaults().left(); @@ -182,7 +182,7 @@ public class ContentDisplay{ public static void displayUnit(Table table, UnitType unit){ table.table(title -> { title.addImage(unit.icon(Cicon.xlarge)).size(8 * 6); - title.add("[accent]" + unit.localizedName()).padLeft(5); + title.add("[accent]" + unit.localizedName).padLeft(5); }); table.row(); diff --git a/core/src/io/anuke/mindustry/ui/ItemDisplay.java b/core/src/io/anuke/mindustry/ui/ItemDisplay.java index 1efcd10919..a55a5034c5 100644 --- a/core/src/io/anuke/mindustry/ui/ItemDisplay.java +++ b/core/src/io/anuke/mindustry/ui/ItemDisplay.java @@ -15,7 +15,7 @@ public class ItemDisplay extends Table{ public ItemDisplay(Item item, int amount, boolean showName){ add(new ItemImage(new ItemStack(item, amount))).size(8 * 4).padRight(amount > 99 ? 12 : 0); - if(showName) add(item.localizedName()).padLeft(4 + amount > 99 ? 4 : 0); + if(showName) add(item.localizedName).padLeft(4 + amount > 99 ? 4 : 0); this.item = item; this.amount = amount; diff --git a/core/src/io/anuke/mindustry/ui/ItemsDisplay.java b/core/src/io/anuke/mindustry/ui/ItemsDisplay.java index f10b17e3eb..e198673c08 100644 --- a/core/src/io/anuke/mindustry/ui/ItemsDisplay.java +++ b/core/src/io/anuke/mindustry/ui/ItemsDisplay.java @@ -29,7 +29,7 @@ public class ItemsDisplay extends Table{ 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.add(item.localizedName).color(Color.lightGray).left(); t.row(); } } diff --git a/core/src/io/anuke/mindustry/ui/LiquidDisplay.java b/core/src/io/anuke/mindustry/ui/LiquidDisplay.java index be4d22b124..741491d9b9 100644 --- a/core/src/io/anuke/mindustry/ui/LiquidDisplay.java +++ b/core/src/io/anuke/mindustry/ui/LiquidDisplay.java @@ -33,6 +33,6 @@ public class LiquidDisplay extends Table{ add(StatUnit.perSecond.localized()).padLeft(2).padRight(5).color(Color.lightGray); } - add(liquid.localizedName()); + add(liquid.localizedName); } } diff --git a/core/src/io/anuke/mindustry/ui/Styles.java b/core/src/io/anuke/mindustry/ui/Styles.java index 29c1321009..1f7be8f08c 100644 --- a/core/src/io/anuke/mindustry/ui/Styles.java +++ b/core/src/io/anuke/mindustry/ui/Styles.java @@ -25,7 +25,7 @@ import static io.anuke.mindustry.gen.Tex.*; public class Styles{ public static Drawable black, black9, black8, black6, black3, none, flatDown, flatOver; public static ButtonStyle defaultb, waveb; - public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet; + public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet, transt; public static ImageButtonStyle defaulti, nodei, righti, emptyi, emptytogglei, selecti, cleari, clearFulli, clearPartiali, clearPartial2i, clearTogglei, clearTransi, clearToggleTransi, clearTogglePartiali; public static ScrollPaneStyle defaultPane, horizontalPane, smallPane; public static KeybindDialogStyle defaultKeybindDialog; @@ -110,6 +110,14 @@ public class Styles{ fontColor = Color.white; disabledFontColor = Color.gray; }}; + transt = new TextButtonStyle(){{ + down = flatDown; + up = none; + over = flatOver; + font = Fonts.def; + fontColor = Color.white; + disabledFontColor = Color.gray; + }}; clearTogglet = new TextButtonStyle(){{ font = Fonts.def; fontColor = Color.white; @@ -201,6 +209,9 @@ public class Styles{ down = flatDown; up = black6; over = flatOver; + disabled = black8; + imageDisabledColor = Color.lightGray; + imageUpColor = Color.white; }}; clearToggleTransi = new ImageButtonStyle(){{ down = flatDown; diff --git a/core/src/io/anuke/mindustry/ui/dialogs/DatabaseDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/DatabaseDialog.java index faa3f6f39a..406665f431 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/DatabaseDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/DatabaseDialog.java @@ -10,9 +10,9 @@ import io.anuke.arc.util.*; import io.anuke.mindustry.*; import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; -import io.anuke.mindustry.type.*; import io.anuke.mindustry.ui.*; public class DatabaseDialog extends FloatingDialog{ @@ -66,7 +66,7 @@ public class DatabaseDialog extends FloatingDialog{ if(unlocked(unlock)){ image.clicked(() -> Vars.ui.content.show(unlock)); - image.addListener(new Tooltip(t -> t.background(Tex.button).add(unlock.localizedName()))); + image.addListener(new Tooltip(t -> t.background(Tex.button).add(unlock.localizedName))); } if((++count) % maxWidth == 0){ diff --git a/core/src/io/anuke/mindustry/ui/dialogs/DeployDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/DeployDialog.java index 056d0cfc24..a84ff1a73c 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/DeployDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/DeployDialog.java @@ -155,7 +155,7 @@ public class DeployDialog extends FloatingDialog{ }).color(Color.darkGray).grow())); } - TextButton button = Elements.newButton(Core.bundle.format("resume", slot.getZone().localizedName()), Styles.squaret, () -> { + TextButton button = Elements.newButton(Core.bundle.format("resume", slot.getZone().localizedName), Styles.squaret, () -> { control.saves.getZoneSlot().cautiousLoad(() -> { hide(); ui.loadAnd(() -> { @@ -232,7 +232,7 @@ public class DeployDialog extends FloatingDialog{ }); if(zone.unlocked() && !hidden(zone)){ - button.labelWrap(zone.localizedName()).style(Styles.outlineLabel).width(140).growX().get().setAlignment(Align.center); + button.labelWrap(zone.localizedName).style(Styles.outlineLabel).width(140).growX().get().setAlignment(Align.center); }else{ Cons flasher = zone.canUnlock() && !hidden(zone) ? e -> e.update(() -> e.getColor().set(Color.white).lerp(Pal.accent, Mathf.absin(3f, 1f))) : e -> {}; flasher.get(button.addImage(Icon.locked).get()); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java b/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java index c726778b5a..811cf7add5 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/FileChooser.java @@ -18,20 +18,20 @@ import java.util.*; import static io.anuke.mindustry.Vars.platform; public class FileChooser extends FloatingDialog{ - private static final FileHandle homeDirectory = Core.files.absolute(Core.files.getExternalStoragePath()); - private static FileHandle lastDirectory = homeDirectory; + private static final Fi homeDirectory = Core.files.absolute(Core.files.getExternalStoragePath()); + private static Fi lastDirectory = homeDirectory; private Table files; - private FileHandle directory = lastDirectory; + private Fi directory = lastDirectory; private ScrollPane pane; private TextField navigation, filefield; private TextButton ok; private FileHistory stack = new FileHistory(); - private Boolf filter; - private Cons selectListener; + private Boolf filter; + private Cons selectListener; private boolean open; - public FileChooser(String title, Boolf filter, boolean open, Cons result){ + public FileChooser(String title, Boolf filter, boolean open, Cons result){ super(title); setFillParent(true); this.open = open; @@ -154,8 +154,8 @@ public class FileChooser extends FloatingDialog{ } } - private FileHandle[] getFileNames(){ - FileHandle[] handles = directory.list(file -> !file.getName().startsWith(".")); + private Fi[] getFileNames(){ + Fi[] handles = directory.list(file -> !file.getName().startsWith(".")); Arrays.sort(handles, (a, b) -> { if(a.isDirectory() && !b.isDirectory()) return -1; @@ -183,7 +183,7 @@ public class FileChooser extends FloatingDialog{ files.clearChildren(); files.top().left(); - FileHandle[] names = getFileNames(); + Fi[] names = getFileNames(); Image upimage = new Image(Icon.folderParentSmall); TextButton upbutton = new TextButton(".." + directory.toString(), Styles.clearTogglet); @@ -204,7 +204,7 @@ public class FileChooser extends FloatingDialog{ ButtonGroup group = new ButtonGroup<>(); group.setMinCheckCount(0); - for(FileHandle file : names){ + for(Fi file : names){ if(!file.isDirectory() && !filter.get(file)) continue; //skip non-filtered files String filename = file.name(); @@ -255,14 +255,14 @@ public class FileChooser extends FloatingDialog{ } public class FileHistory{ - private Array history = new Array<>(); + private Array history = new Array<>(); private int index; public FileHistory(){ } - public void push(FileHandle file){ + public void push(Fi file){ if(index != history.size) history.truncate(index); history.add(file); index++; @@ -296,7 +296,7 @@ public class FileChooser extends FloatingDialog{ System.out.println("\n\n\n\n\n\n"); int i = 0; - for(FileHandle file : history){ + for(Fi file : history){ i++; if(index == i){ System.out.println("[[" + file.toString() + "]]"); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java index 815a5b6516..a1dfe4622a 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/LoadDialog.java @@ -101,7 +101,7 @@ public class LoadDialog extends FloatingDialog{ }); }else{ try{ - FileHandle file = Core.files.local("save-" + slot.getName() + "." + saveExtension); + Fi file = Core.files.local("save-" + slot.getName() + "." + saveExtension); slot.exportFile(file); platform.shareFile(file); }catch(Exception e){ diff --git a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java index 0ae118d5d2..4fd821d051 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/MapsDialog.java @@ -143,7 +143,7 @@ public class MapsDialog extends FloatingDialog{ button.row(); button.stack(new Image(map.safeTexture()).setScaling(Scaling.fit), new BorderImage(map.safeTexture()).setScaling(Scaling.fit)).size(mapsize - 20f); button.row(); - button.add(map.custom ? "$custom" : map.workshop ? "$workshop" : map.mod != null ? "[lightgray]" + map.mod.meta.name : "$builtin").color(Color.gray).padTop(3); + button.add(map.custom ? "$custom" : map.workshop ? "$workshop" : map.mod != null ? "[lightgray]" + map.mod.meta.displayName() : "$builtin").color(Color.gray).padTop(3); i++; } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java index ed8b3c5670..b3003cbb0b 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/ModsDialog.java @@ -2,7 +2,6 @@ package io.anuke.mindustry.ui.dialogs; import io.anuke.arc.*; import io.anuke.arc.Net.*; -import io.anuke.arc.collection.*; import io.anuke.arc.files.*; import io.anuke.arc.util.*; import io.anuke.arc.util.io.*; @@ -47,7 +46,7 @@ public class ModsDialog extends FloatingDialog{ ui.loadfrag.hide(); }else{ try{ - FileHandle file = tmpDirectory.child(text.replace("/", "") + ".zip"); + Fi file = tmpDirectory.child(text.replace("/", "") + ".zip"); Streams.copyStream(result.getResultAsStream(), file.write(false)); mods.importMod(file); file.delete(); @@ -75,7 +74,7 @@ public class ModsDialog extends FloatingDialog{ hidden(() -> { if(mods.requiresReload()){ ui.loadAnd("$reloading", () -> { - mods.all().each(mod -> { + mods.eachEnabled(mod -> { if(mod.hasUnmetDependencies()){ ui.showErrorMessage(Core.bundle.format("mod.nowdisabled", mod.name, mod.missingDependencies.toString(", "))); } @@ -107,14 +106,13 @@ public class ModsDialog extends FloatingDialog{ cont.defaults().width(mobile ? 500 : 560f).pad(4); cont.add("$mod.reloadrequired").visible(mods::requiresReload).center().get().setAlignment(Align.center); cont.row(); - if(!(mods.all().isEmpty() && mods.disabled().isEmpty())){ + if(!mods.list().isEmpty()){ cont.pane(table -> { table.margin(10f).top(); - Array all = Array.withArrays(mods.all(), mods.disabled()); boolean anyDisabled = false; - for(LoadedMod mod : all){ - if(!mod.enabled() && !anyDisabled && mods.all().size > 0){ + for(LoadedMod mod : mods.list()){ + if(!mod.enabled() && !anyDisabled && mods.list().size > 0){ anyDisabled = true; table.row(); table.addImage().growX().height(4f).pad(6f).color(Pal.gray); @@ -126,7 +124,7 @@ public class ModsDialog extends FloatingDialog{ t.margin(14f).left(); t.table(title -> { title.left(); - title.add("[accent]" + mod.meta.name + "[lightgray] v" + mod.meta.version + (mod.enabled() ? "" : "\n" + Core.bundle.get("mod.disabled") + "")).width(200f).wrap(); + title.add("[accent]" + mod.meta.displayName() + "[lightgray] v" + mod.meta.version + (mod.enabled() ? "" : "\n" + Core.bundle.get("mod.disabled") + "")).width(200f).wrap(); title.add().growX(); title.addImageTextButton(mod.enabled() ? "$mod.disable" : "$mod.enable", mod.enabled() ? Icon.arrowDownSmall : Icon.arrowUpSmall, Styles.cleart, () -> { @@ -167,6 +165,9 @@ public class ModsDialog extends FloatingDialog{ }else if(mod.hasUnmetDependencies()){ t.labelWrap(Core.bundle.format("mod.missingdependencies", mod.missingDependencies.toString(", "))).growX(); t.row(); + }else if(mod.hasContentErrors()){ + t.labelWrap("$mod.erroredcontent").growX(); + t.row(); } }).width(mobile ? 430f : 500f); table.row(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/SchematicsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/SchematicsDialog.java index 52f236fa81..4e10a46160 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/SchematicsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/SchematicsDialog.java @@ -100,7 +100,7 @@ public class SchematicsDialog extends FloatingDialog{ }else{ buttons.addImageButton(Icon.trash16Small, style, () -> { if(s.mod != null){ - ui.showInfo(Core.bundle.format("mod.item.remove", s.mod.meta.name)); + ui.showInfo(Core.bundle.format("mod.item.remove", s.mod.meta.displayName())); }else{ ui.showConfirm("$confirm", "$schematic.delete.confirm", () -> { schematics.remove(s); @@ -158,6 +158,7 @@ public class SchematicsDialog extends FloatingDialog{ dialog.hide(); try{ Schematic s = Schematics.readBase64(Core.app.getClipboardText()); + s.removeSteamID(); schematics.add(s); setup(); ui.showInfoFade("$schematic.saved"); @@ -172,6 +173,7 @@ public class SchematicsDialog extends FloatingDialog{ try{ Schematic s = Schematics.read(file); + s.removeSteamID(); schematics.add(s); setup(); showInfo(s); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java index 28e83c63c8..26cd33ec93 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -95,7 +95,7 @@ public class SettingsMenuDialog extends SettingsDialog{ Core.settings.putAll(map); Core.settings.save(); - for(FileHandle file : dataDirectory.list()){ + for(Fi file : dataDirectory.list()){ file.deleteDirectory(); } @@ -106,7 +106,7 @@ public class SettingsMenuDialog extends SettingsDialog{ t.addButton("$data.export", style, () -> { if(ios){ - FileHandle file = Core.files.local("mindustry-data-export.zip"); + Fi file = Core.files.local("mindustry-data-export.zip"); try{ data.exportData(file); }catch(Exception e){ diff --git a/core/src/io/anuke/mindustry/ui/dialogs/TechTreeDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/TechTreeDialog.java index a9b8282a36..7a60ad2724 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/TechTreeDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/TechTreeDialog.java @@ -337,7 +337,7 @@ public class TechTreeDialog extends FloatingDialog{ t.table(list -> { list.left(); list.addImage(req.item.icon(Cicon.small)).size(8 * 3).padRight(3); - list.add(req.item.localizedName()).color(Color.lightGray); + list.add(req.item.localizedName).color(Color.lightGray); list.label(() -> " " + Math.min(data.getItem(req.item), req.amount) + " / " + req.amount) .update(l -> l.setColor(data.has(req.item, req.amount) ? Color.lightGray : Color.scarlet)); }).fillX().left(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/ZoneInfoDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/ZoneInfoDialog.java index 32d2e264f1..1bf34b0855 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/ZoneInfoDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/ZoneInfoDialog.java @@ -96,7 +96,7 @@ public class ZoneInfoDialog extends FloatingDialog{ }).growX(); }else{ - cont.add(zone.localizedName()).color(Pal.accent).growX().center(); + cont.add(zone.localizedName).color(Pal.accent).growX().center(); cont.row(); cont.addImage().color(Pal.accent).height(3).pad(6).growX(); cont.row(); diff --git a/core/src/io/anuke/mindustry/ui/fragments/BlockConfigFragment.java b/core/src/io/anuke/mindustry/ui/fragments/BlockConfigFragment.java index 7644ec9559..663c275e11 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/BlockConfigFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/BlockConfigFragment.java @@ -50,7 +50,7 @@ public class BlockConfigFragment extends Fragment{ table.visible(true); table.clear(); - tile.block().buildTable(tile, table); + tile.block().buildConfiguration(tile, table); table.pack(); table.setTransform(true); table.actions(Actions.scaleTo(0f, 1f), Actions.visible(true), diff --git a/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java b/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java index 1ea3623790..8dc34edd01 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/BlockInventoryFragment.java @@ -42,6 +42,7 @@ public class BlockInventoryFragment extends Fragment{ int removed = tile.block().removeStack(tile, item, amount); player.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)); } @@ -100,7 +101,7 @@ public class BlockInventoryFragment extends Fragment{ holding = false; holdTime = 0f; - Events.fire(new WithdrawEvent()); + if(net.client()) Events.fire(new WithdrawEvent(tile, player, lastItem, amount)); } } @@ -153,7 +154,7 @@ public class BlockInventoryFragment extends Fragment{ lastItem = item; holding = true; holdTime = 0f; - Events.fire(new WithdrawEvent()); + if(net.client()) Events.fire(new WithdrawEvent(tile, player, item, amount)); } return true; } diff --git a/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java b/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java index 2801d10149..c7c168bc84 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/ChatFragment.java @@ -24,7 +24,7 @@ public class ChatFragment extends Table{ private final static int messagesShown = 10; private Array messages = new Array<>(); private float fadetime; - private boolean chatOpen = false; + private boolean shown = false; private TextField chatfield; private Label fieldlabel = new Label(">"); private BitmapFont font; @@ -52,7 +52,7 @@ public class ChatFragment extends Table{ if(!net.active() && messages.size > 0){ clearMessages(); - if(chatOpen){ + if(shown){ hide(); } } @@ -66,7 +66,7 @@ public class ChatFragment extends Table{ toggle(); } - if(chatOpen){ + if(shown){ if(input.keyTap(Binding.chat_history_prev) && historyPos < history.size - 1){ if(historyPos == 0) history.set(0, chatfield.getText()); historyPos++; @@ -123,7 +123,7 @@ public class ChatFragment extends Table{ Draw.color(shadowColor); - if(chatOpen){ + if(shown){ Fill.crect(offsetx, chatfield.getY(), chatfield.getWidth() + 15f, chatfield.getHeight() - 1); } @@ -131,14 +131,14 @@ public class ChatFragment extends Table{ float spacing = chatspace; - chatfield.visible(chatOpen); - fieldlabel.visible(chatOpen); + chatfield.visible(shown); + fieldlabel.visible(shown); Draw.color(shadowColor); Draw.alpha(shadowColor.a * opacity); float theight = offsety + spacing + getMarginBottom(); - for(int i = scrollPos; i < messages.size && i < messagesShown + scrollPos && (i < fadetime || chatOpen); i++){ + for(int i = scrollPos; i < messages.size && i < messagesShown + scrollPos && (i < fadetime || shown); i++){ layout.setText(font, messages.get(i).formattedMessage, Color.white, textWidth, Align.bottomLeft, true); theight += layout.height + textspacing; @@ -147,7 +147,7 @@ public class ChatFragment extends Table{ font.getCache().clear(); font.getCache().addText(messages.get(i).formattedMessage, fontoffsetx + offsetx, offsety + theight, textWidth, Align.bottomLeft, true); - if(!chatOpen && fadetime - i < 1f && fadetime - i >= 0f){ + if(!shown && fadetime - i < 1f && fadetime - i >= 0f){ font.getCache().setAlphas((fadetime - i) * opacity); Draw.color(0, 0, 0, shadowColor.a * (fadetime - i) * opacity); }else{ @@ -163,7 +163,7 @@ public class ChatFragment extends Table{ Draw.color(); - if(fadetime > 0 && !chatOpen) + if(fadetime > 0 && !shown) fadetime -= Time.delta() / 180f; } @@ -180,9 +180,9 @@ public class ChatFragment extends Table{ public void toggle(){ - if(!chatOpen){ + if(!shown){ scene.setKeyboardFocus(chatfield); - chatOpen = !chatOpen; + shown = !shown; if(mobile){ TextInput input = new TextInput(); input.maxLength = maxTextLength; @@ -199,7 +199,7 @@ public class ChatFragment extends Table{ } }else{ scene.setKeyboardFocus(null); - chatOpen = !chatOpen; + shown = !shown; scrollPos = 0; sendMessage(); } @@ -207,7 +207,7 @@ public class ChatFragment extends Table{ public void hide(){ scene.setKeyboardFocus(null); - chatOpen = false; + shown = false; clearChatInput(); } @@ -222,12 +222,8 @@ public class ChatFragment extends Table{ chatfield.setText(""); } - public boolean chatOpen(){ - return chatOpen; - } - - public int getMessagesSize(){ - return messages.size; + public boolean shown(){ + return shown; } public void addMessage(String message, String sender){ diff --git a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java index 3bbce3b1ec..8b05c07d5a 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java @@ -17,6 +17,7 @@ import io.anuke.arc.scene.ui.ImageButton.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; import io.anuke.mindustry.core.GameState.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.ctype.UnlockableContent; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.type.*; @@ -83,7 +84,7 @@ public class HudFragment extends Fragment{ select.addImageButton(Icon.chatSmall, style,() -> { if(net.active() && mobile){ - if(ui.chatfrag.chatOpen()){ + if(ui.chatfrag.shown()){ ui.chatfrag.hide(); }else{ ui.chatfrag.toggle(); @@ -131,7 +132,7 @@ public class HudFragment extends Fragment{ } cont.update(() -> { - if(Core.input.keyTap(Binding.toggle_menus) && !ui.chatfrag.chatOpen() && !Core.scene.hasDialog() && !(Core.scene.getKeyboardFocus() instanceof TextField)){ + if(Core.input.keyTap(Binding.toggle_menus) && !ui.chatfrag.shown() && !Core.scene.hasDialog() && !(Core.scene.getKeyboardFocus() instanceof TextField)){ toggleMenus(); } }); diff --git a/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java b/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java index b18be4b27e..abf313183b 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/MenuFragment.java @@ -88,11 +88,11 @@ public class MenuFragment extends Fragment{ container.defaults().size(size).pad(5).padTop(4f); MobileButton - play = new MobileButton(Icon.play2, "$campaign", ui.deploy::show), - custom = new MobileButton(Icon.playCustom, "$customgame", ui.custom::show), - maps = new MobileButton(Icon.load, "$loadgame", ui.load::show), - join = new MobileButton(Icon.add, "$joingame", ui.join::show), - editor = new MobileButton(Icon.editor, "$editor", ui.maps::show), + play = new MobileButton(Icon.play2, "$campaign", () -> checkPlay(ui.deploy::show)), + custom = new MobileButton(Icon.playCustom, "$customgame", () -> checkPlay(ui.custom::show)), + maps = new MobileButton(Icon.load, "$loadgame", () -> checkPlay(ui.load::show)), + join = new MobileButton(Icon.add, "$joingame", () -> checkPlay(ui.join::show)), + editor = new MobileButton(Icon.editor, "$editor", () -> checkPlay(ui.maps::show)), tools = new MobileButton(Icon.tools, "$settings", ui.settings::show), mods = new MobileButton(Icon.wiki, "$mods", ui.mods::show), donate = new MobileButton(Icon.link, "$website", () -> Core.net.openURI("https://anuke.itch.io/mindustry")), @@ -153,13 +153,13 @@ public class MenuFragment extends Fragment{ buttons(t, new Buttoni("$play", Icon.play2Small, - new Buttoni("$campaign", Icon.play2Small, ui.deploy::show), - new Buttoni("$joingame", Icon.addSmall, ui.join::show), - new Buttoni("$customgame", Icon.editorSmall, ui.custom::show), - new Buttoni("$loadgame", Icon.loadSmall, ui.load::show), - new Buttoni("$tutorial", Icon.infoSmall, control::playTutorial) + new Buttoni("$campaign", Icon.play2Small, () -> checkPlay(ui.deploy::show)), + new Buttoni("$joingame", Icon.addSmall, () -> checkPlay(ui.join::show)), + new Buttoni("$customgame", Icon.editorSmall, () -> checkPlay(ui.custom::show)), + new Buttoni("$loadgame", Icon.loadSmall, () -> checkPlay(ui.load::show)), + new Buttoni("$tutorial", Icon.infoSmall, () -> checkPlay(control::playTutorial)) ), - new Buttoni("$editor", Icon.editorSmall, ui.maps::show), steam ? new Buttoni("$workshop", Icon.saveSmall, platform::openWorkshop) : null, + new Buttoni("$editor", Icon.editorSmall, () -> checkPlay(ui.maps::show)), steam ? new Buttoni("$workshop", Icon.saveSmall, platform::openWorkshop) : null, new Buttoni(Core.bundle.get("mods") + "\n" + Core.bundle.get("mods.alpha"), Icon.wikiSmall, ui.mods::show), //not enough space for this button //new Buttoni("$schematics", Icon.pasteSmall, ui.schematics::show), @@ -180,6 +180,14 @@ public class MenuFragment extends Fragment{ }).width(width).growY(); } + private void checkPlay(Runnable run){ + if(!mods.hasContentErrors()){ + run.run(); + }else{ + ui.showInfo("$mod.noerrorplay"); + } + } + private void fadeInMenu(){ submenu.clearActions(); submenu.actions(Actions.alpha(1f, 0.15f, Interpolation.fade)); diff --git a/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java b/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java index 95bdd5affa..2a843fd5b9 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/PlacementFragment.java @@ -10,6 +10,7 @@ import io.anuke.arc.scene.style.*; import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.util.*; +import io.anuke.mindustry.content.*; import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.game.EventType.*; @@ -103,7 +104,8 @@ public class PlacementFragment extends Fragment{ } } - if(ui.chatfrag.chatOpen()) return false; + if(ui.chatfrag.shown() || Core.scene.hasKeyboard()) return false; + for(int i = 0; i < blockSelect.length; i++){ if(Core.input.keyTap(blockSelect[i])){ if(i > 9) { //select block directionally @@ -260,7 +262,7 @@ public class PlacementFragment extends Fragment{ if(!mobile && Core.settings.getBool("blockselectkeys")){ Array blocks = getByCategory(currentCategory); for(int i = 0; i < blocks.size; i++){ - if(blocks.get(i) == lastDisplay){ + if(blocks.get(i) == lastDisplay && (i + 1) / 10 - 1 < blockSelect.length){ keyCombo = Core.bundle.format("placement.blockselectkeys", Core.keybinds.get(blockSelect[currentCategory.ordinal()]).key.toString()) + (i < 10 ? "" : Core.keybinds.get(blockSelect[(i + 1) / 10 - 1]).key.toString() + ",") + Core.keybinds.get(blockSelect[i % 10]).key.toString() + "]"; @@ -460,6 +462,6 @@ public class PlacementFragment extends Fragment{ /** Returns the block currently being hovered over in the world. */ Block tileDisplayBlock(){ - return hoverTile == null ? null : hoverTile.block().synthetic() ? hoverTile.block() : hoverTile.drop() != null ? hoverTile.overlay().itemDrop != null ? hoverTile.overlay() : hoverTile.floor() : null; + return hoverTile == null ? null : hoverTile.block().synthetic() ? hoverTile.block() : hoverTile.drop() != null && hoverTile.block() == Blocks.air ? hoverTile.overlay().itemDrop != null ? hoverTile.overlay() : hoverTile.floor() : null; } } diff --git a/core/src/io/anuke/mindustry/ui/fragments/ScriptConsoleFragment.java b/core/src/io/anuke/mindustry/ui/fragments/ScriptConsoleFragment.java new file mode 100644 index 0000000000..87b7f76d6e --- /dev/null +++ b/core/src/io/anuke/mindustry/ui/fragments/ScriptConsoleFragment.java @@ -0,0 +1,221 @@ +package io.anuke.mindustry.ui.fragments; + +import io.anuke.arc.*; +import io.anuke.arc.Input.*; +import io.anuke.arc.collection.*; +import io.anuke.arc.graphics.*; +import io.anuke.arc.graphics.g2d.*; +import io.anuke.arc.math.*; +import io.anuke.arc.scene.*; +import io.anuke.arc.scene.ui.*; +import io.anuke.arc.scene.ui.Label.*; +import io.anuke.arc.scene.ui.layout.*; +import io.anuke.arc.util.*; +import io.anuke.mindustry.*; +import io.anuke.mindustry.input.*; +import io.anuke.mindustry.ui.*; + +import static io.anuke.arc.Core.*; +import static io.anuke.mindustry.Vars.*; + +public class ScriptConsoleFragment extends Table{ + private final static int messagesShown = 30; + private Array messages = new Array<>(); + private boolean open = false, shown; + private TextField chatfield; + private Label fieldlabel = new Label(">"); + private BitmapFont font; + private GlyphLayout layout = new GlyphLayout(); + private float offsetx = Scl.scl(4), offsety = Scl.scl(4), fontoffsetx = Scl.scl(2), chatspace = Scl.scl(50); + private Color shadowColor = new Color(0, 0, 0, 0.4f); + private float textspacing = Scl.scl(10); + private Array history = new Array<>(); + private int historyPos = 0; + private int scrollPos = 0; + private Fragment container = new Fragment(){ + @Override + public void build(Group parent){ + scene.add(ScriptConsoleFragment.this); + } + }; + + public ScriptConsoleFragment(){ + + setFillParent(true); + font = Fonts.def; + + visible(() -> { + if(input.keyTap(Binding.console) && !Vars.net.client() && (scene.getKeyboardFocus() == chatfield || scene.getKeyboardFocus() == null)){ + shown = !shown; + if(shown && !open && enableConsole){ + toggle(); + } + clearChatInput(); + } + + return shown && !Vars.net.active(); + }); + + update(() -> { + if(input.keyTap(Binding.chat) && enableConsole && (scene.getKeyboardFocus() == chatfield || scene.getKeyboardFocus() == null)){ + toggle(); + } + + if(open){ + if(input.keyTap(Binding.chat_history_prev) && historyPos < history.size - 1){ + if(historyPos == 0) history.set(0, chatfield.getText()); + historyPos++; + updateChat(); + } + if(input.keyTap(Binding.chat_history_next) && historyPos > 0){ + historyPos--; + updateChat(); + } + } + + scrollPos = (int)Mathf.clamp(scrollPos + input.axis(Binding.chat_scroll), 0, Math.max(0, messages.size - messagesShown)); + }); + + history.insert(0, ""); + setup(); + } + + public Fragment container(){ + return container; + } + + public void clearMessages(){ + messages.clear(); + history.clear(); + history.insert(0, ""); + } + + private void setup(){ + fieldlabel.setStyle(new LabelStyle(fieldlabel.getStyle())); + fieldlabel.getStyle().font = font; + fieldlabel.setStyle(fieldlabel.getStyle()); + + chatfield = new TextField("", new TextField.TextFieldStyle(scene.getStyle(TextField.TextFieldStyle.class))); + chatfield.setMaxLength(Vars.maxTextLength); + chatfield.getStyle().background = null; + chatfield.getStyle().font = Fonts.chat; + chatfield.getStyle().fontColor = Color.white; + chatfield.setStyle(chatfield.getStyle()); + + bottom().left().marginBottom(offsety).marginLeft(offsetx * 2).add(fieldlabel).padBottom(6f); + + add(chatfield).padBottom(offsety).padLeft(offsetx).growX().padRight(offsetx).height(28); + } + + @Override + public void draw(){ + float opacity = 1f; + float textWidth = graphics.getWidth() - offsetx*2f; + + Draw.color(shadowColor); + + if(open){ + Fill.crect(offsetx, chatfield.getY(), chatfield.getWidth() + 15f, chatfield.getHeight() - 1); + } + + super.draw(); + + float spacing = chatspace; + + chatfield.visible(open); + fieldlabel.visible(open); + + Draw.color(shadowColor); + Draw.alpha(shadowColor.a * opacity); + + float theight = offsety + spacing + getMarginBottom(); + for(int i = scrollPos; i < messages.size && i < messagesShown + scrollPos; i++){ + + layout.setText(font, messages.get(i), Color.white, textWidth, Align.bottomLeft, true); + theight += layout.height + textspacing; + if(i - scrollPos == 0) theight -= textspacing + 1; + + font.getCache().clear(); + font.getCache().addText(messages.get(i), fontoffsetx + offsetx, offsety + theight, textWidth, Align.bottomLeft, true); + + if(!open){ + font.getCache().setAlphas(opacity); + Draw.color(0, 0, 0, shadowColor.a * opacity); + }else{ + font.getCache().setAlphas(opacity); + } + + Fill.crect(offsetx, theight - layout.height - 2, textWidth + Scl.scl(4f), layout.height + textspacing); + Draw.color(shadowColor); + Draw.alpha(opacity * shadowColor.a); + + font.getCache().draw(); + } + + Draw.color(); + } + + private void sendMessage(){ + String message = chatfield.getText(); + clearChatInput(); + + if(message.replaceAll(" ", "").isEmpty()) return; + + history.insert(1, message); + + addMessage("[lightgray]> " + message.replace("[", "[[")); + addMessage(mods.getScripts().runConsole(message).replace("[", "[[")); + } + + public void toggle(){ + + if(!open){ + scene.setKeyboardFocus(chatfield); + open = !open; + if(mobile){ + TextInput input = new TextInput(); + input.maxLength = maxTextLength; + input.accepted = text -> { + chatfield.setText(text); + sendMessage(); + hide(); + Core.input.setOnscreenKeyboardVisible(false); + }; + input.canceled = this::hide; + Core.input.getTextInput(input); + }else{ + chatfield.fireClick(); + } + }else{ + scene.setKeyboardFocus(null); + open = !open; + scrollPos = 0; + sendMessage(); + } + } + + public void hide(){ + scene.setKeyboardFocus(null); + open = false; + clearChatInput(); + } + + public void updateChat(){ + chatfield.setText(history.get(historyPos)); + chatfield.setCursorPosition(chatfield.getText().length()); + } + + public void clearChatInput(){ + historyPos = 0; + history.set(0, ""); + chatfield.setText(""); + } + + public boolean open(){ + return open; + } + + public void addMessage(String message){ + messages.insert(0, message); + } +} diff --git a/core/src/io/anuke/mindustry/world/Block.java b/core/src/io/anuke/mindustry/world/Block.java index 75f4fff536..a6f7769d03 100644 --- a/core/src/io/anuke/mindustry/world/Block.java +++ b/core/src/io/anuke/mindustry/world/Block.java @@ -18,6 +18,7 @@ import io.anuke.arc.util.*; import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.arc.util.pooling.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.effect.*; import io.anuke.mindustry.entities.traits.BuilderTrait.*; @@ -158,7 +159,6 @@ public class Block extends BlockStorage{ public Block(String name){ super(name); - this.description = Core.bundle.getOrNull("block." + name + ".description"); this.solid = false; } @@ -185,7 +185,7 @@ public class Block extends BlockStorage{ } protected void updatePowerGraph(Tile tile){ - TileEntity entity = tile.entity(); + TileEntity entity = tile.ent(); for(Tile other : getPowerConnections(tile, tempTiles)){ if(other.entity.power != null){ @@ -396,11 +396,6 @@ public class Block extends BlockStorage{ return sum / size / size; } - @Override - public String localizedName(){ - return localizedName; - } - @Override public void displayInfo(Table table){ ContentDisplay.displayBlock(table, this); @@ -489,7 +484,7 @@ public class Block extends BlockStorage{ * Called when this block is tapped to build a UI on the table. * {@link #configurable} must return true for this to be called. */ - public void buildTable(Tile tile, Table table){ + public void buildConfiguration(Tile tile, Table table){ } /** Update table alignment after configuring.*/ @@ -553,7 +548,7 @@ public class Block extends BlockStorage{ }else{ 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(), + 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)); } diff --git a/core/src/io/anuke/mindustry/world/Build.java b/core/src/io/anuke/mindustry/world/Build.java index 5f7834ed25..276caefba7 100644 --- a/core/src/io/anuke/mindustry/world/Build.java +++ b/core/src/io/anuke/mindustry/world/Build.java @@ -39,7 +39,7 @@ public class Build{ Block sub = BuildBlock.get(previous.size); world.setBlock(tile, sub, team, rotation); - tile.entity().setDeconstruct(previous); + tile.ent().setDeconstruct(previous); tile.entity.health = tile.entity.maxHealth() * prevPercent; Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, true))); @@ -61,7 +61,7 @@ public class Build{ Block sub = BuildBlock.get(result.size); world.setBlock(tile, sub, team, rotation); - tile.entity().setConstruct(previous, result); + tile.ent().setConstruct(previous, result); Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, false))); } diff --git a/core/src/io/anuke/mindustry/world/Tile.java b/core/src/io/anuke/mindustry/world/Tile.java index 06e6cdca81..b3b82a3c45 100644 --- a/core/src/io/anuke/mindustry/world/Tile.java +++ b/core/src/io/anuke/mindustry/world/Tile.java @@ -99,7 +99,7 @@ public class Tile implements Position, TargetTrait{ } @SuppressWarnings("unchecked") - public T entity(){ + public T ent(){ return (T)entity; } diff --git a/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java b/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java index 9a31172660..4623857790 100644 --- a/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/BuildBlock.java @@ -118,19 +118,19 @@ public class BuildBlock extends Block{ @Override public String getDisplayName(Tile tile){ - BuildEntity entity = tile.entity(); + BuildEntity entity = tile.ent(); return Core.bundle.format("block.constructing", entity.cblock == null ? entity.previous.localizedName : entity.cblock.localizedName); } @Override public TextureRegion getDisplayIcon(Tile tile){ - BuildEntity entity = tile.entity(); + BuildEntity entity = tile.ent(); return (entity.cblock == null ? entity.previous : entity.cblock).icon(io.anuke.mindustry.ui.Cicon.full); } @Override public boolean isSolidFor(Tile tile){ - BuildEntity entity = tile.entity(); + BuildEntity entity = tile.ent(); return entity == null || (entity.cblock != null && entity.cblock.solid) || entity.previous == null || entity.previous.solid; } @@ -141,7 +141,7 @@ public class BuildBlock extends Block{ @Override public void tapped(Tile tile, Player player){ - BuildEntity entity = tile.entity(); + BuildEntity entity = tile.ent(); //if the target is constructible, begin constructing if(entity.cblock != null){ @@ -164,7 +164,7 @@ public class BuildBlock extends Block{ @Override public void draw(Tile tile){ - BuildEntity entity = tile.entity(); + BuildEntity entity = tile.ent(); //When breaking, don't draw the previous block... since it's the thing you were breaking if(entity.cblock != null && entity.previous == entity.cblock){ @@ -181,7 +181,7 @@ public class BuildBlock extends Block{ @Override public void drawLayer(Tile tile){ - BuildEntity entity = tile.entity(); + BuildEntity entity = tile.ent(); Shaders.blockbuild.color = Pal.accent; @@ -224,6 +224,10 @@ public class BuildBlock extends Block{ return false; } + if(cblock.requirements.length != accumulator.length || totalAccumulator.length != cblock.requirements.length){ + setConstruct(previous, cblock); + } + float maxProgress = core == null ? amount : checkRequired(core.items, amount, false); for(int i = 0; i < cblock.requirements.length; i++){ diff --git a/core/src/io/anuke/mindustry/world/blocks/OreBlock.java b/core/src/io/anuke/mindustry/world/blocks/OreBlock.java index ba74f2db0f..7270ec7aa0 100644 --- a/core/src/io/anuke/mindustry/world/blocks/OreBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/OreBlock.java @@ -16,7 +16,7 @@ public class OreBlock extends OverlayFloor{ public OreBlock(Item ore){ super("ore-" + ore.name); - this.localizedName = ore.localizedName(); + this.localizedName = ore.localizedName; this.itemDrop = ore; this.variants = 3; this.color.set(ore.color); @@ -29,7 +29,7 @@ public class OreBlock extends OverlayFloor{ } public void setup(Item ore){ - this.localizedName = ore.localizedName(); + this.localizedName = ore.localizedName; this.itemDrop = ore; this.color.set(ore.color); } @@ -80,6 +80,6 @@ public class OreBlock extends OverlayFloor{ @Override public String getDisplayName(Tile tile){ - return itemDrop.localizedName(); + return itemDrop.localizedName; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/DeflectorWall.java b/core/src/io/anuke/mindustry/world/blocks/defense/DeflectorWall.java index 1dff9f636c..3cc6d177f0 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/DeflectorWall.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/DeflectorWall.java @@ -27,7 +27,7 @@ public class DeflectorWall extends Wall{ public void draw(Tile tile){ super.draw(tile); - DeflectorEntity entity = tile.entity(); + DeflectorEntity entity = tile.ent(); if(entity.hit < 0.0001f) return; diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/Door.java b/core/src/io/anuke/mindustry/world/blocks/defense/Door.java index b0c83fba9d..e8bfd2c4b4 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/Door.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/Door.java @@ -18,11 +18,11 @@ import java.io.*; import static io.anuke.mindustry.Vars.*; public class Door extends Wall{ - protected final Rectangle rect = new Rectangle(); + protected final static Rectangle rect = new Rectangle(); - protected int timerToggle = timers++; - protected Effect openfx = Fx.dooropen; - protected Effect closefx = Fx.doorclose; + public final int timerToggle = timers++; + public Effect openfx = Fx.dooropen; + public Effect closefx = Fx.doorclose; protected TextureRegion openRegion; @@ -36,7 +36,7 @@ public class Door extends Wall{ @Remote(called = Loc.server) public static void onDoorToggle(Player player, Tile tile, boolean open){ - DoorEntity entity = tile.entity(); + DoorEntity entity = tile.ent(); if(entity != null){ entity.open = open; Door door = (Door)tile.block(); @@ -59,7 +59,7 @@ public class Door extends Wall{ @Override public void draw(Tile tile){ - DoorEntity entity = tile.entity(); + DoorEntity entity = tile.ent(); if(!entity.open){ Draw.rect(region, tile.drawx(), tile.drawy()); @@ -75,13 +75,13 @@ public class Door extends Wall{ @Override public boolean isSolidFor(Tile tile){ - DoorEntity entity = tile.entity(); + DoorEntity entity = tile.ent(); return !entity.open; } @Override public void tapped(Tile tile, Player player){ - DoorEntity entity = tile.entity(); + DoorEntity entity = tile.ent(); if((Units.anyEntities(tile) && entity.open) || !tile.entity.timer.get(timerToggle, 30f)){ return; diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/ForceProjector.java b/core/src/io/anuke/mindustry/world/blocks/defense/ForceProjector.java index 4dce2d9db9..466d677b6c 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/ForceProjector.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/ForceProjector.java @@ -21,17 +21,17 @@ import java.io.*; import static io.anuke.mindustry.Vars.*; public class ForceProjector extends Block{ - protected int timerUse = timers++; - protected float phaseUseTime = 350f; + public final int timerUse = timers++; + public float phaseUseTime = 350f; - protected float phaseRadiusBoost = 80f; - protected float radius = 101.7f; - protected float breakage = 550f; - protected float cooldownNormal = 1.75f; - protected float cooldownLiquid = 1.5f; - protected float cooldownBrokenBase = 0.35f; - protected float basePowerDraw = 0.2f; - protected TextureRegion topRegion; + public float phaseRadiusBoost = 80f; + public float radius = 101.7f; + public float breakage = 550f; + public float cooldownNormal = 1.75f; + public float cooldownLiquid = 1.5f; + public float cooldownBrokenBase = 0.35f; + public float basePowerDraw = 0.2f; + public TextureRegion topRegion; private static Tile paramTile; private static ForceProjector paramBlock; @@ -88,7 +88,7 @@ public class ForceProjector extends Block{ @Override public void update(Tile tile){ - ForceEntity entity = tile.entity(); + ForceEntity entity = tile.ent(); if(entity.shield == null){ entity.shield = new ShieldEntity(tile); @@ -170,7 +170,7 @@ public class ForceProjector extends Block{ public void draw(Tile tile){ super.draw(tile); - ForceEntity entity = tile.entity(); + ForceEntity entity = tile.ent(); if(entity.buildup <= 0f) return; Draw.alpha(entity.buildup / breakage * 0.75f); @@ -214,7 +214,7 @@ public class ForceProjector extends Block{ final ForceEntity entity; public ShieldEntity(Tile tile){ - this.entity = tile.entity(); + this.entity = tile.ent(); set(tile.drawx(), tile.drawy()); } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/MendProjector.java b/core/src/io/anuke/mindustry/world/blocks/defense/MendProjector.java index 5ba2461265..a19d536018 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/MendProjector.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/MendProjector.java @@ -18,19 +18,18 @@ import java.io.*; import static io.anuke.mindustry.Vars.*; public class MendProjector extends Block{ - private static Color color = Color.valueOf("84f491"); - private static Color phase = Color.valueOf("ffd59e"); - private static IntSet healed = new IntSet(); + private static final IntSet healed = new IntSet(); - protected int timerUse = timers++; - - protected TextureRegion topRegion; - protected float reload = 250f; - protected float range = 60f; - protected float healPercent = 12f; - protected float phaseBoost = 12f; - protected float phaseRangeBoost = 50f; - protected float useTime = 400f; + public final int timerUse = timers++; + public Color baseColor = Color.valueOf("84f491"); + public Color phaseColor = Color.valueOf("ffd59e"); + public TextureRegion topRegion; + public float reload = 250f; + public float range = 60f; + public float healPercent = 12f; + public float phaseBoost = 12f; + public float phaseRangeBoost = 50f; + public float useTime = 400f; public MendProjector(String name){ super(name); @@ -65,7 +64,7 @@ public class MendProjector extends Block{ @Override public void update(Tile tile){ - MendEntity entity = tile.entity(); + MendEntity entity = tile.ent(); entity.heat = Mathf.lerpDelta(entity.heat, entity.cons.valid() || tile.isEnemyCheat() ? 1f : 0f, 0.08f); entity.charge += entity.heat * entity.delta(); @@ -92,7 +91,7 @@ public class MendProjector extends Block{ 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(color).lerp(phase, entity.phaseHeat), other.drawx(), other.drawy(), other.block().size); + Effects.effect(Fx.healBlockFull, Tmp.c1.set(baseColor).lerp(phaseColor, entity.phaseHeat), other.drawx(), other.drawy(), other.block().size); healed.add(other.pos()); } } @@ -107,20 +106,20 @@ public class MendProjector extends Block{ @Override public void drawSelect(Tile tile){ - MendEntity entity = tile.entity(); + MendEntity entity = tile.ent(); float realRange = range + entity.phaseHeat * phaseRangeBoost; - Drawf.dashCircle(tile.drawx(), tile.drawy(), realRange, color); + Drawf.dashCircle(tile.drawx(), tile.drawy(), realRange, baseColor); } @Override public void draw(Tile tile){ super.draw(tile); - MendEntity entity = tile.entity(); + MendEntity entity = tile.ent(); float f = 1f - (Time.time() / 100f) % 1f; - Draw.color(color, phase, entity.phaseHeat); + 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()); @@ -135,7 +134,7 @@ public class MendProjector extends Block{ @Override public void drawLight(Tile tile){ - renderer.lights.add(tile.drawx(), tile.drawy(), 50f * tile.entity.efficiency(), color, 0.7f * tile.entity.efficiency()); + renderer.lights.add(tile.drawx(), tile.drawy(), 50f * tile.entity.efficiency(), baseColor, 0.7f * tile.entity.efficiency()); } class MendEntity extends TileEntity{ diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/OverdriveProjector.java b/core/src/io/anuke/mindustry/world/blocks/defense/OverdriveProjector.java index cc8c99a54e..84e88b2f22 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/OverdriveProjector.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/OverdriveProjector.java @@ -16,19 +16,19 @@ import java.io.*; import static io.anuke.mindustry.Vars.*; public class OverdriveProjector extends Block{ - private static Color color = Color.valueOf("feb380"); - private static Color phase = Color.valueOf("ffd59e"); - private static IntSet healed = new IntSet(); + private static final IntSet healed = new IntSet(); - protected int timerUse = timers++; + public final int timerUse = timers++; - protected TextureRegion topRegion; - protected float reload = 60f; - protected float range = 80f; - protected float speedBoost = 1.5f; - protected float speedBoostPhase = 0.75f; - protected float useTime = 400f; - protected float phaseRangeBoost = 20f; + public TextureRegion topRegion; + public float reload = 60f; + public float range = 80f; + public float speedBoost = 1.5f; + public float speedBoostPhase = 0.75f; + public float useTime = 400f; + public float phaseRangeBoost = 20f; + public Color baseColor = Color.valueOf("feb380"); + public Color phaseColor = Color.valueOf("ffd59e"); public OverdriveProjector(String name){ super(name); @@ -69,12 +69,12 @@ public class OverdriveProjector extends Block{ @Override public void drawLight(Tile tile){ - renderer.lights.add(tile.drawx(), tile.drawy(), 50f * tile.entity.efficiency(), color, 0.7f * tile.entity.efficiency()); + renderer.lights.add(tile.drawx(), tile.drawy(), 50f * tile.entity.efficiency(), baseColor, 0.7f * tile.entity.efficiency()); } @Override public void update(Tile tile){ - OverdriveEntity entity = tile.entity(); + OverdriveEntity entity = tile.ent(); entity.heat = Mathf.lerpDelta(entity.heat, entity.cons.valid() ? 1f : 0f, 0.08f); entity.charge += entity.heat * Time.delta(); @@ -115,20 +115,20 @@ public class OverdriveProjector extends Block{ @Override public void drawSelect(Tile tile){ - OverdriveEntity entity = tile.entity(); + OverdriveEntity entity = tile.ent(); float realRange = range + entity.phaseHeat * phaseRangeBoost; - Drawf.dashCircle(tile.drawx(), tile.drawy(), realRange, color); + Drawf.dashCircle(tile.drawx(), tile.drawy(), realRange, baseColor); } @Override public void draw(Tile tile){ super.draw(tile); - OverdriveEntity entity = tile.entity(); + OverdriveEntity entity = tile.ent(); float f = 1f - (Time.time() / 100f) % 1f; - Draw.color(color, phase, entity.phaseHeat); + Draw.color(baseColor, phaseColor, entity.phaseHeat); Draw.alpha(entity.heat * Mathf.absin(Time.time(), 10f, 1f) * 0.5f); Draw.rect(topRegion, tile.drawx(), tile.drawy()); Draw.alpha(1f); diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/ShockMine.java b/core/src/io/anuke/mindustry/world/blocks/defense/ShockMine.java index e834812f5a..de72043c7d 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/ShockMine.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/ShockMine.java @@ -11,13 +11,13 @@ import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; public class ShockMine extends Block{ - protected int timerDamage = timers++; + public final int timerDamage = timers++; - protected float cooldown = 80f; - protected float tileDamage = 5f; - protected float damage = 13; - protected int length = 10; - protected int tendrils = 6; + public float cooldown = 80f; + public float tileDamage = 5f; + public float damage = 13; + public int length = 10; + public int tendrils = 6; public ShockMine(String name){ super(name); diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/SurgeWall.java b/core/src/io/anuke/mindustry/world/blocks/defense/SurgeWall.java index 0f51c74b40..a1c52ac823 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/SurgeWall.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/SurgeWall.java @@ -7,9 +7,9 @@ import io.anuke.mindustry.entities.type.TileEntity; import io.anuke.mindustry.graphics.Pal; public class SurgeWall extends Wall{ - protected float lightningChance = 0.05f; - protected float lightningDamage = 15f; - protected int lightningLength = 17; + public float lightningChance = 0.05f; + public float lightningDamage = 15f; + public int lightningLength = 17; public SurgeWall(String name){ super(name); diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/Wall.java b/core/src/io/anuke/mindustry/world/blocks/defense/Wall.java index 70d6b6f91f..8b60ffd0f2 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/Wall.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/Wall.java @@ -9,7 +9,7 @@ import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.meta.BlockGroup; public class Wall extends Block{ - protected int variants = 0; + public int variants = 0; public Wall(String name){ super(name); diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ArtilleryTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ArtilleryTurret.java index 53ba8cbad4..433987d2c6 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ArtilleryTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ArtilleryTurret.java @@ -13,7 +13,7 @@ import static io.anuke.mindustry.Vars.tilesize; * Artillery turrets have special shooting calculations done to hit targets. */ public class ArtilleryTurret extends ItemTurret{ - protected float velocityInaccuracy = 0f; + public float velocityInaccuracy = 0f; public ArtilleryTurret(String name){ super(name); @@ -22,7 +22,7 @@ public class ArtilleryTurret extends ItemTurret{ @Override protected void shoot(Tile tile, BulletType ammo){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); entity.recoil = recoil; entity.heat = 1f; diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/BurstTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/BurstTurret.java index d746227559..3661ec175c 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/BurstTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/BurstTurret.java @@ -8,7 +8,7 @@ import io.anuke.mindustry.world.Tile; import static io.anuke.mindustry.Vars.tilesize; public class BurstTurret extends ItemTurret{ - protected float burstSpacing = 5; + public float burstSpacing = 5; public BurstTurret(String name){ super(name); @@ -16,7 +16,7 @@ public class BurstTurret extends ItemTurret{ @Override protected void shoot(Tile tile, BulletType ammo){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); entity.heat = 1f; diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ChargeTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ChargeTurret.java index 3f02328eed..dc12e2425f 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ChargeTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ChargeTurret.java @@ -12,11 +12,11 @@ import static io.anuke.mindustry.Vars.tilesize; public class ChargeTurret extends PowerTurret{ - protected float chargeTime = 30f; - protected int chargeEffects = 5; - protected float chargeMaxDelay = 10f; - protected Effect chargeEffect = Fx.none; - protected Effect chargeBeginEffect = Fx.none; + public float chargeTime = 30f; + public int chargeEffects = 5; + public float chargeMaxDelay = 10f; + public Effect chargeEffect = Fx.none; + public Effect chargeBeginEffect = Fx.none; public ChargeTurret(String name){ super(name); @@ -25,7 +25,7 @@ public class ChargeTurret extends PowerTurret{ @Override public void shoot(Tile tile, BulletType ammo){ - LaserTurretEntity entity = tile.entity(); + LaserTurretEntity entity = tile.ent(); useAmmo(tile); @@ -55,7 +55,7 @@ public class ChargeTurret extends PowerTurret{ @Override public boolean shouldTurn(Tile tile){ - LaserTurretEntity entity = tile.entity(); + LaserTurretEntity entity = tile.ent(); return !entity.shooting; } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/CooledTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/CooledTurret.java index 58038d857e..9e48e3fc3a 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/CooledTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/CooledTurret.java @@ -17,8 +17,8 @@ import static io.anuke.mindustry.Vars.tilesize; public class CooledTurret extends Turret{ /** How much reload is lowered by for each unit of liquid of heat capacity. */ - protected float coolantMultiplier = 5f; - protected Effect coolEffect = Fx.fuelburn; + public float coolantMultiplier = 5f; + public Effect coolEffect = Fx.fuelburn; public CooledTurret(String name){ super(name); @@ -50,7 +50,7 @@ public class CooledTurret extends Turret{ float maxUsed = consumes.get(ConsumeType.liquid).amount; - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); 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); diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/DoubleTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/DoubleTurret.java index 2067bd285a..70be09ad4a 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/DoubleTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/DoubleTurret.java @@ -9,7 +9,7 @@ import io.anuke.mindustry.world.meta.StatUnit; import static io.anuke.mindustry.Vars.tilesize; public class DoubleTurret extends ItemTurret{ - protected float shotWidth = 2f; + public float shotWidth = 2f; public DoubleTurret(String name){ super(name); @@ -26,7 +26,7 @@ public class DoubleTurret extends ItemTurret{ @Override protected void shoot(Tile tile, BulletType ammo){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); entity.shots++; int i = Mathf.signs[entity.shots % 2]; diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ItemTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ItemTurret.java index dca1324e66..393e102d7a 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ItemTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/ItemTurret.java @@ -22,8 +22,8 @@ import java.io.*; import static io.anuke.mindustry.Vars.*; public class ItemTurret extends CooledTurret{ - protected int maxAmmo = 30; - protected ObjectMap ammo = new ObjectMap<>(); + public int maxAmmo = 30; + public ObjectMap ammo = new ObjectMap<>(); public ItemTurret(String name){ super(name); @@ -47,7 +47,7 @@ public class ItemTurret extends CooledTurret{ 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)), - () -> tile.entity != null && !((ItemTurretEntity)tile.entity).ammo.isEmpty() && ((ItemEntry)tile.entity().ammo.peek()).item == item))); + () -> tile.entity != null && !((ItemTurretEntity)tile.entity).ammo.isEmpty() && ((ItemEntry)tile.ent().ammo.peek()).item == item))); table.add(image).size(8 * 4); } @@ -79,7 +79,7 @@ public class ItemTurret extends CooledTurret{ public void displayBars(Tile tile, Table bars){ super.displayBars(tile, bars); - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); bars.add(new Bar("blocks.ammo", Pal.ammo, () -> (float)entity.totalAmmo / maxAmmo)).growX(); bars.row(); @@ -87,7 +87,7 @@ public class ItemTurret extends CooledTurret{ @Override public int acceptStack(Item item, int amount, Tile tile, Unit source){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); BulletType type = ammo.get(item); @@ -111,7 +111,7 @@ public class ItemTurret extends CooledTurret{ @Override public void handleItem(Item item, Tile tile, Tile source){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); if(entity == null) return; if(item == Items.pyratite){ @@ -144,7 +144,7 @@ public class ItemTurret extends CooledTurret{ @Override public boolean acceptItem(Item item, Tile tile, Tile source){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); return ammo != null && ammo.get(item) != null && entity.totalAmmo + ammo.get(item).ammoMultiplier <= maxAmmo; } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LaserTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LaserTurret.java index 2766e79724..422b5b57b8 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LaserTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LaserTurret.java @@ -14,8 +14,8 @@ import io.anuke.mindustry.world.meta.values.*; import static io.anuke.mindustry.Vars.tilesize; public class LaserTurret extends PowerTurret{ - protected float firingMoveFract = 0.25f; - protected float shootDuration = 100f; + public float firingMoveFract = 0.25f; + public float shootDuration = 100f; public LaserTurret(String name){ super(name); @@ -41,7 +41,7 @@ public class LaserTurret extends PowerTurret{ public void update(Tile tile){ super.update(tile); - LaserTurretEntity entity = tile.entity(); + LaserTurretEntity entity = tile.ent(); if(entity.bulletLife > 0 && entity.bullet != null){ tr.trns(entity.rotation, size * tilesize / 2f, 0f); @@ -59,7 +59,7 @@ public class LaserTurret extends PowerTurret{ @Override protected void updateShooting(Tile tile){ - LaserTurretEntity entity = tile.entity(); + LaserTurretEntity entity = tile.ent(); if(entity.bulletLife > 0 && entity.bullet != null){ return; @@ -87,14 +87,14 @@ public class LaserTurret extends PowerTurret{ @Override protected void turnToTarget(Tile tile, float targetRot){ - LaserTurretEntity entity = tile.entity(); + LaserTurretEntity entity = tile.ent(); entity.rotation = Angles.moveToward(entity.rotation, targetRot, rotatespeed * entity.delta() * (entity.bulletLife > 0f ? firingMoveFract : 1f)); } @Override protected void bullet(Tile tile, BulletType type, float angle){ - LaserTurretEntity entity = tile.entity(); + LaserTurretEntity entity = tile.ent(); entity.bullet = Bullet.create(type, tile.entity, tile.getTeam(), tile.drawx() + tr.x, tile.drawy() + tr.y, angle); entity.bulletLife = shootDuration; @@ -102,7 +102,7 @@ public class LaserTurret extends PowerTurret{ @Override public boolean shouldActiveSound(Tile tile){ - LaserTurretEntity entity = tile.entity(); + LaserTurretEntity entity = tile.ent(); return entity.bulletLife > 0 && entity.bullet != null; } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LiquidTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LiquidTurret.java index 28a33aa82a..7192ba09fe 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LiquidTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/LiquidTurret.java @@ -15,7 +15,7 @@ import io.anuke.mindustry.world.meta.values.*; import static io.anuke.mindustry.Vars.*; public class LiquidTurret extends Turret{ - protected ObjectMap ammo = new ObjectMap<>(); + public ObjectMap ammo = new ObjectMap<>(); public LiquidTurret(String name){ super(name); @@ -48,13 +48,13 @@ public class LiquidTurret extends Turret{ @Override public boolean shouldActiveSound(Tile tile){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); return entity.target != null && hasAmmo(tile); } @Override protected boolean validateTarget(Tile tile){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); if(entity.liquids.current().canExtinguish() && entity.target instanceof Tile){ return Fire.has(((Tile)entity.target).x, ((Tile)entity.target).y); } @@ -63,7 +63,7 @@ public class LiquidTurret extends Turret{ @Override protected void findTarget(Tile tile){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); if(entity.liquids.current().canExtinguish()){ int tr = (int)(range / tilesize); for(int x = -tr; x <= tr; x++){ @@ -83,7 +83,7 @@ public class LiquidTurret extends Turret{ protected void effects(Tile tile){ BulletType type = peekAmmo(tile); - TurretEntity entity = tile.entity(); + 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); @@ -98,7 +98,7 @@ public class LiquidTurret extends Turret{ @Override public BulletType useAmmo(Tile tile){ - TurretEntity entity = tile.entity(); + 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); @@ -112,7 +112,7 @@ public class LiquidTurret extends Turret{ @Override public boolean hasAmmo(Tile tile){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); return ammo.get(entity.liquids.current()) != null && entity.liquids.total() >= ammo.get(entity.liquids.current()).ammoMultiplier; } diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/PowerTurret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/PowerTurret.java index 7e4c54ace4..1eab2079a8 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/PowerTurret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/PowerTurret.java @@ -7,8 +7,8 @@ import io.anuke.mindustry.world.meta.BlockStat; import io.anuke.mindustry.world.meta.StatUnit; public class PowerTurret extends CooledTurret{ - protected @NonNull BulletType shootType; - protected float powerUse = 1f; + public @NonNull BulletType shootType; + public float powerUse = 1f; public PowerTurret(String name){ super(name); diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/Turret.java index 05edbe5091..e6c3b129d4 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/turrets/Turret.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/turrets/Turret.java @@ -28,40 +28,39 @@ import io.anuke.mindustry.world.meta.*; import static io.anuke.mindustry.Vars.tilesize; public abstract class Turret extends Block{ - protected static final int targetInterval = 20; + public final int timerTarget = timers++; + public int targetInterval = 20; - protected final int timerTarget = timers++; + public Color heatColor = Pal.turretHeat; + public Effect shootEffect = Fx.none; + public Effect smokeEffect = Fx.none; + public Effect ammoUseEffect = Fx.none; + public Sound shootSound = Sounds.shoot; - protected Color heatColor = Pal.turretHeat; - protected Effect shootEffect = Fx.none; - protected Effect smokeEffect = Fx.none; - protected Effect ammoUseEffect = Fx.none; - protected Sound shootSound = Sounds.shoot; - - protected int ammoPerShot = 1; - protected float ammoEjectBack = 1f; - protected float range = 50f; - protected float reload = 10f; - protected float inaccuracy = 0f; - protected int shots = 1; - protected float spread = 4f; - protected float recoil = 1f; - protected float restitution = 0.02f; - protected float cooldown = 0.02f; - protected float rotatespeed = 5f; //in degrees per tick - protected float shootCone = 8f; - protected float shootShake = 0f; - protected float xRand = 0f; - protected boolean targetAir = true; - protected boolean targetGround = true; + public int ammoPerShot = 1; + public float ammoEjectBack = 1f; + public float range = 50f; + public float reload = 10f; + public float inaccuracy = 0f; + public int shots = 1; + public float spread = 4f; + public float recoil = 1f; + public float restitution = 0.02f; + public float cooldown = 0.02f; + public float rotatespeed = 5f; //in degrees per tick + public float shootCone = 8f; + public float shootShake = 0f; + public float xRand = 0f; + public boolean targetAir = true; + public boolean targetGround = true; protected Vector2 tr = new Vector2(); protected Vector2 tr2 = new Vector2(); - protected TextureRegion baseRegion, heatRegion; + public TextureRegion baseRegion, heatRegion; - protected Cons2 drawer = (tile, entity) -> Draw.rect(region, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); - protected Cons2 heatDrawer = (tile, entity) -> { + public Cons2 drawer = (tile, entity) -> Draw.rect(region, tile.drawx() + tr2.x, tile.drawy() + tr2.y, entity.rotation - 90); + public Cons2 heatDrawer = (tile, entity) -> { if(entity.heat <= 0.00001f) return; Draw.color(heatColor, entity.heat); Draw.blend(Blending.additive); @@ -116,7 +115,7 @@ public abstract class Turret extends Block{ @Override public void drawLayer(Tile tile){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); tr2.trns(entity.rotation, -entity.recoil); @@ -144,7 +143,7 @@ public abstract class Turret extends Block{ @Override public void update(Tile tile){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); if(!validateTarget(tile)) entity.target = null; @@ -186,12 +185,12 @@ public abstract class Turret extends Block{ } protected boolean validateTarget(Tile tile){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); return !Units.invalidateTarget(entity.target, tile.getTeam(), tile.drawx(), tile.drawy()); } protected void findTarget(Tile tile){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); if(targetAir && !targetGround){ entity.target = Units.closestEnemy(tile.getTeam(), tile.drawx(), tile.drawy(), range, e -> !e.isDead() && e.isFlying()); @@ -201,7 +200,7 @@ public abstract class Turret extends Block{ } protected void turnToTarget(Tile tile, float targetRot){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); entity.rotation = Angles.moveToward(entity.rotation, targetRot, rotatespeed * entity.delta() * baseReloadSpeed(tile)); } @@ -214,7 +213,7 @@ public abstract class Turret extends Block{ public BulletType useAmmo(Tile tile){ if(tile.isEnemyCheat()) return peekAmmo(tile); - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); AmmoEntry entry = entity.ammo.peek(); entry.amount -= ammoPerShot; if(entry.amount == 0) entity.ammo.pop(); @@ -227,7 +226,7 @@ public abstract class Turret extends Block{ * Get the ammo type that will be returned if useAmmo is called. */ public BulletType peekAmmo(Tile tile){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); return entity.ammo.peek().type(); } @@ -235,12 +234,12 @@ public abstract class Turret extends Block{ * Returns whether the turret has ammo. */ public boolean hasAmmo(Tile tile){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); return entity.ammo.size > 0 && entity.ammo.peek().amount >= ammoPerShot; } protected void updateShooting(Tile tile){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); if(entity.reload >= reload){ BulletType type = peekAmmo(tile); @@ -254,7 +253,7 @@ public abstract class Turret extends Block{ } protected void shoot(Tile tile, BulletType type){ - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); entity.recoil = recoil; entity.heat = 1f; @@ -277,7 +276,7 @@ public abstract class Turret extends Block{ Effect shootEffect = this.shootEffect == Fx.none ? peekAmmo(tile).shootEffect : this.shootEffect; Effect smokeEffect = this.smokeEffect == Fx.none ? peekAmmo(tile).smokeEffect : this.smokeEffect; - TurretEntity entity = tile.entity(); + 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); @@ -292,7 +291,7 @@ public abstract class Turret extends Block{ protected void ejectEffects(Tile tile){ if(!isTurret(tile)) return; - TurretEntity entity = tile.entity(); + TurretEntity entity = tile.ent(); Effects.effect(ammoUseEffect, tile.drawx() - Angles.trnsx(entity.rotation, ammoEjectBack), tile.drawy() - Angles.trnsy(entity.rotation, ammoEjectBack), entity.rotation); diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/BufferedItemBridge.java b/core/src/io/anuke/mindustry/world/blocks/distribution/BufferedItemBridge.java index 4fc815676d..89b91cb50c 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/BufferedItemBridge.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/BufferedItemBridge.java @@ -7,10 +7,10 @@ import io.anuke.mindustry.world.*; import java.io.*; public class BufferedItemBridge extends ExtendingItemBridge{ - protected int timerAccept = timers++; + public final int timerAccept = timers++; - protected float speed = 40f; - protected int bufferCapacity = 50; + public float speed = 40f; + public int bufferCapacity = 50; public BufferedItemBridge(String name){ super(name); @@ -21,7 +21,7 @@ public class BufferedItemBridge extends ExtendingItemBridge{ @Override public void updateTransport(Tile tile, Tile other){ - BufferedItemBridgeEntity entity = tile.entity(); + BufferedItemBridgeEntity entity = tile.ent(); if(entity.buffer.accepts() && entity.items.total() > 0){ entity.buffer.accept(entity.items.take()); diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java b/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java index e05812d523..a3799def15 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/Conveyor.java @@ -32,7 +32,7 @@ public class Conveyor extends Block implements Autotiler{ private final Vector2 tr2 = new Vector2(); private TextureRegion[][] regions = new TextureRegion[7][4]; - protected float speed = 0f; + public float speed = 0f; protected Conveyor(String name){ super(name); @@ -75,7 +75,7 @@ public class Conveyor extends Block implements Autotiler{ @Override public void draw(Tile tile){ - ConveyorEntity entity = tile.entity(); + ConveyorEntity entity = tile.ent(); byte rotation = tile.rotation(); int frame = entity.clogHeat <= 0.5f ? (int)(((Time.time() * speed * 8f * entity.timeScale)) % 4) : 0; @@ -85,7 +85,7 @@ public class Conveyor extends Block implements Autotiler{ @Override public boolean shouldIdleSound(Tile tile){ - ConveyorEntity entity = tile.entity(); + ConveyorEntity entity = tile.ent(); return entity.clogHeat <= 0.5f ; } @@ -93,7 +93,7 @@ public class Conveyor extends Block implements Autotiler{ public void onProximityUpdate(Tile tile){ super.onProximityUpdate(tile); - ConveyorEntity entity = tile.entity(); + ConveyorEntity entity = tile.ent(); int[] bits = buildBlending(tile, tile.rotation(), null, true); entity.blendbits = bits[0]; entity.blendsclx = bits[1]; @@ -122,7 +122,7 @@ public class Conveyor extends Block implements Autotiler{ @Override public void drawLayer(Tile tile){ - ConveyorEntity entity = tile.entity(); + ConveyorEntity entity = tile.ent(); byte rotation = tile.rotation(); @@ -148,7 +148,7 @@ public class Conveyor extends Block implements Autotiler{ @Override public void unitOn(Tile tile, Unit unit){ - ConveyorEntity entity = tile.entity(); + ConveyorEntity entity = tile.ent(); if(entity.clogHeat > 0.5f){ return; @@ -178,12 +178,12 @@ public class Conveyor extends Block implements Autotiler{ @Override public void update(Tile tile){ - ConveyorEntity entity = tile.entity(); + ConveyorEntity entity = tile.ent(); entity.minitem = 1f; Tile next = tile.getNearby(tile.rotation()); if(next != null) next = next.link(); - float nextMax = next != null && next.block() instanceof Conveyor && next.block().acceptItem(null, next, tile) ? 1f - Math.max(itemSpace - next.entity().minitem, 0) : 1f; + 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; for(int i = entity.convey.size - 1; i >= 0; i--){ @@ -211,7 +211,7 @@ public class Conveyor extends Block implements Autotiler{ if(pos.y >= 0.9999f && offloadDir(tile, pos.item)){ if(next != null && next.block() instanceof Conveyor){ - ConveyorEntity othere = next.entity(); + ConveyorEntity othere = next.ent(); ItemPos ni = pos2.set(othere.convey.get(othere.lastInserted), ItemPos.updateShorts); @@ -263,7 +263,7 @@ public class Conveyor extends Block implements Autotiler{ @Override public int removeStack(Tile tile, Item item, int amount){ - ConveyorEntity entity = tile.entity(); + ConveyorEntity entity = tile.ent(); entity.noSleep(); int removed = 0; @@ -289,13 +289,13 @@ public class Conveyor extends Block implements Autotiler{ @Override public int acceptStack(Item item, int amount, Tile tile, Unit source){ - ConveyorEntity entity = tile.entity(); + 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.entity(); + ConveyorEntity entity = tile.ent(); for(int i = amount - 1; i >= 0; i--){ long result = ItemPos.packItem(item, 0f, i * itemSpace); @@ -309,7 +309,7 @@ public class Conveyor extends Block implements Autotiler{ @Override public boolean acceptItem(Item item, Tile tile, Tile source){ int direction = source == null ? 0 : Math.abs(source.relativeTo(tile.x, tile.y) - tile.rotation()); - float minitem = tile.entity().minitem; + 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())); } @@ -324,7 +324,7 @@ public class Conveyor extends Block implements Autotiler{ float pos = ch == 0 ? 0 : ch % 2 == 1 ? 0.5f : 1f; float y = (ang == -1 || ang == 3) ? 1 : (ang == 1 || ang == -3) ? -1 : 0; - ConveyorEntity entity = tile.entity(); + ConveyorEntity entity = tile.ent(); entity.noSleep(); long result = ItemPos.packItem(item, y * 0.9f, pos); diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/ExtendingItemBridge.java b/core/src/io/anuke/mindustry/world/blocks/distribution/ExtendingItemBridge.java index 3889a8078a..7a0a2b1d06 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/ExtendingItemBridge.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/ExtendingItemBridge.java @@ -16,7 +16,7 @@ public class ExtendingItemBridge extends ItemBridge{ @Override public void drawLayer(Tile tile){ - ItemBridgeEntity entity = tile.entity(); + ItemBridgeEntity entity = tile.ent(); Tile other = world.tile(entity.link); if(!linkValid(tile, other)) return; diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java b/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java index 0d692a504d..3624a1079b 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/ItemBridge.java @@ -20,12 +20,12 @@ import java.io.*; import static io.anuke.mindustry.Vars.*; public class ItemBridge extends Block{ - protected int timerTransport = timers++; - protected int range; - protected float transportTime = 2f; - protected TextureRegion endRegion, bridgeRegion, arrowRegion; - protected BuildRequest otherReq; + public final int timerTransport = timers++; + public int range; + public float transportTime = 2f; + public TextureRegion endRegion, bridgeRegion, arrowRegion; + private static BuildRequest otherReq; private static int lastPlaced = Pos.invalid; public ItemBridge(String name){ @@ -46,7 +46,7 @@ public class ItemBridge extends Block{ @Override public void configured(Tile tile, Player player, int value){ - tile.entity().link = value; + tile.ent().link = value; } @Override @@ -126,7 +126,7 @@ public class ItemBridge extends Block{ @Override public void drawConfigure(Tile tile){ - ItemBridgeEntity entity = tile.entity(); + ItemBridgeEntity entity = tile.ent(); Draw.color(Pal.accent); Lines.stroke(1f); @@ -151,7 +151,7 @@ public class ItemBridge extends Block{ @Override public boolean onConfigureTileTapped(Tile tile, Tile other){ - ItemBridgeEntity entity = tile.entity(); + ItemBridgeEntity entity = tile.ent(); if(linkValid(tile, other)){ if(entity.link == other.pos()){ @@ -166,7 +166,7 @@ public class ItemBridge extends Block{ @Override public void update(Tile tile){ - ItemBridgeEntity entity = tile.entity(); + ItemBridgeEntity entity = tile.ent(); entity.time += entity.cycleSpeed * entity.delta(); entity.time2 += (entity.cycleSpeed - 1f) * entity.delta(); @@ -175,7 +175,7 @@ public class ItemBridge extends Block{ while(it.hasNext){ int i = it.next(); Tile other = world.tile(i); - if(!linkValid(tile, other, false) || other.entity().link != tile.pos()){ + if(!linkValid(tile, other, false) || other.ent().link != tile.pos()){ it.remove(); } } @@ -198,7 +198,7 @@ public class ItemBridge extends Block{ } public void updateTransport(Tile tile, Tile other){ - ItemBridgeEntity entity = tile.entity(); + ItemBridgeEntity entity = tile.ent(); if(entity.uptime >= 0.5f && entity.timer.get(timerTransport, transportTime)){ Item item = entity.items.take(); @@ -214,7 +214,7 @@ public class ItemBridge extends Block{ @Override public void drawLayer(Tile tile){ - ItemBridgeEntity entity = tile.entity(); + ItemBridgeEntity entity = tile.ent(); Tile other = world.tile(entity.link); if(!linkValid(tile, other)) return; @@ -254,7 +254,7 @@ public class ItemBridge extends Block{ public boolean acceptItem(Item item, Tile tile, Tile source){ if(tile.getTeam() != source.getTeam()) return false; - ItemBridgeEntity entity = tile.entity(); + ItemBridgeEntity entity = tile.ent(); Tile other = world.tile(entity.link); if(linkValid(tile, other)){ @@ -263,7 +263,7 @@ public class ItemBridge extends Block{ if(rel == rel2) return false; }else{ - return source.block() instanceof ItemBridge && source.entity().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; @@ -272,7 +272,7 @@ public class ItemBridge extends Block{ @Override public boolean canDumpLiquid(Tile tile, Tile to, Liquid liquid){ - ItemBridgeEntity entity = tile.entity(); + ItemBridgeEntity entity = tile.ent(); Tile other = world.tile(entity.link); if(!linkValid(tile, other)){ @@ -300,7 +300,7 @@ public class ItemBridge extends Block{ public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ if(tile.getTeam() != source.getTeam() || !hasLiquids) return false; - ItemBridgeEntity entity = tile.entity(); + ItemBridgeEntity entity = tile.ent(); Tile other = world.tile(entity.link); if(linkValid(tile, other)){ @@ -308,7 +308,7 @@ public class ItemBridge extends Block{ int rel2 = tile.relativeTo(source.x, source.y); if(rel == rel2) return false; - }else if(!(source.block() instanceof ItemBridge && source.entity().link == tile.pos())){ + }else if(!(source.block() instanceof ItemBridge && source.ent().link == tile.pos())){ return false; } @@ -317,7 +317,7 @@ public class ItemBridge extends Block{ @Override public boolean canDump(Tile tile, Tile to, Item item){ - ItemBridgeEntity entity = tile.entity(); + ItemBridgeEntity entity = tile.ent(); Tile other = world.tile(entity.link); if(!linkValid(tile, other)){ @@ -355,7 +355,7 @@ public class ItemBridge extends Block{ return false; } - return other.block() == this && (!checkDouble || other.entity().link != tile.pos()); + return other.block() == this && (!checkDouble || other.ent().link != tile.pos()); } public static class ItemBridgeEntity extends TileEntity{ diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/Junction.java b/core/src/io/anuke/mindustry/world/blocks/distribution/Junction.java index 7877317185..45fea7b8a4 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/Junction.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/Junction.java @@ -17,8 +17,8 @@ import java.io.IOException; import static io.anuke.mindustry.Vars.content; public class Junction extends Block{ - protected float speed = 26; //frames taken to go through this junction - protected int capacity = 6; + public float speed = 26; //frames taken to go through this junction + public int capacity = 6; public Junction(String name){ super(name); @@ -42,7 +42,7 @@ public class Junction extends Block{ @Override public void update(Tile tile){ - JunctionEntity entity = tile.entity(); + JunctionEntity entity = tile.ent(); DirectionalItemBuffer buffer = entity.buffer; for(int i = 0; i < 4; i++){ @@ -72,14 +72,14 @@ public class Junction extends Block{ @Override public void handleItem(Item item, Tile tile, Tile source){ - JunctionEntity entity = tile.entity(); + JunctionEntity entity = tile.ent(); int relative = source.relativeTo(tile.x, tile.y); entity.buffer.accept(relative, item); } @Override public boolean acceptItem(Item item, Tile tile, Tile source){ - JunctionEntity entity = tile.entity(); + JunctionEntity entity = tile.ent(); int relative = source.relativeTo(tile.x, tile.y); if(entity == null || relative == -1 || !entity.buffer.accepts(relative)) diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java b/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java index c4a1aba990..1f75a716c8 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java @@ -20,17 +20,17 @@ import java.io.*; import static io.anuke.mindustry.Vars.*; public class MassDriver extends Block{ - protected float range; - protected float rotateSpeed = 0.04f; - protected float translation = 7f; - protected int minDistribute = 10; - protected float knockback = 4f; - protected float reloadTime = 100f; - protected Effect shootEffect = Fx.shootBig2; - protected Effect smokeEffect = Fx.shootBigSmoke2; - protected Effect recieveEffect = Fx.mineBig; - protected float shake = 3f; - protected TextureRegion baseRegion; + public float range; + public float rotateSpeed = 0.04f; + public float translation = 7f; + public int minDistribute = 10; + public float knockback = 4f; + public float reloadTime = 100f; + public Effect shootEffect = Fx.shootBig2; + public Effect smokeEffect = Fx.shootBigSmoke2; + public Effect recieveEffect = Fx.mineBig; + public float shake = 3f; + public TextureRegion baseRegion; public MassDriver(String name){ super(name); @@ -47,7 +47,7 @@ public class MassDriver extends Block{ @Override public void configured(Tile tile, Player player, int value){ - tile.entity().link = value; + tile.ent().link = value; } @Override @@ -64,7 +64,7 @@ public class MassDriver extends Block{ @Override public void update(Tile tile){ - MassDriverEntity entity = tile.entity(); + MassDriverEntity entity = tile.ent(); Tile link = world.tile(entity.link); boolean hasLink = linkValid(tile); @@ -120,7 +120,7 @@ public class MassDriver extends Block{ 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.entity(); + MassDriverEntity other = link.ent(); other.waitingShooters.add(tile); if(entity.reload <= 0.0001f){ @@ -152,7 +152,7 @@ public class MassDriver extends Block{ @Override public void drawLayer(Tile tile){ - MassDriverEntity entity = tile.entity(); + MassDriverEntity entity = tile.ent(); Draw.rect(region, tile.drawx() + Angles.trnsx(entity.rotation + 180f, entity.reload * knockback), @@ -172,7 +172,7 @@ public class MassDriver extends Block{ Lines.stroke(1f); Drawf.circles(tile.drawx(), tile.drawy(), (tile.block().size / 2f + 1) * tilesize + sin - 2f, Pal.accent); - MassDriverEntity entity = tile.entity(); + MassDriverEntity entity = tile.ent(); if(linkValid(tile)){ Tile target = world.tile(entity.link); @@ -187,7 +187,7 @@ public class MassDriver extends Block{ public boolean onConfigureTileTapped(Tile tile, Tile other){ if(tile == other) return false; - MassDriverEntity entity = tile.entity(); + MassDriverEntity entity = tile.ent(); if(entity.link == other.pos()){ tile.configure(-1); @@ -207,8 +207,8 @@ public class MassDriver extends Block{ } protected void fire(Tile tile, Tile target){ - MassDriverEntity entity = tile.entity(); - MassDriverEntity other = target.entity(); + MassDriverEntity entity = tile.ent(); + MassDriverEntity other = target.ent(); //reset reload, use power. entity.reload = 1f; @@ -264,13 +264,13 @@ public class MassDriver extends Block{ protected boolean shooterValid(Tile tile, Tile other){ if(other == null) return true; if(!(other.block() instanceof MassDriver)) return false; - MassDriverEntity entity = other.entity(); + MassDriverEntity entity = other.ent(); return entity.link == tile.pos() && tile.dst(other) <= range; } protected boolean linkValid(Tile tile){ if(tile == null) return false; - MassDriverEntity entity = tile.entity(); + MassDriverEntity entity = tile.ent(); if(entity == null || entity.link == -1) return false; Tile link = world.tile(entity.link); diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/OverflowGate.java b/core/src/io/anuke/mindustry/world/blocks/distribution/OverflowGate.java index b25635e005..a6c8f779ac 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/OverflowGate.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/OverflowGate.java @@ -10,7 +10,7 @@ import io.anuke.mindustry.world.meta.BlockGroup; import java.io.*; public class OverflowGate extends Block{ - protected float speed = 1f; + public float speed = 1f; public OverflowGate(String name){ super(name); @@ -29,7 +29,7 @@ public class OverflowGate extends Block{ @Override public int removeStack(Tile tile, Item item, int amount){ - OverflowGateEntity entity = tile.entity(); + OverflowGateEntity entity = tile.ent(); int result = super.removeStack(tile, item, amount); if(result != 0 && item == entity.lastItem){ entity.lastItem = null; @@ -39,7 +39,7 @@ public class OverflowGate extends Block{ @Override public void update(Tile tile){ - OverflowGateEntity entity = tile.entity(); + OverflowGateEntity entity = tile.ent(); if(entity.lastItem == null && entity.items.total() > 0){ entity.items.clear(); @@ -60,14 +60,14 @@ public class OverflowGate extends Block{ @Override public boolean acceptItem(Item item, Tile tile, Tile source){ - OverflowGateEntity entity = tile.entity(); + OverflowGateEntity entity = tile.ent(); return tile.getTeam() == source.getTeam() && entity.lastItem == null && entity.items.total() == 0; } @Override public void handleItem(Item item, Tile tile, Tile source){ - OverflowGateEntity entity = tile.entity(); + OverflowGateEntity entity = tile.ent(); entity.items.add(item, 1); entity.lastItem = item; entity.time = 0f; diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/Router.java b/core/src/io/anuke/mindustry/world/blocks/distribution/Router.java index fdff392743..1893af98e2 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/Router.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/Router.java @@ -9,7 +9,7 @@ import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.meta.BlockGroup; public class Router extends Block{ - protected float speed = 8f; + public float speed = 8f; public Router(String name){ super(name); @@ -24,7 +24,7 @@ public class Router extends Block{ @Override public void update(Tile tile){ - RouterEntity entity = tile.entity(); + RouterEntity entity = tile.ent(); if(entity.lastItem == null && entity.items.total() > 0){ entity.items.clear(); @@ -45,14 +45,14 @@ public class Router extends Block{ @Override public boolean acceptItem(Item item, Tile tile, Tile source){ - RouterEntity entity = tile.entity(); + RouterEntity entity = tile.ent(); return tile.getTeam() == source.getTeam() && entity.lastItem == null && entity.items.total() == 0; } @Override public void handleItem(Item item, Tile tile, Tile source){ - RouterEntity entity = tile.entity(); + RouterEntity entity = tile.ent(); entity.items.add(item, 1); entity.lastItem = item; entity.time = 0f; @@ -75,7 +75,7 @@ public class Router extends Block{ @Override public int removeStack(Tile tile, Item item, int amount){ - RouterEntity entity = tile.entity(); + RouterEntity entity = tile.ent(); int result = super.removeStack(tile, item, amount); if(result != 0 && item == entity.lastItem){ entity.lastItem = null; diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/Sorter.java b/core/src/io/anuke/mindustry/world/blocks/distribution/Sorter.java index 13eb1224e8..1794161654 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/Sorter.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/Sorter.java @@ -18,7 +18,7 @@ import static io.anuke.mindustry.Vars.content; public class Sorter extends Block{ private static Item lastItem; - protected boolean invert; + public boolean invert; public Sorter(String name){ super(name); @@ -45,7 +45,7 @@ public class Sorter extends Block{ @Override public void configured(Tile tile, Player player, int value){ - tile.entity().sortItem = content.item(value); + tile.ent().sortItem = content.item(value); } @Override @@ -57,7 +57,7 @@ public class Sorter extends Block{ public void draw(Tile tile){ super.draw(tile); - SorterEntity entity = tile.entity(); + SorterEntity entity = tile.ent(); if(entity.sortItem == null) return; Draw.color(entity.sortItem.color); @@ -67,7 +67,7 @@ public class Sorter extends Block{ @Override public int minimapColor(Tile tile){ - return tile.entity().sortItem == null ? 0 : tile.entity().sortItem.color.rgba(); + return tile.ent().sortItem == null ? 0 : tile.ent().sortItem.color.rgba(); } @Override @@ -89,7 +89,7 @@ public class Sorter extends Block{ } Tile getTileTarget(Item item, Tile dest, Tile source, boolean flip){ - SorterEntity entity = dest.entity(); + SorterEntity entity = dest.ent(); int dir = source.relativeTo(dest.x, dest.y); if(dir == -1) return null; @@ -130,8 +130,8 @@ public class Sorter extends Block{ } @Override - public void buildTable(Tile tile, Table table){ - SorterEntity entity = tile.entity(); + public void buildConfiguration(Tile tile, Table table){ + SorterEntity entity = tile.ent(); ItemSelection.buildItemTable(table, () -> entity.sortItem, item -> { lastItem = item; tile.configure(item == null ? -1 : item.id); diff --git a/core/src/io/anuke/mindustry/world/blocks/liquid/ArmoredConduit.java b/core/src/io/anuke/mindustry/world/blocks/liquid/ArmoredConduit.java index 7a50ef5f0a..d74087123c 100644 --- a/core/src/io/anuke/mindustry/world/blocks/liquid/ArmoredConduit.java +++ b/core/src/io/anuke/mindustry/world/blocks/liquid/ArmoredConduit.java @@ -9,7 +9,7 @@ import io.anuke.mindustry.world.Edges; import io.anuke.mindustry.world.Tile; public class ArmoredConduit extends Conduit{ - protected TextureRegion capRegion; + public TextureRegion capRegion; public ArmoredConduit(String name){ super(name); diff --git a/core/src/io/anuke/mindustry/world/blocks/liquid/Conduit.java b/core/src/io/anuke/mindustry/world/blocks/liquid/Conduit.java index 80c2ab5baf..0b6518b956 100644 --- a/core/src/io/anuke/mindustry/world/blocks/liquid/Conduit.java +++ b/core/src/io/anuke/mindustry/world/blocks/liquid/Conduit.java @@ -16,12 +16,12 @@ import io.anuke.mindustry.world.blocks.*; import io.anuke.mindustry.world.modules.*; public class Conduit extends LiquidBlock implements Autotiler{ - protected final int timerFlow = timers++; + public final int timerFlow = timers++; - protected TextureRegion[] topRegions = new TextureRegion[7]; - protected TextureRegion[] botRegions = new TextureRegion[7]; + public TextureRegion[] topRegions = new TextureRegion[7]; + public TextureRegion[] botRegions = new TextureRegion[7]; - protected float leakResistance = 1.5f; + public float leakResistance = 1.5f; public Conduit(String name){ super(name); @@ -47,7 +47,7 @@ public class Conduit extends LiquidBlock implements Autotiler{ public void onProximityUpdate(Tile tile){ super.onProximityUpdate(tile); - ConduitEntity entity = tile.entity(); + ConduitEntity entity = tile.ent(); int[] bits = buildBlending(tile, tile.rotation(), null, true); entity.blendbits = bits[0]; } @@ -91,7 +91,7 @@ public class Conduit extends LiquidBlock implements Autotiler{ @Override public void draw(Tile tile){ - ConduitEntity entity = tile.entity(); + ConduitEntity entity = tile.ent(); LiquidModule mod = tile.entity.liquids; int rotation = tile.rotation() * 90; @@ -108,7 +108,7 @@ public class Conduit extends LiquidBlock implements Autotiler{ @Override public void update(Tile tile){ - ConduitEntity entity = tile.entity(); + ConduitEntity entity = tile.ent(); entity.smoothLiquid = Mathf.lerpDelta(entity.smoothLiquid, entity.liquids.total() / liquidCapacity, 0.05f); if(tile.entity.liquids.total() > 0.001f && tile.entity.timer.get(timerFlow, 1)){ diff --git a/core/src/io/anuke/mindustry/world/blocks/liquid/LiquidBridge.java b/core/src/io/anuke/mindustry/world/blocks/liquid/LiquidBridge.java index f64a16ba80..5575d6d779 100644 --- a/core/src/io/anuke/mindustry/world/blocks/liquid/LiquidBridge.java +++ b/core/src/io/anuke/mindustry/world/blocks/liquid/LiquidBridge.java @@ -21,7 +21,7 @@ public class LiquidBridge extends ItemBridge{ @Override public void update(Tile tile){ - ItemBridgeEntity entity = tile.entity(); + ItemBridgeEntity entity = tile.ent(); entity.time += entity.cycleSpeed * Time.delta(); entity.time2 += (entity.cycleSpeed - 1f) * Time.delta(); diff --git a/core/src/io/anuke/mindustry/world/blocks/liquid/LiquidExtendingBridge.java b/core/src/io/anuke/mindustry/world/blocks/liquid/LiquidExtendingBridge.java index 8c82053b7f..1753e17d55 100644 --- a/core/src/io/anuke/mindustry/world/blocks/liquid/LiquidExtendingBridge.java +++ b/core/src/io/anuke/mindustry/world/blocks/liquid/LiquidExtendingBridge.java @@ -21,7 +21,7 @@ public class LiquidExtendingBridge extends ExtendingItemBridge{ @Override public void update(Tile tile){ - ItemBridgeEntity entity = tile.entity(); + ItemBridgeEntity entity = tile.ent(); entity.time += entity.cycleSpeed * Time.delta(); entity.time2 += (entity.cycleSpeed - 1f) * Time.delta(); diff --git a/core/src/io/anuke/mindustry/world/blocks/liquid/LiquidOverflowGate.java b/core/src/io/anuke/mindustry/world/blocks/liquid/LiquidOverflowGate.java index dafcef1508..3004835249 100644 --- a/core/src/io/anuke/mindustry/world/blocks/liquid/LiquidOverflowGate.java +++ b/core/src/io/anuke/mindustry/world/blocks/liquid/LiquidOverflowGate.java @@ -9,7 +9,7 @@ import io.anuke.mindustry.world.meta.*; //TODO implement later public class LiquidOverflowGate extends LiquidBlock{ - int topRegion; + public int topRegion; public LiquidOverflowGate(String name){ super(name); diff --git a/core/src/io/anuke/mindustry/world/blocks/logic/MessageBlock.java b/core/src/io/anuke/mindustry/world/blocks/logic/MessageBlock.java index 9b773c6356..0d00c50d09 100644 --- a/core/src/io/anuke/mindustry/world/blocks/logic/MessageBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/logic/MessageBlock.java @@ -61,7 +61,7 @@ public class MessageBlock extends Block{ } } - MessageBlockEntity entity = tile.entity(); + MessageBlockEntity entity = tile.ent(); if(entity != null){ entity.message = result.toString(); entity.lines = entity.message.split("\n"); @@ -70,7 +70,7 @@ public class MessageBlock extends Block{ @Override public void drawSelect(Tile tile){ - MessageBlockEntity entity = tile.entity(); + MessageBlockEntity entity = tile.ent(); BitmapFont font = Fonts.outline; GlyphLayout l = Pools.obtain(GlyphLayout.class, GlyphLayout::new); boolean ints = font.usesIntegerPositions(); @@ -95,8 +95,8 @@ public class MessageBlock extends Block{ } @Override - public void buildTable(Tile tile, Table table){ - MessageBlockEntity entity = tile.entity(); + public void buildConfiguration(Tile tile, Table table){ + MessageBlockEntity entity = tile.ent(); table.addImageButton(Icon.pencilSmall, () -> { if(mobile){ @@ -147,8 +147,8 @@ public class MessageBlock extends Block{ } public class MessageBlockEntity extends TileEntity{ - protected String message = ""; - protected String[] lines = {""}; + public String message = ""; + public String[] lines = {""}; @Override public void write(DataOutput stream) throws IOException{ diff --git a/core/src/io/anuke/mindustry/world/blocks/power/ImpactReactor.java b/core/src/io/anuke/mindustry/world/blocks/power/ImpactReactor.java index e1945f1609..e74eab58ef 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/ImpactReactor.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/ImpactReactor.java @@ -19,17 +19,17 @@ import java.io.*; import static io.anuke.mindustry.Vars.*; public class ImpactReactor extends PowerGenerator{ - protected int timerUse = timers++; + public final int timerUse = timers++; - protected int plasmas = 4; - protected float warmupSpeed = 0.001f; - protected float itemDuration = 60f; - protected int explosionRadius = 50; - protected int explosionDamage = 2000; + public int plasmas = 4; + public float warmupSpeed = 0.001f; + public float itemDuration = 60f; + public int explosionRadius = 50; + public int explosionDamage = 2000; - protected Color plasma1 = Color.valueOf("ffd06b"), plasma2 = Color.valueOf("ff361b"); - protected int bottomRegion; - protected int[] plasmaRegions; + public Color plasma1 = Color.valueOf("ffd06b"), plasma2 = Color.valueOf("ff361b"); + public int bottomRegion; + public int[] plasmaRegions; public ImpactReactor(String name){ super(name); @@ -69,7 +69,7 @@ public class ImpactReactor extends PowerGenerator{ @Override public void update(Tile tile){ - FusionReactorEntity entity = tile.entity(); + FusionReactorEntity entity = tile.ent(); if(entity.cons.valid() && entity.power.status >= 0.99f){ boolean prevOut = getPowerProduction(tile) <= consumes.getPower().requestedPower(entity); @@ -95,7 +95,7 @@ public class ImpactReactor extends PowerGenerator{ @Override public void draw(Tile tile){ - FusionReactorEntity entity = tile.entity(); + FusionReactorEntity entity = tile.ent(); Draw.rect(reg(bottomRegion), tile.drawx(), tile.drawy()); @@ -118,7 +118,7 @@ public class ImpactReactor extends PowerGenerator{ @Override public void drawLight(Tile tile){ - float fract = tile.entity().warmup; + float fract = tile.ent().warmup; renderer.lights.add(tile.drawx(), tile.drawy(), (110f + Mathf.absin(5, 5f)) * fract, Tmp.c1.set(plasma2).lerp(plasma1, Mathf.absin(7f, 0.2f)), 0.8f * fract); } @@ -131,7 +131,7 @@ public class ImpactReactor extends PowerGenerator{ public void onDestroyed(Tile tile){ super.onDestroyed(tile); - FusionReactorEntity entity = tile.entity(); + FusionReactorEntity entity = tile.ent(); if(entity.warmup < 0.4f || !state.rules.reactorExplosions) return; diff --git a/core/src/io/anuke/mindustry/world/blocks/power/ItemLiquidGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/ItemLiquidGenerator.java index 07effa5b30..c0c9e240cf 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/ItemLiquidGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/ItemLiquidGenerator.java @@ -20,20 +20,20 @@ import static io.anuke.mindustry.Vars.*; * Liquids will take priority over items. */ public class ItemLiquidGenerator extends PowerGenerator{ - protected float minItemEfficiency = 0.2f; + public float minItemEfficiency = 0.2f; /** The time in number of ticks during which a single item will produce power. */ - protected float itemDuration = 70f; + public float itemDuration = 70f; - protected float minLiquidEfficiency = 0.2f; + public float minLiquidEfficiency = 0.2f; /** Maximum liquid used per frame. */ - protected float maxLiquidGenerate = 0.4f; + public float maxLiquidGenerate = 0.4f; - protected Effect generateEffect = Fx.generatespark; - protected Effect explodeEffect = Fx.generatespark; - protected Color heatColor = Color.valueOf("ff9b59"); - protected TextureRegion topRegion, liquidRegion; - protected boolean randomlyExplode = true; - protected boolean defaults = false; + public Effect generateEffect = Fx.generatespark; + public Effect explodeEffect = Fx.generatespark; + public Color heatColor = Color.valueOf("ff9b59"); + public TextureRegion topRegion, liquidRegion; + public boolean randomlyExplode = true; + public boolean defaults = false; public ItemLiquidGenerator(boolean hasItems, boolean hasLiquids, String name){ this(name); @@ -87,13 +87,13 @@ public class ItemLiquidGenerator extends PowerGenerator{ @Override public boolean productionValid(Tile tile){ - ItemLiquidGeneratorEntity entity = tile.entity(); + ItemLiquidGeneratorEntity entity = tile.ent(); return entity.generateTime > 0; } @Override public void update(Tile tile){ - ItemLiquidGeneratorEntity entity = tile.entity(); + ItemLiquidGeneratorEntity entity = tile.ent(); //Note: Do not use this delta when calculating the amount of power or the power efficiency, but use it for resource consumption if necessary. //Power amount is delta'd by PowerGraph class already. @@ -120,7 +120,7 @@ public class ItemLiquidGenerator extends PowerGenerator{ float maximumPossible = maxLiquidGenerate * calculationDelta; float used = Math.min(entity.liquids.get(liquid) * calculationDelta, maximumPossible); - entity.liquids.remove(liquid, used); + entity.liquids.remove(liquid, used * entity.power.graph.getUsageFraction()); entity.productionEfficiency = baseLiquidEfficiency * used / maximumPossible; if(used > 0.001f && Mathf.chance(0.05 * entity.delta())){ @@ -137,7 +137,7 @@ public class ItemLiquidGenerator extends PowerGenerator{ } if(entity.generateTime > 0f){ - entity.generateTime -= Math.min(1f / itemDuration * entity.delta(), 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 @@ -156,7 +156,7 @@ public class ItemLiquidGenerator extends PowerGenerator{ public void draw(Tile tile){ super.draw(tile); - ItemLiquidGeneratorEntity entity = tile.entity(); + ItemLiquidGeneratorEntity entity = tile.ent(); if(hasItems){ Draw.color(heatColor); @@ -175,7 +175,7 @@ public class ItemLiquidGenerator extends PowerGenerator{ @Override public void drawLight(Tile tile){ - ItemLiquidGeneratorEntity entity = tile.entity(); + ItemLiquidGeneratorEntity entity = tile.ent(); renderer.lights.add(tile.drawx(), tile.drawy(), (60f + Mathf.absin(10f, 5f)) * entity.productionEfficiency * size, Color.orange, 0.5f); } diff --git a/core/src/io/anuke/mindustry/world/blocks/power/LightBlock.java b/core/src/io/anuke/mindustry/world/blocks/power/LightBlock.java index 0fc61676f2..989775dc40 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/LightBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/LightBlock.java @@ -16,9 +16,9 @@ import static io.anuke.mindustry.Vars.*; public class LightBlock extends Block{ private static int lastColor = 0; - protected float brightness = 0.9f; - protected float radius = 200f; - protected int topRegion; + public float brightness = 0.9f; + public float radius = 200f; + public int topRegion; public LightBlock(String name){ super(name); @@ -39,7 +39,7 @@ public class LightBlock extends Block{ @Override public void draw(Tile tile){ super.draw(tile); - LightEntity entity = tile.entity(); + LightEntity entity = tile.ent(); Draw.blend(Blending.additive); Draw.color(Tmp.c1.set(entity.color), entity.efficiency() * 0.3f); @@ -49,8 +49,8 @@ public class LightBlock extends Block{ } @Override - public void buildTable(Tile tile, Table table){ - LightEntity entity = tile.entity(); + public void buildConfiguration(Tile tile, Table table){ + LightEntity entity = tile.ent(); table.addImageButton(Icon.pencilSmall, () -> { ui.picker.show(Tmp.c1.set(entity.color).a(0.5f), false, res -> { @@ -63,12 +63,12 @@ public class LightBlock extends Block{ @Override public void configured(Tile tile, Player player, int value){ - tile.entity().color = value; + tile.ent().color = value; } @Override public void drawLight(Tile tile){ - LightEntity entity = tile.entity(); + LightEntity entity = tile.ent(); renderer.lights.add(tile.drawx(), tile.drawy(), radius, Tmp.c1.set(entity.color), brightness * tile.entity.efficiency()); } diff --git a/core/src/io/anuke/mindustry/world/blocks/power/NuclearReactor.java b/core/src/io/anuke/mindustry/world/blocks/power/NuclearReactor.java index 2aa478a3bf..5957a92ac6 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/NuclearReactor.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/NuclearReactor.java @@ -22,22 +22,22 @@ import java.io.*; import static io.anuke.mindustry.Vars.*; public class NuclearReactor extends PowerGenerator{ - protected final int timerFuel = timers++; + public final int timerFuel = timers++; - protected final Vector2 tr = new Vector2(); + public final Vector2 tr = new Vector2(); - protected Color lightColor = Color.valueOf("7f19ea"); - protected Color coolColor = new Color(1, 1, 1, 0f); - protected Color hotColor = Color.valueOf("ff9575a3"); - protected float itemDuration = 120; //time to consume 1 fuel - protected float heating = 0.01f; //heating per frame * fullness - protected float smokeThreshold = 0.3f; //threshold at which block starts smoking - protected int explosionRadius = 40; - protected int explosionDamage = 1350; - protected float flashThreshold = 0.46f; //heat threshold at which the lights start flashing - protected float coolantPower = 0.5f; + public Color lightColor = Color.valueOf("7f19ea"); + public Color coolColor = new Color(1, 1, 1, 0f); + public Color hotColor = Color.valueOf("ff9575a3"); + public float itemDuration = 120; //time to consume 1 fuel + public float heating = 0.01f; //heating per frame * fullness + public float smokeThreshold = 0.3f; //threshold at which block starts smoking + public int explosionRadius = 40; + public int explosionDamage = 1350; + public float flashThreshold = 0.46f; //heat threshold at which the lights start flashing + public float coolantPower = 0.5f; - protected TextureRegion topRegion, lightsRegion; + public TextureRegion topRegion, lightsRegion; public NuclearReactor(String name){ super(name); @@ -73,7 +73,7 @@ public class NuclearReactor extends PowerGenerator{ @Override public void update(Tile tile){ - NuclearReactorEntity entity = tile.entity(); + NuclearReactorEntity entity = tile.ent(); ConsumeLiquid cliquid = consumes.get(ConsumeType.liquid); Item item = consumes.get(ConsumeType.item).items[0].item; @@ -120,7 +120,7 @@ public class NuclearReactor extends PowerGenerator{ Sounds.explosionbig.at(tile); - NuclearReactorEntity entity = tile.entity(); + NuclearReactorEntity entity = tile.ent(); int fuel = entity.items.get(consumes.get(ConsumeType.item).items[0].item); @@ -151,7 +151,7 @@ public class NuclearReactor extends PowerGenerator{ @Override public void drawLight(Tile tile){ - NuclearReactorEntity entity = tile.entity(); + NuclearReactorEntity entity = tile.ent(); float fract = entity.productionEfficiency; renderer.lights.add(tile.drawx(), tile.drawy(), (90f + Mathf.absin(5, 5f)) * fract, Tmp.c1.set(lightColor).lerp(Color.scarlet, entity.heat), 0.6f * fract); } @@ -160,7 +160,7 @@ public class NuclearReactor extends PowerGenerator{ public void draw(Tile tile){ super.draw(tile); - NuclearReactorEntity entity = tile.entity(); + NuclearReactorEntity entity = tile.ent(); Draw.color(coolColor, hotColor, entity.heat); Fill.rect(tile.drawx(), tile.drawy(), size * tilesize, size * tilesize); diff --git a/core/src/io/anuke/mindustry/world/blocks/power/PowerDiode.java b/core/src/io/anuke/mindustry/world/blocks/power/PowerDiode.java index 08d621a09c..1dee0636a5 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/PowerDiode.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/PowerDiode.java @@ -13,7 +13,7 @@ import io.anuke.arc.graphics.g2d.TextureRegion; import io.anuke.mindustry.entities.traits.BuilderTrait; public class PowerDiode extends Block{ - protected TextureRegion arrow; + public TextureRegion arrow; public PowerDiode(String name){ super(name); @@ -50,7 +50,7 @@ public class PowerDiode extends Block{ } // battery % of the graph on either side, defaults to zero - protected float bar(Tile tile){ + public float bar(Tile tile){ return (tile != null && tile.block().hasPower) ? tile.entity.power.graph.getBatteryStored() / tile.entity.power.graph.getTotalBatteryCapacity() : 0f; } diff --git a/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java index a7bfe3da97..7612e9ff16 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/PowerGenerator.java @@ -13,7 +13,7 @@ import java.io.*; public class PowerGenerator extends PowerDistributor{ /** The amount of power produced per tick in case of an efficiency of 1.0, which represents 100%. */ - protected float powerProduction; + public float powerProduction; public BlockStat generationType = BlockStat.basePowerGeneration; public PowerGenerator(String name){ @@ -45,7 +45,7 @@ public class PowerGenerator extends PowerDistributor{ @Override public float getPowerProduction(Tile tile){ - return powerProduction * tile.entity().productionEfficiency; + return powerProduction * tile.ent().productionEfficiency; } @Override diff --git a/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java b/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java index b5d29266ac..43a782d2e8 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java @@ -19,7 +19,7 @@ public class PowerGraph{ private final ObjectSet all = new ObjectSet<>(); private final WindowedMean powerBalance = new WindowedMean(60); - private float lastPowerProduced, lastPowerNeeded; + private float lastPowerProduced, lastPowerNeeded, lastUsageFraction; private long lastFrameUpdated = -1; private final int graphID; @@ -54,6 +54,12 @@ public class PowerGraph{ return Mathf.clamp(lastPowerProduced / lastPowerNeeded); } + /** @return multiplier of speed at which resources should be consumed for power generation. */ + public float getUsageFraction(){ + //TODO enable it later, or not? + return 1f; //lastUsageFraction; + } + public float getPowerProduced(){ float powerProduced = 0f; for(Tile producer : producers){ @@ -180,7 +186,7 @@ public class PowerGraph{ tile.entity.power.status = 1f; } - lastPowerNeeded = lastPowerProduced = 1f; + lastPowerNeeded = lastPowerProduced = lastUsageFraction = 1f; return; } @@ -188,6 +194,7 @@ public class PowerGraph{ float powerNeeded = getPowerNeeded(); float powerProduced = getPowerProduced(); + float rawProduced = powerProduced; lastPowerNeeded = powerNeeded; lastPowerProduced = powerProduced; @@ -208,6 +215,12 @@ public class PowerGraph{ } powerBalance.addValue((lastPowerProduced - lastPowerNeeded) / Time.delta()); + + //overproducing: 10 / 20 = 0.5 + //underproducing: 20 / 10 = 2 -> clamp -> 1.0 + //nothing being produced: 20 / 0 -> 1.0 + //nothing being consumed: 0 / 20 -> 0.0 + lastUsageFraction = Mathf.zero(rawProduced) ? 1f : Mathf.clamp(powerNeeded / rawProduced); } public void add(PowerGraph graph){ @@ -296,7 +309,7 @@ public class PowerGraph{ private boolean otherConsumersAreValid(Tile tile, Consume consumePower){ for(Consume cons : tile.block().consumes.all()){ - if(cons != consumePower && !cons.isOptional() && !cons.valid(tile.entity())){ + if(cons != consumePower && !cons.isOptional() && !cons.valid(tile.ent())){ return false; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/power/PowerNode.java b/core/src/io/anuke/mindustry/world/blocks/power/PowerNode.java index 8c3002c417..bfd60a2cdb 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/PowerNode.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/PowerNode.java @@ -21,12 +21,12 @@ import static io.anuke.mindustry.Vars.*; public class PowerNode extends PowerBlock{ protected static boolean returnValue = false; - protected ObjectSet graphs = new ObjectSet<>(); - protected Vector2 t1 = new Vector2(), t2 = new Vector2(); - protected TextureRegion laser, laserEnd; + protected final ObjectSet graphs = new ObjectSet<>(); + protected final Vector2 t1 = new Vector2(), t2 = new Vector2(); - protected float laserRange = 6; - protected int maxNodes = 3; + public TextureRegion laser, laserEnd; + public float laserRange = 6; + public int maxNodes = 3; public PowerNode(String name){ super(name); @@ -108,7 +108,7 @@ public class PowerNode extends PowerBlock{ && !other.entity.proximity().contains(tile) && other.entity.power.graph != tile.entity.power.graph; tempTiles.clear(); - Geometry.circle(tile.x, tile.y, (int)(laserRange + 1), (x, y) -> { + Geometry.circle(tile.x, tile.y, (int)(laserRange + 2), (x, y) -> { Tile other = world.ltile(x, y); if(valid.get(other)){ if(!insulated(tile, other)){ @@ -139,7 +139,7 @@ public class PowerNode extends PowerBlock{ tempTiles.clear(); graphs.clear(); - Geometry.circle(tile.x, tile.y, (int)(laserRange + 1), (x, y) -> { + Geometry.circle(tile.x, tile.y, (int)(laserRange + 2), (x, y) -> { Tile other = world.ltile(x, y); if(valid.get(other) && !tempTiles.contains(other)){ tempTiles.add(other); @@ -172,7 +172,7 @@ public class PowerNode extends PowerBlock{ @Override public boolean onConfigureTileTapped(Tile tile, Tile other){ - TileEntity entity = tile.entity(); + TileEntity entity = tile.ent(); other = other.link(); if(linkValid(tile, other)){ @@ -183,7 +183,7 @@ public class PowerNode extends PowerBlock{ if(tile == other){ if(other.entity.power.links.size == 0){ getPotentialLinks(tile, link -> { - tile.configure(link.pos()); + if(!insulated(tile, link)) tile.configure(link.pos()); }); }else{ while(entity.power.links.size > 0){ @@ -220,8 +220,8 @@ public class PowerNode extends PowerBlock{ Lines.stroke(1.5f); - for(int x = (int)(tile.x - laserRange - 1); x <= tile.x + laserRange + 1; x++){ - for(int y = (int)(tile.y - laserRange - 1); y <= tile.y + laserRange + 1; y++){ + for(int x = (int)(tile.x - laserRange - 2); x <= tile.x + laserRange + 2; x++){ + for(int y = (int)(tile.y - laserRange - 2); y <= tile.y + laserRange + 2; y++){ Tile link = world.ltile(x, y); if(link != tile && linkValid(tile, link, false)){ @@ -262,7 +262,7 @@ public class PowerNode extends PowerBlock{ public void drawLayer(Tile tile){ if(Core.settings.getInt("lasersopacity") == 0) return; - TileEntity entity = tile.entity(); + TileEntity entity = tile.ent(); for(int i = 0; i < entity.power.links.size; i++){ Tile link = world.tile(entity.power.links.get(i)); diff --git a/core/src/io/anuke/mindustry/world/blocks/power/SolarGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/SolarGenerator.java index 4844fc2297..81712ba4bc 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/SolarGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/SolarGenerator.java @@ -17,7 +17,7 @@ public class SolarGenerator extends PowerGenerator{ @Override public void update(Tile tile){ - tile.entity().productionEfficiency = state.rules.lighting ? 1f - state.rules.ambientLight.a : 1f; + tile.ent().productionEfficiency = state.rules.lighting ? 1f - state.rules.ambientLight.a : 1f; } @Override diff --git a/core/src/io/anuke/mindustry/world/blocks/power/ThermalGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/ThermalGenerator.java index b2d9576718..61570c66df 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/ThermalGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/ThermalGenerator.java @@ -12,7 +12,7 @@ import io.anuke.mindustry.world.meta.*; import static io.anuke.mindustry.Vars.renderer; public class ThermalGenerator extends PowerGenerator{ - protected Effect generateEffect = Fx.none; + public Effect generateEffect = Fx.none; public ThermalGenerator(String name){ super(name); @@ -20,7 +20,7 @@ public class ThermalGenerator extends PowerGenerator{ @Override public void update(Tile tile){ - GeneratorEntity entity = tile.entity(); + 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)); @@ -34,7 +34,7 @@ public class ThermalGenerator extends PowerGenerator{ @Override public void drawLight(Tile tile){ - GeneratorEntity entity = tile.entity(); + GeneratorEntity entity = tile.ent(); renderer.lights.add(tile.drawx(), tile.drawy(), (40f + Mathf.absin(10f, 5f)) * entity.productionEfficiency * size, Color.scarlet, 0.4f); } @@ -42,7 +42,7 @@ public class ThermalGenerator extends PowerGenerator{ public void onProximityAdded(Tile tile){ super.onProximityAdded(tile); - GeneratorEntity entity = tile.entity(); + GeneratorEntity entity = tile.ent(); entity.productionEfficiency = sumAttribute(Attribute.heat, tile.x, tile.y); } @@ -50,7 +50,7 @@ public class ThermalGenerator extends PowerGenerator{ public float getPowerProduction(Tile tile){ //in this case, productionEfficiency means 'total heat' //thus, it may be greater than 1.0 - return powerProduction * tile.entity().productionEfficiency; + return powerProduction * tile.ent().productionEfficiency; } @Override diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Cultivator.java b/core/src/io/anuke/mindustry/world/blocks/production/Cultivator.java index c3901d435c..640f438b40 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Cultivator.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Cultivator.java @@ -16,14 +16,14 @@ import io.anuke.mindustry.world.meta.Attribute; import java.io.*; public class Cultivator extends GenericCrafter{ - protected static final Color plantColor = Color.valueOf("5541b1"); - protected static final Color plantColorLight = Color.valueOf("7457ce"); - protected static final Color bottomColor = Color.valueOf("474747"); + public Color plantColor = Color.valueOf("5541b1"); + public Color plantColorLight = Color.valueOf("7457ce"); + public Color bottomColor = Color.valueOf("474747"); - protected TextureRegion middleRegion, topRegion; - protected RandomXS128 random = new RandomXS128(0); - protected float recurrence = 6f; - protected Attribute attribute = Attribute.spores; + public TextureRegion middleRegion, topRegion; + public RandomXS128 random = new RandomXS128(0); + public float recurrence = 6f; + public Attribute attribute = Attribute.spores; public Cultivator(String name){ super(name); @@ -43,7 +43,7 @@ public class Cultivator extends GenericCrafter{ public void update(Tile tile){ super.update(tile); - CultivatorEntity entity = tile.entity(); + CultivatorEntity entity = tile.ent(); entity.warmup = Mathf.lerpDelta(entity.warmup, entity.cons.valid() ? 1f : 0f, 0.015f); } @@ -64,7 +64,7 @@ public class Cultivator extends GenericCrafter{ @Override public void draw(Tile tile){ - CultivatorEntity entity = tile.entity(); + CultivatorEntity entity = tile.ent(); Draw.rect(region, tile.drawx(), tile.drawy()); @@ -99,7 +99,7 @@ public class Cultivator extends GenericCrafter{ public void onProximityAdded(Tile tile){ super.onProximityAdded(tile); - CultivatorEntity entity = tile.entity(); + CultivatorEntity entity = tile.ent(); entity.boost = sumAttribute(attribute, tile.x, tile.y); } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Drill.java b/core/src/io/anuke/mindustry/world/blocks/production/Drill.java index 309761830b..1ef45a3c2f 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Drill.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Drill.java @@ -14,48 +14,46 @@ import io.anuke.mindustry.gen.*; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.type.*; import io.anuke.mindustry.ui.*; -import io.anuke.mindustry.ui.Cicon; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.meta.*; import static io.anuke.mindustry.Vars.*; public class Drill extends Block{ - protected final static float hardnessDrillMultiplier = 50f; + public float hardnessDrillMultiplier = 50f; protected final ObjectIntMap oreCount = new ObjectIntMap<>(); protected final Array itemArray = new Array<>(); /** Maximum tier of blocks this drill can mine. */ - protected int tier; + public int tier; /** Base time to drill one ore, in frames. */ - protected float drillTime = 300; + public float drillTime = 300; /** How many times faster the drill will progress when boosted by liquid. */ - protected float liquidBoostIntensity = 1.6f; + public float liquidBoostIntensity = 1.6f; /** Speed at which the drill speeds up. */ - protected float warmupSpeed = 0.02f; + public float warmupSpeed = 0.02f; //return variables for countOre protected Item returnItem; protected int returnCount; /** Whether to draw the item this drill is mining. */ - protected boolean drawMineItem = false; + public boolean drawMineItem = false; /** Effect played when an item is produced. This is colored. */ - protected Effect drillEffect = Fx.mine; + public Effect drillEffect = Fx.mine; /** Speed the drill bit rotates at. */ - protected float rotateSpeed = 2f; + public float rotateSpeed = 2f; /** Effect randomly played while drilling. */ - protected Effect updateEffect = Fx.pulverizeSmall; + public Effect updateEffect = Fx.pulverizeSmall; /** Chance the update effect will appear. */ - protected float updateEffectChance = 0.02f; + public float updateEffectChance = 0.02f; - protected boolean drawRim = false; - - protected Color heatColor = Color.valueOf("ff5512"); - protected TextureRegion rimRegion; - protected TextureRegion rotatorRegion; - protected TextureRegion topRegion; + public boolean drawRim = false; + public Color heatColor = Color.valueOf("ff5512"); + public TextureRegion rimRegion; + public TextureRegion rotatorRegion; + public TextureRegion topRegion; public Drill(String name){ super(name); @@ -99,7 +97,7 @@ public class Drill extends Block{ float s = 0.3f; float ts = 0.6f; - DrillEntity entity = tile.entity(); + DrillEntity entity = tile.ent(); Draw.rect(region, tile.drawx(), tile.drawy()); super.drawCracks(tile); @@ -164,7 +162,7 @@ public class Drill extends Block{ @Override public void drawSelect(Tile tile){ - DrillEntity entity = tile.entity(); + DrillEntity entity = tile.ent(); if(entity.dominantItem != null){ float dx = tile.drawx() - size * tilesize/2f, dy = tile.drawy() + size * tilesize/2f; @@ -180,23 +178,23 @@ public class Drill extends Block{ super.setStats(); stats.add(BlockStat.drillTier, table -> { - Array list = new Array<>(); + Array list = content.blocks().select(b -> b.isFloor() && b.asFloor().itemDrop != null && b.asFloor().itemDrop.hardness <= tier); - for(Item item : content.items()){ - if(tier >= item.hardness && Core.atlas.has(item.name + "1")){ - list.add(item); + table.table(l -> { + l.left(); + + for(int i = 0; i < list.size; i++){ + Block item = list.get(i); + + l.addImage(item.icon(Cicon.small)).size(8 * 3).padRight(2).padLeft(2).padTop(3).padBottom(3); + l.add(item.localizedName).left().padLeft(1).padRight(4); + if(i % 5 == 4){ + l.row(); + } } - } + }); - for(int i = 0; i < list.size; i++){ - Item item = list.get(i); - table.addImage(Core.atlas.find(item.name + "1")).size(8 * 3).padRight(2).padLeft(2).padTop(3).padBottom(3); - table.add(item.localizedName()); - if(i != list.size - 1){ - table.add("/").padLeft(5).padRight(5); - } - } }); stats.add(BlockStat.drillSpeed, 60f / drillTime * size * size, StatUnit.itemsSecond); @@ -240,7 +238,7 @@ public class Drill extends Block{ @Override public void update(Tile tile){ - DrillEntity entity = tile.entity(); + DrillEntity entity = tile.ent(); if(entity.dominantItem == null){ countOre(tile); diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Fracker.java b/core/src/io/anuke/mindustry/world/blocks/production/Fracker.java index deb606eedd..d70d8e878c 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Fracker.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Fracker.java @@ -6,11 +6,11 @@ import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.meta.*; public class Fracker extends SolidPump{ - protected final float itemUseTime = 100f; + public float itemUseTime = 100f; - protected TextureRegion liquidRegion; - protected TextureRegion rotatorRegion; - protected TextureRegion topRegion; + public TextureRegion liquidRegion; + public TextureRegion rotatorRegion; + public TextureRegion topRegion; public Fracker(String name){ super(name); @@ -49,7 +49,7 @@ public class Fracker extends SolidPump{ @Override public void draw(Tile tile){ - FrackerEntity entity = tile.entity(); + FrackerEntity entity = tile.ent(); Draw.rect(region, tile.drawx(), tile.drawy()); super.drawCracks(tile); @@ -70,7 +70,7 @@ public class Fracker extends SolidPump{ @Override public void update(Tile tile){ - FrackerEntity entity = tile.entity(); + FrackerEntity entity = tile.ent(); if(entity.cons.valid()){ if(entity.accumulator >= itemUseTime){ diff --git a/core/src/io/anuke/mindustry/world/blocks/production/GenericCrafter.java b/core/src/io/anuke/mindustry/world/blocks/production/GenericCrafter.java index 9f4c8c693d..00075370e4 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/GenericCrafter.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/GenericCrafter.java @@ -17,16 +17,16 @@ import io.anuke.mindustry.world.meta.*; import java.io.*; public class GenericCrafter extends Block{ - protected ItemStack outputItem; - protected LiquidStack outputLiquid; + public ItemStack outputItem; + public LiquidStack outputLiquid; - protected float craftTime = 80; - protected Effect craftEffect = Fx.none; - protected Effect updateEffect = Fx.none; - protected float updateEffectChance = 0.04f; + public float craftTime = 80; + public Effect craftEffect = Fx.none; + public Effect updateEffect = Fx.none; + public float updateEffectChance = 0.04f; - protected Cons drawer = null; - protected Prov drawIcons = null; + public Cons drawer = null; + public Prov drawIcons = null; public GenericCrafter(String name){ super(name); @@ -86,7 +86,7 @@ public class GenericCrafter extends Block{ @Override public void update(Tile tile){ - GenericCrafterEntity entity = tile.entity(); + GenericCrafterEntity entity = tile.ent(); if(entity.cons.valid()){ diff --git a/core/src/io/anuke/mindustry/world/blocks/production/GenericSmelter.java b/core/src/io/anuke/mindustry/world/blocks/production/GenericSmelter.java index 828decc1e0..3fe9e1eb7a 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/GenericSmelter.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/GenericSmelter.java @@ -11,8 +11,8 @@ import static io.anuke.mindustry.Vars.renderer; /** A GenericCrafter with a new glowing region drawn on top. */ public class GenericSmelter extends GenericCrafter{ - protected Color flameColor = Color.valueOf("ffc999"); - protected TextureRegion topRegion; + public Color flameColor = Color.valueOf("ffc999"); + public TextureRegion topRegion; public GenericSmelter(String name){ super(name); @@ -28,7 +28,7 @@ public class GenericSmelter extends GenericCrafter{ public void draw(Tile tile){ super.draw(tile); - GenericCrafterEntity entity = tile.entity(); + GenericCrafterEntity entity = tile.ent(); //draw glowing center if(entity.warmup > 0f && flameColor.a > 0.001f){ @@ -50,7 +50,7 @@ public class GenericSmelter extends GenericCrafter{ @Override public void drawLight(Tile tile){ - GenericCrafterEntity entity = tile.entity(); + GenericCrafterEntity entity = tile.ent(); renderer.lights.add(tile.drawx(), tile.drawy(), (60f + Mathf.absin(10f, 5f)) * entity.warmup * size, flameColor, 0.65f); } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Incinerator.java b/core/src/io/anuke/mindustry/world/blocks/production/Incinerator.java index fce368f246..656476c4d8 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Incinerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Incinerator.java @@ -15,8 +15,8 @@ import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; public class Incinerator extends Block{ - protected Effect effect = Fx.fuelburn; - protected Color flameColor = Color.valueOf("ffad9d"); + public Effect effect = Fx.fuelburn; + public Color flameColor = Color.valueOf("ffad9d"); public Incinerator(String name){ super(name); @@ -29,7 +29,7 @@ public class Incinerator extends Block{ @Override public void update(Tile tile){ - IncineratorEntity entity = tile.entity(); + IncineratorEntity entity = tile.ent(); if(entity.cons.valid()){ entity.heat = Mathf.lerpDelta(entity.heat, 1f, 0.04f); @@ -42,7 +42,7 @@ public class Incinerator extends Block{ public void draw(Tile tile){ super.draw(tile); - IncineratorEntity entity = tile.entity(); + IncineratorEntity entity = tile.ent(); if(entity.heat > 0f){ float g = 0.3f; @@ -68,7 +68,7 @@ public class Incinerator extends Block{ @Override public boolean acceptItem(Item item, Tile tile, Tile source){ - IncineratorEntity entity = tile.entity(); + IncineratorEntity entity = tile.ent(); return entity.heat > 0.5f; } @@ -81,7 +81,7 @@ public class Incinerator extends Block{ @Override public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){ - IncineratorEntity entity = tile.entity(); + IncineratorEntity entity = tile.ent(); return entity.heat > 0.5f; } diff --git a/core/src/io/anuke/mindustry/world/blocks/production/LiquidConverter.java b/core/src/io/anuke/mindustry/world/blocks/production/LiquidConverter.java index 6908ad4176..95fdc2184f 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/LiquidConverter.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/LiquidConverter.java @@ -41,7 +41,7 @@ public class LiquidConverter extends GenericCrafter{ @Override public void update(Tile tile){ - GenericCrafterEntity entity = tile.entity(); + GenericCrafterEntity entity = tile.ent(); ConsumeLiquidBase cl = consumes.get(ConsumeType.liquid); if(tile.entity.cons.valid()){ diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Pump.java b/core/src/io/anuke/mindustry/world/blocks/production/Pump.java index 9b91d8b98f..9142cc49af 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Pump.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Pump.java @@ -19,7 +19,7 @@ public class Pump extends LiquidBlock{ protected final Array drawTiles = new Array<>(); protected final Array updateTiles = new Array<>(); - protected final int timerContentCheck = timers++; + public final int timerContentCheck = timers++; /** Pump amount, total. */ protected float pumpAmount = 1f; diff --git a/core/src/io/anuke/mindustry/world/blocks/production/Separator.java b/core/src/io/anuke/mindustry/world/blocks/production/Separator.java index bd3f98966b..c297851e67 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/Separator.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/Separator.java @@ -64,7 +64,7 @@ public class Separator extends Block{ public void draw(Tile tile){ super.draw(tile); - GenericCrafterEntity entity = tile.entity(); + GenericCrafterEntity entity = tile.ent(); Draw.color(tile.entity.liquids.current().color); Draw.alpha(tile.entity.liquids.total() / liquidCapacity); @@ -78,7 +78,7 @@ public class Separator extends Block{ @Override public void update(Tile tile){ - GenericCrafterEntity entity = tile.entity(); + GenericCrafterEntity entity = tile.ent(); entity.totalProgress += entity.warmup * entity.delta(); diff --git a/core/src/io/anuke/mindustry/world/blocks/production/SolidPump.java b/core/src/io/anuke/mindustry/world/blocks/production/SolidPump.java index bb6cb397cf..e7ac5b0c14 100644 --- a/core/src/io/anuke/mindustry/world/blocks/production/SolidPump.java +++ b/core/src/io/anuke/mindustry/world/blocks/production/SolidPump.java @@ -20,12 +20,12 @@ import io.anuke.mindustry.world.meta.BlockStat; * Pump that makes liquid from solids and takes in power. Only works on solid floor blocks. */ public class SolidPump extends Pump{ - protected Liquid result = Liquids.water; - protected Effect updateEffect = Fx.none; - protected float updateEffectChance = 0.02f; - protected float rotateSpeed = 1f; + public Liquid result = Liquids.water; + public Effect updateEffect = Fx.none; + public float updateEffectChance = 0.02f; + public float rotateSpeed = 1f; /** Attribute that is checked when calculating output. */ - protected Attribute attribute; + public Attribute attribute; public SolidPump(String name){ super(name); @@ -67,7 +67,7 @@ public class SolidPump extends Pump{ @Override public void draw(Tile tile){ - SolidPumpEntity entity = tile.entity(); + SolidPumpEntity entity = tile.ent(); Draw.rect(region, tile.drawx(), tile.drawy()); Draw.color(tile.entity.liquids.current().color); @@ -85,7 +85,7 @@ public class SolidPump extends Pump{ @Override public void update(Tile tile){ - SolidPumpEntity entity = tile.entity(); + SolidPumpEntity entity = tile.ent(); float fraction = 0f; @@ -140,7 +140,7 @@ public class SolidPump extends Pump{ super.onProximityAdded(tile); if(attribute != null){ - SolidPumpEntity entity = tile.entity(); + SolidPumpEntity entity = tile.ent(); entity.boost = sumAttribute(attribute, tile.x, tile.y); } } diff --git a/core/src/io/anuke/mindustry/world/blocks/sandbox/ItemSource.java b/core/src/io/anuke/mindustry/world/blocks/sandbox/ItemSource.java index d38c9dc432..46e1e86ee2 100644 --- a/core/src/io/anuke/mindustry/world/blocks/sandbox/ItemSource.java +++ b/core/src/io/anuke/mindustry/world/blocks/sandbox/ItemSource.java @@ -30,7 +30,7 @@ public class ItemSource extends Block{ @Override public void configured(Tile tile, Player player, int value){ - tile.entity().outputItem = content.item(value); + tile.ent().outputItem = content.item(value); } @Override @@ -60,7 +60,7 @@ public class ItemSource extends Block{ public void draw(Tile tile){ super.draw(tile); - ItemSourceEntity entity = tile.entity(); + ItemSourceEntity entity = tile.ent(); if(entity.outputItem == null) return; Draw.color(entity.outputItem.color); @@ -70,7 +70,7 @@ public class ItemSource extends Block{ @Override public void update(Tile tile){ - ItemSourceEntity entity = tile.entity(); + ItemSourceEntity entity = tile.ent(); if(entity.outputItem == null) return; entity.items.set(entity.outputItem, 1); @@ -79,8 +79,8 @@ public class ItemSource extends Block{ } @Override - public void buildTable(Tile tile, Table table){ - ItemSourceEntity entity = tile.entity(); + public void buildConfiguration(Tile tile, Table table){ + ItemSourceEntity entity = tile.ent(); ItemSelection.buildItemTable(table, () -> entity.outputItem, item -> { lastItem = item; tile.configure(item == null ? -1 : item.id); diff --git a/core/src/io/anuke/mindustry/world/blocks/sandbox/LiquidSource.java b/core/src/io/anuke/mindustry/world/blocks/sandbox/LiquidSource.java index 5513f462ec..ac260679a7 100644 --- a/core/src/io/anuke/mindustry/world/blocks/sandbox/LiquidSource.java +++ b/core/src/io/anuke/mindustry/world/blocks/sandbox/LiquidSource.java @@ -21,7 +21,7 @@ import java.io.*; import static io.anuke.mindustry.Vars.*; public class LiquidSource extends Block{ - private static Liquid lastLiquid; + public static Liquid lastLiquid; public LiquidSource(String name){ super(name); @@ -50,7 +50,7 @@ public class LiquidSource extends Block{ @Override public void update(Tile tile){ - LiquidSourceEntity entity = tile.entity(); + LiquidSourceEntity entity = tile.ent(); if(entity.source == null){ tile.entity.liquids.clear(); @@ -69,7 +69,7 @@ public class LiquidSource extends Block{ public void draw(Tile tile){ super.draw(tile); - LiquidSourceEntity entity = tile.entity(); + LiquidSourceEntity entity = tile.ent(); if(entity.source != null){ Draw.color(entity.source.color); @@ -79,8 +79,8 @@ public class LiquidSource extends Block{ } @Override - public void buildTable(Tile tile, Table table){ - LiquidSourceEntity entity = tile.entity(); + public void buildConfiguration(Tile tile, Table table){ + LiquidSourceEntity entity = tile.ent(); Array items = content.liquids(); @@ -109,7 +109,7 @@ public class LiquidSource extends Block{ @Override public void configured(Tile tile, Player player, int value){ - tile.entity().source = value == -1 ? null : content.liquid(value); + tile.ent().source = value == -1 ? null : content.liquid(value); } class LiquidSourceEntity extends TileEntity{ diff --git a/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java b/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java index c164e7011e..557dddce45 100644 --- a/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/storage/CoreBlock.java @@ -24,7 +24,7 @@ import io.anuke.mindustry.world.modules.*; import static io.anuke.mindustry.Vars.*; public class CoreBlock extends StorageBlock{ - protected Mech mech = Mechs.starter; + public Mech mech = Mechs.starter; public CoreBlock(String name){ super(name); @@ -43,7 +43,7 @@ public class CoreBlock extends StorageBlock{ public static void onUnitRespawn(Tile tile, Player player){ if(player == null || tile.entity == null) return; - CoreEntity entity = tile.entity(); + CoreEntity entity = tile.ent(); Effects.effect(Fx.spawn, entity); entity.progress = 0; entity.spawnPlayer = player; @@ -76,13 +76,13 @@ public class CoreBlock extends StorageBlock{ @Override public int getMaximumAccepted(Tile tile, Item item){ - CoreEntity entity = tile.entity(); + CoreEntity entity = tile.ent(); return item.type == ItemType.material ? entity.storageCapacity : 0; } @Override public void onProximityUpdate(Tile tile){ - CoreEntity entity = tile.entity(); + CoreEntity entity = tile.ent(); for(Tile other : state.teams.get(tile.getTeam()).cores){ if(other != tile){ @@ -94,7 +94,7 @@ public class CoreBlock extends StorageBlock{ 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().linkedCore = tile; + t.ent().linkedCore = tile; }); for(Tile other : state.teams.get(tile.getTeam()).cores){ @@ -109,7 +109,7 @@ public class CoreBlock extends StorageBlock{ } for(Tile other : state.teams.get(tile.getTeam()).cores){ - CoreEntity oe = other.entity(); + CoreEntity oe = other.ent(); oe.storageCapacity = entity.storageCapacity; } } @@ -183,7 +183,7 @@ public class CoreBlock extends StorageBlock{ @Override public void drawLayer(Tile tile){ - CoreEntity entity = tile.entity(); + CoreEntity entity = tile.ent(); if(entity.heat > 0.001f){ RespawnBlock.drawRespawn(tile, entity.heat, entity.progress, entity.time, entity.spawnPlayer, mech); @@ -202,7 +202,7 @@ public class CoreBlock extends StorageBlock{ @Override public void update(Tile tile){ - CoreEntity entity = tile.entity(); + CoreEntity entity = tile.ent(); if(entity.spawnPlayer != null){ if(!entity.spawnPlayer.isDead() || !entity.spawnPlayer.isAdded()){ @@ -225,7 +225,7 @@ public class CoreBlock extends StorageBlock{ @Override public boolean shouldActiveSound(Tile tile){ - CoreEntity entity = tile.entity(); + CoreEntity entity = tile.ent(); return entity.spawnPlayer != null; } diff --git a/core/src/io/anuke/mindustry/world/blocks/storage/LaunchPad.java b/core/src/io/anuke/mindustry/world/blocks/storage/LaunchPad.java index 47973a9a8b..92aa7ae75c 100644 --- a/core/src/io/anuke/mindustry/world/blocks/storage/LaunchPad.java +++ b/core/src/io/anuke/mindustry/world/blocks/storage/LaunchPad.java @@ -21,9 +21,9 @@ import static io.anuke.mindustry.Vars.data; import static io.anuke.mindustry.Vars.world; public class LaunchPad extends StorageBlock{ - protected final int timerLaunch = timers++; + public final int timerLaunch = timers++; /** Time inbetween launches. */ - protected float launchTime; + public float launchTime; public LaunchPad(String name){ super(name); diff --git a/core/src/io/anuke/mindustry/world/blocks/storage/StorageBlock.java b/core/src/io/anuke/mindustry/world/blocks/storage/StorageBlock.java index 7746932916..710f97fbe3 100644 --- a/core/src/io/anuke/mindustry/world/blocks/storage/StorageBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/storage/StorageBlock.java @@ -16,7 +16,7 @@ public abstract class StorageBlock extends Block{ @Override public boolean acceptItem(Item item, Tile tile, Tile source){ - StorageBlockEntity entity = tile.entity(); + StorageBlockEntity entity = tile.ent(); return entity.linkedCore != null ? entity.linkedCore.block().acceptItem(item, entity.linkedCore, source) : tile.entity.items.get(item) < getMaximumAccepted(tile, item); } @@ -27,7 +27,7 @@ public abstract class StorageBlock extends Block{ @Override public void drawSelect(Tile tile){ - StorageBlockEntity entity = tile.entity(); + StorageBlockEntity entity = tile.ent(); if(entity.linkedCore != null){ entity.linkedCore.block().drawSelect(entity.linkedCore); } diff --git a/core/src/io/anuke/mindustry/world/blocks/storage/Unloader.java b/core/src/io/anuke/mindustry/world/blocks/storage/Unloader.java index f67701d4d5..8186ade094 100644 --- a/core/src/io/anuke/mindustry/world/blocks/storage/Unloader.java +++ b/core/src/io/anuke/mindustry/world/blocks/storage/Unloader.java @@ -15,8 +15,8 @@ import java.io.*; import static io.anuke.mindustry.Vars.content; public class Unloader extends Block{ - protected float speed = 1f; - protected final int timerUnload = timers++; + public float speed = 1f; + public final int timerUnload = timers++; private static Item lastItem; @@ -56,12 +56,12 @@ public class Unloader extends Block{ @Override public void configured(Tile tile, Player player, int value){ tile.entity.items.clear(); - tile.entity().sortItem = content.item(value); + tile.ent().sortItem = content.item(value); } @Override public void update(Tile tile){ - UnloaderEntity entity = tile.entity(); + UnloaderEntity entity = tile.ent(); if(tile.entity.timer.get(timerUnload, speed / entity.timeScale) && tile.entity.items.total() == 0){ for(Tile other : tile.entity.proximity()){ @@ -113,7 +113,7 @@ public class Unloader extends Block{ public void draw(Tile tile){ super.draw(tile); - UnloaderEntity entity = tile.entity(); + UnloaderEntity entity = tile.ent(); Draw.color(entity.sortItem == null ? Color.clear : entity.sortItem.color); Draw.rect("unloader-center", tile.worldx(), tile.worldy()); @@ -121,8 +121,8 @@ public class Unloader extends Block{ } @Override - public void buildTable(Tile tile, Table table){ - UnloaderEntity entity = tile.entity(); + public void buildConfiguration(Tile tile, Table table){ + UnloaderEntity entity = tile.ent(); ItemSelection.buildItemTable(table, () -> entity.sortItem, item -> { lastItem = item; tile.configure(item == null ? -1 : item.id); diff --git a/core/src/io/anuke/mindustry/world/blocks/units/CommandCenter.java b/core/src/io/anuke/mindustry/world/blocks/units/CommandCenter.java index d44b966493..9423ac6cae 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/CommandCenter.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/CommandCenter.java @@ -45,8 +45,8 @@ public class CommandCenter extends Block{ ObjectSet set = indexer.getAllied(tile.getTeam(), BlockFlag.comandCenter); if(set.size > 0){ - CommandCenterEntity entity = tile.entity(); - CommandCenterEntity oe = set.first().entity(); + CommandCenterEntity entity = tile.ent(); + CommandCenterEntity oe = set.first().ent(); entity.command = oe.command; } } @@ -75,7 +75,7 @@ public class CommandCenter extends Block{ @Override public void draw(Tile tile){ - CommandCenterEntity entity = tile.entity(); + CommandCenterEntity entity = tile.ent(); super.draw(tile); float size = IconSize.small.size/4f; @@ -88,8 +88,8 @@ public class CommandCenter extends Block{ } @Override - public void buildTable(Tile tile, Table table){ - CommandCenterEntity entity = tile.entity(); + public void buildConfiguration(Tile tile, Table table){ + CommandCenterEntity entity = tile.ent(); ButtonGroup group = new ButtonGroup<>(); Table buttons = new Table(); @@ -109,7 +109,7 @@ public class CommandCenter extends Block{ for(Tile center : indexer.getAllied(tile.getTeam(), BlockFlag.comandCenter)){ if(center.block() instanceof CommandCenter){ - CommandCenterEntity entity = center.entity(); + CommandCenterEntity entity = center.ent(); entity.command = command; } } diff --git a/core/src/io/anuke/mindustry/world/blocks/units/MechPad.java b/core/src/io/anuke/mindustry/world/blocks/units/MechPad.java index ef7314e00b..54bc28fb03 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/MechPad.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/MechPad.java @@ -26,7 +26,7 @@ import static io.anuke.mindustry.Vars.*; public class MechPad extends Block{ public @NonNull Mech mech; - protected float buildTime = 60 * 5; + public float buildTime = 60 * 5; public MechPad(String name){ super(name); @@ -47,9 +47,9 @@ public class MechPad extends Block{ @Remote(targets = Loc.both, called = Loc.server) public static void onMechFactoryTap(Player player, Tile tile){ - if(player == null || !(tile.block() instanceof MechPad) || !checkValidTap(tile, player)) return; + if(player == null || tile == null || !(tile.block() instanceof MechPad) || !checkValidTap(tile, player)) return; - MechFactoryEntity entity = tile.entity(); + MechFactoryEntity entity = tile.ent(); if(!entity.cons.valid()) return; player.beginRespawning(entity); @@ -60,7 +60,7 @@ public class MechPad extends Block{ public static void onMechFactoryDone(Tile tile){ if(!(tile.entity instanceof MechFactoryEntity)) return; - MechFactoryEntity entity = tile.entity(); + MechFactoryEntity entity = tile.ent(); Effects.effect(Fx.spawn, entity); @@ -80,7 +80,7 @@ public class MechPad extends Block{ } protected static boolean checkValidTap(Tile tile, Player player){ - MechFactoryEntity entity = tile.entity(); + 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; } @@ -97,7 +97,7 @@ public class MechPad extends Block{ @Override public void tapped(Tile tile, Player player){ - MechFactoryEntity entity = tile.entity(); + MechFactoryEntity entity = tile.ent(); if(checkValidTap(tile, player)){ Call.onMechFactoryTap(player, tile); @@ -109,7 +109,7 @@ public class MechPad extends Block{ @Override public void drawLayer(Tile tile){ - MechFactoryEntity entity = tile.entity(); + 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 ? mech : Mechs.starter)); @@ -118,7 +118,7 @@ public class MechPad extends Block{ @Override public void update(Tile tile){ - MechFactoryEntity entity = tile.entity(); + MechFactoryEntity entity = tile.ent(); if(entity.player != null){ entity.player.set(tile.drawx(), tile.drawy()); diff --git a/core/src/io/anuke/mindustry/world/blocks/units/RepairPoint.java b/core/src/io/anuke/mindustry/world/blocks/units/RepairPoint.java index 6c5e8698b2..11b8fd89e6 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/RepairPoint.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/RepairPoint.java @@ -14,18 +14,20 @@ import io.anuke.mindustry.entities.type.Unit; import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; -import io.anuke.mindustry.world.meta.BlockFlag; +import io.anuke.mindustry.world.meta.*; + +import static io.anuke.mindustry.Vars.tilesize; public class RepairPoint extends Block{ private static Rectangle rect = new Rectangle(); - protected int timerTarget = timers++; + public int timerTarget = timers++; - protected float repairRadius = 50f; - protected float repairSpeed = 0.3f; - protected float powerUse; - protected TextureRegion baseRegion; - protected TextureRegion laser, laserEnd; + public float repairRadius = 50f; + public float repairSpeed = 0.3f; + public float powerUse; + public TextureRegion baseRegion; + public TextureRegion laser, laserEnd; public RepairPoint(String name){ super(name); @@ -48,6 +50,12 @@ public class RepairPoint extends Block{ laserEnd = Core.atlas.find("laser-end"); } + @Override + public void setStats(){ + super.setStats(); + stats.add(BlockStat.range, repairRadius / tilesize, StatUnit.blocks); + } + @Override public void init(){ consumes.powerCond(powerUse, entity -> ((RepairPointEntity)entity).target != null); @@ -59,6 +67,11 @@ public class RepairPoint extends Block{ Drawf.dashCircle(tile.drawx(), tile.drawy(), repairRadius, Pal.accent); } + @Override + public void drawPlace(int x, int y, int rotation, boolean valid){ + Drawf.dashCircle(x * tilesize + offset(), y * tilesize + offset(), repairRadius, Pal.accent); + } + @Override public void draw(Tile tile){ Draw.rect(baseRegion, tile.drawx(), tile.drawy()); @@ -66,14 +79,14 @@ public class RepairPoint extends Block{ @Override public void drawLayer(Tile tile){ - RepairPointEntity entity = tile.entity(); + RepairPointEntity entity = tile.ent(); Draw.rect(region, tile.drawx(), tile.drawy(), entity.rotation - 90); } @Override public void drawLayer2(Tile tile){ - RepairPointEntity entity = tile.entity(); + RepairPointEntity entity = tile.ent(); if(entity.target != null && Angles.angleDist(entity.angleTo(entity.target), entity.rotation) < 30f){ @@ -95,7 +108,7 @@ public class RepairPoint extends Block{ @Override public void update(Tile tile){ - RepairPointEntity entity = tile.entity(); + 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())){ @@ -122,7 +135,7 @@ public class RepairPoint extends Block{ @Override public boolean shouldConsume(Tile tile){ - RepairPointEntity entity = tile.entity(); + RepairPointEntity entity = tile.ent(); return entity.target != null; } diff --git a/core/src/io/anuke/mindustry/world/blocks/units/UnitFactory.java b/core/src/io/anuke/mindustry/world/blocks/units/UnitFactory.java index 678d43c10f..8879f991b5 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/UnitFactory.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/UnitFactory.java @@ -27,12 +27,12 @@ import java.io.*; import static io.anuke.mindustry.Vars.*; public class UnitFactory extends Block{ - protected UnitType unitType; - protected float produceTime = 1000f; - protected float launchVelocity = 0f; - protected TextureRegion topRegion; - protected int maxSpawn = 4; - protected int[] capacities; + public UnitType unitType; + public float produceTime = 1000f; + public float launchVelocity = 0f; + public TextureRegion topRegion; + public int maxSpawn = 4; + public int[] capacities; public UnitFactory(String name){ super(name); @@ -48,7 +48,7 @@ public class UnitFactory extends Block{ public static void onUnitFactorySpawn(Tile tile, int spawns){ if(!(tile.entity instanceof UnitFactoryEntity) || !(tile.block() instanceof UnitFactory)) return; - UnitFactoryEntity entity = tile.entity(); + UnitFactoryEntity entity = tile.ent(); UnitFactory factory = (UnitFactory)tile.block(); entity.buildTime = 0f; @@ -110,7 +110,7 @@ public class UnitFactory extends Block{ @Override public void unitRemoved(Tile tile, Unit unit){ - UnitFactoryEntity entity = tile.entity(); + UnitFactoryEntity entity = tile.ent(); entity.spawned--; entity.spawned = Math.max(entity.spawned, 0); } @@ -122,7 +122,7 @@ public class UnitFactory extends Block{ @Override public void draw(Tile tile){ - UnitFactoryEntity entity = tile.entity(); + UnitFactoryEntity entity = tile.ent(); TextureRegion region = unitType.icon(Cicon.full); Draw.rect(name, tile.drawx(), tile.drawy()); @@ -153,7 +153,7 @@ public class UnitFactory extends Block{ @Override public void update(Tile tile){ - UnitFactoryEntity entity = tile.entity(); + UnitFactoryEntity entity = tile.ent(); if(entity.spawned >= maxSpawn){ return; @@ -184,7 +184,7 @@ public class UnitFactory extends Block{ @Override public boolean shouldConsume(Tile tile){ - UnitFactoryEntity entity = tile.entity(); + UnitFactoryEntity entity = tile.ent(); return entity.spawned < maxSpawn; } diff --git a/core/src/io/anuke/mindustry/world/meta/values/AmmoListValue.java b/core/src/io/anuke/mindustry/world/meta/values/AmmoListValue.java index c531fabe45..c19503c5d1 100644 --- a/core/src/io/anuke/mindustry/world/meta/values/AmmoListValue.java +++ b/core/src/io/anuke/mindustry/world/meta/values/AmmoListValue.java @@ -29,7 +29,7 @@ public class AmmoListValue implements StatValue{ for(T t : map.keys()){ BulletType type = map.get(t); table.addImage(icon(t)).size(3 * 8).padRight(4).right().top(); - table.add(t.localizedName()).padRight(10).left().top(); + table.add(t.localizedName).padRight(10).left().top(); table.table(Tex.underline, bt -> { bt.left().defaults().padRight(3).left(); diff --git a/core/src/io/anuke/mindustry/world/meta/values/BoosterListValue.java b/core/src/io/anuke/mindustry/world/meta/values/BoosterListValue.java index 4d1a867904..30c1ff0765 100644 --- a/core/src/io/anuke/mindustry/world/meta/values/BoosterListValue.java +++ b/core/src/io/anuke/mindustry/world/meta/values/BoosterListValue.java @@ -33,7 +33,7 @@ public class BoosterListValue implements StatValue{ if(!filter.get(liquid)) continue; c.addImage(liquid.icon(Cicon.medium)).size(3 * 8).padRight(4).right().top(); - c.add(liquid.localizedName()).padRight(10).left().top(); + c.add(liquid.localizedName).padRight(10).left().top(); c.table(Tex.underline, bt -> { bt.left().defaults().padRight(3).left(); diff --git a/core/src/io/anuke/mindustry/world/modules/LiquidModule.java b/core/src/io/anuke/mindustry/world/modules/LiquidModule.java index e597be1b66..c0cce49dac 100644 --- a/core/src/io/anuke/mindustry/world/modules/LiquidModule.java +++ b/core/src/io/anuke/mindustry/world/modules/LiquidModule.java @@ -101,6 +101,7 @@ public class LiquidModule extends BlockModule{ @Override public void read(DataInput stream) throws IOException{ + Arrays.fill(liquids, 0); byte count = stream.readByte(); for(int j = 0; j < count; j++){ diff --git a/core/src/io/anuke/mindustry/world/modules/PowerModule.java b/core/src/io/anuke/mindustry/world/modules/PowerModule.java index ad1a958fb7..f0c76e2aaf 100644 --- a/core/src/io/anuke/mindustry/world/modules/PowerModule.java +++ b/core/src/io/anuke/mindustry/world/modules/PowerModule.java @@ -28,6 +28,7 @@ public class PowerModule extends BlockModule{ @Override public void read(DataInput stream) throws IOException{ + links.clear(); short amount = stream.readShort(); for(int i = 0; i < amount; i++){ links.add(stream.readInt()); diff --git a/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java b/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java index 1bea20db40..b1b76c171a 100644 --- a/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java +++ b/desktop/src/io/anuke/mindustry/desktop/DesktopLauncher.java @@ -9,24 +9,17 @@ import io.anuke.arc.backends.sdl.jni.*; import io.anuke.arc.collection.*; import io.anuke.arc.files.*; import io.anuke.arc.func.*; -import io.anuke.arc.input.*; import io.anuke.arc.math.*; -import io.anuke.arc.scene.event.*; -import io.anuke.arc.scene.ui.*; import io.anuke.arc.util.*; -import io.anuke.arc.util.Log.*; -import io.anuke.arc.util.io.*; import io.anuke.arc.util.serialization.*; import io.anuke.mindustry.*; import io.anuke.mindustry.core.GameState.*; -import io.anuke.mindustry.core.Version; +import io.anuke.mindustry.core.*; import io.anuke.mindustry.desktop.steam.*; import io.anuke.mindustry.game.EventType.*; -import io.anuke.mindustry.mod.Mods.*; import io.anuke.mindustry.net.*; import io.anuke.mindustry.net.Net.*; import io.anuke.mindustry.type.*; -import io.anuke.mindustry.ui.*; import java.io.*; import java.net.*; @@ -49,6 +42,7 @@ public class DesktopLauncher extends ClientLauncher{ public static void main(String[] arg){ try{ + Vars.loadLogger(); new SdlApplication(new DesktopLauncher(arg), new SdlConfig(){{ title = "Mindustry"; maximized = true; @@ -56,7 +50,7 @@ public class DesktopLauncher extends ClientLauncher{ stencil = 0; width = 900; height = 700; - setWindowIcon(FileType.Internal, "icons/icon_64.png"); + setWindowIcon(FileType.internal, "icons/icon_64.png"); }}); }catch(Throwable e){ handleCrash(e); @@ -64,7 +58,6 @@ public class DesktopLauncher extends ClientLauncher{ } public DesktopLauncher(String[] args){ - Log.setUseColors(false); Version.init(); boolean useSteam = Version.modifier.contains("steam"); testMobile = Array.with(args).contains("-testMobile"); @@ -84,57 +77,14 @@ public class DesktopLauncher extends ClientLauncher{ if(useSteam){ //delete leftover dlls - FileHandle file = new FileHandle("."); - for(FileHandle other : file.parent().list()){ + Fi file = new Fi("."); + for(Fi other : file.parent().list()){ if(other.name().contains("steam") && (other.extension().equals("dll") || other.extension().equals("so") || other.extension().equals("dylib"))){ other.delete(); } } - StringBuilder base = new StringBuilder(); - Log.setLogger(new LogHandler(){ - @Override - public void print(String text, Object... args){ - String out = Log.format(text, false, args); - - base.append(out).append("\n"); - } - }); - Events.on(ClientLoadEvent.class, event -> { - Label[] label = {null}; - boolean[] visible = {false}; - Core.scene.table(t -> { - t.touchable(Touchable.disabled); - t.top().left(); - t.update(() -> { - if(Core.input.keyTap(KeyCode.BACKTICK) && (loadError || System.getProperty("user.name").equals("anuke") || Version.modifier.contains("beta"))){ - visible[0] = !visible[0]; - } - - t.toFront(); - }); - t.table(Styles.black3, f -> label[0] = f.add("").get()).visible(() -> visible[0]); - label[0].getText().append(base); - }); - - Log.setLogger(new LogHandler(){ - @Override - public void print(String text, Object... args){ - super.print(text, args); - String out = Log.format(text, false, args); - - int maxlen = 2048; - - if(label[0].getText().length() > maxlen){ - label[0].setText(label[0].getText().substring(label[0].getText().length() - maxlen)); - } - - label[0].getText().append(out).append("\n"); - label[0].invalidateHierarchy(); - } - }); - if(steamError != null){ Core.app.post(() -> Core.app.post(() -> Core.app.post(() -> { ui.showErrorMessage(Core.bundle.format("steam.error", (steamError.getMessage() == null) ? steamError.getClass().getSimpleName() : steamError.getClass().getSimpleName() + ": " + steamError.getMessage())); @@ -156,6 +106,9 @@ public class DesktopLauncher extends ClientLauncher{ if(SteamAPI.restartAppIfNecessary(SVars.steamID)){ System.exit(0); } + }catch(NullPointerException ignored){ + steam = false; + Log.info("Running in offline mode."); }catch(Throwable e){ steam = false; Log.err("Failed to load Steam native libraries."); @@ -176,21 +129,8 @@ public class DesktopLauncher extends ClientLauncher{ } } - void fallbackSteam(){ - try{ - String name = "steam_api"; - if(OS.isMac || OS.isLinux) name = "lib" + name; - if(OS.isWindows && OS.is64Bit) name += "64"; - name += (OS.isLinux ? ".so" : OS.isMac ? ".dylib" : ".dll"); - Streams.copyStream(getClass().getResourceAsStream(name), new FileOutputStream(name)); - System.loadLibrary(new File(name).getAbsolutePath()); - }catch(Throwable e){ - logSteamError(e); - } - } - void initSteam(String[] args){ - SVars.net = new SNet(new ArcNetImpl()); + SVars.net = new SNet(new ArcNetProvider()); SVars.stats = new SStats(); SVars.workshop = new SWorkshop(); SVars.user = new SUser(); @@ -254,18 +194,15 @@ public class DesktopLauncher extends ClientLauncher{ boolean fbgp = badGPU; CrashSender.send(e, file -> { - Array causes = Strings.getCauses(e); - Throwable fc = causes.find(t -> t instanceof ModLoadException); - if(fc == null) fc = Strings.getFinalCause(e); - Throwable cause = fc; + Throwable fc = Strings.getFinalCause(e); if(!fbgp){ - dialog.get(() -> message("A crash has occured. It has been saved in:\n" + file.getAbsolutePath() + "\n" + cause.getClass().getSimpleName().replace("Exception", "") + (cause.getMessage() == null ? "" : ":\n" + cause.getMessage()))); + dialog.get(() -> message("A crash has occured. It has been saved in:\n" + file.getAbsolutePath() + "\n" + fc.getClass().getSimpleName().replace("Exception", "") + (fc.getMessage() == null ? "" : ":\n" + fc.getMessage()))); } }); } @Override - public Array getWorkshopContent(Class type){ + public Array getWorkshopContent(Class type){ return !steam ? super.getWorkshopContent(type) : SVars.workshop.getWorkshopFiles(type); } @@ -281,7 +218,7 @@ public class DesktopLauncher extends ClientLauncher{ @Override public NetProvider getNet(){ - return steam ? SVars.net : new ArcNetImpl(); + return steam ? SVars.net : new ArcNetProvider(); } @Override diff --git a/desktop/src/io/anuke/mindustry/desktop/steam/SNet.java b/desktop/src/io/anuke/mindustry/desktop/steam/SNet.java index 526152a52e..a3c8e5b178 100644 --- a/desktop/src/io/anuke/mindustry/desktop/steam/SNet.java +++ b/desktop/src/io/anuke/mindustry/desktop/steam/SNet.java @@ -13,7 +13,7 @@ import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.core.Version; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.*; -import io.anuke.mindustry.net.ArcNetImpl.*; +import io.anuke.mindustry.net.ArcNetProvider.*; import io.anuke.mindustry.net.*; import io.anuke.mindustry.net.Net.*; import io.anuke.mindustry.net.Packets.*; diff --git a/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java b/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java index 8f12e22ca9..480830e1e3 100644 --- a/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java +++ b/desktop/src/io/anuke/mindustry/desktop/steam/SWorkshop.java @@ -21,7 +21,7 @@ import static io.anuke.mindustry.Vars.*; public class SWorkshop implements SteamUGCCallback{ public final SteamUGC ugc = new SteamUGC(this); - private ObjectMap, Array> workshopFiles = new ObjectMap<>(); + private ObjectMap, Array> workshopFiles = new ObjectMap<>(); private ObjectMap, SteamResult>> detailHandlers = new ObjectMap<>(); private Array> itemHandlers = new Array<>(); private ObjectMap updatedHandlers = new ObjectMap<>(); @@ -32,9 +32,9 @@ public class SWorkshop implements SteamUGCCallback{ ItemInstallInfo info = new ItemInstallInfo(); ugc.getSubscribedItems(ids); - Array folders = Array.with(ids).map(f -> { + Array folders = Array.with(ids).map(f -> { ugc.getItemInstallInfo(f, info); - return new FileHandle(info.getFolder()); + return new Fi(info.getFolder()); }).select(f -> f != null && f.list().length > 0); workshopFiles.put(Map.class, folders.select(f -> f.list().length == 1 && f.list()[0].extension().equals(mapExtension)).map(f -> f.list()[0])); @@ -50,7 +50,7 @@ public class SWorkshop implements SteamUGCCallback{ }); } - public Array getWorkshopFiles(Class type){ + public Array getWorkshopFiles(Class type){ return workshopFiles.getOr(type, () -> new Array<>(0)); } diff --git a/fastlane/metadata/android/en-US/changelogs/101.1.txt b/fastlane/metadata/android/en-US/changelogs/101.1.txt new file mode 100644 index 0000000000..0f00ca0c5c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/101.1.txt @@ -0,0 +1,7 @@ +- Added safer mod loading system - errors should no longer crash, but display a log +- Added new Cyrllic font +- Added range display and stats for repair point +- Whitelisted some more classes for scripting +- Fixed scripting not working on some devices [Android] +- Fixed power node desync +- Fixed some blocks not showing up in drill mining list diff --git a/fastlane/metadata/android/en-US/changelogs/101.txt b/fastlane/metadata/android/en-US/changelogs/101.txt new file mode 100644 index 0000000000..d53a88571c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/101.txt @@ -0,0 +1,7 @@ +- Added various new features for modding - see documentation +- Added server block state autosync +- Added support for Thai font +- Added JS scripting - unstable, not well tested +- Fixed liquid junction to item bridge crash +- Fixed launch items not saving +- General maintenance bugfixes and translation updates diff --git a/fastlane/metadata/android/en-US/changelogs/29553.txt b/fastlane/metadata/android/en-US/changelogs/29553.txt new file mode 100644 index 0000000000..d53a88571c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29553.txt @@ -0,0 +1,7 @@ +- Added various new features for modding - see documentation +- Added server block state autosync +- Added support for Thai font +- Added JS scripting - unstable, not well tested +- Fixed liquid junction to item bridge crash +- Fixed launch items not saving +- General maintenance bugfixes and translation updates diff --git a/fastlane/metadata/android/en-US/changelogs/29556.txt b/fastlane/metadata/android/en-US/changelogs/29556.txt new file mode 100644 index 0000000000..d53a88571c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29556.txt @@ -0,0 +1,7 @@ +- Added various new features for modding - see documentation +- Added server block state autosync +- Added support for Thai font +- Added JS scripting - unstable, not well tested +- Fixed liquid junction to item bridge crash +- Fixed launch items not saving +- General maintenance bugfixes and translation updates diff --git a/fastlane/metadata/android/en-US/changelogs/29558.txt b/fastlane/metadata/android/en-US/changelogs/29558.txt new file mode 100644 index 0000000000..0f00ca0c5c --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/29558.txt @@ -0,0 +1,7 @@ +- Added safer mod loading system - errors should no longer crash, but display a log +- Added new Cyrllic font +- Added range display and stats for repair point +- Whitelisted some more classes for scripting +- Fixed scripting not working on some devices [Android] +- Fixed power node desync +- Fixed some blocks not showing up in drill mining list diff --git a/fastlane/metadata/android/pl/changelogs/100.1.txt b/fastlane/metadata/android/pl-PL/changelogs/100.1.txt similarity index 100% rename from fastlane/metadata/android/pl/changelogs/100.1.txt rename to fastlane/metadata/android/pl-PL/changelogs/100.1.txt diff --git a/fastlane/metadata/android/pl/changelogs/100.txt b/fastlane/metadata/android/pl-PL/changelogs/100.txt similarity index 100% rename from fastlane/metadata/android/pl/changelogs/100.txt rename to fastlane/metadata/android/pl-PL/changelogs/100.txt diff --git a/fastlane/metadata/android/pl/full_description.txt b/fastlane/metadata/android/pl-PL/full_description.txt similarity index 100% rename from fastlane/metadata/android/pl/full_description.txt rename to fastlane/metadata/android/pl-PL/full_description.txt diff --git a/fastlane/metadata/android/pl/short_description.txt b/fastlane/metadata/android/pl-PL/short_description.txt similarity index 100% rename from fastlane/metadata/android/pl/short_description.txt rename to fastlane/metadata/android/pl-PL/short_description.txt diff --git a/fastlane/metadata/android/pl/summary.txt b/fastlane/metadata/android/pl-PL/summary.txt similarity index 100% rename from fastlane/metadata/android/pl/summary.txt rename to fastlane/metadata/android/pl-PL/summary.txt diff --git a/fastlane/metadata/android/pl/title.txt b/fastlane/metadata/android/pl-PL/title.txt similarity index 100% rename from fastlane/metadata/android/pl/title.txt rename to fastlane/metadata/android/pl-PL/title.txt diff --git a/gradle.properties b/gradle.properties index 0e54b8fa9e..29c1e50fad 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=2caecb328322b840a760dbb8877952867abd54d1 +archash=88c1a9afe2f5be4dd06e47ac8afe070247b3da29 diff --git a/ios/src/io/anuke/mindustry/IOSLauncher.java b/ios/src/io/anuke/mindustry/IOSLauncher.java index 7f4783d1a8..9ecbb6c75d 100644 --- a/ios/src/io/anuke/mindustry/IOSLauncher.java +++ b/ios/src/io/anuke/mindustry/IOSLauncher.java @@ -10,7 +10,6 @@ import io.anuke.arc.util.io.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.Saves.*; import io.anuke.mindustry.io.*; -import io.anuke.mindustry.mod.*; import io.anuke.mindustry.ui.*; import org.robovm.apple.coregraphics.*; import org.robovm.apple.foundation.*; @@ -39,7 +38,7 @@ public class IOSLauncher extends IOSApplication.Delegate{ return new IOSApplication(new ClientLauncher(){ @Override - public void showFileChooser(boolean open, String extension, Cons cons){ + public void showFileChooser(boolean open, String extension, Cons cons){ UIDocumentBrowserViewController cont = new UIDocumentBrowserViewController((NSArray)null); @@ -65,8 +64,8 @@ public class IOSLauncher extends IOSApplication.Delegate{ try{ coord.coordinateReadingItem(url, NSFileCoordinatorReadingOptions.ForUploading, result -> { - FileHandle src = Core.files.absolute(result.getAbsoluteURL().getPath()); - FileHandle dst = Core.files.absolute(getDocumentsDirectory()).child(src.name()); + Fi src = Core.files.absolute(result.getAbsoluteURL().getPath()); + Fi dst = Core.files.absolute(getDocumentsDirectory()).child(src.name()); src.copyTo(dst); Core.app.post(() -> { @@ -117,10 +116,10 @@ public class IOSLauncher extends IOSApplication.Delegate{ } @Override - public void shareFile(FileHandle file){ + public void shareFile(Fi file){ try{ Log.info("Attempting to share file " + file); - FileHandle to = Core.files.absolute(getDocumentsDirectory()).child(file.name()); + Fi to = Core.files.absolute(getDocumentsDirectory()).child(file.name()); file.copyTo(to); NSURL url = new NSURL(to.file()); @@ -153,7 +152,7 @@ public class IOSLauncher extends IOSApplication.Delegate{ UINavigationController.attemptRotationToDeviceOrientation(); } }, new IOSApplicationConfiguration(){{ - errorHandler = ModCrashHandler::handle; + //errorHandler = ModCrashHandler::handle; }}); } @@ -197,7 +196,7 @@ public class IOSLauncher extends IOSApplication.Delegate{ void openURL(NSURL url){ Core.app.post(() -> Core.app.post(() -> { - FileHandle file = Core.files.absolute(getDocumentsDirectory()).child(url.getLastPathComponent()); + Fi file = Core.files.absolute(getDocumentsDirectory()).child(url.getLastPathComponent()); Core.files.absolute(url.getPath()).copyTo(file); if(file.extension().equalsIgnoreCase(saveExtension)){ //open save diff --git a/server/build.gradle b/server/build.gradle index 31f6d57dc5..09299943fa 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -46,6 +46,9 @@ task dist(type: Jar){ exclude("com/badlogic/gdx/**") exclude("icons/**") exclude("bundles/**") + if(!versionModifier.contains("steam")){ + exclude("**.dll", "**.so", "**.dylib") + } manifest{ attributes 'Main-Class': project.mainClassName diff --git a/server/src/io/anuke/mindustry/server/MindustryServer.java b/server/src/io/anuke/mindustry/server/MindustryServer.java deleted file mode 100644 index ad83a69eb7..0000000000 --- a/server/src/io/anuke/mindustry/server/MindustryServer.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.anuke.mindustry.server; - -import io.anuke.arc.*; -import io.anuke.arc.files.*; -import io.anuke.arc.util.*; -import io.anuke.mindustry.*; -import io.anuke.mindustry.core.*; -import io.anuke.mindustry.mod.*; - -import static io.anuke.mindustry.Vars.*; - -public class MindustryServer implements ApplicationListener{ - private String[] args; - - public MindustryServer(String[] args){ - this.args = args; - } - - @Override - public void init(){ - Core.settings.setDataDirectory(Core.files.local("config")); - loadLocales = false; - headless = true; - - FileHandle plugins = Core.settings.getDataDirectory().child("plugins"); - if(plugins.isDirectory() && plugins.list().length > 0 && !plugins.sibling("mods").exists()){ - Log.warn("[IMPORTANT NOTICE] &lrPlugins have been detected.&ly Automatically moving all contents of the plugin folder into the 'mods' folder. The original folder will not be removed; please do so manually."); - plugins.sibling("mods").mkdirs(); - for(FileHandle file : plugins.list()){ - file.copyTo(plugins.sibling("mods")); - } - } - - Vars.loadSettings(); - Vars.init(); - content.createContent(); - content.init(); - - Core.app.addListener(logic = new Logic()); - Core.app.addListener(netServer = new NetServer()); - Core.app.addListener(new ServerControl(args)); - - mods.each(Mod::init); - } - - -} diff --git a/server/src/io/anuke/mindustry/server/ServerControl.java b/server/src/io/anuke/mindustry/server/ServerControl.java index f8f03f526e..42eb87cbee 100644 --- a/server/src/io/anuke/mindustry/server/ServerControl.java +++ b/server/src/io/anuke/mindustry/server/ServerControl.java @@ -39,14 +39,16 @@ import static io.anuke.mindustry.Vars.*; public class ServerControl implements ApplicationListener{ private static final int roundExtraTime = 12; - //in bytes: 512 kb is max private static final int maxLogLength = 1024 * 512; private static final int commandSocketPort = 6859; - private final CommandHandler handler = new CommandHandler(""); - private final FileHandle logFolder = Core.settings.getDataDirectory().child("logs/"); + protected static String[] tags = {"&lc&fb[D]", "&lg&fb[I]", "&ly&fb[W]", "&lr&fb[E]", ""}; + protected static DateTimeFormatter dateTime = DateTimeFormatter.ofPattern("MM-dd-yyyy | HH:mm:ss"); - private FileHandle currentLogFile; + private final CommandHandler handler = new CommandHandler(""); + private final Fi logFolder = Core.settings.getDataDirectory().child("logs/"); + + private Fi currentLogFile; private boolean inExtraRound; private Task lastTask; private Gamemode lastMode = Gamemode.survival; @@ -68,44 +70,19 @@ public class ServerControl implements ApplicationListener{ "globalrules", "{reactorExplosions: false}" ); - Log.setLogger(new LogHandler(){ - DateTimeFormatter dateTime = DateTimeFormatter.ofPattern("MM-dd-yyyy | HH:mm:ss"); + Log.setLogger((level, text, args1) -> { + String result = "[" + dateTime.format(LocalDateTime.now()) + "] " + format(tags[level.ordinal()] + " " + text + "&fr", args1); + System.out.println(result); - @Override - public void debug(String text, Object... args){ - print("&lc&fb" + "[DEBG] " + text, args); + if(Core.settings.getBool("logging")){ + logToFile("[" + dateTime.format(LocalDateTime.now()) + "] " + format(tags[level.ordinal()] + " " + text + "&fr", false, args1)); } - @Override - public void info(String text, Object... args){ - print("&lg&fb" + "[INFO] " + text, args); - } - - @Override - public void err(String text, Object... args){ - print("&lr&fb" + "[ERR!] " + text, args); - } - - @Override - public void warn(String text, Object... args){ - print("&ly&fb" + "[WARN] " + text, args); - } - - @Override - public void print(String text, Object... args){ - String result = "[" + dateTime.format(LocalDateTime.now()) + "] " + format(text + "&fr", args); - System.out.println(result); - - if(Core.settings.getBool("logging")){ - logToFile("[" + dateTime.format(LocalDateTime.now()) + "] " + format(text + "&fr", false, args)); - } - - if(socketOutput != null){ - try{ - socketOutput.println(format(text + "&fr", false, args).replace("[DEBG] ", "").replace("[WARN] ", "").replace("[INFO] ", "").replace("[ERR!] ", "")); - }catch(Throwable e){ - err("Error occurred logging to socket: {0}", e.getClass().getSimpleName()); - } + if(socketOutput != null){ + try{ + socketOutput.println(format(text + "&fr", false, args1)); + }catch(Throwable e){ + err("Error occurred logging to socket: {0}", e.getClass().getSimpleName()); } } }); @@ -180,8 +157,8 @@ public class ServerControl implements ApplicationListener{ } }); - if(!mods.all().isEmpty()){ - info("&lc{0} mods loaded.", mods.all().size); + if(!mods.list().isEmpty()){ + info("&lc{0} mods loaded.", mods.list().size); } info("&lcServer loaded. Type &ly'help'&lc for help."); @@ -333,10 +310,10 @@ public class ServerControl implements ApplicationListener{ }); handler.register("mods", "Display all loaded mods.", arg -> { - if(!mods.all().isEmpty()){ + if(!mods.list().isEmpty()){ info("Mods:"); - for(LoadedMod mod : mods.all()){ - info(" &ly{0} &lcv{1}", mod.meta.name, mod.meta.version); + for(LoadedMod mod : mods.list()){ + info(" &ly{0} &lcv{1}", mod.meta.displayName(), mod.meta.version); } }else{ info("No mods found."); @@ -345,9 +322,10 @@ public class ServerControl implements ApplicationListener{ }); handler.register("mod", "", "Display information about a loaded plugin.", arg -> { - LoadedMod mod = mods.all().find(p -> p.meta.name.equalsIgnoreCase(arg[0])); + LoadedMod mod = mods.list().find(p -> p.meta.name.equalsIgnoreCase(arg[0])); if(mod != null){ - info("Name: &ly{0}", mod.meta.name); + info("Name: &ly{0}", mod.meta.displayName()); + info("Internal Name: &ly{0}", mod.name); info("Version: &ly{0}", mod.meta.version); info("Author: &ly{0}", mod.meta.author); info("Path: &ly{0}", mod.file.path()); @@ -357,6 +335,10 @@ public class ServerControl implements ApplicationListener{ } }); + handler.register("js", "", "Run arbitrary Javascript.", arg -> { + info("&lc" + mods.getScripts().runConsole(arg[0])); + }); + handler.register("say", "", "Send a message to all players.", arg -> { if(!state.is(State.playing)){ err("Not hosting. Host a game first."); @@ -764,7 +746,7 @@ public class ServerControl implements ApplicationListener{ return; } - FileHandle file = saveDirectory.child(arg[0] + "." + saveExtension); + Fi file = saveDirectory.child(arg[0] + "." + saveExtension); if(!SaveIO.isSaveValid(file)){ err("No (valid) save data found for slot."); @@ -790,7 +772,7 @@ public class ServerControl implements ApplicationListener{ return; } - FileHandle file = saveDirectory.child(arg[0] + "." + saveExtension); + Fi file = saveDirectory.child(arg[0] + "." + saveExtension); Core.app.post(() -> { SaveIO.save(file); @@ -800,7 +782,7 @@ public class ServerControl implements ApplicationListener{ handler.register("saves", "List all saves in the save directory.", arg -> { info("Save files: "); - for(FileHandle file : saveDirectory.list()){ + for(Fi file : saveDirectory.list()){ if(file.extension().equals(saveExtension)){ info("| &ly{0}", file.nameWithoutExtension()); } @@ -846,8 +828,8 @@ public class ServerControl implements ApplicationListener{ info("&ly{0}&lg MB collected. Memory usage now at &ly{1}&lg MB.", pre - post, post); }); - mods.each(p -> p.registerServerCommands(handler)); - mods.each(p -> p.registerClientCommands(netServer.clientCommands)); + mods.eachClass(p -> p.registerServerCommands(handler)); + mods.eachClass(p -> p.registerClientCommands(netServer.clientCommands)); } private void applyRules(){ diff --git a/server/src/io/anuke/mindustry/server/ServerLauncher.java b/server/src/io/anuke/mindustry/server/ServerLauncher.java index fcf6a52077..1210d81606 100644 --- a/server/src/io/anuke/mindustry/server/ServerLauncher.java +++ b/server/src/io/anuke/mindustry/server/ServerLauncher.java @@ -1,22 +1,85 @@ package io.anuke.mindustry.server; +import io.anuke.arc.*; import io.anuke.arc.backends.headless.*; +import io.anuke.arc.files.*; +import io.anuke.arc.util.*; import io.anuke.mindustry.*; import io.anuke.mindustry.core.*; +import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.game.EventType.*; +import io.anuke.mindustry.mod.*; +import io.anuke.mindustry.mod.Mods.*; +import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.*; -import static io.anuke.mindustry.Vars.platform; +import java.time.*; -public class ServerLauncher{ +import static io.anuke.arc.util.Log.format; +import static io.anuke.mindustry.Vars.*; +import static io.anuke.mindustry.server.ServerControl.*; + +public class ServerLauncher implements ApplicationListener{ + static String[] args; public static void main(String[] args){ try{ + ServerLauncher.args = args; Vars.platform = new Platform(){}; Vars.net = new Net(platform.getNet()); - new HeadlessApplication(new MindustryServer(args), null, throwable -> CrashSender.send(throwable, f -> {})); + + Log.setLogger((level, text, args1) -> { + String result = "[" + dateTime.format(LocalDateTime.now()) + "] " + format(tags[level.ordinal()] + " " + text + "&fr", args1); + System.out.println(result); + }); + new HeadlessApplication(new ServerLauncher(), null, throwable -> CrashSender.send(throwable, f -> {})); }catch(Throwable t){ CrashSender.send(t, f -> {}); } } + + @Override + public void init(){ + Core.settings.setDataDirectory(Core.files.local("config")); + loadLocales = false; + headless = true; + + Fi plugins = Core.settings.getDataDirectory().child("plugins"); + if(plugins.isDirectory() && plugins.list().length > 0 && !plugins.sibling("mods").exists()){ + Log.warn("[IMPORTANT NOTICE] &lrPlugins have been detected.&ly Automatically moving all contents of the plugin folder into the 'mods' folder. The original folder will not be removed; please do so manually."); + plugins.sibling("mods").mkdirs(); + for(Fi file : plugins.list()){ + file.copyTo(plugins.sibling("mods")); + } + } + + Vars.loadSettings(); + Vars.init(); + content.createBaseContent(); + mods.loadScripts(); + content.createModContent(); + content.init(); + if(mods.hasContentErrors()){ + Log.err("Error occurred loading mod content:"); + for(LoadedMod mod : mods.list()){ + if(mod.hasContentErrors()){ + Log.err("| &ly[{0}]", mod.name); + for(Content cont : mod.erroredContent){ + Log.err("| | &y{0}: &c{1}", cont.minfo.sourceFile.name(), Strings.getSimpleMessage(cont.minfo.baseError).replace("\n", " ")); + } + } + } + Log.err("The server will now exit."); + System.exit(1); + } + + Core.app.addListener(logic = new Logic()); + Core.app.addListener(netServer = new NetServer()); + Core.app.addListener(new ServerControl(args)); + + mods.eachClass(Mod::init); + + Events.fire(new ServerLoadEvent()); + } } \ No newline at end of file diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java index a9ed831fbc..2e706644c2 100644 --- a/tests/src/test/java/ApplicationTests.java +++ b/tests/src/test/java/ApplicationTests.java @@ -16,7 +16,7 @@ import io.anuke.mindustry.game.Team; import io.anuke.mindustry.io.SaveIO; import io.anuke.mindustry.maps.Map; import io.anuke.mindustry.net.*; -import io.anuke.mindustry.type.ContentType; +import io.anuke.mindustry.ctype.ContentType; import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.blocks.BlockPart; @@ -47,7 +47,7 @@ public class ApplicationTests{ net = new Net(null); tree = new FileTree(); Vars.init(); - content.createContent(); + content.createBaseContent(); add(logic = new Logic()); add(netServer = new NetServer()); @@ -289,8 +289,8 @@ public class ApplicationTests{ void buildingOverlap(){ initBuilding(); - Phantom d1 = (Phantom)UnitTypes.phantom.create(Team.sharded); - Phantom d2 = (Phantom)UnitTypes.phantom.create(Team.sharded); + BuilderDrone d1 = (BuilderDrone)UnitTypes.phantom.create(Team.sharded); + BuilderDrone d2 = (BuilderDrone)UnitTypes.phantom.create(Team.sharded); d1.set(10f, 20f); d2.set(10f, 20f); @@ -311,8 +311,8 @@ public class ApplicationTests{ void buildingDestruction(){ initBuilding(); - Phantom d1 = (Phantom)UnitTypes.phantom.create(Team.sharded); - Phantom d2 = (Phantom)UnitTypes.phantom.create(Team.sharded); + BuilderDrone d1 = (BuilderDrone)UnitTypes.phantom.create(Team.sharded); + BuilderDrone d2 = (BuilderDrone)UnitTypes.phantom.create(Team.sharded); d1.set(10f, 20f); d2.set(10f, 20f); diff --git a/tests/src/test/java/power/DirectConsumerTests.java b/tests/src/test/java/power/DirectConsumerTests.java index 89ed331c8b..0892b13d88 100644 --- a/tests/src/test/java/power/DirectConsumerTests.java +++ b/tests/src/test/java/power/DirectConsumerTests.java @@ -41,7 +41,7 @@ public class DirectConsumerTests extends PowerTestFixture{ consumerTile.entity.items.add(Items.lead, leadAmount); Tile producerTile = createFakeTile(2, 0, createFakeProducerBlock(producedPower)); - producerTile.entity().productionEfficiency = 1f; + producerTile.ent().productionEfficiency = 1f; PowerGraph graph = new PowerGraph(); graph.add(producerTile); diff --git a/tests/src/test/java/power/ItemLiquidGeneratorTests.java b/tests/src/test/java/power/ItemLiquidGeneratorTests.java index e6bc2a20de..5e5a2ed034 100644 --- a/tests/src/test/java/power/ItemLiquidGeneratorTests.java +++ b/tests/src/test/java/power/ItemLiquidGeneratorTests.java @@ -52,7 +52,7 @@ public class ItemLiquidGeneratorTests extends PowerTestFixture{ }; tile = createFakeTile(0, 0, generator); - entity = tile.entity(); + entity = tile.ent(); } /** Tests the consumption and efficiency when being supplied with liquids. */ diff --git a/tests/src/test/java/power/PowerTestFixture.java b/tests/src/test/java/power/PowerTestFixture.java index 75f4a56854..1cd8930449 100644 --- a/tests/src/test/java/power/PowerTestFixture.java +++ b/tests/src/test/java/power/PowerTestFixture.java @@ -33,7 +33,7 @@ public class PowerTestFixture{ } }; - content.createContent(); + content.createBaseContent(); Log.setUseColors(false); Time.setDeltaProvider(() -> 0.5f); } @@ -91,6 +91,13 @@ public class PowerTestFixture{ if(block.hasLiquids) tile.entity.liquids = new LiquidModule(); if(block.hasPower){ 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); } diff --git a/tests/src/test/java/power/PowerTests.java b/tests/src/test/java/power/PowerTests.java index 6b253e4f29..b3353cfc2c 100644 --- a/tests/src/test/java/power/PowerTests.java +++ b/tests/src/test/java/power/PowerTests.java @@ -51,7 +51,7 @@ public class PowerTests extends PowerTestFixture{ void simulateDirectConsumption(float producedPower, float requiredPower, float expectedSatisfaction, String parameterDescription){ Tile producerTile = createFakeTile(0, 0, createFakeProducerBlock(producedPower)); - producerTile.entity().productionEfficiency = 1f; + producerTile.ent().productionEfficiency = 1f; Tile directConsumerTile = createFakeTile(0, 1, createFakeDirectConsumer(requiredPower)); PowerGraph powerGraph = new PowerGraph(); @@ -91,7 +91,7 @@ public class PowerTests extends PowerTestFixture{ if(producedPower > 0.0f){ Tile producerTile = createFakeTile(0, 0, createFakeProducerBlock(producedPower)); - producerTile.entity().productionEfficiency = 1f; + producerTile.ent().productionEfficiency = 1f; powerGraph.add(producerTile); } Tile directConsumerTile = null; @@ -116,7 +116,7 @@ public class PowerTests extends PowerTestFixture{ @Test void directConsumptionStopsWithNoPower(){ Tile producerTile = createFakeTile(0, 0, createFakeProducerBlock(10.0f)); - producerTile.entity().productionEfficiency = 1.0f; + producerTile.ent().productionEfficiency = 1.0f; Tile consumerTile = createFakeTile(0, 1, createFakeDirectConsumer(5.0f)); PowerGraph powerGraph = new PowerGraph(); @@ -133,7 +133,7 @@ public class PowerTests extends PowerTestFixture{ 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.entity())); + assertFalse(consumePower.valid(consumerTile.ent())); } } } diff --git a/tools/build.gradle b/tools/build.gradle index dff7745f5d..6a2825747a 100644 --- a/tools/build.gradle +++ b/tools/build.gradle @@ -297,7 +297,7 @@ task pack(dependsOn: classes){ //run generation task; generate all needed sprites file(genFolder).mkdirs() javaexec{ - main = "io.anuke.mindustry.ImagePacker" + main = "io.anuke.mindustry.tools.ImagePacker" classpath = sourceSets.main.runtimeClasspath standardInput = System.in workingDir = genFolder @@ -310,7 +310,7 @@ task pack(dependsOn: classes){ } jvmArgs("-Djava.awt.headless=true") - main = "io.anuke.mindustry.Upscaler" + main = "io.anuke.mindustry.tools.Upscaler" classpath = sourceSets.main.runtimeClasspath standardInput = System.in workingDir = "../core/assets-raw/sprites_out/ui/icons" @@ -351,7 +351,7 @@ task pack(dependsOn: classes){ task genSprites(dependsOn: classes, type: JavaExec){ finalizedBy 'antialiasGen' - main = "io.anuke.mindustry.ImagePacker" + main = "io.anuke.mindustry.tools.ImagePacker" classpath = sourceSets.main.runtimeClasspath jvmArgs("-Djava.awt.headless=true") standardInput = System.in @@ -361,7 +361,7 @@ task genSprites(dependsOn: classes, type: JavaExec){ task updateBundles(dependsOn: classes, type: JavaExec){ file(genFolder).mkdirs() - main = "io.anuke.mindustry.BundleLauncher" + main = "io.anuke.mindustry.tools.BundleLauncher" classpath = sourceSets.main.runtimeClasspath standardInput = System.in workingDir = "../core/assets/bundles/" diff --git a/tools/src/io/anuke/mindustry/BundleLauncher.java b/tools/src/io/anuke/mindustry/BundleLauncher.java deleted file mode 100644 index 3888f641da..0000000000 --- a/tools/src/io/anuke/mindustry/BundleLauncher.java +++ /dev/null @@ -1,75 +0,0 @@ -package io.anuke.mindustry; - -import io.anuke.arc.collection.Array; -import io.anuke.arc.collection.OrderedMap; -import io.anuke.arc.func.Func2; -import io.anuke.arc.util.Log; -import io.anuke.arc.util.Strings; -import io.anuke.arc.util.io.PropertiesUtils; - -import java.io.*; -import java.nio.file.*; - -public class BundleLauncher{ - - public static void main(String[] args) throws Exception{ - File file = new File("bundle.properties"); - OrderedMap base = new OrderedMap<>(); - PropertiesUtils.load(base, new InputStreamReader(new FileInputStream(file))); - Array removals = new Array<>(); - - Files.walk(Paths.get("")).forEach(child -> { - try{ - if(child.getFileName().toString().equals("bundle.properties") || Files.isDirectory(child) || child.toString().contains("output")) - return; - - Log.info("Parsing bundle: {0}", child); - - OrderedMap other = new OrderedMap<>(); - PropertiesUtils.load(other, Files.newBufferedReader(child, Strings.utf8)); - removals.clear(); - - for(String key : other.orderedKeys()){ - if(!base.containsKey(key)){ - removals.add(key); - Log.info("&lr- Removing unused key '{0}'...", key); - } - } - Log.info("&lr{0} keys removed.", removals.size); - for(String s : removals){ - other.remove(s); - } - - int added = 0; - - for(String key : base.orderedKeys()){ - if(!other.containsKey(key) || other.get(key).trim().isEmpty()){ - other.put(key, base.get(key)); - added++; - Log.info("&lc- Adding missing key '{0}'...", key); - } - } - - Func2 processor = (key, value) -> (key + " = " + value).replace("\\", "\\\\").replace("\n", "\\n") + "\n"; - - Path output = child.resolveSibling("output/" + child.getFileName()); - - Log.info("&lc{0} keys added.", added); - Log.info("Writing bundle to {0}", output); - StringBuilder result = new StringBuilder(); - - //add everything ordered - for(String key : base.orderedKeys()){ - result.append(processor.get(key, other.get(key))); - other.remove(key); - } - - Files.write(child, result.toString().getBytes(Strings.utf8)); - - }catch(IOException e){ - throw new RuntimeException(e); - } - }); - } - -} diff --git a/tools/src/io/anuke/mindustry/tools/BundleLauncher.java b/tools/src/io/anuke/mindustry/tools/BundleLauncher.java new file mode 100644 index 0000000000..30624ea663 --- /dev/null +++ b/tools/src/io/anuke/mindustry/tools/BundleLauncher.java @@ -0,0 +1,67 @@ +package io.anuke.mindustry.tools; + +import io.anuke.arc.collection.*; +import io.anuke.arc.files.*; +import io.anuke.arc.func.*; +import io.anuke.arc.util.*; +import io.anuke.arc.util.io.*; + +import java.io.*; + +public class BundleLauncher{ + + public static void main(String[] args) throws Exception{ + File file = new File("bundle.properties"); + OrderedMap base = new OrderedMap<>(); + PropertiesUtils.load(base, new InputStreamReader(new FileInputStream(file))); + Array removals = new Array<>(); + Fi.get("").walk(child -> { + if(child.name().equals("bundle.properties") || child.isDirectory() || child.toString().contains("output")) + return; + + Log.info("Parsing bundle: {0}", child); + + OrderedMap other = new OrderedMap<>(); + PropertiesUtils.load(other, child.reader(2048, "UTF-8")); + removals.clear(); + + for(String key : other.orderedKeys()){ + if(!base.containsKey(key)){ + removals.add(key); + Log.info("&lr- Removing unused key '{0}'...", key); + } + } + Log.info("&lr{0} keys removed.", removals.size); + for(String s : removals){ + other.remove(s); + } + + int added = 0; + + for(String key : base.orderedKeys()){ + if(!other.containsKey(key) || other.get(key).trim().isEmpty()){ + other.put(key, base.get(key)); + added++; + Log.info("&lc- Adding missing key '{0}'...", key); + } + } + + Func2 processor = (key, value) -> (key + " = " + value).replace("\\", "\\\\").replace("\n", "\\n") + "\n"; + + Fi output = child.sibling("output/" + child.name()); + + Log.info("&lc{0} keys added.", added); + Log.info("Writing bundle to {0}", output); + StringBuilder result = new StringBuilder(); + + //add everything ordered + for(String key : base.orderedKeys()){ + result.append(processor.get(key, other.get(key))); + other.remove(key); + } + + child.writeString(result.toString()); + }); + } + +} diff --git a/tools/src/io/anuke/mindustry/Generators.java b/tools/src/io/anuke/mindustry/tools/Generators.java similarity index 93% rename from tools/src/io/anuke/mindustry/Generators.java rename to tools/src/io/anuke/mindustry/tools/Generators.java index 718f994376..e1ad420f50 100644 --- a/tools/src/io/anuke/mindustry/Generators.java +++ b/tools/src/io/anuke/mindustry/tools/Generators.java @@ -1,21 +1,19 @@ -package io.anuke.mindustry; +package io.anuke.mindustry.tools; import io.anuke.arc.collection.*; +import io.anuke.arc.files.*; import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.math.*; import io.anuke.arc.util.*; import io.anuke.arc.util.noise.*; -import io.anuke.mindustry.ImagePacker.*; import io.anuke.mindustry.ctype.*; +import io.anuke.mindustry.tools.ImagePacker.*; import io.anuke.mindustry.type.*; import io.anuke.mindustry.ui.*; import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.blocks.*; -import java.io.*; -import java.nio.file.*; - import static io.anuke.mindustry.Vars.*; public class Generators{ @@ -73,17 +71,13 @@ public class Generators{ for(Block block : content.blocks()){ TextureRegion[] regions = block.getGeneratedIcons(); - try{ - if(block instanceof Floor){ - block.load(); - for(TextureRegion region : block.variantRegions()){ - GenRegion gen = (GenRegion)region; - if(gen.path == null) continue; - Files.copy(gen.path, Paths.get("../editor/editor-" + gen.path.getFileName())); - } + if(block instanceof Floor){ + block.load(); + for(TextureRegion region : block.variantRegions()){ + GenRegion gen = (GenRegion)region; + if(gen.path == null) continue; + gen.path.copyTo(Fi.get("../editor/editor-" + gen.path.name())); } - }catch(IOException e){ - throw new RuntimeException(e); } if(regions.length == 0){ @@ -120,11 +114,7 @@ public class Generators{ } } - try{ - Files.delete(region.path); - }catch(IOException e){ - e.printStackTrace(); - } + region.path.delete(); out.save(block.name); } diff --git a/tools/src/io/anuke/mindustry/Image.java b/tools/src/io/anuke/mindustry/tools/Image.java similarity index 97% rename from tools/src/io/anuke/mindustry/Image.java rename to tools/src/io/anuke/mindustry/tools/Image.java index 30e06b8170..f7c987762b 100644 --- a/tools/src/io/anuke/mindustry/Image.java +++ b/tools/src/io/anuke/mindustry/tools/Image.java @@ -1,9 +1,9 @@ -package io.anuke.mindustry; +package io.anuke.mindustry.tools; import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.g2d.TextureRegion; import io.anuke.arc.util.Structs; -import io.anuke.mindustry.ImagePacker.GenRegion; +import io.anuke.mindustry.tools.ImagePacker.GenRegion; import javax.imageio.ImageIO; import java.awt.*; diff --git a/tools/src/io/anuke/mindustry/ImagePacker.java b/tools/src/io/anuke/mindustry/tools/ImagePacker.java similarity index 78% rename from tools/src/io/anuke/mindustry/ImagePacker.java rename to tools/src/io/anuke/mindustry/tools/ImagePacker.java index 200da5c602..226155a245 100644 --- a/tools/src/io/anuke/mindustry/ImagePacker.java +++ b/tools/src/io/anuke/mindustry/tools/ImagePacker.java @@ -1,39 +1,36 @@ -package io.anuke.mindustry; +package io.anuke.mindustry.tools; -import io.anuke.arc.Core; -import io.anuke.arc.collection.ObjectMap; +import io.anuke.arc.*; +import io.anuke.arc.collection.*; +import io.anuke.arc.files.*; import io.anuke.arc.graphics.g2d.*; -import io.anuke.arc.graphics.g2d.TextureAtlas.AtlasRegion; +import io.anuke.arc.graphics.g2d.TextureAtlas.*; import io.anuke.arc.util.*; -import io.anuke.arc.util.Log.LogHandler; -import io.anuke.arc.util.Log.NoopLogHandler; -import io.anuke.mindustry.core.ContentLoader; +import io.anuke.arc.util.Log.*; +import io.anuke.mindustry.*; +import io.anuke.mindustry.core.*; -import javax.imageio.ImageIO; -import java.awt.image.BufferedImage; -import java.io.IOException; -import java.nio.file.*; +import javax.imageio.*; +import java.awt.image.*; +import java.io.*; public class ImagePacker{ static ObjectMap regionCache = new ObjectMap<>(); static ObjectMap imageCache = new ObjectMap<>(); - public static void main(String[] args) throws IOException{ + public static void main(String[] args){ Vars.headless = true; Log.setLogger(new NoopLogHandler()); Vars.content = new ContentLoader(); - Vars.content.createContent(); - Log.setLogger(new LogHandler()); + Vars.content.createBaseContent(); + Log.setLogger(new DefaultLogHandler()); + + Fi.get("../../../assets-raw/sprites_out").walk(path -> { + String fname = path.nameWithoutExtension(); - Files.walk(Paths.get("../../../assets-raw/sprites_out")).forEach(path -> { try{ - if(Files.isDirectory(path)) return; - - String fname = path.getFileName().toString(); - fname = fname.substring(0, fname.length() - 4); - - BufferedImage image = ImageIO.read(path.toFile()); + BufferedImage image = ImageIO.read(path.file()); GenRegion region = new GenRegion(fname, path){ @Override @@ -59,9 +56,8 @@ public class ImagePacker{ regionCache.put(fname, region); imageCache.put(region, image); - }catch(IOException e){ - e.printStackTrace(); + throw new RuntimeException(e); } }); @@ -134,9 +130,9 @@ public class ImagePacker{ static class GenRegion extends AtlasRegion{ String name; boolean invalid; - Path path; + Fi path; - GenRegion(String name, Path path){ + GenRegion(String name, Fi path){ this.name = name; this.path = path; } diff --git a/tools/src/io/anuke/mindustry/tools/ScriptStubGenerator.java b/tools/src/io/anuke/mindustry/tools/ScriptStubGenerator.java new file mode 100644 index 0000000000..c2110eb4e1 --- /dev/null +++ b/tools/src/io/anuke/mindustry/tools/ScriptStubGenerator.java @@ -0,0 +1,79 @@ +package io.anuke.mindustry.tools; + +import io.anuke.arc.*; +import io.anuke.arc.collection.Array; +import io.anuke.arc.collection.*; +import io.anuke.arc.files.*; +import io.anuke.arc.graphics.*; +import io.anuke.arc.graphics.g2d.*; +import io.anuke.arc.graphics.g2d.TextureAtlas.*; +import io.anuke.arc.math.*; +import io.anuke.arc.util.*; +import io.anuke.mindustry.gen.*; +import org.reflections.*; +import org.reflections.scanners.*; +import org.reflections.util.*; + +import java.io.*; +import java.lang.reflect.*; +import java.util.*; + +public class ScriptStubGenerator{ + + public static void main(String[] args){ + String base = "io.anuke.mindustry"; + Array blacklist = Array.with("plugin", "mod", "net", "io", "tools"); + Array nameBlacklist = Array.with("ClientLauncher", "NetClient", "NetServer", "ClassAccess"); + Array> whitelist = Array.with(Draw.class, Fill.class, Lines.class, Core.class, TextureAtlas.class, TextureRegion.class, Time.class, System.class, PrintStream.class, + AtlasRegion.class, String.class, Mathf.class, Angles.class, Color.class, Runnable.class, Object.class, Icon.class, Tex.class, + Sounds.class, Musics.class, Call.class, Texture.class, TextureData.class, Pixmap.class, I18NBundle.class); + Array nopackage = Array.with("java.lang", "java"); + + String fileTemplate = "package io.anuke.mindustry.mod;\n" + + "\n" + + "import io.anuke.arc.collection.*;\n" + + "//obviously autogenerated, do not touch\n" + + "public class ClassAccess{\n" + + "\tpublic static final ObjectSet allowedClassNames = ObjectSet.with($ALLOWED_CLASS_NAMES$);\n" + + "}"; + + List classLoadersList = new LinkedList<>(); + classLoadersList.add(ClasspathHelper.contextClassLoader()); + classLoadersList.add(ClasspathHelper.staticClassLoader()); + + Reflections reflections = new Reflections(new ConfigurationBuilder() + .setScanners(new SubTypesScanner(false), new ResourcesScanner()) + .setUrls(ClasspathHelper.forClassLoader(classLoadersList.toArray(new ClassLoader[0]))) + .filterInputsBy(new FilterBuilder() + .include(FilterBuilder.prefix("io.anuke.mindustry")) + .include(FilterBuilder.prefix("io.anuke.arc.func")) + .include(FilterBuilder.prefix("io.anuke.arc.collection")) + .include(FilterBuilder.prefix("io.anuke.arc.scene")) + )); + + Array> classes = Array.with(reflections.getSubTypesOf(Object.class)); + classes.addAll(reflections.getSubTypesOf(Enum.class)); + classes.addAll(whitelist); + classes.sort(Structs.comparing(Class::getName)); + + classes.removeAll(type -> type.isSynthetic() || type.isAnonymousClass() || type.getCanonicalName() == null || Modifier.isPrivate(type.getModifiers()) + || blacklist.contains(s -> type.getName().startsWith(base + "." + s + ".")) || nameBlacklist.contains(type.getSimpleName())); + classes.distinct(); + ObjectSet used = ObjectSet.with(); + + StringBuilder result = new StringBuilder("//Generated class. Do not modify.\n"); + result.append("\n").append(new Fi("core/assets/scripts/base.js").readString()).append("\n"); + for(Class type : classes){ + if(used.contains(type.getPackage().getName()) || nopackage.contains(s -> type.getName().startsWith(s))) continue; + result.append("importPackage(Packages.").append(type.getPackage().getName()).append(")\n"); + used.add(type.getPackage().getName()); + } + + //Log.info(result); + + new Fi("core/assets/scripts/global.js").writeString(result.toString()); + new Fi("core/src/io/anuke/mindustry/mod/ClassAccess.java").writeString(fileTemplate + .replace("$ALLOWED_CLASSES$", classes.toString(", ", type -> type.getName() + ".class")) + .replace("$ALLOWED_CLASS_NAMES$", classes.toString(", ", type -> "\"" + type.getName() + "\""))); + } +} diff --git a/tools/src/io/anuke/mindustry/SquareMarcher.java b/tools/src/io/anuke/mindustry/tools/SquareMarcher.java similarity index 98% rename from tools/src/io/anuke/mindustry/SquareMarcher.java rename to tools/src/io/anuke/mindustry/tools/SquareMarcher.java index 278f9543aa..de5f142df5 100644 --- a/tools/src/io/anuke/mindustry/SquareMarcher.java +++ b/tools/src/io/anuke/mindustry/tools/SquareMarcher.java @@ -1,7 +1,7 @@ -package io.anuke.mindustry; +package io.anuke.mindustry.tools; import io.anuke.arc.Core; -import io.anuke.arc.files.FileHandle; +import io.anuke.arc.files.Fi; import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.Pixmap; import io.anuke.arc.graphics.g2d.Draw; @@ -19,7 +19,7 @@ public class SquareMarcher{ this.buffer = new FrameBuffer(resolution, resolution); } - void render(Pixmap pixmap, FileHandle file){ + void render(Pixmap pixmap, Fi file){ boolean[][] grid = new boolean[pixmap.getWidth()][pixmap.getHeight()]; for(int x = 0; x < pixmap.getWidth(); x++){ diff --git a/tools/src/io/anuke/mindustry/Upscaler.java b/tools/src/io/anuke/mindustry/tools/Upscaler.java similarity index 88% rename from tools/src/io/anuke/mindustry/Upscaler.java rename to tools/src/io/anuke/mindustry/tools/Upscaler.java index 12cc32ee3b..6ba497ff98 100644 --- a/tools/src/io/anuke/mindustry/Upscaler.java +++ b/tools/src/io/anuke/mindustry/tools/Upscaler.java @@ -1,4 +1,4 @@ -package io.anuke.mindustry; +package io.anuke.mindustry.tools; import io.anuke.arc.*; import io.anuke.arc.backends.sdl.*; @@ -24,17 +24,17 @@ public class Upscaler{ Core.batch = new SpriteBatch(); Core.atlas = new TextureAtlas(); Core.atlas.addRegion("white", Pixmaps.blankTextureRegion()); - FileHandle file = Core.files.local(""); + Fi file = Core.files.local(""); Log.info("Upscaling icons..."); Time.mark(); - FileHandle[] list = file.list(); + Fi[] list = file.list(); for(IconSize size : IconSize.values()){ String suffix = size == IconSize.def ? "" : "-" + size.name(); SquareMarcher marcher = new SquareMarcher(size.size); - for(FileHandle img : list){ + for(Fi img : list){ if(img.extension().equals("png")){ marcher.render(new Pixmap(img), img.sibling(img.nameWithoutExtension() + suffix + ".png")); }