Merge branches '4.0' and 'master' of https://github.com/Anuken/Mindustry into 4.0

# Conflicts:
#	core/assets/version.properties
#	core/src/io/anuke/mindustry/core/NetClient.java
#	core/src/io/anuke/mindustry/world/Tile.java
This commit is contained in:
Anuken
2018-03-03 18:06:57 -05:00
23 changed files with 425 additions and 356 deletions

View File

@@ -25,7 +25,7 @@ allprojects {
appName = 'Mindustry' appName = 'Mindustry'
gdxVersion = '1.9.8' gdxVersion = '1.9.8'
aiVersion = '1.8.1' aiVersion = '1.8.1'
uCoreVersion = '0a15aeb' uCoreVersion = '7f46315'
getVersionString = { getVersionString = {
String buildVersion = getBuildVersion() String buildVersion = getBuildVersion()

View File

@@ -1,25 +1,25 @@
text.about=Créé par [ROYAL]Anuken.[]\nÀ l'origine une entrée dans le [orange]GDL[] MM Jam.\n\n Crédits:\n- Effets sonores réalisés avec [YELLOW]bfxr[]\n- Musique faite par [GREEN]RoccoW[] / trouvé sur [lime]FreeMusicArchive.org[]\n\n Un grand merci à:\n- [coral]MitchellFJN[]: test de jeu étendu et rétroaction\n- [sky]Luxray5474[]: wiki travail, contribution de code\n- Tous les bêta-testeurs sur itch.io et Google Play\n text.about=Créé par [ROYAL]Anuken.[]\nÀ l'origine une entrée dans le [orange]GDL[] MM Jam.\n\n Crédits:\n- Effets sonores réalisés avec [YELLOW]bfxr[]\n- Musique faite par [GREEN]RoccoW[] / trouvé sur [lime]FreeMusicArchive.org[]\n\n Un grand merci à:\n- [coral]MitchellFJN[]: test de jeu étendu et rétroaction\n- [sky]Luxray5474[]: wiki travail, contribution de code\n- Tous les bêta-testeurs sur itch.io et Google Play\n
text.discord=Rejoignez le discord de Mindustry! text.discord=Rejoignez le discord de Mindustry!
text.gameover=Le Noyau a été détruit. text.gameover=Le Noyau a été détruit.
text.highscore=[YELLOW]Nouveau record text.highscore=[YELLOW]Nouveau record
text.lasted=Vous avez survécu jusqu'à la vague text.lasted=Vous avez survécu jusqu'à la vague
text.level.highscore=Meilleur Score : [accent] {0} text.level.highscore=Meilleur Score : [accent] {0}
text.level.delete.title=Confirmation de la suppression text.level.delete.title=Confirmation de la suppression
text.level.delete=Êtes-vous sûr de vouloir supprimer \nla carte "[orange]{0}" ? text.level.delete=Êtes-vous sûr de vouloir supprimer \nla carte "[orange]{0}" ?
text.level.select=Sélection de niveau text.level.select=Sélection de niveau
text.level.mode=Mode de jeu : text.level.mode=Mode de jeu :
text.savegame=Sauvegarder la partie text.savegame=Sauvegarder la partie
text.loadgame=Chargement du jeu text.loadgame=Chargement du jeu
text.quit=Quitter text.quit=Quitter
text.tutorial.back=< Précédent text.tutorial.back=< Précédent
text.tutorial.next=Suivant > text.tutorial.next=Suivant >
text.save.new=Nouvelle Sauvegarde text.save.new=Nouvelle Sauvegarde
text.save.overwrite=Êtes-vous sûr de vouloir remplacer \ncet emplacement de sauvegarde ? text.save.overwrite=Êtes-vous sûr de vouloir remplacer \ncet emplacement de sauvegarde ?
text.overwrite=Écraser text.overwrite=Écraser
text.save.none=Aucune sauvegarde trouvée ! text.save.none=Aucune sauvegarde trouvée !
text.saveload=[accent]Sauvegarde... text.saveload=[accent]Sauvegarde...
text.savefail=Échec de la sauvegarde du jeu ! text.savefail=Échec de la sauvegarde du jeu !
text.save.delete.confirm=Êtes-vous sur de vouloir supprimer cette sauvegarde ? text.save.delete.confirm=Êtes-vous sur de vouloir supprimer cette sauvegarde ?
text.save.delete=Supprimer text.save.delete=Supprimer
text.save.export=Exporter une sauvegarde text.save.export=Exporter une sauvegarde
text.save.import.invalid=[orange]Cette sauvegarde est invalide ! text.save.import.invalid=[orange]Cette sauvegarde est invalide !
@@ -28,9 +28,9 @@ text.save.export.fail=[crimson]Erreur pour exporter cette sauvegarde : [orange]{
text.save.import=Importer une sauvegarde text.save.import=Importer une sauvegarde
text.save.newslot=Nom de la sauvegarde : text.save.newslot=Nom de la sauvegarde :
text.save.rename=Renommer text.save.rename=Renommer
text.save.rename.text=nouveaux nom : text.save.rename.text=nouveau nom :
text.selectslot=Sélectionnez une sauvegarde. text.selectslot=Sélectionnez une sauvegarde.
text.selectslot=Sélectionnez un emplacement de sauvegarde. text.selectslot=Sélectionnez un emplacement de sauvegarde.
text.slot=[accent]Emplacement {0} text.slot=[accent]Emplacement {0}
text.save.corrupted=[orange]Ficher de sauvegarde invalide ou corrompu ! text.save.corrupted=[orange]Ficher de sauvegarde invalide ou corrompu !
text.empty=<vide> text.empty=<vide>
@@ -39,15 +39,15 @@ text.off=Off
text.save.autosave=Sauvegarde auto : {0} text.save.autosave=Sauvegarde auto : {0}
text.save.map=Carte : {0} text.save.map=Carte : {0}
text.save.wave=Vague {0} text.save.wave=Vague {0}
text.save.date=Dernier enregistrement: {0} text.save.date=Enregistré le {0}
text.confirm=Confirmer text.confirm=Confirmer
text.delete=Effacer text.delete=Effacer
text.ok=Ok text.ok=Ok
text.open=Ouvrir text.open=Ouvrir
text.cancel=Annuler text.cancel=Annuler
text.openlink=Ouvrir le lien text.openlink=Ouvrir le lien
text.back=Arrière text.back=Retour
text.quit.confirm=Êtes-vous sûr de vouloir quitter ? text.quit.confirm=Êtes-vous sûr de vouloir quitter ?
text.loading=[accent]Chargement... text.loading=[accent]Chargement...
text.wave=[orange]Vague {0} text.wave=[orange]Vague {0}
text.wave.waiting=Vague dans {0} text.wave.waiting=Vague dans {0}
@@ -60,106 +60,106 @@ text.saveimage=Enregistrer l'image
text.editor.badsize=[orange]Dimensions de l'image incorrectes![]\n Dimensions de carte valides: {0} text.editor.badsize=[orange]Dimensions de l'image incorrectes![]\n Dimensions de carte valides: {0}
text.editor.errorimageload=Erreur lors du chargement du fichier image:\n[orange]{0} text.editor.errorimageload=Erreur lors du chargement du fichier image:\n[orange]{0}
text.editor.errorimagesave=Erreur lors de l'enregistrement du fichier image:\n[orange]{0} text.editor.errorimagesave=Erreur lors de l'enregistrement du fichier image:\n[orange]{0}
text.editor.generate=Générer text.editor.generate=Générer
text.editor.resize=Redimensionner text.editor.resize=Redimensionner
text.editor.loadmap=Chargement de la carte text.editor.loadmap=Chargement de la carte
text.editor.savemap=Enregistrer la carte text.editor.savemap=Enregistrer la carte
text.editor.loadimage=Chargement de l'image text.editor.loadimage=Chargement de l'image
text.editor.saveimage=Enregistrer l'image text.editor.saveimage=Enregistrer l'image
text.editor.unsaved=[scarlet]Vous avez des changements non enregistrés![]\n Êtes-vous sûr de vouloir quitter? text.editor.unsaved=[scarlet]Vous avez des changements non enregistrés![]\n Êtes-vous sûr de vouloir quitter?
text.editor.brushsize=Taille du pinceau: {0} text.editor.brushsize=Taille du pinceau: {0}
text.editor.noplayerspawn=Cette carte n'a pas de point d'apparition de joueur! text.editor.noplayerspawn=Cette carte n'a pas de point d'apparition de joueur!
text.editor.manyplayerspawns=Les cartes ne peuvent pas avoir plus \nd'un point d'apparition! text.editor.manyplayerspawns=Les cartes ne peuvent pas avoir plus \nd'un point d'apparition!
text.editor.manyenemyspawns=Ne peut pas avoir plus de \n{0} points de réapparition ennemis! text.editor.manyenemyspawns=Ne peut pas avoir plus de \n{0} points de réapparition ennemis!
text.editor.resizemap=Redimensionner la carte text.editor.resizemap=Redimensionner la carte
text.editor.resizebig=[scarlet]Attention! \n[]Les cartes de plus de 256 unités peuvent être décalées et instables! text.editor.resizebig=[scarlet]Attention! \n[]Les cartes de plus de 256 unités peuvent être décalées et instables!
text.editor.mapname=Nom de la carte: text.editor.mapname=Nom de la carte:
text.editor.overwrite=[accent]Attention! \nCela écrase une carte existante text.editor.overwrite=[accent]Attention! \nCela écrase une carte existante
text.editor.failoverwrite=[crimson]Impossible d'écraser la carte par défaut! text.editor.failoverwrite=[crimson]Impossible d'écraser la carte par défaut!
text.editor.selectmap=Sélectionnez une carte à charger: text.editor.selectmap=Sélectionnez une carte à charger:
text.width=Largeur: text.width=Largeur:
text.height=Hauteur: text.height=Hauteur:
text.randomize=Aléatoire text.randomize=Aléatoire
text.apply=Appliquer text.apply=Appliquer
text.update=Mettre à jour text.update=Mettre à jour
text.menu=Menu text.menu=Menu
text.play=Jouer text.play=Jouer
text.load=Charger text.load=Charger
text.save=sauvegarder text.save=Sauvegarder
text.settings=Paramètres text.settings=Paramètres
text.tutorial=Tutoriel text.tutorial=Tutoriel
text.editor=Éditeur text.editor=Éditeur
text.mapeditor=Éditeur de carte text.mapeditor=Éditeur de carte
text.donate=Faire un don text.donate=Faire un don
text.settings.reset=Réinitialiser les paramètres par défaut text.settings.reset=Remettre les paramètres par défaut
text.settings.controls=Controles text.settings.controls=Contrôles
text.settings.game=Jeu text.settings.game=Jeu
text.settings.sound=Son text.settings.sound=Son
text.settings.graphics=Graphiques text.settings.graphics=Graphismes
text.upgrades=Mises à niveau text.upgrades=Mises à niveau
text.purchased=[LIME]Acheté! text.purchased=[LIME]Acheté!
text.weapons=Armes text.weapons=Armes
text.paused=En pause text.paused=Pause
text.respawn=Réappartition dans text.respawn=Réapparition dans
text.error.title=[crimson]Une erreur est survenue text.error.title=[crimson]Une erreur est survenue
text.error.crashmessage=[SCARLET]Une erreur inattendue s'est produite, qui aurait causé un crash. []Veuillez indiquer les circonstances exactes dans lesquelles cette erreur c'est produite pour le développeur: \n[ORANGE]anukendev@gmail.com[] text.error.crashmessage=[SCARLET]Une erreur inattendue s'est produite qui aurait causé un crash. []Veuillez indiquer les circonstances exactes dans lesquelles cette erreur s'est produite pour le développeur: \n[ORANGE]anukendev@gmail.com[]
text.error.crashtitle=Une erreur est survenue text.error.crashtitle=Une erreur est survenue
text.blocks.extrainfo=[accent]Informations supplémentaires sur les blocs: text.blocks.extrainfo=[accent]Informations supplémentaires sur les blocs:
text.blocks.blockinfo=Bloquer les infos text.blocks.blockinfo=Bloquer les infos
text.blocks.powercapacity=Capacité Electrique text.blocks.powercapacity=Capacité Electrique
text.blocks.powershot=Puissance/Tir text.blocks.powershot=Puissance/Tir
text.blocks.powersecond=Puissance/Seconde text.blocks.powersecond=Puissance/Seconde
text.blocks.powerdraindamage=Drain de puissance/Dégats text.blocks.powerdraindamage=Drain de puissance/Dégats
text.blocks.shieldradius=Rayon de bouclier text.blocks.shieldradius=Rayon de bouclier
text.blocks.itemspeedsecond=Article vitesse/objet text.blocks.itemspeedsecond=Vitesse/objet
text.blocks.range=Portée text.blocks.range=Portée
text.blocks.size=Taille text.blocks.size=Taille
text.blocks.powerliquid=Puissance/Liquide text.blocks.powerliquid=Puissance/Liquide
text.blocks.maxliquidsecond=Max liquide/Seconde text.blocks.maxliquidsecond=Max liquide/Seconde
text.blocks.liquidcapacity=Capacité Liquide text.blocks.liquidcapacity=Capacité Liquide
text.blocks.liquidsecond=Liquide/Seconde text.blocks.liquidsecond=Liquide/Seconde
text.blocks.damageshot=Dégats/Tirs text.blocks.damageshot=Dégats/Tirs
text.blocks.ammocapacity=Capacité de munitions text.blocks.ammocapacity=Capacité de munitions
text.blocks.ammo=Munitions text.blocks.ammo=Munitions
text.blocks.ammoitem=Munitions/objet text.blocks.ammoitem=Munitions/objet
text.blocks.maxitemssecond=Max d'objet/Seconde text.blocks.maxitemssecond=Max d'objet/Seconde
text.blocks.powerrange=Portée de la Puissance text.blocks.powerrange=Portée de la Puissance
text.blocks.lasertilerange=Portée du carreau Laser text.blocks.lasertilerange=Portée du carreau Laser
text.blocks.capacity=Capacité text.blocks.capacity=Capacité
text.blocks.itemcapacity=Capacité de l'objet text.blocks.itemcapacity=Capacité de l'objet
text.blocks.powergenerationsecond=Génération d'énergie/seconde text.blocks.powergenerationsecond=Génération d'énergie/seconde
text.blocks.generationsecondsitem=Génération secondes/item text.blocks.generationsecondsitem=Génération secondes/item
text.blocks.input=Contribution text.blocks.input=Carburant
text.blocks.inputliquid=Liquide d'entrée text.blocks.inputliquid=Liquide d'entrée
text.blocks.inputitem=Élément d'entrée text.blocks.inputitem=Élément d'entrée
text.blocks.output=Sortie text.blocks.output=Sortie
text.blocks.secondsitem=Secondes/Article text.blocks.secondsitem=Secondes/Article
text.blocks.maxpowertransfersecond=Transfert de puissance maximum/seconde text.blocks.maxpowertransfersecond=Transfert de puissance maximum/seconde
text.blocks.explosive=Hautement explosif! text.blocks.explosive=Hautement explosif!
text.blocks.repairssecond=Réparations/seconde text.blocks.repairssecond=Réparations/seconde
text.blocks.health=Santé text.blocks.health=Santé
text.blocks.inaccuracy=présicion text.blocks.inaccuracy=Présicion
text.blocks.shots=Tirs text.blocks.shots=Tirs
text.blocks.shotssecond=Tirs/seconde text.blocks.shotssecond=Tirs/seconde
text.placemode=Mode de Placement text.placemode=Mode Placement
text.breakmode=Mode démolition text.breakmode=Mode Démolition
text.health=Santé text.health=Santé
setting.saveinterval.name=Intervale de l'Autosave setting.saveinterval.name=Intervalle de la sauvegarde automatique
setting.seconds={0} Secondes setting.seconds={0} Secondes
setting.difficulty.easy=Facile setting.difficulty.easy=Facile
setting.difficulty.normal=Classique setting.difficulty.normal=Normal
setting.difficulty.hard=Difficile setting.difficulty.hard=Difficile
setting.difficulty.name=Difficulté setting.difficulty.name=Difficulté
setting.screenshake.name=Tremblement d'écran setting.screenshake.name=Vibration de l'écran
setting.smoothcam.name=Caméra lisse setting.smoothcam.name=Mouvements de la caméra lissés
setting.indicators.name=Indicateurs d'ennemis setting.indicators.name=Indicateurs d'ennemis
setting.effects.name=Effets setting.effects.name=Afficher les effets
setting.sensitivity.name=Sensibilité du contrôleur setting.sensitivity.name=Sensibilité de la manette
setting.fps.name=Afficher FPS setting.fps.name=Afficher FPS
setting.vsync.name=VSync setting.vsync.name=VSync
setting.lasers.name=Afficher les lasers d'énergie setting.lasers.name=Afficher les lasers d'énergie
setting.healthbars.name=Afficher les barres de santés d'une entitée setting.healthbars.name=Afficher les barres de santés d'une entitée
setting.pixelate.name=Écran Pixéliser setting.pixelate.name=Écran Pixélisé
setting.musicvol.name=Volume de la musique setting.musicvol.name=Volume de la musique
setting.mutemusic.name=Musique muette setting.mutemusic.name=Musique muette
setting.sfxvol.name=Volume des effets sonores setting.sfxvol.name=Volume des effets sonores
@@ -170,66 +170,66 @@ map.sinkhole.name=Gouffre
map.caves.name=Cavernes map.caves.name=Cavernes
map.volcano.name=Volcan map.volcano.name=Volcan
map.caldera.name=Caldera map.caldera.name=Caldera
map.scorch.name=Brûlée map.scorch.name=Terres Brûlée
map.desert.name=Désert map.desert.name=Désert
map.island.name=île map.island.name=île
map.grassland.name=Prairie map.grassland.name=Prairie
map.tundra.name=Toundra map.tundra.name=Toundra
map.spiral.name=Spirale map.spiral.name=Spirale
map.tutorial.name=Tutoriel map.tutorial.name=Tutoriel
tutorial.intro.text=[yellow]Bienvenue dans le tutoriel.[] Pour commencer, appuyez sur "Suivant" tutorial.intro.text=[yellow]Bienvenue dans le tutoriel.[] Pour commencer, appuyez sur "Suivant"
tutorial.moveDesktop.text=Pour vous déplacer, utilisez les touches [orange][[WASD (pour qwerty) ou ZQSD (pour azerty)][] . tenir [orange]MAJ[] active le Booster. tenir [orange]CTRL[] en utilisant la [orange]molette[] pour faire un zoom avant ou arrière. tutorial.moveDesktop.text=Pour vous déplacer, utilisez les touches [orange][[WASD (pour qwerty) ou ZQSD (pour azerty)][] . Maintenir [orange]MAJ[] active le Booster. Maintenir [orange]CTRL[] en utilisant la [orange]molette[] pour faire un zoom avant ou arrière.
tutorial.shootInternal.text=Utilisez votre souris pour viser, maintenez [orange]le bouton gauche de la souris[] pour tirer. essayez de vous entraîner sur la [yellow]cible[]. tutorial.shootInternal.text=Utilisez votre souris pour viser, maintenez [orange]le clic gauche de la souris[] pour tirer. Essayez de vous entraîner sur la [yellow]cible[].
tutorial.moveAndroid.text=Pour déplacer la vue, faites glisser un doigt sur l'écran. Pincez et faites glisser pour effectuer un zoom avant ou arrière. tutorial.moveAndroid.text=Pour déplacer la vue, faites glisser un doigt sur l'écran. Pincez et faites glisser pour effectuer un zoom avant ou arrière.
tutorial.placeSelect.text=Essayez de sélectionner un [yellow]tapis roulant[] du menu de bloc en bas à droite. tutorial.placeSelect.text=Essayez de sélectionner un [yellow]tapis roulant[] du menu à bloc en bas à droite.
tutorial.placeConveyorDesktop.text=Utilisez la [orange][[molette][] faire tourner le tapis roulant pour faire face [orange]avant[], puis placez-le dans l'[yellow]emplacement marqué[] en utilisant le [orange][[bouton gauche de la souris][]. tutorial.placeConveyorDesktop.text=Utilisez la [orange]molette[] pour faire tourner le tapis roulant afin de l'orienter vers l'[orange]avant[], puis placez-le dans l'[yellow]emplacement marqué[] en utilisant le [orange]clic gauche de la souris[].
tutorial.placeConveyorAndroid.text=Utilisez le [orange][[bouton de rotation][] faire tourner le tapis roulant pour faire face [orange]avant[], faites-le glisser avec un doigt, puis placez-le dans l'[yellow]emplacement marqué[] en utilisant la [orange][[coche][]. tutorial.placeConveyorAndroid.text=Utilisez le [orange]bouton de rotation[] pour faire tourner le tapis roulant afin de l'orienter vers l'[orange]avant[], faites-le glisser puis puis placez-le dans l'[yellow]emplacement marqué[].
tutorial.placeConveyorAndroidInfo.text=Vous pouvez également appuyer sur l'icône oeil en bas à gauche pour passer en [orange][[mode tactile][]et placez des blocs en tapant sur l'écran. En mode tactile, les blocs peuvent être pivotés avec la flèche en bas à gauche. pressez [yellow]prochain[] pour l'essayer tutorial.placeConveyorAndroidInfo.text=Vous pouvez également appuyer sur l'icône oeil en bas à gauche pour passer en [orange]mode tactile[]et placez des blocs en tapant sur l'écran. En mode tactile, les blocs peuvent être pivotés avec la flèche en bas à gauche. Pressez [yellow]prochain[] pour l'essayer
tutorial.placeDrill.text=Maintenant, sélectionnez et placez un [yellow]extracteur de pierre[] à l'endroit marqué tutorial.placeDrill.text=Maintenant, sélectionnez et placez un [yellow]extracteur de pierre[] à l'endroit marqué
tutorial.blockInfo.text=Si vous voulez en savoir plus sur un bloc, vous pouvez appuyer sur le [orange]point d'interrogation[] en haut à droite pour lire sa description. tutorial.blockInfo.text=Si vous voulez en savoir plus sur un bloc, vous pouvez appuyer sur le [orange]point d'intérrogation[] en haut à droite pour lire sa description.
tutorial.deselectDesktop.text=Vous pouvez désélectionner un bloc en appuyant sur le [orange][[bouton droit de la souris][]. tutorial.deselectDesktop.text=Vous pouvez désélectionner un bloc en appuyant sur le [orange]clic droit de la souris[].
tutorial.deselectAndroid.text=Vous pouvez désélectionner un bloc en appuyant sur le bouton [orange]X[]. tutorial.deselectAndroid.text=Vous pouvez désélectionner un bloc en appuyant sur le bouton [orange]X[].
tutorial.drillPlaced.text=L'extracteur va maintenant produire [yellow]de la pierre,[] la sortir sur le tapis roulant, et le déplacer dans le [Yellow]noyau[]. tutorial.drillPlaced.text=L'extracteur va maintenant produire [yellow]de la pierre,[] la sortir sur le tapis roulant, et le déplacer dans le [Yellow]noyau[].
tutorial.drillInfo.text=Les différents minerais ont besoin d'extracteurs différents. La pierre nécessite des extracteurs de pierre, le fer nécessite des extracteurs de fer, etc. tutorial.drillInfo.text=Les différents minerais ont besoin d'extracteurs différents. La pierre nécessite des extracteurs de pierre, le fer nécessite des extracteurs de fer, etc.
tutorial.drillPlaced2.text=Le déplacement d'éléments dans le noyau les place dans votre [yellow]inventaire d'éléments[], en haut à gauche. Le placement de blocs utilise des éléments de votre inventaire. tutorial.drillPlaced2.text=Le déplacement de minerais dans le noyau les placent dans votre [yellow]inventaire[], en haut à gauche. Le placement de blocs utilise des minerais de votre inventaire.
tutorial.moreDrills.text=Vous pouvez relier plusieurs extracteurs et tapis roulants ensemble, comme ça. tutorial.moreDrills.text=Vous pouvez relier plusieurs extracteurs et tapis roulants ensemble, comme ça.
tutorial.deleteBlock.text=vous pouvez supprimer des blocs en utilisant le [orange]bouton droit de la souris[] sur le bloc que vous voulez supprimer. Essayez de supprimer ce tapis roulant. tutorial.deleteBlock.text=vous pouvez supprimer des blocs en utilisant le [orange]clic droit de la souris[] sur le bloc que vous voulez supprimer. Essayez de supprimer ce tapis roulant.
tutorial.deleteBlockAndroid.text=Vous pouvez supprimer des blocs en sélectionnant l'oeil[] dans le [orange]menu en mode pause[] en bas à gauche et en tapant un bloc. Essayez de supprimer ce tapis roulant. tutorial.deleteBlockAndroid.text=Vous pouvez supprimer des blocs en sélectionnant l'oeil[] dans le [orange]menu en mode pause[] en bas à gauche et en tapant un bloc. Essayez de supprimer ce tapis roulant.
tutorial.placeTurret.text=Maintenant, sélectionnez et placez une [yellow]tourelle[] [yellow]à l'endroit marqué[]. tutorial.placeTurret.text=Maintenant, sélectionnez et placez une [yellow]tourelle[] [yellow]à l'endroit marqué[].
tutorial.placedTurretAmmo.text=la tourelle va maintenant accepter les [yellow]munitions[] venant du tapis roulant. vous pouvez voir combien de munitions il reste en la touchant et en regardant la [green]barre verte[]. tutorial.placedTurretAmmo.text=La tourelle va maintenant accepter les [yellow]munitions[] venant du tapis roulant. vous pouvez voir combien de munitions il reste en la touchant et en regardant la [green]barre verte[].
tutorial.turretExplanation.text=Les tourelle tirent automatiquement sur l'ennemi le plus proche et à portée de tirs, tant qu'elles ont assez de munitions. tutorial.turretExplanation.text=Les tourelles tirent automatiquement sur l'ennemi le plus proche et à portée de tir si elles ont des munitions.
tutorial.waves.text=Toutes les [yellow]60[] secondes, une vague d'[coral]ennemis[] apparaîtra dans des endroits spécifiques et tentera de détruire le noyau. tutorial.waves.text=Toutes les [yellow]60[] secondes, une vague d'[coral]ennemis[] apparaîtra dans des endroits spécifiques et tentera de détruire le noyau.
tutorial.coreDestruction.text=Votre objectif est de [yellow]défendre le noyau[]. Si le noyau est détruit, vous [coral]perdez la partie[]. tutorial.coreDestruction.text=Votre objectif est de [yellow]défendre le noyau[]. Si le noyau est détruit, vous [coral]perdez la partie[].
tutorial.pausingDesktop.text=Si vous avez besoin de mettre en pause, appuyer sur le [orange]boutton pause[] en haut à gauche ou sur [orange]la touche espace[]. Vous pourez toujours sélectionner et placer des blocs, mais vous ne pourez ni bouger, ni tirer. tutorial.pausingDesktop.text=Si vous avez besoin de mettre en pause, appuyer sur le [orange]boutton pause[] en haut à gauche ou sur [orange]la touche espace[]. Vous pourrez toujours sélectionner et placer des blocs mais vous ne pourrez bouger ou tirer.
tutorial.pausingAndroid.text=Si vous avez besoin de mettre en pause, appuyer sur le [orange]boutton pause[] en haut à gauche. Vous pourez toujours sélectionner et placer des blocs. tutorial.pausingAndroid.text=Si vous avez besoin de mettre en pause, appuyer sur le [orange]boutton pause[] en haut à gauche. Vous pourez toujours sélectionner et placer des blocs.
tutorial.purchaseWeapons.text=Vous pouvez achetez de nouvelles [yellow]armes[] pour votre mecha en ouvrant le menu des amélioration en bas à gauche. tutorial.purchaseWeapons.text=Vous pouvez acheter de nouvelles [yellow]armes[] pour votre mecha en ouvrant le menu des améliorations en bas à gauche.
tutorial.switchWeapons.text=Changez d'armes en cliquant sur leurs icones en bas à gauche, ou en utilisant les chiffres [orange][[1-9][]. tutorial.switchWeapons.text=Changez d'armes en cliquant sur leur icône en bas à gauche, ou en utilisant les chiffres [orange][[1-9][].
tutorial.spawnWave.text=Une vague est en train d'arriver. Détruisez la. tutorial.spawnWave.text=Une vague est en train d'arriver. Détruisez-la.
tutorial.pumpDesc.text=Pour les vagues suivantes, Vous pouriez avoir besoin de la [yellow]pompe[] pour alimenter les générateurs avec certains liquides. tutorial.pumpDesc.text=Pour les vagues suivantes, Vous pourriez avoir besoin de la [yellow]pompe[] pour alimenter les générateurs avec certains liquides.
tutorial.pumpPlace.text=Les pompes fonctionnent pareil que les extracteurs, à l'exception qu'elles produisent un liquide et non un minerais. Essayez de placer une pompe sur [yellow]la flaque d'huile désignée[]. tutorial.pumpPlace.text=Les pompes fonctionnent comme les extracteurs à l'exception qu'elles produisent un liquide et non un minerai. Essayez de placer une pompe sur [yellow]la flaque d'huile désignée[].
tutorial.conduitUse.text=Maintenant, placez un [orange]conduit[] pour récupérer la production de la pompe. tutorial.conduitUse.text=Maintenant, placez un [orange]conduit[] pour récupérer la production de la pompe.
tutorial.conduitUse2.text=Et un autre... tutorial.conduitUse2.text=Et un autre...
tutorial.conduitUse3.text=Et encore un autre... tutorial.conduitUse3.text=Et encore un autre...
tutorial.generator.text=Maintenant, placez un [orange]generateur à combustion[] à la fin des conduits. tutorial.generator.text=Maintenant, placez un [orange]générateur à combustion[] à la fin des conduits.
tutorial.generatorExplain.text=Ce générateur va maintenant créé de l'[yellow]énergie[] à partir de l'huile. tutorial.generatorExplain.text=Ce générateur va maintenant créer de l'[yellow]énergie[] à partir de l'huile.
tutorial.lasers.text=L'énergie peut-être redistribuée en utilisant les [yellow]lasers énergétiques[]. Placez-en un. tutorial.lasers.text=L'énergie peut-être redistribuée en utilisant les [yellow]lasers énergétiques[]. Placez-en un.
tutorial.laserExplain.text=Le générateur va maintenant distribuer de l'énergie à travers le laser. Un faisceau [yellow]opaque[] signifie une transmition d'énergie, et un faisceau [yellow]transparent[] signifie qu'il n'en transmet pas. tutorial.laserExplain.text=Le générateur va maintenant distribuer de l'énergie à travers le laser. Un faisceau [yellow]opaque[] signifie une transmission d'énergie, et un faisceau [yellow]transparent[] signifie qu'il n'en transmet pas.
tutorial.laserMore.text=Vous pouvez vérifier le niveau énergétique d'un bloc en le selectionnant et en regardant la [yellow]barre jaune[] au-dessus du bloc. tutorial.laserMore.text=Vous pouvez vérifier le niveau énergétique d'un bloc en le sélectionnant et en regardant la [yellow]barre jaune[] au-dessus du bloc.
tutorial.healingTurret.text=Ce laser peut-être utilisé pour alimenter une [lime]tourelle réparatrice[]. Placez-en une ici. tutorial.healingTurret.text=Ce laser peut-être utilisé pour alimenter une [lime]tourelle réparatrice[]. Placez-en une ici.
tutorial.healingTurretExplain.text=Tant qu'elle sera allimentée, cette tourelle va [lime]réparer les bloc voisin.[] Lorsque vous jouez, assurez-vous d'en avoir le plus rapidement possible! tutorial.healingTurretExplain.text=Tant qu'elle sera alimentée, cette tourelle va [lime]réparer les blocs voisins.[] Lorsque vous jouez, assurez-vous d'en avoir le plus rapidement possible !
tutorial.smeltery.text=Beaucoup de bloc ont besoin d'[orange]acier[]. Pour en fabriquer, il faut une [orange]fonderie[]. Placez-en une ici. tutorial.smeltery.text=Beaucoup de blocs ont besoin d'[orange]acier[]. Pour en fabriquer, il faut une [orange]fonderie[]. Placez-en une ici.
tutorial.smelterySetup.text=La fonderie produit maintenant de l'[orange]acier[] avec le charbon et le fer. tutorial.smelterySetup.text=La fonderie produit maintenant de l'[orange]acier[] avec le charbon et le fer.
tutorial.end.text=Vous avez fini le tutoriel! Bien joué! tutorial.end.text=Vous avez fini le tutoriel! Bien joué!
keybind.move_x.name=déplacement_x keybind.move_x.name=déplacement_x
keybind.move_y.name=déplacement_y keybind.move_y.name=déplacement_y
keybind.select.name=selectionner keybind.select.name=sélectionner
keybind.break.name=casser keybind.break.name=casser
keybind.shootInternal.name=tirer keybind.shootInternal.name=tirer
keybind.zoom_hold.name=maintenir_pour_zoomer keybind.zoom_hold.name=maintenir_pour_zoomer
keybind.zoom.name=zoomer keybind.zoom.name=zoomer
keybind.menu.name=menu keybind.menu.name=menu
keybind.pause.name=pause keybind.pause.name=pause
keybind.dash.name=accélération keybind.dash.name=accélération
keybind.rotate_alt.name=tourner_alt keybind.rotate_alt.name=tourner_alt
keybind.rotate.name=tourner keybind.rotate.name=tourner
keybind.weapon_1.name=arme_1 keybind.weapon_1.name=arme_1
@@ -239,42 +239,42 @@ keybind.weapon_4.name=arme_4
keybind.weapon_5.name=arme_5 keybind.weapon_5.name=arme_5
keybind.weapon_6.name=arme_6 keybind.weapon_6.name=arme_6
mode.waves.name=vagues mode.waves.name=vagues
mode.sandbox.name=bac à sable mode.sandbox.name=bac à sable
mode.freebuild.name=construction mode.freebuild.name=construction
weapon.blaster.name=blaster weapon.blaster.name=Blaster
weapon.blaster.description=Tire une balle lente et faible. weapon.blaster.description=Tire une balle lente et faible.
weapon.triblaster.name=triblaster weapon.triblaster.name=Triple blaster
weapon.triblaster.description=Tire 3 balles dans une propagation. weapon.triblaster.description=Tire 3 balles dans une propagation.
weapon.multigun.name=mitrailleuse weapon.multigun.name=Mitrailleuse
weapon.multigun.description=Tire des balles imprécises mais avec une haute cadance de feu. weapon.multigun.description=Tire des balles imprécises mais avec une haute cadance de feu.
weapon.flamer.name=lance-flamme weapon.flamer.name=Lance-flamme
weapon.flamer.description=Tire une collone de feu. weapon.flamer.description=Tire une colonne de feu.
weapon.railgun.name=Fusil a energie weapon.railgun.name=Fusil a énergie
weapon.railgun.description=Tire une balle à longue portée. weapon.railgun.description=Tire une balle à longue portée.
weapon.mortar.name=Mortier weapon.mortar.name=Mortier
weapon.mortar.description=Tire sur un obus lent mais explosif. weapon.mortar.description=Tire sur un obus lent mais explosif.
item.stone.name=pierre item.stone.name=pierre
item.iron.name=fer item.iron.name=fer
item.coal.name=charbon item.coal.name=charbon
item.steel.name=acier item.steel.name=acier
item.titanium.name=titanium item.titanium.name=titane
item.dirium.name=dirium item.dirium.name=dirium
item.uranium.name=uranium item.uranium.name=uranium
liquid.water.name=eau liquid.water.name=eau
liquid.plasma.name=plasma liquid.plasma.name=plasma
liquid.lava.name=lave liquid.lava.name=lave
liquid.oil.name=pétrole liquid.oil.name=pétrole
block.air.name=air block.air.name=air
block.blockpart.name=blockpart block.blockpart.name=blockpart
block.deepwater.name=eau profonde block.deepwater.name=eau profonde
block.water.name=eau block.water.name=eau
block.lava.name=lave block.lava.name=lave
block.oil.name=pétrole block.oil.name=pétrole
block.stone.name=pierre block.stone.name=pierre
block.blackstone.name=pierre noir block.blackstone.name=pierre noir
block.iron.name=fer block.iron.name=fer
block.coal.name=charbon block.coal.name=charbon
block.titanium.name=titanium block.titanium.name=titane
block.uranium.name=uranium block.uranium.name=uranium
block.dirt.name=terre block.dirt.name=terre
block.sand.name=sable block.sand.name=sable
@@ -289,182 +289,182 @@ block.grassblock.name=block d'herbe
block.mossblock.name=bloc de mousse block.mossblock.name=bloc de mousse
block.shrub.name=arbuste block.shrub.name=arbuste
block.rock.name=rocher block.rock.name=rocher
block.icerock.name=rocher glacé block.icerock.name=rocher glacé
block.blackrock.name=rocher noir block.blackrock.name=rocher noir
block.dirtblock.name=bloc de pousière block.dirtblock.name=bloc de pousière
block.stonewall.name=mur de pierre block.stonewall.name=mur de pierre
block.stonewall.fulldescription=Un bloc défensif bon marché. Utile pour protéger le noyau et les tourelles dans les premières vagues. block.stonewall.fulldescription=Un bloc défensif bon marché. Utile pour protéger le noyau et les tourelles dans les premières vagues.
block.ironwall.name=mur de fer block.ironwall.name=mur de fer
block.ironwall.fulldescription=Un bloc défensif de base. Fournit une protection contre les ennemis. block.ironwall.fulldescription=Un bloc défensif de base. Fournit une protection contre les ennemis.
block.steelwall.name=mur d'acier block.steelwall.name=mur d'acier
block.steelwall.fulldescription=Un bloc défensif standard. une protection adéquate contre les ennemis. block.steelwall.fulldescription=Un bloc défensif standard. une protection adéquate contre les ennemis.
block.titaniumwall.name=mur de titanium block.titaniumwall.name=mur de titane
block.titaniumwall.fulldescription=Un bloc défensif fort. Fournit une protection contre les ennemis. block.titaniumwall.fulldescription=Un bloc défensif soldie. Fournit une protection contre les ennemis.
block.duriumwall.name=mur de dirium block.duriumwall.name=mur de dirium
block.duriumwall.fulldescription=Un bloc défensif très fort. Fournit une protection contre les ennemis. block.duriumwall.fulldescription=Un bloc défensif très solide. Fournit une protection contre les ennemis.
block.compositewall.name=mur composite block.compositewall.name=mur composite
block.steelwall-large.name=grand mur d'acier block.steelwall-large.name=grand mur d'acier
block.steelwall-large.fulldescription=Un bloc défensif standard. Couvre plusieurs cases. block.steelwall-large.fulldescription=Un bloc défensif standard. Couvre plusieurs cases.
block.titaniumwall-large.name=grand mur de titanium block.titaniumwall-large.name=grand mur de titane
block.titaniumwall-large.fulldescription=Un bloc défensif fort. Couvre plusieurs cases. block.titaniumwall-large.fulldescription=Un bloc défensif solide. Couvre plusieurs cases.
block.duriumwall-large.name=grand mur de dirium block.duriumwall-large.name=grand mur de dirium
block.duriumwall-large.fulldescription=Un bloc défensif très fort. Couvre plusieurs cases. block.duriumwall-large.fulldescription=Un bloc défensif très solide. Couvre plusieurs cases.
block.titaniumshieldwall.name=mur blindé block.titaniumshieldwall.name=mur blindé
block.titaniumshieldwall.fulldescription=Un bloc défensif solide, avec un bouclier intégré supplémentaire. Nécessite de l'énergie. Utilise l'énergie pour absorber les balles ennemies. Il est recommandé d'utiliser des boosters de puissance pour fournir de l'énergie à ce bloc. block.titaniumshieldwall.fulldescription=Un bloc défensif résistant, avec un bouclier intégré supplémentaire. Nécessite de l'énergie. Utilise l'énergie pour absorber les balles ennemies. Il est recommandé d'utiliser des boosters de puissance pour fournir de l'énergie à ce bloc.
block.repairturret.name=tourelle de réparation block.repairturret.name=tourelle de réparation
block.repairturret.fulldescription=Répare les blocs endommagés à portée à un rythme lent. Utilise de petites quantités d'énergie. block.repairturret.fulldescription=Répare les blocs endommagés à portée à un rythme lent. Utilise de petites quantités d'énergie.
block.repairturret.description=[powerinfo]Utilise de l'énergie[white]\nRépare les bloc à proximité. block.repairturret.description=[powerinfo]Utilise de l'énergie[white]\nRépare les bloc à proximité.
block.megarepairturret.name=tourelle de réparation II block.megarepairturret.name=tourelle de réparation II
block.megarepairturret.fulldescription=Répare les blocs endommagés à porté à un rythme moyen. Utilise de l'énergie. block.megarepairturret.fulldescription=Répare les blocs endommagés à porté à un rythme moyen. Utilise de l'énergie.
block.megarepairturret.description=[powerinfo]Utilise de l'énergie[white]\nRépare les bloc à proximité. block.megarepairturret.description=[powerinfo]Utilise de l'énergie[white]\nRépare les bloc à proximité.
block.shieldgenerator.name=generateur de bouclier block.shieldgenerator.name=générateur de bouclier
block.shieldgenerator.fulldescription=Un bloc défensif avancé. Protège tous les blocs dans un rayon des attaques. Utilise l'énergie à un rythme lent, mais draine l'énergie rapidement au contact des balles. block.shieldgenerator.fulldescription=Un bloc défensif avancé. Protège tous les blocs dans un rayon des attaques. Utilise l'énergie à un rythme lent, mais draine l'énergie rapidement au contact des balles.
block.door.name=Porte block.door.name=Porte
block.door.fulldescription=Un bloc qui peut être ouvert et fermé en le tapant. block.door.fulldescription=Un bloc qui peut être ouvert et fermé en le tapant.
block.door.description=Ouvre et ferme. \ N [interact] Appuyez pour ouvrir block.door.description=Ouvre et ferme. \ N [interact] Appuyez pour ouvrir
block.door-large.name=Grande Porte block.door-large.name=Grande Porte
block.door-large.fulldescription=Un bloc qui peut être ouvert et fermé en le tapant. block.door-large.fulldescription=Un bloc qui peut être ouvert et fermé en le tapant.
block.door-large.description=Ouvre et ferme. \ N [interact] Appuyez pour ouvrir block.door-large.description=Ouvre et ferme. \ N [interact] Appuyez pour ouvrir
block.conduit.name=conduit block.conduit.name=conduit
block.conduit.fulldescription=Bloc de transport de liquide. Fonctionne comme un tapis roulant, mais avec des liquides. Peut-être connecté avec des pompes ou d'autres conduits. Peut-être utilisé comme un pont au-dessus des liquides pour les ennemis et les joueurs. block.conduit.fulldescription=Bloc de transport de liquide. Fonctionne comme un tapis roulant, mais avec des liquides. Peut-être connecté avec des pompes ou d'autres conduits. Peut-être utilisé comme un pont au-dessus des liquides pour les ennemis et les joueurs.
block.pulseconduit.name=conduit à pulsation block.pulseconduit.name=conduit à pulsation
block.pulseconduit.fulldescription=Bloc de transport de liquide avancé. Transporte les liquides plus rapidement et stocke plus que les conduits standards. block.pulseconduit.fulldescription=Bloc de transport de liquide avancé. Transporte les liquides plus rapidement et stocke plus que les conduits standards.
block.liquidrouter.name=routeur de liquide block.liquidrouter.name=routeur de liquide
block.liquidrouter.fulldescription=Fonctionne de manière similaire à un routeur. Accepte l'entrée de liquide d'un côté et l'envoie vers les autres côtés. Utile pour séparer le liquide d'un seul conduit en plusieurs autres conduits. block.liquidrouter.fulldescription=Fonctionne de manière similaire à un routeur. Accepte l'entrée de liquide d'un côté et l'envoie vers les autres côtés. Utile pour séparer le liquide d'un seul conduit en plusieurs autres conduits.
block.liquidrouter.description=Divise le liquide d'entrée dans 3 directions. block.liquidrouter.description=Divise le liquide d'entrée dans 3 directions.
block.conveyor.name=tapis roulant block.conveyor.name=tapis roulant
block.conveyor.fulldescription=Bloc de transport élémentaire. Déplace les objets vers l'avant et les dépose automatiquement dans les tourelles ou les crafters. Rotatif. Peut être utilisé comme un pont sur les liquides pour les ennemis et les joueurs. block.conveyor.fulldescription=Bloc de transport élémentaire. Déplace les objets vers l'avant et les dépose automatiquement dans les tourelles ou les crafters. Rotatif. Peut être utilisé comme un pont sur les liquides pour les ennemis et les joueurs.
block.steelconveyor.name=tapis roulant en acier block.steelconveyor.name=tapis roulant en acier
block.steelconveyor.fulldescription=Bloc de transport d'élément avancé. Déplace les objets plus rapidement que les tapis roulants standard. block.steelconveyor.fulldescription=Bloc de transport d'élément avancé. Déplace les objets plus rapidement que les tapis roulants standard.
block.poweredconveyor.name=tapis roulant à pulsation block.poweredconveyor.name=tapis roulant à pulsation
block.poweredconveyor.fulldescription=Le bloc de transport d'élément ultime. Déplace les objets plus rapidement que les tapis roulants en acier. block.poweredconveyor.fulldescription=Le bloc de transport d'élément ultime. Déplace les objets plus rapidement que les tapis roulants en acier.
block.router.name=routeur block.router.name=routeur
block.router.fulldescription=Accepte les éléments d'une direction et les redistribues dans les 3 autres directions. Peut également stocker une certaine quantité d'objets. Utile pour dédoubler les matériaux d'un extracteur dans plusieurs tourelles. block.router.fulldescription=Accepte les éléments d'une direction et les redistribue dans les 3 autres directions. Peut également stocker une certaine quantité d'objets. Utile pour dédoubler les matériaux d'un extracteur dans plusieurs tourelles.
block.router.description=Diviser les matériaux d'entrée dans 3 directions. block.router.description=Diviser les matériaux d'entrée dans 3 directions.
block.junction.name=jonction block.junction.name=jonction
block.junction.fulldescription=Agit comme un pont pour deux tapis roulants croisée. Utile dans les situations avec deux tapis roulants différents transportant des matériaux différents se coupant. block.junction.fulldescription=Agit comme un pont pour deux tapis roulants croisé. Utile dans les situations avec deux tapis roulants différents transportant des matériaux différents se coupant.
block.junction.description=Sert de jonction de tapis roulant. block.junction.description=Sert de jonction de tapis roulant.
block.conveyortunnel.name=tunnel de transport block.conveyortunnel.name=tunnel de transport
block.conveyortunnel.fulldescription=Transporte l'objet sous les blocs. Pour l'utiliser, placez les côte-à-côte, les entrées de chaque côtés avec maximum deux bloc d'écart. block.conveyortunnel.fulldescription=Transporte l'objet sous les blocs. Pour l'utiliser, placez les côte à côte, les entrées de chaque côté avec maximum deux blocs d'écart.
block.conveyortunnel.description=Transporte les objets sous les blocs. block.conveyortunnel.description=Transporte les objets sous les blocs.
block.liquidjunction.name=jonction pour liquide block.liquidjunction.name=jonction pour liquide
block.liquidjunction.fulldescription=Agit comme un pont pour deux conduits de passage. Utile dans les situations avec deux conduits différents transportant différents liquides se coupant. block.liquidjunction.fulldescription=Agit comme un pont pour deux conduits de passage. Utile dans les situations avec deux conduits différents transportant différents liquides se coupant.
block.liquiditemjunction.name=jonction de liquides-objets block.liquiditemjunction.name=jonction de liquides-objets
block.liquiditemjunction.fulldescription=Agit comme un pont quand un conduit coupe un tapis roulant. block.liquiditemjunction.fulldescription=Agit comme un pont quand un conduit coupe un tapis roulant.
block.liquiditemjunction.description=Sert de jonction pour les articles et les liquides. block.liquiditemjunction.description=Sert de jonction pour les articles et les liquides.
block.powerbooster.name=booster d'énergie block.powerbooster.name=booster d'énergie
block.powerbooster.fulldescription=Distribue l'énergie à tous les blocs se trouvant dans son rayon. block.powerbooster.fulldescription=Distribue l'énergie à tous les blocs se trouvant dans son rayon.
block.powerbooster.description=Distribue la puissance dans un rayon. block.powerbooster.description=Distribue la puissance dans un rayon.
block.powerlaser.name=laser énergénique block.powerlaser.name=laser d'énergie
block.powerlaser.fulldescription=Crée un laser qui transmet l'énergie au bloc en face de lui. Ne génère pas d'énergie lui-même. Idéal avec des générateurs ou d'autres lasers. block.powerlaser.fulldescription=Crée un laser qui transmet l'énergie au bloc en face de lui. Ne génère pas d'énergie lui-même. Idéal avec des générateurs ou d'autres lasers.
block.powerlaser.description=Transmet l'énergie. block.powerlaser.description=Transmet l'énergie.
block.powerlaserrouter.name=routeur laser block.powerlaserrouter.name=routeur laser
block.powerlaserrouter.fulldescription=Laser qui distribue la puissance dans trois directions à la fois. Utile dans les situations où il est nécessaire d'alimenter plusieurs blocs avec un seul générateur. block.powerlaserrouter.fulldescription=Laser qui distribue la puissance dans trois directions à la fois. Utile dans les situations où il est nécessaire d'alimenter plusieurs blocs avec un seul générateur.
block.powerlaserrouter.description=Divise l'énergie d'entrée en 3 lasers. block.powerlaserrouter.description=Divise l'énergie d'entrée en 3 lasers.
block.powerlasercorner.name=laser d'angle block.powerlasercorner.name=laser d'angle
block.powerlasercorner.fulldescription=Laser qui distribue la puissance dans deux directions à la fois. Utile dans les situations où il est nécessaire d'alimenter plusieurs blocs avec un seul générateur, et, où, un routeur est imprécis. block.powerlasercorner.fulldescription=Laser qui distribue la puissance dans deux directions à la fois. Utile dans les situations où il est nécessaire d'alimenter plusieurs blocs avec un seul générateur, et, où, un routeur est imprécis.
block.powerlasercorner.description=Divise l'énergie d'entrée en 2 lasers. block.powerlasercorner.description=Divise l'énergie d'entrée en 2 lasers.
block.teleporter.name=teleporteur block.teleporter.name=téléporteur
block.teleporter.fulldescription=Bloc de transport d'élément avancé. Les téléporteurs transmettent des objets à d'autres téléporteurs de la même couleur. Ne fait rien si aucun téléporteur de la même couleur n'existe. Si plusieurs téléporteurs de la même couleur existent, un téléporteur aléatoire est sélectionné. Appuyez sur et cliquez sur les flèches pour changer de couleur. block.teleporter.fulldescription=Bloc de transport de minerai avancé. Les téléporteurs transmettent des objets à d'autres téléporteurs de la même couleur. Ne fait rien si aucun téléporteur de la même couleur n'existe. Si plusieurs téléporteurs de la même couleur existent, un téléporteur aléatoire est sélectionné. Cliquez sur les flèches pour changer de couleur.
block.teleporter.description=[interact]Tapez sur le bloc pour le configurer[] block.teleporter.description=[interact]Tapez sur le bloc pour le configurer[]
block.sorter.name=trieur block.sorter.name=trieur
block.sorter.fulldescription=Trie les objets par type de matériau. Le matériel à accepter est indiqué par la couleur dans le bloc. Tous les éléments qui correspondent au matériau de tri sont sortis vers l'avant, tout le reste est sorti à gauche et à droite. block.sorter.fulldescription=Trie les objets par type de matériau. Le matériel à accepter est indiqué par la couleur dans le bloc. Tous les éléments qui correspondent au matériau de tri sont sortis vers l'avant, tout le reste est sorti à gauche et à droite.
block.sorter.description=[interact]Tapez sur le bloc pour le configurer[] block.sorter.description=[interact]Tapez sur le bloc pour le configurer[]
block.core.name=noyau block.core.name=noyau
block.pump.name=pompe block.pump.name=pompe
block.pump.fulldescription=Pompe les liquides provenant d'un bloc source - généralement de l'eau, de la lave ou de l'huile. distribut le liquide dans les conduits voisins. block.pump.fulldescription=Pompe les liquides provenant d'un bloc source - généralement de l'eau, de la lave ou de l'huile. distribut le liquide dans les conduits voisins.
block.pump.description=Pompe les liquides dans les conduits voisins. block.pump.description=Pompe les liquides dans les conduits voisins.
block.fluxpump.name=pompe à flux élevé block.fluxpump.name=pompe à flux élevé
block.fluxpump.fulldescription=Une version avancée de la pompe. Stocke plus de liquide et pompe le liquide plus rapidement. block.fluxpump.fulldescription=Une version avancée de la pompe. Stocke plus de liquide et pompe le liquide plus rapidement.
block.fluxpump.description=Pompe les liquides dans les conduits voisins. block.fluxpump.description=Pompe les liquides dans les conduits voisins.
block.smelter.name=fonderie block.smelter.name=fonderie
block.smelter.fulldescription=Le bloc d'artisanat essentiel. Lorsqu'est entré 1x fer et 1x charbon,un acier est produit. block.smelter.fulldescription=Le bloc d'artisanat essentiel. Lorsqu'est entré 1 fer et 1 charbon, un acier est produit.
block.smelter.description=Convertit le charbon + le fer en acier. block.smelter.description=Convertit le charbon + le fer en acier.
block.crucible.name=creuset block.crucible.name=creuset
block.crucible.fulldescription=Un bloc d'artisanat avancé. Lors de l'entrée 1x titane et 1x acier, un dirium en sort. block.crucible.fulldescription=Un bloc d'artisanat avancé. Lors de l'entrée d'un titane et d'un acier, un dirium en sort.
block.crucible.description=Convertit l'acier + le titane en dirium. block.crucible.description=Convertit l'acier + le titane en dirium.
block.coalpurifier.name=convertisseur de charbon block.coalpurifier.name=convertisseur de charbon
block.coalpurifier.fulldescription=Un bloc de conversion de base. Produit du charbon lorsqu'il est fourni de grandes quantités d'eau et de pierre. block.coalpurifier.fulldescription=Un bloc de conversion de base. Produit du charbon lorsqu'on lui fourni de grandes quantités d'eau et de pierre.
block.coalpurifier.description=Convertit la pierre + l'eau en charbon. block.coalpurifier.description=Convertit la pierre + l'eau en charbon.
block.titaniumpurifier.name=convertisseur de titanium block.titaniumpurifier.name=convertisseur de titane
block.titaniumpurifier.fulldescription=Un bloc de conversion standard. Produit du titane lorsqu'est fourni de grandes quantités d'eau et de fer. block.titaniumpurifier.fulldescription=Un bloc de conversion standard. Produit du titane lorsqu'est fourni de grandes quantités d'eau et de fer.
block.titaniumpurifier.description=Convertit le fer + l'eau en titane. block.titaniumpurifier.description=Convertit le fer + l'eau en titane.
block.oilrefinery.name=raffinerie de pétrole block.oilrefinery.name=raffinerie de pétrole
block.oilrefinery.fulldescription=Raffine de grandes quantités de pétrole en charbon. Utile pour alimenter les tourelles à charbon lorsque les filon de charbon sont rares. block.oilrefinery.fulldescription=Raffine de grandes quantités de pétrole en charbon. Utile pour alimenter les tourelles à charbon lorsque les filons de charbon sont rares.
block.oilrefinery.description=Convertit l'huile en charbon. block.oilrefinery.description=Convertit l'huile en charbon.
block.stoneformer.name=fabrique de pierre block.stoneformer.name=fabrique de pierre
block.stoneformer.fulldescription=Il transforme la lave liquide en pierre. Utile pour produire des quantités massives de pierre pour les convertisseur de charbon. block.stoneformer.fulldescription=Il transforme la lave en pierre. Utile pour produire des quantités massives de pierre pour les convertisseurs de charbon.
block.stoneformer.description=Convertit la lave en pierre. block.stoneformer.description=Convertit la lave en pierre.
block.lavasmelter.name=fonderie de lave block.lavasmelter.name=fonderie de lave
block.lavasmelter.fulldescription=Utilise la lave pour convertir le fer en acier. Une alternative aux fonderies. Utile dans les situations où le charbon est rare. block.lavasmelter.fulldescription=Utilise la lave pour convertir le fer en acier. Une alternative aux fonderies. Utile dans les situations où le charbon est rare.
block.lavasmelter.description=Convertit le fer + la lave en acier. block.lavasmelter.description=Convertit le fer + la lave en acier.
block.stonedrill.name=extracteur de pierre block.stonedrill.name=extracteur de pierre
block.stonedrill.fulldescription=L'extracteur essentiel. Lorsqu'il est placé sur des cases de pierre, les pierres sont produitent à un rythme lent, indéfiniment. block.stonedrill.fulldescription=L'extracteur essentiel. Lorsqu'il est placé sur des cases de pierre, les pierres sont produitent à un rythme lent, indéfiniment.
block.stonedrill.description=Mines 1 pierre toutes les 4 secondes. block.stonedrill.description=Mine 1 pierre toutes les 4 secondes.
block.irondrill.name=extracteur de fer block.irondrill.name=extracteur de fer
block.irondrill.fulldescription=Un extracteur de base. Lorsqu'il est placé sur des cases de minerai de fer, produit du fer à un rythme lent, indéfiniment. block.irondrill.fulldescription=Un extracteur de base. Lorsqu'il est placé sur des cases de minerai de fer, produit du fer à un rythme lent, indéfiniment.
block.irondrill.description=Mines 1 fer toutes les 5 secondes. block.irondrill.description=Mine 1 fer toutes les 5 secondes.
block.coaldrill.name=extracteur de charbon block.coaldrill.name=extracteur de charbon
block.coaldrill.fulldescription=Un extracteur de base. Lorsqu'il est placé sur des cases de minerai de charbon, produit du charbon à un rythme lent, indéfiniment. block.coaldrill.fulldescription=Un extracteur de base. Lorsqu'il est placé sur des cases de minerai de charbon, produit du charbon à un rythme lent, indéfiniment.
block.coaldrill.description=Mines 1 charbon toutes les 5 secondes. block.coaldrill.description=Mine 1 charbon toutes les 5 secondes.
block.uraniumdrill.name=extracteur d'uranium block.uraniumdrill.name=extracteur d'uranium
block.uraniumdrill.fulldescription=Un extracteur avancé. Lorsqu'il est placés sur des cases de minerai d'uranium, il produit de l'uranium à un rythme lent, indéfiniment. block.uraniumdrill.fulldescription=Un extracteur avancé. Lorsqu'il est placés sur des cases d'uranium, il produit de l'uranium à un rythme lent, indéfiniment.
block.uraniumdrill.description=Mines 1 d'uranium toutes les 7 secondes. block.uraniumdrill.description=Mine 1 uranium toutes les 7 secondes.
block.titaniumdrill.name=extracteur de titanium block.titaniumdrill.name=extracteur de titane
block.titaniumdrill.fulldescription=Un extracteur avancé. Lorsqu'il est placé sur des cases de minerai de titane, il produit le titane à un rythme lent, indéfiniment. block.titaniumdrill.fulldescription=Un extracteur avancé. Lorsqu'il est placé sur des cases de minerai de titane, il produit du titane à un rythme lent, indéfiniment.
block.titaniumdrill.description=Mines 1 titane toutes les 5 secondes. block.titaniumdrill.description=Mine 1 titane toutes les 5 secondes.
block.omnidrill.name=omni-extracteur block.omnidrill.name=omni-extracteur
block.omnidrill.fulldescription=L'extracteur ultime. Exploitera n'importe quel minerai sur lequel il est placé à un rythme rapide. block.omnidrill.fulldescription=L'extracteur ultime. Exploitera n'importe quel minerai sur lequel il est placé à un rythme rapide.
block.omnidrill.description=Mines 1 de toute ressource toutes les 3 secondes. block.omnidrill.description=Mine 1 de toute ressource toutes les 3 secondes.
block.coalgenerator.name=générateur à charbon block.coalgenerator.name=générateur à charbon
block.coalgenerator.fulldescription=Le générateur essentiel. Génère de l'énergie à partir du charbon. Sorties de l'énergie comme lasers à ses 4 côtés. block.coalgenerator.fulldescription=Le générateur essentiel. Génère de l'énergie à partir du charbon. Des lasers d'énergies sortent des 4 côtés.
block.coalgenerator.description=Genere de la puissance depuis du charbon. block.coalgenerator.description=Génère de la puissance depuis du charbon.
block.thermalgenerator.name=Generateur thermique block.thermalgenerator.name=Générateur thermique
block.thermalgenerator.fulldescription=Genere de la puissance depuis la lave. Emet de la puissance depuis les 4 cotes. block.thermalgenerator.fulldescription=Génère de la puissance depuis la lave. Emet de la puissance depuis les 4 cotés.
block.thermalgenerator.description=Genere de la puissance depuis la lave. block.thermalgenerator.description=Génère de la puissance depuis la lave.
block.combustiongenerator.name=Generateur a combustion block.combustiongenerator.name=Générateur a combustion
block.combustiongenerator.fulldescription=Genere de la puissance depuis du petrole. Emet de la puissance depuis les 4 cotes. block.combustiongenerator.fulldescription=Génère de la puissance depuis du petrole. Emet de la puissance depuis les 4 cotés.
block.combustiongenerator.description=Genere de la puissance depuis du petrole. block.combustiongenerator.description=Génère de la puissance avec du pétrole.
block.rtgenerator.name=Generateur RTG block.rtgenerator.name=Générateur RTG
block.rtgenerator.fulldescription=Genere de petites partie de puissance depuis le reste d'uranium. Emet de la puissance depuis les 4 cotes. block.rtgenerator.fulldescription=Génère de petites partie de puissance avec de l'uranium. Emet de la puissance depuis les 4 cotés.
block.rtgenerator.description=Genere de la puissance depuis l'uranium block.rtgenerator.description=Génère de la puissance depuis l'uranium
block.nuclearreactor.name=reacteur nucleaire block.nuclearreactor.name=acteur nucléaire
block.nuclearreactor.fulldescription=Une version avancee du generateur RTG, et le generateur ultime de puissance. Genere de la puissance depuis l'uranium. Requiert un refoidissement contant par l'eau. Tres instable; explose violament si il n'est pas bien refroidit block.nuclearreactor.fulldescription=Une version avancée du générateur RTG, et le générateur ultime de puissance. Génère de la puissance depuis l'uranium. Requiert un refoidissement par eau. Très instable; Explose violemment s'il n'est pas bien refroidit.
block.turret.name=tourelle block.turret.name=tourelle
block.turret.fulldescription=Une tourrelle basique. Utilise la pierre comme munition. A legerment plus de distance que la tourrelle double. block.turret.fulldescription=Une tourrelle basique. Utilise de la pierre comme munition. A légèrement plus de distance que la tourelle double.
block.turret.description=[turretinfo]Munition: pierre block.turret.description=[turretinfo]Munition: pierre
block.doubleturret.name=tourelle double block.doubleturret.name=tourelle double
block.doubleturret.fulldescription=Une version legerement plus puissancte que la tourelle. Utilise la pierre comme munition. Inflinge plus de degats mais a une distance plus faible. Tire deux balles. block.doubleturret.fulldescription=Une version légèrement plus puissante que la tourelle. Utilise de la pierre comme munition. Inflige plus de dégâts mais a une distance plus faible. Tire deux balles.
block.doubleturret.description=[turretinfo]Munition: pierre block.doubleturret.description=[turretinfo]Munition: pierre
block.machineturret.name=tourrelle gattling block.machineturret.name=tourelle gatling
block.machineturret.fulldescription=Une tourelle rotative. Utilise le fer comme munition. A une cadence de tir avec des degats croissant block.machineturret.fulldescription=Une tourelle rotative. Utilise du fer comme munition. A une cadence de tir avec des dégâts croissants.
block.machineturret.description=[turretinfo]Munition: fer block.machineturret.description=[turretinfo]Munition: fer
block.shotgunturret.name=tourelle à dispersion block.shotgunturret.name=tourelle à dispersion
block.shotgunturret.fulldescription=une tourelle basique. Utilise le fer comme munition. Tire 7 balles dispersées. Distance faible, mais inflige plus degats que la tourrelle gattling. block.shotgunturret.fulldescription=une tourelle basique. Utilise du fer comme munition. Tire 7 balles dispersées. Distance faible, mais inflige plus de dégâts que la tourelle gatling.
block.shotgunturret.description=[turretinfo]Munition: fer block.shotgunturret.description=[turretinfo]Munition: fer
block.flameturret.name=Tourelle lance-flame block.flameturret.name=Tourelle lance-flamme
block.flameturret.fulldescription=Tourelle avancée à faible distance. utilise le charbon comme munition. A une distance très faible, mais inflige beaucoup de dégats. Fort au combat rapproche. Utilisation recommande derrière les murs. block.flameturret.fulldescription=Tourelle avancée à faible distance. Utilise le charbon comme munition. A une distance très faible, mais inflige beaucoup de dégâts. Fort au combat rapproché. Utilisation recommandé derrière les murs.
block.flameturret.description=[turretinfo]Munition: charbon block.flameturret.description=[turretinfo]Munition: charbon
block.sniperturret.name=tourelle à énergie block.sniperturret.name=tourelle à énergie
block.sniperturret.fulldescription=Tourelle avancée à longue portée. Utilise l'acier pour les munitions. Dommages très élevés, mais faible cadance de tir. Chere à utiliser, mais peut être placé loin des lignes ennemies en raison de sa portée. block.sniperturret.fulldescription=Tourelle avancée à longue portée. Utilise l'acier pour les munitions. Dommages très élevés, mais faible cadence de tir. Cher à utiliser, mais peut-être placé loin des lignes ennemies en raison de sa portée.
block.sniperturret.description=[turretinfo]munition : acier block.sniperturret.description=[turretinfo]munition : acier
block.mortarturret.name=tourelle antiaérienne block.mortarturret.name=tourelle antiaérienne
block.mortarturret.fulldescription=Tourelle avancée pour les dégats de zone. Utilise du charbon pour les munitions. Vitesse de tir et balles très lente, mais très haut niveau de dégâts de cible et de zone. Utile pour les grandes foules d'ennemis. block.mortarturret.fulldescription=Tourelle avancée pour les dégâts de zone. Utilise du charbon pour les munitions. Vitesse de tir et balles très lente mais de gros dégâts de cible et de zone. Utile pour les grandes foules d'ennemis.
block.mortarturret.description=[turretinfo]munition : charbon block.mortarturret.description=[turretinfo]munition : charbon
block.laserturret.name=tourelle laser block.laserturret.name=tourelle laser
block.laserturret.fulldescription=Tourelle avancée à cible unique. Utilise de l'énergie. Tourelle polyvalente de moyenne portée. Une seule cible seulement. Ne manque jamais. block.laserturret.fulldescription=Tourelle avancée à cible unique. Utilise de l'énergie. Tourelle polyvalente de moyenne portée. Une seule cible seulement. Ne manque jamais.
block.laserturret.description=[turretinfo]Utilise de l'énergie. block.laserturret.description=[turretinfo]Utilise de l'énergie.
block.waveturret.name=tourelle Tesla block.waveturret.name=tourelle Tesla
block.waveturret.fulldescription=Tourelle multi-cible avancée. Utilise de l'énergie. Portée moyenne. Ne manque jamais. Peu de dégâts, mais peut frapper plusieurs ennemis simultanément avec une chaîne d'éclairs. block.waveturret.fulldescription=Tourelle multi-cible avancée utilisant de l'énergie. A une portée moyenne. Ne rate jamais sa cible. Elle provoque peu de dégâts mais peut frapper plusieurs ennemis simultanément avec une chaîne d'éclairs.
block.waveturret.description=[turretinfo]Utilise de l'énergie. block.waveturret.description=[turretinfo]Utilise de l'énergie.
block.plasmaturret.name=tourelle à plasma block.plasmaturret.name=tourelle à plasma
block.plasmaturret.fulldescription=Version très avancée de la tourelle lance-flamme. Utilise le charbon comme munition. Dommages très élevés, de faible à moyenne portée. block.plasmaturret.fulldescription=Version très avancée de la tourelle lance-flamme. Utilise du charbon comme munition. Dommages très élevés, de faible à moyenne portée.
block.plasmaturret.description=[turretinfo]munition : charbon block.plasmaturret.description=[turretinfo]munition : charbon
block.chainturret.name=tourelle à mitrailleuse block.chainturret.name=tourelle à mitrailleuse
block.chainturret.fulldescription=La tourelle ultime à tir rapide. Utilise l'uranium comme munition. Tire de grosses salves à une fréquence élevée. Portée moyenne. traverse plusieurs carreaux. Extrêmement puissant. block.chainturret.fulldescription=La tourelle ultime à tir rapide. Utilise de l'uranium comme munition. Tire de grosses salves à une fréquence élevée. Portée moyenne. Traverse plusieurs carreaux. Extrêmement puissant.
block.chainturret.description=[turretinfo]munition : uranium block.chainturret.description=[turretinfo]munition : Uranium
block.titancannon.name=canon titan block.titancannon.name=Canon titan
block.titancannon.fulldescription=La tourelle à longue portée ultime. Utilise l'uranium comme munition. Tire de gros obus avec dégâts de zone un taux de feu moyen. Longue portée, traverse plusieurs carreaux. Extrêmement puissant. block.titancannon.fulldescription=La tourelle à longue portée ultime. Utilise de l'uranium comme munition. Tire de gros obus provoquant des dégâts de zone à une cadence de tir moyenne. Traverse plusieurs carreaux. Extrêmement puissant.
block.titancannon.description=[turretinfo]munition : uranium block.titancannon.description=[turretinfo]munition : uranium
block.playerspawn.name=point d'apparition du joueur block.playerspawn.name=point d'apparition du joueur
block.enemyspawn.name=point d'apparition des ennemis block.enemyspawn.name=point d'apparition des ennemis

View File

@@ -1,7 +1,7 @@
#Autogenerated file. Do not modify. #Autogenerated file. Do not modify.
#Sat Mar 03 18:02:39 EST 2018 #Sat Mar 03 12:04:38 EST 2018
version=release version=release
androidBuildCode=320 androidBuildCode=333
name=Mindustry name=Mindustry
code=3.4 code=3.4
build=custom build build=30

View File

@@ -139,6 +139,6 @@ public class Vars{
public static final EntityGroup<Enemy> enemyGroup = Entities.addGroup(Enemy.class).enableMapping(); public static final EntityGroup<Enemy> enemyGroup = Entities.addGroup(Enemy.class).enableMapping();
public static final EntityGroup<TileEntity> tileGroup = Entities.addGroup(TileEntity.class, false); public static final EntityGroup<TileEntity> tileGroup = Entities.addGroup(TileEntity.class, false);
public static final EntityGroup<Bullet> bulletGroup = Entities.addGroup(Bullet.class); public static final EntityGroup<Bullet> bulletGroup = Entities.addGroup(Bullet.class);
public static final EntityGroup<Shield> shieldGroup = Entities.addGroup(Shield.class); public static final EntityGroup<Shield> shieldGroup = Entities.addGroup(Shield.class, false);
public static final EntityGroup<EffectEntity> effectGroup = Entities.addGroup(EffectEntity.class); public static final EntityGroup<EffectEntity> effectGroup = Entities.addGroup(EffectEntity.class, false);
} }

View File

@@ -1,7 +1,6 @@
package io.anuke.mindustry.core; package io.anuke.mindustry.core;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.enemies.Enemy; import io.anuke.mindustry.entities.enemies.Enemy;
import io.anuke.mindustry.game.EnemySpawn; import io.anuke.mindustry.game.EnemySpawn;
@@ -130,9 +129,9 @@ public class Logic extends Module {
if(!state.mode.disableWaveTimer){ if(!state.mode.disableWaveTimer){
if(state.enemies <= 0){ if(state.enemies <= 0){
state.wavetime -= delta(); if(!world.getMap().name.equals("tutorial")) state.wavetime -= delta();
if(state.lastUpdated < state.wave + 1 && state.wavetime < Vars.aheadPathfinding){ //start updating beforehand if(state.lastUpdated < state.wave + 1 && state.wavetime < aheadPathfinding){ //start updating beforehand
world.pathfinder().resetPaths(); world.pathfinder().resetPaths();
state.lastUpdated = state.wave + 1; state.lastUpdated = state.wave + 1;
} }
@@ -152,8 +151,8 @@ public class Logic extends Module {
Entities.update(shieldGroup); Entities.update(shieldGroup);
Entities.update(playerGroup); Entities.update(playerGroup);
Entities.collideGroups(enemyGroup, bulletGroup); Entities.collideGroups(bulletGroup, enemyGroup);
Entities.collideGroups(playerGroup, bulletGroup); Entities.collideGroups(bulletGroup, playerGroup);
} }
} }
} }

View File

@@ -27,15 +27,19 @@ public class ThreadHandler {
public ThreadHandler(ThreadProvider impl){ public ThreadHandler(ThreadProvider impl){
this.impl = impl; this.impl = impl;
Timers.setDeltaProvider(() ->{ Timers.setDeltaProvider(() -> {
float result = impl.isOnThread() ? delta : Gdx.graphics.getDeltaTime()*60f; float result = impl.isOnThread() ? delta : Gdx.graphics.getDeltaTime()*60f;
return Float.isNaN(result) ? 1f : result; return Math.min(Float.isNaN(result) ? 1f : result, 12f);
}); });
} }
public void run(Runnable r){ public void run(Runnable r){
synchronized (toRun) { if(enabled) {
toRun.add(r); synchronized (toRun) {
toRun.add(r);
}
}else{
r.run();
} }
} }
@@ -52,6 +56,7 @@ public class ThreadHandler {
} }
public void handleRender(){ public void handleRender(){
if(!enabled) return; if(!enabled) return;
framesSinceUpdate += Timers.delta(); framesSinceUpdate += Timers.delta();

View File

@@ -1,6 +1,7 @@
package io.anuke.mindustry.core; package io.anuke.mindustry.core;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Colors; import com.badlogic.gdx.graphics.Colors;
import com.badlogic.gdx.math.Interpolation; import com.badlogic.gdx.math.Interpolation;
@@ -121,8 +122,10 @@ public class UI extends SceneModule{
} }
@Override @Override
public void update(){ public synchronized void update(){
if(Vars.debug && !Vars.showUI) return; if(Vars.debug && !Vars.showUI) return;
if(Graphics.drawing()) Graphics.end();
scene.act(); scene.act();
scene.draw(); scene.draw();
@@ -173,6 +176,11 @@ public class UI extends SceneModule{
build.end(); build.end();
} }
@Override
public synchronized boolean hasMouse() {
return super.hasMouse();
}
public Locale getLocale(){ public Locale getLocale(){
String loc = Settings.getString("locale"); String loc = Settings.getString("locale");
if(loc.equals("default")){ if(loc.equals("default")){
@@ -233,6 +241,8 @@ public class UI extends SceneModule{
dialog.hide(); dialog.hide();
confirmed.listen(); confirmed.listen();
}); });
dialog.keyDown(Keys.ESCAPE, dialog::hide);
dialog.keyDown(Keys.BACK, dialog::hide);
dialog.show(); dialog.show();
} }

View File

@@ -126,6 +126,10 @@ public class World extends Module{
public Tile tileWorld(float x, float y){ public Tile tileWorld(float x, float y){
return tile(Mathf.scl2(x, tilesize), Mathf.scl2(y, tilesize)); return tile(Mathf.scl2(x, tilesize), Mathf.scl2(y, tilesize));
} }
public int toTile(float coord){
return Mathf.scl2(coord, tilesize);
}
public Tile[][] getTiles(){ public Tile[][] getTiles(){
return tiles; return tiles;
@@ -236,7 +240,7 @@ public class World extends Module{
if(!tile.block().isMultiblock() && !tile.isLinked()){ if(!tile.block().isMultiblock() && !tile.isLinked()){
tile.setBlock(Blocks.air); tile.setBlock(Blocks.air);
}else{ }else{
Tile target = tile.isLinked() ? tile.getLinked() : tile; Tile target = tile.target();
Array<Tile> removals = target.getLinkedTiles(); Array<Tile> removals = target.getLinkedTiles();
for(Tile toremove : removals){ for(Tile toremove : removals){
//note that setting a new block automatically unlinks it //note that setting a new block automatically unlinks it
@@ -319,4 +323,37 @@ public class World extends Module{
} }
return null; return null;
} }
public void raycastEach(int x0f, int y0f, int x1, int y1, Raycaster cons){
int x0 = x0f;
int y0 = y0f;
int dx = Math.abs(x1 - x0);
int dy = Math.abs(y1 - y0);
int sx = x0 < x1 ? 1 : -1;
int sy = y0 < y1 ? 1 : -1;
int err = dx - dy;
int e2;
while(true){
if(cons.accept(x0, y0)) break;
if(x0 == x1 && y0 == y1) break;
e2 = 2 * err;
if(e2 > -dy){
err = err - dy;
x0 = x0 + sx;
}
if(e2 < dx){
err = err + dx;
y0 = y0 + sy;
}
}
}
public interface Raycaster{
boolean accept(int x, int y);
}
} }

View File

@@ -1,10 +1,10 @@
package io.anuke.mindustry.entities; package io.anuke.mindustry.entities;
import io.anuke.mindustry.entities.enemies.Enemy;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.entities.BulletEntity; import io.anuke.ucore.entities.BulletEntity;
import io.anuke.ucore.entities.Entity; import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.SolidEntity; import io.anuke.ucore.entities.SolidEntity;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Timer; import io.anuke.ucore.util.Timer;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -36,49 +36,38 @@ public class Bullet extends BulletEntity{
public float drawSize(){ public float drawSize(){
return 8; return 8;
} }
public boolean collidesTiles(){
return owner instanceof Enemy;
}
@Override @Override
public void update(){ public void update(){
int tilex = Mathf.scl2(x, tilesize);
int tiley = Mathf.scl2(y, tilesize);
Tile tile = world.tile(tilex, tiley);
TileEntity targetEntity = null;
if(tile != null){
if(tile.entity != null && tile.entity.collide(this) && !tile.entity.dead){
targetEntity = tile.entity;
}else{
//make sure to check for linked block collisions
Tile linked = tile.getLinked();
if(linked != null &&
linked.entity != null && linked.entity.collide(this) && !linked.entity.dead){
targetEntity = linked.entity;
}
}
}
if(targetEntity != null){
targetEntity.collision(this);
remove();
type.removed(this);
}
super.update(); super.update();
if (collidesTiles()) {
world.raycastEach(world.toTile(lastX), world.toTile(lastY), world.toTile(x), world.toTile(y), (x, y) -> {
Tile tile = world.tile(x, y);
if (tile == null) return false;
tile = tile.target();
if (tile.entity != null && tile.entity.collide(this) && !tile.entity.dead) {
tile.entity.collision(this);
remove();
type.hit(this);
return true;
}
return false;
});
}
} }
@Override @Override
public boolean collides(SolidEntity other){ public boolean collides(SolidEntity other){
if(owner instanceof TileEntity && other instanceof Player) return true;
return false;
return super.collides(other);
}
@Override
public void collision(SolidEntity other){
super.collision(other);
type.removed(this);
} }
@Override @Override
@@ -90,5 +79,4 @@ public class Bullet extends BulletEntity{
public Bullet add(){ public Bullet add(){
return super.add(bulletGroup); return super.add(bulletGroup);
} }
} }

View File

@@ -79,10 +79,10 @@ public abstract class BulletType extends BaseBulletType<Bullet>{
} }
public void despawned(Bullet b){ public void despawned(Bullet b){
removed(b); hit(b);
} }
public void removed(Bullet b){ public void hit(Bullet b, float hitx, float hity){
Timers.run(5f, ()-> new EMP(b.x, b.y, b.getDamage()).add()); Timers.run(5f, ()-> new EMP(b.x, b.y, b.getDamage()).add());
Effects.effect(Fx.empshockwave, b); Effects.effect(Fx.empshockwave, b);
Effects.shake(3f, 3f, b); Effects.shake(3f, 3f, b);
@@ -113,10 +113,10 @@ public abstract class BulletType extends BaseBulletType<Bullet>{
} }
public void despawned(Bullet b){ public void despawned(Bullet b){
removed(b); hit(b);
} }
public void removed(Bullet b){ public void hit(Bullet b, float hitx, float hity){
Effects.shake(3f, 3f, b); Effects.shake(3f, 3f, b);
Effects.effect(Fx.shellsmoke, b); Effects.effect(Fx.shellsmoke, b);
@@ -146,16 +146,16 @@ public abstract class BulletType extends BaseBulletType<Bullet>{
Draw.reset(); Draw.reset();
} }
public void removed(Bullet b) { public void hit(Bullet b, float hitx, float hity) {
despawned(b); Effects.effect(shellsmoke, b);
for(int i = 0; i < 3; i ++){
Bullet bullet = new Bullet(flakspark, b.owner, hitx, hity, b.angle() + Mathf.range(120f));
bullet.add();
}
} }
public void despawned(Bullet b) { public void despawned(Bullet b) {
Effects.effect(shellsmoke, b); hit(b, b.x, b.y);
for(int i = 0; i < 3; i ++){
Bullet bullet = new Bullet(flakspark, b.owner, b.x, b.y, b.angle() + Mathf.range(120f));
bullet.add();
}
} }
}, },
flakspark = new BulletType(2f, 2) { flakspark = new BulletType(2f, 2) {
@@ -193,10 +193,10 @@ public abstract class BulletType extends BaseBulletType<Bullet>{
} }
public void despawned(Bullet b){ public void despawned(Bullet b){
removed(b); hit(b);
} }
public void removed(Bullet b){ public void hit(Bullet b, float hitx, float hity){
Effects.shake(3f, 3f, b); Effects.shake(3f, 3f, b);
Effects.effect(Fx.shellsmoke, b); Effects.effect(Fx.shellsmoke, b);
@@ -224,10 +224,10 @@ public abstract class BulletType extends BaseBulletType<Bullet>{
} }
public void despawned(Bullet b){ public void despawned(Bullet b){
removed(b); hit(b);
} }
public void removed(Bullet b){ public void hit(Bullet b, float hitx, float hity){
Effects.shake(3f, 3f, b); Effects.shake(3f, 3f, b);
Effects.effect(Fx.shellsmoke, b); Effects.effect(Fx.shellsmoke, b);
@@ -244,19 +244,19 @@ public abstract class BulletType extends BaseBulletType<Bullet>{
} }
public void despawned(Bullet b){ public void despawned(Bullet b){
removed(b); hit(b);
} }
public void removed(Bullet b){ public void hit(Bullet b, float hitx, float hity){
Effects.shake(3f, 3f, b); Effects.shake(3f, 3f, b);
Effects.effect(Fx.blastsmoke, b); Effects.effect(Fx.blastsmoke, b);
Effects.effect(Fx.blastexplosion, b); Effects.effect(Fx.blastexplosion, b);
//TODO remove translation() usage //TODO remove translation() usage
Angles.circleVectors(30, 6f, (x, y) -> { Angles.circleVectors(30, 6f, (nx, ny) -> {
float ang = Mathf.atan2(x, y); float ang = Mathf.atan2(nx, ny);
Bullet o = new Bullet(blastshot, b.owner, b.x + x, b.y + y, ang).add(); Bullet o = new Bullet(blastshot, b.owner, b.x + nx, b.y + ny, ang).add();
o.damage = b.damage/9; o.damage = b.damage/9;
}); });
} }
@@ -363,10 +363,10 @@ public abstract class BulletType extends BaseBulletType<Bullet>{
} }
public void despawned(Bullet b){ public void despawned(Bullet b){
removed(b); hit(b);
} }
public void removed(Bullet b){ public void hit(Bullet b, float hitx, float hity){
Effects.shake(1.5f, 1.5f, b); Effects.shake(1.5f, 1.5f, b);
Effects.effect(Fx.clusterbomb, b); Effects.effect(Fx.clusterbomb, b);
@@ -415,10 +415,10 @@ public abstract class BulletType extends BaseBulletType<Bullet>{
} }
public void despawned(Bullet b) { public void despawned(Bullet b) {
removed(b); hit(b);
} }
public void removed(Bullet b) { public void hit(Bullet b, float hitx, float hity) {
for(int i = 0; i < 4; i ++){ for(int i = 0; i < 4; i ++){
Bullet bullet = new Bullet(scrap, b.owner, b.x, b.y, b.angle() + Mathf.range(80f)); Bullet bullet = new Bullet(scrap, b.owner, b.x, b.y, b.angle() + Mathf.range(80f));
bullet.add(); bullet.add();
@@ -479,7 +479,7 @@ public abstract class BulletType extends BaseBulletType<Bullet>{
} }
@Override @Override
public void removed(Bullet b){ public void hit(Bullet b, float hitx, float hity){
Effects.effect(Fx.hit, b); Effects.effect(Fx.hit, hitx, hity);
} }
} }

View File

@@ -150,7 +150,7 @@ public class Player extends SyncEntity{
public void update(){ public void update(){
if(!isLocal || isAndroid){ if(!isLocal || isAndroid){
if(isAndroid && isLocal){ if(isAndroid && isLocal){
angle = Mathf.lerpAngDelta(angle, targetAngle, 0.2f); angle = Mathf.slerpDelta(angle, targetAngle, 0.2f);
} }
if(!isLocal) interpolate(); if(!isLocal) interpolate();
return; return;
@@ -216,10 +216,10 @@ public class Player extends SyncEntity{
if(!shooting){ if(!shooting){
if(!movement.isZero()) if(!movement.isZero())
angle = Mathf.lerpAngDelta(angle, movement.angle(), 0.13f); angle = Mathf.slerpDelta(angle, movement.angle(), 0.13f);
}else{ }else{
float angle = Angles.mouseAngle(x, y); float angle = Angles.mouseAngle(x, y);
this.angle = Mathf.lerpAngDelta(this.angle, angle, 0.1f); this.angle = Mathf.slerpDelta(this.angle, angle, 0.1f);
} }
x = Mathf.clamp(x, 0, world.width() * tilesize); x = Mathf.clamp(x, 0, world.width() * tilesize);

View File

@@ -59,7 +59,7 @@ public abstract class SyncEntity extends DestructibleEntity{
this.x = spos.x = Mathf.lerpDelta(spos.x, x, 0.2f); this.x = spos.x = Mathf.lerpDelta(spos.x, x, 0.2f);
this.y = spos.y = Mathf.lerpDelta(spos.y, y, 0.2f); this.y = spos.y = Mathf.lerpDelta(spos.y, y, 0.2f);
this.angle = spos.z = Mathf.lerpAngDelta(spos.z, angle, 0.3f); this.angle = spos.z = Mathf.slerpDelta(spos.z, angle, 0.3f);
} }
drawSmooth(); drawSmooth();
@@ -124,7 +124,7 @@ public abstract class SyncEntity extends DestructibleEntity{
Mathf.lerp2(pos.set(last), target, time); Mathf.lerp2(pos.set(last), target, time);
angle = Mathf.lerpAngDelta(angle, targetrot, 0.6f); angle = Mathf.slerpDelta(angle, targetrot, 0.6f);
if(target.dst(pos) > 128){ if(target.dst(pos) > 128){
pos.set(target); pos.set(target);

View File

@@ -1,6 +1,5 @@
package io.anuke.mindustry.entities; package io.anuke.mindustry.entities;
import io.anuke.mindustry.entities.enemies.Enemy;
import io.anuke.mindustry.graphics.Fx; import io.anuke.mindustry.graphics.Fx;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.NetEvents; import io.anuke.mindustry.net.NetEvents;
@@ -22,8 +21,6 @@ import static io.anuke.mindustry.Vars.tileGroup;
import static io.anuke.mindustry.Vars.world; import static io.anuke.mindustry.Vars.world;
public class TileEntity extends Entity{ public class TileEntity extends Entity{
private static final boolean friendlyFire = false;
public Tile tile; public Tile tile;
public int[] items = new int[Item.getAllItems().size]; public int[] items = new int[Item.getAllItems().size];
public Timer timer; public Timer timer;
@@ -101,7 +98,7 @@ public class TileEntity extends Entity{
} }
public boolean collide(Bullet other){ public boolean collide(Bullet other){
return other.owner instanceof Enemy || friendlyFire; return true;
} }
@Override @Override

View File

@@ -47,7 +47,7 @@ public class TeslaOrb extends Entity{
Array<SolidEntity> enemies = Entities.getNearby(enemyGroup, curx, cury, range*2f); Array<SolidEntity> enemies = Entities.getNearby(enemyGroup, curx, cury, range*2f);
for(SolidEntity entity : enemies){ for(SolidEntity entity : enemies){
if(entity.distanceTo(curx, cury) < range && !hit.contains((Enemy)entity)){ if(entity != null && entity.distanceTo(curx, cury) < range && !hit.contains((Enemy)entity)){
hit.add((Enemy)entity); hit.add((Enemy)entity);
points.add(new Vector2(entity.x + Mathf.range(shake), entity.y + Mathf.range(shake))); points.add(new Vector2(entity.x + Mathf.range(shake), entity.y + Mathf.range(shake)));
damageEnemy((Enemy)entity); damageEnemy((Enemy)entity);

View File

@@ -144,9 +144,9 @@ public class EnemyType {
} }
if(enemy.target == null || alwaysRotate){ if(enemy.target == null || alwaysRotate){
enemy.angle = Mathf.slerp(enemy.angle, enemy.velocity.angle(), rotatespeed * Timers.delta()); enemy.angle = Mathf.slerpDelta(enemy.angle, enemy.velocity.angle(), rotatespeed);
}else{ }else{
enemy.angle = Mathf.slerp(enemy.angle, enemy.angleTo(enemy.target), turretrotatespeed * Timers.delta()); enemy.angle = Mathf.slerpDelta(enemy.angle, enemy.angleTo(enemy.target), turretrotatespeed);
} }
enemy.x = Mathf.clamp(enemy.x, 0, world.width() * tilesize); enemy.x = Mathf.clamp(enemy.x, 0, world.width() * tilesize);

View File

@@ -15,7 +15,6 @@ import io.anuke.ucore.scene.ui.ScrollPane;
import io.anuke.ucore.scene.ui.layout.Table; import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.util.Log; import io.anuke.ucore.util.Log;
import io.anuke.ucore.util.Log.LogHandler; import io.anuke.ucore.util.Log.LogHandler;
import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -68,9 +67,7 @@ public class DebugFragment implements Fragment {
}); });
row(); row();
new button("spawn", () -> { new button("spawn", () -> {
for(int i = 0; i < 30; i ++){ new Enemy(EnemyTypes.healer).set(player.x, player.y).add();
new Enemy(EnemyTypes.healer).set(player.x + Mathf.range(50f), player.y + Mathf.range(50f)).add();
}
}); });
row(); row();
}}.end(); }}.end();

View File

@@ -40,7 +40,7 @@ public class Placement {
state.inventory.addItem(tile.block().drops.item, tile.block().drops.amount); state.inventory.addItem(tile.block().drops.item, tile.block().drops.amount);
} }
if(sound) Sounds.play("break"); if(sound) threads.run(() -> Sounds.play("break"));
if(!tile.block().isMultiblock() && !tile.isLinked()){ if(!tile.block().isMultiblock() && !tile.isLinked()){
tile.setBlock(Blocks.air); tile.setBlock(Blocks.air);
@@ -85,7 +85,7 @@ public class Placement {
} }
}else if(effects) Effects.effect(Fx.place, x * tilesize, y * tilesize); }else if(effects) Effects.effect(Fx.place, x * tilesize, y * tilesize);
if(effects && sound) Sounds.play("place"); if(effects && sound) threads.run(() -> Sounds.play("place"));
} }
public static boolean validPlace(int x, int y, Block type){ public static boolean validPlace(int x, int y, Block type){

View File

@@ -81,7 +81,7 @@ public class LiquidBlock extends Block implements LiquidAcceptor{
LiquidAcceptor other = (LiquidAcceptor)next.block(); LiquidAcceptor other = (LiquidAcceptor)next.block();
float flow = Math.min(other.getLiquidCapacity(next) - other.getLiquid(next) - 0.001f, float flow = Math.min(other.getLiquidCapacity(next) - other.getLiquid(next) - 0.001f,
Math.min(entity.liquidAmount/flowfactor * Timers.delta(), entity.liquidAmount)); Math.min(entity.liquidAmount/flowfactor * Math.max(Timers.delta(), 1f), entity.liquidAmount));
if(flow <= 0f || entity.liquidAmount < flow) return; if(flow <= 0f || entity.liquidAmount < flow) return;

View File

@@ -56,7 +56,7 @@ public class RepairTurret extends PowerTurret{
} }
float target = entity.angleTo(entity.blockTarget); float target = entity.angleTo(entity.blockTarget);
entity.rotation = Mathf.slerp(entity.rotation, target, 0.16f*Timers.delta()); entity.rotation = Mathf.slerpDelta(entity.rotation, target, 0.16f);
int maxhealth = entity.blockTarget.tile.block().health; int maxhealth = entity.blockTarget.tile.block().health;

View File

@@ -70,9 +70,9 @@ public class Sorter extends Block{
}else{ }else{
Tile a = dest.getNearby(Mathf.mod(dir - 1, 4)); Tile a = dest.getNearby(Mathf.mod(dir - 1, 4));
Tile b = dest.getNearby(Mathf.mod(dir + 1, 4)); Tile b = dest.getNearby(Mathf.mod(dir + 1, 4));
boolean ac = !(a.block().instantTransfer && source.block().instantTransfer) && boolean ac = a != null && !(a.block().instantTransfer && source.block().instantTransfer) &&
a.block().acceptItem(item, a, dest); a.block().acceptItem(item, a, dest);
boolean bc = !(b.block().instantTransfer && source.block().instantTransfer) && boolean bc = b != null && !(b.block().instantTransfer && source.block().instantTransfer) &&
b.block().acceptItem(item, b, dest); b.block().acceptItem(item, b, dest);
if(ac && !bc){ if(ac && !bc){

View File

@@ -72,7 +72,7 @@ public class NuclearReactor extends LiquidPowerGenerator{
float fullness = (float)fuel / itemCapacity; float fullness = (float)fuel / itemCapacity;
if(fuel > 0){ if(fuel > 0){
entity.heat += fullness * heating * Timers.delta(); entity.heat += fullness * heating * Math.min(Timers.delta(), 4f);
entity.power += powerMultiplier * fullness * Timers.delta(); entity.power += powerMultiplier * fullness * Timers.delta();
entity.power = Mathf.clamp(entity.power, 0f, powerCapacity); entity.power = Mathf.clamp(entity.power, 0f, powerCapacity);
if(entity.timer.get(timerFuel, fuelUseTime)){ if(entity.timer.get(timerFuel, fuelUseTime)){
@@ -93,6 +93,8 @@ public class NuclearReactor extends LiquidPowerGenerator{
tile.worldy() + Mathf.random(height * tilesize / 2f)); tile.worldy() + Mathf.random(height * tilesize / 2f));
} }
} }
entity.heat = Mathf.clamp(entity.heat);
if(entity.heat >= 1f){ if(entity.heat >= 1f){
entity.damage((int)entity.health); entity.damage((int)entity.health);

View File

@@ -34,6 +34,7 @@ import java.net.InetSocketAddress;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.ClosedSelectorException; import java.nio.channels.ClosedSelectorException;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import static io.anuke.mindustry.Vars.headless; import static io.anuke.mindustry.Vars.headless;
import static io.anuke.mindustry.Vars.state; import static io.anuke.mindustry.Vars.state;
@@ -45,6 +46,7 @@ public class KryoServer implements ServerProvider {
final ByteSerializer serializer = new ByteSerializer(); final ByteSerializer serializer = new ByteSerializer();
final ByteBuffer buffer = ByteBuffer.allocate(4096); final ByteBuffer buffer = ByteBuffer.allocate(4096);
final CopyOnWriteArrayList<KryoConnection> connections = new CopyOnWriteArrayList<>(); final CopyOnWriteArrayList<KryoConnection> connections = new CopyOnWriteArrayList<>();
final CopyOnWriteArraySet<Integer> missing = new CopyOnWriteArraySet<>();
final Array<KryoConnection> array = new Array<>(); final Array<KryoConnection> array = new Array<>();
SocketServer webServer; SocketServer webServer;
Thread serverThread; Thread serverThread;
@@ -72,7 +74,7 @@ public class KryoServer implements ServerProvider {
c.id = kn.id; c.id = kn.id;
c.addressTCP = ip; c.addressTCP = ip;
Log.info("&bRecieved connection: {0} / {1}", c.id, c.addressTCP); Log.info("&bRecieved connection: {0} / {1}. Kryonet ID: {2}", c.id, c.addressTCP, connection.getID());
connections.add(kn); connections.add(kn);
Gdx.app.postRunnable(() -> Net.handleServerReceived(kn.id, c)); Gdx.app.postRunnable(() -> Net.handleServerReceived(kn.id, c));
@@ -81,15 +83,18 @@ public class KryoServer implements ServerProvider {
@Override @Override
public void disconnected (Connection connection) { public void disconnected (Connection connection) {
KryoConnection k = getByKryoID(connection.getID()); KryoConnection k = getByKryoID(connection.getID());
Log.info("&bLost kryonet connection {0}", connection.getID());
if(k == null) return; if(k == null) return;
connections.remove(k);
Disconnect c = new Disconnect(); Disconnect c = new Disconnect();
c.id = k.id; c.id = k.id;
Log.info("&bLost connection: {0}", k.id); Log.info("&bLost connection: {0}", k.id);
Gdx.app.postRunnable(() -> Net.handleServerReceived(k.id, c)); Gdx.app.postRunnable(() -> {
Net.handleServerReceived(k.id, c);
connections.remove(k);
});
} }
@Override @Override
@@ -156,6 +161,7 @@ public class KryoServer implements ServerProvider {
public void host(int port) throws IOException { public void host(int port) throws IOException {
lastconnection = 0; lastconnection = 0;
connections.clear(); connections.clear();
missing.clear();
server.bind(port, port); server.bind(port, port);
webServer = new SocketServer(Vars.webPort); webServer = new SocketServer(Vars.webPort);
webServer.start(); webServer.start();
@@ -177,7 +183,7 @@ public class KryoServer implements ServerProvider {
connections.clear(); connections.clear();
lastconnection = 0; lastconnection = 0;
Thread thread = new Thread(() ->{ Thread thread = new Thread(() -> {
try { try {
server.close(); server.close();
try { try {
@@ -259,7 +265,12 @@ public class KryoServer implements ServerProvider {
@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) throw new RuntimeException("Unable to find connection with ID " + id + "!"); if(conn == null){
if(!missing.contains(id))
Log.err("Failed to find connection with ID {0}.", id);
missing.add(id);
return;
}
conn.send(object, mode); conn.send(object, mode);
} }
@@ -327,6 +338,27 @@ public class KryoServer implements ServerProvider {
return null; return null;
} }
void throwErrorAndExit(){
Log.err("KRYONET CONNECTIONS:");
for(Connection c : server.getConnections()){
NetConnection k = getByKryoID(c.getID());
Log.err(" - Kryonet connection / ID {0} / IP {1} / NetConnection ID {2}",
c.getID(), c.getRemoteAddressTCP().getAddress().getHostAddress(), k == null ? "NOT FOUND" : k.id);
}
Log.err("NET CONNECTIONS:");
for(NetConnection c : connections){
Log.err(" - NetConnection / ID {0} / IP {1}", c.id, c.address);
}
Log.err("\nSTACK TRACE:");
StackTraceElement[] e = Thread.getAllStackTraces().get(Thread.currentThread());
for(StackTraceElement s : e){
Log.err("- {0}", s);
}
System.exit(-1);
}
class KryoConnection extends NetConnection{ class KryoConnection extends NetConnection{
public final WebSocket socket; public final WebSocket socket;
public final Connection connection; public final Connection connection;
@@ -418,6 +450,8 @@ public class KryoServer implements ServerProvider {
Log.info("&bRecieved web connection: {0} {1}", kn.id, connect.addressTCP); Log.info("&bRecieved web connection: {0} {1}", kn.id, connect.addressTCP);
connections.add(kn); connections.add(kn);
Gdx.app.postRunnable(() -> Net.handleServerReceived(kn.id, connect));
} }
@Override @Override
@@ -430,7 +464,7 @@ public class KryoServer implements ServerProvider {
Disconnect disconnect = new Disconnect(); Disconnect disconnect = new Disconnect();
disconnect.id = k.id; disconnect.id = k.id;
Log.info("&bLost web connection: {0}", k.id); Log.info("&bLost web connection: {0}", k.id);
Net.handleServerReceived(k.id, disconnect); Gdx.app.postRunnable(() -> Net.handleServerReceived(k.id, disconnect));
} }
@Override @Override
@@ -447,7 +481,7 @@ public class KryoServer implements ServerProvider {
byte[] out = Base64Coder.decode(message); byte[] out = Base64Coder.decode(message);
ByteBuffer buffer = ByteBuffer.wrap(out); ByteBuffer buffer = ByteBuffer.wrap(out);
Object o = serializer.read(buffer); Object o = serializer.read(buffer);
Net.handleServerReceived(k.id, o); Gdx.app.postRunnable(() -> Net.handleServerReceived(k.id, o));
} }
}catch (Exception e){ }catch (Exception e){
Log.err(e); Log.err(e);

View File

@@ -291,7 +291,7 @@ public class ServerControl extends Module {
} }
if(target != null){ if(target != null){
String ip = Net.getConnection(player.clientid).address; String ip = Net.getConnection(target.clientid).address;
netServer.admins.banPlayer(ip); netServer.admins.banPlayer(ip);
Net.kickConnection(target.clientid, KickReason.banned); Net.kickConnection(target.clientid, KickReason.banned);
info("Banned player by IP: {0}", ip); info("Banned player by IP: {0}", ip);
@@ -352,7 +352,7 @@ public class ServerControl extends Module {
} }
if(target != null){ if(target != null){
String ip = Net.getConnection(player.clientid).address; String ip = Net.getConnection(target.clientid).address;
netServer.admins.adminPlayer(ip); netServer.admins.adminPlayer(ip);
NetEvents.handleAdminSet(target, true); NetEvents.handleAdminSet(target, true);
info("Admin-ed player by IP: {0} / {1}", ip, arg[0]); info("Admin-ed player by IP: {0} / {1}", ip, arg[0]);
@@ -377,7 +377,7 @@ public class ServerControl extends Module {
} }
if(target != null){ if(target != null){
String ip = Net.getConnection(player.clientid).address; String ip = Net.getConnection(target.clientid).address;
netServer.admins.unAdminPlayer(ip); netServer.admins.unAdminPlayer(ip);
NetEvents.handleAdminSet(target, false); NetEvents.handleAdminSet(target, false);
info("Un-admin-ed player by IP: {0} / {1}", ip, arg[0]); info("Un-admin-ed player by IP: {0} / {1}", ip, arg[0]);
@@ -386,7 +386,7 @@ public class ServerControl extends Module {
} }
}); });
handler.register("admins", "List all banned IPs.", arg -> { handler.register("admins", "List all admins.", arg -> {
Array<String> admins = netServer.admins.getAdmins(); Array<String> admins = netServer.admins.getAdmins();
if(admins.size == 0){ if(admins.size == 0){