Compare commits

..

104 Commits
v121 ... v121.3

Author SHA1 Message Date
Anuken
5ab090f28d Merge remote-tracking branch 'origin/master' 2020-12-14 22:56:06 -05:00
Anuken
8a5bd7571e 121.3 2020-12-14 22:55:58 -05:00
Fernando
3cb0cc9a3c Brazil is under maintenance (#3898)
We will be back later
2020-12-14 20:07:02 -05:00
Anuken
ff93c21269 Merge remote-tracking branch 'origin/master' 2020-12-14 16:31:01 -05:00
Anuken
0512e54df5 Merge remote-tracking branch 'origin/master' 2020-12-14 13:42:52 -05:00
Anuken
cec1eb5608 Fixed jitpack build error 2020-12-14 13:42:48 -05:00
L0615T1C5-216AC-9437
1c6ebd3f6a retire CN from v5 Mindustry (#3977) 2020-12-14 13:31:41 -05:00
Anuken
16f7a8e9d2 Merge remote-tracking branch 'origin/master' 2020-12-14 13:29:59 -05:00
Anuken
889c53dc1b Update SERVERLIST.md 2020-12-14 13:26:42 -05:00
Anuken
f4d0dfd0da Less junction capacity (again) 2020-12-14 10:36:37 -05:00
Skat
aee5d46dfa Code formatting (#3904) 2020-12-13 23:56:13 -05:00
alex
6286b0b275 Add ALEX v6 servers to servers_v6.json (#3927) 2020-12-13 23:52:15 -05:00
Sharlotte
5223a89bf1 Update bundle_ko.properties (#3953)
fix some miss-translation
add translated values
2020-12-13 23:47:00 -05:00
YellOw139
5b11dbc085 [Bundle][RO] Translation Update (#3957)
This PR was tested in-game and is _**ready to merge at any time**_ (unless marked as draft).

Changelog:
- New strings/changes up to commit 98c4ee6e74
- Typo fixes & various other improvements
2020-12-13 23:46:50 -05:00
GamyGamer
df1f8b8bb4 Update bundle_pl.properties (#3964)
Added missing lines and fixed typo
2020-12-13 23:46:39 -05:00
DeltaNedas
ffa7256e5a add ContentInitEvent (#3951)
* add ContentInit(ialized)Event

* a

* a
2020-12-13 23:43:27 -05:00
Anuken
bbf84185cc Fixed #3973 2020-12-13 23:40:06 -05:00
Anuken
901c23f295 Fixed #3969 2020-12-13 18:01:22 -05:00
Anuken
1c8d368d3b Merge remote-tracking branch 'origin/master' 2020-12-13 16:28:32 -05:00
Anuken
37ebae20d7 Removed tools.jar 2020-12-13 16:28:29 -05:00
Anuken
e25f0c6ae2 Merge pull request #3967 from DeltaNedas/version
disallow descriptions after mod version
2020-12-13 16:26:23 -05:00
Anuken
484b480076 Fixed #3968 2020-12-13 16:25:36 -05:00
DeltaNedas
926497ba77 disallow descriptions after mod version 2020-12-13 19:30:21 +00:00
Anuken
ddd9f2259c Fixed #3960 2020-12-13 10:27:44 -05:00
Anuken
d6546a38c0 #3830 2020-12-12 18:49:24 -05:00
Anuken
d171048004 Merge pull request #3950 from Auswaschbar/master
Fix units aiming sidewards missing their aim
2020-12-12 16:47:01 -05:00
Karl-Robert Ernst
4aebba0a0c fix units aiming sidewards missing their aim 2020-12-12 22:11:19 +01:00
Anuken
8afb6006ce Merge pull request #3941 from DeltaNedas/public
make some proc stuff public
2020-12-12 13:27:22 -05:00
Anuken
d117eb249e Merge remote-tracking branch 'origin/master' 2020-12-12 13:26:34 -05:00
Anuken
768d14088a Fixed #3943 2020-12-12 13:26:30 -05:00
Anuken
86f16bfc94 Merge pull request #3934 from LottieVixen/fix-issue
fixed an error in global.js
2020-12-12 11:31:36 -05:00
Anuken
8fa6b76bf9 Fixed #3936 2020-12-12 11:14:17 -05:00
DeltaNedas
19af1a0cc8 make some proc stuff public 2020-12-12 15:57:43 +00:00
Charlotte Lily-Llaitchee Vixen
409d27e3df found more occurances of the error 2020-12-12 07:23:23 +00:00
Charlotte Lily-Llaitchee Vixen
d47abd4f83 fixed an error in global.js 2020-12-12 07:15:24 +00:00
Anuken
e6c4a6cf69 Fixed #3932 2020-12-11 23:52:43 -05:00
Anuken
7c80af85e3 Property cleanup 2020-12-11 19:28:03 -05:00
Anuken
6983f57459 circleTarget unit AI parameter 2020-12-11 18:54:03 -05:00
Anuken
adeeaa6e27 Merge remote-tracking branch 'origin/master' 2020-12-11 12:56:10 -05:00
Anuken
075e7cf5d8 Disabled poly spawns 2020-12-11 12:56:07 -05:00
Anuken
98c4ee6e74 Merge pull request #3855 from AFFalcons/patch-1
[QOL] Ability to Disable Weather Effects
2020-12-11 12:52:07 -05:00
Anuken
87f9a077ac Increase wave spacing by 10sec every sector defeat 2020-12-11 12:43:43 -05:00
Anuken
bc26d3ba7b Merge remote-tracking branch 'origin/master' 2020-12-11 11:48:27 -05:00
Anuken
daaea591e4 Implemented #3486 with some minor changes 2020-12-11 11:48:20 -05:00
Anuken
175d66ad72 Merge pull request #3843 from Nikolass1000/patch-6
Update achievements.vdf [PL]
2020-12-11 11:13:54 -05:00
Anuken
c444cbf623 Merge pull request #3908 from buthed010203/patch-2
Delete old bleeding edge builds on update
2020-12-11 10:52:19 -05:00
Anuken
c54f398063 Fixed Parallax not moving players serverside 2020-12-10 18:21:39 -05:00
Anuken
2d6db1583b Improved approach behavior in formations/logic 2020-12-10 12:51:07 -05:00
buthed010203
b3beb92557 fixed 2020-12-10 12:18:11 -05:00
buthed010203
0f8304674f now 100% less readable 2020-12-10 11:54:47 -05:00
buthed010203
3b3daf0e25 Delete old bleeding edge builds on update 2020-12-10 11:41:50 -05:00
Anuken
28e18332a0 Decreased junction item capacity 2020-12-10 09:58:09 -05:00
Anuken
dcc4764914 Merge remote-tracking branch 'origin/master' 2020-12-10 09:50:12 -05:00
Anuken
ee4ace1146 Fixed #3902 2020-12-10 09:50:06 -05:00
Anuken
1faffadcab Merge pull request #3905 from Quezler/patch-81
Prevent accelerator from blending with conveyors
2020-12-10 09:35:33 -05:00
Patrick 'Quezler' Mounier
2da7afc081 Update Accelerator.java 2020-12-10 12:15:29 +01:00
Patrick 'Quezler' Mounier
e5b341c63e Prevent accelerator from blending with conveyors 2020-12-10 12:14:57 +01:00
Anuken
a544888f16 cleanup 2020-12-09 20:20:22 -05:00
Anuken
57ad1d5366 Fixed #3899 2020-12-09 20:19:54 -05:00
Anuken
42d66d1136 Sector item system cleanup 2020-12-09 16:26:50 -05:00
Anuken
999cc9c651 Fixed #3890 2020-12-09 14:02:38 -05:00
Anuken
9537051590 Merge pull request #3836 from Nikolass1000/patch-5
Update polish bundle
2020-12-09 11:10:02 -05:00
Anuken
827372633d Merge pull request #3838 from YellOw139/patch-3
[Bundle][RO][Ready-for-Stable] Translation Update
2020-12-09 11:09:42 -05:00
Anuken
dcf0b15b2c Fixed #3888 2020-12-09 11:08:22 -05:00
Anuken
c93bc0e457 Fixed #3884 / Fixed #3881 / Fixed #3880 2020-12-09 10:49:26 -05:00
Anuken
1460a15942 Fixed #3874 2020-12-08 21:36:20 -05:00
Anuken
15a07a4a18 Merge remote-tracking branch 'origin/master' 2020-12-08 16:43:27 -05:00
Anuken
e07a203d56 Don't use mods for floor decoration 2020-12-08 16:43:23 -05:00
Anuken
cead92b2c7 Merge pull request #3865 from Ordoviz/master
Improve German translation
2020-12-08 14:31:26 -05:00
Anuken
8d4ab2d7fb Cleanup 2020-12-08 14:23:13 -05:00
Anuken
9bd2057237 Fixed #3871 2020-12-08 14:07:18 -05:00
Lennard Hofmann
5ec5f1aa93 Improve German translation 2020-12-08 17:09:37 +01:00
Anuken
5e10c9d416 Decreased slag viscosity 2020-12-08 10:13:08 -05:00
Matthew
881491d151 Requested Changes 2020-12-08 09:10:30 -06:00
Matthew
863159a5fe Init 2020-12-07 18:14:58 -06:00
Anuken
849943a0de Increased surge smelter item capacity 2020-12-07 18:57:59 -05:00
Anuken
b5abc23c9d Minor Fungal Pass tweaks 2020-12-07 16:27:25 -05:00
Anuken
c2b03a3fdc Merge remote-tracking branch 'origin/master' 2020-12-07 15:52:53 -05:00
Anuken
4e1d999838 Rounded up lancer requirements 2020-12-07 15:52:50 -05:00
Anuken
4af971776f Rounded up lancer requirements 2020-12-07 15:48:07 -05:00
Anuken
86d2788232 Merge pull request #3735 from Nikolass1000/patch-4
Fix for missing foreshadow description [PL]
2020-12-07 15:18:13 -05:00
Anuken
5654e3120d Logic constant optimizations / Display admins on top 2020-12-07 12:51:31 -05:00
Anuken
b4e7928622 Test fixes 2020-12-07 12:12:08 -05:00
Anuken
25125f5a9b Removed Tile#bc(), use Tile.build instead 2020-12-07 11:44:57 -05:00
Anuken
5d4b8a43e3 Merge remote-tracking branch 'origin/master' 2020-12-07 11:10:23 -05:00
Anuken
557cb1c532 Fixed #3834 / Fixed #3835 / Fixed #3837 2020-12-07 11:10:19 -05:00
Anuken
5594395ac1 Merge pull request #3840 from Quezler/patch-78
Fixes #3839
2020-12-07 10:58:26 -05:00
Nikolass1000
81b593c031 Update achievements.vdf 2020-12-07 14:30:08 +01:00
Patrick 'Quezler' Mounier
2a1ddf2573 Fixed #3839 2020-12-07 13:21:32 +01:00
YellOw139
fdb8da5767 [Bundle][RO][Ready-for-Stable] Translation Update
This PR was tested in-game and is ready to merge at any time (unless marked as draft).
Its strings are ready and _**merging**_ is _**recommended**_ for **_the next stable release._**

Changelog:

- New strings/changes up to commit f9cfc8a2b8
- Typo fixes & various other improvements
2020-12-07 13:50:55 +02:00
Nikolass1000
738aa26a20 Another completion 2020-12-07 10:41:16 +01:00
Anuken
5e0ba2f4af Merge remote-tracking branch 'origin/master' 2020-12-06 13:55:55 -05:00
Anuken
91b2d1a9bf Fixed #3824 2020-12-06 13:55:52 -05:00
Anuken
e636ceb317 Merge pull request #3791 from joshuaptfan/master
Enable double-click to play sector
2020-12-06 11:47:54 -05:00
Anuken
2eeb230694 Merge pull request #3792 from Neba-MD/master
Add TWS v6 to servers_v6.json
2020-12-06 11:10:48 -05:00
Joshua Fan
70cc6d07b0 Detect double-tap using count 2020-12-06 07:52:50 -08:00
Anuken
4d5c2c83fd Removed spawn shockwave delay 2020-12-06 10:50:13 -05:00
Anuken
cf91bcbd49 Run damage before spawn points activate 2020-12-06 10:23:24 -05:00
Joshua Fan
dd6ae80817 Merge remote-tracking branch 'origin/master' 2020-12-05 22:56:34 -08:00
Joshua Fan
58c1718d01 Detect double-tap 2020-12-05 22:07:09 -08:00
Neba-MD
db76ffe46a Update servers_v6.json 2020-12-06 05:31:51 +08:00
Neba-MD
a687aeb789 Update servers_v6.json 2020-12-05 17:32:00 +08:00
Joshua Fan
6ececea004 Enable double-click to play sector 2020-12-05 00:58:56 -08:00
Nikolass1000
df418c5a7d Small fix 2020-12-03 10:49:58 +01:00
108 changed files with 819 additions and 497 deletions

View File

@@ -1,7 +1,7 @@
### Adding a server to the list ### Adding a server to the list
Mindustry now has a public list of servers that everyone can see and connect to. Mindustry now has a public list of servers that everyone can see and connect to.
This is done by letting clients `GET` a [JSON list of servers](https://github.com/Anuken/Mindustry/blob/master/servers.json) in this repository. This is done by letting clients `GET` a [JSON list of servers](https://github.com/Anuken/Mindustry/blob/master/servers_v6.json) in this repository.
You may want to add your server to this list. The steps for getting this done are as follows: You may want to add your server to this list. The steps for getting this done are as follows:
@@ -16,7 +16,7 @@ You'll need to either hire some moderators, or make use of (currently non-existe
3. **Get some good maps.** *(optional, but highly recommended)*. Add some maps to your server and set the map rotation to custom-only. You can get maps from the Steam workshop by subscribing and exporting them; using the `#maps` channel on Discord is also an option. 3. **Get some good maps.** *(optional, but highly recommended)*. Add some maps to your server and set the map rotation to custom-only. You can get maps from the Steam workshop by subscribing and exporting them; using the `#maps` channel on Discord is also an option.
4. **Check your server configuration.** *(optional)* I would recommend adding a message rate limit of 1 second (`config messageRateLimit 1`), and disabling connect/disconnect messages to reduce spam (`config showConnectMessages false`). 4. **Check your server configuration.** *(optional)* I would recommend adding a message rate limit of 1 second (`config messageRateLimit 1`), and disabling connect/disconnect messages to reduce spam (`config showConnectMessages false`).
5. Finally, **submit a pull request** to add your server's IP to the list. 5. Finally, **submit a pull request** to add your server's IP to the list.
This should be fairly straightforward: Press the edit button on the [server file](https://github.com/Anuken/Mindustry/blob/master/servers.json), then add a JSON object with a single key, indicating your server address. This should be fairly straightforward: Press the edit button on the [server file](https://github.com/Anuken/Mindustry/blob/master/servers_v6.json), then add a JSON object with a single key, indicating your server address.
For example, if your server address is `google.com`, you would add a comma after the last entry and insert: For example, if your server address is `google.com`, you would add a comma after the last entry and insert:
```json ```json
{ {

View File

@@ -383,7 +383,6 @@ project(":annotations"){
dependencies{ dependencies{
implementation 'com.squareup:javapoet:1.12.1' implementation 'com.squareup:javapoet:1.12.1'
implementation "com.github.Anuken.Arc:arc-core:$arcHash" implementation "com.github.Anuken.Arc:arc-core:$arcHash"
implementation files("${System.getProperty('java.home')}/../lib/tools.jar")
} }
} }

View File

@@ -13,6 +13,7 @@ link.google-play.description = Google Play store listing
link.f-droid.description = F-Droid listing link.f-droid.description = F-Droid listing
link.wiki.description = Official Mindustry wiki link.wiki.description = Official Mindustry wiki
link.suggestions.description = Suggest new features link.suggestions.description = Suggest new features
link.bug.description = Found one? Report it here
linkfail = Failed to open link!\nThe URL has been copied to your clipboard. linkfail = Failed to open link!\nThe URL has been copied to your clipboard.
screenshot = Screenshot saved to {0} screenshot = Screenshot saved to {0}
screenshot.invalid = Map too large, potentially not enough memory for screenshot. screenshot.invalid = Map too large, potentially not enough memory for screenshot.
@@ -832,6 +833,7 @@ setting.chatopacity.name = Chat Opacity
setting.lasersopacity.name = Power Laser Opacity setting.lasersopacity.name = Power Laser Opacity
setting.bridgeopacity.name = Bridge Opacity setting.bridgeopacity.name = Bridge Opacity
setting.playerchat.name = Display Player Bubble Chat setting.playerchat.name = Display Player Bubble Chat
setting.showweather.name = Show Weather Graphics
public.confirm = Do you want to make your game public?\n[accent]Anyone will be able to join your games.\n[lightgray]This can be changed later in Settings->Game->Public Game Visibility. public.confirm = Do you want to make your game public?\n[accent]Anyone will be able to join your games.\n[lightgray]This can be changed later in Settings->Game->Public Game Visibility.
public.beta = Note that beta versions of the game cannot make public lobbies. public.beta = Note that beta versions of the game cannot make public lobbies.
uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] seconds... uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] seconds...

View File

@@ -2,8 +2,8 @@ credits.text = Entwickelt von [royal]Anuken[] - [sky]anukendev@gmail.com[]\n\n[g
credits = Danksagungen credits = Danksagungen
contributors = Übersetzer und Mitwirkende contributors = Übersetzer und Mitwirkende
discord = Tritt dem Mindustry-Discord bei! discord = Tritt dem Mindustry-Discord bei!
link.discord.description = Der offizielle Mindustry Discord Server link.discord.description = Der offizielle Mindustry Discord-Server
link.reddit.description = Der Mindustry Subreddit link.reddit.description = Mindustry-Subreddit
link.github.description = Quellcode des Spiels link.github.description = Quellcode des Spiels
link.changelog.description = Liste der Änderungen link.changelog.description = Liste der Änderungen
link.dev-builds.description = Entwicklungs-Builds (instabil) link.dev-builds.description = Entwicklungs-Builds (instabil)
@@ -11,7 +11,7 @@ link.trello.description = Offizielles Trello-Board für geplante Features
link.itch.io.description = itch.io-Seite mit Downloads und der Web-Version des Spiels link.itch.io.description = itch.io-Seite mit Downloads und der Web-Version des Spiels
link.google-play.description = Google Play Store-Seite link.google-play.description = Google Play Store-Seite
link.f-droid.description = F-Droid-Seite link.f-droid.description = F-Droid-Seite
link.wiki.description = Offizelles Mindustry-Wiki link.wiki.description = Offizielles Mindustry-Wiki
link.suggestions.description = Neue Ideen einbringen link.suggestions.description = Neue Ideen einbringen
linkfail = Fehler beim Öffnen des Links!\nDie URL wurde in die Zwischenablage kopiert. linkfail = Fehler beim Öffnen des Links!\nDie URL wurde in die Zwischenablage kopiert.
screenshot = Screenshot gespeichert unter {0} screenshot = Screenshot gespeichert unter {0}
@@ -23,7 +23,7 @@ gameover.waiting = [accent]Warte auf neue Karte...
highscore = [accent]Neuer Highscore! highscore = [accent]Neuer Highscore!
copied = Kopiert. copied = Kopiert.
indev.notready = Dieser Teil vom Spiel ist noch unfertig. indev.notready = Dieser Teil vom Spiel ist noch unfertig.
indev.campaign = [accent]Du hast das Ende der Kampagne erreicht![]\n\nMehr gibt es noch nicht. In einem zukünfttigen Update wird interplanetarisches Reisen möglich werden. indev.campaign = [accent]Du hast das Ende der Kampagne erreicht![]\n\nMehr gibt es noch nicht. In einem zukünftigen Update wird interplanetarisches Reisen möglich werden.
load.sound = Audio load.sound = Audio
load.map = Karten load.map = Karten
@@ -101,9 +101,9 @@ uploadingcontent = Inhalt hochladen
uploadingpreviewfile = Vorschaudatei hochladen uploadingpreviewfile = Vorschaudatei hochladen
committingchanges = Veränderungen übernehmen committingchanges = Veränderungen übernehmen
done = Fertig done = Fertig
feature.unsupported = Dein System unsterstützt dieses Feature nicht. feature.unsupported = Dein System unterstützt dieses Feature nicht.
mods.alphainfo = Vergiss nicht, dass Mods in der Alpha sind, und[scarlet] sehr fehlerhaft sein können[].\nMelde alle Probleme an den Mindustry GitHub oder Discord. mods.alphainfo = Vergiss nicht, dass Mods in der Alpha sind und[scarlet] sehr fehlerhaft sein können[].\nMelde alle Probleme auf GitHub oder Discord.
mods = Mods mods = Mods
mods.none = [lightgray]Keine Mods gefunden! mods.none = [lightgray]Keine Mods gefunden!
mods.guide = Modding-Anleitung mods.guide = Modding-Anleitung
@@ -131,13 +131,13 @@ mod.import = Mod importieren
mod.import.file = Datei importieren mod.import.file = Datei importieren
mod.import.github = GitHub-Mod importieren mod.import.github = GitHub-Mod importieren
mod.jarwarn = [scarlet]JAR Mods sind nicht sicher.[]\nInstalliere nur Mods von vertrauenswürdigen Quellen! mod.jarwarn = [scarlet]JAR Mods sind nicht sicher.[]\nInstalliere nur Mods von vertrauenswürdigen Quellen!
mod.item.remove = Dies ist Teil vom [accent] '{0}'[] Mod. Deaktivieren sie diesen Mod, um dies zu entfernen. mod.item.remove = Dies ist Teil vom [accent] '{0}'[] Mod. Deaktivieren Sie diesen Mod, um dies zu entfernen.
mod.remove.confirm = Dieser Mod wird gelöscht. mod.remove.confirm = Dieser Mod wird gelöscht.
mod.author = [lightgray]Autor:[] {0} mod.author = [lightgray]Autor:[] {0}
mod.missing = Dieser Spielstand enthält Mods, welche nicht mehr vorhanden oder aktualisiert wurden. Spielstandfehler könnten passieren. Bist du dir sicher, das du ihn laden möchtest?\n[lightgray]Mods:\n{0} mod.missing = Dieser Spielstand enthält Mods, welche nicht mehr vorhanden sind oder aktualisiert wurden. Spielstandfehler könnten passieren. Bist du dir sicher, dass du ihn laden möchtest?\n[lightgray]Mods:\n{0}
mod.preview.missing = Bevor du diesen Mod hochladen kannst, musst du eine Bildvorschau einbinden.\nLade ein Bild namens[accent] preview.png[] in den Modordner und versuche es nochmal. mod.preview.missing = Bevor du diesen Mod hochladen kannst, musst du eine Bildvorschau einbinden.\nLade ein Bild namens[accent] preview.png[] in den Modordner und versuche es nochmal.
mod.folder.missing = Nur Mods in Ordnerform können in den Workshop hochgeladen werden.\nUm einen Mod in einen Ordner zu konvertieren, extrahiere das Archiv und lösche das alte Archiv danach. Starte dann das Spiel neu oder lade die Mods neu. mod.folder.missing = Nur Mods in Ordnerform können in den Workshop hochgeladen werden.\nUm einen Mod in einen Ordner zu konvertieren, extrahiere das Archiv und lösche das alte Archiv danach. Starte dann das Spiel neu oder lade die Mods neu.
mod.scripts.disable = Ihr Gerät unterstüzt keine Mods mit Scripts. Du musst diese Mods deaktivieren, um spielen zu können. mod.scripts.disable = Ihr Gerät unterstützt keine Mods mit Scripts. Du musst diese Mods deaktivieren, um spielen zu können.
about.button = Info about.button = Info
name = Name: name = Name:
@@ -146,7 +146,7 @@ planetmap = Planetenkarte
launchcore = Kern starten launchcore = Kern starten
filename = Dateiname: filename = Dateiname:
unlocked = Neuer Inhalt freigeschaltet! unlocked = Neuer Inhalt freigeschaltet!
available = Neue Forschung möchlich! available = Neue Forschung möglich
completed = [accent]Abgeschlossen completed = [accent]Abgeschlossen
techtree = Forschung techtree = Forschung
research.legacy = [accent]5.0[] Forschungsdaten gefunden.\nMöchtest du [accent]diese Daten behalten[] oder [accent]sie löschen[] und neu anfangen (empfohlen)? research.legacy = [accent]5.0[] Forschungsdaten gefunden.\nMöchtest du [accent]diese Daten behalten[] oder [accent]sie löschen[] und neu anfangen (empfohlen)?
@@ -170,7 +170,7 @@ server.kicked.serverOutdated = Veralteter Server! Bitte den Host um ein Update!
server.kicked.banned = Du wurdest vom Server verbannt. server.kicked.banned = Du wurdest vom Server verbannt.
server.kicked.typeMismatch = Dieser Server ist nicht mit deinem Buildtyp kompatibel. server.kicked.typeMismatch = Dieser Server ist nicht mit deinem Buildtyp kompatibel.
server.kicked.playerLimit = Dieser Server ist voll. Warte auf einen freien Platz. server.kicked.playerLimit = Dieser Server ist voll. Warte auf einen freien Platz.
server.kicked.recentKick = Du wurdest gerade gekickt.\nWarte bevor du dich wieder verbindest. server.kicked.recentKick = Du wurdest gerade gekickt.\nWarte, bevor du dich wieder verbindest.
server.kicked.nameInUse = Es ist bereits ein Spieler \nmit diesem Namen auf dem Server. server.kicked.nameInUse = Es ist bereits ein Spieler \nmit diesem Namen auf dem Server.
server.kicked.nameEmpty = Dein Name muss mindestens einen Buchstaben oder eine Zahl enthalten. server.kicked.nameEmpty = Dein Name muss mindestens einen Buchstaben oder eine Zahl enthalten.
server.kicked.idInUse = Du bist bereits auf dem Server! Anmeldungen mit zwei Accounts sind nicht gestattet. server.kicked.idInUse = Du bist bereits auf dem Server! Anmeldungen mit zwei Accounts sind nicht gestattet.
@@ -178,7 +178,7 @@ server.kicked.customClient = Der Server akzeptiert keine Custom Builds von Mindu
server.kicked.gameover = Game Over! server.kicked.gameover = Game Over!
server.kicked.serverRestarting = Der Server startet neu. server.kicked.serverRestarting = Der Server startet neu.
server.versions = Deine Version:[accent] {0}[]\nServerversion:[accent] {1}[] server.versions = Deine Version:[accent] {0}[]\nServerversion:[accent] {1}[]
host.info = Der [accent]Server hosten[]-Knopf startet einen Server auf den Ports [scarlet]6567[] und [scarlet]6568.[]\nJeder im gleichen [lightgray]W-Lan oder lokalen Netzwerk[] sollte deinen Server in seiner Serverliste sehen können.\n\nWenn du anderen die Verbindung über deine IP-Adresse ermöglichen willst, musst du [accent]Port-Forwarding[] durchführen.\n\n[lightgray]Hinweis: Falls es Probleme mit der Verbindung im Netzwerk gibt, stelle sicher, dass Mindustry in deinen Firewall-Einstellungen Zugriff auf das lokale Netzwerk hat. host.info = Der [accent]'Server hosten'[]-Knopf startet einen Server auf den Ports [scarlet]6567[] und [scarlet]6568.[]\nJeder im gleichen [lightgray]W-Lan oder lokalen Netzwerk[] sollte deinen Server in seiner Serverliste sehen können.\n\nWenn du anderen die Verbindung über deine IP-Adresse ermöglichen willst, musst du [accent]Port-Forwarding[] durchführen.\n\n[lightgray]Hinweis: Falls es Probleme mit der Verbindung im Netzwerk gibt, stelle sicher, dass Mindustry in deinen Firewall-Einstellungen Zugriff auf das lokale Netzwerk hat.
join.info = Hier kannst du eine [accent]Server-IP[] eingeben, um dich zu verbinden, oder Server im [accent]lokalen Netzwerk[] entdecken und dich mit ihnen verbinden.\nSowohl Spielen über das lokale Netzwerk als auch Spielen über das Internet werden unterstützt.\n\n[lightgray]Hinweis: Es gibt keine globale Serverliste; wenn du dich mit jemandem per IP-Adresse verbinden willst, musst du den Host nach seiner IP-Adresse fragen. join.info = Hier kannst du eine [accent]Server-IP[] eingeben, um dich zu verbinden, oder Server im [accent]lokalen Netzwerk[] entdecken und dich mit ihnen verbinden.\nSowohl Spielen über das lokale Netzwerk als auch Spielen über das Internet werden unterstützt.\n\n[lightgray]Hinweis: Es gibt keine globale Serverliste; wenn du dich mit jemandem per IP-Adresse verbinden willst, musst du den Host nach seiner IP-Adresse fragen.
hostserver = Mehrspieler hosten hostserver = Mehrspieler hosten
invitefriends = Freunde einladen invitefriends = Freunde einladen
@@ -196,8 +196,9 @@ servers.local = Lokale Server
servers.remote = Andere Server servers.remote = Andere Server
servers.global = Community-Server servers.global = Community-Server
servers.disclaimer = Community-Server werden vom Entwickler [accent]nicht[] geprüft.\n\Sie können Inhalte, die nicht für jedes Alter geeignet sind, enthalten.
servers.showhidden = Versteckte Server anzeigen servers.showhidden = Versteckte Server anzeigen
server.shown = Angeziegt server.shown = Angezeigt
server.hidden = Versteckt server.hidden = Versteckt
trace = Spieler verfolgen trace = Spieler verfolgen
@@ -287,7 +288,7 @@ data.import = Daten importieren
data.openfolder = Datenordner öffnen data.openfolder = Datenordner öffnen
data.exported = Daten exportiert. data.exported = Daten exportiert.
data.invalid = Dies sind keine gültigen Spieldaten. data.invalid = Dies sind keine gültigen Spieldaten.
data.import.confirm = Der Import von externen Daten wird [scarlet] alle[] deine gegenwärtigen Spieldaten löschen.\n[accent]Das kann nicht rückgängig gemacht werden![]Sobald der Import abeschlossen ist, wird dein Spiel sofort beendet. data.import.confirm = Der Import von externen Daten wird [scarlet] alle[] deine gegenwärtigen Spieldaten löschen.\n[accent]Das kann nicht rückgängig gemacht werden![]\n\nSobald der Import abgeschlossen ist, wird dein Spiel sofort beendet.
quit.confirm = Willst du wirklich aufhören? quit.confirm = Willst du wirklich aufhören?
quit.confirm.tutorial = Weißt du, was du tust?\nDu kannst das Tutorial unter[accent] Einstellungen->Spiel->Tutorial wiederholen[] erneut spielen. quit.confirm.tutorial = Weißt du, was du tust?\nDu kannst das Tutorial unter[accent] Einstellungen->Spiel->Tutorial wiederholen[] erneut spielen.
loading = [accent]Wird geladen... loading = [accent]Wird geladen...
@@ -298,7 +299,7 @@ cancelbuilding = [accent][[{0}][] um den Plan zu leeren
selectschematic = [accent][[{0}][] zum Auswählen+Kopieren selectschematic = [accent][[{0}][] zum Auswählen+Kopieren
pausebuilding = [accent][[{0}][] um das Bauen zu pausieren pausebuilding = [accent][[{0}][] um das Bauen zu pausieren
resumebuilding = [scarlet][[{0}][] um das Bauen fortzusetzen resumebuilding = [scarlet][[{0}][] um das Bauen fortzusetzen
showui = Bedienflächen versteckt.\nDrücke [accent][[{0}][] um sie wieder anzuzeigen. showui = Bedienflächen versteckt.\nDrücke [accent][[{0}][], um sie wieder anzuzeigen.
wave = [accent]Welle {0} wave = [accent]Welle {0}
wave.cap = [accent]Welle {0}/{1} wave.cap = [accent]Welle {0}/{1}
wave.waiting = Welle in {0} wave.waiting = Welle in {0}
@@ -316,11 +317,11 @@ saveimage = Bild speichern
unknown = Unbekannt unknown = Unbekannt
custom = Benutzerdefiniert custom = Benutzerdefiniert
builtin = Enthalten builtin = Enthalten
map.delete.confirm = Bist du sicher, dass du diese Karte löschen willst? Dies kann nicht rückgänig gemacht werden! map.delete.confirm = Bist du sicher, dass du diese Karte löschen willst? Dies kann nicht rückgängig gemacht werden!
map.random = [accent]Zufällige Karte map.random = [accent]Zufällige Karte
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. map.nospawn = Diese Karte hat keine Kerne, in denen die Spieler beginnen können! Füge einen [royal]orangen[] Kern zu dieser Karte im Editor hinzu.
map.nospawn.pvp = Diese Karte hat keine gegnerischen Kerne in denen Gegner starten können! Füge über den Editor [scarlet] rote[] Kerne zu dieser Karte hinzu. map.nospawn.pvp = Diese Karte hat keine Kerne für die gegnerischen Spieler! Füge über den Editor [scarlet] nicht-orange[] Kerne zu dieser Karte hinzu.
map.nospawn.attack = Diese Karte hat keine gengnerischen Kerne, die Spieler angreifen können! Füge über den Editor [scarlet] rote[] Kerne zu dieser Karte hinzu. map.nospawn.attack = Diese Karte hat keine gegnerischen Kerne, die Spieler angreifen können! Füge über den Editor [scarlet] rote[] Kerne zu dieser Karte hinzu.
map.invalid = Fehler beim Laden der Karte: Beschädigte oder ungültige Kartendatei. map.invalid = Fehler beim Laden der Karte: Beschädigte oder ungültige Kartendatei.
workshop.update = Objekt aktualisieren workshop.update = Objekt aktualisieren
workshop.error = Fehler beim Laden von Workshop-Details: {0} workshop.error = Fehler beim Laden von Workshop-Details: {0}
@@ -333,7 +334,7 @@ missing = Dieses Objekt wurde gelöscht oder verschoben.\n[lightgray]Die Worksho
publishing = [accent]Veröffentlichen... publishing = [accent]Veröffentlichen...
publish.confirm = Willst du das wirklich veröffentlichen?\n\n[lightgray]Vergewissere dich, dass du der Workshop-EULA zugestimmt hast, sonst tauchen deine Objekte nicht auf! publish.confirm = Willst du das wirklich veröffentlichen?\n\n[lightgray]Vergewissere dich, dass du der Workshop-EULA zugestimmt hast, sonst tauchen deine Objekte nicht auf!
publish.error = Fehler beim Veröffentlichen des Objekts: {0} publish.error = Fehler beim Veröffentlichen des Objekts: {0}
steam.error = Fehler beim laden der Steam-Dienste.\nError: {0} steam.error = Fehler beim Laden der Steam-Dienste.\nError: {0}
editor.brush = Pinsel editor.brush = Pinsel
editor.openin = Öffne im Editor editor.openin = Öffne im Editor
@@ -342,11 +343,11 @@ editor.oregen.info = Erze generiert:
editor.mapinfo = Karten-Info editor.mapinfo = Karten-Info
editor.author = Autor: editor.author = Autor:
editor.description = Beschreibung: editor.description = Beschreibung:
editor.nodescription = Eine Karte benötigt eine Beschreibung mit mindestens 4 Buchstaben, bevor sie veröffentlich werden kann. editor.nodescription = Eine Karte benötigt eine Beschreibung mit mindestens 4 Buchstaben, bevor sie veröffentlicht werden kann.
editor.waves = Wellen: editor.waves = Wellen:
editor.rules = Regeln: editor.rules = Regeln:
editor.generation = Generator: editor.generation = Generator:
editor.ingame = Im Spiel Bearbeiten editor.ingame = Im Spiel bearbeiten
editor.publish.workshop = Im Workshop veröffentlichen editor.publish.workshop = Im Workshop veröffentlichen
editor.newmap = Neue Karte editor.newmap = Neue Karte
editor.center = Zur Mitte editor.center = Zur Mitte
@@ -382,7 +383,7 @@ editor.removeunit = Bereich entfernen
editor.teams = Teams editor.teams = Teams
editor.errorload = Fehler beim Laden der Datei:\n[accent]{0} editor.errorload = Fehler beim Laden der Datei:\n[accent]{0}
editor.errorsave = Fehler beim Speichern der Datei:\n[accent]{0} editor.errorsave = Fehler beim Speichern der Datei:\n[accent]{0}
editor.errorimage = Das ist ein Bild, keine Karte. Wechsle nicht den Dateityp und erwarte, dass es funktioniert.\n\nWenn du eine 3.5/build 40-Karte importieren möchtest, benutze den 'Importiere Terrainbild' Knopf im Editor. editor.errorimage = Das ist ein Bild, keine Karte. Wechsle nicht den Dateityp und erwarte, dass es funktioniert.\n\nWenn du eine 'v3.5/build 40'-Karte importieren möchtest, benutze den 'Importiere Terrainbild'-Knopf im Editor.
editor.errorlegacy = Diese Karte ist zu alt und benutzt ein veraltetes Kartenformat, das nicht mehr unterstützt wird. editor.errorlegacy = Diese Karte ist zu alt und benutzt ein veraltetes Kartenformat, das nicht mehr unterstützt wird.
editor.errornot = Dies ist keine Kartendatei. editor.errornot = Dies ist keine Kartendatei.
editor.errorheader = Diese Karte ist entweder nicht gültig oder beschädigt. editor.errorheader = Diese Karte ist entweder nicht gültig oder beschädigt.
@@ -395,9 +396,9 @@ editor.resize = Größe\nanpassen
editor.loadmap = Karte\nladen editor.loadmap = Karte\nladen
editor.savemap = Karte\nspeichern editor.savemap = Karte\nspeichern
editor.saved = Gespeichert! editor.saved = Gespeichert!
editor.save.noname = Deine Karte hat keinen Namen! Setze einen Namen im [accent]Karten Info[] Menu. editor.save.noname = Deine Karte hat keinen Namen! Setze einen Namen im [accent]Karten-Info[]-Menü.
editor.save.overwrite = Deine Karte überschreibt eine built-in Karte! Wähle einen anderen Karten Namen im [accent]'Karten info'[] Menu. editor.save.overwrite = Deine Karte überschreibt eine Standardkarte! Wähle einen anderen Karten Namen im [accent]Karten-Info[]-Menü.
editor.import.exists = [scarlet]Fehler beim Import:[] Ein built-in Karte namens '{0}' existiert bereits! editor.import.exists = [scarlet]Fehler beim Import:[] Ein Standardkarte namens '{0}' existiert bereits!
editor.import = Importieren... editor.import = Importieren...
editor.importmap = Importiere Karte editor.importmap = Importiere Karte
editor.importmap.description = Importiere von einer bestehenden Karte editor.importmap.description = Importiere von einer bestehenden Karte
@@ -432,7 +433,7 @@ toolmode.eraseores = Erze löschen
toolmode.eraseores.description = Löscht nur Erze. toolmode.eraseores.description = Löscht nur Erze.
toolmode.fillteams = Teams ausfüllen toolmode.fillteams = Teams ausfüllen
toolmode.fillteams.description = Füllt Teams aus statt Blöcke. toolmode.fillteams.description = Füllt Teams aus statt Blöcke.
toolmode.drawteams = Teams Zeichnen toolmode.drawteams = Teams zeichnen
toolmode.drawteams.description = Zeichnet Teams statt Blöcke. toolmode.drawteams.description = Zeichnet Teams statt Blöcke.
filters.empty = [lightgray]Keine Filter! Füge einen mit dem unteren Knopf hinzu. filters.empty = [lightgray]Keine Filter! Füge einen mit dem unteren Knopf hinzu.
@@ -463,7 +464,7 @@ filter.option.angle = Winkel
filter.option.amount = Menge filter.option.amount = Menge
filter.option.block = Block filter.option.block = Block
filter.option.floor = Boden filter.option.floor = Boden
filter.option.flooronto = Ziel Boden filter.option.flooronto = Zielboden
filter.option.target = Ziel filter.option.target = Ziel
filter.option.wall = Wand filter.option.wall = Wand
filter.option.ore = Erz filter.option.ore = Erz
@@ -542,12 +543,12 @@ sectors.wave = Welle:
sectors.stored = Gelagert: sectors.stored = Gelagert:
sectors.resume = Weiterspielen sectors.resume = Weiterspielen
sectors.launch = Start sectors.launch = Start
sectors.select = Select sectors.select = Auswählen
sectors.nonelaunch = [lightgray]none (sun) sectors.nonelaunch = [lightgray]none (sun)
sectors.rename = Sektor umbenennen sectors.rename = Sektor umbenennen
sectors.enemybase = [scarlet]Gegnerische Basis sectors.enemybase = [scarlet]Gegnerische Basis
sectors.vulnerable = [scarlet]Angriffsgefährdet sectors.vulnerable = [scarlet]Angriffsgefährdet
sectors.underattack = [scarlet]Wird angegriffen! [accent]{0}% damaged sectors.underattack = [scarlet]Wird angegriffen! [accent]{0}% geschädigt
sectors.survives = [accent]Kann {0} Wellen überleben sectors.survives = [accent]Kann {0} Wellen überleben
sectors.go = Hingehen sectors.go = Hingehen
sector.curcapture = Sektor erfolgreich erobert sector.curcapture = Sektor erfolgreich erobert
@@ -586,21 +587,21 @@ sector.windsweptIslands.name = Windswept Islands
sector.extractionOutpost.name = Extraction Outpost sector.extractionOutpost.name = Extraction Outpost
sector.planetaryTerminal.name = Planetary Launch Terminal sector.planetaryTerminal.name = Planetary Launch Terminal
sector.groundZero.description = Der optimale Ort um anzufangen. Schwache Gegner und weniger Ressourcen.\nSammele so viel Kupfer und Blei wie möglich.\nGeh weiter. sector.groundZero.description = Der optimale Ort, um anzufangen. Schwache Gegner und weniger Ressourcen.\nSammele so viel Kupfer und Blei wie möglich.\nGeh weiter.
sector.frozenForest.description = Auch hier, näher an den Bergen, sind die Sporen. Sogar die niedrigen Temperaturen können sie nicht zurückhalten.\n\nLerne, Strom zu verwenden. Baue Verbrennungsgeneratoren und Reparateure. sector.frozenForest.description = Auch hier, näher an den Bergen, sind die Sporen. Sogar die niedrigen Temperaturen können sie nicht zurückhalten.\n\nLerne, Strom zu verwenden. Baue Verbrennungsgeneratoren und Reparateure.
sector.saltFlats.description = Du befindest dich in der Nähe der Wüste. Hier gibt es nur wenige Ressourcen.\n\nDer Gegner hat hier ein Lager aufgestellt. Zerstöre es. Lasse nichts stehen. sector.saltFlats.description = Du befindest dich in der Nähe der Wüste. Hier gibt es nur wenige Ressourcen.\n\nDer Gegner hat hier ein Lager aufgestellt. Zerstöre es. Lasse nichts stehen.
sector.craters.description = Wasser hat sich hier, in diesem Überbleibsel aus dem alten Krieg, versammelt. Sammele Sand. Stelle Metaglas her. Benutze Wasser, um Bohrer und Geschütze zu kühlen. sector.craters.description = Wasser hat sich hier, in diesem Überbleibsel aus dem alten Krieg, versammelt. Sammele Sand. Stelle Metaglas her. Benutze Wasser, um Bohrer und Geschütze zu kühlen.
sector.ruinousShores.description = Hinter der Wüste ist das Ufer. Es gab hier vor langer Zeit ein Uferabwehrsystem. Heute sind nur noch die einfachsten Abwehrgeschütze vorhanden, der Rest wurde verschrottet.\nBreite dich weiter aus. Finde die verlorenen Technologien wieder. sector.ruinousShores.description = Hinter der Wüste ist das Ufer. Es gab hier vor langer Zeit ein Uferabwehrsystem. Heute sind nur noch die einfachsten Abwehrgeschütze vorhanden, der Rest wurde verschrottet.\nBreite dich weiter aus. Finde die verlorenen Technologien wieder.
sector.stainedMountains.description = Im Landesinneren sind die Berge, noch unversehrt von den Sporen.\nNutze das reichliche vorhandene Titan und lerne, es zu benutzen.\n\nDie Gegner hier sind stärker. Gib ihnen keine Zeit, um ihre stärksten Einheiten zu schicken. sector.stainedMountains.description = Im Landesinneren sind die Berge, noch unversehrt von den Sporen.\nNutze das reichliche vorhandene Titan und lerne, es zu benutzen.\n\nDie Gegner hier sind stärker. Gib ihnen keine Zeit, um ihre stärksten Einheiten zu schicken.
sector.overgrowth.description = Dieser Bereich ist überwuchert, näher an die Quelle der Sporen.\nDer Gegner hat hier einen Außenposten errichtet. Baue Mace-Einheiten. Zerstöre ihn. sector.overgrowth.description = Dieser Bereich ist überwuchert, näher an die Quelle der Sporen.\nDer Gegner hat hier einen Außenposten errichtet. Baue Mace-Einheiten. Zerstöre ihn.
sector.tarFields.description = Der Rand einer Ölproduktionszone, swischen den Bergen und der Wüste. Einer der wenigen Orte mit brauchbaren Ölquellen.\nObwohl er vergessen wurde, hat dieser Ort mächtige Gegnerische Lager in der Nähe. Unterschätze sie nicht.\n\n[lightgray]Erforsche, falls mögloch, die Ölverarbeitung. sector.tarFields.description = Der Rand einer Ölproduktionszone, zwischen den Bergen und der Wüste. Einer der wenigen Orte mit brauchbaren Ölquellen.\nObwohl er vergessen wurde, hat dieser Ort mächtige gegnerische Lager in der Nähe. Unterschätze sie nicht.\n\n[lightgray]Erforsche, falls möglich, die Ölverarbeitung.
sector.desolateRift.description = Eine besonders gefährliche Zone. Viele Ressourcen aber wenig Platz. Hohe Wahrscheinlichkeit, vernichtet zu werden. Verlasse diesen Ort so bald wie möglich. Lass dich nicht durch die langen Abstände zwischen gegnerischen Angriffen täuschen. sector.desolateRift.description = Eine besonders gefährliche Zone. Viele Ressourcen aber wenig Platz. Hohe Wahrscheinlichkeit, vernichtet zu werden. Verlasse diesen Ort so bald wie möglich. Lass dich nicht durch die langen Abstände zwischen gegnerischen Angriffen täuschen.
sector.nuclearComplex.description = Diese Ruine war vor langer Zeit eine Anlage zur Verarbeitung von Thorium.\n[lightgray]Erforsche Thorium und dessen Anwendungen.\n\nDer Gegner ist hier stark vertreten, auf der Suche nach Angreifern. sector.nuclearComplex.description = Diese Ruine war vor langer Zeit eine Anlage zur Verarbeitung von Thorium.\n[lightgray]Erforsche Thorium und dessen Anwendungen.\n\nDer Gegner ist hier stark vertreten und hält nach Angreifern Ausschau.
sector.fungalPass.description = Eine Übergangszone zwischen den Bergen und den niedrigeren, Sporen-Infestierten Gebieten. Hier ist eine kleine gegnerische Basis.\nZerstöre sie.\nBenutze Dagger- und Crawler-Einheiten. Vernichte die beiden Kerne. sector.fungalPass.description = Eine Übergangszone zwischen den Bergen und den niedrigeren, von Sporen befallenen Gebieten. Hier ist eine kleine gegnerische Basis.\nZerstöre sie.\nBenutze Dagger- und Crawler-Einheiten. Vernichte die beiden Kerne.
sector.biomassFacility.description = Die Sporenquelle. Dies ist der Ort, wo sie erforscht und hergestellt wurden.\nErforsche die Technologie, die sich hier versteckt. Stellen Sporen her, um Plastanium und Öl herzustellen.\n\n[lightgray]Als diese Anlage zerstört wurde, wurden die Sporen freigesetzt. Nichts im lokalen Ökosystem konnte so ein eindringliches Lebenwesen bekämpfen. sector.biomassFacility.description = Die Sporenquelle. Dies ist der Ort, wo sie erforscht und hergestellt wurden.\nErforsche die Technologie, die sich hier versteckt. Stellen Sporen her, um Plastanium und Öl herzustellen.\n\n[lightgray]Als diese Anlage zerstört wurde, wurden die Sporen freigesetzt. Nichts im lokalen Ökosystem konnte so ein eindringliches Lebewesen bekämpfen.
sector.windsweptIslands.description = Diese Inseln befinden sich in der Nähe vom Ufer. Manche Aufzeichnungen behaupten, hier seien Fabriken, die [accent]Plastanium[] herstellen können.\n\nWehre dich gegen die gegnerischen Wassereinheiten. Stelle eine Basis auf den Inseln auf. Erforsche diese Fabriken. sector.windsweptIslands.description = Diese Inseln befinden sich in der Nähe vom Ufer. Manche Aufzeichnungen behaupten, hier seien Fabriken, die [accent]Plastanium[] herstellen können.\n\nWehre dich gegen die gegnerischen Wassereinheiten. Stelle eine Basis auf den Inseln auf. Erforsche diese Fabriken.
sector.extractionOutpost.description = Ein Außenposten, der vom Gegner erstellt wurde, um Ressourcen in andere Sektoren zu transportieren.\n\nTrans-Sektorischer Transport ist nötig, um weiter voranzuschreiten. Zerstöre den Posten. Erforsche deren Launchpads. sector.extractionOutpost.description = Ein Außenposten, der vom Gegner erstellt wurde, um Ressourcen in andere Sektoren zu transportieren.\n\nTrans-Sektorischer Transport ist nötig, um weiter voranzuschreiten. Zerstöre den Posten. Erforsche deren Launchpads.
sector.impact0078.description = Here liegen Reste der interplanetarischen Transporteinheit, die dieses Sonnensystem zuerst betreten hat.\n\nRette so viel wie möglich von den Ruinen. Erforsche jede intakte Technologie. sector.impact0078.description = Hier liegen Reste der interplanetarischen Transporteinheit, die dieses Sonnensystem zuerst betreten hat.\n\nRette so viel wie möglich von den Ruinen. Erforsche jede intakte Technologie.
sector.planetaryTerminal.description = Das Endziel.\n\nDiese Uferbasis besitzt ein Gerät, mit dem es möglich ist, Kerne auf andere Planeten zu schicken. Es ist [accent]sehr[] gut beschützt.\n\nStelle Wassereinheiten her. Eliminiere den Gegner so schnell wie möglich. Erforsche das Launchgerät. sector.planetaryTerminal.description = Das Endziel.\n\nDiese Uferbasis besitzt ein Gerät, mit dem es möglich ist, Kerne auf andere Planeten zu schicken. Es ist [accent]sehr[] gut beschützt.\n\nStelle Wassereinheiten her. Eliminiere den Gegner so schnell wie möglich. Erforsche das Launchgerät.
settings.language = Sprache settings.language = Sprache
settings.data = Spieldaten settings.data = Spieldaten
@@ -623,7 +624,6 @@ settings.clearcampaignsaves.confirm = Möchtest du wirklich alle Kampagne-Speich
paused = [accent]< Pausiert > paused = [accent]< Pausiert >
clear = Leeren clear = Leeren
banned = [scarlet]Verbannt banned = [scarlet]Verbannt
unplaceable.sectorcaptured = [scarlet]Erfordert erforderter Sektor
yes = Ja yes = Ja
no = Nein no = Nein
info.title = Info info.title = Info
@@ -692,7 +692,7 @@ stat.speed = Geschwindigkeit
stat.buildspeed = Baugeschwindigkeit stat.buildspeed = Baugeschwindigkeit
stat.minespeed = Abbaugeschwindigkeit stat.minespeed = Abbaugeschwindigkeit
stat.minetier = Abbau-Kraft stat.minetier = Abbau-Kraft
stat.payloadcapacity = Payload Capacity stat.payloadcapacity = Einheitenkapazität
stat.commandlimit = Kommandier-Limit stat.commandlimit = Kommandier-Limit
stat.abilities = Fähigkeiten stat.abilities = Fähigkeiten
stat.canboost = Kann boosten stat.canboost = Kann boosten
@@ -705,7 +705,7 @@ ability.unitspawn = {0} Fabrik
ability.shieldregenfield = Schild-regenerations-Feld ability.shieldregenfield = Schild-regenerations-Feld
ability.movelightning = Bewegungsblitze ability.movelightning = Bewegungsblitze
bar.drilltierreq = Besserer Bohrer Benötigt bar.drilltierreq = Besserer Bohrer benötigt
bar.noresources = Fehlende Ressourcen bar.noresources = Fehlende Ressourcen
bar.corereq = Kern-Basis erforderlich bar.corereq = Kern-Basis erforderlich
bar.drillspeed = Bohrgeschwindigkeit: {0}/s bar.drillspeed = Bohrgeschwindigkeit: {0}/s
@@ -777,7 +777,7 @@ setting.shadows.name = Schatten
setting.blockreplace.name = Automatische Blockvorschläge setting.blockreplace.name = Automatische Blockvorschläge
setting.linear.name = Lineare Filterung setting.linear.name = Lineare Filterung
setting.hints.name = Tipps setting.hints.name = Tipps
setting.flow.name = Ressourcen-Fluss anzeigen [scarlet] (experimentell) setting.flow.name = Ressourcen-Fluss anzeigen
setting.backgroundpause.name = Im Hintergrund pausieren setting.backgroundpause.name = Im Hintergrund pausieren
setting.buildautopause.name = Bauen automatisch pausieren setting.buildautopause.name = Bauen automatisch pausieren
setting.animatedwater.name = Animiertes Wasser setting.animatedwater.name = Animiertes Wasser
@@ -786,7 +786,7 @@ setting.antialias.name = Antialias[lightgray] (Neustart erforderlich)[]
setting.playerindicators.name = Spieler-Indikatoren setting.playerindicators.name = Spieler-Indikatoren
setting.indicators.name = Verbündeten-Indikatoren setting.indicators.name = Verbündeten-Indikatoren
setting.autotarget.name = Auto-Zielauswahl setting.autotarget.name = Auto-Zielauswahl
setting.keyboard.name = Maus+Tastatur Steuerung setting.keyboard.name = Maus+Tastatur-Steuerung
setting.touchscreen.name = Touchscreen-Steuerung setting.touchscreen.name = Touchscreen-Steuerung
setting.fpscap.name = Max. FPS setting.fpscap.name = Max. FPS
setting.fpscap.none = Kein(e) setting.fpscap.none = Kein(e)
@@ -831,13 +831,13 @@ setting.chatopacity.name = Chat-Deckkraft
setting.lasersopacity.name = Power-Laser-Deckkraft setting.lasersopacity.name = Power-Laser-Deckkraft
setting.bridgeopacity.name = Brücken-Deckkraft setting.bridgeopacity.name = Brücken-Deckkraft
setting.playerchat.name = Chat im Spiel anzeigen setting.playerchat.name = Chat im Spiel anzeigen
public.confirm = Willst du dein Spiel öffentlich zugänglich machen?\n[accent]Jeder kann deinem Spiel beitreten.\n[lightgray]Dies kann später in den Einstellung->Spielt->Öffentliches Spiel geändert werden. public.confirm = Willst du dein Spiel öffentlich zugänglich machen?\n[accent]Jeder kann deinem Spiel beitreten.\n[lightgray]Dies kann später in den Einstellungen->Spiel->Öffentliches Spiel geändert werden.
public.beta = Bemerke: Beta-Versionen des Spiels können keine öffentlichen Spiele machen. public.beta = Bemerke: Beta-Versionen des Spiels können keine öffentlichen Spiele machen.
uiscale.reset = UI-Skalierung wurde geändert.\nDrücke "OK", um diese Skalierung zu bestätigen.\n[scarlet]Zurückkehren und Beenden in[accent] {0}[] Einstellungen... uiscale.reset = UI-Skalierung wurde geändert.\nDrücke "OK", um diese Skalierung zu bestätigen.\n[scarlet]Zurückkehren und Beenden in[accent] {0}[] Einstellungen...
uiscale.cancel = Abbrechen & Beenden uiscale.cancel = Abbrechen & Beenden
setting.bloom.name = Bloom setting.bloom.name = Bloom
keybind.title = Tasten zuweisen keybind.title = Tasten zuweisen
keybinds.mobile = [scarlet]Die meisten Tastenzuweisungen hier funktionieren auf z.B. mobilen Geräten nicht. Nur grundlegende Bewegung wird unterstützt. keybinds.mobile = [scarlet]Die meisten Tastenzuweisungen hier funktionieren auf mobilen Geräten nicht. Nur grundlegende Bewegung wird unterstützt.
category.general.name = Allgemein category.general.name = Allgemein
category.view.name = Ansicht category.view.name = Ansicht
category.multiplayer.name = Mehrspieler category.multiplayer.name = Mehrspieler
@@ -845,7 +845,7 @@ category.blocks.name = Blockauswahl
command.attack = Angreifen command.attack = Angreifen
command.rally = Patrouillieren command.rally = Patrouillieren
command.retreat = Rückzug command.retreat = Rückzug
command.idle = Idle command.idle = Stehen bleiben
placement.blockselectkeys = \n[lightgray]Taste: [{0}, placement.blockselectkeys = \n[lightgray]Taste: [{0},
keybind.respawn.name = Respawn keybind.respawn.name = Respawn
keybind.control.name = Einheit steuern keybind.control.name = Einheit steuern
@@ -888,7 +888,7 @@ keybind.break_block.name = Block zerstören
keybind.deselect.name = Auswahl aufheben keybind.deselect.name = Auswahl aufheben
keybind.pickupCargo.name = Block aufheben keybind.pickupCargo.name = Block aufheben
keybind.dropCargo.name = Block fallen lassen keybind.dropCargo.name = Block fallen lassen
keybind.command.name = Eineiten kommandieren keybind.command.name = Einheiten kommandieren
keybind.shoot.name = Schießen keybind.shoot.name = Schießen
keybind.zoom.name = Zoomen keybind.zoom.name = Zoomen
keybind.menu.name = Menü keybind.menu.name = Menü
@@ -933,7 +933,7 @@ rules.blockdamagemultiplier = Block-Schaden-Multiplikator
rules.unitbuildspeedmultiplier = Baugeschwindigkeit-Einheit Multiplikator rules.unitbuildspeedmultiplier = Baugeschwindigkeit-Einheit Multiplikator
rules.unithealthmultiplier = Lebenspunkte-Einheit Multiplikator rules.unithealthmultiplier = Lebenspunkte-Einheit Multiplikator
rules.unitdamagemultiplier = Schaden-Einheit Multiplikator rules.unitdamagemultiplier = Schaden-Einheit Multiplikator
rules.enemycorebuildradius = Bauverbot Radius druch feindlichen Kern:[lightgray] (Kacheln) rules.enemycorebuildradius = Bauverbot-Radius durch feindlichen Kern:[lightgray] (Kacheln)
rules.wavespacing = Wellen-Abstand:[lightgray] (Sek) rules.wavespacing = Wellen-Abstand:[lightgray] (Sek)
rules.buildcostmultiplier = Bau-Kosten Multiplikator rules.buildcostmultiplier = Bau-Kosten Multiplikator
rules.buildspeedmultiplier = Bau-Schnelligkeit Multiplikator rules.buildspeedmultiplier = Bau-Schnelligkeit Multiplikator
@@ -1217,7 +1217,7 @@ block.multiplicative-reconstructor.name = Multiplikativer Rekonstrukteur
block.exponential-reconstructor.name = Exponentieller Rekonstrukteur block.exponential-reconstructor.name = Exponentieller Rekonstrukteur
block.tetrative-reconstructor.name = Tetrativer Rekonstrukteur block.tetrative-reconstructor.name = Tetrativer Rekonstrukteur
block.payload-conveyor.name = Einheitenförderband block.payload-conveyor.name = Einheitenförderband
block.payload-router.name = Einheitverteiler block.payload-router.name = Einheitenverteiler
block.disassembler.name = Großer Trenner block.disassembler.name = Großer Trenner
block.silicon-crucible.name = Silizium Schmelztiegel block.silicon-crucible.name = Silizium Schmelztiegel
block.overdrive-dome.name = Beschleunigungs-Maschine block.overdrive-dome.name = Beschleunigungs-Maschine
@@ -1230,7 +1230,7 @@ block.interplanetary-accelerator.name = Interplanetarischer Beschleuniger
block.switch.name = Schalter block.switch.name = Schalter
block.micro-processor.name = Mikroprozessor block.micro-processor.name = Mikroprozessor
block.logic-processor.name = Logikprozessor block.logic-processor.name = Logikprozessor
block.hyper-processor.name = Hyperprocessor block.hyper-processor.name = Hyperprozessor
block.logic-display.name = Logik-Bildschirm block.logic-display.name = Logik-Bildschirm
block.large-logic-display.name = Großer Logik-Bildschirm block.large-logic-display.name = Großer Logik-Bildschirm
block.memory-cell.name = Speicherzelle block.memory-cell.name = Speicherzelle
@@ -1245,83 +1245,86 @@ team.green.name = Grün
team.purple.name = Lila team.purple.name = Lila
hint.skip = Überspringen hint.skip = Überspringen
hint.desktopMove = Drücke [accent][[WASD][] um dich zu bewegen. hint.desktopMove = Drücke [accent][[WASD][], um dich zu bewegen.
hint.zoom = [accent]Scrolle[] um rein oder raus zu zoomen. hint.zoom = [accent]Scrolle[], um rein oder raus zu zoomen.
hint.mine = Bewege dich zum \uf8c4 Kupfererz und [accent]tippe darauf[], um es manuell abzubauen. hint.mine = Bewege dich zum \uf8c4 Kupfererz und [accent]tippe darauf[], um es manuell abzubauen.
hint.desktopShoot = Benutze [accent][[Links-Click][] um zu schießen. hint.desktopShoot = Benutze [accent][[Linksklick][], um zu schießen.
hint.depositItems = Um Materialien in den Kern zu tun, ziehe sie von dir zum Kern. hint.depositItems = Um Materialien in den Kern zu tun, ziehe sie von dir zum Kern.
hint.respawn = Um im Kern zu respawnen, drücke [accent][[V][]. hint.respawn = Um im Kern zu respawnen, drücke [accent][[V][].
hint.respawn.mobile = Du steuerst nun eine Einheit oder einen Block. Um wieder zur normalen Einheit zu werden, [accent]drücke die Abbildung von dir oben links.[] hint.respawn.mobile = Du steuerst nun eine Einheit oder einen Block. Um wieder zur normalen Einheit zu werden, [accent]drücke die Abbildung von dir oben links.[]
hint.desktopPause = Benutze [accent][[Leertaste][] um das Spiel zu pausieren oder entpausieren. hint.desktopPause = Benutze [accent][[Leertaste][], um das Spiel zu pausieren oder entpausieren.
hint.placeDrill = Wähle die \ue85e [accent]Bohrer[]-Kategorie im Menü unten rechts aus, drücke dann auf den \uf870 [accent]Bohrer[] und clicke auf ein Feld mit Kupfererz, um ihn zu platzieren. hint.placeDrill = Wähle die \ue85e [accent]Bohrer[]-Kategorie im Menü unten rechts aus, drücke dann auf den \uf870 [accent]Bohrer[] und klicke auf ein Feld mit Kupfererz, um ihn zu platzieren.
hint.placeDrill.mobile = Wähle die \ue85e[accent]Bohrer[]-Kategorie im Menü unten rechts aus, drücke dann auf den \uf870 [accent]Bohrer[] und clicke auf ein Feld mit Kupfererz, um ihn zu platzieren.\n\nGehe zuletzt auf das \ue800 [accent]Häkchen[] unten rechts, um dies zu bestätigen. hint.placeDrill.mobile = Wähle die \ue85e[accent]Bohrer[]-Kategorie im Menü unten rechts aus, drücke dann auf den \uf870 [accent]Bohrer[] und klicke auf ein Feld mit Kupfererz, um ihn zu platzieren.\n\nGehe zuletzt auf das \ue800 [accent]Häkchen[] unten rechts, um dies zu bestätigen.
hint.placeConveyor = Förderbänder bewegen Materialen zwischen verschiedene Blöcke. Wähle ein \uf896 [accent]Förderband[] aus der \ue814 [accent]Verteilung[]-Kategorie aus.\n\nClicke und bewege deine Maus, um mehrere Förderbänder zu setzen.\n[accent]Scrolle[] um sie zu drehen. hint.placeConveyor = Förderbänder bewegen Materialien zwischen verschiedenen Blöcken. Wähle ein \uf896 [accent]Förderband[] aus der \ue814 [accent]Verteilung[]-Kategorie aus.\n\nKlicke und bewege deine Maus, um mehrere Förderbänder zu setzen.\n[accent]Scrolle[] um sie zu drehen.
hint.placeConveyor.mobile = Förderbänder bewegen Materialen zwischen verschiedene Blöcke. Wähle ein \uf896 [accent]Förderband[] aus der \ue814 [accent]Verteilung[]-Kategorie aus.\n\nHalte deinen Finger eine Sekunde auf dem Bildschirmund bewege ihn dann, um mehrere Förderbänder zu setzen. hint.placeConveyor.mobile = Förderbänder bewegen Materialien zwischen verschiedenen Blöcken. Wähle ein \uf896 [accent]Förderband[] aus der \ue814 [accent]Verteilung[]-Kategorie aus.\n\nHalte deinen Finger eine Sekunde auf dem Bildschirm und bewege ihn dann, um mehrere Förderbänder zu setzen.
hint.placeTurret = Platziere \uf861 [accent]Geschütze[] um deine Basis vor Gegnern zu beschützen.\n\nGeschütze benötigen Munition - in diesem Fall \uf838Kupfer.\nBenutze Bohrer und Förderbänder, um dies zu besorgen. hint.placeTurret = Platziere \uf861 [accent]Geschütze[], um deine Basis vor Gegnern zu beschützen.\n\nGeschütze benötigen Munition - in diesem Fall \uf838Kupfer.\nBenutze Bohrer und Förderbänder, um dies zu besorgen.
hint.breaking = Benutze [accent]Rechts-Click[] und bewege deine Maus, um zu zerstören. hint.breaking = Benutze [accent]Rechtsklick[] und bewege deine Maus, um zu zerstören.
hint.breaking.mobile = Aktiviere den \ue817 [accent]Hammer[] unten rechts and tippe, um Blöcke zu zerstören.\n\nHalte deinen Finger auf dem Bildschirm um eine Fläche auszuwählen. hint.breaking.mobile = Aktiviere den \ue817 [accent]Hammer[] unten rechts und tippe, um Blöcke zu zerstören.\n\nHalte deinen Finger auf dem Bildschirm, um eine Fläche auszuwählen.
hint.research = Nehme den \ue875 [accent]Forschen[]-Knopf um neue Technologien zu erforschen. hint.research = Nehme den \ue875 [accent]Forschen[]-Knopf um neue Technologien zu erforschen.
hint.research.mobile = Nehme den \ue875 [accent]Forschen[]-Knopf im \ue88c [accent]Menü[] um neue Technologien zu erforschen. hint.research.mobile = Nehme den \ue875 [accent]Forschen[]-Knopf im \ue88c [accent]Menü[], um neue Technologien zu erforschen.
hint.unitControl = Halte [accent][[L-STRG][] und [accent]clicke[] um alliierte Einheiten oder Geschütze zu steuern. hint.unitControl = Halte [accent][[L-STRG][] und [accent]klicke[], um alliierte Einheiten oder Geschütze zu steuern.
hint.unitControl.mobile = [accent][Doppel-Clicke[], um alliierte Einheiten oder Geschütze zu steuern. hint.unitControl.mobile = [accent][Doppelklicke[], um alliierte Einheiten oder Geschütze zu steuern.
hint.launch = Sobald du genug Ressourcen gesammelt hast, kannst du [accent]Starten[], indem du andere Sektoren auf der \ue827 [accent]Karte[] unten rechts auswählst. hint.launch = Sobald du genug Ressourcen gesammelt hast, kannst du [accent]Starten[], indem du andere Sektoren auf der \ue827 [accent]Karte[] unten rechts auswählst.
hint.launch.mobile = Sobald du genug Ressourcen gesammelt hast, kannst du [accent]Starten[], indem du andere Sektoren auf der \ue827 [accent]Karte[] im \ue88c [accent]Menu[] auswählst. hint.launch.mobile = Sobald du genug Ressourcen gesammelt hast, kannst du [accent]Starten[], indem du andere Sektoren auf der \ue827 [accent]Karte[] im \ue88c [accent]Menü[] auswählst.
hint.schematicSelect = Halte [accent][[F][] gedrückt und bewege deine Maus, um Blöcke zu kopieren.\n\nMit [accent][[Mittel-Click][] kannst du einen einzelnen Block kopieren. hint.schematicSelect = Halte [accent][[F][] gedrückt und bewege deine Maus, um Blöcke zu kopieren.\n\nMit [accent][[Mittelklick][] kannst du einen einzelnen Block kopieren.
hint.conveyorPathfind = Halte [accent][[L-STRG][] während du Förderbänder baust, um automatisch einen Weg zu finden. hint.conveyorPathfind = Halte [accent][[L-STRG][] während du Förderbänder baust, um automatisch einen Weg zu finden.
hint.conveyorPathfind.mobile = Aktiviere den \ue844 [accent]Diagonal-Modus[] unten rechts und platziere Förderbänder, um automatisch einen Weg zu generieren. hint.conveyorPathfind.mobile = Aktiviere den \ue844 [accent]Diagonal-Modus[] unten rechts und platziere Förderbänder, um automatisch einen Weg zu generieren.
hint.boost = Halte [accent][[L-Shift][] gedrückt um über Hindernisse zu boosten.\n\nNur manche Bodeneinheiten können das. hint.boost = Halte [accent][[L-Shift][] gedrückt, um über Hindernisse zu boosten.\n\nNur manche Bodeneinheiten können das.
hint.command = Drücke [accent][[G][] um [accent]ähnliche[] Einheiten in Formation zu steuern.\n\nUm Bodeneinheiten zu steuern musst du zuerst eine Bodeneinheite werden. hint.command = Drücke [accent][[G][], um [accent]ähnliche[] Einheiten in Formation zu steuern.\n\nUm Bodeneinheiten zu steuern, musst du zuerst eine Bodeneinheit werden.
hint.command.mobile = [accent][[Doppel-Clicke][] deine Einheit um [accent]ähnliche[] Einheiten in Formation zu steuern. hint.command.mobile = [accent][[Doppelklicke][] deine Einheit, um [accent]ähnliche[] Einheiten in Formation zu steuern.
hint.payloadPickup = Du kannst [accent][[[] drücken, um kleine Einheiten oder Blöcke hochzuheben. hint.payloadPickup = Du kannst [accent][[[] drücken, um kleine Einheiten oder Blöcke hochzuheben.
hint.payloadPickup.mobile = [accent]Halte deinen Finger[] auf eine kleine Einheit oder einen kleinen Block, um ihn aufzuheben. hint.payloadPickup.mobile = [accent]Halte deinen Finger[] auf eine kleine Einheit oder einen kleinen Block, um ihn aufzuheben.
hint.payloadDrop = Drücke [accent]][] um etwas fallen zu lassen. hint.payloadDrop = Drücke [accent]][], um etwas fallen zu lassen.
hint.payloadDrop.mobile = [accent]Halte deinen Finger[] auf einen Freien Ort um eine Einheit oder einen Block da fallen zu lassen. hint.payloadDrop.mobile = [accent]Halte deinen Finger[] auf einen freien Ort, um eine Einheit oder einen Block da fallen zu lassen.
hint.waveFire = [accent]Wellen[]-Geschütze mit Wassermunition löschen automatisch Feuer. hint.waveFire = [accent]Wellen[]-Geschütze mit Wassermunition löschen automatisch Feuer.
hint.generator = \uf879 [accent]Verbrennungsgeneratoren[] verbrennen Kohle und übertragen diesen Strom in angrenzende Blöcke.\n\nDie Reichweite der Stromübertragung kann mit \uf87f [accent]Stromknoten[] erweitert werden. hint.generator = \uf879 [accent]Verbrennungsgeneratoren[] verbrennen Kohle und übertragen diesen Strom in angrenzende Blöcke.\n\nDie Reichweite der Stromübertragung kann mit \uf87f [accent]Stromknoten[] erweitert werden.
hint.guardian = [accent]Boss[]-Einheiten sind gepanzert. Schwache Munition wie [accent]Kupfer[] und [accent]Blei[] sind [scarlet]nicht ausreichend[].\n\nBenutze bessere Geschütze oder \uf835 [accent]Graphit[] als \uf861Duo-/\uf859Salvenmunition um einen Boss zu besiegen. hint.guardian = [accent]Boss[]-Einheiten sind gepanzert. Schwache Munition wie [accent]Kupfer[] und [accent]Blei[] sind [scarlet]nicht effektiv[].\n\nBenutze bessere Geschütze oder \uf835 [accent]Graphit[] als \uf861Duo-/\uf859Salvenmunition um einen Boss zu besiegen.
hint.coreUpgrade = Kerne können aufgerüstet werden, indem man [accent]bessere Kerne über sie platziert[].\n\nPlatziere einen  [accent]Fundament[]-Kern über einen  [accent]Scherben[]-Kern. Stelle sicher, dass ausreichend Platz verfügbar ist.
hint.presetLaunch = Zu grauen [accent]Sektoren[] wie dem [accent]Frozen Forest[] kann man von überall aus hin starten. Es ist nicht nötig, benachbarte Sektoren zu erobern.\n\n[accent]Nummerierte Sektoren[] wie dieser hier sind [accent]optional[].
hint.coreIncinerate = Wenn dem Kern Materialien zugeführt werden, für die er keinen Platz mehr hat, werden diese [accent]verbrannt[].
item.copper.description = Wird als Baumaterial oder Munition verwendet. item.copper.description = Wird als Baumaterial oder Munition verwendet.
item.copper.details = Kupfer. Auf Serpulo reichlich vorhanden. Strukturell schwach, solange es nicht verstärkt wird. item.copper.details = Kupfer. Auf Serpulo reichlich vorhanden. Strukturell schwach, solange es nicht verstärkt wird.
item.lead.description = Wird in elektrischen Blöcken oder beim Flüssigkeitstransport verwendet. item.lead.description = Wird in elektrischen Blöcken oder beim Flüssigkeitstransport verwendet.
item.lead.details = Dicht. Träge. Wird sehr oft in Batterien verwendet.\nInfo: Wahrscheinlich giftig für biologische Lebenwesen, obwohl es sowieso nicht mehr viele von denen gibt. item.lead.details = Dicht. Träge. Wird sehr oft in Batterien verwendet.\nInfo: Wahrscheinlich giftig für biologische Lebewesen, obwohl es sowieso nicht mehr viele von denen gibt.
item.metaglass.description = Wird beim Flüssigkeitstransport und -lagerung verwendet. item.metaglass.description = Wird beim Flüssigkeitstransport und -lagerung verwendet.
item.graphite.description = Wird als Munition oder elektrischer Leiter eingesetzt. item.graphite.description = Wird als Munition oder elektrischer Leiter eingesetzt.
item.sand.description = Nützlich für die Herstellung vieler anderer Materialen. item.sand.description = Nützlich für die Herstellung vieler anderer Materialien.
item.coal.description = Kann als Brennstoff oder zur Herstellung anderer Materialen verwendet werden. item.coal.description = Kann als Brennstoff oder zur Herstellung anderer Materialien verwendet werden.
item.coal.details = Scheint versteinerte Pflanzenmasse zu sein, die sich schon lange vor dem Seeding gebildet hat. item.coal.details = Scheint versteinerte Pflanzenmasse zu sein, die sich schon lange vor dem Seeding gebildet hat.
item.titanium.description = Wird im Flüssigkeitsbereich, im Bohrerbereich und für Flugzeuge vielfältig eingesetzt. item.titanium.description = Wird im Flüssigkeitsbereich, im Bohrerbereich und für Flugzeuge vielfältig eingesetzt.
item.thorium.description = Wird als festes Baumaterial oder radioaktiver Kraftstoff verwendet. item.thorium.description = Wird als festes Baumaterial oder radioaktiver Kraftstoff verwendet.
item.scrap.description = Wird in Pulverisierer und Schmelzer zu anderen Materialen bearbeitet. item.scrap.description = Wird in Pulverisierer und Schmelzer zu anderen Materialien bearbeitet.
item.scrap.details = Übriggebliebene Reste alter Gebäude oder Einheiten. item.scrap.details = Übriggebliebene Reste alter Gebäude oder Einheiten.
item.silicon.description = Wird in Solarzellen, komplizierte Elektronik und als zielsuchende Munition verwendet. item.silicon.description = Wird in Solarzellen, komplizierter Elektronik und als zielsuchende Munition verwendet.
item.plastanium.description = Wird für fortgeschrittene Einheiten, Isolation und Munition eingesetzt. item.plastanium.description = Wird für fortgeschrittene Einheiten, Isolation und Munition eingesetzt.
item.phase-fabric.description = Kann in Elektronik und selbstreparierende Blöcke verwendet werden. item.phase-fabric.description = Kann in Elektronik und selbstreparierende Blöcke verwendet werden.
item.surge-alloy.description = Wird in sehr fortgeschrittenen Waffen und Abwehrsystemen benutzt. item.surge-alloy.description = Wird in sehr fortgeschrittenen Waffen und Abwehrsystemen benutzt.
item.spore-pod.description = Wird zur Umwandlung in Öl, Sprengstoff und Kraftstoff verwendet. item.spore-pod.description = Wird zur Umwandlung in Öl, Sprengstoff und Kraftstoff verwendet.
item.spore-pod.details = Sporen. Wahrscheinlich ein künstlich erschaffenes Lebenwesen. Geben giftige Gase für andere Lebenwesen ab. Sehr invasiv. Unter bestimmten Bedingungen sehr brennbar. item.spore-pod.details = Sporen. Wahrscheinlich ein künstlich erschaffenes Lebewesen. Geben giftige Gase für andere Lebewesen ab. Sehr invasiv. Unter bestimmten Bedingungen sehr brennbar.
item.blast-compound.description = Wird in Bomben oder als explosive Munition verwendet. item.blast-compound.description = Wird in Bomben oder als explosive Munition verwendet.
item.pyratite.description = Kann in Verbrennungsgeneratoren oder als brennende Munition verbrannt werden. item.pyratite.description = Kann in Verbrennungsgeneratoren oder als brennende Munition verbrannt werden.
liquid.water.description = Wird üblicherweise zum Kühlen von Maschinen und zur Müllverarbeitung verwendet. liquid.water.description = Wird üblicherweise zum Kühlen von Maschinen und zur Müllverarbeitung verwendet.
liquid.slag.description = Kann in Trennern verfeinert oder als Waffe gegen Gegner verwendet werden. liquid.slag.description = Kann in Trennern verfeinert oder als Waffe gegen Gegner verwendet werden.
liquid.oil.description = Used in advanced material production and as incendiary ammunition. liquid.oil.description = Wird in fortgeschrittener Materialgewinnung und als brennende Munition verwendet.
liquid.cryofluid.description = Used as coolant in reactors, turrets and factories. Wird als Kühlung in Geschütze, Fabriken oder Reaktoren verwendet. liquid.cryofluid.description = Wird als Kühlung in Geschützen, Fabriken oder Reaktoren verwendet.
block.resupply-point.description = Füllt Einheiten in der Nähe mit Kupfermunition wieder auf. Nicht mit Einheiten kompatibel, die Strom benötigen. block.resupply-point.description = Füllt Einheiten in der Nähe mit Kupfermunition wieder auf. Nicht mit Einheiten kompatibel, die Strom benötigen.
block.armored-conveyor.description = Bewegt Materialen foran. Materialen können von der Seite nicht auf das Förderband. block.armored-conveyor.description = Bewegt Materialien voran. Materialien können von der Seite nicht auf das Förderband.
block.illuminator.description = Eine Lichtquelle. block.illuminator.description = Eine Lichtquelle.
block.message.description = Speichert eine Nachricht, die genutzt wird, um mit Verbündeten zu kommunizieren. block.message.description = Speichert eine Nachricht, die genutzt wird, um mit Verbündeten zu kommunizieren.
block.graphite-press.description = Komprimiert Kohle zu Graphit. block.graphite-press.description = Komprimiert Kohle zu Graphit.
block.multi-press.description = Komprimiert Kohle zu Graphit. Braucht für die Kühlung Wasser. block.multi-press.description = Komprimiert Kohle zu Graphit. Braucht für die Kühlung Wasser.
block.silicon-smelter.description = Stellt aus Sand und Kohle Silizium her. block.silicon-smelter.description = Stellt aus Sand und Kohle Silizium her.
block.kiln.description = Schmelzt Sand und Blei zu Metaglass. block.kiln.description = Schmelzt Sand und Blei zu Metaglas.
block.plastanium-compressor.description = Produziert Plastanium aus Öl und Titan. block.plastanium-compressor.description = Produziert Plastanium aus Öl und Titan.
block.phase-weaver.description = Produziert Phasengewebe aus Thorium und Sand. block.phase-weaver.description = Produziert Phasengewebe aus Thorium und Sand.
block.alloy-smelter.description = Verschmilzt Titan, Blei, Silizium und Kupfer zu einer Stromstoßlegierung. block.alloy-smelter.description = Verschmilzt Titan, Blei, Silizium und Kupfer zu einer Stromstoßlegierung.
block.cryofluid-mixer.description = Verarbeitet Wasser mit Titan zu einer Kryoflüssigkeit, die viel effizienter kühlt. block.cryofluid-mixer.description = Verarbeitet Wasser mit Titan zu einer Kryoflüssigkeit, die viel effizienter kühlt.
block.blast-mixer.description = Stellt aus Sporen und Pyratit eine explosive Mischung her. block.blast-mixer.description = Stellt aus Sporen und Pyratit eine explosive Mischung her.
block.pyratite-mixer.description = Vermischt Kohle, Blei und Sand zu hochentzündlichem Pyratit. block.pyratite-mixer.description = Vermischt Kohle, Blei und Sand zu hochentzündlichem Pyratit.
block.melter.description = Erhitzt Schrott um Schlacke zu erhalten. block.melter.description = Erhitzt Schrott, um Schlacke zu erhalten.
block.separator.description = Trennt Schlacke in seine Bestandteile. block.separator.description = Trennt Schlacke in seine Bestandteile.
block.spore-press.description = Komprimiert Sporen-Pods zu Öl. block.spore-press.description = Komprimiert Sporen-Pods zu Öl.
block.pulverizer.description = Zertrümmert Schrott zu Sand. block.pulverizer.description = Zertrümmert Schrott zu Sand.
@@ -1354,24 +1357,24 @@ block.force-projector.description = Erzeugt ein sechseckiges Kraftfeld um sich h
block.shock-mine.description = Greift Gegner mit Lichtbögen an, wenn sie über sie laufen. block.shock-mine.description = Greift Gegner mit Lichtbögen an, wenn sie über sie laufen.
block.conveyor.description = Bewegt Materialien vorwärts. block.conveyor.description = Bewegt Materialien vorwärts.
block.titanium-conveyor.description = Bewegt Materialien vorwärts, aber schneller als ein normales Förderband. block.titanium-conveyor.description = Bewegt Materialien vorwärts, aber schneller als ein normales Förderband.
block.plastanium-conveyor.description = Bewegt Materialen in Gruppen.\nNimmt hinten Materialien an und gibt sie vorne in drei Richtungen aus. Erfordert für maximale Effizienz mehrere Ein- und Ausgänge. block.plastanium-conveyor.description = Bewegt Materialien in Gruppen.\nNimmt hinten Materialien an und gibt sie vorne in drei Richtungen aus. Erfordert für maximale Effizienz mehrere Ein- und Ausgänge.
block.junction.description = Fungiert als Brücke zwischen zwei kreuzenden Förderbändern. block.junction.description = Fungiert als Brücke zwischen zwei kreuzenden Förderbändern.
block.bridge-conveyor.description = Transportiert Materialien über Terrain oder über Blöcke. block.bridge-conveyor.description = Transportiert Materialien über Terrain oder über Blöcke.
block.phase-conveyor.description = Transportiert Materialien sofort über Terrain oder über Blöcke. Höhere Reichweite als Brückenförderbänder, braucht aber Strom. block.phase-conveyor.description = Transportiert Materialien sofort über Terrain oder über Blöcke. Höhere Reichweite als Brückenförderbänder, braucht aber Strom.
block.sorter.description = Sortiert Materialien. Wenn ein Gegenstand der Auswahl entspricht, wird er vorne herausgegeben. Andernfalls wird er links oder rechts ausgegeben. block.sorter.description = Sortiert Materialien. Wenn ein Gegenstand der Auswahl entspricht, wird er vorne herausgegeben. Andernfalls wird er links oder rechts ausgegeben.
block.inverted-sorter.description = Wie ein normaler Sortierer, aber gibt das ausgewählte Material seitwärts aus. block.inverted-sorter.description = Wie ein normaler Sortierer, aber gibt das ausgewählte Material seitwärts aus.
block.router.description = Verteilt Materialen auf bis zu drei Richtungen. block.router.description = Verteilt Materialien auf bis zu drei Richtungen.
block.router.details = Ein nötiges Übel. Es is nicht empfehlenswert, ihn neben Fabriken zu setzen, da er sich dort verstopfen kann. block.router.details = Ein nötiges Übel. Es ist nicht empfehlenswert, ihn neben Fabriken zu setzen, da er sich dort verstopfen kann.
block.distributor.description = Verteilt Materialen auf bis zu sieben Richtungen. block.distributor.description = Verteilt Materialien auf bis zu sieben Richtungen.
block.overflow-gate.description = Gibt Materialen nur zu den Seiten heraus, wenn der fordere Ausgang blockiert ist. Kann nicht neben anderen Überlauf- oder Unterlauftoren verwendet werden. block.overflow-gate.description = Gibt Materialien nur zu den Seiten heraus, wenn der fordere Ausgang blockiert ist. Kann nicht neben anderen Überlauf- oder Unterlauftoren verwendet werden.
block.underflow-gate.description = Das Gegenteil eines Überlauftors. Gibt Materialen nur nach vorne heraus, wenn die Seiten blockiert sind. Kann nicht neben anderen Überlauf- oder Unterlauftoren verwendet werden. block.underflow-gate.description = Das Gegenteil eines Überlauftors. Gibt Materialien nur nach vorne heraus, wenn die Seiten blockiert sind. Kann nicht neben anderen Überlauf- oder Unterlauftoren verwendet werden.
block.mass-driver.description = Ein Transportblock mit sehr hoher Reichweite. Sammelt mehrere Materialien und schießt sie zu einem verbundenen Massenbeschleuniger. block.mass-driver.description = Ein Transportblock mit sehr hoher Reichweite. Sammelt mehrere Materialien und schießt sie zu einem verbundenen Massenbeschleuniger.
block.mechanical-pump.description = Eine Pumpe, die keinen Strom benötigt. block.mechanical-pump.description = Eine Pumpe, die keinen Strom benötigt.
block.rotary-pump.description = Eine Pumpe, die Strom verbraucht. block.rotary-pump.description = Eine Pumpe, die Strom verbraucht.
block.thermal-pump.description = Eine Pumpe. block.thermal-pump.description = Eine Pumpe.
block.conduit.description = Transportiert Flüssigkeiten. Wird mit Extraktoren, Pumpen oder anderen Kanälen benutzt. block.conduit.description = Transportiert Flüssigkeiten. Wird mit Extraktoren, Pumpen oder anderen Kanälen benutzt.
block.pulse-conduit.description = Transportiert Flüssigkeiten. Transportiert Flüssigkeiten schneller und speichert mehr als ein Leitungsrohr. block.pulse-conduit.description = Transportiert Flüssigkeiten. Transportiert Flüssigkeiten schneller und speichert mehr als ein Leitungsrohr.
block.plated-conduit.description = Transportiert Flüssigkeiten. Nimmt keine Flüssigkeiten von der Seite an.\nHat keine Leks. block.plated-conduit.description = Transportiert Flüssigkeiten. Nimmt keine Flüssigkeiten von der Seite an.\nHat keine Lecks.
block.liquid-router.description = Verteilt Flüssigkeiten auf bis zu drei Richtungen. Speicher außerdem eine kleine Menge an Flüssigkeit. block.liquid-router.description = Verteilt Flüssigkeiten auf bis zu drei Richtungen. Speicher außerdem eine kleine Menge an Flüssigkeit.
block.liquid-tank.description = Speichert eine große Menge an Flüssigkeiten. Ähnlich wie ein Flüssigkeitsverteiler. block.liquid-tank.description = Speichert eine große Menge an Flüssigkeiten. Ähnlich wie ein Flüssigkeitsverteiler.
block.liquid-junction.description = Fungiert als Brücke über zwei kreuzende Kanäle. block.liquid-junction.description = Fungiert als Brücke über zwei kreuzende Kanäle.
@@ -1385,37 +1388,37 @@ block.battery.description = Speichert Strom, solange ein Überschuss besteht, un
block.battery-large.description = Speichert Strom, solange ein Überschuss besteht, und gibt ihn bei Knappheit ab, solange Kapazität vorhanden ist. Speichert mehr Strom als eine normale Batterie. block.battery-large.description = Speichert Strom, solange ein Überschuss besteht, und gibt ihn bei Knappheit ab, solange Kapazität vorhanden ist. Speichert mehr Strom als eine normale Batterie.
block.combustion-generator.description = Generiert Strom, indem Kohle oder andere entzündliche Materialien verbrannt werden. block.combustion-generator.description = Generiert Strom, indem Kohle oder andere entzündliche Materialien verbrannt werden.
block.thermal-generator.description = Erzeugt an heißen Orten große Mengen Strom. block.thermal-generator.description = Erzeugt an heißen Orten große Mengen Strom.
block.steam-generator.description = Wandelt mit endzündlichen Materialen Wasser zu Wasserdampf um und benutzt diesen dann, um Strom zu generieren. block.steam-generator.description = Wandelt mit entzündlichen Materialien Wasser zu Wasserdampf um und benutzt diesen dann, um Strom zu generieren.
block.differential-generator.description = Erzeugt große Mengen an Energie. Nutzt den Temperaturunterschied zwischen Kryofluid und brennendem Pyratit. block.differential-generator.description = Erzeugt große Mengen an Energie. Nutzt den Temperaturunterschied zwischen Kryoflüssigkeit und brennendem Pyratit.
block.rtg-generator.description = Ein Radioisotopengenerator, der aus radioaktivem Zerfall Energie herstellt. block.rtg-generator.description = Ein Radioisotopengenerator, der aus radioaktivem Zerfall Energie herstellt.
block.solar-panel.description = Erzeugt kleine Mengen an Strom aus Sonnenenergie. block.solar-panel.description = Erzeugt kleine Mengen an Strom aus Sonnenenergie.
block.solar-panel-large.description = Erzeugt kleine Mengen an Strom aus Sonnenenergie. Effizienter als eine normale Solarzelle. block.solar-panel-large.description = Erzeugt kleine Mengen an Strom aus Sonnenenergie. Effizienter als eine normale Solarzelle.
block.thorium-reactor.description = Erzeugt riesige Mengen Strom aus Thorium. Benötigt konstante Kühlung. Explodiert gewaltsam, wenn unzureichende Kühlung vorhanden ist. block.thorium-reactor.description = Erzeugt riesige Mengen Strom aus Thorium. Benötigt konstante Kühlung. Explodiert gewaltsam, wenn unzureichende Kühlung vorhanden ist.
block.impact-reactor.description = Ein Generator, der bei höchster Effizienz enorme Mengen an Leistung erzeugen kann. Erfordert eine erhebliche Leistungsaufnahme, um den Prozess zu starten. block.impact-reactor.description = Ein Generator, der bei höchster Effizienz enorme Mengen an Leistung erzeugen kann. Erfordert eine erhebliche Leistungsaufnahme, um den Prozess zu starten.
block.mechanical-drill.description = Ein günstiger Bohrer. Wenn er auf Erz gesetzt wird, baut er unbegrenzt das Erz mit geringer Geschwindigkeit ab. Kann nur einfach Ressourcen abbauen. block.mechanical-drill.description = Ein günstiger Bohrer. Wenn er auf Erz gesetzt wird, baut er unbegrenzt das Erz mit geringer Geschwindigkeit ab. Kann nur einfach Ressourcen abbauen.
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.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.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.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.water-extractor.description = Extrahiert Wasser aus dem Boden. Verwende ihn, wenn es keinen See in der Nähe gibt.
block.cultivator.description = Kultiviert winzige Mengen atmosphärischer Mikrosporen in Sporen-Pods. block.cultivator.description = Kultiviert winzige Mengen atmosphärischer Mikrosporen in Sporen-Pods.
block.cultivator.details = Zurückgewonnene Technologie. Wird benutzt, um große Mengen Biomasse so effizient wie möglich herzustellen. Wahrscheinlich der ehemaliger Inkbator der Sporen, die Serpulo heute bedecken. block.cultivator.details = Zurückgewonnene Technologie. Wird benutzt, um große Mengen Biomasse so effizient wie möglich herzustellen. Wahrscheinlich der ehemaliger Inkubator der Sporen, die Serpulo heute bedecken.
block.oil-extractor.description = Verwendet große Mengen an Strom, Sand und Wasser um Öl zu extrahieren. block.oil-extractor.description = Verwendet große Mengen an Strom, Sand und Wasser, um Öl zu extrahieren.
block.core-shard.description = Kern der Basis. Einmal zerstört, ist jeglicher Kontakt zum Sektor verloren. block.core-shard.description = Kern der Basis. Einmal zerstört, ist jeglicher Kontakt zum Sektor verloren.
block.core-shard.details = The erste Version. Kompakt. Selbstduplizierend. Mit Einwmalraketen ausgestattet. Nicht für Interplanetarische Reisen geeignet. block.core-shard.details = Die erste Version. Kompakt. Selbstduplizierend. Mit Einmalraketen ausgestattet. Nicht für Interplanetarische Reisen geeignet.
block.core-foundation.description = Kern der Basis. Besser gepanzert. Speichert mehr Ressourcen. block.core-foundation.description = Kern der Basis. Besser gepanzert. Speichert mehr Ressourcen.
block.core-foundation.details = Die zeite Version. block.core-foundation.details = Die zweite Version.
block.core-nucleus.description = Kern der Basis. Sehr gut gepanzert. Speichert enorme Mengen an Ressourcen. block.core-nucleus.description = Kern der Basis. Sehr gut gepanzert. Speichert enorme Mengen an Ressourcen.
block.core-nucleus.details = Die dritte und letzte Version. block.core-nucleus.details = Die dritte und letzte Version.
block.vault.description = Speichert eine große Menge an Materialien pro Typ. Ein[lightgray] Entlader[] kann verwendet werden, um Materialien auszuladen. block.vault.description = Speichert eine große Menge an Materialien pro Typ. Ein[lightgray] Entlader[] kann verwendet werden, um Materialien auszuladen.
block.container.description = Speichert eine kleine Menge an Materialien pro Typ. Ein[lightgray] Entlader[] kann verwendet werden, um Materialien auszuladen. block.container.description = Speichert eine kleine Menge an Materialien pro Typ. Ein[lightgray] Entlader[] kann verwendet werden, um Materialien auszuladen.
block.unloader.description = Entlädt Materialien aus einem Block. block.unloader.description = Entlädt Materialien aus einem Block.
block.launch-pad.description = Startet Materialen in andere Sektoren. block.launch-pad.description = Startet Materialien in andere Sektoren.
block.duo.description = Schießt auf Gegner. block.duo.description = Schießt auf Gegner.
block.scatter.description = Ein mittelgroßer Anti-Luft-Turm. Sprüht Blei- oder Schrottklumpen auf feindliche Lufteinheiten. block.scatter.description = Ein mittelgroßer Anti-Luft-Turm. Sprüht Blei- oder Schrottklumpen auf feindliche Lufteinheiten.
block.scorch.description = Verbrennt alle Bodenfeinde in der Nähe. Hochwirksam im Nahbereich. block.scorch.description = Verbrennt alle Bodenfeinde in der Nähe. Hochwirksam im Nahbereich.
block.hail.description = Schießt kleine Geschosse auf weit entfernte Gegner. block.hail.description = Schießt kleine Geschosse auf weit entfernte Gegner.
block.wave.description = Schießt Flüssigkeiten auf Gegner. Löscht Feuer automatisch, wenn Wasser aks Munition verwendet wird. block.wave.description = Schießt Flüssigkeiten auf Gegner. Löscht Feuer automatisch, wenn Wasser als Munition verwendet wird.
block.lancer.description = Läd sich auf und schießt kräftige Laserstrahlen auf Feinde. block.lancer.description = Lädt sich auf und schießt kräftige Laserstrahlen auf Feinde.
block.arc.description = Schießt Lichtbögen in Richtung des Gegners. block.arc.description = Schießt Lichtbögen in Richtung des Gegners.
block.swarmer.description = Schießt zielsuchende Raketenschwärme ab. block.swarmer.description = Schießt zielsuchende Raketenschwärme ab.
block.salvo.description = Schießt Schüsse in Salven ab. block.salvo.description = Schießt Schüsse in Salven ab.
@@ -1423,16 +1426,16 @@ block.fuse.description = Schießt drei starke Strahlen mit kurzer Reichweite ab.
block.ripple.description = Schießt mehrere Schüsse gleichzeitig auf weit entfernte Gegner. block.ripple.description = Schießt mehrere Schüsse gleichzeitig auf weit entfernte Gegner.
block.cyclone.description = Schießt explodierende Geschosse auf Gegner. block.cyclone.description = Schießt explodierende Geschosse auf Gegner.
block.spectre.description = Schießt große, panzerbrechende Kugeln auf Luft- und Bodenziele. block.spectre.description = Schießt große, panzerbrechende Kugeln auf Luft- und Bodenziele.
block.meltdown.description = Läd sich auf und schießt einen starken, durchgängigen Laser auf Gegner. Braucht Kühlung. block.meltdown.description = Lädt sich auf und schießt einen starken, durchgängigen Laser auf Gegner. Braucht Kühlung.
block.foreshadow.description = Schießt einen eingizen Schuss mit einem einzigen Ziel über eine erstaunlich große Distanz. block.foreshadow.description = Schießt einen einzigen Schuss mit einem einzigen Ziel über eine erstaunlich große Distanz.
block.repair-point.description = Heilt durchgehend die nächste befreundete, beschädigte Einheit in der Umgebung. block.repair-point.description = Heilt durchgehend die nächste befreundete, beschädigte Einheit in der Umgebung.
block.segment.description = Beschädigt und zerstört gegnerische Projektile. Laser werden nicht anvisiert. block.segment.description = Beschädigt und zerstört gegnerische Projektile. Laser werden nicht anvisiert.
block.parallax.description = Benutzt einen Traktorstrahl, um Gegner heranzuziehen und sie dabei anzugreifen. block.parallax.description = Benutzt einen Traktorstrahl, um Gegner heranzuziehen und sie dabei anzugreifen.
block.tsunami.description = Schießt mit einem kräftgem Strahl aus Flüssigkeit auf Gegner. Löscht Feuer automatisch, wenn Wasser aks Munition verwendet wird. block.tsunami.description = Schießt mit einem kräftigen Strahl aus Flüssigkeit auf Gegner. Löscht Feuer automatisch, wenn Wasser als Munition verwendet wird.
block.silicon-crucible.description = Benutzt Pyratit als Hitzequelle, um aus Sand und Kohle Silizium herzustellen. Die Effizienz wird an heißen Orten erhöht. block.silicon-crucible.description = Benutzt Pyratit als Hitzequelle, um aus Sand und Kohle Silizium herzustellen. Die Effizienz wird an heißen Orten erhöht.
block.disassembler.description = Trennt Schlacke in winzige Mengen exotischer Mineralien, verliert dafür aber an Effizienz. Kann Thorium herstellen. block.disassembler.description = Trennt Schlacke in winzige Mengen exotischer Mineralien, verliert dafür aber an Effizienz. Kann Thorium herstellen.
block.overdrive-dome.description = Erhöht die Geschwindigkeit von nahegelegenen Blöcken. \nBenötigt Phasengewebe und Silizium. block.overdrive-dome.description = Erhöht die Geschwindigkeit von nahegelegenen Blöcken. \nBenötigt Phasengewebe und Silizium.
block.payload-conveyor.description = Bewegt größere Objeke, zum Beispiel Einheiten. block.payload-conveyor.description = Bewegt größere Objekte, zum Beispiel Einheiten.
block.payload-router.description = Verteilt Einheiten auf bis zu drei Richtungen. block.payload-router.description = Verteilt Einheiten auf bis zu drei Richtungen.
block.command-center.description = Steuert Einheiten mit verschiedenen Befehlen. block.command-center.description = Steuert Einheiten mit verschiedenen Befehlen.
block.ground-factory.description = Stellt Bodeneinheiten her. Einheiten können einfach so verwendet oder in einem Rekonstrukteur verbessert werden. block.ground-factory.description = Stellt Bodeneinheiten her. Einheiten können einfach so verwendet oder in einem Rekonstrukteur verbessert werden.
@@ -1450,7 +1453,7 @@ block.memory-cell.description = Speichert Informationen für einen Prozessor.
block.memory-bank.description = Speichert Informationen für einen Prozessor. Hohe Kapazität. block.memory-bank.description = Speichert Informationen für einen Prozessor. Hohe Kapazität.
block.logic-display.description = Zeigt mithilfe eines Prozessors Beliebiges an. block.logic-display.description = Zeigt mithilfe eines Prozessors Beliebiges an.
block.large-logic-display.description = Zeigt mithilfe eines Prozessors Beliebiges an. block.large-logic-display.description = Zeigt mithilfe eines Prozessors Beliebiges an.
block.interplanetary-accelerator.description = Ein riesen Railgun-Turm, der mithilfe des Elektromagnetismuses Kerne auf die nötige Geschwindigkeit bringt, um interplanetarisches Reisen zu ermöglichen. block.interplanetary-accelerator.description = Ein Riesen-Railgun-Turm, der mithilfe des Elektromagnetismus Kerne auf die nötige Geschwindigkeit bringt, um interplanetarisches Reisen zu ermöglichen.
unit.dagger.description = Schießt normale Kugeln auf alle Feinde in der Nähe. unit.dagger.description = Schießt normale Kugeln auf alle Feinde in der Nähe.
unit.mace.description = Schießt Feuer auf alle Gegner in der Nähe. unit.mace.description = Schießt Feuer auf alle Gegner in der Nähe.
@@ -1475,7 +1478,7 @@ unit.eclipse.description = Feuert zwei durchdringende Laser und einen Flaksperrf
unit.mono.description = Baut Automatisch Blei und Kupfer ab. Dieses wird in den Kern gebracht. unit.mono.description = Baut Automatisch Blei und Kupfer ab. Dieses wird in den Kern gebracht.
unit.poly.description = Baut zerstörte Blöcke wieder auf und hilft anderen Einheiten beim Bauen. unit.poly.description = Baut zerstörte Blöcke wieder auf und hilft anderen Einheiten beim Bauen.
unit.mega.description = Heilt automatisch beschädigte Blöcke. Kann kleine Blöcke oder Bodeneinheiten tragen. unit.mega.description = Heilt automatisch beschädigte Blöcke. Kann kleine Blöcke oder Bodeneinheiten tragen.
unit.quad.description = Wirft große Bomben auf Bodenziele ab, welche Gegnern schaden und eingene Blöcke heilen. Kann Bodeneinheiten tragen. unit.quad.description = Wirft große Bomben auf Bodenziele ab, welche Gegnern schaden und einige Blöcke heilen. Kann Bodeneinheiten tragen.
unit.oct.description = Schützt mithilfe eines regenerierenden Schildes andere Einheiten. Kann die meisten Bodeneinheiten tragen. unit.oct.description = Schützt mithilfe eines regenerierenden Schildes andere Einheiten. Kann die meisten Bodeneinheiten tragen.
unit.risso.description = Schießt ein Sperrfeuer aus Raketen und Kugeln auf alle Gegner in der Nähe. unit.risso.description = Schießt ein Sperrfeuer aus Raketen und Kugeln auf alle Gegner in der Nähe.
unit.minke.description = Schießt Geschosse und Kugeln auf Feinde. unit.minke.description = Schießt Geschosse und Kugeln auf Feinde.

View File

@@ -13,6 +13,7 @@ link.google-play.description = Google Play 스토어 목록
link.f-droid.description = F-Droid 카탈로그 목록 link.f-droid.description = F-Droid 카탈로그 목록
link.wiki.description = 공식 Mindustry 위키 link.wiki.description = 공식 Mindustry 위키
link.suggestions.description = 새 기능 제안하기 link.suggestions.description = 새 기능 제안하기
link.bug.description = 버그 제보하기
linkfail = 링크를 열지 못했습니다!\nURL이 클립보드에 복사되었습니다. linkfail = 링크를 열지 못했습니다!\nURL이 클립보드에 복사되었습니다.
screenshot = 스크린 캡처가 {0} 에 저장되었습니다. screenshot = 스크린 캡처가 {0} 에 저장되었습니다.
screenshot.invalid = 맵이 너무 커서 스크린 캡처에 사용될 메모리가 부족합니다. screenshot.invalid = 맵이 너무 커서 스크린 캡처에 사용될 메모리가 부족합니다.
@@ -299,7 +300,7 @@ cancelbuilding = [accent][[{0}][] 를 눌러 건설 계획을 초기화
selectschematic = [accent][[{0}][] 를 눌러 선택+복사 selectschematic = [accent][[{0}][] 를 눌러 선택+복사
pausebuilding = [accent][[{0}][] 를 눌러 건설을 일시중지 pausebuilding = [accent][[{0}][] 를 눌러 건설을 일시중지
resumebuilding = [scarlet][[{0}][] 를 눌러 건설을 재개 resumebuilding = [scarlet][[{0}][] 를 눌러 건설을 재개
showui = UI를 .\n[accent][[{0}][] 키를 눌러 UI를 활성화 showui = [accent][[{0}][] 키를 눌러 UI를 활성화
wave = [accent]{0} 단계 wave = [accent]{0} 단계
wave.cap = [accent]단계 {0}/{1} wave.cap = [accent]단계 {0}/{1}
wave.waiting = 다음 단계까지[lightgray] {0}초 wave.waiting = 다음 단계까지[lightgray] {0}초
@@ -832,6 +833,7 @@ setting.chatopacity.name = 채팅창 투명도
setting.lasersopacity.name = 전선 투명도 setting.lasersopacity.name = 전선 투명도
setting.bridgeopacity.name = 터널 투명도 setting.bridgeopacity.name = 터널 투명도
setting.playerchat.name = 채팅 말풍선 표시 setting.playerchat.name = 채팅 말풍선 표시
setting.showweather.name = 날씨 그래픽 표시
public.confirm = 게임을 모두에게 공개하시겠습니까?\n[accent]모든 플레이어가 게임에 참여할 수 있습니다.\n[lightgray]설정->게임->멀티플레이 공용 서버로 표시에서 나중에 변경할 수 있습니다.\n\n[sky]번역자 추가[]\n[accent]친구끼리 하려고 이 기능을 활성화 한 뒤에, 친구 외에 다른 플레이어가 들어왔을 때\n해당 플레이어를 차단하는 행위는 비매너를 넘어서는 얌체 행위 그 자체입니다.\n정말로 [scarlet]많은 다른 플레이어들이 오길 원한다[]면 확인하세요. public.confirm = 게임을 모두에게 공개하시겠습니까?\n[accent]모든 플레이어가 게임에 참여할 수 있습니다.\n[lightgray]설정->게임->멀티플레이 공용 서버로 표시에서 나중에 변경할 수 있습니다.\n\n[sky]번역자 추가[]\n[accent]친구끼리 하려고 이 기능을 활성화 한 뒤에, 친구 외에 다른 플레이어가 들어왔을 때\n해당 플레이어를 차단하는 행위는 비매너를 넘어서는 얌체 행위 그 자체입니다.\n정말로 [scarlet]많은 다른 플레이어들이 오길 원한다[]면 확인하세요.
public.beta = 베타 버전의 게임은 공개 서버를 만들 수 없습니다. public.beta = 베타 버전의 게임은 공개 서버를 만들 수 없습니다.
uiscale.reset = UI 스케일이 변경되었습니다.\n"확인"버튼을 눌러 저장하세요.\n[accent] {0}[][scarlet]초 후에 예전 설정으로 되돌리고 게임을 종료합니다... uiscale.reset = UI 스케일이 변경되었습니다.\n"확인"버튼을 눌러 저장하세요.\n[accent] {0}[][scarlet]초 후에 예전 설정으로 되돌리고 게임을 종료합니다...

View File

@@ -13,6 +13,7 @@ link.google-play.description = Strona w sklepie Google Play
link.f-droid.description = Wykaz Katalogu F-Droid link.f-droid.description = Wykaz Katalogu F-Droid
link.wiki.description = Oficjana Wiki Mindustry link.wiki.description = Oficjana Wiki Mindustry
link.suggestions.description = Zaproponuj nowe funkcje link.suggestions.description = Zaproponuj nowe funkcje
link.bug.description = Znalazłeś błąd? Zgłoś go tutaj
linkfail = Nie udało się otworzyć linku!\nURL został skopiowany. linkfail = Nie udało się otworzyć linku!\nURL został skopiowany.
screenshot = Zapisano zrzut ekranu w {0} screenshot = Zapisano zrzut ekranu w {0}
screenshot.invalid = Zrzut ekranu jest zbyt duży. Najprawdopodobniej brakuje miejsca w pamięci urządzenia. screenshot.invalid = Zrzut ekranu jest zbyt duży. Najprawdopodobniej brakuje miejsca w pamięci urządzenia.
@@ -196,6 +197,7 @@ servers.local = Serwery Lokalne
servers.remote = Serwery Zdalne servers.remote = Serwery Zdalne
servers.global = Serwery Publiczne servers.global = Serwery Publiczne
servers.disclaimer = Serwery społeczności [accent]nie są[] w posiadaniu ani nie moderuje nimi twórca gry.\n\nSerwery mogą posiadać zawartość stworzoną przez graczy, która może być nieodpowiednia dla wszystkich grup wiekowych.
servers.showhidden = Pokaż Ukryte Serwery servers.showhidden = Pokaż Ukryte Serwery
server.shown = Pokazane server.shown = Pokazane
server.hidden = Ukryte server.hidden = Ukryte
@@ -510,7 +512,7 @@ resources = Zasoby
bannedblocks = Zabronione bloki bannedblocks = Zabronione bloki
addall = Dodaj wszystkie addall = Dodaj wszystkie
launch.from = Wstrzelony Z: [accent]{0} launch.from = Wstrzelony Z: [accent]{0}
launch.destination = Cell: {0} launch.destination = Cel: {0}
configure.invalid = Ilość musi być liczbą pomiędzy 0 a {0}. configure.invalid = Ilość musi być liczbą pomiędzy 0 a {0}.
add = Dodaj... add = Dodaj...
boss.health = Zdrowie Strażnika boss.health = Zdrowie Strażnika
@@ -831,6 +833,7 @@ setting.chatopacity.name = Przezroczystość czatu
setting.lasersopacity.name = Przezroczystość laserów zasilających setting.lasersopacity.name = Przezroczystość laserów zasilających
setting.bridgeopacity.name = Przezroczystość mostów setting.bridgeopacity.name = Przezroczystość mostów
setting.playerchat.name = Wyświetlaj czat w grze setting.playerchat.name = Wyświetlaj czat w grze
setting.showweather.name = Pokaż pogodę
public.confirm = Czy chcesz ustawić swoją grę jako publiczną?\n[accent]Każdy będzie mógł dołączyć do Twojej gry.\n[lightgray]Można to później zmienić w Ustawienia->Gra->Widoczność Gry Publicznej. public.confirm = Czy chcesz ustawić swoją grę jako publiczną?\n[accent]Każdy będzie mógł dołączyć do Twojej gry.\n[lightgray]Można to później zmienić w Ustawienia->Gra->Widoczność Gry Publicznej.
public.beta = Wersje beta gry nie mogą tworzyć publicznych pokoi. public.beta = Wersje beta gry nie mogą tworzyć publicznych pokoi.
uiscale.reset = Skala interfejsu uległa zmianie.\nNaciśnij "OK" by potwierdzić zmiany.\n[scarlet]Cofanie zmian i wyjście z gry za[accent] {0}[] uiscale.reset = Skala interfejsu uległa zmianie.\nNaciśnij "OK" by potwierdzić zmiany.\n[scarlet]Cofanie zmian i wyjście z gry za[accent] {0}[]
@@ -1279,6 +1282,10 @@ hint.payloadDrop.mobile = [accent]Kliknij i przytrzymaj[] w puste miejsce by opu
hint.waveFire = [accent]Strumień[] wypełniony wodą będzie gasić pobiskie pożary. hint.waveFire = [accent]Strumień[] wypełniony wodą będzie gasić pobiskie pożary.
hint.generator = \uf879 [accent]Generatory Spalinowe[] spalają węgiel i przekuzują moc do pobliskich bloków.\n\nMożesz powiększyć odległość transmitowanej mocy używająć \uf87f [accent]Węzeły Prądu[]. hint.generator = \uf879 [accent]Generatory Spalinowe[] spalają węgiel i przekuzują moc do pobliskich bloków.\n\nMożesz powiększyć odległość transmitowanej mocy używająć \uf87f [accent]Węzeły Prądu[].
hint.guardian = Jednostki [accent]Strażnicze[] są uzbrojone. Słaba amunicja - taka jak [accent]Miedź[] oraz [accent]Ołów[] [scarlet]nie jest efektywna[].\n\nUżyj lepszych działek takich jak \uf835 [accent]Naładowane Grafitem[] \uf861Duo/\uf859Salwa by pozbyć się strażników. hint.guardian = Jednostki [accent]Strażnicze[] są uzbrojone. Słaba amunicja - taka jak [accent]Miedź[] oraz [accent]Ołów[] [scarlet]nie jest efektywna[].\n\nUżyj lepszych działek takich jak \uf835 [accent]Naładowane Grafitem[] \uf861Duo/\uf859Salwa by pozbyć się strażników.
hint.coreUpgrade = Rdzenie mogą być ulepszone poprzez [accent]płożenie na nich rdzeń wyższego poziomu[].\n\nPołóż  rdzeń [accent]Fundacji[] na  rdzeń:[accent]Odłamek[] core. Żadna przeszkoda ani blok nie może stać na miejscu rdzenia.
hint.presetLaunch = Szare [accent]sektory[], takie jak [accent]Zamrożony Las[], to sektory do których możesz dotrzeć z każdego miejsca. Nie wymagają podbicia pobliskiego terenu.\n\n[accent]Ponumerowane sektory[], takie jak ten, [accent]są dodatkowe[].
hint.coreIncinerate = Jak rdzeń zostanie w pełni wypełniony danym przedmiotem, reszta przedmiotów tego typu zostanie [accent]spalona[].
hint.coopCampaign = Gdy grasz [accent]kooperacyjną kampanie[], przedmioty które są produkowane na mapie trafią także [accent]dotwoich lokalnych sektorów[].\n\nWszelkie nowe badania przeprowadzone przez hosta są również przenoszone.
item.copper.description = Przydatny materiał budowlany. Szeroko używany w prawie każdej konstrukcji. item.copper.description = Przydatny materiał budowlany. Szeroko używany w prawie każdej konstrukcji.
item.copper.details = Miedź. Nienormalnie obfity metal na Serpulo. Strukturalnie słaba, chyba że zostanie wzmocniona. item.copper.details = Miedź. Nienormalnie obfity metal na Serpulo. Strukturalnie słaba, chyba że zostanie wzmocniona.
@@ -1424,7 +1431,7 @@ block.ripple.description = Duża wieża artyleryjska, która strzela jednocześn
block.cyclone.description = Duża szybkostrzelna wieża. block.cyclone.description = Duża szybkostrzelna wieża.
block.spectre.description = Duże działo dwulufowe, które strzela potężnymi pociskami przebijającymi pancerz w jednostki naziemne i powietrzne. block.spectre.description = Duże działo dwulufowe, które strzela potężnymi pociskami przebijającymi pancerz w jednostki naziemne i powietrzne.
block.meltdown.description = Duże działo laserowe, które strzela potężnymi wiązkami dalekiego zasięgu. Wymaga chłodzenia. block.meltdown.description = Duże działo laserowe, które strzela potężnymi wiązkami dalekiego zasięgu. Wymaga chłodzenia.
block.foreshadow.description = Fires a large single-target bolt over long distances. block.foreshadow.description = Strzela potężnym pociskiem z daleka we wrogów.
block.repair-point.description = Bez przerw naprawia najbliższą uszkodzoną jednostkę w jego zasięgu. block.repair-point.description = Bez przerw naprawia najbliższą uszkodzoną jednostkę w jego zasięgu.
block.segment.description = Uszkadza i niszczy wrogie pociskiski poza laserami. block.segment.description = Uszkadza i niszczy wrogie pociskiski poza laserami.
block.parallax.description = Wykorzystuje laser, który przyciąga do siebie wrogów, zadając im obrażenia. block.parallax.description = Wykorzystuje laser, który przyciąga do siebie wrogów, zadając im obrażenia.

View File

@@ -13,6 +13,7 @@ link.google-play.description = Google Play
link.f-droid.description = Catalogul F-Droid link.f-droid.description = Catalogul F-Droid
link.wiki.description = Wikiul oficial al Mindustry link.wiki.description = Wikiul oficial al Mindustry
link.suggestions.description = Sugerează noi funcții link.suggestions.description = Sugerează noi funcții
link.bug.description = Ai găsit vreunul? Raportează-l aici
linkfail = Linkul nu a putut fi deschis!\nAdresa URL a fost copiată. linkfail = Linkul nu a putut fi deschis!\nAdresa URL a fost copiată.
screenshot = Captură de ecran salvată la {0} screenshot = Captură de ecran salvată la {0}
screenshot.invalid = Harta e prea mare. Se poate să nu existe suficientă memorie pentru captura de ecran. screenshot.invalid = Harta e prea mare. Se poate să nu existe suficientă memorie pentru captura de ecran.
@@ -832,6 +833,7 @@ setting.chatopacity.name = Opacitate Chat
setting.lasersopacity.name = Opacitate Laser Electric setting.lasersopacity.name = Opacitate Laser Electric
setting.bridgeopacity.name = Opacitate Poduri setting.bridgeopacity.name = Opacitate Poduri
setting.playerchat.name = Vezi Chat Temporar setting.playerchat.name = Vezi Chat Temporar
setting.showweather.name = Vezi Vremea
public.confirm = Vrei să îți faci jocul public?\n[accent]Oricine va putea intra în jocurile tale.\n[lightgray]Asta se poate schimba mai târziu în Setări->Joc->Vizibilitatea Jocurilor Publice. public.confirm = Vrei să îți faci jocul public?\n[accent]Oricine va putea intra în jocurile tale.\n[lightgray]Asta se poate schimba mai târziu în Setări->Joc->Vizibilitatea Jocurilor Publice.
public.beta = De reținut că versiunile beta ale jocului nu poate face servere publice. public.beta = De reținut că versiunile beta ale jocului nu poate face servere publice.
uiscale.reset = Scara interfeței a fost schimbată.\nApasă "OK" pt a confirma această scară.\n[scarlet]Revin setările și se iese în [accent] {0}[] secunde... uiscale.reset = Scara interfeței a fost schimbată.\nApasă "OK" pt a confirma această scară.\n[scarlet]Revin setările și se iese în [accent] {0}[] secunde...
@@ -1283,6 +1285,7 @@ hint.guardian = Unitățile [accent]Gardian[] au armuri puternice. Munițiile sl
hint.coreUpgrade = Un nucleu poate pot fi îmbunătățit [accent]plasând o alt nucleu mai bun peste el[].\n\nPlasează un nucleu  [accent]Foundation[] peste nucleul  [accent]Shard[]. Nucleul nu poate fi plasat decât pe alte nuclee. Asigură-te că nu sunt alte benzi sau obstacole care să împiedice plasarea. hint.coreUpgrade = Un nucleu poate pot fi îmbunătățit [accent]plasând o alt nucleu mai bun peste el[].\n\nPlasează un nucleu  [accent]Foundation[] peste nucleul  [accent]Shard[]. Nucleul nu poate fi plasat decât pe alte nuclee. Asigură-te că nu sunt alte benzi sau obstacole care să împiedice plasarea.
hint.presetLaunch = Poți lansa de oriunde în sectoarele gri, precum [accent]Pădurea Glacială[]. Ele sunt [accent]zone[] speciale [accent]de aterizare[]. Nu ai nevoie să capturezi sectoarele învecinate pt a lansa.\n\n[accent]Sectoarele numerotate[], ca acesta, sunt [accent]opționale[]. hint.presetLaunch = Poți lansa de oriunde în sectoarele gri, precum [accent]Pădurea Glacială[]. Ele sunt [accent]zone[] speciale [accent]de aterizare[]. Nu ai nevoie să capturezi sectoarele învecinate pt a lansa.\n\n[accent]Sectoarele numerotate[], ca acesta, sunt [accent]opționale[].
hint.coreIncinerate = După ce nucleul se umple până la refuz cu un tip de material, toate materialele în plus de acel tip care încearcă să între în nucleu sunt [accent]incinerate[]. hint.coreIncinerate = După ce nucleul se umple până la refuz cu un tip de material, toate materialele în plus de acel tip care încearcă să între în nucleu sunt [accent]incinerate[].
hint.coopCampaign = Când joci [accent]campania cooperând cu alți jucători[], materialele produse în sectorul curent vor fi transferate și către [accent]sectoarele tale locale[].\n\nDe asemenea, vei debloca tot ceea ce cercetează gazda.
item.copper.description = Folosit în tot felul de construcții și muniție. item.copper.description = Folosit în tot felul de construcții și muniție.
item.copper.details = Cupru. Metal anormal de abundent pe Serpulo. Structural slab dacă nu este consolidat. item.copper.details = Cupru. Metal anormal de abundent pe Serpulo. Structural slab dacă nu este consolidat.

View File

@@ -84,6 +84,7 @@ amrsoll
ねらひかだ ねらひかだ
Draco Draco
Quezler Quezler
killall -q
Alicila Alicila
Daniel Dusek Daniel Dusek
DeltaNedas DeltaNedas

Binary file not shown.

View File

@@ -50,5 +50,5 @@ const cons = method => new Cons(){get: method}
const prov = method => new Prov(){get: method} const prov = method => new Prov(){get: method}
const func = method => new Func(){get: method} const func = method => new Func(){get: method}
const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer})) const newEffect = (lifetime, renderer) => new Effect.Effect(lifetime, new Effect.EffectRenderer({render: renderer}))
Call = Packages.mindustry.gen.Call Call = Packages.mindustry.gen.Call

View File

@@ -52,7 +52,7 @@ const cons = method => new Cons(){get: method}
const prov = method => new Prov(){get: method} const prov = method => new Prov(){get: method}
const func = method => new Func(){get: method} const func = method => new Func(){get: method}
const newEffect = (lifetime, renderer) => new Effects.Effect(lifetime, new Effects.EffectRenderer({render: renderer})) const newEffect = (lifetime, renderer) => new Effect.Effect(lifetime, new Effect.EffectRenderer({render: renderer}))
Call = Packages.mindustry.gen.Call Call = Packages.mindustry.gen.Call
importPackage(Packages.arc) importPackage(Packages.arc)
@@ -165,6 +165,7 @@ const SectorInvasionEvent = Packages.mindustry.game.EventType.SectorInvasionEven
const SectorLoseEvent = Packages.mindustry.game.EventType.SectorLoseEvent const SectorLoseEvent = Packages.mindustry.game.EventType.SectorLoseEvent
const WorldLoadEvent = Packages.mindustry.game.EventType.WorldLoadEvent const WorldLoadEvent = Packages.mindustry.game.EventType.WorldLoadEvent
const ClientLoadEvent = Packages.mindustry.game.EventType.ClientLoadEvent const ClientLoadEvent = Packages.mindustry.game.EventType.ClientLoadEvent
const ContentInitEvent = Packages.mindustry.game.EventType.ContentInitEvent
const BlockInfoEvent = Packages.mindustry.game.EventType.BlockInfoEvent const BlockInfoEvent = Packages.mindustry.game.EventType.BlockInfoEvent
const CoreItemDeliverEvent = Packages.mindustry.game.EventType.CoreItemDeliverEvent const CoreItemDeliverEvent = Packages.mindustry.game.EventType.CoreItemDeliverEvent
const TurretAmmoDeliverEvent = Packages.mindustry.game.EventType.TurretAmmoDeliverEvent const TurretAmmoDeliverEvent = Packages.mindustry.game.EventType.TurretAmmoDeliverEvent

View File

@@ -17,6 +17,7 @@ import mindustry.game.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.input.*; import mindustry.input.*;
import mindustry.io.*; import mindustry.io.*;
import mindustry.logic.*;
import mindustry.maps.Map; import mindustry.maps.Map;
import mindustry.maps.*; import mindustry.maps.*;
import mindustry.mod.*; import mindustry.mod.*;
@@ -67,6 +68,8 @@ public class Vars implements Loadable{
public static final String reportIssueURL = "https://github.com/Anuken/Mindustry/issues/new?labels=bug&template=bug_report.md"; public static final String reportIssueURL = "https://github.com/Anuken/Mindustry/issues/new?labels=bug&template=bug_report.md";
/** list of built-in servers.*/ /** list of built-in servers.*/
public static final Seq<ServerGroup> defaultServers = Seq.with(); public static final Seq<ServerGroup> defaultServers = Seq.with();
/** maximum size of any block, do not change unless you know what you're doing */
public static final int maxBlockSize = 16;
/** maximum distance between mine and core that supports automatic transferring */ /** maximum distance between mine and core that supports automatic transferring */
public static final float mineTransferRange = 220f; public static final float mineTransferRange = 220f;
/** max chat message length */ /** max chat message length */
@@ -193,6 +196,7 @@ public class Vars implements Loadable{
public static BeControl becontrol; public static BeControl becontrol;
public static AsyncCore asyncCore; public static AsyncCore asyncCore;
public static BaseRegistry bases; public static BaseRegistry bases;
public static GlobalConstants constants;
public static Universe universe; public static Universe universe;
public static World world; public static World world;
@@ -266,6 +270,7 @@ public class Vars implements Loadable{
indexer = new BlockIndexer(); indexer = new BlockIndexer();
pathfinder = new Pathfinder(); pathfinder = new Pathfinder();
bases = new BaseRegistry(); bases = new BaseRegistry();
constants = new GlobalConstants();
state = new GameState(); state = new GameState();

View File

@@ -55,6 +55,12 @@ public class WaveSpawner{
public void spawnEnemies(){ public void spawnEnemies(){
spawning = true; spawning = true;
eachGroundSpawn((spawnX, spawnY, doShockwave) -> {
if(doShockwave){
doShockwave(spawnX, spawnY);
}
});
for(SpawnGroup group : state.rules.spawns){ for(SpawnGroup group : state.rules.spawns){
if(group.type == null) continue; if(group.type == null) continue;
@@ -86,18 +92,12 @@ public class WaveSpawner{
} }
} }
eachGroundSpawn((spawnX, spawnY, doShockwave) -> {
if(doShockwave){
doShockwave(spawnX, spawnY);
}
});
Time.runTask(121f, () -> spawning = false); Time.runTask(121f, () -> spawning = false);
} }
public void doShockwave(float x, float y){ public void doShockwave(float x, float y){
Time.run(20f, () -> Fx.spawnShockwave.at(x, y, state.rules.dropZoneRadius)); Fx.spawnShockwave.at(x, y, state.rules.dropZoneRadius);
Time.run(40f, () -> Damage.damage(state.rules.waveTeam, x, y, state.rules.dropZoneRadius, 99999999f, true)); Damage.damage(state.rules.waveTeam, x, y, state.rules.dropZoneRadius, 99999999f, true);
} }
public void eachGroundSpawn(Intc2 cons){ public void eachGroundSpawn(Intc2 cons){

View File

@@ -45,8 +45,18 @@ public class BuilderAI extends AIController{
//approach request if building //approach request if building
BuildPlan req = unit.buildPlan(); BuildPlan req = unit.buildPlan();
//clear break plan if another player is breaking something.
if(!req.breaking && timer.get(timerTarget2, 40f)){
for(Player player : Groups.player){
if(player.isBuilder() && player.unit().activelyBuilding() && player.unit().buildPlan().samePos(req) && player.unit().buildPlan().breaking){
unit.plans.removeFirst();
return;
}
}
}
boolean valid = boolean valid =
(req.tile() != null && req.tile().build instanceof ConstructBuild && req.tile().<ConstructBuild>bc().cblock == req.block) || (req.tile() != null && req.tile().build instanceof ConstructBuild cons && cons.cblock == req.block) ||
(req.breaking ? (req.breaking ?
Build.validBreak(unit.team(), req.x, req.y) : Build.validBreak(unit.team(), req.x, req.y) :
Build.validPlace(req.block, unit.team(), req.x, req.y, req.rotation)); Build.validPlace(req.block, unit.team(), req.x, req.y, req.rotation));
@@ -120,6 +130,6 @@ public class BuilderAI extends AIController{
@Override @Override
public boolean shouldShoot(){ public boolean shouldShoot(){
return !((Builderc)unit).isBuilding(); return !unit.isBuilding();
} }
} }

View File

@@ -12,7 +12,7 @@ public class FlyingAI extends AIController{
@Override @Override
public void updateMovement(){ public void updateMovement(){
if(target != null && unit.hasWeapons() && command() == UnitCommand.attack){ if(target != null && unit.hasWeapons() && command() == UnitCommand.attack){
if(unit.type.weapons.first().rotate){ if(unit.type.circleTarget){
moveTo(target, unit.range() * 0.8f); moveTo(target, unit.range() * 0.8f);
unit.lookAt(target); unit.lookAt(target);
}else{ }else{

View File

@@ -33,11 +33,10 @@ public class FormationAI extends AIController implements FormationMember{
} }
if(unit.type.canBoost){ if(unit.type.canBoost){
unit.elevation = Mathf.approachDelta(unit.elevation, !unit.canPassOn() ? 1f : leader.type.canBoost ? leader.elevation : 0f, 0.08f); unit.elevation = Mathf.approachDelta(unit.elevation, unit.onSolid() ? 1f : leader.type.canBoost ? leader.elevation : 0f, 0.08f);
} }
unit.controlWeapons(true, leader.isShooting); unit.controlWeapons(true, leader.isShooting);
// unit.moveAt(Tmp.v1.set(deltaX, deltaY).limit(unit.type().speed));
unit.aim(leader.aimX(), leader.aimY()); unit.aim(leader.aimX(), leader.aimY());
@@ -47,17 +46,10 @@ public class FormationAI extends AIController implements FormationMember{
unit.lookAt(unit.vel.angle()); unit.lookAt(unit.vel.angle());
} }
Vec2 realtarget = vec.set(target); Vec2 realtarget = vec.set(target).add(leader.vel.x, leader.vel.y);
float margin = 4f; float speed = unit.realSpeed() * unit.floorSpeedMultiplier();
unit.approach(Mathf.arrive(unit.x, unit.y, realtarget.x, realtarget.y, unit.vel, 0f, 0.01f, speed, 1f));
float speed = unit.realSpeed();
if(unit.dst(realtarget) <= margin){
//unit.vel.approachDelta(Vec2.ZERO, speed * type.accel / 2f);
}else{
unit.moveAt(realtarget.sub(unit).limit(speed));
}
if(unit.canMine() && leader.canMine()){ if(unit.canMine() && leader.canMine()){
if(leader.mineTile != null && unit.validMine(leader.mineTile)){ if(leader.mineTile != null && unit.validMine(leader.mineTile)){

View File

@@ -1,6 +1,7 @@
package mindustry.ai.types; package mindustry.ai.types;
import arc.math.*; import arc.math.*;
import arc.math.geom.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.ai.*; import mindustry.ai.*;
@@ -67,7 +68,7 @@ public class LogicAI extends AIController{
moveTo(Tmp.v1.set(moveX, moveY), 1f, 30f); moveTo(Tmp.v1.set(moveX, moveY), 1f, 30f);
} }
case approach -> { case approach -> {
moveTo(Tmp.v1.set(moveX, moveY), moveRad - 8f, 8f); moveTo(Tmp.v1.set(moveX, moveY), moveRad - 7f, 7);
} }
case pathfind -> { case pathfind -> {
Building core = unit.closestEnemyCore(); Building core = unit.closestEnemyCore();
@@ -103,7 +104,7 @@ public class LogicAI extends AIController{
//look where moving if there's nothing to aim at //look where moving if there's nothing to aim at
if(!shoot){ if(!shoot){
unit.lookAt(unit.prefRotation()); unit.lookAt(unit.prefRotation());
}else if(unit.hasWeapons()){ //if there is, look at the object }else if(unit.hasWeapons() && unit.mounts.length > 0){ //if there is, look at the object
unit.lookAt(unit.mounts[0].aimX, unit.mounts[0].aimY); unit.lookAt(unit.mounts[0].aimX, unit.mounts[0].aimY);
} }
} }
@@ -112,6 +113,24 @@ public class LogicAI extends AIController{
return radars.add(radar); return radars.add(radar);
} }
@Override
protected void moveTo(Position target, float circleLength, float smooth){
if(target == null) return;
vec.set(target).sub(unit);
float length = circleLength <= 0.001f ? 1f : Mathf.clamp((unit.dst(target) - circleLength) / smooth, -1f, 1f);
vec.setLength(unit.realSpeed() * length);
if(length < -0.5f){
vec.rotate(180f);
}else if(length < 0){
vec.setZero();
}
unit.approach(vec);
}
//always retarget //always retarget
@Override @Override
protected boolean retarget(){ protected boolean retarget(){

View File

@@ -4,6 +4,7 @@ import arc.*;
import arc.graphics.*; import arc.graphics.*;
import arc.graphics.g2d.*; import arc.graphics.g2d.*;
import arc.struct.*; import arc.struct.*;
import mindustry.*;
import mindustry.ctype.*; import mindustry.ctype.*;
import mindustry.entities.bullet.*; import mindustry.entities.bullet.*;
import mindustry.gen.*; import mindustry.gen.*;
@@ -134,7 +135,7 @@ public class Blocks implements ContentList{
//Registers build blocks //Registers build blocks
//no reference is needed here since they can be looked up by name later //no reference is needed here since they can be looked up by name later
for(int i = 1; i <= ConstructBlock.maxSize; i++){ for(int i = 1; i <= Vars.maxBlockSize; i++){
new ConstructBlock(i); new ConstructBlock(i);
} }
@@ -613,6 +614,7 @@ public class Blocks implements ContentList{
craftTime = 75f; craftTime = 75f;
size = 3; size = 3;
hasPower = true; hasPower = true;
itemCapacity = 20;
consumes.power(4f); consumes.power(4f);
consumes.items(with(Items.copper, 3, Items.lead, 4, Items.titanium, 2, Items.silicon, 3)); consumes.items(with(Items.copper, 3, Items.lead, 4, Items.titanium, 2, Items.silicon, 3));
@@ -981,7 +983,7 @@ public class Blocks implements ContentList{
junction = new Junction("junction"){{ junction = new Junction("junction"){{
requirements(Category.distribution, with(Items.copper, 2), true); requirements(Category.distribution, with(Items.copper, 2), true);
speed = 26; speed = 26;
capacity = 12; capacity = 6;
health = 30; health = 30;
buildCostMultiplier = 6f; buildCostMultiplier = 6f;
}}; }};
@@ -1514,7 +1516,7 @@ public class Blocks implements ContentList{
}}; }};
lancer = new PowerTurret("lancer"){{ lancer = new PowerTurret("lancer"){{
requirements(Category.turret, with(Items.copper, 25, Items.lead, 50, Items.silicon, 45)); requirements(Category.turret, with(Items.copper, 60, Items.lead, 70, Items.silicon, 50));
range = 165f; range = 165f;
chargeTime = 40f; chargeTime = 40f;
chargeMaxDelay = 30f; chargeMaxDelay = 30f;
@@ -1547,7 +1549,7 @@ public class Blocks implements ContentList{
}}; }};
arc = new PowerTurret("arc"){{ arc = new PowerTurret("arc"){{
requirements(Category.turret, with(Items.copper, 35, Items.lead, 50)); requirements(Category.turret, with(Items.copper, 50, Items.lead, 50));
shootType = new LightningBulletType(){{ shootType = new LightningBulletType(){{
damage = 20; damage = 20;
lightningLength = 25; lightningLength = 25;
@@ -1601,7 +1603,7 @@ public class Blocks implements ContentList{
}}; }};
salvo = new ItemTurret("salvo"){{ salvo = new ItemTurret("salvo"){{
requirements(Category.turret, with(Items.copper, 105, Items.graphite, 95, Items.titanium, 60)); requirements(Category.turret, with(Items.copper, 100, Items.graphite, 90, Items.titanium, 60));
ammo( ammo(
Items.copper, Bullets.standardCopper, Items.copper, Bullets.standardCopper,
Items.graphite, Bullets.standardDense, Items.graphite, Bullets.standardDense,

View File

@@ -32,6 +32,7 @@ public class Items implements ContentList{
sand = new Item("sand", Color.valueOf("f7cba4")){{ sand = new Item("sand", Color.valueOf("f7cba4")){{
alwaysUnlocked = true; alwaysUnlocked = true;
lowPriority = true;
}}; }};
coal = new Item("coal", Color.valueOf("272727")){{ coal = new Item("coal", Color.valueOf("272727")){{

View File

@@ -18,7 +18,7 @@ public class Liquids implements ContentList{
slag = new Liquid("slag", Color.valueOf("ffa166")){{ slag = new Liquid("slag", Color.valueOf("ffa166")){{
temperature = 1f; temperature = 1f;
viscosity = 0.8f; viscosity = 0.7f;
effect = StatusEffects.melting; effect = StatusEffects.melting;
lightColor = Color.valueOf("f0511d").a(0.4f); lightColor = Color.valueOf("f0511d").a(0.4f);
}}; }};

View File

@@ -25,10 +25,10 @@ public class StatusEffects implements ContentList{
effect = Fx.burning; effect = Fx.burning;
init(() -> { init(() -> {
opposite(wet,freezing); opposite(wet, freezing);
trans(tarred, ((unit, time, newTime, result) -> { trans(tarred, ((unit, time, newTime, result) -> {
unit.damagePierce(8f); unit.damagePierce(8f);
Fx.burning.at(unit.x() + Mathf.range(unit.bounds() / 2f), unit.y() + Mathf.range(unit.bounds() / 2f)); Fx.burning.at(unit.x + Mathf.range(unit.bounds() / 2f), unit.y + Mathf.range(unit.bounds() / 2f));
result.set(this, Math.min(time + newTime, 300f)); result.set(this, Math.min(time + newTime, 300f));
})); }));
}); });
@@ -93,8 +93,12 @@ public class StatusEffects implements ContentList{
effect = Fx.melting; effect = Fx.melting;
init(() -> { init(() -> {
trans(tarred, ((unit, time, newTime, result) -> result.set(this, Math.min(time + newTime / 2f, 140f))));
opposite(wet, freezing); opposite(wet, freezing);
trans(tarred, ((unit, time, newTime, result) -> {
unit.damagePierce(8f);
Fx.burning.at(unit.x + Mathf.range(unit.bounds() / 2f), unit.y + Mathf.range(unit.bounds() / 2f));
result.set(this, Math.min(time + newTime, 200f));
}));
}); });
}}; }};
@@ -119,7 +123,7 @@ public class StatusEffects implements ContentList{
effect = Fx.oily; effect = Fx.oily;
init(() -> { init(() -> {
trans(melting, ((unit, time, newTime, result) -> result.set(burning, newTime + time))); trans(melting, ((unit, time, newTime, result) -> result.set(melting, newTime + time)));
trans(burning, ((unit, time, newTime, result) -> result.set(burning, newTime + time))); trans(burning, ((unit, time, newTime, result) -> result.set(burning, newTime + time)));
}); });
}}; }};

View File

@@ -760,7 +760,7 @@ public class UnitTypes implements ContentList{
ejectEffect = Fx.casing1; ejectEffect = Fx.casing1;
shootSound = Sounds.artillery; shootSound = Sounds.artillery;
rotate = true; rotate = true;
occlusion = 8f; shadow = 8f;
recoil = 3f; recoil = 3f;
bullet = new ArtilleryBulletType(2f, 12){{ bullet = new ArtilleryBulletType(2f, 12){{
@@ -827,7 +827,7 @@ public class UnitTypes implements ContentList{
ejectEffect = Fx.casing1; ejectEffect = Fx.casing1;
shootSound = Sounds.shootBig; shootSound = Sounds.shootBig;
rotate = true; rotate = true;
occlusion = 12f; shadow = 12f;
recoil = 3f; recoil = 3f;
shots = 2; shots = 2;
spacing = 17f; spacing = 17f;
@@ -859,7 +859,7 @@ public class UnitTypes implements ContentList{
ejectEffect = Fx.casing3; ejectEffect = Fx.casing3;
shootSound = Sounds.artillery; shootSound = Sounds.artillery;
rotate = true; rotate = true;
occlusion = 30f; shadow = 30f;
bullet = new ArtilleryBulletType(3f, 50){{ bullet = new ArtilleryBulletType(3f, 50){{
hitEffect = Fx.sapExplosion; hitEffect = Fx.sapExplosion;
@@ -918,6 +918,7 @@ public class UnitTypes implements ContentList{
range = 140f; range = 140f;
targetAir = false; targetAir = false;
commandLimit = 4; commandLimit = 4;
circleTarget = true;
weapons.add(new Weapon(){{ weapons.add(new Weapon(){{
y = 0f; y = 0f;
@@ -950,6 +951,7 @@ public class UnitTypes implements ContentList{
armor = 3f; armor = 3f;
targetFlag = BlockFlag.factory; targetFlag = BlockFlag.factory;
commandLimit = 5; commandLimit = 5;
circleTarget = true;
weapons.add(new Weapon(){{ weapons.add(new Weapon(){{
minShootVelocity = 0.75f; minShootVelocity = 0.75f;
@@ -1059,7 +1061,7 @@ public class UnitTypes implements ContentList{
bullet = missiles; bullet = missiles;
shootSound = Sounds.missile; shootSound = Sounds.missile;
rotate = true; rotate = true;
occlusion = 6f; shadow = 6f;
}}, }},
new Weapon("missiles-mount"){{ new Weapon("missiles-mount"){{
y = -8f; y = -8f;
@@ -1070,7 +1072,7 @@ public class UnitTypes implements ContentList{
bullet = missiles; bullet = missiles;
shootSound = Sounds.missile; shootSound = Sounds.missile;
rotate = true; rotate = true;
occlusion = 6f; shadow = 6f;
}}, }},
new Weapon("large-bullet-mount"){{ new Weapon("large-bullet-mount"){{
y = 2f; y = 2f;
@@ -1082,7 +1084,7 @@ public class UnitTypes implements ContentList{
ejectEffect = Fx.casing1; ejectEffect = Fx.casing1;
shootSound = Sounds.shootBig; shootSound = Sounds.shootBig;
rotate = true; rotate = true;
occlusion = 8f; shadow = 8f;
bullet = new BasicBulletType(7f, 50){{ bullet = new BasicBulletType(7f, 50){{
width = 12f; width = 12f;
height = 18f; height = 18f;
@@ -1130,7 +1132,7 @@ public class UnitTypes implements ContentList{
reload = 45f; reload = 45f;
recoil = 4f; recoil = 4f;
shootSound = Sounds.laser; shootSound = Sounds.laser;
occlusion = 20f; shadow = 20f;
rotate = true; rotate = true;
bullet = new LaserBulletType(){{ bullet = new LaserBulletType(){{
@@ -1150,7 +1152,7 @@ public class UnitTypes implements ContentList{
rotateSpeed = 2f; rotateSpeed = 2f;
reload = 9f; reload = 9f;
shootSound = Sounds.shoot; shootSound = Sounds.shoot;
occlusion = 7f; shadow = 7f;
rotate = true; rotate = true;
recoil = 0.5f; recoil = 0.5f;
@@ -1165,7 +1167,7 @@ public class UnitTypes implements ContentList{
shake = 1f; shake = 1f;
shootSound = Sounds.shoot; shootSound = Sounds.shoot;
rotate = true; rotate = true;
occlusion = 12f; shadow = 12f;
bullet = fragBullet; bullet = fragBullet;
}}); }});
}}; }};
@@ -1517,7 +1519,7 @@ public class UnitTypes implements ContentList{
shootY = 7f; shootY = 7f;
shake = 5f; shake = 5f;
recoil = 4f; recoil = 4f;
occlusion = 12f; shadow = 12f;
shots = 1; shots = 1;
inaccuracy = 3f; inaccuracy = 3f;
@@ -1553,7 +1555,7 @@ public class UnitTypes implements ContentList{
x = 8.5f; x = 8.5f;
y = -9f; y = -9f;
occlusion = 6f; shadow = 6f;
rotateSpeed = 4f; rotateSpeed = 4f;
rotate = true; rotate = true;
@@ -1609,7 +1611,7 @@ public class UnitTypes implements ContentList{
rotateSpeed = 4f; rotateSpeed = 4f;
mirror = false; mirror = false;
occlusion = 20f; shadow = 20f;
shootY = 2f; shootY = 2f;
recoil = 4f; recoil = 4f;
@@ -1655,7 +1657,7 @@ public class UnitTypes implements ContentList{
shootY = 7f; shootY = 7f;
shake = 2f; shake = 2f;
recoil = 3f; recoil = 3f;
occlusion = 12f; shadow = 12f;
ejectEffect = Fx.casing3; ejectEffect = Fx.casing3;
shootSound = Sounds.shootBig; shootSound = Sounds.shootBig;
@@ -1701,7 +1703,7 @@ public class UnitTypes implements ContentList{
shootY = 23f; shootY = 23f;
shake = 6f; shake = 6f;
recoil = 10.5f; recoil = 10.5f;
occlusion = 50f; shadow = 50f;
shootSound = Sounds.railgun; shootSound = Sounds.railgun;
shots = 1; shots = 1;

View File

@@ -1,5 +1,6 @@
package mindustry.core; package mindustry.core;
import arc.*;
import arc.files.*; import arc.files.*;
import arc.func.*; import arc.func.*;
import arc.graphics.*; import arc.graphics.*;
@@ -7,8 +8,10 @@ import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.ctype.*; import mindustry.ctype.*;
import mindustry.game.EventType.*;
import mindustry.entities.bullet.*; import mindustry.entities.bullet.*;
import mindustry.mod.Mods.*; import mindustry.mod.Mods.*;
import mindustry.net.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.world.*; import mindustry.world.*;
@@ -96,6 +99,8 @@ public class ContentLoader{
/** Calls Content#init() on everything. Use only after all modules have been created.*/ /** Calls Content#init() on everything. Use only after all modules have been created.*/
public void init(){ public void init(){
initialize(Content::init); initialize(Content::init);
if(constants != null) constants.init();
Events.fire(new ContentInitEvent());
} }
/** Calls Content#load() on everything. Use only after all modules have been created on the client.*/ /** Calls Content#load() on everything. Use only after all modules have been created on the client.*/

View File

@@ -341,7 +341,7 @@ public class Control implements ApplicationListener, Loadable{
state.rules.waves = true; state.rules.waves = true;
//reset win wave?? //reset win wave??
state.rules.winWave = state.rules.attackMode ? -1 : sector.preset != null && sector.preset.captureWave > 0 ? sector.preset.captureWave : state.rules.winWave > state.wave ? state.rules.winWave : 40; state.rules.winWave = state.rules.attackMode ? -1 : sector.preset != null && sector.preset.captureWave > 0 ? sector.preset.captureWave : state.rules.winWave > state.wave ? state.rules.winWave : 30;
//if there's still an enemy base left, fix it //if there's still an enemy base left, fix it
if(state.rules.attackMode){ if(state.rules.attackMode){
@@ -424,7 +424,7 @@ public class Control implements ApplicationListener, Loadable{
net.dispose(); net.dispose();
Musics.dispose(); Musics.dispose();
Sounds.dispose(); Sounds.dispose();
ui.editor.dispose(); if(ui != null && ui.editor != null) ui.editor.dispose();
} }
@Override @Override

View File

@@ -41,7 +41,7 @@ public class NetServer implements ApplicationListener{
private static final Vec2 vector = new Vec2(); private static final Vec2 vector = new Vec2();
private static final Rect viewport = new Rect(); private static final Rect viewport = new Rect();
/** If a player goes away of their server-side coordinates by this distance, they get teleported back. */ /** If a player goes away of their server-side coordinates by this distance, they get teleported back. */
private static final float correctDist = tilesize * 8f; private static final float correctDist = tilesize * 12f;
public final Administration admins = new Administration(); public final Administration admins = new Administration();
public final CommandHandler clientCommands = new CommandHandler("/"); public final CommandHandler clientCommands = new CommandHandler("/");
@@ -284,7 +284,7 @@ public class NetServer implements ApplicationListener{
} }
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
result.append(Strings.format("[orange]-- Commands Page[lightgray] @[gray]/[lightgray]@[orange] --\n\n", (page+1), pages)); result.append(Strings.format("[orange]-- Commands Page[lightgray] @[gray]/[lightgray]@[orange] --\n\n", (page + 1), pages));
for(int i = commandsPerPage * page; i < Math.min(commandsPerPage * (page + 1), clientCommands.getCommandList().size); i++){ for(int i = commandsPerPage * page; i < Math.min(commandsPerPage * (page + 1), clientCommands.getCommandList().size); i++){
Command command = clientCommands.getCommandList().get(i); Command command = clientCommands.getCommandList().get(i);
@@ -347,8 +347,8 @@ public class NetServer implements ApplicationListener{
boolean checkPass(){ boolean checkPass(){
if(votes >= votesRequired()){ if(votes >= votesRequired()){
Call.sendMessage(Strings.format("[orange]Vote passed.[scarlet] @[orange] will be banned from the server for @ minutes.", target.name, (kickDuration/60))); Call.sendMessage(Strings.format("[orange]Vote passed.[scarlet] @[orange] will be banned from the server for @ minutes.", target.name, (kickDuration / 60)));
target.getInfo().lastKicked = Time.millis() + kickDuration*1000; target.getInfo().lastKicked = Time.millis() + kickDuration * 1000;
Groups.player.each(p -> p.uuid().equals(target.uuid()), p -> p.kick(KickReason.vote)); Groups.player.each(p -> p.uuid().equals(target.uuid()), p -> p.kick(KickReason.vote));
map[0] = null; map[0] = null;
task.cancel(); task.cancel();

View File

@@ -22,8 +22,8 @@ public interface Platform{
/** Dynamically loads a jar file. */ /** Dynamically loads a jar file. */
default Class<?> loadJar(Fi jar, String mainClass) throws Exception{ default Class<?> loadJar(Fi jar, String mainClass) throws Exception{
URLClassLoader classLoader = new URLClassLoader(new URL[]{jar.file().toURI().toURL()}, ClassLoader.getSystemClassLoader()); URLClassLoader classLoader = new URLClassLoader(new URL[]{jar.file().toURI().toURL()}, getClass().getClassLoader());
return classLoader.loadClass(mainClass); return Class.forName(mainClass, true, classLoader);
} }
/** Steam: Update lobby visibility.*/ /** Steam: Update lobby visibility.*/

View File

@@ -66,7 +66,7 @@ public class Renderer implements ApplicationListener{
float dest = Mathf.round(targetscale, 0.5f); float dest = Mathf.round(targetscale, 0.5f);
camerascale = Mathf.lerpDelta(camerascale, dest, 0.1f); camerascale = Mathf.lerpDelta(camerascale, dest, 0.1f);
if(Mathf.within(camerascale, dest, 0.001f)) camerascale = dest; if(Mathf.equal(camerascale, dest, 0.001f)) camerascale = dest;
laserOpacity = Core.settings.getInt("lasersopacity") / 100f; laserOpacity = Core.settings.getInt("lasersopacity") / 100f;
if(landTime > 0){ if(landTime > 0){
@@ -111,7 +111,10 @@ public class Renderer implements ApplicationListener{
minimap.dispose(); minimap.dispose();
effectBuffer.dispose(); effectBuffer.dispose();
blocks.dispose(); blocks.dispose();
if(planets != null){
planets.dispose(); planets.dispose();
planets = null;
}
if(bloom != null){ if(bloom != null){
bloom.dispose(); bloom.dispose();
bloom = null; bloom = null;

View File

@@ -186,14 +186,14 @@ public class World{
/** /**
* Call to signify the beginning of map loading. * Call to signify the beginning of map loading.
* BuildinghangeEvents will not be fired until endMapLoad(). * TileEvents will not be fired until endMapLoad().
*/ */
public void beginMapLoad(){ public void beginMapLoad(){
generating = true; generating = true;
} }
/** /**
* Call to signify the end of map loading. Updates tile occlusions and sets up physics for the world. * Call to signify the end of map loading. Updates tile proximities and sets up physics for the world.
* A WorldLoadEvent will be fire. * A WorldLoadEvent will be fire.
*/ */
public void endMapLoad(){ public void endMapLoad(){

View File

@@ -23,7 +23,7 @@ public class Damage{
private static Tile furthest; private static Tile furthest;
private static Rect rect = new Rect(); private static Rect rect = new Rect();
private static Rect hitrect = new Rect(); private static Rect hitrect = new Rect();
private static Vec2 tr = new Vec2(); private static Vec2 tr = new Vec2(), seg1 = new Vec2(), seg2 = new Vec2();
private static Seq<Unit> units = new Seq<>(); private static Seq<Unit> units = new Seq<>();
private static GridBits bits = new GridBits(30, 30); private static GridBits bits = new GridBits(30, 30);
private static IntQueue propagation = new IntQueue(); private static IntQueue propagation = new IntQueue();
@@ -120,6 +120,7 @@ public class Damage{
collidedBlocks.clear(); collidedBlocks.clear();
tr.trns(angle, length); tr.trns(angle, length);
Intc2 collider = (cx, cy) -> { Intc2 collider = (cx, cy) -> {
Building tile = world.build(cx, cy); Building tile = world.build(cx, cy);
boolean collide = tile != null && collidedBlocks.add(tile.pos()); boolean collide = tile != null && collidedBlocks.add(tile.pos());
@@ -131,17 +132,21 @@ public class Damage{
} }
//try to heal the tile //try to heal the tile
if(collide && hitter.type.collides(hitter, tile)){ if(collide && hitter.type.testCollision(hitter, tile)){
hitter.type.hitTile(hitter, tile, tile.health, false); hitter.type.hitTile(hitter, tile, tile.health, false);
} }
} }
}; };
if(hitter.type.collidesGround){ if(hitter.type.collidesGround){
world.raycastEachWorld(x, y, x + tr.x, y + tr.y, (cx, cy) -> { seg1.set(x, y);
seg2.set(seg1).add(tr);
world.raycastEachWorld(x, y, seg2.x, seg2.y, (cx, cy) -> {
collider.get(cx, cy); collider.get(cx, cy);
if(large){
for(Point2 p : Geometry.d4){ for(Point2 p : Geometry.d4){
Tile other = world.tile(p.x + cx, p.y + cy);
if(other != null && (large || Intersector.intersectSegmentRectangle(seg1, seg2, other.getBounds(Tmp.r1)))){
collider.get(cx + p.x, cy + p.y); collider.get(cx + p.x, cy + p.y);
} }
} }

View File

@@ -58,8 +58,8 @@ public class Predict{
ddy += h.deltaY(); ddy += h.deltaY();
} }
if(src instanceof Hitboxc h){ if(src instanceof Hitboxc h){
ddx -= h.deltaX()/(Time.delta); ddx -= h.deltaX();
ddy -= h.deltaY()/(Time.delta); ddy -= h.deltaY();
} }
return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), ddx, ddy, v); return intercept(src.getX(), src.getY(), dst.getX(), dst.getY(), ddx, ddy, v);
} }

View File

@@ -157,7 +157,7 @@ public abstract class BulletType extends Content{
return Math.max(speed * lifetime * (1f - drag), maxRange); return Math.max(speed * lifetime * (1f - drag), maxRange);
} }
public boolean collides(Bullet bullet, Building tile){ public boolean testCollision(Bullet bullet, Building tile){
return healPercent <= 0.001f || tile.team != bullet.team || tile.healthf() < 1f; return healPercent <= 0.001f || tile.team != bullet.team || tile.healthf() < 1f;
} }

View File

@@ -78,7 +78,7 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{
if(!(tile.block() instanceof ConstructBlock)){ if(!(tile.block() instanceof ConstructBlock)){
if(!current.initialized && !current.breaking && Build.validPlace(current.block, team, current.x, current.y, current.rotation)){ if(!current.initialized && !current.breaking && Build.validPlace(current.block, team, current.x, current.y, current.rotation)){
boolean hasAll = infinite || !Structs.contains(current.block.requirements, i -> core != null && !core.items.has(i.item)); boolean hasAll = infinite || current.isRotation(team) || !Structs.contains(current.block.requirements, i -> core != null && !core.items.has(i.item));
if(hasAll){ if(hasAll){
Call.beginPlace(self(), current.block, team, current.x, current.y, current.rotation); Call.beginPlace(self(), current.block, team, current.x, current.y, current.rotation);
@@ -102,13 +102,11 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{
} }
//if there is no core to build with or no build entity, stop building! //if there is no core to build with or no build entity, stop building!
if((core == null && !infinite) || !(tile.build instanceof ConstructBuild)){ if((core == null && !infinite) || !(tile.build instanceof ConstructBuild entity)){
return; return;
} }
//otherwise, update it. //otherwise, update it.
ConstructBuild entity = tile.bc();
if(current.breaking){ if(current.breaking){
entity.deconstruct(self(), core, 1f / entity.buildCost * Time.delta * type.buildSpeed * state.rules.buildSpeedMultiplier); entity.deconstruct(self(), core, 1f / entity.buildCost * Time.delta * type.buildSpeed * state.rules.buildSpeedMultiplier);
}else{ }else{
@@ -140,7 +138,8 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{
/** @return whether this request should be skipped, in favor of the next one. */ /** @return whether this request should be skipped, in favor of the next one. */
boolean shouldSkip(BuildPlan request, @Nullable Building core){ boolean shouldSkip(BuildPlan request, @Nullable Building core){
//requests that you have at least *started* are considered //requests that you have at least *started* are considered
if(state.rules.infiniteResources || team.rules().infiniteResources || request.breaking || core == null) return false; if(state.rules.infiniteResources || team.rules().infiniteResources || request.breaking || core == null || request.isRotation(team)) return false;
return (request.stuck && !core.items.has(request.block.requirements)) || (Structs.contains(request.block.requirements, i -> !core.items.has(i.item) && Mathf.round(i.amount * state.rules.buildCostMultiplier) > 0) && !request.initialized); return (request.stuck && !core.items.has(request.block.requirements)) || (Structs.contains(request.block.requirements, i -> !core.items.has(i.item) && Mathf.round(i.amount * state.rules.buildCostMultiplier) > 0) && !request.initialized);
} }
@@ -182,8 +181,8 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{
plans.remove(replace); plans.remove(replace);
} }
Tile tile = world.tile(place.x, place.y); Tile tile = world.tile(place.x, place.y);
if(tile != null && tile.build instanceof ConstructBuild){ if(tile != null && tile.build instanceof ConstructBuild cons){
place.progress = tile.<ConstructBuild>bc().progress; place.progress = cons.progress;
} }
if(tail){ if(tail){
plans.addLast(place); plans.addLast(place);

View File

@@ -201,7 +201,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
if(self() instanceof ConstructBuild entity){ if(self() instanceof ConstructBuild entity){
//update block to reflect the fact that something was being constructed //update block to reflect the fact that something was being constructed
if(entity.cblock != null && entity.cblock.synthetic()){ if(entity.cblock != null && entity.cblock.synthetic() && entity.wasConstructing){
block = entity.cblock; block = entity.cblock;
}else{ }else{
//otherwise this was a deconstruction that was interrupted, don't want to rebuild that //otherwise this was a deconstruction that was interrupted, don't want to rebuild that

View File

@@ -125,7 +125,7 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
Building tile = world.build(x, y); Building tile = world.build(x, y);
if(tile == null || !isAdded()) return false; if(tile == null || !isAdded()) return false;
if(tile.collide(self()) && type.collides(self(), tile) && !tile.dead() && (type.collidesTeam || tile.team != team) && !(type.pierceBuilding && collided.contains(tile.id))){ if(tile.collide(self()) && type.testCollision(self(), tile) && !tile.dead() && (type.collidesTeam || tile.team != team) && !(type.pierceBuilding && collided.contains(tile.id))){
boolean remove = false; boolean remove = false;
float health = tile.health; float health = tile.health;

View File

@@ -68,7 +68,7 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
if(isFlying() != wasFlying){ if(isFlying() != wasFlying){
if(wasFlying){ if(wasFlying){
if(tileOn() != null){ if(tileOn() != null){
Fx.unitLand.at(x, y, floorOn().isLiquid ? 1f : 0.5f, floorOn().mapColor); Fx.unitLand.at(x, y, floorOn().isLiquid ? 1f : 0.5f, tileOn().floor().mapColor);
} }
} }

View File

@@ -83,4 +83,12 @@ abstract class MechComp implements Posc, Flyingc, Hitboxc, Unitc, Mechc, Elevati
walked = true; walked = true;
} }
} }
@Override
public void approach(Vec2 vector){
if(!vector.isZero(0.09f)){
//mark walking state when moving in a controlled manner
walked = true;
}
}
} }

View File

@@ -117,6 +117,8 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{
u.rotation(rotation); u.rotation(rotation);
//reset the ID to a new value to make sure it's synced //reset the ID to a new value to make sure it's synced
u.id = EntityGroup.nextId(); u.id = EntityGroup.nextId();
//decrement count to prevent double increment
if(!u.isAdded()) u.team.data().updateCount(u.type, -1);
u.add(); u.add();
return true; return true;

View File

@@ -29,4 +29,15 @@ abstract class PhysicsComp implements Velc, Hitboxc, Flyingc{
void impulse(Vec2 v){ void impulse(Vec2 v){
impulse(v.x, v.y); impulse(v.x, v.y);
} }
void impulseNet(Vec2 v){
impulse(v.x, v.y);
//manually move units to simulate velocity for remote players
if(isRemote()){
float mass = mass();
move(v.x / mass, v.y / mass);
}
}
} }

View File

@@ -44,7 +44,6 @@ abstract class PuddleComp implements Posc, Puddlec, Drawc{
float addSpeed = accepting > 0 ? 3f : 0f; float addSpeed = accepting > 0 ? 3f : 0f;
amount -= Time.delta * (1f - liquid.viscosity) / (5f + addSpeed); amount -= Time.delta * (1f - liquid.viscosity) / (5f + addSpeed);
amount += accepting; amount += accepting;
accepting = 0f; accepting = 0f;

View File

@@ -38,6 +38,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
@Import Team team; @Import Team team;
@Import int id; @Import int id;
@Import @Nullable Tile mineTile; @Import @Nullable Tile mineTile;
@Import Vec2 vel;
private UnitController controller; private UnitController controller;
UnitType type; UnitType type;
@@ -51,6 +52,10 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
moveAt(vector, type.accel); moveAt(vector, type.accel);
} }
public void approach(Vec2 vector){
vel.approachDelta(vector, type.accel * realSpeed() * floorSpeedMultiplier());
}
public void aimLook(Position pos){ public void aimLook(Position pos){
aim(pos); aim(pos);
lookAt(pos); lookAt(pos);
@@ -397,6 +402,8 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
/** Actually destroys the unit, removing it and creating explosions. **/ /** Actually destroys the unit, removing it and creating explosions. **/
public void destroy(){ public void destroy(){
if(!isAdded()) return;
float explosiveness = 2f + item().explosiveness * stack().amount * 1.53f; float explosiveness = 2f + item().explosiveness * stack().amount * 1.53f;
float flammability = item().flammability * stack().amount / 1.9f; float flammability = item().flammability * stack().amount / 1.9f;

View File

@@ -3,6 +3,7 @@ package mindustry.entities.units;
import arc.func.*; import arc.func.*;
import arc.math.geom.*; import arc.math.geom.*;
import arc.util.*; import arc.util.*;
import mindustry.game.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.world.*; import mindustry.world.*;
@@ -61,6 +62,16 @@ public class BuildPlan implements Position{
} }
public boolean isRotation(Team team){
if(breaking) return false;
Tile tile = tile();
return tile != null && tile.team() == team && tile.block() == block && tile.build != null && tile.build.rotation != rotation;
}
public boolean samePos(BuildPlan other){
return x == other.x && y == other.y;
}
/** Transforms the internal position of this config using the specified function, and return the result. */ /** Transforms the internal position of this config using the specified function, and return the result. */
public static Object pointConfig(Block block, Object config, Cons<Point2> cons){ public static Object pointConfig(Block block, Object config, Cons<Point2> cons){
if(config instanceof Point2){ if(config instanceof Point2){

View File

@@ -64,6 +64,8 @@ public class EventType{
public static class CoreItemDeliverEvent{} public static class CoreItemDeliverEvent{}
/** Called when the player opens info for a specific block.*/ /** Called when the player opens info for a specific block.*/
public static class BlockInfoEvent{} public static class BlockInfoEvent{}
/** Called *after* all content has been initialized. */
public static class ContentInitEvent{}
/** Called when the client game is first loaded. */ /** Called when the client game is first loaded. */
public static class ClientLoadEvent{} public static class ClientLoadEvent{}
/** Called when a game begins and the world is loaded. */ /** Called when a game begins and the world is loaded. */

View File

@@ -91,18 +91,23 @@ public class MinimapRenderer implements Disposable{
rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize); rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize);
for(Unit unit : units){ for(Unit unit : units){
float rx = !withLabels ? (unit.x() - rect.x) / rect.width * w : unit.x() / (world.width() * tilesize) * w; float rx = !withLabels ? (unit.x - rect.x) / rect.width * w : unit.x / (world.width() * tilesize) * w;
float ry = !withLabels ? (unit.y() - rect.y) / rect.width * h : unit.y() / (world.height() * tilesize) * h; float ry = !withLabels ? (unit.y - rect.y) / rect.width * h : unit.y / (world.height() * tilesize) * h;
Draw.mixcol(unit.team().color, 1f); Draw.mixcol(unit.team().color, 1f);
float scale = Scl.scl(1f) / 2f * scaling * 32f; float scale = Scl.scl(1f) / 2f * scaling * 32f;
Draw.rect(unit.type.icon(Cicon.full), x + rx, y + ry, scale, scale, unit.rotation() - 90); Draw.rect(unit.type.icon(Cicon.full), x + rx, y + ry, scale, scale, unit.rotation() - 90);
Draw.reset(); Draw.reset();
}
//only disable player names in multiplayer if(withLabels && net.active()){
if(withLabels && unit.isPlayer() && net.active()){ for(Player player : Groups.player){
Player pl = unit.getPlayer(); if(!player.dead()){
drawLabel(x + rx, y + ry, pl.name, unit.team().color); float rx = player.x / (world.width() * tilesize) * w;
float ry = player.y / (world.height() * tilesize) * h;
drawLabel(x + rx, y + ry, player.name, player.team().color);
}
} }
} }

View File

@@ -278,8 +278,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
throw new ValidateException(player, "Player cannot drop an item."); throw new ValidateException(player, "Player cannot drop an item.");
} }
Fx.dropItem.at(player.x, player.y, angle, Color.white, player.unit().item()); player.unit().eachGroup(unit -> {
player.unit().clearItem(); Fx.dropItem.at(unit.x, unit.y, angle, Color.white, unit.item());
unit.clearItem();
});
} }
@Remote(targets = Loc.both, called = Loc.server, forward = true, unreliable = true) @Remote(targets = Loc.both, called = Loc.server, forward = true, unreliable = true)
@@ -514,7 +516,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
public boolean requestMatches(BuildPlan request){ public boolean requestMatches(BuildPlan request){
Tile tile = world.tile(request.x, request.y); Tile tile = world.tile(request.x, request.y);
return tile != null && tile.block() instanceof ConstructBlock && tile.<ConstructBuild>bc().cblock == request.block; return tile != null && tile.build instanceof ConstructBuild cons && cons.cblock == request.block;
} }
public void drawBreaking(int x, int y){ public void drawBreaking(int x, int y){

View File

@@ -0,0 +1,78 @@
package mindustry.logic;
import arc.struct.*;
import mindustry.*;
import mindustry.content.*;
import mindustry.logic.LExecutor.*;
import mindustry.type.*;
import mindustry.world.*;
/** Stores global constants for logic processors. */
public class GlobalConstants{
private ObjectIntMap<String> namesToIds = new ObjectIntMap<>();
private Seq<Var> vars = new Seq<>(Var.class);
public void init(){
put("the end", null);
//add default constants
put("false", 0);
put("true", 1);
put("null", null);
//store base content
for(Item item : Vars.content.items()){
put("@" + item.name, item);
}
for(Liquid liquid : Vars.content.liquids()){
put("@" + liquid.name, liquid);
}
for(Block block : Vars.content.blocks()){
if(block.synthetic()){
put("@" + block.name, block);
}
}
//used as a special value for any environmental solid block
put("@solid", Blocks.stoneWall);
put("@air", Blocks.air);
for(UnitType type : Vars.content.units()){
put("@" + type.name, type);
}
//store sensor constants
for(LAccess sensor : LAccess.all){
put("@" + sensor.name(), sensor);
}
}
/** @return a constant ID > 0 if there is a constant with this name, otherwise -1. */
public int get(String name){
return namesToIds.get(name, -1);
}
/** @return a constant variable by ID. ID is not bound checked and must be positive. */
public Var get(int id){
return vars.items[id];
}
/** Adds a constant value by name. */
public Var put(String name, Object value){
Var var = new Var(name);
var.constant = true;
if(value instanceof Number num){
var.numval = num.doubleValue();
}else{
var.isobj = true;
var.objval = value;
}
int index = vars.size;
namesToIds.put(name, index);
vars.add(var);
return var;
}
}

View File

@@ -4,12 +4,9 @@ import arc.func.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.*; import mindustry.*;
import mindustry.content.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.logic.LExecutor.*; import mindustry.logic.LExecutor.*;
import mindustry.logic.LStatements.*; import mindustry.logic.LStatements.*;
import mindustry.type.*;
import mindustry.world.*;
/** "Compiles" a sequence of statements into instructions. */ /** "Compiles" a sequence of statements into instructions. */
public class LAssembler{ public class LAssembler{
@@ -31,42 +28,6 @@ public class LAssembler{
putConst("@unit", null); putConst("@unit", null);
//reference to self //reference to self
putConst("@this", null); putConst("@this", null);
//add default constants
putConst("false", 0);
putConst("true", 1);
putConst("null", null);
//store base content (TODO hacky?)
for(Item item : Vars.content.items()){
putConst("@" + item.name, item);
}
for(Liquid liquid : Vars.content.liquids()){
putConst("@" + liquid.name, liquid);
}
for(Block block : Vars.content.blocks()){
if(block.synthetic()){
putConst("@" + block.name, block);
}
}
//used as a special value for any environmental solid block
putConst("@solid", Blocks.stoneWall);
putConst("@air", Blocks.air);
for(UnitType type : Vars.content.units()){
putConst("@" + type.name, type);
}
//store sensor constants
for(LAccess sensor : LAccess.all){
putConst("@" + sensor.name(), sensor);
}
} }
public static LAssembler assemble(String data, int maxInstructions){ public static LAssembler assemble(String data, int maxInstructions){
@@ -185,6 +146,12 @@ public class LAssembler{
/** @return a variable ID by name. /** @return a variable ID by name.
* This may be a constant variable referring to a number or object. */ * This may be a constant variable referring to a number or object. */
public int var(String symbol){ public int var(String symbol){
int constId = Vars.constants.get(symbol);
if(constId > 0){
//global constants are *negated* and stored separately
return -constId;
}
symbol = symbol.trim(); symbol = symbol.trim();
//string case //string case

View File

@@ -97,28 +97,33 @@ public class LExecutor{
//region utility //region utility
public Var var(int index){
//global constants have variable IDs < 0, and they are fetched from the global constants object after being negated
return index < 0 ? constants.get(-index) : vars[index];
}
public @Nullable Building building(int index){ public @Nullable Building building(int index){
Object o = vars[index].objval; Object o = var(index).objval;
return vars[index].isobj && o instanceof Building building ? building : null; return var(index).isobj && o instanceof Building building ? building : null;
} }
public @Nullable Object obj(int index){ public @Nullable Object obj(int index){
Object o = vars[index].objval; Object o = var(index).objval;
return vars[index].isobj ? o : null; return var(index).isobj ? o : null;
} }
public boolean bool(int index){ public boolean bool(int index){
Var v = vars[index]; Var v = var(index);
return v.isobj ? v.objval != null : Math.abs(v.numval) >= 0.00001; return v.isobj ? v.objval != null : Math.abs(v.numval) >= 0.00001;
} }
public double num(int index){ public double num(int index){
Var v = vars[index]; Var v = var(index);
return v.isobj ? v.objval != null ? 1 : 0 : Double.isNaN(v.numval) || Double.isInfinite(v.numval) ? 0 : v.numval; return v.isobj ? v.objval != null ? 1 : 0 : Double.isNaN(v.numval) || Double.isInfinite(v.numval) ? 0 : v.numval;
} }
public float numf(int index){ public float numf(int index){
Var v = vars[index]; Var v = var(index);
return v.isobj ? v.objval != null ? 1 : 0 : Double.isNaN(v.numval) || Double.isInfinite(v.numval) ? 0 : (float)v.numval; return v.isobj ? v.objval != null ? 1 : 0 : Double.isNaN(v.numval) || Double.isInfinite(v.numval) ? 0 : (float)v.numval;
} }
@@ -131,7 +136,7 @@ public class LExecutor{
} }
public void setnum(int index, double value){ public void setnum(int index, double value){
Var v = vars[index]; Var v = var(index);
if(v.constant) return; if(v.constant) return;
v.numval = Double.isNaN(value) || Double.isInfinite(value) ? 0 : value; v.numval = Double.isNaN(value) || Double.isInfinite(value) ? 0 : value;
v.objval = null; v.objval = null;
@@ -139,20 +144,21 @@ public class LExecutor{
} }
public void setobj(int index, Object value){ public void setobj(int index, Object value){
Var v = vars[index]; Var v = var(index);
if(v.constant) return; if(v.constant) return;
v.objval = value; v.objval = value;
v.isobj = true; v.isobj = true;
} }
public void setconst(int index, Object value){ public void setconst(int index, Object value){
Var v = vars[index]; Var v = var(index);
v.objval = value; v.objval = value;
v.isobj = true; v.isobj = true;
} }
//endregion //endregion
/** A logic variable. */
public static class Var{ public static class Var{
public final String name; public final String name;
@@ -735,8 +741,8 @@ public class LExecutor{
@Override @Override
public void run(LExecutor exec){ public void run(LExecutor exec){
Var v = exec.vars[to]; Var v = exec.var(to);
Var f = exec.vars[from]; Var f = exec.var(from);
//TODO error out when the from-value is a constant //TODO error out when the from-value is a constant
if(!v.constant){ if(!v.constant){
@@ -769,10 +775,10 @@ public class LExecutor{
if(op.unary){ if(op.unary){
exec.setnum(dest, op.function1.get(exec.num(a))); exec.setnum(dest, op.function1.get(exec.num(a)));
}else{ }else{
Var va = exec.vars[a]; Var va = exec.var(a);
Var vb = exec.vars[b]; Var vb = exec.var(b);
if(op.objFunction2 != null && (va.isobj || vb.isobj)){ if(op.objFunction2 != null && va.isobj && vb.isobj){
//use object function if provided, and one of the variables is an object //use object function if provided, and one of the variables is an object
exec.setnum(dest, op.objFunction2.get(exec.obj(a), exec.obj(b))); exec.setnum(dest, op.objFunction2.get(exec.obj(a), exec.obj(b)));
}else{ }else{
@@ -788,7 +794,7 @@ public class LExecutor{
@Override @Override
public void run(LExecutor exec){ public void run(LExecutor exec){
exec.vars[varCounter].numval = exec.instructions.length; exec.var(varCounter).numval = exec.instructions.length;
} }
} }
@@ -876,7 +882,7 @@ public class LExecutor{
if(exec.textBuffer.length() >= maxTextBuffer) return; if(exec.textBuffer.length() >= maxTextBuffer) return;
//this should avoid any garbage allocation //this should avoid any garbage allocation
Var v = exec.vars[value]; Var v = exec.var(value);
if(v.isobj && value != 0){ if(v.isobj && value != 0){
String strValue = String strValue =
v.objval == null ? "null" : v.objval == null ? "null" :
@@ -940,8 +946,8 @@ public class LExecutor{
@Override @Override
public void run(LExecutor exec){ public void run(LExecutor exec){
if(address != -1){ if(address != -1){
Var va = exec.vars[value]; Var va = exec.var(value);
Var vb = exec.vars[compare]; Var vb = exec.var(compare);
boolean cmp; boolean cmp;
if(op.objFunction != null && (va.isobj || vb.isobj)){ if(op.objFunction != null && (va.isobj || vb.isobj)){
@@ -952,7 +958,7 @@ public class LExecutor{
} }
if(cmp){ if(cmp){
exec.vars[varCounter].numval = address; exec.var(varCounter).numval = address;
} }
} }
} }

View File

@@ -23,7 +23,6 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
float scl = 5f; float scl = 5f;
float waterOffset = 0.07f; float waterOffset = 0.07f;
//TODO fix sand near snow (sector 173)
Block[][] arr = Block[][] arr =
{ {
{Blocks.water, Blocks.darksandWater, Blocks.darksand, Blocks.darksand, Blocks.darksand, Blocks.darksand, Blocks.sand, Blocks.sand, Blocks.sand, Blocks.sand, Blocks.darksandTaintedWater, Blocks.stone, Blocks.stone}, {Blocks.water, Blocks.darksandWater, Blocks.darksand, Blocks.darksand, Blocks.darksand, Blocks.darksand, Blocks.sand, Blocks.sand, Blocks.sand, Blocks.sand, Blocks.darksandTaintedWater, Blocks.stone, Blocks.stone},
@@ -55,7 +54,6 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
float water = 2f / arr[0].length; float water = 2f / arr[0].length;
float rawHeight(Vec3 position){ float rawHeight(Vec3 position){
position = Tmp.v33.set(position).scl(scl); position = Tmp.v33.set(position).scl(scl);
return (Mathf.pow((float)noise.octaveNoise3D(7, 0.5f, 1f/3f, position.x, position.y, position.z), 2.3f) + waterOffset) / (1f + waterOffset); return (Mathf.pow((float)noise.octaveNoise3D(7, 0.5f, 1f/3f, position.x, position.y, position.z), 2.3f) + waterOffset) / (1f + waterOffset);
@@ -340,11 +338,12 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
} }
}else if(floor != Blocks.basalt && floor != Blocks.ice && floor.asFloor().hasSurface()){ }else if(floor != Blocks.basalt && floor != Blocks.ice && floor.asFloor().hasSurface()){
float noise = noise(x + 782, y, 5, 0.75f, 260f, 1f); float noise = noise(x + 782, y, 5, 0.75f, 260f, 1f);
if(noise > 0.67f && !enemies.contains(e -> Mathf.within(x, y, e.x, e.y, 8))){
if(noise > 0.72f){ if(noise > 0.72f){
floor = noise > 0.78f ? Blocks.taintedWater : (floor == Blocks.sand ? Blocks.sandWater : Blocks.darksandTaintedWater); floor = noise > 0.78f ? Blocks.taintedWater : (floor == Blocks.sand ? Blocks.sandWater : Blocks.darksandTaintedWater);
ore = Blocks.air; }else{
}else if(noise > 0.67f){
floor = (floor == Blocks.sand ? floor : Blocks.darksand); floor = (floor == Blocks.sand ? floor : Blocks.darksand);
}
ore = Blocks.air; ore = Blocks.air;
} }
} }

View File

@@ -39,6 +39,8 @@ import mindustry.world.meta.*;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.*; import java.util.*;
import static mindustry.Vars.*;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class ContentParser{ public class ContentParser{
private static final boolean ignoreUnknownFields = true; private static final boolean ignoreUnknownFields = true;
@@ -250,8 +252,8 @@ public class ContentParser{
readFields(block, value, true); readFields(block, value, true);
if(block.size > ConstructBlock.maxSize){ if(block.size > maxBlockSize){
throw new IllegalArgumentException("Blocks cannot be larger than " + ConstructBlock.maxSize); throw new IllegalArgumentException("Blocks cannot be larger than " + maxBlockSize);
} }
//make block visible by default if there are requirements and no visibility set //make block visible by default if there are requirements and no visibility set

View File

@@ -647,6 +647,14 @@ public class Mods implements Loadable{
meta.hidden = true; meta.hidden = true;
} }
//disallow putting a description after the version
if(meta.version != null){
int line = meta.version.indexOf('\n');
if(line != -1){
meta.version = meta.version.substring(0, line);
}
}
if(!headless){ if(!headless){
Log.info("Loaded mod '@' in @ms", meta.name, Time.elapsed()); Log.info("Loaded mod '@' in @ms", meta.name, Time.elapsed());
} }

View File

@@ -50,6 +50,8 @@ public class BeControl{
Fi dest = Fi.get(System.getProperty("becopy")); Fi dest = Fi.get(System.getProperty("becopy"));
Fi self = Fi.get(BeControl.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath()); Fi self = Fi.get(BeControl.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
for(Fi file : self.parent().findAll(f -> !f.equals(self))) file.delete();
self.copyTo(dest); self.copyTo(dest);
}catch(Throwable e){ }catch(Throwable e){
e.printStackTrace(); e.printStackTrace();

View File

@@ -24,6 +24,8 @@ public class Item extends UnlockableContent{
* 1 cost = 1 tick added to build time * 1 cost = 1 tick added to build time
*/ */
public float cost = 1f; public float cost = 1f;
/** if true, this item is of lowest priority to drills. */
public boolean lowPriority;
public Item(String name, Color color){ public Item(String name, Color color){
super(name); super(name);

View File

@@ -152,10 +152,6 @@ public class Sector{
return res % 2 == 0 ? res : res + 1; return res % 2 == 0 ? res : res + 1;
} }
public void addItem(Item item, int amount){
removeItem(item, -amount);
}
public void removeItems(ItemSeq items){ public void removeItems(ItemSeq items){
ItemSeq copy = items.copy(); ItemSeq copy = items.copy();
copy.each((i, a) -> copy.set(i, -a)); copy.each((i, a) -> copy.set(i, -a));
@@ -169,7 +165,6 @@ public class Sector{
} }
public void addItems(ItemSeq items){ public void addItems(ItemSeq items){
if(net.client()) return;
if(isBeingPlayed()){ if(isBeingPlayed()){
if(state.rules.defaultTeam.core() != null){ if(state.rules.defaultTeam.core() != null){

View File

@@ -46,7 +46,7 @@ public class UnitType extends UnlockableContent{
public float health = 200f, range = -1, armor = 0f, maxRange = -1f; public float health = 200f, range = -1, armor = 0f, maxRange = -1f;
public float crashDamageMultiplier = 1f; public float crashDamageMultiplier = 1f;
public boolean targetAir = true, targetGround = true; public boolean targetAir = true, targetGround = true;
public boolean faceTarget = true, rotateShooting = true, isCounted = true, lowAltitude = false; public boolean faceTarget = true, rotateShooting = true, isCounted = true, lowAltitude = false, circleTarget = true;
public boolean canBoost = false; public boolean canBoost = false;
public boolean destructibleWreck = true; public boolean destructibleWreck = true;
public float groundLayer = Layer.groundUnit; public float groundLayer = Layer.groundUnit;
@@ -106,7 +106,7 @@ public class UnitType extends UnlockableContent{
public Seq<Weapon> weapons = new Seq<>(); public Seq<Weapon> weapons = new Seq<>();
public TextureRegion baseRegion, legRegion, region, shadowRegion, cellRegion, public TextureRegion baseRegion, legRegion, region, shadowRegion, cellRegion,
occlusionRegion, jointRegion, footRegion, legBaseRegion, baseJointRegion, outlineRegion; softShadowRegion, jointRegion, footRegion, legBaseRegion, baseJointRegion, outlineRegion;
public TextureRegion[] wreckRegions; public TextureRegion[] wreckRegions;
protected @Nullable ItemStack[] cachedRequirements; protected @Nullable ItemStack[] cachedRequirements;
@@ -351,7 +351,7 @@ public class UnitType extends UnlockableContent{
legBaseRegion = Core.atlas.find(name + "-leg-base", name + "-leg"); legBaseRegion = Core.atlas.find(name + "-leg-base", name + "-leg");
baseRegion = Core.atlas.find(name + "-base"); baseRegion = Core.atlas.find(name + "-base");
cellRegion = Core.atlas.find(name + "-cell", Core.atlas.find("power-cell")); cellRegion = Core.atlas.find(name + "-cell", Core.atlas.find("power-cell"));
occlusionRegion = Core.atlas.find("circle-shadow"); softShadowRegion = Core.atlas.find("circle-shadow");
outlineRegion = Core.atlas.find(name + "-outline"); outlineRegion = Core.atlas.find(name + "-outline");
shadowRegion = icon(Cicon.full); shadowRegion = icon(Cicon.full);
@@ -439,7 +439,7 @@ public class UnitType extends UnlockableContent{
drawPayload((Unit & Payloadc)unit); drawPayload((Unit & Payloadc)unit);
} }
drawOcclusion(unit); drawSoftShadow(unit);
Draw.z(z - outlineSpace); Draw.z(z - outlineSpace);
@@ -501,11 +501,11 @@ public class UnitType extends UnlockableContent{
Draw.color(); Draw.color();
} }
public void drawOcclusion(Unit unit){ public void drawSoftShadow(Unit unit){
Draw.color(0, 0, 0, 0.4f); Draw.color(0, 0, 0, 0.4f);
float rad = 1.6f; float rad = 1.6f;
float size = Math.max(region.width, region.height) * Draw.scl; float size = Math.max(region.width, region.height) * Draw.scl;
Draw.rect(occlusionRegion, unit, size * rad, size * rad); Draw.rect(softShadowRegion, unit, size * rad, size * rad);
Draw.color(); Draw.color();
} }
@@ -580,8 +580,8 @@ public class UnitType extends UnlockableContent{
float wx = unit.x + Angles.trnsx(rotation, weapon.x, weapon.y) + Angles.trnsx(weaponRotation, 0, recoil), float wx = unit.x + Angles.trnsx(rotation, weapon.x, weapon.y) + Angles.trnsx(weaponRotation, 0, recoil),
wy = unit.y + Angles.trnsy(rotation, weapon.x, weapon.y) + Angles.trnsy(weaponRotation, 0, recoil); wy = unit.y + Angles.trnsy(rotation, weapon.x, weapon.y) + Angles.trnsy(weaponRotation, 0, recoil);
if(weapon.occlusion > 0){ if(weapon.shadow > 0){
Drawf.shadow(wx, wy, weapon.occlusion); Drawf.shadow(wx, wy, weapon.shadow);
} }
if(weapon.outlineRegion.found()){ if(weapon.outlineRegion.found()){

View File

@@ -50,8 +50,8 @@ public class Weapon{
public float x = 5f, y = 0f; public float x = 5f, y = 0f;
/** random spread on the X axis */ /** random spread on the X axis */
public float xRand = 0f; public float xRand = 0f;
/** radius of occlusion drawn under the weapon; <0 to disable */ /** radius of shadow drawn under the weapon; <0 to disable */
public float occlusion = -1f; public float shadow = -1f;
/** fraction of velocity that is random */ /** fraction of velocity that is random */
public float velocityRnd = 0f; public float velocityRnd = 0f;
/** delay in ticks between shots */ /** delay in ticks between shots */

View File

@@ -314,7 +314,7 @@ public class Weather extends UnlockableContent{
@Override @Override
public void draw(){ public void draw(){
if(renderer.weatherAlpha() > 0.0001f){ if(renderer.weatherAlpha() > 0.0001f && Core.settings.getBool("showweather")){
Draw.draw(Layer.weather, () -> { Draw.draw(Layer.weather, () -> {
weather.rand.setSeed(0); weather.rand.setSeed(0);
Draw.alpha(renderer.weatherAlpha() * opacity * weather.opacityMultiplier); Draw.alpha(renderer.weatherAlpha() * opacity * weather.opacityMultiplier);

View File

@@ -82,6 +82,10 @@ public class Bar extends Element{
lastValue = computed; lastValue = computed;
} }
if(Float.isNaN(lastValue)) lastValue = 0;
if(Float.isInfinite(lastValue)) lastValue = 1f;
if(Float.isNaN(value)) value = 0;
if(Float.isInfinite(value)) value = 1f;
if(Float.isNaN(computed)) computed = 0; if(Float.isNaN(computed)) computed = 0;
if(Float.isInfinite(computed)) computed = 1f; if(Float.isInfinite(computed)) computed = 1f;

View File

@@ -4,8 +4,11 @@ import arc.*;
import arc.graphics.*; import arc.graphics.*;
import arc.scene.style.*; import arc.scene.style.*;
import arc.util.*; import arc.util.*;
import mindustry.*;
import mindustry.core.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.mod.Mods.*;
public class Links{ public class Links{
private static LinkEntry[] links; private static LinkEntry[] links;
@@ -22,7 +25,8 @@ public class Links{
new LinkEntry("google-play", "https://play.google.com/store/apps/details?id=io.anuke.mindustry", Icon.googleplay, Color.valueOf("689f38")), new LinkEntry("google-play", "https://play.google.com/store/apps/details?id=io.anuke.mindustry", Icon.googleplay, Color.valueOf("689f38")),
new LinkEntry("f-droid", "https://f-droid.org/packages/io.anuke.mindustry/", Icon.android, Color.valueOf("026aa7")), new LinkEntry("f-droid", "https://f-droid.org/packages/io.anuke.mindustry/", Icon.android, Color.valueOf("026aa7")),
new LinkEntry("github", "https://github.com/Anuken/Mindustry/", Icon.github, Color.valueOf("24292e")), new LinkEntry("github", "https://github.com/Anuken/Mindustry/", Icon.github, Color.valueOf("24292e")),
new LinkEntry("dev-builds", "https://github.com/Anuken/MindustryBuilds", Icon.githubSquare, Color.valueOf("fafbfc")) new LinkEntry("dev-builds", "https://github.com/Anuken/MindustryBuilds", Icon.githubSquare, Color.valueOf("fafbfc")),
new LinkEntry("bug", report(), Icon.wrench, Color.valueOf("cbd97f"))
}; };
} }
@@ -48,4 +52,23 @@ public class Links{
this.title = Core.bundle.get("link." + name + ".title", Strings.capitalize(name.replace("-", " "))); this.title = Core.bundle.get("link." + name + ".title", Strings.capitalize(name.replace("-", " ")));
} }
} }
private static String report(){
return "https://github.com/Anuken/Mindustry/issues/new?assignees=&labels=bug&body=" +
Strings.encode(Strings.format(
"**Platform**: `@`\n" +
"\n**Build**: `@`\n" +
"\n**Issue**: *Explain your issue in detail.*\n" +
"\n**Steps to reproduce**: *How you happened across the issue, and what exactly you did to make the bug happen.*\n" +
"\n**Link(s) to mod(s) used**: `@`\n" +
"\n**Save file**: *The (zipped) save file you were playing on when the bug happened. THIS IS REQUIRED FOR ANY ISSUE HAPPENING IN-GAME, REGARDLESS OF WHETHER YOU THINK IT HAPPENS EVERYWHERE. DO NOT DELETE OR OMIT THIS LINE UNLESS YOU ARE SURE THAT THE ISSUE DOES NOT HAPPEN IN-GAME.*\n" +
"\n**Crash report**: *The contents of relevant crash report files. REQUIRED if you are reporting a crash.*\n" +
"\n---\n" +
"\n*Place an X (no spaces) between the brackets to confirm that you have read the line below.*" +
"\n- [ ] **I have updated to the latest release (https://github.com/Anuken/Mindustry/releases) to make sure my issue has not been fixed.**" +
"\n- [ ] **I have searched the closed and open issues to make sure that this problem has not already been reported.**",
OS.isAndroid ? "Android " + Core.app.getVersion() : (System.getProperty("os.name") + (OS.is64Bit ? " x64" : " x32")),
Version.combined(),
Vars.mods.list().any() ? Vars.mods.list().select(LoadedMod::enabled).map(l -> l.meta.author + "/" + l.name + ":" + l.meta.version) : "none"));
}
} }

View File

@@ -413,6 +413,10 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
public void tap(InputEvent event, float x, float y, int count, KeyCode button){ public void tap(InputEvent event, float x, float y, int count, KeyCode button){
if(showing()) return; if(showing()) return;
if(hovered != null && selected == hovered && count == 2){
playSelected();
}
if(hovered != null && (canSelect(hovered) || debugSelect)){ if(hovered != null && (canSelect(hovered) || debugSelect)){
selected = hovered; selected = hovered;
} }
@@ -762,7 +766,36 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
sector.isBeingPlayed() ? "@sectors.resume" : sector.isBeingPlayed() ? "@sectors.resume" :
sector.hasBase() ? "@sectors.go" : sector.hasBase() ? "@sectors.go" :
locked ? "@locked" : "@sectors.launch", locked ? "@locked" : "@sectors.launch",
locked ? Icon.lock :Icon.play, () -> { locked ? Icon.lock : Icon.play, this::playSelected).growX().height(54f).minWidth(170f).padTop(4).disabled(locked);
}
stable.pack();
stable.setPosition(x, y, Align.center);
stable.update(() -> {
if(selected != null){
if(launching){
stable.color.sub(0, 0, 0, 0.05f * Time.delta);
}else{
//fade out UI when not facing selected sector
Tmp.v31.set(selected.tile.v).rotate(Vec3.Y, -planets.planet.getRotation()).scl(-1f).nor();
float dot = planets.cam.direction.dot(Tmp.v31);
stable.color.a = Math.max(dot, 0f)*2f;
if(dot*2f <= -0.1f){
selected = null;
updateSelected();
}
}
}
});
stable.act(0f);
}
void playSelected(){
if(selected == null) return;
Sector sector = selected;
if(sector.isBeingPlayed()){ if(sector.isBeingPlayed()){
//already at this sector //already at this sector
@@ -815,30 +848,6 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
} }
if(shouldHide) hide(); if(shouldHide) hide();
}).growX().height(54f).minWidth(170f).padTop(4).disabled(locked);
}
stable.pack();
stable.setPosition(x, y, Align.center);
stable.update(() -> {
if(selected != null){
if(launching){
stable.color.sub(0, 0, 0, 0.05f * Time.delta);
}else{
//fade out UI when not facing selected sector
Tmp.v31.set(selected.tile.v).rotate(Vec3.Y, -planets.planet.getRotation()).scl(-1f).nor();
float dot = planets.cam.direction.dot(Tmp.v31);
stable.color.a = Math.max(dot, 0f)*2f;
if(dot*2f <= -0.1f){
selected = null;
updateSelected();
}
}
}
});
stable.act(0f);
} }
public enum Mode{ public enum Mode{

View File

@@ -404,6 +404,7 @@ public class SettingsMenuDialog extends SettingsDialog{
graphics.checkPref("fps", false); graphics.checkPref("fps", false);
graphics.checkPref("playerindicators", true); graphics.checkPref("playerindicators", true);
graphics.checkPref("indicators", true); graphics.checkPref("indicators", true);
graphics.checkPref("showweather", true);
graphics.checkPref("animatedwater", true); graphics.checkPref("animatedwater", true);
if(Shaders.shield != null){ if(Shaders.shield != null){
graphics.checkPref("animatedshields", !mobile); graphics.checkPref("animatedshields", !mobile);

View File

@@ -26,7 +26,7 @@ public class HintsFragment extends Fragment{
private static final float foutTime = 0.6f; private static final float foutTime = 0.6f;
/** All hints to be displayed in the game. */ /** All hints to be displayed in the game. */
public Seq<Hint> hints = Seq.with(DefaultHint.values()); public Seq<Hint> hints = new Seq<>().and(DefaultHint.values()).as();
@Nullable Hint current; @Nullable Hint current;
Group group = new WidgetGroup(); Group group = new WidgetGroup();

View File

@@ -145,7 +145,7 @@ public class PlacementFragment extends Fragment{
break; break;
} }
} }
}else if(blockSelectEnd || Time.timeSinceMillis(blockSelectSeqMillis) > 750){ //1st number of combo, select category }else if(blockSelectEnd || Time.timeSinceMillis(blockSelectSeqMillis) > 400){ //1st number of combo, select category
//select only visible categories //select only visible categories
if(!getUnlockedByCategory(Category.all[i]).isEmpty()){ if(!getUnlockedByCategory(Category.all[i]).isEmpty()){
currentCategory = Category.all[i]; currentCategory = Category.all[i];

View File

@@ -6,6 +6,7 @@ import arc.scene.*;
import arc.scene.event.*; import arc.scene.event.*;
import arc.scene.ui.*; import arc.scene.ui.*;
import arc.scene.ui.layout.*; import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
@@ -21,6 +22,7 @@ public class PlayerListFragment extends Fragment{
private Interval timer = new Interval(); private Interval timer = new Interval();
private TextField sField; private TextField sField;
private boolean found = false; private boolean found = false;
private Seq<Player> players = new Seq<>();
@Override @Override
public void build(Group parent){ public void build(Group parent){
@@ -78,8 +80,12 @@ public class PlayerListFragment extends Fragment{
float h = 74f; float h = 74f;
found = false; found = false;
Groups.player.sort(Structs.comparing(Player::team)); players.clear();
Groups.player.each(user -> { Groups.player.copy(players);
players.sort(Structs.comps(Structs.comparing(Player::team), Structs.comparingBool(p -> !p.admin)));
for(var user : players){
found = true; found = true;
NetConnection connection = user.con; NetConnection connection = user.con;
@@ -159,7 +165,7 @@ public class PlayerListFragment extends Fragment{
content.row(); content.row();
content.image().height(4f).color(state.rules.pvp ? user.team().color : Pal.gray).growX(); content.image().height(4f).color(state.rules.pvp ? user.team().color : Pal.gray).growX();
content.row(); content.row();
}); }
if(!found){ if(!found){
content.add(Core.bundle.format("players.notfound")).padBottom(6).width(350f).maxHeight(h + 14); content.add(Core.bundle.format("players.notfound")).padBottom(6).width(350f).maxHeight(h + 14);

View File

@@ -287,7 +287,7 @@ public class Block extends UnlockableContent{
Tile tile = world.tile(x, y); Tile tile = world.tile(x, y);
if(tile == null) return 0; if(tile == null) return 0;
return tile.getLinkedTilesAs(this, tempTiles) return tile.getLinkedTilesAs(this, tempTiles)
.sumf(other -> other.floor().attributes.get(attr)); .sumf(other -> !floating && other.floor().isDeep() ? 0 : other.floor().attributes.get(attr));
} }
public TextureRegion getDisplayIcon(Tile tile){ public TextureRegion getDisplayIcon(Tile tile){
@@ -377,7 +377,8 @@ public class Block extends UnlockableContent{
public boolean canReplace(Block other){ public boolean canReplace(Block other){
if(other.alwaysReplace) return true; if(other.alwaysReplace) return true;
return (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group && (size == other.size || (size >= other.size && subclass != null && subclass == other.subclass)); return (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group &&
(size == other.size || (size >= other.size && ((subclass != null && subclass == other.subclass) || group.anyReplace)));
} }
/** @return a possible replacement for this block when placed in a line by the player. */ /** @return a possible replacement for this block when placed in a line by the player. */

View File

@@ -41,8 +41,9 @@ public class Build{
if(tile.build != null) prevBuild.add(tile.build); if(tile.build != null) prevBuild.add(tile.build);
tile.setBlock(sub, team, rotation); tile.setBlock(sub, team, rotation);
tile.<ConstructBuild>bc().setDeconstruct(previous); var build = (ConstructBuild)tile.build;
tile.<ConstructBuild>bc().prevBuild = prevBuild; build.setDeconstruct(previous);
build.prevBuild = prevBuild;
tile.build.health = tile.build.maxHealth * prevPercent; tile.build.health = tile.build.maxHealth * prevPercent;
if(unit != null && unit.isPlayer()) tile.build.lastAccessed = unit.getPlayer().name; if(unit != null && unit.isPlayer()) tile.build.lastAccessed = unit.getPlayer().name;
@@ -85,7 +86,7 @@ public class Build{
tile.setBlock(sub, team, rotation); tile.setBlock(sub, team, rotation);
ConstructBuild build = tile.bc(); var build = (ConstructBuild)tile.build;
build.setConstruct(previous.size == sub.size ? previous : Blocks.air, result); build.setConstruct(previous.size == sub.size ? previous : Blocks.air, result);
build.prevBuild = prevBuild; build.prevBuild = prevBuild;
@@ -150,10 +151,10 @@ public class Build{
!check.floor().placeableOn || //solid wall !check.floor().placeableOn || //solid wall
!((type.canReplace(check.block()) || //can replace type !((type.canReplace(check.block()) || //can replace type
//controversial change: allow rebuilding damaged blocks //controversial change: allow rebuilding damaged blocks
//this could be buggy and abusable, so I'm not enabling it yet //this could be buggy and abuse-able, so I'm not enabling it yet
//note that this requires a change in BuilderComp as well //note that this requires a change in BuilderComp as well
//(type == check.block() && check.centerX() == x && check.centerY() == y && check.build != null && check.build.health < check.build.maxHealth - 0.0001f) || //(type == check.block() && check.centerX() == x && check.centerY() == y && check.build != null && check.build.health < check.build.maxHealth - 0.0001f) ||
(check.block instanceof ConstructBlock && check.<ConstructBuild>bc().cblock == type && check.centerX() == tile.x && check.centerY() == tile.y)) && //same type in construction (check.build instanceof ConstructBuild build && build.cblock == type && check.centerX() == tile.x && check.centerY() == tile.y)) && //same type in construction
type.bounds(tile.x, tile.y, Tmp.r1).grow(0.01f).contains(check.block.bounds(check.centerX(), check.centerY(), Tmp.r2))) || //no replacement type.bounds(tile.x, tile.y, Tmp.r1).grow(0.01f).contains(check.block.bounds(check.centerX(), check.centerY(), Tmp.r2))) || //no replacement
(type.requiresWater && check.floor().liquidDrop != Liquids.water) //requires water but none found (type.requiresWater && check.floor().liquidDrop != Liquids.water) //requires water but none found
) return false; ) return false;

View File

@@ -9,10 +9,9 @@ import java.util.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class Edges{ public class Edges{
private static final int maxSize = 14;
private static final int maxRadius = 12; private static final int maxRadius = 12;
private static Point2[][] edges = new Point2[maxSize][0]; private static Point2[][] edges = new Point2[maxBlockSize][0];
private static Point2[][] edgeInside = new Point2[maxSize][0]; private static Point2[][] edgeInside = new Point2[maxBlockSize][0];
private static Vec2[][] polygons = new Vec2[maxRadius * 2][0]; private static Vec2[][] polygons = new Vec2[maxRadius * 2][0];
static{ static{
@@ -20,7 +19,7 @@ public class Edges{
polygons[i] = Geometry.pixelCircle((i + 1) / 2f); polygons[i] = Geometry.pixelCircle((i + 1) / 2f);
} }
for(int i = 0; i < maxSize; i++){ for(int i = 0; i < maxBlockSize; i++){
int bot = -(int)(i / 2f) - 1; int bot = -(int)(i / 2f) - 1;
int top = (int)(i / 2f + 0.5f) + 1; int top = (int)(i / 2f + 0.5f) + 1;
edges[i] = new Point2[(i + 1) * 4]; edges[i] = new Point2[(i + 1) * 4];
@@ -72,13 +71,13 @@ public class Edges{
} }
public static Point2[] getEdges(int size){ public static Point2[] getEdges(int size){
if(size < 0 || size > maxSize) throw new RuntimeException("Block size must be between 0 and " + maxSize); if(size < 0 || size > maxBlockSize) throw new RuntimeException("Block size must be between 0 and " + maxBlockSize);
return edges[size - 1]; return edges[size - 1];
} }
public static Point2[] getInsideEdges(int size){ public static Point2[] getInsideEdges(int size){
if(size < 0 || size > maxSize) throw new RuntimeException("Block size must be between 0 and " + maxSize); if(size < 0 || size > maxBlockSize) throw new RuntimeException("Block size must be between 0 and " + maxBlockSize);
return edgeInside[size - 1]; return edgeInside[size - 1];
} }

View File

@@ -125,13 +125,6 @@ public class Tile implements Position, QuadTreeObject, Displayable{
return 0; return 0;
} }
/** Convenience method that returns the building of this tile with a cast.
* Method name is shortened to prevent conflict. */
@SuppressWarnings("unchecked")
public <T extends Building> T bc(){
return (T)build;
}
public float worldx(){ public float worldx(){
return x * tilesize; return x * tilesize;
} }
@@ -448,6 +441,10 @@ public class Tile implements Position, QuadTreeObject, Displayable{
return rect.setCentered(drawx(), drawy(), block.size * tilesize, block.size * tilesize); return rect.setCentered(drawx(), drawy(), block.size * tilesize, block.size * tilesize);
} }
public Rect getBounds(Rect rect){
return rect.set(x * tilesize - tilesize/2f, y * tilesize - tilesize/2f, tilesize, tilesize);
}
@Override @Override
public void hitbox(Rect rect){ public void hitbox(Rect rect){
getHitbox(rect); getHitbox(rect);

View File

@@ -26,8 +26,7 @@ import static mindustry.Vars.*;
/** A block in the process of construction. */ /** A block in the process of construction. */
public class ConstructBlock extends Block{ public class ConstructBlock extends Block{
public static final int maxSize = 16; private static final ConstructBlock[] consBlocks = new ConstructBlock[maxBlockSize];
private static final ConstructBlock[] consBlocks = new ConstructBlock[maxSize];
private static long lastTime = 0; private static long lastTime = 0;
private static int pitchSeq = 0; private static int pitchSeq = 0;
@@ -46,7 +45,7 @@ public class ConstructBlock extends Block{
/** Returns a ConstructBlock by size. */ /** Returns a ConstructBlock by size. */
public static ConstructBlock get(int size){ public static ConstructBlock get(int size){
if(size > maxSize) throw new IllegalArgumentException("No. Don't place ConstructBlock of size greater than " + maxSize); if(size > maxBlockSize) throw new IllegalArgumentException("No. Don't place ConstructBlock of size greater than " + maxBlockSize);
return consBlocks[size - 1]; return consBlocks[size - 1];
} }
@@ -147,6 +146,7 @@ public class ConstructBlock extends Block{
*/ */
public Block previous; public Block previous;
public Object lastConfig; public Object lastConfig;
public boolean wasConstructing;
@Nullable @Nullable
public Unit lastBuilder; public Unit lastBuilder;
@@ -218,6 +218,7 @@ public class ConstructBlock extends Block{
} }
public void construct(Unit builder, @Nullable Building core, float amount, Object config){ public void construct(Unit builder, @Nullable Building core, float amount, Object config){
wasConstructing = true;
if(cblock == null){ if(cblock == null){
kill(); kill();
return; return;
@@ -252,6 +253,7 @@ public class ConstructBlock extends Block{
} }
public void deconstruct(Unit builder, @Nullable Building core, float amount){ public void deconstruct(Unit builder, @Nullable Building core, float amount){
wasConstructing = false;
float deconstructMultiplier = state.rules.deconstructRefundMultiplier; float deconstructMultiplier = state.rules.deconstructRefundMultiplier;
if(builder.isPlayer()){ if(builder.isPlayer()){
@@ -331,6 +333,7 @@ public class ConstructBlock extends Block{
} }
public void setConstruct(Block previous, Block block){ public void setConstruct(Block previous, Block block){
wasConstructing = true;
this.cblock = block; this.cblock = block;
this.previous = previous; this.previous = previous;
this.accumulator = new float[block.requirements.length]; this.accumulator = new float[block.requirements.length];
@@ -340,6 +343,7 @@ public class ConstructBlock extends Block{
public void setDeconstruct(Block previous){ public void setDeconstruct(Block previous){
if(previous == null) return; if(previous == null) return;
wasConstructing = false;
this.previous = previous; this.previous = previous;
this.progress = 1f; this.progress = 1f;
if(previous.buildCost >= 0.01f){ if(previous.buildCost >= 0.01f){

View File

@@ -21,7 +21,7 @@ public class Accelerator extends Block{
public @Load("launch-arrow") TextureRegion arrowRegion; public @Load("launch-arrow") TextureRegion arrowRegion;
public Block launching = Blocks.coreNucleus; public Block launching = Blocks.coreNucleus;
public int[] capacities = new int[content.items().size]; public int[] capacities;
public Accelerator(String name){ public Accelerator(String name){
super(name); super(name);
@@ -35,6 +35,7 @@ public class Accelerator extends Block{
@Override @Override
public void init(){ public void init(){
itemCapacity = 0; itemCapacity = 0;
capacities = new int[content.items().size];
for(ItemStack stack : launching.requirements){ for(ItemStack stack : launching.requirements){
capacities[stack.item.id] = stack.amount; capacities[stack.item.id] = stack.amount;
itemCapacity += stack.amount; itemCapacity += stack.amount;
@@ -43,6 +44,11 @@ public class Accelerator extends Block{
super.init(); super.init();
} }
@Override
public boolean outputsItems(){
return false;
}
public class AcceleratorBuild extends Building{ public class AcceleratorBuild extends Building{
@Override @Override

View File

@@ -69,12 +69,6 @@ public class Wall extends Block{
return new TextureRegion[]{Core.atlas.find(Core.atlas.has(name) ? name : name + "1")}; return new TextureRegion[]{Core.atlas.find(Core.atlas.has(name) ? name : name + "1")};
} }
@Override
public boolean canReplace(Block other){
if(other.alwaysReplace) return true;
return (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group && other != this && size >= other.size;
}
public class WallBuild extends Building{ public class WallBuild extends Building{
public float hit; public float hit;

View File

@@ -147,7 +147,7 @@ public class LiquidTurret extends Turret{
public boolean acceptLiquid(Building source, Liquid liquid){ public boolean acceptLiquid(Building source, Liquid liquid){
return ammoTypes.get(liquid) != null return ammoTypes.get(liquid) != null
&& (liquids.current() == liquid || (ammoTypes.containsKey(liquid) && (liquids.current() == liquid || (ammoTypes.containsKey(liquid)
&& liquids.get(liquids.current()) <= 1f / ammoTypes.get(liquids.current()).ammoMultiplier + 0.001f)); && (!ammoTypes.containsKey(liquids.current()) || liquids.get(liquids.current()) <= 1f / ammoTypes.get(liquids.current()).ammoMultiplier + 0.001f)));
} }
} }
} }

View File

@@ -118,7 +118,7 @@ public class TractorBeamTurret extends BaseTurret{
} }
any = true; any = true;
target.impulse(Tmp.v1.set(this).sub(target).limit((force + (1f - target.dst(this) / range) * scaledForce) * efficiency() * timeScale)); target.impulseNet(Tmp.v1.set(this).sub(target).limit((force + (1f - target.dst(this) / range) * scaledForce) * efficiency() * timeScale));
} }
}else{ }else{
strength = Mathf.lerpDelta(strength, 0, 0.1f); strength = Mathf.lerpDelta(strength, 0, 0.1f);

View File

@@ -209,7 +209,7 @@ public class Turret extends ReloadTurret{
} }
public void targetPosition(Posc pos){ public void targetPosition(Posc pos){
if(!hasAmmo()) return; if(!hasAmmo() || target == null) return;
BulletType bullet = peekAmmo(); BulletType bullet = peekAmmo();
float speed = bullet.speed; float speed = bullet.speed;
//slow bullets never intersect //slow bullets never intersect

View File

@@ -120,7 +120,7 @@ public class ItemBridge extends Block{
return ((other.block() == tile.block() && tile.block() == this) || (!(tile.block() instanceof ItemBridge) && other.block() == this)) return ((other.block() == tile.block() && tile.block() == this) || (!(tile.block() instanceof ItemBridge) && other.block() == this))
&& (other.team() == tile.team() || tile.block() != this) && (other.team() == tile.team() || tile.block() != this)
&& (!checkDouble || other.<ItemBridgeBuild>bc().link != tile.pos()); && (!checkDouble || ((ItemBridgeBuild)other.build).link != tile.pos());
} }
public Tile findLink(int x, int y){ public Tile findLink(int x, int y){
@@ -238,7 +238,7 @@ public class ItemBridge extends Block{
while(it.hasNext){ while(it.hasNext){
int i = it.next(); int i = it.next();
Tile other = world.tile(i); Tile other = world.tile(i);
if(!linkValid(tile, other, false) || other.<ItemBridgeBuild>bc().link != tile.pos()){ if(!linkValid(tile, other, false) || ((ItemBridgeBuild)other.build).link != tile.pos()){
it.remove(); it.remove();
} }
} }

View File

@@ -302,8 +302,7 @@ public class MassDriver extends Block{
protected boolean shooterValid(Tile other){ protected boolean shooterValid(Tile other){
if(other == null) return true; if(other == null) return true;
if(!(other.block() instanceof MassDriver)) return false; if(!(other.build instanceof MassDriverBuild entity)) return false;
MassDriverBuild entity = other.bc();
return entity.link == tile.pos() && tile.dst(other) <= range; return entity.link == tile.pos() && tile.dst(other) <= range;
} }

View File

@@ -23,12 +23,6 @@ public class Router extends Block{
noUpdateDisabled = true; noUpdateDisabled = true;
} }
@Override
public boolean canReplace(Block other){
if(other.alwaysReplace) return true;
return (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group && size >= other.size;
}
public class RouterBuild extends Building implements ControlBlock{ public class RouterBuild extends Building implements ControlBlock{
public Item lastItem; public Item lastItem;
public Tile lastInput; public Tile lastInput;

View File

@@ -43,7 +43,8 @@ public class Sorter extends Block{
@Override @Override
public int minimapColor(Tile tile){ public int minimapColor(Tile tile){
return tile.<SorterBuild>bc().sortItem == null ? 0 : tile.<SorterBuild>bc().sortItem.color.rgba(); var build = (SorterBuild)tile.build;
return build == null || build.sortItem == null ? 0 : build.sortItem.color.rgba();
} }
public class SorterBuild extends Building{ public class SorterBuild extends Building{

View File

@@ -119,7 +119,7 @@ public class Floor extends Block{
if(wall == null) wall = Blocks.air; if(wall == null) wall = Blocks.air;
if(decoration == Blocks.air){ if(decoration == Blocks.air){
decoration = content.blocks().min(b -> b instanceof Boulder && b.breakable ? mapColor.diff(b.mapColor) : Float.POSITIVE_INFINITY); decoration = content.blocks().min(b -> b instanceof Boulder && b.minfo.mod == null && b.breakable ? mapColor.diff(b.mapColor) : Float.POSITIVE_INFINITY);
} }
if(isLiquid && walkEffect == Fx.none){ if(isLiquid && walkEffect == Fx.none){

View File

@@ -68,7 +68,7 @@ public class LogicBlock extends Block{
}); });
} }
static String getLinkName(Block block){ public static String getLinkName(Block block){
String name = block.name; String name = block.name;
if(name.contains("-")){ if(name.contains("-")){
String[] split = name.split("-"); String[] split = name.split("-");
@@ -82,11 +82,11 @@ public class LogicBlock extends Block{
return name; return name;
} }
static byte[] compress(String code, Seq<LogicLink> links){ public static byte[] compress(String code, Seq<LogicLink> links){
return compress(code.getBytes(charset), links); return compress(code.getBytes(charset), links);
} }
static byte[] compress(byte[] bytes, Seq<LogicLink> links){ public static byte[] compress(byte[] bytes, Seq<LogicLink> links){
try{ try{
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream stream = new DataOutputStream(new DeflaterOutputStream(baos)); DataOutputStream stream = new DataOutputStream(new DeflaterOutputStream(baos));

View File

@@ -168,7 +168,7 @@ public class Drill extends Block{
} }
itemArray.sort((item1, item2) -> { itemArray.sort((item1, item2) -> {
int type = Boolean.compare(item1 != Items.sand, item2 != Items.sand); int type = Boolean.compare(!item1.lowPriority, !item2.lowPriority);
if(type != 0) return type; if(type != 0) return type;
int amounts = Integer.compare(oreCount.get(item1, 0), oreCount.get(item2, 0)); int amounts = Integer.compare(oreCount.get(item1, 0), oreCount.get(item2, 0));
if(amounts != 0) return amounts; if(amounts != 0) return amounts;

View File

@@ -17,8 +17,12 @@ public class LiquidConverter extends GenericCrafter{
@Override @Override
public void init(){ public void init(){
ConsumeLiquidBase cl = consumes.get(ConsumeType.liquid); if(!consumes.has(ConsumeType.liquid) || !(consumes.get(ConsumeType.liquid) instanceof ConsumeLiquid)){
cl.update(true); throw new RuntimeException("LiquidsConverters must have a ConsumeLiquid. Note that filters are not supported.");
}
ConsumeLiquid cl = consumes.get(ConsumeType.liquid);
cl.update(false);
outputLiquid.amount = cl.amount; outputLiquid.amount = cl.amount;
super.init(); super.init();
} }
@@ -40,11 +44,13 @@ public class LiquidConverter extends GenericCrafter{
@Override @Override
public void updateTile(){ public void updateTile(){
ConsumeLiquidBase cl = consumes.get(ConsumeType.liquid); ConsumeLiquid cl = consumes.get(ConsumeType.liquid);
if(cons.valid()){ if(cons.valid()){
float use = Math.min(cl.amount * edelta(), liquidCapacity - liquids.get(outputLiquid.liquid)); float use = Math.min(cl.amount * edelta(), liquidCapacity - liquids.get(outputLiquid.liquid));
liquids.remove(cl.liquid, Math.min(use, liquids.get(cl.liquid)));
progress += use / cl.amount; progress += use / cl.amount;
liquids.add(outputLiquid.liquid, use); liquids.add(outputLiquid.liquid, use);
if(progress >= craftTime){ if(progress >= craftTime){

View File

@@ -58,9 +58,8 @@ public class CoreBlock extends StorageBlock{
@Remote(called = Loc.server) @Remote(called = Loc.server)
public static void playerSpawn(Tile tile, Player player){ public static void playerSpawn(Tile tile, Player player){
if(player == null || tile == null) return; if(player == null || tile == null || !(tile.build instanceof CoreBuild entity)) return;
CoreBuild entity = tile.bc();
CoreBlock block = (CoreBlock)tile.block(); CoreBlock block = (CoreBlock)tile.block();
Fx.spawn.at(entity); Fx.spawn.at(entity);
@@ -255,7 +254,7 @@ public class CoreBlock extends StorageBlock{
for(Building other : state.teams.cores(team)){ for(Building other : state.teams.cores(team)){
if(other.tile() == tile) continue; if(other.tile() == tile) continue;
storageCapacity += other.block.itemCapacity + other.proximity().sum(e -> owns(e) && owns(other, e) ? e.block.itemCapacity : 0); storageCapacity += other.block.itemCapacity + other.proximity().sum(e -> owns(other, e) ? e.block.itemCapacity : 0);
} }
//Team.sharded.core().items.set(Items.surgeAlloy, 12000) //Team.sharded.core().items.set(Items.surgeAlloy, 12000)

View File

@@ -27,6 +27,7 @@ public class Unloader extends Block{
saveConfig = true; saveConfig = true;
itemCapacity = 0; itemCapacity = 0;
noUpdateDisabled = true; noUpdateDisabled = true;
unloadable = false;
config(Item.class, (UnloaderBuild tile, Item item) -> tile.sortItem = item); config(Item.class, (UnloaderBuild tile, Item item) -> tile.sortItem = item);
configClear((UnloaderBuild tile) -> tile.sortItem = null); configClear((UnloaderBuild tile) -> tile.sortItem = null);
@@ -47,10 +48,15 @@ public class Unloader extends Block{
public Item sortItem = null; public Item sortItem = null;
public Building dumpingTo; public Building dumpingTo;
public int offset = 0; public int offset = 0;
public int[] rotations;
@Override @Override
public void updateTile(){ public void updateTile(){
if(timer(timerUnload, speed / timeScale())){ if(timer(timerUnload, speed / timeScale())){
if(rotations == null || rotations.length != proximity.size){
rotations = new int[proximity.size];
}
for(int i = 0; i < proximity.size; i++){ for(int i = 0; i < proximity.size; i++){
int pos = (offset + i) % proximity.size; int pos = (offset + i) % proximity.size;
var other = proximity.get(pos); var other = proximity.get(pos);
@@ -61,18 +67,19 @@ public class Unloader extends Block{
dumpingTo = other; dumpingTo = other;
//get item to be taken //get item to be taken
Item item = sortItem == null ? other.items.beginTake() : sortItem; Item item = sortItem == null ? other.items.takeIndex(rotations[pos]) : sortItem;
//remove item if it's dumped correctly //remove item if it's dumped correctly
if(put(item)){ if(put(item)){
if(sortItem == null){
other.items.endTake(item);
}else{
other.items.remove(item, 1); other.items.remove(item, 1);
if(sortItem == null){
rotations[pos] = item.id + 1;
} }
other.itemTaken(item); other.itemTaken(item);
}else if(sortItem == null){ }else if(sortItem == null){
other.items.failTake(); rotations[pos] = other.items.nextIndex(rotations[pos]);
} }
} }
} }

View File

@@ -10,6 +10,7 @@ import mindustry.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.entities.*; import mindustry.entities.*;
import mindustry.entities.units.*; import mindustry.entities.units.*;
import mindustry.game.EventType.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.type.*; import mindustry.type.*;
@@ -174,6 +175,7 @@ public class Reconstructor extends UnitBlock{
Effect.shake(2f, 3f, this); Effect.shake(2f, 3f, this);
Fx.producesmoke.at(this); Fx.producesmoke.at(this);
consume(); consume();
Events.fire(new UnitCreateEvent(payload.unit));
} }
} }
} }

View File

@@ -27,8 +27,8 @@ public class UnitBlock extends PayloadAcceptor{
@Remote(called = Loc.server) @Remote(called = Loc.server)
public static void unitBlockSpawn(Tile tile){ public static void unitBlockSpawn(Tile tile){
if(!(tile.build instanceof UnitBuild)) return; if(!(tile.build instanceof UnitBuild build)) return;
tile.<UnitBuild>bc().spawned(); build.spawned();
} }
public class UnitBuild extends PayloadAcceptorBuild<UnitPayload>{ public class UnitBuild extends PayloadAcceptorBuild<UnitPayload>{

View File

@@ -1,5 +1,16 @@
package mindustry.world.meta; package mindustry.world.meta;
public enum BlockGroup{ public enum BlockGroup{
none, walls, projectors, turrets, transportation, power, liquids, drills, storage, units, logic none, walls(true), projectors(true), turrets, transportation(true), power, liquids(true), drills, storage, units, logic(true);
/** if true, any block in this category replaces any other block in this category. */
public final boolean anyReplace;
BlockGroup(boolean anyReplace){
this.anyReplace = anyReplace;
}
BlockGroup(){
this(false);
}
} }

View File

@@ -206,7 +206,7 @@ public class ItemModule extends BlockModule{
/** Begins a speculative take operation. This returns the item that would be returned by #take(), but does not change state. */ /** Begins a speculative take operation. This returns the item that would be returned by #take(), but does not change state. */
@Nullable @Nullable
public Item beginTake(){ public Item takeIndex(int takeRotation){
for(int i = 0; i < items.length; i++){ for(int i = 0; i < items.length; i++){
int index = (i + takeRotation); int index = (i + takeRotation);
if(index >= items.length) index -= items.length; if(index >= items.length) index -= items.length;
@@ -217,23 +217,15 @@ public class ItemModule extends BlockModule{
return null; return null;
} }
/** Finishes a take operation. Updates take state, removes the item. */ public int nextIndex(int takeRotation){
public void endTake(Item item){
items[item.id] --;
total --;
takeRotation = item.id + 1;
}
public void failTake(){
for(int i = 1; i < items.length; i++){ for(int i = 1; i < items.length; i++){
int index = (i + takeRotation); int index = (i + takeRotation);
if(index >= items.length) index -= items.length; if(index >= items.length) index -= items.length;
if(items[index] > 0){ if(items[index] > 0){
takeRotation += i; return (takeRotation + i) % items.length;
takeRotation %= items.length;
return;
} }
} }
return takeRotation;
} }
public int get(int id){ public int get(int id){

View File

@@ -461,9 +461,10 @@ public class SNet implements SteamNetworkingCallback, SteamMatchmakingCallback,
writeBuffer.limit(writeBuffer.capacity()); writeBuffer.limit(writeBuffer.capacity());
writeBuffer.position(0); writeBuffer.position(0);
serializer.write(writeBuffer, object); serializer.write(writeBuffer, object);
int length = writeBuffer.position();
writeBuffer.flip(); writeBuffer.flip();
snet.sendP2PPacket(sid, writeBuffer, mode == SendMode.tcp ? object instanceof StreamChunk ? P2PSend.ReliableWithBuffering : P2PSend.Reliable : P2PSend.UnreliableNoDelay, 0); snet.sendP2PPacket(sid, writeBuffer, mode == SendMode.tcp || length >= 1200 ? object instanceof StreamChunk ? P2PSend.ReliableWithBuffering : P2PSend.Reliable : P2PSend.UnreliableNoDelay, 0);
}catch(Exception e){ }catch(Exception e){
Log.err(e); Log.err(e);
Log.info("Error sending packet. Disconnecting invalid client!"); Log.info("Error sending packet. Disconnecting invalid client!");

View File

@@ -28,7 +28,7 @@ public enum SStat{
public void max(int amount){ public void max(int amount){
if(amount > get()){ if(amount > get()){
add(amount - get()); set(amount);
} }
} }
@@ -42,7 +42,7 @@ public enum SStat{
} }
public void add(int amount){ public void add(int amount){
set(get() + 1); set(get() + amount);
} }
public void add(){ public void add(){

View File

@@ -1,7 +1,6 @@
package mindustry.desktop.steam; package mindustry.desktop.steam;
import arc.*; import arc.*;
import arc.math.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import com.codedisaster.steamworks.*; import com.codedisaster.steamworks.*;
@@ -22,18 +21,19 @@ public class SStats implements SteamUserStatsCallback{
public final SteamUserStats stats = new SteamUserStats(this); public final SteamUserStats stats = new SteamUserStats(this);
private boolean updated = false; private boolean updated = false;
//private ObjectSet<String> mechs = new ObjectSet<>();
private int statSavePeriod = 4; //in minutes private int statSavePeriod = 4; //in minutes
private ObjectSet<String> blocksBuilt = new ObjectSet<>(), unitsBuilt = new ObjectSet<>(); private ObjectSet<String> blocksBuilt = new ObjectSet<>(), unitsBuilt = new ObjectSet<>();
private ObjectSet<UnitType> t5s = new ObjectSet<>(); private ObjectSet<UnitType> t5s = new ObjectSet<>();
private ObjectSet<UnitType> tmpSet = new ObjectSet<>(); private IntSet checked = new IntSet();
public SStats(){ public SStats(){
stats.requestCurrentStats(); stats.requestCurrentStats();
Events.on(ClientLoadEvent.class, e -> { Events.on(ClientLoadEvent.class, e -> {
//mechs = Core.settings.getObject("mechs", ObjectSet.class, ObjectSet::new); unitsBuilt = Core.settings.getJson("units-built" , ObjectSet.class, String.class, ObjectSet::new);
blocksBuilt = Core.settings.getJson("blocks-built" , ObjectSet.class, String.class, ObjectSet::new);
t5s = ObjectSet.with(UnitTypes.omura, UnitTypes.reign, UnitTypes.toxopid, UnitTypes.eclipse, UnitTypes.oct, UnitTypes.corvus);
Core.app.addListener(new ApplicationListener(){ Core.app.addListener(new ApplicationListener(){
Interval i = new Interval(); Interval i = new Interval();
@@ -76,14 +76,9 @@ public class SStats implements SteamUserStatsCallback{
} }
private void registerEvents(){ private void registerEvents(){
Events.on(ClientLoadEvent.class, e -> {
unitsBuilt = Core.settings.getJson("units-built" , ObjectSet.class, String.class, ObjectSet::new);
blocksBuilt = Core.settings.getJson("blocks-built" , ObjectSet.class, String.class, ObjectSet::new);
t5s = ObjectSet.with(UnitTypes.omura, UnitTypes.reign, UnitTypes.toxopid, UnitTypes.eclipse, UnitTypes.oct, UnitTypes.corvus);
});
Events.on(UnitDestroyEvent.class, e -> { Events.on(UnitDestroyEvent.class, e -> {
if(ncustom()){ if(campaign()){
if(e.unit.team != Vars.player.team()){ if(e.unit.team != Vars.player.team()){
SStat.unitsDestroyed.add(); SStat.unitsDestroyed.add();
@@ -106,7 +101,7 @@ public class SStats implements SteamUserStatsCallback{
} }
} }
SStat.maxProduction.max(Mathf.round(total)); SStat.maxProduction.max(Math.round(total));
}); });
Events.run(Trigger.newGame, () -> Core.app.post(() -> { Events.run(Trigger.newGame, () -> Core.app.post(() -> {
@@ -142,9 +137,11 @@ public class SStats implements SteamUserStatsCallback{
} }
if(e.tile.block() instanceof Conveyor){ if(e.tile.block() instanceof Conveyor){
checked.clear();
check: { check: {
Tile current = e.tile; Tile current = e.tile;
for(int i = 0; i < 4; i++){ for(int i = 0; i < 4; i++){
checked.add(current.pos());
if(current.build == null) break check; if(current.build == null) break check;
Tile next = current.nearby(current.build.rotation); Tile next = current.nearby(current.build.rotation);
if(next != null && next.block() instanceof Conveyor){ if(next != null && next.block() instanceof Conveyor){
@@ -154,7 +151,7 @@ public class SStats implements SteamUserStatsCallback{
} }
} }
if(current == e.tile){ if(current == e.tile && checked.size == 4){
circleConveyor.complete(); circleConveyor.complete();
} }
} }
@@ -249,15 +246,6 @@ public class SStats implements SteamUserStatsCallback{
} }
}); });
Events.on(LoseEvent.class, e -> {
if(campaign()){
//TODO implement
//if(state.getSector().metCondition() && (state.wave - state.getSector().conditionWave) / state.getSector().launchPeriod >= 1){
// skipLaunching2Death.complete();
//}
}
});
Events.on(SectorLaunchEvent.class, e -> { Events.on(SectorLaunchEvent.class, e -> {
SStat.timesLaunched.add(); SStat.timesLaunched.add();
}); });
@@ -267,7 +255,7 @@ public class SStats implements SteamUserStatsCallback{
}); });
Events.on(WaveEvent.class, e -> { Events.on(WaveEvent.class, e -> {
if(ncustom()){ if(campaign()){
SStat.maxWavesSurvived.max(Vars.state.wave); SStat.maxWavesSurvived.max(Vars.state.wave);
if(state.stats.buildingsBuilt == 0 && state.wave >= 10){ if(state.stats.buildingsBuilt == 0 && state.wave >= 10){
@@ -301,6 +289,7 @@ public class SStats implements SteamUserStatsCallback{
}); });
Events.on(SectorCaptureEvent.class, e -> { Events.on(SectorCaptureEvent.class, e -> {
if(e.sector.isBeingPlayed() || net.client()){
if(Vars.state.wave <= 5 && state.rules.attackMode){ if(Vars.state.wave <= 5 && state.rules.attackMode){
defeatAttack5Waves.complete(); defeatAttack5Waves.complete();
} }
@@ -308,6 +297,7 @@ public class SStats implements SteamUserStatsCallback{
if(state.stats.buildingsDestroyed == 0){ if(state.stats.buildingsDestroyed == 0){
captureNoBlocksBroken.complete(); captureNoBlocksBroken.complete();
} }
}
if(Vars.state.rules.attackMode){ if(Vars.state.rules.attackMode){
SStat.attacksWon.add(); SStat.attacksWon.add();
@@ -323,16 +313,6 @@ public class SStats implements SteamUserStatsCallback{
SStat.sectorsControlled.set(e.sector.planet.sectors.count(Sector::hasBase)); SStat.sectorsControlled.set(e.sector.planet.sectors.count(Sector::hasBase));
}); });
//TODO dead achievement
/*
Events.on(MechChangeEvent.class, e -> {
if(campaign()){
if(mechs.add(e.mech.name)){
SStat.zoneMechsUsed.max(mechs.size);
}
}
});*/
} }
private void save(){ private void save(){
@@ -348,10 +328,6 @@ public class SStats implements SteamUserStatsCallback{
}); });
} }
private boolean ncustom(){
return campaign();
}
private boolean campaign(){ private boolean campaign(){
return Vars.state.isCampaign(); return Vars.state.isCampaign();
} }

View File

@@ -0,0 +1,11 @@
Baue komplexe Produktionsketten aus Förderbändern, um deine Geschütztürme mit Munition zu versorgen. Stelle Materialien her, um deine Fabrik zu vergrößern und sie vor Gegnerwellen zu schützen. Spiele mit deinen Freunden in plattformübergreifenden Partien oder fordere sie zum Kampf heraus.
Dieses Tower-Defense-Spiel bietet:
- 24 Karten
- Eine Kampagne, die ins Spiel einführt und einen Forschungsbaum enthält
- 4 mächtige Bosse
- Transportsysteme für Materialien, Flüssigkeiten und Strom
- 19 verschiedene Einheiten, die du kommandieren kannst
- Mehrspielerpartien im lokalen Netzwerk oder über einen Server
Mithilfe eines eingebauten Editors können eigene Karten und Gegnerwellen erstellt werden. Die Spielregeln kannst du flexibel nach deinen Wünschen anpassen.

View File

@@ -0,0 +1 @@
Verteidige deine Basis mit einer Fabrik in diesem Sandbox-Spiel.

View File

@@ -0,0 +1 @@
Verteidige deine Basis mit einer Fabrik in diesem Sandbox-Spiel.

View File

@@ -0,0 +1 @@
Mindustry

View File

@@ -0,0 +1,10 @@
[This is a truncated changelog, see Github for full notes]
- Fixed rebuilding a core near vault causing resources to drop to 1K
- Fixed captured sectors getting locked
Campaign multiplayer changes:
- New host research is now carried over to clients
- Clients can now use their research even if the host doesn't have it
- Clients can now research new tech in multiplayer
- Added a hint that explains this information

View File

@@ -0,0 +1,8 @@
[This is a truncated changelog, see Github for full notes]
- Slightly increased Lancer build cost
- Double-tapping now enters a campaign map (Contributed by @joshuaptfan)
- Minor logic memory optimizations - block/sensor constants are no longer stored in every processor
- Doubled surge smelter item capacity
- Made Fungal Pass slightly easier
- Fixed some rare crashes
- Fixed unit spawn shockwave appearing too late

View File

@@ -0,0 +1,2 @@
[This is a truncated changelog, see Github for full notes]
- Fixed a common crash related to planet selection

View File

@@ -32,7 +32,7 @@
"NEW_ACHIEVEMENT_20_14_NAME" "Stromschlag" "NEW_ACHIEVEMENT_20_14_NAME" "Stromschlag"
"NEW_ACHIEVEMENT_20_14_DESC" "Treffe einen nassen Gegner mit Elektrizität." "NEW_ACHIEVEMENT_20_14_DESC" "Treffe einen nassen Gegner mit Elektrizität."
"NEW_ACHIEVEMENT_20_15_NAME" "Zurück zum Sender" "NEW_ACHIEVEMENT_20_15_NAME" "Zurück zum Sender"
"NEW_ACHIEVEMENT_20_15_DESC" "Zerstöre eine Einheit mit dessem eigenem reflektiertem Projektiel." "NEW_ACHIEVEMENT_20_15_DESC" "Zerstöre eine Einheit mit dessen eigenem reflektierten Projektil."
"NEW_ACHIEVEMENT_20_17_NAME" "Ein schwerer Fehler..." "NEW_ACHIEVEMENT_20_17_NAME" "Ein schwerer Fehler..."
"NEW_ACHIEVEMENT_20_17_DESC" "Erforsche den Verteiler." "NEW_ACHIEVEMENT_20_17_DESC" "Erforsche den Verteiler."
"NEW_ACHIEVEMENT_20_18_NAME" "Erschaffen" "NEW_ACHIEVEMENT_20_18_NAME" "Erschaffen"
@@ -66,15 +66,15 @@
"NEW_ACHIEVEMENT_21_3_NAME" "Schwarm" "NEW_ACHIEVEMENT_21_3_NAME" "Schwarm"
"NEW_ACHIEVEMENT_21_3_DESC" "Habe 100 Einheiten auf einmal aktiv." "NEW_ACHIEVEMENT_21_3_DESC" "Habe 100 Einheiten auf einmal aktiv."
"NEW_ACHIEVEMENT_21_4_NAME" "Schar" "NEW_ACHIEVEMENT_21_4_NAME" "Schar"
"NEW_ACHIEVEMENT_21_4_DESC" "Habe 10 Phantom-Drone auf einmal aktiv." "NEW_ACHIEVEMENT_21_4_DESC" "Habe 10 Phantom-Drohnen auf einmal aktiv."
"NEW_ACHIEVEMENT_21_5_NAME" "Instabile Armee" "NEW_ACHIEVEMENT_21_5_NAME" "Instabile Armee"
"NEW_ACHIEVEMENT_21_5_DESC" "Habe 50 Crawler auf einmal aktiv." "NEW_ACHIEVEMENT_21_5_DESC" "Habe 50 Crawler auf einmal aktiv."
"NEW_ACHIEVEMENT_21_6_NAME" "Legion" "NEW_ACHIEVEMENT_21_6_NAME" "Legion"
"NEW_ACHIEVEMENT_21_6_DESC" "Baue 1.000 Einheiten insgesamt." "NEW_ACHIEVEMENT_21_6_DESC" "Baue 1.000 Einheiten insgesamt."
"NEW_ACHIEVEMENT_21_7_NAME" "Super" "NEW_ACHIEVEMENT_21_7_NAME" "Super"
"NEW_ACHIEVEMENT_21_7_DESC" "Verdiene den S Rank in einer Zone." "NEW_ACHIEVEMENT_21_7_DESC" "Verdiene den S-Rank in einer Zone."
"NEW_ACHIEVEMENT_21_8_NAME" "Super Super" "NEW_ACHIEVEMENT_21_8_NAME" "Super Super"
"NEW_ACHIEVEMENT_21_8_DESC" "Verdiene den SS Rank in einer Zone." "NEW_ACHIEVEMENT_21_8_DESC" "Verdiene den SS-Rank in einer Zone."
"NEW_ACHIEVEMENT_21_9_NAME" "Du Solltest Zuhören..." "NEW_ACHIEVEMENT_21_9_NAME" "Du Solltest Zuhören..."
"NEW_ACHIEVEMENT_21_9_DESC" "Stirb im Gegnerspawn." "NEW_ACHIEVEMENT_21_9_DESC" "Stirb im Gegnerspawn."
"NEW_ACHIEVEMENT_21_10_NAME" "Drück einfach Umschalt" "NEW_ACHIEVEMENT_21_10_NAME" "Drück einfach Umschalt"

View File

@@ -0,0 +1,56 @@
[img]{STEAM_APP_IMAGE}/extras/ezgif-4-0e70c282f775.gif[/img]
[h2]Spielmechanik[/h2]
[list]
[*] Baue komplexe Produktionsketten aus Förderbändern, um deine Geschütztürme mit Munition zu versorgen
[*] Stelle Materialien her, um deine Fabrik zu vergrößern und sie vor Gegnerwellen zu schützen
[*] Spiele mit deinen Freunden in plattformübergreifenden Partien oder fordere sie zum Kampf heraus
[*] Es gibt immer etwas zu tun: Wenn du deine Kühlsysteme nicht im Blick behältst, könnte dein Reaktor explodieren!
[*] Produziere Einheiten, die bei deiner Basis helfen oder den Gegner angreifen
[/list]
[img]{STEAM_APP_IMAGE}/extras/ezgif-1-8679abe089cd.gif[/img]
[h2]Kampagne[/h2]
[list]
[*] Erobere den Planeten Serpulo, indem du über 250 prozedural generierte Sektoren und 16 handgemachte Karten eroberst
[*] Stelle Materialien in eroberten Sektoren her, während du den nächsten Sektor eroberst
[*] Verteidige deine Sektoren vor regelmäßigen Invasionen
[*] Transportiere Materialien zwischen deinen Sektoren
[*] Schalte neue Blöcke in der Forschung frei
[*] Schließe Missionen zusammen mit deinen Freunden ab
[*] 33 verschiedene Einheiten
[*] über 50 Erfolge
[/list]
[h2]Spielmodi[/h2]
[list]
[*] [b]Überleben[/b]: Baue Geschütztürme und verteidige Wellen von Gegnern. Bereite dich auf zwischenzeitliche Zerstörungsangriffe von flugfähigen Einheiten vor.
[*] [b]Angriff[/b]: Stelle Einheiten her, um den gegnerischen Kern zu zerstören. Vergesse dabei nicht, deinen eigenen Kern zu schützen!
[*] [b]PvP[/b]: Kämpfe gegen andere Spieler in Teams und zerstöre die gegnerischen Kerne.
[*] [b]Sandkasten[/b]: Probiere deine Designs mit unendlichen Ressourcen und Gegnerwellen auf Anfrage aus.
[/list]
[img]{STEAM_APP_IMAGE}/extras/2020-11-30_10-46-02.gif[/img]
[h2]Mehrspielermodus[/h2]
[list]
[*] Trete einem öffentlichen Server bei oder eröffne ein Spiel für deine Freunde
[*] Ändere die Spielregeln: Kosten, Schadenswerte und mehr!
[*] Kombiniere PvP und PvE (player versus enemies)
[/list]
[h2]Karteneditor[/h2]
[list]
[*] Passe die Werkzeuge nach deinen Vorstellungen an
[*] Viele Filter für das prozedurale Generieren der Umgebung
[*] Verschönere die Landschaft mit Rauschen, Verzerrungen, Erosion, Symmetrie und Zufallsgenerierung
[*] Modifiziere die Gegnerwellen
[*] Teile deine Karten im Steam-Workshop
[*] Nutze über 80 verschiedene Umgebungsblöcke
[/list]

View File

@@ -0,0 +1 @@
Ein offenes Tower-Defense-Spiel mit Fokus auf Ressourcenverwaltung

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