1
0
mirror of https://github.com/Anuken/Mindustry.git synced 2025-03-13 19:39:04 +07:00
This commit is contained in:
Anuken 2018-11-02 19:45:31 -04:00
commit 208ae6183c
24 changed files with 329 additions and 131 deletions

View File

@ -427,7 +427,7 @@ item.titanium.name = Titan
item.titanium.description = Ein seltenes sehr leichtes Metal. Häufig in Flüssigkeits-Transport Blöcken, Abbauanlagen und Flugzeugen verwendet.
item.thorium.name = Uran
item.thorium.description = Ein dichtes radioaktives Metal, welches als strukturelle Unterstützung und nuklearer Kraftstoff verwendet wird.
item.silicon.name = Silikon
item.silicon.name = Silizium
item.silicon.description = Ein sehr nützlicher Halbleiter. Findet Anwendung in Solar Anlagen und komplexer Elektronik.
item.plastanium.name = Plastanium
item.plastanium.description = Ein leichtes dehnbares Material welches in Flugzeugen und Splittermunition verwendet wird.
@ -536,7 +536,7 @@ block.bridgeconveyor.name = Transportband Brücke
block.bridgeconveyor.description = Ein Transportband welches über Blöcke gehen kann. Insgesamt maximal zwei Blöcke hoch.
block.smelter.name = Schmelzer
block.arc-smelter.name = Lichtbogen Schmelzer
block.silicon-smelter.name = Silikon Schmelzer
block.silicon-smelter.name = Silizium Schmelzer
block.phase-weaver.name = Phase Weaver
block.pulverizer.name = Pulverisierer
block.cryofluidmixer.name = Cryofluid Mixer
@ -656,13 +656,13 @@ tutorial.waves = Der [LIGHT_GRAY] Gegner[] greift an.\n\nVerteidige deinen Kern
tutorial.lead = Mehr Erz ist verfügbar. Finde Blei und bau es ab.\n\n Klicke auf deine Einheit und ziehe die Maus auf den Kern um Ressourcen zu übertragen.
tutorial.smelter = Kupfer und Blei sind schwache Metalle.\n Super [accent]dichte Legierung [] kann in einem Schmeltzer erzeugt werden.\n\n Bau einen.
tutorial.densealloy = Der Schmeltzer wird nun Legierung produzieren.\n Produziere einige.\n Verbessere die Produktion sofern notwendig.
tutorial.siliconsmelter = Der Kern wird nun [accent]spirit drohnen[] erstellen. Diese Bauen Rohstoffe und reparieren Blöcke.\n\nFabriken für andere Einheiten benötigen [accent]Silikon[].\n Baue ein Silikon Schmeltzer.
tutorial.silicondrill = Silikon benötigt [accent]Kohle[] und [accent]Sand[].\n Fange damit an die Bohrer zu platzieren.
tutorial.siliconsmelter = Der Kern wird nun [accent]spirit drohnen[] erstellen. Diese Bauen Rohstoffe und reparieren Blöcke.\n\nFabriken für andere Einheiten benötigen [accent]Silizium[].\n Baue ein Silizium Schmeltzer.
tutorial.silicondrill = Silizium benötigt [accent]Kohle[] und [accent]Sand[].\n Fange damit an die Bohrer zu platzieren.
tutorial.generator = Diese Technologie benötigt power.\n Erstelle einen Verbrennungs-Generator dafür.
tutorial.generatordrill = Verbrennungs Generatoren benötigen Kraftstoff.\nBenutze Kohle aus einem Bohrer als Kraftstoff.
tutorial.node = Power muss transportiert werden.\nErstelle einen [accent]Power Knoten[] nahe deinem Verbrennungs Generator um seine Power zu transportieren.
tutorial.nodelink = Power kann über verbundene Power Blocks, Generatoren oder Power Knoten transferierd werden.\n\n Verbinde die Power in dem du auf den Knoten klickst und dann den Generator und den Silikon Schmeltzer auswählst.
tutorial.silicon = Silikon wird produziert. Produziere einiges.\n\n Verbesserungen am Produktionssystem werden empfohlen.
tutorial.nodelink = Power kann über verbundene Power Blocks, Generatoren oder Power Knoten transferierd werden.\n\n Verbinde die Power in dem du auf den Knoten klickst und dann den Generator und den Silizium Schmeltzer auswählst.
tutorial.silicon = Silizium wird produziert. Produziere einiges.\n\n Verbesserungen am Produktionssystem werden empfohlen.
tutorial.daggerfactory = Konstruiere eine Dagger Mech Fabrik.\n\n Diese wird verwendet um Angreifende Mechs zu erstellen.
tutorial.router = Fabriken benötigen Ressourcen um zu funktionieren.\n Platziere ein Router um Gegenstände auf Transportbändern aufzuteilen.
tutorial.dagger = Verbinde die Fabrik mit einem Power Knoten. Wenn alle Voraussetzungen gegeben sind, beginnt die Fabrik Mechs zu konstruieren.\n\n Platziere mehr Bohrer und Transportbänder um die Versorgung der Fabrik zu sichern.

View File

@ -1,7 +1,7 @@
text.credits.text = Created by [ROYAL]Anuken[] - [SKY]anukendev@gmail.com[]\n\n[GRAY](In case you can't tell, this text is currently unfinished.\nTranslators, don't edit it yet\!)
text.credits = Crédits
text.discord = Rejoignez le discord de Mindustry
text.link.discord.description = the official Mindustry discord chatroom
text.link.discord.description = Le discord officiel de mindustry
text.link.github.description = Code source du jeu
text.link.dev-builds.description = Versions instables du jeu
text.link.trello.description = Trello officiel pour les futurs ajouts .
@ -14,12 +14,12 @@ text.web.unsupported = La version web ne supporte pas cette fonction \! Téléch
text.gameover = Partie terminée.
text.gameover.pvp = L'équipe [accent] {0}[] a gagnée \!
text.sector.gameover = Ce secteur a été perdu. Réessayer?
text.sector.retry = Retry
text.sector.retry = Réessayer
text.highscore = [YELLOW]Nouveau meilleur score\!
text.wave.lasted = You lasted until wave [accent]{0}[].
text.wave.lasted = Vous avez survécu jusqu'à la vague [accent]{0}[].
text.level.highscore = Meilleur score\: [accent]{0}
text.level.delete.title = Confirmer
text.map.delete = Are you sure you want to delete the map "[orange]{0}[]"?
text.map.delete = Êtes-vous sûr de supprimer cette carte"[orange]{0}[]"?
text.level.select = Sélection de niveau
text.level.mode = Mode de jeu \:
text.construction.desktop = Pour désélectionner un bloc ou arrêter de construire, appuyer sur [accent]espace[].
@ -308,7 +308,7 @@ text.blocks.outputitem = Objet produit
text.blocks.drilltier = Forable
text.blocks.drillspeed = Vitesse de forage de base
text.blocks.liquidoutput = Liquide en sortie
text.blocks.liquidoutputspeed = Liquid Output Speed
text.blocks.liquidoutputspeed = Vitesse de production de liquide
text.blocks.liquiduse = Quantité de liquide utilisée
text.blocks.coolant = Liquide de refroidissement
text.blocks.coolantuse = Quantité de liquide de refroidissement utilisée
@ -321,8 +321,8 @@ text.blocks.shots = Tir
text.blocks.reload = Tirs/Seconde
text.blocks.inputfuel = Carburant
text.blocks.fuelburntime = Durée du carburant
text.blocks.inputcapacity = Input capacity
text.blocks.outputcapacity = Output capacity
text.blocks.inputcapacity = Capacité d'entrée
text.blocks.outputcapacity = Capacité de production
text.unit.blocks = blocs
text.unit.powersecond = Énergie/seconde
text.unit.liquidsecond = Liquides/seconde
@ -369,31 +369,31 @@ setting.sfxvol.name = Volume des SFX
setting.mutesound.name = Couper les SFX
text.keybind.title = Paramétrer les touches
category.general.name = General
category.view.name = View
category.multiplayer.name = Multiplayer
command.attack = Attack
command.retreat = Retreat
command.patrol = Patrol
keybind.press = Press a key...
keybind.press.axis = Press an axis or key...
category.view.name = Voir
category.multiplayer.name = Multijoueur
command.attack = Attaque
command.retreat = Retraite
command.patrol = Patrouille
keybind.press = Appuyer sur une touche...
keybind.press.axis = Appuyer sur un axe ou une touche...
keybind.move_x.name = mouvement x
keybind.move_y.name = mouvement y
keybind.select.name = sélectionner
keybind.break.name = Pause
keybind.deselect.name = Deselect
keybind.deselect.name = Déselectionner
keybind.shoot.name = tirer
keybind.zoom_hold.name = tenir le zoom
keybind.zoom.name = zoom
keybind.menu.name = menu
keybind.pause.name = Pause
keybind.dash.name = sprint
keybind.dash.name = Courir
keybind.chat.name = chat
keybind.player_list.name = Liste des joueurs
keybind.console.name = console
keybind.rotate.name = Tourner
keybind.toggle_menus.name = Toggle menus
keybind.chat_history_prev.name = Chat history prev
keybind.chat_history_next.name = Chat history next
keybind.toggle_menus.name = Cacher/afficher les menus
keybind.chat_history_prev.name = remonter l'historique du chat
keybind.chat_history_next.name = descendre l'historique du chat
keybind.chat_scroll.name = Chat scroll
keybind.drop_unit.name = drop unit
keybind.zoom_minimap.name = Zoom minimap
@ -403,7 +403,7 @@ mode.waves.description = le mode de jeu normal. Ressource limitée et vagues d'e
mode.sandbox.name = bac à sable
mode.sandbox.description = Ressources infinies et pas de timer pour les vagues.
mode.custom.warning = Notez que les blocs débloqués en partie personnalisées ne sont pas conservés pour les secteurs.\n\n[LIGHT_GRAY]En mode bac à sable, seul les blocs débloqués en mode secteur peuvent être utilisés.
mode.custom.warning.read = Just to make sure you've read it\:\n[scarlet]UNLOCKS IN CUSTOM GAMES DO NOT CARRY OVER TO SECTORS OR OTHER MODES\!\n\n[LIGHT_GRAY](I wish this wasn't necessary, but apparently it is)
mode.custom.warning.read = Simplement pour vérifier que vous l'avez lu \:\n[scarlet]CE QUI EST DEBLOQUE LORS DES PARITES PERSONNALISEES NE L'EST POUR LES SECTEURS OU LES AUTRES MODES DE JEU\!\n\n[LIGHT_GRAY](J'aurais souhaité que ce ne soit pas nécessaire, mais ça a l'air de l'être )
mode.freebuild.name = construction libre
mode.freebuild.description = Ressource limitée et pas de timer pour les vagues.
mode.pvp.name = JcJ
@ -427,14 +427,14 @@ item.titanium.name = Titane
item.titanium.description = Un métal rare super-léger largement utilisé dans le transport de liquides et d'objets ainsi que dans les foreuses de haut-niveau et l'aviation .item.thorium.name\=Thorium
item.thorium.name = Thorium
item.thorium.description = Un métal dense, et radioactif utilisé comme support structurel et comme carburant nucléaire.
item.silicon.name = Silicon
item.silicon.description = An extremely useful semiconductor, with applications in solar panels and many complex electronics.
item.silicon.name = Silicone
item.silicon.description=Un matériau semi-conducteur extrêmement utile, avec des utilisations dans les panneaux solaires et beaucoup d'autre composants électroniques complexes.
item.plastanium.name = Plastanium
item.plastanium.description = Un matériau léger et docile utilisé dans l'aviation avancée et dans les munitions à fragmentation.
item.phase-matter.name = Matière phasée
item.surge-alloy.name = alliage superchargé
item.biomatter.name = Biomasse
item.biomatter.description = A clump of organic mush; used for conversion into oil or as a basic fuel.
item.biomatter.description = Un mélange de matières organiques; utilisé pour la transformation en huile ou en tant que carburant de base.
item.sand.name = Sable
item.sand.description = Un matériau commun utilisé largement dans la fonte, à la fois dans l'alliage et comme un flux.
item.blast-compound.name = Mélange explosif
@ -528,13 +528,13 @@ block.router.name = [accent]routeur[]
block.router.description = Distribue les articles dans les 4 directions. Le seul et l'unique.
block.distributor.name = Distributeur
block.distributor.description = C'est un bloc qui peut envoyer les articles dans 8 directions.
block.sorter.name = Sorter
block.sorter.name = Sorteur
block.sorter.description = Trie les articles. Si un article rcorrespond à la sélection, il peut passer. Autrement, l'article est distribué vers la gauche ou la droite.
block.overflow-gate.name = Barrière de Débordement
block.overflow-gate.description = C'est la combinaison entre un Routeur et un Diviseur qui peut seulement distribuer à gauche et à droite si le chemin de devant est bloqué.
block.bridgeconveyor.name = Pont
block.bridgeconveyor.description = C'est un convoyeur qui peut passer par-dessus les blocs, jusqu'à deux blocs de distance.
block.smelter.name = Smelter
block.smelter.name = Fonderie d'alliage lourd
block.arc-smelter.name = Fonderie d'alliage lourd électrique
block.silicon-smelter.name = Fonderie de Silicone
block.phase-weaver.name = Tisseur à Phase
@ -593,7 +593,7 @@ block.wraith-factory.name = Usine de "Combattants spectraux"
block.ghoul-factory.name = Usine de "Bombardiers goules"
block.dagger-factory.name = Usine de "Poignards"
block.titan-factory.name = Usine de "Titans"
block.fortress-factory.name = Fortress Mech Factory
block.fortress-factory.name = Usine de "Forteresse"
block.revenant-factory.name = Usine de "Revenants"
block.repair-point.name = Point de Réparation
block.pulse-conduit.name = Conduit à Impulsion
@ -634,10 +634,10 @@ unit.spirit.name = Drone sppirituel
unit.spirit.description = L'unité de soutien de départ.Apparaît dans la base par défaut .Mine automatiquement les minerais, récupère les objets au sol et répare les blocs.
unit.phantom.name = Drone Fantôme
unit.phantom.description = Une unité de soutien avancée. Mine automatiquement les minerais, récupère les objets au sol et répare les blocs. Bien plus efficace qu'un drone spirituel.
unit.dagger.name = Dagger
unit.dagger.description = A basic ground unit. Useful in swarms.
unit.dagger.name = Poignard
unit.dagger.description = Une unité terrestre basiquee. Utile en armée.
unit.titan.name = Titan
unit.titan.description = An advanced, armored ground unit. Attacks both ground and air targets.
unit.titan.description = Une unité terrestre cuirassée avancée. Attaque les unités terrestres comme aériennes.
unit.ghoul.name = Bombardier goule
unit.ghoul.description = Un bombardier lourd . Utilise de la pyratite ou des explosifs comme munitions.
unit.wraith.name = Combattant spectral
@ -667,4 +667,4 @@ tutorial.daggerfactory = Construire [accent]une usine de "Poignards" []est recom
tutorial.router = Les usines ont besoin de ressources pour fonctionner.\nCréez un routeur pour séparer les objets.
tutorial.dagger = Reliez des transmetteurs énergétiques à l'usine.\nUne fois que les conditions seront remplies , un mécha sera créé.\nConstruisez autant de foreuses, de générateurs et de tapis roulants que nécessaire.
tutorial.battle = [LIGHT_GRAY]L'Ennemi[] a révélé sa base .\nDétruisez la avec votre unité et des méchas "Poignard".
block.bridge-conveyor.description = C'est un convoyeur qui peut passer par-dessus les blocs, jusqu'à deux blocs de distance.
block.bridge-conveyor.description = C'est un convoyeur qui peut passer par-dessus les blocs, jusqu'à deux blocs de distance.

View File

@ -32,10 +32,10 @@ text.coreattack = < 코어가 공격받고 있습니다 ! >
text.unlocks = 아이템들
text.savegame = 게임 저장
text.loadgame = 게임 불러오기
text.joingame = 게임 참가
text.joingame = 멀티플레이
text.addplayers = 플레이어 추가/제거
text.customgame = 커스텀 게임
text.sectors = 구역
text.sectors = 싱글 플레이
text.sector = 구역 : [LIGHT_GRAY]{0}
text.sector.time = 시간 : [LIGHT_GRAY]{0}
text.sector.deploy = 시작
@ -280,8 +280,11 @@ text.paused = 일시 정지
text.yes =
text.no = 아니오
text.info.title = [accent]정보
text.error.title = [crimson]오류가 발생했습니다.
text.error.crashtitle = 오류가 발생했습니다.
text.error.alreadyconnected = 이미 접속중입니다.
text.blocks.blockinfo = 블록 정보
text.blocks.powercapacity = 최대 전력 용량
text.blocks.powershot = 1발당 전력 소모량
@ -703,7 +706,7 @@ block.silicon-smelter.description = 실리콘을 제작할 수 있는 건물입
block.phase-weaver.description = 메타를 제작할 수 있는 건물입니다.
block.pulverizer.description = 돌을 갈아서 모래로 만들 수 있는 건물입니다.
block.cryofluidmixer.description = 냉각수를 제작할 수 있는 건물입니다.
block.melter.description = 용암을 돌로 만들 수 있는 건물입니다.
block.melter.description = 돌로 용암을 만들 수 있는 건물입니다.
block.incinerator.description = 불필요한 아이템을 소각시켜 줄 수 있는 건물입니다.
block.biomattercompressor.description = 잔디밭에서 바이오메터를 추출할 수 있는 건물입니다.
block.separator.description = 돌을 분해하여 각종 자원으로 재활용 할 수 있게 해 주는 건물입니다.

View File

@ -2,7 +2,7 @@ package io.anuke.mindustry.ai;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.*;
import io.anuke.mindustry.content.Items;
import com.badlogic.gdx.utils.Bits;
import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.game.EventType.TileChangeEvent;
@ -14,10 +14,7 @@ import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.ucore.core.Events;
import io.anuke.ucore.function.Predicate;
import io.anuke.ucore.util.EnumSet;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.ThreadArray;
import io.anuke.ucore.util.*;
import static io.anuke.mindustry.Vars.*;
@ -33,12 +30,14 @@ public class BlockIndexer{
private final static int structQuadrantSize = 12;
/**Set of all ores that are being scanned.*/
private final ObjectSet<Item> scanOres = ObjectSet.with(Items.copper, Items.coal, Items.lead, Items.thorium, Items.titanium);
private final ObjectSet<Item> scanOres = new ObjectSet<Item>(){{addAll(Item.getAllOres());}};
private final ObjectSet<Item> itemSet = new ObjectSet<>();
/**Stores all ore quadtrants on the map.*/
private ObjectMap<Item, ObjectSet<Tile>> ores;
/**Tags all quadrants.*/
private Bits[] structQuadrants;
/**Stores all damaged tile entities by team.*/
private ObjectSet<Tile>[] damagedTiles = new ObjectSet[Team.all.length];
/**Maps teams to a map of flagged tiles by type.*/
private ObjectSet<Tile>[][] flagMap = new ObjectSet[Team.all.length][BlockFlag.all.length];
@ -62,7 +61,9 @@ public class BlockIndexer{
});
Events.on(WorldLoadEvent.class, event -> {
damagedTiles = new ObjectSet[Team.all.length];
flagMap = new ObjectSet[Team.all.length][BlockFlag.all.length];
for(int i = 0; i < flagMap.length; i++){
for(int j = 0; j < BlockFlag.all.length; j++){
flagMap[i][j] = new ObjectSet<>();
@ -79,7 +80,13 @@ public class BlockIndexer{
for(int x = 0; x < world.width(); x++){
for(int y = 0; y < world.height(); y++){
process(world.tile(x, y));
Tile tile = world.tileWorld(x, y);
process(tile);
if(tile.entity != null && tile.entity.healthf() < 0.9999f){
notifyTileDamaged(tile.entity);
}
}
}
@ -97,6 +104,28 @@ public class BlockIndexer{
return flagMap[team.ordinal()];
}
/**Returns all damaged tiles by team.*/
public ObjectSet<Tile> getDamaged(Team team){
returnArray.clear();
if(damagedTiles[team.ordinal()] == null){
damagedTiles[team.ordinal()] = new ObjectSet<>();
}
ObjectSet<Tile> set = damagedTiles[team.ordinal()];
for(Tile tile : set){
if(tile.entity == null || tile.entity.getTeam() != team || tile.entity.healthf() >= 0.9999f){
returnArray.add(tile);
}
}
for(Tile tile : returnArray){
set.remove(tile);
}
return set;
}
/**Get all allied blocks with a flag.*/
public ObjectSet<Tile> getAllied(Team team, BlockFlag type){
return flagMap[team.ordinal()][type.ordinal()];
@ -115,6 +144,15 @@ public class BlockIndexer{
return returnArray;
}
public void notifyTileDamaged(TileEntity entity){
if(damagedTiles[entity.getTeam().ordinal()] == null){
damagedTiles[entity.getTeam().ordinal()] = new ObjectSet<>();
}
ObjectSet<Tile> set = damagedTiles[entity.getTeam().ordinal()];
set.add(entity.tile);
}
public TileEntity findTile(Team team, float x, float y, float range, Predicate<Tile> pred){
TileEntity closest = null;
float dst = 0;

View File

@ -143,10 +143,14 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
public void damage(float damage){
if(dead) return;
float preHealth = health;
Call.onTileDamage(tile, health - tile.block().handleDamage(tile, damage));
if(health <= 0){
Call.onTileDestroyed(tile);
}else if(preHealth >= maxHealth() - 0.00001f && health < maxHealth()){ //when just damaged
world.indexer.notifyTileDamaged(this);
}
}

View File

@ -11,8 +11,9 @@ import io.anuke.ucore.entities.EntityGroup;
import io.anuke.ucore.entities.EntityQuery;
import io.anuke.ucore.function.Consumer;
import io.anuke.ucore.function.Predicate;
import io.anuke.ucore.util.Threads;
import io.anuke.ucore.util.EnumSet;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Threads;
import static io.anuke.mindustry.Vars.*;
@ -125,6 +126,12 @@ public class Units{
return value[0];
}
/**Returns the neareset damaged tile.*/
public static TileEntity findDamagedTile(Team team, float x, float y){
Tile tile = Geometry.findClosest(x, y, world.indexer.getDamaged(team));
return tile == null ? null : tile.entity;
}
/**Returns the neareset ally tile in a range.*/
public static TileEntity findAllyTile(Team team, float x, float y, float range, Predicate<Tile> pred){
return world.indexer.findTile(team, x, y, range, pred);

View File

@ -79,12 +79,14 @@ public class Drone extends FlyingUnit implements BuilderTrait{
}
//if it's missing requirements, try and mine them
for(ItemStack stack : entity.recipe.requirements){
if(!core.items.has(stack.item, stack.amount) && type.toMine.contains(stack.item)){
targetItem = stack.item;
getPlaceQueue().clear();
setState(mine);
return;
if(entity.recipe != null){
for(ItemStack stack : entity.recipe.requirements){
if(!core.items.has(stack.item, stack.amount) && type.toMine.contains(stack.item)){
targetItem = stack.item;
getPlaceQueue().clear();
setState(mine);
return;
}
}
}
@ -102,22 +104,19 @@ public class Drone extends FlyingUnit implements BuilderTrait{
}
public void update(){
if(target != null && (((TileEntity) target).health >= ((TileEntity) target).tile.block().health
|| target.distanceTo(Drone.this) > discoverRange)){
target = null;
}
if(target == null){
retarget(() -> {
target = Units.findAllyTile(team, x, y, discoverRange,
tile -> tile.entity != null && tile.entity.health + 0.0001f < tile.block().health);
retarget(() -> {
target = Units.findDamagedTile(team, x, y);
if(target == null){
setState(mine);
}
});
}else if(target.distanceTo(Drone.this) > type.range){
circle(type.range);
if(target == null){
setState(mine);
}
});
if(target == null) return;
if(target.distanceTo(Drone.this) > type.range){
circle(type.range*0.9f);
}else{
TileEntity entity = (TileEntity) target;
entity.healBy(type.healSpeed * entity.tile.block().health / 100f * Timers.delta());
@ -316,7 +315,7 @@ public class Drone extends FlyingUnit implements BuilderTrait{
target = null;
}
if(Net.client() && state.is(repair) && target instanceof TileEntity){
if(Net.client() && state.is(repair) && target instanceof TileEntity && target.distanceTo(this) < type.range){
TileEntity entity = (TileEntity) target;
entity.health += type.healSpeed * Timers.delta();
entity.health = Mathf.clamp(entity.health, 0, entity.tile.block().health);
@ -327,7 +326,7 @@ public class Drone extends FlyingUnit implements BuilderTrait{
@Override
protected void updateRotation(){
if(target != null && (state.is(repair) || state.is(mine))){
if(target != null && ((state.is(repair) && target.distanceTo(this) < type.range) || state.is(mine))){
rotation = Mathf.slerpDelta(rotation, angleTo(target), 0.3f);
}else{
rotation = Mathf.slerpDelta(rotation, velocity.angle(), 0.3f);
@ -353,7 +352,7 @@ public class Drone extends FlyingUnit implements BuilderTrait{
TargetTrait entity = target;
if(entity instanceof TileEntity && state.is(repair)){
if(entity instanceof TileEntity && state.is(repair) && target.distanceTo(this) < type.range){
float len = 5f;
Draw.color(Color.BLACK, Color.WHITE, 0.95f + Mathf.absin(Timers.time(), 0.8f, 0.05f));
Shapes.laser("beam", "beam-end",

View File

@ -206,22 +206,12 @@ public abstract class InputHandler extends InputAdapter{
consumed = true;
showedInventory = true;
}
if(tile.block().consumes.hasAny()){
frag.consume.show(tile);
consumed = true;
showedConsume = true;
}
}
if(!showedInventory){
frag.inv.hide();
}
if(!showedConsume){
frag.consume.hide();
}
if(!consumed && player.isBuilding()){
player.clearBuilding();
recipe = null;
@ -231,9 +221,7 @@ public abstract class InputHandler extends InputAdapter{
return consumed;
}
/**
* Tries to select the player to drop off items, returns true if successful.
*/
/**Tries to select the player to drop off items, returns true if successful.*/
boolean tryTapPlayer(float x, float y){
if(canTapPlayer(x, y)){
droppingItem = true;
@ -246,9 +234,7 @@ public abstract class InputHandler extends InputAdapter{
return Vector2.dst(x, y, player.x, player.y) <= playerSelectRange && player.inventory.hasItem();
}
/**
* Tries to begin mining a tile, returns true if successful.
*/
/**Tries to begin mining a tile, returns true if successful.*/
boolean tryBeginMine(Tile tile){
if(canMine(tile)){
//if a block is clicked twice, reset it

View File

@ -6,10 +6,10 @@ import io.anuke.mindustry.game.Content;
import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.type.ContentType;
import io.anuke.mindustry.world.meta.StatValue;
import io.anuke.ucore.scene.event.HandCursorListener;
import io.anuke.ucore.scene.ui.Image;
import io.anuke.ucore.scene.ui.ScrollPane;
import io.anuke.ucore.scene.ui.Tooltip;
import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.scene.utils.UIUtils;
@ -65,10 +65,7 @@ public class UnlocksDialog extends FloatingDialog{
if(control.unlocks.isUnlocked(unlock)){
image.clicked(() -> Vars.ui.content.show(unlock));
image.addListener(new Tooltip<>(new Table("clear"){{
add(unlock.localizedName());
margin(4);
}}));
StatValue.addToolTip(image, unlock);
}
if((++count) % maxWidth == 0){

View File

@ -12,6 +12,7 @@ import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.consumers.Consume;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.scene.Element;
import io.anuke.ucore.scene.Group;
import io.anuke.ucore.scene.ui.layout.Table;
@ -19,6 +20,7 @@ import static io.anuke.mindustry.Vars.*;
public class BlockConsumeFragment extends Fragment{
private Table table;
private Tile lastTile;
private boolean visible;
@Override
@ -26,6 +28,24 @@ public class BlockConsumeFragment extends Fragment{
table = new Table();
table.visible(() -> !state.is(State.menu) && visible);
table.setTransform(true);
parent.addChild(new Element(){{update(() -> {
if(!ui.hasMouse()){
Tile tile = world.tileWorld(Graphics.mouseWorld().x, Graphics.mouseWorld().y);
if(tile == null) return;
tile = tile.target();
if(tile != lastTile){
if(tile.block().consumes.hasAny()){
show(tile);
}else if(visible){
hide();
}
lastTile = tile;
}
}
});}});
parent.setTransform(true);
parent.addChild(table);
}
@ -66,7 +86,7 @@ public class BlockConsumeFragment extends Fragment{
rebuild(block, entity);
}
Vector2 v = Graphics.screen(tile.drawx() - tile.block().size * tilesize / 2f, tile.drawy() + tile.block().size * tilesize / 2f);
Vector2 v = Graphics.screen(tile.drawx() - tile.block().size * tilesize / 2f + 0.25f, tile.drawy() + tile.block().size * tilesize / 2f);
table.pack();
table.setPosition(v.x, v.y, Align.topRight);
});
@ -76,8 +96,7 @@ public class BlockConsumeFragment extends Fragment{
public void hide(){
table.clear();
table.update(() -> {
});
table.update(() -> {});
visible = false;
}

View File

@ -101,14 +101,6 @@ public class Tile implements PosTrait, TargetTrait{
return -1;
}
public byte sizedRelativeTo(int cx, int cy){
if(x == cx && y == cy - 1 - block().size / 2) return 1;
if(x == cx && y == cy + 1 + block().size / 2) return 3;
if(x == cx - 1 - block().size / 2 && y == cy) return 0;
if(x == cx + 1 + block().size / 2 && y == cy) return 2;
return -1;
}
public <T extends TileEntity> T entity(){
return (T) entity;
}

View File

@ -14,6 +14,7 @@ import io.anuke.mindustry.graphics.Layer;
import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Edges;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.meta.BlockGroup;
import io.anuke.ucore.core.Timers;
@ -265,7 +266,8 @@ public class ItemBridge extends Block{
Tile other = world.tile(entity.link);
if(!linkValid(tile, other)){
int i = tile.absoluteRelativeTo(to.x, to.y);
Tile edge = Edges.getFacingEdge(to, tile);
int i = tile.absoluteRelativeTo(edge.x, edge.y);
IntSetIterator it = entity.incoming.iterator();

View File

@ -37,27 +37,62 @@ public class PowerGraph{
lastFrameUpdated = threads.getFrameID();
boolean charge = false;
float totalInput = 0f;
float bufferInput = 0f;
for(Tile producer : producers){
totalInput += producer.entity.power.amount;
if (producer.block().consumesPower) {
bufferInput += producer.entity.power.amount;
} else {
totalInput += producer.entity.power.amount;
}
}
float maxOutput = 0f;
float bufferOutput = 0f;
for(Tile consumer : consumers){
maxOutput += consumer.block().powerCapacity - consumer.entity.power.amount;
if (consumer.block().outputsPower) {
bufferOutput += consumer.block().powerCapacity - consumer.entity.power.amount;
} else {
maxOutput += consumer.block().powerCapacity - consumer.entity.power.amount;
}
}
if (totalInput <= 0.0001f || maxOutput <= 0.0001f) {
if (maxOutput < totalInput) {
charge = true;
}
if (totalInput + bufferInput <= 0.0001f || maxOutput + bufferOutput <= 0.0001f) {
return;
}
float inputUsed = Math.min(maxOutput / totalInput, 1f);
float bufferUsed = 0;
if (charge) {
bufferUsed = Math.min((totalInput - maxOutput) / bufferOutput, 1f);
} else {
bufferUsed = Math.min((maxOutput - totalInput) / bufferInput, 1f);
}
float inputUsed = charge ? Math.min((maxOutput + bufferOutput) / totalInput, 1f) : 1f;
for(Tile producer : producers){
if (producer.block().consumesPower) {
if (!charge) {
producer.entity.power.amount -= producer.entity.power.amount * bufferUsed;
}
continue;
}
producer.entity.power.amount -= producer.entity.power.amount * inputUsed;
}
float outputSatisfied = Math.min(totalInput / maxOutput, 1f);
float outputSatisfied = charge ? 1f : Math.min((totalInput + bufferInput) / maxOutput, 1f);
for(Tile consumer : consumers){
if (consumer.block().outputsPower) {
if (charge) {
consumer.entity.power.amount += (consumer.block().powerCapacity - consumer.entity.power.amount) * bufferUsed;
}
continue;
}
consumer.entity.power.amount += (consumer.block().powerCapacity - consumer.entity.power.amount) * outputSatisfied;
}
}

View File

@ -42,6 +42,7 @@ public class Cultivator extends Drill{
stats.remove(BlockStat.drillTier);
stats.add(BlockStat.drillTier, table -> {
table.addImage("grass1").size(8 * 3).padBottom(3).padTop(3);
// TODO: find out localized name and add tool tip
});
}

View File

@ -16,11 +16,14 @@ import io.anuke.mindustry.world.consumers.ConsumeLiquid;
import io.anuke.mindustry.world.meta.BlockGroup;
import io.anuke.mindustry.world.meta.BlockStat;
import io.anuke.mindustry.world.meta.StatUnit;
import io.anuke.mindustry.world.meta.StatValue;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Effects.Effect;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.graphics.Draw;
import io.anuke.ucore.scene.ui.Image;
import io.anuke.ucore.scene.ui.layout.Cell;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Threads;
@ -133,7 +136,8 @@ public class Drill extends Block{
for(int i = 0; i < list.size; i++){
Item item = list.get(i);
table.addImage(item.name + "1").size(8 * 3).padRight(2).padLeft(2).padTop(3).padBottom(3);
Cell<Image> imageCell = table.addImage(item.name + "1").size(8 * 3).padRight(2).padLeft(2).padTop(3).padBottom(3);
StatValue.addToolTip(imageCell.getElement(), item);
if(i != list.size - 1){
table.add("/");
}

View File

@ -64,15 +64,11 @@ public class Pump extends LiquidBlock{
if(isMultiblock()){
Liquid last = null;
for(Tile other : tile.getLinkedTilesAs(this, drawTiles)){
if(other == null) return false;
//can't place pump on block with multiple liquids
if(last != null && other.floor().liquidDrop != last){
if(other.floor().liquidDrop == null)
continue;
if(other.floor().liquidDrop != last && last != null)
return false;
}
if(isValid(other)){
last = other.floor().liquidDrop;
}
last = other.floor().liquidDrop;
}
return last != null;
}else{

View File

@ -81,11 +81,15 @@ public class CommandCenter extends Block{
public void buildTable(Tile tile, Table table){
CommandCenterEntity entity = tile.entity();
ButtonGroup<ImageButton> group = new ButtonGroup<>();
Table buttons = new Table();
for(UnitCommand cmd : UnitCommand.values()){
table.addImageButton("command-" + cmd.name(), "toggle", 8*3, () -> threads.run(() -> Call.onCommandCenterSet(players[0], tile, cmd))).size(40f, 44f)
buttons.addImageButton("command-" + cmd.name(), "toggle", 8*3, () -> threads.run(() -> Call.onCommandCenterSet(players[0], tile, cmd))).size(40f, 44f)
.checked(entity.command == cmd).group(group);
}
table.add(buttons);
table.row();
table.table("button", t -> t.label(() -> entity.command.localized()).center().growX()).growX().padTop(-5);
}
@Remote(called = Loc.server, forward = true, targets = Loc.both)

View File

@ -1,5 +1,10 @@
package io.anuke.mindustry.world.meta;
import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.ucore.scene.Element;
import io.anuke.ucore.scene.ui.Image;
import io.anuke.ucore.scene.ui.Tooltip;
import io.anuke.ucore.scene.ui.layout.Cell;
import io.anuke.ucore.scene.ui.layout.Table;
/**
@ -7,8 +12,38 @@ import io.anuke.ucore.scene.ui.layout.Table;
*/
public interface StatValue{
/**
* This method should all elements necessary to display this stat to the specified table.
* This method should provide all elements necessary to display this stat to the specified table.
* For example, a stat that is just text would add label to the table.
*/
void display(Table table);
/**
* This method adds an icon image together with a tool tip which contains the name of the item.
* @param table the table to add the image cell to.
* @param item The item which provides the tool tip content.
* @return the image cell which was created. The cell is not yet sized or padded.
*/
static Cell<Image> addImageWithToolTip(Table table, UnlockableContent item){
// Create a table cell with a new image as provided by the item
Cell<Image> imageCell = table.addImage(item.getContentIcon());
// Retrieve the image and add a tool tip with the item's name
addToolTip(imageCell.getElement(), item);
// Return the table cell for further processing (sizing, padding, ...)
return imageCell;
}
/**
* Adds a tool tip containing the item's localized name to the given element.
* @param element The element to assign the tool tip to.
* @param item The item which provides the tool tip content.
*/
static void addToolTip(Element element, UnlockableContent item){
element.addListener(new Tooltip<>(new Table("clear"){{
add(item.localizedName());
margin(4);
}}));
}
}

View File

@ -4,6 +4,8 @@ import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.meta.StatValue;
import io.anuke.ucore.function.Predicate;
import io.anuke.ucore.scene.ui.Image;
import io.anuke.ucore.scene.ui.layout.Cell;
import io.anuke.ucore.scene.ui.layout.Table;
import static io.anuke.mindustry.Vars.*;
@ -24,7 +26,12 @@ public class ItemFilterValue implements StatValue{
for(int i = 0; i < list.size; i++){
Item item = list.get(i);
table.addImage(item.region).size(8 * 3).padRight(2).padLeft(2);
Cell<Image> imageCell = table.addImage(item.region);
imageCell.size(8 * 3).padRight(2).padLeft(2);
StatValue.addToolTip(imageCell.getElement(), item);
if(i != list.size - 1){
table.add("/");
}

View File

@ -5,6 +5,9 @@ import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.ui.ItemImage;
import io.anuke.mindustry.world.meta.ContentStatValue;
import io.anuke.mindustry.world.meta.StatValue;
import io.anuke.ucore.scene.ui.Image;
import io.anuke.ucore.scene.ui.layout.Cell;
import io.anuke.ucore.scene.ui.layout.Table;
public class ItemListValue implements ContentStatValue{
@ -38,11 +41,17 @@ public class ItemListValue implements ContentStatValue{
public void display(Table table){
if(items != null){
for(Item item : items){
table.addImage(item.region).size(8 * 3).padRight(5);
Cell<Image> imageCell = table.addImage(item.region);
imageCell.size(8 * 3).padRight(5);
StatValue.addToolTip(imageCell.getElement(), item);
}
}else{
for(ItemStack stack : stacks){
table.add(new ItemImage(stack)).size(8 * 3).padRight(5);
ItemImage image = new ItemImage(stack);
table.add(image).size(8 * 3).padRight(5);
StatValue.addToolTip(image, stack.item);
}
}
}

View File

@ -5,6 +5,7 @@ import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.ui.ItemImage;
import io.anuke.mindustry.world.meta.ContentStatValue;
import io.anuke.mindustry.world.meta.StatValue;
import io.anuke.ucore.scene.ui.layout.Table;
public class ItemValue implements ContentStatValue{
@ -22,6 +23,8 @@ public class ItemValue implements ContentStatValue{
@Override
public void display(Table table){
//TODO better implementation, quantity support
table.add(new ItemImage(item)).size(8 * 3);
ItemImage image = new ItemImage(item);
table.add(image).size(8 * 3);
StatValue.addToolTip(image, item.item);
}
}

View File

@ -4,6 +4,9 @@ import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.world.meta.StatValue;
import io.anuke.ucore.function.Predicate;
import io.anuke.ucore.scene.ui.Image;
import io.anuke.ucore.scene.ui.Tooltip;
import io.anuke.ucore.scene.ui.layout.Cell;
import io.anuke.ucore.scene.ui.layout.Table;
import static io.anuke.mindustry.Vars.*;
@ -24,7 +27,10 @@ public class LiquidFilterValue implements StatValue{
for(int i = 0; i < list.size; i++){
Liquid item = list.get(i);
table.addImage(item.getContentIcon()).size(8 * 3).padRight(2).padLeft(2).padTop(2).padBottom(2);
Cell<Image> imageCell = StatValue.addImageWithToolTip(table, item);
imageCell.size(8 * 3).padRight(2).padLeft(2).padTop(2).padBottom(2);
if(i != list.size - 1){
table.add("/");
}

View File

@ -3,6 +3,9 @@ package io.anuke.mindustry.world.meta.values;
import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.world.meta.ContentStatValue;
import io.anuke.mindustry.world.meta.StatValue;
import io.anuke.ucore.scene.ui.Image;
import io.anuke.ucore.scene.ui.layout.Cell;
import io.anuke.ucore.scene.ui.layout.Table;
public class LiquidValue implements ContentStatValue{
@ -19,6 +22,7 @@ public class LiquidValue implements ContentStatValue{
@Override
public void display(Table table){
table.addImage(liquid.getContentIcon()).size(8 * 3);
Cell<Image> imageCell = StatValue.addImageWithToolTip(table, liquid);
imageCell.size(8 * 3);
}
}

View File

@ -1,6 +1,7 @@
package io.anuke.mindustry.server;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ObjectSet;
import com.badlogic.gdx.utils.Timer;
@ -41,12 +42,18 @@ import static io.anuke.ucore.util.Log.*;
public class ServerControl extends Module{
private static final int roundExtraTime = 12;
//in bytes: 512 kb is max
private static final int maxLogLength = 1024 * 512;
private final CommandHandler handler = new CommandHandler("");
private final FileHandle logFolder = Gdx.files.local("logs/");
private FileHandle currentLogFile;
private int gameOvers;
private boolean inExtraRound;
private Task lastTask;
public ServerControl(String[] args){
Settings.defaultList(
"shufflemode", "normal",
@ -56,7 +63,8 @@ public class ServerControl extends Module{
"sector_y", 1,
"shuffle", true,
"crashreport", false,
"port", port
"port", port,
"logging", true
);
Log.setLogger(new LogHandler(){
@ -64,22 +72,27 @@ public class ServerControl extends Module{
@Override
public void info(String text, Object... args){
print("&lg&fb" + "[INFO] " + format(text, args));
print("&lg&fb" + "[INFO] " + text, args);
}
@Override
public void err(String text, Object... args){
print("&lr&fb" + "[ERR!] " + format(text, args));
print("&lr&fb" + "[ERR!] " + text, args);
}
@Override
public void warn(String text, Object... args){
print("&ly&fb" + "[WARN] " + format(text, args));
print("&ly&fb" + "[WARN] " + text, args);
}
@Override
public void print(String text, Object... args){
System.out.println("[" + dateTime.format(LocalDateTime.now()) + "] " + format(text + "&fr", args));
String result = "[" + dateTime.format(LocalDateTime.now()) + "] " + format(text + "&fr", args);
System.out.println(result);
if(Settings.getBool("logging")){
logToFile("[" + dateTime.format(LocalDateTime.now()) + "] " + format(text + "&fr", false, args));
}
}
});
@ -311,7 +324,7 @@ public class ServerControl extends Module{
return;
}
Call.sendMessage("[GRAY][[Server]:[] " + arg[0]);
Call.sendMessage("[scarlet][[Server]:[] " + arg[0]);
info("&lyServer: &lb{0}", arg[0]);
});
@ -357,6 +370,13 @@ public class ServerControl extends Module{
info("Crash reporting is now {0}.", value ? "on" : "off");
});
handler.register("logging", "<on/off>", "Disables or enables server logs", arg -> {
boolean value = arg[0].equalsIgnoreCase("on");
Settings.putBool("logging", value);
Settings.save();
info("Logging is now {0}.", value ? "on" : "off");
});
handler.register("strict", "<on/off>", "Disables or enables strict mode", arg -> {
boolean value = arg[0].equalsIgnoreCase("on");
netServer.admins.setStrict(value);
@ -400,6 +420,7 @@ public class ServerControl extends Module{
Player target = playerGroup.find(p -> p.name.equals(arg[0]));
if(target != null){
Call.sendMessage("[scarlet] " + target.name + " has been kicked by the server.");
netServer.kick(target.con.id, KickReason.kick);
info("It is done.");
}else{
@ -425,6 +446,13 @@ public class ServerControl extends Module{
}else{
err("Invalid type.");
}
for(Player player : playerGroup.all()){
if(netServer.admins.isIDBanned(player.uuid)){
Call.sendMessage("[scarlet] " + player.name + " has been banned.");
netServer.kick(player.con.id, KickReason.banned);
}
}
});
handler.register("bans", "List all banned IPs and IDs.", arg -> {
@ -724,4 +752,23 @@ public class ServerControl extends Module{
state.set(State.menu);
}
}
private void logToFile(String text){
if(currentLogFile != null && currentLogFile.length() > maxLogLength){
String date = DateTimeFormatter.ofPattern("MM-dd-yyyy | HH:mm:ss").format(LocalDateTime.now());
currentLogFile.writeString("[End of log file. Date: "+ date + "]\n", true);
currentLogFile = null;
}
if(currentLogFile == null){
int i = 0;
while(logFolder.child("log-" + i + ".txt").length() >= maxLogLength){
i ++;
}
currentLogFile = logFolder.child("log-" + i + ".txt");
}
currentLogFile.writeString(text + "\n", true);
}
}