Merge pull request #12 from Timmeey86/baltitenger

More power changes
This commit is contained in:
Baltazár Radics
2018-12-07 19:42:27 +01:00
committed by GitHub
83 changed files with 836 additions and 688 deletions

1
.gitignore vendored
View File

@@ -28,6 +28,7 @@ logs/
/ios/src/io/anuke/mindustry/gen/ /ios/src/io/anuke/mindustry/gen/
/core/src/io/anuke/mindustry/gen/ /core/src/io/anuke/mindustry/gen/
ios/robovm.properties ios/robovm.properties
config/
*.gif *.gif
version.properties version.properties

View File

@@ -20,11 +20,11 @@ allprojects {
ext { ext {
versionNumber = '4' versionNumber = '4'
versionModifier = 'alpha' versionModifier = 'alpha'
versionType = 'official' if (!project.hasProperty("versionType")) versionType = 'official'
appName = 'Mindustry' appName = 'Mindustry'
gdxVersion = '1.9.9' gdxVersion = '1.9.9'
roboVMVersion = '2.3.0' roboVMVersion = '2.3.0'
uCoreVersion = '3dfb820142a0fc583ad19413a24fc5038aa29d89' uCoreVersion = '5871d2d0385370bc937fed3e5e301d6962a50476'
getVersionString = { getVersionString = {
String buildVersion = getBuildVersion() String buildVersion = getBuildVersion()
@@ -104,17 +104,19 @@ project(":ios") {
apply plugin: "robovm" apply plugin: "robovm"
task copyGen{ task copyGen{
copy{ doLast {
from ("core/build/classes/java/main/io/anuke/mindustry/gen/"){ copy {
from("../core/build/classes/java/main/io/anuke/mindustry/gen/") {
include "**/*.java" include "**/*.java"
} }
into "core/src/io/anuke/mindustry/gen" into "../core/src/io/anuke/mindustry/gen"
}
} }
doFirst{ doFirst{
delete{ delete{
delete "core/src/io/anuke/mindustry/gen/" delete "../core/src/io/anuke/mindustry/gen/"
} }
} }
} }
@@ -132,7 +134,7 @@ project(":ios") {
props['app.mainclass'] = 'io.anuke.mindustry.IOSLauncher' props['app.mainclass'] = 'io.anuke.mindustry.IOSLauncher'
props['app.executable'] = 'IOSLauncher' props['app.executable'] = 'IOSLauncher'
props['app.name'] = 'Mindustry' props['app.name'] = 'Mindustry'
props['app.build'] = (!props.hasProperty("app.build") ? 40 : props['app.build'].toInteger() + 1)+"" props['app.build'] = (!props.containsKey("app.build") ? 40 : props['app.build'].toInteger() + 1)+""
props.store(vfile.newWriter(), null) props.store(vfile.newWriter(), null)
} }
@@ -148,7 +150,7 @@ project(":ios") {
compile "com.badlogicgames.gdx:gdx-backend-robovm:$gdxVersion" compile "com.badlogicgames.gdx:gdx-backend-robovm:$gdxVersion"
compile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-ios" compile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-ios"
compile "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-ios" compile "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-ios"
compileOnly project(":annotations") //compileOnly project(":annotations")
} }
} }

View File

@@ -133,7 +133,7 @@ text.confirmunban = Are you sure you want to unban this player?
text.confirmadmin = Are you sure you want to make this player an admin? text.confirmadmin = Are you sure you want to make this player an admin?
text.confirmunadmin = Are you sure you want to remove admin status from this player? text.confirmunadmin = Are you sure you want to remove admin status from this player?
text.joingame.title = Join Game text.joingame.title = Join Game
text.joingame.ip = IP: text.joingame.ip = Address:
text.disconnect = Disconnected. text.disconnect = Disconnected.
text.disconnect.data = Failed to load world data! text.disconnect.data = Failed to load world data!
text.connecting = [accent]Connecting... text.connecting = [accent]Connecting...
@@ -409,14 +409,16 @@ keybind.chat_scroll.name = Chat scroll
keybind.drop_unit.name = drop unit keybind.drop_unit.name = drop unit
keybind.zoom_minimap.name = Zoom minimap keybind.zoom_minimap.name = Zoom minimap
mode.text.help.title = Description of modes mode.text.help.title = Description of modes
mode.waves.name = waves mode.waves.name = Waves
mode.waves.description = the normal mode. limited resources and automatic incoming waves. mode.waves.description = The normal mode. Limited resources and automatic incoming waves.
mode.sandbox.name = sandbox mode.sandbox.name = Sandbox
mode.sandbox.description = infinite resources and no timer for waves. mode.sandbox.description = Infinite resources and no timer for waves.
mode.freebuild.name = freebuild mode.freebuild.name = Freebuild
mode.freebuild.description = limited resources and no timer for waves. mode.freebuild.description = Limited resources and no timer for waves.
mode.pvp.name = PvP mode.pvp.name = PvP
mode.pvp.description = fight against other players locally. mode.pvp.description = Fight against other players locally.
mode.attack.name = Attack
mode.attack.descrption = No waves, with the goal to destroy the enemy base.
content.item.name = Items content.item.name = Items
content.liquid.name = Liquids content.liquid.name = Liquids
content.unit.name = Units content.unit.name = Units

View File

@@ -349,6 +349,7 @@ text.category.items = Objets
text.category.crafting = Fabrication text.category.crafting = Fabrication
text.category.shooting = Défense text.category.shooting = Défense
text.category.optional = Améliorations facultatives text.category.optional = Améliorations facultatives
setting.indicators.name = Indicateurs d'alliés
setting.autotarget.name = Visée automatique setting.autotarget.name = Visée automatique
setting.fpscap.name = Max FPS setting.fpscap.name = Max FPS
setting.fpscap.none = Vide setting.fpscap.none = Vide
@@ -437,9 +438,9 @@ item.silicon.description = Un matériau semi-conducteur extrêmement utile, avec
item.plastanium.name = Plastanium item.plastanium.name = Plastanium
item.plastanium.description = Un matériau léger et docile utilisé dans l'aviation avancée et dans les munitions à fragmentation. item.plastanium.description = Un matériau léger et docile utilisé dans l'aviation avancée et dans les munitions à fragmentation.
item.phase-fabric.name = Phase Fabric item.phase-fabric.name = Phase Fabric
item.phase-fabric.description = A near-weightless substance used in advanced electronics and self-repairing technology. item.phase-fabric.description = Une substance presque en apesanteur utilisée dans l'électronique de pointe et la technologie autoréparable.
item.surge-alloy.name = Alliage superchargé item.surge-alloy.name = Alliage superchargé
item.surge-alloy.description = An advanced alloy with unique electrical properties. item.surge-alloy.description = Un alliage avancé aux propriétés électriques uniques.
item.biomatter.name = Biomasse item.biomatter.name = Biomasse
item.biomatter.description = Un mélange de matières organiques; utilisé pour la transformation en pétrole ou en tant que carburant de base. item.biomatter.description = Un mélange de matières organiques; utilisé pour la transformation en pétrole ou en tant que carburant de base.
item.sand.name = Sable item.sand.name = Sable
@@ -463,7 +464,7 @@ mech.delta-mech.description = Un mécha rapide avec une armure légère fait pou
mech.tau-mech.name = Tau mech.tau-mech.name = Tau
mech.tau-mech.weapon = Laser restructurant mech.tau-mech.weapon = Laser restructurant
mech.tau-mech.ability = Explosion réparante mech.tau-mech.ability = Explosion réparante
mech.tau-mech.description = Un mécha de support. Soigne les blocs alliés en tirant dessus. Il peut aussi éteindre les feux et soigner ses alliés en zone avec sa compétence. mech.tau-mech.description = Le support technique. Soigne les blocs alliés en leur tirant dessus. Peut soigner les alliés dans un rayon grâce à sa capacité de réparation.
mech.omega-mech.name = Omega mech.omega-mech.name = Omega
mech.omega-mech.weapon = Essaim de missiles auto-guidés mech.omega-mech.weapon = Essaim de missiles auto-guidés
mech.omega-mech.ability = Armure mech.omega-mech.ability = Armure

View File

@@ -2,15 +2,15 @@ text.credits.text = Created by [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[]\n\n[
text.credits = Creditos text.credits = Creditos
text.discord = Junte-se ao Discord do Mindustry! (Lá nós falamos em inglês) text.discord = Junte-se ao Discord do Mindustry! (Lá nós falamos em inglês)
text.link.discord.description = O discord oficial do Mindustry text.link.discord.description = O discord oficial do Mindustry
text.link.github.description = Game source code text.link.github.description = Codigo fonte do jogo.
text.link.dev-builds.description = Desenvolvimentos Instaveis text.link.dev-builds.description = Desenvolvimentos Instaveis
text.link.trello.description = Trello Oficial para Updates Planejados text.link.trello.description = Trello Oficial para Updates Planejados
text.link.itch.io.description = Pagina da Itch.io com os Downloads text.link.itch.io.description = Pagina da Itch.io com os Downloads
text.link.google-play.description = Google Play store listing text.link.google-play.description = Listamento do google play store
text.link.wiki.description = Wiki oficial do Mindustry text.link.wiki.description = Wiki oficial do Mindustry
text.linkfail = Falha ao abrir o link\nO Url foi copiado text.linkfail = Falha ao abrir o link\nO Url foi copiado
text.gameover = O núcleo foi destruído. text.gameover = O núcleo foi destruído.
text.gameover.pvp = The[accent] {0}[] team is victorious! text.gameover.pvp = O time[accent] {0}[] É vitorioso!
text.sector.gameover = Esse setor foi perdido! Soltar Novamente? text.sector.gameover = Esse setor foi perdido! Soltar Novamente?
text.sector.retry = Tentar novamente? text.sector.retry = Tentar novamente?
text.highscore = [YELLOW]Novo recorde! text.highscore = [YELLOW]Novo recorde!
@@ -20,11 +20,11 @@ text.level.delete.title = Confirmar exclusão
text.map.delete = Certeza que quer deletar o mapa "[accent]{0}[]"? text.map.delete = Certeza que quer deletar o mapa "[accent]{0}[]"?
text.level.select = Seleção de Fase text.level.select = Seleção de Fase
text.level.mode = Modo de Jogo: text.level.mode = Modo de Jogo:
text.construction.desktop = Desktop controls have been changed.\nTo deselect a block or stop building, [accent]use space[]. text.construction.desktop = Os controles do Desktop foram Mudados.\nPara descelecionar um bloco ou parar de construir, [accent]Use espaço.[].
text.construction.title = Guia de contrução de blocos text.construction.title = Guia de contrução de blocos
text.construction = You've just selected [accent]block construction mode[].\n\nTo begin placing, simply tap a valid location near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Shift the selection[] by holding and dragging any block in the selection.\n- [accent]Place blocks in a line[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel construction or selection[] by pressing the X at the bottom left. text.construction =Você selecionou [accent]Modo de construção de blocos[].\n\nPara começar a colocar, Simplesmente clique um lugar valido perto de sua nave.\nUma vez que você selecionou alguns blocos, Clique na caixa para confirmar, E sua nave vai começar a construi-los.\n\n- [accent]Remova blocos[] De sua seleção clicando neles.\n- [accent]Mude a seleção[] Segurando e arrastando qualquer bloco na seleção.\n- [accent]Coloque os blocos em linha[] Clicando e segurando em um lugar vazio e arrastando em uma direção.\n- [accent]Cancele a construção ou seleção[] Pressionando X no canto esquerdo.
text.deconstruction.title = Block Deconstruction Guide text.deconstruction.title = Block Deconstruction Guide
text.deconstruction = You've just selected [accent]block deconstruction mode[].\n\nTo begin breaking, simply tap a block near your ship.\nOnce you have selected some blocks, press the checkbox to confirm, and your ship will begin de-constructing them.\n\n- [accent]Remove blocks[] from your selection by tapping them.\n- [accent]Remove blocks in an area[] by tapping and holding an empty spot, then dragging in a direction.\n- [accent]Cancel deconstruction or selection[] by pressing the X at the bottom left. text.deconstruction = Você selecionou [accent]O modo de destruição de blocos[].\n\nPara Começar a quebrar, Simplesmente clique num bloco perto da nave.\nQuando tiver selecionados alguns blocos, Aperte a caixa para confirmar, E sua nave vai começar a construir.\n\n- [accent]Remova blocos[] De sua seleção clicando neles.\n- [accent]Remova blocos em uma area[] Clicando e Apertando um lugar vazio então arraste numa direção.\n- [accent]Cancele a construção ou Seleção[] Apertando X no canto Esquerdo.
text.showagain = Não mostrar na proxima sessão text.showagain = Não mostrar na proxima sessão
text.coreattack = < A base está sobre ataque! > text.coreattack = < A base está sobre ataque! >
text.unlocks = Desbloqueados text.unlocks = Desbloqueados
@@ -37,31 +37,31 @@ text.sectors = Setores
text.sector = Setor Selecionado: [LIGHT_GRAY]{0} text.sector = Setor Selecionado: [LIGHT_GRAY]{0}
text.sector.time = Tempo: [LIGHT_GRAY]{0} text.sector.time = Tempo: [LIGHT_GRAY]{0}
text.sector.deploy = Soltar text.sector.deploy = Soltar
text.sector.abandon = Abandon text.sector.abandon = Abandonar
text.sector.abandon.confirm = Are you sure you want to abandon all progress at this sector?\nThis cannot be undone! text.sector.abandon.confirm = Certeza que quer abandonar seu progresso nesse setor?\nThis cannot be undone!
text.sector.resume = Voltar text.sector.resume = Voltar
text.sector.locked = [scarlet][[Incomplete] text.sector.locked = [scarlet][[Não liberado]
text.sector.unexplored = [accent][[Unexplored] text.sector.unexplored = [accent][[Inexplorado]
text.missions = Missions:[LIGHT_GRAY] {0} text.missions = Missões:[LIGHT_GRAY] {0}
text.mission = Missão:[LIGHT_GRAY] {0} text.mission = Missão:[LIGHT_GRAY] {0}
text.mission.main = Main Mission:[LIGHT_GRAY] {0} text.mission.main = Missão principal:[LIGHT_GRAY] {0}
text.mission.info = Mission Info text.mission.info = Info da missão
text.mission.complete = Mission complete! text.mission.complete = Missão completa!
text.mission.complete.body = Sector {0},{1} has been conquered. text.mission.complete.body = Setor {0},{1} Foi conquistado.
text.mission.wave = Sobrevive [accent]{0}/{1}[] Onda\nOnda em {2} text.mission.wave = Sobrevive [accent]{0}/{1}[] Onda\nOnda em {2}
text.mission.wave.enemies = Survive[accent] {0}/{1} []waves\n{2} Enemies text.mission.wave.enemies = Sobreviva[accent] {0}/{1} []ondas\n{2} inimigos
text.mission.wave.enemy = Survive[accent] {0}/{1} []waves\n{2} Enemy text.mission.wave.enemy = Sobreviva[accent] {0}/{1} []Ondas\n{2} Inimigos
text.mission.wave.menu = Survive[accent] {0} []waves text.mission.wave.menu = Sobreviva[accent] {0} []Ondas
text.mission.battle = Destrua a base inimiga. text.mission.battle = Destrua a base inimiga.
text.mission.resource.menu = Obtain {0} x{1} text.mission.resource.menu = Obtenha {0} x{1}
text.mission.resource = Obtain {0}:\n[accent]{1}/{2}[] text.mission.resource = Obtenha {0}:\n[accent]{1}/{2}[]
text.mission.block = Create {0} text.mission.block = Criar {0}
text.mission.unit = Create {0} Unit text.mission.unit = Criar {0} Unidade
text.mission.command = Send Command {0} To Units text.mission.command = Enviar comando {0} As unidades
text.mission.linknode = Link Power Node text.mission.linknode = Ligar nodo de energia
text.mission.display = [accent]Mission:\n[LIGHT_GRAY]{0} text.mission.display = [accent]Missão:\n[LIGHT_GRAY]{0}
text.mission.mech = Switch to mech[accent] {0}[] text.mission.mech = Trocar para Meca[accent] {0}[]
text.mission.create = Create[accent] {0}[] text.mission.create = Criar[accent] {0}[]
text.none = <none> text.none = <none>
text.close = Fechar text.close = Fechar
text.quit = Sair text.quit = Sair
@@ -71,16 +71,16 @@ text.nextmission = Próxima Missão
text.maps.none = [LIGHT_GRAY]Nenhum Mapa Encontrado! text.maps.none = [LIGHT_GRAY]Nenhum Mapa Encontrado!
text.about.button = Sobre text.about.button = Sobre
text.name = Nome: text.name = Nome:
text.filename = File Name: text.filename = Nome do arquivo:
text.unlocked = Novo bloco Desbloqueado! text.unlocked = Novo bloco Desbloqueado!
text.unlocked.plural = Novos Blocos desbloqueados! text.unlocked.plural = Novos Blocos desbloqueados!
text.players = {0} Jogadores Ativos text.players = {0} Jogadores Ativos
text.players.single = {0} Jogador Ativo text.players.single = {0} Jogador Ativo
text.server.closing = [accent]Fechando servidor... text.server.closing = [accent]Fechando servidor...
text.server.kicked.kick = Voce foi expulso do servidor! text.server.kicked.kick = Voce foi expulso do servidor!
text.server.kicked.serverClose = Server closed. text.server.kicked.serverClose = Servidor Fechado.
text.server.kicked.sectorComplete = Sector completed. text.server.kicked.sectorComplete = Setor completo.
text.server.kicked.sectorComplete.text = Your mission is complete.\nThe server will now continue at the next sector. text.server.kicked.sectorComplete.text = Sua missão esta completa.\nO servidor vai continuar no proximo setor.
text.server.kicked.clientOutdated = Cliente desatualizado! Atualize seu jogo! text.server.kicked.clientOutdated = Cliente desatualizado! Atualize seu jogo!
text.server.kicked.serverOutdated = Servidor desatualiado! Peca ao dono para atualizar! text.server.kicked.serverOutdated = Servidor desatualiado! Peca ao dono para atualizar!
text.server.kicked.banned = Voce foi banido do servidor. text.server.kicked.banned = Voce foi banido do servidor.
@@ -90,9 +90,9 @@ text.server.kicked.nameEmpty = Voce deve ter pelo menos uma letra ou numero.
text.server.kicked.idInUse = Voce ja esta neste servidor! Conectar com duas contas não é permitido. text.server.kicked.idInUse = Voce ja esta neste servidor! Conectar com duas contas não é permitido.
text.server.kicked.customClient = Este servidor não suporta construções customizadas. Baixe a versão original. text.server.kicked.customClient = Este servidor não suporta construções customizadas. Baixe a versão original.
text.host.info = The [accent]Hospedar[]Botão Hopeda um servidor no Host[scarlet]6567[] e [scarlet]6568.[]\nQualquer um no [LIGHT_GRAY]Wi-fi Ou Internet local[] Pode ver este servidor na lista de servidores.\n\nSe voce quer poder entrar em qualquer servidor em seu ip, [accent]port forwarding[] é requerido.\n\n[LIGHT_GRAY]Note: Se alguem esta com problemas em conectar no seu servidor lan, Tenha certeza que deixou mindustry Acessar sua internet local nas configurações de firewall text.host.info = The [accent]Hospedar[]Botão Hopeda um servidor no Host[scarlet]6567[] e [scarlet]6568.[]\nQualquer um no [LIGHT_GRAY]Wi-fi Ou Internet local[] Pode ver este servidor na lista de servidores.\n\nSe voce quer poder entrar em qualquer servidor em seu ip, [accent]port forwarding[] é requerido.\n\n[LIGHT_GRAY]Note: Se alguem esta com problemas em conectar no seu servidor lan, Tenha certeza que deixou mindustry Acessar sua internet local nas configurações de firewall
text.join.info = Here, you can enter a [accent]server IP[] to connect to, or discover [accent]local network[] servers to connect to.\nBoth LAN and WAN multiplayer is supported.\n\n[LIGHT_GRAY]Note: There is no automatic global server list; if you want to connect to someone by IP, you would need to ask the host for their IP. text.join.info = Aqui, Você pode entar em um [accent]IP De servidor[] Para conectar, Ou descobrir [accent]Servidores[] Da rede local.\nAmbos os servidores LAN e WAN São suportados.\n\n[LIGHT_GRAY]Note: Não tem uma lista de servidores automaticos; Se você quer conectar ao IP de alguem, Você precisa pedir o IP Ao Rosteador.
text.hostserver = Hospedar servidor text.hostserver = Hospedar servidor
text.hostserver.mobile = Host\nGame text.hostserver.mobile = Hospedar\nJogo
text.host = Hospedar text.host = Hospedar
text.hosting = [accent]Abrindo server... text.hosting = [accent]Abrindo server...
text.hosts.refresh = atualizar text.hosts.refresh = atualizar
@@ -103,7 +103,7 @@ text.host.invalid = [scarlet]Não foi possivel Hospedar.
text.trace = Traçar jogador text.trace = Traçar jogador
text.trace.playername = Nome do jogador: [accent]{0} text.trace.playername = Nome do jogador: [accent]{0}
text.trace.ip = IP: [accent]{0} text.trace.ip = IP: [accent]{0}
text.trace.id = Unique ID: [accent]{0} text.trace.id = ID unico: [accent]{0}
text.trace.android = Cliente Androide: [accent]{0} text.trace.android = Cliente Androide: [accent]{0}
text.trace.modclient = Cliente Customizado: [accent]{0} text.trace.modclient = Cliente Customizado: [accent]{0}
text.trace.totalblocksbroken = Blocos totais quebrados: [accent]{0} text.trace.totalblocksbroken = Blocos totais quebrados: [accent]{0}
@@ -125,7 +125,7 @@ text.server.outdated.client = [crimson]Cliente desatualizado![]
text.server.version = [lightgray]Versão: {0} text.server.version = [lightgray]Versão: {0}
text.server.custombuild = [yellow]Construção customizada text.server.custombuild = [yellow]Construção customizada
text.confirmban = Certeza que quer banir este jogador? text.confirmban = Certeza que quer banir este jogador?
text.confirmkick = Are you sure you want to kick this player? text.confirmkick = Certeza que quer kickar o jogador?
text.confirmunban = Certeza que quer desbanir este jogador? text.confirmunban = Certeza que quer desbanir este jogador?
text.confirmadmin = Certeza que quer fazer este jogador um administrador? text.confirmadmin = Certeza que quer fazer este jogador um administrador?
text.confirmunadmin = Certeza que quer remover o estatus de adminstrador deste jogador? text.confirmunadmin = Certeza que quer remover o estatus de adminstrador deste jogador?
@@ -201,9 +201,9 @@ text.builtin = Built-In
text.map.delete.confirm = Certeza que quer deletar este mapa? Isto não pode ser desfeito! text.map.delete.confirm = Certeza que quer deletar este mapa? Isto não pode ser desfeito!
text.map.random = [accent]Mapa aleatório text.map.random = [accent]Mapa aleatório
text.map.nospawn = Esse mapa não contém um [yellow]core[] para o jogador Nascer! [ROYAL]blue[] Coloque um [yellow]core[] no editor de mapa. text.map.nospawn = Esse mapa não contém um [yellow]core[] para o jogador Nascer! [ROYAL]blue[] Coloque um [yellow]core[] no editor de mapa.
text.map.nospawn.pvp = This map does not have any enemy cores for player to spawn into! Add[SCARLET] red[] cores to this map in the editor. text.map.nospawn.pvp = Esse mapa não tem cores inimigos para os jogadores nascerem! Adicione[SCARLET] Cores vermelhos[] no mapa no editor.
text.map.invalid = Error loading map: corrupted or invalid map file. text.map.invalid = Erro ao carregar o mapa: Arquivo de mapa invalido ou corrupto.
text.editor.brush = Brush text.editor.brush = Pincel
text.editor.slope = \\ text.editor.slope = \\
text.editor.openin = Abrir no Editor text.editor.openin = Abrir no Editor
text.editor.oregen = Geração de minério text.editor.oregen = Geração de minério
@@ -260,13 +260,13 @@ text.editor = Editor
text.mapeditor = Editor de mapa text.mapeditor = Editor de mapa
text.donate = Doar text.donate = Doar
text.connectfail = [crimson]Falha ao entrar no servidor: [accent]{0} text.connectfail = [crimson]Falha ao entrar no servidor: [accent]{0}
text.error.unreachable = Server unreachable. text.error.unreachable = Servidor inalcançavel.
text.error.invalidaddress = Invalid address. text.error.invalidaddress = Endereço invalido.
text.error.timedout = Timed out!\nMake sure the host has port forwarding set up, and that the address is correct! text.error.timedout = Desconectado!\nTenha certeza que o Rosteador tenha feito Port forwading, E que o indereço esteja correto!
text.error.mismatch = Packet error:\npossible client/server version mismatch.\nMake sure you and the host have the latest version of Mindustry! text.error.mismatch = Erro de pacote:\nPossivel versão do cliente/Servidor incompatibilidade.\nTenha certeza que você e o host tenham a ultima versão!
text.error.alreadyconnected = Already connected. text.error.alreadyconnected = conectado.
text.error.mapnotfound = Map file not found! text.error.mapnotfound = Arquivo de mapa não encontrado!
text.error.any = Unkown network error. text.error.any = Erro de rede desconhecido.
text.settings.language = Linguagem text.settings.language = Linguagem
text.settings.reset = Restaurar Padrões text.settings.reset = Restaurar Padrões
text.settings.rebind = Religar text.settings.rebind = Religar
@@ -274,12 +274,12 @@ text.settings.controls = Controles
text.settings.game = Jogo text.settings.game = Jogo
text.settings.sound = Som text.settings.sound = Som
text.settings.graphics = Gráficos text.settings.graphics = Gráficos
text.settings.cleardata = Clear Game Data... text.settings.cleardata = Data do jogo limpa...
text.settings.clear.confirm = Are you sure you want to clear this data?\nWhat is done cannot be undone! text.settings.clear.confirm = Certeza que quer limpar a data?\nOque é feito não pode ser desfeito!
text.settings.clearall.confirm = [scarlet]WARNING![]\nThis will clear all data, including saves, maps, unlocks and keybinds.\nOnce you press 'ok' the game will wipe all data and automatically exit. text.settings.clearall.confirm = [scarlet]Aviso![]\nIsso vai limpar toda a data, Incluindo saves, mapas, Keybinds e desbloqueados.\nQuando apertar 'ok' Vai apagar toda a data e sair automaticamente.
text.settings.clearsectors = Clear Sectors text.settings.clearsectors = Limpar setores
text.settings.clearunlocks = Clear Unlocks text.settings.clearunlocks = Limpar liberados
text.settings.clearall = Clear All text.settings.clearall = Limpar tudo
text.paused = Pausado text.paused = Pausado
text.yes = Sim text.yes = Sim
text.no = Não text.no = Não
@@ -298,11 +298,11 @@ text.blocks.liquidcapacity = Capacidade de Líquido
text.blocks.maxitemssecond = Máximo de itens/segundo text.blocks.maxitemssecond = Máximo de itens/segundo
text.blocks.powerrange = Alcance da Energia text.blocks.powerrange = Alcance da Energia
text.blocks.poweruse = Uso de energia text.blocks.poweruse = Uso de energia
text.blocks.powerdamage = Power/Damage text.blocks.powerdamage = Dano/Poder
text.blocks.inputitemcapacity = Configurar capacidade de itens text.blocks.inputitemcapacity = Configurar capacidade de itens
text.blocks.outputitemcapacity = Configurar capacidade de itens text.blocks.outputitemcapacity = Configurar capacidade de itens
text.blocks.itemcapacity = Capacidade de Itens text.blocks.itemcapacity = Capacidade de Itens
text.blocks.basepowergeneration = Base Power Generation text.blocks.basepowergeneration = Geração de poder base
text.blocks.powertransferspeed = Transferência de energia text.blocks.powertransferspeed = Transferência de energia
text.blocks.craftspeed = Velocidade de produção text.blocks.craftspeed = Velocidade de produção
text.blocks.inputliquid = Líquido de entrada text.blocks.inputliquid = Líquido de entrada
@@ -313,14 +313,14 @@ text.blocks.outputitem = Itens de saida
text.blocks.drilltier = Furaveis text.blocks.drilltier = Furaveis
text.blocks.drillspeed = Velocidade da furadeira base text.blocks.drillspeed = Velocidade da furadeira base
text.blocks.liquidoutput = Saida de liquido text.blocks.liquidoutput = Saida de liquido
text.blocks.liquidoutputspeed = Liquid Output Speed text.blocks.liquidoutputspeed = Velocidade da saida de líquido
text.blocks.liquiduse = Uso de liquido text.blocks.liquiduse = Uso de liquido
text.blocks.coolant = Esfriador text.blocks.coolant = Esfriador
text.blocks.coolantuse = Uso do esfriador text.blocks.coolantuse = Uso do esfriador
text.blocks.inputliquidfuel = Liquido de combustivel text.blocks.inputliquidfuel = Liquido de combustivel
text.blocks.liquidfueluse = Uso do liquido de combustivel text.blocks.liquidfueluse = Uso do liquido de combustivel
text.blocks.boostitem = Boost Item text.blocks.boostitem = Acelerar item
text.blocks.boostliquid = Boost Liquid text.blocks.boostliquid = Acelerar líquido
text.blocks.health = Saúde text.blocks.health = Saúde
text.blocks.inaccuracy = Imprecisão text.blocks.inaccuracy = Imprecisão
text.blocks.shots = Tiros text.blocks.shots = Tiros
@@ -345,12 +345,12 @@ text.category.liquids = Liquidos
text.category.items = Itens text.category.items = Itens
text.category.crafting = Construindo text.category.crafting = Construindo
text.category.shooting = Atirando text.category.shooting = Atirando
text.category.optional = Optional Enhancements text.category.optional = Melhoras opcionais
setting.autotarget.name = Auto-Target setting.autotarget.name = Alvo automatico
setting.fpscap.name = FPS Maximo setting.fpscap.name = FPS Maximo
setting.fpscap.none = Nenhum setting.fpscap.none = Nenhum
setting.fpscap.text = {0} FPS setting.fpscap.text = {0} FPS
setting.difficulty.training = training setting.difficulty.training = treinamento
setting.difficulty.easy = Fácil setting.difficulty.easy = Fácil
setting.difficulty.normal = Normal setting.difficulty.normal = Normal
setting.difficulty.hard = Difícil setting.difficulty.hard = Difícil
@@ -370,21 +370,21 @@ setting.musicvol.name = Volume da Música
setting.mutemusic.name = Desligar Música setting.mutemusic.name = Desligar Música
setting.sfxvol.name = Volume de Efeitos setting.sfxvol.name = Volume de Efeitos
setting.mutesound.name = Desligar Som setting.mutesound.name = Desligar Som
setting.crashreport.name = Send Anonymous Crash Reports setting.crashreport.name = Enviar denuncias de crash anonimas
text.keybind.title = Refazer teclas text.keybind.title = Refazer teclas
category.general.name = General category.general.name = Geral
category.view.name = View category.view.name = Ver
category.multiplayer.name = Multiplayer category.multiplayer.name = Multijogador
command.attack = Attack command.attack = Atacar
command.retreat = Retreat command.retreat = Recuar
command.patrol = Patrol command.patrol = Patrulha
keybind.press = Press a key... keybind.press = Pressione uma tecla...
keybind.press.axis = Press an axis or key... keybind.press.axis = Pressione uma Axis ou tecla...
keybind.move_x.name = move_x keybind.move_x.name = mover_x
keybind.move_y.name = move_y keybind.move_y.name = mover_y
keybind.select.name = selecionar keybind.select.name = selecionar
keybind.break.name = quebrar keybind.break.name = quebrar
keybind.deselect.name = Deselect keybind.deselect.name = Deselecionar
keybind.shoot.name = Atirar keybind.shoot.name = Atirar
keybind.zoom_hold.name = segurar_zoom keybind.zoom_hold.name = segurar_zoom
keybind.zoom.name = zoom keybind.zoom.name = zoom
@@ -396,49 +396,49 @@ keybind.player_list.name = Lista_de_jogadores
keybind.console.name = console keybind.console.name = console
keybind.rotate.name = girar keybind.rotate.name = girar
keybind.toggle_menus.name = Toggle menus keybind.toggle_menus.name = Toggle menus
keybind.chat_history_prev.name = Chat history prev keybind.chat_history_prev.name = Historico do chat anterior
keybind.chat_history_next.name = Chat history next keybind.chat_history_next.name = Historico do proximo chat
keybind.chat_scroll.name = Chat scroll keybind.chat_scroll.name = Rolar chat
keybind.drop_unit.name = drop unit keybind.drop_unit.name = Soltar unidade
keybind.zoom_minimap.name = Zoom minimap keybind.zoom_minimap.name = Zoom minimap
mode.text.help.title = Descrição dos modos mode.text.help.title = Descrição dos modos
mode.waves.name = hordas mode.waves.name = hordas
mode.waves.description = O modo normal. Recursos limitados E os ataques vem automaticamente. mode.waves.description = O modo normal. Recursos limitados E os ataques vem automaticamente.
mode.sandbox.name = sandbox mode.sandbox.name = Caixa de areia
mode.sandbox.description = Recursos infinitos E sem tempo para Ataques. mode.sandbox.description = Recursos infinitos E sem tempo para Ataques.
mode.freebuild.name = construção \nlivre mode.freebuild.name = construção \nlivre
mode.freebuild.description = recursos limitados e Sem tempo para Ataques. mode.freebuild.description = recursos limitados e Sem tempo para Ataques.
mode.pvp.name = PvP mode.pvp.name = PvP
mode.pvp.description = fight against other players locally. mode.pvp.description = Lutar contra outros jogadores locais.
content.item.name = Itens content.item.name = Itens
content.liquid.name = Liquidos content.liquid.name = Liquidos
content.unit.name = Units content.unit.name = Units
content.recipe.name = Blocos content.recipe.name = Blocos
content.mech.name = Mechs content.mech.name = Mecas
item.stone.name = Pedra item.stone.name = Pedra
item.stone.description = Um Material Incomum Cru. Usado para separar e refinar Em outros materiais,Ou Derreter em Lava. item.stone.description = Um Material Incomum Cru. Usado para separar e refinar Em outros materiais,Ou Derreter em Lava.
item.copper.name = Cobre item.copper.name = Cobre
item.copper.description = A useful structure material. Used extensively in all types of blocks. item.copper.description = Um material de estrutura util. Usado extensivamente em Maioria dos blocos.
item.lead.name = Chumbo item.lead.name = Chumbo
item.lead.description = Material de comeco basico. usado intensivamente em Blocos de transporte de liquidos e eletronicos. item.lead.description = Material de comeco basico. usado intensivamente em Blocos de transporte de liquidos e eletronicos.
item.coal.name = Carvão item.coal.name = Carvão
item.coal.description = Combustivel pronto. item.coal.description = Combustivel pronto.
item.dense-alloy.name = Dense Alloy item.dense-alloy.name = Liga densa
item.dense-alloy.description = A tough alloy made with lead and copper. Used in advanced transportation blocks and high-tier drills. item.dense-alloy.description = Uma liga densa de chumbo e cobre. Usado na transportação de blocos e mineradoras de alto nivel.
item.titanium.name = Titânio item.titanium.name = Titânio
item.titanium.description = Um Material raro super leve, metal usado intensivamente na transportação de líquidos, Brocas e Aeronaves. item.titanium.description = Um Material raro super leve, metal usado intensivamente na transportação de líquidos, Brocas e Aeronaves.
item.thorium.name = Urânio item.thorium.name = Urânio
item.thorium.description = A dense, radioactive metal used as structural support and nuclear fuel. item.thorium.description = Um metal denso e radioativo, Usado como suporte material e combustivel nuclear.
item.silicon.name = Sílicio item.silicon.name = Sílicio
item.silicon.description = Condutor extremamente importante,Com aplicação em paneis solares e dispositivos complexos. item.silicon.description = Condutor extremamente importante,Com aplicação em paneis solares e dispositivos complexos.
item.plastanium.name = Plastanio item.plastanium.name = Plastanio
item.plastanium.description = Leve, Material dutil Usado em aeronaves Avançadas E munição de fragmentação. item.plastanium.description = Leve, Material dutil Usado em aeronaves Avançadas E munição de fragmentação.
item.phase-fabric.name = Phase Fabric item.phase-fabric.name = Fabrica fase
item.phase-fabric.description = A near-weightless substance used in advanced electronics and self-repairing technology. item.phase-fabric.description = Uma substancia quase sem peso Usado em eletronica avançada E tecnologia de auto-reparo.
item.surge-alloy.name = Liga de surto item.surge-alloy.name = Liga de surto
item.surge-alloy.description = An advanced alloy with unique electrical properties. item.surge-alloy.description = Uma liga com propriedades unicas eletricas.
item.biomatter.name = Biomateria item.biomatter.name = Biomateria
item.biomatter.description = A clump of organic mush; used for conversion into oil or as a basic fuel. item.biomatter.description = Um monte de materia organica; Usado na conversão de oleo Ou como oleo basico.
item.sand.name = Areia item.sand.name = Areia
item.sand.description = Um material comum Que é usado intensivamente em derretimento, Tanto em ligas como fluxo. item.sand.description = Um material comum Que é usado intensivamente em derretimento, Tanto em ligas como fluxo.
item.blast-compound.name = Composto de explosão item.blast-compound.name = Composto de explosão
@@ -449,54 +449,54 @@ liquid.water.name = Água
liquid.lava.name = Lava liquid.lava.name = Lava
liquid.oil.name = Petróleo liquid.oil.name = Petróleo
liquid.cryofluid.name = Crio Fluido liquid.cryofluid.name = Crio Fluido
mech.alpha-mech.name = Alpha mech.alpha-mech.name = Alfa
mech.alpha-mech.weapon = Heavy Repeater mech.alpha-mech.weapon = Repetidor pesado
mech.alpha-mech.ability = Drone Swarm mech.alpha-mech.ability = Onda de drones
mech.alpha-mech.description = The standard mech. Has decent speed and damage output; can create up to 3 drones for increased offensive capability. mech.alpha-mech.description = O meca padrão. Tem uma saida de dano e velocidade decente; Pode criar até 3 drones Para capacidades ofensivas aumentadas.
mech.delta-mech.name = Delta mech.delta-mech.name = Delta
mech.delta-mech.weapon = Arc Generator mech.delta-mech.weapon = Gerador Arc
mech.delta-mech.ability = Discharge mech.delta-mech.ability = Descarga
mech.delta-mech.description = A fast, lightly-armored mech made for hit-and-run attacks. Does little damage against structures, but can kill large groups of enemy units very quickly with its arc lightning weapons. mech.delta-mech.description = Um meca rapido, De baixa armadura Feito for para ataques rapidos. Da pouco dano as estruturas, Mas pode matar grandes grupos de unidades inimigas muito rapidamente Com sua arma ARC.
mech.tau-mech.name = Tau mech.tau-mech.name = Tau
mech.tau-mech.weapon = Restruct Laser mech.tau-mech.weapon = Laser restruturador
mech.tau-mech.ability = Repair Burst mech.tau-mech.ability = Tiro reparador
mech.tau-mech.description = The support mech. Heals allied blocks by shooting at them. Can extinguish fires and heal allies in a radius with its repair ability. mech.tau-mech.description = O meca de suporte. Conserta blocos aliados Atirando neles. Pode extinguir o fogo e consertar aliados em uma distancia Com sua habilidade de consertar.
mech.omega-mech.name = Omega mech.omega-mech.name = Omega
mech.omega-mech.weapon = Swarm Missiles mech.omega-mech.weapon = Onda de missies
mech.omega-mech.ability = Armored Configuration mech.omega-mech.ability = Configuração Armadurada
mech.omega-mech.description = A bulky and well-armored mech, made for front-line assaults. Its armor ability can block up to 90% of incoming damage. mech.omega-mech.description = Um meca volumoso e bem armadurado, Feito para assaltos da primeira linha. Sua habilidade de armadura Pode bloquear 90% de dano.
mech.dart-ship.name = Dart mech.dart-ship.name = Dardo
mech.dart-ship.weapon = Repeater mech.dart-ship.weapon = Repetidor
mech.dart-ship.description = The standard ship. Reasonably fast and light, but has little offensive capability and low mining speed. mech.dart-ship.description = Nave padrão. Consideravelmente leve e rapido, Tem pouca capacidade ofensiva E baixa velocidade de mineração.
mech.javelin-ship.name = Javelin mech.javelin-ship.name = Javelin
mech.javelin-ship.description = A hit-and-run strike ship. While initially slow, it can accelerate to great speeds and fly by enemy outposts, dealing large amounts of damage with its lightning ability and missiles. mech.javelin-ship.description = Uma nave de espinhos de atacar e correr. Quando inicialmente lento, pode acelerar a altas velocidades e voar até bases inimigas, Dando altas quantidades de dano Com seus raios e habilidades.
mech.javelin-ship.weapon = Burst Missiles mech.javelin-ship.weapon = Ondas de misseis
mech.javelin-ship.ability = Discharge Booster mech.javelin-ship.ability = Acelerador de explosão
mech.trident-ship.name = Trident mech.trident-ship.name = Tridente
mech.trident-ship.description = A heavy bomber. Reasonably well armored. mech.trident-ship.description = Um bombardeiro pesado. Consideravelmente bem armadurado.
mech.trident-ship.weapon = Bomb Bay mech.trident-ship.weapon = Carga de bombas
mech.glaive-ship.name = Glaive mech.glaive-ship.name = Glaive
mech.glaive-ship.description = A large, well-armored gunship. Equipped with an incendiary repeater. Good acceleration and maximum speed. mech.glaive-ship.description = Uma nave armada, bem armadurada. Com um repetidor incendario equipado. Boa aceleração e maxima velocidade.
mech.glaive-ship.weapon = Flame Repeater mech.glaive-ship.weapon = Repetidor de fogo
text.item.explosiveness = [LIGHT_GRAY]Explosividade: {0} text.item.explosiveness = [LIGHT_GRAY]Explosividade: {0}
text.item.flammability = [LIGHT_GRAY]Inflamabilidade: {0} text.item.flammability = [LIGHT_GRAY]Inflamabilidade: {0}
text.item.radioactivity = [LIGHT_GRAY]RadioAtividade: {0} text.item.radioactivity = [LIGHT_GRAY]RadioAtividade: {0}
text.item.fluxiness = [LIGHT_GRAY]Poder do fluxo: {0} text.item.fluxiness = [LIGHT_GRAY]Poder do fluxo: {0}
text.unit.health = [LIGHT_GRAY]Health: {0} text.unit.health = [LIGHT_GRAY]Vida: {0}
text.unit.speed = [LIGHT_GRAY]Speed: {0} text.unit.speed = [LIGHT_GRAY]Velocidade: {0}
text.mech.weapon = [LIGHT_GRAY]Weapon: {0} text.mech.weapon = [LIGHT_GRAY]Arma: {0}
text.mech.armor = [LIGHT_GRAY]Armor: {0} text.mech.armor = [LIGHT_GRAY]Armadura: {0}
text.mech.itemcapacity = [LIGHT_GRAY]Item Capacity: {0} text.mech.itemcapacity = [LIGHT_GRAY]Capacidade de itens: {0}
text.mech.minespeed = [LIGHT_GRAY]Mining Speed: {0} text.mech.minespeed = [LIGHT_GRAY]Velocidade de mineração: {0}
text.mech.minepower = [LIGHT_GRAY]Mining Power: {0} text.mech.minepower = [LIGHT_GRAY]Poder de mineração: {0}
text.mech.ability = [LIGHT_GRAY]Ability: {0} text.mech.ability = [LIGHT_GRAY]Habilidade: {0}
text.liquid.heatcapacity = [LIGHT_GRAY]Capacidade de aquecimento: {0} text.liquid.heatcapacity = [LIGHT_GRAY]Capacidade de aquecimento: {0}
text.liquid.viscosity = [LIGHT_GRAY]Viscosidade: {0} text.liquid.viscosity = [LIGHT_GRAY]Viscosidade: {0}
text.liquid.temperature = [LIGHT_GRAY]Temperatura: {0} text.liquid.temperature = [LIGHT_GRAY]Temperatura: {0}
block.constructing = {0}\n[LIGHT_GRAY](Constructing) block.constructing = {0}\n[LIGHT_GRAY](Construindo)
block.spawn.name = Enemy Spawn block.spawn.name = Spawn dos inimigos
block.core.name = Core block.core.name = Core
block.metalfloor.name = Metal Floor block.metalfloor.name = Chão de metal
block.deepwater.name = água funda block.deepwater.name = água funda
block.water.name = água block.water.name = água
block.lava.name = lava block.lava.name = lava
@@ -508,24 +508,24 @@ block.sand.name = areia
block.ice.name = gelo block.ice.name = gelo
block.snow.name = neve block.snow.name = neve
block.grass.name = grama block.grass.name = grama
block.shrub.name = shrub block.shrub.name = Arbusto
block.rock.name = rocha block.rock.name = rocha
block.blackrock.name = rocha negra block.blackrock.name = rocha negra
block.icerock.name = rocha de gelo block.icerock.name = rocha de gelo
block.copper-wall.name = Parede de Cobre block.copper-wall.name = Parede de Cobre
block.copper-wall-large.name = Parede de Cobre Grande block.copper-wall-large.name = Parede de Cobre Grande
block.dense-alloy-wall.name = Dense Alloy Wall block.dense-alloy-wall.name = Parede de liga densa
block.dense-alloy-wall-large.name = Large Dense Alloy Wall block.dense-alloy-wall-large.name = Parede de liga densa grande
block.phase-wall.name = Phase Wall block.phase-wall.name = Parede de fase
block.phase-wall-large.name = Large Phase Wall block.phase-wall-large.name = Parde de fase grande
block.thorium-wall.name = Parede de tório block.thorium-wall.name = Parede de tório
block.thorium-wall-large.name = Parede larga de tório block.thorium-wall-large.name = Parede larga de tório
block.door.name = Porta block.door.name = Porta
block.door-large.name = Porta Grande block.door-large.name = Porta Grande
block.duo.name = Duplo block.duo.name = Dupla
block.scorch.name = Quimar block.scorch.name = Queimar
block.hail.name = Hail block.hail.name = Hail
block.lancer.name = Lancer block.lancer.name = Lancador
block.conveyor.name = Esteira block.conveyor.name = Esteira
block.titanium-conveyor.name = Esteira de Titanio block.titanium-conveyor.name = Esteira de Titanio
block.junction.name = Junção block.junction.name = Junção
@@ -553,21 +553,21 @@ block.battery-large.name = Bateria Grande
block.combustion-generator.name = Gerador de combustão block.combustion-generator.name = Gerador de combustão
block.turbine-generator.name = Gerador de Turbina block.turbine-generator.name = Gerador de Turbina
block.mechanical-drill.name = Furadera Mecânica block.mechanical-drill.name = Furadera Mecânica
block.pneumatic-drill.name = Pneumatic Drill block.pneumatic-drill.name = Mineradora Pneumatica
block.laser-drill.name = Broca a Laser block.laser-drill.name = Broca a Laser
block.water-extractor.name = Extrator de Agua block.water-extractor.name = Extrator de Agua
block.cultivator.name = Cultivador block.cultivator.name = Cultivador
block.alpha-mech-pad.name = Alpha Mech Pad block.alpha-mech-pad.name = Controle do meca Alfa
block.dart-ship-pad.name = Dart Ship Pad block.dart-ship-pad.name = Controle do meca Dart
block.delta-mech-pad.name = Delta Mech Pad block.delta-mech-pad.name = Controle do meca Delta
block.javelin-ship-pad.name = Javelin Ship Pad block.javelin-ship-pad.name = Controle do meca Javelin
block.trident-ship-pad.name = Trident Ship Pad block.trident-ship-pad.name = Controle do meca Tridente
block.glaive-ship-pad.name = Glaive Ship Pad block.glaive-ship-pad.name = Controle do meca Glaive
block.omega-mech-pad.name = Omega Mech Pad block.omega-mech-pad.name = Controle do meca Omega
block.tau-mech-pad.name = Tau Mech Pad block.tau-mech-pad.name = Controle do meca Tau
block.conduit.name = Cano block.conduit.name = Cano
block.mechanical-pump.name = Bomba Mecanica block.mechanical-pump.name = Bomba Mecanica
block.itemsource.name = Item Source block.itemsource.name = Fonte do item
block.itemvoid.name = Item Void block.itemvoid.name = Item Void
block.liquidsource.name = Liquid Source block.liquidsource.name = Liquid Source
block.powervoid.name = Power Void block.powervoid.name = Power Void
@@ -582,19 +582,19 @@ block.phase-conveyor.name = Esteira de Fases
block.bridge-conveyor.name = Esteira-Ponte block.bridge-conveyor.name = Esteira-Ponte
block.plastanium-compressor.name = Compressor de Plastanio block.plastanium-compressor.name = Compressor de Plastanio
block.pyratite-mixer.name = Misturador de Piratita block.pyratite-mixer.name = Misturador de Piratita
block.blast-mixer.name = Blast Mixer block.blast-mixer.name = Misturador de Explosão
block.solidifer.name = Solidificador block.solidifer.name = Solidificador
block.solar-panel.name = Painel Solar block.solar-panel.name = Painel Solar
block.solar-panel-large.name = Painel Solar Grande block.solar-panel-large.name = Painel Solar Grande
block.oil-extractor.name = Extrator de Oleo block.oil-extractor.name = Extrator de Oleo
block.spirit-factory.name = Spirit Drone Factory block.spirit-factory.name = Fabrica de Drone Spirit
block.phantom-factory.name = Phantom Drone Factory block.phantom-factory.name = Fabrica de Drone Phantom
block.wraith-factory.name = Wraith Fighter Factory block.wraith-factory.name = Fabrica de Drone Wraith
block.ghoul-factory.name = Ghoul Bomber Factory block.ghoul-factory.name = Fabrica de Bombardeiro Ghoul
block.dagger-factory.name = Dagger Mech Factory block.dagger-factory.name = Fabrica de meca Dagger
block.titan-factory.name = Titan Mech Factory block.titan-factory.name = Fabrica de meca titan
block.fortress-factory.name = Fortress Mech Factory block.fortress-factory.name = Fabrica de meca Fortress
block.revenant-factory.name = Revenant Fighter Factory block.revenant-factory.name = Fabrica de lutadores Revenant
block.repair-point.name = Ponto de Reparo block.repair-point.name = Ponto de Reparo
block.pulse-conduit.name = Conduto de Pulso block.pulse-conduit.name = Conduto de Pulso
block.phase-conduit.name = Conduto de Fase block.phase-conduit.name = Conduto de Fase
@@ -603,178 +603,178 @@ block.liquid-tank.name = Tanque de Líquido
block.liquid-junction.name = Junção de Líquido block.liquid-junction.name = Junção de Líquido
block.bridge-conduit.name = Conduto-Ponte block.bridge-conduit.name = Conduto-Ponte
block.rotary-pump.name = Bomba Rotatoria block.rotary-pump.name = Bomba Rotatoria
block.thorium-reactor.name = Thorium Reactor block.thorium-reactor.name = Reator Torio
block.command-center.name = Centro De Comando block.command-center.name = Centro De Comando
block.mass-driver.name = Mass Driver block.mass-driver.name = Drive de Massa
block.blast-drill.name = Blast Drill block.blast-drill.name = Mineradora de Explosão
block.thermal-pump.name = Thermal Pump block.thermal-pump.name = Cano termico
block.thermal-generator.name = Gerador Térmico block.thermal-generator.name = Gerador Térmico
block.alloy-smelter.name = Alloy Smtler block.alloy-smelter.name = Fundidora de Liga
block.mend-projector.name = Mend Projector block.mend-projector.name = Projetor Mend
block.surge-wall.name = Surge Wall block.surge-wall.name = Parede de Surge
block.surge-wall-large.name = Large Surge Wall block.surge-wall-large.name = Parede de surge grande
block.cyclone.name = Cyclone block.cyclone.name = Ciclone
block.fuse.name = Fuse block.fuse.name = Fundir
block.shock-mine.name = Shock Mine block.shock-mine.name = Mina de Choque
block.overdrive-projector.name = Overdrive Projector block.overdrive-projector.name = Projetor Overdrive
block.force-projector.name = Force Projector block.force-projector.name = Projetor Force
block.arc.name = Arc block.arc.name = Arc
block.rtg-generator.name = RTG Generator block.rtg-generator.name = Gerador RTG
block.spectre.name = Spectre block.spectre.name = Espectra
block.meltdown.name = Meltdown block.meltdown.name = Derreter
block.container.name = Container block.container.name = Container
block.core.description = The most important building in the game. block.core.description = A mais importante construção do jogo.
team.blue.name = blue team.blue.name = Azul
team.red.name = red team.red.name = Vermelho
team.orange.name = orange team.orange.name = Laranja
team.none.name = gray team.none.name = Cinza
team.green.name = green team.green.name = Verde
team.purple.name = purple team.purple.name = Roxo
unit.alpha-drone.name = Alpha Drone unit.alpha-drone.name = Drone alfa
unit.spirit.name = Spirit Drone unit.spirit.name = Drone Spirit
unit.spirit.description = The starter drone unit. Spawns in the core by default. Automatically mines ores, collects items and repairs blocks. unit.spirit.description = A unidade de drone inicial. Ele nasce no core por padrão. Minera minérios automaticamente, Coleta itens e repara blocos.
unit.phantom.name = Phantom Drone unit.phantom.name = Drone Phantom
unit.phantom.description = An advanced drone unit. Automatically mines ores, collects items and repairs blocks. Significantly more effective than a drone. unit.phantom.description = Uma unidade de drone avançada. Minera minérios automaticamente, Coleta itens e repara blocos automaticamente. Significantemente mais efetiva.
unit.dagger.name = Dagger unit.dagger.name = Dagger
unit.dagger.description = A basic ground unit. Useful in swarms. unit.dagger.description = Unidade terrestre basica, Forte em grupos.
unit.titan.name = Titan unit.titan.name = Titan
unit.titan.description = An advanced armored ground unit. Uses carbide as ammo. Attacks both ground and air targets. unit.titan.description = Uma unidade armadurada terreste avancada. Usa carbide como munição. Ataca ambas as unidades de Aereas e terrestres.
unit.ghoul.name = Ghoul Bomber unit.ghoul.name = Bombardeiro Ghoul
unit.ghoul.description = A heavy carpet bomber. Uses blast compound or pyratite as ammo. unit.ghoul.description = Um bombardeiro pesado. Usa composto de explosão Ou piratite como munição.
unit.wraith.name = Wraith Fighter unit.wraith.name = Lutador Wraith
unit.wraith.description = A fast, hit-and-run interceptor unit. unit.wraith.description = Uma unidade rapida, Interceptadora de bater e correr.
unit.fortress.name = Fortress unit.fortress.name = Fortaleza
unit.fortress.description = A heavy artillery ground unit. unit.fortress.description = Uma unidade pesada de artilharia terrestre.
unit.revenant.name = Revenant unit.revenant.name = Revenant
unit.revenant.description = A heavy laser platform. unit.revenant.description = Uma plataforma de laser pesada.
tutorial.begin = Your mission here is to eradicate the[LIGHT_GRAY] enemy[].\n\nBegin by[accent] mining copper[]. Tap a copper ore vein near your core to do this. tutorial.begin = Sua missão aqui é de erradicar[LIGHT_GRAY] Inimigo[].\n\nComeçe por[accent] Minerar cobre[]. Clique numa veia de cobre perto de seu core para fazer isso.
tutorial.drill = Mining manually is inefficient.\n[accent]Drills []can mine automatically.\nPlace one on a copper vein. tutorial.drill = Minerar manualmente é ineficiente.\n[accent]Mineradoras []podem minerar automaticamente.\nColoque uma numa veia de cobre.
tutorial.conveyor = [accent]Conveyors[] are used to transport items to the core.\nMake a line of conveyors from the drill to the core. tutorial.conveyor = [accent]Esteiras[] São usadas para transportar itens até o core.\nFaça uma linha de Esteiras da mineradora até o core.
tutorial.morecopper = More copper is required.\n\nEither mine it manually, or place more drills. tutorial.morecopper = Mais cobre é preciso.\n\nTanto minere manualmente, Ou coloque mais mineradoras.
tutorial.turret = Defensive structures must be built to repel the[LIGHT_GRAY] enemy[].\nBuild a duo turret near your base. tutorial.turret = Estruturas defensivas devem ser construidas para repelir[LIGHT_GRAY] O inimigo[].\nConstrua uma torre dupla perto de sua base.
tutorial.drillturret = Duo turrets require[accent] copper ammo []to shoot.\nPlace a drill next to the turret to supply it with mined copper. tutorial.drillturret = Torres duplas precisam de[accent] Cobre como munição []Para atirar.\nColoque uma mineradoura Proxima a torre Para carregar ela com cobre minerado.
tutorial.waves = The[LIGHT_GRAY] enemy[] approaches.\n\nDefend your core for 2 waves. Build more turrets. tutorial.waves = O[LIGHT_GRAY] Inimigo[] se aproxima.\n\nDefenda seu core por 2 ondas. Construa mais torres.
tutorial.lead = More ores are available. Explore and mine[accent] lead[].\n\nDrag from your unit to the core to transfer resources. tutorial.lead = Mais minerios estão disponiveis. Explore e minere[accent] Cobre[].\n\nArraste Da sua unidade até o core para transferir recursos.
tutorial.smelter = Copper and lead are weak metals.\nSuperior[accent] Dense Alloy[] can be created in a smelter.\n\nBuild one. tutorial.smelter = Cobre e chumbo são materiais fracos.\nLiga densa[accent] Superior[] Pode ser feito num fundidor.\n\nConstrua um.
tutorial.densealloy = The smelter will now produce alloy.\nGet some.\nImprove the production if necessary. tutorial.densealloy = O fundidor agora vai fazer a liga.\nPegue.\nMelhore a produção se necessario.
tutorial.siliconsmelter = The core will now create a[accent] spirit drone[] for mining and repairing blocks.\n\nFactories for other units can be created with [accent] silicon.\nMake a silicon smelter. tutorial.siliconsmelter = O core agora vai criar[accent] O drone Spirit[] Para minerar e consertar blocos.\n\nFabricas para outras unidades podem ser criadas usando [accent] silicio.\nFaça um fundidor de Silicio.
tutorial.silicondrill = Silicon requires[accent] coal[] and[accent] sand[].\nStart by making drills. tutorial.silicondrill = Silicio requer[accent] carvão[] e[accent] areia[].\nComeçe a fazer mineradouras.
tutorial.generator = This technology requires power.\nCreate a[accent] combustion generator[] for it. tutorial.generator = Essa tecnologia requer energia.\nCrie[accent] um gerador a combustão[] para isso.
tutorial.generatordrill = Combustion generators need fuel.\nFuel it with coal from a drill. tutorial.generatordrill = Gerador de combustão requer combustivel.\nCarregue com carvão minerado.
tutorial.node = Power requires transport.\nCreate a[accent] power node[] next to your combustion generator to transfer its power. tutorial.node = Energia requer transporte.\nCrie um[accent] Nodo de energia[] Proximo do gerador de combustão.
tutorial.nodelink = Power can be transferred through contacting power blocks and generators, or by linked power nodes.\n\nLink power by tapping the node and selecting the generator and silicon smelter. tutorial.nodelink = Poder pode ser transportado construindo blocos de energia e geradores, Apenas construindo nodos de Energia.\n\nLigue a energia clicando no nodo e selecionando o gerador e o fundidor de silicio.
tutorial.silicon = Silicon is being produced. Get some.\n\nImproving the production system is advised. tutorial.silicon = Silicio esta sendo feito. Pegue.\n\nMelhorar a produção é recomendado.
tutorial.daggerfactory = Construct a[accent] dagger mech factory.[]\n\nThis will be used to create attack mechs. tutorial.daggerfactory = Construa uma[accent] Fabrica do meca Dagger.[]\n\nIsso vai ser feito para construi mecas de ataque.
tutorial.router = Factories need resources to function.\nCreate a router to split conveyor resources. tutorial.router = Fabricas precisam de recursos pra construir\nCrie um roteador para espalhadar recursos da esteira.
tutorial.dagger = Link power nodes to the factory.\nOnce requirements are met, a mech will be created.\n\nCreate more drills, generators and conveyors as necessary. tutorial.dagger = Ligue os nodos de energia a fabrica.\nQuando os requerimentos forem alcançados, Um meca vai ser criado.\n\nCrie mais mineradoras, geradoras e esteiras se necessario.
tutorial.battle = The[LIGHT_GRAY] enemy[] has revealed their core.\nDestroy it with your unit and dagger mechs. tutorial.battle = O[LIGHT_GRAY] Inimigo[] revelou seu core.\nDestrua com sua unidade e Dagger's.
block.copper-wall.description = A cheap defensive block.\nUseful for protecting the core and turrets in the first few waves. block.copper-wall.description = Um bloco defensivo e barato.\nUtil para proteger o core e torres no começo.
block.copper-wall-large.description = A cheap defensive block.\nUseful for protecting the core and turrets in the first few waves.\nSpans multiple tiles. block.copper-wall-large.description = Um bloco defensivo e barato.\nUtil para proteger o core e torres no começo.\nOcupa multiplos espaços.
block.dense-alloy-wall.description = A standard defensive block.\nAdequate protection from enemies. block.dense-alloy-wall.description = Um bloco defensivo padrão.\nProteção adequada contra inimigos.
block.dense-alloy-wall-large.description = A standard defensive block.\nAdequate protection from enemies.\nSpans multiple tiles. block.dense-alloy-wall-large.description = Um bloco defensivo padrão.\nProteção adequada contra inimigos.\nOcupa multiplos espaços.
block.thorium-wall.description = A strong defensive block.\nGood protection from enemies. block.thorium-wall.description = A strong defensive block.\nBoa proteção contra inimigos.
block.thorium-wall-large.description = A strong defensive block.\nGood protection from enemies.\nSpans multiple tiles. block.thorium-wall-large.description = Um bloco grande e defensivo.\nBoa proteção contra inimigos.\nOcupa multiplos espaços.
block.phase-wall.description = Not as strong as a thorium wall but will deflect bullets unless they are too powerful. block.phase-wall.description = Não tão forte quanto a parede de torio Mas vai defletir balas a menos que seja muito forte.
block.phase-wall-large.description = Not as strong as a thorium wall but will deflect bullets unless they are too powerful.\nSpans multiple tiles. block.phase-wall-large.description = Não tão forte quanto a parde de torio mas vai defletir balas a menos que seja muito forte.\nOcupa multiplos espaços.
block.surge-wall.description = The strongest defensive block.\nHas a small chance of triggering lightning towards the attacker. block.surge-wall.description = O bloco defensivo mais forte.\nQue tem uma pequena chance de lancar um raio Contra o atacante.
block.surge-wall-large.description = The strongest defensive block.\nHas a small chance of triggering lightning towards the attacker.\nSpans multiple tiles. block.surge-wall-large.description = O bloco defensivo mais forte.\nQue tem uma pequena chance de lancar um raio Contra o atacante.\nOcupa multiplos espaços
block.door.description = A small door that can be opened and closed by tapping on it.\nIf opened, enemies can shoot and move through. block.door.description = Uma pequena porta que pode ser aberta o fechada quando voce clica.\nSe aberta, Os inimigos podem atirar e passar.
block.door-large.description = A large door that can be opened and closed by tapping on it.\nIf opened, enemies can shoot and move through.\nSpans multiple tiles. block.door-large.description = Uma grande porta que pode ser aberta o fechada quando voce clica.\nSe aberta, Os inimigos podem atirar e passar..\nOcupa multiplos espaços.
block.mend-projector.description = Periodically heals buildings in its vicinity. block.mend-projector.description = Periodicamente conserta as construções.
block.overdrive-projector.description = Increases the speed of nearby buildings like drills and conveyors. block.overdrive-projector.description = Aumenta a velocidade de unidades proximas de geradores e esteiras.
block.force-projector.description = Creates a hexagonal force field around itself, protecting buildings and units inside from damage through bullets. block.force-projector.description = Cria um campo de forca hexagonal em volta de si mesmo, Protegendo construções e unidades dentro de dano por balas.
block.shock-mine.description = Damages enemies stepping on the mine. Nearly invisible to the enemy. block.shock-mine.description = Danifica inimigos em cima da mina. Quase invisivel ao inimigo.
block.duo.description = A small, cheap turret. block.duo.description = Uma torre pequena e barata.
block.arc.description = A small turret which shoots electricity in a random arc towards the enemy. block.arc.description = Uma pequena torre que atira eletricidade em um pequeno arc aleatoriamente no inimigo.
block.hail.description = A small artillery turret. block.hail.description = Uma pequena torre de artilharia.
block.lancer.description = A medium-sized turret which shoots charged electricity beams. block.lancer.description = Uma torre de Tamanho-Medio que atira raios de eletricidade.
block.wave.description = A medium-sized rapid-fire turret which shoots liquid bubbles. block.wave.description = Uma torre que Tamanho medio que atira bolhas.
block.salvo.description = A medium-sized turret which fires shots in salvos. block.salvo.description = Uma torre media que da tiros em salvos.
block.swarmer.description = A medium-sized turret which shoots burst missiles. block.swarmer.description = Uma torre media que atira ondas de misseis.
block.ripple.description = A large artillery turret which fires several shots simultaneously. block.ripple.description = Uma grande torre que atira simultaneamente.
block.cyclone.description = A large rapid fire turret. block.cyclone.description = Uma grande torre de tiro rapido.
block.fuse.description = A large turret which shoots powerful short-range beams. block.fuse.description = Uma torre grande que atira raios de curta distancia poderosos.
block.spectre.description = A large turret which shoots two powerful bullets at once. block.spectre.description = Uma grande torre que da dois tiros poderosos ao mesmo tempo.
block.meltdown.description = A large turret which shoots powerful long-range beams. block.meltdown.description = Uma grande torre que atira dois raios poderosos ao mesmo tempo.
block.conveyor.description = Basic item transport block. Moved items forward and automatically deposits them into turrets or crafters. Rotatable. block.conveyor.description = Bloco de transporte de item basico. Move os itens a frente e os deposita automaticamente Em torres ou construtores. Rotacionavel.
block.titanium-conveyor.description = Advanced item transport block. Moves items faster than standard conveyors. block.titanium-conveyor.description = Bloco de transporte de item avancado. Move itens mais rapidos que esteiras padrões.
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 = Bloco de transporte de item avançado. Usa energia para teleportar itens a uma esteira de fase sobre uma severa distancia.
block.junction.description = Acts as a bridge for two crossing conveyor belts. Useful in situations with two different conveyors carrying different materials to different locations. block.junction.description = Funciona como uma ponte Para duas esteiras que estejam se cruzando. Util em situações que tenha duas esteiras diferentes carregando materiais diferentes para lugares diferentes.
block.mass-driver.description = Ultimate item transport block. Collects several items and then shoots them to another mass driver over a long range. block.mass-driver.description = Bloco de transporte de itens supremo. Coleta itens severos e atira eles em outro mass driver de uma longa distancia.
block.smelter.description = Burns coal for smelting copper and lead into dense alloy. block.smelter.description = Queima carvão para derreter cobre e chumbo em liga densa.
block.arc-smelter.description = Smelts copper and lead into dense alloy by using an external power source. block.arc-smelter.description = Derrete Cobre e chumbo em liga densa usando energia exterior.
block.silicon-smelter.description = Reduces sand with highly pure coke in order to produce silicon. block.silicon-smelter.description = Reduz areia a coque altamente puro Para fazer silicio.
block.plastanium-compressor.description = Produces plastanium from oil and titanium. block.plastanium-compressor.description = Produz plastanio para usando oleo e titanio.
block.phase-weaver.description = Produces phase fabric from radioactive thorium and high amounts of sand. block.phase-weaver.description = Produz tecido de fase de torio radioativo e grandes quantidades de areia.
block.alloy-smelter.description = Produces surge alloy from titanium, lead, silicon and copper. block.alloy-smelter.description = Produz liga de surge de titanio, chumbo, silicio e cobre.
block.pulverizer.description = Crushes stone into sand. Useful when there is a lack of natural sand. block.pulverizer.description = Esmaga pedra em areia. Util quando esta em falta de areia natural.
block.pyratite-mixer.description = Mixes coal, lead and sand into highly flammable pyratite. block.pyratite-mixer.description = Mistura carvão, Cobre e areia em piratite altamente inflamavel
block.blast-mixer.description = Uses oil for transforming pyratite into the less flammable but more explosive blast compound. block.blast-mixer.description = Usa oleo em Transformar piratite em composto de explosão menos inflamavel mas mais explosivo
block.cryofluidmixer.description = Combines water and titanium into cryofluid which is much more efficient for cooling. block.cryofluidmixer.description = Combina agua e titanio em cryo fluido que é mais eficiente em esfriar.
block.solidifer.description = Cools lava to stone at a fast pace. block.solidifer.description = Esfria lava em pedra em um ritmo rapido.
block.melter.description = Heats up stone to very high temperatures to obtain lava. block.melter.description = Aquece pedra em altas temperaturas para fazer lava.
block.incinerator.description = Gets rid of any excess item or liquid. block.incinerator.description = Se livra de itens em excesso ou liquidos.
block.biomattercompressor.description = Compresses biomatter in order to retrieve oil. block.biomattercompressor.description = Compressa Biomassa para recuperar oleo.
block.separator.description = Exposes stone to water pressure in order to obtain various minerals contained in the stone. block.separator.description = Expos pedra em agua em pressão para ter varios mineiras contendo na pedra.
block.centrifuge.description = More efficient than the separator, but also more expensive to build and requires power. block.centrifuge.description = Mais eficiente que o separador, Mas mais caro e precisa de energia.
block.power-node.description = Transmits power to connected nodes. Up to four power sources, sinks or nodes can be connected. The node will receive power from or supply power to any adjacent blocks. block.power-node.description = Transmite poder em nodos. Maximo de 4 fontes de energia, sinks ou nodos podem ser conectados. Os nodos vão receber energia de ou dar energia para qualquer bloco adjacente.
block.power-node-large.description = Has a larger radius than the power node and connects to up to six power sources, sinks or nodes. block.power-node-large.description = Tem um raio maior que o nodo de energia e pode conectar até 6 fontes de energia, sinks ou nodos.
block.battery.description = Stores power whenever there is an abundance and provides power whenever there is a shortage, as long as there is capacity left. block.battery.description = Guarda energia sempre que tiver em abundancia e da energia sempre que precisar enquanto tiver capacidade.
block.battery-large.description = Stores much more power than a regular battery. block.battery-large.description = Guarda muito mais energia que uma beteria comum
block.combustion-generator.description = Generates power by burning oil or flammable materials. block.combustion-generator.description = Gera poder usando combustivel ou oleo.
block.turbine-generator.description = More efficient than a combustion generator, but requires additional water. block.turbine-generator.description = Mais eficiente que o gerador de Combustão, Mas requer agua adicional.
block.thermal-generator.description = Generates a large amount of power from lava. block.thermal-generator.description = Gera uma quantidade grande de energia usando lava.
block.solar-panel.description = Provides a small amount of power from the sun. block.solar-panel.description = Gera pequenas quantidades de energia do sol.
block.solar-panel-large.description = Provides much better power supply than a standard solar panel, but is also much more expensive to build. block.solar-panel-large.description = Da muito mais energia que o painel solar comum, Mas sua produção é mais cara.
block.thorium-reactor.description = Generates huge amounts of power from highly radioactive thorium. Requires constant cooling. Will explode violently if insufficient amounts of coolant are supplied. block.thorium-reactor.description = Gera altas quantidades de energia do torio radioativo. Requer resfriamento constante. Vai explodir violentamente Se resfriamento insuficiente for fornecido.
block.rtg-generator.description = A radioisotope thermoelectric generator which does not require cooling but provides less power than a thorium reactor. block.rtg-generator.description = Um Gerador termoelétrico de radioisótopos Que não precisa de refriamento Mas da muito mais energia que o reator de torio.
block.unloader.description = Unloads items from a container, vault or core onto a conveyor or directly into an adjacent block. The type of item to be unloaded can be changed by tapping on the unloader. block.unloader.description = Descarrega itens de um container, Descarrega em uma esteira ou diretamente em um bloco adjacente. O tipo de item que pode ser descarregado pode ser mudado clicando no descarregador.
block.container.description = Stores a small amount of items. Use it for creating buffers when there is a non-constant demand of materials. An[LIGHT_GRAY] unloader[] can be used to retrieve items from the container. block.container.description = Carrega uma baixa quantidade de itens. Usado para criar fontes Quando não tem uma necessidade constante de materiais. Um[LIGHT_GRAY] Descarregador[] pode ser usado para recuperar esses itens do container.
block.vault.description = Stores a large amount of items. Use it for creating buffers when there is a non-constant demand of materials. An[LIGHT_GRAY] unloader[] can be used to retrieve items from the vault. block.vault.description = Carrega uma alta quantidade de itens. Usado para criar fontes Quando não tem uma necessidade constante de materiais. Um[LIGHT_GRAY] Descarregador[] pode ser usado para recuperar esses itens do container.
block.mechanical-drill.description = A cheap drill. When placed on appropriate tiles, outputs items at a slow pace indefinitely. block.mechanical-drill.description = Uma mineradoura barata. Quando colocado em blocos apropriados, retira itens em um ritmo lento e indefinitavamente.
block.pneumatic-drill.description = An improved drill which is faster and able to process harder materials by making use of air pressure. block.pneumatic-drill.description = Uma mineradora improvisada que é mais rapida e capaz de processar mateirais mais duros usando a pressao do ar
block.laser-drill.description = Allows drilling even faster through laser technology, but requires power. Additionally, radioactive thorium can be retrieved with this drill. block.laser-drill.description = Possibilita a mineração ainda mais rapida usando tecnologia a laser, Mas requer poder adcionalmente torio radioativo pode ser recuperado com essa mineradora
block.blast-drill.description = The ultimate drill. Requires large amounts of power. block.blast-drill.description = A melhor mineradora. Requer muita energia.
block.water-extractor.description = Extracts water from the ground. Use it when there is no lake nearby. block.water-extractor.description = Extrai agua do chão. Use quando não tive nenhum lago proximo
block.cultivator.description = Cultivates the soil with water in order to obtain biomatter. block.cultivator.description = Cultiva o solo com agua para pegar bio materia.
block.oil-extractor.description = Uses large amounts of power in order to extract oil from sand. Use it when there is no direct source of oil nearby. block.oil-extractor.description = Usa altas quantidades de energia Para extrair oleo da areia. Use quando não tiver fontes de oleo por perto
block.dart-ship-pad.description = Leave your current vessel and change into a basic fighter aircraft.\nUse the pad by double tapping while standing on it. block.dart-ship-pad.description = Deixe sua atual embarcação e mude para uma aeronave lutadora basica.\nUse o pad clicando duas vezes em cima enquando fica em cima dele.
block.trident-ship-pad.description = Leave your current vessel and change into a reasonably well armored heavy bomber.\nUse the pad by double tapping while standing on it. block.trident-ship-pad.description = Deixe sua atual embarcação e mude para um bombardeiro resionavelmente bem armadurado.\nUse o pad clicando duas vezes em cima enquando fica em cima dele.
block.javelin-ship-pad.description = Leave your current vessel and change into a strong and fast interceptor with lightning weapons.\nUse the pad by double tapping while standing on it. block.javelin-ship-pad.description = Deixe sua atual embarcação e mude para um interceptador forte e rapido com armas de raio.\nUse o pad clicando duas vezes em cima enquando fica em cima dele.
block.glaive-ship-pad.description = Leave your current vessel and change into a large, well-armored gunship.\nUse the pad by double tapping while standing on it. block.glaive-ship-pad.description = Deixe sua atual embarcação e mude para grande, bem armadurada nave de combate.\nUse o pad clicando duas vezes em cima enquando fica em cima dele.
block.tau-mech-pad.description = Leave your current vessel and change into a support mech which can heal friendly buildings and units.\nUse the pad by double tapping while standing on it. block.tau-mech-pad.description = Deixe sua atual embarcação e mude para o meca de suporte que pode consertar construções aliadas e unidades.\nUse o pad clicando duas vezes em cima enquando fica em cima dele.
block.delta-mech-pad.description = Leave your current vessel and change into a fast, lightly-armored mech made for hit-and-run attacks.\nUse the pad by double tapping while standing on it. block.delta-mech-pad.description = Deixe sua atual embarcação e mude para o rapido, Levemente armadurado meca feito para ataques rapidos.\nUse o pad clicando duas vezes em cima enquando fica em cima dele.
block.omega-mech-pad.description = Leave your current vessel and change into a bulky and well-armored mech, made for front-line assaults.\nUse the pad by double tapping while standing on it. block.omega-mech-pad.description = Deixe sua atual embarcação e mude para o volumoso e bem armadurado meca feito para ataques da primeira linha.\nUse o pad clicando duas vezes em cima enquando fica em cima dele.
block.spirit-factory.description = Produces light drones which mine ore and repair blocks. block.spirit-factory.description = Produz drones leves que mineram e reparam blocos.
block.phantom-factory.description = Produces advanced drone units which are significantly more effective than a spirit drone. block.phantom-factory.description = Produz unidades de drone avancadas Que são significativamente mais efetivos que um drone spirit.
block.wraith-factory.description = Produces fast, hit-and-run interceptor units. block.wraith-factory.description = produz unidades interceptor de ataque rapido.
block.ghoul-factory.description = Produces heavy carpet bombers. block.ghoul-factory.description = Produz bombardeiros pesados.
block.dagger-factory.description = Produces basic ground units. block.dagger-factory.description = Produz unidades terrestres.
block.titan-factory.description = Produces advanced, armored ground units. block.titan-factory.description = Produz unidades avancadas, armaduradas e terrestres.
block.fortress-factory.description = Produces heavy artillery ground units. block.fortress-factory.description = Produz unidades terrestres pesadas de artilharia.
block.revenant-factory.description = Produces heavy laser ground units. block.revenant-factory.description = Produz unidades laser, pesadas e terrestres.
block.repair-point.description = Continuously heals the closest damaged unit in its vicinity. block.repair-point.description = Continuamente repara a unidade danificada mais proxima.
block.command-center.description = Allows changing friendly AI behavior. Currently, attack, retreat and patrol commands are supported. block.command-center.description = Permite mudar o comportamento IA dos aliados. Atualmente, atacar, recuar e patrulha são suportados.
block.conduit.description = Basic liquid transport block. Works like a conveyor, but with liquids. Best used with extractors, pumps or other conduits. block.conduit.description = Bloco de transporte de liquido basico. Funciona como a esteira, Mas com liquidos. Melhor usado com extratores, Bombas ou condutos.
block.pulse-conduit.description = Advanced liquid transport block. Transports liquids faster and stores more than standard conduits. block.pulse-conduit.description = Bloco avancado de transporte de liquido. Transporta liquidos mais rapido E armazena mais que os condutos padrões.
block.phase-conduit.description = Advanced liquid transport block. Uses power to teleport liquids to a connected phase conduit over several tiles. block.phase-conduit.description = Bloco avancado de transporte de liquido. Usa energia para teleportar liquidos conduto de fase sobre uma distancia severa.
block.liquid-router.description = Accepts liquids from one direction and outputs them to up to 3 other directions equally. Can also store a certain amount of liquid. Useful for splitting the liquids from one source to multiple targets. block.liquid-router.description = Aceita liquidos de uma direcão e os joga em 3 direções igualmente. Pode armazenar uma certa quantidade de liquido. Util para espalhar liquidosd a fonte para multiplos alvos.
block.liquid-tank.description = Stores a large amount of liquids. Use it for creating buffers when there is a non-constant demand of materials or as a safeguard for cooling vital blocks. block.liquid-tank.description = Armazena grandes quantidades de liquido. Use quando a demanda de materiais não for constante ou para guardar itens para resfriar blocos vitais.
block.liquid-junction.description = Acts as a bridge for two crossing conduits. Useful in situations with two different conduits carrying different liquids to different locations. block.liquid-junction.description = Age como uma ponte para dois canos que se cruzam. Util em situações que tem dois condutos carregando liquidos diferentes até localizações diferentes.
block.bridge-conduit.description = Advanced liquid transport block. Allows transporting liquids over up to 3 tiles of any terrain or building. block.bridge-conduit.description = Bloco de transporte de liquidos avancados. Possibilita o transporte de liquido sobre 3 blocos acima de construções ou paredes
block.mechanical-pump.description = A cheap pump with slow output, but no power consumption. block.mechanical-pump.description = Uma bomba barata mais saida de liquidos lenta, Sem consumo de energia.
block.rotary-pump.description = An advanced pump which doubles up speed by using power. block.rotary-pump.description = Uma bomba avancada que duplica a velocidade da saida de liquida usando energia.
block.thermal-pump.description = The ultimate pump. Three times as fast as a mechanical pump and the only pump which is able to retrieve lava. block.thermal-pump.description = A melhor bomba. Trez vezes mais rapida que a bomba mecanica e a unica bomba capaz de pegar lava.
block.router.description = Accepts items from one direction and outputs them to up to 3 other directions equally. Useful for splitting the materials from one source to multiple targets. block.router.description = Aceita itens de uma direção e os divide em 3 direções igualmente. Util para espalhar materiais da fonte para multiplos alvos.
block.distributor.description = An advanced router which splits items to up to 7 other directions equally. block.distributor.description = Um roteador avancada que espalhas os itens em 7 outras direções igualmente.
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 = Bloco de transporte de itens avancado. Possibilita o transporte de itens acima de 3 blocos de construção ou paredes.
block.alpha-mech-pad.description = When given enough power, rebuilds your ship into the[accent] Alpha[] mech. block.alpha-mech-pad.description = Quando dado energia o suficiente, Reconstrua sua nave em [accent] Alpha[] mech.
block.itemsource.description = Infinitely outputs items. Sandbox only. block.itemsource.description = Infinivamente da itens. Apenas caixa de areia.
block.liquidsource.description = Infinitely outputs liquids. Sandbox only. block.liquidsource.description = Infinitivamente da Liquidos. Apenas caixa de areia.
block.itemvoid.description = Destroys any items which go into it without using power. Sandbox only. block.itemvoid.description = Destroi qualquer item que entre sem requerir energia. Apenas caixa de areia.
block.powerinfinite.description = Infinitely outputs power. Sandbox only. block.powerinfinite.description = Infinitivamente da energia. Apenas caixa de areia.
block.powervoid.description = Voids all power inputted into it. Sandbox only. block.powervoid.description = Destroi qualquer energia que entre dentro. Apenas caixa de areia.
liquid.water.description = Commonly used for cooling machines and waste processing. liquid.water.description = Comumente usado em resfriamento e no processo de perda.
liquid.lava.description = Can be transformed into[LIGHT_GRAY] stone[], used for generating power or used as ammo for certain turrets. liquid.lava.description = Pode ser transformado em[LIGHT_GRAY] pedra[], usado para gerar energia ou usado como munição para certas torres.
liquid.oil.description = Can be burnt, exploded or used as a coolant. liquid.oil.description = Pode ser queimado, explodido ou usado como resfriador.
liquid.cryofluid.description = The most efficient liquid for cooling things down. liquid.cryofluid.description = A maneira mais eficiente de resfriar qualquer coisa.

View File

@@ -32,6 +32,7 @@ TextButtonStyle: {
clear-partial: {down: white, up: button-select, over: flat-down, font: default-font, fontColor: white, disabledFontColor: gray }, clear-partial: {down: white, up: button-select, over: flat-down, font: default-font, fontColor: white, disabledFontColor: gray },
clear-partial-2: {down: flat-over, up: none, over: flat-over, font: default-font, fontColor: white, disabledFontColor: gray }, clear-partial-2: {down: flat-over, up: none, over: flat-over, font: default-font, fontColor: white, disabledFontColor: gray },
empty: {font: default-font}, empty: {font: default-font},
clear-toggle: {font: default-font, fontColor: white, checked: flat-down, down: flat-down, up: flat, over: flat-over, disabled: flat, disabledFontColor: gray }
toggle: {font: default-font, fontColor: white, checked: button-down, down: button-down, up: button, over: button-over, disabled: button, disabledFontColor: gray } toggle: {font: default-font, fontColor: white, checked: button-down, down: button-down, up: button, over: button-over, disabled: button, disabledFontColor: gray }
}, },
ImageButtonStyle: { ImageButtonStyle: {

View File

@@ -51,8 +51,8 @@ public class BlockIndexer{
public BlockIndexer(){ public BlockIndexer(){
Events.on(TileChangeEvent.class, event -> { Events.on(TileChangeEvent.class, event -> {
if(typeMap.get(event.tile.packedPosition()) != null){ if(typeMap.get(event.tile.pos()) != null){
TileIndex index = typeMap.get(event.tile.packedPosition()); TileIndex index = typeMap.get(event.tile.pos());
for(BlockFlag flag : index.flags){ for(BlockFlag flag : index.flags){
getFlagged(index.team)[flag.ordinal()].remove(event.tile); getFlagged(index.team)[flag.ordinal()].remove(event.tile);
} }
@@ -86,7 +86,7 @@ public class BlockIndexer{
process(tile); process(tile);
if(tile.entity != null && tile.entity.healthf() < 0.9999f){ if(tile.entity != null && tile.entity.damaged()){
notifyTileDamaged(tile.entity); notifyTileDamaged(tile.entity);
} }
} }
@@ -116,7 +116,7 @@ public class BlockIndexer{
ObjectSet<Tile> set = damagedTiles[team.ordinal()]; ObjectSet<Tile> set = damagedTiles[team.ordinal()];
for(Tile tile : set){ for(Tile tile : set){
if(tile.entity == null || tile.entity.getTeam() != team || tile.entity.healthf() >= 0.9999f){ if(tile.entity == null || tile.entity.getTeam() != team || !tile.entity.damaged()){
returnArray.add(tile); returnArray.add(tile);
} }
} }
@@ -230,7 +230,7 @@ public class BlockIndexer{
map[flag.ordinal()] = arr; map[flag.ordinal()] = arr;
} }
typeMap.put(tile.packedPosition(), new TileIndex(tile.block().flags, tile.getTeam())); typeMap.put(tile.pos(), new TileIndex(tile.block().flags, tile.getTeam()));
} }
if(ores == null) return; if(ores == null) return;

View File

@@ -21,7 +21,7 @@ import java.io.IOException;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
public class WaveSpawner{ public class WaveSpawner{
private static final int quadsize = 4; private static final int quadsize = 6;
private GridBits quadrants; private GridBits quadrants;
@@ -164,7 +164,7 @@ public class WaveSpawner{
for(int y = quady * quadsize; y < world.height() && y < (quady + 1) * quadsize; y++){ for(int y = quady * quadsize; y < world.height() && y < (quady + 1) * quadsize; y++){
Tile tile = world.tile(x, y); Tile tile = world.tile(x, y);
if(tile == null || tile.solid() || world.pathfinder.getValueforTeam(Team.red, x, y) == Float.MAX_VALUE){ if(tile == null || tile.solid() || tile.getTeam() == defaultTeam || world.pathfinder.getValueforTeam(Team.red, x, y) == Float.MAX_VALUE || tile.floor().isLiquid){
setQuad(quadx, quady, false); setQuad(quadx, quady, false);
break outer; break outer;
} }
@@ -217,8 +217,8 @@ public class WaveSpawner{
//TODO instead of randomly scattering locations around the map, find spawns close to each other //TODO instead of randomly scattering locations around the map, find spawns close to each other
private void findLocation(GroundSpawn spawn){ private void findLocation(GroundSpawn spawn){
spawn.x = -1; spawn.x = Mathf.random(quadWidth()-1);
spawn.y = -1; spawn.y = Mathf.random(quadHeight()-1);
int shellWidth = quadWidth() * 2 + quadHeight() * 2 * 6; int shellWidth = quadWidth() * 2 + quadHeight() * 2 * 6;
shellWidth = Math.min(quadWidth() * quadHeight() / 4, shellWidth); shellWidth = Math.min(quadWidth() * quadHeight() / 4, shellWidth);

View File

@@ -11,7 +11,7 @@ import io.anuke.ucore.core.Timers;
import io.anuke.ucore.util.Mathf; import io.anuke.ucore.util.Mathf;
public class StatusEffects implements ContentList{ public class StatusEffects implements ContentList{
public static StatusEffect none, burning, freezing, wet, melting, tarred, overdrive, shielded; public static StatusEffect none, burning, freezing, wet, melting, tarred, overdrive, shielded, shocked;
@Override @Override
public void load(){ public void load(){
@@ -47,7 +47,8 @@ public class StatusEffects implements ContentList{
freezing = new StatusEffect(5 * 60f){ freezing = new StatusEffect(5 * 60f){
{ {
oppositeScale = 0.4f; oppositeScale = 0.4f;
speedMultiplier = 0.5f; speedMultiplier = 0.6f;
armorMultiplier = 0.8f;
} }
@Override @Override
@@ -65,6 +66,17 @@ public class StatusEffects implements ContentList{
speedMultiplier = 0.9f; speedMultiplier = 0.9f;
} }
@Override
public StatusEntry getTransition(Unit unit, StatusEffect to, float time, float newTime, StatusEntry result){
if(to == shocked){
//get shocked when wet
unit.damage(15f);
return result.set(this, time);
}
return super.getTransition(unit, to, time, newTime, result);
}
@Override @Override
public void update(Unit unit, float time){ public void update(Unit unit, float time){
if(Mathf.chance(Timers.delta() * 0.15f)){ if(Mathf.chance(Timers.delta() * 0.15f)){
@@ -145,6 +157,13 @@ public class StatusEffects implements ContentList{
} }
}; };
shocked = new StatusEffect(1f){
{
armorMultiplier = 3f;
}
};
wet.setOpposites(shocked);
melting.setOpposites(wet, freezing); melting.setOpposites(wet, freezing);
wet.setOpposites(burning); wet.setOpposites(burning);
freezing.setOpposites(burning, melting); freezing.setOpposites(burning, melting);

View File

@@ -71,13 +71,13 @@ public class DefenseBlocks extends BlockList implements ContentList{
}}; }};
mendProjector = new MendProjector("mend-projector"){{ mendProjector = new MendProjector("mend-projector"){{
consumes.powerDirect(0.2f); consumes.powerDirect(0.2f, 1.0f);
size = 2; size = 2;
consumes.item(Items.phasefabric).optional(true); consumes.item(Items.phasefabric).optional(true);
}}; }};
overdriveProjector = new OverdriveProjector("overdrive-projector"){{ overdriveProjector = new OverdriveProjector("overdrive-projector"){{
consumes.powerDirect(0.35f); consumes.powerDirect(0.35f, 1.0f);
size = 2; size = 2;
consumes.item(Items.phasefabric).optional(true); consumes.item(Items.phasefabric).optional(true);
}}; }};

View File

@@ -35,7 +35,7 @@ public class DistributionBlocks extends BlockList implements ContentList{
phaseConveyor = new ItemBridge("phase-conveyor"){{ phaseConveyor = new ItemBridge("phase-conveyor"){{
range = 12; range = 12;
hasPower = true; hasPower = true;
consumes.powerDirect(0.03f); consumes.powerDirect(0.03f, 1.0f);
}}; }};
sorter = new Sorter("sorter"); sorter = new Sorter("sorter");

View File

@@ -48,10 +48,10 @@ public class LiquidBlocks extends BlockList implements ContentList{
}}; }};
liquidRouter = new LiquidRouter("liquid-router"){{ liquidRouter = new LiquidRouter("liquid-router"){{
liquidCapacity = 40f; liquidCapacity = 20f;
}}; }};
liquidtank = new LiquidRouter("liquid-tank"){{ liquidtank = new LiquidTank("liquid-tank"){{
size = 3; size = 3;
liquidCapacity = 1500f; liquidCapacity = 1500f;
health = 500; health = 500;
@@ -67,7 +67,7 @@ public class LiquidBlocks extends BlockList implements ContentList{
phaseConduit = new LiquidBridge("phase-conduit"){{ phaseConduit = new LiquidBridge("phase-conduit"){{
range = 12; range = 12;
hasPower = true; hasPower = true;
consumes.powerDirect(0.03f); consumes.powerDirect(0.03f, 1.0f);
}}; }};
} }
} }

View File

@@ -39,6 +39,8 @@ public class TurretBullets extends BulletList implements ContentList{
lifetime = Lightning.lifetime; lifetime = Lightning.lifetime;
hiteffect = BulletFx.hitLancer; hiteffect = BulletFx.hitLancer;
despawneffect = Fx.none; despawneffect = Fx.none;
status = StatusEffects.shocked;
statusIntensity = 1f;
} }
}; };
@@ -71,7 +73,7 @@ public class TurretBullets extends BulletList implements ContentList{
super.hit(b); super.hit(b);
tile = tile.target(); tile = tile.target();
if(tile.getTeam() == b.getTeam() && !(tile.block() instanceof BuildBlock)){ if(tile != null && tile.getTeam() == b.getTeam() && !(tile.block() instanceof BuildBlock)){
Effects.effect(BlockFx.healBlockFull, Palette.heal, tile.drawx(), tile.drawy(), tile.block().size); Effects.effect(BlockFx.healBlockFull, Palette.heal, tile.drawx(), tile.drawy(), tile.block().size);
tile.entity.healBy(healPercent / 100f * tile.entity.maxHealth()); tile.entity.healBy(healPercent / 100f * tile.entity.maxHealth());
} }

View File

@@ -26,7 +26,10 @@ import io.anuke.mindustry.ui.dialogs.FloatingDialog;
import io.anuke.ucore.core.*; import io.anuke.ucore.core.*;
import io.anuke.ucore.entities.EntityQuery; import io.anuke.ucore.entities.EntityQuery;
import io.anuke.ucore.modules.Module; import io.anuke.ucore.modules.Module;
import io.anuke.ucore.util.*; import io.anuke.ucore.util.Atlas;
import io.anuke.ucore.util.Bundles;
import io.anuke.ucore.util.Strings;
import io.anuke.ucore.util.Timer;
import java.io.IOException; import java.io.IOException;
@@ -372,7 +375,7 @@ public class Control extends Module{
} }
} }
if(Inputs.keyTap("screenshot") && !ui.chatfrag.chatOpen()){ if(!mobile && Inputs.keyTap("screenshot") && !ui.chatfrag.chatOpen()){
renderer.takeMapScreenshot(); renderer.takeMapScreenshot();
} }

View File

@@ -127,7 +127,7 @@ public class NetServer extends Module{
return; return;
} }
if(packet.versionType == null || ((packet.version == -1 || !packet.versionType.equals("official")) && Version.build != -1 && !admins.allowsCustomClients())){ if(packet.versionType == null || ((packet.version == -1 || !packet.versionType.equals(Version.type)) && Version.build != -1 && !admins.allowsCustomClients())){
kick(id, KickReason.customClient); kick(id, KickReason.customClient);
return; return;
} }
@@ -281,6 +281,7 @@ public class NetServer extends Module{
} }
player.remove(); player.remove();
netServer.connections.remove(player.con.id); netServer.connections.remove(player.con.id);
Log.info("&lc{0} has disconnected.", player.name);
} }
private static float compound(float speed, float drag){ private static float compound(float speed, float drag){
@@ -381,7 +382,7 @@ public class NetServer extends Module{
return; return;
} }
if(other == null || (other.isAdmin && other != player)){ //fun fact: this means you can ban yourself if(other == null || ((other.isAdmin && !player.isLocal) && other != player)){
Log.err("{0} attempted to perform admin action on nonexistant or admin player.", player.name); Log.err("{0} attempted to perform admin action on nonexistant or admin player.", player.name);
return; return;
} }
@@ -492,7 +493,7 @@ public class NetServer extends Module{
//write all core inventory data //write all core inventory data
for(Tile tile : cores){ for(Tile tile : cores){
dataStream.writeInt(tile.packedPosition()); dataStream.writeInt(tile.pos());
tile.entity.items.write(dataStream); tile.entity.items.write(dataStream);
} }

View File

@@ -152,7 +152,7 @@ public class Renderer extends RendererModule{
if(players[0].isDead()){ if(players[0].isDead()){
TileEntity core = players[0].getClosestCore(); TileEntity core = players[0].getClosestCore();
if(core != null && players[0].spawner == -1){ if(core != null && players[0].spawner == Unit.noSpawner){
smoothCamera(core.x, core.y, 0.08f); smoothCamera(core.x, core.y, 0.08f);
}else{ }else{
smoothCamera(position.x + 0.0001f, position.y + 0.0001f, 0.08f); smoothCamera(position.x + 0.0001f, position.y + 0.0001f, 0.08f);
@@ -395,8 +395,8 @@ public class Renderer extends RendererModule{
Graphics.getEffectSurface().setSize(w, h, true); Graphics.getEffectSurface().setSize(w, h, true);
Core.camera.viewportWidth = w; Core.camera.viewportWidth = w;
Core.camera.viewportHeight = h; Core.camera.viewportHeight = h;
Core.camera.position.x = w/2f; Core.camera.position.x = w/2f + tilesize/2f;
Core.camera.position.y = h/2f; Core.camera.position.y = h/2f + tilesize/2f;
draw(); draw();

View File

@@ -15,6 +15,7 @@ import io.anuke.mindustry.io.MapIO;
import io.anuke.mindustry.maps.*; import io.anuke.mindustry.maps.*;
import io.anuke.mindustry.maps.generation.WorldGenerator; import io.anuke.mindustry.maps.generation.WorldGenerator;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.OreBlock; import io.anuke.mindustry.world.blocks.OreBlock;
import io.anuke.ucore.core.Events; import io.anuke.ucore.core.Events;
@@ -103,12 +104,8 @@ public class World extends Module{
return tiles == null ? 0 : tiles[0].length; return tiles == null ? 0 : tiles[0].length;
} }
public int toPacked(int x, int y){ public Tile tile(int pos){
return x + y * width(); return tiles == null ? null : tile(Pos.x(pos), Pos.y(pos));
}
public Tile tile(int packed){
return tiles == null ? null : tile(packed % width(), packed / width());
} }
public Tile tile(int x, int y){ public Tile tile(int x, int y){

View File

@@ -567,16 +567,16 @@ public class MapEditorDialog extends Dialog implements Disposable{
button.getImage().remove(); button.getImage().remove();
button.update(() -> button.setChecked(editor.getDrawBlock() == block)); button.update(() -> button.setChecked(editor.getDrawBlock() == block));
group.add(button); group.add(button);
content.add(button).size(60f); content.add(button).size(50f);
if(i++ % 3 == 2){ if(++i % 4 == 0){
content.row(); content.row();
} }
} }
group.getButtons().get(2).setChecked(true); group.getButtons().get(2).setChecked(true);
table.table("underline", extra -> extra.labelWrap(() -> editor.getDrawBlock().formalName).width(220f).center()).growX(); table.table("underline", extra -> extra.labelWrap(() -> editor.getDrawBlock().formalName).width(200f).center()).growX();
table.row(); table.row();
table.add(pane).growY().fillX(); table.add(pane).growY().fillX();
} }

View File

@@ -58,7 +58,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
public boolean achievedFlight; public boolean achievedFlight;
public Color color = new Color(); public Color color = new Color();
public Mech mech; public Mech mech;
public int spawner = -1; public int spawner = noSpawner;
public NetConnection con; public NetConnection con;
public int playerIndex = 0; public int playerIndex = 0;
@@ -498,7 +498,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
updateRespawning(); updateRespawning();
return; return;
}else{ }else{
spawner = -1; spawner = noSpawner;
} }
avoidOthers(1f); avoidOthers(1f);
@@ -788,23 +788,23 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
public void updateRespawning(){ public void updateRespawning(){
if(spawner != -1 && world.tile(spawner) != null && world.tile(spawner).entity instanceof SpawnerTrait){ if(spawner != noSpawner && world.tile(spawner) != null && world.tile(spawner).entity instanceof SpawnerTrait){
((SpawnerTrait) world.tile(spawner).entity).updateSpawning(this); ((SpawnerTrait) world.tile(spawner).entity).updateSpawning(this);
}else{ }else{
CoreEntity entity = (CoreEntity) getClosestCore(); CoreEntity entity = (CoreEntity) getClosestCore();
if(entity != null && !netServer.isWaitingForPlayers()){ if(entity != null && !netServer.isWaitingForPlayers()){
this.spawner = entity.tile.id(); this.spawner = entity.tile.pos();
} }
} }
} }
public void beginRespawning(SpawnerTrait spawner){ public void beginRespawning(SpawnerTrait spawner){
this.spawner = spawner.getTile().packedPosition(); this.spawner = spawner.getTile().pos();
this.dead = true; this.dead = true;
} }
public void endRespawning(){ public void endRespawning(){
spawner = -1; spawner = noSpawner;
} }
//endregion //endregion
@@ -860,7 +860,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
buffer.writeByte(Bits.toByte(isAdmin) | (Bits.toByte(dead) << 1) | (Bits.toByte(isBoosting) << 2)); buffer.writeByte(Bits.toByte(isAdmin) | (Bits.toByte(dead) << 1) | (Bits.toByte(isBoosting) << 2));
buffer.writeInt(Color.rgba8888(color)); buffer.writeInt(Color.rgba8888(color));
buffer.writeByte(mech.id); buffer.writeByte(mech.id);
buffer.writeInt(mining == null ? -1 : mining.packedPosition()); buffer.writeInt(mining == null ? -1 : mining.pos());
buffer.writeInt(spawner); buffer.writeInt(spawner);
buffer.writeShort((short) (baseRotation * 2)); buffer.writeShort((short) (baseRotation * 2));

View File

@@ -154,6 +154,10 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
} }
} }
public boolean damaged(){
return health < maxHealth() - 0.00001f;
}
public Tile getTile(){ public Tile getTile(){
return tile; return tile;
} }

View File

@@ -12,6 +12,7 @@ import io.anuke.mindustry.net.Interpolator;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.StatusEffect; import io.anuke.mindustry.type.StatusEffect;
import io.anuke.mindustry.type.Weapon; import io.anuke.mindustry.type.Weapon;
import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Floor; import io.anuke.mindustry.world.blocks.Floor;
import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Effects;
@@ -39,6 +40,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
public static final float velocityPercision = 8f; public static final float velocityPercision = 8f;
/**Maximum absolute value of a velocity vector component.*/ /**Maximum absolute value of a velocity vector component.*/
public static final float maxAbsVelocity = 127f / velocityPercision; public static final float maxAbsVelocity = 127f / velocityPercision;
public static final int noSpawner = Pos.get(-1, 1);
private static final Rectangle queryRect = new Rectangle(); private static final Rectangle queryRect = new Rectangle();
private static final Vector2 moveVector = new Vector2(); private static final Vector2 moveVector = new Vector2();

View File

@@ -48,7 +48,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
public static void create(Tile tile){ public static void create(Tile tile){
if(Net.client() || tile == null) return; //not clientside. if(Net.client() || tile == null) return; //not clientside.
Fire fire = map.get(tile.packedPosition()); Fire fire = map.get(tile.pos());
if(fire == null){ if(fire == null){
fire = Pooling.obtain(Fire.class, Fire::new); fire = Pooling.obtain(Fire.class, Fire::new);
@@ -56,7 +56,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
fire.lifetime = baseLifetime; fire.lifetime = baseLifetime;
fire.set(tile.worldx(), tile.worldy()); fire.set(tile.worldx(), tile.worldy());
fire.add(); fire.add();
map.put(tile.packedPosition(), fire); map.put(tile.pos(), fire);
}else{ }else{
fire.lifetime = baseLifetime; fire.lifetime = baseLifetime;
fire.time = 0f; fire.time = 0f;
@@ -75,8 +75,8 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
* Attempts to extinguish a fire by shortening its life. If there is no fire here, does nothing. * Attempts to extinguish a fire by shortening its life. If there is no fire here, does nothing.
*/ */
public static void extinguish(Tile tile, float intensity){ public static void extinguish(Tile tile, float intensity){
if(tile != null && map.containsKey(tile.packedPosition())){ if(tile != null && map.containsKey(tile.pos())){
map.get(tile.packedPosition()).time += intensity * Timers.delta(); map.get(tile.pos()).time += intensity * Timers.delta();
} }
} }
@@ -157,7 +157,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
@Override @Override
public void writeSave(DataOutput stream) throws IOException{ public void writeSave(DataOutput stream) throws IOException{
stream.writeInt(tile.packedPosition()); stream.writeInt(tile.pos());
stream.writeFloat(lifetime); stream.writeFloat(lifetime);
stream.writeFloat(time); stream.writeFloat(time);
} }
@@ -202,7 +202,7 @@ public class Fire extends TimedEntity implements SaveTrait, SyncTrait, Poolable{
@Override @Override
public void removed(){ public void removed(){
if(tile != null){ if(tile != null){
map.remove(tile.packedPosition()); map.remove(tile.pos());
} }
reset(); reset();
} }

View File

@@ -6,7 +6,7 @@ import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Effects.Effect; import io.anuke.ucore.core.Effects.Effect;
import io.anuke.ucore.core.Timers; import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.impl.EffectEntity; import io.anuke.ucore.entities.impl.EffectEntity;
import io.anuke.ucore.function.EffectRenderer; import io.anuke.ucore.core.Effects.EffectRenderer;
import io.anuke.ucore.util.Mathf; import io.anuke.ucore.util.Mathf;
/** /**

View File

@@ -91,7 +91,6 @@ public class Lightning extends TimedEntity implements DrawTrait, SyncTrait, Time
x += Angles.trnsx(rotation, hitRange/2f); x += Angles.trnsx(rotation, hitRange/2f);
y += Angles.trnsy(rotation, hitRange/2f); y += Angles.trnsy(rotation, hitRange/2f);
} }
} }
} }

View File

@@ -73,7 +73,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
/**Returns the puddle on the specified tile. May return null.*/ /**Returns the puddle on the specified tile. May return null.*/
public static Puddle getPuddle(Tile tile){ public static Puddle getPuddle(Tile tile){
return map.get(tile.packedPosition()); return map.get(tile.pos());
} }
private static void deposit(Tile tile, Tile source, Liquid liquid, float amount, int generation){ private static void deposit(Tile tile, Tile source, Liquid liquid, float amount, int generation){
@@ -83,7 +83,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
reactPuddle(tile.floor().liquidDrop, liquid, amount, tile, reactPuddle(tile.floor().liquidDrop, liquid, amount, tile,
(tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f); (tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f);
Puddle p = map.get(tile.packedPosition()); Puddle p = map.get(tile.pos());
if(generation == 0 && p != null && p.lastRipple <= Timers.time() - 40f){ if(generation == 0 && p != null && p.lastRipple <= Timers.time() - 40f){
Effects.effect(BlockFx.ripple, tile.floor().liquidDrop.color, Effects.effect(BlockFx.ripple, tile.floor().liquidDrop.color,
@@ -93,7 +93,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
return; return;
} }
Puddle p = map.get(tile.packedPosition()); Puddle p = map.get(tile.pos());
if(p == null){ if(p == null){
if(Net.client()) return; //not clientside. if(Net.client()) return; //not clientside.
@@ -104,7 +104,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
puddle.generation = (byte) generation; puddle.generation = (byte) generation;
puddle.set((tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f); puddle.set((tile.worldx() + source.worldx()) / 2f, (tile.worldy() + source.worldy()) / 2f);
puddle.add(); puddle.add();
map.put(tile.packedPosition(), puddle); map.put(tile.pos(), puddle);
}else if(p.liquid == liquid){ }else if(p.liquid == liquid){
p.accepting = Math.max(amount, p.accepting); p.accepting = Math.max(amount, p.accepting);
@@ -249,7 +249,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
@Override @Override
public void writeSave(DataOutput stream) throws IOException{ public void writeSave(DataOutput stream) throws IOException{
stream.writeInt(tile.packedPosition()); stream.writeInt(tile.pos());
stream.writeFloat(x); stream.writeFloat(x);
stream.writeFloat(y); stream.writeFloat(y);
stream.writeByte(liquid.id); stream.writeByte(liquid.id);
@@ -288,7 +288,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
@Override @Override
public void removed(){ public void removed(){
map.remove(tile.packedPosition()); map.remove(tile.pos());
reset(); reset();
} }
@@ -298,7 +298,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
data.writeFloat(y); data.writeFloat(y);
data.writeByte(liquid.id); data.writeByte(liquid.id);
data.writeShort((short) (amount * 4)); data.writeShort((short) (amount * 4));
data.writeInt(tile.packedPosition()); data.writeInt(tile.pos());
} }
@Override @Override
@@ -309,7 +309,7 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
targetAmount = data.readShort() / 4f; targetAmount = data.readShort() / 4f;
tile = world.tile(data.readInt()); tile = world.tile(data.readInt());
map.put(tile.packedPosition(), this); map.put(tile.pos(), this);
} }
@Override @Override

View File

@@ -16,6 +16,7 @@ import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.Recipe; import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.world.Build; import io.anuke.mindustry.world.Build;
import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.BuildBlock; import io.anuke.mindustry.world.blocks.BuildBlock;
import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity; import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity;
@@ -27,7 +28,10 @@ import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.graphics.Fill; import io.anuke.ucore.graphics.Fill;
import io.anuke.ucore.graphics.Lines; import io.anuke.ucore.graphics.Lines;
import io.anuke.ucore.graphics.Shapes; import io.anuke.ucore.graphics.Shapes;
import io.anuke.ucore.util.*; import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Translator;
import java.io.DataInput; import java.io.DataInput;
import java.io.DataOutput; import java.io.DataOutput;
@@ -72,7 +76,7 @@ public interface BuilderTrait extends Entity{
if(request != null){ if(request != null){
output.writeByte(request.breaking ? 1 : 0); output.writeByte(request.breaking ? 1 : 0);
output.writeInt(world.toPacked(request.x, request.y)); output.writeInt(Pos.get(request.x, request.y));
output.writeFloat(request.progress); output.writeFloat(request.progress);
if(!request.breaking){ if(!request.breaking){
output.writeByte(request.recipe.id); output.writeByte(request.recipe.id);
@@ -97,11 +101,11 @@ public interface BuilderTrait extends Entity{
BuildRequest request; BuildRequest request;
if(type == 1){ //remove if(type == 1){ //remove
request = new BuildRequest(position % world.width(), position / world.width()); request = new BuildRequest(Pos.x(position), Pos.y(position));
}else{ //place }else{ //place
byte recipe = input.readByte(); byte recipe = input.readByte();
byte rotation = input.readByte(); byte rotation = input.readByte();
request = new BuildRequest(position % world.width(), position / world.width(), rotation, content.recipe(recipe)); request = new BuildRequest(Pos.x(position), Pos.y(position), rotation, content.recipe(recipe));
} }
request.progress = progress; request.progress = progress;

View File

@@ -52,7 +52,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
protected boolean isWave; protected boolean isWave;
protected Squad squad; protected Squad squad;
protected int spawner = -1; protected int spawner = noSpawner;
/**internal constructor used for deserialization, DO NOT USE*/ /**internal constructor used for deserialization, DO NOT USE*/
public BaseUnit(){ public BaseUnit(){
@@ -111,16 +111,8 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
return type; return type;
} }
public Tile getSpawner(){
return world.tile(spawner);
}
public void setSpawner(Tile tile){ public void setSpawner(Tile tile){
this.spawner = tile.packedPosition(); this.spawner = tile.pos();
}
public void setIntSpawner(int pos){
this.spawner = pos;
} }
/**Sets this to a 'wave' unit, which means it has slightly different AI and will not run out of ammo.*/ /**Sets this to a 'wave' unit, which means it has slightly different AI and will not run out of ammo.*/
@@ -143,7 +135,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
} }
public void updateRespawning(){ public void updateRespawning(){
if(spawner == -1) return; if(spawner == noSpawner) return;
Tile tile = world.tile(spawner); Tile tile = world.tile(spawner);
if(tile != null && tile.entity != null){ if(tile != null && tile.entity != null){
@@ -151,7 +143,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
((SpawnerTrait) tile.entity).updateSpawning(this); ((SpawnerTrait) tile.entity).updateSpawning(this);
} }
}else{ }else{
spawner = -1; spawner = noSpawner;
} }
} }
@@ -305,7 +297,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
avoidOthers(1.25f); avoidOthers(1.25f);
if(spawner != -1 && (world.tile(spawner) == null || world.tile(spawner).entity == null)){ if(spawner != noSpawner && (world.tile(spawner) == null || world.tile(spawner).entity == null)){
damage(health); damage(health);
} }
@@ -336,7 +328,7 @@ public abstract class BaseUnit extends Unit implements ShooterTrait{
@Override @Override
public void removed(){ public void removed(){
spawner = -1; spawner = noSpawner;
} }
@Override @Override

View File

@@ -358,8 +358,8 @@ public class Drone extends FlyingUnit implements BuilderTrait{
@Override @Override
public void write(DataOutput data) throws IOException{ public void write(DataOutput data) throws IOException{
super.write(data); super.write(data);
data.writeInt(mineTile == null || !state.is(mine) ? -1 : mineTile.packedPosition()); data.writeInt(mineTile == null || !state.is(mine) ? -1 : mineTile.pos());
data.writeInt(state.is(repair) && target instanceof TileEntity ? ((TileEntity)target).tile.packedPosition() : -1); data.writeInt(state.is(repair) && target instanceof TileEntity ? ((TileEntity)target).tile.pos() : -1);
writeBuilding(data); writeBuilding(data);
} }

View File

@@ -3,7 +3,7 @@ package io.anuke.mindustry.game;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.traits.BuilderTrait; import io.anuke.mindustry.entities.traits.BuilderTrait;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.function.Event; import io.anuke.ucore.core.Events.Event;
public class EventType{ public class EventType{

View File

@@ -11,7 +11,7 @@ public enum GameMode{
freebuild{{ freebuild{{
disableWaveTimer = true; disableWaveTimer = true;
}}, }},
noWaves{{ attack{{
disableWaves = true; disableWaves = true;
hidden = true; hidden = true;
enemyCheat = true; enemyCheat = true;

View File

@@ -127,6 +127,7 @@ public class Saves{
saveMap.put(slot.index, slot); saveMap.put(slot.index, slot);
slot.meta = SaveIO.getData(slot.index); slot.meta = SaveIO.getData(slot.index);
current = slot; current = slot;
slot.meta.sector = invalidSector;
saveSlots(); saveSlots();
return slot; return slot;
} }
@@ -164,14 +165,7 @@ public class Saves{
public void save(){ public void save(){
long time = totalPlaytime; long time = totalPlaytime;
threads.runGraphics(() -> {
//Renderer fog needs to be written on graphics thread, but save() can run on logic thread
//thus, runGraphics is required here
renderer.fog.writeFog(); renderer.fog.writeFog();
//save on the logic thread
threads.run(() -> {
long prev = totalPlaytime; long prev = totalPlaytime;
totalPlaytime = time; totalPlaytime = time;
@@ -182,8 +176,6 @@ public class Saves{
} }
totalPlaytime = prev; totalPlaytime = prev;
});
});
} }
public boolean isHidden(){ public boolean isHidden(){

View File

@@ -96,6 +96,14 @@ public class Waves{
max = 10; max = 10;
}}, }},
new SpawnGroup(UnitTypes.fortress){{
begin = 40;
spacing = 5;
unitAmount = 2;
unitScaling = 3;
max = 10;
}},
new SpawnGroup(UnitTypes.dagger){{ new SpawnGroup(UnitTypes.dagger){{
begin = 35; begin = 35;
spacing = 3; spacing = 3;
@@ -134,6 +142,15 @@ public class Waves{
max = 8; max = 8;
}}, }},
new SpawnGroup(UnitTypes.revenant){{
begin = 50;
unitAmount = 4;
unitScaling = 3;
spacing = 5;
groupAmount = 2;
max = 8;
}},
new SpawnGroup(UnitTypes.ghoul){{ new SpawnGroup(UnitTypes.ghoul){{
begin = 53; begin = 53;
unitAmount = 2; unitAmount = 2;

View File

@@ -77,9 +77,11 @@ public class FogRenderer implements Disposable{
pixelBuffer.position(0); pixelBuffer.position(0);
for(int i = 0; i < world.width() * world.height(); i++){ for(int i = 0; i < world.width() * world.height(); i++){
int x = i % world.width();
int y = i / world.width();
byte r = pixelBuffer.get(); byte r = pixelBuffer.get();
if(r != 0){ if(r != 0){
world.tile(i).setVisibility((byte)1); world.tile(x, y).setVisibility((byte)1);
} }
pixelBuffer.position(pixelBuffer.position() + 3); pixelBuffer.position(pixelBuffer.position() + 3);
} }
@@ -128,12 +130,14 @@ public class FogRenderer implements Disposable{
changeQueue.clear(); changeQueue.clear();
if(dirty){ if(dirty){
for(int i = 0; i < world.width() * world.height(); i++){ for(int x = 0; x < world.width(); x++){
Tile tile = world.tile(i); for(int y = 0; y < world.height(); y++){
Tile tile = world.tile(x, y);
if(tile.discovered()){ if(tile.discovered()){
Fill.rect(tile.worldx(), tile.worldy(), tilesize, tilesize); Fill.rect(tile.worldx(), tile.worldy(), tilesize, tilesize);
} }
} }
}
dirty = false; dirty = false;
} }

View File

@@ -200,9 +200,10 @@ public class OverlayRenderer{
} }
void drawBar(Color color, float x, float y, float finion){ void drawBar(Color color, float x, float y, float finion){
if(finion > 0.9f) finion = 1f; //fixes precision errors
finion = Mathf.clamp(finion); finion = Mathf.clamp(finion);
if(finion > 0) finion = Mathf.clamp(finion + 0.2f, 0.24f, 1f); if(finion > 0.001f) finion = Mathf.clamp(finion, 0.24f, 1f);
float len = 3; float len = 3;

View File

@@ -95,7 +95,7 @@ public abstract class InputHandler extends InputAdapter{
ItemTransfer.create(item, ItemTransfer.create(item,
player.x + Angles.trnsx(player.rotation + 180f, backTrns), player.y + Angles.trnsy(player.rotation + 180f, backTrns), player.x + Angles.trnsx(player.rotation + 180f, backTrns), player.y + Angles.trnsy(player.rotation + 180f, backTrns),
new Translator(tile.drawx() + stackTrns.x, tile.drawy() + stackTrns.y), () -> { new Translator(tile.drawx() + stackTrns.x, tile.drawy() + stackTrns.y), () -> {
if(tile.block() != block || tile.entity == null) return; if(tile.block() != block || tile.entity == null || tile.entity.items == null) return;
tile.block().handleStack(item, removed, tile, player); tile.block().handleStack(item, removed, tile, player);
remaining[1] -= removed; remaining[1] -= removed;

View File

@@ -598,6 +598,10 @@ public class MobileInput extends InputHandler implements GestureListener{
showGuide("construction"); showGuide("construction");
} }
if(recipe == null && mode == placing){
mode = none;
}
//automatically switch to placing after a new recipe is selected //automatically switch to placing after a new recipe is selected
if(lastRecipe != recipe && mode == breaking && recipe != null){ if(lastRecipe != recipe && mode == breaking && recipe != null){
mode = placing; mode = placing;

View File

@@ -50,7 +50,7 @@ public abstract class SaveFileVersion{
stream.writeShort(world.height()); stream.writeShort(world.height());
for(int i = 0; i < world.width() * world.height(); i++){ for(int i = 0; i < world.width() * world.height(); i++){
Tile tile = world.tile(i); Tile tile = world.tile(i % world.width(), i / world.width());
stream.writeByte(tile.getFloorID()); stream.writeByte(tile.getFloorID());
stream.writeByte(tile.getBlockID()); stream.writeByte(tile.getBlockID());
@@ -73,7 +73,7 @@ public abstract class SaveFileVersion{
int consecutives = 0; int consecutives = 0;
for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){ for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){
Tile nextTile = world.tile(j); Tile nextTile = world.tile(j % world.width(), j / world.width());
if(nextTile.getFloorID() != tile.getFloorID() || nextTile.block() != Blocks.air || nextTile.getElevation() != tile.getElevation()){ if(nextTile.getFloorID() != tile.getFloorID() || nextTile.block() != Blocks.air || nextTile.getElevation() != tile.getElevation()){
break; break;
@@ -89,13 +89,13 @@ public abstract class SaveFileVersion{
//write visibility, length-run encoded //write visibility, length-run encoded
for(int i = 0; i < world.width() * world.height(); i++){ for(int i = 0; i < world.width() * world.height(); i++){
Tile tile = world.tile(i); Tile tile = world.tile(i % world.width(), i / world.width());
boolean discovered = tile.discovered(); boolean discovered = tile.discovered();
int consecutives = 0; int consecutives = 0;
for(int j = i + 1; j < world.width() * world.height() && consecutives < 32767*2-1; j++){ for(int j = i + 1; j < world.width() * world.height() && consecutives < 32767*2-1; j++){
Tile nextTile = world.tile(j); Tile nextTile = world.tile(j % world.width(), j / world.width());
if(nextTile.discovered() != discovered){ if(nextTile.discovered() != discovered){
break; break;

View File

@@ -14,7 +14,7 @@ import java.util.zip.InflaterInputStream;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
public class SaveIO{ public class SaveIO{
public static final IntArray breakingVersions = IntArray.with(47, 48, 49, 50, 51, 52, 53, 54, 55, 56); public static final IntArray breakingVersions = IntArray.with(47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58);
public static final IntMap<SaveFileVersion> versions = new IntMap<>(); public static final IntMap<SaveFileVersion> versions = new IntMap<>();
public static final Array<SaveFileVersion> versionArray = Array.with( public static final Array<SaveFileVersion> versionArray = Array.with(
new Save16() new Save16()

View File

@@ -18,6 +18,7 @@ import io.anuke.mindustry.net.Packets.AdminAction;
import io.anuke.mindustry.net.Packets.KickReason; import io.anuke.mindustry.net.Packets.KickReason;
import io.anuke.mindustry.type.*; import io.anuke.mindustry.type.*;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Effects.Effect; import io.anuke.ucore.core.Effects.Effect;
@@ -52,6 +53,10 @@ public class TypeIO{
@WriteClass(Unit.class) @WriteClass(Unit.class)
public static void writeUnit(ByteBuffer buffer, Unit unit){ public static void writeUnit(ByteBuffer buffer, Unit unit){
if(unit.getGroup() == null){
buffer.put((byte)-1);
return;
}
buffer.put((byte) unit.getGroup().getID()); buffer.put((byte) unit.getGroup().getID());
buffer.putInt(unit.getID()); buffer.putInt(unit.getID());
} }
@@ -59,6 +64,7 @@ public class TypeIO{
@ReadClass(Unit.class) @ReadClass(Unit.class)
public static Unit readUnit(ByteBuffer buffer){ public static Unit readUnit(ByteBuffer buffer){
byte gid = buffer.get(); byte gid = buffer.get();
if(gid == -1) return null;
int id = buffer.getInt(); int id = buffer.getInt();
return (Unit) Entities.getGroup(gid).getByID(id); return (Unit) Entities.getGroup(gid).getByID(id);
} }
@@ -142,13 +148,12 @@ public class TypeIO{
@WriteClass(Tile.class) @WriteClass(Tile.class)
public static void writeTile(ByteBuffer buffer, Tile tile){ public static void writeTile(ByteBuffer buffer, Tile tile){
buffer.putInt(tile == null ? -1 : tile.packedPosition()); buffer.putInt(tile == null ? Pos.get(-1, -1) : tile.pos());
} }
@ReadClass(Tile.class) @ReadClass(Tile.class)
public static Tile readTile(ByteBuffer buffer){ public static Tile readTile(ByteBuffer buffer){
int position = buffer.getInt(); return world.tile(buffer.getInt());
return position == -1 ? null : world.tile(position);
} }
@WriteClass(Block.class) @WriteClass(Block.class)
@@ -166,7 +171,7 @@ public class TypeIO{
buffer.putShort((short)requests.length); buffer.putShort((short)requests.length);
for(BuildRequest request : requests){ for(BuildRequest request : requests){
buffer.put(request.breaking ? (byte) 1 : 0); buffer.put(request.breaking ? (byte) 1 : 0);
buffer.putInt(world.toPacked(request.x, request.y)); buffer.putInt(Pos.get(request.x, request.y));
if(!request.breaking){ if(!request.breaking){
buffer.put(request.recipe.id); buffer.put(request.recipe.id);
buffer.put((byte) request.rotation); buffer.put((byte) request.rotation);
@@ -184,11 +189,11 @@ public class TypeIO{
BuildRequest currentRequest; BuildRequest currentRequest;
if(type == 1){ //remove if(type == 1){ //remove
currentRequest = new BuildRequest(position % world.width(), position / world.width()); currentRequest = new BuildRequest(Pos.x(position), Pos.y(position));
}else{ //place }else{ //place
byte recipe = buffer.get(); byte recipe = buffer.get();
byte rotation = buffer.get(); byte rotation = buffer.get();
currentRequest = new BuildRequest(position % world.width(), position / world.width(), rotation, content.recipe(recipe)); currentRequest = new BuildRequest(Pos.x(position), Pos.y(position), rotation, content.recipe(recipe));
} }
reqs[i] = (currentRequest); reqs[i] = (currentRequest);

View File

@@ -59,7 +59,7 @@ public class Save16 extends SaveFileVersion{
stream.writeLong(TimeUtils.millis()); //last saved stream.writeLong(TimeUtils.millis()); //last saved
stream.writeLong(headless ? 0 : control.saves.getTotalPlaytime()); //playtime stream.writeLong(headless ? 0 : control.saves.getTotalPlaytime()); //playtime
stream.writeInt(Version.build); //build stream.writeInt(Version.build); //build
stream.writeInt(world.getSector() == null ? invalidSector : world.getSector().packedPosition()); //sector ID stream.writeInt(world.getSector() == null ? invalidSector : world.getSector().pos()); //sector ID
//--GENERAL STATE-- //--GENERAL STATE--
stream.writeByte(state.mode.ordinal()); //gamemode stream.writeByte(state.mode.ordinal()); //gamemode

View File

@@ -67,7 +67,7 @@ public class Sector{
return !headless && control.saves.getByID(saveID) != null; return !headless && control.saves.getByID(saveID) != null;
} }
public int packedPosition(){ public int pos(){
return Bits.packInt(x, y); return Bits.packInt(x, y);
} }
} }

View File

@@ -53,7 +53,7 @@ public class Sectors{
world.loadSector(sector); world.loadSector(sector);
logic.play(); logic.play();
if(!headless){ if(!headless){
sector.saveID = control.saves.addSave("sector-" + sector.packedPosition()).index; sector.saveID = control.saves.addSave("sector-" + sector.pos()).index;
} }
world.sectors.save(); world.sectors.save();
world.setSector(sector); world.setSector(sector);

View File

@@ -17,6 +17,7 @@ import io.anuke.mindustry.maps.Sector;
import io.anuke.mindustry.maps.missions.Mission; import io.anuke.mindustry.maps.missions.Mission;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Floor; import io.anuke.mindustry.world.blocks.Floor;
import io.anuke.mindustry.world.blocks.OreBlock; import io.anuke.mindustry.world.blocks.OreBlock;
@@ -86,7 +87,7 @@ public class WorldGenerator{
Tile tile = tiles[x][y]; Tile tile = tiles[x][y];
if(tile.block().isMultiblock()){ if(tile.block().isMultiblock()){
multiblocks.add(tile.packedPosition()); multiblocks.add(tile.pos());
} }
} }
} }
@@ -95,8 +96,8 @@ public class WorldGenerator{
for(int i = 0; i < multiblocks.size; i++){ for(int i = 0; i < multiblocks.size; i++){
int pos = multiblocks.get(i); int pos = multiblocks.get(i);
int x = pos % tiles.length; int x = Pos.x(pos);
int y = pos / tiles.length; int y = Pos.y(pos);
Block result = tiles[x][y].block(); Block result = tiles[x][y].block();
Team team = tiles[x][y].getTeam(); Team team = tiles[x][y].getTeam();

View File

@@ -38,7 +38,7 @@ public class BattleMission extends MissionWithStartingCore{
@Override @Override
public GameMode getMode(){ public GameMode getMode(){
return GameMode.noWaves; return GameMode.attack;
} }
@Override @Override

View File

@@ -2,10 +2,8 @@ package io.anuke.mindustry.maps.missions;
import com.badlogic.gdx.math.GridPoint2; import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.content.blocks.StorageBlocks;
import io.anuke.mindustry.game.GameMode; import io.anuke.mindustry.game.GameMode;
import io.anuke.mindustry.game.SpawnGroup; import io.anuke.mindustry.game.SpawnGroup;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.game.UnlockableContent; import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.mindustry.maps.Sector; import io.anuke.mindustry.maps.Sector;
import io.anuke.mindustry.maps.generation.Generation; import io.anuke.mindustry.maps.generation.Generation;
@@ -34,7 +32,7 @@ public abstract class Mission{
} }
public GameMode getMode(){ public GameMode getMode(){
return GameMode.noWaves; return GameMode.attack;
} }
/**Sets the message displayed on mission begin. Returns this mission for chaining.*/ /**Sets the message displayed on mission begin. Returns this mission for chaining.*/

View File

@@ -42,6 +42,13 @@ public abstract class MissionWithStartingCore extends Mission{
startingCoreTile.setBlock(StorageBlocks.core); startingCoreTile.setBlock(StorageBlocks.core);
startingCoreTile.setTeam(team); startingCoreTile.setTeam(team);
state.teams.get(team).cores.add(startingCoreTile); state.teams.get(team).cores.add(startingCoreTile);
//makes sure there's a flat area around core
for(int dx = -2; dx <= 2; dx++){
for(int dy = -2; dy <= 2; dy++){
gen.tiles[startingCoreTile.x + dx][startingCoreTile.y + dy].setElevation(startingCoreTile.getElevation());
}
}
} }
/** /**

View File

@@ -74,7 +74,7 @@ public class WaveMission extends MissionWithStartingCore{
@Override @Override
public void update(){ public void update(){
if(state.wave > target){ if(state.wave > target){
state.mode = GameMode.noWaves; state.mode = GameMode.attack;
} }
} }

View File

@@ -1,5 +1,7 @@
package io.anuke.mindustry.net; package io.anuke.mindustry.net;
import io.anuke.mindustry.game.GameMode;
public class Host{ public class Host{
public final String name; public final String name;
public final String address; public final String address;
@@ -8,8 +10,9 @@ public class Host{
public final int players; public final int players;
public final int version; public final int version;
public final String versionType; public final String versionType;
public final GameMode mode;
public Host(String name, String address, String mapname, int wave, int players, int version, String versionType){ public Host(String name, String address, String mapname, int wave, int players, int version, String versionType, GameMode mode){
this.name = name; this.name = name;
this.address = address; this.address = address;
this.players = players; this.players = players;
@@ -17,5 +20,6 @@ public class Host{
this.wave = wave; this.wave = wave;
this.version = version; this.version = version;
this.versionType = versionType; this.versionType = versionType;
this.mode = mode;
} }
} }

View File

@@ -21,6 +21,7 @@ import io.anuke.ucore.util.Bits;
import java.io.*; import java.io.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -32,7 +33,7 @@ public class NetworkIO{
//--GENERAL STATE-- //--GENERAL STATE--
stream.writeByte(state.mode.ordinal()); //gamemode stream.writeByte(state.mode.ordinal()); //gamemode
stream.writeUTF(world.getMap().name); //map name stream.writeUTF(world.getMap().name); //map name
stream.writeInt(world.getSector() == null ? invalidSector : world.getSector().packedPosition()); //sector ID stream.writeInt(world.getSector() == null ? invalidSector : world.getSector().pos()); //sector ID
stream.writeInt(world.getSector() == null ? 0 : world.getSector().completedMissions); stream.writeInt(world.getSector() == null ? 0 : world.getSector().completedMissions);
//write tags //write tags
@@ -56,7 +57,7 @@ public class NetworkIO{
stream.writeShort(world.height()); stream.writeShort(world.height());
for(int i = 0; i < world.width() * world.height(); i++){ for(int i = 0; i < world.width() * world.height(); i++){
Tile tile = world.tile(i); Tile tile = world.tile(i % world.width(), i / world.width());
stream.writeByte(tile.getFloorID()); stream.writeByte(tile.getFloorID());
stream.writeByte(tile.getBlockID()); stream.writeByte(tile.getBlockID());
@@ -79,7 +80,7 @@ public class NetworkIO{
int consecutives = 0; int consecutives = 0;
for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){ for(int j = i + 1; j < world.width() * world.height() && consecutives < 255; j++){
Tile nextTile = world.tile(j); Tile nextTile = world.tile(j % world.width(), j / world.width());
if(nextTile.getFloorID() != tile.getFloorID() || nextTile.block() != Blocks.air || nextTile.getElevation() != tile.getElevation()){ if(nextTile.getFloorID() != tile.getFloorID() || nextTile.block() != Blocks.air || nextTile.getElevation() != tile.getElevation()){
break; break;
@@ -95,13 +96,13 @@ public class NetworkIO{
//write visibility, length-run encoded //write visibility, length-run encoded
for(int i = 0; i < world.width() * world.height(); i++){ for(int i = 0; i < world.width() * world.height(); i++){
Tile tile = world.tile(i); Tile tile = world.tile(i % world.width(), i / world.width());;
boolean discovered = tile.discovered(); boolean discovered = tile.discovered();
int consecutives = 0; int consecutives = 0;
for(int j = i + 1; j < world.width() * world.height() && consecutives < 32767*2-1; j++){ for(int j = i + 1; j < world.width() * world.height() && consecutives < 32767*2-1; j++){
Tile nextTile = world.tile(j); Tile nextTile = world.tile(j % world.width(), j / world.width());;
if(nextTile.discovered() != discovered){ if(nextTile.discovered() != discovered){
break; break;
@@ -129,7 +130,7 @@ public class NetworkIO{
stream.writeByte(data.cores.size); stream.writeByte(data.cores.size);
for(Tile tile : data.cores){ for(Tile tile : data.cores){
stream.writeInt(tile.packedPosition()); stream.writeInt(tile.pos());
} }
} }
@@ -305,17 +306,18 @@ public class NetworkIO{
ByteBuffer buffer = ByteBuffer.allocate(128); ByteBuffer buffer = ByteBuffer.allocate(128);
buffer.put((byte) host.getBytes().length); buffer.put((byte) host.getBytes(StandardCharsets.UTF_8).length);
buffer.put(host.getBytes()); buffer.put(host.getBytes(StandardCharsets.UTF_8));
buffer.put((byte) map.getBytes().length); buffer.put((byte) map.getBytes(StandardCharsets.UTF_8).length);
buffer.put(map.getBytes()); buffer.put(map.getBytes(StandardCharsets.UTF_8));
buffer.putInt(playerGroup.size()); buffer.putInt(playerGroup.size());
buffer.putInt(state.wave); buffer.putInt(state.wave);
buffer.putInt(Version.build); buffer.putInt(Version.build);
buffer.put((byte)Version.type.getBytes().length); buffer.put((byte)Version.type.getBytes(StandardCharsets.UTF_8).length);
buffer.put(Version.type.getBytes()); buffer.put(Version.type.getBytes(StandardCharsets.UTF_8));
buffer.put((byte)state.mode.ordinal());
return buffer; return buffer;
} }
@@ -328,8 +330,8 @@ public class NetworkIO{
byte[] mb = new byte[mlength]; byte[] mb = new byte[mlength];
buffer.get(mb); buffer.get(mb);
String host = new String(hb); String host = new String(hb, StandardCharsets.UTF_8);
String map = new String(mb); String map = new String(mb, StandardCharsets.UTF_8);
int players = buffer.getInt(); int players = buffer.getInt();
int wave = buffer.getInt(); int wave = buffer.getInt();
@@ -337,8 +339,9 @@ public class NetworkIO{
byte tlength = buffer.get(); byte tlength = buffer.get();
byte[] tb = new byte[tlength]; byte[] tb = new byte[tlength];
buffer.get(tb); buffer.get(tb);
String vertype = new String(tb); String vertype = new String(tb, StandardCharsets.UTF_8);
GameMode mode = GameMode.values()[buffer.get()];
return new Host(host, hostAddress, map, wave, players, version, vertype); return new Host(host, hostAddress, map, wave, players, version, vertype, mode);
} }
} }

View File

@@ -38,10 +38,6 @@ public class FileChooser extends FloatingDialog{
private Consumer<FileHandle> selectListener; private Consumer<FileHandle> selectListener;
private boolean open; private boolean open;
public FileChooser(String title, boolean open, Consumer<FileHandle> result){
this(title, defaultFilter, open, result);
}
public FileChooser(String title, Predicate<FileHandle> filter, boolean open, Consumer<FileHandle> result){ public FileChooser(String title, Predicate<FileHandle> filter, boolean open, Consumer<FileHandle> result){
super(title); super(title);
this.open = open; this.open = open;
@@ -127,7 +123,7 @@ public class FileChooser extends FloatingDialog{
updateFiles(true); updateFiles(true);
}); });
icontable.defaults().height(50).growX().uniform(); icontable.defaults().height(50).growX().padTop(5).uniform();
icontable.add(home); icontable.add(home);
icontable.add(back); icontable.add(back);
icontable.add(forward); icontable.add(forward);
@@ -202,7 +198,7 @@ public class FileChooser extends FloatingDialog{
//macs are confined to the Downloads/ directory //macs are confined to the Downloads/ directory
if(!OS.isMac){ if(!OS.isMac){
Image upimage = new Image("icon-folder-parent"); Image upimage = new Image("icon-folder-parent");
TextButton upbutton = new TextButton(".." + directory.toString()); TextButton upbutton = new TextButton(".." + directory.toString(), "clear-toggle");
upbutton.clicked(() -> { upbutton.clicked(() -> {
directory = directory.parent(); directory = directory.parent();
updateFiles(true); updateFiles(true);
@@ -224,7 +220,7 @@ public class FileChooser extends FloatingDialog{
String filename = file.name(); String filename = file.name();
TextButton button = new TextButton(shorten(filename), "toggle"); TextButton button = new TextButton(shorten(filename), "clear-toggle");
group.add(button); group.add(button);
button.clicked(() -> { button.clicked(() -> {

View File

@@ -268,6 +268,7 @@ public class JoinDialog extends FloatingDialog{
if(totalHosts == 0){ if(totalHosts == 0){
local.clear(); local.clear();
} }
local.background((Drawable) null);
totalHosts ++; totalHosts ++;
float w = targetWidth(); float w = targetWidth();

View File

@@ -161,6 +161,7 @@ public class LoadDialog extends FloatingDialog{
control.saves.importSave(file); control.saves.importSave(file);
setup(); setup();
}catch(IOException e){ }catch(IOException e){
e.printStackTrace();
ui.showError(Bundles.format("text.save.import.fail", Strings.parseException(e, false))); ui.showError(Bundles.format("text.save.import.fail", Strings.parseException(e, false)));
} }
}else{ }else{

View File

@@ -36,9 +36,11 @@ public class PlacementFragment extends Fragment{
Tile hoverTile; Tile hoverTile;
Table blockTable, toggler, topTable; Table blockTable, toggler, topTable;
boolean shown = true; boolean shown = true;
boolean lastGround;
public PlacementFragment(){ public PlacementFragment(){
Events.on(WorldLoadGraphicsEvent.class, event -> { Events.on(WorldLoadGraphicsEvent.class, event -> {
currentCategory = Category.turret;
Group group = toggler.getParent(); Group group = toggler.getParent();
toggler.remove(); toggler.remove();
build(group); build(group);
@@ -109,13 +111,14 @@ public class PlacementFragment extends Fragment{
frame.table("button-edge-2", top -> { frame.table("button-edge-2", top -> {
topTable = top; topTable = top;
top.add(new Table()).growX().update(topTable -> { top.add(new Table()).growX().update(topTable -> {
if((tileDisplayBlock() == null && lastDisplay == getSelected()) || if((tileDisplayBlock() == null && lastDisplay == getSelected() && !lastGround) ||
(tileDisplayBlock() != null && lastDisplay == tileDisplayBlock())) return; (tileDisplayBlock() != null && lastDisplay == tileDisplayBlock() && lastGround)) return;
topTable.clear(); topTable.clear();
topTable.top().left().margin(5); topTable.top().left().margin(5);
lastDisplay = getSelected(); lastDisplay = getSelected();
lastGround = tileDisplayBlock() != null;
if(lastDisplay != null){ //show selected recipe if(lastDisplay != null){ //show selected recipe
topTable.table(header -> { topTable.table(header -> {
@@ -181,7 +184,7 @@ public class PlacementFragment extends Fragment{
categories.addImageButton("icon-" + cat.name(), "clear-toggle", 16*2, () -> { categories.addImageButton("icon-" + cat.name(), "clear-toggle", 16*2, () -> {
currentCategory = cat; currentCategory = cat;
rebuildCategory.run(); rebuildCategory.run();
}).group(group); }).group(group).update(i -> i.setChecked(currentCategory == cat));
if(cat.ordinal() %2 == 1) categories.row(); if(cat.ordinal() %2 == 1) categories.row();
} }

View File

@@ -116,7 +116,7 @@ public class PlayerListFragment extends Fragment{
t.row(); t.row();
t.addImageButton("icon-admin", "clear-toggle", 14 * 2, () -> { t.addImageButton("icon-admin", "clear-toggle-partial", 14 * 2, () -> {
if(Net.client()) return; if(Net.client()) return;
String id = player.uuid; String id = player.uuid;

View File

@@ -165,7 +165,7 @@ public class Block extends BaseBlock {
for(int i = 0; i < tile.entity.power.links.size; i++){ for(int i = 0; i < tile.entity.power.links.size; i++){
Tile other = world.tile(tile.entity.power.links.get(i)); Tile other = world.tile(tile.entity.power.links.get(i));
if(other != null && other.entity != null && other.entity.power != null){ if(other != null && other.entity != null && other.entity.power != null){
other.entity.power.links.removeValue(tile.packedPosition()); other.entity.power.links.removeValue(tile.pos());
} }
} }
} }
@@ -174,7 +174,7 @@ public class Block extends BaseBlock {
out.clear(); out.clear();
for(Tile other : tile.entity.proximity()){ for(Tile other : tile.entity.proximity()){
if(other.entity.power != null && !(consumesPower && other.block().consumesPower && !outputsPower && !other.block().outputsPower) if(other.entity.power != null && !(consumesPower && other.block().consumesPower && !outputsPower && !other.block().outputsPower)
&& !tile.entity.power.links.contains(other.packedPosition())){ && !tile.entity.power.links.contains(other.pos())){
out.add(other); out.add(other);
} }
} }
@@ -345,12 +345,11 @@ public class Block extends BaseBlock {
} }
public void setBars(){ public void setBars(){
if(consumes.has(ConsumePower.class)) if(consumes.hasSubtypeOf(ConsumePower.class) && consumes.getSubtypeOf(ConsumePower.class).isBuffered){
bars.add(new BlockBar(BarType.power, true, tile -> tile.entity.power.satisfaction)); bars.add(new BlockBar(BarType.power, true, tile -> tile.entity.power.satisfaction));
if(hasLiquids) }
bars.add(new BlockBar(BarType.liquid, true, tile -> tile.entity.liquids.total() / liquidCapacity)); if(hasLiquids) bars.add(new BlockBar(BarType.liquid, true, tile -> tile.entity.liquids.total() / liquidCapacity));
if(hasItems) if(hasItems) bars.add(new BlockBar(BarType.inventory, true, tile -> (float) tile.entity.items.total() / itemCapacity));
bars.add(new BlockBar(BarType.inventory, true, tile -> (float) tile.entity.items.total() / itemCapacity));
} }
public String name(){ public String name(){
@@ -413,8 +412,8 @@ public class Block extends BaseBlock {
explosiveness += tile.entity.liquids.sum((liquid, amount) -> liquid.flammability * amount / 2f); explosiveness += tile.entity.liquids.sum((liquid, amount) -> liquid.flammability * amount / 2f);
} }
if(consumes.has(ConsumePower.class) && consumes.get(ConsumePower.class).isBuffered){ if(consumes.hasSubtypeOf(ConsumePower.class) && consumes.getSubtypeOf(ConsumePower.class).isBuffered){
power += tile.entity.power.satisfaction * consumes.get(ConsumePower.class).powerCapacity; power += tile.entity.power.satisfaction * consumes.getSubtypeOf(ConsumePower.class).powerCapacity;
} }
tempColor.mul(1f / units); tempColor.mul(1f / units);

View File

@@ -0,0 +1,20 @@
package io.anuke.mindustry.world;
/**Methods for a packed position 'struct', contained in an int.*/
public class Pos{
/**Returns packed position from an x/y position. The values must be within short limits.*/
public static int get(int x, int y){
return (((short)x) << 16) | (((short)y) & 0xFFFF);
}
/**Returns the x component of a position.*/
public static short x(int pos){
return (short) (pos >>> 16);
}
/**Returns the y component of a position.*/
public static short y(int pos){
return (short) (pos & 0xFFFF);
}
}

View File

@@ -71,8 +71,9 @@ public class Tile implements PosTrait, TargetTrait{
return visibility > 0; return visibility > 0;
} }
public int packedPosition(){ /**Returns this tile's position as a {@link Pos}.*/
return x + y * world.width(); public int pos(){
return Pos.get(x, y);
} }
public byte getBlockID(){ public byte getBlockID(){
@@ -104,10 +105,6 @@ public class Tile implements PosTrait, TargetTrait{
return (T) entity; return (T) entity;
} }
public int id(){
return x + y * world.width();
}
public float worldx(){ public float worldx(){
return x * tilesize; return x * tilesize;
} }

View File

@@ -130,16 +130,16 @@ public class Floor extends Block{
@Override @Override
public void drawNonLayer(Tile tile){ public void drawNonLayer(Tile tile){
MathUtils.random.setSeed(tile.id()); MathUtils.random.setSeed(tile.pos());
drawEdges(tile, true); drawEdges(tile, true);
} }
@Override @Override
public void draw(Tile tile){ public void draw(Tile tile){
MathUtils.random.setSeed(tile.id()); MathUtils.random.setSeed(tile.pos());
Draw.rect(variantRegions[Mathf.randomSeed(tile.id(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy()); Draw.rect(variantRegions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy());
if(tile.hasCliffs() && cliffRegions != null){ if(tile.hasCliffs() && cliffRegions != null){
for(int i = 0; i < 4; i++){ for(int i = 0; i < 4; i++){

View File

@@ -39,14 +39,14 @@ public class OreBlock extends Floor{
@Override @Override
public void draw(Tile tile){ public void draw(Tile tile){
Draw.rect(variantRegions[Mathf.randomSeed(tile.id(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy()); Draw.rect(variantRegions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, variantRegions.length - 1))], tile.worldx(), tile.worldy());
drawEdges(tile, false); drawEdges(tile, false);
} }
@Override @Override
public void drawNonLayer(Tile tile){ public void drawNonLayer(Tile tile){
MathUtils.random.setSeed(tile.id()); MathUtils.random.setSeed(tile.pos());
base.drawEdges(tile, true); base.drawEdges(tile, true);
} }

View File

@@ -19,7 +19,7 @@ public class Rock extends Block{
@Override @Override
public void draw(Tile tile){ public void draw(Tile tile){
if(variants > 0){ if(variants > 0){
Draw.rect(regions[Mathf.randomSeed(tile.id(), 0, Math.max(0, regions.length - 1))], tile.worldx(), tile.worldy()); Draw.rect(regions[Mathf.randomSeed(tile.pos(), 0, Math.max(0, regions.length - 1))], tile.worldx(), tile.worldy());
}else{ }else{
Draw.rect(region, tile.worldx(), tile.worldy()); Draw.rect(region, tile.worldx(), tile.worldy());
} }
@@ -28,7 +28,7 @@ public class Rock extends Block{
@Override @Override
public void drawShadow(Tile tile){ public void drawShadow(Tile tile){
if(shadowRegions != null){ if(shadowRegions != null){
Draw.rect(shadowRegions[(Mathf.randomSeed(tile.id(), 0, variants - 1))], tile.worldx(), tile.worldy()); Draw.rect(shadowRegions[(Mathf.randomSeed(tile.pos(), 0, variants - 1))], tile.worldx(), tile.worldy());
}else if(shadowRegion != null){ }else if(shadowRegion != null){
Draw.rect(shadowRegion, tile.drawx(), tile.drawy()); Draw.rect(shadowRegion, tile.drawx(), tile.drawy());
} }

View File

@@ -44,7 +44,7 @@ public class ForceProjector extends Block {
protected float cooldownBrokenBase = 0.35f; protected float cooldownBrokenBase = 0.35f;
protected float basePowerDraw = 0.2f; protected float basePowerDraw = 0.2f;
protected float powerDamage = 0.1f; protected float powerDamage = 0.1f;
protected final ConsumePower consumePower; protected final ConsumeForceProjectorPower consumePower;
protected TextureRegion topRegion; protected TextureRegion topRegion;
@@ -58,7 +58,8 @@ public class ForceProjector extends Block {
hasItems = true; hasItems = true;
itemCapacity = 10; itemCapacity = 10;
consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.1f)).optional(true).update(false); consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.1f)).optional(true).update(false);
consumePower = consumes.powerBuffered(60f); consumePower = new ConsumeForceProjectorPower(60f, 60f);
consumes.add(consumePower);
} }
@Override @Override
@@ -104,18 +105,27 @@ public class ForceProjector extends Block {
Effects.effect(BlockFx.reactorsmoke, tile.drawx() + Mathf.range(tilesize/2f), tile.drawy() + Mathf.range(tilesize/2f)); Effects.effect(BlockFx.reactorsmoke, tile.drawx() + Mathf.range(tilesize/2f), tile.drawy() + Mathf.range(tilesize/2f));
} }
// Draw base power from buffer manually (ConsumePower doesn't support both filling a buffer and drawing power additionally so we have to do it here) // Use Cases:
entity.power.satisfaction -= Math.min(entity.power.satisfaction, basePowerDraw / consumePower.powerCapacity); // - There is enough power in the buffer, and there are no shots fired => Draw base power and keep shield up
// - There is enough power in the buffer, but not enough power to cope for shots being fired => Draw all power and break shield
// - There is enough power in the buffer and enough power to cope for shots being fired => Draw base power + additional power based on shots absorbed
// - There is not enough base power in the buffer => Draw all power and break shield
// - The generator is in the AI base and uses cheat mode => Only draw power from shots being absorbed
if(entity.power.satisfaction == 0.0f && !cheat){ float relativePowerDraw = 0.0f;
if(!cheat){
relativePowerDraw = basePowerDraw / consumePower.powerCapacity;
}
if(entity.power.satisfaction < relativePowerDraw){
entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, 0.15f); entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, 0.15f);
entity.power.satisfaction = .0f;
if(entity.warmup <= 0.09f){ if(entity.warmup <= 0.09f){
entity.broken = true; entity.broken = true;
} }
}else{ }else{
entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, 0.1f); entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, 0.1f);
float relativePowerDraw = powerDamage * entity.delta() * (1f + entity.buildup / breakage) / consumePower.powerCapacity; entity.power.satisfaction -= Math.min(entity.power.satisfaction, relativePowerDraw);
entity.power.satisfaction -= Math.min(relativePowerDraw, entity.power.satisfaction);
} }
if(entity.buildup > 0){ if(entity.buildup > 0){
@@ -150,10 +160,10 @@ public class ForceProjector extends Block {
if(trait.canBeAbsorbed() && trait.getTeam() != tile.getTeam() && isInsideHexagon(trait.getX(), trait.getY(), realRadius * 2f, tile.drawx(), tile.drawy())){ if(trait.canBeAbsorbed() && trait.getTeam() != tile.getTeam() && isInsideHexagon(trait.getX(), trait.getY(), realRadius * 2f, tile.drawx(), tile.drawy())){
trait.absorb(); trait.absorb();
Effects.effect(BulletFx.absorb, trait); Effects.effect(BulletFx.absorb, trait);
float relativePowerDraw = trait.getShieldDamage() * powerDamage / consumePower.powerCapacity; float relativeDamagePowerDraw = trait.getShieldDamage() * powerDamage / consumePower.powerCapacity;
entity.hit = 1f; entity.hit = 1f;
entity.power.satisfaction -= Math.min(relativePowerDraw, entity.power.satisfaction); entity.power.satisfaction -= Math.min(relativeDamagePowerDraw, entity.power.satisfaction);
if(entity.power.satisfaction <= 0.0001f){ if(entity.power.satisfaction <= 0.0001f){
entity.buildup += trait.getShieldDamage() * entity.warmup * 2f; entity.buildup += trait.getShieldDamage() * entity.warmup * 2f;
} }
@@ -264,4 +274,14 @@ public class ForceProjector extends Block {
return shieldGroup; return shieldGroup;
} }
} }
public class ConsumeForceProjectorPower extends ConsumePower{
public ConsumeForceProjectorPower(float powerCapacity, float ticksToFill){
super(powerCapacity / ticksToFill, 0.0f, powerCapacity, true);
}
@Override
public boolean valid(Block block, TileEntity entity){
return entity.power.satisfaction >= basePowerDraw / powerCapacity && super.valid(block, entity);
}
}
} }

View File

@@ -83,10 +83,10 @@ public class MendProjector extends Block{
if(other == null) continue; if(other == null) continue;
other = other.target(); other = other.target();
if(other.getTeamID() == tile.getTeamID() && !healed.contains(other.packedPosition()) && other.entity != null && other.entity.health < other.entity.maxHealth()){ if(other.getTeamID() == tile.getTeamID() && !healed.contains(other.pos()) && other.entity != null && other.entity.health < other.entity.maxHealth()){
other.entity.healBy(other.entity.maxHealth() * (healPercent + entity.phaseHeat*phaseBoost)/100f * entity.power.satisfaction); other.entity.healBy(other.entity.maxHealth() * (healPercent + entity.phaseHeat*phaseBoost)/100f * entity.power.satisfaction);
Effects.effect(BlockFx.healBlockFull, Hue.mix(color, phase, entity.phaseHeat), other.drawx(), other.drawy(), other.block().size); Effects.effect(BlockFx.healBlockFull, Hue.mix(color, phase, entity.phaseHeat), other.drawx(), other.drawy(), other.block().size);
healed.add(other.packedPosition()); healed.add(other.pos());
} }
} }
} }

View File

@@ -85,11 +85,11 @@ public class OverdriveProjector extends Block{
if(other == null) continue; if(other == null) continue;
other = other.target(); other = other.target();
if(other.getTeamID() == tile.getTeamID() && !healed.contains(other.packedPosition()) && other.entity != null){ if(other.getTeamID() == tile.getTeamID() && !healed.contains(other.pos()) && other.entity != null){
other.entity.timeScaleDuration = Math.max(other.entity.timeScaleDuration, reload + 1f); other.entity.timeScaleDuration = Math.max(other.entity.timeScaleDuration, reload + 1f);
other.entity.timeScale = Math.max(other.entity.timeScale, realBoost); other.entity.timeScale = Math.max(other.entity.timeScale, realBoost);
Effects.effect(BlockFx.overdriveBlockFull, Hue.mix(color, phase, entity.phaseHeat), other.drawx(), other.drawy(), other.block().size); Effects.effect(BlockFx.overdriveBlockFull, Hue.mix(color, phase, entity.phaseHeat), other.drawx(), other.drawy(), other.block().size);
healed.add(other.packedPosition()); healed.add(other.pos());
} }
} }
} }

View File

@@ -15,6 +15,7 @@ import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Edges; import io.anuke.mindustry.world.Edges;
import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.meta.BlockGroup; import io.anuke.mindustry.world.meta.BlockGroup;
import io.anuke.ucore.core.Timers; import io.anuke.ucore.core.Timers;
@@ -58,8 +59,8 @@ public class ItemBridge extends Block{
public static void linkItemBridge(Player player, Tile tile, Tile other){ public static void linkItemBridge(Player player, Tile tile, Tile other){
ItemBridgeEntity entity = tile.entity(); ItemBridgeEntity entity = tile.entity();
ItemBridgeEntity oe = other.entity(); ItemBridgeEntity oe = other.entity();
entity.link = other.packedPosition(); entity.link = other.pos();
oe.incoming.add(tile.packedPosition()); oe.incoming.add(tile.pos());
} }
@Remote(targets = Loc.both, called = Loc.server, forward = true) @Remote(targets = Loc.both, called = Loc.server, forward = true)
@@ -68,7 +69,7 @@ public class ItemBridge extends Block{
entity.link = -1; entity.link = -1;
if(other != null){ if(other != null){
ItemBridgeEntity oe = other.entity(); ItemBridgeEntity oe = other.entity();
oe.incoming.remove(tile.packedPosition()); oe.incoming.remove(tile.pos());
} }
} }
@@ -90,7 +91,7 @@ public class ItemBridge extends Block{
Call.linkItemBridge(null, last, tile); Call.linkItemBridge(null, last, tile);
} }
} }
lastPlaced = tile.packedPosition(); lastPlaced = tile.pos();
} }
@Override @Override
@@ -122,7 +123,7 @@ public class ItemBridge extends Block{
for(int j = 0; j < 4; j++){ for(int j = 0; j < 4; j++){
Tile other = tile.getNearby(Geometry.d4[j].x * i, Geometry.d4[j].y * i); Tile other = tile.getNearby(Geometry.d4[j].x * i, Geometry.d4[j].y * i);
if(linkValid(tile, other)){ if(linkValid(tile, other)){
boolean linked = other.packedPosition() == entity.link; boolean linked = other.pos() == entity.link;
Draw.color(linked ? Palette.place : Palette.breakInvalid); Draw.color(linked ? Palette.place : Palette.breakInvalid);
Lines.square(other.drawx(), other.drawy(), Lines.square(other.drawx(), other.drawy(),
@@ -139,7 +140,7 @@ public class ItemBridge extends Block{
ItemBridgeEntity entity = tile.entity(); ItemBridgeEntity entity = tile.entity();
if(linkValid(tile, other)){ if(linkValid(tile, other)){
if(entity.link == other.packedPosition()){ if(entity.link == other.pos()){
Call.unlinkItemBridge(null, tile, other); Call.unlinkItemBridge(null, tile, other);
}else{ }else{
Call.linkItemBridge(null, tile, other); Call.linkItemBridge(null, tile, other);
@@ -254,7 +255,7 @@ public class ItemBridge extends Block{
if(rel == rel2) return false; if(rel == rel2) return false;
}else{ }else{
return source.block() instanceof ItemBridge && source.<ItemBridgeEntity>entity().link == tile.packedPosition() && tile.entity.items.total() < itemCapacity; return source.block() instanceof ItemBridge && source.<ItemBridgeEntity>entity().link == tile.pos() && tile.entity.items.total() < itemCapacity;
} }
return tile.entity.items.total() < itemCapacity; return tile.entity.items.total() < itemCapacity;
@@ -273,9 +274,7 @@ public class ItemBridge extends Block{
while(it.hasNext){ while(it.hasNext){
int v = it.next(); int v = it.next();
int x = v % world.width(); if(tile.absoluteRelativeTo(Pos.x(v), Pos.y(v)) == i){
int y = v / world.width();
if(tile.absoluteRelativeTo(x, y) == i){
return false; return false;
} }
} }
@@ -315,7 +314,7 @@ public class ItemBridge extends Block{
return false; return false;
} }
return other.block() == this && (!checkDouble || other.<ItemBridgeEntity>entity().link != tile.packedPosition()); return other.block() == this && (!checkDouble || other.<ItemBridgeEntity>entity().link != tile.pos());
} }
public static class ItemBridgeEntity extends TileEntity{ public static class ItemBridgeEntity extends TileEntity{

View File

@@ -3,6 +3,7 @@ package io.anuke.mindustry.world.blocks.distribution;
import com.badlogic.gdx.utils.IntSet.IntSetIterator; import com.badlogic.gdx.utils.IntSet.IntSetIterator;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.meta.BlockGroup; import io.anuke.mindustry.world.meta.BlockGroup;
import io.anuke.ucore.core.Timers; import io.anuke.ucore.core.Timers;
@@ -65,9 +66,7 @@ public class LiquidExtendingBridge extends ExtendingItemBridge{
while(it.hasNext){ while(it.hasNext){
int v = it.next(); int v = it.next();
int x = v % world.width(); if(tile.absoluteRelativeTo(Pos.x(v), Pos.y(v)) == i){
int y = v / world.width();
if(tile.absoluteRelativeTo(x, y) == i){
return false; return false;
} }
} }

View File

@@ -0,0 +1,16 @@
package io.anuke.mindustry.world.blocks.distribution;
import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.world.Tile;
public class LiquidTank extends LiquidRouter{
public LiquidTank(String name){
super(name);
}
@Override
public boolean canDumpLiquid(Tile tile, Tile to, Liquid liquid){
return super.canDumpLiquid(tile, to, liquid) && !(to.block() instanceof LiquidTank);
}
}

View File

@@ -131,7 +131,7 @@ public class MassDriver extends Block{
public void setStats(){ public void setStats(){
super.setStats(); super.setStats();
stats.add(BlockStat.powerShot, consumes.get(ConsumePower.class).powerCapacity * powerPercentageUsed, StatUnit.powerUnits); stats.add(BlockStat.powerShot, consumes.getSubtypeOf(ConsumePower.class).powerCapacity * powerPercentageUsed, StatUnit.powerUnits);
} }
@Override @Override
@@ -230,11 +230,11 @@ public class MassDriver extends Block{
MassDriverEntity entity = tile.entity(); MassDriverEntity entity = tile.entity();
if(entity.link == other.packedPosition()){ if(entity.link == other.pos()){
Call.linkMassDriver(null, tile, -1); Call.linkMassDriver(null, tile, -1);
return false; return false;
}else if(other.block() instanceof MassDriver && other.distanceTo(tile) <= range){ }else if(other.block() instanceof MassDriver && other.distanceTo(tile) <= range){
Call.linkMassDriver(null, tile, other.packedPosition()); Call.linkMassDriver(null, tile, other.pos());
return false; return false;
} }

View File

@@ -4,6 +4,7 @@ import io.anuke.annotations.Annotations.Loc;
import io.anuke.annotations.Annotations.Remote; import io.anuke.annotations.Annotations.Remote;
import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.gen.Call;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
@@ -12,7 +13,6 @@ import io.anuke.mindustry.world.meta.BlockGroup;
import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.util.Mathf; import io.anuke.ucore.util.Mathf;
import io.anuke.mindustry.gen.Call;
import java.io.DataInput; import java.io.DataInput;
import java.io.DataOutput; import java.io.DataOutput;

View File

@@ -48,8 +48,8 @@ public class PowerGraph{
float powerNeeded = 0f; float powerNeeded = 0f;
for(Tile consumer : consumers){ for(Tile consumer : consumers){
Consumers consumes = consumer.block().consumes; Consumers consumes = consumer.block().consumes;
if(consumes.has(ConsumePower.class)){ if(consumes.hasSubtypeOf(ConsumePower.class)){
ConsumePower consumePower = consumes.get(ConsumePower.class); ConsumePower consumePower = consumes.getSubtypeOf(ConsumePower.class);
if(otherConsumersAreValid(consumer, consumePower)){ if(otherConsumersAreValid(consumer, consumePower)){
powerNeeded += consumePower.requestedPower(consumer.block(), consumer.entity) * consumer.entity.delta(); powerNeeded += consumePower.requestedPower(consumer.block(), consumer.entity) * consumer.entity.delta();
} }
@@ -62,8 +62,8 @@ public class PowerGraph{
float totalAccumulator = 0f; float totalAccumulator = 0f;
for(Tile battery : batteries){ for(Tile battery : batteries){
Consumers consumes = battery.block().consumes; Consumers consumes = battery.block().consumes;
if(consumes.has(ConsumePower.class)){ if(consumes.hasSubtypeOf(ConsumePower.class)){
totalAccumulator += battery.entity.power.satisfaction * consumes.get(ConsumePower.class).powerCapacity; totalAccumulator += battery.entity.power.satisfaction * consumes.getSubtypeOf(ConsumePower.class).powerCapacity;
} }
} }
return totalAccumulator; return totalAccumulator;
@@ -73,8 +73,8 @@ public class PowerGraph{
float totalCapacity = 0f; float totalCapacity = 0f;
for(Tile battery : batteries){ for(Tile battery : batteries){
Consumers consumes = battery.block().consumes; Consumers consumes = battery.block().consumes;
if(consumes.has(ConsumePower.class)){ if(consumes.hasSubtypeOf(ConsumePower.class)){
totalCapacity += consumes.get(ConsumePower.class).requestedPower(battery.block(), battery.entity) * battery.entity.delta(); totalCapacity += consumes.getSubtypeOf(ConsumePower.class).requestedPower(battery.block(), battery.entity) * battery.entity.delta();
} }
} }
return totalCapacity; return totalCapacity;
@@ -88,8 +88,8 @@ public class PowerGraph{
float consumedPowerPercentage = Math.min(1.0f, needed / stored); float consumedPowerPercentage = Math.min(1.0f, needed / stored);
for(Tile battery : batteries){ for(Tile battery : batteries){
Consumers consumes = battery.block().consumes; Consumers consumes = battery.block().consumes;
if(consumes.has(ConsumePower.class)){ if(consumes.hasSubtypeOf(ConsumePower.class)){
ConsumePower consumePower = consumes.get(ConsumePower.class); ConsumePower consumePower = consumes.getSubtypeOf(ConsumePower.class);
if(consumePower.powerCapacity > 0f){ if(consumePower.powerCapacity > 0f){
battery.entity.power.satisfaction = Math.max(0.0f, battery.entity.power.satisfaction - consumedPowerPercentage); battery.entity.power.satisfaction = Math.max(0.0f, battery.entity.power.satisfaction - consumedPowerPercentage);
} }
@@ -104,8 +104,8 @@ public class PowerGraph{
for(Tile battery : batteries){ for(Tile battery : batteries){
Consumers consumes = battery.block().consumes; Consumers consumes = battery.block().consumes;
if(consumes.has(ConsumePower.class)){ if(consumes.hasSubtypeOf(ConsumePower.class)){
ConsumePower consumePower = consumes.get(ConsumePower.class); ConsumePower consumePower = consumes.getSubtypeOf(ConsumePower.class);
if(consumePower.powerCapacity > 0f){ if(consumePower.powerCapacity > 0f){
float additionalPowerPercentage = Math.min(1.0f, excess / consumePower.powerCapacity); float additionalPowerPercentage = Math.min(1.0f, excess / consumePower.powerCapacity);
battery.entity.power.satisfaction = Math.min(1.0f, battery.entity.power.satisfaction + additionalPowerPercentage); battery.entity.power.satisfaction = Math.min(1.0f, battery.entity.power.satisfaction + additionalPowerPercentage);
@@ -121,8 +121,8 @@ public class PowerGraph{
float coverage = Math.min(1, produced / needed); float coverage = Math.min(1, produced / needed);
for(Tile consumer : consumers){ for(Tile consumer : consumers){
Consumers consumes = consumer.block().consumes; Consumers consumes = consumer.block().consumes;
if(consumes.has(ConsumePower.class)){ if(consumes.hasSubtypeOf(ConsumePower.class)){
ConsumePower consumePower = consumes.get(ConsumePower.class); ConsumePower consumePower = consumes.getSubtypeOf(ConsumePower.class);
if(!otherConsumersAreValid(consumer, consumePower)){ if(!otherConsumersAreValid(consumer, consumePower)){
consumer.entity.power.satisfaction = 0.0f; // Only supply power if the consumer would get valid that way consumer.entity.power.satisfaction = 0.0f; // Only supply power if the consumer would get valid that way
}else{ }else{
@@ -180,7 +180,10 @@ public class PowerGraph{
public void clear(){ public void clear(){
for(Tile other : all){ for(Tile other : all){
if(other.entity != null && other.entity.power != null){ other.entity.power.graph = null; } if(other.entity != null && other.entity.power != null){
other.entity.power.satisfaction = 0.0f;
other.entity.power.graph = null;
}
} }
all.clear(); all.clear();
producers.clear(); producers.clear();
@@ -197,9 +200,9 @@ public class PowerGraph{
child.entity.power.graph = this; child.entity.power.graph = this;
add(child); add(child);
for(Tile next : child.block().getPowerConnections(child, outArray2)){ for(Tile next : child.block().getPowerConnections(child, outArray2)){
if(next.entity.power != null && next.entity.power.graph == null && !closedSet.contains(next.packedPosition())){ if(next.entity.power != null && next.entity.power.graph == null && !closedSet.contains(next.pos())){
queue.addLast(next); queue.addLast(next);
closedSet.add(next.packedPosition()); closedSet.add(next.pos());
} }
} }
} }
@@ -219,9 +222,9 @@ public class PowerGraph{
child.entity.power.graph = graph; child.entity.power.graph = graph;
graph.add(child); graph.add(child);
for(Tile next : child.block().getPowerConnections(child, outArray2)){ for(Tile next : child.block().getPowerConnections(child, outArray2)){
if(next != tile && next.entity.power != null && next.entity.power.graph == null && !closedSet.contains(next.packedPosition())){ if(next != tile && next.entity.power != null && next.entity.power.graph == null && !closedSet.contains(next.pos())){
queue.addLast(next); queue.addLast(next);
closedSet.add(next.packedPosition()); closedSet.add(next.pos());
} }
} }
} }

View File

@@ -50,14 +50,14 @@ public class PowerNode extends PowerBlock{
TileEntity entity = tile.entity(); TileEntity entity = tile.entity();
if(!entity.power.links.contains(other.packedPosition())){ if(!entity.power.links.contains(other.pos())){
entity.power.links.add(other.packedPosition()); entity.power.links.add(other.pos());
} }
if(other.getTeamID() == tile.getTeamID()){ if(other.getTeamID() == tile.getTeamID()){
if(!other.entity.power.links.contains(tile.packedPosition())){ if(!other.entity.power.links.contains(tile.pos())){
other.entity.power.links.add(tile.packedPosition()); other.entity.power.links.add(tile.pos());
} }
} }
@@ -74,8 +74,8 @@ public class PowerNode extends PowerBlock{
PowerGraph tg = entity.power.graph; PowerGraph tg = entity.power.graph;
tg.clear(); tg.clear();
entity.power.links.removeValue(other.packedPosition()); entity.power.links.removeValue(other.pos());
other.entity.power.links.removeValue(tile.packedPosition()); other.entity.power.links.removeValue(tile.pos());
//reflow from this point, covering all tiles on this side //reflow from this point, covering all tiles on this side
tg.reflow(tile); tg.reflow(tile);
@@ -98,14 +98,14 @@ public class PowerNode extends PowerBlock{
if(linkValid(tile, before) && before.block() instanceof PowerNode){ if(linkValid(tile, before) && before.block() instanceof PowerNode){
for(Tile near : before.entity.proximity()){ for(Tile near : before.entity.proximity()){
if(near.target() == tile){ if(near.target() == tile){
lastPlaced = tile.packedPosition(); lastPlaced = tile.pos();
return; return;
} }
} }
Call.linkPowerNodes(null, tile, before); Call.linkPowerNodes(null, tile, before);
} }
lastPlaced = tile.packedPosition(); lastPlaced = tile.pos();
} }
@Override @Override
@@ -201,7 +201,7 @@ public class PowerNode extends PowerBlock{
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.block() instanceof PowerNode) if(linkValid(tile, link) && (!(link.block() instanceof PowerNode)
|| ((tile.block().size > link.block().size) || (tile.block().size == link.block().size && tile.id() < link.id())))){ || ((tile.block().size > link.block().size) || (tile.block().size == link.block().size && tile.pos() < link.pos())))){
drawLaser(tile, link); drawLaser(tile, link);
} }
} }
@@ -210,7 +210,7 @@ public class PowerNode extends PowerBlock{
} }
protected boolean linked(Tile tile, Tile other){ protected boolean linked(Tile tile, Tile other){
return tile.entity.power.links.contains(other.packedPosition()); return tile.entity.power.links.contains(other.pos());
} }
protected boolean linkValid(Tile tile, Tile link){ protected boolean linkValid(Tile tile, Tile link){
@@ -226,7 +226,7 @@ public class PowerNode extends PowerBlock{
return Vector2.dst(tile.drawx(), tile.drawy(), link.drawx(), link.drawy()) <= Math.max(laserRange * tilesize, return Vector2.dst(tile.drawx(), tile.drawy(), link.drawx(), link.drawy()) <= Math.max(laserRange * tilesize,
((PowerNode) link.block()).laserRange * tilesize) ((PowerNode) link.block()).laserRange * tilesize)
+ (link.block().size - 1) * tilesize / 2f + (tile.block().size - 1) * tilesize / 2f && + (link.block().size - 1) * tilesize / 2f + (tile.block().size - 1) * tilesize / 2f &&
(!checkMaxNodes || (oe.power.links.size < ((PowerNode) link.block()).maxNodes || oe.power.links.contains(tile.packedPosition()))); (!checkMaxNodes || (oe.power.links.size < ((PowerNode) link.block()).maxNodes || oe.power.links.contains(tile.pos())));
}else{ }else{
return Vector2.dst(tile.drawx(), tile.drawy(), link.drawx(), link.drawy()) return Vector2.dst(tile.drawx(), tile.drawy(), link.drawx(), link.drawy())
<= laserRange * tilesize + (link.block().size - 1) * tilesize; <= laserRange * tilesize + (link.block().size - 1) * tilesize;
@@ -251,7 +251,6 @@ public class PowerNode extends PowerBlock{
Draw.color(Palette.powerLight, Palette.power, Mathf.absin(Timers.time(), 8f, 1f)); Draw.color(Palette.powerLight, Palette.power, Mathf.absin(Timers.time(), 8f, 1f));
Lines.stroke(2f); Lines.stroke(2f);
Lines.line(x1, y1, x2, y2); Lines.line(x1, y1, x2, y2);
} }
} }

View File

@@ -74,7 +74,7 @@ public class Cultivator extends Drill{
Draw.color(bottomColor, plantColorLight, entity.warmup); Draw.color(bottomColor, plantColorLight, entity.warmup);
random.setSeed(tile.packedPosition()); random.setSeed(tile.pos());
for(int i = 0; i < 12; i++){ for(int i = 0; i < 12; i++){
float offset = random.nextFloat() * 999999f; float offset = random.nextFloat() * 999999f;
float x = random.range(4f), y = random.range(4f); float x = random.range(4f), y = random.range(4f);

View File

@@ -17,15 +17,22 @@ import java.io.DataOutput;
import java.io.IOException; import java.io.IOException;
import static io.anuke.mindustry.Vars.content; import static io.anuke.mindustry.Vars.content;
import static io.anuke.mindustry.Vars.threads;
public class SortedUnloader extends Unloader implements SelectionTrait{ public class SortedUnloader extends Unloader implements SelectionTrait{
protected float speed = 1f; protected float speed = 1f;
private static Item lastItem;
public SortedUnloader(String name){ public SortedUnloader(String name){
super(name); super(name);
configurable = true; configurable = true;
} }
@Override
public void playerPlaced(Tile tile){
threads.runDelay(() -> Call.setSortedUnloaderItem(null, tile, lastItem));
}
@Remote(targets = Loc.both, called = Loc.both, forward = true) @Remote(targets = Loc.both, called = Loc.both, forward = true)
public static void setSortedUnloaderItem(Player player, Tile tile, Item item){ public static void setSortedUnloaderItem(Player player, Tile tile, Item item){
SortedUnloaderEntity entity = tile.entity(); SortedUnloaderEntity entity = tile.entity();
@@ -65,7 +72,10 @@ public class SortedUnloader extends Unloader implements SelectionTrait{
@Override @Override
public void buildTable(Tile tile, Table table){ public void buildTable(Tile tile, Table table){
SortedUnloaderEntity entity = tile.entity(); SortedUnloaderEntity entity = tile.entity();
buildItemTable(table, () -> entity.sortItem, item -> Call.setSortedUnloaderItem(null, tile, item)); buildItemTable(table, () -> entity.sortItem, item -> {
lastItem = item;
Call.setSortedUnloaderItem(null, tile, item);
});
} }
@Override @Override

View File

@@ -101,9 +101,9 @@ public class StorageGraph{
add(child); add(child);
for(Tile next : child.entity.proximity()){ for(Tile next : child.entity.proximity()){
if(next != base && next.block() instanceof StorageBlock && next.<StorageEntity>entity().graph == null && !closedSet.contains(next.packedPosition())){ if(next != base && next.block() instanceof StorageBlock && next.<StorageEntity>entity().graph == null && !closedSet.contains(next.pos())){
queue.addLast(next); queue.addLast(next);
closedSet.add(next.packedPosition()); closedSet.add(next.pos());
} }
} }
} }

View File

@@ -64,7 +64,7 @@ public class Reconstructor extends Block{
if(other != null && other.block() instanceof Reconstructor){ if(other != null && other.block() instanceof Reconstructor){
ReconstructorEntity oe = other.entity(); ReconstructorEntity oe = other.entity();
if(oe.link == entity.tile.packedPosition()){ if(oe.link == entity.tile.pos()){
oe.link = -1; oe.link = -1;
} }
} }
@@ -105,8 +105,8 @@ public class Reconstructor extends Block{
unlink(entity); unlink(entity);
unlink(oe); unlink(oe);
entity.link = other.packedPosition(); entity.link = other.pos();
oe.link = tile.packedPosition(); oe.link = tile.pos();
}); });
} }
@@ -163,7 +163,7 @@ public class Reconstructor extends Block{
ReconstructorEntity entity = tile.entity(); ReconstructorEntity entity = tile.entity();
if(entity.link == other.packedPosition()){ if(entity.link == other.pos()){
Call.unlinkReconstructor(null, tile, other); Call.unlinkReconstructor(null, tile, other);
return false; return false;
}else if(other.block() instanceof Reconstructor){ }else if(other.block() instanceof Reconstructor){

View File

@@ -37,12 +37,12 @@ public class Consumers{
} }
/** /**
* Creates a consumer which directly uses power without buffering it. The module will work while at least 60% of power is supplied. * Creates a consumer which directly uses power without buffering it. The module will work while at least 50% of power is supplied.
* @param powerPerTick The amount of power which is required each tick for 100% efficiency. * @param powerPerTick The amount of power which is required each tick for 100% efficiency.
* @return the created consumer object. * @return the created consumer object.
*/ */
public ConsumePower powerDirect(float powerPerTick){ public ConsumePower powerDirect(float powerPerTick){
return powerDirect(powerPerTick, 0.6f); return powerDirect(powerPerTick, 0.5f);
} }
/** /**
@@ -122,6 +122,15 @@ public class Consumers{
return map.containsKey(type); return map.containsKey(type);
} }
public boolean hasSubtypeOf(Class<? extends Consume> type){
for(Consume consume : all()){
if(type.isAssignableFrom(consume.getClass())){
return true;
}
}
return false;
}
public <T extends Consume> T get(Class<T> type){ public <T extends Consume> T get(Class<T> type){
if(!map.containsKey(type)){ if(!map.containsKey(type)){
throw new IllegalArgumentException("Block does not contain consumer of type '" + type + "'!"); throw new IllegalArgumentException("Block does not contain consumer of type '" + type + "'!");
@@ -129,6 +138,15 @@ public class Consumers{
return (T) map.get(type); return (T) map.get(type);
} }
public <T extends Consume> T getSubtypeOf(Class<T> type){
for(Consume consume : all()){
if(type.isAssignableFrom(consume.getClass())){
return (T)consume;
}
}
throw new IllegalArgumentException("Block does not contain consumer of type '" + type + "' or any of its subtypes!");
}
public Iterable<Consume> all(){ public Iterable<Consume> all(){
return map.values(); return map.values();
} }

View File

@@ -60,7 +60,7 @@ public class DesktopPlatform extends Platform{
presence.largeImageText = "Wave " + state.wave; presence.largeImageText = "Wave " + state.wave;
} }
if(state.mode != GameMode.noWaves){ if(state.mode != GameMode.attack){
presence.state = Strings.capitalize(state.mode.name()); presence.state = Strings.capitalize(state.mode.name());
}else{ }else{
presence.state = unitGroups[players[0].getTeam().ordinal()].size() == 1 ? "1 Unit Active" : presence.state = unitGroups[players[0].getTeam().ordinal()].size() == 1 ? "1 Unit Active" :

View File

@@ -1,4 +1,4 @@
apply plugin: "java" apply plugin: "java"
sourceCompatibility = 1.8 sourceCompatibility = 1.8
sourceSets.main.java.srcDirs = [ "src/" ] sourceSets.main.java.srcDirs = ["src/"]

View File

@@ -10,18 +10,18 @@ import io.anuke.ucore.util.Pooling;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class ByteSerializer implements Serialization { public class ByteSerializer implements Serialization{
@Override @Override
public void write(ByteBuffer byteBuffer, Object o) { public void write(ByteBuffer byteBuffer, Object o){
if(o instanceof FrameworkMessage){ if(o instanceof FrameworkMessage){
byteBuffer.put((byte)-2); //code for framework message byteBuffer.put((byte) -2); //code for framework message
FrameworkSerializer.write(byteBuffer, (FrameworkMessage)o); FrameworkSerializer.write(byteBuffer, (FrameworkMessage) o);
}else { }else{
if (!(o instanceof Packet)) if(!(o instanceof Packet))
throw new RuntimeException("All sent objects must implement be Packets! Class: " + o.getClass()); throw new RuntimeException("All sent objects must implement be Packets! Class: " + o.getClass());
byte id = Registrator.getID(o.getClass()); byte id = Registrator.getID(o.getClass());
if (id == -1) if(id == -1)
throw new RuntimeException("Unregistered class: " + o.getClass()); throw new RuntimeException("Unregistered class: " + o.getClass());
byteBuffer.put(id); byteBuffer.put(id);
((Packet) o).write(byteBuffer); ((Packet) o).write(byteBuffer);
@@ -29,7 +29,7 @@ public class ByteSerializer implements Serialization {
} }
@Override @Override
public Object read(ByteBuffer byteBuffer) { public Object read(ByteBuffer byteBuffer){
byte id = byteBuffer.get(); byte id = byteBuffer.get();
if(id == -2){ if(id == -2){
return FrameworkSerializer.read(byteBuffer); return FrameworkSerializer.read(byteBuffer);
@@ -41,17 +41,17 @@ public class ByteSerializer implements Serialization {
} }
@Override @Override
public int getLengthLength() { public int getLengthLength(){
return 2; return 2;
} }
@Override @Override
public void writeLength(ByteBuffer byteBuffer, int i) { public void writeLength(ByteBuffer byteBuffer, int i){
byteBuffer.putShort((short)i); byteBuffer.putShort((short) i);
} }
@Override @Override
public int readLength(ByteBuffer byteBuffer) { public int readLength(ByteBuffer byteBuffer){
return byteBuffer.getShort(); return byteBuffer.getShort();
} }
} }

View File

@@ -5,32 +5,32 @@ import com.esotericsoftware.kryonet.FrameworkMessage.*;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
public class FrameworkSerializer { public class FrameworkSerializer{
public static void write(ByteBuffer buffer, FrameworkMessage message){ public static void write(ByteBuffer buffer, FrameworkMessage message){
if(message instanceof Ping){ if(message instanceof Ping){
Ping p = (Ping)message; Ping p = (Ping) message;
buffer.put((byte)0); buffer.put((byte) 0);
buffer.putInt(p.id); buffer.putInt(p.id);
buffer.put(p.isReply ? 1 : (byte)0); buffer.put(p.isReply ? 1 : (byte) 0);
}else if(message instanceof DiscoverHost){ }else if(message instanceof DiscoverHost){
DiscoverHost p = (DiscoverHost)message; DiscoverHost p = (DiscoverHost) message;
buffer.put((byte)1); buffer.put((byte) 1);
}else if(message instanceof KeepAlive){ }else if(message instanceof KeepAlive){
KeepAlive p = (KeepAlive)message; KeepAlive p = (KeepAlive) message;
buffer.put((byte)2); buffer.put((byte) 2);
}else if(message instanceof RegisterUDP){ }else if(message instanceof RegisterUDP){
RegisterUDP p = (RegisterUDP)message; RegisterUDP p = (RegisterUDP) message;
buffer.put((byte)3); buffer.put((byte) 3);
buffer.putInt(p.connectionID); buffer.putInt(p.connectionID);
}else if(message instanceof RegisterTCP){ }else if(message instanceof RegisterTCP){
RegisterTCP p = (RegisterTCP)message; RegisterTCP p = (RegisterTCP) message;
buffer.put((byte)4); buffer.put((byte) 4);
buffer.putInt(p.connectionID); buffer.putInt(p.connectionID);
} }
} }

View File

@@ -35,14 +35,14 @@ public class KryoClient implements ClientProvider{
public KryoClient(){ public KryoClient(){
KryoCore.init(); KryoCore.init();
handler = new ClientDiscoveryHandler() { handler = new ClientDiscoveryHandler(){
@Override @Override
public DatagramPacket onRequestNewDatagramPacket() { public DatagramPacket onRequestNewDatagramPacket(){
return new DatagramPacket(new byte[128], 128); return new DatagramPacket(new byte[128], 128);
} }
@Override @Override
public void onDiscoveredHost(DatagramPacket datagramPacket) { public void onDiscoveredHost(DatagramPacket datagramPacket){
ByteBuffer buffer = ByteBuffer.wrap(datagramPacket.getData()); ByteBuffer buffer = ByteBuffer.wrap(datagramPacket.getData());
Host host = NetworkIO.readServerData(datagramPacket.getAddress().getHostAddress(), buffer); Host host = NetworkIO.readServerData(datagramPacket.getAddress().getHostAddress(), buffer);
for(InetAddress address : foundAddresses){ for(InetAddress address : foundAddresses){
@@ -55,7 +55,7 @@ public class KryoClient implements ClientProvider{
} }
@Override @Override
public void onFinally() { public void onFinally(){
} }
}; };
@@ -65,7 +65,7 @@ public class KryoClient implements ClientProvider{
Listener listener = new Listener(){ Listener listener = new Listener(){
@Override @Override
public void connected (Connection connection) { public void connected(Connection connection){
Connect c = new Connect(); Connect c = new Connect();
c.addressTCP = connection.getRemoteAddressTCP().getAddress().getHostAddress(); c.addressTCP = connection.getRemoteAddressTCP().getAddress().getHostAddress();
c.id = connection.getID(); c.id = connection.getID();
@@ -75,7 +75,7 @@ public class KryoClient implements ClientProvider{
} }
@Override @Override
public void disconnected (Connection connection) { public void disconnected(Connection connection){
if(connection.getLastProtocolError() != null){ if(connection.getLastProtocolError() != null){
netClient.setQuiet(); netClient.setQuiet();
} }
@@ -85,13 +85,13 @@ public class KryoClient implements ClientProvider{
} }
@Override @Override
public void received (Connection connection, Object object) { public void received(Connection connection, Object object){
if(object instanceof FrameworkMessage) return; if(object instanceof FrameworkMessage) return;
threads.runDelay(() -> { threads.runDelay(() -> {
try{ try{
Net.handleClientReceived(object); Net.handleClientReceived(object);
}catch (Exception e){ }catch(Exception e){
handleException(e); handleException(e);
} }
}); });
@@ -106,12 +106,12 @@ public class KryoClient implements ClientProvider{
} }
} }
private static boolean isLocal(InetAddress addr) { private static boolean isLocal(InetAddress addr){
if (addr.isAnyLocalAddress() || addr.isLoopbackAddress()) return true; if(addr.isAnyLocalAddress() || addr.isLoopbackAddress()) return true;
try { try{
return NetworkInterface.getByInetAddress(addr) != null; return NetworkInterface.getByInetAddress(addr) != null;
} catch (Exception e) { }catch(Exception e){
return false; return false;
} }
} }
@@ -150,12 +150,12 @@ public class KryoClient implements ClientProvider{
} }
@Override @Override
public void disconnect() { public void disconnect(){
client.close(); client.close();
} }
@Override @Override
public void send(Object object, SendMode mode) { public void send(Object object, SendMode mode){
if(mode == SendMode.tcp){ if(mode == SendMode.tcp){
client.sendTCP(object); client.sendTCP(object);
}else{ }else{
@@ -166,12 +166,12 @@ public class KryoClient implements ClientProvider{
} }
@Override @Override
public void updatePing() { public void updatePing(){
client.updateReturnTripTime(); client.updateReturnTripTime();
} }
@Override @Override
public int getPing() { public int getPing(){
return client.getReturnTripTime(); return client.getReturnTripTime();
} }
@@ -218,7 +218,7 @@ public class KryoClient implements ClientProvider{
public void dispose(){ public void dispose(){
try{ try{
client.dispose(); client.dispose();
}catch (IOException e){ }catch(IOException e){
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }

View File

@@ -10,8 +10,8 @@ import java.util.concurrent.ScheduledExecutorService;
import static io.anuke.mindustry.Vars.headless; import static io.anuke.mindustry.Vars.headless;
/**Utilities and configs for kryo module.*/ /** Utilities and configs for kryo module. */
public class KryoCore { public class KryoCore{
public static boolean fakeLag = false; public static boolean fakeLag = false;
public static final int fakeLagMax = 500; public static final int fakeLagMax = 500;
public static final int fakeLagMin = 0; public static final int fakeLagMin = 0;
@@ -26,7 +26,7 @@ public class KryoCore {
Log.set(fakeLag ? Log.LEVEL_DEBUG : Log.LEVEL_WARN); Log.set(fakeLag ? Log.LEVEL_DEBUG : Log.LEVEL_WARN);
Log.setLogger(new Logger(){ Log.setLogger(new Logger(){
public void log (int level, String category, String message, Throwable ex) { public void log(int level, String category, String message, Throwable ex){
if(fakeLag){ if(fakeLag){
if(message.contains("UDP")){ if(message.contains("UDP")){
lastUDP = true; lastUDP = true;
@@ -45,7 +45,7 @@ public class KryoCore {
builder.append(message); builder.append(message);
if (ex != null) { if(ex != null){
StringWriter writer = new StringWriter(256); StringWriter writer = new StringWriter(256);
ex.printStackTrace(new PrintWriter(writer)); ex.printStackTrace(new PrintWriter(writer));
builder.append('\n'); builder.append('\n');
@@ -60,7 +60,7 @@ public class KryoCore {
}); });
} }
private static int calculateLag() { private static int calculateLag(){
return fakeLagMin + (int)(Math.random() * (fakeLagMax - fakeLagMin)); return fakeLagMin + (int) (Math.random() * (fakeLagMax - fakeLagMin));
} }
} }

View File

@@ -29,7 +29,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
import static io.anuke.mindustry.Vars.threads; import static io.anuke.mindustry.Vars.threads;
public class KryoServer implements ServerProvider { public class KryoServer implements ServerProvider{
final Server server; final Server server;
final CopyOnWriteArrayList<KryoConnection> connections = new CopyOnWriteArrayList<>(); final CopyOnWriteArrayList<KryoConnection> connections = new CopyOnWriteArrayList<>();
final CopyOnWriteArraySet<Integer> missing = new CopyOnWriteArraySet<>(); final CopyOnWriteArraySet<Integer> missing = new CopyOnWriteArraySet<>();
@@ -42,7 +42,7 @@ public class KryoServer implements ServerProvider {
public KryoServer(){ public KryoServer(){
KryoCore.init(); KryoCore.init();
server = new Server(4096*2, 4096, connection -> new ByteSerializer()); server = new Server(4096 * 2, 4096, connection -> new ByteSerializer());
server.setDiscoveryHandler((datagramChannel, fromAddress) -> { server.setDiscoveryHandler((datagramChannel, fromAddress) -> {
ByteBuffer buffer = NetworkIO.writeServerData(); ByteBuffer buffer = NetworkIO.writeServerData();
buffer.position(0); buffer.position(0);
@@ -53,31 +53,29 @@ public class KryoServer implements ServerProvider {
Listener listener = new Listener(){ Listener listener = new Listener(){
@Override @Override
public void connected (Connection connection) { public void connected(Connection connection){
String ip = connection.getRemoteAddressTCP().getAddress().getHostAddress(); String ip = connection.getRemoteAddressTCP().getAddress().getHostAddress();
KryoConnection kn = new KryoConnection(lastconnection ++, ip, connection); KryoConnection kn = new KryoConnection(lastconnection++, ip, connection);
Connect c = new Connect(); Connect c = new Connect();
c.id = kn.id; c.id = kn.id;
c.addressTCP = ip; c.addressTCP = ip;
Log.info("&bRecieved connection: {0} / {1}. Kryonet ID: {2}", c.id, c.addressTCP, connection.getID()); Log.info("&bRecieved connection: {0}", c.addressTCP);
connections.add(kn); connections.add(kn);
threads.runDelay(() -> Net.handleServerReceived(kn.id, c)); threads.runDelay(() -> Net.handleServerReceived(kn.id, c));
} }
@Override @Override
public void disconnected (Connection connection) { public void disconnected(Connection connection){
KryoConnection k = getByKryoID(connection.getID()); KryoConnection k = getByKryoID(connection.getID());
if(k == null) return; if(k == null) return;
Disconnect c = new Disconnect(); Disconnect c = new Disconnect();
c.id = k.id; c.id = k.id;
Log.info("&bLost connection: {0}", k.id);
threads.runDelay(() -> { threads.runDelay(() -> {
Net.handleServerReceived(k.id, c); Net.handleServerReceived(k.id, c);
connections.remove(k); connections.remove(k);
@@ -85,14 +83,14 @@ public class KryoServer implements ServerProvider {
} }
@Override @Override
public void received (Connection connection, Object object) { public void received(Connection connection, Object object){
KryoConnection k = getByKryoID(connection.getID()); KryoConnection k = getByKryoID(connection.getID());
if(object instanceof FrameworkMessage || k == null) return; if(object instanceof FrameworkMessage || k == null) return;
threads.runDelay(() -> { threads.runDelay(() -> {
try{ try{
Net.handleServerReceived(k.id, object); Net.handleServerReceived(k.id, object);
}catch (Exception e){ }catch(Exception e){
e.printStackTrace(); e.printStackTrace();
} }
}); });
@@ -112,7 +110,7 @@ public class KryoServer implements ServerProvider {
} }
@Override @Override
public Array<KryoConnection> getConnections() { public Array<KryoConnection> getConnections(){
array.clear(); array.clear();
for(KryoConnection c : connections){ for(KryoConnection c : connections){
array.add(c); array.add(c);
@@ -122,7 +120,7 @@ public class KryoServer implements ServerProvider {
@Override @Override
public KryoConnection getByID(int id){ public KryoConnection getByID(int id){
for(int i = 0; i < connections.size(); i ++){ for(int i = 0; i < connections.size(); i++){
KryoConnection con = connections.get(i); KryoConnection con = connections.get(i);
if(con.id == id){ if(con.id == id){
return con; return con;
@@ -133,7 +131,7 @@ public class KryoServer implements ServerProvider {
} }
@Override @Override
public void host(int port) throws IOException { public void host(int port) throws IOException{
//attempt to open default ports if they're not already open //attempt to open default ports if they're not already open
//this only opens the default port due to security concerns (?) //this only opens the default port due to security concerns (?)
if(port == Vars.port){ if(port == Vars.port){
@@ -141,7 +139,8 @@ public class KryoServer implements ServerProvider {
try{ try{
if(!UPnP.isMappedTCP(port)) UPnP.openPortTCP(port); if(!UPnP.isMappedTCP(port)) UPnP.openPortTCP(port);
if(!UPnP.isMappedUDP(port)) UPnP.openPortUDP(port); if(!UPnP.isMappedUDP(port)) UPnP.openPortUDP(port);
}catch(Throwable ignored){} }catch(Throwable ignored){
}
}); });
} }
@@ -153,7 +152,7 @@ public class KryoServer implements ServerProvider {
serverThread = new Thread(() -> { serverThread = new Thread(() -> {
try{ try{
server.run(); server.run();
}catch (Throwable e){ }catch(Throwable e){
if(!(e instanceof ClosedSelectorException)) handleException(e); if(!(e instanceof ClosedSelectorException)) handleException(e);
} }
}, "Kryonet Server"); }, "Kryonet Server");
@@ -162,7 +161,7 @@ public class KryoServer implements ServerProvider {
} }
@Override @Override
public void close() { public void close(){
connections.clear(); connections.clear();
lastconnection = 0; lastconnection = 0;
@@ -170,17 +169,17 @@ public class KryoServer implements ServerProvider {
} }
@Override @Override
public void sendStream(int id, Streamable stream) { public void sendStream(int id, Streamable stream){
KryoConnection connection = getByID(id); KryoConnection connection = getByID(id);
if(connection == null) return; if(connection == null) return;
try { try{
if (connection.connection != null) { if(connection.connection != null){
connection.connection.addListener(new InputStreamSender(stream.stream, 512) { connection.connection.addListener(new InputStreamSender(stream.stream, 512){
int id; int id;
protected void start() { protected void start(){
//send an object so the receiving side knows how to handle the following chunks //send an object so the receiving side knows how to handle the following chunks
StreamBegin begin = new StreamBegin(); StreamBegin begin = new StreamBegin();
begin.total = stream.stream.available(); begin.total = stream.stream.available();
@@ -189,14 +188,14 @@ public class KryoServer implements ServerProvider {
id = begin.id; id = begin.id;
} }
protected Object next(byte[] bytes) { protected Object next(byte[] bytes){
StreamChunk chunk = new StreamChunk(); StreamChunk chunk = new StreamChunk();
chunk.id = id; chunk.id = id;
chunk.data = bytes; chunk.data = bytes;
return chunk; //wrap the byte[] with an object so the receiving side knows how to handle it. return chunk; //wrap the byte[] with an object so the receiving side knows how to handle it.
} }
}); });
} else { }else{
int cid; int cid;
StreamBegin begin = new StreamBegin(); StreamBegin begin = new StreamBegin();
begin.total = stream.stream.available(); begin.total = stream.stream.available();
@@ -204,7 +203,7 @@ public class KryoServer implements ServerProvider {
connection.send(begin, SendMode.tcp); connection.send(begin, SendMode.tcp);
cid = begin.id; cid = begin.id;
while (stream.stream.available() > 0) { while(stream.stream.available() > 0){
byte[] bytes = new byte[Math.min(512, stream.stream.available())]; byte[] bytes = new byte[Math.min(512, stream.stream.available())];
stream.stream.read(bytes); stream.stream.read(bytes);
@@ -214,20 +213,20 @@ public class KryoServer implements ServerProvider {
connection.send(chunk, SendMode.tcp); connection.send(chunk, SendMode.tcp);
} }
} }
}catch (IOException e){ }catch(IOException e){
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
@Override @Override
public void send(Object object, SendMode mode) { public void send(Object object, SendMode mode){
for(int i = 0; i < connections.size(); i ++){ for(int i = 0; i < connections.size(); i++){
connections.get(i).send(object, mode); connections.get(i).send(object, mode);
} }
} }
@Override @Override
public void sendTo(int id, Object object, SendMode mode) { public void sendTo(int id, Object object, SendMode mode){
NetConnection conn = getByID(id); NetConnection conn = getByID(id);
if(conn == null){ if(conn == null){
if(!missing.contains(id)) if(!missing.contains(id))
@@ -239,8 +238,8 @@ public class KryoServer implements ServerProvider {
} }
@Override @Override
public void sendExcept(int id, Object object, SendMode mode) { public void sendExcept(int id, Object object, SendMode mode){
for(int i = 0; i < connections.size(); i ++){ for(int i = 0; i < connections.size(); i++){
KryoConnection conn = connections.get(i); KryoConnection conn = connections.get(i);
if(conn.id != id) conn.send(object, mode); if(conn.id != id) conn.send(object, mode);
} }
@@ -253,11 +252,13 @@ public class KryoServer implements ServerProvider {
} }
private void handleException(Throwable e){ private void handleException(Throwable e){
Timers.run(0f, () -> { throw new RuntimeException(e);}); Timers.run(0f, () -> {
throw new RuntimeException(e);
});
} }
KryoConnection getByKryoID(int id){ KryoConnection getByKryoID(int id){
for(int i = 0; i < connections.size(); i ++){ for(int i = 0; i < connections.size(); i++){
KryoConnection con = connections.get(i); KryoConnection con = connections.get(i);
if(con.connection != null && con.connection.getID() == id){ if(con.connection != null && con.connection.getID() == id){
return con; return con;
@@ -276,7 +277,7 @@ public class KryoServer implements ServerProvider {
class KryoConnection extends NetConnection{ class KryoConnection extends NetConnection{
public final Connection connection; public final Connection connection;
public KryoConnection(int id, String address, Connection connection) { public KryoConnection(int id, String address, Connection connection){
super(id, address); super(id, address);
this.connection = connection; this.connection = connection;
} }
@@ -288,13 +289,13 @@ public class KryoServer implements ServerProvider {
@Override @Override
public void send(Object object, SendMode mode){ public void send(Object object, SendMode mode){
try { try{
if (mode == SendMode.tcp) { if(mode == SendMode.tcp){
connection.sendTCP(object); connection.sendTCP(object);
} else { }else{
connection.sendUDP(object); connection.sendUDP(object);
} }
}catch (Exception e){ }catch(Exception e){
Log.err(e); Log.err(e);
Log.info("Disconnecting invalid client!"); Log.info("Disconnecting invalid client!");
connection.close(); connection.close();

View File

@@ -174,8 +174,8 @@ public class PowerTests extends PowerTestFixture{
powerGraph.update(); powerGraph.update();
assertEquals(0.0f, consumerTile.entity.power.satisfaction, MathUtils.FLOAT_ROUNDING_ERROR); assertEquals(0.0f, consumerTile.entity.power.satisfaction, MathUtils.FLOAT_ROUNDING_ERROR);
if(consumerTile.block().consumes.has(ConsumePower.class)){ if(consumerTile.block().consumes.hasSubtypeOf(ConsumePower.class)){
ConsumePower consumePower = consumerTile.block().consumes.get(ConsumePower.class); ConsumePower consumePower = consumerTile.block().consumes.getSubtypeOf(ConsumePower.class);
assertFalse(consumePower.valid(consumerTile.block(), consumerTile.entity())); assertFalse(consumePower.valid(consumerTile.block(), consumerTile.entity()));
} }
} }