Merge pull request #1 from Anuken/master

merge with Anuken/Mindustry
This commit is contained in:
BasedUser
2019-10-14 13:51:32 +03:00
committed by GitHub
86 changed files with 11766 additions and 11070 deletions

View File

@@ -37,6 +37,7 @@ public class AssetsAnnotationProcessor extends AbstractProcessor{
path = Paths.get(Utils.filer.createResource(StandardLocation.CLASS_OUTPUT, "no", "no") path = Paths.get(Utils.filer.createResource(StandardLocation.CLASS_OUTPUT, "no", "no")
.toUri().toURL().toString().substring(System.getProperty("os.name").contains("Windows") ? 6 : "file:".length())) .toUri().toURL().toString().substring(System.getProperty("os.name").contains("Windows") ? 6 : "file:".length()))
.getParent().getParent().getParent().getParent().getParent().getParent().toString(); .getParent().getParent().getParent().getParent().getParent().getParent().toString();
path = path.replace("%20", " ");
processSounds("Sounds", path + "/assets/sounds", "io.anuke.arc.audio.Sound"); processSounds("Sounds", path + "/assets/sounds", "io.anuke.arc.audio.Sound");
processSounds("Musics", path + "/assets/music", "io.anuke.arc.audio.Music"); processSounds("Musics", path + "/assets/music", "io.anuke.arc.audio.Music");

View File

@@ -152,7 +152,7 @@ project(":desktop"){
compile "com.code-disaster.steamworks4j:steamworks4j-server:$steamworksVersion" compile "com.code-disaster.steamworks4j:steamworks4j-server:$steamworksVersion"
compile arcModule("backends:backend-sdl") compile arcModule("backends:backend-sdl")
compile 'com.github.MinnDevelopment:java-discord-rpc:v2.0.2' compile 'com.github.MinnDevelopment:java-discord-rpc:v2.0.1'
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 B

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -216,6 +216,9 @@ quit.confirm.tutorial = Are you sure you know what you're doing?\nThe tutorial c
loading = [accent]Loading... loading = [accent]Loading...
reloading = [accent]Reloading Mods... reloading = [accent]Reloading Mods...
saving = [accent]Saving... saving = [accent]Saving...
cancelbuilding = [accent][[{0}][] to clear plan
pausebuilding = [accent][[{0}][] to pause building
resumebuilding = [scarlet][[{0}][] to resume building
wave = [accent]Wave {0} wave = [accent]Wave {0}
wave.waiting = [lightgray]Wave in {0} wave.waiting = [lightgray]Wave in {0}
wave.waveInProgress = [lightgray]Wave in progress wave.waveInProgress = [lightgray]Wave in progress
@@ -560,6 +563,7 @@ category.optional = Optional Enhancements
setting.landscape.name = Lock Landscape setting.landscape.name = Lock Landscape
setting.shadows.name = Shadows setting.shadows.name = Shadows
setting.linear.name = Linear Filtering setting.linear.name = Linear Filtering
setting.hints.name = Hints
setting.animatedwater.name = Animated Water setting.animatedwater.name = Animated Water
setting.animatedshields.name = Animated Shields setting.animatedshields.name = Animated Shields
setting.antialias.name = Antialias[lightgray] (requires restart)[] setting.antialias.name = Antialias[lightgray] (requires restart)[]
@@ -587,7 +591,6 @@ setting.fullscreen.name = Fullscreen
setting.borderlesswindow.name = Borderless Window[lightgray] (may require restart) setting.borderlesswindow.name = Borderless Window[lightgray] (may require restart)
setting.fps.name = Show FPS setting.fps.name = Show FPS
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Show Power Lasers
setting.pixelate.name = Pixelate[lightgray] (disables animations) setting.pixelate.name = Pixelate[lightgray] (disables animations)
setting.minimap.name = Show Minimap setting.minimap.name = Show Minimap
setting.musicvol.name = Music Volume setting.musicvol.name = Music Volume
@@ -599,8 +602,10 @@ setting.crashreport.name = Send Anonymous Crash Reports
setting.savecreate.name = Auto-Create Saves setting.savecreate.name = Auto-Create Saves
setting.publichost.name = Public Game Visibility setting.publichost.name = Public Game Visibility
setting.chatopacity.name = Chat Opacity setting.chatopacity.name = Chat Opacity
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Display Player Bubble Chat setting.playerchat.name = Display Player Bubble Chat
public.confirm = Do you want to make your game public?\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.
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...
uiscale.cancel = Cancel & Exit uiscale.cancel = Cancel & Exit
setting.bloom.name = Bloom setting.bloom.name = Bloom
@@ -614,6 +619,7 @@ command.rally = Rally
command.retreat = Retreat command.retreat = Retreat
keybind.gridMode.name = Block Select keybind.gridMode.name = Block Select
keybind.gridModeShift.name = Category Select keybind.gridModeShift.name = Category Select
keybind.clear_building.name = Clear Building
keybind.press = Press a key... keybind.press = Press a key...
keybind.press.axis = Press an axis or key... keybind.press.axis = Press an axis or key...
keybind.screenshot.name = Map Screenshot keybind.screenshot.name = Map Screenshot
@@ -630,6 +636,7 @@ keybind.zoom_hold.name = Zoom Hold
keybind.zoom.name = Zoom keybind.zoom.name = Zoom
keybind.menu.name = Menu keybind.menu.name = Menu
keybind.pause.name = Pause keybind.pause.name = Pause
keybind.pause_building.name = Pause/Resume Building
keybind.minimap.name = Minimap keybind.minimap.name = Minimap
keybind.dash.name = Dash keybind.dash.name = Dash
keybind.chat.name = Chat keybind.chat.name = Chat
@@ -838,6 +845,7 @@ block.junction.name = Junction
block.router.name = Router block.router.name = Router
block.distributor.name = Distributor block.distributor.name = Distributor
block.sorter.name = Sorter block.sorter.name = Sorter
block.inverted-sorter.name = Inverted Sorter
block.message.name = Message block.message.name = Message
block.overflow-gate.name = Overflow Gate block.overflow-gate.name = Overflow Gate
block.silicon-smelter.name = Silicon Smelter block.silicon-smelter.name = Silicon Smelter
@@ -1059,6 +1067,7 @@ block.junction.description = Acts as a bridge for two crossing conveyor belts. U
block.bridge-conveyor.description = Advanced item transport block. Allows transporting items over up to 3 tiles of any terrain or building. block.bridge-conveyor.description = Advanced item transport block. Allows transporting items over up to 3 tiles of any terrain or building.
block.phase-conveyor.description = Advanced item transport block. Uses power to teleport items to a connected phase conveyor over several tiles. block.phase-conveyor.description = Advanced item transport block. Uses power to teleport items to a connected phase conveyor over several tiles.
block.sorter.description = Sorts items. If an item matches the selection, it is allowed to pass. Otherwise, the item is outputted to the left and right. block.sorter.description = Sorts items. If an item matches the selection, it is allowed to pass. Otherwise, the item is outputted to the left and right.
block.inverted-sorter.descriptions = Processes items like a standard sorter, but outputs selected items to the sides instead.
block.router.description = Accepts items, then outputs them to up to 3 other directions equally. Useful for splitting the materials from one source to multiple targets.\n\n[scarlet]Never use next to production inputs, as they will get clogged by output.[] block.router.description = Accepts items, then outputs them to up to 3 other directions equally. Useful for splitting the materials from one source to multiple targets.\n\n[scarlet]Never use next to production inputs, as they will get clogged by output.[]
block.distributor.description = An advanced router. Splits items to up to 7 other directions equally. block.distributor.description = An advanced router. Splits items to up to 7 other directions equally.
block.overflow-gate.description = A combination splitter and router. Only outputs to the left and right if the front path is blocked. block.overflow-gate.description = A combination splitter and router. Only outputs to the left and right if the front path is blocked.

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Celá obrazovka
setting.borderlesswindow.name = Borderless Window[LIGHT_GRAY] (may require restart) setting.borderlesswindow.name = Borderless Window[LIGHT_GRAY] (may require restart)
setting.fps.name = Ukázat snímky/sekundu setting.fps.name = Ukázat snímky/sekundu
setting.vsync.name = Vertikální synchronizace setting.vsync.name = Vertikální synchronizace
setting.lasers.name = Ukázat laser energie
setting.pixelate.name = Pixelate [LIGHT_GRAY](may decrease performance) setting.pixelate.name = Pixelate [LIGHT_GRAY](may decrease performance)
setting.minimap.name = Ukázat minimapu setting.minimap.name = Ukázat minimapu
setting.musicvol.name = Hlasitost hudby setting.musicvol.name = Hlasitost hudby
@@ -557,6 +556,7 @@ setting.crashreport.name = Poslat anonymní spis o zhroucení hry
setting.savecreate.name = Auto-Create Saves setting.savecreate.name = Auto-Create Saves
setting.publichost.name = Public Game Visibility setting.publichost.name = Public Game Visibility
setting.chatopacity.name = Chat Opacity setting.chatopacity.name = Chat Opacity
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Display In-Game Chat setting.playerchat.name = Display In-Game Chat
uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings...
uiscale.cancel = Cancel & Exit uiscale.cancel = Cancel & Exit

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Vollbild
setting.borderlesswindow.name = Randloses Fenster[LIGHT_GRAY] (Neustart teilweise erforderlich) setting.borderlesswindow.name = Randloses Fenster[LIGHT_GRAY] (Neustart teilweise erforderlich)
setting.fps.name = Zeige FPS setting.fps.name = Zeige FPS
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Zeige Stromlaser
setting.pixelate.name = Verpixeln [LIGHT_GRAY](Könnte die Leistung beeinträchtigen) setting.pixelate.name = Verpixeln [LIGHT_GRAY](Könnte die Leistung beeinträchtigen)
setting.minimap.name = Zeige die Minimap setting.minimap.name = Zeige die Minimap
setting.musicvol.name = Musiklautstärke setting.musicvol.name = Musiklautstärke
@@ -557,6 +556,7 @@ setting.crashreport.name = Anonyme Absturzberichte senden
setting.savecreate.name = Auto-Create Saves setting.savecreate.name = Auto-Create Saves
setting.publichost.name = Public Game Visibility setting.publichost.name = Public Game Visibility
setting.chatopacity.name = Chat Deckkraft setting.chatopacity.name = Chat Deckkraft
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Chat im Spiel anzeigen setting.playerchat.name = Chat im Spiel anzeigen
uiscale.reset = UI-Skalierung wurde geändert.\nDrücke "OK", um diese Skalierung zu bestätigen.\n[scarlet]Zurückkehren und Beenden in[accent] {0}[] Einstellungen... 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

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Pantalla Completa
setting.borderlesswindow.name = Ventana sin Bordes[LIGHT_GRAY] (podría requerir un reinicio) setting.borderlesswindow.name = Ventana sin Bordes[LIGHT_GRAY] (podría requerir un reinicio)
setting.fps.name = Mostrar FPS setting.fps.name = Mostrar FPS
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Mostrar Energía de los Láseres
setting.pixelate.name = Pixelar [LIGHT_GRAY](podría reducir el rendimiento) setting.pixelate.name = Pixelar [LIGHT_GRAY](podría reducir el rendimiento)
setting.minimap.name = Mostrar Minimapa setting.minimap.name = Mostrar Minimapa
setting.musicvol.name = Volumen de la Música setting.musicvol.name = Volumen de la Música
@@ -557,6 +556,7 @@ setting.crashreport.name = Enviar informes de fallos anónimos
setting.savecreate.name = Auto-Create Saves setting.savecreate.name = Auto-Create Saves
setting.publichost.name = Public Game Visibility setting.publichost.name = Public Game Visibility
setting.chatopacity.name = Opacidad del Chat setting.chatopacity.name = Opacidad del Chat
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Display In-Game Chat setting.playerchat.name = Display In-Game Chat
uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] seconds... uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] seconds...
uiscale.cancel = Cancel & Exit uiscale.cancel = Cancel & Exit

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Täisekraan
setting.borderlesswindow.name = Borderless Window[LIGHT_GRAY] (may require restart) setting.borderlesswindow.name = Borderless Window[LIGHT_GRAY] (may require restart)
setting.fps.name = Show FPS setting.fps.name = Show FPS
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Näita Energia Lasereid
setting.pixelate.name = Pixelate[LIGHT_GRAY] (disables animations) setting.pixelate.name = Pixelate[LIGHT_GRAY] (disables animations)
setting.minimap.name = Näita Kaarti setting.minimap.name = Näita Kaarti
setting.musicvol.name = Heli tase setting.musicvol.name = Heli tase
@@ -557,6 +556,7 @@ setting.crashreport.name = Send Anonymous Crash Reports
setting.savecreate.name = Auto-Create Saves setting.savecreate.name = Auto-Create Saves
setting.publichost.name = Public Game Visibility setting.publichost.name = Public Game Visibility
setting.chatopacity.name = Chat Opacity setting.chatopacity.name = Chat Opacity
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Display In-Game Chat setting.playerchat.name = Display In-Game Chat
uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] seconds... uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] seconds...
uiscale.cancel = Cancel & Exit uiscale.cancel = Cancel & Exit

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Pantaila osoa
setting.borderlesswindow.name = Ertzik gabeko leihoa[lightgray] (berrabiaraztea behar lezake) setting.borderlesswindow.name = Ertzik gabeko leihoa[lightgray] (berrabiaraztea behar lezake)
setting.fps.name = Erakutsi FPS setting.fps.name = Erakutsi FPS
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Erakutsi energia laserrak
setting.pixelate.name = Pixelatu[lightgray] (animazioak desgaitzen ditu) setting.pixelate.name = Pixelatu[lightgray] (animazioak desgaitzen ditu)
setting.minimap.name = Erakutsi mapatxoa setting.minimap.name = Erakutsi mapatxoa
setting.musicvol.name = Musikaren bolumena setting.musicvol.name = Musikaren bolumena
@@ -557,6 +556,7 @@ setting.crashreport.name = Bidali kraskatze txosten automatikoak
setting.savecreate.name = Gorde automatikoki setting.savecreate.name = Gorde automatikoki
setting.publichost.name = Public Game Visibility setting.publichost.name = Public Game Visibility
setting.chatopacity.name = Txataren opakotasuna setting.chatopacity.name = Txataren opakotasuna
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Erakutsi jolas barneko txata setting.playerchat.name = Erakutsi jolas barneko txata
uiscale.reset = Interfazearen eskala aldatu da.\nSakatu "Ados" eskala hau berresteko.\n[scarlet][accent] {0}[] segundo atzera egin eta irteteko... uiscale.reset = Interfazearen eskala aldatu da.\nSakatu "Ados" eskala hau berresteko.\n[scarlet][accent] {0}[] segundo atzera egin eta irteteko...
uiscale.cancel = Utzi eta irten uiscale.cancel = Utzi eta irten

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Plein Écran
setting.borderlesswindow.name = Fenêtre sans bords (Borderless)[lightgray] (peut requérir le redémarrage du jeu) setting.borderlesswindow.name = Fenêtre sans bords (Borderless)[lightgray] (peut requérir le redémarrage du jeu)
setting.fps.name = Afficher FPS setting.fps.name = Afficher FPS
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Afficher les connections Électriques
setting.pixelate.name = Pixeliser[lightgray] (désactive les animations) setting.pixelate.name = Pixeliser[lightgray] (désactive les animations)
setting.minimap.name = Montrer la Minimap setting.minimap.name = Montrer la Minimap
setting.musicvol.name = Volume Musique setting.musicvol.name = Volume Musique
@@ -557,6 +556,7 @@ setting.crashreport.name = Envoyer un Rapport de Crash Anonyme
setting.savecreate.name = Sauvegardes Auto setting.savecreate.name = Sauvegardes Auto
setting.publichost.name = Visibilité de la Partie Publique setting.publichost.name = Visibilité de la Partie Publique
setting.chatopacity.name = Opacité du Chat setting.chatopacity.name = Opacité du Chat
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Montrer le Chat setting.playerchat.name = Montrer le Chat
uiscale.reset = L'échelle de l'interface a été modifiée.\nAppuyez sur "OK" pour confirmer.\n[scarlet]Rétablissement aux parametres d'avant et fermeture dans [accent] {0}[]... uiscale.reset = L'échelle de l'interface a été modifiée.\nAppuyez sur "OK" pour confirmer.\n[scarlet]Rétablissement aux parametres d'avant et fermeture dans [accent] {0}[]...
uiscale.cancel = Annuler & Quitter uiscale.cancel = Annuler & Quitter

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Plein écran
setting.borderlesswindow.name = Fenêtre sans bordure[LIGHT_GRAY] (peut nécessiter un redémarrage) setting.borderlesswindow.name = Fenêtre sans bordure[LIGHT_GRAY] (peut nécessiter un redémarrage)
setting.fps.name = Afficher FPS setting.fps.name = Afficher FPS
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Afficher les rayons des lasers
setting.pixelate.name = Pixélisé [LIGHT_GRAY](peut diminuer les performances)[] setting.pixelate.name = Pixélisé [LIGHT_GRAY](peut diminuer les performances)[]
setting.minimap.name = Montrer la minimap setting.minimap.name = Montrer la minimap
setting.musicvol.name = Volume de la musique setting.musicvol.name = Volume de la musique
@@ -557,6 +556,7 @@ setting.crashreport.name = Envoyer des rapports d'incident anonymement.
setting.savecreate.name = Auto-Create Saves setting.savecreate.name = Auto-Create Saves
setting.publichost.name = Public Game Visibility setting.publichost.name = Public Game Visibility
setting.chatopacity.name = Opacité du tchat setting.chatopacity.name = Opacité du tchat
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Afficher le tchat en jeu setting.playerchat.name = Afficher le tchat en jeu
uiscale.reset = L'échelle de l'interface a été modifiée.\nAppuyez sur "OK" pour confirmer cette échelle.\n[scarlet]Revenir et sortir en[accent] {0}[] réglages... uiscale.reset = L'échelle de l'interface a été modifiée.\nAppuyez sur "OK" pour confirmer cette échelle.\n[scarlet]Revenir et sortir en[accent] {0}[] réglages...
uiscale.cancel = Annuler et quitter uiscale.cancel = Annuler et quitter

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Layar Penuh
setting.borderlesswindow.name = Jendela tak Berbatas[LIGHT_GRAY] (bisa membutuhkan restart) setting.borderlesswindow.name = Jendela tak Berbatas[LIGHT_GRAY] (bisa membutuhkan restart)
setting.fps.name = Tunjukkan FPS setting.fps.name = Tunjukkan FPS
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Tunjukkan Laser
setting.pixelate.name = Mode Pixel[LIGHT_GRAY] (menonaktifkan animasi) setting.pixelate.name = Mode Pixel[LIGHT_GRAY] (menonaktifkan animasi)
setting.minimap.name = Tunjukkan Peta kecil setting.minimap.name = Tunjukkan Peta kecil
setting.musicvol.name = Volume Musik setting.musicvol.name = Volume Musik
@@ -557,6 +556,7 @@ setting.crashreport.name = Laporkan Masalah
setting.savecreate.name = Auto-Create Saves setting.savecreate.name = Auto-Create Saves
setting.publichost.name = Public Game Visibility setting.publichost.name = Public Game Visibility
setting.chatopacity.name = Jelas-Beningnya Chat setting.chatopacity.name = Jelas-Beningnya Chat
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Tunjukkan Chat dalam Permainan setting.playerchat.name = Tunjukkan Chat dalam Permainan
uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings...
uiscale.cancel = Cancel & Exit uiscale.cancel = Cancel & Exit

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Schermo Intero
setting.borderlesswindow.name = Schermo senza bordi[LIGHT_GRAY] (potrebbe richiedere riapertura gioco) setting.borderlesswindow.name = Schermo senza bordi[LIGHT_GRAY] (potrebbe richiedere riapertura gioco)
setting.fps.name = Mostra FPS setting.fps.name = Mostra FPS
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Mostra Laser Energetici
setting.pixelate.name = Sfocare [LIGHT_GRAY](potrebbe ridure il rendimento) setting.pixelate.name = Sfocare [LIGHT_GRAY](potrebbe ridure il rendimento)
setting.minimap.name = Mostra minimappa setting.minimap.name = Mostra minimappa
setting.musicvol.name = Volume Musica setting.musicvol.name = Volume Musica
@@ -557,6 +556,7 @@ setting.crashreport.name = Invia rapporti sugli arresti anomali anonimamente
setting.savecreate.name = Auto-Create Saves setting.savecreate.name = Auto-Create Saves
setting.publichost.name = Public Game Visibility setting.publichost.name = Public Game Visibility
setting.chatopacity.name = Opacità chat setting.chatopacity.name = Opacità chat
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Mostra Chat in-game setting.playerchat.name = Mostra Chat in-game
uiscale.reset = La scala dell'interfaccia utente è stata modificata.\nPremere "OK" per confermare questa scala.\n[scarlet] Ripristina ed esci dalle impostazioni [accent] {0}[] impostazioni... uiscale.reset = La scala dell'interfaccia utente è stata modificata.\nPremere "OK" per confermare questa scala.\n[scarlet] Ripristina ed esci dalle impostazioni [accent] {0}[] impostazioni...
uiscale.cancel = Annulla ed esci uiscale.cancel = Annulla ed esci

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = フルスクリーン
setting.borderlesswindow.name = 境界の無いウィンドウ[lightgray] (再起動が必要になる場合があります) setting.borderlesswindow.name = 境界の無いウィンドウ[lightgray] (再起動が必要になる場合があります)
setting.fps.name = FPSを表示 setting.fps.name = FPSを表示
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = 電力線を表示
setting.pixelate.name = ピクセル化[lightgray] (アニメーションが無効化されます) setting.pixelate.name = ピクセル化[lightgray] (アニメーションが無効化されます)
setting.minimap.name = ミニマップを表示 setting.minimap.name = ミニマップを表示
setting.musicvol.name = 音楽 音量 setting.musicvol.name = 音楽 音量
@@ -557,6 +556,7 @@ setting.crashreport.name = 匿名でクラッシュレポートを送信する
setting.savecreate.name = 自動保存 setting.savecreate.name = 自動保存
setting.publichost.name = 誰でもゲームに参加できるようにする setting.publichost.name = 誰でもゲームに参加できるようにする
setting.chatopacity.name = チャットの透明度 setting.chatopacity.name = チャットの透明度
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = ゲーム内にチャットを表示 setting.playerchat.name = ゲーム内にチャットを表示
uiscale.reset = UIサイズが変更されました。\nこのままでよければ「OK」を押してください。\n[scarlet][accent]{0}[] 秒で元の設定に戻ります... uiscale.reset = UIサイズが変更されました。\nこのままでよければ「OK」を押してください。\n[scarlet][accent]{0}[] 秒で元の設定に戻ります...
uiscale.cancel = キャンセル & 終了 uiscale.cancel = キャンセル & 終了

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = 전체 화면
setting.borderlesswindow.name = 테두리 없는 창모드[LIGHT_GRAY] (재시작이 필요할 수 있습니다) setting.borderlesswindow.name = 테두리 없는 창모드[LIGHT_GRAY] (재시작이 필요할 수 있습니다)
setting.fps.name = FPS 표시 setting.fps.name = FPS 표시
setting.vsync.name = VSync 활성화 setting.vsync.name = VSync 활성화
setting.lasers.name = 전력 노드 레이저 표시
setting.pixelate.name = 픽셀화[LIGHT_GRAY] (애니메이션 효과가 꺼집니다) setting.pixelate.name = 픽셀화[LIGHT_GRAY] (애니메이션 효과가 꺼집니다)
setting.minimap.name = 미니맵 보기 setting.minimap.name = 미니맵 보기
setting.musicvol.name = 음악 크기 setting.musicvol.name = 음악 크기
@@ -557,6 +556,7 @@ setting.crashreport.name = 오류 보고서 보내기
setting.savecreate.name = 자동 저장 활성화 setting.savecreate.name = 자동 저장 활성화
setting.publichost.name = 공용 서버 보이기 setting.publichost.name = 공용 서버 보이기
setting.chatopacity.name = 채팅 투명도 setting.chatopacity.name = 채팅 투명도
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = 인게임 채팅 표시 setting.playerchat.name = 인게임 채팅 표시
uiscale.reset = UI 스케일이 변경되었습니다.\n"확인"버튼을 눌러 스케일을 확인하세요.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... uiscale.reset = UI 스케일이 변경되었습니다.\n"확인"버튼을 눌러 스케일을 확인하세요.\n[scarlet]Reverting and exiting in[accent] {0}[] settings...
uiscale.cancel = 취소 & 나가기 uiscale.cancel = 취소 & 나가기

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Fullscreen
setting.borderlesswindow.name = Borderless Window[LIGHT_GRAY] (may require restart) setting.borderlesswindow.name = Borderless Window[LIGHT_GRAY] (may require restart)
setting.fps.name = Show FPS setting.fps.name = Show FPS
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Show Power Lasers
setting.pixelate.name = Pixelate [LIGHT_GRAY](may decrease performance) setting.pixelate.name = Pixelate [LIGHT_GRAY](may decrease performance)
setting.minimap.name = Show Minimap setting.minimap.name = Show Minimap
setting.musicvol.name = Music Volume setting.musicvol.name = Music Volume
@@ -557,6 +556,7 @@ setting.crashreport.name = Send Anonymous Crash Reports
setting.savecreate.name = Auto-Create Saves setting.savecreate.name = Auto-Create Saves
setting.publichost.name = Public Game Visibility setting.publichost.name = Public Game Visibility
setting.chatopacity.name = Chat Opacity setting.chatopacity.name = Chat Opacity
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Display In-Game Chat setting.playerchat.name = Display In-Game Chat
uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings...
uiscale.cancel = Cancel & Exit uiscale.cancel = Cancel & Exit

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Fullscreen
setting.borderlesswindow.name = Borderless Window[LIGHT_GRAY] (may require restart) setting.borderlesswindow.name = Borderless Window[LIGHT_GRAY] (may require restart)
setting.fps.name = Show FPS setting.fps.name = Show FPS
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Show Power Lasers
setting.pixelate.name = Pixelate [LIGHT_GRAY](may decrease performance, disables animations) setting.pixelate.name = Pixelate [LIGHT_GRAY](may decrease performance, disables animations)
setting.minimap.name = Show Minimap setting.minimap.name = Show Minimap
setting.musicvol.name = Music Volume setting.musicvol.name = Music Volume
@@ -557,6 +556,7 @@ setting.crashreport.name = Send Anonymous Crash Reports
setting.savecreate.name = Auto-Create Saves setting.savecreate.name = Auto-Create Saves
setting.publichost.name = Public Game Visibility setting.publichost.name = Public Game Visibility
setting.chatopacity.name = Chat Opacity setting.chatopacity.name = Chat Opacity
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Display In-Game Chat setting.playerchat.name = Display In-Game Chat
uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings...
uiscale.cancel = Cancel & Exit uiscale.cancel = Cancel & Exit

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Pełny ekran
setting.borderlesswindow.name = Bezramkowe okno[LIGHT_GRAY] (może wymagać restartu) setting.borderlesswindow.name = Bezramkowe okno[LIGHT_GRAY] (może wymagać restartu)
setting.fps.name = Pokazuj FPS setting.fps.name = Pokazuj FPS
setting.vsync.name = Synchronizacja pionowa setting.vsync.name = Synchronizacja pionowa
setting.lasers.name = Pokaż lasery zasilające
setting.pixelate.name = Pikselacja [LIGHT_GRAY](wyłącza animacje) setting.pixelate.name = Pikselacja [LIGHT_GRAY](wyłącza animacje)
setting.minimap.name = Pokaż Minimapę setting.minimap.name = Pokaż Minimapę
setting.musicvol.name = Głośność muzyki setting.musicvol.name = Głośność muzyki
@@ -557,6 +556,7 @@ setting.crashreport.name = Wysyłaj anonimowo dane o crashu gry
setting.savecreate.name = Automatyczne tworzenie zapisu setting.savecreate.name = Automatyczne tworzenie zapisu
setting.publichost.name = Widoczność gry publicznej setting.publichost.name = Widoczność gry publicznej
setting.chatopacity.name = Przezroczystość czatu setting.chatopacity.name = Przezroczystość czatu
setting.lasersopacity.name = Przezroczystość laserów zasilających
setting.playerchat.name = Wyświetlaj czat w grze setting.playerchat.name = Wyświetlaj czat w grze
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}[]
uiscale.cancel = Anuluj i wyjdź uiscale.cancel = Anuluj i wyjdź

View File

@@ -560,7 +560,6 @@ setting.fullscreen.name = Tela Cheia
setting.borderlesswindow.name = Janela sem borda[LIGHT_GRAY] (Pode precisar reiniciar) setting.borderlesswindow.name = Janela sem borda[LIGHT_GRAY] (Pode precisar reiniciar)
setting.fps.name = Mostrar FPS setting.fps.name = Mostrar FPS
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Mostrar lasers
setting.pixelate.name = Pixelizado [LIGHT_GRAY](Pode diminuir a performace) setting.pixelate.name = Pixelizado [LIGHT_GRAY](Pode diminuir a performace)
setting.minimap.name = Mostrar minimapa setting.minimap.name = Mostrar minimapa
setting.musicvol.name = Volume da Música setting.musicvol.name = Volume da Música
@@ -572,6 +571,7 @@ setting.crashreport.name = Enviar denuncias de crash anonimas
setting.savecreate.name = Criar salvamentos automaticamente setting.savecreate.name = Criar salvamentos automaticamente
setting.publichost.name = Visibilidade do jogo público setting.publichost.name = Visibilidade do jogo público
setting.chatopacity.name = Opacidade do chat setting.chatopacity.name = Opacidade do chat
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Mostrar chat em jogo setting.playerchat.name = Mostrar chat em jogo
uiscale.reset = A escala da IU foi mudada.\nPressione "OK" para confirmar esta escala.\n[scarlet]Revertendo e saindo em[accent] {0}[] settings... uiscale.reset = A escala da IU foi mudada.\nPressione "OK" para confirmar esta escala.\n[scarlet]Revertendo e saindo em[accent] {0}[] settings...
uiscale.cancel = Cancelar e sair uiscale.cancel = Cancelar e sair

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Полноэкранный режим
setting.borderlesswindow.name = Безрамочное окно[lightgray] (может потребоваться перезапуск) setting.borderlesswindow.name = Безрамочное окно[lightgray] (может потребоваться перезапуск)
setting.fps.name = Показывать FPS setting.fps.name = Показывать FPS
setting.vsync.name = Вертикальная синхронизация setting.vsync.name = Вертикальная синхронизация
setting.lasers.name = Показывать лазеры энергоснабжения
setting.pixelate.name = Пикселизация[lightgray] (отключает анимации) setting.pixelate.name = Пикселизация[lightgray] (отключает анимации)
setting.minimap.name = Показать миникарту setting.minimap.name = Показать миникарту
setting.musicvol.name = Громкость музыки setting.musicvol.name = Громкость музыки
@@ -557,6 +556,7 @@ setting.crashreport.name = Отправлять анонимные отчёты
setting.savecreate.name = Автоматическое создание сохранений setting.savecreate.name = Автоматическое создание сохранений
setting.publichost.name = Общедоступность игры setting.publichost.name = Общедоступность игры
setting.chatopacity.name = Непрозрачность чата setting.chatopacity.name = Непрозрачность чата
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Отображать облака чата над игроками setting.playerchat.name = Отображать облака чата над игроками
uiscale.reset = Масштаб пользовательского интерфейса был изменён.\nНажмите «ОК» для подтверждения этого масштаба.\n[scarlet]Возврат настроек и выход через[accent] {0}[] секунд… uiscale.reset = Масштаб пользовательского интерфейса был изменён.\nНажмите «ОК» для подтверждения этого масштаба.\n[scarlet]Возврат настроек и выход через[accent] {0}[] секунд…
uiscale.cancel = Отменить & Выйти uiscale.cancel = Отменить & Выйти

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Fullskärm
setting.borderlesswindow.name = Borderless Window[lightgray] (may require restart) setting.borderlesswindow.name = Borderless Window[lightgray] (may require restart)
setting.fps.name = Show FPS setting.fps.name = Show FPS
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Show Power Lasers
setting.pixelate.name = Pixellera[lightgray] (disables animations) setting.pixelate.name = Pixellera[lightgray] (disables animations)
setting.minimap.name = Visa Minikarta setting.minimap.name = Visa Minikarta
setting.musicvol.name = Musikvolym setting.musicvol.name = Musikvolym
@@ -557,6 +556,7 @@ setting.crashreport.name = Skicka Anonyma Krashrapporter
setting.savecreate.name = Auto-Create Saves setting.savecreate.name = Auto-Create Saves
setting.publichost.name = Public Game Visibility setting.publichost.name = Public Game Visibility
setting.chatopacity.name = Chattgenomskinlighet setting.chatopacity.name = Chattgenomskinlighet
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Visa Chatt setting.playerchat.name = Visa Chatt
uiscale.reset = UI-skalan har ändrats.\nTryck "OK" för att använda den här skalan.\n[scarlet]Avslutar och återställer om[accent] {0}[] sekunder... uiscale.reset = UI-skalan har ändrats.\nTryck "OK" för att använda den här skalan.\n[scarlet]Avslutar och återställer om[accent] {0}[] sekunder...
uiscale.cancel = Avbryt och Avsluta uiscale.cancel = Avbryt och Avsluta

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Tam ekran
setting.borderlesswindow.name = Borderless Window[LIGHT_GRAY] (may require restart) setting.borderlesswindow.name = Borderless Window[LIGHT_GRAY] (may require restart)
setting.fps.name = FPS'i goster setting.fps.name = FPS'i goster
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Guc lazerlerini goster
setting.pixelate.name = Pixelate [LIGHT_GRAY](may decrease performance) setting.pixelate.name = Pixelate [LIGHT_GRAY](may decrease performance)
setting.minimap.name = Haritayi goster setting.minimap.name = Haritayi goster
setting.musicvol.name = Ses yuksekligi setting.musicvol.name = Ses yuksekligi
@@ -557,6 +556,7 @@ setting.crashreport.name = Send Anonymous Crash Reports
setting.savecreate.name = Auto-Create Saves setting.savecreate.name = Auto-Create Saves
setting.publichost.name = Public Game Visibility setting.publichost.name = Public Game Visibility
setting.chatopacity.name = Chat Opacity setting.chatopacity.name = Chat Opacity
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Display In-Game Chat setting.playerchat.name = Display In-Game Chat
uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings...
uiscale.cancel = Cancel & Exit uiscale.cancel = Cancel & Exit

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = Fullscreen
setting.borderlesswindow.name = Borderless Window[lightgray] (may require restart) setting.borderlesswindow.name = Borderless Window[lightgray] (may require restart)
setting.fps.name = Show FPS setting.fps.name = Show FPS
setting.vsync.name = VSync setting.vsync.name = VSync
setting.lasers.name = Show Power Lasers
setting.pixelate.name = Pixelate[lightgray] (disables animations) setting.pixelate.name = Pixelate[lightgray] (disables animations)
setting.minimap.name = Show Minimap setting.minimap.name = Show Minimap
setting.musicvol.name = Music Volume setting.musicvol.name = Music Volume
@@ -557,6 +556,7 @@ setting.crashreport.name = Send Anonymous Crash Reports
setting.savecreate.name = Auto-Create Saves setting.savecreate.name = Auto-Create Saves
setting.publichost.name = Public Game Visibility setting.publichost.name = Public Game Visibility
setting.chatopacity.name = Chat Opacity setting.chatopacity.name = Chat Opacity
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Display In-Game Chat setting.playerchat.name = Display In-Game Chat
uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] seconds... uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] seconds...
uiscale.cancel = Cancel & Exit uiscale.cancel = Cancel & Exit

View File

@@ -551,7 +551,6 @@ setting.fullscreen.name = Повноекранний режим
setting.borderlesswindow.name = Вікно без полів[lightgray] (може потребувати перезапуску) setting.borderlesswindow.name = Вікно без полів[lightgray] (може потребувати перезапуску)
setting.fps.name = Показувати FPS setting.fps.name = Показувати FPS
setting.vsync.name = Вертикальна синхронізація setting.vsync.name = Вертикальна синхронізація
setting.lasers.name = Показувати енергію лазерів
setting.pixelate.name = Пікселізація[lightgray] (вимикає анімації) setting.pixelate.name = Пікселізація[lightgray] (вимикає анімації)
setting.minimap.name = Показувати міні-мапу setting.minimap.name = Показувати міні-мапу
setting.musicvol.name = Гучність музики setting.musicvol.name = Гучність музики
@@ -563,6 +562,7 @@ setting.crashreport.name = Відсилати анонімні звіти про
setting.savecreate.name = Автоматичне створення збережень setting.savecreate.name = Автоматичне створення збережень
setting.publichost.name = Загальнодоступність гри setting.publichost.name = Загальнодоступність гри
setting.chatopacity.name = Непрозорість чату setting.chatopacity.name = Непрозорість чату
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = Відображати хмару чата над гравцями setting.playerchat.name = Відображати хмару чата над гравцями
public.confirm = Ви хочете зробити цю гру загальнодоступною?\n[lightgray]Це можна змінити у Налаштування->Гра->Public Game Visibility. public.confirm = Ви хочете зробити цю гру загальнодоступною?\n[lightgray]Це можна змінити у Налаштування->Гра->Public Game Visibility.
uiscale.reset = Масштаб користувальницького інтерфейсу було змінено.\nНатисніть «ОК» для підтверждення цього масшатабу.\n[scarlet]Повернення налаштувань і вихід через[accent] {0}[] … uiscale.reset = Масштаб користувальницького інтерфейсу було змінено.\nНатисніть «ОК» для підтверждення цього масшатабу.\n[scarlet]Повернення налаштувань і вихід через[accent] {0}[] …

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = 全屏
setting.borderlesswindow.name = 无边框窗口[LIGHT_GRAY] (可能需要重启) setting.borderlesswindow.name = 无边框窗口[LIGHT_GRAY] (可能需要重启)
setting.fps.name = 显示 FPS setting.fps.name = 显示 FPS
setting.vsync.name = 垂直同步 setting.vsync.name = 垂直同步
setting.lasers.name = 显示能量射线
setting.pixelate.name = 像素画面 [LIGHT_GRAY](禁用动画) setting.pixelate.name = 像素画面 [LIGHT_GRAY](禁用动画)
setting.minimap.name = 显示小地图 setting.minimap.name = 显示小地图
setting.musicvol.name = 音乐音量 setting.musicvol.name = 音乐音量
@@ -557,6 +556,7 @@ setting.crashreport.name = 发送匿名崩溃报告
setting.savecreate.name = 自动创建存档 setting.savecreate.name = 自动创建存档
setting.publichost.name = 公共游戏旁观 setting.publichost.name = 公共游戏旁观
setting.chatopacity.name = 聊天界面透明度 setting.chatopacity.name = 聊天界面透明度
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = 显示游戏内聊天界面 setting.playerchat.name = 显示游戏内聊天界面
uiscale.reset = UI缩放比例已经改变。\n按下“确定”来确定缩放比例\n[accent]{0}[]秒后[scarlet]退出并恢复设定。 uiscale.reset = UI缩放比例已经改变。\n按下“确定”来确定缩放比例\n[accent]{0}[]秒后[scarlet]退出并恢复设定。
uiscale.cancel = 取消并退出 uiscale.cancel = 取消并退出

View File

@@ -545,7 +545,6 @@ setting.fullscreen.name = 全螢幕
setting.borderlesswindow.name = 無邊框窗口[LIGHT_GRAY](可能需要重啟) setting.borderlesswindow.name = 無邊框窗口[LIGHT_GRAY](可能需要重啟)
setting.fps.name = 顯示FPS setting.fps.name = 顯示FPS
setting.vsync.name = 垂直同步 setting.vsync.name = 垂直同步
setting.lasers.name = 顯示雷射光束
setting.pixelate.name = 像素化[LIGHT_GRAY](可能降低性能) setting.pixelate.name = 像素化[LIGHT_GRAY](可能降低性能)
setting.minimap.name = 顯示小地圖 setting.minimap.name = 顯示小地圖
setting.musicvol.name = 音樂音量 setting.musicvol.name = 音樂音量
@@ -557,6 +556,7 @@ setting.crashreport.name = 發送匿名崩潰報告
setting.savecreate.name = Auto-Create Saves setting.savecreate.name = Auto-Create Saves
setting.publichost.name = Public Game Visibility setting.publichost.name = Public Game Visibility
setting.chatopacity.name = 聊天框不透明度 setting.chatopacity.name = 聊天框不透明度
setting.lasersopacity.name = Power Laser Opacity
setting.playerchat.name = 在遊戲中顯示聊天框 setting.playerchat.name = 在遊戲中顯示聊天框
uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings... uiscale.reset = UI scale has been changed.\nPress "OK" to confirm this scale.\n[scarlet]Reverting and exiting in[accent] {0}[] settings...
uiscale.cancel = Cancel & Exit uiscale.cancel = Cancel & Exit

Binary file not shown.

Before

Width:  |  Height:  |  Size: 725 B

After

Width:  |  Height:  |  Size: 727 B

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 712 KiB

After

Width:  |  Height:  |  Size: 712 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 259 KiB

After

Width:  |  Height:  |  Size: 259 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 893 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 892 KiB

After

Width:  |  Height:  |  Size: 134 KiB

View File

@@ -261,7 +261,7 @@ public class Vars implements Loadable{
public static void loadSettings(){ public static void loadSettings(){
Core.settings.setAppName(appName); Core.settings.setAppName(appName);
if(steam || "steam".equals(Version.modifier)){ if(steam || (Version.modifier != null && Version.modifier.contains("steam"))){
Core.settings.setDataDirectory(Core.files.local("saves/")); Core.settings.setDataDirectory(Core.files.local("saves/"));
} }

View File

@@ -58,7 +58,7 @@ public class Blocks implements ContentList{
phaseWall, phaseWallLarge, surgeWall, surgeWallLarge, mender, mendProjector, overdriveProjector, forceProjector, shockMine, phaseWall, phaseWallLarge, surgeWall, surgeWallLarge, mender, mendProjector, overdriveProjector, forceProjector, shockMine,
//transport //transport
conveyor, titaniumConveyor, armoredConveyor, distributor, junction, itemBridge, phaseConveyor, sorter, router, overflowGate, massDriver, conveyor, titaniumConveyor, armoredConveyor, distributor, junction, itemBridge, phaseConveyor, sorter, invertedSorter, router, overflowGate, massDriver,
//liquids //liquids
mechanicalPump, rotaryPump, thermalPump, conduit, pulseConduit, liquidRouter, liquidTank, liquidJunction, bridgeConduit, phaseConduit, mechanicalPump, rotaryPump, thermalPump, conduit, pulseConduit, liquidRouter, liquidTank, liquidJunction, bridgeConduit, phaseConduit,
@@ -935,7 +935,11 @@ public class Blocks implements ContentList{
sorter = new Sorter("sorter"){{ sorter = new Sorter("sorter"){{
requirements(Category.distribution, ItemStack.with(Items.lead, 2, Items.copper, 2)); requirements(Category.distribution, ItemStack.with(Items.lead, 2, Items.copper, 2));
}};
invertedSorter = new Sorter("inverted-sorter"){{
requirements(Category.distribution, ItemStack.with(Items.lead, 2, Items.copper, 2));
invert = true;
}}; }};
router = new Router("router"){{ router = new Router("router"){{
@@ -1083,11 +1087,12 @@ public class Blocks implements ContentList{
size = 2; size = 2;
}}; }};
differentialGenerator = new SingleTypeGenerator(true, false, "differential-generator"){{ differentialGenerator = new SingleTypeGenerator("differential-generator"){{
requirements(Category.power, ItemStack.with(Items.copper, 70, Items.titanium, 50, Items.lead, 100, Items.silicon, 65, Items.metaglass, 50)); requirements(Category.power, ItemStack.with(Items.copper, 70, Items.titanium, 50, Items.lead, 100, Items.silicon, 65, Items.metaglass, 50));
powerProduction = 16f; powerProduction = 16f;
itemDuration = 120f; itemDuration = 120f;
hasLiquids = true; hasLiquids = true;
hasItems = true;
size = 3; size = 3;
consumes.item(Items.pyratite).optional(true, false); consumes.item(Items.pyratite).optional(true, false);

View File

@@ -31,6 +31,7 @@ public class TechTree implements ContentList{
node(distributor); node(distributor);
node(sorter, () -> { node(sorter, () -> {
node(invertedSorter);
node(message); node(message);
node(overflowGate); node(overflowGate);
}); });

View File

@@ -62,7 +62,7 @@ public class UnitTypes implements ContentList{
range = 70f; range = 70f;
itemCapacity = 70; itemCapacity = 70;
health = 400; health = 400;
buildPower = 1f; buildPower = 0.4f;
engineOffset = 6.5f; engineOffset = 6.5f;
toMine = ObjectSet.with(Items.lead, Items.copper, Items.titanium); toMine = ObjectSet.with(Items.lead, Items.copper, Items.titanium);
weapon = new Weapon("heal-blaster"){{ weapon = new Weapon("heal-blaster"){{

View File

@@ -177,7 +177,7 @@ public class Control implements ApplicationListener, Loadable{
}); });
Events.on(UnitDestroyEvent.class, e -> { Events.on(UnitDestroyEvent.class, e -> {
if(e.unit instanceof BaseUnit){ if(e.unit instanceof BaseUnit && world.isZone()){
data.unlockContent(((BaseUnit)e.unit).getType()); data.unlockContent(((BaseUnit)e.unit).getType());
} }
}); });
@@ -416,6 +416,7 @@ public class Control implements ApplicationListener, Loadable{
music.update(); music.update();
loops.update(); loops.update();
Time.updateGlobal();
if(Core.input.keyTap(Binding.fullscreen)){ if(Core.input.keyTap(Binding.fullscreen)){
boolean full = settings.getBool("fullscreen"); boolean full = settings.getBool("fullscreen");

View File

@@ -2,7 +2,6 @@ package io.anuke.mindustry.core;
import io.anuke.annotations.Annotations.*; import io.anuke.annotations.Annotations.*;
import io.anuke.arc.*; import io.anuke.arc.*;
import io.anuke.arc.collection.ObjectSet.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.mindustry.content.*; import io.anuke.mindustry.content.*;
import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.core.GameState.*;
@@ -175,7 +174,7 @@ public class Logic implements ApplicationListener{
ui.hudfrag.showLaunch(); ui.hudfrag.showLaunch();
} }
for(Tile tile : new ObjectSetIterator<>(state.teams.get(defaultTeam).cores)){ for(Tile tile : state.teams.get(defaultTeam).cores){
Effects.effect(Fx.launch, tile); Effects.effect(Fx.launch, tile);
} }
@@ -184,7 +183,7 @@ public class Logic implements ApplicationListener{
} }
Time.runTask(30f, () -> { Time.runTask(30f, () -> {
for(Tile tile : new ObjectSetIterator<>(state.teams.get(defaultTeam).cores)){ for(Tile tile : state.teams.get(defaultTeam).cores){
for(Item item : content.items()){ for(Item item : content.items()){
if(tile == null || tile.entity == null || tile.entity.items == null) continue; if(tile == null || tile.entity == null || tile.entity.items == null) continue;
data.addItem(item, tile.entity.items.get(item)); data.addItem(item, tile.entity.items.get(item));

View File

@@ -94,11 +94,6 @@ public class NetServer implements ApplicationListener{
return; return;
} }
if(admins.isIDBanned(uuid)){
con.kick(KickReason.banned);
return;
}
if(admins.getPlayerLimit() > 0 && playerGroup.size() >= admins.getPlayerLimit()){ if(admins.getPlayerLimit() > 0 && playerGroup.size() >= admins.getPlayerLimit()){
con.kick(KickReason.playerLimit); con.kick(KickReason.playerLimit);
return; return;
@@ -357,6 +352,11 @@ public class NetServer implements ApplicationListener{
if(currentlyKicking[0] == null){ if(currentlyKicking[0] == null){
player.sendMessage("[scarlet]Nobody is being voted on."); player.sendMessage("[scarlet]Nobody is being voted on.");
}else{ }else{
if(player.isLocal){
player.sendMessage("Local players can't vote. Kick the player yourself instead.");
return;
}
//hosts can vote all they want //hosts can vote all they want
if(player.uuid != null && (currentlyKicking[0].voted.contains(player.uuid) || currentlyKicking[0].voted.contains(admins.getInfo(player.uuid).lastIP))){ if(player.uuid != null && (currentlyKicking[0].voted.contains(player.uuid) || currentlyKicking[0].voted.contains(admins.getInfo(player.uuid).lastIP))){
player.sendMessage("[scarlet]You've already voted. Sit down."); player.sendMessage("[scarlet]You've already voted. Sit down.");

View File

@@ -238,7 +238,6 @@ public class UI implements ApplicationListener, Loadable{
Core.scene.add(menuGroup); Core.scene.add(menuGroup);
Core.scene.add(hudGroup); Core.scene.add(hudGroup);
control.input.getFrag().build(hudGroup);
hudfrag.build(hudGroup); hudfrag.build(hudGroup);
menufrag.build(menuGroup); menufrag.build(menuGroup);
chatfrag.container().build(hudGroup); chatfrag.container().build(hudGroup);
@@ -339,6 +338,7 @@ public class UI implements ApplicationListener, Loadable{
} }
public void showException(String text, Throwable exc){ public void showException(String text, Throwable exc){
loadfrag.hide();
new Dialog(""){{ new Dialog(""){{
String message = Strings.getFinalMesage(exc); String message = Strings.getFinalMesage(exc);

View File

@@ -272,6 +272,7 @@ public class World{
} }
public void removeBlock(Tile tile){ public void removeBlock(Tile tile){
if(tile == null) return;
tile.link().getLinkedTiles(other -> other.setBlock(Blocks.air)); tile.link().getLinkedTiles(other -> other.setBlock(Blocks.air));
} }

View File

@@ -6,8 +6,8 @@ import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.*; import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*; import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.*;
import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.arc.util.ArcAnnotate.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.*; import io.anuke.mindustry.*;
import io.anuke.mindustry.content.*; import io.anuke.mindustry.content.*;
import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.entities.type.*;
@@ -188,6 +188,11 @@ public interface BuilderTrait extends Entity, TeamTrait{
/** Add another build requests to the tail of the queue, if it doesn't exist there yet. */ /** Add another build requests to the tail of the queue, if it doesn't exist there yet. */
default void addBuildRequest(BuildRequest place){ default void addBuildRequest(BuildRequest place){
addBuildRequest(place, true);
}
/** Add another build requests to the queue, if it doesn't exist there yet. */
default void addBuildRequest(BuildRequest place, boolean tail){
for(BuildRequest request : buildQueue()){ for(BuildRequest request : buildQueue()){
if(request.x == place.x && request.y == place.y){ if(request.x == place.x && request.y == place.y){
return; return;
@@ -197,7 +202,11 @@ public interface BuilderTrait extends Entity, TeamTrait{
if(tile != null && tile.entity instanceof BuildEntity){ if(tile != null && tile.entity instanceof BuildEntity){
place.progress = tile.<BuildEntity>entity().progress; place.progress = tile.<BuildEntity>entity().progress;
} }
buildQueue().addLast(place); if(tail){
buildQueue().addLast(place);
}else{
buildQueue().addFirst(place);
}
} }
/** /**
@@ -258,15 +267,19 @@ public interface BuilderTrait extends Entity, TeamTrait{
/** Class for storing build requests. Can be either a place or remove request. */ /** Class for storing build requests. Can be either a place or remove request. */
class BuildRequest{ class BuildRequest{
public final int x, y, rotation; public int x, y, rotation;
public final Block block; public @Nullable Block block;
public final boolean breaking; public boolean breaking;
public boolean hasConfig; public boolean hasConfig;
public int config; public int config;
public float progress; public float progress;
public boolean initialized; public boolean initialized;
//animation variables
public float animScale = 0f;
public float animInvalid;
/** This creates a build request. */ /** This creates a build request. */
public BuildRequest(int x, int y, int rotation, Block block){ public BuildRequest(int x, int y, int rotation, Block block){
this.x = x; this.x = x;
@@ -285,13 +298,42 @@ public interface BuilderTrait extends Entity, TeamTrait{
this.breaking = true; this.breaking = true;
} }
public BuildRequest(){
}
public Rectangle bounds(Rectangle rect){
if(breaking){
return rect.set(-100f, -100f, 0f, 0f);
}else{
return block.bounds(x, y, rect);
}
}
public BuildRequest set(int x, int y, int rotation, Block block){
this.x = x;
this.y = y;
this.rotation = rotation;
this.block = block;
this.breaking = false;
return this;
}
public float drawx(){
return x*tilesize + block.offset();
}
public float drawy(){
return y*tilesize + block.offset();
}
public BuildRequest configure(int config){ public BuildRequest configure(int config){
this.config = config; this.config = config;
this.hasConfig = true; this.hasConfig = true;
return this; return this;
} }
public Tile tile(){ public @Nullable Tile tile(){
return world.tile(x, y); return world.tile(x, y);
} }

View File

@@ -19,9 +19,7 @@ import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.traits.*; import io.anuke.mindustry.entities.traits.*;
import io.anuke.mindustry.game.*; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*; import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.input.*; import io.anuke.mindustry.input.*;
import io.anuke.mindustry.input.InputHandler.*;
import io.anuke.mindustry.io.*; import io.anuke.mindustry.io.*;
import io.anuke.mindustry.net.Administration.*; import io.anuke.mindustry.net.Administration.*;
import io.anuke.mindustry.net.*; import io.anuke.mindustry.net.*;
@@ -51,7 +49,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
public String name = "noname"; public String name = "noname";
public @Nullable public @Nullable
String uuid, usid; String uuid, usid;
public boolean isAdmin, isTransferring, isShooting, isBoosting, isMobile, isTyping; public boolean isAdmin, isTransferring, isShooting, isBoosting, isMobile, isTyping, isBuilding = true;
public float boostHeat, shootHeat, destructTime; public float boostHeat, shootHeat, destructTime;
public boolean achievedFlight; public boolean achievedFlight;
public Color color = new Color(); public Color color = new Color();
@@ -357,7 +355,13 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
public void drawOver(){ public void drawOver(){
if(dead) return; if(dead) return;
drawMechanics(); if(isBuilding()){
if(!state.isPaused() && isBuilding){
drawBuilding();
}
}else{
drawMining();
}
} }
@Override @Override
@@ -424,57 +428,17 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
/** Draw all current build requests. Does not draw the beam effect, only the positions. */ /** Draw all current build requests. Does not draw the beam effect, only the positions. */
public void drawBuildRequests(){ public void drawBuildRequests(){
BuildRequest last = null; if(!isLocal) return;
for(BuildRequest request : buildQueue()){ for(BuildRequest request : buildQueue()){
if(request.progress > 0.01f || (buildRequest() == request && request.initialized && (dst(request.x * tilesize, request.y * tilesize) <= placeDistance || state.isEditor()))) continue; if(request.progress > 0.01f || (buildRequest() == request && request.initialized && (dst(request.x * tilesize, request.y * tilesize) <= placeDistance || state.isEditor()))) continue;
request.animScale = 1f;
if(request.breaking){ if(request.breaking){
Block block = world.ltile(request.x, request.y).block(); control.input.drawBreaking(request);
//draw removal request
Lines.stroke(2f, Pal.removeBack);
float rad = Mathf.absin(Time.time(), 7f, 1f) + block.size * tilesize / 2f - 1;
Lines.square(
request.x * tilesize + block.offset(),
request.y * tilesize + block.offset() - 1,
rad);
Draw.color(Pal.remove);
Lines.square(
request.x * tilesize + block.offset(),
request.y * tilesize + block.offset(), rad);
}else{ }else{
Draw.color(); request.block.drawRequest(request, control.input.allRequests(),
PlaceDraw draw = PlaceDraw.instance; Build.validPlace(getTeam(), request.x, request.y, request.block, request.rotation));
draw.scalex = 1;
draw.scaley = 1;
draw.rotation = request.rotation;
if(last == null){
request.block.getPlaceDraw(draw, request.rotation, request.x, request.y, request.rotation);
}else{
request.block.getPlaceDraw(draw, request.rotation, last.x - request.x, last.y - request.y, last.rotation);
}
TextureRegion region = draw.region;
Draw.rect(region,
request.x * tilesize + request.block.offset(), request.y * tilesize + request.block.offset(),
region.getWidth() * 1f * Draw.scl * draw.scalex,
region.getHeight() * 1f * Draw.scl * draw.scaley, request.block.rotate ? draw.rotation * 90 : 0);
Draw.color(Pal.accent);
for(int i = 0; i < 4; i++){
Point2 p = Geometry.d8edge[i];
float offset = -Math.max(request.block.size - 1, 0) / 2f * tilesize;
Draw.rect("block-select", request.x * tilesize + request.block.offset() + offset * p.x, request.y * tilesize + request.block.offset() + offset * p.y, i * 90);
}
Draw.color();
last = request;
} }
} }
@@ -485,6 +449,18 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
//region update methods //region update methods
@Override
public void updateMechanics(){
if(isBuilding){
updateBuilding();
}
//mine only when not building
if(buildRequest() == null){
updateMining();
}
}
@Override @Override
public void update(){ public void update(){
hitTime -= Time.delta(); hitTime -= Time.delta();
@@ -517,7 +493,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
} }
BuildRequest request = buildRequest(); BuildRequest request = buildRequest();
if(isBuilding() && request.tile() != null && (request.tile().withinDst(x, y, placeDistance) || state.isEditor())){ if(isBuilding() && isBuilding && request.tile() != null && (request.tile().withinDst(x, y, placeDistance) || state.isEditor())){
loops.play(Sounds.build, request.tile(), 0.75f); loops.play(Sounds.build, request.tile(), 0.75f);
} }
@@ -817,6 +793,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
placeQueue.clear(); placeQueue.clear();
dead = true; dead = true;
lastText = null; lastText = null;
isBuilding = true;
textFadeTime = 0f; textFadeTime = 0f;
target = null; target = null;
moveTarget = null; moveTarget = null;
@@ -910,7 +887,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
public void write(DataOutput buffer) throws IOException{ public void write(DataOutput buffer) throws IOException{
super.writeSave(buffer, !isLocal); super.writeSave(buffer, !isLocal);
TypeIO.writeStringData(buffer, name); TypeIO.writeStringData(buffer, name);
buffer.writeByte(Pack.byteValue(isAdmin) | (Pack.byteValue(dead) << 1) | (Pack.byteValue(isBoosting) << 2) | (Pack.byteValue(isTyping) << 3)); buffer.writeByte(Pack.byteValue(isAdmin) | (Pack.byteValue(dead) << 1) | (Pack.byteValue(isBoosting) << 2) | (Pack.byteValue(isTyping) << 3)| (Pack.byteValue(isBuilding) << 4));
buffer.writeInt(Color.rgba8888(color)); buffer.writeInt(Color.rgba8888(color));
buffer.writeByte(mech.id); buffer.writeByte(mech.id);
buffer.writeInt(mining == null ? noSpawner : mining.pos()); buffer.writeInt(mining == null ? noSpawner : mining.pos());
@@ -932,6 +909,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
dead = (bools & 2) != 0; dead = (bools & 2) != 0;
boolean boosting = (bools & 4) != 0; boolean boosting = (bools & 4) != 0;
isTyping = (bools & 8) != 0; isTyping = (bools & 8) != 0;
boolean building = (bools & 16) != 0;
color.set(buffer.readInt()); color.set(buffer.readInt());
mech = content.getByID(ContentType.mech, buffer.readByte()); mech = content.getByID(ContentType.mech, buffer.readByte());
int mine = buffer.readInt(); int mine = buffer.readInt();
@@ -950,6 +928,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
velocity.y = lastvy; velocity.y = lastvy;
}else{ }else{
mining = world.tile(mine); mining = world.tile(mine);
isBuilding = building;
isBoosting = boosting; isBoosting = boosting;
} }

View File

@@ -1,5 +1,6 @@
package io.anuke.mindustry.game; package io.anuke.mindustry.game;
import io.anuke.arc.files.*;
import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.arc.util.ArcAnnotate.*;
import io.anuke.mindustry.*; import io.anuke.mindustry.*;
import io.anuke.mindustry.mod.Mods.*; import io.anuke.mindustry.mod.Mods.*;
@@ -11,6 +12,8 @@ public abstract class Content implements Comparable<Content>{
public final short id; public final short id;
/** The mod that loaded this piece of content. */ /** The mod that loaded this piece of content. */
public @Nullable LoadedMod mod; public @Nullable LoadedMod mod;
/** File that this content was loaded from. */
public @Nullable FileHandle sourceFile;
public Content(){ public Content(){
this.id = (short)Vars.content.getBy(getContentType()).size; this.id = (short)Vars.content.getBy(getContentType()).size;

View File

@@ -132,7 +132,13 @@ public class EventType{
/** Called when a player deposits items to a block.*/ /** Called when a player deposits items to a block.*/
public static class DepositEvent{ public static class DepositEvent{
public final Tile tile;
public final Player player;
public DepositEvent(Tile tile, Player player){
this.tile = tile;
this.player = player;
}
} }
public static class GameOverEvent{ public static class GameOverEvent{

View File

@@ -31,7 +31,11 @@ public abstract class UnlockableContent extends MappableContent{
/** Returns a specific content icon, or the region {contentType}-{name} if not found.*/ /** Returns a specific content icon, or the region {contentType}-{name} if not found.*/
public TextureRegion icon(Cicon icon){ public TextureRegion icon(Cicon icon){
if(cicons[icon.ordinal()] == null){ if(cicons[icon.ordinal()] == null){
cicons[icon.ordinal()] = Core.atlas.find(getContentType().name() + "-" + name + "-" + icon.name(), Core.atlas.find(getContentType().name() + "-" + name + "-full", Core.atlas.find(getContentType().name() + "-" + name, Core.atlas.find(name)))); cicons[icon.ordinal()] = Core.atlas.find(getContentType().name() + "-" + name + "-" + icon.name(),
Core.atlas.find(getContentType().name() + "-" + name + "-full",
Core.atlas.find(getContentType().name() + "-" + name,
Core.atlas.find(name,
Core.atlas.find(name + "1")))));
} }
return cicons[icon.ordinal()]; return cicons[icon.ordinal()];
} }

View File

@@ -10,11 +10,10 @@ import io.anuke.arc.math.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.mindustry.content.*; import io.anuke.mindustry.content.*;
import io.anuke.mindustry.entities.type.base.*; import io.anuke.mindustry.entities.type.base.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.*; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.Teams.*; import io.anuke.mindustry.game.Teams.*;
import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.Block.*;
import static io.anuke.arc.Core.camera; import static io.anuke.arc.Core.camera;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -131,7 +130,7 @@ public class BlockRenderer implements Disposable{
if(!camera.bounds(Tmp.r1).grow(tilesize * 2f).overlaps(Tmp.r2.setSize(b.size * tilesize).setCenter(block.x * tilesize + b.offset(), block.y * tilesize + b.offset()))) continue; if(!camera.bounds(Tmp.r1).grow(tilesize * 2f).overlaps(Tmp.r2.setSize(b.size * tilesize).setCenter(block.x * tilesize + b.offset(), block.y * tilesize + b.offset()))) continue;
Draw.alpha(0.5f); Draw.alpha(0.5f);
Draw.mixcol(Pal.accent, 0.2f + Mathf.absin(5f, 0.2f)); Draw.mixcol(Color.white, 0.2f + Mathf.absin(Time.globalTime(), 6f, 0.2f));
Draw.rect(b.icon(Cicon.full), block.x * tilesize + b.offset(), block.y * tilesize + b.offset(), b.rotate ? block.rotation * 90 : 0f); Draw.rect(b.icon(Cicon.full), block.x * tilesize + b.offset(), block.y * tilesize + b.offset(), b.rotate ? block.rotation * 90 : 0f);
} }
Draw.reset(); Draw.reset();
@@ -242,28 +241,34 @@ public class BlockRenderer implements Disposable{
} }
public void drawBlocks(Layer stopAt){ public void drawBlocks(Layer stopAt){
int startIdx = iterateidx;
for(; iterateidx < requestidx; iterateidx++){ for(; iterateidx < requestidx; iterateidx++){
BlockRequest request = requests.get(iterateidx);
if(iterateidx < requests.size && requests.get(iterateidx).layer.ordinal() > stopAt.ordinal()){ if(request.layer.ordinal() > stopAt.ordinal()){
break; break;
} }
BlockRequest req = requests.get(iterateidx); if(request.layer == Layer.power){
Block block = req.tile.block(); if(iterateidx - startIdx > 0 && request.tile.pos() == requests.get(iterateidx - 1).tile.pos()){
continue;
}
}
if(req.layer == Layer.block){ Block block = request.tile.block();
block.draw(req.tile);
if(req.tile.entity != null && req.tile.entity.damaged()){ if(request.layer == Layer.block){
block.drawCracks(req.tile); block.draw(request.tile);
if(request.tile.entity != null && request.tile.entity.damaged()){
block.drawCracks(request.tile);
} }
if(block.synthetic() && req.tile.getTeam() != player.getTeam()){ if(block.synthetic() && request.tile.getTeam() != player.getTeam()){
block.drawTeam(req.tile); block.drawTeam(request.tile);
} }
}else if(req.layer == block.layer){ }else if(request.layer == block.layer){
block.drawLayer(req.tile); block.drawLayer(request.tile);
}else if(req.layer == block.layer2){ }else if(request.layer == block.layer2){
block.drawLayer2(req.tile); block.drawLayer2(request.tile);
} }
} }
} }
@@ -328,7 +333,9 @@ public class BlockRenderer implements Disposable{
@Override @Override
public int compareTo(BlockRequest other){ public int compareTo(BlockRequest other){
return layer.compareTo(other.layer); int compare = layer.compareTo(other.layer);
return (compare != 0) ? compare : Integer.compare(tile.pos(), other.tile.pos());
} }
@Override @Override

View File

@@ -25,9 +25,9 @@ public class OverlayRenderer{
public void drawBottom(){ public void drawBottom(){
InputHandler input = control.input; InputHandler input = control.input;
if(!input.isDrawing() || player.isDead()) return; if(player.isDead()) return;
input.drawOutlined(); input.drawBottom();
} }
public void drawTop(){ public void drawTop(){

View File

@@ -12,6 +12,8 @@ public enum Binding implements KeyBind{
select(KeyCode.MOUSE_LEFT), select(KeyCode.MOUSE_LEFT),
deselect(KeyCode.MOUSE_RIGHT), deselect(KeyCode.MOUSE_RIGHT),
break_block(KeyCode.MOUSE_RIGHT), break_block(KeyCode.MOUSE_RIGHT),
clear_building(KeyCode.Q),
pause_building(KeyCode.E),
rotate(new Axis(KeyCode.SCROLL)), rotate(new Axis(KeyCode.SCROLL)),
rotateplaced(KeyCode.R), rotateplaced(KeyCode.R),
diagonal_placement(KeyCode.CONTROL_LEFT), diagonal_placement(KeyCode.CONTROL_LEFT),

View File

@@ -5,15 +5,15 @@ import io.anuke.arc.Graphics.*;
import io.anuke.arc.Graphics.Cursor.*; import io.anuke.arc.Graphics.Cursor.*;
import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.*; import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*; import io.anuke.arc.scene.*;
import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.ArcAnnotate.*;
import io.anuke.mindustry.content.*;
import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.core.GameState.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.gen.*; import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.input.PlaceUtils.*; import io.anuke.mindustry.ui.*;
import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.*;
import static io.anuke.arc.Core.scene; import static io.anuke.arc.Core.scene;
@@ -23,101 +23,77 @@ import static io.anuke.mindustry.input.PlaceMode.*;
public class DesktopInput extends InputHandler{ public class DesktopInput extends InputHandler{
/** Current cursor type. */ /** Current cursor type. */
private Cursor cursorType = SystemCursor.arrow; private Cursor cursorType = SystemCursor.arrow;
/** Position where the player started dragging a line. */ /** Position where the player started dragging a line. */
private int selectX, selectY; private int selectX, selectY;
/** Last known line positions.*/
private int lastLineX, lastLineY;
/** Whether selecting mode is active. */ /** Whether selecting mode is active. */
private PlaceMode mode; private PlaceMode mode;
/** Animation scale for line. */ /** Animation scale for line. */
private float selectScale; private float selectScale;
/** Selected build request for movement. */
private @Nullable BuildRequest sreq;
/** Whether player is currently deleting removal requests. */
private boolean deleting = false;
private int prevX, prevY, prevRotation; @Override
public void buildUI(Group group){
/** Draws a placement icon for a specific block. */ group.fill(t -> {
void drawPlace(int x, int y, Block block, int rotation, int prevX, int prevY, int prevRotation){ t.bottom().update(() -> t.getColor().a = Mathf.lerpDelta(t.getColor().a, player.isBuilding() ? 1f : 0f, 0.15f));
if(validPlace(x, y, block, rotation)){ t.visible(() -> Core.settings.getBool("hints"));
block.getPlaceDraw(placeDraw, rotation, prevX, prevY, prevRotation); t.table(Styles.black6, b -> {
b.defaults().left();
Draw.color(); b.label(() -> Core.bundle.format(!player.isBuilding ? "resumebuilding" : "pausebuilding", Core.keybinds.get(Binding.pause_building).key.name())).style(Styles.outlineLabel);
Draw.mixcol(Pal.accent, 0.12f + Mathf.absin(Time.time(), 8f, 0.35f)); b.row();
Draw.rect(placeDraw.region, x * tilesize + block.offset(), y * tilesize + block.offset(), b.add(Core.bundle.format("cancelbuilding", Core.keybinds.get(Binding.clear_building).key.name())).style(Styles.outlineLabel);
placeDraw.region.getWidth() * selectScale * Draw.scl * placeDraw.scalex, }).margin(10f);
placeDraw.region.getHeight() * selectScale * Draw.scl * placeDraw.scaley, });
block.rotate ? placeDraw.rotation * 90 : 0);
Draw.color(Pal.accent);
for(int i = 0; i < 4; i++){
Point2 p = Geometry.d8edge[i];
float offset = -Math.max(block.size - 1, 0) / 2f * tilesize;
if(i % 2 == 0)
Draw.rect("block-select", x * tilesize + block.offset() + offset * p.x, y * tilesize + block.offset() + offset * p.y, i * 90);
}
Draw.color();
Draw.mixcol();
}else{
Draw.color(Pal.removeBack);
Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset() - 1, block.size * tilesize / 2f - 1);
Draw.color(Pal.remove);
Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset(), block.size * tilesize / 2f - 1);
}
} }
@Override @Override
public boolean isDrawing(){ public void drawTop(){
return mode != none || block != null;
}
@Override
public void drawOutlined(){
Lines.stroke(1f); Lines.stroke(1f);
int cursorX = tileX(Core.input.mouseX()); int cursorX = tileX(Core.input.mouseX());
int cursorY = tileY(Core.input.mouseY()); int cursorY = tileY(Core.input.mouseY());
//draw selection(s) //draw selection(s)
if(mode == placing && block != null){ if(mode == placing && block != null){
prevX = selectX; for(int i = 0; i < lineRequests.size; i++){
prevY = selectY; BuildRequest req = lineRequests.get(i);
prevRotation = rotation; if(i == lineRequests.size - 1 && req.block.rotate){
drawArrow(block, req.x, req.y, req.rotation);
iterateLine(selectX, selectY, cursorX, cursorY, l -> {
if(l.last && block.rotate){
drawArrow(block, l.x, l.y, l.rotation);
}
drawPlace(l.x, l.y, block, l.rotation, prevX - l.x, prevY - l.y, prevRotation);
prevX = l.x;
prevY = l.y;
prevRotation = l.rotation;
});
}else if(mode == breaking){
NormalizeDrawResult result = PlaceUtils.normalizeDrawArea(Blocks.air, selectX, selectY, cursorX, cursorY, false, maxLength, 1f);
NormalizeResult dresult = PlaceUtils.normalizeArea(selectX, selectY, cursorX, cursorY, rotation, false, maxLength);
for(int x = dresult.x; x <= dresult.x2; x++){
for(int y = dresult.y; y <= dresult.y2; y++){
Tile tile = world.ltile(x, y);
if(tile == null || !validBreak(tile.x, tile.y)) continue;
Draw.color(Pal.removeBack);
Lines.square(tile.drawx(), tile.drawy() - 1, tile.block().size * tilesize / 2f - 1);
Draw.color(Pal.remove);
Lines.square(tile.drawx(), tile.drawy(), tile.block().size * tilesize / 2f - 1);
} }
drawRequest(lineRequests.get(i));
} }
}else if(mode == breaking){
Draw.color(Pal.removeBack); drawSelection(selectX, selectY, cursorX, cursorY);
Lines.rect(result.x, result.y - 1, result.x2 - result.x, result.y2 - result.y);
Draw.color(Pal.remove);
Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y);
}else if(isPlacing()){ }else if(isPlacing()){
if(block.rotate){ if(block.rotate){
drawArrow(block, cursorX, cursorY, rotation); drawArrow(block, cursorX, cursorY, rotation);
} }
drawPlace(cursorX, cursorY, block, rotation, cursorX, cursorY, rotation); Draw.color();
drawRequest(cursorX, cursorY, block, rotation);
block.drawPlace(cursorX, cursorY, rotation, validPlace(cursorX, cursorY, block, rotation)); block.drawPlace(cursorX, cursorY, rotation, validPlace(cursorX, cursorY, block, rotation));
} }
if(mode == none && !isPlacing()){
BuildRequest req = getRequest(cursorX, cursorY);
if(req != null){
drawSelected(req.x, req.y, req.breaking ? req.tile().block() : req.block, Pal.accent);
}
}
if(sreq != null){
boolean valid = validPlace(sreq.x, sreq.y, sreq.block, sreq.rotation, sreq);
if(sreq.block.rotate){
drawArrow(sreq.block, sreq.x, sreq.y, sreq.rotation, valid);
}
sreq.block.drawRequest(sreq, allRequests(), valid);
drawSelected(sreq.x, sreq.y, sreq.block, getRequest(sreq.x, sreq.y, sreq.block.size, sreq) != null ? Pal.remove : Pal.accent);
}
Draw.reset(); Draw.reset();
} }
@@ -171,6 +147,14 @@ public class DesktopInput extends InputHandler{
rotation = Mathf.mod(rotation + (int)Core.input.axisTap(Binding.rotate), 4); rotation = Mathf.mod(rotation + (int)Core.input.axisTap(Binding.rotate), 4);
if(sreq != null){
sreq.rotation = Mathf.mod(sreq.rotation + (int)Core.input.axisTap(Binding.rotate), 4);
}
if(Math.abs((int)Core.input.axisTap(Binding.rotate)) > 0 && isPlacing() && mode == placing){
updateLine(selectX, selectY);
}
Tile cursor = tileAt(Core.input.mouseX(), Core.input.mouseY()); Tile cursor = tileAt(Core.input.mouseX(), Core.input.mouseY());
if(cursor != null){ if(cursor != null){
@@ -186,6 +170,10 @@ public class DesktopInput extends InputHandler{
cursorType = ui.drillCursor; cursorType = ui.drillCursor;
} }
if(getRequest(cursor.x, cursor.y) != null && mode == none){
cursorType = SystemCursor.hand;
}
if(canTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y)){ if(canTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y)){
cursorType = ui.unloadCursor; cursorType = ui.unloadCursor;
} }
@@ -211,11 +199,46 @@ public class DesktopInput extends InputHandler{
player.setMineTile(null); player.setMineTile(null);
} }
if(Core.input.keyTap(Binding.clear_building)){
player.clearBuilding();
}
if(sreq != null){
float offset = ((sreq.block.size + 2) % 2) * tilesize / 2f;
float x = Core.input.mouseWorld().x + offset;
float y = Core.input.mouseWorld().y + offset;
sreq.x = (int)(x / tilesize);
sreq.y = (int)(y / tilesize);
}
if(block == null || mode != placing){
lineRequests.clear();
}
if(Core.input.keyTap(Binding.pause_building)){
player.isBuilding = !player.isBuilding;
}
if((cursorX != lastLineX || cursorY != lastLineY) && isPlacing() && mode == placing){
updateLine(selectX, selectY);
lastLineX = cursorX;
lastLineY = cursorY;
}
if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){ if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){
BuildRequest req = getRequest(cursorX, cursorY);
if(isPlacing()){ if(isPlacing()){
selectX = cursorX; selectX = cursorX;
selectY = cursorY; selectY = cursorY;
lastLineX = cursorX;
lastLineY = cursorY;
mode = placing; mode = placing;
updateLine(selectX, selectY);
}else if(req != null && !req.breaking && mode == none && !req.initialized){
sreq = req;
}else if(req != null && req.breaking){
deleting = true;
}else if(selected != null){ }else if(selected != null){
//only begin shooting if there's no cursor event //only begin shooting if there's no cursor event
if(!tileTapped(selected) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && player.buildQueue().size == 0 && !droppingItem && if(!tileTapped(selected) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && player.buildQueue().size == 0 && !droppingItem &&
@@ -225,23 +248,28 @@ public class DesktopInput extends InputHandler{
}else if(!ui.chatfrag.chatOpen()){ //if it's out of bounds, shooting is just fine }else if(!ui.chatfrag.chatOpen()){ //if it's out of bounds, shooting is just fine
player.isShooting = true; player.isShooting = true;
} }
}else if(Core.input.keyTap(Binding.deselect) && (block != null || mode != none || player.isBuilding()) && }else if(Core.input.keyTap(Binding.deselect) && block != null){
!(player.buildRequest() != null && player.buildRequest().breaking && Core.keybinds.get(Binding.deselect) == Core.keybinds.get(Binding.break_block))){
if(block == null){
player.clearBuilding();
}
block = null; block = null;
mode = none; mode = none;
}else if(Core.input.keyTap(Binding.break_block) && !Core.scene.hasMouse()){ }else if(Core.input.keyTap(Binding.break_block) && !Core.scene.hasMouse()){
//is recalculated because setting the mode to breaking removes potential multiblock cursor offset //is recalculated because setting the mode to breaking removes potential multiblock cursor offset
deleting = false;
mode = breaking; mode = breaking;
selectX = tileX(Core.input.mouseX()); selectX = tileX(Core.input.mouseX());
selectY = tileY(Core.input.mouseY()); selectY = tileY(Core.input.mouseY());
} }
if (mode == placing && block != null){ if(Core.input.keyDown(Binding.select) && mode == none && !isPlacing() && deleting){
if (!overrideLineRotation && !Core.input.keyDown(Binding.diagonal_placement) && (selectX != cursorX || selectY != cursorY) && ((int) Core.input.axisTap(Binding.rotate) != 0)){ BuildRequest req = getRequest(cursorX, cursorY);
if(req != null && req.breaking){
player.buildQueue().remove(req);
}
}else{
deleting = false;
}
if(mode == placing && block != null){
if(!overrideLineRotation && !Core.input.keyDown(Binding.diagonal_placement) && (selectX != cursorX || selectY != cursorY) && ((int) Core.input.axisTap(Binding.rotate) != 0)){
rotation = ((int)((Angles.angle(selectX, selectY, cursorX, cursorY) + 45) / 90f)) % 4; rotation = ((int)((Angles.angle(selectX, selectY, cursorX, cursorY) + 45) / 90f)) % 4;
overrideLineRotation = true; overrideLineRotation = true;
} }
@@ -252,27 +280,24 @@ public class DesktopInput extends InputHandler{
if(Core.input.keyRelease(Binding.break_block) || Core.input.keyRelease(Binding.select)){ if(Core.input.keyRelease(Binding.break_block) || Core.input.keyRelease(Binding.select)){
if(mode == placing && block != null){ //touch up while placing, place everything in selection if(mode == placing && block != null){ //touch up while placing, place everything in selection
iterateLine(selectX, selectY, cursorX, cursorY, l -> { flushRequests(lineRequests);
rotation = l.rotation; lineRequests.clear();
tryPlaceBlock(l.x, l.y);
});
Events.fire(new LineConfirmEvent()); Events.fire(new LineConfirmEvent());
}else if(mode == breaking){ //touch up while breaking, break everything in selection }else if(mode == breaking){ //touch up while breaking, break everything in selection
NormalizeResult result = PlaceUtils.normalizeArea(selectX, selectY, cursorX, cursorY, rotation, false, maxLength); removeSelection(selectX, selectY, cursorX, cursorY);
for(int x = 0; x <= Math.abs(result.x2 - result.x); x++){
for(int y = 0; y <= Math.abs(result.y2 - result.y); y++){
int wx = selectX + x * Mathf.sign(cursorX - selectX);
int wy = selectY + y * Mathf.sign(cursorY - selectY);
tryBreakBlock(wx, wy);
}
}
} }
if(selected != null){ if(selected != null){
tryDropItems(selected.link(), Core.input.mouseWorld().x, Core.input.mouseWorld().y); tryDropItems(selected.link(), Core.input.mouseWorld().x, Core.input.mouseWorld().y);
} }
if(sreq != null){
if(getRequest(sreq.x, sreq.y, sreq.block.size, sreq) != null){
player.buildQueue().remove(sreq, true);
}
sreq = null;
}
mode = none; mode = none;
} }
} }
@@ -298,6 +323,7 @@ public class DesktopInput extends InputHandler{
droppingItem = false; droppingItem = false;
mode = none; mode = none;
block = null; block = null;
sreq = null;
} }
} }
} }

View File

@@ -7,8 +7,11 @@ import io.anuke.arc.function.*;
import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.input.*; import io.anuke.arc.input.*;
import io.anuke.arc.input.GestureDetector.*;
import io.anuke.arc.math.*; import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*; import io.anuke.arc.math.geom.*;
import io.anuke.arc.scene.*;
import io.anuke.arc.scene.event.*;
import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.scene.ui.layout.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.mindustry.content.*; import io.anuke.mindustry.content.*;
@@ -17,21 +20,26 @@ import io.anuke.mindustry.entities.effect.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.Teams.*;
import io.anuke.mindustry.gen.*; import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.input.PlaceUtils.*;
import io.anuke.mindustry.net.*; import io.anuke.mindustry.net.*;
import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.ui.fragments.*; import io.anuke.mindustry.ui.fragments.*;
import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.*;
import java.util.*;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
public abstract class InputHandler implements InputProcessor{ public abstract class InputHandler implements InputProcessor, GestureListener{
/** Used for dropping items. */ /** Used for dropping items. */
final static float playerSelectRange = mobile ? 17f : 11f; final static float playerSelectRange = mobile ? 17f : 11f;
/** Maximum line length. */ /** Maximum line length. */
final static int maxLength = 100; final static int maxLength = 100;
final static Vector2 stackTrns = new Vector2(); final static Vector2 stackTrns = new Vector2();
final static Rectangle r1 = new Rectangle(), r2 = new Rectangle();
/** Distance on the back from where items originate. */ /** Distance on the back from where items originate. */
final static float backTrns = 3f; final static float backTrns = 3f;
@@ -41,9 +49,14 @@ public abstract class InputHandler implements InputProcessor{
public boolean overrideLineRotation; public boolean overrideLineRotation;
public int rotation; public int rotation;
public boolean droppingItem; public boolean droppingItem;
public Group uiGroup;
protected PlaceDraw placeDraw = new PlaceDraw(); protected GestureDetector detector;
private PlaceLine line = new PlaceLine(); protected PlaceLine line = new PlaceLine();
protected BuildRequest resultreq;
protected BuildRequest brequest = new BuildRequest();
protected Array<BuildRequest> lineRequests = new Array<>();
protected Array<BuildRequest> selectRequests = new Array<>();
//methods to override //methods to override
@@ -92,7 +105,7 @@ public abstract class InputHandler implements InputProcessor{
int[] remaining = {accepted, accepted}; int[] remaining = {accepted, accepted};
Block block = tile.block(); Block block = tile.block();
Events.fire(new DepositEvent()); Core.app.post(() -> Events.fire(new DepositEvent(tile, player)));
for(int i = 0; i < sent; i++){ for(int i = 0; i < sent; i++){
boolean end = i == sent - 1; boolean end = i == sent - 1;
@@ -134,6 +147,14 @@ public abstract class InputHandler implements InputProcessor{
tile.block().configured(tile, player, value); tile.block().configured(tile, player, value);
} }
public Eachable<BuildRequest> allRequests(){
return cons -> {
for(BuildRequest request : player.buildQueue()) cons.accept(request);
for(BuildRequest request : selectRequests) cons.accept(request);
for(BuildRequest request : lineRequests) cons.accept(request);
};
}
public OverlayFragment getFrag(){ public OverlayFragment getFrag(){
return frag; return frag;
} }
@@ -150,7 +171,11 @@ public abstract class InputHandler implements InputProcessor{
return Core.input.mouseY(); return Core.input.mouseY();
} }
public void buildUI(Table table){ public void buildPlacementUI(Table table){
}
public void buildUI(Group group){
} }
@@ -158,7 +183,7 @@ public abstract class InputHandler implements InputProcessor{
} }
public void drawOutlined(){ public void drawBottom(){
} }
@@ -166,8 +191,217 @@ public abstract class InputHandler implements InputProcessor{
} }
public boolean isDrawing(){ public void drawSelected(int x, int y, Block block, Color color){
return false; Draw.color(color);
for(int i = 0; i < 4; i++){
Point2 p = Geometry.d8edge[i];
float offset = -Math.max(block.size - 1, 0) / 2f * tilesize;
Draw.rect("block-select",
x*tilesize + block.offset() + offset * p.x,
y*tilesize + block.offset() + offset * p.y, i * 90);
}
Draw.reset();
}
public void drawBreaking(BuildRequest request){
if(request.breaking){
drawBreaking(request.x, request.y);
}else{
drawSelected(request.x, request.y, request.tile().block(), Pal.remove);
}
}
public void drawBreaking(int x, int y){
Tile tile = world.ltile(x, y);
if(tile == null) return;
Block block = tile.block();
drawSelected(x, y, block, Pal.remove);
}
/** Returns the selection request that overlaps this position, or null. */
protected BuildRequest getRequest(int x, int y){
return getRequest(x, y, 1, null);
}
/** Returns the selection request that overlaps this position, or null. */
protected BuildRequest getRequest(int x, int y, int size, BuildRequest skip){
float offset = ((size + 1) % 2) * tilesize / 2f;
r2.setSize(tilesize * size);
r2.setCenter(x * tilesize + offset, y * tilesize + offset);
resultreq = null;
Predicate<BuildRequest> test = req -> {
if(req == skip) return false;
Tile other = req.tile();
if(other == null) return false;
if(!req.breaking){
r1.setSize(req.block.size * tilesize);
r1.setCenter(other.worldx() + req.block.offset(), other.worldy() + req.block.offset());
}else{
r1.setSize(other.block().size * tilesize);
r1.setCenter(other.worldx() + other.block().offset(), other.worldy() + other.block().offset());
}
return r2.overlaps(r1);
};
for(BuildRequest req : player.buildQueue()){
if(test.test(req)) return req;
}
for(BuildRequest req : selectRequests){
if(test.test(req)) return req;
}
return null;
}
protected void drawSelection(int x1, int y1, int x2, int y2){
NormalizeDrawResult result = PlaceUtils.normalizeDrawArea(Blocks.air, x1, y1, x2, y2, false, maxLength, 1f);
NormalizeResult dresult = PlaceUtils.normalizeArea(x1, y1, x2, y2, rotation, false, maxLength);
for(int x = dresult.x; x <= dresult.x2; x++){
for(int y = dresult.y; y <= dresult.y2; y++){
Tile tile = world.ltile(x, y);
if(tile == null || !validBreak(tile.x, tile.y)) continue;
drawBreaking(tile.x, tile.y);
}
}
Tmp.r1.set(result.x, result.y, result.x2 - result.x, result.y2 - result.y);
Draw.color(Pal.remove);
Lines.stroke(1f);
for(BuildRequest req : player.buildQueue()){
if(req.breaking) continue;
if(req.bounds(Tmp.r2).overlaps(Tmp.r1)){
drawBreaking(req);
}
}
/*
for(BuildRequest req : selectRequests){
if(req.breaking) continue;
if(req.bounds(Tmp.r2).overlaps(Tmp.r1)){
drawBreaking(req);
}
}*/
for(BrokenBlock req : state.teams.get(player.getTeam()).brokenBlocks){
Block block = content.block(req.block);
if(block.bounds(req.x, req.y, Tmp.r2).overlaps(Tmp.r1)){
drawSelected(req.x, req.y, content.block(req.block), Pal.remove);
}
}
Lines.stroke(2f);
Draw.color(Pal.removeBack);
Lines.rect(result.x, result.y - 1, result.x2 - result.x, result.y2 - result.y);
Draw.color(Pal.remove);
Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y);
}
protected void flushSelectRequests(Array<BuildRequest> requests){
for(BuildRequest req : requests){
if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){
selectRequests.add(req);
}
}
}
protected void flushRequests(Array<BuildRequest> requests){
for(BuildRequest req : requests){
if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){
player.addBuildRequest(req);
}
}
}
protected void drawRequest(BuildRequest request){
drawRequest(request.x, request.y, request.block, request.rotation);
}
/** Draws a placement icon for a specific block. */
protected void drawRequest(int x, int y, Block block, int rotation){
brequest.set(x, y, rotation, block);
brequest.animScale = 1f;
block.drawRequest(brequest, allRequests(), validPlace(x, y, block, rotation));
}
/** Remove everything from the queue in a selection. */
protected void removeSelection(int x1, int y1, int x2, int y2){
removeSelection(x1, y1, x2, y2, false);
}
/** Remove everything from the queue in a selection. */
protected void removeSelection(int x1, int y1, int x2, int y2, boolean flush){
NormalizeResult result = PlaceUtils.normalizeArea(x1, y1, x2, y2, rotation, false, maxLength);
for(int x = 0; x <= Math.abs(result.x2 - result.x); x++){
for(int y = 0; y <= Math.abs(result.y2 - result.y); y++){
int wx = x1 + x * Mathf.sign(x2 - x1);
int wy = y1 + y * Mathf.sign(y2 - y1);
Tile tile = world.ltile(wx, wy);
if(tile == null) continue;
if(!flush){
tryBreakBlock(wx, wy);
}else if(validBreak(tile.x, tile.y) && !selectRequests.contains(r -> r.tile() != null && r.tile().link() == tile)){
selectRequests.add(new BuildRequest(tile.x, tile.y));
}
}
}
//remove build requests
Tmp.r1.set(result.x * tilesize, result.y * tilesize, (result.x2 - result.x) * tilesize, (result.y2 - result.y) * tilesize);
Iterator<BuildRequest> it = player.buildQueue().iterator();
while(it.hasNext()){
BuildRequest req = it.next();
if(!req.breaking && req.bounds(Tmp.r2).overlaps(Tmp.r1)){
it.remove();
}
}
/*
it = selectRequests.iterator();
while(it.hasNext()){
BuildRequest req = it.next();
if(!req.breaking && req.bounds(Tmp.r2).overlaps(Tmp.r1)){
it.remove();
}
}*/
//remove blocks to rebuild
Iterator<BrokenBlock> broken = state.teams.get(player.getTeam()).brokenBlocks.iterator();
while(broken.hasNext()){
BrokenBlock req = broken.next();
Block block = content.block(req.block);
if(block.bounds(req.x, req.y, Tmp.r2).overlaps(Tmp.r1)){
broken.remove();
}
}
}
protected void updateLine(int x1, int y1, int x2, int y2){
lineRequests.clear();
iterateLine(x1, y1, x2, y2, l -> {
rotation = l.rotation;
BuildRequest req = new BuildRequest(l.x, l.y, l.rotation, block);
req.animScale = 1f;
lineRequests.add(req);
});
}
protected void updateLine(int x1, int y1){
updateLine(x1, y1, tileX(getMouseX()), tileY(getMouseY()));
} }
/** Handles tile tap events that are not platform specific. */ /** Handles tile tap events that are not platform specific. */
@@ -214,12 +448,13 @@ public abstract class InputHandler implements InputProcessor{
} }
} }
/*
//clear when the player taps on something else //clear when the player taps on something else
if(!consumed && !mobile && player.isBuilding() && block == null){ if(!consumed && !mobile && player.isBuilding() && block == null){
player.clearBuilding(); //player.clearBuilding();
block = null; block = null;
return true; return true;
} }*/
if(!showedInventory){ if(!showedInventory){
frag.inv.hide(); frag.inv.hide();
@@ -301,16 +536,36 @@ public abstract class InputHandler implements InputProcessor{
table.clear(); table.clear();
} }
} }
if(detector != null){
Core.input.removeProcessor(detector);
}
if(uiGroup != null){
uiGroup.remove();
uiGroup = null;
}
} }
public void add(){ public void add(){
Core.input.addProcessor(detector = new GestureDetector(20, 0.5f, 0.4f, 0.15f, this));
Core.input.addProcessor(this); Core.input.addProcessor(this);
if(Core.scene != null){ if(Core.scene != null){
Table table = (Table)Core.scene.find("inputTable"); Table table = (Table)Core.scene.find("inputTable");
if(table != null){ if(table != null){
table.clear(); table.clear();
buildUI(table); buildPlacementUI(table);
} }
uiGroup = new WidgetGroup();
uiGroup.touchable(Touchable.childrenOnly);
uiGroup.setFillParent(true);
ui.hudGroup.addChild(uiGroup);
buildUI(uiGroup);
frag.add();
}
if(player != null){
player.isBuilding = true;
} }
} }
@@ -356,6 +611,15 @@ public abstract class InputHandler implements InputProcessor{
} }
public boolean validPlace(int x, int y, Block type, int rotation){ public boolean validPlace(int x, int y, Block type, int rotation){
return validPlace(x, y, type, rotation, null);
}
public boolean validPlace(int x, int y, Block type, int rotation, BuildRequest ignore){
for(BuildRequest req : player.buildQueue()){
if(req != ignore && !req.breaking && req.block.bounds(req.x, req.y, Tmp.r1).overlaps(type.bounds(x, y, Tmp.r2))){
return false;
}
}
return Build.validPlace(player.getTeam(), x, y, type, rotation); return Build.validPlace(player.getTeam(), x, y, type, rotation);
} }
@@ -407,8 +671,8 @@ public abstract class InputHandler implements InputProcessor{
float angle = Angles.angle(startX, startY, endX, endY); float angle = Angles.angle(startX, startY, endX, endY);
int baseRotation = rotation; int baseRotation = rotation;
if (!overrideLineRotation || diagonal){ if(!overrideLineRotation || diagonal){
baseRotation = (startX == endX && startY == endY) ? rotation : ((int)((angle + 45) / 90f)) % 4; baseRotation = (startX == endX && startY == endY) ? rotation : ((int)((angle + 45) / 90f)) % 4;
} }
Tmp.r3.set(-1, -1, 0, 0); Tmp.r3.set(-1, -1, 0, 0);
@@ -423,7 +687,7 @@ public abstract class InputHandler implements InputProcessor{
Point2 next = i == points.size - 1 ? null : points.get(i + 1); Point2 next = i == points.size - 1 ? null : points.get(i + 1);
line.x = point.x; line.x = point.x;
line.y = point.y; line.y = point.y;
if (!overrideLineRotation || diagonal){ if(!overrideLineRotation || diagonal){
line.rotation = next != null ? Tile.relativeTo(point.x, point.y, next.x, next.y) : baseRotation; line.rotation = next != null ? Tile.relativeTo(point.x, point.y, next.x, next.y) : baseRotation;
}else{ }else{
line.rotation = rotation; line.rotation = rotation;
@@ -435,13 +699,6 @@ public abstract class InputHandler implements InputProcessor{
} }
} }
public static class PlaceDraw{
public int rotation, scalex, scaley;
public TextureRegion region;
public static final PlaceDraw instance = new PlaceDraw();
}
class PlaceLine{ class PlaceLine{
public int x, y, rotation; public int x, y, rotation;
public boolean last; public boolean last;

View File

@@ -2,12 +2,12 @@ package io.anuke.mindustry.input;
import io.anuke.arc.*; import io.anuke.arc.*;
import io.anuke.arc.collection.*; import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.input.*;
import io.anuke.arc.input.GestureDetector.*; import io.anuke.arc.input.GestureDetector.*;
import io.anuke.arc.input.*;
import io.anuke.arc.math.*; import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*; import io.anuke.arc.math.geom.*;
import io.anuke.arc.scene.*;
import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.scene.ui.layout.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.mindustry.content.*; import io.anuke.mindustry.content.*;
@@ -19,7 +19,6 @@ import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.gen.*; import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.input.PlaceUtils.*;
import io.anuke.mindustry.ui.*; import io.anuke.mindustry.ui.*;
import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.*;
@@ -29,17 +28,15 @@ import static io.anuke.mindustry.input.PlaceMode.*;
public class MobileInput extends InputHandler implements GestureListener{ public class MobileInput extends InputHandler implements GestureListener{
/** Maximum speed the player can pan. */ /** Maximum speed the player can pan. */
private static final float maxPanSpeed = 1.3f; private static final float maxPanSpeed = 1.3f;
private static Rectangle r1 = new Rectangle(), r2 = new Rectangle();
/** Distance to edge of screen to start panning. */ /** Distance to edge of screen to start panning. */
private final float edgePan = Scl.scl(60f); private final float edgePan = Scl.scl(60f);
//gesture data //gesture data
private Vector2 vector = new Vector2(); private Vector2 vector = new Vector2();
private float lastZoom = -1; private float lastZoom = -1;
private GestureDetector detector;
/** Position where the player started dragging a line. */ /** Position where the player started dragging a line. */
private int lineStartX, lineStartY; private int lineStartX, lineStartY, lastLineX, lastLineY;
/** Animation scale for line. */ /** Animation scale for line. */
private float lineScale; private float lineScale;
@@ -49,10 +46,8 @@ public class MobileInput extends InputHandler implements GestureListener{
/** Used for shifting build requests. */ /** Used for shifting build requests. */
private float shiftDeltaX, shiftDeltaY; private float shiftDeltaX, shiftDeltaY;
/** List of currently selected tiles to place. */
private Array<PlaceRequest> selection = new Array<>();
/** Place requests to be removed. */ /** Place requests to be removed. */
private Array<PlaceRequest> removals = new Array<>(); private Array<BuildRequest> removals = new Array<>();
/** Whether or not the player is currently shifting all placed tiles. */ /** Whether or not the player is currently shifting all placed tiles. */
private boolean selecting; private boolean selecting;
/** Whether the player is currently in line-place mode. */ /** Whether the player is currently in line-place mode. */
@@ -62,9 +57,9 @@ public class MobileInput extends InputHandler implements GestureListener{
/** Whether no recipe was available when switching to break mode. */ /** Whether no recipe was available when switching to break mode. */
private Block lastBlock; private Block lastBlock;
/** Last placed request. Used for drawing block overlay. */ /** Last placed request. Used for drawing block overlay. */
private PlaceRequest lastPlaced; private BuildRequest lastPlaced;
/** Down tracking for panning.*/
private int prevX, prevY, prevRotation; private boolean down = false;
//region utility methods //region utility methods
@@ -99,10 +94,10 @@ public class MobileInput extends InputHandler implements GestureListener{
r2.setSize(block.size * tilesize); r2.setSize(block.size * tilesize);
r2.setCenter(x * tilesize + block.offset(), y * tilesize + block.offset()); r2.setCenter(x * tilesize + block.offset(), y * tilesize + block.offset());
for(PlaceRequest req : selection){ for(BuildRequest req : selectRequests){
Tile other = req.tile(); Tile other = req.tile();
if(other == null || req.remove) continue; if(other == null || req.breaking) continue;
r1.setSize(req.block.size * tilesize); r1.setSize(req.block.size * tilesize);
r1.setCenter(other.worldx() + req.block.offset(), other.worldy() + req.block.offset()); r1.setCenter(other.worldx() + req.block.offset(), other.worldy() + req.block.offset());
@@ -128,16 +123,16 @@ public class MobileInput extends InputHandler implements GestureListener{
} }
/** Returns the selection request that overlaps this tile, or null. */ /** Returns the selection request that overlaps this tile, or null. */
PlaceRequest getRequest(Tile tile){ BuildRequest getRequest(Tile tile){
r2.setSize(tilesize); r2.setSize(tilesize);
r2.setCenter(tile.worldx(), tile.worldy()); r2.setCenter(tile.worldx(), tile.worldy());
for(PlaceRequest req : selection){ for(BuildRequest req : selectRequests){
Tile other = req.tile(); Tile other = req.tile();
if(other == null) continue; if(other == null) continue;
if(!req.remove){ if(!req.breaking){
r1.setSize(req.block.size * tilesize); r1.setSize(req.block.size * tilesize);
r1.setCenter(other.worldx() + req.block.offset(), other.worldy() + req.block.offset()); r1.setCenter(other.worldx() + req.block.offset(), other.worldy() + req.block.offset());
@@ -156,8 +151,8 @@ public class MobileInput extends InputHandler implements GestureListener{
return null; return null;
} }
void removeRequest(PlaceRequest request){ void removeRequest(BuildRequest request){
selection.removeValue(request, true); selectRequests.removeValue(request, true);
removals.add(request); removals.add(request);
} }
@@ -172,80 +167,8 @@ public class MobileInput extends InputHandler implements GestureListener{
//endregion //endregion
//region UI and drawing //region UI and drawing
void drawRequest(PlaceRequest request, PlaceRequest prev){
Tile tile = request.tile();
if(!request.remove){
if(prev != null){
request.block.getPlaceDraw(placeDraw, request.rotation, prev.x - request.x, prev.y - request.y, prev.rotation);
}else{
request.block.getPlaceDraw(placeDraw, request.rotation, 0, 0, request.rotation);
}
//draw placing request
float offset = request.block.offset();
TextureRegion region = placeDraw.region;
Draw.mixcol(Pal.accent, Mathf.clamp((1f - request.scale) / 0.5f + 0.12f + Mathf.absin(Time.time(), 8f, 0.35f)));
Draw.tint(Color.white, Pal.breakInvalid, request.redness);
Draw.rect(region, tile.worldx() + offset, tile.worldy() + offset,
region.getWidth() * request.scale * Draw.scl * placeDraw.scalex,
region.getHeight() * request.scale * Draw.scl * placeDraw.scaley,
request.block.rotate ? placeDraw.rotation * 90 : 0);
Draw.mixcol(Pal.accent, 1f);
for(int i = 0; i < 4; i++){
Point2 p = Geometry.d8edge[i];
float poffset = -Math.max(request.block.size - 1, 0) / 2f * tilesize;
TextureRegion find = Core.atlas.find("block-select");
if(i % 2 == 0)
Draw.rect("block-select", request.tile().x * tilesize + request.block.offset() + poffset * p.x, request.tile().y * tilesize + request.block.offset() + poffset * p.y,
find.getWidth() * Draw.scl * request.scale, find.getHeight() * Draw.scl * request.scale, i * 90);
}
Draw.color();
}else{
float rad = Math.max((tile.block().size * tilesize / 2f - 1) * request.scale, 1f);
if(rad <= 1.01f) return;
Draw.mixcol();
//draw removing request
Draw.tint(Pal.removeBack);
Lines.square(tile.drawx(), tile.drawy() - 1, rad);
Draw.tint(Pal.remove);
Lines.square(tile.drawx(), tile.drawy(), rad);
}
}
/** Draws a placement icon for a specific block. */
void drawPlace(int x, int y, Block block, int rotation, int prevX, int prevY, int prevRotation){
if(validPlace(x, y, block, rotation) && !checkOverlapPlacement(x, y, block)){
block.getPlaceDraw(placeDraw, rotation, prevX, prevY, prevRotation);
Draw.color();
Draw.rect(placeDraw.region, x * tilesize + block.offset(), y * tilesize + block.offset(),
placeDraw.region.getWidth() * Draw.scl * placeDraw.scalex,
placeDraw.region.getHeight() * Draw.scl * placeDraw.scaley,
block.rotate ? placeDraw.rotation * 90 : 0);
Draw.color(Pal.accent);
for(int i = 0; i < 4; i++){
Point2 p = Geometry.d8edge[i];
float offset = -Math.max(block.size - 1, 0) / 2f * tilesize;
if(i % 2 == 0)
Draw.rect("block-select", x * tilesize + block.offset() + offset * p.x, y * tilesize + block.offset() + offset * p.y, i * 90);
}
Draw.color();
}else{
Draw.color(Pal.removeBack);
Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset() - 1, block.size * tilesize / 2f - 1);
Draw.color(Pal.remove);
Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset(), block.size * tilesize / 2f - 1);
}
}
@Override @Override
public void buildUI(Table table){ public void buildPlacementUI(Table table){
table.addImage().color(Pal.gray).height(4f).colspan(4).growX(); table.addImage().color(Pal.gray).height(4f).colspan(4).growX();
table.row(); table.row();
table.left().margin(0f).defaults().size(48f); table.left().margin(0f).defaults().size(48f);
@@ -267,12 +190,12 @@ public class MobileInput extends InputHandler implements GestureListener{
//confirm button //confirm button
table.addImageButton(Icon.checkSmall, Styles.clearPartiali, () -> { table.addImageButton(Icon.checkSmall, Styles.clearPartiali, () -> {
for(PlaceRequest request : selection){ for(BuildRequest request : selectRequests){
Tile tile = request.tile(); Tile tile = request.tile();
//actually place/break all selected blocks //actually place/break all selected blocks
if(tile != null){ if(tile != null){
if(!request.remove){ if(!request.breaking){
rotation = request.rotation; rotation = request.rotation;
Block before = block; Block before = block;
block = request.block; block = request.block;
@@ -285,25 +208,23 @@ public class MobileInput extends InputHandler implements GestureListener{
} }
//move all current requests to removal array so they fade out //move all current requests to removal array so they fade out
removals.addAll(selection); removals.addAll(selectRequests.find(r -> !r.breaking));
selection.clear(); selectRequests.clear();
selecting = false; selecting = false;
}).visible(() -> !selection.isEmpty()).name("confirmplace"); }).visible(() -> !selectRequests.isEmpty()).name("confirmplace");
Core.scene.table(t -> {
t.setName("cancelMobile");
t.bottom().left().visible(() -> (player.isBuilding() || block != null || mode == breaking) && !state.is(State.menu));
t.addImageTextButton("$cancel", Icon.cancelSmall, () -> {
player.clearBuilding();
mode = none;
block = null;
}).width(155f);
});
} }
@Override @Override
public boolean isDrawing(){ public void buildUI(Group group){
return selection.size > 0 || removals.size > 0 || lineMode || player.target != null || mode != PlaceMode.none; group.fill(t -> {
t.bottom().left().visible(() -> (player.isBuilding() || block != null || mode == breaking || !selectRequests.isEmpty()) && !state.is(State.menu));
t.addImageTextButton("$cancel", Icon.cancelSmall, () -> {
player.clearBuilding();
selectRequests.clear();
mode = none;
block = null;
}).width(155f);
});
} }
@Override @Override
@@ -312,55 +233,58 @@ public class MobileInput extends InputHandler implements GestureListener{
} }
@Override @Override
public void drawOutlined(){ public void drawBottom(){
Lines.stroke(1f); Lines.stroke(1f);
//draw removals //draw removals
for(PlaceRequest request : removals){ for(BuildRequest request : removals){
Tile tile = request.tile(); Tile tile = request.tile();
if(tile == null) continue; if(tile == null) continue;
request.scale = Mathf.lerpDelta(request.scale, 0f, 0.2f); request.animScale = Mathf.lerpDelta(request.animScale, 0f, 0.2f);
request.redness = Mathf.lerpDelta(request.redness, 0f, 0.2f); request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0f, 0.2f);
drawRequest(request, null); if(request.breaking){
drawSelected(request.x, request.y, tile.block(), Pal.remove);
}else{
request.block.drawRequest(request, allRequests(), true);
}
//TODO
//drawRequest(request);
} }
PlaceRequest last = null;
//draw list of requests //draw list of requests
for(PlaceRequest request : selection){ for(BuildRequest request : selectRequests){
Tile tile = request.tile(); Tile tile = request.tile();
if(tile == null) continue; if(tile == null) continue;
if((!request.remove && validPlace(tile.x, tile.y, request.block, request.rotation)) if((!request.breaking && validPlace(tile.x, tile.y, request.block, request.rotation))
|| (request.remove && validBreak(tile.x, tile.y))){ || (request.breaking && validBreak(tile.x, tile.y))){
request.scale = Mathf.lerpDelta(request.scale, 1f, 0.2f); request.animScale = Mathf.lerpDelta(request.animScale, 1f, 0.2f);
request.redness = Mathf.lerpDelta(request.redness, 0f, 0.2f); request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0f, 0.2f);
}else{ }else{
request.scale = Mathf.lerpDelta(request.scale, 0.6f, 0.1f); request.animScale = Mathf.lerpDelta(request.animScale, 0.6f, 0.1f);
request.redness = Mathf.lerpDelta(request.redness, 0.9f, 0.2f); request.animInvalid = Mathf.lerpDelta(request.animInvalid, 0.9f, 0.2f);
} }
Tmp.c1.set(Draw.getMixColor()); Tmp.c1.set(Draw.getMixColor());
if(!request.remove && request == lastPlaced && request.block != null){ if(!request.breaking && request == lastPlaced && request.block != null){
Draw.mixcol(); Draw.mixcol();
if(request.block.rotate) drawArrow(request.block, tile.x, tile.y, request.rotation); if(request.block.rotate) drawArrow(request.block, tile.x, tile.y, request.rotation);
} }
Draw.mixcol(Tmp.c1, 1f); //Draw.mixcol(Tmp.c1, 1f);
drawRequest(request, last); Draw.reset();
drawRequest(request);
//draw last placed request //draw last placed request
if(!request.remove && request == lastPlaced && request.block != null){ if(!request.breaking && request == lastPlaced && request.block != null){
Draw.mixcol(); Draw.mixcol();
request.block.drawPlace(tile.x, tile.y, rotation, validPlace(tile.x, tile.y, request.block, rotation)); request.block.drawPlace(tile.x, tile.y, rotation, validPlace(tile.x, tile.y, request.block, rotation));
} }
last = request;
} }
Draw.mixcol(); Draw.mixcol();
@@ -373,46 +297,16 @@ public class MobileInput extends InputHandler implements GestureListener{
if(mode == placing && block != null){ if(mode == placing && block != null){
//draw placing //draw placing
for(int i = 0; i < lineRequests.size; i++){
prevX = lineStartX; BuildRequest req = lineRequests.get(i);
prevY = lineStartY; if(i == lineRequests.size - 1 && req.block.rotate){
prevRotation = rotation; drawArrow(block, req.x, req.y, req.rotation);
iterateLine(lineStartX, lineStartY, tileX, tileY, l -> {
if(l.last && block.rotate){
drawArrow(block, l.x, l.y, l.rotation);
}
drawPlace(l.x, l.y, block, l.rotation, prevX - l.x, prevY - l.y, prevRotation);
rotation = l.rotation;
prevX = l.x;
prevY = l.y;
prevRotation = l.rotation;
});
}else if(mode == breaking){
//draw breaking
NormalizeDrawResult result = PlaceUtils.normalizeDrawArea(Blocks.air, lineStartX, lineStartY, tileX, tileY, false, maxLength, 1f);
NormalizeResult dresult = PlaceUtils.normalizeArea(lineStartX, lineStartY, tileX, tileY, rotation, false, maxLength);
for(int x = dresult.x; x <= dresult.x2; x++){
for(int y = dresult.y; y <= dresult.y2; y++){
Tile other = world.ltile(x, y);
if(other == null || !validBreak(other.x, other.y)) continue;
Draw.color(Pal.removeBack);
Lines.square(other.drawx(), other.drawy() - 1, other.block().size * tilesize / 2f - 1);
Draw.color(Pal.remove);
Lines.square(other.drawx(), other.drawy(), other.block().size * tilesize / 2f - 1);
} }
drawRequest(lineRequests.get(i));
} }
}else if(mode == breaking){
Draw.color(Pal.removeBack); drawSelection(lineStartX, lineStartY, tileX, tileY);
Lines.rect(result.x, result.y - 1, result.x2 - result.x, result.y2 - result.y);
Draw.color(Pal.remove);
Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y);
} }
} }
TargetTrait target = player.target; TargetTrait target = player.target;
@@ -438,31 +332,28 @@ public class MobileInput extends InputHandler implements GestureListener{
Draw.reset(); Draw.reset();
} }
@Override
protected void drawRequest(BuildRequest request){
if(request.tile() == null) return;
brequest.animScale = request.animScale = Mathf.lerpDelta(request.animScale, 1f, 0.1f);
if(request.breaking){
drawSelected(request.x, request.y, request.tile().block(), Pal.remove);
}else{
drawRequest(request.x, request.y, request.block, request.rotation);
drawSelected(request.x, request.y, request.block, Pal.accent);
}
}
//endregion //endregion
//region input events //region input events
@Override
public void add(){
Core.input.addProcessor(detector = new GestureDetector(20, 0.5f, 0.4f, 0.15f, this));
super.add();
}
@Override
public void remove(){
super.remove();
if(detector != null){
Core.input.removeProcessor(detector);
}
if(Core.scene != null && Core.scene.find("cancelMobile") != null){
Core.scene.find("cancelMobile").remove();
}
}
@Override @Override
public boolean touchDown(int screenX, int screenY, int pointer, KeyCode button){ public boolean touchDown(int screenX, int screenY, int pointer, KeyCode button){
if(state.is(State.menu) || player.isDead()) return false; if(state.is(State.menu) || player.isDead()) return false;
down = true;
//get tile on cursor //get tile on cursor
Tile cursor = tileAt(screenX, screenY); Tile cursor = tileAt(screenX, screenY);
@@ -489,44 +380,20 @@ public class MobileInput extends InputHandler implements GestureListener{
public boolean touchUp(int screenX, int screenY, int pointer, KeyCode button){ public boolean touchUp(int screenX, int screenY, int pointer, KeyCode button){
lastZoom = renderer.getScale(); lastZoom = renderer.getScale();
if(!Core.input.isTouched()){
down = false;
}
//place down a line if in line mode //place down a line if in line mode
if(lineMode){ if(lineMode){
int tileX = tileX(screenX); int tileX = tileX(screenX);
int tileY = tileY(screenY); int tileY = tileY(screenY);
if(mode == placing && isPlacing()){ if(mode == placing && isPlacing()){
iterateLine(lineStartX, lineStartY, tileX, tileY, l -> { flushSelectRequests(lineRequests);
Tile tile = world.tile(l.x, l.y);
if(tile != null && checkOverlapPlacement(tile.x, tile.y, block)){
return;
}
PlaceRequest request = new PlaceRequest(l.x, l.y, block, l.rotation);
request.scale = 1f;
selection.add(request);
});
Events.fire(new LineConfirmEvent()); Events.fire(new LineConfirmEvent());
}else if(mode == breaking){ }else if(mode == breaking){
//normalize area removeSelection(lineStartX, lineStartY, tileX, tileY, true);
NormalizeResult result = PlaceUtils.normalizeArea(lineStartX, lineStartY, tileX, tileY, rotation, false, maxLength);
//break everything in area
for(int x = 0; x <= Math.abs(result.x2 - result.x); x++){
for(int y = 0; y <= Math.abs(result.y2 - result.y); y++){
int wx = lineStartX + x * Mathf.sign(tileX - lineStartX);
int wy = lineStartY + y * Mathf.sign(tileY - lineStartY);
Tile tar = world.ltile(wx, wy);
if(tar == null) continue;
if(!hasRequest(world.tile(tar.x, tar.y)) && validBreak(tar.x, tar.y)){
PlaceRequest request = new PlaceRequest(tar.x, tar.y);
request.scale = 1f;
selection.add(request);
}
}
}
} }
lineMode = false; lineMode = false;
@@ -554,11 +421,14 @@ public class MobileInput extends InputHandler implements GestureListener{
//long pressing enables line mode otherwise //long pressing enables line mode otherwise
lineStartX = cursor.x; lineStartX = cursor.x;
lineStartY = cursor.y; lineStartY = cursor.y;
lastLineX = cursor.x;
lastLineY = cursor.y;
lineMode = true; lineMode = true;
if(mode == breaking){ if(mode == breaking){
Effects.effect(Fx.tapBlock, cursor.worldx(), cursor.worldy(), 1f); Effects.effect(Fx.tapBlock, cursor.worldx(), cursor.worldy(), 1f);
}else if(block != null){ }else if(block != null){
updateLine(lineStartX, lineStartY, cursor.x, cursor.y);
Effects.effect(Fx.tapBlock, cursor.worldx() + block.offset(), cursor.worldy() + block.offset(), block.size); Effects.effect(Fx.tapBlock, cursor.worldx() + block.offset(), cursor.worldy() + block.offset(), block.size);
} }
@@ -584,11 +454,11 @@ public class MobileInput extends InputHandler implements GestureListener{
removeRequest(getRequest(cursor)); removeRequest(getRequest(cursor));
}else if(mode == placing && isPlacing() && validPlace(cursor.x, cursor.y, block, rotation) && !checkOverlapPlacement(cursor.x, cursor.y, block)){ }else if(mode == placing && isPlacing() && validPlace(cursor.x, cursor.y, block, rotation) && !checkOverlapPlacement(cursor.x, cursor.y, block)){
//add to selection queue if it's a valid place position //add to selection queue if it's a valid place position
selection.add(lastPlaced = new PlaceRequest(cursor.x, cursor.y, block, rotation)); selectRequests.add(lastPlaced = new BuildRequest(cursor.x, cursor.y, rotation, block));
}else if(mode == breaking && validBreak(cursor.link().x, cursor.link().y) && !hasRequest(cursor.link())){ }else if(mode == breaking && validBreak(cursor.link().x, cursor.link().y) && !hasRequest(cursor.link())){
//add to selection queue if it's a valid BREAK position //add to selection queue if it's a valid BREAK position
cursor = cursor.link(); cursor = cursor.link();
selection.add(new PlaceRequest(cursor.x, cursor.y)); selectRequests.add(new BuildRequest(cursor.x, cursor.y));
}else if(!canTapPlayer(worldx, worldy) && !tileTapped(cursor.link())){ }else if(!canTapPlayer(worldx, worldy) && !tileTapped(cursor.link())){
tryBeginMine(cursor); tryBeginMine(cursor);
} }
@@ -598,12 +468,16 @@ public class MobileInput extends InputHandler implements GestureListener{
@Override @Override
public void update(){ public void update(){
if(state.is(State.menu) || player.isDead()){ if(state.is(State.menu) ){
selection.clear(); selectRequests.clear();
removals.clear(); removals.clear();
mode = none; mode = none;
} }
if(player.isDead()){
mode = none;
}
//zoom things //zoom things
if(Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && (Core.input.keyDown(Binding.zoom_hold))){ if(Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && (Core.input.keyDown(Binding.zoom_hold))){
renderer.scaleCamera(Core.input.axisTap(Binding.zoom)); renderer.scaleCamera(Core.input.axisTap(Binding.zoom));
@@ -629,8 +503,6 @@ public class MobileInput extends InputHandler implements GestureListener{
if(mode == none){ if(mode == none){
selecting = false; selecting = false;
lineMode = false; lineMode = false;
removals.addAll(selection);
selection.clear();
} }
if(lineMode && mode == placing && block == null){ if(lineMode && mode == placing && block == null){
@@ -656,7 +528,7 @@ public class MobileInput extends InputHandler implements GestureListener{
lineScale = Mathf.lerpDelta(lineScale, 1f, 0.1f); lineScale = Mathf.lerpDelta(lineScale, 1f, 0.1f);
//When in line mode, pan when near screen edges automatically //When in line mode, pan when near screen edges automatically
if(Core.input.isTouched(0) && lineMode){ if(Core.input.isTouched(0)){
float screenX = Core.input.mouseX(), screenY = Core.input.mouseY(); float screenX = Core.input.mouseX(), screenY = Core.input.mouseY();
float panX = 0, panY = 0; float panX = 0, panY = 0;
@@ -684,15 +556,24 @@ public class MobileInput extends InputHandler implements GestureListener{
Core.camera.position.x += vector.x; Core.camera.position.x += vector.x;
Core.camera.position.y += vector.y; Core.camera.position.y += vector.y;
} }
int lx = tileX(Core.input.mouseX()), ly = tileY(Core.input.mouseY());
if((lastLineX != lx || lastLineY != ly) && isPlacing()){
lastLineX = lx;
lastLineY = ly;
updateLine(lineStartX, lineStartY, lx, ly);
}
}else{ }else{
lineRequests.clear();
lineScale = 0f; lineScale = 0f;
} }
//remove place requests that have disappeared //remove place requests that have disappeared
for(int i = removals.size - 1; i >= 0; i--){ for(int i = removals.size - 1; i >= 0; i--){
PlaceRequest request = removals.get(i); BuildRequest request = removals.get(i);
if(request.scale <= 0.0001f){ if(request.animScale <= 0.0001f){
removals.remove(i); removals.remove(i);
i--; i--;
} }
@@ -712,6 +593,8 @@ public class MobileInput extends InputHandler implements GestureListener{
return false; return false;
} }
if(!down) return false;
if(selecting){ //pan all requests if(selecting){ //pan all requests
shiftDeltaX += deltaX; shiftDeltaX += deltaX;
shiftDeltaY += deltaY; shiftDeltaY += deltaY;
@@ -720,8 +603,8 @@ public class MobileInput extends InputHandler implements GestureListener{
int shiftedY = (int)(shiftDeltaY / tilesize); int shiftedY = (int)(shiftDeltaY / tilesize);
if(Math.abs(shiftedX) > 0 || Math.abs(shiftedY) > 0){ if(Math.abs(shiftedX) > 0 || Math.abs(shiftedY) > 0){
for(PlaceRequest req : selection){ for(BuildRequest req : selectRequests){
if(req.remove) continue; //don't shift removal requests if(req.breaking) continue; //don't shift removal requests
req.x += shiftedX; req.x += shiftedX;
req.y += shiftedY; req.y += shiftedY;
} }
@@ -756,33 +639,4 @@ public class MobileInput extends InputHandler implements GestureListener{
} }
//endregion //endregion
private class PlaceRequest{
int x, y;
Block block;
int rotation;
boolean remove;
//animation variables
float scale;
float redness;
PlaceRequest(int x, int y, Block block, int rotation){
this.x = x;
this.y = y;
this.block = block;
this.rotation = rotation;
this.remove = false;
}
PlaceRequest(int x, int y){
this.x = x;
this.y = y;
this.remove = true;
}
Tile tile(){
return world.tile(x, y);
}
}
} }

View File

@@ -257,7 +257,7 @@ public abstract class SaveVersion extends SaveFileReader{
TeamData data = state.teams.get(team); TeamData data = state.teams.get(team);
int blocks = stream.readInt(); int blocks = stream.readInt();
for(int j = 0; j < blocks; j++){ for(int j = 0; j < blocks; j++){
data.brokenBlocks.addLast(new BrokenBlock(stream.readShort(), stream.readShort(), stream.readShort(), stream.readShort(), stream.readInt())); data.brokenBlocks.addLast(new BrokenBlock(stream.readShort(), stream.readShort(), stream.readShort(), content.block(stream.readShort()).id, stream.readInt()));
} }
} }

View File

@@ -4,6 +4,7 @@ import io.anuke.arc.*;
import io.anuke.arc.audio.*; import io.anuke.arc.audio.*;
import io.anuke.arc.collection.Array; import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.*; import io.anuke.arc.collection.*;
import io.anuke.arc.files.*;
import io.anuke.arc.function.*; import io.anuke.arc.function.*;
import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.*;
import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.arc.util.ArcAnnotate.*;
@@ -95,7 +96,7 @@ public class ContentParser{
T two = (T)Vars.content.getByName(ctype, jsonData.asString()); T two = (T)Vars.content.getByName(ctype, jsonData.asString());
if(two != null) return two; if(two != null) return two;
throw new IllegalArgumentException("No " + ctype + " found with name: '" + jsonData.asString() + "'"); throw new IllegalArgumentException("\"" + jsonData.name + "\": No " + ctype + " found with name '" + jsonData.asString() + "'.");
} }
} }
@@ -107,28 +108,39 @@ public class ContentParser{
ContentType.block, (TypeParser<Block>)(mod, name, value) -> { ContentType.block, (TypeParser<Block>)(mod, name, value) -> {
readBundle(ContentType.block, name, value); readBundle(ContentType.block, name, value);
//TODO generate dynamically instead of doing.. this Block block;
Class<? extends Block> type = resolve(value.getString("type"),
"io.anuke.mindustry.world", if(Vars.content.getByName(ContentType.block, name) != null){
"io.anuke.mindustry.world.blocks", block = Vars.content.getByName(ContentType.block, name);
"io.anuke.mindustry.world.blocks.defense",
"io.anuke.mindustry.world.blocks.defense.turrets", if(value.has("type")){
"io.anuke.mindustry.world.blocks.distribution", throw new IllegalArgumentException("When overwriting an existing block, you must not re-declared its type. The original type will be used. Block: " + name);
"io.anuke.mindustry.world.blocks.logic", }
"io.anuke.mindustry.world.blocks.power", }else{
"io.anuke.mindustry.world.blocks.production", //TODO generate dynamically instead of doing.. this
"io.anuke.mindustry.world.blocks.sandbox", Class<? extends Block> type = resolve(value.getString("type"),
"io.anuke.mindustry.world.blocks.storage", "io.anuke.mindustry.world",
"io.anuke.mindustry.world.blocks.units" "io.anuke.mindustry.world.blocks",
); "io.anuke.mindustry.world.blocks.defense",
"io.anuke.mindustry.world.blocks.defense.turrets",
"io.anuke.mindustry.world.blocks.distribution",
"io.anuke.mindustry.world.blocks.logic",
"io.anuke.mindustry.world.blocks.power",
"io.anuke.mindustry.world.blocks.production",
"io.anuke.mindustry.world.blocks.sandbox",
"io.anuke.mindustry.world.blocks.storage",
"io.anuke.mindustry.world.blocks.units"
);
block = make(type, mod + "-" + name);
}
Block block = type.getDeclaredConstructor(String.class).newInstance(mod + "-" + name);
currentContent = block; currentContent = block;
read(() -> { read(() -> {
if(value.has("consumes")){ if(value.has("consumes")){
for(JsonValue child : value.get("consumes")){ for(JsonValue child : value.get("consumes")){
if(child.name.equals("item")){ if(child.name.equals("item")){
block.consumes.item(Vars.content.getByName(ContentType.item, child.asString())); block.consumes.item(find(ContentType.item, child.asString()));
}else if(child.name.equals("items")){ }else if(child.name.equals("items")){
block.consumes.add((Consume)parser.readValue(ConsumeItems.class, child)); block.consumes.add((Consume)parser.readValue(ConsumeItems.class, child));
}else if(child.name.equals("liquid")){ }else if(child.name.equals("liquid")){
@@ -152,7 +164,7 @@ public class ContentParser{
//add research tech node //add research tech node
if(value.has("research")){ if(value.has("research")){
TechTree.create(Vars.content.getByName(ContentType.block, value.get("research").asString()), block); TechTree.create(find(ContentType.block, value.get("research").asString()), block);
} }
//make block visible //make block visible
@@ -179,14 +191,21 @@ public class ContentParser{
ContentType.zone, parser(ContentType.zone, Zone::new) ContentType.zone, parser(ContentType.zone, Zone::new)
); );
private <T extends Content> T find(ContentType type, String name){
Content c = Vars.content.getByName(type, name);
if(c == null) c = Vars.content.getByName(type, currentMod.name + "-" + name);
if(c == null) throw new IllegalArgumentException("No " + type + " found with name '" + name + "'");
return (T)c;
}
private <T extends Content> TypeParser<T> parser(ContentType type, Function<String, T> constructor){ private <T extends Content> TypeParser<T> parser(ContentType type, Function<String, T> constructor){
return (mod, name, value) -> { return (mod, name, value) -> {
T item; T item;
if(Vars.content.getByName(type, name) != null){ if(Vars.content.getByName(type, name) != null){
item = (T)Vars.content.getByName(type, name); item = (T)Vars.content.getByName(type, name);
readBundle(type, name, value);
}else{ }else{
readBundle(type, name, value); readBundle(type, name, value);
item = constructor.get(mod + "-" + name); item = constructor.get(mod + "-" + name);
} }
currentContent = item; currentContent = item;
@@ -196,26 +215,33 @@ public class ContentParser{
} }
private void readBundle(ContentType type, String name, JsonValue value){ private void readBundle(ContentType type, String name, JsonValue value){
String entryName = type + "." + currentMod.name + "-" + name + "."; UnlockableContent cont = Vars.content.getByName(type, name) instanceof UnlockableContent ?
Vars.content.getByName(type, name) : null;
String entryName = cont == null ? type + "." + currentMod.name + "-" + name + "." : type + "." + cont.name + ".";
I18NBundle bundle = Core.bundle; I18NBundle bundle = Core.bundle;
while(bundle.getParent() != null) bundle = bundle.getParent(); while(bundle.getParent() != null) bundle = bundle.getParent();
if(value.has("name")){ if(value.has("name")){
bundle.getProperties().put(entryName + "name", value.getString("name")); bundle.getProperties().put(entryName + "name", value.getString("name"));
if(cont != null) cont.localizedName = value.getString("name");
value.remove("name"); value.remove("name");
} }
if(value.has("description")){ if(value.has("description")){
bundle.getProperties().put(entryName + "description", value.getString("description")); bundle.getProperties().put(entryName + "description", value.getString("description"));
if(cont != null) cont.description = value.getString("description");
value.remove("description"); value.remove("description");
} }
} }
/** Call to read a content's extra info later.*/ /** Call to read a content's extra info later.*/
private void read(Runnable run){ private void read(Runnable run){
Content cont = currentContent;
LoadedMod mod = currentMod; LoadedMod mod = currentMod;
reads.add(() -> { reads.add(() -> {
this.currentMod = mod; this.currentMod = mod;
this.currentContent = cont;
run.run(); run.run();
}); });
} }
@@ -239,7 +265,7 @@ public class ContentParser{
try{ try{
reads.each(Runnable::run); reads.each(Runnable::run);
}catch(Exception e){ }catch(Exception e){
throw new RuntimeException("Error occurred parsing content: " + currentContent, e); Vars.mods.handleError(new ModLoadException("Error occurred parsing content: " + currentContent, currentContent, e), currentMod);
} }
reads.clear(); reads.clear();
} }
@@ -249,9 +275,10 @@ public class ContentParser{
* @param name the name of the file without its extension * @param name the name of the file without its extension
* @param json the json to parse * @param json the json to parse
* @param type the type of content this is * @param type the type of content this is
* @param file file that this content is being parsed from
* @return the content that was parsed * @return the content that was parsed
*/ */
public Content parse(LoadedMod mod, String name, String json, ContentType type) throws Exception{ public Content parse(LoadedMod mod, String name, String json, FileHandle file, ContentType type) throws Exception{
if(contentTypes.isEmpty()){ if(contentTypes.isEmpty()){
init(); init();
} }
@@ -262,8 +289,12 @@ public class ContentParser{
} }
currentMod = mod; currentMod = mod;
boolean exists = Vars.content.getByName(type, name) != null;
Content c = parsers.get(type).parse(mod.name, name, value); Content c = parsers.get(type).parse(mod.name, name, value);
c.mod = mod; if(!exists){
c.sourceFile = file;
c.mod = mod;
}
checkNulls(c); checkNulls(c);
return c; return c;
} }
@@ -278,6 +309,16 @@ public class ContentParser{
} }
} }
private <T> T make(Class<T> type, String name){
try{
java.lang.reflect.Constructor<T> cons = type.getDeclaredConstructor(String.class);
cons.setAccessible(true);
return cons.newInstance(name);
}catch(Exception e){
throw new RuntimeException(e);
}
}
private <T> Supplier<T> supply(Class<T> type){ private <T> Supplier<T> supply(Class<T> type){
try{ try{
java.lang.reflect.Constructor<T> cons = type.getDeclaredConstructor(); java.lang.reflect.Constructor<T> cons = type.getDeclaredConstructor();
@@ -387,6 +428,8 @@ public class ContentParser{
/** Tries to resolve a class from a list of potential class names. */ /** Tries to resolve a class from a list of potential class names. */
private <T> Class<T> resolve(String base, String... potentials){ private <T> Class<T> resolve(String base, String... potentials){
if(!base.isEmpty() && Character.isLowerCase(base.charAt(0))) base = Strings.capitalize(base);
for(String type : potentials){ for(String type : potentials){
try{ try{
return (Class<T>)Class.forName(type + '.' + base); return (Class<T>)Class.forName(type + '.' + base);

View File

@@ -47,8 +47,7 @@ public class Mods implements Loadable{
} }
/** @return the loaded mod found by class, or null if not found. */ /** @return the loaded mod found by class, or null if not found. */
public @Nullable public @Nullable LoadedMod getMod(Class<? extends Mod> type){
LoadedMod getMod(Class<? extends Mod> type){
return loaded.find(l -> l.mod.getClass() == type); return loaded.find(l -> l.mod.getClass() == type);
} }
@@ -125,7 +124,7 @@ public class Mods implements Loadable{
//get textures packed //get textures packed
if(totalSprites > 0){ if(totalSprites > 0){
TextureFilter filter = TextureFilter.Nearest; TextureFilter filter = Core.settings.getBool("linear") ? TextureFilter.Linear : TextureFilter.Nearest;
packer.updateTextureAtlas(Core.atlas, filter, filter, false); packer.updateTextureAtlas(Core.atlas, filter, filter, false);
//generate new icons //generate new icons
@@ -203,11 +202,14 @@ public class Mods implements Loadable{
private void buildFiles(){ private void buildFiles(){
for(LoadedMod mod : loaded){ for(LoadedMod mod : loaded){
boolean zipFolder = !mod.file.isDirectory() && mod.root.parent() != null;
String parentName = zipFolder ? mod.root.name() : null;
for(FileHandle file : mod.root.list()){ for(FileHandle file : mod.root.list()){
//ignore special folders like bundles or sprites //ignore special folders like bundles or sprites
if(file.isDirectory() && !specialFolders.contains(file.name())){ if(file.isDirectory() && !specialFolders.contains(file.name())){
//TODO calling child/parent on these files will give you gibberish; create wrapper class. //TODO calling child/parent on these files will give you gibberish; create wrapper class.
file.walk(f -> tree.addFile(mod.file.isDirectory() ? f.path().substring(1 + mod.file.path().length()) : f.path(), f)); file.walk(f -> tree.addFile(mod.file.isDirectory() ? f.path().substring(1 + mod.file.path().length()) :
zipFolder ? f.path().substring(parentName.length() + 1) : f.path(), f));
} }
} }
@@ -266,30 +268,34 @@ public class Mods implements Loadable{
/** Creates all the content found in mod files. */ /** Creates all the content found in mod files. */
public void loadContent(){ public void loadContent(){
for(LoadedMod mod : loaded){ for(LoadedMod mod : loaded){
if(mod.root.child("content").exists()){ safeRun(mod, () -> {
FileHandle contentRoot = mod.root.child("content"); if(mod.root.child("content").exists()){
for(ContentType type : ContentType.all){ FileHandle contentRoot = mod.root.child("content");
FileHandle folder = contentRoot.child(type.name().toLowerCase() + "s"); for(ContentType type : ContentType.all){
if(folder.exists()){ FileHandle folder = contentRoot.child(type.name().toLowerCase() + "s");
for(FileHandle file : folder.list()){ if(folder.exists()){
if(file.extension().equals("json")){ for(FileHandle file : folder.list()){
try{ if(file.extension().equals("json")){
//this binds the content but does not load it entirely try{
Content loaded = parser.parse(mod, file.nameWithoutExtension(), file.readString(), type); //this binds the content but does not load it entirely
Log.info("[{0}] Loaded '{1}'.", mod.meta.name, (loaded instanceof UnlockableContent ? ((UnlockableContent)loaded).localizedName : loaded)); Content loaded = parser.parse(mod, file.nameWithoutExtension(), file.readString("UTF-8"), file, type);
}catch(Exception e){ Log.info("[{0}] Loaded '{1}'.", mod.meta.name,
throw new RuntimeException("Failed to parse content file '" + file + "' for mod '" + mod.meta.name + "'.", e); (loaded instanceof UnlockableContent ? ((UnlockableContent)loaded).localizedName : loaded));
}catch(Exception e){
throw new RuntimeException("Failed to parse content file '" + file + "' for mod '" + mod.meta.name + "'.", e);
}
} }
} }
} }
} }
} }
} });
} }
//this finishes parsing content fields //this finishes parsing content fields
parser.finishParsing(); parser.finishParsing();
//load content for code mods
each(Mod::loadContent); each(Mod::loadContent);
} }
@@ -343,7 +349,40 @@ public class Mods implements Loadable{
/** Iterates through each mod with a main class.*/ /** Iterates through each mod with a main class.*/
public void each(Consumer<Mod> cons){ public void each(Consumer<Mod> cons){
loaded.each(p -> p.mod != null, p -> cons.accept(p.mod)); loaded.each(p -> p.mod != null, p -> safeRun(p, () -> cons.accept(p.mod)));
}
public void handleError(Throwable t, LoadedMod mod){
Array<Throwable> causes = Strings.getCauses(t);
Content content = null;
for(Throwable e : causes){
if(e instanceof ModLoadException && ((ModLoadException) e).content != null){
content = ((ModLoadException) e).content;
}
}
String realCause = "<???>";
for(int i = causes.size -1 ; i >= 0; i--){
if(causes.get(i).getMessage() != null){
realCause = causes.get(i).getMessage();
break;
}
}
if(content != null){
throw new ModLoadException(Strings.format("Error loading '{0}' from mod '{1}' ({2}):\n{3}",
content, mod.meta.name, content.sourceFile.name(), realCause), content, t);
}else{
throw new ModLoadException("Error loading mod " + mod.meta.name, t);
}
}
public void safeRun(LoadedMod mod, Runnable run){
try{
run.run();
}catch(Throwable t){
handleError(t, mod);
}
} }
/** Loads a mod file+meta, but does not add it to the list. /** Loads a mod file+meta, but does not add it to the list.
@@ -428,6 +467,15 @@ public class Mods implements Loadable{
public boolean enabled(){ public boolean enabled(){
return Core.settings.getBool(name + "-enabled", true); return Core.settings.getBool(name + "-enabled", true);
} }
@Override
public String toString(){
return "LoadedMod{" +
"file=" + file +
", root=" + root +
", name='" + name + '\'' +
'}';
}
} }
/** Plugin metadata information.*/ /** Plugin metadata information.*/
@@ -437,4 +485,22 @@ public class Mods implements Loadable{
/** Hidden mods are only server-side or client-side, and do not support adding new content. */ /** Hidden mods are only server-side or client-side, and do not support adding new content. */
public boolean hidden; public boolean hidden;
} }
/** Thrown when an error occurs while loading a mod.*/
public static class ModLoadException extends RuntimeException{
public Content content;
public LoadedMod mod;
public ModLoadException(String message, Throwable cause){
super(message, cause);
}
public ModLoadException(String message, @Nullable Content content, Throwable cause){
super(message, cause);
this.content = content;
if(content != null){
this.mod = content.mod;
}
}
}
} }

View File

@@ -2,13 +2,14 @@ package io.anuke.mindustry.ui.dialogs;
import io.anuke.arc.*; import io.anuke.arc.*;
import io.anuke.arc.collection.*; import io.anuke.arc.collection.*;
import io.anuke.arc.collection.ObjectSet.*;
import io.anuke.arc.function.*; import io.anuke.arc.function.*;
import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.input.*;
import io.anuke.arc.math.*; import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*; import io.anuke.arc.math.geom.*;
import io.anuke.arc.scene.*; import io.anuke.arc.scene.*;
import io.anuke.arc.scene.event.*;
import io.anuke.arc.scene.style.*; import io.anuke.arc.scene.style.*;
import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.*;
import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.scene.ui.layout.*;
@@ -22,7 +23,8 @@ import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.io.SaveIO.*; import io.anuke.mindustry.io.SaveIO.*;
import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.ui.*; import io.anuke.mindustry.ui.*;
import io.anuke.mindustry.ui.TreeLayout.*; import io.anuke.mindustry.ui.layout.*;
import io.anuke.mindustry.ui.layout.TreeLayout.*;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -31,13 +33,14 @@ public class DeployDialog extends FloatingDialog{
private ObjectSet<ZoneNode> nodes = new ObjectSet<>(); private ObjectSet<ZoneNode> nodes = new ObjectSet<>();
private ZoneInfoDialog info = new ZoneInfoDialog(); private ZoneInfoDialog info = new ZoneInfoDialog();
private Rectangle bounds = new Rectangle(); private Rectangle bounds = new Rectangle();
private View view = new View();
public DeployDialog(){ public DeployDialog(){
super("", Styles.fullDialog); super("", Styles.fullDialog);
ZoneNode root = new ZoneNode(Zones.groundZero, null); ZoneNode root = new ZoneNode(Zones.groundZero, null);
TreeLayout layout = new TreeLayout(); BranchTreeLayout layout = new BranchTreeLayout();
layout.gapBetweenLevels = layout.gapBetweenNodes = Scl.scl(60f); layout.gapBetweenLevels = layout.gapBetweenNodes = Scl.scl(60f);
layout.gapBetweenNodes = Scl.scl(120f); layout.gapBetweenNodes = Scl.scl(120f);
layout.layout(root); layout.layout(root);
@@ -48,6 +51,51 @@ public class DeployDialog extends FloatingDialog{
buttons.addImageTextButton("$techtree", Icon.tree, () -> ui.tech.show()).size(230f, 64f); buttons.addImageTextButton("$techtree", Icon.tree, () -> ui.tech.show()).size(230f, 64f);
shown(this::setup); shown(this::setup);
//view input.
addListener(new InputListener(){
@Override
public boolean scrolled(InputEvent event, float x, float y, float amountX, float amountY){
view.setScale(Mathf.clamp(view.getScaleX() - amountY / 40f, 0.25f, 1f));
view.setOrigin(Align.center);
view.setTransform(true);
return true;
}
@Override
public boolean mouseMoved(InputEvent event, float x, float y){
view.requestScroll();
return super.mouseMoved(event, x, y);
}
});
addListener(new ElementGestureListener(){
@Override
public void zoom(InputEvent event, float initialDistance, float distance){
if(view.lastZoom < 0){
view.lastZoom = view.getScaleX();
}
view.setScale(Mathf.clamp(distance / initialDistance * view.lastZoom, 0.25f, 1f));
view.setOrigin(Align.center);
view.setTransform(true);
}
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){
view.lastZoom = view.getScaleX();
}
@Override
public void pan(InputEvent event, float x, float y, float deltaX, float deltaY){
view.panX += deltaX / view.getScaleX();
view.panY += deltaY / view.getScaleY();
view.moved = true;
view.clamp();
}
});
} }
public void setup(){ public void setup(){
@@ -72,7 +120,7 @@ public class DeployDialog extends FloatingDialog{
update(() -> { update(() -> {
setOrigin(Align.center); setOrigin(Align.center);
time[0] += Core.graphics.getDeltaTime() * 10f; time[0] += Core.graphics.getDeltaTime() * 10f;
setTranslation(Mathf.sin(time[0], 60f, 70f) + panX / 30f, Mathf.cos(time[0], 140f, 80f) + (panY + 200) / 30f); setTranslation(Mathf.sin(time[0], 60f, 70f) + view.panX / 30f, Mathf.cos(time[0], 140f, 80f) + (view.panY + 200) / 30f);
}); });
}}.setScaling(Scaling.fit)); }}.setScaling(Scaling.fit));
@@ -142,7 +190,7 @@ public class DeployDialog extends FloatingDialog{
}).width(size).height(50f).padTop(3); }).width(size).height(50f).padTop(3);
})); }));
}else{ }else{
stack.add(new View()); stack.add(view = new View());
} }
stack.add(new ItemsDisplay()); stack.add(new ItemsDisplay());
@@ -153,12 +201,15 @@ public class DeployDialog extends FloatingDialog{
for(ZoneNode node : nodes){ for(ZoneNode node : nodes){
node.allChildren.clear(); node.allChildren.clear();
node.allChildren.addAll(node.children); node.allChildren.addAll(node.children);
for(ZoneNode other : new ObjectSetIterator<>(nodes)){ for(ZoneNode other : nodes){
if(other.zone.requirements.contains(req -> req.zone() == node.zone)){ if(other.zone.requirements.contains(req -> req.zone() == node.zone)){
node.allChildren.add(other); node.allChildren.add(other);
} }
} }
} }
view.setOrigin(Align.center);
view.setTransform(true);
} }
boolean hidden(Zone zone){ boolean hidden(Zone zone){
@@ -167,7 +218,11 @@ public class DeployDialog extends FloatingDialog{
void buildButton(Zone zone, Button button){ void buildButton(Zone zone, Button button){
button.setDisabled(() -> hidden(zone)); button.setDisabled(() -> hidden(zone));
button.clicked(() -> info.show(zone)); button.clicked(() -> {
if(!view.moved){
info.show(zone);
}
});
if(zone.unlocked() && !hidden(zone)){ if(zone.unlocked() && !hidden(zone)){
button.labelWrap(zone.localizedName()).style(Styles.outlineLabel).width(140).growX().get().setAlignment(Align.center); button.labelWrap(zone.localizedName()).style(Styles.outlineLabel).width(140).growX().get().setAlignment(Align.center);
@@ -179,10 +234,9 @@ public class DeployDialog extends FloatingDialog{
} }
} }
//should be static variables of View, but that's impossible
static float panX = 0, panY = -200;
class View extends Group{ class View extends Group{
float panX = 0, panY = -200, lastZoom = -1;
boolean moved = false;
{ {
for(ZoneNode node : nodes){ for(ZoneNode node : nodes){
@@ -202,11 +256,7 @@ public class DeployDialog extends FloatingDialog{
addChild(stack); addChild(stack);
} }
dragged((x, y) -> { released(() -> moved = false);
panX += x;
panY += y;
clamp();
});
} }
void clamp(){ void clamp(){
@@ -222,9 +272,9 @@ public class DeployDialog extends FloatingDialog{
} }
@Override @Override
public void draw(){ public void drawChildren(){
clamp(); clamp();
float offsetX = panX + width / 2f + x, offsetY = panY + height / 2f + y; float offsetX = panX + width / 2f, offsetY = panY + height / 2f;
for(ZoneNode node : nodes){ for(ZoneNode node : nodes){
for(ZoneNode child : node.allChildren){ for(ZoneNode child : node.allChildren){
@@ -235,7 +285,7 @@ public class DeployDialog extends FloatingDialog{
} }
Draw.reset(); Draw.reset();
super.draw(); super.drawChildren();
} }
} }

View File

@@ -5,6 +5,7 @@ import io.anuke.arc.graphics.*;
import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.mindustry.*; import io.anuke.mindustry.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*; import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.ui.*; import io.anuke.mindustry.ui.*;
@@ -69,13 +70,19 @@ public class HostDialog extends FloatingDialog{
player.isAdmin = true; player.isAdmin = true;
if(steam){ if(steam){
Core.app.post(() -> Core.settings.getBoolOnce("steampublic", () -> { Core.app.post(() -> Core.settings.getBoolOnce("steampublic2", () -> {
ui.showCustomConfirm("$setting.publichost.name", "$public.confirm", "$yes", "$no", () -> { ui.showCustomConfirm("$setting.publichost.name", "$public.confirm", "$yes", "$no", () -> {
Core.settings.putSave("publichost", true); Core.settings.putSave("publichost", true);
platform.updateLobby(); platform.updateLobby();
}); });
})); }));
} }
if(Version.modifier.contains("beta")){
Core.settings.putSave("publichost", false);
platform.updateLobby();
Core.settings.getBoolOnce("betapublic", () -> ui.showInfo("$public.beta"));
}
}catch(IOException e){ }catch(IOException e){
ui.showException("$server.error", e); ui.showException("$server.error", e);
} }

View File

@@ -1,6 +1,7 @@
package io.anuke.mindustry.ui.dialogs; package io.anuke.mindustry.ui.dialogs;
import io.anuke.arc.Core; import io.anuke.arc.Core;
import io.anuke.arc.collection.*;
import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.*;
import io.anuke.arc.scene.ui.layout.Table; import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.arc.util.Log; import io.anuke.arc.util.Log;
@@ -14,6 +15,10 @@ import static io.anuke.mindustry.Vars.ui;
public class LanguageDialog extends FloatingDialog{ public class LanguageDialog extends FloatingDialog{
private Locale lastLocale; private Locale lastLocale;
private ObjectMap<Locale, String> displayNames = ObjectMap.of(
Locale.TRADITIONAL_CHINESE, "正體中文",
Locale.SIMPLIFIED_CHINESE, "简体中文"
);
public LanguageDialog(){ public LanguageDialog(){
super("$settings.language"); super("$settings.language");
@@ -30,7 +35,7 @@ public class LanguageDialog extends FloatingDialog{
ButtonGroup<TextButton> group = new ButtonGroup<>(); ButtonGroup<TextButton> group = new ButtonGroup<>();
for(Locale loc : locales){ for(Locale loc : locales){
TextButton button = new TextButton(Strings.capitalize(loc.getDisplayName(loc)), Styles.clearTogglet); TextButton button = new TextButton(Strings.capitalize(displayNames.get(loc, loc.getDisplayName(loc))), Styles.clearTogglet);
button.clicked(() -> { button.clicked(() -> {
if(getLocale().equals(loc)) return; if(getLocale().equals(loc)) return;
Core.settings.put("locale", loc.toString()); Core.settings.put("locale", loc.toString());

View File

@@ -4,7 +4,6 @@ import io.anuke.arc.*;
import io.anuke.arc.collection.*; import io.anuke.arc.collection.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.arc.util.io.*; import io.anuke.arc.util.io.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*; import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.mod.Mods.*; import io.anuke.mindustry.mod.Mods.*;
@@ -24,9 +23,35 @@ public class ModsDialog extends FloatingDialog{
() -> Core.net.openURI(reportIssueURL)) () -> Core.net.openURI(reportIssueURL))
.size(250f, 64f); .size(250f, 64f);
buttons.row();
buttons.addImageTextButton("$mods.guide", Icon.wiki, buttons.addImageTextButton("$mods.guide", Icon.wiki,
() -> Core.net.openURI(modGuideURL)) () -> Core.net.openURI(modGuideURL))
.size(280f, 64f); .size(210f, 64f);
buttons.addImageTextButton("$mod.import.github", Icon.github, () -> {
ui.showTextInput("$mod.import.github", "", "Anuken/ExampleMod", text -> {
ui.loadfrag.show();
Core.net.httpGet("http://api.github.com/repos/" + text + "/zipball/master", loc -> {
Core.net.httpGet(loc.getHeader("Location"), result -> {
try{
Streams.copyStream(result.getResultAsStream(), modDirectory.child(text.replace("/", "") + ".zip").write(false));
Core.app.post(() -> {
try{
mods.reloadContent();
setup();
ui.loadfrag.hide();
}catch(Exception e){
ui.showException(e);
}
});
}catch(Exception e){
ui.showException(e);
}
}, t -> Core.app.post(() -> ui.showException(t)));
}, t -> Core.app.post(() -> ui.showException(t)));
});
}).size(250f, 64f);
shown(this::setup); shown(this::setup);
@@ -120,27 +145,5 @@ public class ModsDialog extends FloatingDialog{
} }
}); });
}).margin(12f).width(500f); }).margin(12f).width(500f);
//not well tested currently
if(Version.build == -1){
cont.row();
cont.addImageTextButton("$mod.import.github", Icon.github, () -> {
ui.showTextInput("$mod.import.github", "", "Anuken/ExampleMod", text -> {
Core.net.httpGet("http://api.github.com/repos/" + text + "/zipball/master", loc -> {
Core.net.httpGet(loc.getHeader("Location"), result -> {
try{
Streams.copyStream(result.getResultAsStream(), modDirectory.child(text.replace("/", "") + ".zip").write(false));
ui.loadAnd(() -> {
mods.reloadContent();
});
}catch(Exception e){
ui.showException(e);
}
}, ui::showException);
}, ui::showException);
});
}).margin(12f).width(500f);
}
} }
} }

View File

@@ -14,6 +14,7 @@ import io.anuke.arc.scene.ui.TextButton.*;
import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.scene.ui.layout.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.core.GameState.*;
import io.anuke.mindustry.game.*;
import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.gen.*; import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.graphics.*;
@@ -225,7 +226,9 @@ public class SettingsMenuDialog extends SettingsDialog{
game.checkPref("savecreate", true); game.checkPref("savecreate", true);
if(steam){ game.checkPref("hints", true);
if(steam && !Version.modifier.contains("beta")){
game.checkPref("publichost", false, i -> { game.checkPref("publichost", false, i -> {
platform.updateLobby(); platform.updateLobby();
}); });
@@ -252,6 +255,7 @@ public class SettingsMenuDialog extends SettingsDialog{
}); });
graphics.sliderPref("fpscap", 240, 15, 245, 5, s -> (s > 240 ? Core.bundle.get("setting.fpscap.none") : Core.bundle.format("setting.fpscap.text", s))); graphics.sliderPref("fpscap", 240, 15, 245, 5, s -> (s > 240 ? Core.bundle.get("setting.fpscap.none") : Core.bundle.format("setting.fpscap.text", s)));
graphics.sliderPref("chatopacity", 100, 0, 100, 5, s -> s + "%"); graphics.sliderPref("chatopacity", 100, 0, 100, 5, s -> s + "%");
graphics.sliderPref("lasersopacity", 100, 0, 100, 5, s -> s + "%");
if(!mobile){ if(!mobile){
graphics.checkPref("vsync", true, b -> Core.graphics.setVSync(b)); graphics.checkPref("vsync", true, b -> Core.graphics.setVSync(b));
@@ -297,7 +301,6 @@ public class SettingsMenuDialog extends SettingsDialog{
graphics.checkPref("animatedshields", !mobile); graphics.checkPref("animatedshields", !mobile);
} }
graphics.checkPref("bloom", false, val -> renderer.toggleBloom(val)); graphics.checkPref("bloom", false, val -> renderer.toggleBloom(val));
graphics.checkPref("lasers", true);
graphics.checkPref("pixelate", false, val -> { graphics.checkPref("pixelate", false, val -> {
if(val){ if(val){
Events.fire(Trigger.enablePixelation); Events.fire(Trigger.enablePixelation);

View File

@@ -4,6 +4,7 @@ import io.anuke.arc.*;
import io.anuke.arc.collection.*; import io.anuke.arc.collection.*;
import io.anuke.arc.graphics.*; import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.input.*;
import io.anuke.arc.math.*; import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*; import io.anuke.arc.math.geom.*;
import io.anuke.arc.scene.*; import io.anuke.arc.scene.*;
@@ -21,7 +22,8 @@ import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.ui.*; import io.anuke.mindustry.ui.*;
import io.anuke.mindustry.ui.TreeLayout.*; import io.anuke.mindustry.ui.layout.*;
import io.anuke.mindustry.ui.layout.TreeLayout.*;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -31,13 +33,14 @@ public class TechTreeDialog extends FloatingDialog{
private TechTreeNode root = new TechTreeNode(TechTree.root, null); private TechTreeNode root = new TechTreeNode(TechTree.root, null);
private Rectangle bounds = new Rectangle(); private Rectangle bounds = new Rectangle();
private ItemsDisplay items; private ItemsDisplay items;
private View view;
public TechTreeDialog(){ public TechTreeDialog(){
super(""); super("");
titleTable.remove(); titleTable.remove();
margin(0f).marginBottom(8); margin(0f).marginBottom(8);
cont.stack(new View(), items = new ItemsDisplay()).grow(); cont.stack(view = new View(), items = new ItemsDisplay()).grow();
shown(() -> { shown(() -> {
checkNodes(root); checkNodes(root);
@@ -52,16 +55,57 @@ public class TechTreeDialog extends FloatingDialog{
hide(); hide();
ui.database.show(); ui.database.show();
}).size(210f, 64f); }).size(210f, 64f);
//scaling/drag input
addListener(new InputListener(){
@Override
public boolean scrolled(InputEvent event, float x, float y, float amountX, float amountY){
view.setScale(Mathf.clamp(view.getScaleX() - amountY / 40f, 0.25f, 1f));
view.setOrigin(Align.center);
view.setTransform(true);
return true;
}
@Override
public boolean mouseMoved(InputEvent event, float x, float y){
view.requestScroll();
return super.mouseMoved(event, x, y);
}
});
addListener(new ElementGestureListener(){
@Override
public void zoom(InputEvent event, float initialDistance, float distance){
if(view.lastZoom < 0){
view.lastZoom = view.getScaleX();
}
view.setScale(Mathf.clamp(distance / initialDistance * view.lastZoom, 0.25f, 1f));
view.setOrigin(Align.center);
view.setTransform(true);
}
@Override
public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){
view.lastZoom = view.getScaleX();
}
@Override
public void pan(InputEvent event, float x, float y, float deltaX, float deltaY){
view.panX += deltaX / view.getScaleX();
view.panY += deltaY / view.getScaleY();
view.moved = true;
view.clamp();
}
});
} }
void treeLayout(){ void treeLayout(){
TreeLayout layout = new TreeLayout(); RadialTreeLayout layout = new RadialTreeLayout();
layout.gapBetweenLevels = Scl.scl(60f);
layout.gapBetweenNodes = Scl.scl(40f);
LayoutNode node = new LayoutNode(root, null); LayoutNode node = new LayoutNode(root, null);
layout.layout(node); layout.layout(node);
bounds.set(layout.getBounds()); //bounds.y += nodeSize*1.5f;
bounds.y += nodeSize*1.5f;
copyInfo(node); copyInfo(node);
} }
@@ -110,7 +154,7 @@ public class TechTreeDialog extends FloatingDialog{
this.parent = parent; this.parent = parent;
this.width = this.height = nodeSize; this.width = this.height = nodeSize;
if(node.children != null){ if(node.children != null){
children = Array.with(node.children).select(n -> n.visible).map(t -> new LayoutNode(t, this)).toArray(LayoutNode.class); children = Array.with(node.children).map(t -> new LayoutNode(t, this)).toArray(LayoutNode.class);
} }
} }
} }
@@ -134,7 +178,7 @@ public class TechTreeDialog extends FloatingDialog{
} }
class View extends Group{ class View extends Group{
float panX = 0, panY = -200; float panX = 0, panY = -200, lastZoom = -1;
boolean moved = false; boolean moved = false;
ImageButton hoverNode; ImageButton hoverNode;
Table infoTable = new Table(); Table infoTable = new Table();
@@ -146,6 +190,8 @@ public class TechTreeDialog extends FloatingDialog{
ImageButton button = new ImageButton(node.node.block.icon(Cicon.medium), Styles.nodei); ImageButton button = new ImageButton(node.node.block.icon(Cicon.medium), Styles.nodei);
button.visible(() -> node.visible); button.visible(() -> node.visible);
button.clicked(() -> { button.clicked(() -> {
if(moved) return;
if(mobile){ if(mobile){
hoverNode = button; hoverNode = button;
rebuild(); rebuild();
@@ -182,7 +228,6 @@ public class TechTreeDialog extends FloatingDialog{
}); });
button.touchable(() -> !node.visible ? Touchable.disabled : Touchable.enabled); button.touchable(() -> !node.visible ? Touchable.disabled : Touchable.enabled);
button.setUserObject(node.node); button.setUserObject(node.node);
button.tapped(() -> moved = false);
button.setSize(nodeSize); button.setSize(nodeSize);
button.update(() -> { button.update(() -> {
float offset = (Core.graphics.getHeight() % 2) / 2f; float offset = (Core.graphics.getHeight() % 2) / 2f;
@@ -205,12 +250,9 @@ public class TechTreeDialog extends FloatingDialog{
}); });
} }
dragged((x, y) -> { setOrigin(Align.center);
moved = true; setTransform(true);
panX += x; released(() -> moved = false);
panY += y;
clamp();
});
} }
void clamp(){ void clamp(){
@@ -308,9 +350,9 @@ public class TechTreeDialog extends FloatingDialog{
} }
@Override @Override
public void draw(){ public void drawChildren(){
clamp(); clamp();
float offsetX = panX + width / 2f + x, offsetY = panY + height / 2f + y; float offsetX = panX + width / 2f, offsetY = panY + height / 2f;
for(TechTreeNode node : nodes){ for(TechTreeNode node : nodes){
if(!node.visible) continue; if(!node.visible) continue;
@@ -324,7 +366,7 @@ public class TechTreeDialog extends FloatingDialog{
} }
Draw.reset(); Draw.reset();
super.draw(); super.drawChildren();
} }
} }
} }

View File

@@ -51,6 +51,7 @@ public class HudFragment extends Fragment{
//menu at top left //menu at top left
parent.fill(cont -> { parent.fill(cont -> {
cont.setName("overlaymarker");
cont.top().left(); cont.top().left();
if(mobile){ if(mobile){

View File

@@ -1,11 +1,12 @@
package io.anuke.mindustry.ui.fragments; package io.anuke.mindustry.ui.fragments;
import io.anuke.arc.scene.Group; import io.anuke.arc.*;
import io.anuke.arc.scene.event.Touchable; import io.anuke.arc.scene.event.*;
import io.anuke.arc.scene.ui.layout.WidgetGroup; import io.anuke.arc.scene.ui.layout.*;
import io.anuke.mindustry.*;
/** Fragment for displaying overlays such as block inventories. */ /** Fragment for displaying overlays such as block inventories. */
public class OverlayFragment extends Fragment{ public class OverlayFragment{
public final BlockInventoryFragment inv; public final BlockInventoryFragment inv;
public final BlockConfigFragment config; public final BlockConfigFragment config;
@@ -17,10 +18,9 @@ public class OverlayFragment extends Fragment{
config = new BlockConfigFragment(); config = new BlockConfigFragment();
} }
@Override public void add(){
public void build(Group parent){
group.setFillParent(true); group.setFillParent(true);
parent.addChild(group); Vars.ui.hudGroup.addChildBefore(Core.scene.find("overlaymarker"), group);
inv.build(group); inv.build(group);
config.build(group); config.build(group);

View File

@@ -10,6 +10,8 @@ import io.anuke.arc.scene.event.*;
import io.anuke.arc.scene.style.*; import io.anuke.arc.scene.style.*;
import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.*;
import io.anuke.arc.scene.ui.layout.*; import io.anuke.arc.scene.ui.layout.*;
import io.anuke.arc.util.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.*; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.EventType.*;
@@ -17,7 +19,7 @@ import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.input.*; import io.anuke.mindustry.input.*;
import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.ui.Styles; import io.anuke.mindustry.ui.*;
import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.*;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -74,17 +76,21 @@ public class PlacementFragment extends Fragment{
boolean gridUpdate(InputHandler input){ boolean gridUpdate(InputHandler input){
if(Core.input.keyDown(Binding.pick)){ //mouse eyedropper select if(Core.input.keyDown(Binding.pick)){ //mouse eyedropper select
Tile tile = world.tileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y); Tile tile = world.ltileWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
Block tryRecipe = tile == null ? null : tile.block();
if(tile != null){ for(BuildRequest req : player.buildQueue()){
tile = tile.link(); if(!req.breaking && req.block.bounds(req.x, req.y, Tmp.r1).contains(Core.input.mouseWorld())){
Block tryRecipe = tile.block(); tryRecipe = req.block;
if(tryRecipe.isVisible() && unlocked(tryRecipe)){ break;
input.block = tryRecipe;
currentCategory = input.block.category;
return true;
} }
} }
if(tryRecipe != null && tryRecipe.isVisible() && unlocked(tryRecipe)){
input.block = tryRecipe;
currentCategory = input.block.category;
return true;
}
} }
if(!Core.input.keyDown(Binding.gridMode) || ui.chatfrag.chatOpen()) return false; if(!Core.input.keyDown(Binding.gridMode) || ui.chatfrag.chatOpen()) return false;
@@ -263,7 +269,7 @@ public class PlacementFragment extends Fragment{
blocksSelect.margin(4).marginTop(0); blocksSelect.margin(4).marginTop(0);
blocksSelect.table(blocks -> blockTable = blocks).grow(); blocksSelect.table(blocks -> blockTable = blocks).grow();
blocksSelect.row(); blocksSelect.row();
blocksSelect.table(control.input::buildUI).name("inputTable").growX(); blocksSelect.table(control.input::buildPlacementUI).name("inputTable").growX();
}).fillY().bottom().touchable(Touchable.enabled); }).fillY().bottom().touchable(Touchable.enabled);
frame.table(categories -> { frame.table(categories -> {
categories.defaults().size(50f); categories.defaults().size(50f);

View File

@@ -1,4 +1,4 @@
package io.anuke.mindustry.ui; package io.anuke.mindustry.ui.layout;
import io.anuke.arc.collection.*; import io.anuke.arc.collection.*;
import io.anuke.arc.math.geom.*; import io.anuke.arc.math.geom.*;
@@ -6,7 +6,7 @@ import io.anuke.arc.math.geom.*;
/** /**
* Algorithm taken from <a href="https://github.com/abego/treelayout">TreeLayout</a>. * Algorithm taken from <a href="https://github.com/abego/treelayout">TreeLayout</a>.
*/ */
public class TreeLayout{ public class BranchTreeLayout implements TreeLayout{
public TreeLocation rootLocation = TreeLocation.top; public TreeLocation rootLocation = TreeLocation.top;
public TreeAlignment alignment = TreeAlignment.awayFromRoot; public TreeAlignment alignment = TreeAlignment.awayFromRoot;
public float gapBetweenLevels = 10; public float gapBetweenLevels = 10;
@@ -18,6 +18,7 @@ public class TreeLayout{
private float boundsTop = Float.MAX_VALUE; private float boundsTop = Float.MAX_VALUE;
private float boundsBottom = Float.MIN_VALUE; private float boundsBottom = Float.MIN_VALUE;
@Override
public void layout(TreeNode root){ public void layout(TreeNode root){
firstWalk(root, null); firstWalk(root, null);
calcSizeOfLevels(root, 0); calcSizeOfLevels(root, 0);
@@ -288,20 +289,4 @@ public class TreeLayout{
public enum TreeAlignment{ public enum TreeAlignment{
center, towardsRoot, awayFromRoot center, towardsRoot, awayFromRoot
} }
public static class TreeNode<T extends TreeNode>{
public float width, height, x, y;
//should be initialized by user
public T[] children;
public T parent;
private float mode, prelim, change, shift;
private int number = -1;
private TreeNode thread, ancestor;
boolean isLeaf(){
return children == null || children.length == 0;
}
}
} }

View File

@@ -0,0 +1,66 @@
package io.anuke.mindustry.ui.layout;
import io.anuke.arc.collection.*;
import io.anuke.arc.math.*;
public class RadialTreeLayout implements TreeLayout{
private static ObjectSet<TreeNode> visited = new ObjectSet<>();
private static Queue<TreeNode> queue = new Queue<>();
public float startRadius, delta;
@Override
public void layout(TreeNode root){
startRadius = root.height * 2.4f;
delta = root.height * 2.4f;
bfs(root, true);
radialize(root, 0, 360);
}
void radialize(TreeNode root, float from, float to){
int depthOfVertex = root.number;
float theta = from;
float radius = startRadius + (delta * depthOfVertex);
int leavesNumber = bfs(root, false);
for(TreeNode child : root.children){
int lambda = bfs(child, false);
float mi = theta + ((float)lambda / leavesNumber * (to - from));
float x = radius * Mathf.cos((theta + mi) / 2f * Mathf.degRad);
float y = radius * Mathf.sin((theta + mi) / 2f * Mathf.degRad);
child.x = x;
child.y = y;
if(child.children.length > 0) radialize(child, theta, mi);
theta = mi;
}
}
int bfs(TreeNode node, boolean assign){
visited.clear();
queue.clear();
if(assign) node.number = 0;
int leaves = 0;
visited.add(node);
queue.addFirst(node);
while(!queue.isEmpty()){
TreeNode current = queue.removeFirst();
if(current.children.length == 0) leaves++;
for(TreeNode child : current.children){
if(assign) child.number = current.number + 1;
if(!visited.contains(child)){
visited.add(child);
queue.addLast(child);
}
}
}
return leaves;
}
}

View File

@@ -0,0 +1,22 @@
package io.anuke.mindustry.ui.layout;
public interface TreeLayout{
void layout(TreeNode root);
class TreeNode<T extends TreeNode>{
public float width, height, x, y;
//should be initialized by user
public T[] children;
public T parent;
//internal stuff
public float mode, prelim, change, shift;
public int number = -1;
public TreeNode thread, ancestor;
public boolean isLeaf(){
return children == null || children.length == 0;
}
}
}

View File

@@ -19,11 +19,11 @@ import io.anuke.arc.util.ArcAnnotate.*;
import io.anuke.arc.util.pooling.*; import io.anuke.arc.util.pooling.*;
import io.anuke.mindustry.entities.*; import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.effect.*; import io.anuke.mindustry.entities.effect.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.*; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*; import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.input.InputHandler.*;
import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.ui.*; import io.anuke.mindustry.ui.*;
import io.anuke.mindustry.world.blocks.*; import io.anuke.mindustry.world.blocks.*;
@@ -667,10 +667,19 @@ public class Block extends BlockStorage{
} }
} }
public void getPlaceDraw(PlaceDraw draw, int rotation, int prevX, int prevY, int prevRotation){ public void drawRequest(BuildRequest req, Eachable<BuildRequest> list, boolean valid){
draw.region = icon(Cicon.full); Draw.reset();
draw.scalex = draw.scaley = 1; Draw.mixcol(!valid ? Pal.breakInvalid : Color.white, (!valid ? 0.4f : 0.24f) + Mathf.absin(Time.globalTime(), 6f, 0.28f));
draw.rotation = rotation; Draw.alpha(1f);
drawRequestRegion(req, list);
Draw.reset();
}
public void drawRequestRegion(BuildRequest req, Eachable<BuildRequest> list){
TextureRegion reg = icon(Cicon.full);
Draw.rect(icon(Cicon.full), req.drawx(), req.drawy(),
reg.getWidth() * req.animScale * Draw.scl, reg.getHeight() * req.animScale * Draw.scl,
!rotate ? 0 : req.rotation * 90);
} }
@Override @Override
@@ -785,6 +794,10 @@ public class Block extends BlockStorage{
return ((size + 1) % 2) * tilesize / 2f; return ((size + 1) % 2) * tilesize / 2f;
} }
public Rectangle bounds(int x, int y, Rectangle rect){
return rect.setSize(size * tilesize).setCenter(x * tilesize + offset(), y * tilesize + offset());
}
public boolean isMultiblock(){ public boolean isMultiblock(){
return size > 1; return size > 1;
} }

View File

@@ -50,10 +50,14 @@ public class Edges{
} }
public static Tile getFacingEdge(Tile tile, Tile other){ public static Tile getFacingEdge(Tile tile, Tile other){
if(!tile.block().isMultiblock()) return tile; return getFacingEdge(tile.block, tile.x, tile.y, other);
int size = tile.block().size; }
return world.tile(tile.x + Mathf.clamp(other.x - tile.x, -(size - 1) / 2, (size / 2)),
tile.y + Mathf.clamp(other.y - tile.y, -(size - 1) / 2, (size / 2))); public static Tile getFacingEdge(Block block, int tilex, int tiley, Tile other){
if(!block.isMultiblock()) return world.tile(tilex, tiley);
int size = block.size;
return world.tile(tilex + Mathf.clamp(other.x - tilex, -(size - 1) / 2, (size / 2)),
tiley + Mathf.clamp(other.y - tiley, -(size - 1) / 2, (size / 2)));
} }
public static Vector2[] getPixelPolygon(float radius){ public static Vector2[] getPixelPolygon(float radius){

View File

@@ -0,0 +1,96 @@
package io.anuke.mindustry.world.blocks;
import io.anuke.arc.function.*;
import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.ArcAnnotate.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.world.*;
import java.util.*;
public interface Autotiler{
class AutotilerHolder{
static final int[] blendresult = new int[3];
static final BuildRequest[] directionals = new BuildRequest[4];
}
default @Nullable int[] getTiling(BuildRequest req, Eachable<BuildRequest> list){
if(req.tile() == null) return null;
BuildRequest[] directionals = AutotilerHolder.directionals;
Arrays.fill(directionals, null);
list.each(other -> {
if(other.breaking || other == req) return;
int i = 0;
for(Point2 point : Geometry.d4){
int x = req.x + point.x, y = req.y + point.y;
if(x >= other.x -(other.block.size - 1) / 2 && x <= other.x + (other.block.size / 2) && y >= other.y -(other.block.size - 1) / 2 && y <= other.y + (other.block.size / 2)){
directionals[i] = other;
}
i++;
}
});
return buildBlending(req.tile(), req.rotation, directionals);
}
default int[] buildBlending(Tile tile, int rotation, BuildRequest[] directional){
int[] blendresult = AutotilerHolder.blendresult;
blendresult[0] = 0;
blendresult[1] = blendresult[2] = 1;
int num =
(blends(tile, rotation, directional, 2) && blends(tile, rotation, directional, 1) && blends(tile, rotation, directional, 3)) ? 0 :
(blends(tile, rotation, directional, 1) && blends(tile, rotation, directional, 3)) ? 1 :
(blends(tile, rotation, directional, 1) && blends(tile, rotation, directional, 2)) ? 2 :
(blends(tile, rotation, directional, 3) && blends(tile, rotation, directional, 2)) ? 3 :
blends(tile, rotation, directional, 1) ? 4 :
blends(tile, rotation, directional, 3) ? 5 :
-1;
transformCase(num, blendresult);
return blendresult;
}
default void transformCase(int num, int[] bits){
if(num == 0){
bits[0] = 3;
}else if(num == 1){
bits[0] = 4;
}else if(num == 2){
bits[0] = 2;
}else if(num == 3){
bits[0] = 2;
bits[2] = -1;
}else if(num == 4){
bits[0] = 1;
bits[2] = -1;
}else if(num == 5){
bits[0] = 1;
}
}
default boolean blends(Tile tile, int rotation, @Nullable BuildRequest[] directional, int direction){
int realDir = Mathf.mod(rotation - direction, 4);
if(directional != null && directional[realDir] != null){
BuildRequest req = directional[realDir];
if(blends(tile, rotation, req.x, req.y, req.rotation, req.block)){
return true;
}
}
return blends(tile, rotation, direction);
}
default boolean blends(Tile tile, int rotation, int direction){
Tile other = tile.getNearby(Mathf.mod(rotation - direction, 4));
if(other != null) other = other.link();
return other != null && blends(tile, rotation, other.x, other.y, other.rotation(), other.block());
}
default boolean lookingAt(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
return (Point2.equals(tile.x + Geometry.d4(rotation).x, tile.y + Geometry.d4(rotation).y, otherx, othery)
|| (!otherblock.rotate || Point2.equals(otherx + Geometry.d4(otherrot).x, othery + Geometry.d4(otherrot).y, tile.x, tile.y)));
}
boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock);
}

View File

@@ -110,8 +110,8 @@ public class BuildBlock extends Block{
//if the target is constructible, begin constructing //if the target is constructible, begin constructing
if(entity.cblock != null){ if(entity.cblock != null){
player.clearBuilding(); //player.clearBuilding();
player.addBuildRequest(new BuildRequest(tile.x, tile.y, tile.rotation(), entity.cblock)); player.addBuildRequest(new BuildRequest(tile.x, tile.y, tile.rotation(), entity.cblock), false);
} }
} }

View File

@@ -94,6 +94,13 @@ public class Floor extends Block{
return; return;
} }
if(variants > 0){
for(int i = 0; i < variants; i++){
String rname = name + (i + 1);
editor.pack("editor-" + rname, Core.atlas.getPixmap(rname).crop());
}
}
Color color = new Color(); Color color = new Color();
Color color2 = new Color(); Color color2 = new Color();
PixmapRegion image = Core.atlas.getPixmap((AtlasRegion)generateIcons()[0]); PixmapRegion image = Core.atlas.getPixmap((AtlasRegion)generateIcons()[0]);
@@ -204,10 +211,6 @@ public class Floor extends Block{
return true; return true;
} }
boolean eq(int i){
return (eq & (1 << Mathf.mod(i, 8))) != 0;
}
TextureRegion edge(Floor block, int x, int y){ TextureRegion edge(Floor block, int x, int y){
return block.edges()[x][2 - y]; return block.edges()[x][2 - y];
} }

View File

@@ -23,19 +23,19 @@ public class OreBlock extends OverlayFloor{
/** For mod use only!*/ /** For mod use only!*/
public OreBlock(String name){ public OreBlock(String name){
super(name); super(name);
variants = 3;
} }
public void setup(Item ore){ public void setup(Item ore){
this.localizedName = ore.localizedName(); this.localizedName = ore.localizedName();
this.itemDrop = ore; this.itemDrop = ore;
this.variants = 3;
this.color.set(ore.color); this.color.set(ore.color);
} }
@Override @Override
@OverrideCallSuper @OverrideCallSuper
public void createIcons(PixmapPacker out, PixmapPacker editor){ public void createIcons(PixmapPacker out, PixmapPacker editor){
for(int i = 0; i < 3; i++){ for(int i = 0; i < variants; i++){
Pixmap image = new Pixmap(32, 32); Pixmap image = new Pixmap(32, 32);
PixmapRegion shadow = Core.atlas.getPixmap(itemDrop.name + (i + 1)); PixmapRegion shadow = Core.atlas.getPixmap(itemDrop.name + (i + 1));

View File

@@ -1,6 +1,6 @@
package io.anuke.mindustry.world.blocks.distribution; package io.anuke.mindustry.world.blocks.distribution;
import io.anuke.arc.math.*; import io.anuke.arc.math.geom.*;
import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.*;
@@ -16,11 +16,8 @@ public class ArmoredConveyor extends Conveyor{
} }
@Override @Override
protected boolean blends(Tile tile, int direction){ public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
Tile other = tile.getNearby(Mathf.mod(tile.rotation() - direction, 4)); return otherblock.outputsItems() && (Point2.equals(tile.x + Geometry.d4(rotation).x, tile.y + Geometry.d4(rotation).y, otherx, othery)
if(other != null) other = other.link(); || ((!otherblock.rotate && Edges.getFacingEdge(otherblock, otherx, othery, tile).relativeTo(tile) == tile.rotation()) || Point2.equals(otherx + Geometry.d4(otherrot).x, othery + Geometry.d4(otherrot).y, tile.x, tile.y)));
return other != null && other.block().outputsItems()
&& ((tile.getNearby(tile.rotation()) == other) || ((!other.block().rotate && Edges.getFacingEdge(other, tile).relativeTo(tile) == tile.rotation()) || (other.block().rotate && other.getNearby(other.rotation()) == tile)));
} }
} }

View File

@@ -1,16 +1,17 @@
package io.anuke.mindustry.world.blocks.distribution; package io.anuke.mindustry.world.blocks.distribution;
import io.anuke.arc.Core; import io.anuke.arc.*;
import io.anuke.arc.graphics.g2d.Draw; import io.anuke.arc.function.*;
import io.anuke.arc.graphics.g2d.TextureRegion; import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.Mathf; import io.anuke.arc.math.*;
import io.anuke.mindustry.entities.type.TileEntity; import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.blocks.LiquidBlock; import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.modules.LiquidModule; import io.anuke.mindustry.world.blocks.*;
import io.anuke.mindustry.world.modules.*;
public class Conduit extends LiquidBlock{ public class Conduit extends LiquidBlock implements Autotiler{
protected final int timerFlow = timers++; protected final int timerFlow = timers++;
protected TextureRegion[] topRegions = new TextureRegion[7]; protected TextureRegion[] topRegions = new TextureRegion[7];
@@ -39,29 +40,33 @@ public class Conduit extends LiquidBlock{
super.onProximityUpdate(tile); super.onProximityUpdate(tile);
ConduitEntity entity = tile.entity(); ConduitEntity entity = tile.entity();
entity.blendbits = 0; int[] bits = buildBlending(tile, tile.rotation(), null);
entity.blendrot = 0; entity.blendbits = bits[0];
if(blends(tile, 2) && blends(tile, 1) && blends(tile, 3)){
entity.blendbits = 3;
}else if(blends(tile, 1) && blends(tile, 3)){
entity.blendbits = 6;
}else if(blends(tile, 1) && blends(tile, 2)){
entity.blendbits = 2;
}else if(blends(tile, 3) && blends(tile, 2)){
entity.blendbits = 4;
}else if(blends(tile, 1)){
entity.blendbits = 5;
}else if(blends(tile, 3)){
entity.blendbits = 1;
}
} }
private boolean blends(Tile tile, int direction){ @Override
Tile other = tile.getNearby(Mathf.mod(tile.rotation() - direction, 4)); public void drawRequestRegion(BuildRequest req, Eachable<BuildRequest> list){
if(other != null) other = other.link(); int[] bits = getTiling(req, list);
return other != null && other.block().hasLiquids && other.block().outputsLiquid && ((tile.getNearby(tile.rotation()) == other) || (!other.block().rotate || other.getNearby(other.rotation()) == tile)); if(bits == null) return;
Draw.colorl(0.34f);
Draw.alpha(0.5f);
Draw.rect(botRegions[bits[0]], req.drawx(), req.drawy(), req.rotation * 90);
Draw.color();
Draw.rect(topRegions[bits[0]], req.drawx(), req.drawy(), req.rotation * 90);
}
@Override
public void transformCase(int num, int[] bits){
bits[0] = num == 0 ? 3 : num == 1 ? 6 : num == 2 ? 2 : num == 3 ? 4 : num == 4 ? 5 : num == 5 ? 1 : 0;
}
@Override
public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
return otherblock.hasLiquids && otherblock.outputsLiquid && lookingAt(tile, rotation, otherx, othery, otherrot, otherblock);
} }
@Override @Override
@@ -113,7 +118,6 @@ public class Conduit extends LiquidBlock{
public static class ConduitEntity extends TileEntity{ public static class ConduitEntity extends TileEntity{
public float smoothLiquid; public float smoothLiquid;
byte blendbits; int blendbits;
int blendrot;
} }
} }

View File

@@ -2,24 +2,26 @@ package io.anuke.mindustry.world.blocks.distribution;
import io.anuke.arc.*; import io.anuke.arc.*;
import io.anuke.arc.collection.*; import io.anuke.arc.collection.*;
import io.anuke.arc.function.*;
import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.*; import io.anuke.arc.math.*;
import io.anuke.arc.math.geom.*; import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.mindustry.entities.traits.BuilderTrait.*;
import io.anuke.mindustry.entities.type.*; import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.game.*; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.gen.*; import io.anuke.mindustry.gen.*;
import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.graphics.*;
import io.anuke.mindustry.input.InputHandler.*;
import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.*;
import io.anuke.mindustry.world.meta.*; import io.anuke.mindustry.world.meta.*;
import java.io.*; import java.io.*;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
public class Conveyor extends Block{ public class Conveyor extends Block implements Autotiler{
private static final float itemSpace = 0.4f; private static final float itemSpace = 0.4f;
private static final float minmove = 1f / (Short.MAX_VALUE - 2); private static final float minmove = 1f / (Short.MAX_VALUE - 2);
private static ItemPos drawpos = new ItemPos(); private static ItemPos drawpos = new ItemPos();
@@ -27,6 +29,8 @@ public class Conveyor extends Block{
private static ItemPos pos2 = new ItemPos(); private static ItemPos pos2 = new ItemPos();
private final Vector2 tr1 = new Vector2(); private final Vector2 tr1 = new Vector2();
private final Vector2 tr2 = new Vector2(); private final Vector2 tr2 = new Vector2();
private final int[] blendresult = new int[3];
private final BuildRequest[] directionals = new BuildRequest[4];
private TextureRegion[][] regions = new TextureRegion[7][4]; private TextureRegion[][] regions = new TextureRegion[7][4];
@@ -90,55 +94,25 @@ public class Conveyor extends Block{
super.onProximityUpdate(tile); super.onProximityUpdate(tile);
ConveyorEntity entity = tile.entity(); ConveyorEntity entity = tile.entity();
entity.blendbits = 0; int[] bits = buildBlending(tile, tile.rotation(), null);
entity.blendsclx = entity.blendscly = 1; entity.blendbits = bits[0];
entity.blendsclx = bits[1];
if(blends(tile, 2) && blends(tile, 1) && blends(tile, 3)){ entity.blendscly = bits[2];
entity.blendbits = 3;
}else if(blends(tile, 1) && blends(tile, 3)){
entity.blendbits = 4;
}else if(blends(tile, 1) && blends(tile, 2)){
entity.blendbits = 2;
}else if(blends(tile, 3) && blends(tile, 2)){
entity.blendbits = 2;
entity.blendscly = -1;
}else if(blends(tile, 1)){
entity.blendbits = 1;
entity.blendscly = -1;
}else if(blends(tile, 3)){
entity.blendbits = 1;
}
} }
@Override @Override
public void getPlaceDraw(PlaceDraw draw, int rotation, int prevX, int prevY, int prevRotation){ public void drawRequestRegion(BuildRequest req, Eachable<BuildRequest> list){
draw.rotation = rotation; int[] bits = getTiling(req, list);
draw.scalex = draw.scaley = 1;
int blendbits = 0; if(bits == null) return;
if(blends(rotation, 1, prevX, prevY, prevRotation)){ TextureRegion region = regions[bits[0]][0];
blendbits = 1; Draw.rect(region, req.drawx(), req.drawy(), region.getWidth() * bits[1] * Draw.scl, region.getHeight() * bits[2] * Draw.scl, req.rotation * 90);
draw.scaley = -1;
}else if(blends(rotation, 3, prevX, prevY, prevRotation)){
blendbits = 1;
}
draw.rotation = rotation;
draw.region = regions[blendbits][0];
} }
protected boolean blends(int rotation, int offset, int prevX, int prevY, int prevRotation){ @Override
Point2 left = Geometry.d4(rotation - offset); public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
return left.equals(prevX, prevY) && prevRotation == Mathf.mod(rotation + offset, 4); return otherblock.outputsItems() && lookingAt(tile, rotation, otherx, othery, otherrot, otherblock);
}
protected boolean blends(Tile tile, int direction){
Tile other = tile.getNearby(Mathf.mod(tile.rotation() - direction, 4));
if(other != null) other = other.link();
return other != null && other.block().outputsItems()
&& ((tile.getNearby(tile.rotation()) == other) || (!other.block().rotate || other.getNearby(other.rotation()) == tile));
} }
@Override @Override

View File

@@ -232,8 +232,8 @@ public class MassDriver extends Block{
int maxTransfer = Math.min(entity.items.get(content.item(i)), ((MassDriver)tile.block()).itemCapacity - totalUsed); int maxTransfer = Math.min(entity.items.get(content.item(i)), ((MassDriver)tile.block()).itemCapacity - totalUsed);
data.items[i] = maxTransfer; data.items[i] = maxTransfer;
totalUsed += maxTransfer; totalUsed += maxTransfer;
entity.items.remove(content.item(i), maxTransfer);
} }
entity.items.clear();
float angle = tile.angleTo(target); float angle = tile.angleTo(target);

View File

@@ -17,6 +17,7 @@ import static io.anuke.mindustry.Vars.content;
public class Sorter extends Block{ public class Sorter extends Block{
private static Item lastItem; private static Item lastItem;
protected boolean invert;
public Sorter(String name){ public Sorter(String name){
super(name); super(name);
@@ -40,16 +41,6 @@ public class Sorter extends Block{
} }
} }
/*
@Remote(targets = Loc.both, called = Loc.both, forward = true)
public static void setSorterItem(Player player, Tile tile, Item item){
if(!Units.canInteract(player, tile)) return;
SorterEntity entity = tile.entity();
if(entity != null){
entity.sortItem = item;
}
}*/
@Override @Override
public void configured(Tile tile, Player player, int value){ public void configured(Tile tile, Player player, int value){
tile.<SorterEntity>entity().sortItem = content.item(value); tile.<SorterEntity>entity().sortItem = content.item(value);
@@ -92,7 +83,7 @@ public class Sorter extends Block{
if(dir == -1) return null; if(dir == -1) return null;
Tile to; Tile to;
if(item == entity.sortItem){ if((item == entity.sortItem) != invert){
//prevent 3-chains //prevent 3-chains
if(isSame(dest, source) && isSame(dest, dest.getNearby(dir))){ if(isSame(dest, source) && isSame(dest, dest.getNearby(dir))){
return null; return null;
@@ -115,12 +106,10 @@ public class Sorter extends Block{
}else{ }else{
if(dest.rotation() == 0){ if(dest.rotation() == 0){
to = a; to = a;
if(flip) if(flip) dest.rotation((byte)1);
dest.rotation((byte)1);
}else{ }else{
to = b; to = b;
if(flip) if(flip) dest.rotation((byte)0);
dest.rotation((byte)0);
} }
} }
} }

View File

@@ -1,24 +1,20 @@
package io.anuke.mindustry.world.blocks.power; package io.anuke.mindustry.world.blocks.power;
import io.anuke.arc.Core; import io.anuke.arc.*;
import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.Draw; import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.graphics.g2d.TextureRegion; import io.anuke.arc.math.*;
import io.anuke.arc.math.Mathf; import io.anuke.arc.util.*;
import io.anuke.arc.util.Time; import io.anuke.mindustry.content.*;
import io.anuke.mindustry.content.Fx; import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.Effects; import io.anuke.mindustry.entities.Effects.*;
import io.anuke.mindustry.entities.type.TileEntity; import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.consumers.*;
import io.anuke.mindustry.world.consumers.ConsumeItemFilter; import io.anuke.mindustry.world.meta.*;
import io.anuke.mindustry.world.consumers.ConsumeLiquidFilter;
import io.anuke.mindustry.world.meta.BlockStat;
import io.anuke.mindustry.world.meta.StatUnit;
import static io.anuke.mindustry.Vars.content; import static io.anuke.mindustry.Vars.*;
import static io.anuke.mindustry.Vars.tilesize;
/** /**
* Power generation block which can use items, liquids or both as input sources for power production. * Power generation block which can use items, liquids or both as input sources for power production.
@@ -33,17 +29,26 @@ public class ItemLiquidGenerator extends PowerGenerator{
/** Maximum liquid used per frame. */ /** Maximum liquid used per frame. */
protected float maxLiquidGenerate = 0.4f; protected float maxLiquidGenerate = 0.4f;
protected Effects.Effect generateEffect = Fx.generatespark; protected Effect generateEffect = Fx.generatespark;
protected Effects.Effect explodeEffect = Fx.generatespark; protected Effect explodeEffect = Fx.generatespark;
protected Color heatColor = Color.valueOf("ff9b59"); protected Color heatColor = Color.valueOf("ff9b59");
protected TextureRegion topRegion, liquidRegion; protected TextureRegion topRegion, liquidRegion;
protected boolean randomlyExplode = true; protected boolean randomlyExplode = true;
protected boolean defaults = false;
public ItemLiquidGenerator(boolean hasItems, boolean hasLiquids, String name){ public ItemLiquidGenerator(boolean hasItems, boolean hasLiquids, String name){
super(name); super(name);
this.hasItems = hasItems; this.hasItems = hasItems;
this.hasLiquids = hasLiquids; this.hasLiquids = hasLiquids;
setDefaults();
}
public ItemLiquidGenerator(String name){
super(name);
}
protected void setDefaults(){
if(hasItems){ if(hasItems){
consumes.add(new ConsumeItemFilter(item -> getItemEfficiency(item) >= minItemEfficiency)).update(false).optional(true, false); consumes.add(new ConsumeItemFilter(item -> getItemEfficiency(item) >= minItemEfficiency)).update(false).optional(true, false);
} }
@@ -51,6 +56,16 @@ public class ItemLiquidGenerator extends PowerGenerator{
if(hasLiquids){ if(hasLiquids){
consumes.add(new ConsumeLiquidFilter(liquid -> getLiquidEfficiency(liquid) >= minLiquidEfficiency, maxLiquidGenerate)).update(false).optional(true, false); consumes.add(new ConsumeLiquidFilter(liquid -> getLiquidEfficiency(liquid) >= minLiquidEfficiency, maxLiquidGenerate)).update(false).optional(true, false);
} }
defaults = true;
}
@Override
public void init(){
if(!defaults){
setDefaults();
}
super.init();
} }
@Override @Override

View File

@@ -275,15 +275,18 @@ public class PowerNode extends PowerBlock{
@Override @Override
public void drawLayer(Tile tile){ public void drawLayer(Tile tile){
if(!Core.settings.getBool("lasers")) return; if(Core.settings.getInt("lasersopacity") == 0) return;
TileEntity entity = tile.entity(); TileEntity entity = tile.entity();
for(int i = 0; i < entity.power.links.size; i++){ for(int i = 0; i < entity.power.links.size; i++){
Tile link = world.tile(entity.power.links.get(i)); Tile link = world.tile(entity.power.links.get(i));
if(linkValid(tile, link) && (link.pos() < tile.pos() || !(link.block() instanceof PowerNode) || !Core.camera.bounds(Tmp.r1).contains(link.drawx(), link.drawy()))){
drawLaser(tile, link); if(!linkValid(tile, link)) continue;
}
if(link.block() instanceof PowerNode && !(link.pos() < tile.pos())) continue;
drawLaser(tile, link);
} }
Draw.reset(); Draw.reset();
@@ -318,6 +321,11 @@ public class PowerNode extends PowerBlock{
} }
protected void drawLaser(Tile tile, Tile target){ protected void drawLaser(Tile tile, Tile target){
int opacityPercentage = Core.settings.getInt("lasersopacity");
if(opacityPercentage == 0) return;
float opacity = opacityPercentage / 100f;
float x1 = tile.drawx(), y1 = tile.drawy(), float x1 = tile.drawx(), y1 = tile.drawy(),
x2 = target.drawx(), y2 = target.drawy(); x2 = target.drawx(), y2 = target.drawy();
@@ -333,7 +341,8 @@ public class PowerNode extends PowerBlock{
float fract = 1f-tile.entity.power.graph.getSatisfaction(); float fract = 1f-tile.entity.power.graph.getSatisfaction();
Draw.color(Color.white, Pal.powerLight, fract*0.86f + Mathf.absin(3f, 0.1f)); Draw.color(Color.white, Pal.powerLight, fract*0.86f + Mathf.absin(3f, 0.1f));
Drawf.laser(laser, laserEnd, x1, y1, x2, y2, 0.3f); Draw.alpha(opacity);
Drawf.laser(laser, laserEnd, x1, y1, x2, y2, 0.25f);
Draw.color(); Draw.color();
} }

View File

@@ -5,8 +5,9 @@ import io.anuke.mindustry.type.Liquid;
public class SingleTypeGenerator extends ItemLiquidGenerator{ public class SingleTypeGenerator extends ItemLiquidGenerator{
public SingleTypeGenerator(boolean hasItems, boolean hasLiquids, String name){ public SingleTypeGenerator(String name){
super(hasItems, hasLiquids, name); super(name);
defaults = true;
} }
@Override @Override

View File

@@ -3,7 +3,6 @@ package io.anuke.mindustry.world.blocks.storage;
import io.anuke.annotations.Annotations.*; import io.anuke.annotations.Annotations.*;
import io.anuke.arc.*; import io.anuke.arc.*;
import io.anuke.arc.collection.*; import io.anuke.arc.collection.*;
import io.anuke.arc.collection.ObjectSet.*;
import io.anuke.arc.function.*; import io.anuke.arc.function.*;
import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.*; import io.anuke.arc.math.*;
@@ -157,7 +156,7 @@ public class CoreBlock extends StorageBlock{
tile.entity.items.set(item, Math.min(tile.entity.items.get(item), max)); tile.entity.items.set(item, Math.min(tile.entity.items.get(item), max));
} }
for(Tile other : new ObjectSetIterator<>(state.teams.get(tile.getTeam()).cores)){ for(Tile other : state.teams.get(tile.getTeam()).cores){
other.block().onProximityUpdate(other); other.block().onProximityUpdate(other);
} }
} }

View File

@@ -15,6 +15,7 @@ import io.anuke.arc.scene.event.*;
import io.anuke.arc.scene.ui.*; import io.anuke.arc.scene.ui.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.arc.util.Log.*; import io.anuke.arc.util.Log.*;
import io.anuke.arc.util.io.*;
import io.anuke.arc.util.serialization.*; import io.anuke.arc.util.serialization.*;
import io.anuke.mindustry.*; import io.anuke.mindustry.*;
import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.core.GameState.*;
@@ -22,6 +23,7 @@ import io.anuke.mindustry.desktop.steam.*;
import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.game.Version; import io.anuke.mindustry.game.Version;
import io.anuke.mindustry.maps.Map; import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.mod.Mods.*;
import io.anuke.mindustry.net.*; import io.anuke.mindustry.net.*;
import io.anuke.mindustry.net.Net.*; import io.anuke.mindustry.net.Net.*;
import io.anuke.mindustry.ui.*; import io.anuke.mindustry.ui.*;
@@ -64,7 +66,7 @@ public class DesktopLauncher extends ClientLauncher{
public DesktopLauncher(String[] args){ public DesktopLauncher(String[] args){
Log.setUseColors(false); Log.setUseColors(false);
Version.init(); Version.init();
boolean useSteam = Version.modifier.equals("steam"); boolean useSteam = Version.modifier.contains("steam");
testMobile = Array.with(args).contains("-testMobile"); testMobile = Array.with(args).contains("-testMobile");
if(useDiscord){ if(useDiscord){
@@ -81,6 +83,14 @@ public class DesktopLauncher extends ClientLauncher{
} }
if(useSteam){ if(useSteam){
//delete leftover dlls
FileHandle file = new FileHandle(".");
for(FileHandle other : file.parent().list()){
if(other.name().contains("steam") && (other.extension().equals("dll") || other.extension().equals("so") || other.extension().equals("dylib"))){
other.delete();
}
}
if(showConsole){ if(showConsole){
StringBuilder base = new StringBuilder(); StringBuilder base = new StringBuilder();
Log.setLogger(new LogHandler(){ Log.setLogger(new LogHandler(){
@@ -129,7 +139,13 @@ public class DesktopLauncher extends ClientLauncher{
} }
try{ try{
SteamAPI.loadLibraries(); try{
SteamAPI.loadLibraries();
}catch(Throwable t){
Log.err(t);
fallbackSteam();
}
if(!SteamAPI.init()){ if(!SteamAPI.init()){
Log.err("Steam client not running."); Log.err("Steam client not running.");
}else{ }else{
@@ -144,6 +160,19 @@ public class DesktopLauncher extends ClientLauncher{
} }
} }
void fallbackSteam(){
try{
String name = "steam_api";
if(OS.isMac || OS.isLinux) name = "lib" + name;
if(OS.isWindows && OS.is64Bit) name += "64";
name += (OS.isLinux ? ".so" : OS.isMac ? ".dylib" : ".dll");
Streams.copyStream(getClass().getResourceAsStream(name), new FileOutputStream(name));
System.loadLibrary(new File(name).getAbsolutePath());
}catch(Throwable e){
Log.err(e);
}
}
void initSteam(String[] args){ void initSteam(String[] args){
SVars.net = new SNet(new ArcNetImpl()); SVars.net = new SNet(new ArcNetImpl());
SVars.stats = new SStats(); SVars.stats = new SStats();
@@ -209,7 +238,10 @@ public class DesktopLauncher extends ClientLauncher{
boolean fbgp = badGPU; boolean fbgp = badGPU;
CrashSender.send(e, file -> { CrashSender.send(e, file -> {
Throwable cause = Strings.getFinalCause(e); Array<Throwable> causes = Strings.getCauses(e);
Throwable fc = causes.find(t -> t instanceof ModLoadException);
if(fc == null) fc = Strings.getFinalCause(e);
Throwable cause = fc;
if(!fbgp){ if(!fbgp){
dialog.accept(() -> message("A crash has occured. It has been saved in:\n" + file.getAbsolutePath() + "\n" + cause.getClass().getSimpleName().replace("Exception", "") + (cause.getMessage() == null ? "" : ":\n" + cause.getMessage()))); dialog.accept(() -> message("A crash has occured. It has been saved in:\n" + file.getAbsolutePath() + "\n" + cause.getClass().getSimpleName().replace("Exception", "") + (cause.getMessage() == null ? "" : ":\n" + cause.getMessage())));
} }

View File

@@ -1,3 +1,3 @@
org.gradle.daemon=true org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m org.gradle.jvmargs=-Xms256m -Xmx1024m
archash=59cff366c4d46577b659e153183eb824eaafd7f7 archash=9ed2c7bd64741309e2ece3fdc15f169862922ef3

View File

@@ -1,7 +1,9 @@
import io.anuke.arc.collection.*; import io.anuke.arc.collection.*;
import io.anuke.arc.util.*; import io.anuke.arc.util.*;
import io.anuke.mindustry.core.*;
import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.core.GameState.*;
import io.anuke.mindustry.game.*; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.io.SaveIO.*;
import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.*; import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.storage.*; import io.anuke.mindustry.world.blocks.storage.*;
@@ -28,12 +30,18 @@ public class ZoneTests{
@TestFactory @TestFactory
DynamicTest[] testZoneValidity(){ DynamicTest[] testZoneValidity(){
Array<DynamicTest> out = new Array<>(); Array<DynamicTest> out = new Array<>();
if(world == null) world = new World();
for(Zone zone : content.zones()){ for(Zone zone : content.zones()){
out.add(dynamicTest(zone.name, () -> { out.add(dynamicTest(zone.name, () -> {
zone.generator.init(zone.loadout); zone.generator.init(zone.loadout);
logic.reset(); logic.reset();
world.loadGenerator(zone.generator); try{
world.loadGenerator(zone.generator);
}catch(SaveException e){
e.printStackTrace();
return;
}
zone.rules.accept(state.rules); zone.rules.accept(state.rules);
ObjectSet<Item> resources = new ObjectSet<>(); ObjectSet<Item> resources = new ObjectSet<>();
boolean hasSpawnPoint = false; boolean hasSpawnPoint = false;