diff --git a/annotations/src/main/java/mindustry/annotations/BaseProcessor.java b/annotations/src/main/java/mindustry/annotations/BaseProcessor.java index 05f9aae5f6..d9a4ac5998 100644 --- a/annotations/src/main/java/mindustry/annotations/BaseProcessor.java +++ b/annotations/src/main/java/mindustry/annotations/BaseProcessor.java @@ -211,10 +211,7 @@ public abstract class BaseProcessor extends AbstractProcessor{ if(round++ >= rounds) return false; //only process 1 round if(rootDirectory == null){ try{ - String path = Fi.get(filer.getResource(StandardLocation.CLASS_OUTPUT, "no", "no") - .toUri().toURL().toString().substring(OS.isWindows ? 6 : "file:".length())) - .parent().parent().parent().parent().parent().parent().parent().toString().replace("%20", " "); - rootDirectory = Fi.get(path).parent(); + rootDirectory = new Fi(new File(filer.getResource(StandardLocation.CLASS_OUTPUT, "no", "no").toUri())).parent().parent().parent().parent().parent().parent().parent().parent(); }catch(IOException e){ throw new RuntimeException(e); } diff --git a/build.gradle b/build.gradle index ad9b9e26ae..bb46c808bb 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ allprojects{ if(!project.hasProperty("versionModifier")) versionModifier = 'alpha' if(!project.hasProperty("versionType")) versionType = 'official' appName = 'Mindustry' - steamworksVersion = 'da41c05b7a2a44c8625ca0ba7d6ca1a2e73f621a' + steamworksVersion = '185e76cfe630a6f0e1dd7b9bf57be41f6064a1f2' rhinoVersion = '32395f942976a6d1d21ec9877664554cd5762306' loadVersionProps = { diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index a6989f369a..8fe48cd691 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -1310,7 +1310,7 @@ bar.cargounitcap = Cargo Unit Cap Reached bar.drillspeed = Drill Speed: {0}/s bar.pumpspeed = Pump Speed: {0}/s bar.efficiency = Efficiency: {0}% -bar.yield = Yield: +{0}% +bar.yield = Yield: {0}% bar.boost = Boost: +{0}% bar.powerbuffer = Batteries: {0}/{1} bar.powerbalance = Power: {0}/s @@ -3402,7 +3402,7 @@ logicrule.label.wavetimer = wave timer? logicrule.label.waves = waves logicrule.label.wave = wave logicrule.label.wavespacing = wave spacing -logicrule.label.wavesending = waves ending? +logicrule.label.wavesending = waves sending? logicrule.label.attackmode = attack mode? logicrule.label.enemycorebuildradius = enemy core build radius logicrule.label.dropzoneradius = drop zone radius diff --git a/core/assets/bundles/bundle_es.properties b/core/assets/bundles/bundle_es.properties index c474375f77..df4e64ed3d 100644 --- a/core/assets/bundles/bundle_es.properties +++ b/core/assets/bundles/bundle_es.properties @@ -844,7 +844,7 @@ objective.destroyblock.name = Destruir bloque objective.destroyblocks.name = Destruir bloques objective.destroycore.name = Destruir núcleo objective.commandmode.name = Modo comando -objective.flag.name = Etiqueta +objective.flag.name = Flag marker.shapetext.name = Forma del texto marker.point.name = Punto @@ -1244,7 +1244,7 @@ stat.reactive = Reacciona con stat.immunities = Inmune a stat.healing = Curación stat.status = Efecto de estado -stat.efficiency = [stat]{0}% Eficiencia +stat.efficiency = {0}% Eficiencia stat.chance = [stat]{0}%[lightgray] probabilidad de [white] stat.hitsize = Tamaño de Unidad stat.resettime = Tiempo de Reinicio @@ -1305,7 +1305,7 @@ bar.cargounitcap = Se alcanzó el límite de carga de unidades bar.drillspeed = Velocidad del taladro: {0}/s bar.pumpspeed = Velocidad de bombeado: {0}/s bar.efficiency = Eficiencia: {0}% -bar.yield = Yield: +{0}% +bar.yield = Producción: {0}% bar.boost = Aceleración: +{0}% bar.powerbuffer = Poder en baterías: {0}/{1} bar.powerbalance = Energía: {0}/s @@ -1325,7 +1325,7 @@ bar.nevermelts = nunca hace fusión bar.heatamount = Calor: {0} bar.heatpercent = Calor: {0} ({1}%) bar.power = Energía -bar.progress = Construyendo... +bar.progress = {0}% Construido bar.loadprogress = Progreso bar.launchcooldown = Recarga de lanzamiento bar.input = Entrada @@ -1996,8 +1996,8 @@ block.metal-tiles-13.name = Casilla de metal 13 block.metal-wall-1.name = Muro de metal 1 block.metal-wall-2.name = Muro de metal 2 block.metal-wall-3.name = Muro de metal 3 -block.colored-floor.name = Piso coloreado -block.colored-wall.name = Muro coloreado +block.colored-floor.name = Suelo de Color +block.colored-wall.name = Muro de Color block.character-overlay.name = Caracter block.character-overlay-white.name = Caracter (Blanco) block.rune-overlay.name = Runa @@ -2763,7 +2763,7 @@ block.ship-refabricator.description = Mejora al segundo nivel la nave selecciona block.mech-refabricator.description = Mejora al segundo nivel el mech seleccionado. block.prime-refabricator.description = Mejora al tercer nivel las unidades entrantes. block.basic-assembler-module.description = Incrementa el nivel del ensamblador si se coloca junto a un área de construcción. Requiere energía. Se puede usar como entrada de un cargador. -block.small-deconstructor.description = Deconstruye las estructuras y unidades entrantes. Devuelve el 100% de su coste de construcción. +block.small-deconstructor.description = Deconstruye las estructuras y unidades entrantes. Devuelve el 100% de su coste de construcción. Guarda los objetos en diferentes capacidades de objetos. block.reinforced-payload-conveyor.description = Mueve los lotes de carga en una dirección. block.reinforced-payload-router.description = Distribuye las cargas a los bloques adyacentes. Funcionará como un clasificador si se le establece un filtro. block.payload-mass-driver.description = Estructura de transporte de carga de largo alcance. Dispara las cargas entrantes a otras catapultas enlazadas. @@ -2951,63 +2951,63 @@ laccess.displayheight = Alto de un bloque de pantalla, en pixeles. laccess.buffersize = Número de comandos sin ejecutar en el buffer gráfico de una pantalla. laccess.operations = Número de operaciones ejecutadas en el bloque.\nPara pantallas, retorna el número de operaciones drawflush. laccess.maxunits = Unidades máximas que un equipo puede tener.\nSolo puede ser obtenido de los núcleos. -laccess.totalitems = Total number of items contained. -laccess.firstitem = First item contained, or null if empty. -laccess.totalliquids = Total amount of liquid contained. -laccess.totalpower = For blocks with a buffered power store, the amount of power stored; for other blocks, buffer fullness from 0 to 1. -laccess.itemcapacity = Maximum number of items this building can hold. -laccess.liquidcapacity = Maximum amount of liquid this building can hold. -laccess.powercapacity = Maximum amount of power this building can store. -laccess.powernetstored = Total power stored in the connected power grid. -laccess.powernetcapacity = Total power storage capacity of the connected power grid. -laccess.powernetin = Power entering the connected power grid, per second. -laccess.powernetout = Power leaving the connected power grid, per second. -laccess.ammo = Current ammo count of a turret. -laccess.ammocapacity = Maximum ammo count of a turret. -laccess.health = Current health.\nFor bullets, their damage. -laccess.maxhealth = Maximum health.\nFor bullets, the base damage. -laccess.heat = Current heat of a turret that consumes heat, 0 to 1. -laccess.shield = Current shield amount of a unit. -laccess.armor = Armor value; flat damage reduction per hit. -laccess.efficiency = Operating efficiency of a building, where 1 is nominal. -laccess.timescale = Time scale multiplier affecting a building, where 1 is normal speed. -laccess.rotation = Facing angle of a unit or turret, in degrees.\nFor most other buildings, the 0 to 3 orientation. -laccess.x = X position, in tiles. -laccess.y = Y position, in tiles. -laccess.velocityx = X velocity of a unit, in tiles/sec. -laccess.velocityy = Y velocity of a unit, in tiles/sec. -laccess.shootx = X coordinate a unit or turret is aiming at. -laccess.shooty = Y coordinate a unit or turret is aiming at. -laccess.camerax = X position of the controlling player's camera. -laccess.cameray = Y position of the controlling player's camera. -laccess.camerawidth = Width of the controlling player's view, in tiles. -laccess.cameraheight = Height of the controlling player's view, in tiles. -laccess.solid = Whether this building blocks movement. -laccess.range = Range of a unit or turret, in tiles. -laccess.shooting = Whether a unit or turret is currently shooting. -laccess.boosting = Whether a unit is currently boosting or flying over terrain. -laccess.minex = X tile coordinate a unit is mining, or -1 if not mining. -laccess.miney = Y tile coordinate a unit is mining, or -1 if not mining. -laccess.mining = Whether a unit is currently mining. -laccess.buildx = X tile coordinate a unit is building at, or -1 if not building. -laccess.buildy = Y tile coordinate a unit is building at, or -1 if not building. -laccess.pingx = X coordinate a player is pinging, or null if not pinging. -laccess.pingy = Y coordinate a player is pinging, or null if not pinging. -laccess.pingtext = Text of a player's current ping, or null if not pinging. -laccess.building = Building a unit is currently constructing, or null. -laccess.breaking = Building a unit is currently deconstructing, or null. -laccess.team = Team ID of a unit or building. -laccess.flag = Numeric flag value stored on a unit. -laccess.flying = Whether a unit is currently airborne. -laccess.name = Name of the player controlling this unit, or null. -laccess.payloadcount = Number of payloads currently held. -laccess.payloadtype = Type of the last payload picked up, or null. -laccess.totalpayload = Combined size of all held payloads. -laccess.payloadcapacity = Maximum combined payload size a unit or building can carry. -laccess.selectedblock = Block currently selected by the controlling player, or null. -laccess.selectedrotation = Build rotation currently selected by the controlling player, 0 to 3. -laccess.bulletlifetime = Total lifetime of a bullet, in ticks. -laccess.bullettime = Time a bullet has existed, in ticks. +laccess.totalitems = Número total de items dentro. +laccess.firstitem = Primer item dentro, Devuelve null si se encuentra vacío. +laccess.totalliquids = Cantidad total de líquido contenido. +laccess.totalpower = Para bloques con la capacidad de almacenar energía, la cantidad de energía almacenada; para otros bloques, de 0 a 1. +laccess.itemcapacity = Número total de items que esta construcción o unidad puede almacenar. +laccess.liquidcapacity = Tamaño máximo de liquido que esta construcción puede almacenar. +laccess.powercapacity = Cantidad máxima de energía que esta construcción puede almacenar. +laccess.powernetstored = Total de energía almacenada en la red de energía conectada. +laccess.powernetcapacity = Capacidad de almacenamiento total en la red de energía conectada. +laccess.powernetin = Energía que entra en la red de energía conectada, por segundo. +laccess.powernetout = Energía que abandona la red de energía conectada, por segundo. +laccess.ammo = Cantidad de munición actual de una torreta. +laccess.ammocapacity = Cantidad de munición máxima de una torreta. +laccess.health = Salud actual.\nPara balas, su daño. +laccess.maxhealth = Salud máxima.\nPara balas, su daño base. +laccess.heat = Calor actual de una torreta que puede usarlo, 0 a 1. +laccess.shield = Cantidad de escudo actual de una unidad. +laccess.armor = Valor de armadura; reducción plana de daño por golpe. +laccess.efficiency = Eficiencia operativa de la construcción, donde 1 es el valor nominal. +laccess.timescale = Multiplicador de escala de tiempo afectando a la construcción, donde 1 es la velocidad normal. +laccess.rotation = El ángulo al que está mirando una unidad o torreta, en grados.\nPara muchas de las otras construcciones, la orientación de 0 a 3. +laccess.x = Posición X, en casillas. +laccess.y = Posición Y, en casillas. +laccess.velocityx = Velocidad horizontal de una unidad, en casillas/segundo. +laccess.velocityy = Velocidad vertical de una unidad, en casillas/segundo. +laccess.shootx = Coordenada X a la cual una unidad o torreta está apuntando. +laccess.shooty = Coordenada Y a la cual una unidad o torreta está apuntando. +laccess.camerax = Posición X de la camara del jugador que está controlando. +laccess.cameray = Posición Y de la camara del jugador que está controlando. +laccess.camerawidth = Ancho de la vista del jugador que está controlando, en casillas. +laccess.cameraheight = Largo de la vista del jugador que está controlando, en casillas. +laccess.solid = Si una construcción bloquea el movimiento sobre de ella. +laccess.range = Rango de una unidad o torreta, en casillas. +laccess.shooting = Si una unidad o torreta se encuentra disparando. +laccess.boosting = Si una unidad está volando sobrevolando o volando sobre el terreno. +laccess.minex = Coordenada X de la casilla en la cual una unidad está minando, o -1 si no está minando. +laccess.miney = Coordenada Y de la casilla en la cual una unidad está minando, o -1 si no está minando. +laccess.mining = Si una unidad se encuentra minando. +laccess.buildx = Coordenada X de la casilla en la cual una unidad está construyendo, o -1 si no está construyendo. +laccess.buildy = Coordenada Y de la casilla en la cual una unidad está construyendo, o -1 si no está construyendo. +laccess.pingx = Coordenada X en la cual un jugador esta pingeando, o null si no está pingeando. +laccess.pingy = Coordenada Y en la cual un jugador está pingeando, o null si no está pingeando. +laccess.pingtext = Texto del ping actual de un jugador, o null si no está pingeando. +laccess.building = Construcción que la unidad está construyendo actualmente, o null. +laccess.breaking = Construcción que la unidad está deconstruyendo actualmente, o null. +laccess.team = Identificador de equipo de una unidad o construcción. +laccess.flag = Valor numérico o flag almacenada en una unidad. +laccess.flying = Si la unidad se encuentra volando. +laccess.name = Nombre del jugador controlando esta unidad, o null. +laccess.payloadcount = Numero de carga que se lleva actualmente. +laccess.payloadtype = Tipo de la última carga recogida, o null. +laccess.totalpayload = Tamaño combinado de toda la carga llevada. +laccess.payloadcapacity = Tamaño máximo combinado que una unidad o construcción pueden cargar. +laccess.selectedblock = Bloque seleccionado actualmente por el jugador que está controlando, o null. +laccess.selectedrotation = Rotación del bloque actualmente seleccionado por el jugador que está controland, de 0 a 3. +laccess.bulletlifetime = Tiempo de vida total de una bala, en ticks. +laccess.bullettime = Tiempo que una bala ha existido, en ticks. lcategory.unknown = Desconocido lcategory.unknown.description = Instrucciones no clasificadas. @@ -3192,8 +3192,8 @@ instruction.print = Agregar texto instruction.printchar = Agregar Carácter instruction.format = Reemplazar Formato instruction.drawflush = Dibujar Gráficos -instruction.printflush = Imprimir -instruction.getlink = Obtener Enlazados +instruction.printflush = Imprimir Texto +instruction.getlink = Obtener Enlazado instruction.control = Controlar instruction.radar = Radar instruction.sensor = Sensor @@ -3201,9 +3201,9 @@ instruction.set = Asignar instruction.operation = Operación instruction.select = Seleccionar instruction.wait = Esperar -instruction.stop = Detener +instruction.stop = Detener Ejecución instruction.lookup = Buscar -instruction.jump = Salto Condicional +instruction.jump = Jump instruction.end = Terminar instruction.unitbind = Vincular Unidad instruction.unitcontrol = Controlar Unidad @@ -3212,31 +3212,31 @@ instruction.unitlocate = Localizar con Unidad instruction.query = Query instruction.getblock = Obtener Bloque instruction.setblock = Crear Bloque -instruction.spawnunit = Aparecer Unidad -instruction.spawnbullet = Aparecer Bala +instruction.spawnunit = Crear Unidad +instruction.spawnbullet = Crear Bala instruction.applystatus = Aplicar Estado -instruction.weathersense = Detectar Clima +instruction.weathersense = Obtener Clima instruction.weatherset = Establecer Clima -instruction.spawnwave = Aparecer Oleada +instruction.spawnwave = Generar Oleada instruction.setrule = Cambiar Regla -instruction.flushmessage = Flush Message +instruction.flushmessage = Mostrar Mensaje instruction.cutscene = Cinematica instruction.effect = Efecto instruction.explosion = Explosion -instruction.setrate = Set Rate +instruction.setrate = Establecer Velocidad instruction.fetch = Buscar instruction.sync = Sincronizar instruction.clientdata = Datos del Cliente -instruction.getflag = Get Flag -instruction.setflag = Set Flag -instruction.setprop = Set Prop +instruction.getflag = Obtener Flag Global +instruction.setflag = Asignar Flag Global +instruction.setprop = Asignar Propiedad instruction.playsound = Reproducir Sonido instruction.playmusic = Reproducir Musica instruction.setmarker = Set Marker instruction.makemarker = Make Marker instruction.localeprint = Locale Print -instruction.packcolor = Desagrupar Color -instruction.unpackcolor = Agrupar Color +instruction.packcolor = Agrupar Color +instruction.unpackcolor = Desagrupar Color instruction.invalid = Instrucción Invalida # Implemented via the enumText() method blockflag.label.core = núcleos @@ -3269,22 +3269,22 @@ fetchtype.label.unitcount = cantidad de unidades fetchtype.label.playercount = cantidad de jugadores fetchtype.label.corecount = cantidad de núcleos fetchtype.label.buildcount = cantidad de construcciones -graphicstype.label.clear = clear +graphicstype.label.clear = llenar graphicstype.label.color = color graphicstype.label.col = col -graphicstype.label.stroke = stroke -graphicstype.label.line = line -graphicstype.label.rect = rect -graphicstype.label.linerect = line rect -graphicstype.label.poly = poly -graphicstype.label.linepoly = line poly -graphicstype.label.triangle = triangle -graphicstype.label.image = image -graphicstype.label.print = print +graphicstype.label.stroke = ancho +graphicstype.label.line = linea +graphicstype.label.rect = rectangulo +graphicstype.label.linerect = lineas rect +graphicstype.label.poly = poligono +graphicstype.label.linepoly = lineas poly +graphicstype.label.triangle = triangulo +graphicstype.label.image = imágen +graphicstype.label.print = texto graphicstype.label.translate = translate -graphicstype.label.scale = scale -graphicstype.label.rotate = rotate -graphicstype.label.reset = reset +graphicstype.label.scale = escalar +graphicstype.label.rotate = rotar +graphicstype.label.reset = reiniciar laccess.label.totalitems = total de objetos laccess.label.firstitem = primer objeto laccess.label.totalliquids = liquido total @@ -3324,27 +3324,27 @@ laccess.label.displayheight = largo de pantalla laccess.label.buffersize = tamaño de buffer laccess.label.operations = operaciones laccess.label.size = tamaño -laccess.label.solid = ¿solido? -laccess.label.dead = ¿muerto? +laccess.label.solid = solido? +laccess.label.dead = muerto? laccess.label.range = rango -laccess.label.shooting = ¿disparando? -laccess.label.boosting = ¿sobrevolando? +laccess.label.shooting = disparando? +laccess.label.boosting = sobrevolando? laccess.label.minex = minando x laccess.label.miney = minando y -laccess.label.mining = ¿minando? +laccess.label.mining = minando? laccess.label.buildx = construyendo x laccess.label.buildy = construyendo y laccess.label.pingx = ping x laccess.label.pingy = ping y laccess.label.pingtext = texto en ping -laccess.label.building = ¿construyendo? -laccess.label.breaking = ¿deconstruyendo? +laccess.label.building = construyendo? +laccess.label.breaking = deconstruyendo? laccess.label.speed = velocidad laccess.label.team = equipo laccess.label.type = tipo laccess.label.flag = flag -laccess.label.flying = ¿puede volar? -laccess.label.controlled = ¿controlada? +laccess.label.flying = puede volar? +laccess.label.controlled = controlada? laccess.label.controller = controlador laccess.label.name = nombre laccess.label.payloadcount = conteo de carga @@ -3357,7 +3357,7 @@ laccess.label.selectedblock = bloque seleccionado laccess.label.selectedrotation = rotación seleccionada laccess.label.bulletlifetime = tiempo de vida de la bala laccess.label.bullettime = tiempo de bala -laccess.label.enabled = ¿activado? +laccess.label.enabled = activado? laccess.label.shoot = disparo laccess.label.shootp = disparo con predicción laccess.label.config = configuración @@ -3393,17 +3393,17 @@ lmarkercontrol.label.posi = posi lmarkercontrol.label.uvi = uvi lmarkercontrol.label.colori = colori logicrule.label.currentwavetime = tiempo restante oleada actual -logicrule.label.wavetimer = ¿temporizador de oleada? -logicrule.label.waves = ¿oleadas activas? +logicrule.label.wavetimer = temporizador de oleada? +logicrule.label.waves = oleadas activas? logicrule.label.wave = oleada logicrule.label.wavespacing = tiempo entre oleadas -logicrule.label.wavesending = ¿adelantar oleada? -logicrule.label.attackmode = ¿modo de juego ataque? +logicrule.label.wavesending = enviar oleadas? +logicrule.label.attackmode = modo de juego ataque? logicrule.label.enemycorebuildradius = radio de construccion de núcleo enemiga logicrule.label.dropzoneradius = radio de zona de aparición logicrule.label.unitcap = capacidad de unidades logicrule.label.maparea = area del mapa -logicrule.label.lighting = ¿iluminación? +logicrule.label.lighting = iluminación? logicrule.label.cangameover = se puede perder logicrule.label.ambientlight = iluminación ambiental logicrule.label.unitlight = iluminación de unidad @@ -3411,7 +3411,7 @@ logicrule.label.solarmultiplier = multiplicador solar logicrule.label.dragmultiplier = multiplicador de arrastre logicrule.label.ban = banear logicrule.label.unban = desbanear -logicrule.label.pausedisabled = ¿desactivar pausa? +logicrule.label.pausedisabled = desactivar pausa? logicrule.label.musicvolume = volumen de la música logicrule.label.buildspeed = velocidad de construcción logicrule.label.unithealth = salud de unidad @@ -3427,29 +3427,29 @@ lunitcontrol.label.idle = inactiva lunitcontrol.label.stop = detenerse lunitcontrol.label.unbind = desvincular lunitcontrol.label.move = mover -lunitcontrol.label.approach = aproximar -lunitcontrol.label.pathfind = encontrarRuta -lunitcontrol.label.autopathfind = encontrarRuta auto -lunitcontrol.label.target = target -lunitcontrol.label.targetp = target predict +lunitcontrol.label.approach = acercar +lunitcontrol.label.pathfind = seguir ruta +lunitcontrol.label.autopathfind = auto-seguir ruta +lunitcontrol.label.target = disparar +lunitcontrol.label.targetp = disparar con predicción lunitcontrol.label.itemdrop = soltar objeto lunitcontrol.label.itemtake = tomar objeto lunitcontrol.label.paydrop = soltar carga lunitcontrol.label.paytake = tomar carga lunitcontrol.label.payenter = entrar como carga -lunitcontrol.label.flag = etiqueta +lunitcontrol.label.flag = flag lunitcontrol.label.mine = minar lunitcontrol.label.build = construir bloque lunitcontrol.label.getblock = obtener bloque lunitcontrol.label.deconstruct = deconstruir -lunitcontrol.label.within = ¿dentro de? -lunitcontrol.label.boost = ¿potenciar? +lunitcontrol.label.within = dentro de? +lunitcontrol.label.boost = sobrevolar? messagetype.label.notify = notify messagetype.label.announce = announce messagetype.label.toast = toast messagetype.label.mission = mission -querytype.label.unit = unit -querytype.label.building = building +querytype.label.unit = unidad +querytype.label.building = construcción radarsort.label.distance = distancia radarsort.label.health = salud radarsort.label.maxhealth = salud máxima @@ -3463,40 +3463,40 @@ radartarget.label.attacker = unidad armada radartarget.label.flying = unidad aérea radartarget.label.ground = unidad terrestre radartarget.label.boss = boss -tilelayer.label.floor = floor -tilelayer.label.ore = ore -tilelayer.label.block = block -tilelayer.label.building = building +tilelayer.label.floor = suelo +tilelayer.label.ore = mineral +tilelayer.label.block = bloque +tilelayer.label.building = construcción name.token.color = color -name.token.width = width -name.token.height = height -name.token.sides = sides -name.token.radius = radius -name.token.rotation = rotation -name.token.image = image -name.token.size = size -name.token.align = align -name.token.set = crear -name.token.of = of +name.token.width = ancho +name.token.height = largo +name.token.sides = lados +name.token.radius = radio +name.token.rotation = rotación +name.token.image = imagen +name.token.size = tamaño +name.token.align = alinear +name.token.set = asigna +name.token.of = de name.token.to = a name.token.at = en name.token.in = en name.token.damage = daño -name.token.velocityScl = velocity scale -name.token.lifeScl = life scale -name.token.aimX = aim X -name.token.aimY = aim Y -name.token.read = read -name.token.write = write -name.token.from = from -name.token.char = char +name.token.velocityScl = escala de velocidad +name.token.lifeScl = escala de salud +name.token.aimX = apuntar X +name.token.aimY = apuntar Y +name.token.read = lee +name.token.write = escribe +name.token.from = de +name.token.char = carácter name.token.linknum = link# -name.token.draw = draw -name.token.clear = clear -name.token.apply = apply -name.token.circle = circle -name.token.rect = rect +name.token.draw = dibujar +name.token.clear = limpiar +name.token.apply = aplicar +name.token.circle = circulo +name.token.rect = recta name.token.positional = posicional name.token.global = global name.token.target = objetivo @@ -3513,43 +3513,43 @@ name.token.then = then name.token.else = else name.token.find = localizar name.token.group = grupo -name.token.enemy = ¿enemigo? +name.token.enemy = enemigo? name.token.ore = mineral name.token.outX = X obtenida name.token.outY = Y obtenida name.token.owner = owner -name.token.found = ¿encontrado? +name.token.found = encontrado? name.token.building = construcción name.token.always = always name.token.not = not -name.token.pack = pack -name.token.unpack = unpack -name.token.-lookup = = lookup -name.token.type = type +name.token.pack = agrupar +name.token.unpack = desagrupar +name.token.-lookup = = bucar +name.token.type = tipo name.token.get = get -name.token.team = team -name.token.angle = angle -name.token.spawn = spawn -name.token.-bullet = = bullet -name.token.unit = unit -name.token.weather = weather -name.token.state = state +name.token.team = equipo +name.token.angle = ángulo +name.token.spawn = crear +name.token.-bullet = = bala +name.token.unit = unidad +name.token.weather = clima +name.token.state = estado name.token.natural = natural name.token.speed = speed name.token.level = level -name.token.duration = duration -name.token.seconds = seconds +name.token.duration = duración +name.token.seconds = segundos name.token.shown = shown name.token.data = data -name.token.effect = effect -name.token.pierce = pierce -name.token.ground = ground +name.token.effect = efecto +name.token.pierce = atraviesa +name.token.ground = terrestre name.token.air = air name.token.flag = flag -name.token.volume = volume +name.token.volume = volumen name.token.pitch = pitch name.token.pan = pan -name.token.limit = limit +name.token.limit = limite name.token.id = id # name.token.replace = replace? name.token.for = for @@ -3568,13 +3568,13 @@ name.token.name = name name.token.index = index name.token.block-unit = block/unit name.token.enable = enable -name.token.amount = amount +name.token.amount = cantidad name.token.item = item -name.token.takeUnits = take units +name.token.takeUnits = tomar unidades? name.token.value = value name.token.floor = floor name.token.result = resultado -name.token.config = config +name.token.config = configuración name.token.shapeText = shape text name.token.point = point name.token.shape = shape @@ -3583,12 +3583,12 @@ name.token.line = line name.token.texture = texture name.token.quad = quad name.token.light = light -name.token.snowing = snowing -name.token.rain = rain -name.token.sandstorm = sand storm -name.token.sporestorm = spore storm -name.token.fog = fog -name.token.suspend-particles = suspended particles +name.token.snowing = nevando +name.token.rain = lloviendo +name.token.sandstorm = tormenta de arena +name.token.sporestorm = tormenta de esporas +name.token.fog = neblina +name.token.suspend-particles = particulas suspendidas name.token.topLeft = top left name.token.top = top name.token.topRight = top right @@ -3632,15 +3632,15 @@ name.token.sparkExplosion = explosión con chispas name.token.crossExplosion = explosión con cruz name.token.wave = oleada name.token.bubble = burbuja -name.token.music = music -name.token.interrupt = interrupt +name.token.music = musica +name.token.interrupt = interrumpe name.token.all = Todos name.token.beams = Rayos -name.token.block = Bloques +name.token.block = bloque name.token.charge = Carga name.token.environment = Clima name.token.explosions = Explosiones name.token.loops = Bucles name.token.movement = Movimiento -name.token.shoot = Disparos -name.token.ui = Interfaz Usuario +name.token.shoot = disparar +name.token.ui = Interfaz de Usuario diff --git a/core/assets/bundles/bundle_hu.properties b/core/assets/bundles/bundle_hu.properties index c669525d97..de26e0a600 100644 --- a/core/assets/bundles/bundle_hu.properties +++ b/core/assets/bundles/bundle_hu.properties @@ -1025,7 +1025,7 @@ sector.crateredBattleground.description = Víz gyűlt össze ebben a kráterben, sector.ruinousShores.description = A pusztaság mögött a partvonal húzódik. Valaha ezen a helyen egy partvédelmi rendszer állt. Nem sok minden maradt belőle. Csak a legalapvetőbb védelmi szerkezetek maradtak érintetlenül, minden más csak törmelék lett.\nFolytasd a terjeszkedést. Fedezd fel újra a technológiát. sector.stainedMountains.description = Mélyebben a szárazföldön fekszenek a hegyek, a spóráktól még érintetlenül.\nTermeld ki a bőséges titán készleteket a körzetben. Tanuld meg felhasználni.\n\nAz ellenség itt nagyobb létszámban van jelen. Ne hagyj nekik időt, hogy a legerősebb egységeiket hadba állíthassák. sector.overgrowth.description = Ez a terület közelebb esik a spórák forrásához, a spórák már kinőtték.\nAz ellenség egy helyőrséget létesített itt. Építs Mace egységeket. Pusztítsd el a bázist. -sector.tarFields.description = Egy olajtermelő övezet peremvidéke a hegyek és a sivatag határán. Egy azon kevés szektorok közül, ahol még hasznosítható kátránykészletek találhatók.\nBár a terület elhagyatott, veszélyes ellenséges erők fészkelnek a közelben. Ne becsüld alá őket.\n\n[lightgray]Fedezd fel az olajfeldolgozási lehetőségeket, ha tudod. +sector.tarFields.description = Egy olajtermelő övezet peremvidéke a hegyek és a sivatag határán. Azon kevés szektorok egyike, ahol még hasznosítható kátránykészletek találhatók.\nBár a terület elhagyatott, veszélyes ellenséges erők fészkelnek a közelben. Ne becsüld alá őket.\n\n[lightgray]Fedezd fel az olajfeldolgozási lehetőségeket, ha tudod. sector.desolateRift.description = Ez egy rendkívül veszélyes zóna. Bár nyersanyagokban gazdag, kevés hely áll rendelkezésre. Magas a kockázat. Építs szárazföldi és légvédelmet, amint csak tudsz. Ne tévesszen meg a hosszú szünet az ellenség támadásai között. sector.nuclearComplex.description = Egy néhai tóriumkitermelő és feldolgozó létesítmény, romokban.\n[lightgray]Fedezd fel a tóriumot és a sokrétű felhasználását.\n\nAz ellenség nagy létszámban van jelen, és folyamatosan megfigyelés alatt tartják a környéket. sector.fungalPass.description = Átmeneti terület a magas hegyek és a mélyebben fekvő, spórák uralta lapály között. Egy kisebb ellenséges megfigyelő állomás található itt.\nSemmisítsd meg.\nHasználj Dagger egységeket. Pusztítsd el a támaszpontot. @@ -1305,7 +1305,7 @@ bar.cargounitcap = Az egység raktere megtelt bar.drillspeed = Termelés: {0}/mp bar.pumpspeed = Termelés: {0}/mp bar.efficiency = Hatásfok: {0}% -bar.yield = Hozam: +{0}% +bar.yield = Hozam: {0}% bar.boost = Erősítés: +{0}% bar.powerbuffer = Akkumulátorok: {0}/{1} bar.powerbalance = Áram: {0}/mp @@ -3397,14 +3397,14 @@ logicrule.label.wavetimer = hullámidőzítő? logicrule.label.waves = hullámok logicrule.label.wave = hullám logicrule.label.wavespacing = hullámok közötti idő -logicrule.label.wavesending = hullámok véget érnek? +logicrule.label.wavesending = hullámok küldése? logicrule.label.attackmode = támadó mód? logicrule.label.enemycorebuildradius = ellenséges támaszpont építési sugara logicrule.label.dropzoneradius = ledobási zóna sugara logicrule.label.unitcap = egységkorlát logicrule.label.maparea = térkép területe logicrule.label.lighting = világítás? -logicrule.label.cangameover = lehetséges játék vége +logicrule.label.cangameover = befejeződhet a játék logicrule.label.ambientlight = környezeti fény logicrule.label.unitlight = egység fénye logicrule.label.solarmultiplier = napelemszorzó diff --git a/core/assets/bundles/bundle_id_ID.properties b/core/assets/bundles/bundle_id_ID.properties index 843aa0138b..0a73d83b7f 100644 --- a/core/assets/bundles/bundle_id_ID.properties +++ b/core/assets/bundles/bundle_id_ID.properties @@ -888,7 +888,7 @@ bannedunits.whitelist = Unit yang Dilarang Sebagai Whitelist bannedblocks.whitelist = Blok yang Dilarang Sebagai Whitelist addall = Tambah Semua launch.from = Meluncurkan Dari: [accent]{0} -launch.capacity = Kapasitas item yang Diluncurkan: [accent]{0} +launch.capacity = Kapasitas Item yang Diluncurkan: [accent]{0} launch.destination = Destinasi: {0} landing.sources = Total Sumber Sektor: [accent]{0}[] landing.import = Total Impor Maksimum: {0}[accent]{1}[lightgray]/mnt @@ -1080,7 +1080,7 @@ sector.caldera-erekir.description = Sumber daya yang terdeteksi di sektor ini te sector.stronghold.description = Markas musuh yang besar di sektor ini menjaga simpanan [accent]torium[] dalam jumlah besar.\nGunakan itu untuk mengembangkan unit dan menara ke tingkat yang lebih tinggi. sector.crevice.description = Musuh akan mengirimkan pasukan serangan yang hebat untuk menghancurkan markasmu di sektor ini.\nKembangkan [accent]karbida[] dan [accent]Generator Pirolisis[] mungkin imperatif untuk bertahan hidup. sector.siege.description = Sektor ini memiliki dua ngarai paralel yang akan memaksa serangan dari dua arah.\nRiset [accent]sianogen[] untuk mendapatkan kemampuan untuk memproduksi unit tank yang lebih kuat.\nPeringatan: Rudal jarak jauh milik musuh telah terdeteksi. Rudal tersebut mungkin ditembak jatuh sebelum terjadi benturan. -sector.crossroads.description = Markas musuh di sektor ini telah didirikan di berbagai medan. Riset unit yang berbeda untuk beradaptasi.\nSelain itu, beberapa markas telah dilindungi oleh perisai. Cari tahu bagaimana mereka diberi daya. +sector.crossroads.description = Markas musuh di sektor ini telah didirikan di berbagai medan. Riset unit yang berbeda untuk beradaptasi.\nSelain itu, beberapa markas telah dilindungi oleh perisai. Cari tahu bagaimana mereka diberi tenaga. sector.karst.description = Sektor ini kaya akan sumber daya, namun akan diserang oleh musuh begitu inti baru mendarat.\nManfaatkan sumber daya dan riset [accent]fabrik phase[]. sector.origin.description = Sektor terakhir dengan kehadiran musuh yang signifikan.\nTidak ada peluang riset yang tersisa - fokus menghancurkan semua inti musuh. @@ -1305,7 +1305,7 @@ bar.cargounitcap = Kapasitas Unit Kargo Telah Mencapai Batas bar.drillspeed = Kecepatan Bor: {0}/d bar.pumpspeed = Kecepatan Pompa: {0}/d bar.efficiency = Efisiensi: {0}% -bar.yield = Hasil: +{0}% +bar.yield = Hasil: {0}% bar.boost = Pendorongan: +{0}% bar.powerbuffer = Tenaga Baterai: {0}/{1} bar.powerbalance = Tenaga: {0}/d @@ -1453,7 +1453,7 @@ setting.autotarget.name = Bidik Musuh Secara Otomatis setting.autotarget.description = Ketika diaktifkan, unit Anda akan secara otomatis membidik dan menembaki musuh di sekitar. setting.keyboard.name = Kontrol Tetikus+Papan Ketik setting.fpscap.name = Batas FPS -setting.fpscap.description = Mengatur jumlah maksimum bingkai per detik (FPS) saat permainan berjalan.\nNilai yang lebih tinggi dapat meningkatkan konsumsi daya baterai. +setting.fpscap.description = Mengatur jumlah maksimum bingkai per detik (FPS) saat permainan berjalan.\nNilai yang lebih tinggi dapat meningkatkan konsumsi baterai. setting.fpscap.none = Tidak Ada setting.fpscap.text = {0} FPS setting.uiscale.name = Skala UI @@ -2459,7 +2459,7 @@ onset.defenses = [accent]Siapkan pertahanan:[lightgray] {0} onset.attack = Musuh dalam keadaan rentan diserang. Lancarkan serangan balasan. onset.cores = Inti baru dapat ditempatkan di [accent]ubin inti[].\nInti baru berfungsi sebagai pangkalan depan dan berbagi sumber daya dengan inti lainnya.\nTempatkan sebuah :core-bastion: inti. onset.detect = Musuh akan dapat mendeteksi Anda dalam 2 menit.\nSiapkan pertahanan, penambangan, dan produksi. -onset.commandmode = Tahan [accent]shift[] untuk masuk ke[accent]mode perintah[].\n[accent]Klik kiri dan seret[] untuk memilih unit.\n[accent]Klik kanan[] untuk memerintahkan unit yang dipilih untuk bergerak atau menyerang. +onset.commandmode = Tahan [accent]shift[] untuk masuk ke [accent]mode perintah[].\n[accent]Klik kiri dan seret[] untuk memilih unit.\n[accent]Klik kanan[] untuk memerintahkan unit yang dipilih untuk bergerak atau menyerang. onset.commandmode.mobile = Tekan tombol [accent]perintah[] untuk masuk ke [accent]mode perintah[].\nTekan dan tahan jari Anda, lalu [accent]seret[] untuk memilih unit.\n[accent]Ketuk[] untuk memerintahkan unit yang dipilih untuk bergerak atau menyerang. aegis.tungsten = Tungsten dapat ditambang menggunakan [accent]bor tumbukan[].\nBangunan ini memerlukan [accent]air[] dan [accent]tenaga[]. @@ -2692,7 +2692,7 @@ block.smite.description = Menembakan semburan peluru yang menusuk dan menyambar. block.malign.description = Menembakkan rentetan muatan laser pelacak ke arah musuh. Memerlukan pemanasan ekstensif. block.silicon-arc-furnace.description = Memurnikan silikon dari pasir dan grafit. block.oxidation-chamber.description = Mengubah berilium dan ozon menjadi oksida. Memancarkan panas sebagai produk sampingan. -block.electric-heater.description = Pemanas yang menghadap ke arah blok. Memerlukan daya yang besar. +block.electric-heater.description = Pemanas yang menghadap ke arah blok. Memerlukan tenaga yang besar. block.slag-heater.description = Pemanas yang menghadap ke arah blok. Memerlukan lava. block.phase-heater.description = Pemanas yang menghadap ke arah blok. Memerlukan fabrik phase. block.heat-redirector.description = Mengalihkan akumulasi panas ke blok lain. @@ -2706,7 +2706,7 @@ block.carbide-crucible.description = Memadukan grafit dan tungsten menjadi karbi block.cyanogen-synthesizer.description = Mensintesis sianogen dari arkisit dan grafit. Memerlukan panas. block.slag-incinerator.description = Membakar benda atau cairan yang tidak mudah menguap. Memerlukan lava. block.vent-condenser.description = Mengondensasi gas ventilasi menjadi air. Memerlukan tenaga. -block.plasma-bore.description = Saat ditempatkan menghadap dinding bijih, mengeluarkan bahan tanpa batas. Memerlukan daya dalam jumlah kecil. +block.plasma-bore.description = Saat ditempatkan menghadap dinding bijih, mengeluarkan bahan tanpa batas. Memerlukan tenaga dalam jumlah kecil. block.large-plasma-bore.description = Bor plasma yang lebih besar. Mampu menambang tungsten dan torium. Memerlukan hidrogen dan tenaga. block.cliff-crusher.description = Menghancurkan dinding, mengeluarkan pasir tanpa batas. Memerlukan tenaga. Efisiensi bervariasi berdasarkan jenis dinding. block.large-cliff-crusher.description = Menghancurkan dinding, mengeluarkan pasir tanpa batas. Memerlukan tenaga dan hidrogen. Efisiensi bervariasi berdasarkan jenis dinding. Dapat menggunakan grafit untuk meningkatkan efisiensi. @@ -2747,7 +2747,7 @@ block.turbine-condenser.description = Menghasilkan tenaga ketika ditempatkan pad block.chemical-combustion-chamber.description = Menghasilkan tenaga dari arkisit dan ozon. block.pyrolysis-generator.description = Menghasilkan tenaga dalam jumlah besar dari arkisit dan lava. Memproduksi air sebagai produk sampingan. block.flux-reactor.description = Menghasilkan tenaga dalam jumlah besar ketika dipanaskan. Memerlukan sianogen sebagai penstabil. Tenaga yang dihasilkan dan kebutuhan sianogen sebanding dengan panas yang masuk.\nMeledak jika sianogen yang disediakan tidak mencukupi. -block.neoplasia-reactor.description = Menggunakan arkisit, air, dan fabrik phase untuk menghasilkan daya dalam jumlah besar. Menghasilkan panas dan neoplasma yang berbahaya sebagai produk sampingan.\nMeledak jika neoplasma tidak dikeluarkan dari reaktor melalui saluran. +block.neoplasia-reactor.description = Menggunakan arkisit, air, dan fabrik phase untuk menghasilkan tenaga dalam jumlah besar. Menghasilkan panas dan neoplasma yang berbahaya sebagai produk sampingan.\nMeledak jika neoplasma tidak dikeluarkan dari reaktor melalui saluran. block.build-tower.description = Secara otomatis membangun kembali bangunan dalam jangkauan dan membantu unit lain dalam konstruksi. block.regen-projector.description = Perlahan memperbaiki bangunan sekutu di perimeter persegi. Memerlukan hidrogen. Dapat menggunakan fabrik phase untuk meningkatkan efisiensi. block.reinforced-container.description = Menyimpan sejumlah kecil item. Isi kontainer dapat dibongkar melalui pembongkar muatan. Tidak dapat meningkatkan kapasitas penyimpanan inti. @@ -2951,63 +2951,63 @@ laccess.displayheight = Tinggi blok tampilan logika dalam piksel. laccess.buffersize = Untuk pesan: Panjang dari isi pesan.\nUntuk tampilan: Jumlah dari perintah grafis mentah. laccess.operations = Jumlah operasi yang dilakukan pada blok.\nUntuk tampilan, mengembalikan jumlah dari operasi drawflush. laccess.maxunits = Jumlah unit maksimum yang dapat dimiliki sebuah tim.\nHanya dapat dideteksi dari inti. -laccess.totalitems = Total number of items contained. -laccess.firstitem = First item contained, or null if empty. -laccess.totalliquids = Total amount of liquid contained. -laccess.totalpower = For blocks with a buffered power store, the amount of power stored; for other blocks, buffer fullness from 0 to 1. -laccess.itemcapacity = Maximum number of items this building can hold. -laccess.liquidcapacity = Maximum amount of liquid this building can hold. -laccess.powercapacity = Maximum amount of power this building can store. -laccess.powernetstored = Total power stored in the connected power grid. -laccess.powernetcapacity = Total power storage capacity of the connected power grid. -laccess.powernetin = Power entering the connected power grid, per second. -laccess.powernetout = Power leaving the connected power grid, per second. -laccess.ammo = Current ammo count of a turret. -laccess.ammocapacity = Maximum ammo count of a turret. -laccess.health = Current health.\nFor bullets, their damage. -laccess.maxhealth = Maximum health.\nFor bullets, the base damage. -laccess.heat = Current heat of a turret that consumes heat, 0 to 1. -laccess.shield = Current shield amount of a unit. -laccess.armor = Armor value; flat damage reduction per hit. -laccess.efficiency = Operating efficiency of a building, where 1 is nominal. -laccess.timescale = Time scale multiplier affecting a building, where 1 is normal speed. -laccess.rotation = Facing angle of a unit or turret, in degrees.\nFor most other buildings, the 0 to 3 orientation. -laccess.x = X position, in tiles. -laccess.y = Y position, in tiles. -laccess.velocityx = X velocity of a unit, in tiles/sec. -laccess.velocityy = Y velocity of a unit, in tiles/sec. -laccess.shootx = X coordinate a unit or turret is aiming at. -laccess.shooty = Y coordinate a unit or turret is aiming at. -laccess.camerax = X position of the controlling player's camera. -laccess.cameray = Y position of the controlling player's camera. -laccess.camerawidth = Width of the controlling player's view, in tiles. -laccess.cameraheight = Height of the controlling player's view, in tiles. -laccess.solid = Whether this building blocks movement. -laccess.range = Range of a unit or turret, in tiles. -laccess.shooting = Whether a unit or turret is currently shooting. -laccess.boosting = Whether a unit is currently boosting or flying over terrain. -laccess.minex = X tile coordinate a unit is mining, or -1 if not mining. -laccess.miney = Y tile coordinate a unit is mining, or -1 if not mining. -laccess.mining = Whether a unit is currently mining. -laccess.buildx = X tile coordinate a unit is building at, or -1 if not building. -laccess.buildy = Y tile coordinate a unit is building at, or -1 if not building. -laccess.pingx = X coordinate a player is pinging, or null if not pinging. -laccess.pingy = Y coordinate a player is pinging, or null if not pinging. -laccess.pingtext = Text of a player's current ping, or null if not pinging. -laccess.building = Building a unit is currently constructing, or null. -laccess.breaking = Building a unit is currently deconstructing, or null. -laccess.team = Team ID of a unit or building. -laccess.flag = Numeric flag value stored on a unit. -laccess.flying = Whether a unit is currently airborne. -laccess.name = Name of the player controlling this unit, or null. -laccess.payloadcount = Number of payloads currently held. -laccess.payloadtype = Type of the last payload picked up, or null. -laccess.totalpayload = Combined size of all held payloads. -laccess.payloadcapacity = Maximum combined payload size a unit or building can carry. -laccess.selectedblock = Block currently selected by the controlling player, or null. -laccess.selectedrotation = Build rotation currently selected by the controlling player, 0 to 3. -laccess.bulletlifetime = Total lifetime of a bullet, in ticks. -laccess.bullettime = Time a bullet has existed, in ticks. +laccess.totalitems = Jumlah total item yang tersimpan. +laccess.firstitem = Item pertama yang dimuat, atau null jika kosong. +laccess.totalliquids = Jumlah total cairan yang tersimpan. +laccess.totalpower = Untuk blok dengan penyimpanan tenaga berpenyangga (dioda), jumlah tenaga yang tersimpan; untuk blok lainnya, tingkat keterisian penyangga dari 0 hingga 1. +laccess.itemcapacity = Jumlah maksimum item yang dapat disimpan oleh bangunan ini. +laccess.liquidcapacity = Jumlah maksimum cairan yang dapat disimpan oleh bangunan ini. +laccess.powercapacity = Jumlah tenaga maksimum yang dapat disimpan oleh bangunan ini. +laccess.powernetstored = Total Tenaga yang tersimpan dalam jaringan listrik yang terhubung. +laccess.powernetcapacity = Total kapasitas penyimpanan tenaga dari jaringan listrik yang terhubung. +laccess.powernetin = Tenaga yang masuk ke jaringan listrik yang terhubung, per detik. +laccess.powernetout = Tenaga yang keluar dari jaringan listrik yang terhubung, per detik. +laccess.ammo = Jumlah amunisi menara saat ini. +laccess.ammocapacity = Jumlah amunisi maksimum menara. +laccess.health = Nyawa saat ini.\nUntuk peluru, besaran damage-nya. +laccess.maxhealth = Nyawa maksimum.\nUntuk peluru, damage dasar. +laccess.heat = Unit panas saat ini dari menara yang mengonsumsi unit panas, 0 hingga 1. +laccess.shield = Jumlah perisai yang dimiliki oleh unit saat ini. +laccess.armor = Nilai armor; pengurangan damage tetap per serangan. +laccess.efficiency = Efisiensi operasional bangunan, dengan nilai nominal 1. +laccess.timescale = Pengali skala waktu yang memengaruhi bangunan, dengan nilai 1 berarti kecepatan normal. +laccess.rotation = Sudut hadap unit atau turret, dalam derajat.\nUntuk sebagian besar bangunan lainnya, orientasi berkisar antara 0 hingga 3. +laccess.x = Posisi X, dalam satuan ubin. +laccess.y = Posisi Y, dalam satuan ubin. +laccess.velocityx = Kecepatan X suatu unit, dalam satuan ubin/detik. +laccess.velocityy = Kecepatan Y suatu unit, dalam satuan ubin/detik. +laccess.shootx = Koordinat X yang dituju oleh unit atau turret. +laccess.shooty = Koordinat Y yang dituju oleh unit atau turret. +laccess.camerax = Posisi X kamera pemain yang memegang kendali. +laccess.cameray = Posisi Y kamera pemain yang memegang kendali. +laccess.camerawidth = Lebar pandangan pemain yang memegang kendali, dalam satuan ubin. +laccess.cameraheight = Tinggi pandangan pemain yang memegang kendali, dalam satuan ubin. +laccess.solid = Apakah bangunan ini menghalangi pergerakan. +laccess.range = Jangkauan unit atau turret, dalam satuan ubin. +laccess.shooting = Apakah unit atau turret sedang menembak. +laccess.boosting = Apakah unit saat ini sedang mengaktifkan pendorong atau terbang melintasi medan. +laccess.minex = Koordinat ubin X tempat unit sedang menambang, atau -1 jika tidak sedang menambang. +laccess.miney = Koordinat ubin Y tempat unit sedang menambang, atau -1 jika tidak sedang menambang. +laccess.mining = Apakah suatu unit sedang menambang. +laccess.buildx = Koordinat ubin X tempat unit sedang membangun, atau -1 jika tidak sedang membangun. +laccess.buildy = Koordinat ubin Y tempat unit sedang membangun, atau -1 jika tidak sedang membangun. +laccess.pingx = Koordinat X yang sedang ditandai oleh pemain, atau null jika tidak sedang menandai. +laccess.pingy = Koordinat Y yang sedang ditandai oleh pemain, atau null jika tidak sedang menandai. +laccess.pingtext = Teks yang menunjukkan ping pemain saat ini, atau null jika tidak sedang melakukan ping. +laccess.building = Unit yang sedang membangun saat ini, atau null. +laccess.breaking = Unit yang sedang mendekonstruksi saat ini, atau null. +laccess.team = ID Tim dari unit atau bangunan. +laccess.flag = Nilai flag numerik yang disimpan pada unit. +laccess.flying = Apakah suatu unit saat ini sedang berada di udara. +laccess.name = Nama pemain yang mengendalikan unit ini, atau null. +laccess.payloadcount = Jumlah muatan yang saat ini dimiliki. +laccess.payloadtype = Jenis muatan terakhir yang diambil, atau null. +laccess.totalpayload = Ukuran gabungan dari semua muatan yang disimpan. +laccess.payloadcapacity = Ukuran muatan gabungan maksimum yang dapat dibawa oleh unit atau bangunan. +laccess.selectedblock = Blok yang saat ini dipilih oleh pemain yang memegang kendali, atau null. +laccess.selectedrotation = Rotasi bangunan yang saat ini dipilih oleh pemain yang memegang kendali, 0 hingga 3. +laccess.bulletlifetime = Total masa hidup peluru, dalam satuan tick. +laccess.bullettime = Durasi peluru aktif, dalam satuan tick. lcategory.unknown = Tak Diketahui lcategory.unknown.description = Instruksi tanpa kategori. @@ -3288,7 +3288,7 @@ graphicstype.label.reset = atur ulang laccess.label.totalitems = total item laccess.label.firstitem = item pertama laccess.label.totalliquids = total cairan -laccess.label.totalpower = total daya +laccess.label.totalpower = total tenaga laccess.label.itemcapacity = kapasitas item laccess.label.liquidcapacity = kapasitas cairan laccess.label.powercapacity = kapasitas tenaga @@ -3357,7 +3357,7 @@ laccess.label.selectedblock = blok terpilih laccess.label.selectedrotation = rotasi terpilih laccess.label.bulletlifetime = masa aktif peluru laccess.label.bullettime = waktu peluru -laccess.label.enabled = diaktifkan +laccess.label.enabled = aktifkan laccess.label.shoot = tembak laccess.label.shootp = prediksi tembak laccess.label.config = konfig @@ -3462,7 +3462,7 @@ radartarget.label.player = pemain radartarget.label.attacker = penyerang radartarget.label.flying = terbang radartarget.label.ground = darat -radartarget.label.boss = boss +radartarget.label.boss = penjaga tilelayer.label.floor = lantai tilelayer.label.ore = bijih tilelayer.label.block = blok diff --git a/core/assets/bundles/bundle_ru.properties b/core/assets/bundles/bundle_ru.properties index 637a61b0ae..e00ba18630 100644 --- a/core/assets/bundles/bundle_ru.properties +++ b/core/assets/bundles/bundle_ru.properties @@ -1305,7 +1305,7 @@ bar.cargounitcap = Достигнут предел грузовой единиц bar.drillspeed = Скорость бурения: {0}/с bar.pumpspeed = Скорость выкачивания: {0}/с bar.efficiency = Эффективность: {0}% -bar.yield = Получение: +{0}% +bar.yield = Получение: {0}% bar.boost = Ускорение: +{0}% bar.powerbuffer = Энергия в аккумуляторах: {0}/{1} bar.powerbalance = Энергия: {0}/с @@ -2951,63 +2951,63 @@ laccess.displayheight = Высота дисплея, в пикселях. laccess.buffersize = Количество необработанных команд в графическом буфере дисплея. laccess.operations = Количество операций, выполненных в блоке.\nДля дисплеев, возвращает количество выполненных операций Вывод рисования/drawflush. laccess.maxunits = Максимальное количество единиц, которое может быть у команды.\nОпределяется с помощью ядер. -laccess.totalitems = Total number of items contained. -laccess.firstitem = First item contained, or null if empty. -laccess.totalliquids = Total amount of liquid contained. -laccess.totalpower = For blocks with a buffered power store, the amount of power stored; for other blocks, buffer fullness from 0 to 1. -laccess.itemcapacity = Maximum number of items this building can hold. -laccess.liquidcapacity = Maximum amount of liquid this building can hold. -laccess.powercapacity = Maximum amount of power this building can store. -laccess.powernetstored = Total power stored in the connected power grid. -laccess.powernetcapacity = Total power storage capacity of the connected power grid. -laccess.powernetin = Power entering the connected power grid, per second. -laccess.powernetout = Power leaving the connected power grid, per second. -laccess.ammo = Current ammo count of a turret. -laccess.ammocapacity = Maximum ammo count of a turret. -laccess.health = Current health.\nFor bullets, their damage. -laccess.maxhealth = Maximum health.\nFor bullets, the base damage. -laccess.heat = Current heat of a turret that consumes heat, 0 to 1. -laccess.shield = Current shield amount of a unit. -laccess.armor = Armor value; flat damage reduction per hit. -laccess.efficiency = Operating efficiency of a building, where 1 is nominal. -laccess.timescale = Time scale multiplier affecting a building, where 1 is normal speed. -laccess.rotation = Facing angle of a unit or turret, in degrees.\nFor most other buildings, the 0 to 3 orientation. -laccess.x = X position, in tiles. -laccess.y = Y position, in tiles. -laccess.velocityx = X velocity of a unit, in tiles/sec. -laccess.velocityy = Y velocity of a unit, in tiles/sec. -laccess.shootx = X coordinate a unit or turret is aiming at. -laccess.shooty = Y coordinate a unit or turret is aiming at. -laccess.camerax = X position of the controlling player's camera. -laccess.cameray = Y position of the controlling player's camera. -laccess.camerawidth = Width of the controlling player's view, in tiles. -laccess.cameraheight = Height of the controlling player's view, in tiles. -laccess.solid = Whether this building blocks movement. -laccess.range = Range of a unit or turret, in tiles. -laccess.shooting = Whether a unit or turret is currently shooting. -laccess.boosting = Whether a unit is currently boosting or flying over terrain. -laccess.minex = X tile coordinate a unit is mining, or -1 if not mining. -laccess.miney = Y tile coordinate a unit is mining, or -1 if not mining. -laccess.mining = Whether a unit is currently mining. -laccess.buildx = X tile coordinate a unit is building at, or -1 if not building. -laccess.buildy = Y tile coordinate a unit is building at, or -1 if not building. -laccess.pingx = X coordinate a player is pinging, or null if not pinging. -laccess.pingy = Y coordinate a player is pinging, or null if not pinging. -laccess.pingtext = Text of a player's current ping, or null if not pinging. -laccess.building = Building a unit is currently constructing, or null. -laccess.breaking = Building a unit is currently deconstructing, or null. -laccess.team = Team ID of a unit or building. -laccess.flag = Numeric flag value stored on a unit. -laccess.flying = Whether a unit is currently airborne. -laccess.name = Name of the player controlling this unit, or null. -laccess.payloadcount = Number of payloads currently held. -laccess.payloadtype = Type of the last payload picked up, or null. -laccess.totalpayload = Combined size of all held payloads. -laccess.payloadcapacity = Maximum combined payload size a unit or building can carry. -laccess.selectedblock = Block currently selected by the controlling player, or null. -laccess.selectedrotation = Build rotation currently selected by the controlling player, 0 to 3. -laccess.bulletlifetime = Total lifetime of a bullet, in ticks. -laccess.bullettime = Time a bullet has existed, in ticks. +laccess.totalitems = Общее количество хранимых предметов. +laccess.firstitem = Первый хранимый предмет. Если пусто - возвращает null. +laccess.totalliquids = Общее количество хранимой жидкости. +laccess.totalpower = Для блоков, хранящих энергию, возвращает её количество; для остальных блоков, их уровень энергии от 0 до 1. +laccess.itemcapacity = Максимальное количество предметов, хранимых этой постройкой. +laccess.liquidcapacity = Максимальное количество жидкости, хранимой этой постройкой. +laccess.powercapacity = Максимальное количество энергии, хранимой этой постройкой. +laccess.powernetstored = Общее количество энергии, хранимой в сети. +laccess.powernetcapacity = Максимальное количество энергии, хранимой в сети. +laccess.powernetin = Энергия, входящая в сеть за секунду. +laccess.powernetout = Энергия, выходящая из сети за секунду. +laccess.ammo = Текущее количество боеприпасов в турели. +laccess.ammocapacity = Максимальное количество боеприпасов в турели. +laccess.health = Текущее здоровье.\nДля пуль возвращает их урон. +laccess.maxhealth = Максимальное здоровье.\nДля пуль возвращает их базовый урон. +laccess.heat = Текущий нагрев турели, от 0 до 1. +laccess.shield = Общее количество щита у юнита. +laccess.armor = Значение брони; на сколько снизится получаемый урон за удар. +laccess.efficiency = Эффективность работы постройки. 1 - обычная эффективность. +laccess.timescale = Множитель скорости, применённый на эту постройку. 1 - обычная скорость. +laccess.rotation = Угол направления юнита или турели в градусах.\nДля большинства других построек возвращает 0-3 в зависимости от их направления. +laccess.x = Позиция X блока/юнита в блоках. +laccess.y = Позиция Y блока/юнита в блоках. +laccess.velocityx = Скорость юнита по X в блоках/сек. +laccess.velocityy = Скорость юнита по Y в блоках/сек. +laccess.shootx = Позиция X, в которую нацелен юнит или турель. +laccess.shooty = Позиция Y, в которую нацелен юнит или турель. +laccess.camerax = Позиция X камеры управляющего игрока. +laccess.cameray = Позиция Y камеры управляющего игрока. +laccess.camerawidth = Ширина камеры управляющего игрока в блоках. +laccess.cameraheight = Высота камеры управляющего игрока в блоках. +laccess.solid = Блокирует ли этот блок движение. +laccess.range = Радиус юнита или турели в блоках. +laccess.shooting = Стреляет ли юнит/турель в данный момент. +laccess.boosting = Летает ли этот наземный юнит. +laccess.minex = Позиция X руды, которую сейчас добывает юнит, или -1, если не добывает. +laccess.miney = Позиция Y руды, которую сейчас добывает юнит, или -1, если не добывает. +laccess.mining = Добывает ли юнит руду. +laccess.buildx = Позиция X, на которой сейчас строит юнит, или -1, если не строит. +laccess.buildy = Позиция Y, на которой сейчас строит юнит, или -1, если не строит. +laccess.pingx = Позиция X отметки, поставленной игроком, или null, если отметки нет. +laccess.pingy = Позиция Y отметки, поставленной игроком, или null, если отметки нет. +laccess.pingtext = Текст отметки, поставленной игроком, или null, если отметки нет. +laccess.building = Блок, который сейчас строится юнитом, или null. +laccess.breaking = Блок, который сейчас разбирается юнитом, или null. +laccess.team = ID команды юнита/блока. +laccess.flag = Числовой флаг, назначенный юниту. +laccess.flying = Летает ли этот юнит. +laccess.name = Имя управляющего игрока, или null. +laccess.payloadcount = Количество перевозимых грузов. +laccess.payloadtype = Тип последнего подобранного груза, или null. +laccess.totalpayload = Суммарный размер всех перевозимых грузов. +laccess.payloadcapacity = Максимальный суммарный размер всех перевозимых грузов юнита. +laccess.selectedblock = Блок, выбранный управляющим игроком, или null. +laccess.selectedrotation = Вращение блока, выбранного управляющим игроком, от 0 до 3. +laccess.bulletlifetime = Максимальное время жизни пули в тиках. +laccess.bullettime = Время существования пули в тиках. lcategory.unknown = Неизвестно lcategory.unknown.description = Нет категории. @@ -3502,9 +3502,9 @@ name.token.global = глобальный name.token.target = цель name.token.and = и name.token.or = или -name.token.b-and = бит-и -name.token.xor = ис-или -name.token.flip = бит-не +name.token.b-and = b-and +name.token.xor = xor +name.token.flip = flip name.token.order = порядок name.token.sort = сортировка name.token.output = выход @@ -3515,8 +3515,8 @@ name.token.find = найти name.token.group = группа name.token.enemy = враг? name.token.ore = руда -name.token.outX = X -name.token.outY = Y +name.token.outX = X цели +name.token.outY = Y цели name.token.owner = владелец name.token.found = найден? name.token.building = постройка @@ -3538,7 +3538,7 @@ name.token.natural = естественная name.token.speed = скорость name.token.level = уровень name.token.duration = длительность -name.token.seconds = seconds +name.token.seconds = секунд name.token.shown = отображается name.token.data = данные name.token.effect = эффект @@ -3605,7 +3605,7 @@ name.token.blockFall = падение блока name.token.placeBlock = размещение блока name.token.placeBlockSpark = размещение блока (искры) name.token.breakBlock = разрушение блока -name.token.-spawn = = spawn +name.token.-spawn = = создать name.token.trail = след name.token.breakProp = разрушение валуна name.token.smokeCloud = облако дыма diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java index f2baaaaddb..37b4a9e811 100644 --- a/core/src/mindustry/ai/Pathfinder.java +++ b/core/src/mindustry/ai/Pathfinder.java @@ -8,7 +8,6 @@ import arc.struct.*; import arc.util.TaskQueue; import arc.util.*; import mindustry.annotations.Annotations.*; -import mindustry.content.*; import mindustry.core.*; import mindustry.game.EventType.*; import mindustry.game.*; @@ -263,7 +262,7 @@ public class Pathfinder implements Runnable{ tile.build == null || !solid || tile.block() instanceof CoreBlock ? 0 : Math.min((int)(tile.build.health / 40), 80), tid == 0 && tile.build != null && state.rules.coreCapture ? 255 : tid, //use teamid = 255 when core capture is enabled to mark out derelict structures solid, - tile.floor().isLiquid && tile.block() == Blocks.air, + tile.floor().isLiquid && !tile.block().solid, tile.legSolid(), nearLiquid, nearGround, diff --git a/core/src/mindustry/core/UI.java b/core/src/mindustry/core/UI.java index 381aa9703f..5b01645412 100644 --- a/core/src/mindustry/core/UI.java +++ b/core/src/mindustry/core/UI.java @@ -415,8 +415,9 @@ public class UI implements ApplicationListener, Loadable{ table.touchable = Touchable.disabled; table.setFillParent(true); if(cinfo.visible && !state.isMenu()) table.marginTop(cinfo.getPrefHeight() / Scl.scl() / 2); - table.update(() -> { + table.visible(() -> { if(state.isMenu()) table.remove(); + return ui.hudfrag.shown; }); table.actions(Actions.delay(duration * 0.9f), Actions.fadeOut(duration * 0.1f, Interp.fade), Actions.remove()); table.top().table(Styles.black3, t -> t.margin(4).add(info).style(Styles.outlineLabel)).padTop(10); @@ -438,11 +439,12 @@ public class UI implements ApplicationListener, Loadable{ } table.setFillParent(true); table.touchable = Touchable.disabled; - table.update(() -> { + table.visible(() -> { if(state.isMenu()){ table.remove(); if(id != null) popups.remove(id); } + return ui.hudfrag.shown; }); table.actions(Actions.delay(duration), Actions.remove(), Actions.run(() -> { if(id != null) popups.remove(id); })); table.align(align).table(Styles.black3, t -> t.margin(4).add(info).style(Styles.outlineLabel)).pad(top, left, bottom, right); diff --git a/core/src/mindustry/entities/Lightning.java b/core/src/mindustry/entities/Lightning.java index 43c18ca0ba..4554ce7dc9 100644 --- a/core/src/mindustry/entities/Lightning.java +++ b/core/src/mindustry/entities/Lightning.java @@ -84,7 +84,7 @@ public class Lightning{ Unit furthest = Geometry.findFurthest(x, y, entities); - if(furthest != null && furthest.dst(x, y) < length * 1.5f){ + if(furthest != null && furthest.within(x, y, hitRange * 2f)){ hit.add(furthest.id()); x = furthest.x(); y = furthest.y(); diff --git a/core/src/mindustry/entities/comp/TargetDummyComp.java b/core/src/mindustry/entities/comp/TargetDummyComp.java index 5167680d41..37748972d2 100644 --- a/core/src/mindustry/entities/comp/TargetDummyComp.java +++ b/core/src/mindustry/entities/comp/TargetDummyComp.java @@ -16,6 +16,7 @@ abstract class TargetDummyComp implements Unitc, Healthc{ } } + @Replace @Override public void rawDamage(float amount){ if(building instanceof TargetDummyBuild td){ diff --git a/core/src/mindustry/logic/LAssembler.java b/core/src/mindustry/logic/LAssembler.java index b5d7443639..c2c40ea97c 100644 --- a/core/src/mindustry/logic/LAssembler.java +++ b/core/src/mindustry/logic/LAssembler.java @@ -11,9 +11,6 @@ import mindustry.logic.LExecutor.*; public class LAssembler{ public static ObjectMap> customParsers = new ObjectMap<>(); - private static final long invalidNumNegative = Long.MIN_VALUE; - private static final long invalidNumPositive = Long.MAX_VALUE; - public boolean privileged; /** Maps names to variable. */ public OrderedMap vars = new OrderedMap<>(); @@ -110,23 +107,48 @@ public class LAssembler{ } double parseDouble(String symbol){ + //fail fast for obvious non-numbers + if(symbol.isEmpty() || !isNumStart(symbol.charAt(0))) return Double.NaN; + //parse hex/binary syntax - if(symbol.startsWith("0b")) return parseLong(false, symbol, 2, 2, symbol.length()); - if(symbol.startsWith("+0b")) return parseLong(false, symbol, 2, 3, symbol.length()); - if(symbol.startsWith("-0b")) return parseLong(true,symbol, 2, 3, symbol.length()); - if(symbol.startsWith("0x")) return parseLong(false,symbol, 16, 2, symbol.length()); - if(symbol.startsWith("+0x")) return parseLong(false,symbol, 16, 3, symbol.length()); - if(symbol.startsWith("-0x")) return parseLong(true,symbol, 16, 3, symbol.length()); + if(symbol.startsWith("0b")) return parseHexOrBin(false, symbol, true, 2); + if(symbol.startsWith("+0b")) return parseHexOrBin(false, symbol, true, 3); + if(symbol.startsWith("-0b")) return parseHexOrBin(true, symbol, true, 3); + if(symbol.startsWith("0x")) return parseHexOrBin(false, symbol, false, 2); + if(symbol.startsWith("+0x")) return parseHexOrBin(false, symbol, false, 3); + if(symbol.startsWith("-0x")) return parseHexOrBin(true, symbol, false, 3); if(symbol.startsWith("%[") && symbol.endsWith("]") && symbol.length() > 3) return parseNamedColor(symbol); if(symbol.startsWith("%") && (symbol.length() == 7 || symbol.length() == 9)) return parseColor(symbol); return Strings.parseDouble(symbol, Double.NaN); } - double parseLong(boolean negative, String s, int radix, int start, int end) { - long usedInvalidNum = negative ? invalidNumPositive : invalidNumNegative; - long l = Strings.parseLong(s, radix, start, end, usedInvalidNum); - return l == usedInvalidNum ? Double.NaN : negative ? -l : l; + boolean isNumStart(char c){ + //note that 'e10' isn't a valid number; '%ffffff' is. Hex numbers start with '0x'. + return c >= '0' && c <= '9' || c == '.' || c == '-' || c == '+' || c == '%'; + } + + //parses *unsigned* hex or bin number, including negative ones (0xffffffffffffffff as -1) + //detects overflow by input length and uses bit manipulation to avoid signed arithmetics + double parseHexOrBin(boolean negative, String s, boolean binary, int offset){ + int end = s.length(); + if(offset >= end) return Double.NaN; + + int pos = offset; + while(pos < end && s.charAt(pos) == '0') pos ++; //skip leading zeros to avoid incorrect overflow detection + + int shift = binary ? 1 : 4; + if(end - pos > 64 / shift) return Double.NaN; + + long acc = 0; + int radix = 1 << shift; + while(pos < end){ + int digit = Character.digit(s.charAt(pos), radix); + if(digit < 0) return Double.NaN; + acc = acc << shift | digit; + pos ++; + } + return negative ? -acc : acc; } double parseColor(String symbol){ @@ -178,4 +200,4 @@ public class LAssembler{ return vars.get(name); } -} \ No newline at end of file +} diff --git a/core/src/mindustry/logic/LStatements.java b/core/src/mindustry/logic/LStatements.java index 1491fa884c..575a6c9bc4 100644 --- a/core/src/mindustry/logic/LStatements.java +++ b/core/src/mindustry/logic/LStatements.java @@ -2541,7 +2541,7 @@ public class LStatements{ b.label(() -> bundle(type)); b.clicked(() -> showSelect(b, MapObjectives.allMarkerTypeNames.toArray(String.class), type, t -> { - type = bundle(t); + type = t; build(table); }, 2, cell -> cell.size(160, 50))); }, Styles.logict, () -> {}).size(180, 40).color(table.color).left().padLeft(2); diff --git a/core/src/mindustry/mod/DataPatcher.java b/core/src/mindustry/mod/DataPatcher.java index b3f6bc0536..599470f8e5 100644 --- a/core/src/mindustry/mod/DataPatcher.java +++ b/core/src/mindustry/mod/DataPatcher.java @@ -195,8 +195,8 @@ public class DataPatcher{ //register global variables for(var cont : all){ - if(!cont.hasErrored() && cont instanceof UnlockableContent u && Vars.logicVars.get("@" + u.name) == null){ - addedVars.add(Vars.logicVars.put("@" + u.name, u, false)); + if(!cont.hasErrored() && cont instanceof UnlockableContent u && Vars.logicVars.get("@" + (u instanceof StatusEffect ? "status-" : "") + u.name) == null){ + addedVars.add(Vars.logicVars.put("@" + (u instanceof StatusEffect ? "status-" : "") + u.name, u, false)); } } diff --git a/core/src/mindustry/mod/ModListing.java b/core/src/mindustry/mod/ModListing.java index 68d26ce95f..3ddff52b78 100644 --- a/core/src/mindustry/mod/ModListing.java +++ b/core/src/mindustry/mod/ModListing.java @@ -1,10 +1,16 @@ package mindustry.mod; +import arc.struct.*; +import arc.util.*; +import mindustry.ui.dialogs.*; + /** Mod listing as a data class. */ public class ModListing{ public String repo, name, internalName, author, lastUpdated, description, minGameVersion, version, iconHash = ""; public boolean hasScripts, hasJava, iosCompatible, legacyCompatible, hasIcon; - public String[] contentTypes = {}; + /** game build -> release ID + mod version */ + public @Nullable ArrayMap releases; + public String[] tags = {}; public int stars; @Override @@ -22,4 +28,30 @@ public class ModListing{ ", stars=" + stars + '}'; } + + /** @return the specific release that matches the current game version, or null if no specific match is found (i.e. /latest should be used) */ + public @Nullable ModRelease getMatchingRelease(){ + if(releases == null) return null; + for(var entry : releases){ + if(ModsDialog.matchesGameVersion(ModsDialog.parseVersion(entry.key))){ + return entry.value; + } + } + return null; + } + + public static class ModRelease{ + /** Github release ID ($API/releases/$ID) */ + public String id = ""; + /** Actual mod version string in release's mod.json */ + public String version = ""; + + @Override + public String toString(){ + return "ModRelease{" + + "id='" + id + '\'' + + ", version='" + version + '\'' + + '}'; + } + } } diff --git a/core/src/mindustry/ui/dialogs/EditorMapsDialog.java b/core/src/mindustry/ui/dialogs/EditorMapsDialog.java index b1ece85c3d..807b7a5d20 100644 --- a/core/src/mindustry/ui/dialogs/EditorMapsDialog.java +++ b/core/src/mindustry/ui/dialogs/EditorMapsDialog.java @@ -130,7 +130,7 @@ public class EditorMapsDialog extends MapListDialog{ if(!map.tags.get("description", "").isEmpty()){ t.add("@editor.description").padRight(10).color(Color.gray).top(); t.row(); - t.add(map.description()).growX().wrap().padTop(2); + t.add(map.description()).growX().wrap(true).padTop(2); } }).height(mapsize).width(mapsize); diff --git a/core/src/mindustry/ui/dialogs/ModBrowserDialog.java b/core/src/mindustry/ui/dialogs/ModBrowserDialog.java index 40caae2fe5..d61372755c 100644 --- a/core/src/mindustry/ui/dialogs/ModBrowserDialog.java +++ b/core/src/mindustry/ui/dialogs/ModBrowserDialog.java @@ -65,6 +65,11 @@ public class ModBrowserDialog extends BaseDialog{ shown(this::rebuildBrowser); } + public @Nullable ModListing getCachedMod(String repo){ + if(modList == null) return null; + return modList.find(m -> m.repo.equalsIgnoreCase(repo)); + } + public void getModList(Cons> listener){ //mods already fetched, use that if(modList != null){ @@ -247,7 +252,7 @@ public class ModBrowserDialog extends BaseDialog{ textureCache.put(repo, last = Core.atlas.find("nomap")); if(mod.hasIcon){ - Fi cacheFolder = Vars.mobile ? Core.files.cache("modIconCache"): dataDirectory.child("modIconCache"); + Fi cacheFolder = mobile ? Core.files.cache("modIconCache"): dataDirectory.child("modIconCache"); cacheFolder.mkdirs(); Fi cacheFile = cacheFolder.child(Strings.sanitizeFilename(mod.repo + "_" + mod.iconHash) + ".png"); @@ -337,7 +342,7 @@ public class ModBrowserDialog extends BaseDialog{ var found = mods.list().find(l -> mod.repo != null && mod.repo.equals(l.getRepo())); sel.buttons.button(found == null ? "@mods.browser.add" : "@mods.browser.reinstall", Icon.download, () -> { sel.hide(); - ui.mods.githubImportMod(mod.repo, mod.hasJava, null, true); + ui.mods.githubImportMod(mod); }); if(Core.graphics.isPortrait()){ diff --git a/core/src/mindustry/ui/dialogs/ModsDialog.java b/core/src/mindustry/ui/dialogs/ModsDialog.java index 9446c191de..5d2575de75 100644 --- a/core/src/mindustry/ui/dialogs/ModsDialog.java +++ b/core/src/mindustry/ui/dialogs/ModsDialog.java @@ -17,6 +17,7 @@ import arc.util.Http.*; import arc.util.io.*; import arc.util.serialization.*; import arc.util.serialization.Jval.*; +import mindustry.core.*; import mindustry.ctype.*; import mindustry.game.EventType.*; import mindustry.gen.*; @@ -26,10 +27,13 @@ import mindustry.mod.Mods.*; import mindustry.ui.*; import java.util.*; +import java.util.regex.*; import static mindustry.Vars.*; public class ModsDialog extends BaseDialog{ + private static final Pattern modVersionPattern = Pattern.compile("\\[[vb](\\d+)(?:\\.(\\d+))?\\]"); + public ModBrowserDialog browser; protected float modImportProgress; @@ -105,7 +109,11 @@ public class ModsDialog extends BaseDialog{ var mod = repoToMod.get(entry.repo); if(mod != null){ modToListing.put(mod, entry); - if(Strings.checkNewerSemver(entry.version, mod.meta.version)) withUpdates.add(mod); + var release = entry.getMatchingRelease(); + //Only compare to the release that fits the current version the client is using, if one exists; don't look for updates that don't match the version + if(Strings.checkNewerSemver(entry.version, release == null ? mod.meta.version : release.version)){ + withUpdates.add(mod); + } } } @@ -171,8 +179,15 @@ public class ModsDialog extends BaseDialog{ if(text.startsWith("https://github.com/")) text = text.substring("https://github.com/".length()); Core.settings.put("lastmod", text); - //there's no good way to know if it's a java mod here, so assume it's not - githubImportMod(text, false, null, true); + var listing = browser.getCachedMod(text); + if(listing != null){ + //auto-choose release when a listing is found + githubImportMod(listing); + }else{ + //this will auto-detect whether it's java, then grab latest release unconditionally + //TODO: would be nice to grab version-appropriate release but I don't want to copy-paste browser logic for this + githubImportMod(text, false, null, true); + } }); }).margin(12f); }); @@ -526,7 +541,7 @@ public class ModsDialog extends BaseDialog{ } } - public void viewReleases(String repo, boolean isJava, boolean reinstall) { + public void viewReleases(String repo, boolean isJava, boolean reinstall){ BaseDialog load = new BaseDialog(""); load.cont.add("[accent]" + Core.bundle.get("mods.browser.fetching")); load.show(); @@ -596,6 +611,11 @@ public class ModsDialog extends BaseDialog{ })); } + public void githubImportMod(ModListing mod){ + var matchingRelease = mod.getMatchingRelease(); + githubImportMod(mod.repo, mod.hasJava, matchingRelease == null ? null : matchingRelease.id, true); + } + public void githubImportMod(String repo, boolean isJava, boolean forceEnable){ githubImportMod(repo, isJava, null, forceEnable); } @@ -686,4 +706,52 @@ public class ModsDialog extends BaseDialog{ }, this::importFail); } } + + /** @return {major, minor} parsed from a leading/trailing "[v{major}]" or "[v{major}.{minor}]" tag, or null if none is found at either end (or the numbers are unparseable). */ + public static @Nullable int[] parseVersionTag(String str){ + if(str == null) return null; + + Matcher m = modVersionPattern.matcher(str); + while(m.find()){ + if(m.start() == 0 || m.end() == str.length()){ + int major = Strings.parseInt(m.group(1)); + //any major version below 15 is likely a major-version tag like [v7] and should be ignored + if(major == Integer.MIN_VALUE || major < 15) return null; + int minor = m.group(2) != null ? Strings.parseInt(m.group(2)) : 0; + if(minor == Integer.MIN_VALUE) return null; + return new int[]{major, minor}; + } + } + return null; + } + + public static @Nullable int[] parseVersion(String str){ + if(str == null || str.isEmpty()) return null; + + int dot = str.indexOf('.'); + String majorStr = dot == -1 ? str : str.substring(0, dot); + String minorStr = dot == -1 ? null : str.substring(dot + 1); + + if(majorStr.isEmpty() || (dot != -1 && (minorStr.isEmpty() || str.indexOf('.', dot + 1) != -1))) return null; + + int major = Strings.parseInt(majorStr); + if(major == Integer.MIN_VALUE) return null; + int minor = minorStr != null ? Strings.parseInt(minorStr) : 0; + if(minor == Integer.MIN_VALUE) return null; + + return new int[]{major, minor}; + } + + /** @return whether the specified release name and its tags match the current game build (e.g. "Bingus Mod [v160]" should only match build 160) */ + public static boolean matchesGameVersion(String releaseTitle){ + return matchesGameVersion(parseVersionTag(releaseTitle)); + } + + public static boolean matchesGameVersion(@Nullable int[] tag){ + //version not specified, matches anything. + if(tag == null) return true; + //must match exactly; custom builds (-1) do not match. + //for revisions, either match if the revision is unspecified (v160 -> matches ALL 160.x builds), OR, if it is specified, match the exact version (the mod author must have had a good reason for it) + return Version.build == tag[0] && (tag[1] == 0 || Version.revision == tag[1]); + } } diff --git a/core/src/mindustry/ui/fragments/PlayerListFragment.java b/core/src/mindustry/ui/fragments/PlayerListFragment.java index 65dbc91870..ce97fad416 100644 --- a/core/src/mindustry/ui/fragments/PlayerListFragment.java +++ b/core/src/mindustry/ui/fragments/PlayerListFragment.java @@ -235,8 +235,6 @@ public class PlayerListFragment{ dialog.cont.button("@back", Icon.left, dialog::hide).padTop(-1f).size(220f, 55f); dialog.show(); - - }).size(h); } }else if(!user.isLocal() && !user.admin && net.client() && Groups.player.size() >= 3 && player.team() == user.team()){ //votekick diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index d77871bdb2..de85946388 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -756,7 +756,7 @@ public class Block extends UnlockableContent implements Senseable{ } //nothing was added, so it's safe to add a dynamic liquid bar (probably?) - if(!added){ + if(!added && liquidCapacity > 0f){ addLiquidBar(build -> build.liquids.current()); } } diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java index 6d99b4e48a..7036ba204f 100644 --- a/core/src/mindustry/world/Build.java +++ b/core/src/mindustry/world/Build.java @@ -186,7 +186,7 @@ public class Build{ return false; } - if(!state.rules.editor && checkCoreRadius){ + if(!state.rules.editor && checkCoreRadius && !(!checkVisible && team == Team.derelict)){ //find closest core, if it doesn't match the team, placing is not legal if(state.rules.polygonCoreProtection){ float mindst = Float.MAX_VALUE; diff --git a/core/src/mindustry/world/blocks/production/AttributeCrafter.java b/core/src/mindustry/world/blocks/production/AttributeCrafter.java index 1054174ad8..448e00bada 100644 --- a/core/src/mindustry/world/blocks/production/AttributeCrafter.java +++ b/core/src/mindustry/world/blocks/production/AttributeCrafter.java @@ -11,11 +11,15 @@ import mindustry.world.meta.*; /** A crafter that gains efficiency from attribute tiles. */ public class AttributeCrafter extends GenericCrafter{ public Attribute attribute = Attribute.heat; + /** Base efficiency of the crafter. */ public float baseEfficiency = 1f; + /** Maximum efficiency/output boost from attributes. */ public float maxBoost = 1f; + /** Minimum efficiency required to place this block. */ public float minEfficiency = -1f; - public boolean displayEfficiency = true; - public boolean displayScaledOutput = true; + /** Whether to show this bar in the UI. */ + public boolean displayEfficiency = true, displayScaledOutput = true; + /** Whether liquid consumption scales with efficiency. */ public boolean scaleLiquidConsumption = false; /** Scaled output (yield) multiplier, scales with attribute. <=0 to disable. */ public float outputScale = 0f; @@ -34,12 +38,10 @@ public class AttributeCrafter extends GenericCrafter{ drawPlaceText( (displayEfficiency && boostScale > 0f ? - Core.bundle.format("bar.efficiency", - (int)((baseEfficiency + Math.min(maxBoost, boostScale * sumAttribute(attribute, x, y))) * 100f)) + Core.bundle.format("bar.efficiency", (int)((baseEfficiency + Math.min(maxBoost, boostScale * sumAttribute(attribute, x, y))) * 100f)) : "") + - (displayScaledOutput && outputScale > 0f ? "\n" + - Core.bundle.format("bar.yield", - (int)(Math.min(maxBoost, outputScale * sumAttribute(attribute, x, y)) * 100f)) + (displayScaledOutput && outputScale > 0f ? + "\n" + Core.bundle.format("bar.yield", (int)((1f + Math.min(maxBoost, outputScale * sumAttribute(attribute, x, y))) * 100f)) : ""), x, y, valid); } @@ -59,7 +61,7 @@ public class AttributeCrafter extends GenericCrafter{ if(displayScaledOutput && outputScale > 0f){ addBar("yield", (AttributeCrafterBuild entity) -> new Bar( - () -> Core.bundle.format("bar.yield", (int)((entity.outputMultiplier() - baseEfficiency) * 100)), + () -> Core.bundle.format("bar.yield", (int)(entity.outputMultiplier() * 100)), () -> Pal.lightOrange, entity::outputMultiplier)); } diff --git a/core/src/mindustry/world/blocks/production/GenericCrafter.java b/core/src/mindustry/world/blocks/production/GenericCrafter.java index 429caf672d..24729d2da2 100644 --- a/core/src/mindustry/world/blocks/production/GenericCrafter.java +++ b/core/src/mindustry/world/blocks/production/GenericCrafter.java @@ -334,7 +334,10 @@ public class GenericCrafter extends Block{ public void dumpOutputs(){ if(outputItems != null && timer(timerDump, dumpTime / timeScale)){ for(ItemStack output : outputItems){ - dump(output.item); + int amount = Math.max(1, Mathf.round(scaleOutput(output.amount))); + for(int i = 0; i < amount; i++){ + if(!dump(output.item)) break; + } } } diff --git a/core/src/mindustry/world/modules/ItemModule.java b/core/src/mindustry/world/modules/ItemModule.java index 59e068a3bf..49240a2f91 100644 --- a/core/src/mindustry/world/modules/ItemModule.java +++ b/core/src/mindustry/world/modules/ItemModule.java @@ -97,7 +97,7 @@ public class ItemModule extends BlockModule{ /** @return a specific item's flow rate in items/s; any value < 0 means not ready.*/ public float getFlowRate(Item item){ - return flow == null ? -1f : displayFlow[item.id] * 60; + return flow == null ? -1f : displayFlow != null ? displayFlow[item.id] * 60 : -1f; } public boolean hasFlowItem(Item item){ diff --git a/core/src/mindustry/world/modules/LiquidModule.java b/core/src/mindustry/world/modules/LiquidModule.java index 23bfc60659..dfbcb8635f 100644 --- a/core/src/mindustry/world/modules/LiquidModule.java +++ b/core/src/mindustry/world/modules/LiquidModule.java @@ -78,7 +78,7 @@ public class LiquidModule extends BlockModule{ /** @return current liquid's flow rate in u/s; any value < 0 means 'not ready'. */ public float getFlowRate(Liquid liquid){ - return flow == null ? -1f : displayFlow[liquid.id] * 60; + return flow == null ? -1f : displayFlow != null ? displayFlow[liquid.id] * 60 : -1f; } public boolean hasFlowLiquid(Liquid liquid){ diff --git a/gradle.properties b/gradle.properties index f40ab3f9d4..7b31c918db 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,4 +26,4 @@ org.gradle.caching=true org.gradle.internal.http.socketTimeout=100000 org.gradle.internal.http.connectionTimeout=100000 android.enableR8.fullMode=false -archash=c082cc548b +archash=ac71a73ac8 diff --git a/ios/Info.plist.xml b/ios/Info.plist.xml index 3ace8e7c9c..d55a48f855 100644 --- a/ios/Info.plist.xml +++ b/ios/Info.plist.xml @@ -38,6 +38,8 @@ UIRequiresFullScreen + CADisableMinimumFrameDurationOnPhone + LSSupportsOpeningDocumentsInPlace NSPhotoLibraryAddUsageDescription diff --git a/tests/src/test/java/LogicTests.java b/tests/src/test/java/LogicTests.java index a7abccea83..140145398a 100644 --- a/tests/src/test/java/LogicTests.java +++ b/tests/src/test/java/LogicTests.java @@ -1,3 +1,4 @@ +import arc.graphics.*; import mindustry.logic.*; import mindustry.logic.LExecutor.*; import org.junit.jupiter.api.*; @@ -243,6 +244,123 @@ public class LogicTests{ ); } + /** Values that must resolve to a numeric constant (isobj == false) or an object constant. */ + static Stream parseValCases(){ + return Stream.of( + // name, symbol, expected (Double => numeric, anything else => object) + Arguments.of("parse null", "null", null), + + //decimal + Arguments.of("decimal: zero", "0", 0.0), + Arguments.of("decimal: positive integer", "42", 42.0), + Arguments.of("decimal: negative integer", "-42", -42.0), + Arguments.of("decimal: explicit plus sign", "+42", 42.0), + Arguments.of("decimal: fraction", "3.14", 3.14), + Arguments.of("decimal: negative fraction", "-3.14", -3.14), + Arguments.of("decimal: leading dot", ".5", 0.5), + Arguments.of("decimal: large integer", "123456789012", 123456789012.0), + Arguments.of("decimal: scientific", "1e3", 1000.0), + Arguments.of("decimal: scientific negative exponent", "1.5e-2", 0.015), + + //hex + Arguments.of("hex: zero", "0x0", 0.0), + Arguments.of("hex: uppercase digits", "0xFF", 255.0), + Arguments.of("hex: lowercase digits", "0xff", 255.0), + Arguments.of("hex: mixed case", "0xDeadBeef", 3735928559.0), + Arguments.of("hex: explicit plus", "+0xFF", 255.0), + Arguments.of("hex: negative", "-0xFF", -255.0), + Arguments.of("hex: many leading zeros aren't overflow", "0x0000000000000000000000FF", 255.0), + Arguments.of("hex: only zeros", "0x" + "0".repeat(100), 0.0), + Arguments.of("hex: Long.MAX_VALUE", "0x7FFFFFFFFFFFFFFF", (double)Long.MAX_VALUE), + Arguments.of("hex: Long.MIN_VALUE (0x8000...)", "0x8000000000000000", (double)Long.MIN_VALUE), + Arguments.of("hex: unsigned long max wraps to -1", "0xFFFFFFFFFFFFFFFF", -1.0), + Arguments.of("hex: unsigned long max - 1 wraps to -2", "0xFFFFFFFFFFFFFFFE", -2.0), + Arguments.of("hex: negated -1 wrap gives 1", "-0xFFFFFFFFFFFFFFFF", 1.0), + Arguments.of("hex: negative Long.MAX_VALUE", "-0x7FFFFFFFFFFFFFFF", -(double)Long.MAX_VALUE), + + //binary + Arguments.of("bin: zero", "0b0", 0.0), + Arguments.of("bin: one", "0b1", 1.0), + Arguments.of("bin: ten", "0b1010", 10.0), + Arguments.of("bin: explicit plus", "+0b1010", 10.0), + Arguments.of("bin: negative", "-0b1010", -10.0), + Arguments.of("bin: many leading zeros aren't overflow", "0b" + "0".repeat(70) + "1", 1.0), + Arguments.of("bin: 63 ones is Long.MAX_VALUE", "0b0" + "1".repeat(63), (double)Long.MAX_VALUE), + Arguments.of("bin: 1 followed by 63 zeros is Long.MIN_VALUE", "0b1" + "0".repeat(63), (double)Long.MIN_VALUE), + Arguments.of("bin: 64 ones wraps to -1", "0b" + "1".repeat(64), -1.0) + ); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("parseValCases") + void parseVarValues(String name, String symbol, Object expected){ + LAssembler asm = new LAssembler(); + LVar v = asm.var(symbol); + if(expected instanceof Double d){ + assertFalse(v.isobj, "should be numeric: " + symbol); + assertEquals(d, v.numval, 0.00001f); + }else{ + assertTrue(v.isobj); + assertEquals(expected, v.objval); + } + } + + /** Colors are packed into the bits of a (tiny, denormal) double, so they need an exact comparison. */ + static Stream parseColorCases(){ + return Stream.of( + Arguments.of("color: rgb white", "%ffffff", Color.toDoubleBits(255, 255, 255, 255)), + Arguments.of("color: rgba", "%ff000080", Color.toDoubleBits(255, 0, 0, 128)), + Arguments.of("color: named", "%[red]", Colors.get("red").toDoubleBits()) + ); + } + + @ParameterizedTest(name = "{0}") + @MethodSource("parseColorCases") + void parseColorValues(String name, String symbol, double expected){ + LAssembler asm = new LAssembler(); + LVar v = asm.var(symbol); + assertFalse(v.isobj); + assertEquals(expected, v.numval, 0.0); + } + + /** Anything here must NOT be parsed as a number (i.e. it becomes a plain variable name). */ + static Stream invalidNumberCases(){ + return Stream.of( + //fail-fast: first char can't start a number + "", + "abc", + "e10", + "NaN", + "Infinity", + + //prefix with no digits + "0x", "0b", "+0x", "-0b", + + //invalid digits + "0xG", "0x12G4", "0b2", "0b102", "0x-1", "0x1.5", + + //overflow: more than 64 significant bits + "0x1" + "0".repeat(16), //17 hex digits + "-0x1" + "0".repeat(16), + "0x" + "F".repeat(17), + "0b1" + "0".repeat(64), //65 binary digits + "0b" + "1".repeat(65), + + //malformed colors + "%fff", + "%[nosuchcolor]" + ); + } + + @ParameterizedTest(name = "invalid: [{0}]") + @MethodSource("invalidNumberCases") + void parseInvalidNumbers(String symbol){ + LAssembler asm = new LAssembler(); + LVar v = asm.var(symbol); + assertTrue(v.isobj, "should not parse as a number: " + symbol); + assertNull(v.objval); + } + //unterminated / malformed string literals: these must fail loudly, never silently misparse @ParameterizedTest(name = "{0}")