From 93c2ca8df1252bbdd69dde5db7d2852d5ad3bf6e Mon Sep 17 00:00:00 2001 From: Timmeey86 Date: Wed, 7 Nov 2018 22:45:57 +0100 Subject: [PATCH 01/34] Reworked and extended german translation (#314) * Reworked existing german translation * Translated all block descriptions * Replaced orange by accent highlighting --- core/assets/bundles/bundle_de.properties | 760 +++++++++++------------ 1 file changed, 380 insertions(+), 380 deletions(-) diff --git a/core/assets/bundles/bundle_de.properties b/core/assets/bundles/bundle_de.properties index 0dd7373d4c..f7db71e4fe 100644 --- a/core/assets/bundles/bundle_de.properties +++ b/core/assets/bundles/bundle_de.properties @@ -2,52 +2,52 @@ text.credits.text = Created by [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[]\n\n[ text.credits = Danksagungen text.discord = Trete dem Mindustry Discord bei! text.link.discord.description = Der offizielle Mindustry Discord Chatroom -text.link.github.description = Spiel Source Code -text.link.dev-builds.description = Entwicklungs- Builds (instabil) +text.link.github.description = Quellcode des Spiels +text.link.dev-builds.description = Entwicklungs-Builds (instabil) text.link.trello.description = Offizielles Trello Board für geplante Features -text.link.itch.io.description = itch.io Seite mit downloads und der Web-Version des Spiels -text.link.google-play.description = Google Play store listing -text.link.wiki.description = offizelles Mindustry wiki -text.linkfail = Fehler beim Öffnen des Links!\nThe URL wurde in die Zwischenablage kopiert. +text.link.itch.io.description = itch.io Seite mit Downloads und der Web-Version des Spiels +text.link.google-play.description = Google Play Store Seite +text.link.wiki.description = Offizelles Mindustry Wiki +text.linkfail = Fehler beim Öffnen des Links!\nDie URL wurde in die Zwischenablage kopiert. text.editor.web = Die Web-Version unterstützt den Editor nicht!\nLade das Spiel herunter um ihn zu benutzen. -text.web.unsupported = Die Web-Version unterstützt den editor nicht! Lade das Spiel herunter um ihn zu benutzen. +text.web.unsupported = Die Web-Version unterstützt dieses Feature nicht! Lade das Spiel herunter um es zu benutzen. text.gameover = Der Kern wurde zerstört. -text.gameover.pvp = Das[accent] {0}[] Team ist Siegreich! +text.gameover.pvp = Das[accent] {0}[] Team ist siegreich! text.sector.gameover = Du hast diesen Sektor verloren. Erneuter Einsatz? -text.sector.retry = Erneut Versuchen +text.sector.retry = Erneut versuchen text.highscore = [YELLOW] Neuer Highscore! -text.wave.lasted = Du hast es bis Welle[accent]{0}[] ausgehalten. -text.level.highscore = High Score: [accent] {0} +text.wave.lasted = Du hast es bis Welle [accent]{0}[] ausgehalten. +text.level.highscore = High Score: [accent]{0} text.level.delete.title = Löschen bestätigen -text.map.delete = Bist du sicher das du die Karte "[accent]{0}[]" löschen möchtest? +text.map.delete = Bist du sicher, dass du die Karte "[accent]{0}[]" löschen möchtest? text.level.select = Level Auswahl text.level.mode = Spielmodus: -text.construction.desktop = Die Desktop Steuerung wurde geändert.\n Zum deselektieren eines Blocks oder das Bauen abzubrechen benutze die [accent] Space Taste[]. -text.construction.title = Block Konstruktions-Anleitung -text.construction = You've just selected [accent]block construction mode[].\n\nTo begin placing, simply tap a valid location near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Shift the selection[] by holding and dragging any block in the selection.\n- [accent]Place blocks in a line[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel construction or selection[] by pressing the X at the bottom left. -text.deconstruction.title = Block Dekonstructions Anleitung -text.deconstruction = You've just selected [accent]block deconstruction mode[].\n\nTo begin breaking, simply tap a block near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin de-constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Remove blocks in an area[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel deconstruction or selection[] by pressing the X at the bottom left. -text.showagain = Zeige die nächste Session nicht nochmal -text.coreattack = < Der Kern wird angegriffen! > +text.construction.desktop = Um einen Block zu deselektieren oder den Bau abzubrechen, [accent]verwende die Leertaste[]. +text.construction.title = Bauanleitung für Blöcke. +text.construction = Du hast soeben den [accent]Block-Baumodus[] ausgewählt.\n\nTippe einfach auf einen gültigen Platz in der Nähe deines Schiffs, um den Bau zu planen.\nSobald du einige Blöcke platziert hast, drücke zum Bestätigen auf den Haken, und dein Schiff wird mit dem Bau beginnen.\n\n- [accent]Entferne Blöcke[] von deiner Auswahl, indem du darauf tippst.\n- [accent]Verschiebe die Selektion[], indem du einen beliebigen Block in der Auswahl gedrückt hältst und verschiebst.\n- [accent]Platziere Blöcke in einer Linie[], indem du einen leeren Platz gedrückt hältst, und in eine Richtung ziehst.\n- [accent]Breche den Bau oder die Auswahl ab[], indem du das X links unten drückst. +text.deconstruction.title = Abbruchanleitung für Blöcke +text.deconstruction = Du hast soeben den [accent]Abbruchmodus für Blöcke[] aktiviert.\n\nUm mit dem Abriss zu beginnen, tippe einfach auf einen Block in der Nähe deines Schiffs.\nSobald du einige Blöcke ausgewählt hast, drücke zum Bestätigen auf den Haken, und dein Schiff wird mit dem Abriss beginnen.\n\n- [accent]Entferne einen Block[] von deiner Selektion, indem du darauf tippst.\n- [accent]Reiße Blöcke in einem Gebiet ab[], indem du einen leeren Platz gedrückt hältst, und in eine Richtung ziehst.\n- [accent]Breche den Abriss or die Selektion ab[], indem du das X links unten drückst. +text.showagain = Nächstes mal nicht mehr anzeigen +text.coreattack = < Die Basis wird angegriffen! > text.unlocks = Freigeschaltet text.savegame = Spiel speichern text.loadgame = Spiel laden text.joingame = Spiel beitreten text.addplayers = Hinzufügen/Entfernen von Spielern -text.customgame = Custom Game +text.customgame = Benutzerdefiniertes Spiel text.sectors = Sektoren -text.sector = Ausgewählter Sektor: [LIGHT_GRAY]{0} +text.sector = Sektor: [LIGHT_GRAY]{0} text.sector.time = Zeit: [LIGHT_GRAY]{0} text.sector.deploy = Einsatz text.sector.abandon = Aufgeben -text.sector.abandon.confirm = Bist du sicher das du allen Fortschritt in diesem Sektor aufgeben willst?\n Diese Aktion kann nicht Rückgängig gemacht werden! +text.sector.abandon.confirm = Bist du sicher, dass du den gesamten Fortschritt in diesem Sektor aufgeben willst?\n Diese Aktion kann nicht rückgängig gemacht werden! text.sector.resume = Fortsetzen text.sector.locked = [scarlet][[Unvollständig] text.sector.unexplored = [accent][[Unerforscht] text.missions = Missionen:[LIGHT_GRAY] {0} text.mission = Mission:[LIGHT_GRAY] {0} -text.mission.main = Haupt Mission:[LIGHT_GRAY] {0} -text.mission.info = Mission Info +text.mission.main = Hauptmission:[LIGHT_GRAY] {0} +text.mission.info = Missionsbeschreibung text.mission.complete = Mission erfolgreich! text.mission.complete.body = Sektor {0},{1} wurde erobert. text.mission.wave = Überlebe [accent]{0}[] Wellen. @@ -59,10 +59,10 @@ text.mission.resource.menu = Erlange {0} x{1} text.mission.resource = Sammele {0}:\n[accent]{1}/{2}[] text.mission.block = Erstelle {0} text.mission.unit = Erstelle {0} Einheiten -text.mission.command = Sende Command {0} an Einheiten -text.mission.linknode = Verbinde Power Knoten +text.mission.command = Sende {0}-Kommando an Einheiten +text.mission.linknode = Verbinde Stromknoten text.mission.display = [accent]Mission:\n[LIGHT_GRAY]{0} -text.mission.mech = Wechsele zu Mech[accent] {0}[] +text.mission.mech = Wechsle zum [accent] {0}[]-Mech text.mission.create = Platziere[accent] {0}[] text.none = text.close = Schließen @@ -81,17 +81,17 @@ text.players.single = {0} Spieler online text.server.closing = [accent]Schließe den Server... text.server.kicked.kick = Du wurdest vom Server gekickt! text.server.kicked.serverClose = Server geschlossen. -text.server.kicked.sectorComplete = Sektor komplett. +text.server.kicked.sectorComplete = Sektor abgeschlossen. text.server.kicked.sectorComplete.text = Deine Mission ist abgeschlossen.\nDer Server wird nun in einen neuen Sektor wechseln. text.server.kicked.clientOutdated = Veralteter Client! Aktualisiere dein Spiel! text.server.kicked.serverOutdated = Veralteter Server! Bitte den Host um ein Update! text.server.kicked.banned = Du wurdest vom Server verbannt. text.server.kicked.recentKick = Du wurdest gerade gekickt.\nWarte bevor du dich wieder verbindest. -text.server.kicked.nameInUse = Da ist bereits ein Spieler \nmit diesem Namen auf dem Server. -text.server.kicked.nameEmpty = Dein Name muss zumindest ein Buchstaben oder eine Zahl enthalten. +text.server.kicked.nameInUse = Es ist bereits ein Spieler \nmit diesem Namen auf dem Server. +text.server.kicked.nameEmpty = Dein Name muss zumindest einen Buchstaben oder eine Zahl enthalten. text.server.kicked.idInUse = Du bist bereits auf dem Server! Anmeldungen mit zwei Accounts sind nicht gestattet. text.server.kicked.customClient = Der Server akzeptiert keine Custom Builds von Mindustry. Lade dir die offizielle Version herunter. -text.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 das Mindustry in deinen Firewall Einstellungen Zugriff auf das lokale Netzwerk hat. +text.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. text.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. text.hostserver = Server hosten text.hostserver.mobile = Host\nGame @@ -102,48 +102,48 @@ text.hosts.discovering = Suche nach LAN-Spielen text.server.refreshing = Server wird aktualisiert text.hosts.none = [lightgray] Keine LAN Spiele gefunden! text.host.invalid = [scarlet] Kann keine Verbindung zum Host herstellen. -text.trace = Trace Player -text.trace.playername = Player name: [accent]{0} +text.trace = Spieler verfolgen +text.trace.playername = Spielername: [accent]{0} text.trace.ip = IP: [accent]{0} -text.trace.id = Unique ID: [accent]{0} +text.trace.id = Eindeutige ID: [accent]{0} text.trace.android = Android Client: [accent]{0} text.trace.modclient = Custom Client: [accent]{0} -text.trace.totalblocksbroken = Total blocks broken: [accent]{0} -text.trace.structureblocksbroken = Structure blocks broken: [accent]{0} -text.trace.lastblockbroken = Last block broken: [accent]{0} -text.trace.totalblocksplaced = Total blocks placed: [accent]{0} -text.trace.lastblockplaced = Last block placed: [accent]{0} -text.invalidid = Invalid client ID! Submit a bug report. +text.trace.totalblocksbroken = Anzahl zerstörter Blöcke: [accent]{0} +text.trace.structureblocksbroken = Anzahl zerstörter Gebäude-Blöcke: [accent]{0} +text.trace.lastblockbroken = Letzter zerstörter Block: [accent]{0} +text.trace.totalblocksplaced = Anzahl platzierter Blöcke: [accent]{0} +text.trace.lastblockplaced = Letzter platzierter Block: [accent]{0} +text.invalidid = Ungültige Client ID! Berichte den Bug. text.server.bans = Bans text.server.bans.none = Keine gebannten Spieler gefunden! text.server.admins = Admins text.server.admins.none = Keine Admins gefunden! text.server.add = Server hinzufügen -text.server.delete = Bist du dir sicher das du diesen Server löschen möchtest? +text.server.delete = Bist du dir sicher, dass du diesen Server löschen möchtest? text.server.hostname = Host: {0} text.server.edit = Server bearbeiten text.server.outdated = [crimson]Veralteter Server![] text.server.outdated.client = [crimson]Veralteter Client![] text.server.version = [lightgray]Version: {0} text.server.custombuild = [yellow]Custom Build -text.confirmban = Bist du sicher das du diesen Spieler verbannen möchtest? -text.confirmkick = Bist du sicher das du diesen Spieler kicken willst? +text.confirmban = Bist du sicher, dass du diesen Spieler verbannen möchtest? +text.confirmkick = Bist du sicher, dass du diesen Spieler kicken willst? text.confirmunban = Bist du sicher, dass du die Verbannung des Spielers rückgängig machen willst? text.confirmadmin = Bist du sicher, dass du diesen Spieler zu einem Admin machen möchtest? text.confirmunadmin = Bis du sicher, dass dieser Spieler kein Admin mehr sein soll? text.joingame.title = Spiel beitreten text.joingame.ip = IP: text.disconnect = Verbindung unterbrochen. -text.disconnect.data = Fehler beim Laden der Welt Daten! -text.connecting = [accent] Verbindet... -text.connecting.data = [accent] Welt Daten werden geladen... +text.disconnect.data = Fehler beim Laden der Welt! +text.connecting = [accent] Verbinde... +text.connecting.data = [accent] Welt wird geladen... text.server.port = Port: -text.server.addressinuse = Adresse bereits in Benutzung! +text.server.addressinuse = Adresse bereits in Verwendung! text.server.invalidport = Falscher Port! text.server.error = [crimson] Fehler beim Hosten des Servers: [accent] {0} -text.save.old = This save is for an older version of the game, and can no longer be used.\n\n[LIGHT_GRAY]Save backwards compatibility will be implemented in the full 4.0 release. +text.save.old = Dieser Spielstand ist von einer älteren Version des Spiels, und kann nicht mehr verwendet werden.\n\n[LIGHT_GRAY]Abwärtskompatibilität von Speicherständen wird in der 4.0 Vollversion hinzugefügt. text.save.new = Neuer Spielstand -text.save.overwrite = Möchten du diesen Spielstand wirklich überschreiben? +text.save.overwrite = Möchtest du diesen Spielstand wirklich überschreiben? text.overwrite = Überschreiben text.save.none = Keine Spielstände gefunden! text.saveload = [accent] Speichern ... @@ -181,26 +181,26 @@ text.copylink = Kopiere Link text.back = Zurück text.quit.confirm = Willst du wirklich aufhören? text.changelog.title = Changelog -text.changelog.loading = Lade Changelog... -text.changelog.error.android = [accent]Beachte: Das Changelog funktioniert manchmal nicht auf Android 4.4 (und älter)!\nDies resultiert aus einem Android bug. -text.changelog.error.ios = [accent]Das Changelog wird aktuell nicht von IOS unterstützt. -text.changelog.error = [scarlet]Fehler beim Laden des Changelog!\nPrüfe deine Internet Verbindung. +text.changelog.loading = Lade Änderungshistorie... +text.changelog.error.android = [accent]Beachte: Die Änderungshistorie funktioniert manchmal nicht auf Android 4.4 (und älter)!\nDies liegt an einem Android bug. +text.changelog.error.ios = [accent]Die Änderungshistorie wird aktuell nicht von IOS unterstützt. +text.changelog.error = [scarlet]Fehler beim Laden der Änderungshistorie!\nPrüfe deine Internetverbindung. text.changelog.current = [yellow][[Current version] text.changelog.latest = [accent][[Latest version] -text.loading = [accent] Wird geladen ... +text.loading = [accent]Wird geladen ... text.saving = [accent]Speichere... -text.wave = [accent] Welle {0} +text.wave = [accent]Welle {0} text.wave.waiting = Welle in {0} text.waiting = Warten... text.waiting.players = Warte auf Spieler... -text.wave.enemies = [LIGHT_GRAY]{0} Gegner Verbleiben -text.wave.enemy = [LIGHT_GRAY]{0} Gegner Verbleiben +text.wave.enemies = [LIGHT_GRAY]{0} Gegner verbleiben +text.wave.enemy = [LIGHT_GRAY]{0} Gegner verbleiben text.loadimage = Bild laden text.saveimage = Bild speichern text.unknown = Unbekannt -text.custom = Custom -text.builtin = Built-In -text.map.delete.confirm = Bist du sicher das du diese Karte löschen willst? Die Aktion kann nicht rückgänig gemacht werden! +text.custom = Benutzerdefiniert +text.builtin = Enthalten +text.map.delete.confirm = Bist du sicher, dass du diese Karte löschen willst? Die Aktion kann nicht rückgänig gemacht werden! text.map.random = [accent]Zufällige Karte text.map.nospawn = Diese Karte hat keine Kerne in denen die Spieler beginnen können! Füge einen [ROYAL]blue[] Kern zu dieser Karte im Editor hinzu. text.map.nospawn.pvp = Diese Karte hat keine gegnerischen Kerne wo Gegner starten könnten! Füge über den Editor [SCARLET] rote[] Kerne zu dieser Karte hinzu. @@ -244,7 +244,7 @@ text.editor.unsaved = [crimson] Du hast Änderungen nicht gespeichert [] Möchte text.editor.resizemap = Grösse der Karte ändern text.editor.mapname = Karten Name text.editor.overwrite = [accent] Warnung! Dies überschreibt eine vorhandene Karte. -text.editor.overwrite.confirm = [scarlet]Warnung![] Eine Karte mit diesem Namen existiert bereits. Bist du sicher das du sie überschreiben willst? +text.editor.overwrite.confirm = [scarlet]Warnung![] Eine Karte mit diesem Namen existiert bereits. Bist du sicher, dass du sie überschreiben willst? text.editor.selectmap = Wähle eine Karte zum Laden: text.width = Breite: text.height = Höhe: @@ -262,13 +262,12 @@ text.editor = Editor text.mapeditor = Karten Editor text.donate = Spenden text.connectfail = [crimson] Verbindung zum Server konnte nicht hergestellt werden: [accent]{0} -text.error.unreachable = Server unreachable. -text.error.invalidaddress = Invalid address. -text.error.timedout = Timed out!\nMake sure the host has port forwarding set up, and that the address is correct! -text.error.mismatch = Packet error:\npossible client/server version mismatch.\nMake sure you and the host have the latest version of Mindustry! -text.error.alreadyconnected = Already connected. -text.error.mapnotfound = Map file not found! -text.error.any = Unkown network error. +text.error.unreachable = Server nicht erreichbar. +text.error.invalidaddress = Ungültige Adresse. +text.error.timedout = Zeitüberschreitung!\nStelle sicher, dass die Portweiterleitung auf dem Host richtig eingerichtet ist, und die Adresse stimmt! +text.error.mismatch = Paketfehler:\nClient und Server passen möglicherweise nicht zusammen.\nStelle sicher, dass du und der Host jeweils die neueste Version von Mindustry haben! +text.error.alreadyconnected = Bereits verbunden. +text.error.any = Unbekannter Netzwerkfehler. text.settings.language = Sprache text.settings.reset = Auf Standard zurücksetzen text.settings.rebind = Zuweisen @@ -277,7 +276,7 @@ text.settings.game = Spiel text.settings.sound = Audio text.settings.graphics = Grafiken text.settings.cleardata = Spieldaten zurücksetzen... -text.settings.clear.confirm = Bist du sicher das du die Spieldaten zurücksetzen willst?\n Diese Aktion kann nicht rückgänig gemacht werden! +text.settings.clear.confirm = Bist du sicher, dass du die Spieldaten zurücksetzen willst?\n Diese Aktion kann nicht rückgänig gemacht werden! text.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. text.settings.clearsectors = Sektoren zurücksetzen text.settings.clearunlocks = Freischaltungen zurücksetzen @@ -289,273 +288,273 @@ text.info.title = [accent]Info text.error.title = [crimson] Ein Fehler ist aufgetreten text.error.crashtitle = Ein Fehler ist aufgetreten! text.blocks.blockinfo = Blockinfo: -text.blocks.powercapacity = Power Kapazität -text.blocks.powershot = Power / Schuss +text.blocks.powercapacity = Kapazität +text.blocks.powershot = Stromverbrauch/Schuss text.blocks.targetsair = Visiert Luft Einheiten an -text.blocks.itemspeed = Units Moved +text.blocks.itemspeed = Beförderte Materialien text.blocks.shootrange = Reichweite -text.blocks.size = Grösse +text.blocks.size = Größe text.blocks.liquidcapacity = Flüssigkeitskapazität -text.blocks.maxitemssecond = Max Gegenstand / Sekunde -text.blocks.powerrange = Power Reichweite -text.blocks.poweruse = Powerbedarf -text.blocks.powerdamage = Power/Schaden -text.blocks.inputitemcapacity = Annahme Kapazität -text.blocks.outputitemcapacity = Ausgabe Kapazität -text.blocks.itemcapacity = Gegenstand Kapazität -text.blocks.basepowergeneration = Base Power Generation -text.blocks.powertransferspeed = Power Transfer -text.blocks.craftspeed = Produktions-Geschwindigkeit -text.blocks.inputliquid = Annahme von Flüssigkeit -text.blocks.inputliquidaux = Aux Flüssigkeit -text.blocks.inputitem = Verwendung von Gegenstand -text.blocks.inputitems = Annahme von Gegenständen -text.blocks.outputitem = Ausgabe von Gegenständen -text.blocks.drilltier = Abbaubar -text.blocks.drillspeed = Grund Abbau Geschwindigkeit -text.blocks.liquidoutput = Flüssigkeits-Ausgabe -text.blocks.liquidoutputspeed = Flüssigkeits-Ausgabe Geschwindigkeit -text.blocks.liquiduse = Flüssigkeits-Verwendung +text.blocks.maxitemssecond = Max Materialien +text.blocks.powerrange = Stromreichweite +text.blocks.poweruse = Stromverbrauch +text.blocks.powerdamage = Stromverbrauch/Schadenspunkt +text.blocks.inputitemcapacity = Annahmekapazität +text.blocks.outputitemcapacity = Ausgabekapazität +text.blocks.itemcapacity = Materialkapazität +text.blocks.basepowergeneration = Basis-Stromerzeugung +text.blocks.powertransferspeed = Stromübertragung +text.blocks.craftspeed = Produktionsgeschwindigkeit +text.blocks.inputliquid = Benötigte Flüssigkeit +text.blocks.inputliquidaux = Optionale Flüssigkeit +text.blocks.inputitem = Akzeptiertes Material +text.blocks.inputitems = Akzeptierte Materialien +text.blocks.outputitem = Erzeugtes Material +text.blocks.drilltier = Abbaubare Erze +text.blocks.drillspeed = Bohrgeschwindigkeit +text.blocks.liquidoutput = Erzeugte Flüssigkeit +text.blocks.liquidoutputspeed = Ausgabegeschwindigkeit +text.blocks.liquiduse = Flüssigkeitsverbrauch text.blocks.coolant = Kühlmittel -text.blocks.coolantuse = Kühlmittel Verwendung -text.blocks.inputliquidfuel = Flüssigkraftstoff -text.blocks.liquidfueluse = Flüssigkraftstoff Benutzung +text.blocks.coolantuse = Kühlmittelverbrauch +text.blocks.inputliquidfuel = Kraftstoff +text.blocks.liquidfueluse = Kraftstoffverbrauch text.blocks.explosive = Hochexplosiv! text.blocks.health = Lebenspunkte text.blocks.inaccuracy = Ungenauigkeit text.blocks.shots = Schüsse -text.blocks.reload = Nachladen +text.blocks.reload = Schüsse/Sekunde text.blocks.inputfuel = Kraftstoff text.blocks.fuelburntime = Kraftstoff Verbrennungs-Zeit text.blocks.inputcapacity = Annahmekapazität text.blocks.outputcapacity = Ausgabekapazität -text.unit.blocks = blocks -text.unit.powersecond = Power Einheit/Sekunde -text.unit.liquidsecond = flüssige Einheit/Sekunde -text.unit.itemssecond = Gegenstand/Sekunde +text.unit.blocks = Blöcke +text.unit.powersecond = Stromverbrauch/Sekunde +text.unit.liquidsecond = Flüssigkeitsverbrauch/Sekunde +text.unit.itemssecond = Materialverbrauch/Sekunde text.unit.pixelssecond = Pixel/Sekunde -text.unit.liquidunits = flüssige Einheiten -text.unit.powerunits = Power Einheiten -text.unit.degrees = grad +text.unit.liquidunits = Flüssigkeitseinheiten +text.unit.powerunits = Stromeinheiten +text.unit.degrees = Grad text.unit.seconds = Sekunden -text.unit.items = Gegenstände -text.category.general = General -text.category.power = Power +text.unit.items = Materialeinheiten +text.category.general = Generell +text.category.power = Strom text.category.liquids = Flüssigkeiten -text.category.items = Gegenstände -text.category.crafting = Herstellung +text.category.items = Materialien +text.category.crafting = Erzeugung text.category.shooting = Schießen -setting.autotarget.name = Auto-Target +setting.autotarget.name = Auto-Zielauswahl setting.fpscap.name = Max FPS setting.fpscap.none = kein setting.fpscap.text = {0} FPS -setting.difficulty.training = training +setting.difficulty.training = Training setting.difficulty.easy = Leicht setting.difficulty.normal = Normal setting.difficulty.hard = Schwer setting.difficulty.insane = Unmöglich setting.difficulty.name = Schwierigkeit -setting.screenshake.name = Bildschirm wackeln +setting.screenshake.name = Bildschirmwackeln setting.effects.name = Effekte anzeigen -setting.sensitivity.name = Kontroller Empfindlichkeit +setting.sensitivity.name = Controller-Empfindlichkeit setting.saveinterval.name = Autosave Häufigkeit setting.seconds = {0} Sekunden setting.fullscreen.name = Vollbild setting.multithread.name = Multithreading setting.fps.name = Zeige FPS setting.vsync.name = VSync -setting.lasers.name = Zeige Powerlaser +setting.lasers.name = Zeige Stromlaser setting.minimap.name = Zeige die Minimap setting.musicvol.name = Musiklautstärke setting.mutemusic.name = Musik stummschalten -setting.sfxvol.name = Audioeffekte Lautstärke +setting.sfxvol.name = Audioeffekt-Lautstärke setting.mutesound.name = Audioeffekte stummschalten -text.keybind.title = Tasten Zuweisen +text.keybind.title = Tasten zuweisen category.general.name = Allgemein -category.view.name = View +category.view.name = Ansicht category.multiplayer.name = Mehrspieler command.attack = Angreifen command.retreat = Rückzug command.patrol = Patrouillieren keybind.press = Drücke eine Taste... keybind.press.axis = Drücke eine Taste oder bewege eine Achse... -keybind.move_x.name = bewege_x -keybind.move_y.name = bewege_y -keybind.select.name = wählen -keybind.break.name = Unterbrechung -keybind.deselect.name = Deselektieren -keybind.shoot.name = Schiess -keybind.zoom_hold.name = zoomen_halten -keybind.zoom.name = zoomen +keybind.move_x.name = X-Achse +keybind.move_y.name = Y-Achse +keybind.select.name = Auswählen/Schießen +keybind.break.name = Abreißen +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 keybind.dash.name = Bindestrich keybind.chat.name = Chat -keybind.player_list.name = player_list -keybind.console.name = console +keybind.player_list.name = Spielerliste +keybind.console.name = Konsole keybind.rotate.name = Drehen -keybind.toggle_menus.name = Wechsele Menüs +keybind.toggle_menus.name = Menüs umschalten keybind.chat_history_prev.name = Chat Historie zurück keybind.chat_history_next.name = Chat Historie vor -keybind.chat_scroll.name = Chat scroll -keybind.drop_unit.name = drop unit -keybind.zoom_minimap.name = Zoom minimap +keybind.chat_scroll.name = Chat scrollen +keybind.drop_unit.name = Einheit absetzen +keybind.zoom_minimap.name = Minimap-Zoom mode.text.help.title = Beschreibung der Modi mode.waves.name = Wellen -mode.waves.description = Der Normale Modus. Begrenzte Ressourcen und automatische Wellen. +mode.waves.description = Der normale Modus. Begrenzte Ressourcen und automatische Wellen. mode.sandbox.name = Sandkasten -mode.sandbox.description = unendliche Ressourcen und kein Timer für Wellen. -mode.custom.warning = Beachte das Blöcke auch in Eigenen Spielen nicht verwendet werden können, solange sie nicht in den Sektoren freigespielt wurden.\n\n[LIGHT_GRAY]Solange ein Block nicht freigeschaltet wurde, ist er nicht sichtbar. -mode.custom.warning.read = Nur um sicherzugehen das du es gelesen hast:\n[scarlet]FREISCHALTUNGEN in Eigenen Spielen übertragen sich NICHT in Sektoren oder andere Modis!\n\n[LIGHT_GRAY](Ich wünschte der Hinweis wäre nicht notwendig, aber offensichtlich ist es das)[] +mode.sandbox.description = Unendliche Ressourcen und kein Timer für Wellen. +mode.custom.warning = [scarlet]FREISCHALTUNGEN IN BENUTZERDEFINIERTEN SPIELEN ODER SERVERN WERDEN NICHT GESPEICHERT.[]\n\nSpiele in Sektoren, um Dinge freizuschalten. +mode.custom.warning.read = Nur um sicherzugehen, dass du es gelesen hast:\n[scarlet]FREISCHALTUNGEN IN BENUTZERDEFINIERTEN SPIELEN ODER SERVERN WERDEN NICHT GESPEICHERT.[]\n\nSpiele in Sektoren, um Dinge freizuschalten.(Ich wünschte, der Hinweis wäre nicht notwendig, aber anscheinend ist er das)[] mode.freebuild.name = Freier Bau -mode.freebuild.description = begrenzte Ressourcen und kein Timer für Wellen. +mode.freebuild.description = Begrenzte Ressourcen und kein Timer für Wellen. mode.pvp.name = PvP mode.pvp.description = Kämpfe gegen andere Spieler local. -content.item.name = Gegenstand -content.liquid.name = Flüssigkeit +content.item.name = Materialien +content.liquid.name = Flüssigkeiten content.unit.name = Einheiten content.recipe.name = Blöcke content.mech.name = Mechs item.stone.name = Stein -item.stone.description = Ein gängiger Rohstoff der für die Zerteilung und Verfeinerung in andere Gegenstände oder geschmolzen als Lava verwendet wird. +item.stone.description = Ein gängiger Rohstoff ,der für die Zerteilung und Verfeinerung in andere Materialien oder geschmolzen als Lava verwendet wird. item.copper.name = Kupfer item.copper.description = Ein nützliches Material. Wird in allen Arten von Blöcken verwendet. item.lead.name = Blei -item.lead.description = Ein grundliegendes Material. Häufig in Elektronik und Flüssigkeits-Transport Blöcken verwendet. +item.lead.description = Ein grundliegendes Material. Häufig in Elektronik und Flüssigkeits-Transport-Blöcken verwendet. item.coal.name = Kohle item.coal.description = Ein sehr häufiger vorkommender Kraftstoff. item.dense-alloy.name = Dichte Legierung -item.dense-alloy.description = Eine Robuste Legierung aus Blei und Kupfer. Findet Verwendung in fortgeschrittenen Transport Blöcken und höherwertigen Bohrern. +item.dense-alloy.description = Eine robuste Legierung aus Blei und Kupfer. Findet Verwendung in fortgeschrittenen Transport-Blöcken und höherwertigen Bohrern. item.titanium.name = Titan -item.titanium.description = Ein seltenes sehr leichtes Metal. Häufig in Flüssigkeits-Transport Blöcken, Abbauanlagen und Flugzeugen verwendet. +item.titanium.description = Ein seltenes, sehr leichtes Metall. Häufig in Flüssigkeits-Transport-Blöcken, Abbauanlagen und Flugzeugen verwendet. item.thorium.name = Uran -item.thorium.description = Ein dichtes radioaktives Metal, welches als strukturelle Unterstützung und nuklearer Kraftstoff verwendet wird. +item.thorium.description = Ein dichtes radioaktives Metall, welches als strukturelle Unterstützung und nuklearer Kraftstoff verwendet wird. item.silicon.name = Silizium -item.silicon.description = Ein sehr nützlicher Halbleiter. Findet Anwendung in Solar Anlagen und komplexer Elektronik. +item.silicon.description = Ein sehr nützlicher Halbleiter. Findet Anwendung in Solaranlagen und komplexer Elektronik. item.plastanium.name = Plastanium item.plastanium.description = Ein leichtes dehnbares Material welches in Flugzeugen und Splittermunition verwendet wird. -item.phase-fabric.name = Phase Fabric -item.phase-fabric.description = A near-weightless substance used in advanced electronics and self-repairing technology. -item.surge-alloy.name = Gewalzte Legierung -item.surge-alloy.description = An advanced alloy with unique electrical properties. +item.phase-fabric.name = Phasengewebe +item.phase-fabric.description = Eine nahezu gewichtslose Substanz, die in fortgeschrittener Elektronik und in selbstreparierender Technologie verwendet wird. +item.surge-alloy.name = Spannungsstoß-Legierung +item.surge-alloy.description = Eine fortgeschrittene Legierung mit einzigartigen elektrischen Eigenschaften. item.biomatter.name = Biomasse item.biomatter.description = Ein Klumpen organischer Brei. Wird für die Umwandlung in Öl oder als grundliegender Kraftstoff verwendet. item.sand.name = Sand -item.sand.description = Ein gäniges Material welches häufig in geschmolzener Form, flüssig oder als Legierung verwendet wird. +item.sand.description = Ein gängiges Material, welches häufig in geschmolzener Form, flüssig oder als Legierung verwendet wird. item.blast-compound.name = Explosive Mischung -item.blast-compound.description = Eine flüchtige Mischung die in Bomben und Sprengstoffen Verwendung findet. Es besteht die Möglichkeit es als Treibstoff zu verwenden, es wird dringend davon abgeraten. -item.pyratite.name = Pyratite -item.pyratite.description = Eine extrem leicht entflammen Substanz. Verwendet in Brand Waffen. +item.blast-compound.description = Eine flüchtige Mischung, die in Bomben und Sprengstoffen Verwendung findet. Es besteht die Möglichkeit, es als Treibstoff zu verwenden, aber dies ist nicht empfehlenswert. +item.pyratite.name = Pyratit +item.pyratite.description = Eine extrem leicht entflammbare Substanz. Findet Verwendeung in Brandwaffen. liquid.water.name = Wasser liquid.lava.name = Lava liquid.oil.name = Öl -liquid.cryofluid.name = Cryofluid +liquid.cryofluid.name = Kryoflüssigkeit mech.alpha-mech.name = Alpha -mech.alpha-mech.weapon = Heavy Repeater -mech.alpha-mech.ability = Drone Swarm -mech.alpha-mech.description = Der Standart Mech. Ist angemessen Schnell und hat ordentlich Schaden. Kann für erweiterte Offensive Fähigkeiten bis zu 3 Drohnen erzeugen. +mech.alpha-mech.weapon = Schwerer Mehrlader +mech.alpha-mech.ability = Drohnenschwarm +mech.alpha-mech.description = Der Standard-Mech. Ist angemessen schnell und hat ordentlich Schaden. Kann für erweiterte offensive Fähigkeiten bis zu 3 Drohnen erzeugen. mech.delta-mech.name = Delta -mech.delta-mech.weapon = Lichtbogen Generator +mech.delta-mech.weapon = Lichtbogen-Generator mech.delta-mech.ability = Entladen -mech.delta-mech.description = Ein schneller, leicht gepanzerter Mech, der für hit-and-run Attacken gemacht wurde. Verursacht wenig Schaden gegen Gebäude aber tötet Gruppen von Gegnern durch seine Lichtbogen Blitz Waffen. +mech.delta-mech.description = Ein schneller, leicht gepanzerter Mech, der für Überfälle gemacht wurde. Verursacht wenig Schaden gegen Gebäude aber tötet Gruppen von Gegnern durch seine Lichtbogen-Waffen. mech.tau-mech.name = Tau -mech.tau-mech.weapon = Restrukt Laser -mech.tau-mech.ability = Reparier Burst -mech.tau-mech.description = Der Support Mech. Kann Blöcke durch Schüsse heilen. Kann Feuer löschen und verbündete in seinem Aktions Radius heilen. +mech.tau-mech.weapon = Restrukturierlaser +mech.tau-mech.ability = Reparatursalve +mech.tau-mech.description = Der Support Mech. Kann Blöcke durch Schüsse heilen. Kann Feuer löschen und verbündete in seinem Aktionsradius heilen. mech.omega-mech.name = Omega -mech.omega-mech.weapon = Schwarm Raketen -mech.omega-mech.ability = Rüstungs Konfiguration -mech.omega-mech.description = Ein klobiger und gut gepanzerter Mech, der für den Angriff in der Front Line gemacht wurde. Seine Rüstungsfähigkeit ermöglicht es ihm 90% des Schadens abzuwehren. +mech.omega-mech.weapon = Raketenschwarm +mech.omega-mech.ability = Rüstungskonfiguration +mech.omega-mech.description = Ein klobiger und gut gepanzerter Mech, der für den Angriff an der Front entwickelt wurde. Seine Rüstungsfähigkeit ermöglicht es ihm, 90% des Schadens abzuwehren. mech.dart-ship.name = Dart -mech.dart-ship.weapon = Repeater -mech.dart-ship.description = Das standard Schiff. Einigermaßen schnell und leicht. Hat nur wenig offensiv Kraft und geringe Abbaugeschwindigkeit. +mech.dart-ship.weapon = Mehrlader +mech.dart-ship.description = Das Standard-Schiff. Einigermaßen schnell und leicht. Hat nur wenig Offensivkraft und geringe Erzabbaugeschwindigkeit. mech.javelin-ship.name = Javelin -mech.javelin-ship.description = Ein hit-and-run Schiff. Anfänglich träge kann es auf hohe Geschwindigkeiten beschleunigen um an gegnerischen Aussenposten vorbei zu fliegen und dabei mit seinen Blitz Waffen und Raketen große Mengen an Schaden verursachen. -mech.javelin-ship.weapon = Burst Missiles -mech.javelin-ship.ability = Discharge Booster +mech.javelin-ship.description = Ein Schiff für Überfälle. Anfänglich träge, kann es auf hohe Geschwindigkeiten beschleunigen um an gegnerischen Aussenposten vorbei zu fliegen und dabei mit seinen Blitzwaffen und Raketen große Mengen an Schaden verursachen. +mech.javelin-ship.weapon = Raketensalve +mech.javelin-ship.ability = Statische Entladung mech.trident-ship.name = Trident mech.trident-ship.description = Ein schwerer Bomber, solide gepanzert. -mech.trident-ship.weapon = Bomb Bay +mech.trident-ship.weapon = Bombenschacht mech.glaive-ship.name = Glaive -mech.glaive-ship.description = Ein großes gut gepanzertes Gunship. Ausgerüstet mit einer Brand Waffe. Gute Beschleunigung und maximal Geschwindigkeit. -mech.glaive-ship.weapon = Flame Repeater +mech.glaive-ship.description = Ein großes, gut gepanzertes Gunship. Ausgerüstet mit einer Brandwaffe. Gute Beschleunigung und maximale Geschwindigkeit. +mech.glaive-ship.weapon = Flammen-Mehrlader text.item.explosiveness = [LIGHT_GRAY]Explosivität: {0} text.item.flammability = [LIGHT_GRAY]Entflammbarkeit: {0} text.item.radioactivity = [LIGHT_GRAY]Radioaktivität: {0} -text.item.fluxiness = [LIGHT_GRAY]Fluss Power: {0} -text.unit.health = [LIGHT_GRAY]Gesundheit: {0} +text.item.fluxiness = [LIGHT_GRAY]Strömungskraft: {0} +text.unit.health = [LIGHT_GRAY]Lebenskraft: {0} text.unit.speed = [LIGHT_GRAY]Geschwindigkeit: {0} text.mech.weapon = [LIGHT_GRAY]Waffe: {0} text.mech.armor = [LIGHT_GRAY]Rüstung: {0} -text.mech.itemcapacity = [LIGHT_GRAY]Gegenstands Kapazität: {0} -text.mech.minespeed = [LIGHT_GRAY]Mining Geschwindigkeit: {0} -text.mech.minepower = [LIGHT_GRAY]Mining Power: {0} +text.mech.itemcapacity = [LIGHT_GRAY]Materialkapazität: {0} +text.mech.minespeed = [LIGHT_GRAY]Erzabbaugeschwindigkeit: {0} +text.mech.minepower = [LIGHT_GRAY]Erzabbaukraft: {0} text.mech.ability = [LIGHT_GRAY]Fähigkeit: {0} -text.liquid.heatcapacity = [LIGHT_GRAY]Hitze Kapazität: {0} +text.liquid.heatcapacity = [LIGHT_GRAY]Wärmekapazität: {0} text.liquid.viscosity = [LIGHT_GRAY]Viskosität: {0} text.liquid.temperature = [LIGHT_GRAY]Temperatur: {0} -block.spawn.name = Gegner Spawn -block.core.name = Kern -block.metalfloor.name = Metal Boden +block.spawn.name = Gegnerischer Startpunkt +block.core.name = Basis +block.metalfloor.name = Metallboden block.deepwater.name = Tiefes Wasser block.water.name = Wasser block.lava.name = Lava -block.tar.name = Tar +block.tar.name = Teer block.blackstone.name = Schwarzer Stein block.stone.name = Stein block.dirt.name = Dreck block.sand.name = Sand block.ice.name = Eis block.snow.name = Schnee -block.grass.name = Grass +block.grass.name = Gras block.shrub.name = Busch block.rock.name = Fels block.blackrock.name = Schwarzer Fels -block.icerock.name = Eis Fels -block.copper-wall.name = Kupfer Mauer -block.copper-wall-large.name = Grosse Kupfer Mauer -block.dense-alloy-wall.name = Dichte Legierungs Mauer -block.dense-alloy-wall-large.name = Grosse Dichte Legierungs Mauer -block.phase-wall.name = Phase Mauer -block.phase-wall-large.name = Grosse Phase Mauer -block.thorium-wall.name = Thorium Mauer -block.thorium-wall-large.name = Große Thorium Mauer +block.icerock.name = Eisfels +block.copper-wall.name = Kupfermauer +block.copper-wall-large.name = Große Kupfermauer +block.dense-alloy-wall.name = Dichte Legierungsmauer +block.dense-alloy-wall-large.name = Große dichte Legierungsmauer +block.phase-wall.name = Phasenmauer +block.phase-wall-large.name = Große Phasenmauer +block.thorium-wall.name = Thorium-Mauer +block.thorium-wall-large.name = Große Thorium-Mauer block.door.name = Tür -block.door-large.name = grosse Tür +block.door-large.name = Große Tür block.duo.name = Duo block.scorch.name = Scorch block.hail.name = Hail block.lancer.name = Lancer block.conveyor.name = Förderband -block.titanium-conveyor.name = Titanium Transportband +block.titanium-conveyor.name = Titan-Förderband block.junction.name = Kreuzung block.router.name = Verteiler -block.distributor.name = Verteiler +block.distributor.name = Großer Verteiler block.sorter.name = Sortierer -block.sorter.description = Sortiert Gegenstände. Wenn ein Gegenstand der Auswahl entspricht darf er vorbei. Andernfalls wird er links oder rechts ausgegeben. -block.overflow-gate.name = Overflow Gate -block.overflow-gate.description = Eine Kombination aus Splitter und router der nur Gegenstände nach links oder rechts ausgibt falls der Weg gerade aus blockiert ist. +block.sorter.description = Sortiert Materialien. Wenn ein Gegenstand der Auswahl entspricht, darf er vorbei. Andernfalls wird er links oder rechts ausgegeben. +block.overflow-gate.name = Überlauftor +block.overflow-gate.description = Ein Verteiler, der nur Materialien nach links oder rechts ausgibt, falls der Weg gerade aus blockiert ist. block.smelter.name = Schmelzer -block.arc-smelter.name = Lichtbogen Schmelzer -block.silicon-smelter.name = Silizium Schmelzer -block.phase-weaver.name = Phase Weaver +block.arc-smelter.name = Lichtbogen-Schmelzer +block.silicon-smelter.name = Silizium-Schmelzer +block.phase-weaver.name = Phasenweber block.pulverizer.name = Pulverisierer -block.cryofluidmixer.name = Cryofluid Mixer +block.cryofluidmixer.name = Kryoflüssigkeitsmixer block.melter.name = Schmelzer block.incinerator.name = Verbrennungsanlage -block.biomattercompressor.name = Biomassen Verdichter -block.separator.name = Seperierer +block.biomattercompressor.name = Biomassenverdichter +block.separator.name = Separierer block.centrifuge.name = Zentrifuge -block.power-node.name = Power Knoten -block.power-node-large.name = Grosser Power Knoten +block.power-node.name = Stromknoten +block.power-node-large.name = Großer Stromknoten block.battery.name = Batterie -block.battery-large.name = Grosse Batterie -block.combustion-generator.name = Verbrennungs-Generator -block.turbine-generator.name = Turbinen Generator +block.battery-large.name = Große Batterie +block.combustion-generator.name = Verbrennungsgenerator +block.turbine-generator.name = Turbinengenerator block.mechanical-drill.name = Mechanischer Bohrer block.pneumatic-drill.name = Pneumatischer Bohrer -block.laser-drill.name = Laser Bohrer -block.water-extractor.name = Wasser Extraktor +block.laser-drill.name = Laser-Bohrer +block.water-extractor.name = Wasser-Extraktor block.cultivator.name = Kultivierer block.alpha-mech-pad.name = Alpha Mech Pad block.dart-ship-pad.name = Dart Ship Pad @@ -567,57 +566,57 @@ block.omega-mech-pad.name = Omega Mech Pad block.tau-mech-pad.name = Tau Mech Pad block.conduit.name = Leitungsrohr block.mechanical-pump.name = Mechanische Pumpe -block.itemsource.name = Gegenstands Quelle -block.itemvoid.name = Gegenstand Void -block.liquidsource.name = Flüssigkeits-Quelle -block.powervoid.name = Power Void -block.powerinfinite.name = Power Unendlich +block.itemsource.name = Materialquelle +block.itemvoid.name = Materialschlucker +block.liquidsource.name = Flüssigkeitsquelle +block.powervoid.name = Stromsenke +block.powerinfinite.name = Unendliche Stromquelle block.unloader.name = Entlader block.vault.name = Tresor block.wave.name = Welle -block.swarmer.name = Swarmer -block.salvo.name = Salvo -block.ripple.name = Ripple -block.phase-conveyor.name = Phase Transportband -block.bridge-conveyor.name = Brücken Transportband -block.plastanium-compressor.name = Plastanium Verdichter -block.pyratite-mixer.name = Pyratite Mixer -block.blast-mixer.name = Blast Mixer -block.solidifer.name = Solidifer +block.swarmer.name = Schwärmer +block.salvo.name = Salve +block.ripple.name = Riffel +block.phase-conveyor.name = Phasen-Transportband +block.bridge-conveyor.name = Brücken-Transportband +block.plastanium-compressor.name = Plastanium-Verdichter +block.pyratite-mixer.name = Pyratit-Mixer +block.blast-mixer.name = Sprengmixer +block.solidifer.name = Verhärter block.solar-panel.name = Solar Panel -block.solar-panel-large.name = Grosses Solar Panel +block.solar-panel-large.name = Großes Solar Panel block.oil-extractor.name = Oil Extraktor -block.spirit-factory.name = Spirit Drone Fabrik -block.phantom-factory.name = Phantom Drone Fabrik -block.wraith-factory.name = Wraith Fighter Fabrik -block.ghoul-factory.name = Ghoul Bomber Fabrik -block.dagger-factory.name = Dagger Mech Fabrik -block.titan-factory.name = Titan Mech Fabrik -block.fortress-factory.name = Fortress Mech Fabrik -block.revenant-factory.name = Revenant Fighter Fabrik -block.repair-point.name = Reparatur Punkt -block.pulse-conduit.name = Pulse Rohr -block.phase-conduit.name = Phase Rohr -block.liquid-router.name = Liquid Router -block.liquid-tank.name = Liquid Tank -block.liquid-junction.name = Liquid Kreuzung -block.bridge-conduit.name = Brücken Rohr +block.spirit-factory.name = Spirit-Drohnenfabrik +block.phantom-factory.name = Phantom-Drohnenfabrik +block.wraith-factory.name = Wraith Fighter-Fabrik +block.ghoul-factory.name = Ghoul Bomber-Fabrik +block.dagger-factory.name = Dagger Mech-Fabrik +block.titan-factory.name = Titan Mech-Fabrik +block.fortress-factory.name = Fortress Mech-Fabrik +block.revenant-factory.name = Revenant Fighter-Fabrik +block.repair-point.name = Reparaturpunkt +block.pulse-conduit.name = Impulskanal +block.phase-conduit.name = Phasenkanal +block.liquid-router.name = Flüssigkeits-Router +block.liquid-tank.name = Flüssigkeitstank +block.liquid-junction.name = Flüssigkeits-Kreuzung +block.bridge-conduit.name = Kanalbrücke block.rotary-pump.name = Rotierende Pumpe -block.thorium-reactor.name = Thorium Reaktor -block.command-center.name = Kommando Zentrum -block.mass-driver.name = Mass Driver -block.blast-drill.name = Spreng Bohrer +block.thorium-reactor.name = Thorium-Reaktor +block.command-center.name = Kommandozentrum +block.mass-driver.name = Massenbeschleuniger +block.blast-drill.name = Sprengbohrer block.thermal-pump.name = Thermische Pumpe block.thermal-generator.name = Thermischer Generator -block.alloy-smelter.name = Legierungs Schmeltzer -block.mend-projector.name = Mend Projector -block.surge-wall.name = Surge Mauer -block.surge-wall-large.name = Grosse Surge Mauer +block.alloy-smelter.name = Legierungsschmeltzer +block.mend-projector.name = Reparaturprojektor +block.surge-wall.name = Spannungsstoß-Mauer +block.surge-wall-large.name = Große Spannungsstoß-Mauer block.cyclone.name = Cyclone block.fuse.name = Fuse -block.shock-mine.name = Schock Mine -block.overdrive-projector.name = Overdrive Projektor -block.force-projector.name = Force Projektor +block.shock-mine.name = Schock-Mine +block.overdrive-projector.name = Beschleunigungs-Projektor +block.force-projector.name = Kraftfeld-Projektor block.arc.name = Arc block.rtg-generator.name = RTG Generator block.spectre.name = Spectre @@ -630,29 +629,29 @@ team.orange.name = Orange team.none.name = Grau team.green.name = Grün team.purple.name = Lila -unit.alpha-drone.name = Alpha Drone -unit.spirit.name = Spirit Drone -unit.spirit.description = Die anfängliche Drohne. Sie wird gewöhnlich im Kern erzeugt. Baut automatisch Erz ab, sammelt Gegenstände und repariert Blöcke. -unit.phantom.name = Phantom Drone -unit.phantom.description = Eine fortgeschrittene Drohne. Baut automatisch Erz ab, sammelt Gegenstände und repariert Blöcke. Signifikant effizienter als die Drohne. +unit.alpha-drone.name = Alpha Drohne +unit.spirit.name = Spirit Drohne +unit.spirit.description = Die anfängliche Drohne. Sie wird gewöhnlich in der Basis Erz ab, sammelt Materialien und repariert Blöcke. +unit.phantom.name = Phantom Drohne +unit.phantom.description = Eine fortgeschrittene Drohne. Baut automatisch Erz ab, sammelt Materialien und repariert Blöcke. Deutlich effizienter als die Drohne. unit.dagger.name = Dagger -unit.dagger.description = Eine Standard Bodeneinheit. Nützlich in Schwärmen. +unit.dagger.description = Eine Standard-Bodeneinheit. Nützlich in Schwärmen. unit.titan.name = Titan -unit.titan.description = Eine fortgeschrittene gepanzerte Bodeneinheit. Benutzt Carbide als Munition. Kann sowohl Boden als auch Luft Einheiten angreifen. +unit.titan.description = Eine fortgeschrittene gepanzerte Bodeneinheit. Greift sowohl Boden- als auch Luftziele an. unit.ghoul.name = Ghoul Bomber -unit.ghoul.description = Ein schwerer Flächen Bomber. Benutzt Explosives Gemisch und Pyratite als Munition. +unit.ghoul.description = Ein schwerer Flächenbomber. unit.wraith.name = Wraith Fighter -unit.wraith.description = Eine schnelle Abfangjäger Einheit. +unit.wraith.description = Eine schneller Abfangjäger. unit.fortress.name = Fortress -unit.fortress.description = Eine schwere Artillerie Boden-Einheit. +unit.fortress.description = Eine schwere Artillerie-Bodeneinheit. unit.revenant.name = Revenant -unit.revenant.description = Eine schwere Laser Platform. +unit.revenant.description = Eine schwere Laser-Platform. tutorial.begin = Deine Mission ist es den [LIGHT_GRAY]Gegner[] auszurotten.\n\n Beginne damit [accent] Kupfer abzubauen[]. Beginne in dem du auf ein Kupfer Vorkommen nahe deines Kerns klickst. tutorial.drill = Manuelles Abbauen von Ressourcen ist ineffizient.\n[accent]Bohrer[] können automatisch abbauen.\n Platziere einen auf einem Kupfer Vorkommen. -tutorial.conveyor = [accent]Transportbänder[] werden dazu benutzt Gegenstände zum Kern zu transportieren.\n Erstelle eine Reihe von Transportbändern zum Kern. +tutorial.conveyor = [accent]Transportbänder[] werden dazu benutzt Materialien zum Kern zu transportieren.\n Erstelle eine Reihe von Transportbändern zum Kern. tutorial.morecopper = Du brauchst [accent]mehr Kupfer[]!\n\nEntweder du baust es manuell ab, oder du platzierst weitere Bohrer. -tutorial.turret = Wir benötigen Verteidigung gegen den [LIGHT_GRAY] Gegner[].\n Baue einen Duo Turm nahe deiner Basis. -tutorial.drillturret = Der Duo Turm benötigt[accent] Kupfer[] als Munition. Platziere einen Bohrer neben dem Turm, um ihn mit Kupfer zu versorgen. +tutorial.Geschützturm = Wir benötigen Verteidigung gegen den [LIGHT_GRAY] Gegner[].\n Baue einen Duo Turm nahe deiner Basis. +tutorial.drillGeschützturm = Der Duo Turm benötigt[accent] Kupfer[] als Munition. Platziere einen Bohrer neben dem Turm, um ihn mit Kupfer zu versorgen. tutorial.waves = Der [LIGHT_GRAY] Gegner[] greift an.\n\nVerteidige deinen Kern 2 Wellen lang. Bau mehr Türme. tutorial.lead = Mehr Erz ist verfügbar. Finde Blei und bau es ab.\n\n Klicke auf deine Einheit und ziehe die Maus auf den Kern um Ressourcen zu übertragen. tutorial.smelter = Kupfer und Blei sind schwache Metalle.\n Super [accent]dichte Legierung [] kann in einem Schmeltzer erzeugt werden.\n\n Bau einen. @@ -661,120 +660,121 @@ tutorial.siliconsmelter = Der Kern wird nun [accent]spirit drohnen[] erstellen. tutorial.silicondrill = Silizium benötigt [accent]Kohle[] und [accent]Sand[].\n Fange damit an die Bohrer zu platzieren. tutorial.generator = Diese Technologie benötigt power.\n Erstelle einen Verbrennungs-Generator dafür. tutorial.generatordrill = Verbrennungs Generatoren benötigen Kraftstoff.\nBenutze Kohle aus einem Bohrer als Kraftstoff. -tutorial.node = Power muss transportiert werden.\nErstelle einen [accent]Power Knoten[] nahe deinem Verbrennungs Generator um seine Power zu transportieren. -tutorial.nodelink = Power kann über verbundene Power Blocks, Generatoren oder Power Knoten transferierd werden.\n\n Verbinde die Power in dem du auf den Knoten klickst und dann den Generator und den Silizium Schmeltzer auswählst. +tutorial.node = Power muss transportiert werden.\nErstelle einen [accent]Stromknoten[] nahe deinem Verbrennungs Generator um seine Power zu transportieren. +tutorial.nodelink = Power kann über verbundene Power Blocks, Generatoren oder Stromknoten transferierd werden.\n\n Verbinde die Power in dem du auf den Knoten klickst und dann den Generator und den Silizium Schmeltzer auswählst. tutorial.silicon = Silizium wird produziert. Produziere einiges.\n\n Verbesserungen am Produktionssystem werden empfohlen. tutorial.daggerfactory = Konstruiere eine Dagger Mech Fabrik.\n\n Diese wird verwendet um Angreifende Mechs zu erstellen. -tutorial.router = Fabriken benötigen Ressourcen um zu funktionieren.\n Platziere ein Router um Gegenstände auf Transportbändern aufzuteilen. -tutorial.dagger = Verbinde die Fabrik mit einem Power Knoten. Wenn alle Voraussetzungen gegeben sind, beginnt die Fabrik Mechs zu konstruieren.\n\n Platziere mehr Bohrer und Transportbänder um die Versorgung der Fabrik zu sichern. +tutorial.router = Fabriken benötigen Ressourcen um zu funktionieren.\n Platziere ein Router um Materialien auf Transportbändern aufzuteilen. +tutorial.dagger = Verbinde die Fabrik mit einem Stromknoten. Wenn alle Voraussetzungen gegeben sind, beginnt die Fabrik Mechs zu konstruieren.\n\n Platziere mehr Bohrer und Transportbänder um die Versorgung der Fabrik zu sichern. tutorial.battle = Der[LIGHT_GRAY] Gegner[] hat seinen Kern offenbart.\nZerstöre ihn mit deiner Einheit und den Dagger Mechs. -block.copper-wall.description = A cheap defensive block.\nUseful for protecting the core and turrets in the first few waves. -block.copper-wall-large.description = A cheap defensive block.\nUseful for protecting the core and turrets in the first few waves.\nSpans multiple tiles. -block.dense-alloy-wall.description = A standard defensive block.\nAdequate protection from enemies. -block.dense-alloy-wall-large.description = A standard defensive block.\nAdequate protection from enemies.\nSpans multiple tiles. -block.thorium-wall.description = A strong defensive block.\nGood protection from enemies. -block.thorium-wall-large.description = A strong defensive block.\nGood protection from enemies.\nSpans multiple tiles. -block.phase-wall.description = Not as strong as a thorium wall but will deflect bullets unless they are too powerful. -block.phase-wall-large.description = Not as strong as a thorium wall but will deflect bullets unless they are too powerful.\nSpans multiple tiles. -block.surge-wall.description = The strongest defensive block.\nHas a small chance of triggering lightning towards the attacker. -block.surge-wall-large.description = The strongest defensive block.\nHas a small chance of triggering lightning towards the attacker.\nSpans multiple tiles. -block.door.description = A small door that can be opened and closed by tapping on it.\nIf opened, enemies can shoot and move through. -block.door-large.description = A large door that can be opened and closed by tapping on it.\nIf opened, enemies can shoot and move through.\nSpans multiple tiles. -block.mend-projector.description = Periodically heals buildings in its vicinity. -block.overdrive-projector.description = Increases the speed of nearby buildings like drills and conveyors. -block.force-projector.description = Creates a hexagonal force field around itself, protecting buildings and units inside from damage through bullets. -block.shock-mine.description = Damages enemies stepping on the mine. Nearly invisible to the enemy. -block.duo.description = A small, cheap turret. -block.arc.description = A small turret which shoots electricity in a random arc towards the enemy. -block.hail.description = A small artillery turret. -block.lancer.description = A medium-sized turret which shoots charged electricity beams. -block.wave.description = A medium-sized rapid-fire turret which shoots liquid bubbles. -block.salvo.description = A medium-sized turret which fires shots in salvos. -block.swarmer.description = A medium-sized turret which shoots burst missiles. -block.ripple.description = A large artillery turret which fires several shots simultaneously. -block.cyclone.description = A large rapid fire turret. -block.fuse.description = A large turret which shoots powerful short-range beams. -block.spectre.description = A large turret which shoots two powerful bullets at once. -block.meltdown.description = A large turret which shoots powerful long-range beams. -block.conveyor.description = Basic item transport block. Moved items forward and automatically deposits them into turrets or crafters. Rotatable. -block.titanium-conveyor.description = Advanced item transport block. Moves items faster than standard conveyors. -block.phase-conveyor.description = Advanced item transport block. Uses power to teleport items to a connected phase conveyor over several tiles. -block.junction.description = Acts as a bridge for two crossing conveyor belts. Useful in situations with two different conveyors carrying different materials to different locations. -block.mass-driver.description = Ultimate item transport block. Collects several items and then shoots them to another mass driver over a long range. -block.smelter.description = Burns coal for smelting copper and lead into dense alloy. -block.arc-smelter.description = Smelts copper and lead into dense alloy by using an external power source. -block.silicon-smelter.description = Reduces sand with highly pure coke in order to produce silicon. -block.plastanium-compressor.description = Produces plastanium from oil and titanium. -block.phase-weaver.description = Produces phase fabric from radioactive thorium and high amounts of sand. -block.alloy-smelter.description = Produces surge alloy from titanium, lead, silicon and copper. -block.pulverizer.description = Crushes stone into sand. Useful when there is a lack of natural sand. -block.pyratite-mixer.description = Mixes coal, lead and sand into highly flammable pyratite. -block.blast-mixer.description = Uses oil for transforming pyratite into the less flammable but more explosive blast compound. -block.cryofluidmixer.description = Combines water and titanium into cryofluid which is much more efficient for cooling. -block.solidifer.description = Cools lava to stone at a fast pace. -block.melter.description = Heats up stone to very high temperatures to obtain lava. -block.incinerator.description = Gets rid of any excess item or liquid. -block.biomattercompressor.description = Compresses biomatter in order to retrieve oil. -block.separator.description = Exposes stone to water pressure in order to obtain various minerals contained in the stone. -block.centrifuge.description = More efficient than the separator, but also more expensive to build and requires power. -block.power-node.description = Transmits power to connected nodes. Up to four power sources, sinks or nodes can be connected. The node will receive power from or supply power to any adjacent blocks. -block.power-node-large.description = Has a larger radius than the power node and connects to up to six power sources, sinks or nodes. -block.battery.description = Stores power whenever there is an abundance and provides power whenever there is a shortage, as long as there is capacity left. -block.battery-large.description = Stores much more power than a regular battery. -block.combustion-generator.description = Generates power by burning oil or flammable materials. -block.turbine-generator.description = More efficient than a combustion generator, but requires additional water. -block.thermal-generator.description = Generates a large amount of power from lava. -block.solar-panel.description = Provides a small amount of power from the sun. -block.solar-panel-large.description = Provides much better power supply than a standard solar panel, but is also much more expensive to build. -block.thorium-reactor.description = Generates huge amounts of power from highly radioactive thorium. Requires constant cooling. Will explode violently if insufficient amounts of coolant are supplied. -block.rtg-generator.description = A radioisotope thermoelectric generator which does not require cooling but provides less power than a thorium reactor. -block.unloader.description = Unloads items from a container, vault or core onto a conveyor or directly into an adjacent block. The type of item to be unloaded can be changed by tapping on the unloader. -block.container.description = Stores a small amount of items. Use it for creating buffers when there is a non-constant demand of materials. An[LIGHT_GRAY] unloader[] can be used to retrieve items from the container. -block.vault.description = Stores a large amount of items. Use it for creating buffers when there is a non-constant demand of materials. An[LIGHT_GRAY] unloader[] can be used to retrieve items from the vault. -block.mechanical-drill.description = A cheap drill. When placed on appropriate tiles, outputs items at a slow pace indefinitely. -block.pneumatic-drill.description = An improved drill which is faster and able to process harder materials by making use of air pressure. -block.laser-drill.description = Allows drilling even faster through laser technology, but requires power. Additionally, radioactive thorium can be retrieved with this drill. -block.blast-drill.description = The ultimate drill. Requires large amounts of power. -block.water-extractor.description = Extracts water from the ground. Use it when there is no lake nearby. -block.cultivator.description = Cultivates the soil with water in order to obtain biomatter. -block.oil-extractor.description = Uses large amounts of power in order to extract oil from sand. Use it when there is no direct source of oil nearby. -block.dart-ship-pad.description = Leave your current vessel and change into a basic fighter aircraft.\nUse the pad by double tapping while standing on it. -block.trident-ship-pad.description = Leave your current vessel and change into a reasonably well armored heavy bomber.\nUse the pad by double tapping while standing on it. -block.javelin-ship-pad.description = Leave your current vessel and change into a strong and fast interceptor with lightning weapons.\nUse the pad by double tapping while standing on it. -block.glaive-ship-pad.description = Leave your current vessel and change into a large, well-armored gunship.\nUse the pad by double tapping while standing on it. -block.tau-mech-pad.description = Leave your current vessel and change into a support mech which can heal friendly buildings and units.\nUse the pad by double tapping while standing on it. -block.delta-mech-pad.description = Leave your current vessel and change into a fast, lightly-armored mech made for hit-and-run attacks.\nUse the pad by double tapping while standing on it. -block.omega-mech-pad.description = Leave your current vessel and change into a bulky and well-armored mech, made for front-line assaults.\nUse the pad by double tapping while standing on it. -block.spirit-factory.description = Produces light drones which mine ore and repair blocks. -block.phantom-factory.description = Produces advanced drone units which are significantly more effective than a spirit drone. -block.wraith-factory.description = Produces fast, hit-and-run interceptor units. -block.ghoul-factory.description = Produces heavy carpet bombers. -block.dagger-factory.description = Produces basic ground units. -block.titan-factory.description = Produces advanced, armored ground units. -block.fortress-factory.description = Produces heavy artillery ground units. -block.revenant-factory.description = Produces heavy laser ground units. -block.repair-point.description = Continuously heals the closest damaged unit in its vicinity. -block.command-center.description = Allows changing friendly AI behavior. Currently, attack, retreat and patrol commands are supported. -block.conduit.description = Basic liquid transport block. Works like a conveyor, but with liquids. Best used with extractors, pumps or other conduits. -block.pulse-conduit.description = Advanced liquid transport block. Transports liquids faster and stores more than standard conduits. -block.phase-conduit.description = Advanced liquid transport block. Uses power to teleport liquids to a connected phase conduit over several tiles. -block.liquid-router.description = Accepts liquids from one direction and outputs them to up to 3 other directions equally. Can also store a certain amount of liquid. Useful for splitting the liquids from one source to multiple targets. -block.liquid-tank.description = Stores a large amount of liquids. Use it for creating buffers when there is a non-constant demand of materials or as a safeguard for cooling vital blocks. -block.liquid-junction.description = Acts as a bridge for two crossing conduits. Useful in situations with two different conduits carrying different liquids to different locations. -block.bridge-conduit.description = Advanced liquid transport block. Allows transporting liquids over up to 3 tiles of any terrain or building. -block.mechanical-pump.description = A cheap pump with slow output, but no power consumption. -block.rotary-pump.description = An advanced pump which doubles up speed by using power. -block.thermal-pump.description = The ultimate pump. Three times as fast as a mechanical pump and the only pump which is able to retrieve lava. -block.router.description = Accepts items from one direction and outputs them to up to 3 other directions equally. Useful for splitting the materials from one source to multiple targets. -block.distributor.description = An advanced router which splits items to up to 7 other directions equally. -block.bridge-conveyor.description = Advanced item transport block. Allows transporting items over up to 3 tiles of any terrain or building. -block.alpha-mech-pad.description = When given enough power, rebuilds your ship into the[accent] Alpha[] mech. -block.itemsource.description = Infinitely outputs items. Sandbox only. -block.liquidsource.description = Infinitely outputs liquids. Sandbox only. -block.itemvoid.description = Destroys any items which go into it without using power. Sandbox only. -block.powerinfinite.description = Infinitely outputs power. Sandbox only. -block.powervoid.description = Voids all power inputted into it. Sandbox only. -liquid.water.description = Commonly used for cooling machines and waste processing. -liquid.lava.description = Can be transformed into[LIGHT_GRAY] stone[], used for generating power or used as ammo for certain turrets. -liquid.oil.description = Can be burnt, exploded or used as a coolant. -liquid.cryofluid.description = The most efficient liquid for cooling things down. +block.core.description = Das wichtigste Gebäude im Spiel +block.copper-wall.description = Ein günstiger Verteidigungsblock.\nNützlich, um die Basis und Türme in den ersten Wellen zu beschützen. +block.copper-wall-large.description = Ein günstiger Verteidigungsblock.\nNützlich, um die Basis und Türme in den ersten Wellen zu beschützen.\nBenötigt mehrere Kacheln. +block.dense-alloy-wall.description = Ein Standard-Verteidigungsblock.\nAngemessener Schutz vor Feinden. +block.dense-alloy-wall-large.description = Ein Standard-Verteidigungsblock.\nAngemessener Schutz vor Feinden.\nBenötigt mehrere Kacheln. +block.thorium-wall.description = Ein starker Verteidigungsblock.\nGuter Schutz vor Feinden. +block.thorium-wall-large.description = Ein starker Verteidigungsblock.\nGuter Schutz vor Feinden.\nBenötigt mehrere Kacheln. +block.phase-wall.description = Nicht so stark wie eine Thorium-Mauer, aber reflektiert Schüsse bis zu einer gewissen Stärke. +block.phase-wall-large.description = Nicht so stark wie eine Thorium-Mauer, aber reflektiert Schüsse bis zu einer gewissen Stärke.\nBenötigt mehrere Kacheln. +block.surge-wall.description = Der stärkste Verteidigungsblock.\nHat eine kleine Chance, bei einem Schuss einen Lichtbogen in Richtung angreifer auszulösen. +block.surge-wall-large.description = Der stärkste Verteidigungsblock.\nHat eine kleine Chance, bei einem Schuss einen Lichtbogen in Richtung angreifer auszulösen.\nBenötigt mehrere Kacheln. +block.door.description = Eine kleine Tür, die durch darauf tippen geöffnet und geschlossen werden kann.\nGegner können durch geöffnete Türen schießen und laufen. +block.door-large.description = Eine kleine Tür, die durch darauf tippen geöffnet und geschlossen werden kann.\nGegner können durch geöffnete Türen schießen und laufen.\nBenötigt mehrere Kacheln. +block.mend-projector.description = Heilt zyklisch Blöcke in seiner Umgebung. +block.overdrive-projector.description = Erhöht die Geschwindigkeit von nahegelegenen Blöcken wie Bohrer und Förderbänder. +block.force-projector.description = Erzeugt ein sechseckiges Kraftfeld um sich selbst, durch das Blöcke und Einheiten vor Schaden beschützt werden. +block.shock-mine.description = Beschädigt Gegner, die auf die Mine laufen. Für Gegener schwer zu sehen. +block.duo.description = Ein kleiner, günstiger Geschützturm. +block.arc.description = Ein kleiner Geschützturm, der Lichtbögen in Richtung des Gegners schießt. +block.hail.description = Ein kleiner Artillerie-Geschützturm. +block.lancer.description = Ein mittelgroßer Geschützturm, der sich auflädt und Elektrizitätsstrahlen verschießt. +block.wave.description = Ein mittelgroßer Geschützturm, der flüssige Kugeln verschießt. +block.salvo.description = Ein mittelgroßer Geschützturm, der Schüsse in Salven abfeuert. +block.swarmer.description = Ein mittelgroßer Geschützturm, der Raketenschwärme abfeuert. +block.ripple.description = Ein großer Artillerie-Geschützturm, der mehrere Schüsse gleichzeitig abfeuert. +block.cyclone.description = Ein großer Schnellfeuer-Geschützturm. +block.fuse.description = Ein großer Geschützturm, der starke Strahlen mit kurzer Reichweite abfeuert. +block.spectre.description = Ein großer Geschützturm, der zwei starke Schüsse gleichzeitig abfeuert. +block.meltdown.description = Ein großer Geschützturm, der starke Strahlen mit großer Reichweite abfeuert. +block.conveyor.description = Basis-Transportblock. Bewegt Materialien vorwärts und lädt sie automatisch in Geschütztürme oder Verarbeitungsanlagen. Rotierbar. +block.titanium-conveyor.description = Verbesserter Transportblock. Bewegt Materialien schneller als Standard-Förderbänder. +block.phase-conveyor.description = Verbesserter Transportblock. Verwendet Strom, um Materialien zu einem verbundenen Phasen-Förderband über mehrere Kacheln zu teleportieren. +block.junction.description = Fungiert als Brücke zwischen zwei kreuzenden Förderbändern. Nützlich, wenn zwei verschiedene Förderbänder sich kreuzen, aber unterschiedliche Materialien verwenden. +block.mass-driver.description = Ultimativer Transportblock. Sammelt mehrere Materialien und schießt sie zu einem verbundenen Massenbeschleuniger über eine große Reichweite. +block.smelter.description = Verbrennt Kohle, um Kupfer und Blei zu einer dichten Legierung zu verschmelzen. +block.arc-smelter.description = Verschmilzt Kupfer und Blei zu einer dichten Legierung, indem es eine externe Stromquelle benutzt. +block.silicon-smelter.description = Reduziert Sand mit hochreinem Kohlenstoff, um Silizium zu produzieren. +block.plastanium-compressor.description = Produziert Plastanium aus Öl und Titan. +block.phase-weaver.description = Produziert Phasengewebe aus radioaktivem Thorium und großen Mengen an Sand. +block.alloy-smelter.description = Verarbeitet Titan, Blei, Silizium und Kupfer zu einer Stromstoßlegierung. +block.pulverizer.description = Zertrümmert Stein zu Sand. Nützlich, wenn kein natürlicher Sand verfügbar ist. +block.pyratite-mixer.description = Vermischt Kohle, Blei und Sand zu hochentzündlichem Pyratit. +block.blast-mixer.description = Verwendet Öl, um Pyratit in eine weniger enzündliche aber explosivee Mischung umzuwandeln. +block.cryofluidmixer.description = Verarbeitet Wasser mit Titan zu einer Kryoflüssigkeit, die viel effizienter kühlt. +block.solidifer.description = Kühlt Lava zu großen Mengen Stein. +block.melter.description = Erhitzt Stein auf extrem hohe Temperaturen, um Lava zu erhalten. +block.incinerator.description = Vernichtet beliebige überschüssige Materialien oder Flüssigkeiten. +block.biomattercompressor.description = Komprimiert Biomasse, um Öl zu erhalten. +block.separator.description = Setzt Stein Wasserdruck aus, um verschiedene Mineralien im Stein freizulegen. +block.centrifuge.description = Effizienter als der Separierer, aber auch teurer zum Bauen und benötigt Strom. +block.power-node.description = Überträgt Strom zu verbundenen Knoten. Bis zu vier Stromquellen, -verbraucher oder -knoten können verbunden werden. Der Knoten erhält Strom von benachbarten Knoten und gibt Strom benachbarte Blöcke weiter. +block.power-node-large.description = Hat einen größeren Radius als der normale Stromknoten und verbindet bis zu sechs Stromquellen, -verbraucher oder -knoten. +block.battery.description = Speichert Strom, solange ein Überschuss besteht, und gibt ihn bei Knappheit ab, solange Kapazität vorhanden ist. +block.battery-large.description = Speichert sehr viel mehr Strom als eine normale Batterie. +block.combustion-generator.description = Generiert Stromg, indem Öl oder entzündliche Materialien verbrannt werden. +block.turbine-generator.description = Effizienter als ein Verbrennungsgenerator, benötigt jedoch zusätzlich Wasser. +block.thermal-generator.description = Erzeugt große Mengen Strom aus Lava. +block.solar-panel.description = Erzeugt kleine Mengen an Strom aus Sonnenenergie. +block.solar-panel-large.description = Erzeugt viel mehr Strom als ein normales Solar Panel, ist aber auch sehr viel teurer in der Anschaffung. +block.thorium-reactor.description = Erzeugt riesige Mengen Strom aus radioaktivem Thorium. Benötigt konstante Kühlung. Explodiert verheerend, wenn unzureichende Mengen an Kühlung vorhanden sind. +block.rtg-generator.description = Ein Radioisotopengenerator, der keine Kühlung benötigt, aber weniger Strom als ein Thorium-Reaktor liefert. +block.unloader.description = Entlädt Materialien aus einem Container, Tresor oder einer Basis auf ein Förderband oder direkt in einen benachbarten Block. Der Typ des auszuladenden Materials kann durch darauf tippen verändert werden. +block.container.description = Speichert eine kleine Menge an Materialien pro Typ. Benachbarte Container, Tresore und Basen werden zu einem Behälter zusammengefasst. Ein[LIGHT_GRAY] Entlader[] kann verwendet werden, um Materialien auszuladen. +block.vault.description = Speichert eine große Menge an Materialien pro Typ. Benachbarte Container, Tresore und Basen werden zu einem Behälter zusammengefasst. Ein[LIGHT_GRAY] Entlader[] kann verwendet werden, um Materialien auszuladen. +block.mechanical-drill.description = Ein günstiger Bohrer. Wenn er auf passende Kacheln gesetzt wird, baut er unbegrenzt Erze des entsprechenden Typs mit geringer Geschwindigkeit ab. +block.pneumatic-drill.description = Ein verbesserter Bohrer, der schneller ist und in der Lage ist, härtere Erze abzubauen, indem er von Luftdruck gebrauch macht. +block.laser-drill.description = Erlaubt es, durch Lasertechnologie noch schneller zu bohren, benötigt aber Strom. Erlaubt zusätzlich das Abbauen von radioaktivem Thorium. +block.blast-drill.description = Der ultimative Bohrer. Benötigt große Mengen an Strom. +block.water-extractor.description = Extrahiert Wasser aus dem Boden. Verwende ihn, wenn es keinen See in der Nähe gibt. +block.cultivator.description = Kultiviert den Boden mit Wasser, um Biomasse zu erzeugen. +block.oil-extractor.description = Verwendet große Mengen an Strom, um Öl aus Sand zu extrahieren. Verwende ihn, wenn es keine direkte Ölquelle gibt. +block.dart-ship-pad.description = Wechsle in einen Standard-Jäger.\nVerwende das Pad, indem du doppelt darauf tippst, während du darauf bist. +block.trident-ship-pad.description = Wechsle in einen massiv gepanzerten schweren Bomber.\nVerwende das Pad, indem du doppelt darauf tippst, während du darauf bist. +block.javelin-ship-pad.description = Wechsle in einen starken und schnellen Abfangjäger mit Blitz-Waffen.\nVerwende das Pad, indem du doppelt darauf tippst, während du darauf bist. +block.glaive-ship-pad.description = Wechsle in ein großes, gut gepanzertes Kampfflugzeug.\nVerwende das Pad, indem du doppelt darauf tippst, während du darauf bist. +block.tau-mech-pad.description = Wechsle in einen Support-Mech, der befreundete Blöcke und Einheiten heilen kann.\nVerwende das Pad, indem du doppelt darauf tippst, während du darauf bist. +block.delta-mech-pad.description = Wechsle in einen schnellen, leicht gepanzerten Mech, der für Überfälle gemacht ist.\nVerwende das Pad, indem du doppelt darauf tippst, während du darauf bist. +block.omega-mech-pad.description = Wechsle in einen klobigen und gut gepanzerten Mech, der für Frontangriffe gemacht ist.\nVerwende das Pad, indem du doppelt darauf tippst, während du darauf bist. +block.spirit-factory.description = Produziert leichte Drohnen, die Erz abbauen und Blöcke reparieren können. +block.phantom-factory.description = Produziert erweiterte Drohnen, die deutlich effizienter sind als Spirit-Drohnen. +block.wraith-factory.description = Produziert schnelle Abfangjäger. +block.ghoul-factory.description = Produziert schwere Flächenbomber. +block.dagger-factory.description = Produziert Standard-Bodeneinheiten. +block.titan-factory.description = Produziert fortgeschrittene, gepanzerte Bodeneinheiten. +block.fortress-factory.description = Produziert schwere Artillerie-Bodeneinheiten. +block.revenant-factory.description = Produziert schwere Laser-Bodeneinheiten. +block.repair-point.description = Heilt durchgehend die nächste befreundete, beschädigte Einheit in der Umgebung. +block.command-center.description = Erlaubt es, die KI der eigenen Einheiten zu ändern. Momentan sind Angriff, Rückzug und Patroulle unterstützt. +block.conduit.description = Standard Flüssigkeits-Transportblock. Funktioniert wie ein Förderband, nur für Flüssigkeiten. Wird am Besten mit Extraktoren, Pumpen oder anderen Kanälen benutzt. +block.pulse-conduit.description = Verbesserter Flüssigkeits-Transportblock. Transportiert Flüssigkeiten schneller und speichert mehr als Standard Kanäle. +block.phase-conduit.description = Verbesserter Flüssigkeits-Transportblock. Verwendet Strom, um Flüssigkeiten zu einem verbundenen Phasenkanal zu teleportieren. +block.liquid-router.description = Akzeptiert Flüssigkeiten aus einer Richtung und verteilt sie an bis zu drei andere Richtungen weiter. Nützlich, um Flüssigkeiten aus einer Quelle an mehrere Empfänger zu verteilen. +block.liquid-tank.description = Speichert eine große Menge an Flüssigkeiten. Verwende es als Puffer, wenn Angebot und Nachfrage an einer Flüssigkeit schwanken. +block.liquid-junction.description = Fungiert als Brücke über zwei kreuzende Kanäle. Nützlich in Situationen, in denen sich zwei Kanäle mit verschiedenen Flüssigkeiten kreuzen. +block.bridge-conduit.description = Verbesserter Flüssigkeits-Transportblock. Erlaubt es, Flüssigkeiten über bis zu 3 Kacheln beliebigen Terrains oder Inhalts zu transportieren. +block.mechanical-pump.description = Eine günstige, langsame Punkte, die keine Strom benötigt. +block.rotary-pump.description = Eine fortgeschrittene Pumpe, die mithilfe von Strom doppelt so schnell pumpt. +block.thermal-pump.description = Die ultimative Pumpe, dreimal so schnell wie eine mechanische Pumpe und die einzige Pumpe, die Lava fördern kann. +block.router.description = Akzeptiert Materialien aus einer Richtung und leitet sie gleichmäßig in bis zu drei andere Richtungen weiter. Nützlich, wenn die Materialien aus einer Richtung an mehrere Empfänger verteilt werden sollen. +block.distributor.description = Ein weiterentwickelter Router, der Materialien in bis zu sieben Richtungen gleichmäßig verteilt. +block.bridge-conveyor.description = Verbesserter Transportblock. Erlaubt es, Materialien über bis zu 3 Kacheln beliebigen Terrains oder Inhalts zu transportieren. +block.alpha-mech-pad.description = Sofern genügend Strom zur Verfügung steht, baut dieses Pad deinen Schiff in einen [accent]Alpha[] mech zurück. +block.itemsource.description = Produziert unendlich items. Nur im Sandkasten verfügbar. +block.liquidsource.description = Produziert unendlich Flüssigkeiten. Nur im Sandkasten verfügbar. +block.itemvoid.description = Zerstört Materialien, die hereingegeben werden, ohne Strom zu verbrauchen. Nur im Sandkasten verfügbar. +block.powerinfinite.description = Erzeugt unendlich viel Strom. Nur im Sandkasten verfügbar. +block.powervoid.description = Verschlingt den kompletten übrigen Strom. Nur im Sandkasten verfügbar. +liquid.water.description = Wird überlicherweise zum Kühlen von Maschinen und zur Müllverarbeitung verwendet. +liquid.lava.description = Kann zu [LIGHT_GRAY] Stein[] verarbeitet werden, zur Stromerzeugung verwendet werden oder als Munition für bestimmte Geschütztürme verwendet werden. +liquid.oil.description = Kann verbrannt, zum explodieren gebracht, oder als Kühlung verwendet werden. +liquid.cryofluid.description = Die effizienteste Flüssigkeit, um Dinge herunter zu kühlen. From 3759d32c8948194259d0a9b10d7b0606f47113a3 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 7 Nov 2018 16:56:47 -0500 Subject: [PATCH 02/34] Improved map previews --- core/src/io/anuke/mindustry/entities/Player.java | 4 ++-- core/src/io/anuke/mindustry/io/MapIO.java | 14 +++----------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/core/src/io/anuke/mindustry/entities/Player.java b/core/src/io/anuke/mindustry/entities/Player.java index cf98629d50..a454e2078c 100644 --- a/core/src/io/anuke/mindustry/entities/Player.java +++ b/core/src/io/anuke/mindustry/entities/Player.java @@ -512,14 +512,14 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra achievedFlight = true; } - if(boostHeat <= liftoffBoost + 0.05f && achievedFlight){ + if(boostHeat <= liftoffBoost + 0.05f && achievedFlight && !mech.flying){ if(tile != null){ if(mech.shake > 1f){ Effects.shake(mech.shake, mech.shake, this); } Effects.effect(UnitFx.unitLand, tile.floor().minimapColor, x, y, tile.floor().isLiquid ? 1f : 0.5f); } - if(!mech.flying) mech.onLand(this); + mech.onLand(this); achievedFlight = false; } diff --git a/core/src/io/anuke/mindustry/io/MapIO.java b/core/src/io/anuke/mindustry/io/MapIO.java index 4e07de02e3..c46e9bf6d3 100644 --- a/core/src/io/anuke/mindustry/io/MapIO.java +++ b/core/src/io/anuke/mindustry/io/MapIO.java @@ -47,23 +47,15 @@ public class MapIO{ data.position(0, 0); TileDataMarker marker = data.newDataMarker(); - Color color = new Color(); for(int y = 0; y < data.height(); y++){ for(int x = 0; x < data.width(); x++){ data.read(marker); + byte elev = y >= data.height() - 1 ? 0 : data.read(x, y + 1, DataPosition.elevation); Block floor = content.block(marker.floor); Block wall = content.block(marker.wall); - int wallc = ColorMapper.getBlockColor(wall); - if(wallc == 0 && (wall.update || wall.solid || wall.breakable)) wallc = Team.all[marker.team].intColor; - wallc = wallc == 0 ? ColorMapper.getBlockColor(floor) : wallc; - if(marker.elevation > 0){ - float scaling = 1f + marker.elevation / 8f; - color.set(wallc); - color.mul(scaling, scaling, scaling, 1f); - wallc = Color.rgba8888(color); - } - pixmap.drawPixel(x, pixmap.getHeight() - 1 - y, wallc); + int color = ColorMapper.colorFor(floor, wall, Team.all[marker.team], marker.elevation, elev > marker.elevation ? (byte)(1 << 6) : (byte)0); + pixmap.drawPixel(x, pixmap.getHeight() - 1 - y, color); } } From 2f4730a9c6d2b921b49cf47ff778f6c242609d7a Mon Sep 17 00:00:00 2001 From: Timmeey86 Date: Thu, 8 Nov 2018 00:12:01 +0100 Subject: [PATCH 03/34] Fixed unit/second translations since (#315) --- core/assets/bundles/bundle_de.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/assets/bundles/bundle_de.properties b/core/assets/bundles/bundle_de.properties index f7db71e4fe..22eb16c8ed 100644 --- a/core/assets/bundles/bundle_de.properties +++ b/core/assets/bundles/bundle_de.properties @@ -329,9 +329,9 @@ text.blocks.fuelburntime = Kraftstoff Verbrennungs-Zeit text.blocks.inputcapacity = Annahmekapazität text.blocks.outputcapacity = Ausgabekapazität text.unit.blocks = Blöcke -text.unit.powersecond = Stromverbrauch/Sekunde -text.unit.liquidsecond = Flüssigkeitsverbrauch/Sekunde -text.unit.itemssecond = Materialverbrauch/Sekunde +text.unit.powersecond = Stromeinheiten/Sekunde +text.unit.liquidsecond = Flüssigkeitseinheiten/Sekunde +text.unit.itemssecond = Materialeinheiten/Sekunde text.unit.pixelssecond = Pixel/Sekunde text.unit.liquidunits = Flüssigkeitseinheiten text.unit.powerunits = Stromeinheiten From 38fdc11917ea322268121d9b79fd9a485d9c7c43 Mon Sep 17 00:00:00 2001 From: Timmeey86 Date: Thu, 8 Nov 2018 00:14:01 +0100 Subject: [PATCH 04/34] Adjustable core position (#307) * Made starting core position configurable and fixed tutorial sector core position * Refactored classes to use a public int interface and a GridPoint2 as internal storage * Battle missions now spawn the core at 50, 50 again * Default player cores are now created at the first spawnpoint * Manually fixed formatting which was not caught by auto formatter --- .../anuke/mindustry/maps/TutorialSector.java | 3 +- .../maps/missions/BattleMission.java | 20 +++++- .../mindustry/maps/missions/Mission.java | 6 -- .../missions/MissionWithStartingCore.java | 63 +++++++++++++++++++ .../mindustry/maps/missions/WaveMission.java | 27 +++++--- 5 files changed, 102 insertions(+), 17 deletions(-) create mode 100644 core/src/io/anuke/mindustry/maps/missions/MissionWithStartingCore.java diff --git a/core/src/io/anuke/mindustry/maps/TutorialSector.java b/core/src/io/anuke/mindustry/maps/TutorialSector.java index 3d6a486e72..81937c9973 100644 --- a/core/src/io/anuke/mindustry/maps/TutorialSector.java +++ b/core/src/io/anuke/mindustry/maps/TutorialSector.java @@ -30,7 +30,8 @@ public class TutorialSector{ //TODO fill turret with items mission //new BlockMission(ProductionBlocks.mechanicalDrill).setMessage("$tutorial.drillturret"), - new WaveMission(2).setMessage("$tutorial.waves"), + // Create a wave mission which spawns the core at 60, 60 rather than in the center of the map + new WaveMission(2, 60, 60).setMessage("$tutorial.waves"), new ItemMission(Items.lead, 150).setMessage("$tutorial.lead"), new ItemMission(Items.copper, 250).setMessage("$tutorial.morecopper"), diff --git a/core/src/io/anuke/mindustry/maps/missions/BattleMission.java b/core/src/io/anuke/mindustry/maps/missions/BattleMission.java index 4ea34022c6..bd2e8e26a9 100644 --- a/core/src/io/anuke/mindustry/maps/missions/BattleMission.java +++ b/core/src/io/anuke/mindustry/maps/missions/BattleMission.java @@ -12,8 +12,24 @@ import io.anuke.ucore.util.Bundles; import static io.anuke.mindustry.Vars.*; -public class BattleMission extends Mission{ +public class BattleMission extends MissionWithStartingCore{ final int spacing = 30; + public static final int defaultXCorePos = 50; + public static final int defaultYCorePos = 50; + + /** Creates a battle mission with the player core being at (@defaultXCorePos, @defaultYCorePos) */ + public BattleMission(){ + this(defaultXCorePos, defaultYCorePos); + } + + /** + * Creates a wave survival with the player core being at a custom location. + * @param xCorePos The X coordinate of the custom core position. + * @param yCorePos The Y coordinate of the custom core position. + */ + public BattleMission(int xCorePos, int yCorePos){ + super(xCorePos, yCorePos); + } @Override public String getIcon(){ @@ -37,7 +53,7 @@ public class BattleMission extends Mission{ @Override public void generate(Generation gen){ - generateCoreAt(gen, 50, 50, defaultTeam); + generateCoreAtFirstSpawnPoint(gen, defaultTeam); if(state.teams.get(defaultTeam).cores.size == 0){ return; diff --git a/core/src/io/anuke/mindustry/maps/missions/Mission.java b/core/src/io/anuke/mindustry/maps/missions/Mission.java index 7544ee5861..25c9c5574e 100644 --- a/core/src/io/anuke/mindustry/maps/missions/Mission.java +++ b/core/src/io/anuke/mindustry/maps/missions/Mission.java @@ -100,10 +100,4 @@ public abstract class Mission{ } public void generate(Generation gen){} - - public void generateCoreAt(Generation gen, int coreX, int coreY, Team team){ - gen.tiles[coreX][coreY].setBlock(StorageBlocks.core); - gen.tiles[coreX][coreY].setTeam(team); - state.teams.get(team).cores.add(gen.tiles[coreX][coreY]); - } } diff --git a/core/src/io/anuke/mindustry/maps/missions/MissionWithStartingCore.java b/core/src/io/anuke/mindustry/maps/missions/MissionWithStartingCore.java new file mode 100644 index 0000000000..7b42129055 --- /dev/null +++ b/core/src/io/anuke/mindustry/maps/missions/MissionWithStartingCore.java @@ -0,0 +1,63 @@ +package io.anuke.mindustry.maps.missions; + +import com.badlogic.gdx.math.GridPoint2; +import com.badlogic.gdx.utils.Array; +import io.anuke.mindustry.content.blocks.StorageBlocks; +import io.anuke.mindustry.game.Team; +import io.anuke.mindustry.maps.generation.Generation; +import io.anuke.mindustry.world.Tile; + +import static io.anuke.mindustry.Vars.state; + +public abstract class MissionWithStartingCore extends Mission{ + + + /** Stores a custom starting location for the core, or null if the default calculation (map center) shall be used. */ + private final GridPoint2 customStartingPoint; + + /** Default constructor. Missions created this way will have a player starting core in the center of the map. */ + MissionWithStartingCore(){ + this.customStartingPoint = null; + } + + /** + * Creates a mission with a core on a non-default location. + * @param xCorePos The x coordinate of the custom core position. + * @param yCorePos The y coordinate of the custom core position. + */ + MissionWithStartingCore(int xCorePos, int yCorePos){ + this.customStartingPoint = new GridPoint2(xCorePos, yCorePos); + } + + /** + * Generates a player core based on generation parameters. + * @param gen The generation parameters which provide the map size. + * @param team The team to generate the core for. + */ + public void generateCoreAtFirstSpawnPoint(Generation gen, Team team){ + Array spawnPoints = getSpawnPoints(gen); + if(spawnPoints == null || spawnPoints.size == 0){ + throw new IllegalArgumentException("A MissionWithStartingCore subclass did not provide a spawn point in getSpawnPoints(). However, at least one point must always be provided."); + } + + Tile startingCoreTile = gen.tiles[spawnPoints.first().x][spawnPoints.first().y]; + startingCoreTile.setBlock(StorageBlocks.core); + startingCoreTile.setTeam(team); + state.teams.get(team).cores.add(startingCoreTile); + } + + /** + * Retrieves the spawn point in the center of the map or at a custom location which was provided through the constructor. + * @param gen The generation parameters which provide the map size. + * @return The center of the map or a custom location. + * @implNote Must return an array with at least one entry. + */ + @Override + public Array getSpawnPoints(Generation gen){ + if(this.customStartingPoint == null){ + return Array.with(new GridPoint2(gen.width / 2, gen.height / 2)); + }else{ + return Array.with(this.customStartingPoint); + } + } +} diff --git a/core/src/io/anuke/mindustry/maps/missions/WaveMission.java b/core/src/io/anuke/mindustry/maps/missions/WaveMission.java index 7a002d85b7..7ddaa5e0d0 100644 --- a/core/src/io/anuke/mindustry/maps/missions/WaveMission.java +++ b/core/src/io/anuke/mindustry/maps/missions/WaveMission.java @@ -15,13 +15,30 @@ import static io.anuke.mindustry.Vars.state; import static io.anuke.mindustry.Vars.waveTeam; import static io.anuke.mindustry.Vars.world; -public class WaveMission extends Mission{ +public class WaveMission extends MissionWithStartingCore{ private final int target; + /** + * Creates a wave survival mission with the player core being in the center of the map. + * @param target The number of waves to be survived. + */ public WaveMission(int target){ + super(); this.target = target; } + /** + * Creates a wave survival with the player core being at a custom location. + * @param target The number of waves to be survived. + * @param xCorePos The X coordinate of the custom core position. + * @param yCorePos The Y coordinate of the custom core position. + */ + public WaveMission(int target, int xCorePos, int yCorePos){ + super(xCorePos, yCorePos); + this.target = target; + } + + @Override public Array getWaves(Sector sector){ return Waves.getSpawns(); @@ -29,8 +46,7 @@ public class WaveMission extends Mission{ @Override public void generate(Generation gen){ - int coreX = gen.width/2, coreY = gen.height/2; - generateCoreAt(gen, coreX, coreY, Team.blue); + generateCoreAtFirstSpawnPoint(gen, Team.blue); } @Override @@ -71,9 +87,4 @@ public class WaveMission extends Mission{ public boolean isComplete(){ return state.wave > target && Vars.unitGroups[Vars.waveTeam.ordinal()].size() == 0; } - - @Override - public Array getSpawnPoints(Generation gen){ - return Array.with(new GridPoint2(gen.width/2, gen.height/2)); - } } From 042c671bd435867291743c468f4aaf0875e13162 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 7 Nov 2018 18:51:27 -0500 Subject: [PATCH 05/34] Difficulty balance / Better map display / UI fixes --- core/assets-raw/sprites/ui/empty-sector.png | Bin 230 -> 230 bytes core/assets-raw/sprites/ui/sector-edge.png | Bin 106 -> 167 bytes core/assets/maps/sandbox.mmap | Bin 330398 -> 330441 bytes core/assets/sprites/sprites.png | Bin 102664 -> 102670 bytes core/src/io/anuke/mindustry/io/MapIO.java | 2 +- core/src/io/anuke/mindustry/maps/MapMeta.java | 11 ++++++++--- .../maps/generation/FortressGenerator.java | 1 + .../missions/MissionWithStartingCore.java | 2 -- .../mindustry/ui/dialogs/SectorsDialog.java | 4 ++-- .../io/anuke/mindustry/world/ColorMapper.java | 6 +----- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/core/assets-raw/sprites/ui/empty-sector.png b/core/assets-raw/sprites/ui/empty-sector.png index 905ec6eea2231c42724f798daf67e30b2741c09a..347b3bfc8da46c40dcadbc44b39c6958404a75ff 100644 GIT binary patch delta 66 zcmaFH_>6Hvurj;24x<*scOM1@hGI__$B>A_Z>Jmb9WdZvo~xn%z`An({i_qpVnn2W XshZYb$zfw)U|{fc^>bP0l+XkK6HvurezH2h+z!D?J7VhGI__$B>A_Z>Jmb9WdZvo~x0s_`kj{{_@1K7?J(w XR5(*?mHHVN7#KWV{an^LB{Ts5 bSo`*ON-FESq^*CLK;oXRel9HQoD!M URf0zBJS-q_Pgg&ebxsLQ0KLQ&-v9sr diff --git a/core/assets/maps/sandbox.mmap b/core/assets/maps/sandbox.mmap index 3a448b7c1d602e01a8242a07437884e2f33920b6..14e89ed3b77dc48e9e2e20eff1a55a6c9ca01405 100644 GIT binary patch delta 72 zcmbO?RpjJUkqI_B+Kvh(sYOMZNja$sxrqe|B^ik&3Pq`jIXRUI#TogfIVpMSB?_q( bnZ+e~jkc|}jIFjzt+vdqwk%t1SrfSc#8(*9 delta 29 kcmX>(Rb<{&kqI`842>DB8H}wNOsyHrtr;v^GguS30H50ly8r+H diff --git a/core/assets/sprites/sprites.png b/core/assets/sprites/sprites.png index b17d0e864988190e5a0cdc0c7c6b164b46ed3cf6..53901c92d1d6eb898bb5a164b97b583ec2ba7e74 100644 GIT binary patch delta 44295 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 ZX)IluQ?lNLfq{X+)0NH7Wt~$(69B#C=PdvL delta 44391 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

-4EWP$Lh-O{fZ4s6r8w^(`p6vO`! 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 B)1v?Y diff --git a/core/src/io/anuke/mindustry/io/MapIO.java b/core/src/io/anuke/mindustry/io/MapIO.java index c46e9bf6d3..7dea904ef3 100644 --- a/core/src/io/anuke/mindustry/io/MapIO.java +++ b/core/src/io/anuke/mindustry/io/MapIO.java @@ -54,7 +54,7 @@ public class MapIO{ byte elev = y >= data.height() - 1 ? 0 : data.read(x, y + 1, DataPosition.elevation); Block floor = content.block(marker.floor); Block wall = content.block(marker.wall); - int color = ColorMapper.colorFor(floor, wall, Team.all[marker.team], marker.elevation, elev > marker.elevation ? (byte)(1 << 6) : (byte)0); + int color = ColorMapper.colorFor(floor, wall, Team.all[marker.team], marker.elevation + 1, elev > marker.elevation ? (byte)(1 << 6) : (byte)0); pixmap.drawPixel(x, pixmap.getHeight() - 1 - y, color); } } diff --git a/core/src/io/anuke/mindustry/maps/MapMeta.java b/core/src/io/anuke/mindustry/maps/MapMeta.java index c731941297..148ad5a099 100644 --- a/core/src/io/anuke/mindustry/maps/MapMeta.java +++ b/core/src/io/anuke/mindustry/maps/MapMeta.java @@ -2,6 +2,7 @@ package io.anuke.mindustry.maps; import com.badlogic.gdx.utils.IntIntMap; import com.badlogic.gdx.utils.ObjectMap; +import io.anuke.ucore.util.Bundles; public class MapMeta{ public final int version; @@ -18,15 +19,19 @@ public class MapMeta{ } public String author(){ - return tags.get("author", "unknown"); + return tag("author"); } public String description(){ - return tags.get("description", "unknown"); + return tag("description"); } public String name(){ - return tags.get("name", "unknown"); + return tag("name"); + } + + public String tag(String name){ + return tags.containsKey(name) && !tags.get(name).trim().isEmpty() ? tags.get(name): Bundles.get("text.unknown"); } public boolean hasOreGen(){ diff --git a/core/src/io/anuke/mindustry/maps/generation/FortressGenerator.java b/core/src/io/anuke/mindustry/maps/generation/FortressGenerator.java index ef58381653..def5cf1e0c 100644 --- a/core/src/io/anuke/mindustry/maps/generation/FortressGenerator.java +++ b/core/src/io/anuke/mindustry/maps/generation/FortressGenerator.java @@ -57,6 +57,7 @@ public class FortressGenerator{ void gen(){ gen.setBlock(enemyX, enemyY, StorageBlocks.core, team); + gen.random.nextBoolean(); float difficultyScl = Mathf.clamp(gen.sector.difficulty / 20f + gen.random.range(0.25f), 0f, 0.9999f); float dscl2 = Mathf.clamp(0.5f + gen.sector.difficulty / 20f + gen.random.range(0.1f), 0f, 1.5f); diff --git a/core/src/io/anuke/mindustry/maps/missions/MissionWithStartingCore.java b/core/src/io/anuke/mindustry/maps/missions/MissionWithStartingCore.java index 7b42129055..1dbb2b81a3 100644 --- a/core/src/io/anuke/mindustry/maps/missions/MissionWithStartingCore.java +++ b/core/src/io/anuke/mindustry/maps/missions/MissionWithStartingCore.java @@ -10,8 +10,6 @@ import io.anuke.mindustry.world.Tile; import static io.anuke.mindustry.Vars.state; public abstract class MissionWithStartingCore extends Mission{ - - /** Stores a custom starting location for the core, or null if the default calculation (map center) shall be used. */ private final GridPoint2 customStartingPoint; diff --git a/core/src/io/anuke/mindustry/ui/dialogs/SectorsDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/SectorsDialog.java index 90a466e023..1ea6ed5d04 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/SectorsDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/SectorsDialog.java @@ -60,7 +60,7 @@ public class SectorsDialog extends FloatingDialog{ margin(0); getTitleTable().clear(); clear(); - stack(content(), buttons(), container).grow(); + stack(content(), container, buttons()).grow(); shown(this::setup); } @@ -128,7 +128,7 @@ public class SectorsDialog extends FloatingDialog{ class SectorView extends Element{ float lastX, lastY; boolean clicked = false; - float panX = 0, panY = -sectorSize/2f; + float panX = sectorSize/2f, panY = sectorSize/2f; SectorView(){ addListener(new InputListener(){ diff --git a/core/src/io/anuke/mindustry/world/ColorMapper.java b/core/src/io/anuke/mindustry/world/ColorMapper.java index e8a5205267..6d3bdea310 100644 --- a/core/src/io/anuke/mindustry/world/ColorMapper.java +++ b/core/src/io/anuke/mindustry/world/ColorMapper.java @@ -14,11 +14,7 @@ public class ColorMapper implements ContentList{ private static ObjectIntMap colorMap = new ObjectIntMap<>(); private static ThreadLocal tmpColors = new ThreadLocal<>(); - public static Block getByColor(int color){ - return blockMap.get(color); - } - - public static int getBlockColor(Block block){ + private static int getBlockColor(Block block){ return colorMap.get(block, 0); } From 122fbbed22b6b5b83b216fb84f5424adb07acf86 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 7 Nov 2018 19:23:40 -0500 Subject: [PATCH 06/34] Added a 'tutorial' / Bugfixes --- core/src/io/anuke/mindustry/core/Logic.java | 2 +- .../anuke/mindustry/maps/SectorPresets.java | 6 ++-- core/src/io/anuke/mindustry/maps/Sectors.java | 2 +- .../anuke/mindustry/maps/TutorialSector.java | 31 ++++++++++++++----- core/src/io/anuke/mindustry/world/Tile.java | 3 +- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index fb1feb196d..4dd94aa2b8 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -167,7 +167,7 @@ public class Logic extends Module{ if(!state.isPaused()){ Timers.update(); - if(!state.mode.disableWaveTimer && !state.mode.disableWaves){ + if(!state.mode.disableWaveTimer && !state.mode.disableWaves && !state.gameOver){ state.wavetime -= Timers.delta(); } diff --git a/core/src/io/anuke/mindustry/maps/SectorPresets.java b/core/src/io/anuke/mindustry/maps/SectorPresets.java index 24368e333c..29540e1d5b 100644 --- a/core/src/io/anuke/mindustry/maps/SectorPresets.java +++ b/core/src/io/anuke/mindustry/maps/SectorPresets.java @@ -23,10 +23,10 @@ public class SectorPresets{ public SectorPresets(){ - //base tutorial mission (disabled) - /*add(new SectorPreset(0, 0, + //base tutorial mission + add(new SectorPreset(0, 0, TutorialSector.getMissions(), - Array.with(Items.copper, Items.coal, Items.lead)));*/ + Array.with(Items.copper, Items.coal, Items.lead))); //command center mission add(new SectorPreset(0, 1, diff --git a/core/src/io/anuke/mindustry/maps/Sectors.java b/core/src/io/anuke/mindustry/maps/Sectors.java index 140be792ed..1599dd8092 100644 --- a/core/src/io/anuke/mindustry/maps/Sectors.java +++ b/core/src/io/anuke/mindustry/maps/Sectors.java @@ -229,7 +229,7 @@ public class Sectors{ private void generate(Sector sector){ //50% chance to get a wave mission - if(Mathf.randomSeed(sector.getSeed() + 6) < 0.5){ + if(Mathf.randomSeed(sector.getSeed() + 7) < 0.5){ //recipe mission (maybe) addRecipeMission(sector, 3); sector.missions.add(new WaveMission(sector.difficulty*5 + Mathf.randomSeed(sector.getSeed(), 1, 4)*5)); diff --git a/core/src/io/anuke/mindustry/maps/TutorialSector.java b/core/src/io/anuke/mindustry/maps/TutorialSector.java index 81937c9973..ccc75b38db 100644 --- a/core/src/io/anuke/mindustry/maps/TutorialSector.java +++ b/core/src/io/anuke/mindustry/maps/TutorialSector.java @@ -2,12 +2,15 @@ package io.anuke.mindustry.maps; import com.badlogic.gdx.utils.Array; import io.anuke.mindustry.content.Items; -import io.anuke.mindustry.content.UnitTypes; -import io.anuke.mindustry.content.blocks.*; -import io.anuke.mindustry.maps.generation.Generation; -import io.anuke.mindustry.maps.missions.*; +import io.anuke.mindustry.content.blocks.CraftingBlocks; +import io.anuke.mindustry.content.blocks.ProductionBlocks; +import io.anuke.mindustry.content.blocks.StorageBlocks; +import io.anuke.mindustry.content.blocks.UnitBlocks; +import io.anuke.mindustry.maps.missions.BlockMission; +import io.anuke.mindustry.maps.missions.ItemMission; +import io.anuke.mindustry.maps.missions.Mission; +import io.anuke.mindustry.maps.missions.WaveMission; import io.anuke.mindustry.world.Block; -import io.anuke.ucore.util.Bundles; import static io.anuke.mindustry.Vars.*; @@ -16,7 +19,7 @@ public class TutorialSector{ private static int droneIndex; public static Array getMissions(){ - +/* Array missions = Array.with( new ItemMission(Items.copper, 60).setMessage("$tutorial.begin"), @@ -83,9 +86,21 @@ public class TutorialSector{ droneIndex = i; break; } - } + }*/ - return missions; + return Array.with( + //intentionally unlocalized + new ItemMission(Items.copper, 10).setMessage("An updated tutorial will return next build.\nFor now, you'll have to deal with... this."), + + new BlockMission(ProductionBlocks.mechanicalDrill), + + new ItemMission(Items.copper, 100), + new ItemMission(Items.lead, 50), + + new BlockMission(CraftingBlocks.smelter), + new ItemMission(Items.densealloy, 10), + new WaveMission(5) + ); } public static boolean supressDrone(){ diff --git a/core/src/io/anuke/mindustry/world/Tile.java b/core/src/io/anuke/mindustry/world/Tile.java index f3fad923ef..f6ea510048 100644 --- a/core/src/io/anuke/mindustry/world/Tile.java +++ b/core/src/io/anuke/mindustry/world/Tile.java @@ -133,8 +133,9 @@ public class Tile implements PosTrait, TargetTrait{ return wall; } + @Override public Team getTeam(){ - return Team.all[team]; + return Team.all[target().team]; } public void setTeam(Team team){ From 216433aa2dd5d697cb496a8608f75865cfe0205c Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 7 Nov 2018 19:34:31 -0500 Subject: [PATCH 07/34] New alpha drone mechanics --- .../src/io/anuke/mindustry/content/Mechs.java | 4 +-- .../entities/units/types/AlphaDrone.java | 27 ++++++++++++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/core/src/io/anuke/mindustry/content/Mechs.java b/core/src/io/anuke/mindustry/content/Mechs.java index e8898e9a84..d56a37d003 100644 --- a/core/src/io/anuke/mindustry/content/Mechs.java +++ b/core/src/io/anuke/mindustry/content/Mechs.java @@ -37,7 +37,7 @@ public class Mechs implements ContentList{ alpha = new Mech("alpha-mech", false){ int maxDrones = 3; - float buildTime = 200f; + float buildTime = 20f; { drillPower = 1; @@ -53,7 +53,7 @@ public class Mechs implements ContentList{ @Override public void updateAlt(Player player){ - if(getDrones(player) < maxDrones && !TutorialSector.supressDrone() && player.timer.get(Player.timerAbility, buildTime)){ + if(player.isShooting && player.timer.get(Player.timerAbility, buildTime) && getDrones(player) < maxDrones && !TutorialSector.supressDrone()){ if(!Net.client()) { AlphaDrone drone = (AlphaDrone) UnitTypes.alphaDrone.create(player.getTeam()); drone.leader = player; diff --git a/core/src/io/anuke/mindustry/entities/units/types/AlphaDrone.java b/core/src/io/anuke/mindustry/entities/units/types/AlphaDrone.java index 7f4f017e92..4063ac6100 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/AlphaDrone.java +++ b/core/src/io/anuke/mindustry/entities/units/types/AlphaDrone.java @@ -1,15 +1,21 @@ package io.anuke.mindustry.entities.units.types; import com.badlogic.gdx.math.Vector2; +import io.anuke.annotations.Annotations.Loc; +import io.anuke.annotations.Annotations.Remote; import io.anuke.mindustry.Vars; +import io.anuke.mindustry.content.fx.UnitFx; +import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.entities.Predict; -import io.anuke.mindustry.entities.Unit; import io.anuke.mindustry.entities.traits.TargetTrait; +import io.anuke.mindustry.entities.units.BaseUnit; import io.anuke.mindustry.entities.units.FlyingUnit; import io.anuke.mindustry.entities.units.UnitCommand; import io.anuke.mindustry.entities.units.UnitState; +import io.anuke.mindustry.gen.Call; import io.anuke.mindustry.net.Net; import io.anuke.mindustry.type.AmmoType; +import io.anuke.ucore.core.Effects; import io.anuke.ucore.util.Mathf; import java.io.DataInput; @@ -22,7 +28,8 @@ import static io.anuke.mindustry.Vars.players; public class AlphaDrone extends FlyingUnit { static final float followDistance = 80f; - public Unit leader; + public Player leader; + public final UnitState attack = new UnitState() { @Override public void update() { @@ -32,15 +39,18 @@ public class AlphaDrone extends FlyingUnit { } TargetTrait last = target; target = leader; + if(last == null){ - circle(50f); + circle(leader.isShooting ? 50f : 0f); } + target = last; if(distanceTo(leader) < followDistance){ targetClosest(); }else{ target = null; } + if(target != null){ attack(50f); @@ -51,9 +61,20 @@ public class AlphaDrone extends FlyingUnit { getWeapon().update(AlphaDrone.this, to.x, to.y); } } + + if(!leader.isShooting && distanceTo(leader) < 8f){ + Call.onAlphaDroneFade(AlphaDrone.this); + } } }; + @Remote(called = Loc.server) + public static void onAlphaDroneFade(BaseUnit drone){ + if(drone == null) return; + drone.remove(); + Effects.effect(UnitFx.pickup, drone); + } + @Override public void onCommand(UnitCommand command){ //nuh From 56ffa7905eb61606602f90d65595a6a2190a45fe Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 7 Nov 2018 19:58:53 -0500 Subject: [PATCH 08/34] Fixed instant-win wave missions / Fixed units clipping off screen --- core/src/io/anuke/mindustry/content/Mechs.java | 18 +++++++++++------- core/src/io/anuke/mindustry/core/Logic.java | 5 ++++- .../mindustry/entities/units/BaseUnit.java | 4 ++-- .../entities/units/types/AlphaDrone.java | 2 +- .../io/anuke/mindustry/io/SaveFileVersion.java | 7 +++++++ core/src/io/anuke/mindustry/maps/Sectors.java | 4 +--- .../mindustry/maps/missions/WaveMission.java | 5 +---- 7 files changed, 27 insertions(+), 18 deletions(-) diff --git a/core/src/io/anuke/mindustry/content/Mechs.java b/core/src/io/anuke/mindustry/content/Mechs.java index d56a37d003..9e7d8ee3fd 100644 --- a/core/src/io/anuke/mindustry/content/Mechs.java +++ b/core/src/io/anuke/mindustry/content/Mechs.java @@ -53,14 +53,18 @@ public class Mechs implements ContentList{ @Override public void updateAlt(Player player){ - if(player.isShooting && player.timer.get(Player.timerAbility, buildTime) && getDrones(player) < maxDrones && !TutorialSector.supressDrone()){ - if(!Net.client()) { - AlphaDrone drone = (AlphaDrone) UnitTypes.alphaDrone.create(player.getTeam()); - drone.leader = player; - drone.set(player.x, player.y); - drone.add(); + if(player.isShooting && getDrones(player) < maxDrones && !TutorialSector.supressDrone()){ + player.timer.get(Player.timerAbility, buildTime); + + if(player.timer.getTime(Player.timerAbility) > buildTime/2f){ + if(!Net.client()){ + AlphaDrone drone = (AlphaDrone) UnitTypes.alphaDrone.create(player.getTeam()); + drone.leader = player; + drone.set(player.x, player.y); + drone.add(); + } + Effects.effect(UnitFx.unitLand, player); } - Effects.effect(UnitFx.unitLand, player); } } diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index 4dd94aa2b8..d6659dc925 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -41,7 +41,10 @@ public class Logic extends Module{ @Override public void init(){ EntityQuery.init(); - EntityQuery.collisions().setCollider(tilesize, world::solid); + EntityQuery.collisions().setCollider(tilesize, (x, y) -> { + Tile tile = world.tile(x, y); + return tile != null && tile.solid(); + }); } public void play(){ diff --git a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java index b49db5d02c..98720743bb 100644 --- a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java +++ b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java @@ -324,8 +324,8 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{ if(target != null) behavior(); if(!isWave && !isFlying()){ - x = Mathf.clamp(x, 0, world.width() * tilesize); - y = Mathf.clamp(y, 0, world.height() * tilesize); + x = Mathf.clamp(x, tilesize/2f, world.width() * tilesize - tilesize/2f); + y = Mathf.clamp(y, tilesize/2f, world.height() * tilesize - tilesize/2f); } } diff --git a/core/src/io/anuke/mindustry/entities/units/types/AlphaDrone.java b/core/src/io/anuke/mindustry/entities/units/types/AlphaDrone.java index 4063ac6100..6f80b842c0 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/AlphaDrone.java +++ b/core/src/io/anuke/mindustry/entities/units/types/AlphaDrone.java @@ -41,7 +41,7 @@ public class AlphaDrone extends FlyingUnit { target = leader; if(last == null){ - circle(leader.isShooting ? 50f : 0f); + circle(leader.isShooting ? 60f : 0f); } target = last; diff --git a/core/src/io/anuke/mindustry/io/SaveFileVersion.java b/core/src/io/anuke/mindustry/io/SaveFileVersion.java index b4b60634a9..b46f2644f3 100644 --- a/core/src/io/anuke/mindustry/io/SaveFileVersion.java +++ b/core/src/io/anuke/mindustry/io/SaveFileVersion.java @@ -1,6 +1,7 @@ package io.anuke.mindustry.io; import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.ObjectSet; import io.anuke.mindustry.content.blocks.Blocks; import io.anuke.mindustry.content.blocks.StorageBlocks; import io.anuke.mindustry.entities.traits.SaveTrait; @@ -214,6 +215,7 @@ public abstract class SaveFileVersion{ } public void readEntities(DataInputStream stream) throws IOException{ + ObjectSet> set = new ObjectSet<>(); byte groups = stream.readByte(); for(int i = 0; i < groups; i++){ @@ -222,8 +224,13 @@ public abstract class SaveFileVersion{ byte typeid = stream.readByte(); SaveTrait trait = (SaveTrait) TypeTrait.getTypeByID(typeid).get(); trait.readSave(stream); + set.add(trait.targetGroup()); } } + + for(EntityGroup group : set){ + group.updateEvents(); + } } public MappableContent[][] readContentHeader(DataInputStream stream) throws IOException{ diff --git a/core/src/io/anuke/mindustry/maps/Sectors.java b/core/src/io/anuke/mindustry/maps/Sectors.java index 1599dd8092..984788ae3e 100644 --- a/core/src/io/anuke/mindustry/maps/Sectors.java +++ b/core/src/io/anuke/mindustry/maps/Sectors.java @@ -88,9 +88,7 @@ public class Sectors{ public Difficulty getDifficulty(Sector sector){ if(sector.difficulty == 0){ - //yes, this means hard tutorial difficulty - //(((have fun))) - return Difficulty.hard; + return Difficulty.normal; }else if(sector.difficulty < 4){ return Difficulty.normal; }else if(sector.difficulty < 9){ diff --git a/core/src/io/anuke/mindustry/maps/missions/WaveMission.java b/core/src/io/anuke/mindustry/maps/missions/WaveMission.java index 7ddaa5e0d0..258ae7814d 100644 --- a/core/src/io/anuke/mindustry/maps/missions/WaveMission.java +++ b/core/src/io/anuke/mindustry/maps/missions/WaveMission.java @@ -1,6 +1,5 @@ package io.anuke.mindustry.maps.missions; -import com.badlogic.gdx.math.GridPoint2; import com.badlogic.gdx.utils.Array; import io.anuke.mindustry.Vars; import io.anuke.mindustry.game.GameMode; @@ -11,9 +10,7 @@ import io.anuke.mindustry.maps.Sector; import io.anuke.mindustry.maps.generation.Generation; import io.anuke.ucore.util.Bundles; -import static io.anuke.mindustry.Vars.state; -import static io.anuke.mindustry.Vars.waveTeam; -import static io.anuke.mindustry.Vars.world; +import static io.anuke.mindustry.Vars.*; public class WaveMission extends MissionWithStartingCore{ private final int target; From 97857453842f5905c5aedcc1642788782c9cd33e Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 7 Nov 2018 20:24:38 -0500 Subject: [PATCH 09/34] Fixed many multiplayer bugs --- core/src/io/anuke/mindustry/Vars.java | 2 ++ .../src/io/anuke/mindustry/content/Mechs.java | 3 ++- core/src/io/anuke/mindustry/core/Control.java | 6 ----- core/src/io/anuke/mindustry/core/Logic.java | 22 +++++++++++++++++-- .../mindustry/entities/units/types/Drone.java | 4 ++++ core/src/io/anuke/mindustry/game/Unlocks.java | 8 ------- core/src/io/anuke/mindustry/maps/Sectors.java | 2 +- .../anuke/mindustry/maps/TutorialSector.java | 2 +- .../mindustry/maps/missions/WaveMission.java | 4 ++-- core/src/io/anuke/mindustry/world/Block.java | 2 +- 10 files changed, 33 insertions(+), 22 deletions(-) diff --git a/core/src/io/anuke/mindustry/Vars.java b/core/src/io/anuke/mindustry/Vars.java index 038a48ee7e..a11a7dbdcb 100644 --- a/core/src/io/anuke/mindustry/Vars.java +++ b/core/src/io/anuke/mindustry/Vars.java @@ -94,6 +94,7 @@ public class Vars{ public static float controllerMin = 0.25f; public static float baseControllerSpeed = 11f; public static boolean snapCamera = true; + public static ContentLoader content; public static GameState state; public static ThreadHandler threads; @@ -162,6 +163,7 @@ public class Vars{ }); } + state = new GameState(); threads = new ThreadHandler(); mobile = Gdx.app.getType() == ApplicationType.Android || Gdx.app.getType() == ApplicationType.iOS || testMobile; diff --git a/core/src/io/anuke/mindustry/content/Mechs.java b/core/src/io/anuke/mindustry/content/Mechs.java index 9e7d8ee3fd..88fb7b6a9e 100644 --- a/core/src/io/anuke/mindustry/content/Mechs.java +++ b/core/src/io/anuke/mindustry/content/Mechs.java @@ -62,8 +62,9 @@ public class Mechs implements ContentList{ drone.leader = player; drone.set(player.x, player.y); drone.add(); + + Effects.effect(UnitFx.unitLand, player); } - Effects.effect(UnitFx.unitLand, player); } } } diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index e55d559ec1..7fec236a56 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -178,12 +178,6 @@ public class Control extends Module{ }); Events.on(WorldLoadEvent.class, event -> threads.runGraphics(() -> Events.fire(new WorldLoadGraphicsEvent()))); - - Events.on(TileChangeEvent.class, event -> { - if(event.tile.getTeam() == players[0].getTeam() && Recipe.getByResult(event.tile.block()) != null){ - unlocks.handleContentUsed(Recipe.getByResult(event.tile.block())); - } - }); } public void addPlayer(int index){ diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index d6659dc925..625e0ec42a 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -10,9 +10,11 @@ import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.GameMode; import io.anuke.mindustry.game.Team; import io.anuke.mindustry.game.Teams; +import io.anuke.mindustry.game.UnlockableContent; import io.anuke.mindustry.gen.Call; import io.anuke.mindustry.net.Net; import io.anuke.mindustry.type.ItemStack; +import io.anuke.mindustry.type.Recipe; import io.anuke.mindustry.world.Tile; import io.anuke.ucore.core.Events; import io.anuke.ucore.core.Timers; @@ -35,7 +37,11 @@ public class Logic extends Module{ public boolean doUpdate = true; public Logic(){ - state = new GameState(); + Events.on(TileChangeEvent.class, event -> { + if(event.tile.getTeam() == defaultTeam && Recipe.getByResult(event.tile.block()) != null){ + handleContent(Recipe.getByResult(event.tile.block())); + } + }); } @Override @@ -47,6 +53,17 @@ public class Logic extends Module{ }); } + /**Handles the event of content being used by either the player or some block.*/ + public void handleContent(UnlockableContent content){ + if(world.getSector() != null){ + world.getSector().currentMission().onContentUsed(content); + } + + if(!headless){ + control.unlocks.unlockContent(content); + } + } + public void play(){ state.set(State.playing); state.wavetime = wavespace * state.difficulty.timeScaling * 2; @@ -145,7 +162,8 @@ public class Logic extends Module{ world.sectors.completeSector(world.getSector().x, world.getSector().y); world.sectors.save(); - if(!headless){ + + if(!headless && !Net.client()){ ui.missions.show(world.getSector()); } diff --git a/core/src/io/anuke/mindustry/entities/units/types/Drone.java b/core/src/io/anuke/mindustry/entities/units/types/Drone.java index ed5cc2c6fd..d5c3d283f0 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/Drone.java +++ b/core/src/io/anuke/mindustry/entities/units/types/Drone.java @@ -319,6 +319,10 @@ public class Drone extends FlyingUnit implements BuilderTrait{ TileEntity entity = (TileEntity) target; entity.health += type.healSpeed * Timers.delta(); entity.health = Mathf.clamp(entity.health, 0, entity.tile.block().health); + + if(timer.get(timerRepairEffect, 30)){ + Effects.effect(BlockFx.healBlockFull, Palette.heal, entity.x, entity.y, entity.tile.block().size); + } } updateBuilding(this); diff --git a/core/src/io/anuke/mindustry/game/Unlocks.java b/core/src/io/anuke/mindustry/game/Unlocks.java index 0730c4af64..e2bbd5984b 100644 --- a/core/src/io/anuke/mindustry/game/Unlocks.java +++ b/core/src/io/anuke/mindustry/game/Unlocks.java @@ -19,14 +19,6 @@ public class Unlocks{ Settings.setSerializer(ContentType.class, (stream, t) -> stream.writeInt(t.ordinal()), stream -> ContentType.values()[stream.readInt()]); } - /**Handles the event of content being used by either the player or some block.*/ - public void handleContentUsed(UnlockableContent content){ - if(world.getSector() != null){ - world.getSector().currentMission().onContentUsed(content); - } - unlockContent(content); - } - /** Returns whether or not this piece of content is unlocked yet.*/ public boolean isUnlocked(UnlockableContent content){ return rootSet().isUnlocked(content) || currentSet().isUnlocked(content); diff --git a/core/src/io/anuke/mindustry/maps/Sectors.java b/core/src/io/anuke/mindustry/maps/Sectors.java index 984788ae3e..9e372acc43 100644 --- a/core/src/io/anuke/mindustry/maps/Sectors.java +++ b/core/src/io/anuke/mindustry/maps/Sectors.java @@ -88,7 +88,7 @@ public class Sectors{ public Difficulty getDifficulty(Sector sector){ if(sector.difficulty == 0){ - return Difficulty.normal; + return Difficulty.hard; }else if(sector.difficulty < 4){ return Difficulty.normal; }else if(sector.difficulty < 9){ diff --git a/core/src/io/anuke/mindustry/maps/TutorialSector.java b/core/src/io/anuke/mindustry/maps/TutorialSector.java index ccc75b38db..f88dbbabc9 100644 --- a/core/src/io/anuke/mindustry/maps/TutorialSector.java +++ b/core/src/io/anuke/mindustry/maps/TutorialSector.java @@ -90,7 +90,7 @@ public class TutorialSector{ return Array.with( //intentionally unlocalized - new ItemMission(Items.copper, 10).setMessage("An updated tutorial will return next build.\nFor now, you'll have to deal with... this."), + new ItemMission(Items.copper, 50).setMessage("An updated tutorial will return next build.\nFor now, you'll have to deal with... this."), new BlockMission(ProductionBlocks.mechanicalDrill), diff --git a/core/src/io/anuke/mindustry/maps/missions/WaveMission.java b/core/src/io/anuke/mindustry/maps/missions/WaveMission.java index 258ae7814d..5a257192a4 100644 --- a/core/src/io/anuke/mindustry/maps/missions/WaveMission.java +++ b/core/src/io/anuke/mindustry/maps/missions/WaveMission.java @@ -8,6 +8,7 @@ import io.anuke.mindustry.game.Team; import io.anuke.mindustry.game.Waves; import io.anuke.mindustry.maps.Sector; import io.anuke.mindustry.maps.generation.Generation; +import io.anuke.mindustry.net.Net; import io.anuke.ucore.util.Bundles; import static io.anuke.mindustry.Vars.*; @@ -35,7 +36,6 @@ public class WaveMission extends MissionWithStartingCore{ this.target = target; } - @Override public Array getWaves(Sector sector){ return Waves.getSpawns(); @@ -62,7 +62,7 @@ public class WaveMission extends MissionWithStartingCore{ public String displayString(){ return state.wave > target ? Bundles.format( - Vars.unitGroups[Vars.waveTeam.ordinal()].size() > 1 ? + Vars.unitGroups[Vars.waveTeam.ordinal()].size() > 1 && !Net.client() ? "text.mission.wave.enemies" : "text.mission.wave.enemy", target, target, Vars.unitGroups[Vars.waveTeam.ordinal()].size()) : Bundles.format("text.mission.wave", state.wave, target, (int)(state.wavetime/60)); diff --git a/core/src/io/anuke/mindustry/world/Block.java b/core/src/io/anuke/mindustry/world/Block.java index 90e513763b..e12050bbb5 100644 --- a/core/src/io/anuke/mindustry/world/Block.java +++ b/core/src/io/anuke/mindustry/world/Block.java @@ -230,7 +230,7 @@ public class Block extends BaseBlock { /**Call when some content is produced. This unlocks the content if it is applicable.*/ public void useContent(Tile tile, UnlockableContent content){ if(!headless && tile.getTeam() == players[0].getTeam()){ - control.unlocks.handleContentUsed(content); + logic.handleContent(content); } } From b449847ad12d2a5759968f331010ebe606bd7241 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 7 Nov 2018 20:30:02 -0500 Subject: [PATCH 10/34] Reverted to power system that wasn't broken --- .../world/blocks/power/PowerGraph.java | 72 +++++++------------ 1 file changed, 24 insertions(+), 48 deletions(-) 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 f9d4a8aba2..5fecfbeba3 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/PowerGraph.java @@ -5,6 +5,7 @@ import com.badlogic.gdx.utils.IntSet; import com.badlogic.gdx.utils.ObjectSet; import com.badlogic.gdx.utils.Queue; import io.anuke.mindustry.world.Tile; +import io.anuke.ucore.core.Timers; import static io.anuke.mindustry.Vars.threads; @@ -37,63 +38,38 @@ public class PowerGraph{ lastFrameUpdated = threads.getFrameID(); - boolean charge = false; - float totalInput = 0f; - float bufferInput = 0f; + for(Tile producer : producers){ - if (producer.block().consumesPower) { - bufferInput += producer.entity.power.amount; - } else { - totalInput += producer.entity.power.amount; - } + totalInput += producer.entity.power.amount; } - float maxOutput = 0f; - float bufferOutput = 0f; - for(Tile consumer : consumers){ - if (consumer.block().outputsPower) { - bufferOutput += consumer.block().powerCapacity - consumer.entity.power.amount; - } else { - maxOutput += consumer.block().powerCapacity - consumer.entity.power.amount; - } - } - - if (maxOutput < totalInput) { - charge = true; - } - - if (totalInput + bufferInput <= 0.0001f || maxOutput + bufferOutput <= 0.0001f) { - return; - } - - float bufferUsed = 0; - if (charge) { - bufferUsed = Math.min((totalInput - maxOutput) / bufferOutput, 1f); - } else { - bufferUsed = Math.min((maxOutput - totalInput) / bufferInput, 1f); - } - - float inputUsed = charge ? Math.min((maxOutput + bufferOutput) / totalInput, 1f) : 1f; for(Tile producer : producers){ - if (producer.block().consumesPower) { - if (!charge) { - producer.entity.power.amount -= producer.entity.power.amount * bufferUsed; - } + float accumulator = producer.entity.power.amount; + + if(accumulator <= 0.0001f) continue; + + float toEach = accumulator / consumers.size; + float outputs = 0f; + + for(Tile tile : consumers){ + outputs += Math.min(tile.block().powerCapacity - tile.entity.power.amount, toEach) / toEach; + } + + float finalEach = toEach / outputs * Timers.delta(); + float buffer = 0f; + + if(Float.isNaN(finalEach) || Float.isInfinite(finalEach)){ continue; } - producer.entity.power.amount -= producer.entity.power.amount * inputUsed; - } - float outputSatisfied = charge ? 1f : Math.min((totalInput + bufferInput) / maxOutput, 1f); - for(Tile consumer : consumers){ - if (consumer.block().outputsPower) { - if (charge) { - consumer.entity.power.amount += (consumer.block().powerCapacity - consumer.entity.power.amount) * bufferUsed; - } - continue; + for(Tile tile : consumers){ + float used = Math.min(tile.block().powerCapacity - tile.entity.power.amount, finalEach) * accumulator / totalInput; + buffer += used; + tile.entity.power.amount += used; } - consumer.entity.power.amount += (consumer.block().powerCapacity - consumer.entity.power.amount) * outputSatisfied; + + producer.entity.power.amount -= buffer; } } From 7488dc3ebb9ff320f3530712f70ee0c9315afff1 Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 7 Nov 2018 21:49:26 -0500 Subject: [PATCH 11/34] Fixed access violation crash --- core/src/io/anuke/mindustry/core/NetClient.java | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/core/src/io/anuke/mindustry/core/NetClient.java b/core/src/io/anuke/mindustry/core/NetClient.java index baebe42cc8..91b52c1cdf 100644 --- a/core/src/io/anuke/mindustry/core/NetClient.java +++ b/core/src/io/anuke/mindustry/core/NetClient.java @@ -165,14 +165,17 @@ public class NetClient extends Module{ public static void onKick(KickReason reason){ netClient.disconnectQuietly(); state.set(State.menu); - if(!reason.quiet){ - if(reason.extraText() != null){ - ui.showText(reason.toString(), reason.extraText()); - }else{ - ui.showText("$text.disconnect", reason.toString()); + + threads.runGraphics(() -> { + if(!reason.quiet){ + if(reason.extraText() != null){ + ui.showText(reason.toString(), reason.extraText()); + }else{ + ui.showText("$text.disconnect", reason.toString()); + } } - } - ui.loadfrag.hide(); + ui.loadfrag.hide(); + }); } @Remote(variants = Variant.both) From cf50d558ba9bd2ba8a271a5156af4cb9f5d00e3d Mon Sep 17 00:00:00 2001 From: Anuken Date: Wed, 7 Nov 2018 22:37:34 -0500 Subject: [PATCH 12/34] Fixed many various things --- .gitignore | 1 + .../anuke/mindustry/TextFieldDialogListener.java | 13 +++++++------ core/assets/bundles/bundle.properties | 1 + core/assets/bundles/bundle_ru.properties | 2 +- core/src/io/anuke/mindustry/core/UI.java | 7 +++++++ core/src/io/anuke/mindustry/maps/Sectors.java | 2 +- .../mindustry/maps/missions/MessageMission.java | 15 --------------- .../mindustry/ui/dialogs/SettingsMenuDialog.java | 6 +++++- .../io/anuke/mindustry/desktop/CrashHandler.java | 10 ++++++++++ kryonet/src/io/anuke/kryonet/KryoServer.java | 9 ++------- .../io/anuke/mindustry/server/ServerControl.java | 2 +- 11 files changed, 36 insertions(+), 32 deletions(-) delete mode 100644 core/src/io/anuke/mindustry/maps/missions/MessageMission.java diff --git a/.gitignore b/.gitignore index fdf2b4f464..e658c17679 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ ##Packr, build stuff +logs/ /core/assets/mindustry-saves/ /core/assets/mindustry-maps/ /core/assets/bundles/output/ diff --git a/android/src/io/anuke/mindustry/TextFieldDialogListener.java b/android/src/io/anuke/mindustry/TextFieldDialogListener.java index be1cc6d924..c603fbff05 100644 --- a/android/src/io/anuke/mindustry/TextFieldDialogListener.java +++ b/android/src/io/anuke/mindustry/TextFieldDialogListener.java @@ -42,12 +42,13 @@ public class TextFieldDialogListener extends ClickListener{ AndroidTextFieldDialog dialog = new AndroidTextFieldDialog(); - dialog.setTextPromptListener(text -> { - field.clearText(); - field.appendText(text); - field.fire(new ChangeListener.ChangeEvent()); - Gdx.graphics.requestRendering(); - }); + dialog.setTextPromptListener(text -> + Gdx.app.postRunnable(() -> { + field.clearText(); + field.appendText(text); + field.fire(new ChangeListener.ChangeEvent()); + Gdx.graphics.requestRendering(); + })); if(type == 0){ dialog.setInputType(InputType.TYPE_CLASS_TEXT); diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index d50ec7eb18..d4d20529e8 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -372,6 +372,7 @@ setting.musicvol.name = Music Volume setting.mutemusic.name = Mute Music setting.sfxvol.name = SFX Volume setting.mutesound.name = Mute Sound +setting.crashreport.name = Send Anonymous Crash Reports text.keybind.title = Rebind Keys category.general.name = General category.view.name = View diff --git a/core/assets/bundles/bundle_ru.properties b/core/assets/bundles/bundle_ru.properties index ec1c960dad..d73654bbb6 100644 --- a/core/assets/bundles/bundle_ru.properties +++ b/core/assets/bundles/bundle_ru.properties @@ -407,7 +407,7 @@ mode.sandbox.name = Песочница mode.sandbox.description = Бесконечные ресурсы и нет таймера для волн, но можно самим вызвать волну. mode.custom.warning = [scarlet]РАЗБЛОКИРОВАННОЕ В ПОЛЬЗОВАТЕЛЬСКИХ ИГРАХ ИЛИ НА СЕРВЕРАХ НЕ СОХРАНЯЕТСЯ[]\n\nИграйте в секторах для разблокировки чего-либо mode.custom.warning.read = Внимательно прочитайте это!:\n[scarlet]РАЗБЛОКИРОВАННОЕ В ПОЛЬЗОВАТЕЛЬСКИХ ИГРАХ ИЛИ ДРУГИХ РЕЖИМАХ ИГРЫ НЕ РАСПРОСТРАНЯЕТСЯ НА СЕКТОРА ИЛИ ДРУГИЕ РЕЖИМЫ ИГРЫ!\n\n[LIGHT_GRAY](Я бы хотел, чтобы это не было необходимо, но, по-видимому, это так) -mode.freebuild.name = Cвободная\nстройка +mode.freebuild.name = Свободная\nстройка mode.freebuild.description = ограниченные ресурсы и нет таймера для волн. mode.pvp.name = Противо-\nстояние mode.pvp.description = боритесь против других игроков. diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index d8158b84fe..8120e2212a 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -28,6 +28,7 @@ import io.anuke.ucore.scene.ui.TextField.TextFieldFilter; import io.anuke.ucore.scene.ui.TooltipManager; import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.scene.ui.layout.Unit; +import io.anuke.ucore.util.Threads; import static io.anuke.mindustry.Vars.*; import static io.anuke.ucore.scene.actions.Actions.*; @@ -239,6 +240,8 @@ public class UI extends SceneModule{ } public void showInfoFade(String info){ + Threads.assertGraphics(); + Table table = new Table(); table.setFillParent(true); table.actions(Actions.fadeOut(7f, Interpolation.fade), Actions.removeActor()); @@ -247,6 +250,8 @@ public class UI extends SceneModule{ } public void showInfo(String info){ + Threads.assertGraphics(); + new Dialog("$text.info.title", "dialog"){{ getCell(content()).growX(); content().margin(15).add(info).width(400f).wrap().get().setAlignment(Align.center, Align.center); @@ -255,6 +260,8 @@ public class UI extends SceneModule{ } public void showInfo(String info, Runnable clicked){ + Threads.assertGraphics(); + new Dialog("$text.info.title", "dialog"){{ getCell(content()).growX(); content().margin(15).add(info).width(400f).wrap().get().setAlignment(Align.center, Align.center); diff --git a/core/src/io/anuke/mindustry/maps/Sectors.java b/core/src/io/anuke/mindustry/maps/Sectors.java index 9e372acc43..5f85f364b6 100644 --- a/core/src/io/anuke/mindustry/maps/Sectors.java +++ b/core/src/io/anuke/mindustry/maps/Sectors.java @@ -41,7 +41,7 @@ public class Sectors{ private final AsyncExecutor executor = new AsyncExecutor(6); public void playSector(Sector sector){ - if(sector.hasSave() && SaveIO.breakingVersions.contains(sector.getSave().getBuild())){ + if(!headless && sector.hasSave() && SaveIO.breakingVersions.contains(sector.getSave().getBuild())){ sector.getSave().delete(); ui.showInfo("$text.save.old"); } diff --git a/core/src/io/anuke/mindustry/maps/missions/MessageMission.java b/core/src/io/anuke/mindustry/maps/missions/MessageMission.java deleted file mode 100644 index 920f2cc111..0000000000 --- a/core/src/io/anuke/mindustry/maps/missions/MessageMission.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.anuke.mindustry.maps.missions; - -import io.anuke.mindustry.Vars; - -/**A mission that just displays some text.*/ -public class MessageMission extends ActionMission{ - - public MessageMission(String text){ - super(() -> { - if(!Vars.headless){ - Vars.ui.showInfo(text); - } - }); - } -} diff --git a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java index 79faa1a780..62595ad41e 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -136,7 +136,7 @@ public class SettingsMenuDialog extends SettingsDialog{ game.checkPref("autotarget", true); } //game.sliderPref("sensitivity", 100, 10, 300, i -> i + "%"); - game.sliderPref("saveinterval", 60, 10, 5 * 120, i -> Bundles.format("setting.seconds", i)); + game.sliderPref("saveinterval", 120, 10, 5 * 120, i -> Bundles.format("setting.seconds", i)); game.pref(new Setting(){ @Override public void add(SettingsTable table){ @@ -186,6 +186,10 @@ public class SettingsMenuDialog extends SettingsDialog{ } }); + if(!mobile){ + game.checkPref("crashreport", true); + } + graphics.sliderPref("fpscap", 125, 5, 125, 5, s -> (s > 120 ? Bundles.get("setting.fpscap.none") : Bundles.format("setting.fpscap.text", s))); graphics.checkPref("multithread", mobile, threads::setEnabled); diff --git a/desktop/src/io/anuke/mindustry/desktop/CrashHandler.java b/desktop/src/io/anuke/mindustry/desktop/CrashHandler.java index 54bfa7e1dd..1f29c1a906 100644 --- a/desktop/src/io/anuke/mindustry/desktop/CrashHandler.java +++ b/desktop/src/io/anuke/mindustry/desktop/CrashHandler.java @@ -23,6 +23,16 @@ public class CrashHandler{ public static void handle(Throwable e){ e.printStackTrace(); + try{ + //check crash report setting + if(!Settings.getBool("crashreport")){ + return; + } + }catch(Throwable ignored){ + //don't send since we don't know if the user has the setting set + return; + } + if(!OS.isMac){ try{ javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName()); diff --git a/kryonet/src/io/anuke/kryonet/KryoServer.java b/kryonet/src/io/anuke/kryonet/KryoServer.java index fc8882da9c..45269e42fb 100644 --- a/kryonet/src/io/anuke/kryonet/KryoServer.java +++ b/kryonet/src/io/anuke/kryonet/KryoServer.java @@ -30,7 +30,6 @@ import java.util.concurrent.CopyOnWriteArraySet; import static io.anuke.mindustry.Vars.threads; public class KryoServer implements ServerProvider { - final boolean tcpOnly = System.getProperty("java.version") == null; final Server server; final CopyOnWriteArrayList connections = new CopyOnWriteArrayList<>(); final CopyOnWriteArraySet missing = new CopyOnWriteArraySet<>(); @@ -150,11 +149,7 @@ public class KryoServer implements ServerProvider { lastconnection = 0; connections.clear(); missing.clear(); - if(tcpOnly){ - server.bind(port); - }else{ - server.bind(port, port); - } + server.bind(port, port); serverThread = new Thread(() -> { try{ @@ -172,7 +167,7 @@ public class KryoServer implements ServerProvider { connections.clear(); lastconnection = 0; - async(server::close); + async(server::stop); } @Override diff --git a/server/src/io/anuke/mindustry/server/ServerControl.java b/server/src/io/anuke/mindustry/server/ServerControl.java index 18260e3315..c0a43aae57 100644 --- a/server/src/io/anuke/mindustry/server/ServerControl.java +++ b/server/src/io/anuke/mindustry/server/ServerControl.java @@ -68,7 +68,7 @@ public class ServerControl extends Module{ ); Log.setLogger(new LogHandler(){ - DateTimeFormatter dateTime = DateTimeFormatter.ofPattern("MM-dd-yyyy | HH:mm:ss"); + DateTimeFormatter dateTime = DateTimeFormatter.ofPattern("MM-dd-yyyy | HH:mm:ss"); @Override public void info(String text, Object... args){ From 4355881fb25cbb50c746d81528e240de25ef640b Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 8 Nov 2018 09:03:42 -0500 Subject: [PATCH 13/34] Fixed save files not working --- core/src/io/anuke/mindustry/ai/BlockIndexer.java | 1 + .../mindustry/content/blocks/PowerBlocks.java | 4 ++-- core/src/io/anuke/mindustry/core/Logic.java | 10 +++++----- .../anuke/mindustry/entities/units/BaseUnit.java | 5 +---- .../src/io/anuke/mindustry/io/SaveFileVersion.java | 7 ------- .../mindustry/ui/dialogs/SettingsMenuDialog.java | 12 +++++------- .../world/blocks/power/ItemLiquidGenerator.java | 11 ++++++++--- .../world/blocks/power/LiquidGenerator.java | 14 ++++++++------ .../world/blocks/power/LiquidHeatGenerator.java | 2 +- 9 files changed, 31 insertions(+), 35 deletions(-) diff --git a/core/src/io/anuke/mindustry/ai/BlockIndexer.java b/core/src/io/anuke/mindustry/ai/BlockIndexer.java index c8b87d4750..1213bd2721 100644 --- a/core/src/io/anuke/mindustry/ai/BlockIndexer.java +++ b/core/src/io/anuke/mindustry/ai/BlockIndexer.java @@ -71,6 +71,7 @@ public class BlockIndexer{ flagMap[i][j] = new ObjectSet<>(); } } + typeMap.clear(); ores = null; diff --git a/core/src/io/anuke/mindustry/content/blocks/PowerBlocks.java b/core/src/io/anuke/mindustry/content/blocks/PowerBlocks.java index fb43623e58..1420f0c838 100644 --- a/core/src/io/anuke/mindustry/content/blocks/PowerBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/PowerBlocks.java @@ -20,9 +20,9 @@ public class PowerBlocks extends BlockList implements ContentList{ }}; thermalGenerator = new LiquidHeatGenerator("thermal-generator"){{ - maxLiquidGenerate = 0.5f; + maxLiquidGenerate = 4f; powerCapacity = 40f; - powerPerLiquid = 1f; + powerPerLiquid = 0.1f; generateEffect = BlockFx.redgeneratespark; size = 2; }}; diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index 625e0ec42a..f4aa97922b 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -180,11 +180,6 @@ public class Logic extends Module{ if(!state.is(State.menu)){ - if(!Net.client() && !world.isInvalidMap()){ - updateSectors(); - checkGameOver(); - } - if(!state.isPaused()){ Timers.update(); @@ -237,6 +232,11 @@ public class Logic extends Module{ world.pathfinder.update(); } + + if(!Net.client() && !world.isInvalidMap()){ + updateSectors(); + checkGameOver(); + } } if(threads.isEnabled()){ diff --git a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java index 98720743bb..3a4a8c7c36 100644 --- a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java +++ b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java @@ -28,10 +28,7 @@ import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Timers; import io.anuke.ucore.entities.EntityGroup; import io.anuke.ucore.graphics.Draw; -import io.anuke.ucore.util.Angles; -import io.anuke.ucore.util.Geometry; -import io.anuke.ucore.util.Mathf; -import io.anuke.ucore.util.Timer; +import io.anuke.ucore.util.*; import java.io.DataInput; import java.io.DataOutput; diff --git a/core/src/io/anuke/mindustry/io/SaveFileVersion.java b/core/src/io/anuke/mindustry/io/SaveFileVersion.java index b46f2644f3..b4b60634a9 100644 --- a/core/src/io/anuke/mindustry/io/SaveFileVersion.java +++ b/core/src/io/anuke/mindustry/io/SaveFileVersion.java @@ -1,7 +1,6 @@ package io.anuke.mindustry.io; import com.badlogic.gdx.utils.Array; -import com.badlogic.gdx.utils.ObjectSet; import io.anuke.mindustry.content.blocks.Blocks; import io.anuke.mindustry.content.blocks.StorageBlocks; import io.anuke.mindustry.entities.traits.SaveTrait; @@ -215,7 +214,6 @@ public abstract class SaveFileVersion{ } public void readEntities(DataInputStream stream) throws IOException{ - ObjectSet> set = new ObjectSet<>(); byte groups = stream.readByte(); for(int i = 0; i < groups; i++){ @@ -224,13 +222,8 @@ public abstract class SaveFileVersion{ byte typeid = stream.readByte(); SaveTrait trait = (SaveTrait) TypeTrait.getTypeByID(typeid).get(); trait.readSave(stream); - set.add(trait.targetGroup()); } } - - for(EntityGroup group : set){ - group.updateEvents(); - } } public MappableContent[][] readContentHeader(DataInputStream stream) throws IOException{ diff --git a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java index 62595ad41e..1c0f04abc9 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -130,13 +130,16 @@ public class SettingsMenuDialog extends SettingsDialog{ sound.volumePrefs(); game.screenshakePref(); - //game.checkPref("smoothcam", true); game.checkPref("effects", true); if(mobile){ game.checkPref("autotarget", true); } - //game.sliderPref("sensitivity", 100, 10, 300, i -> i + "%"); game.sliderPref("saveinterval", 120, 10, 5 * 120, i -> Bundles.format("setting.seconds", i)); + + if(!mobile){ + game.checkPref("crashreport", true); + } + game.pref(new Setting(){ @Override public void add(SettingsTable table){ @@ -186,10 +189,6 @@ public class SettingsMenuDialog extends SettingsDialog{ } }); - if(!mobile){ - game.checkPref("crashreport", true); - } - graphics.sliderPref("fpscap", 125, 5, 125, 5, s -> (s > 120 ? Bundles.get("setting.fpscap.none") : Bundles.format("setting.fpscap.text", s))); graphics.checkPref("multithread", mobile, threads::setEnabled); @@ -197,7 +196,6 @@ public class SettingsMenuDialog extends SettingsDialog{ threads.setEnabled(true); } - if(!mobile){ graphics.checkPref("vsync", true, b -> Gdx.graphics.setVSync(b)); graphics.checkPref("fullscreen", false, b -> { 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 8f71d61531..fa1a44c5cf 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/ItemLiquidGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/ItemLiquidGenerator.java @@ -5,6 +5,7 @@ import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.consumers.ConsumeLiquidFilter; +import io.anuke.mindustry.world.meta.BlockStat; import io.anuke.ucore.core.Effects; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.util.Mathf; @@ -15,9 +16,7 @@ import static io.anuke.mindustry.Vars.tilesize; public abstract class ItemLiquidGenerator extends ItemGenerator{ protected float minLiquidEfficiency = 0.2f; protected float powerPerLiquid = 0.13f; - /** - * Maximum liquid used per frame. - */ + /**Maximum liquid used per frame.*/ protected float maxLiquidGenerate = 0.4f; public ItemLiquidGenerator(String name){ @@ -28,6 +27,12 @@ public abstract class ItemLiquidGenerator extends ItemGenerator{ consumes.add(new ConsumeLiquidFilter(liquid -> getLiquidEfficiency(liquid) >= minLiquidEfficiency, 0.001f, true)).update(false).optional(true); } + @Override + public void init(){ + super.init(); + stats.remove(BlockStat.liquidFuelUse); + } + @Override public void update(Tile tile){ ItemGeneratorEntity entity = tile.entity(); diff --git a/core/src/io/anuke/mindustry/world/blocks/power/LiquidGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/LiquidGenerator.java index 2be20f985e..8a8ed8ca25 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/LiquidGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/LiquidGenerator.java @@ -13,19 +13,21 @@ import io.anuke.ucore.util.Mathf; public abstract class LiquidGenerator extends PowerGenerator{ protected float minEfficiency = 0.2f; - protected float powerPerLiquid = 0.13f; - /** - * Maximum liquid used per frame. - */ - protected float maxLiquidGenerate = 0.4f; + protected float powerPerLiquid; + /**Maximum liquid used per frame.*/ + protected float maxLiquidGenerate; protected Effect generateEffect = BlockFx.generatespark; public LiquidGenerator(String name){ super(name); liquidCapacity = 30f; hasLiquids = true; + } - consumes.add(new ConsumeLiquidFilter(liquid -> getEfficiency(liquid) >= minEfficiency, 0.001f)).update(false); + @Override + public void setStats(){ + consumes.add(new ConsumeLiquidFilter(liquid -> getEfficiency(liquid) >= minEfficiency, maxLiquidGenerate)).update(false); + super.setStats(); } @Override diff --git a/core/src/io/anuke/mindustry/world/blocks/power/LiquidHeatGenerator.java b/core/src/io/anuke/mindustry/world/blocks/power/LiquidHeatGenerator.java index 4c19816a8e..67a5bed015 100644 --- a/core/src/io/anuke/mindustry/world/blocks/power/LiquidHeatGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/power/LiquidHeatGenerator.java @@ -14,7 +14,7 @@ public class LiquidHeatGenerator extends LiquidGenerator{ public void setStats(){ super.setStats(); - stats.add(BlockStat.basePowerGeneration, maxLiquidGenerate * powerPerLiquid * 60f * 0.4f, StatUnit.powerSecond); + stats.add(BlockStat.basePowerGeneration, maxLiquidGenerate * powerPerLiquid * 60f, StatUnit.powerSecond); } @Override From b53821976e7faee5a792c70078609c242f93c24b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=ED=82=A4=EC=97=90=EB=A5=B4?= <44261958+Kieaer@users.noreply.github.com> Date: Fri, 9 Nov 2018 00:20:30 +0900 Subject: [PATCH 14/34] Update bundle_ko.properties (#316) * Update bundle_ko.properties * Fix typo --- core/assets/bundles/bundle_ko.properties | 258 ++++++++++++----------- 1 file changed, 130 insertions(+), 128 deletions(-) diff --git a/core/assets/bundles/bundle_ko.properties b/core/assets/bundles/bundle_ko.properties index 2c64fc3e65..2f4d1c04ec 100644 --- a/core/assets/bundles/bundle_ko.properties +++ b/core/assets/bundles/bundle_ko.properties @@ -13,22 +13,22 @@ text.editor.web = HTML5 버전은 에디터 기능을 지원하지 않습니다! text.web.unsupported = HTML5 버전은 이 기능을 지원하지 않습니다! 게임을 다운로드 한 뒤에 사용 해 주세요. text.gameover = 코어가 터졌습니다. 게임 오버! text.gameover.pvp = [accent]{0}[] 팀이 승리했습니다! -text.sector.gameover = 이 구역을 공략하는데 실패했습니다. 다시 배치하시겠습니까? -text.sector.retry = 다시할꺼임 +text.sector.gameover = 이 구역을 공략하는데 실패했습니다. 포기 하시겠습니까? +text.sector.retry = 아니오 text.highscore = [YELLOW]최고점수 달성! text.wave.lasted = [accent]{0}[] 까지 버티셨습니다. text.level.highscore = 최고 점수 : [accent]{0} text.level.delete.title = 삭제 확인 -text.map.delete = 정말로 "[accent]{0}[]" 맵을 삭제하시겠습니까? +text.map.delete = 정말로 "[orange]{0}[]" 맵을 삭제하시겠습니까? text.level.select = 맵 선택 text.level.mode = 게임모드 : text.construction.desktop = PC 에서의 조작 방법이 변경되었습니다.\n블록 선택을 해제하거나 건설을 중지하려면 [accent]스페이스 바[]를 누르세요. text.construction.title = 블록 배치 안내서 text.construction = [accent]블록 배치 모드[]를 선택하셨습니다.\n\n블록을 설치하고 싶으면, 자신의 건설 가능 범위 내에서 간단히 탭 하면 됩니다.\n일부 블록을 선택한 후에 확인 버튼을 누르면 배가 배치 작업을 진행할 것입니다.\n\n- [accent]블록을 삭제[]하고 싶다면 배치하고 싶은 영역을 탭 하세요. \n- [accent]블록을 넓게 배치[]하고 싶다면 배치하고 싶은 시작 영역을 길게 누르며 드래그 하면 됩니다.\n- [accent]블록을 한줄로 배치[]하고 싶다면 배치하고 싶은 시작 영역을 한번 탭 하고 길게 누르면서 드래그 하면 됩니다. \n- [accent]블록 배치 모드를 취소[]하고 싶다면 화면 하단 왼쪽에 있는 X 버튼을 누르면 됩니다. text.deconstruction.title = 블록 삭제 안내서 -text.deconstruction = [accent]블록 삭제 모드[]를 선택하셨습니다\n\n블록을 삭제하고 싶다면, 자신의 건설 가능 범위 내에서 간단히 탭 하면 됩니다.\n일부 블록을 선택한 후에 확인 버튼을 누르면 배가 파괴 작업을 진행할 것입니다.\n\n- [accent]블록을 삭제[]하고 싶다면 배치하고 싶은 영역을 탭 하세요\n- [accent]블록을 넓은 범위로 삭제[]하고 싶다면 배치하고 싶은 시작 영역을 길게 누르며 드래그 하면 됩니다.\n- [accent]블록 삭제 모드를 취소[]하고 싶다면 화면 하단 왼쪽에 있는 X 버튼을 누르면 됩니다. +text.deconstruction = [accent]블록 삭제 모드[]를 선택하셨습니다\n\n블록을 삭제하고 싶다면, 자신의 건설 가능 범위 내에서 간단히 탭 하면 됩니다.\n일부 블록을 선택한 후에 확인 버튼을 누르면 배가 파괴 작업을 진행할 것입니다.\n\n- [accent]블록을 삭제[]하고 싶다면 배치하고 싶은 영역을 탭 하세요\n- [accent]블록을 넓은 범위로 삭제[]하고 싶다면 배치하고 싶은 시작 영역을 길게 누르며 드래그 하면 됩니다.\n- [accent]블록 삭제 모드를 취소[]하고 싶다면 화면 하단 왼쪽에 있는 X 버튼을 누르면 됩니다. text.showagain = 다음 세션에서 이 메세지를 표시하지 않습니다 -text.coreattack = < 코어가 공격받고 있습니다 ! > +text.coreattack = < 코어가 공격받고 있습니다! > text.unlocks = 아이템들 text.savegame = 게임 저장 text.loadgame = 게임 불러오기 @@ -50,20 +50,20 @@ text.mission.main = 주요 목표 : [LIGHT_GRAY]{0} text.mission.info = 미션 정보 text.mission.complete = 미션 성공! text.mission.complete.body = 구역 {0},{1} 클리어. -text.mission.wave = [accent]{0}[]단계가 될때까지 생존하세요. -text.mission.wave.enemies = [accent] {0}/{1} []단계동안 생존하세요.\n{2}마리 남음 -text.mission.wave.enemy = [accent] {0}/{1} []단계동안 생존하세요.\n{2}마리 남음 +text.mission.wave = [accent]{0}/{1}[] 단계동안 생존하세요.남은 시간 {2}\n +text.mission.wave.enemies = [accent] {0}/{1} []단계를 생존하세요.\n{2}마리 남음 +text.mission.wave.enemy = [accent] {0}/{1} []단계를 생존하세요.\n{2}마리 남음 text.mission.wave.menu = [accent]{0}[] 단계 -text.mission.battle = 적 본부를 파괴하세요. +text.mission.battle = 적 코어를 파괴하세요. text.mission.resource.menu = {0} {1}개 수집 text.mission.resource = {0} 자원을 수집하세요 :\n[accent]{1}/{2}[] -text.mission.block = 이것을 만드세요 :\n{0} -text.mission.unit = 이 유닛을 만드세요 :\n{0} -text.mission.command = 유닛에게 이 명령을 보내세요 :\n{0} +text.mission.block = {0} 를 만드세요 +text.mission.unit = {0} 유닛을 만드세요 +text.mission.command = 유닛에게 {0} 명령을 보내세요 text.mission.linknode = 전력 노드를 연결하세요. -text.mission.display = [accent]미션 : \n[LIGHT_GRAY]{0} -text.mission.mech = 이 기체로 바꾸세요 :\n[accent]{0} -text.mission.create = 이 자원을 만드세요 :\n[accent]{0} +text.mission.display = [accent]미션 :\n[LIGHT_GRAY]{0} +text.mission.mech = [accent]{0}[] 기체로 바꾸세요 +text.mission.create = [accent]{0}[] 자원을 만드세요 text.none = <없음> text.close = 닫기 text.quit = 나가기 @@ -91,12 +91,12 @@ text.server.kicked.nameInUse = 이 닉네임이 이미 서버에서 사용중입 text.server.kicked.nameEmpty = 닉네임에는 반드시 영어 또는 숫자가 있어야 합니다. text.server.kicked.idInUse = 이미 서버에 접속중입니다! 다중 계정은 허용되지 않습니다. text.server.kicked.customClient = 이 서버는 직접 빌드한 버전을 지원하지 않습니다. 공식 버전을 사용하세요. -text.host.info = [accent]호스트[] 버튼은 현재 네트워크의 [scarlet]6567[] 과 [scarlet]6568[] 포트를 사용합니다.\n[LIGHY_GRAY]같은 Wi-Fi 또는 로컬 네트워크[] 에서 서버 목록을 볼 수 있습니다.\n\n만약 플레이어들이 이 IP를 통해 어디에서나 연결할 수 있게 하고 싶다면, 공유기 설정에서 [accent]포트 포워딩[]을 해야 합니다.\n\n[LIGHT_GRAY]참고 : LAN 게임 연결에 문제가 있는 사람이 있다면, 방화벽 설정에서 Mindustry 가 로컬 네트워크에 액세스하도록 허용했는지 확인 해 주세요. +text.host.info = [accent]호스트[] 버튼은 현재 네트워크의 [scarlet]6567[] 포트를 사용합니다.\n[LIGHY_GRAY]같은 Wi-Fi 또는 로컬 네트워크[] 에서 서버 목록을 볼 수 있습니다.\n\n만약 플레이어들이 이 IP를 통해 어디에서나 연결할 수 있게 하고 싶다면, 공유기 설정에서 [accent]포트 포워딩[]을 해야 합니다.\n\n[LIGHT_GRAY]참고 : LAN 게임 연결에 문제가 있는 사람이 있다면, 방화벽 설정에서 Mindustry 가 로컬 네트워크에 액세스하도록 허용했는지 확인 해 주세요. text.join.info = 여기서 [accent]서버 IP[]를 입력하여 다른 서버에 접속할 수 있습니다.\n또는 [accent]로컬 네트워크(LAN)[] 서버를 검색하여 접속할 수 있습니다.\nLAN 및 WAN 멀티 플레이어 모두 지원됩니다.\n\n[LIGHT_GRAY]참고:여기에서는 자동으로 글로벌 서버를 추가하지 않습니다. IP로 다른 사람의 서버에 접속할려면 서버장에게 IP를 요청해야 합니다. text.hostserver = 서버 열기 -text.hostserver.mobile = 게임\n호스트 -text.host = 호스트 -text.hosting = [accent]서버 여는중.. +text.hostserver.mobile = 서버\n열기 +text.host = 서버 열기 +text.hosting = [accent]서버 여는중... text.hosts.refresh = 새로고침 text.hosts.discovering = LAN 게임 찾기 text.server.refreshing = 서버 목록 새로고치는중... @@ -129,7 +129,7 @@ text.server.custombuild = [yellow]커스텀 서버 text.confirmban = 이 플레이어를 차단하시겠습니까? text.confirmkick = 정말로 이 플레이어를 추방시키겠습니까? text.confirmunban = 이 플레이어를 차단해제 하시겠습니까? -text.confirmadmin = 이 플레이어를 영자로 만들겠습니까? +text.confirmadmin = 이 플레이어를 관리자로 만들겠습니까? text.confirmunadmin = 이 플레이어를 일반 유저로 만들겠습니까? text.joingame.title = 게임 참가 text.joingame.ip = IP : @@ -140,7 +140,7 @@ text.connecting.data = [accent]맵 데이터 다운로드중... text.server.port = 포트 : text.server.addressinuse = 이 주소는 이미 사용중입니다! text.server.invalidport = 포트 번호가 잘못되었습니다. -text.server.error = [crimson]{0}[accent]서버를 여는데 오류가 발생했습니다.[] +text.server.error = [crimson]{0}[orange]서버를 여는데 오류가 발생했습니다.[] text.save.old = 이 저장파일은 이전 버전의 게임용이며, 지금은 사용할 수 없습니다. \n\n[LIGHT_GRAY]4.0 정식때 이전 게임버전에서 만든 저장파일과 호환됩니다. text.save.new = 새로 저장 text.save.overwrite = 이 저장 슬롯을 덮어씌우겠습니까? @@ -151,17 +151,17 @@ text.savefail = 게임을 저장하지 못했습니다! text.save.delete.confirm = 이 저장파일을 삭제 하시겠습니까? text.save.delete = 삭제 text.save.export = 저장파일 내보내기 -text.save.import.invalid = [accent]파일이 잘못되었습니다! -text.save.import.fail = [crimson]저장파일을 불러오지 못함 : [accent]{0} -text.save.export.fail = [crimson]저장파일을 내보내지 못함 : [accent]{0} +text.save.import.invalid = [orange]파일이 잘못되었습니다! +text.save.import.fail = [crimson]저장파일을 불러오지 못함 : [orange]{0} +text.save.export.fail = [crimson]저장파일을 내보내지 못함 : [orange]{0} text.save.import = 저장파일 불러오기 text.save.newslot = 저장 파일이름 : text.save.rename = 이름 변경 text.save.rename.text = 새 이름 : text.selectslot = 저장슬롯을 선택하십시오. text.slot = [accent]{0}번째 슬롯 -text.save.corrupted = [accent]세이브 파일이 손상되었거나 잘못된 파일입니다! 만약 게임을 업데이트 했다면 이것은 아마 저장 형식 변경일 것이고, 이것은 버그가 [scarlet]아닙니다[]. -text.sector.corrupted = [accent]저장 파일에서 구역을 발견했으나 불러오지 못했습니다.\n새로 생성되었습니다. +text.save.corrupted = [orange]세이브 파일이 손상되었거나 잘못된 파일입니다! 만약 게임을 업데이트 했다면 이것은 아마 저장 형식 변경일 것이고, 이것은 버그가 [scarlet]아닙니다[]. +text.sector.corrupted = [orange]저장 파일에서 구역을 발견했으나 불러오지 못했습니다.\n새로 생성되었습니다. text.empty = <비어있음> text.on = 켜기 text.off = 끄기 @@ -182,14 +182,14 @@ text.back = 뒤로가기 text.quit.confirm = 정말로 종료하시겠습니까? text.changelog.title = 변경사항 text.changelog.loading = 변경사항 가져오는중... -text.changelog.error.android = [accent]게임 변경사항은 가끔 Android 4.4 이하에서 작동하지 않습니다.이것은 내부 Android 버그 때문입니다. -text.changelog.error.ios = [accent]현재 iOS에서는 변경 사항을 지원하지 않습니다. +text.changelog.error.android = [orange]게임 변경사항은 가끔 Android 4.4 이하에서 작동하지 않습니다. 이것은 내부 Android 버그 때문입니다. +text.changelog.error.ios = [orange]현재 iOS에서는 변경 사항을 지원하지 않습니다. text.changelog.error = [scarlet]게임 변경사항을 가져오는 중 오류가 발생했습니다![]\n인터넷 연결을 확인하십시오. -text.changelog.current = [accent][[현재 버전] -text.changelog.latest = [accent][[최신 버전] +text.changelog.current = [orange][[현재 버전] +text.changelog.latest = [orange][[최신 버전] text.loading = [accent]불러오는중... text.saving = [accent]저장중... -text.wave = [accent]{0}단계 +text.wave = [orange]{0}단계 text.wave.waiting = 다음 단계 시작까지 {0}초 text.waiting = [LIGHT_GRAY]대기중... text.waiting.players = 다른 플레이어를 기다리는 중.. @@ -216,14 +216,14 @@ text.editor.description = 설명 : text.editor.name = 이름 : text.editor.teams = 팀 text.editor.elevation = 지형 높이 -text.editor.errorimageload = [accent]{0}[] 파일을 불러오는데 오류가 발생했습니다. -text.editor.errorimagesave = [accent]{0}[] 파일 저장중 오류가 발생했습니다. +text.editor.errorimageload = [orange]{0}[] 파일을 불러오는데 오류가 발생했습니다. +text.editor.errorimagesave = [orange]{0}[] 파일 저장중 오류가 발생했습니다. text.editor.generate = 생성 text.editor.resize = 맵 크기조정 text.editor.loadmap = 맵 불러오기 text.editor.savemap = 맵 저장 text.editor.saved = 저장됨! -text.editor.save.noname = 지도에 이름이 없습니다! '맵 정보' 메뉴에서 설정하세요. +text.editor.save.noname = 지도에 이름이 없습니다! 메뉴 -> '맵 정보' 에서 설정하세요. text.editor.save.overwrite = 이 맵의 이름은 기존에 있던 맵을 덮어씁니다! '맵 정보' 메뉴에서 다른 이름을 선택하세요. text.editor.import.exists = [scarlet]맵을 불러올 수 없음 : [] 기존에 있던 '{0}' 맵이 이미 존재합니다! text.editor.import = 가져오기 @@ -261,7 +261,7 @@ text.tutorial = 게임 방법 text.editor = 편집기 text.mapeditor = 맵 편집기 text.donate = 기부 -text.connectfail = [crimson]{0}[accent] 서버에 연결하지 못했습니다.[] +text.connectfail = [crimson]{0}[orange] 서버에 연결하지 못했습니다.[] text.error.unreachable = 서버에 연결하지 못했습니다. text.error.invalidaddress = 잘못된 주소입니다. text.error.timedout = 시간 초과!\n서버에 포트 포워딩이 설정되어 있고 주소가 올바른지 확인하십시오. @@ -285,50 +285,50 @@ text.settings.clearall = 모두 초기화 text.paused = 일시 정지 text.yes = 예 text.no = 아니오 -text.info.title = 정보 +text.info.title = [accent]정보 text.error.title = [crimson]오류가 발생했습니다. text.error.crashtitle = 오류가 발생했습니다. text.blocks.blockinfo = 블록 정보 -text.blocks.powercapacity = 최대 전력 용량 -text.blocks.powershot = 1발당 전력 소모량 -text.blocks.targetsair = 공중공격 가능 -text.blocks.itemspeed = 유닛 이동 속도 -text.blocks.shootrange = 사거리 -text.blocks.size = 블록 크기 -text.blocks.liquidcapacity = 최대 액체 용량 -text.blocks.maxitemssecond = 최대 아이템 보관량 -text.blocks.powerrange = 전력 범위 -text.blocks.poweruse = 전력 사용 -text.blocks.powerdamage = 전력/데미지 -text.blocks.inputitemcapacity = 입력 아이템 용량 -text.blocks.outputitemcapacity = 출력 아이템 용량 -text.blocks.itemcapacity = 저장 용량 -text.blocks.basepowergeneration = 기지 전력 생성기 -text.blocks.powertransferspeed = 전력 전송량 -text.blocks.craftspeed = 생산 속도 -text.blocks.inputliquid = 사용되는 액체 -text.blocks.inputliquidaux = 보조 액체 -text.blocks.inputitem = 사용되는 아이템 -text.blocks.inputitems = 사용되는 아이템들 -text.blocks.outputitem = 출력 아이템 -text.blocks.drilltier = 드릴 -text.blocks.drillspeed = 기본 드릴 속도 -text.blocks.liquidoutput = 액체 출력 -text.blocks.liquidoutputspeed = 액체 출력속도 -text.blocks.liquiduse = 액체 사용량 -text.blocks.coolant = 냉각제 -text.blocks.coolantuse = 냉각수 사용 -text.blocks.inputliquidfuel = 연료 액 -text.blocks.liquidfueluse = 액체 연료 사용 -text.blocks.explosive = 이게 터지면 펑 터지면서 주변 블록에게 피해를 입힙니다! -text.blocks.health = 체력 -text.blocks.inaccuracy = 오차각 -text.blocks.shots = 발포 횟수 -text.blocks.reload = 재장전 -text.blocks.inputfuel = 연료 -text.blocks.fuelburntime = 연료 연소 시간 -text.blocks.inputcapacity = 입력 용량 -text.blocks.outputcapacity = 출력 용량 +text.blocks.powercapacity = 최대 전력 용량 +text.blocks.powershot = 1발당 전력 소모량 +text.blocks.targetsair = 공중공격 가능 +text.blocks.itemspeed = 유닛 이동 속도 +text.blocks.shootrange = 사거리 +text.blocks.size = 블록 크기 +text.blocks.liquidcapacity = 최대 액체 용량 +text.blocks.maxitemssecond = 최대 아이템 보관량 +text.blocks.powerrange = 전력 범위 +text.blocks.poweruse = 전력 사용 +text.blocks.powerdamage = 전력/데미지 +text.blocks.inputitemcapacity = 입력 아이템 용량 +text.blocks.outputitemcapacity = 출력 아이템 용량 +text.blocks.itemcapacity = 저장 용량 +text.blocks.basepowergeneration = 기지 전력 생성기 +text.blocks.powertransferspeed = 전력 전송량 +text.blocks.craftspeed = 생산 속도 +text.blocks.inputliquid = 사용되는 액체 +text.blocks.inputliquidaux = 보조 액체 +text.blocks.inputitem = 사용되는 아이템 +text.blocks.inputitems = 사용되는 아이템들 +text.blocks.outputitem = 출력 아이템 +text.blocks.drilltier = 드릴 +text.blocks.drillspeed = 기본 드릴 속도 +text.blocks.liquidoutput = 액체 출력 +text.blocks.liquidoutputspeed = 액체 출력속도 +text.blocks.liquiduse = 액체 사용량 +text.blocks.coolant = 냉각제 +text.blocks.coolantuse = 냉각수 사용 +text.blocks.inputliquidfuel = 연료 액 +text.blocks.liquidfueluse = 액체 연료 사용 +text.blocks.explosive = 이 블록이 터지면 주변 블록과 같이 자폭을 합니다!! +text.blocks.health = 체력 +text.blocks.inaccuracy = 오차각 +text.blocks.shots = 발포 횟수 +text.blocks.reload = 재장전 +text.blocks.inputfuel = 연료 +text.blocks.fuelburntime = 연료 연소 시간 +text.blocks.inputcapacity = 입력 용량 +text.blocks.outputcapacity = 출력 용량 text.unit.blocks = 블록 text.unit.powersecond = 전력/초 text.unit.liquidsecond = 액체/초 @@ -370,6 +370,7 @@ setting.musicvol.name = 음악 크기 setting.mutemusic.name = 음소거 setting.sfxvol.name = 효과음 크기 setting.mutesound.name = 소리 끄기 +setting.crashreport.name = 오류 보고서 보내기 text.keybind.title = 키 바인딩 category.general.name = 일반 category.view.name = 보기 @@ -417,11 +418,11 @@ content.unit.name = 유닛 content.recipe.name = 블록 content.mech.name = 기체 item.stone.name = 돌 -item.stone.description = 주로 용암을 사용하여 얻을 수 있습니다. +item.stone.description = 주로 용암을 사용하여 얻을 수 있는 자원입니다. item.copper.name = 구리 item.copper.description = 모든 유형의 블록에서 광범위하게 사용되는 자원입니다. item.lead.name = 납 -item.lead.description = 쉽게 구할 수 있는 자원.\n전자 및 액체 수송 블록에서 광범위하게 사용되는 자원입니다. +item.lead.description = 쉽게 구할 수 있으며, 전자 및 액체 수송 블록에서 광범위하게 사용되는 자원입니다. item.coal.name = 석탄 item.coal.description = 쉽게 구할 수 있으며, 주로 제련소 등에서 연료로 사용됩니다. item.dense-alloy.name = 합금 @@ -439,9 +440,9 @@ item.phase-fabric.description = 최첨단 전자 제품과 자기수리 기술 item.surge-alloy.name = 설금 item.surge-alloy.description = 주로 건물의 재료로 사용되는 자원입니다 item.biomatter.name = 바이오메터 -item.biomatter.description = 이것은 유기농 덤불입니다!\n석유로 전환하거나 연료로 사용됩니다. +item.biomatter.description = 이것은 유기농 덤불입니다!\n압축기에 넣어 석유로 바꿀 수 있습니다. item.sand.name = 모래 -item.sand.description = 합금이나 플렉스 등에서 제련시 광범위하게 사용되는 일반적인 재료입니다. +item.sand.description = 합금이나 플럭스 등에서 제련시 광범위하게 사용되는 일반적인 재료입니다. item.blast-compound.name = 화합물 item.blast-compound.description = 포탑 및 건설의 재료로 사용되는 휘발성 화합물.\n연료로도 사용할 수 있지만, 별로 추천하지는 않습니다. item.pyratite.name = 피라테 @@ -482,7 +483,7 @@ mech.glaive-ship.weapon = 방화총 text.item.explosiveness = [LIGHT_GRAY]폭발력 : {0} text.item.flammability = [LIGHT_GRAY]인화성 : {0} text.item.radioactivity = [LIGHT_GRAY]방사능 : {0} -text.item.fluxiness = [LIGHT_GRAY]플렉스 파워 : {0} +text.item.fluxiness = [LIGHT_GRAY]플럭스 파워 : {0} text.unit.health = [LIGHT_GRAY]체력 : {0} text.unit.speed = [LIGHT_GRAY]속도 : {0} text.mech.weapon = [LIGHT_GRAY]무기 : {0} @@ -496,7 +497,7 @@ text.liquid.viscosity = [LIGHT_GRAY]점도 : {0} text.liquid.temperature = [LIGHT_GRAY]온도 : {0} block.spawn.name = 적 스폰지점 block.core.name = 코어 -block.metalfloor.name = 메탈 바닥 +block.metalfloor.name = 철판 block.deepwater.name = 깊은물 block.water.name = 물 block.lava.name = 용암 @@ -517,7 +518,7 @@ block.copper-wall-large.name = 큰 구리벽 block.dense-alloy-wall.name = 합금 벽 block.dense-alloy-wall-large.name = 큰 합금 벽 block.phase-wall.name = 메타벽 -block.phase-wall-large.name = 메타벽 +block.phase-wall-large.name = 큰 메타벽 block.thorium-wall.name = 토륨벽 block.thorium-wall-large.name = 대형 토륨벽 block.door.name = 문 @@ -534,7 +535,7 @@ block.distributor.name = 대형 분배기 block.sorter.name = 필터 block.sorter.description = 아이템을 넣어서 필터에 설정된 아이템일 경우 바로 앞으로 통과하며, 그렇지 않을 경우 옆으로 통과합니다. block.overflow-gate.name = 오버플로 게이트 -block.overflow-gate.description = 정면 경로가 차단된 경우 왼쪽과 오른쪽으로만 출력하는 복합 분배기입니다. +block.overflow-gate.description = 정면으로 가는 자원이 막히면 옆으로 출력하고, 그렇지 않으면 계속 정면으로 출력합니다. block.smelter.name = 제련소 block.arc-smelter.name = 대형 제련소 block.silicon-smelter.name = 실리콘 제련소 @@ -623,7 +624,6 @@ block.rtg-generator.name = 토륨 발전소 block.spectre.name = 스펙터 block.meltdown.name = 멜트다운 block.container.name = 컨테이너 -block.core.description = 게임에서 가장 중요한 건물.\n파괴되면 게임이 끝납니다. team.blue.name = 블루팀 team.red.name = 레드팀 team.orange.name = 오렌지팀 @@ -637,6 +637,7 @@ unit.phantom.name = 팬텀 드론 unit.phantom.description = 첨단 드론 유닛. 광석을 자동으로 채광하며, 아이템을 수집하고 블록을 수리합니다. 일반 드론보다 훨씬 효과적입니다. unit.dagger.name = 귀여운 디거 unit.dagger.description = 밈의 대상으로 지정되어 이름이 바뀐 기본 지상 유닛입니다. +## unit.dagger.description = 기본 지상 유닛입니다. 스웜과 같이 쓰면 유용합니다. unit.titan.name = 타이탄 unit.titan.description = 고급 지상 유닛입니다. 합금을 탄약으로 사용하며 지상과 공중 둘다 공격할 수 있습니다. unit.ghoul.name = 구울 폭격기 @@ -668,6 +669,7 @@ tutorial.daggerfactory = 이[accent] 귀여운 디거 기체 공장[]은\n\n공 tutorial.router = 공장을 작동시키기 위해 자원이 필요합니다.\n컨베이어에 운반되고 있는 자원을 분할할 분배기를 만드세요. tutorial.dagger = 전력 노드를 공장에 연결하세요.\n일단 요구 사항이 충족되면 기체 생산을 시작합니다.\n\n필요에 따라 드릴 및 발전기, 컨베이어를 더 많이 만들 수 있습니다. tutorial.battle = [LIGHT_GRAY]적[]의 코어가 드러났습니다.\n당신의 부대와 귀여운 디거를 사용하여 파괴하세요. +block.core.description = 게임에서 가장 중요한 건물.\n파괴되면 게임이 끝납니다. block.copper-wall.description = 구리로 만든 벽. block.copper-wall-large.description = 구리로 만든 큰 벽. block.dense-alloy-wall.description = 합금으로 만든 벽. 구리벽보다 체력이 높습니다. @@ -680,17 +682,17 @@ block.surge-wall.description = 데미지를 입으면 번개를 일으켜 대상 block.surge-wall-large.description = 설금을 재료로 한 큰 벽.\n데미지를 입으면 번개를 일으켜 대상에게 피해를 입힙니다. block.door.description = 유닛이 지나갈 수 있도록 만든 문. 클릭하면 열고 닫습니다. block.door-large.description = 유닛이 자나갈 수 있도록 만든 큰 문. 클릭하면 열고 닫습니다. -block.mend-projector.description = 주위 건물을 치료하는 건물. -block.overdrive-projector.description = 범위 내 모든 행동의 속도를 높여주는 보조형 방어 건물. +block.mend-projector.description = 주위 건물을 치료하는 건물입니다. +block.overdrive-projector.description = 범위 내 모든 행동의 속도를 높여주는 보조형 방어 건물입니다. block.force-projector.description = 보호막을 생성하는 건물.\n기본적으로 전기만 있으면 작동하지만, 메타를 넣어 보호막의 범위를 크게 확장시킬 수 있습니다. -block.shock-mine.description = 적이 이 블록을 지나가면 전격 공격을 하는 함정형 방어 건물. +block.shock-mine.description = 적이 이 블록을 지나가면 전격 공격을 하는 함정형 방어 건물입니다. block.duo.description = 범용성을 가진 터렛.\n지상 및 공중공격을 하며, 초중반에 유용합니다. block.arc.description = 목표 방향으로 전격 공격을 하는 포탑입니다. block.hail.description = 장거리 지상 공격을 하는 터렛입니다.\n적이 오기 전에 쓸어버릴 수 있습니다. block.lancer.description = 중거리 레이져 포탑입니다.\n적을 관통하기 때문에 뭉쳐있는 적들에게 매우 효과적입니다. block.wave.description = 적이 있는 자리에 액체를 뿌립니다.\n이 포탑을 활용하여 액체를 뿌린 곳에 불을 붙이거나 적을 느리게 할 수 있습니다. block.salvo.description = 명중률이 높고, 3발씩 끊어 발사하는 포탑입니다. -block.swarmer.description = 4발씩 끊어 발사하고, 유도 미사일을 가진 포탑입니다. +block.swarmer.description = 4발씩 끊어서 유도체를 발사하는 포탑입니다 block.ripple.description = 4개의 탄약으로 나눠 발사하여 명중률이 낮지만, 사거리가 매우 긴 포탑입니다. block.cyclone.description = 낮은 명중률과 높은 RPM 을 가진 포탑입니다.\n탄약이 남아있는 한 멈추지 않고 계속 연사합니다. block.fuse.description = 단거리에서 범위형 레이저를 발사하는 포탑입니다. @@ -701,21 +703,21 @@ block.titanium-conveyor.description = 빠른 속도로 자원을 수송할 수 block.phase-conveyor.description = 자원을 순간이동 시켜 주는 컨베이어 입니다. block.junction.description = 컨베이어를 교차시켜 자원을 수송할 때 사용할 수 있는 블록입니다. block.mass-driver.description = 자원을 받아서 다른 물질 이동기로 전달할 수 있는 블록입니다.\n엄청난 사거리를 가지고 있으며, 주로 컨베이어가 접근할 수 없는 곳에 유용하게 사용됩니다. -block.smelter.description = 합금을 제작할 수 있는 건물. +block.smelter.description = 합금을 제작할 수 있는 건물입니다. block.arc-smelter.description = 합금을 제작할 수 있는 건물이지만, 이 건물은 석탄이 필요 없고 좀더 빠른 속도로 합금을 생산해낼 수 있습니다. -block.silicon-smelter.description = 실리콘을 제작할 수 있는 건물. -block.plastanium-compressor.description = 플라스터늄을 제조할 수 있는 건물. -block.phase-weaver.description = 메타를 제작할 수 있는 건물. -block.alloy-smelter.description = 설금을 제작할 수 있는 건물. -block.pulverizer.description = 돌을 갈아서 모래로 만들 수 있는 건물. -block.pyratite-mixer.description = 피라테를 제조할 수 있는 건물. -block.blast-mixer.description = 화합물을 제조할 수 있는 건물. -block.cryofluidmixer.description = 냉각수를 제작할 수 있는 건물. -block.solidifer.description = 용암을 돌로 만들 수 있는 건물. -block.melter.description = 돌로 용암을 만들 수 있는 건물. -block.incinerator.description = 불필요한 아이템을 소각시켜 줄 수 있는 건물. -block.biomattercompressor.description = 잔디밭에서 바이오메터를 추출할 수 있는 건물. -block.separator.description = 돌을 분해하여 각종 자원으로 재활용 할 수 있게 해 주는 건물. +block.silicon-smelter.description = 실리콘을 제작할 수 있는 건물입니다. +block.plastanium-compressor.description = 플라스터늄을 제조할 수 있는 건물입니다. +block.phase-weaver.description = 메타를 제작할 수 있는 건물입니다. +block.alloy-smelter.description = 설금을 제작할 수 있는 건물입니다. +block.pulverizer.description = 돌을 갈아서 모래로 만들 수 있는 건물입니다. +block.pyratite-mixer.description = 피라테를 제조할 수 있는 건물입니다. +block.blast-mixer.description = 화합물을 제조할 수 있는 건물입니다. +block.cryofluidmixer.description = 냉각수를 제작할 수 있는 건물입니다. +block.solidifer.description = 용암을 돌로 만들 수 있는 건물입니다. +block.melter.description = 돌로 용암을 만들 수 있는 건물입니다. +block.incinerator.description = 불필요한 아이템을 소각시켜 줄 수 있는 건물입니다. +block.biomattercompressor.description = 잔디밭에서 바이오메터를 추출할 수 있는 건물입니다. +block.separator.description = 돌을 분해하여 각종 자원으로 재활용 할 수 있게 해 주는 건물입니다. block.centrifuge.description = 돌을 분해하여 각종 자원으로 재활용 할 수 있게 해 주는 건물이지만, 이 건물은 좀 더 다양한 자원을 얻을 수 있게 해 줍니다. block.power-node.description = 생성된 전기를 다른 건물로 전달하기 위한 전력 노드입니다. block.power-node-large.description = 생성된 전기를 다른 건물로 전달하기 위한 건물이며, 일반 노드보다 더 많은 전력을 이동시킬 수 있습니다. @@ -729,31 +731,31 @@ block.solar-panel-large.description = 태양열을 받아 자기 스스로 전 block.thorium-reactor.description = 토륨을 원료로 하는 토륨 원자로 입니다.\n많은 전력을 생산하지만 엄청난 열을 발생시키기 때문에, 많은 량의 물 또는 냉각수가 있어야 터지지 않고 작동합니다. block.rtg-generator.description = 냉각은 필요 없지만 토륨 원자로보다 적은량의 전력을 생산하는 방사선 동위원소 열전자 발전기. block.unloader.description = 해당 창고 및 코어에서 자원을 빼내는데 사용됩니다. -block.container.description = 자원을 운반하기 위한 수송 블록입니다. -block.vault.description = 아이템을 임시로 저장할 수 있는 대형 창고 +block.container.description = 아이템을 임시로 저장할 수 있는 소형 창고입니다. +block.vault.description = 아이템을 임시로 저장할 수 있는 대형 창고입니다. block.mechanical-drill.description = 구리로 제작할 수 있는 기본 드릴입니다. block.pneumatic-drill.description = 돌, 티타늄을 채광할 수 있는 고급 드릴입니다. block.laser-drill.description = 토륨을 채광할 수 있는 최고급 드릴입니다.\n전력과 물을 공급하여 빠른 속도로 채광할 수 있습니다. block.blast-drill.description = 최상위 드릴입니다. 엄청난 양의 전력과 물을 소모하는 대신, 매우 빠른 속도로 채광합니다. -block.water-extractor.description = 바닥에서 물을 추출하여 건물에 공급할 수 있는 건물. -block.cultivator.description = 잔디에서 바이오메터를 추출할 수 있는 건물. -block.oil-extractor.description = 기름을 추출 해 주는 건물. -block.dart-ship-pad.description = 다트 비행선으로 바꿀 수 있는 패드. -block.trident-ship-pad.description = 삼지창 비행선으로 바꿀 수 있는 패드. -block.javelin-ship-pad.description = 자비린 비행선으로 바꿀 수 있는 패드. -block.glaive-ship-pad.description = 글레브 비행선으로 바꿀 수 있는 패드. +block.water-extractor.description = 바닥에서 물을 추출하여 건물에 공급할 수 있는 건물입니다. +block.cultivator.description = 잔디에서 바이오메터를 추출할 수 있는 건물입니다. +block.oil-extractor.description = 기름(타르)을 추출 해 주는 건물입니다. +block.dart-ship-pad.description = 다트 비행선으로 바꿀 수 있는 패드입니다. +block.trident-ship-pad.description = 삼지창 비행선으로 바꿀 수 있는 패드입니다. +block.javelin-ship-pad.description = 자비린 비행선으로 바꿀 수 있는 패드입니다. +block.glaive-ship-pad.description = 글레브 비행선으로 바꿀 수 있는 패드입니다. block.tau-mech-pad.description = 타우 기체로 바꿀 수 있는 패드 -block.delta-mech-pad.description = 델타 기체로 바꿀 수 있는 패드. +block.delta-mech-pad.description = 델타 기체로 바꿀 수 있는 패드입니다. block.omega-mech-pad.description = 오메가 기체로 바꿀 수 있는 패드 -block.spirit-factory.description = 스피릿 유닛을 생산하는 공장. -block.phantom-factory.description = 유닛 팬텀을 생산하는 공장. -block.wraith-factory.description = 유닛 유령 전투기를 소환하는 공장. -block.ghoul-factory.description = 구울 유닛을 생산하는 공장. -block.dagger-factory.description = 귀여운 디거를 생산하는 공장. -block.titan-factory.description = 타이탄 유닛을 생산할 수 있는 공장. -block.fortress-factory.description = 포트리스를 생산하는 공장. -block.revenant-factory.description = 레비던트 유닛을 생산할 수 있는 공장. -block.repair-point.description = 근처 유닛들을 수리하는 건물. +block.spirit-factory.description = 스피릿 유닛을 생산하는 공장입니다. +block.phantom-factory.description = 유닛 팬텀을 생산하는 공장입니다. +block.wraith-factory.description = 유닛 유령 전투기를 소환하는 공장입니다. +block.ghoul-factory.description = 구울 유닛을 생산하는 공장입니다. +block.dagger-factory.description = 귀여운 디거를 생산하는 공장입니다. +block.titan-factory.description = 타이탄 유닛을 생산할 수 있는 공장입니다. +block.fortress-factory.description = 포트리스를 생산하는 공장입니다. +block.revenant-factory.description = 레비던트 유닛을 생산할 수 있는 공장입니다. +block.repair-point.description = 근처 유닛들을 수리하는 건물입니다. block.command-center.description = 생산된 유닛들을 제어할 수 있는 건물.\n첫번째 버튼은 적 기지로 공격하며, 두번째는 대기 상태, 세번째는 기지 근처를 돌며 정찰합니다. block.conduit.description = 일반 파이프. 액체가 지나갈 수 있도록 해 줍니다. block.pulse-conduit.description = 티타늄으로 만들어 졌으며, 일반 파이프보다 액체 수용량이 높습니다. @@ -768,13 +770,13 @@ block.thermal-pump.description = 용암 위에서 사용할 수 있는 펌프입 block.router.description = 한 방향에서 아이템을 받은 후 최대 3개의 다른 방향으로 동일하게 출력합니다.\n재료를 한곳에서 여러 대상으로 분할하여 운반하는데 유용합니다. block.distributor.description = 아이템을 최대 7개의 다른 방향으로 똑같이 분할하는 고급 분배기. block.bridge-conveyor.description = 고급 자원 수송 블록.\n지형이나 건물을 넘어 최대 3개 타일을 건너뛰고 자원을 운송할 수 있습니다. -block.alpha-mech-pad.description = 알파 기체로 바꿀 수 있는 패드. -block.itemsource.description = 자원을 선택하면 그 자원이 무한하게 튀어나오는 블록입니다. +block.alpha-mech-pad.description = 알파 기체로 바꿀 수 있는 패드입니다. +block.itemsource.description = 자원을 선택하면 그 자원이 무한하게 생성되는 블록입니다. block.liquidsource.description = 무한한 액체를 출력해냅니다. block.itemvoid.description = 아이템을 시공으로 빠트려 사라지게 만듭니다. -block.powerinfinite.description = 무한한 전력을 출력해냅니다. -block.powervoid.description = 무한한 아이템을 출력해냅니다. -liquid.water.description = 유닛이 이 위를 지나가면 이동속도가 느려지고, 깊은 물에 빠지면 죽습니다. -liquid.lava.description = 유닛이 이 위를 지나가면 이동속도가 매우 느려지고, 지속적으로 데미지를 입습니다. +block.powerinfinite.description = 무한한 전력을 공급해주는 블록입니다. +block.powervoid.description = 설정된 아이템을 계속해서 출력하는 블록입니다. +liquid.water.description = 지상 유닛이 이 위를 지나가면 이동속도가 느려지고, 깊은 물에 빠지면 죽습니다. +liquid.lava.description = 지상 유닛이 이 위를 지나가면 이동속도가 매우 느려지고, 지속적으로 데미지를 입습니다. liquid.oil.description = 일부 조합 블록에서 사용되는 자원입니다. liquid.cryofluid.description = 포탑 및 토륨 원자로에서 사용되는 자원입니다. 누출시 폭발 및 방화의 위험성이 있습니다. From 235a1f36ecae1be5e7fda9da60aaeeeac088d55c Mon Sep 17 00:00:00 2001 From: Timmeey86 Date: Thu, 8 Nov 2018 20:46:12 +0100 Subject: [PATCH 15/34] Prepared/Fixed translation files for crash reported in #translations (#318) --- core/assets/bundles/bundle_de.properties | 2 +- core/assets/bundles/bundle_es.properties | 2 +- core/assets/bundles/bundle_in_ID.properties | 2 +- core/assets/bundles/bundle_ita.properties | 2 +- core/assets/bundles/bundle_pl.properties | 2 +- core/assets/bundles/bundle_pt_BR.properties | 2 +- core/assets/bundles/bundle_ru.properties | 2 +- core/assets/bundles/bundle_tk.properties | 2 +- core/assets/bundles/bundle_tr.properties | 2 +- core/assets/bundles/bundle_uk_UA.properties | 2 +- core/assets/bundles/bundle_zh_CN.properties | 2 +- core/assets/bundles/bundle_zh_TW.properties | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/assets/bundles/bundle_de.properties b/core/assets/bundles/bundle_de.properties index 22eb16c8ed..5e5df2b1e3 100644 --- a/core/assets/bundles/bundle_de.properties +++ b/core/assets/bundles/bundle_de.properties @@ -50,7 +50,7 @@ text.mission.main = Hauptmission:[LIGHT_GRAY] {0} text.mission.info = Missionsbeschreibung text.mission.complete = Mission erfolgreich! text.mission.complete.body = Sektor {0},{1} wurde erobert. -text.mission.wave = Überlebe [accent]{0}[] Wellen. +text.mission.wave = Überlebe [accent]{0}/{1}[] Wellen\nWelle in {2} text.mission.wave.enemies = Überlebe[accent] {0}/{1} []Wellen\n{2} Gegner text.mission.wave.enemy = Überlebe[accent] {0}/{1} []Wellen\n{2} Gegner text.mission.wave.menu = Überlebe[accent] {0} []Wellen diff --git a/core/assets/bundles/bundle_es.properties b/core/assets/bundles/bundle_es.properties index 8aa84da7d2..ce0ba6cc51 100644 --- a/core/assets/bundles/bundle_es.properties +++ b/core/assets/bundles/bundle_es.properties @@ -50,7 +50,7 @@ text.mission.main = Misión Principal:[LIGHT_GRAY] {0} text.mission.info = Información de la Misión text.mission.complete = ¡Misión completada! text.mission.complete.body = El Sector {0},{1} ha sido conquistado. -text.mission.wave = Sobrevive [accent]{0}[] hordas. +text.mission.wave = Sobrevive [accent]{0}/{1}[] hordas\nHordas en {2} text.mission.wave.enemies = Sobrevive[accent] {0}/{1} []hordas\n{2} Enemigas text.mission.wave.enemy = Sobrevive[accent] {0}/{1} []hordas\n{2} Enemigas text.mission.wave.menu = Sobrevive[accent] {0} []hordas diff --git a/core/assets/bundles/bundle_in_ID.properties b/core/assets/bundles/bundle_in_ID.properties index 7abcfa5a02..838876490c 100644 --- a/core/assets/bundles/bundle_in_ID.properties +++ b/core/assets/bundles/bundle_in_ID.properties @@ -50,7 +50,7 @@ text.mission.main = Main Mission:[LIGHT_GRAY] {0} text.mission.info = Mission Info text.mission.complete = Mission complete! text.mission.complete.body = Sector {0},{1} has been conquered. -text.mission.wave = Survive [accent]{0}[] waves. +text.mission.wave = Survive[accent] {0}/{1} []waves\nWave in {2} text.mission.wave.enemies = Survive[accent] {0}/{1} []waves\n{2} Enemies text.mission.wave.enemy = Survive[accent] {0}/{1} []waves\n{2} Enemy text.mission.wave.menu = Survive[accent] {0} []waves diff --git a/core/assets/bundles/bundle_ita.properties b/core/assets/bundles/bundle_ita.properties index a61ccb7072..bfcd087d53 100644 --- a/core/assets/bundles/bundle_ita.properties +++ b/core/assets/bundles/bundle_ita.properties @@ -50,7 +50,7 @@ text.mission.main = Main Mission:[LIGHT_GRAY] {0} text.mission.info = Mission Info text.mission.complete = Missione completata! text.mission.complete.body = Il settore {0},{1} è stato conquistato. -text.mission.wave = Sopravvivi a [accent]{0}[] onda/e. +text.mission.wave = Sopravvivi a [accent]{0}/{1][] onda/e.Onda in {2} text.mission.wave.enemies = Survive[accent] {0}/{1} []waves\n{2} Enemies text.mission.wave.enemy = Survive[accent] {0}/{1} []waves\n{2} Enemy text.mission.wave.menu = Survive[accent] {0} []waves diff --git a/core/assets/bundles/bundle_pl.properties b/core/assets/bundles/bundle_pl.properties index 5c3d76a869..850ad3327e 100644 --- a/core/assets/bundles/bundle_pl.properties +++ b/core/assets/bundles/bundle_pl.properties @@ -50,7 +50,7 @@ text.mission.main = Main Mission:[LIGHT_GRAY] {0} text.mission.info = Mission Info text.mission.complete = Mission complete! text.mission.complete.body = Sector {0},{1} has been conquered. -text.mission.wave = Survive [accent]{0}[] waves. +text.mission.wave = Survive[accent] {0}/{1} []waves\nWave in {2} text.mission.wave.enemies = Survive[accent] {0}/{1} []waves\n{2} Enemies text.mission.wave.enemy = Survive[accent] {0}/{1} []waves\n{2} Enemy text.mission.wave.menu = Survive[accent] {0} []waves diff --git a/core/assets/bundles/bundle_pt_BR.properties b/core/assets/bundles/bundle_pt_BR.properties index 61e267fdab..e36c930dce 100644 --- a/core/assets/bundles/bundle_pt_BR.properties +++ b/core/assets/bundles/bundle_pt_BR.properties @@ -50,7 +50,7 @@ text.mission.main = Main Mission:[LIGHT_GRAY] {0} text.mission.info = Mission Info text.mission.complete = Mission complete! text.mission.complete.body = Sector {0},{1} has been conquered. -text.mission.wave = Sobrevive [accent]{0}[] Onda. +text.mission.wave = Sobrevive [accent]{0}/{1}[] Onda\nOnda em {2} text.mission.wave.enemies = Survive[accent] {0}/{1} []waves\n{2} Enemies text.mission.wave.enemy = Survive[accent] {0}/{1} []waves\n{2} Enemy text.mission.wave.menu = Survive[accent] {0} []waves diff --git a/core/assets/bundles/bundle_ru.properties b/core/assets/bundles/bundle_ru.properties index d73654bbb6..9c4d361ef3 100644 --- a/core/assets/bundles/bundle_ru.properties +++ b/core/assets/bundles/bundle_ru.properties @@ -50,7 +50,7 @@ text.mission.main = Главная мисия:[LIGHT_GRAY] {0} text.mission.info = Информация о миссии text.mission.complete = Миссия выполнена! text.mission.complete.body = Сектор {0},{1} был завоёван. -text.mission.wave = Пережить следующее количество волн: [accent]{0}[]. +text.mission.wave = Пережить следующее количество волн: [accent]{0}/{1}[]\nВолна в {2} text.mission.wave.enemies = Осталось волн:[accent] {0}/{1}[]\n{2} враг. text.mission.wave.enemy = Осталось волн:[accent] {0}/{1}[]\n{2} враг text.mission.wave.menu = Пережить[accent] {0} []волн diff --git a/core/assets/bundles/bundle_tk.properties b/core/assets/bundles/bundle_tk.properties index 1301e74969..ece71c0b5d 100644 --- a/core/assets/bundles/bundle_tk.properties +++ b/core/assets/bundles/bundle_tk.properties @@ -50,7 +50,7 @@ text.mission.main = Main Mission:[LIGHT_GRAY] {0} text.mission.info = Mission Info text.mission.complete = Gorev tamamlandi! text.mission.complete.body = Sektor {0},{1} ele gecirildi -text.mission.wave = [accent]{0}[] Dalga hayatta kal +text.mission.wave = [accent]{0}/{1}[] Dalga hayatta kal\n{2} Dalga text.mission.wave.enemies = Survive[accent] {0}/{1} []waves\n{2} Enemies text.mission.wave.enemy = Survive[accent] {0}/{1} []waves\n{2} Enemy text.mission.wave.menu = Survive[accent] {0} []waves diff --git a/core/assets/bundles/bundle_tr.properties b/core/assets/bundles/bundle_tr.properties index 560453c021..68df10afd4 100644 --- a/core/assets/bundles/bundle_tr.properties +++ b/core/assets/bundles/bundle_tr.properties @@ -50,7 +50,7 @@ text.mission.main = Main Mission:[LIGHT_GRAY] {0} text.mission.info = Mission Info text.mission.complete = Mission complete! text.mission.complete.body = Sector {0},{1} has been conquered. -text.mission.wave = Survive [accent]{0}[] waves. +text.mission.wave = Survive[accent] {0}/{1} []waves\nWave in {2} text.mission.wave.enemies = Survive[accent] {0}/{1} []waves\n{2} Enemies text.mission.wave.enemy = Survive[accent] {0}/{1} []waves\n{2} Enemy text.mission.wave.menu = Survive[accent] {0} []waves diff --git a/core/assets/bundles/bundle_uk_UA.properties b/core/assets/bundles/bundle_uk_UA.properties index a01322f8e6..95630c8669 100644 --- a/core/assets/bundles/bundle_uk_UA.properties +++ b/core/assets/bundles/bundle_uk_UA.properties @@ -50,7 +50,7 @@ text.mission.main = Головна місія:[LIGHT_GRAY] {0} text.mission.info = Інформація про місії text.mission.complete = Місія завершена! text.mission.complete.body = Сектор {0},{1} був завойований. -text.mission.wave = Пережити наступну кількість хвиль:[accent]{0}[] . +text.mission.wave = Пережити наступну кількість хвиль:[accent]{0}/{1}[]\nХвиля в {2} text.mission.wave.enemies = Пережити [accent] {0}/{1} []хвиль\n{2} Ворог. text.mission.wave.enemy = Пережити[accent] {0}/{1} []хвиль\n{2} Ворог text.mission.wave.menu = Пережити[accent] {0} []хвиль diff --git a/core/assets/bundles/bundle_zh_CN.properties b/core/assets/bundles/bundle_zh_CN.properties index 6e0006c6d5..2e6526dd68 100644 --- a/core/assets/bundles/bundle_zh_CN.properties +++ b/core/assets/bundles/bundle_zh_CN.properties @@ -50,7 +50,7 @@ text.mission.main = Main Mission:[LIGHT_GRAY] {0} text.mission.info = Mission Info text.mission.complete = 任务完成! text.mission.complete.body = 区域 {0},攻占了 {1} 个 -text.mission.wave = 存活了 [accent]{0}[] 波。 +text.mission.wave = 存活了 [accent]{0}/{1}[] 波。\nWave in {2} text.mission.wave.enemies = Survive[accent] {0}/{1} []waves\n{2} Enemies text.mission.wave.enemy = Survive[accent] {0}/{1} []waves\n{2} Enemy text.mission.wave.menu = Survive[accent] {0} []waves diff --git a/core/assets/bundles/bundle_zh_TW.properties b/core/assets/bundles/bundle_zh_TW.properties index 220b24c6b6..3d18289129 100644 --- a/core/assets/bundles/bundle_zh_TW.properties +++ b/core/assets/bundles/bundle_zh_TW.properties @@ -50,7 +50,7 @@ text.mission.main = Main Mission:[LIGHT_GRAY] {0} text.mission.info = Mission Info text.mission.complete = Mission complete! text.mission.complete.body = Sector {0},{1} has been conquered. -text.mission.wave = Survive [accent]{0}[] waves. +text.mission.wave = Survive[accent] {0}/{1} []waves\nWave in {2} text.mission.wave.enemies = Survive[accent] {0}/{1} []waves\n{2} Enemies text.mission.wave.enemy = Survive[accent] {0}/{1} []waves\n{2} Enemy text.mission.wave.menu = Survive[accent] {0} []waves From 58c6df35378eb2c576ae8855165e4826c3dc8c63 Mon Sep 17 00:00:00 2001 From: elmenda452 <44818832+elmenda452@users.noreply.github.com> Date: Thu, 8 Nov 2018 20:46:39 +0100 Subject: [PATCH 16/34] Update bundle_es.properties (#317) Translated the description of nearly everything which wasn't translated and made some changes. I don't really mind if someday these get reset. --- core/assets/bundles/bundle_es.properties | 381 ++++++++++++----------- 1 file changed, 191 insertions(+), 190 deletions(-) diff --git a/core/assets/bundles/bundle_es.properties b/core/assets/bundles/bundle_es.properties index ce0ba6cc51..6832c8e1d0 100644 --- a/core/assets/bundles/bundle_es.properties +++ b/core/assets/bundles/bundle_es.properties @@ -7,13 +7,13 @@ text.link.dev-builds.description = Versiones de desarrollo inestable text.link.trello.description = Tablero de Trello oficial para las características planificadas text.link.itch.io.description = itch.io es la página donde podes descargar las versiones para PC y web text.link.google-play.description = Ficha en la Google Play Store -text.link.wiki.description = wiki oficial de Mindustry +text.link.wiki.description = Wiki oficial de Mindustry text.linkfail = ¡Error al abrir el enlace!\nLa URL ha sido copiada a su portapapeles. -text.editor.web = ¡La versión web no es compatible con el editor!\nDescargue el juego para usarlo. +text.editor.web = ¡La versión web no es compatible con el editor!\nDescarga el juego para usarlo. text.web.unsupported = ¡La versión web no soporta esta característica! Descarga el juego para poder usarla. text.gameover = Tu núcleo ha sido destruido. -text.gameover.pvp = El equipo[accent] {0}[] ha ganado! -text.sector.gameover = Este sector ha sido perdido. ¿Re-instaurar? +text.gameover.pvp = ¡El equipo[accent] {0}[] ha ganado! +text.sector.gameover = Este sector ha sido perdido. ¿Re-desplegar? text.sector.retry = Reintentar text.highscore = [accent]¡Nueva mejor puntuación! text.wave.lasted = Duraste hasta la ronda [accent]{0}[]. @@ -22,29 +22,29 @@ text.level.delete.title = Confirmar Eliminación text.map.delete = ¿Estás seguro que quieres borrar el mapa "[accent]{0}[]"? text.level.select = Selección de nivel text.level.mode = Modo de juego: -text.construction.desktop = Los controles de la versión de escritorio han cambiado.\nPara deseleccionar un bloque o dejar de construir, [accent]usa la barra espaciadora[]. +text.construction.desktop = Los controles de la versión de escritorio han cambiado.\nPara deseleccionar un bloque o dejar de construir, [accent]usa la space tab[]. text.construction.title = Guía de Construcción de Bloques text.construction = Acaba de seleccionar el [accent]modo de construcción de bloques[].\n\nPara empezar a colocar, simplemente presione en una localización valida cerca de su nave.\nCuando haya terminado de seleccionar algunos bloques, presiona la casilla para confirmar, y su nave empezara a construirlos.\n\n- [accent]Remueve bloques[] de tu selección presionando en ellos.\n- [accent]Cambia tu selección de lugar[] manteniendo y arrastrando cualquier bloque en la selección.\n- [accent]Coloca bloques en línea[] presionando y manteniendo en un espacio vacío, y arrastrando hacia cualquier dirección.\n- [accent]Cancela la construcción o selección[] presionando la X abajo a la izquierda. text.deconstruction.title = Guía de Deconstrucción de Bloques -text.deconstruction = Acaba de seleccionar el [accent]modo de deconstrucción de bloques[].\n\nPara empezar a destruir, simplemente presione en un bloque cercano a su nave.\nCuando haya terminado de seleccionar algunos bloques, presiona la casilla para confirmar, y su nave empezara a de-construirlos.\n\n- [accent]Remueve bloques[] de tu selección presionando en ellos.\n- [accent]Remueve bloques en un area[] presionando y manteniendo en un espacio vacío, y arrastrando hacia cualquier dirección.\n- [accent]Cancela la deconstrucción o selección[] presionando la X abajo a la izquierda. -text.showagain = No mostrar devuelta en la próxima sesión +text.deconstruction = Acaba de seleccionar el [accent]modo de deconstrucción de blocks[].\n\nPara empezar a destruir, simplemente presione en un bloque cercano a su nave.\nCuando haya terminado de seleccionar algunos bloques, presiona la casilla para confirmar, y su nave empezara a de-construirlos.\n\n- [accent]Remueve bloques[] de tu selección presionando en ellos.\n- [accent]Remueve bloques en un area[] presionando y manteniendo en un espacio vacío, y arrastrando hacia cualquier dirección.\n- [accent]Cancela la deconstrucción o selección[] presionando la X abajo a la izquierda. +text.showagain = No mostrar otra vez en la próxima sesión text.coreattack = < ¡El núcleo está bajo ataque! > text.unlocks = Desbloqueos text.savegame = Guardar Partida text.loadgame = Cargar Partida text.joingame = Unirse a la Partida -text.addplayers = Agregar/Remover Jugadores +text.addplayers = Agregar/Quitar Jugadores text.customgame = Partida personalizada text.sectors = Sectores text.sector = Sector: [LIGHT_GRAY]{0} text.sector.time = Tiempo: [LIGHT_GRAY]{0} text.sector.deploy = Desplegar text.sector.abandon = Abandonar -text.sector.abandon.confirm = ¿Definitivamente quieres abandonar todo el progreso hecho en este sector?\n¡Esto no se puede deshacer! -text.sector.resume = Resumir +text.sector.abandon.confirm = ¿Realmente quieres abandonar todo el progreso hecho en este sector?\n¡Esto no se puede deshacer! +text.sector.resume = Continuar text.sector.locked = [scarlet][[Incompleto] -text.sector.unexplored = [accent][[Inexplorado] -text.missions = Missions:[LIGHT_GRAY] {0} +text.sector.unexplored = [accent][[No explorado] +text.missions = Misiones:[LIGHT_GRAY] {0} text.mission = Misión:[LIGHT_GRAY] {0} text.mission.main = Misión Principal:[LIGHT_GRAY] {0} text.mission.info = Información de la Misión @@ -58,11 +58,11 @@ text.mission.battle = Destruye la base enemiga. text.mission.resource.menu = Obtener {0} x{1} text.mission.resource = Obtén {0} x{1} text.mission.block = Crear {0} -text.mission.unit = Crear {0} Unit -text.mission.command = Enviar Comando {0} A Las Unidades +text.mission.unit = Crear {0} +text.mission.command = Envía Comando {0} a las unidades text.mission.linknode = Conecta nodo de energía text.mission.display = [accent]Misión:\n[LIGHT_GRAY]{0} -text.mission.mech = Cambiar a mech[accent] {0}[] +text.mission.mech = Cambiar a mecanoide[accent] {0}[] text.mission.create = Crear[accent] {0}[] text.none = text.close = Cerrar @@ -82,24 +82,24 @@ text.server.closing = [accent]Cerrando servidor... text.server.kicked.kick = ¡Has sido expulsado del servidor! text.server.kicked.serverClose = El servidor ha cerrado. text.server.kicked.sectorComplete = Sector completado. -text.server.kicked.sectorComplete.text = Tu misión ha sido completada.\nEl servidor ahora continuara con el próximo sector. +text.server.kicked.sectorComplete.text = Tu misión ha sido completada.\nEl servidor ahora continuará con el próximo sector. text.server.kicked.clientOutdated = ¡Cliente desactualizado! ¡Actualiza tu juego! text.server.kicked.serverOutdated = ¡Servidor desactualizado! ¡Pídele al anfitrión que lo actualice! text.server.kicked.banned = Has sido baneado del servidor. text.server.kicked.recentKick = Has sido expulsado recientemente.\nEspera para poder conectarte de nuevo. -text.server.kicked.nameInUse = Ya hay alguien con ese nombre\nen el servidor. +text.server.kicked.nameInUse = Ya hay alguien con ese\nnombre en el servidor. text.server.kicked.nameEmpty = Tu nombre debe por lo menos contener un carácter o número. text.server.kicked.idInUse = ¡Ya estás en el servidor! Conectarse con dos cuentas no está permitido. text.server.kicked.customClient = Este servidor no soporta versiones personalizadas. Descarga una versión oficial. -text.host.info = El botón [accent]hostear[] hostea un servidor en el puerto [scarlet]6567[]. \nCualquier persona en la misma [LIGHT_GRAY]wifi o red local[] debería poder ver tu servidor en la lista de servidores.\n\nSi quieres que cualquier persona se pueda conectar de cualquier lugar por IP, la [accent]asignación de puertos[] es requerida.\n\n[LIGHT_GRAY]Nota: Si alguien experimenta problemas conectándose a tu partida LAN, asegúrate de permitir a Mindustry acceso a tu red local mediante la configuración de tu firewall. -text.join.info = Aquí, puedes escribir la [accent]IP de un servidor[] para conectarte, o descubrir servidores de [accent]red local[] para conectarte.\nLAN y WAN es soportado para jugar en multijugador.\n\n[LIGHT_GRAY]Nota: No hay una lista automática global de servidores; si quieres conectarte por IP, tendrás que preguntarle al anfitrión por la IP. +text.host.info = El botón [accent]host[] hostea un servidor en el puerto [scarlet]6567[]. \nCualquier persona en la misma [LIGHT_GRAY]wifi o red local[] debería poder ver tu servidor en la lista de servidores.\n\nSi quieres que cualquier persona se pueda conectar de cualquier lugar por IP, la [accent]asignación de puertos[] es requerida.\n\n[LIGHT_GRAY]Nota: Si alguien experimenta problemas conectándose a tu partida LAN, asegúrate de permitir a Mindustry acceso a tu red local mediante la configuración de tu firewall. +text.join.info = Aquí, puedes escribir la [accent]IP de un server[] para conectarte, o descubrir servidores de [accent]red local[] para conectarte.\nLAN y WAN es soportado para jugar en multijugador.\n\n[LIGHT_GRAY]Nota: No hay una lista automática global de servidores; si quieres conectarte por IP, tendrás que preguntarle al anfitrión por la IP. text.hostserver = Hostear Servidor text.hostserver.mobile = Hostear\nJuego text.host = Hostear text.hosting = [accent]Abriendo servidor... text.hosts.refresh = Actualizar text.hosts.discovering = Descubrir partidas LAN -text.server.refreshing = Actualizando servidor +text.server.refreshing = Actualizando servidor... text.hosts.none = [lightgray]¡No se han encontrado partidas LAN! text.host.invalid = [scarlet]No se ha podido conectar al anfitrión text.trace = Rastrear Jugador @@ -108,29 +108,29 @@ text.trace.ip = IP: [accent]{0} text.trace.id = ID Única: [accent]{0} text.trace.android = Cliente de Android: [accent]{0} text.trace.modclient = Cliente Personalizado: [accent]{0} -text.trace.totalblocksbroken = Total de bloques removidos: [accent]{0} -text.trace.structureblocksbroken = Bloques de estructura removidos: [accent]{0} -text.trace.lastblockbroken = Último bloque removido: [accent]{0} +text.trace.totalblocksbroken = Total de bloques quitados: [accent]{0} +text.trace.structureblocksbroken = Bloques de estructura quitados: [accent]{0} +text.trace.lastblockbroken = Último bloque quitado: [accent]{0} text.trace.totalblocksplaced = Total de bloques colocados: [accent]{0} text.trace.lastblockplaced = Último bloque colocado: [accent]{0} -text.invalidid = ¡ID de cliente invalida! Envía un informe del error. -text.server.bans = Bans +text.invalidid = ¡ID de cliente inválida! Envía un informe del error. +text.server.bans = Baneos text.server.bans.none = ¡Ningún usuario ha sido baneado! -text.server.admins = Admins -text.server.admins.none = ¡Ningún admin ha sido encontrado! +text.server.admins = Administradores +text.server.admins.none = ¡Ningún administrador ha sido encontrado! text.server.add = Agregar Servidor -text.server.delete = ¿Estás seguro que quieres borrar este servidor? +text.server.delete = ¿Estás seguro de querer borrar este servidor? text.server.hostname = Anfitrión: {0} text.server.edit = Editar Servidor text.server.outdated = [crimson]¡Servidor desactualizado![] text.server.outdated.client = [crimson]¡Cliente desactualizado![] text.server.version = [lightgray]Versión: {0} text.server.custombuild = [yellow]Versión personalizada -text.confirmban = ¿Estás seguro que quieres banear este jugador? -text.confirmkick = ¿Estás seguro que quieres expulsar este jugador? -text.confirmunban = ¿Estás seguro que quieres desbanear este jugador? -text.confirmadmin = ¿Estás seguro que quieres hacer admin a este jugador? -text.confirmunadmin = ¿Estás seguro que quieres quitar los permisos de admin a este jugador? +text.confirmban = ¿Estás seguro de querer banear este jugador? +text.confirmkick = ¿Estás seguro de querer expulsar este jugador? +text.confirmunban = ¿Estás seguro de querer desbanear este jugador? +text.confirmadmin = ¿Estás seguro de querer hacer administrador a este jugador? +text.confirmunadmin = ¿Estás seguro de querer quitar los permisos de administrador a este jugador? text.joingame.title = Unirse a la partida text.joingame.ip = IP: text.disconnect = Desconectado. @@ -138,29 +138,29 @@ text.disconnect.data = ¡Se ha fallado la carga de datos del mundo! text.connecting = [accent]Conectando... text.connecting.data = [accent]Cargando datos del mundo... text.server.port = Puerto: -text.server.addressinuse = ¡La dirección está en uso! +text.server.addressinuse = ¡La dirección ya está en uso! text.server.invalidport = ¡El número de puerto es invalido! -text.server.error = [crimson]Error hosteando el servidor: [accent]{0} -text.save.old = Este punto de guardado es para una versión más antigua de este juego, y ya no puede ser usada.\n\n[LIGHT_GRAY]Guardados con retrocompatibilidad serán completamente implementados en la versión 4.0. +text.server.error = [crimson]Error hosteando el servidor: error [accent]{0} +text.save.old = Este punto de guardado es de una versión más antigua de este juego, y ya no puede ser usada.\n\n[LIGHT_GRAY]La retrocmpatibilidad de los puntos de guardado estará completamente implementada en la versión 4.0. text.save.new = Nuevo Punto de Guardado -text.save.overwrite = ¿Estás seguro que quieres sobrescribir\neste punto de guardado? +text.save.overwrite = ¿Estás seguro de querer sobrescribir\neste punto de guardado? text.overwrite = Sobrescribir text.save.none = ¡No se ha encontrado ningún punto de guardado! text.saveload = [accent]Guardando... text.savefail = ¡No se ha podido guardar la partida! -text.save.delete.confirm = ¿Estás seguro que quieres borrar este punto de guardado? +text.save.delete.confirm = ¿Estás seguro de querer borrar este punto de guardado? text.save.delete = Borrar text.save.export = Exportar Punto de Guardado -text.save.import.invalid = [accent]¡Este punto de guardado es invalido! -text.save.import.fail = [crimson]Se ha fallado la importación del punto de guardado: [accent]{0} -text.save.export.fail = [crimson]Se ha fallado la exportación del punto de guardado: [accent]{0} +text.save.import.invalid = [accent]¡Este punto de guardado es inválido! +text.save.import.fail = [crimson]La importación del punto de guardado ha fallado: error [accent]{0} +text.save.export.fail = [crimson]La exportación del punto de guardado ha fallado: error [accent]{0} text.save.import = Importar Punto de Guardado text.save.newslot = Nombre del Punto de Guardado: text.save.rename = Renombrar text.save.rename.text = Nuevo nombre: text.selectslot = Selecciona un Punto de Guardado. text.slot = [accent]Casilla {0} -text.save.corrupted = [accent]¡El punto de guardado está corrupto o es invalido!\nSi acabas de actualizar el juego, esto debe ser probablemente un cambio en el formato de guardado y [scarlet]no[] un error. +text.save.corrupted = [accent]¡El punto de guardado está corrupto o es inválido!\nSi acabas de actualizar el juego, esto debe ser probablemente un cambio en el formato de guardado y[scarlet] no[] un error. text.sector.corrupted = [accent]El punto de guardado de este sector fue encontrado, pero su carga ha fallado.\nUn nuevo punto ha sido creado. text.empty = text.on = Encendido @@ -169,7 +169,7 @@ text.save.autosave = Autoguardado: {0} text.save.map = Mapa: {0} text.save.wave = Horda {0} text.save.difficulty = Dificultad: {0} -text.save.date = Ultima vez guardado: {0} +text.save.date = Última vez guardado: {0} text.save.playtime = Tiempo de juego: {0} text.confirm = Confirmar text.delete = Borrar @@ -182,9 +182,9 @@ text.back = Atras text.quit.confirm = ¿Estás seguro de querer salir de la partida? text.changelog.title = Registro de Parches text.changelog.loading = Consiguiendo el registro de parches... -text.changelog.error.android = [accent]¡Nota que el registro de parches a veces no funciona en Android 4.4 o inferior!\nEsto es por un error de Android interno. -text.changelog.error.ios = [accent]El registro de parches no es actualmente soportado por iOS. -text.changelog.error = [scarlet]¡Error consiguiendo el registro de parches!\nChequeá tu conexión a Internet. +text.changelog.error.android = [accent]¡Nota: el registro de parches a veces no funciona en Android 4.4 o inferior!\nEsto es por un error interno de Android. +text.changelog.error.ios = [accent]El registro de parches no está actualmente soportado para iOS. +text.changelog.error = [scarlet]¡Error consiguiendo el registro de parches!\Comprueba tu conexión a Internet. text.changelog.current = [yellow][[Versión actual] text.changelog.latest = [accent][[Última version] text.loading = [accent]Cargando... @@ -192,7 +192,7 @@ text.saving = [accent]Guardando... text.wave = [accent]Horda {0} text.wave.waiting = Horda en {0} text.waiting = Esperando... -text.waiting.players = Esperando por jugafores... +text.waiting.players = Esperando jugadores... text.wave.enemies = [LIGHT_GRAY]{0} Enemigos Restantes text.wave.enemy = [LIGHT_GRAY]{0} Enemigo Restante text.loadimage = Cargar Imagen @@ -200,11 +200,11 @@ text.saveimage = Guardar Imagen text.unknown = Desconocido text.custom = Personalizado text.builtin = Incorporado -text.map.delete.confirm = ¿Estás seguro que quieres borrar este mapa? ¡Recuerda que está acción no puede ser descartada! +text.map.delete.confirm = ¿Estás seguro de querer borrar este mapa? ¡Recuerda que está acción no puede sdeshacerse! text.map.random = [accent]Mapa Aleatorio -text.map.nospawn = ¡Este mapa no tiene ningún núcleo en el cual pueda meter al jugador! Agrega un núcleo [ROYAL]azul[] al mapa con el editor. -text.map.nospawn.pvp = ¡Este mapa no tiene ningún núcleo enemigo para que aparezca el jugador! Añade [SCARLET] red[] núcleos a este mapa en el editor. -text.map.invalid = Error cargando el mapa: corrupto o archivo invalido. +text.map.nospawn = ¡Este mapa no tiene ningún núcleo en el cual pueda aparecer el jugador! Agrega un núcleo[ROYAL] blue[] al mapa con el editor. +text.map.nospawn.pvp = ¡Este mapa no tiene ningún núcleo enemigo para que aparezca el jugador! Añade un núcleo[SCARLET] red[] a este mapa en el editor. +text.map.invalid = Error cargando el mapa: archivo corrupto o inválido. text.editor.brush = Pincel text.editor.slope = \\ text.editor.openin = Abrir en el Editor @@ -216,15 +216,15 @@ text.editor.description = Descripción: text.editor.name = Nombre: text.editor.teams = Equipos text.editor.elevation = Elevación -text.editor.errorimageload = Error cargando el archivo:\n[accent]{0} -text.editor.errorimagesave = Error guardando el archivo:\n[accent]{0} +text.editor.errorimageload = Error cargando el archivo:\n[accent] {0} +text.editor.errorimagesave = Error guardando el archivo:\n[accent] {0} text.editor.generate = Generar text.editor.resize = Cambiar Tamaño text.editor.loadmap = Cargar Mapa text.editor.savemap = Guardar Mapa text.editor.saved = ¡Guardado! text.editor.save.noname = ¡Tu mapa no tiene un nombre! Pon uno en el menú 'Info del Mapa'. -text.editor.save.overwrite = ¡Tu mapa sobrescribe uno ya incorporado! Elige un nombre diferente en el menu 'Info del Mapa'. +text.editor.save.overwrite = ¡Tu mapa sobrescribe uno ya incorporado! Elige un nombre diferente en el menú 'Info del Mapa'. text.editor.import.exists = [scarlet]¡No se ha podido importar:[] un mapa incorporado con el nombre '{0}' ya existe! text.editor.import = Importar... text.editor.importmap = Importar Mapa @@ -240,14 +240,14 @@ text.editor.exportimage = Exportar Imagen del Terreno text.editor.exportimage.description = Exportar archivo de imagen del mapa text.editor.loadimage = Importar Terreno text.editor.saveimage = Exportar Terreno -text.editor.unsaved = [scarlet]¡Tienes cambios sin guardar![]\n¿Estás seguro que quieres salir? +text.editor.unsaved = [scarlet]¡Tienes cambios sin guardar![]\n¿Estás seguro de querer salir? text.editor.resizemap = Cambiar Tamaño del Mapa text.editor.mapname = Nombre del Mapa: text.editor.overwrite = [accent]¡Advertencia!\nEsto sobrescribe un mapa ya existente. -text.editor.overwrite.confirm = [scarlet]¡Advertencia![] Un mapa con ese nombre ya existe. ¿Estás seguro que quieres sobrescribirlo? +text.editor.overwrite.confirm = [scarlet]¡Advertencia![] Un mapa con ese nombre ya existe. ¿Estás seguro de querer sobrescribirlo? text.editor.selectmap = Selecciona un mapa para cargar: text.width = Ancho: -text.height = Altura: +text.height = Alto: text.menu = Menu text.play = Jugar text.load = Cargar @@ -264,7 +264,7 @@ text.donate = Donar text.connectfail = [crimson]Ha fallado la conexión con el servidor: [accent]{0} text.error.unreachable = Servidor inaccesible. text.error.invalidaddress = Dirección inválida. -text.error.timedout = Timed out!\nMake sure the host has port forwarding set up, and that the address is correct! +text.error.timedout = ¡Se acabó el tiempo!\n¡Asegúrate que el host ha hecho el port forwarding, y que la dirección es correcta! text.error.mismatch = Error de paquete:\nposible versión no válida del servidor/cliente.\nAsegúrate de que tú y el host tenéis la última versión de Mindustry. text.error.alreadyconnected = Ya estás conectado. text.error.mapnotfound = ¡Archivo de mapa no encontrado! @@ -277,17 +277,17 @@ text.settings.game = Juego text.settings.sound = Sonido text.settings.graphics = Gráficos text.settings.cleardata = Limpiar Datos del Juego... -text.settings.clear.confirm = ¿Estas seguro de querer limpiar estos datos?\nEsta accion no puede deshacerse! -text.settings.clearall.confirm = [scarlet]ADVERTENCIA![]\nEsto va a eliminar todos tus datos, incluyendo saves, mapas, desbloqueos y keybinds.\nUna vez presiones 'ok' el juego va a borrrar todos tus datos y a salir del juego automáticamente. +text.settings.clear.confirm = ¿Estas seguro de querer limpiar estos datos?\n¡Esta acción no puede deshacerse! +text.settings.clearall.confirm = [scarlet]ADVERTENCIA![]\nEsto va a eliminar todos tus datos, incluyendo guardados, mapas, desbloqueos y keybinds.\nUna vez presiones 'ok', el juego va a borrrar todos tus datos y saldrá del juego automáticamente. text.settings.clearsectors = Limpiar Sectores text.settings.clearunlocks = Limpiar Desbloqueos text.settings.clearall = Limpiar Todo text.paused = Pausado -text.yes = Si +text.yes = Sí text.no = No text.info.title = [accent]Información -text.error.title = [crimson]Un error ha ocurrido -text.error.crashtitle = Un error ha ocurrido +text.error.title = [crimson]Un error ha ocurrido. +text.error.crashtitle = Un error ha ocurrido. text.blocks.blockinfo = Información del Bloque text.blocks.powercapacity = Capacidad de Energía text.blocks.powershot = Energía/Disparo @@ -311,7 +311,7 @@ text.blocks.inputliquidaux = Líquido Auxiliar text.blocks.inputitem = Objeto de Entrada text.blocks.inputitems = Objetos de Entrada text.blocks.outputitem = Objeto de Salida -text.blocks.drilltier = Taladrable +text.blocks.drilltier = Taladrables text.blocks.drillspeed = Velocidad de Base del Taladro text.blocks.liquidoutput = Líquido de Salida text.blocks.liquidoutputspeed = Velocidad de Salida del Líquido @@ -326,7 +326,7 @@ text.blocks.inaccuracy = Imprecisión text.blocks.shots = Disparos text.blocks.reload = Recarga text.blocks.inputfuel = Combustible -text.blocks.fuelburntime = Tiempo de Quema del Combustible +text.blocks.fuelburntime = Tiempo de Quemado del Combustible text.blocks.inputcapacity = Capacidad de entrada text.blocks.outputcapacity = Capacidad de salida text.unit.blocks = bloques @@ -346,7 +346,7 @@ text.category.items = Objetos text.category.crafting = Fabricación text.category.shooting = Disparo setting.autotarget.name = Auto apuntado -setting.fpscap.name = Max FPS +setting.fpscap.name = Máx FPS setting.fpscap.none = Nada setting.fpscap.text = {0} FPS setting.difficulty.training = entrenamiento @@ -361,28 +361,28 @@ setting.sensitivity.name = Sensibilidad del Control setting.saveinterval.name = Intervalo del Auto-guardado setting.seconds = {0} Segundos setting.fullscreen.name = Pantalla Completa -setting.multithread.name = Multihilo +setting.multithread.name = Multiproceso setting.fps.name = Mostrar FPS setting.vsync.name = VSync -setting.lasers.name = Mostrar Energía de los Lasers +setting.lasers.name = Mostrar Energía de los Láseres setting.minimap.name = Mostrar Minimapa -setting.musicvol.name = Volumen de la Musica -setting.mutemusic.name = Mutear Musica +setting.musicvol.name = Volumen de la Música +setting.mutemusic.name = Silenciar Musica setting.sfxvol.name = Volumen de los efectos de sonido -setting.mutesound.name = Mutear Sonido +setting.mutesound.name = Silenciar Sonido text.keybind.title = Reasignar Teclas category.general.name = General category.view.name = Visión category.multiplayer.name = Multijugador command.attack = Atacar -command.retreat = Retirada +command.retreat = Retirarse command.patrol = Patrullar keybind.press = Presiona una tecla... keybind.press.axis = Pulsa un eje o botón... keybind.move_x.name = Mover x keybind.move_y.name = Mover y keybind.select.name = Seleccionar -keybind.break.name = Remover +keybind.break.name = Romper keybind.deselect.name = Deseleccionar keybind.shoot.name = Disparar keybind.zoom_hold.name = Mantener Zoom @@ -402,9 +402,9 @@ keybind.drop_unit.name = drop unit keybind.zoom_minimap.name = Zoom minimapa mode.text.help.title = Descripción de modos mode.waves.name = hordas -mode.waves.description = el modo normal. con recursos limitados y entrada de hordas automática. +mode.waves.description = El modo normal. con recursos limitados y entrada de hordas automática. mode.sandbox.name = sandbox -mode.sandbox.description = recursos ilimitados y no hay temporizador para las hordas. +mode.sandbox.description = Recursos ilimitados y sin temporizador para las hordas. mode.custom.warning = Ten en cuenta que los bloques no pueden usarse en partidas personalizadas hasta que se desbloqueen en sectores.\n\n[LIGHT_GRAY]Si no desbloqueaste ningún bloque, ningno aparecerá. mode.custom.warning.read = Solo para asegurar que lo has leído:\n[scarlet]¡LOS DESBLOQUEOS EN PARTIDAS PERSONALIZADAS NO ESTÁN DISPONIBLES EN LOS SECTORES U OTROS MODOS DE JUEGO!\n\n[LIGHT_GRAY](Ojalá esto no fuera necesario, pero parece que lo es) mode.freebuild.name = construcción libre @@ -451,33 +451,33 @@ liquid.lava.name = Lava liquid.oil.name = Petróleo liquid.cryofluid.name = Criogénico mech.alpha-mech.name = Alpha -mech.alpha-mech.weapon = Heavy Repeater +mech.alpha-mech.weapon = Repetidor Pesado mech.alpha-mech.ability = Drone Swarm -mech.alpha-mech.description = The standard mech. Has decent speed and damage output; can create up to 3 drones for increased offensive capability. +mech.alpha-mech.description = El mecanoide estándar. Tiene velocidad y daño decentes, puede crear hasta 3 drones para poder ofensivo incremenado. mech.delta-mech.name = Delta -mech.delta-mech.weapon = Arc Generator -mech.delta-mech.ability = Discharge -mech.delta-mech.description = A fast, lightly-armored mech made for hit-and-run attacks. Does little damage against structures, but can kill large groups of enemy units very quickly with its arc lightning weapons. +mech.delta-mech.weapon = Generador de arco +mech.delta-mech.ability = Descarga +mech.delta-mech.description = Un mecanoide rápido y ligeramente armado para ataques de ataque y retirada. Hace poco daño a estructuras, pero puede eliminar rápidamente a grandes grupos de unidades con sus armas de arco eléctrico. mech.tau-mech.name = Tau -mech.tau-mech.weapon = Restruct Laser +mech.tau-mech.weapon = Láser de reestructuración mech.tau-mech.ability = Repair Burst -mech.tau-mech.description = The support mech. Heals allied blocks by shooting at them. Can extinguish fires and heal allies in a radius with its repair ability. +mech.tau-mech.description = El mecanoide de soporte. Repara bloques aliados disparándolos. Puede extinguir el fuego y reparar aliados en un rango con su habilidad de reparación. mech.omega-mech.name = Omega mech.omega-mech.weapon = Swarm Missiles mech.omega-mech.ability = Armored Configuration -mech.omega-mech.description = A bulky and well-armored mech, made for front-line assaults. Its armor ability can block up to 90% of incoming damage. -mech.dart-ship.name = Dart -mech.dart-ship.weapon = Repeater +mech.omega-mech.description = Un mecanoide grande y bien armado, hecho para asaltos en primera línea. Su habilidad de armadura puede bloquear hasta el 90% del daño que recibe. +mech.dart-ship.name = Dardo +mech.dart-ship.weapon = Repetidor mech.dart-ship.description = La nave normal. Bastante ligera y rápida, pero tiene poca capacidad ofensiva y baja velocidad minado. mech.javelin-ship.name = Jabalina -mech.javelin-ship.description = A hit-and-run strike ship. While initially slow, it can accelerate to great speeds and fly by enemy outposts, dealing large amounts of damage with its lightning ability and missiles. +mech.javelin-ship.description = Una nave de ataque y retirada. Aunque inicialmente lento, puede acelerar a altas velocidades y volar sobre puestos enemigos, causando gran daño con su habilidad de rayos y misiles. mech.javelin-ship.weapon = Burst Missiles mech.javelin-ship.ability = Discharge Booster mech.trident-ship.name = Tridente -mech.trident-ship.description = A heavy bomber. Reasonably well armored. +mech.trident-ship.description = Un bombardero pesado. Razonablemente bien equipado. mech.trident-ship.weapon = Bomb Bay mech.glaive-ship.name = Glaive -mech.glaive-ship.description = A large, well-armored gunship. Equipped with an incendiary repeater. Good acceleration and maximum speed. +mech.glaive-ship.description = Una nave pistolera grande y bien armada. Equipada con un repetidor incendiario. Buena aceleración y velocidad máxima. mech.glaive-ship.weapon = Flame Repeater text.item.explosiveness = [LIGHT_GRAY]Explosividad: {0} text.item.flammability = [LIGHT_GRAY]Inflamabilidad: {0} @@ -557,14 +557,14 @@ block.pneumatic-drill.name = Taladro neumático block.laser-drill.name = Taladro Laser block.water-extractor.name = Extractor de Agua block.cultivator.name = Cultivador -block.alpha-mech-pad.name = Alpha Mech Pad -block.dart-ship-pad.name = Dart Ship Pad -block.delta-mech-pad.name = Delta Mech Pad -block.javelin-ship-pad.name = Javelin Ship Pad -block.trident-ship-pad.name = Trident Ship Pad +block.alpha-mech-pad.name = Pad de mecanoide Alpha +block.dart-ship-pad.name = Pad de nave de dardos +block.delta-mech-pad.name = Pad de mecanoide Delta +block.javelin-ship-pad.name = Pad de nave Jabalina +block.trident-ship-pad.name = Pad de nave Tridente block.glaive-ship-pad.name = Glaive Ship Pad -block.omega-mech-pad.name = Omega Mech Pad -block.tau-mech-pad.name = Tau Mech Pad +block.omega-mech-pad.name = Pad de mecanoide Omega +block.tau-mech-pad.name = Pad de mecanoide Tau block.conduit.name = Conducto block.mechanical-pump.name = Bomba Mecánica block.itemsource.name = Objeto Fuente @@ -587,12 +587,12 @@ block.solidifer.name = Solidificador block.solar-panel.name = Panel Solar block.solar-panel-large.name = Panel Solar Grande block.oil-extractor.name = Extractor de Petróleo -block.spirit-factory.name = Spirit Drone Factory -block.phantom-factory.name = Phantom Drone Factory +block.spirit-factory.name = Fábrica de Drones Espíritu +block.phantom-factory.name = Fábrica de Drones Fantasmales block.wraith-factory.name = Wraith Fighter Factory block.ghoul-factory.name = Ghoul Bomber Factory -block.dagger-factory.name = Dagger Mech Factory -block.titan-factory.name = Titan Mech Factory +block.dagger-factory.name = Fábrica de Dagas +block.titan-factory.name = Fábrica de Titanes block.fortress-factory.name = Fortress Mech Factory block.revenant-factory.name = Revenant Fighter Factory block.repair-point.name = Punto de Reparación @@ -610,7 +610,7 @@ block.blast-drill.name = Taladro Gigante block.thermal-pump.name = Bomba Térmica block.thermal-generator.name = Generador Térmico block.alloy-smelter.name = Alloy Smtler -block.mend-projector.name = Mend Projector +block.mend-projector.name = Proyector de reparación block.surge-wall.name = Surge Wall block.surge-wall-large.name = Large Surge Wall block.cyclone.name = Ciclón @@ -622,30 +622,30 @@ block.arc.name = Arc block.rtg-generator.name = Generador RTG block.spectre.name = Spectre block.meltdown.name = Meltdown -block.container.name = Container +block.container.name = Contenedor team.blue.name = azul team.red.name = rojo team.orange.name = naranja team.none.name = gris team.green.name = verde team.purple.name = púrpura -unit.alpha-drone.name = Alpha Drone -unit.spirit.name = Spirit Drone +unit.alpha-drone.name = Dron Alpha +unit.spirit.name = Dron Espíritu unit.spirit.description = El dron del comienzo. Aparece en el núcleo por defecto. Mina automáticamente minerales, recoge objetos y repara bloques. -unit.phantom.name = Phantom Drone +unit.phantom.name = Dron Fantasmal unit.phantom.description = Un dron avanzado. Mina automáticamente minerales, recoge objetos y repra bloques. Bastante más efectivo que un dron normal. unit.dagger.name = Daga unit.dagger.description = Una unidad de terreno. Útil con enjambres. unit.titan.name = Titán unit.titan.description = Una unidad blindada de terreno, avanzada. Ataca blancos de aire y de terreno. unit.ghoul.name = Ghoul Bomber -unit.ghoul.description = A heavy carpet bomber. Uses blast compound or pyratite as ammo. +unit.ghoul.description = Una unidad bombardera pesada. Usa compuesto explosivo o pirotita como munición. unit.wraith.name = Wraith Fighter -unit.wraith.description = A fast, hit-and-run interceptor unit. +unit.wraith.description = Una unidad interceptora rápida. unit.fortress.name = Fortress -unit.fortress.description = A heavy artillery ground unit. +unit.fortress.description = Una unidad terrestre pesada de artillería. unit.revenant.name = Revenant -unit.revenant.description = A heavy laser platform. +unit.revenant.description = Una plataforma láser pesada. tutorial.begin = Tu objetivo aquí es erradicar el[LIGHT_GRAY] enemy[].\n\nComienza[accent]minando copper[]. Toca una veta de cobre cerca de tu núcleo para hacer esto. tutorial.drill = Minar manualmente es ineficiente.\nLos [accent]taladros pueden minar automáticamente.\nColoca uno en una veta de cobre. tutorial.conveyor = Los [accent]Conveyors[] se usan para transportar objetos al núcleo.\nConstruye una línea de transportadores del taladro al núcleo. @@ -667,53 +667,53 @@ tutorial.daggerfactory = Construye una[accent] dagger mech factory[].\n\nEsto se tutorial.router = Las fábricas necesitan recursos para funcionar.\nCrea un enrutador para separar recursos del transportador. tutorial.dagger = Conecta nodos de energía a la fábrica.\nUna vez las necesidades se cumplan, una unidad será creada.\n\nCrea taladros, generadores y transportadores según necesites. tutorial.battle = El[LIGHT_GRAY] enemy[] ha revelado su núcleo.\nDestrúyelo con tu nave y tus unidades de combate. -block.copper-wall.description = A cheap defensive block.\nUseful for protecting the core and turrets in the first few waves. -block.copper-wall-large.description = A cheap defensive block.\nUseful for protecting the core and turrets in the first few waves.\nSpans multiple tiles. -block.dense-alloy-wall.description = A standard defensive block.\nAdequate protection from enemies. -block.dense-alloy-wall-large.description = A standard defensive block.\nAdequate protection from enemies.\nSpans multiple tiles. -block.thorium-wall.description = A strong defensive block.\nGood protection from enemies. -block.thorium-wall-large.description = A strong defensive block.\nGood protection from enemies.\nSpans multiple tiles. -block.phase-wall.description = Not as strong as a thorium wall but will deflect bullets unless they are too powerful. -block.phase-wall-large.description = Not as strong as a thorium wall but will deflect bullets unless they are too powerful.\nSpans multiple tiles. -block.surge-wall.description = The strongest defensive block.\nHas a small chance of triggering lightning towards the attacker. -block.surge-wall-large.description = The strongest defensive block.\nHas a small chance of triggering lightning towards the attacker.\nSpans multiple tiles. -block.door.description = A small door that can be opened and closed by tapping on it.\nIf opened, enemies can shoot and move through. -block.door-large.description = A large door that can be opened and closed by tapping on it.\nIf opened, enemies can shoot and move through.\nSpans multiple tiles. -block.mend-projector.description = Periodically heals buildings in its vicinity. -block.overdrive-projector.description = Increases the speed of nearby buildings like drills and conveyors. -block.force-projector.description = Creates a hexagonal force field around itself, protecting buildings and units inside from damage through bullets. -block.shock-mine.description = Damages enemies stepping on the mine. Nearly invisible to the enemy. -block.duo.description = A small, cheap turret. -block.arc.description = A small turret which shoots electricity in a random arc towards the enemy. -block.hail.description = A small artillery turret. -block.lancer.description = A medium-sized turret which shoots charged electricity beams. -block.wave.description = A medium-sized rapid-fire turret which shoots liquid bubbles. -block.salvo.description = A medium-sized turret which fires shots in salvos. -block.swarmer.description = A medium-sized turret which shoots burst missiles. -block.ripple.description = A large artillery turret which fires several shots simultaneously. -block.cyclone.description = A large rapid fire turret. -block.fuse.description = A large turret which shoots powerful short-range beams. -block.spectre.description = A large turret which shoots two powerful bullets at once. -block.meltdown.description = A large turret which shoots powerful long-range beams. -block.conveyor.description = Basic item transport block. Moved items forward and automatically deposits them into turrets or crafters. Rotatable. -block.titanium-conveyor.description = Advanced item transport block. Moves items faster than standard conveyors. -block.phase-conveyor.description = Advanced item transport block. Uses power to teleport items to a connected phase conveyor over several tiles. -block.junction.description = Acts as a bridge for two crossing conveyor belts. Useful in situations with two different conveyors carrying different materials to different locations. -block.mass-driver.description = Ultimate item transport block. Collects several items and then shoots them to another mass driver over a long range. -block.smelter.description = Burns coal for smelting copper and lead into dense alloy. -block.arc-smelter.description = Smelts copper and lead into dense alloy by using an external power source. +block.copper-wall.description = Un bloque defensivo barato.\nÚtil para defneder e núcleo y las torres en las primeras hordas. +block.copper-wall-large.description = Un bloque defensivo barato.\nÚtil para defneder e núcleo y las torres en las primeras hordas.\nOcupa múltiples casillas. +block.dense-alloy-wall.description = Un bloque de defensa estándar.\nProtección adecuada contra enemigos. +block.dense-alloy-wall-large.description = Un bloque de defensa estándar.\nProtección adecuada contra enemigos.\nOcupa múltiples casillas. +block.thorium-wall.description = Un bloque defensivo fuerte.\nBuena protección contra enemigos. +block.thorium-wall-large.description = Un bloque defensivo fuerte.\nBuena protección contra enemigos.\nOcupa múltiples casillas. +block.phase-wall.description = No es tan fuerte como un muro de torio pero rebota balas al enemigo si no son demasiado fuertes. +block.phase-wall-large.description = No es tan fuerte como un muro de torio pero rebota balas al enemigo si no son demasiado fuertes.\nOcupa múltiples casillas. +block.surge-wall.description = El bloque defensivo más fuerte.\nTiene una pequeña probabilidad de disparar rayos al atacante. +block.surge-wall-large.description = El bloque defensivo más fuerte.\nTiene una pequeña probabilidad de disparar rayos al atacante.\nOcupa múltiplies casillas. +block.door.description = Una puerta pequeña que puede ser abierta y cerrada tocándola.\nSi está abirta, los enemigos pueden moverse y disparar a través de ella.\nOcupa múltiples casillas. +block.door-large.description = Una puerta grande que puede ser abierta y cerrada tocándola.\nSi está abirta, los enemigos pueden moverse y disparar a través de ella.\nOcupa múltiples casillas. +block.mend-projector.description = Regenera edificios cercanos periódcamente. +block.overdrive-projector.description = Aumenta la velocidad de edificios cercanos como taladros y transportadores. +block.force-projector.description = Crea un área de fuerza hexagonal alrededor de él, protegiendo edificios y unidades dentro de él del daño de las balas. +block.shock-mine.description = Daña enemigos que pisan a mina. Casi invisible al enemigo. +block.duo.description = Una torre pequeña y barata. +block.arc.description = Una torre pequeña que disapra electricidad en un arco aleatorio al enemigo. +block.hail.description = Una torre de artillería pequeña. +block.lancer.description = Una torre de tamaño mediano que dispara rayos cargados eléctricamente. +block.wave.description = Una torre de tamaño mediano que dispara burbujas de líquido. +block.salvo.description = Una torre de tramaño mediano que dispara balas en salvos. +block.swarmer.description = Una torre de tamaño mediano que dispara misiles en grupo. +block.ripple.description = Una torre de artillería grande que dispara varios disparos simultáneamente. +block.cyclone.description = Una torre de disparo rápido grande. +block.fuse.description = Una torre grande que dispara rayos poderosos de corto alcance. +block.spectre.description = Una torre grande que dispara dos balas poderosas de una vez. +block.meltdown.description = Una torre grande que dispara rayos poderosos de largo alcance. +block.conveyor.description = Bloque de transporte básico. Mueve objetos hacia adelante y los deposita automáticamente en torres o fábricas. Rotable. +block.titanium-conveyor.description = Bloque de transporte avanzado. Mueve objetos más rápido que los transportadores estándar. +block.phase-conveyor.description = Bloque de transporte avanzado. Usa energía para transportar objetos a otro transportador de fase conectado por varias casillas. +block.junction.description = Actúa como puente para dos transportadores que se cruzan. Útil en situaciones con dos diferentes transportadores transportando diferentes materiales a diferentes lugares. +block.mass-driver.description = El mejor bloque de transorte. Recoge varios objetos y los dispara a otro conductor de masa en un largo rango. +block.smelter.description = Quema carbón para fundir cobre y plomo, produciendo así aleación densa. +block.arc-smelter.description = Funde cobre y plomo en aleación densa usando una fuented de energía externa. block.silicon-smelter.description = Reduces sand with highly pure coke in order to produce silicon. -block.plastanium-compressor.description = Produces plastanium from oil and titanium. +block.plastanium-compressor.description = Produce plastanio con aceite y titanio. block.phase-weaver.description = Produces phase fabric from radioactive thorium and high amounts of sand. -block.alloy-smelter.description = Produces surge alloy from titanium, lead, silicon and copper. -block.pulverizer.description = Crushes stone into sand. Useful when there is a lack of natural sand. -block.pyratite-mixer.description = Mixes coal, lead and sand into highly flammable pyratite. -block.blast-mixer.description = Uses oil for transforming pyratite into the less flammable but more explosive blast compound. -block.cryofluidmixer.description = Combines water and titanium into cryofluid which is much more efficient for cooling. -block.solidifer.description = Cools lava to stone at a fast pace. -block.melter.description = Heats up stone to very high temperatures to obtain lava. -block.incinerator.description = Gets rid of any excess item or liquid. -block.biomattercompressor.description = Compresses biomatter in order to retrieve oil. +block.alloy-smelter.description = Produce "surge alloy" con titanio, plomo, silicona y cobre. +block.pulverizer.description = Despedaza la piedra en arena. Útil cuando no hay arena natural. +block.pyratite-mixer.description = Mezcla carbón, plomo y arena en pirotita altamente inflamable. +block.blast-mixer.description = Usa aceite para transformar pirotita en un objeto menos inflamable pero más explosivo: compuesto explosivo. +block.cryofluidmixer.description = Combina agua y titanio en líquido criogénico que es mucho más eficiente para enfriar. +block.solidifer.description = Enfría la lava a piedra a una gran velocidad. +block.melter.description = Calienta piedra a temperaturas muy altas para obtener lava. +block.incinerator.description = Se deshace de cualquier líquido u objeto excesivo. +block.biomattercompressor.description = Comprime biomateria para extraer aceite. block.separator.description = Expone piedra a la presión del agua para obtener diversos minerales contenidos en la piedra. block.centrifuge.description = Más eficiente que un separador, pero es más caro de construir y requiere energía. block.power-node.description = Transmite energía a nodos conectados, conecta hasta cuatro fuentes de energía, edificios que usan energía o nodos. El nodo obtendrá o transmitirá energía de cualquier bloque adyacente. @@ -733,47 +733,48 @@ block.vault.description = Almacena una gran cantidad de objetos. Úsalo para cre block.mechanical-drill.description = Un taladro barato. Cuando es colocado en casillas apropiadas, extrae objetos lentamente de forma indefinida. block.pneumatic-drill.description = Un taladro mejorado que es más rápido y puede obtener minerales más duros usando la presión. block.laser-drill.description = Permite obtener minerales incluso más rápido con la tecnología láser, pero requiere energía. Además, se puede obtener torio radioactivo con este taladro. -block.blast-drill.description = The ultimate drill. Requires large amounts of power. +block.blast-drill.description = El mejor taladro. Requiere grandes cantidades de energía. block.water-extractor.description = Extrae agua de la tierra. Úsalo cuando no haya lagos cercanos. block.cultivator.description = Cultiva la tierra para obtener biomateria. block.oil-extractor.description = Usa grandes cantidades de energía para extraer aceite de la arena. Úsalo cuando no hay fuentes directas de aceite cerca. -block.dart-ship-pad.description = Leave your current vessel and change into a basic fighter aircraft.\nUse the pad by double tapping while standing on it. -block.trident-ship-pad.description = Leave your current vessel and change into a reasonably well armored heavy bomber.\nUse the pad by double tapping while standing on it. -block.javelin-ship-pad.description = Leave your current vessel and change into a strong and fast interceptor with lightning weapons.\nUse the pad by double tapping while standing on it. -block.glaive-ship-pad.description = Leave your current vessel and change into a large, well-armored gunship.\nUse the pad by double tapping while standing on it. -block.tau-mech-pad.description = Leave your current vessel and change into a support mech which can heal friendly buildings and units.\nUse the pad by double tapping while standing on it. +block.dart-ship-pad.description = Deja tu nave actual y transfórmate en una unidad aérea básica.\nUsa el pad tocándolo dos veces mientras estás en él. +block.trident-ship-pad.description = Deja tu nave actual y transfórmate en una unidad aérea bombardera pesada.\nUsa el pad tocándolo dos veces mientras estás en él. +block.javelin-ship-pad.description = Deja tu nave actual y transfórmate en una unidad aérea fuerte y rápida interceptora con arma eléctrica.\nUsa el pad tocándolo dos veces mientras estás en él. +block.glaive-ship-pad.description = Deja tu nave actual y transfórmate en una unidad aérea grande y bien armada nave pistolera.\nUsa el pad tocándolo dos veces mientras estás en él. +block.tau-mech-pad.description = Deja tu nave actual y transfórmate en un mecanoide de soporte que puede reparar construcciones y tropas aliadas.\nUsa el pad tocándolo dos veces mientras estás en él. block.delta-mech-pad.description = Leave your current vessel and change into a fast, lightly-armored mech made for hit-and-run attacks.\nUse the pad by double tapping while standing on it. -block.omega-mech-pad.description = Leave your current vessel and change into a bulky and well-armored mech, made for front-line assaults.\nUse the pad by double tapping while standing on it. +Deja tu nave actual y transfórmate en un mecanoide rápido, con armas ligeras hecho para ataques de ataque y retirada.\nUsa el pad tocándolo dos veces mientras estás en él. +block.omega-mech-pad.description = Deja tu nave actual y transfórmate en un mecanoide pesado y bien armado, hecho para asaltos en primera línea.\nUsa el pad tocándolo dos veces mientras estás en él. block.spirit-factory.description = Produce drones ligeros que obtienen minerales y reparan bloques. -block.phantom-factory.description = Produces advanced drone units which are significantly more effective than a spirit drone. -block.wraith-factory.description = Produces fast, hit-and-run interceptor units. -block.ghoul-factory.description = Produces heavy carpet bombers. +block.phantom-factory.description = Produce drones avanzados que son significativamente más eficientes que un dron espíritu. +block.wraith-factory.description = Produce unidades aéreas rápidas e interceptoras. +block.ghoul-factory.description = Produce unidadess bombarderas pesadas. block.dagger-factory.description = Produce unidades terrestres básicas. -block.titan-factory.description = Produces advanced, armored ground units. -block.fortress-factory.description = Produces heavy artillery ground units. -block.revenant-factory.description = Produces heavy laser ground units. +block.titan-factory.description = Produce unidades terrestres avanzadas. +block.fortress-factory.description = Produce unidades terrestres de artillería pesada. +block.revenant-factory.description = Produce unidades terrestres láser pesadas. block.repair-point.description = Repara la unidad dañada más cercana a su alrededor. -block.command-center.description = Allows changing friendly AI behavior. Currently, attack, retreat and patrol commands are supported. -block.conduit.description = Basic liquid transport block. Works like a conveyor, but with liquids. Best used with extractors, pumps or other conduits. -block.pulse-conduit.description = Advanced liquid transport block. Transports liquids faster and stores more than standard conduits. -block.phase-conduit.description = Advanced liquid transport block. Uses power to teleport liquids to a connected phase conduit over several tiles. -block.liquid-router.description = Accepts liquids from one direction and outputs them to up to 3 other directions equally. Can also store a certain amount of liquid. Useful for splitting the liquids from one source to multiple targets. -block.liquid-tank.description = Stores a large amount of liquids. Use it for creating buffers when there is a non-constant demand of materials or as a safeguard for cooling vital blocks. -block.liquid-junction.description = Acts as a bridge for two crossing conduits. Useful in situations with two different conduits carrying different liquids to different locations. -block.bridge-conduit.description = Advanced liquid transport block. Allows transporting liquids over up to 3 tiles of any terrain or building. -block.mechanical-pump.description = A cheap pump with slow output, but no power consumption. -block.rotary-pump.description = An advanced pump which doubles up speed by using power. -block.thermal-pump.description = The ultimate pump. Three times as fast as a mechanical pump and the only pump which is able to retrieve lava. -block.router.description = Accepts items from one direction and outputs them to up to 3 other directions equally. Useful for splitting the materials from one source to multiple targets. -block.distributor.description = An advanced router which splits items to up to 7 other directions equally. -block.bridge-conveyor.description = Advanced item transport block. Allows transporting items over up to 3 tiles of any terrain or building. -block.alpha-mech-pad.description = When given enough power, rebuilds your ship into the[accent] Alpha[] mech. -block.itemsource.description = Infinitely outputs items. Sandbox only. -block.liquidsource.description = Infinitely outputs liquids. Sandbox only. -block.itemvoid.description = Destroys any items which go into it without using power. Sandbox only. -block.powerinfinite.description = Infinitely outputs power. Sandbox only. -block.powervoid.description = Voids all power inputted into it. Sandbox only. -liquid.water.description = Commonly used for cooling machines and waste processing. -liquid.lava.description = Can be transformed into[LIGHT_GRAY] stone[], used for generating power or used as ammo for certain turrets. -liquid.oil.description = Can be burnt, exploded or used as a coolant. -liquid.cryofluid.description = The most efficient liquid for cooling things down. +block.command-center.description = Permite cambiar el comportamiento de la IA aliada. Actualmente, atacar, retirarse y patrullar son los comandos soportados. +block.conduit.description = Bloque de transporte de líquidos básico. Funciona como un transportador, pero con líquidos. Usado con bombas, extractores u otros conductos. +block.pulse-conduit.description = Bloque de transporte de líquidos avanzado. Transporta líquidos más rápidamente y almacena más que los conductos estándar. +block.phase-conduit.description = Bloque de transporte de líquidos avanzado. Usa energía para transportar líquidos a otro conducto de fase conectado por varias casillas. +block.liquid-router.description = Acepta líquidos de una dirección y los deja en hasta 3 direcciones equitativamente. También puede amacenar cierta capacidad de líquido. Útil para dividir los líquidos de una fuente a varios objetivos. +block.liquid-tank.description = Almacena una gran cantidad de líquidos. Úsalo para crear almacenes cuando no hay una demanda constante de materiales o para asegurarse de enfriar bloques vitales. +block.liquid-junction.description = Actúa como un puente para dos condusctos que se cruzan. Útil en situaciones en las que hay dos conductos con líquidos diferentes a diferentes lugares. +block.bridge-conduit.description = Bloque avanzado de transporte de líquidos. Permite transportar líquidos por encima hasta 3 casillas de cualquier terreno o construcción. +block.mechanical-pump.description = Una bomba barata con extracción lenta, pero sin uso de energía. +block.rotary-pump.description = Una bomba avanzada que duplica la velocidad usando energía. +block.thermal-pump.description = La mejor bomba. Tres veces más rápido que la bomba mecánica, y la única bomba que puede extraer lava. +block.router.description = Acepta objetos de una dirección y deja objetos equitativamente en hasta 3 direcciones diferentes. Útil para dividir los materiales de una fuente de recursos a múltiples objetivos. +block.distributor.description = Un enrutador avanzado que distribuye objetos equitativamente en hasta otras 7 direcciones. +block.bridge-conveyor.description = Bloque avanado de transporte. Puede transportar objetos por encima hasta 3 casillas de cualquier terreno o construcción. +block.alpha-mech-pad.description = Cuando se le da suficiente energía, reconstruye tu nave en el mecanoide[accent] Alpha[]. +block.itemsource.description = Da objetos infinitos. Solo en sandbox. +block.liquidsource.description = Da líquido infinito. Solo en sandbox. +block.itemvoid.description = Destruye cuanquier objeto que va a él sin necesitar energía. Solo en sandbox. +block.powerinfinite.description = Da energía infinita. Solo en sandbox. +block.powervoid.description = Elimina toda la energía que se le da. Solo en sandbox. +liquid.water.description = Usado comúnmente para enfriar máquinas y para procesar residuos. +liquid.lava.description = Puede usarse para ser transformado en[LIGHT_GRAY] stone[], para generar energía o para munición de ciertas torres. +liquid.oil.description = Puede ser quemado, explotado o como un enfriador. +liquid.cryofluid.description = El líquido más eficiente pra enfriar las cosas. From b7506229f8817e4f85800892b6dd822687987f3a Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 8 Nov 2018 14:53:18 -0500 Subject: [PATCH 17/34] Minor bugfixes --- core/src/io/anuke/mindustry/content/blocks/Blocks.java | 2 +- core/src/io/anuke/mindustry/core/Control.java | 2 +- core/src/io/anuke/mindustry/entities/Player.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/io/anuke/mindustry/content/blocks/Blocks.java b/core/src/io/anuke/mindustry/content/blocks/Blocks.java index da606c6851..67e031d4a6 100644 --- a/core/src/io/anuke/mindustry/content/blocks/Blocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/Blocks.java @@ -139,7 +139,7 @@ public class Blocks extends BlockList implements ContentList{ }}; ice = new Floor("ice"){{ - dragMultiplier = 0.3f; + dragMultiplier = 0.2f; speedMultiplier = 0.4f; minimapColor = Color.valueOf("b8eef8"); hasOres = true; diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index 7fec236a56..450773f1d3 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -271,7 +271,7 @@ public class Control extends Module{ outer: for(int i = 0; i < content.recipes().size; i ++){ Recipe recipe = content.recipes().get(i); - if(!recipe.hidden && recipe.requirements != null){ + if(!recipe.isHidden() && recipe.requirements != null){ for(ItemStack stack : recipe.requirements){ if(!entity.items.has(stack.item, Math.min((int) (stack.amount * unlockResourceScaling), 2000))) continue outer; } diff --git a/core/src/io/anuke/mindustry/entities/Player.java b/core/src/io/anuke/mindustry/entities/Player.java index a454e2078c..587b3a0125 100644 --- a/core/src/io/anuke/mindustry/entities/Player.java +++ b/core/src/io/anuke/mindustry/entities/Player.java @@ -323,7 +323,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra } if(floor.isLiquid){ - Draw.tint(Color.WHITE, floor.liquidColor, Mathf.clamp(drownTime)); + Draw.tint(Color.WHITE, floor.liquidColor, Mathf.clamp(drownTime, 0, 0.99f)); }else{ Draw.tint(Color.WHITE); } From 20032def7ef6d784f3d7add19ed9c78685215f74 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 8 Nov 2018 16:30:56 -0500 Subject: [PATCH 18/34] Fixed player turning white before drowning on multiplayer --- core/src/io/anuke/mindustry/content/blocks/LiquidBlocks.java | 2 +- core/src/io/anuke/mindustry/entities/Player.java | 2 +- core/src/io/anuke/mindustry/entities/Unit.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/io/anuke/mindustry/content/blocks/LiquidBlocks.java b/core/src/io/anuke/mindustry/content/blocks/LiquidBlocks.java index 4333317e7a..a9e9f97155 100644 --- a/core/src/io/anuke/mindustry/content/blocks/LiquidBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/LiquidBlocks.java @@ -30,7 +30,7 @@ public class LiquidBlocks extends BlockList implements ContentList{ thermalPump = new Pump("thermal-pump"){{ shadow = "shadow-rounded-2"; - pumpAmount = 0.3f; + pumpAmount = 0.275f; consumes.power(0.03f); liquidCapacity = 40f; hasPower = true; diff --git a/core/src/io/anuke/mindustry/entities/Player.java b/core/src/io/anuke/mindustry/entities/Player.java index 587b3a0125..8e4dc2f682 100644 --- a/core/src/io/anuke/mindustry/entities/Player.java +++ b/core/src/io/anuke/mindustry/entities/Player.java @@ -323,7 +323,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra } if(floor.isLiquid){ - Draw.tint(Color.WHITE, floor.liquidColor, Mathf.clamp(drownTime, 0, 0.99f)); + Draw.tint(Color.WHITE, floor.liquidColor, drownTime); }else{ Draw.tint(Color.WHITE); } diff --git a/core/src/io/anuke/mindustry/entities/Unit.java b/core/src/io/anuke/mindustry/entities/Unit.java index 62e1d20232..e7d4644401 100644 --- a/core/src/io/anuke/mindustry/entities/Unit.java +++ b/core/src/io/anuke/mindustry/entities/Unit.java @@ -276,7 +276,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ drownTime = Mathf.clamp(drownTime); - if(drownTime >= 0.999f){ + if(drownTime >= 0.999f && !Net.client()){ damage(health + 1); } From 969076f1ef080b95c0ffacd3b7cd83d1613e5adf Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 8 Nov 2018 17:38:51 -0500 Subject: [PATCH 19/34] Fixed sector data carry-over --- core/src/io/anuke/mindustry/maps/Sectors.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/io/anuke/mindustry/maps/Sectors.java b/core/src/io/anuke/mindustry/maps/Sectors.java index 5f85f364b6..e80af4024a 100644 --- a/core/src/io/anuke/mindustry/maps/Sectors.java +++ b/core/src/io/anuke/mindustry/maps/Sectors.java @@ -156,7 +156,7 @@ public class Sectors{ } grid.clear(); - Array out = Settings.getObject("sectors", Array.class, Array::new); + Array out = Settings.getObject("sector-data-2", Array.class, Array::new); for(Sector sector : out){ @@ -185,7 +185,7 @@ public class Sectors{ } } - Settings.putObject("sectors", out); + Settings.putObject("sector-data-2", out); Settings.save(); } From 4d8bbe3023bce16510e9bcfae88cb8101dee2088 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 8 Nov 2018 17:40:50 -0500 Subject: [PATCH 20/34] ita -> it --- .../bundles/{bundle_ita.properties => bundle_it.properties} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename core/assets/bundles/{bundle_ita.properties => bundle_it.properties} (100%) diff --git a/core/assets/bundles/bundle_ita.properties b/core/assets/bundles/bundle_it.properties similarity index 100% rename from core/assets/bundles/bundle_ita.properties rename to core/assets/bundles/bundle_it.properties From c554390de539bcecc4ac68fc06abe8559b1a88b5 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 8 Nov 2018 18:48:19 -0500 Subject: [PATCH 21/34] Crash fix --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1dc92a9b97..d16c36a4a5 100644 --- a/build.gradle +++ b/build.gradle @@ -25,7 +25,7 @@ allprojects { appName = 'Mindustry' gdxVersion = '1.9.8' roboVMVersion = '2.3.0' - uCoreVersion = 'eb1503dfb786f5f727bdb4b6a302718490444335' + uCoreVersion = '8919cb7b6881d040fb720149779fcf58c1927893' getVersionString = { String buildVersion = getBuildVersion() From 6342cc41acaa9fa92269b15d08b7d30aa5622a31 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 8 Nov 2018 22:18:34 -0500 Subject: [PATCH 22/34] Better lake generation --- core/assets/shaders/shield.fragment | 15 --------------- .../mindustry/maps/generation/WorldGenerator.java | 6 +++--- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/core/assets/shaders/shield.fragment b/core/assets/shaders/shield.fragment index cfef064bb2..8be35b1ef6 100644 --- a/core/assets/shaders/shield.fragment +++ b/core/assets/shaders/shield.fragment @@ -8,15 +8,12 @@ precision highp int; #define ALPHA 0.18 uniform sampler2D u_texture; - uniform vec4 u_color; uniform vec2 u_texsize; uniform float u_time; uniform float u_scaling; uniform float u_dp; uniform vec2 u_offset; -uniform int u_hitamount; -uniform vec3 u_hits[MAX_HITS]; varying vec4 v_color; varying vec2 v_texCoord; @@ -59,18 +56,6 @@ void main() { } color.a = ALPHA; - - for(int i = 0; i < MAX_HITS; i ++){ - if(i >= u_hitamount) break; - vec3 hit = u_hits[i]; - float rad = hit.z * HIT_RADIUS; - float fin = 1.0 - hit.z; - - if(abs(distance(vec2(hit.x, hit.y), coords - u_texsize/2.0) - rad) < 1.0){ - color = mix(color, mix(u_color, vec4(1.0), si), (1.0 * fin)); - color.a = ALPHA + 0.82 *fin; - } - } } gl_FragColor = color; diff --git a/core/src/io/anuke/mindustry/maps/generation/WorldGenerator.java b/core/src/io/anuke/mindustry/maps/generation/WorldGenerator.java index 1424903a14..45e0c64bcf 100644 --- a/core/src/io/anuke/mindustry/maps/generation/WorldGenerator.java +++ b/core/src/io/anuke/mindustry/maps/generation/WorldGenerator.java @@ -311,7 +311,7 @@ public class WorldGenerator{ + sim3.octaveNoise2D(detailed ? 12 : 9, 0.6, 1f / 1100f, x - 120, y); double lake = sim2.octaveNoise2D(1, 1, 1f / 110f, x, y); - elevation -= lake/3f; + elevation -= Math.pow(lake + 0.15, 5); int lerpDst = 20; lerpDst *= lerpDst; @@ -329,9 +329,9 @@ public class WorldGenerator{ } } - if(elevation < 0.7 || lake > 0.96){ + if(elevation < 0.7){ floor = Blocks.deepwater; - }else if(elevation < 0.79 || lake > 0.948){ + }else if(elevation < 0.79){ floor = Blocks.water; }else if(elevation < 0.85){ floor = Blocks.sand; From e9783eccccd496696be96b97454533f3fe35de39 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 8 Nov 2018 23:19:47 -0500 Subject: [PATCH 23/34] Possible minimap fix --- core/src/io/anuke/mindustry/ui/Minimap.java | 28 ++++++++++----------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/core/src/io/anuke/mindustry/ui/Minimap.java b/core/src/io/anuke/mindustry/ui/Minimap.java index 0adc2145a4..3ee65de5e3 100644 --- a/core/src/io/anuke/mindustry/ui/Minimap.java +++ b/core/src/io/anuke/mindustry/ui/Minimap.java @@ -1,21 +1,17 @@ package io.anuke.mindustry.ui; import com.badlogic.gdx.graphics.Texture.TextureFilter; -import com.badlogic.gdx.graphics.g2d.Batch; import com.badlogic.gdx.graphics.g2d.TextureRegion; import io.anuke.mindustry.graphics.Shaders; import io.anuke.ucore.core.Core; import io.anuke.ucore.core.Graphics; +import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.scene.Element; import io.anuke.ucore.scene.event.InputEvent; import io.anuke.ucore.scene.event.InputListener; -import io.anuke.ucore.scene.style.TextureRegionDrawable; -import io.anuke.ucore.scene.ui.Image; import io.anuke.ucore.scene.ui.layout.Table; -import static io.anuke.mindustry.Vars.renderer; -import static io.anuke.mindustry.Vars.showFog; -import static io.anuke.mindustry.Vars.world; +import static io.anuke.mindustry.Vars.*; public class Minimap extends Table{ @@ -25,14 +21,15 @@ public class Minimap extends Table{ margin(5); marginBottom(10); - Image image = new Image(new TextureRegionDrawable(new TextureRegion())){ + TextureRegion r = new TextureRegion(); + + Element elem = new Element(){ @Override - public void draw(Batch batch, float parentAlpha){ + public void draw(){ if(renderer.minimap.getRegion() == null) return; - TextureRegionDrawable draw = (TextureRegionDrawable) getDrawable(); - draw.getRegion().setRegion(renderer.minimap.getRegion()); - super.draw(batch, parentAlpha); + Draw.crect(renderer.minimap.getRegion(), x, y, width, height); + if(renderer.minimap.getTexture() != null){ renderer.minimap.drawEntities(x, y, width, height); } @@ -40,7 +37,7 @@ public class Minimap extends Table{ if(showFog){ renderer.fog.getTexture().setFilter(TextureFilter.Nearest, TextureFilter.Nearest); - TextureRegion r = draw.getRegion(); + r.setRegion(renderer.minimap.getRegion()); float pad = renderer.fog.getPadding(); float px = r.getU() * world.width() + pad; @@ -55,7 +52,7 @@ public class Minimap extends Table{ r.setV2(1f - py2 / (world.height() + pad*2f)); Graphics.shader(Shaders.fog); - super.draw(batch, parentAlpha); + Draw.crect(r, x, y, width, height); Graphics.shader(); renderer.fog.getTexture().setFilter(TextureFilter.Linear, TextureFilter.Linear); @@ -70,7 +67,7 @@ public class Minimap extends Table{ } }); - image.update(() -> { + elem.update(() -> { Element e = Core.scene.hit(Graphics.mouse().x, Graphics.mouse().y, true); if(e != null && e.isDescendantOf(this)){ @@ -79,6 +76,7 @@ public class Minimap extends Table{ Core.scene.setScrollFocus(null); } }); - add(image).size(140f, 140f); + + add(elem).size(140f, 140f); } } From 4f96744ff29a85e99a09ca27c0d11ff836e0a8e3 Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 8 Nov 2018 23:50:03 -0500 Subject: [PATCH 24/34] Shield shader simplification --- core/assets/shaders/shield.fragment | 21 ++++++------------- .../src/io/anuke/mindustry/core/Renderer.java | 3 ++- .../io/anuke/mindustry/graphics/Shaders.java | 12 +++-------- 3 files changed, 11 insertions(+), 25 deletions(-) diff --git a/core/assets/shaders/shield.fragment b/core/assets/shaders/shield.fragment index 8be35b1ef6..e71cb95f37 100644 --- a/core/assets/shaders/shield.fragment +++ b/core/assets/shaders/shield.fragment @@ -6,9 +6,10 @@ precision highp int; #define MAX_HITS 64 #define HIT_RADIUS 12.0 #define ALPHA 0.18 +#define thickness 1.0 +#define step 2.0 uniform sampler2D u_texture; -uniform vec4 u_color; uniform vec2 u_texsize; uniform float u_time; uniform float u_scaling; @@ -25,29 +26,19 @@ float round(float f){ void main() { vec2 T = v_texCoord.xy; - vec2 coords = (T * u_texsize) + u_offset; T += vec2(sin(coords.y / 3.0 + u_time / 20.0) / 240.0, sin(coords.x / 3.0 + u_time / 20.0) / 240.0) * u_scaling; float si = sin(u_time / 20.0) / 8.0; - vec4 color = texture2D(u_texture, T); - vec2 v = vec2(1.0/u_texsize.x, 1.0/u_texsize.y); - bool any = false; + if(texture2D(u_texture, T).a < 0.1 && + (texture2D(u_texture, T + vec2(0, step) * v).a > 0.1 || texture2D(u_texture, T + vec2(0, -step) * v).a > 0.1 || + texture2D(u_texture, T + vec2(step, 0) * v).a > 0.1 || texture2D(u_texture, T + vec2(-step, 0) * v).a > 0.1)){ - float thickness = 1.0; - float step = 2.0; - - if(texture2D(u_texture, T).a < 0.1 && - (texture2D(u_texture, T + vec2(0, step) * v).a > 0.1 || texture2D(u_texture, T + vec2(0, -step) * v).a > 0.1 || - texture2D(u_texture, T + vec2(step, 0) * v).a > 0.1 || texture2D(u_texture, T + vec2(-step, 0) * v).a > 0.1)) - any = true; - - if(any){ - gl_FragColor = mix(u_color, vec4(1.0), si); + gl_FragColor = mix(v_color, vec4(1.0), si); }else{ if(color.a > 0.1){ diff --git a/core/src/io/anuke/mindustry/core/Renderer.java b/core/src/io/anuke/mindustry/core/Renderer.java index b9e9ea9567..08b9f9de43 100644 --- a/core/src/io/anuke/mindustry/core/Renderer.java +++ b/core/src/io/anuke/mindustry/core/Renderer.java @@ -248,11 +248,12 @@ public class Renderer extends RendererModule{ overlays.drawBottom(); drawAndInterpolate(playerGroup, p -> true, Player::drawBuildRequests); - Shaders.shield.color.set(Palette.accent); Graphics.beginShaders(Shaders.shield); EntityDraw.draw(shieldGroup); EntityDraw.drawWith(shieldGroup, shield -> true, shield -> ((ShieldEntity)shield).drawOver()); + Draw.color(Palette.accent); Graphics.endShaders(); + Draw.color(); overlays.drawTop(); diff --git a/core/src/io/anuke/mindustry/graphics/Shaders.java b/core/src/io/anuke/mindustry/graphics/Shaders.java index 69be1a9008..e3c3a5a656 100644 --- a/core/src/io/anuke/mindustry/graphics/Shaders.java +++ b/core/src/io/anuke/mindustry/graphics/Shaders.java @@ -3,7 +3,6 @@ package io.anuke.mindustry.graphics; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.g2d.TextureRegion; -import com.badlogic.gdx.utils.FloatArray; import io.anuke.ucore.core.Core; import io.anuke.ucore.core.Timers; import io.anuke.ucore.graphics.Draw; @@ -168,9 +167,7 @@ public class Shaders{ } public static class Shield extends Shader{ - public static final int MAX_HITS = 3 * 64; - public Color color = new Color(); - public FloatArray hits = new FloatArray(); + //public Color color = new Color(); public Shield(){ super("shield", "default"); @@ -179,12 +176,9 @@ public class Shaders{ @Override public void apply(){ float scaling = Core.cameraScale / 4f / Core.camera.zoom; - if(hits.size > 0){ - shader.setUniform3fv("u_hits[0]", hits.items, 0, Math.min(hits.size, MAX_HITS)); - shader.setUniformi("u_hitamount", Math.min(hits.size, MAX_HITS) / 3); - } + shader.setUniformf("u_dp", Unit.dp.scl(1f)); - shader.setUniformf("u_color", color); + //shader.setUniformf("u_color", color); shader.setUniformf("u_time", Timers.time() / Unit.dp.scl(1f)); shader.setUniformf("u_scaling", scaling); shader.setUniformf("u_offset", From 1d238c8315d0f3138ef84903741e4d2105b47e6a Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 9 Nov 2018 08:33:43 -0500 Subject: [PATCH 25/34] Crash fix --- core/src/io/anuke/mindustry/input/MobileInput.java | 2 +- core/src/io/anuke/mindustry/world/blocks/units/MechPad.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/io/anuke/mindustry/input/MobileInput.java b/core/src/io/anuke/mindustry/input/MobileInput.java index 97ad3d4a43..ca61675359 100644 --- a/core/src/io/anuke/mindustry/input/MobileInput.java +++ b/core/src/io/anuke/mindustry/input/MobileInput.java @@ -535,7 +535,7 @@ public class MobileInput extends InputHandler implements GestureListener{ if(mode == breaking){ Effects.effect(Fx.tapBlock, cursor.worldx(), cursor.worldy(), 1f); - }else{ + }else if(recipe != null){ Effects.effect(Fx.tapBlock, cursor.worldx() + recipe.result.offset(), cursor.worldy() + recipe.result.offset(), recipe.result.size); } 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 38cec398f8..e2c226a348 100644 --- a/core/src/io/anuke/mindustry/world/blocks/units/MechPad.java +++ b/core/src/io/anuke/mindustry/world/blocks/units/MechPad.java @@ -127,7 +127,7 @@ public class MechPad extends Block{ if(checkValidTap(tile, player)){ Call.onMechFactoryTap(player, tile); - }else if(player.isLocal && mobile){ + }else if(player.isLocal && mobile && !player.isDead()){ player.moveTarget = tile.entity; } } From a8cfc1ef7ad35bcd7c15179bd16e9b929c487900 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 9 Nov 2018 08:49:23 -0500 Subject: [PATCH 26/34] Mobile input tweak --- core/src/io/anuke/mindustry/input/MobileInput.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/io/anuke/mindustry/input/MobileInput.java b/core/src/io/anuke/mindustry/input/MobileInput.java index ca61675359..0197d323e0 100644 --- a/core/src/io/anuke/mindustry/input/MobileInput.java +++ b/core/src/io/anuke/mindustry/input/MobileInput.java @@ -430,7 +430,7 @@ public class MobileInput extends InputHandler implements GestureListener{ @Override public boolean touchDown(int screenX, int screenY, int pointer, int button){ - if(state.is(State.menu)) return false; + if(state.is(State.menu) || player.isDead()) return false; //get tile on cursor Tile cursor = tileAt(screenX, screenY); @@ -519,7 +519,7 @@ public class MobileInput extends InputHandler implements GestureListener{ @Override public boolean longPress(float x, float y){ - if(state.is(State.menu) || mode == none) return false; + if(state.is(State.menu) || mode == none || player.isDead()) return false; //get tile on cursor Tile cursor = tileAt(x, y); @@ -595,7 +595,7 @@ public class MobileInput extends InputHandler implements GestureListener{ @Override public void update(){ - if(state.is(State.menu)){ + if(state.is(State.menu) || player.isDead()){ selection.clear(); removals.clear(); mode = none; From 51a51833d4b0d99880101b3edff00a880e0d4189 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 9 Nov 2018 10:18:53 -0500 Subject: [PATCH 27/34] iOS build fix --- .gitignore | 1 + build.gradle | 3 ++- core/src/Mindustry.gwt.xml | 23 ----------------------- ios/Info.plist.xml | 2 ++ ios/robovm.properties | 2 +- ios/robovm.xml | 1 + 6 files changed, 7 insertions(+), 25 deletions(-) delete mode 100644 core/src/Mindustry.gwt.xml diff --git a/.gitignore b/.gitignore index e658c17679..cfa73a21a5 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ logs/ /core/assets/version.properties /core/assets/locales /ios/src/io/anuke/mindustry/gen/ +/core/src/io/anuke/mindustry/gen/ *.gif version.properties diff --git a/build.gradle b/build.gradle index d16c36a4a5..8bc3fca889 100644 --- a/build.gradle +++ b/build.gradle @@ -120,7 +120,7 @@ project(":ios") { } } - build.dependsOn(copyGen) + //build.dependsOn(copyGen) dependencies { compile project(":core") @@ -131,6 +131,7 @@ project(":ios") { compile "com.badlogicgames.gdx:gdx-backend-robovm:$gdxVersion" compile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-ios" compile "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-ios" + compileOnly project(":annotations") } } diff --git a/core/src/Mindustry.gwt.xml b/core/src/Mindustry.gwt.xml deleted file mode 100644 index 828369ac80..0000000000 --- a/core/src/Mindustry.gwt.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/ios/Info.plist.xml b/ios/Info.plist.xml index bc072235db..abd81b462c 100644 --- a/ios/Info.plist.xml +++ b/ios/Info.plist.xml @@ -34,6 +34,8 @@ UIRequiresFullScreen + LSSupportsOpeningDocumentsInPlace + NSPhotoLibraryAddUsageDescription Mindustry UIDeviceFamily diff --git a/ios/robovm.properties b/ios/robovm.properties index 24b6483340..f6b10f99b5 100644 --- a/ios/robovm.properties +++ b/ios/robovm.properties @@ -2,5 +2,5 @@ app.version=4.0 app.id=io.anuke.mindustry app.mainclass=io.anuke.mindustry.IOSLauncher app.executable=IOSLauncher -app.build=23 +app.build=25 app.name=Mindustry diff --git a/ios/robovm.xml b/ios/robovm.xml index 851c59da6f..efa0df89f0 100644 --- a/ios/robovm.xml +++ b/ios/robovm.xml @@ -18,6 +18,7 @@ + net.jpountz.lz4.** io.anuke.ucore.scene.** io.anuke.mindustry.gen.Call io.anuke.mindustry.net.** From 37d03aaebe1572df2d4378099973660bd23a9872 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 9 Nov 2018 13:12:04 -0500 Subject: [PATCH 28/34] iOS build update --- ios/robovm.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ios/robovm.properties b/ios/robovm.properties index f6b10f99b5..694b9dfa68 100644 --- a/ios/robovm.properties +++ b/ios/robovm.properties @@ -2,5 +2,5 @@ app.version=4.0 app.id=io.anuke.mindustry app.mainclass=io.anuke.mindustry.IOSLauncher app.executable=IOSLauncher -app.build=25 +app.build=27 app.name=Mindustry From 044390b4b4280e28ee5122d560cbbc1e3007a316 Mon Sep 17 00:00:00 2001 From: Timmeey86 Date: Sun, 11 Nov 2018 03:19:27 +0100 Subject: [PATCH 29/34] Sector -2 0 fix (#322) * Added a battle mission to Sector (-2,0) as otherwise no core would be spawned * Fixed a crash which occurred during test execution... ... and could maybe occur during any startup with bad timing * Added a new class for sector tests ... ... and added a test which makes sure that any predefined sector defines a spawn point * Added fix after applying test driven bugfixing --- .../io/anuke/mindustry/ai/BlockIndexer.java | 2 +- .../anuke/mindustry/maps/SectorPresets.java | 5 +- tests/src/test/java/SectorTests.java | 54 +++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 tests/src/test/java/SectorTests.java diff --git a/core/src/io/anuke/mindustry/ai/BlockIndexer.java b/core/src/io/anuke/mindustry/ai/BlockIndexer.java index 1213bd2721..04c5c04cb8 100644 --- a/core/src/io/anuke/mindustry/ai/BlockIndexer.java +++ b/core/src/io/anuke/mindustry/ai/BlockIndexer.java @@ -247,7 +247,7 @@ public class BlockIndexer{ for(int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++){ for(int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++){ Tile result = world.tile(x, y); - if(result.block().drops == null || !scanOres.contains(result.block().drops.item)) continue; + if( result == null || result.block().drops == null || !scanOres.contains(result.block().drops.item)) continue; itemSet.add(result.block().drops.item); } diff --git a/core/src/io/anuke/mindustry/maps/SectorPresets.java b/core/src/io/anuke/mindustry/maps/SectorPresets.java index 29540e1d5b..08fa7f1b19 100644 --- a/core/src/io/anuke/mindustry/maps/SectorPresets.java +++ b/core/src/io/anuke/mindustry/maps/SectorPresets.java @@ -56,7 +56,8 @@ public class SectorPresets{ Missions.blockRecipe(ProductionBlocks.waterExtractor), new ContentMission(Items.biomatter), Missions.blockRecipe(CraftingBlocks.biomatterCompressor), - new ContentMission(Liquids.oil) + new ContentMission(Liquids.oil), + new BattleMission() ), Array.with(Items.copper, Items.lead, Items.coal, Items.titanium))); } @@ -69,6 +70,8 @@ public class SectorPresets{ return presets.get(x, y); } + public GridMap getPresets() { return presets; } + private void add(SectorPreset preset){ presets.put(preset.x, preset.y, preset); orePresets.put(preset.x, preset.y, preset.ores); diff --git a/tests/src/test/java/SectorTests.java b/tests/src/test/java/SectorTests.java new file mode 100644 index 0000000000..3aae6cb305 --- /dev/null +++ b/tests/src/test/java/SectorTests.java @@ -0,0 +1,54 @@ +import com.badlogic.gdx.utils.Array; +import io.anuke.mindustry.Vars; +import io.anuke.mindustry.core.ContentLoader; +import io.anuke.mindustry.maps.SectorPresets; +import io.anuke.mindustry.maps.generation.Generation; +import io.anuke.mindustry.maps.missions.Mission; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +/** This class is responsible for testing predefined sectors. */ +public class SectorTests{ + + private SectorPresets presets; + private Generation fakeGen; + + @BeforeAll + static void initializeDependencies(){ + Vars.content = new ContentLoader(); + Vars.content.load(); + } + + @BeforeEach + void initTest(){ + this.presets = new SectorPresets(); + + // Fake away the Generation dependency + this.fakeGen = new Generation(null, null, 250, 250, null); + } + + /** Returns true if at least one mission provides a spawn point. */ + private boolean spawnPointIsDefined(Array missions){ + for(Mission mission : missions){ + if(mission.getSpawnPoints(this.fakeGen).size > 0){ + return true; + } + } + // No spawn point provided + return false; + } + + /** + * Makes sure that every predefined sector has a position for the player core defined. + * This is achieved by adding at least one mission which defines a spawn point. + */ + @Test + void test_sectorHasACore(){ + for(SectorPresets.SectorPreset preset : this.presets.getPresets().values()){ + assertTrue(spawnPointIsDefined(preset.missions), "Sector at (" + preset.x + "|" + preset.y + ") contains no missions which define a spawn point. Add a battle or wave mission."); + } + } +} From 075be1812339624f1137a78b9812c4bb45b55ff9 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 10 Nov 2018 21:26:11 -0500 Subject: [PATCH 30/34] Fixed wave button layout --- core/src/io/anuke/mindustry/ui/fragments/HudFragment.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java index 0341a51de1..7206e82db0 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java @@ -107,7 +107,7 @@ public class HudFragment extends Fragment{ Stack stack = new Stack(); TextButton waves = new TextButton(""); - Table btable = new Table().margin(14); + Table btable = new Table().margin(0); stack.add(waves); stack.add(btable); @@ -375,7 +375,7 @@ public class HudFragment extends Fragment{ (!state.mode.disableWaveTimer ? Bundles.format("text.wave.waiting", (int)(state.wavetime/60)) : Bundles.get("text.waiting"))) : - Bundles.format("text.mission.display", world.getSector().currentMission().displayString())).growX(); + Bundles.format("text.mission.display", world.getSector().currentMission().displayString())).growX().pad(8f); table.clicked(() -> { if(world.getSector() != null && world.getSector().currentMission().hasMessage()){ From 65a48b324daeb05ac536d8f616927952dc445db2 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 11 Nov 2018 10:32:00 -0500 Subject: [PATCH 31/34] Removed multithreading --- core/src/io/anuke/mindustry/core/Logic.java | 5 - .../io/anuke/mindustry/core/NetServer.java | 1 - .../anuke/mindustry/core/ThreadHandler.java | 164 +----------------- .../ui/dialogs/SettingsMenuDialog.java | 5 - .../mindustry/ui/fragments/HudFragment.java | 1 - 5 files changed, 8 insertions(+), 168 deletions(-) diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index f4aa97922b..471eba010e 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -172,7 +172,6 @@ public class Logic extends Module{ @Override public void update(){ - if(threads.isEnabled() && !threads.isOnThread()) return; if(Vars.control != null){ control.runUpdateLogic(); @@ -238,9 +237,5 @@ public class Logic extends Module{ checkGameOver(); } } - - if(threads.isEnabled()){ - netServer.update(); - } } } diff --git a/core/src/io/anuke/mindustry/core/NetServer.java b/core/src/io/anuke/mindustry/core/NetServer.java index 6fefd332ba..756da10efe 100644 --- a/core/src/io/anuke/mindustry/core/NetServer.java +++ b/core/src/io/anuke/mindustry/core/NetServer.java @@ -416,7 +416,6 @@ public class NetServer extends Module{ } public void update(){ - if(threads.isEnabled() && !threads.isOnThread()) return; if(!headless && !closing && Net.server() && state.is(State.menu)){ closing = true; diff --git a/core/src/io/anuke/mindustry/core/ThreadHandler.java b/core/src/io/anuke/mindustry/core/ThreadHandler.java index f439a6670e..6531acc2ac 100644 --- a/core/src/io/anuke/mindustry/core/ThreadHandler.java +++ b/core/src/io/anuke/mindustry/core/ThreadHandler.java @@ -1,80 +1,35 @@ package io.anuke.mindustry.core; import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.utils.Queue; import com.badlogic.gdx.utils.TimeUtils; import io.anuke.ucore.core.Settings; import io.anuke.ucore.core.Timers; -import io.anuke.ucore.util.Log; -import io.anuke.ucore.util.Threads; import io.anuke.ucore.util.Threads.ThreadInfoProvider; -import static io.anuke.mindustry.Vars.control; -import static io.anuke.mindustry.Vars.logic; - public class ThreadHandler implements ThreadInfoProvider{ - private final Queue toRun = new Queue<>(); - private Thread thread, graphicsThread; - private final Object updateLock = new Object(); - private float delta = 1f; - private float smoothDelta = 1f; - private long frame = 0, lastDeltaUpdate; - private float framesSinceUpdate; - private boolean enabled; - private boolean rendered = true; private long lastFrameTime; public ThreadHandler(){ - Threads.setThreadInfoProvider(this); - graphicsThread = Thread.currentThread(); - Timers.setDeltaProvider(() -> { - float result = isOnThread() ? delta : Gdx.graphics.getDeltaTime() * 60f; - return Math.min(Float.isNaN(result) ? 1f : result, 15f); + float result = Gdx.graphics.getDeltaTime() * 60f; + return Math.min(Float.isNaN(result) || Float.isInfinite(result) ? 1f : result, 15f); }); } public void run(Runnable r){ - if(enabled){ - synchronized(toRun){ - toRun.addLast(r); - } - }else{ - r.run(); - } + r.run(); } public void runGraphics(Runnable r){ - if(enabled){ - Gdx.app.postRunnable(r); - }else{ - r.run(); - } + r.run(); } public void runDelay(Runnable r){ - if(enabled){ - synchronized(toRun){ - toRun.addLast(r); - } - }else{ - Gdx.app.postRunnable(r); - } - } - - public int getTPS(){ - if(smoothDelta == 0f){ - return 60; - } - return (int) (60 / smoothDelta); + Gdx.app.postRunnable(r); } public long getFrameID(){ - return enabled ? frame : Gdx.graphics.getFrameId(); - } - - public float getFramesSinceUpdate(){ - return framesSinceUpdate; + return Gdx.graphics.getFrameId(); } public void handleBeginRender(){ @@ -95,119 +50,16 @@ public class ThreadHandler implements ThreadInfoProvider{ } } } - - if(!enabled) return; - - framesSinceUpdate += Timers.delta(); - - synchronized(updateLock){ - rendered = true; - updateLock.notify(); - } - } - - public boolean isEnabled(){ - return enabled; - } - - public void setEnabled(boolean enabled){ - if(enabled){ - logic.doUpdate = false; - Timers.runTask(2f, () -> { - if(thread != null){ - thread.interrupt(); - thread = null; - } - - thread = new Thread(this::runLogic); - thread.setDaemon(true); - thread.setName("Update Thread"); - thread.start(); - Log.info("Starting logic thread."); - - this.enabled = true; - }); - }else{ - this.enabled = false; - if(thread != null){ - thread.interrupt(); - thread = null; - } - Timers.runTask(2f, () -> { - logic.doUpdate = true; - }); - } - } - - public boolean doInterpolate(){ - return enabled && Gdx.graphics.getFramesPerSecond() - getTPS() > 20 && getTPS() < 30; - } - - public boolean isOnThread(){ - return Thread.currentThread() == thread; } @Override public boolean isOnLogicThread() { - return !enabled || Thread.currentThread() == thread; + return true; } @Override public boolean isOnGraphicsThread() { - return !enabled || Thread.currentThread() == graphicsThread; + return true; } - private void runLogic(){ - try{ - while(true){ - long time = TimeUtils.nanoTime(); - - while(true){ - Runnable r; - synchronized(toRun){ - if(toRun.size > 0){ - r = toRun.removeFirst(); - }else{ - break; - } - } - - r.run(); - } - - logic.doUpdate = true; - logic.update(); - logic.doUpdate = false; - - long elapsed = TimeUtils.nanosToMillis(TimeUtils.timeSinceNanos(time)); - long target = (long) ((1000) / 60f); - - if(elapsed < target){ - Thread.sleep(target - elapsed); - } - - synchronized(updateLock){ - while(!rendered){ - updateLock.wait(); - } - rendered = false; - } - - long actuallyElapsed = TimeUtils.nanosToMillis(TimeUtils.timeSinceNanos(time)); - delta = Math.max(actuallyElapsed, target) / 1000f * 60f; - - if(TimeUtils.timeSinceMillis(lastDeltaUpdate) > 1000){ - lastDeltaUpdate = TimeUtils.millis(); - smoothDelta = delta; - } - - frame++; - framesSinceUpdate = 0; - } - }catch(InterruptedException ex){ - Log.info("Stopping logic thread."); - }catch(Throwable ex){ - control.setError(ex); - } - } } diff --git a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java index 1c0f04abc9..a8931f70a7 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -190,11 +190,6 @@ public class SettingsMenuDialog extends SettingsDialog{ }); graphics.sliderPref("fpscap", 125, 5, 125, 5, s -> (s > 120 ? Bundles.get("setting.fpscap.none") : Bundles.format("setting.fpscap.text", s))); - graphics.checkPref("multithread", mobile, threads::setEnabled); - - if(Settings.getBool("multithread")){ - threads.setEnabled(true); - } if(!mobile){ graphics.checkPref("vsync", true, b -> Gdx.graphics.setVSync(b)); diff --git a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java index 7206e82db0..b2deb85ce9 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java @@ -126,7 +126,6 @@ public class HudFragment extends Fragment{ IntFormat tps = new IntFormat("text.tps"); IntFormat ping = new IntFormat("text.ping"); t.label(() -> fps.get(Gdx.graphics.getFramesPerSecond())).padRight(10); - t.label(() -> tps.get(threads.getTPS())).visible(() -> threads.isEnabled()); t.row(); if(Net.hasClient()){ t.label(() -> ping.get(Net.getPing())).visible(Net::client).colspan(2); From ece3f968671753b03167a40f75495a585eb3beaa Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 11 Nov 2018 10:50:33 -0500 Subject: [PATCH 32/34] Fixed net errors not being displayed properly --- core/assets/bundles/bundle.properties | 2 +- core/src/io/anuke/mindustry/net/Net.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index d4d20529e8..0bb62bbc96 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -263,7 +263,7 @@ text.mapeditor = Map Editor text.donate = Donate text.connectfail = [crimson]Failed to connect to server\:\n\n[accent]{0} -text.error.unreachable = Server unreachable. +text.error.unreachable = Server unreachable.\nIs the address spelled correctly? text.error.invalidaddress = Invalid address. text.error.timedout = Timed out!\nMake sure the host has port forwarding set up, and that the address is correct! text.error.mismatch = Packet error:\npossible client/server version mismatch.\nMake sure you and the host have the latest version of Mindustry! diff --git a/core/src/io/anuke/mindustry/net/Net.java b/core/src/io/anuke/mindustry/net/Net.java index 78941f012f..4bd10f57fd 100644 --- a/core/src/io/anuke/mindustry/net/Net.java +++ b/core/src/io/anuke/mindustry/net/Net.java @@ -59,7 +59,7 @@ public class Net{ } String error = t.getMessage() == null ? "" : t.getMessage().toLowerCase(); - String type = error.getClass().toString().toLowerCase(); + String type = t.getClass().toString().toLowerCase(); if(error.equals("mismatch")){ error = Bundles.get("text.error.mismatch"); From 2d1a97e04228bff050767a1efa02afbb54da8c3d Mon Sep 17 00:00:00 2001 From: Anuken Date: Sun, 11 Nov 2018 11:12:54 -0500 Subject: [PATCH 33/34] Removed unnecessary synchronized() blocks --- .../io/anuke/mindustry/core/NetClient.java | 12 +- .../io/anuke/mindustry/entities/Player.java | 70 +++++------ .../anuke/mindustry/entities/TileEntity.java | 34 +++-- .../entities/traits/BuilderTrait.java | 87 ++++++------- .../mindustry/entities/units/types/Drone.java | 17 ++- .../mindustry/graphics/BlockRenderer.java | 68 +++++----- .../mindustry/graphics/MinimapRenderer.java | 30 ++--- .../mindustry/graphics/OverlayRenderer.java | 70 +++++------ .../io/anuke/mindustry/graphics/Trail.java | 6 +- core/src/io/anuke/mindustry/world/Tile.java | 116 ++++++++---------- 10 files changed, 232 insertions(+), 278 deletions(-) diff --git a/core/src/io/anuke/mindustry/core/NetClient.java b/core/src/io/anuke/mindustry/core/NetClient.java index 91b52c1cdf..12a644687d 100644 --- a/core/src/io/anuke/mindustry/core/NetClient.java +++ b/core/src/io/anuke/mindustry/core/NetClient.java @@ -399,11 +399,11 @@ public class NetClient extends Module{ quiet = true; } - public synchronized void addRemovedEntity(int id){ + public void addRemovedEntity(int id){ removed.add(id); } - public synchronized boolean isEntityUsed(int id){ + public boolean isEntityUsed(int id){ return removed.contains(id); } @@ -414,11 +414,9 @@ public class NetClient extends Module{ BuildRequest[] requests; - synchronized(player.getPlaceQueue()){ - requests = new BuildRequest[player.getPlaceQueue().size]; - for(int i = 0; i < requests.length; i++){ - requests[i] = player.getPlaceQueue().get(i); - } + requests = new BuildRequest[player.getPlaceQueue().size]; + for(int i = 0; i < requests.length; i++){ + requests[i] = player.getPlaceQueue().get(i); } Call.onClientShapshot(lastSent++, TimeUtils.millis(), player.x, player.y, diff --git a/core/src/io/anuke/mindustry/entities/Player.java b/core/src/io/anuke/mindustry/entities/Player.java index 8e4dc2f682..73a4c46b70 100644 --- a/core/src/io/anuke/mindustry/entities/Player.java +++ b/core/src/io/anuke/mindustry/entities/Player.java @@ -70,7 +70,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra public TargetTrait moveTarget; private float walktime; - private Queue placeQueue = new ThreadQueue<>(); + private Queue placeQueue = new Queue<>(); private Tile mining; private CarriableTrait carrying; private Trail trail = new Trail(12); @@ -421,55 +421,53 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra /**Draw all current build requests. Does not draw the beam effect, only the positions.*/ public void drawBuildRequests(){ - synchronized(getPlaceQueue()){ - for(BuildRequest request : getPlaceQueue()){ - if(getCurrentRequest() == request) continue; + for(BuildRequest request : getPlaceQueue()){ + if(getCurrentRequest() == request) continue; - if(request.breaking){ - Block block = world.tile(request.x, request.y).target().block(); + if(request.breaking){ + Block block = world.tile(request.x, request.y).target().block(); - //draw removal request - Lines.stroke(2f); + //draw removal request + Lines.stroke(2f); - Draw.color(Palette.removeBack); + Draw.color(Palette.removeBack); - float rad = Mathf.absin(Timers.time(), 7f, 1f) + block.size * tilesize / 2f - 1; + float rad = Mathf.absin(Timers.time(), 7f, 1f) + block.size * tilesize / 2f - 1; - Lines.square( - request.x * tilesize + block.offset(), - request.y * tilesize + block.offset() - 1, - rad); + Lines.square( + request.x * tilesize + block.offset(), + request.y * tilesize + block.offset() - 1, + rad); - Draw.color(Palette.remove); + Draw.color(Palette.remove); - Lines.square( - request.x * tilesize + block.offset(), - request.y * tilesize + block.offset(), - rad); - }else{ - //draw place request - Lines.stroke(2f); + Lines.square( + request.x * tilesize + block.offset(), + request.y * tilesize + block.offset(), + rad); + }else{ + //draw place request + Lines.stroke(2f); - Draw.color(Palette.accentBack); + Draw.color(Palette.accentBack); - float rad = Mathf.absin(Timers.time(), 7f, 1f) - 2f + request.recipe.result.size * tilesize / 2f; + float rad = Mathf.absin(Timers.time(), 7f, 1f) - 2f + request.recipe.result.size * tilesize / 2f; - Lines.square( - request.x * tilesize + request.recipe.result.offset(), - request.y * tilesize + request.recipe.result.offset() - 1, - rad); + Lines.square( + request.x * tilesize + request.recipe.result.offset(), + request.y * tilesize + request.recipe.result.offset() - 1, + rad); - Draw.color(Palette.accent); + Draw.color(Palette.accent); - Lines.square( - request.x * tilesize + request.recipe.result.offset(), - request.y * tilesize + request.recipe.result.offset(), - rad); - } + Lines.square( + request.x * tilesize + request.recipe.result.offset(), + request.y * tilesize + request.recipe.result.offset(), + rad); } - - Draw.reset(); } + + Draw.reset(); } //endregion diff --git a/core/src/io/anuke/mindustry/entities/TileEntity.java b/core/src/io/anuke/mindustry/entities/TileEntity.java index 910d36d10f..10aec5f47b 100644 --- a/core/src/io/anuke/mindustry/entities/TileEntity.java +++ b/core/src/io/anuke/mindustry/entities/TileEntity.java @@ -259,27 +259,25 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{ @Override public void update(){ - synchronized(Tile.tileSetLock){ - //TODO better smoke effect, this one is awful - if(health != 0 && health < tile.block().health && !(tile.block() instanceof Wall) && - Mathf.chance(0.009f * Timers.delta() * (1f - health / tile.block().health))){ + //TODO better smoke effect, this one is awful + if(health != 0 && health < tile.block().health && !(tile.block() instanceof Wall) && + Mathf.chance(0.009f * Timers.delta() * (1f - health / tile.block().health))){ - Effects.effect(Fx.smoke, x + Mathf.range(4), y + Mathf.range(4)); - } + Effects.effect(Fx.smoke, x + Mathf.range(4), y + Mathf.range(4)); + } - timeScaleDuration -= Timers.delta(); - if(timeScaleDuration <= 0f || !tile.block().canOverdrive){ - timeScale = 1f; - } + timeScaleDuration -= Timers.delta(); + if(timeScaleDuration <= 0f || !tile.block().canOverdrive){ + timeScale = 1f; + } - if(health <= 0){ - onDeath(); - } - Block previous = tile.block(); - tile.block().update(tile); - if(tile.block() == previous && cons != null){ - cons.update(this); - } + if(health <= 0){ + onDeath(); + } + Block previous = tile.block(); + tile.block().update(tile); + if(tile.block() == previous && cons != null){ + cons.update(this); } } diff --git a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java index a086bea466..da6332dcaf 100644 --- a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java @@ -84,30 +84,28 @@ public interface BuilderTrait extends Entity{ } default void readBuilding(DataInput input, boolean applyChanges) throws IOException{ - synchronized(getPlaceQueue()){ - if(applyChanges) getPlaceQueue().clear(); + if(applyChanges) getPlaceQueue().clear(); - byte type = input.readByte(); - if(type != -1){ - int position = input.readInt(); - float progress = input.readFloat(); - BuildRequest request; + byte type = input.readByte(); + if(type != -1){ + int position = input.readInt(); + float progress = input.readFloat(); + BuildRequest request; - if(type == 1){ //remove - request = new BuildRequest(position % world.width(), position / world.width()); - }else{ //place - byte recipe = input.readByte(); - byte rotation = input.readByte(); - request = new BuildRequest(position % world.width(), position / world.width(), rotation, content.recipe(recipe)); - } + if(type == 1){ //remove + request = new BuildRequest(position % world.width(), position / world.width()); + }else{ //place + byte recipe = input.readByte(); + byte rotation = input.readByte(); + request = new BuildRequest(position % world.width(), position / world.width(), rotation, content.recipe(recipe)); + } - request.progress = progress; + request.progress = progress; - if(applyChanges){ - getPlaceQueue().addLast(request); - }else if(isBuilding()){ - getCurrentRequest().progress = progress; - } + if(applyChanges){ + getPlaceQueue().addLast(request); + }else if(isBuilding()){ + getCurrentRequest().progress = progress; } } } @@ -122,13 +120,11 @@ public interface BuilderTrait extends Entity{ * Otherwise, a new place request is added to the queue. */ default void replaceBuilding(int x, int y, int rotation, Recipe recipe){ - synchronized(getPlaceQueue()){ - for(BuildRequest request : getPlaceQueue()){ - if(request.x == x && request.y == y){ - clearBuilding(); - addBuildRequest(request); - return; - } + for(BuildRequest request : getPlaceQueue()){ + if(request.x == x && request.y == y){ + clearBuilding(); + addBuildRequest(request); + return; } } @@ -142,18 +138,16 @@ public interface BuilderTrait extends Entity{ /**Add another build requests to the tail of the queue, if it doesn't exist there yet.*/ default void addBuildRequest(BuildRequest place){ - synchronized(getPlaceQueue()){ - for(BuildRequest request : getPlaceQueue()){ - if(request.x == place.x && request.y == place.y){ - return; - } + for(BuildRequest request : getPlaceQueue()){ + if(request.x == place.x && request.y == place.y){ + return; } - Tile tile = world.tile(place.x, place.y); - if(tile != null && tile.entity instanceof BuildEntity){ - place.progress = tile.entity().progress; - } - getPlaceQueue().addLast(place); } + Tile tile = world.tile(place.x, place.y); + if(tile != null && tile.entity instanceof BuildEntity){ + place.progress = tile.entity().progress; + } + getPlaceQueue().addLast(place); } /** @@ -161,9 +155,7 @@ public interface BuilderTrait extends Entity{ * May return null. */ default BuildRequest getCurrentRequest(){ - synchronized(getPlaceQueue()){ - return getPlaceQueue().size == 0 ? null : getPlaceQueue().first(); - } + return getPlaceQueue().size == 0 ? null : getPlaceQueue().first(); } /** @@ -275,18 +267,15 @@ public interface BuilderTrait extends Entity{ /**Draw placement effects for an entity. This includes mining*/ default void drawBuilding(Unit unit){ BuildRequest request; - - synchronized(getPlaceQueue()){ - if(!isBuilding()){ - if(getMineTile() != null){ - drawMining(unit); - } - return; + if(!isBuilding()){ + if(getMineTile() != null){ + drawMining(unit); } - - request = getCurrentRequest(); + return; } + request = getCurrentRequest(); + Tile tile = world.tile(request.x, request.y); if(unit.distanceTo(tile) > placeDistance){ diff --git a/core/src/io/anuke/mindustry/entities/units/types/Drone.java b/core/src/io/anuke/mindustry/entities/units/types/Drone.java index d5c3d283f0..35c254ce2a 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/Drone.java +++ b/core/src/io/anuke/mindustry/entities/units/types/Drone.java @@ -40,12 +40,11 @@ import static io.anuke.mindustry.Vars.unitGroups; import static io.anuke.mindustry.Vars.world; public class Drone extends FlyingUnit implements BuilderTrait{ - protected static float discoverRange = 120f; protected static int timerRepairEffect = timerIndex++; protected Item targetItem; protected Tile mineTile; - protected Queue placeQueue = new ThreadQueue<>(); + protected Queue placeQueue = new Queue<>(); protected boolean isBreaking; public final UnitState @@ -250,14 +249,12 @@ public class Drone extends FlyingUnit implements BuilderTrait{ for(BaseUnit unit : group.all()){ if(unit instanceof Drone){ Drone drone = (Drone)unit; - synchronized(drone.getPlaceQueue()){ - if(drone.isBuilding()){ - //stop building if opposite building begins. - BuildRequest req = drone.getCurrentRequest(); - if(req.breaking != event.breaking && req.x == event.tile.x && req.y == event.tile.y){ - drone.clearBuilding(); - drone.setState(drone.repair); - } + if(drone.isBuilding()){ + //stop building if opposite building begins. + BuildRequest req = drone.getCurrentRequest(); + if(req.breaking != event.breaking && req.x == event.tile.x && req.y == event.tile.y){ + drone.clearBuilding(); + drone.setState(drone.repair); } } diff --git a/core/src/io/anuke/mindustry/graphics/BlockRenderer.java b/core/src/io/anuke/mindustry/graphics/BlockRenderer.java index 33ac40ce03..2b34127e2a 100644 --- a/core/src/io/anuke/mindustry/graphics/BlockRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/BlockRenderer.java @@ -106,32 +106,29 @@ public class BlockRenderer{ for(int x = minx; x <= maxx; x++){ for(int y = miny; y <= maxy; y++){ boolean expanded = (Math.abs(x - avgx) > rangex || Math.abs(y - avgy) > rangey); + Tile tile = world.rawTile(x, y); - synchronized(Tile.tileSetLock){ - Tile tile = world.rawTile(x, y); + if(tile != null){ + Block block = tile.block(); + Team team = tile.getTeam(); - if(tile != null){ - Block block = tile.block(); - Team team = tile.getTeam(); + if(!expanded && block != Blocks.air && world.isAccessible(x, y)){ + tile.block().drawShadow(tile); + } - if(!expanded && block != Blocks.air && world.isAccessible(x, y)){ - tile.block().drawShadow(tile); + if(block != Blocks.air){ + if(!expanded){ + addRequest(tile, Layer.block); + teamChecks.add(team.ordinal()); } - if(block != Blocks.air){ - if(!expanded){ - addRequest(tile, Layer.block); - teamChecks.add(team.ordinal()); + if(block.expanded || !expanded){ + if(block.layer != null && block.isLayer(tile)){ + addRequest(tile, block.layer); } - if(block.expanded || !expanded){ - if(block.layer != null && block.isLayer(tile)){ - addRequest(tile, block.layer); - } - - if(block.layer2 != null && block.isLayer2(tile)){ - addRequest(tile, block.layer2); - } + if(block.layer2 != null && block.isLayer2(tile)){ + addRequest(tile, block.layer2); } } } @@ -171,16 +168,14 @@ public class BlockRenderer{ layerBegins(req.layer); } - synchronized(Tile.tileSetLock){ - Block block = req.tile.block(); + Block block = req.tile.block(); - if(req.layer == Layer.block){ - block.draw(req.tile); - }else if(req.layer == block.layer){ - block.drawLayer(req.tile); - }else if(req.layer == block.layer2){ - block.drawLayer2(req.tile); - } + if(req.layer == Layer.block){ + block.draw(req.tile); + }else if(req.layer == block.layer){ + block.drawLayer(req.tile); + }else if(req.layer == block.layer2){ + block.drawLayer2(req.tile); } lastLayer = req.layer; @@ -199,17 +194,16 @@ public class BlockRenderer{ BlockRequest req = requests.get(index); if(req.tile.getTeam() != team) continue; - synchronized(Tile.tileSetLock){ - Block block = req.tile.block(); + Block block = req.tile.block(); - if(req.layer == Layer.block){ - block.draw(req.tile); - }else if(req.layer == block.layer){ - block.drawLayer(req.tile); - }else if(req.layer == block.layer2){ - block.drawLayer2(req.tile); - } + if(req.layer == Layer.block){ + block.draw(req.tile); + }else if(req.layer == block.layer){ + block.drawLayer(req.tile); + }else if(req.layer == block.layer2){ + block.drawLayer2(req.tile); } + } } diff --git a/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java b/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java index dab7016c99..917bf12365 100644 --- a/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java @@ -74,20 +74,18 @@ public class MinimapRenderer implements Disposable{ dx = Mathf.clamp(dx, sz, world.width() - sz); dy = Mathf.clamp(dy, sz, world.height() - sz); - synchronized(units){ - rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize); - Graphics.beginClip(x, y, w, h); + rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize); + Graphics.beginClip(x, y, w, h); - for(Unit unit : units){ - float rx = (unit.x - rect.x) / rect.width * w, ry = (unit.y - rect.y) / rect.width * h; - Draw.color(unit.getTeam().color); - Draw.rect("white", x + rx, y + ry, w / (sz * 2), h / (sz * 2)); - } - - Draw.color(); - - Graphics.endClip(); + for(Unit unit : units){ + float rx = (unit.x - rect.x) / rect.width * w, ry = (unit.y - rect.y) / rect.width * h; + Draw.color(unit.getTeam().color); + Draw.rect("white", x + rx, y + ry, w / (sz * 2), h / (sz * 2)); } + + Draw.color(); + + Graphics.endClip(); } public TextureRegion getRegion(){ @@ -128,11 +126,9 @@ public class MinimapRenderer implements Disposable{ dx = Mathf.clamp(dx, sz, world.width() - sz); dy = Mathf.clamp(dy, sz, world.height() - sz); - synchronized(units){ - rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize); - units.clear(); - Units.getNearby(rect, units::add); - } + rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize); + units.clear(); + Units.getNearby(rect, units::add); } private int colorFor(Tile tile){ diff --git a/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java b/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java index f9863fa670..51d65dfbb8 100644 --- a/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java @@ -53,10 +53,7 @@ public class OverlayRenderer{ //draw config selected block if(input.frag.config.isShown()){ Tile tile = input.frag.config.getSelectedTile(); - - synchronized(Tile.tileSetLock){ - tile.block().drawConfigure(tile); - } + tile.block().drawConfigure(tile); } input.drawTop(); @@ -113,53 +110,52 @@ public class OverlayRenderer{ Draw.reset(); } - synchronized(Tile.tileSetLock){ - Block block = target.block(); - TileEntity entity = target.entity; + Block block = target.block(); + TileEntity entity = target.entity; - if(entity != null){ - int[] values = {0, 0}; - boolean[] doDraw = {false}; + if(entity != null){ + int[] values = {0, 0}; + boolean[] doDraw = {false}; - Runnable drawbars = () -> { - for(BlockBar bar : block.bars.list()){ - float offset = Mathf.sign(bar.top) * (block.size / 2f * tilesize + 2f + (bar.top ? values[0] : values[1])); + Runnable drawbars = () -> { + for(BlockBar bar : block.bars.list()){ + float offset = Mathf.sign(bar.top) * (block.size / 2f * tilesize + 2f + (bar.top ? values[0] : values[1])); - float value = bar.value.get(target); + float value = bar.value.get(target); - if(MathUtils.isEqual(value, -1f)) continue; + if(MathUtils.isEqual(value, -1f)) continue; - if(doDraw[0]){ - drawBar(bar.type.color, target.drawx(), target.drawy() + offset, value); - } - - if(bar.top) - values[0]++; - else - values[1]++; + if(doDraw[0]){ + drawBar(bar.type.color, target.drawx(), target.drawy() + offset, value); } - }; - drawbars.run(); - - if(values[0] > 0){ - drawEncloser(target.drawx(), target.drawy() + block.size * tilesize / 2f + 2f, values[0]); + if(bar.top) + values[0]++; + else + values[1]++; } + }; - if(values[1] > 0){ - drawEncloser(target.drawx(), target.drawy() - block.size * tilesize / 2f - 2f - values[1], values[1]); - } + drawbars.run(); - doDraw[0] = true; - values[0] = 0; - values[1] = 1; - - drawbars.run(); + if(values[0] > 0){ + drawEncloser(target.drawx(), target.drawy() + block.size * tilesize / 2f + 2f, values[0]); } + if(values[1] > 0){ + drawEncloser(target.drawx(), target.drawy() - block.size * tilesize / 2f - 2f - values[1], values[1]); + } - target.block().drawSelect(target); + doDraw[0] = true; + values[0] = 0; + values[1] = 1; + + drawbars.run(); } + + + target.block().drawSelect(target); + } } diff --git a/core/src/io/anuke/mindustry/graphics/Trail.java b/core/src/io/anuke/mindustry/graphics/Trail.java index 1d5f3fade1..bd34dc7002 100644 --- a/core/src/io/anuke/mindustry/graphics/Trail.java +++ b/core/src/io/anuke/mindustry/graphics/Trail.java @@ -22,7 +22,7 @@ public class Trail{ this.length = length; } - public synchronized void update(float curx, float cury){ + public void update(float curx, float cury){ if(Vector2.dst(curx, cury, lastX, lastY) >= maxJump){ points.clear(); } @@ -39,11 +39,11 @@ public class Trail{ lastY = cury; } - public synchronized void clear(){ + public void clear(){ points.clear(); } - public synchronized void draw(Color color, float stroke){ + public void draw(Color color, float stroke){ Draw.color(color); for(int i = 0; i < points.size - 2; i += 2){ diff --git a/core/src/io/anuke/mindustry/world/Tile.java b/core/src/io/anuke/mindustry/world/Tile.java index f6ea510048..b75b89e433 100644 --- a/core/src/io/anuke/mindustry/world/Tile.java +++ b/core/src/io/anuke/mindustry/world/Tile.java @@ -22,7 +22,6 @@ import static io.anuke.mindustry.Vars.*; public class Tile implements PosTrait, TargetTrait{ - public static final Object tileSetLock = new Object(); /** * The coordinates of the core tile this is linked to, in the form of two bytes packed into one. * This is relative to the block it is linked to; negate coords to find the link. @@ -147,33 +146,27 @@ public class Tile implements PosTrait, TargetTrait{ } public void setBlock(Block type, int rotation){ - synchronized(tileSetLock){ - preChanged(); - if(rotation < 0) rotation = (-rotation + 2); - this.wall = type; - this.link = 0; - setRotation((byte) (rotation % 4)); - changed(); - } + preChanged(); + if(rotation < 0) rotation = (-rotation + 2); + this.wall = type; + this.link = 0; + setRotation((byte) (rotation % 4)); + changed(); } public void setBlock(Block type, Team team){ - synchronized(tileSetLock){ - preChanged(); - this.wall = type; - this.team = (byte)team.ordinal(); - this.link = 0; - changed(); - } + preChanged(); + this.wall = type; + this.team = (byte)team.ordinal(); + this.link = 0; + changed(); } public void setBlock(Block type){ - synchronized(tileSetLock){ - preChanged(); - this.wall = type; - this.link = 0; - changed(); - } + preChanged(); + this.wall = type; + this.link = 0; + changed(); } public void setFloor(Floor type){ @@ -270,7 +263,7 @@ public class Tile implements PosTrait, TargetTrait{ * Returns the list of all tiles linked to this multiblock, or an empty array if it's not a multiblock. * This array contains all linked tiles, including this tile itself. */ - public synchronized Array getLinkedTiles(Array tmpArray){ + public Array getLinkedTiles(Array tmpArray){ Block block = block(); tmpArray.clear(); if(block.isMultiblock()){ @@ -292,7 +285,7 @@ public class Tile implements PosTrait, TargetTrait{ * Returns the list of all tiles linked to this multiblock if it were this block, or an empty array if it's not a multiblock. * This array contains all linked tiles, including this tile itself. */ - public synchronized Array getLinkedTilesAs(Block block, Array tmpArray){ + public Array getLinkedTilesAs(Block block, Array tmpArray){ tmpArray.clear(); if(block.isMultiblock()){ int offsetx = -(block.size - 1) / 2; @@ -394,52 +387,47 @@ public class Tile implements PosTrait, TargetTrait{ } private void preChanged(){ - synchronized(tileSetLock){ - block().removed(this); - if(entity != null){ - entity.removeFromProximity(); - } - team = 0; + block().removed(this); + if(entity != null){ + entity.removeFromProximity(); } + team = 0; } private void changed(){ - - synchronized(tileSetLock){ - if(entity != null){ - entity.remove(); - entity = null; - } - - Block block = block(); - - if(block.hasEntity()){ - entity = block.newEntity().init(this, block.update); - entity.cons = new ConsumeModule(); - if(block.hasItems) entity.items = new ItemModule(); - if(block.hasLiquids) entity.liquids = new LiquidModule(); - if(block.hasPower){ - entity.power = new PowerModule(); - entity.power.graph.add(this); - } - - if(!world.isGenerating()){ - entity.updateProximity(); - } - }else if(!(block instanceof BlockPart) && !world.isGenerating()){ - //since the entity won't update proximity for us, update proximity for all nearby tiles manually - for(GridPoint2 p : Geometry.d4){ - Tile tile = world.tile(x + p.x, y + p.y); - if(tile != null){ - tile = tile.target(); - tile.block().onProximityUpdate(tile); - } - } - } - - updateOcclusion(); + if(entity != null){ + entity.remove(); + entity = null; } + Block block = block(); + + if(block.hasEntity()){ + entity = block.newEntity().init(this, block.update); + entity.cons = new ConsumeModule(); + if(block.hasItems) entity.items = new ItemModule(); + if(block.hasLiquids) entity.liquids = new LiquidModule(); + if(block.hasPower){ + entity.power = new PowerModule(); + entity.power.graph.add(this); + } + + if(!world.isGenerating()){ + entity.updateProximity(); + } + }else if(!(block instanceof BlockPart) && !world.isGenerating()){ + //since the entity won't update proximity for us, update proximity for all nearby tiles manually + for(GridPoint2 p : Geometry.d4){ + Tile tile = world.tile(x + p.x, y + p.y); + if(tile != null){ + tile = tile.target(); + tile.block().onProximityUpdate(tile); + } + } + } + + updateOcclusion(); + world.notifyChanged(this); } From c9777af91c222c2b9a2f12feffa833aa239eeef5 Mon Sep 17 00:00:00 2001 From: Timmeey86 Date: Sun, 11 Nov 2018 19:03:15 +0100 Subject: [PATCH 34/34] Added Unlocks menu button to Escape menu on desktop (#324) --- core/src/io/anuke/mindustry/core/UI.java | 2 +- core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index 8120e2212a..1fb684cdb2 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -155,6 +155,7 @@ public class UI extends SceneModule{ load = new LoadDialog(); levels = new CustomGameDialog(); language = new LanguageDialog(); + unlocks = new UnlocksDialog(); settings = new SettingsMenuDialog(); host = new HostDialog(); paused = new PausedDialog(); @@ -165,7 +166,6 @@ public class UI extends SceneModule{ traces = new TraceDialog(); maps = new MapsDialog(); localplayers = new LocalPlayerDialog(); - unlocks = new UnlocksDialog(); content = new ContentInfoDialog(); sectors = new SectorsDialog(); missions = new MissionDialog(); diff --git a/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java index 26a90e46bc..728e94bae1 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/PausedDialog.java @@ -57,6 +57,9 @@ public class PausedDialog extends FloatingDialog{ hide(); }); + content().row(); + content().addButton("$text.unlocks", ui.unlocks::show); + content().row(); content().addButton("$text.settings", ui.settings::show);