mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-10-02 11:10:50 +03:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
69ed90bb9d | ||
|
|
e337452d46 | ||
|
|
9f70386466 | ||
|
|
e7de4e1a10 | ||
|
|
4cc15b84f6 | ||
|
|
f3bfa418a5 | ||
|
|
663b0b8737 | ||
|
|
3a54813513 | ||
|
|
3e43d88374 | ||
|
|
580f8f5217 | ||
|
|
067c720a88 | ||
|
|
2541682bee | ||
|
|
78921a064e | ||
|
|
92d53b01fc | ||
|
|
8f1a4c5541 | ||
|
|
e2ccb6ea96 | ||
|
|
2f3a3979a4 | ||
|
|
9f065cea59 | ||
|
|
d2c5e09413 | ||
|
|
1cc5d54fde | ||
|
|
4ef2a6d81e | ||
|
|
be14e4173e | ||
|
|
c58aac5f67 | ||
|
|
cada4b2543 | ||
|
|
ccc5bebc3b | ||
|
|
8b80186320 | ||
|
|
1e8317fbac | ||
|
|
6500b5b6de | ||
|
|
eff677e112 | ||
|
|
543dae701c | ||
|
|
ec2bc54339 | ||
|
|
ca2c51896d | ||
|
|
c640ae21ad | ||
|
|
b8f392a116 | ||
|
|
bfa31bf184 | ||
|
|
088486c1ad | ||
|
|
acf891e419 | ||
|
|
ca90af5f56 | ||
|
|
45b82b9fa2 | ||
|
|
22cf431170 | ||
|
|
b513d92456 | ||
|
|
b3be63437e | ||
|
|
c801b625ac | ||
|
|
0bbc4c6777 | ||
|
|
4eed142ccc | ||
|
|
42ec5c9685 | ||
|
|
ca9876544e | ||
|
|
73d5865908 | ||
|
|
f474eab926 | ||
|
|
b76147ec50 | ||
|
|
22ca0ce33f | ||
|
|
4368c6e60e | ||
|
|
7591c51b60 | ||
|
|
93c88fea8c | ||
|
|
9de4deed37 | ||
|
|
254fd3e28d | ||
|
|
9a886aa582 | ||
|
|
a51047a80d | ||
|
|
55dba0c156 | ||
|
|
a98a7ba227 | ||
|
|
56348b3e31 |
@@ -1,5 +1,6 @@
|
||||
If your pull request is **not** translation or serverlist-related, read the list of requirements below and check each box:
|
||||
If your pull request is **not** translation-related, read the list of requirements below and check each box:
|
||||
|
||||
- [ ] I have read the [contribution guidelines](https://github.com/Anuken/Mindustry/blob/master/CONTRIBUTING.md).
|
||||
- [ ] I have ensured that my code compiles, if applicable.
|
||||
- [ ] I have ensured that any new features in this PR function correctly in-game, if applicable.
|
||||
- [ ] I affirm that this code was not written using generative AI/LLMs.
|
||||
+1
-3
@@ -22,7 +22,7 @@ I **especially** do not want to see PRs that apply any kind of automated analysi
|
||||
|
||||
### Do not make AI "contributions".
|
||||
|
||||
If I see a PR with significant amounts of code that's obviously written by AI, I will reject your PR, and you will be blocked. Don't waste my time with slop.
|
||||
If I see a PR with code that's obviously written by AI, I will reject your PR, and you will be blocked. Don't waste my time with slop.
|
||||
|
||||
Asking AI questions, and using that information to help you write code? Fine. Using it to actually write code? No.
|
||||
|
||||
@@ -67,7 +67,6 @@ What you'll usually need to change:
|
||||
### Avoid boxed types (Integer, Boolean)
|
||||
Never create variables or collections with boxed types `Seq<Integer>` or `ObjectMap<Integer, ...>`. Use the collections specialized for this task, e.g. `IntSeq` and `IntMap`.
|
||||
|
||||
|
||||
### Do not allocate anything if possible.
|
||||
Never allocate `new` objects in the main loop. If you absolutely require new objects, use `Pools` to obtain and free object instances.
|
||||
Otherwise, use the `Tmp` variables for things like vector/shape operations, or create `static` variables for re-use.
|
||||
@@ -77,7 +76,6 @@ If using a list, make it a static variable and clear it every time it is used. R
|
||||
This is situational, but in essence, what it means is to avoid using any sort of getters and setters unless absolutely necessary. Public or protected fields should suffice for most things.
|
||||
If something needs to be encapsulated in the future, IntelliJ can handle it with a few clicks.
|
||||
|
||||
|
||||
### Do not create methods unless necessary.
|
||||
Unless a block of code is very large or used in more than 1-2 places, don't split it up into a separate method. Making unnecessary methods only creates confusion, and may slightly decrease performance.
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Note: The v7 server list is frozen. No new servers will be accepted. All v8 server PRs should be made [here](https://github.com/Anuken/MindustryServerList).
|
||||
|
||||
*PRs to edit addresses of existing servers will still be accepted, although very infrequently.*
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ allprojects{
|
||||
if(!project.hasProperty("versionModifier")) versionModifier = 'release'
|
||||
if(!project.hasProperty("versionType")) versionType = 'official'
|
||||
appName = 'Mindustry'
|
||||
steamworksVersion = 'da41c05b7a2a44c8625ca0ba7d6ca1a2e73f621a'
|
||||
steamworksVersion = '185e76cfe630a6f0e1dd7b9bf57be41f6064a1f2'
|
||||
rhinoVersion = '32395f942976a6d1d21ec9877664554cd5762306'
|
||||
|
||||
loadVersionProps = {
|
||||
|
||||
@@ -1304,7 +1304,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
|
||||
@@ -3396,7 +3396,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
|
||||
|
||||
@@ -838,7 +838,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
|
||||
@@ -1238,7 +1238,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
|
||||
@@ -1299,7 +1299,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
|
||||
@@ -1319,7 +1319,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
|
||||
@@ -1990,8 +1990,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
|
||||
@@ -2757,7 +2757,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.
|
||||
@@ -2945,63 +2945,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.
|
||||
@@ -3186,8 +3186,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
|
||||
@@ -3195,9 +3195,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
|
||||
@@ -3206,31 +3206,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
|
||||
@@ -3263,22 +3263,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
|
||||
@@ -3318,27 +3318,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
|
||||
@@ -3351,7 +3351,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
|
||||
@@ -3387,17 +3387,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
|
||||
@@ -3405,7 +3405,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
|
||||
@@ -3421,29 +3421,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
|
||||
@@ -3457,40 +3457,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
|
||||
@@ -3507,43 +3507,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
|
||||
@@ -3562,13 +3562,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
|
||||
@@ -3577,12 +3577,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
|
||||
@@ -3626,15 +3626,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
|
||||
|
||||
@@ -1019,7 +1019,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.
|
||||
@@ -1299,7 +1299,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
|
||||
@@ -1414,8 +1414,8 @@ category.function = Funkció
|
||||
category.optional = Lehetséges fejlesztések
|
||||
setting.alwaysmusic.name = Folyamatos zenelejátszás
|
||||
setting.alwaysmusic.description = Amikor engedélyezve van, akkor a zene folyamatosan szól a játékban.\nHa ki van kapcsolva, akkor csak véletlenszerű időközönként szólal meg.
|
||||
setting.skipcoreanimation.name = Támaszpont animációjának kihagyása kilövéskor és leszálláskor
|
||||
setting.skipcoreanimation.description = Ha engedélyezve van, akkor a támaszpont fel- és leszállásának\nanimációja nem lesz megjelenítve.
|
||||
setting.skipcoreanimation.name = Támaszpont animációinak kihagyása
|
||||
setting.skipcoreanimation.description = Ha engedélyezve van, akkor a támaszpont fel- és leszállási\nanimációja nem lesz megjelenítve.
|
||||
setting.landscape.name = Fekvő mód zárolása
|
||||
setting.landscape.description = Ha engedélyezve van, akkor a képernyő tájolása fekvő módban lesz rögzítve.
|
||||
setting.blockreplace.name = Automatikus blokkjavaslatok
|
||||
@@ -1468,8 +1468,8 @@ setting.destroyedblocks.name = Lerombolt építmények megjelenítése
|
||||
setting.destroyedblocks.description = Ha engedélyezve van, akkor a megsemmisített blokkok\ntörmeléket hagynak maguk után.
|
||||
setting.blockstatus.name = Blokkok állapotának megjelenítése
|
||||
setting.blockstatus.description = A blokkok felett színes állapotikonok jelennek meg.
|
||||
setting.conveyorpathfinding.name = Szállítószalag nyomvonalkeresése építéskor
|
||||
setting.conveyorpathfinding.description = Ha engedélyezve van, akkor a szállítószalagok elhelyezésekor a rendszer\nautomatikusan megpróbálja megtalálni az útvonalat a célállomásig.
|
||||
setting.conveyorpathfinding.name = Nyomvonalkeresés szállítószalag-építéskor
|
||||
setting.conveyorpathfinding.description = Ha engedélyezve van, akkor a szállítószalagok elhelyezésekor a rendszer\nautomatikusan megpróbálja megtalálni azok nyomvonalát a célállomásig.
|
||||
setting.sensitivity.name = Játékvezérlők érzékenysége
|
||||
setting.sensitivity.description = A játékvezérlők (joystick) érzékenységét lehet vele finomhangolni.
|
||||
setting.saveinterval.name = Mentési időköz
|
||||
@@ -1478,7 +1478,7 @@ setting.seconds = {0} másodperc
|
||||
setting.milliseconds = {0} ezredmásodperc
|
||||
setting.fullscreen.name = Teljes képernyő
|
||||
setting.fps.name = FPS, memóriahasználat és ping megjelenítése
|
||||
setting.fps.description = Megjeleníti a jelenlegi képkockasebességet (FPS), a memóriahasználatot MB/GB-ban\nés a hálózati pinget a képernyő sarkában.
|
||||
setting.fps.description = Megjeleníti a jelenlegi képkockasebességet, a memóriahasználatot MB/GB-ban\nés a hálózati pinget a képernyő sarkában.
|
||||
setting.console.name = Konzol engedélyezése
|
||||
setting.console.description = Engedélyezi a játékon belüli JavaScript-konzolt.
|
||||
setting.drawhitboxes.name = Ütközési dobozok megjelenítése
|
||||
@@ -3391,14 +3391,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ó
|
||||
|
||||
@@ -882,7 +882,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
|
||||
@@ -1074,7 +1074,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.
|
||||
|
||||
@@ -1299,7 +1299,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
|
||||
@@ -1447,7 +1447,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
|
||||
@@ -2453,7 +2453,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[].
|
||||
|
||||
@@ -2686,7 +2686,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.
|
||||
@@ -2700,7 +2700,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.
|
||||
@@ -2741,7 +2741,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.
|
||||
@@ -2945,63 +2945,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.
|
||||
@@ -3282,7 +3282,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
|
||||
@@ -3351,7 +3351,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
|
||||
@@ -3456,7 +3456,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
|
||||
|
||||
@@ -1299,7 +1299,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}/с
|
||||
@@ -2945,63 +2945,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 = Нет категории.
|
||||
@@ -3496,9 +3496,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 = выход
|
||||
@@ -3509,8 +3509,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 = постройка
|
||||
@@ -3532,7 +3532,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 = эффект
|
||||
@@ -3599,7 +3599,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 = облако дыма
|
||||
|
||||
@@ -2461,7 +2461,7 @@ split.pickup = 某些物品可以被核心單位撿起。\n撿起這個[accent]
|
||||
split.pickup.mobile = 某些物品可以被核心單位撿起。\n撿起這個[accent]容器[],然後放到 [accent]重物裝載機[] 上。\n(要撿起或放下東西,請長按該物品。)
|
||||
split.acquire = 您必須獲取一些鎢才能建造單位。
|
||||
split.build = 單位必須被運送到牆的另一邊。\n在牆的兩側各放一個[accent]重物質量驅動器[]。\n通過按壓其中一個來設置連結,然後選擇另一個。
|
||||
split.container = 類似於容器,單位也可以使用[accent]重物質量驅動器[]進行運輸。\n將一個單位兵工廠放置在重物裝載機旁邊以裝載它們,然後將它們送到牆的另一側以進攻敵方基地。
|
||||
split.container = 類似於容器,單位也可以使用[accent]重物質量驅動器[]進行運輸。\n將一個單位兵工廠放置在重物質量驅動器旁邊以裝載它們,然後將它們送到牆的另一側以進攻敵方基地。
|
||||
|
||||
item.copper.description = 最基本的結構材料。在各種類型的方塊中廣泛使用。
|
||||
item.copper.details = 銅,蕈孢星上異常常見的金屬。加工前結構脆弱。
|
||||
|
||||
@@ -183,7 +183,10 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
||||
|
||||
assets.load(schematics);
|
||||
|
||||
assets.loadRun("contentinit", ContentLoader.class, () -> content.init(), () -> content.load());
|
||||
assets.loadRun("contentinit", ContentLoader.class, () -> content.init(), () -> {
|
||||
content.load();
|
||||
mods.loadModPatches();
|
||||
});
|
||||
assets.loadRun("baseparts", BaseRegistry.class, () -> {}, () -> bases.load());
|
||||
|
||||
Core.assets.load("sprites/schematic-background.png", Texture.class).loaded = t -> t.setWrap(TextureWrap.repeat);
|
||||
|
||||
@@ -164,6 +164,7 @@ public class ControlPathfinder implements Runnable{
|
||||
|
||||
//main thread only!
|
||||
long lastUpdateId = state.updateId;
|
||||
long lastRecomputeTime;
|
||||
|
||||
//both threads
|
||||
volatile boolean notFound = false;
|
||||
@@ -456,7 +457,7 @@ public class ControlPathfinder implements Runnable{
|
||||
Cluster[][] dim1 = clusters[team];
|
||||
|
||||
if(dim1 == null){
|
||||
dim1 = clusters[team] = new Cluster[Team.all.length][];
|
||||
dim1 = clusters[team] = new Cluster[costTypes.size][];
|
||||
}
|
||||
|
||||
Cluster[] dim2 = dim1[pathCost];
|
||||
@@ -1192,7 +1193,9 @@ public class ControlPathfinder implements Runnable{
|
||||
long fieldKey = FieldIndex.get(destPos, costId, team);
|
||||
|
||||
//use existing request if it exists.
|
||||
if(request != null && request.destination == destPos){
|
||||
if(request != null && (request.destination == destPos ||
|
||||
//can only recompute path only twice a second, unless it's far away
|
||||
(Time.timeSinceMillis(request.lastRecomputeTime) < 1000 && Mathf.dst(destX, destY, request.destination % wwidth, request.destination / wwidth) <= 4f))){
|
||||
request.lastUpdateId = state.updateId;
|
||||
|
||||
Tile initialTileOn = tileOn;
|
||||
@@ -1313,6 +1316,7 @@ public class ControlPathfinder implements Runnable{
|
||||
unitRequests.put(unit, request = new PathRequest(unit, team, costId, destPos));
|
||||
|
||||
PathRequest f = request;
|
||||
request.lastRecomputeTime = Time.millis();
|
||||
|
||||
//on the pathfinding thread: initialize the request
|
||||
queue.post(() -> {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -259,7 +259,8 @@ public class CommandAI extends AIController{
|
||||
targetPos = new Vec2();
|
||||
lastTargetPos = targetPos;
|
||||
}
|
||||
targetPos.set(attackTarget);
|
||||
//don't target where target dummies are right now, target their block
|
||||
targetPos.set(attackTarget instanceof TargetDummyUnit t && t.building != null ? t.building : attackTarget);
|
||||
|
||||
if(unit.isGrounded() && attackTarget instanceof Building build && build.tile.solid() && unit.type.pathCostId != ControlPathfinder.costIdLegs && !ramming){
|
||||
Tile best = build.findClosestEdge(unit, Tile::solid);
|
||||
|
||||
@@ -92,7 +92,7 @@ public class AvoidanceProcess implements AsyncProcess{
|
||||
float rad = Float.intBitsToFloat(items[i + 1]);
|
||||
float rad2 = rad * rad;
|
||||
|
||||
int r = Math.max(1, Mathf.ceil(rad));
|
||||
int r = Mathf.clamp(1, Mathf.ceil(rad), 20);
|
||||
|
||||
for(int dx = -r; dx <= r; dx++){
|
||||
for(int dy = -r; dy <= r; dy++){
|
||||
|
||||
@@ -26,6 +26,7 @@ public class PhysicsProcess implements AsyncProcess{
|
||||
private PhysicsWorld[] physics;
|
||||
private Seq<PhysicRef> refs = new Seq<>(false, 20, PhysicRef.class);
|
||||
private Seq<Future<?>> futures = new Seq<>(false, layers, Future.class);
|
||||
private Seq<PhysicRef> pendingAdds = new Seq<>(false, 20, PhysicRef.class);
|
||||
|
||||
private static volatile long maxPhysicsTime = 0;
|
||||
|
||||
@@ -44,7 +45,8 @@ public class PhysicsProcess implements AsyncProcess{
|
||||
PhysicRef ref = new PhysicRef(unit, body);
|
||||
refs.add(ref);
|
||||
|
||||
if(ref.lastLayer >= 0) physics[ref.lastLayer].add(body);
|
||||
//defer adds until physics update is done
|
||||
pendingAdds.add(ref);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,6 +70,13 @@ public class PhysicsProcess implements AsyncProcess{
|
||||
PerfCounter.unitPhysicsAsync.add(maxPhysicsTime);
|
||||
maxPhysicsTime = 0;
|
||||
|
||||
//flush newly added entities
|
||||
for(int i = 0; i < pendingAdds.size; i++){
|
||||
PhysicRef ref = pendingAdds.items[i];
|
||||
if(ref.lastLayer >= 0) physics[ref.lastLayer].add(ref.body);
|
||||
}
|
||||
pendingAdds.clear();
|
||||
|
||||
//move entities
|
||||
for(PhysicRef ref : refs){
|
||||
Physicsc entity = ref.entity;
|
||||
|
||||
@@ -6484,7 +6484,7 @@ public class Blocks{
|
||||
regionSuffix = "-dark";
|
||||
|
||||
size = 3;
|
||||
configurable = false;
|
||||
showAllCommands = false;
|
||||
consumePower(3f);
|
||||
consumeLiquid(Liquids.hydrogen, 3f / 60f);
|
||||
consumeItems(with(Items.silicon, 40, Items.tungsten, 30));
|
||||
@@ -6502,7 +6502,7 @@ public class Blocks{
|
||||
regionSuffix = "-dark";
|
||||
|
||||
size = 3;
|
||||
configurable = false;
|
||||
showAllCommands = false;
|
||||
consumePower(2.5f);
|
||||
consumeLiquid(Liquids.hydrogen, 3f / 60f);
|
||||
consumeItems(with(Items.silicon, 60, Items.tungsten, 40));
|
||||
@@ -6521,7 +6521,7 @@ public class Blocks{
|
||||
regionSuffix = "-dark";
|
||||
|
||||
size = 3;
|
||||
configurable = false;
|
||||
showAllCommands = false;
|
||||
consumePower(2.5f);
|
||||
consumeLiquid(Liquids.hydrogen, 3f / 60f);
|
||||
consumeItems(with(Items.silicon, 50, Items.tungsten, 40));
|
||||
@@ -6534,7 +6534,6 @@ public class Blocks{
|
||||
);
|
||||
}};
|
||||
|
||||
//yes very silly name
|
||||
primeRefabricator = new Reconstructor("prime-refabricator"){{
|
||||
requirements(Category.units, with(Items.thorium, 250, Items.oxide, 200, Items.tungsten, 200, Items.silicon, 400));
|
||||
regionSuffix = "-dark";
|
||||
@@ -6542,7 +6541,7 @@ public class Blocks{
|
||||
researchCostMultipliers.put(Items.thorium, 0.2f);
|
||||
|
||||
size = 5;
|
||||
configurable = false;
|
||||
showAllCommands = false;
|
||||
consumePower(4.5f);
|
||||
consumeLiquid(Liquids.nitrogen, 10f / 60f);
|
||||
consumeItems(with(Items.thorium, 80, Items.silicon, 100));
|
||||
|
||||
@@ -972,8 +972,10 @@ public class NetServer implements ApplicationListener{
|
||||
}else{
|
||||
Seq<DataAsset> res = new Seq<>();
|
||||
Seq<DataAsset> allAssets = state.data.getAllExternalAssets();
|
||||
Bits requestedIds = new Bits(allAssets.size);
|
||||
for(short id : ids){
|
||||
if(id >= allAssets.size || id < 0) continue;
|
||||
if(id >= allAssets.size || id < 0 || requestedIds.get(id)) continue;
|
||||
requestedIds.set(id);
|
||||
res.add(allAssets.get(id));
|
||||
}
|
||||
|
||||
|
||||
@@ -408,8 +408,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);
|
||||
@@ -431,11 +432,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);
|
||||
|
||||
@@ -78,7 +78,11 @@ public class MapEditor{
|
||||
if(build != null && tile.isCenter()){
|
||||
builds.add(build);
|
||||
}
|
||||
tiles.seti(i, new EditorTile(tile.x, tile.y, tile.floorID(), tile.overlayID(), build == null ? tile.blockID() : 0));
|
||||
|
||||
var newTile = new EditorTile(tile.x, tile.y, tile.floorID(), tile.overlayID(), build == null ? tile.blockID() : 0);
|
||||
newTile.floorData = tile.floorData;
|
||||
newTile.extraData = tile.extraData;
|
||||
tiles.seti(i, newTile);
|
||||
}
|
||||
|
||||
for(var build : builds){
|
||||
|
||||
@@ -23,7 +23,7 @@ public class Effect{
|
||||
|
||||
public static final Seq<Effect> all = new Seq<>();
|
||||
|
||||
private boolean initialized;
|
||||
private transient boolean initialized;
|
||||
|
||||
public final int id;
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ public class Lightning{
|
||||
|
||||
Unit furthest = Geometry.findFurthest(x, y, entities);
|
||||
|
||||
if(furthest != null){
|
||||
if(furthest != null && furthest.within(x, y, hitRange * 2f)){
|
||||
hit.add(furthest.id());
|
||||
x = furthest.x();
|
||||
y = furthest.y();
|
||||
|
||||
@@ -16,10 +16,18 @@ abstract class TargetDummyComp implements Unitc, Healthc{
|
||||
}
|
||||
}
|
||||
|
||||
@Replace
|
||||
@Override
|
||||
public void rawDamage(float amount){
|
||||
if(building instanceof TargetDummyBuild td){
|
||||
td.dummyHit(amount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Replace
|
||||
public boolean canLand(){
|
||||
//dummies should always respect the boost config even when the landing area is obstructed (usually by other dummies)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -174,7 +174,8 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
|
||||
|
||||
/** @return whether there is solid, un-occupied ground under this unit. */
|
||||
public boolean canLand(){
|
||||
return !onSolid() && Units.count(x, y, physicSize(), f -> f != self() && f.isGrounded()) == 0;
|
||||
float psize = physicSize();
|
||||
return !onSolid() && !Units.any(x - psize/2f, y - psize/2f, psize, psize, f -> f != self() && f.isGrounded());
|
||||
}
|
||||
|
||||
public boolean inRange(Position other){
|
||||
|
||||
@@ -6,6 +6,7 @@ import arc.math.geom.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import arc.util.serialization.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.content.TechTree.*;
|
||||
import mindustry.core.*;
|
||||
@@ -554,6 +555,14 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
public void readDataPatches(DataInput stream, SaveReadState saveState) throws IOException{
|
||||
stream.readInt(); //version - ignored for now
|
||||
|
||||
//the requiredPlanets filter needs this, since the rules aren't read yet
|
||||
if(headless){
|
||||
try{
|
||||
Planet planet = content.planet(new JsonReader().parse(saveState.ruleString).getString("planet", Planets.serpulo.name));
|
||||
state.rules.planet = planet == null ? Planets.serpulo : planet;
|
||||
}catch(Exception ignored){}
|
||||
}
|
||||
|
||||
int total = stream.readInt();
|
||||
Seq<DataAsset> assets = new Seq<>(total);
|
||||
|
||||
|
||||
@@ -11,9 +11,6 @@ import mindustry.logic.LExecutor.*;
|
||||
public class LAssembler{
|
||||
public static ObjectMap<String, Func<String[], LStatement>> 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<String, LVar> 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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,8 @@ public class LExecutor{
|
||||
/** Loads with a specified assembler. Resets all variables. */
|
||||
public void load(LAssembler builder){
|
||||
stop = false;
|
||||
textBuffer.setLength(0);
|
||||
graphicsBuffer.clear();
|
||||
nameMap = null;
|
||||
//retain constants that are links, which, by convention, don't start with @ (builtin) or _ (numeric constant)
|
||||
vars = builder.vars.values().toSeq().retainAll(var -> !var.constant || var.name.charAt(0) != '_' && var.name.charAt(0) != '@').toArray(LVar.class);
|
||||
|
||||
@@ -90,7 +90,7 @@ public abstract class LStatement{
|
||||
/** Sanitizes variable input strings from text fields into values that will not break logic parsing. */
|
||||
public static String sanitize(String value){
|
||||
if(value.length() == 0){
|
||||
return "";
|
||||
return "null";
|
||||
}else if(value.length() == 1){
|
||||
if(value.charAt(0) == '"' || value.charAt(0) == ';' || value.charAt(0) == ' ' ||
|
||||
value.charAt(0) == '\n' || value.charAt(0) == '\t' || value.charAt(0) == '#'){
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -12,6 +12,7 @@ import arc.util.*;
|
||||
import arc.util.Log.*;
|
||||
import mindustry.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.mod.data.*;
|
||||
|
||||
import java.io.*;
|
||||
@@ -106,6 +107,8 @@ public class DataImagePacker{
|
||||
|
||||
try{
|
||||
Pixmap pixmap = new Pixmap(cacheFile);
|
||||
Pixmaps.antialias(pixmap);
|
||||
Drawf.checkBleed(pixmap);
|
||||
//don't add the double dp prefix, only add it if it's not already present
|
||||
String name = (image.isGenerated() && image.name.contains("-dp-") ? "" : regionPrefix) + image.name;
|
||||
|
||||
@@ -178,7 +181,7 @@ public class DataImagePacker{
|
||||
public void unload(){
|
||||
if(patchAtlas != null){
|
||||
for(var texture : patchAtlas.getTextures()){
|
||||
if(texture != null) patchAtlas.getTextures().remove(texture);
|
||||
if(texture != null) Core.atlas.getTextures().remove(texture);
|
||||
}
|
||||
for(var region : patchAtlas.getRegions()){
|
||||
if(region != null){
|
||||
|
||||
@@ -78,6 +78,7 @@ public class DataManager{
|
||||
PixmapRegion error = new PixmapRegion(Pixmaps.blankPixmap());
|
||||
UnlockableContent[] currentContent = {null};
|
||||
String[] currentHash = {null};
|
||||
Fi serverGeneratedDir = Vars.dataDirectory.child("assets/sprites/generated");
|
||||
|
||||
MultiPacker saver = new MultiPacker(false){
|
||||
@Override
|
||||
@@ -89,10 +90,17 @@ public class DataManager{
|
||||
if(name.startsWith(DataImagePacker.regionPrefix)) name = name.substring(DataImagePacker.regionPrefix.length());
|
||||
String path = "generated/" + currentHash[0] + "/" + name + ".png";
|
||||
ImageAsset newImage = new ImageAsset();
|
||||
newImage.setPath(path);
|
||||
//it would be nice to do this async, but the pixmap typically gets disposed right after add() exist
|
||||
|
||||
//it would be nice to do this async, but the pixmap typically gets disposed right after add()
|
||||
byte[] bytes = PixmapIO.writePngBytes(region.pixmap);
|
||||
newImage.updateData(bytes);
|
||||
if(Vars.headless){ //TODO: doesn't actually work on the server yet
|
||||
Fi file = serverGeneratedDir.child(name + ".png");
|
||||
file.writeBytes(bytes);
|
||||
newImage.readOverride(path, file);
|
||||
}else{
|
||||
newImage.setPath(path);
|
||||
newImage.updateData(bytes);
|
||||
}
|
||||
|
||||
images.add(newImage);
|
||||
packed[0] ++;
|
||||
@@ -150,17 +158,15 @@ public class DataManager{
|
||||
imagePixmaps.each((key, val) -> val.pixmap.dispose());
|
||||
error.pixmap.dispose();
|
||||
|
||||
if(packed[0] > 0 || forcePack){
|
||||
if(!Vars.headless && (packed[0] > 0 || forcePack)){
|
||||
reloadImages();
|
||||
|
||||
if(!Vars.headless){
|
||||
for(var cont : contentToPack){
|
||||
try{
|
||||
cont.loadIcon();
|
||||
cont.load();
|
||||
}catch(Exception e){
|
||||
Log.err("Failed to load icons for " + cont, e);
|
||||
}
|
||||
for(var cont : contentToPack){
|
||||
try{
|
||||
cont.loadIcon();
|
||||
cont.load();
|
||||
}catch(Exception e){
|
||||
Log.err("Failed to load icons for " + cont, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
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<String, ModRelease> 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 + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.graphics.MultiPacker.*;
|
||||
import mindustry.mod.ContentParser.*;
|
||||
import mindustry.mod.data.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
|
||||
@@ -936,6 +937,24 @@ public class Mods implements Loadable{
|
||||
Events.fire(new ModContentLoadEvent());
|
||||
}
|
||||
|
||||
public void loadModPatches(){
|
||||
for(LoadedMod mod : orderedMods()){
|
||||
if(mod.root.child("patches").exists()){
|
||||
try{
|
||||
Seq<Fi> patches = mod.root.child("patches").findAll(f -> f.extEquals("json") || f.extEquals("hjson"));
|
||||
if(patches.size > 0){
|
||||
//create a new patcher per mod so the fields don't get reset
|
||||
DataPatcher patcher = new DataPatcher();
|
||||
patches.sort();
|
||||
patcher.apply(patches.map(f -> new PatchAsset(f.readString())), new Seq<>());
|
||||
}
|
||||
}catch(Exception e){
|
||||
Log.err("Failed to apply patches from mod " + mod.meta.name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleContentError(Content content, Throwable error){
|
||||
parser.markError(content, error);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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<Seq<ModListing>> listener){
|
||||
//mods already fetched, use that
|
||||
if(modList != null){
|
||||
@@ -247,9 +252,9 @@ 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.lastUpdated) + ".png");
|
||||
Fi cacheFile = cacheFolder.child(Strings.sanitizeFilename(mod.repo + "_" + mod.iconHash) + ".png");
|
||||
|
||||
if(!cacheFile.exists()){ //fetch from Github
|
||||
ConsT<HttpResponse, Exception> fetch = res -> {
|
||||
@@ -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()){
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,8 +132,7 @@ public class PlayerListFragment{
|
||||
});
|
||||
|
||||
button.add(iconTable).size(h);
|
||||
button.labelWrap("[#" + user.color().toString().toUpperCase() + "]" + user.name()).style(Styles.outlineLabel).width(170f).pad(10);
|
||||
button.add().grow();
|
||||
button.add("[#" + user.color().toString().toUpperCase() + "]" + user.name()).style(Styles.outlineLabel).growX().wrap(true).pad(10);
|
||||
|
||||
button.background(Tex.underline);
|
||||
|
||||
@@ -236,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
|
||||
@@ -249,7 +246,7 @@ public class PlayerListFragment{
|
||||
.size(h);
|
||||
}
|
||||
|
||||
content.add(button).width(350f).height(h + 14);
|
||||
content.add(button).width(mobile ? 350f : 470f).height(h + 14);
|
||||
content.row();
|
||||
}
|
||||
|
||||
|
||||
@@ -760,7 +760,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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -5,15 +5,14 @@ import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.scene.ui.TextField.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.entities.units.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.*;
|
||||
@@ -23,6 +22,8 @@ import mindustry.world.meta.*;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class TargetDummy extends Block{
|
||||
static final float maxDummySize = 30f;
|
||||
|
||||
public final int dpsUpdateTime = timers++;
|
||||
public UnitType unitType = UnitTypes.dummy;
|
||||
public float pullScale = 0.33f;
|
||||
@@ -39,18 +40,18 @@ public class TargetDummy extends Block{
|
||||
underBullets = true;
|
||||
targetable = false;
|
||||
allowedInPayloads = false;
|
||||
|
||||
canOverdrive = false;
|
||||
saveConfig = true;
|
||||
|
||||
config(FloatSeq.class, (TargetDummyBuild tile, FloatSeq config) -> {
|
||||
if(config.size > 0){
|
||||
tile.unitTeam = tile.team;
|
||||
if(config.get(0) == 1) tile.unitTeam = Team.get(tile.dummyTeam());
|
||||
}
|
||||
if(config.size > 1) tile.boosting = config.get(1) == 1;
|
||||
if(config.size > 2) tile.unitArmor = config.get(2);
|
||||
if(config.size > 3) tile.resetTime = config.get(3);
|
||||
if(config.size > 4) tile.dummySize = config.get(4);
|
||||
config(int[].class, (TargetDummyBuild tile, int[] config) -> {
|
||||
if(config.length != 5) return; //invalid, must have 5 values exactly
|
||||
tile.unitTeam = tile.team;
|
||||
if(config[0] == 1) tile.unitTeam = Team.get(tile.dummyTeam());
|
||||
tile.boosting = config[1] == 1;
|
||||
tile.unitArmor = Mathf.clamp(config[2], 0, 100_000);
|
||||
tile.resetTime = config[3];
|
||||
tile.dummySize = Mathf.clamp(Float.intBitsToFloat(config[4]), 0.1f, maxDummySize * tilesize);
|
||||
if(Float.isNaN(tile.dummySize) || Float.isInfinite(tile.dummySize)) tile.dummySize = 8f;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -241,28 +242,28 @@ public class TargetDummy extends Block{
|
||||
t.background(Styles.black6);
|
||||
t.defaults().left();
|
||||
|
||||
t.check(Core.bundle.get("rules.enemyteam"), unitTeam != team, b -> configureFloat(0, Mathf.num(b))).colspan(3).row();
|
||||
t.check(Core.bundle.get("stat.flying"), boosting, b -> configureFloat(1, Mathf.num(b))).colspan(3).row();
|
||||
t.check(Core.bundle.get("rules.enemyteam"), unitTeam != team, b -> configureInt(0, Mathf.num(b))).colspan(3).row();
|
||||
t.check(Core.bundle.get("stat.flying"), boosting, b -> configureInt(1, Mathf.num(b))).colspan(3).row();
|
||||
t.add(Core.bundle.get("stat.armor"));
|
||||
t.field("" + (int)unitArmor, TextFieldFilter.digitsOnly, s -> configureFloat(2, Strings.parseInt(s))).valid(val -> Strings.parseInt(val, Integer.MAX_VALUE) < 100_000).width(200f).padLeft(8f).colspan(2).row();
|
||||
t.field("" + (int)unitArmor, TextFieldFilter.digitsOnly, s -> configureInt(2, Strings.parseInt(s))).valid(val -> Strings.parseInt(val, Integer.MAX_VALUE) < 100_000).width(200f).padLeft(8f).colspan(2).row();
|
||||
t.add(Core.bundle.get("stat.resettime"));
|
||||
t.field(Strings.autoFixed(resetTime / 60f, 2), TextFieldFilter.floatsOnly, s -> configureFloat(3, Strings.parseFloat(s) * 60f)).valid(Strings::canParsePositiveFloat).padLeft(8f).growX();
|
||||
t.field(Strings.autoFixed(resetTime / 60f, 2), TextFieldFilter.floatsOnly, s -> configureInt(3, (int)(Strings.parseFloat(s) * 60f))).valid(Strings::canParsePositiveFloat).padLeft(8f).growX();
|
||||
t.add(StatUnit.seconds.localized()).padLeft(8).row();
|
||||
t.add(Core.bundle.get("stat.hitsize"));
|
||||
t.field("" + (dummySize/tilesize), TextFieldFilter.floatsOnly, s -> configureFloat(4, Strings.parseFloat(s) * tilesize))
|
||||
t.field("" + (dummySize/tilesize), TextFieldFilter.floatsOnly, s -> configureInt(4, Float.floatToIntBits(Strings.parseFloat(s) * tilesize)))
|
||||
.valid(val -> {
|
||||
float parsed = Strings.parseFloat(val, Float.MAX_VALUE);
|
||||
return parsed >= 0.1f && parsed <= 50f;
|
||||
return parsed >= 0.1f && parsed <= maxDummySize;
|
||||
}).padLeft(8f).growX();
|
||||
t.add(StatUnit.blocks.localized()).padLeft(8f);
|
||||
}).top().grow().margin(8f);
|
||||
}
|
||||
|
||||
//helper to send the rest of values, since config does not support arrays
|
||||
public void configureFloat(int index, float value){
|
||||
FloatSeq seq = FloatSeq.with(Mathf.num(unitTeam != team), Mathf.num(boosting), unitArmor, resetTime, dummySize);
|
||||
seq.set(index, value);
|
||||
configure(seq);
|
||||
public void configureInt(int index, int value){
|
||||
int[] values = config();
|
||||
values[index] = value;
|
||||
configure(values);
|
||||
}
|
||||
|
||||
public int dummyTeam(){
|
||||
@@ -271,8 +272,9 @@ public class TargetDummy extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object config(){
|
||||
return FloatSeq.with(Mathf.num(unitTeam != team), Mathf.num(boosting), unitArmor, resetTime, dummySize);
|
||||
public int[] config(){
|
||||
//note: float[] is not supported in build 160
|
||||
return new int[]{Mathf.num(unitTeam != team), Mathf.num(boosting), (int)unitArmor, (int)resetTime, Float.floatToIntBits(dummySize)};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -162,7 +162,7 @@ public class DirectionalUnloader extends Block{
|
||||
public void read(Reads read, byte revision){
|
||||
super.read(read, revision);
|
||||
int id = read.s();
|
||||
unloadItem = id == -1 ? null : content.items().get(id);
|
||||
unloadItem = id == -1 ? null : content.item(id);
|
||||
offset = read.s();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,15 @@ public class ThermalGenerator extends PowerGenerator{
|
||||
lightClipSize = Math.max(lightClipSize, 45f * size * 2f * 2f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPatch(){
|
||||
super.afterPatch();
|
||||
if(outputLiquid != null){
|
||||
outputsLiquid = true;
|
||||
hasLiquids = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
@@ -82,7 +91,7 @@ public class ThermalGenerator extends PowerGenerator{
|
||||
generateEffect.at(x + Mathf.range(3f), y + Mathf.range(3f));
|
||||
}
|
||||
|
||||
if(outputLiquid != null){
|
||||
if(outputLiquid != null && hasLiquids){
|
||||
float added = Math.min(productionEfficiency * delta() * outputLiquid.amount, liquidCapacity - liquids.get(outputLiquid.liquid));
|
||||
liquids.add(outputLiquid.liquid, added);
|
||||
dumpLiquid(outputLiquid.liquid);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -335,7 +335,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ public class Reconstructor extends UnitBlock{
|
||||
|
||||
public Sound createSound = Sounds.unitCreate;
|
||||
public float createSoundVolume = 1f;
|
||||
public boolean showAllCommands = true;
|
||||
|
||||
public Reconstructor(String name){
|
||||
super(name);
|
||||
@@ -187,7 +188,7 @@ public class Reconstructor extends UnitBlock{
|
||||
if(build != null && build.team == this.team){
|
||||
commandPos.set(build);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -197,7 +198,7 @@ public class Reconstructor extends UnitBlock{
|
||||
|
||||
public boolean canSetCommand(){
|
||||
var output = unit();
|
||||
return output == null || output.allowChangeCommands;
|
||||
return showAllCommands ? (output == null || output.allowChangeCommands) : output != null && output.commands.size > 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -214,6 +215,8 @@ public class Reconstructor extends UnitBlock{
|
||||
public void buildConfiguration(Table table){
|
||||
var unit = unit();
|
||||
|
||||
if(!showAllCommands && unit == null) return;
|
||||
|
||||
var group = new ButtonGroup<ImageButton>();
|
||||
group.setMinCheckCount(0);
|
||||
int i = 0, columns = 5;
|
||||
|
||||
@@ -47,8 +47,10 @@ public class ItemModule extends BlockModule{
|
||||
public void updateFlow(){
|
||||
//update the flow at N fps at most
|
||||
if(flowTimer.get(1, flowPollInterval)){
|
||||
int len = content.items().size;
|
||||
if(items.length != len) items = Arrays.copyOf(items, len);
|
||||
|
||||
if(flow == null){
|
||||
if(flow == null || flow.length != len || cacheSums == null || cacheFlow == null){
|
||||
if(cacheFlow == null || cacheFlow.length != items.length){
|
||||
cacheFlow = new WindowedMean[items.length];
|
||||
for(int i = 0; i < items.length; i++){
|
||||
@@ -95,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){
|
||||
@@ -290,6 +292,10 @@ public class ItemModule extends BlockModule{
|
||||
|
||||
public void checkArrayCapacity(int size){
|
||||
if(items.length != size) items = Arrays.copyOf(items, size);
|
||||
cacheFlow = null;
|
||||
cacheSums = null;
|
||||
displayFlow = null;
|
||||
flow = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,9 +20,9 @@ public class LiquidModule extends BlockModule{
|
||||
public static float flowVisualRefreshInterval = 15f;
|
||||
|
||||
private static final Interval flowTimer = new Interval(2);
|
||||
private static WindowedMean[] cacheFlow;
|
||||
private static float[] cacheSums;
|
||||
private static float[] displayFlow;
|
||||
private static @Nullable WindowedMean[] cacheFlow;
|
||||
private static @Nullable float[] cacheSums;
|
||||
private static @Nullable float[] displayFlow;
|
||||
private static final Bits cacheBits = new Bits();
|
||||
|
||||
private float[] liquids = new float[content.liquids().size];
|
||||
@@ -32,7 +32,10 @@ public class LiquidModule extends BlockModule{
|
||||
|
||||
public void updateFlow(){
|
||||
if(flowTimer.get(1, flowPollInterval)){
|
||||
if(flow == null){
|
||||
int len = content.liquids().size;
|
||||
if(liquids.length != len) liquids = Arrays.copyOf(liquids, len);
|
||||
|
||||
if(flow == null || flow.length != len || cacheSums == null || cacheFlow == null){
|
||||
if(cacheFlow == null || cacheFlow.length != liquids.length){
|
||||
cacheFlow = new WindowedMean[liquids.length];
|
||||
for(int i = 0; i < liquids.length; i++){
|
||||
@@ -75,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){
|
||||
@@ -152,6 +155,10 @@ public class LiquidModule extends BlockModule{
|
||||
|
||||
public void checkArrayCapacity(int size){
|
||||
if(liquids.length != size) liquids = Arrays.copyOf(liquids, size);
|
||||
cacheFlow = null;
|
||||
cacheSums = null;
|
||||
displayFlow = null;
|
||||
flow = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+1
-1
@@ -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=68a04fab6e
|
||||
archash=7445105cd2
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
<true/>
|
||||
<key>UIRequiresFullScreen</key>
|
||||
<true/>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>LSSupportsOpeningDocumentsInPlace</key>
|
||||
<true/>
|
||||
<key>NSPhotoLibraryAddUsageDescription</key>
|
||||
|
||||
@@ -54,6 +54,7 @@ public class ServerLauncher implements ApplicationListener{
|
||||
mods.loadScripts();
|
||||
content.createModContent();
|
||||
content.init();
|
||||
mods.loadModPatches();
|
||||
|
||||
if(mods.hasContentErrors()){
|
||||
err("Error occurred loading mod content:");
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import arc.graphics.*;
|
||||
import mindustry.logic.*;
|
||||
import mindustry.logic.LExecutor.*;
|
||||
import org.junit.jupiter.api.*;
|
||||
@@ -122,7 +123,7 @@ public class LogicTests{
|
||||
Arguments.of("a bare single semicolon is invalid", ";", "invalid"),
|
||||
Arguments.of("a bare single space is invalid", " ", "invalid"),
|
||||
Arguments.of("a single ordinary character passes through unchanged", "a", "a"),
|
||||
Arguments.of("empty input stays empty", "", ""),
|
||||
Arguments.of("empty input gets converted to null", "", "null"),
|
||||
Arguments.of("a plain already-quoted value is untouched", "\"hello\"", "\"hello\""),
|
||||
Arguments.of("a unescaped quote at the end gets doubled", "\"hello\\\"", "\"hello\\\\\""),
|
||||
Arguments.of(
|
||||
@@ -243,6 +244,123 @@ public class LogicTests{
|
||||
);
|
||||
}
|
||||
|
||||
/** Values that must resolve to a numeric constant (isobj == false) or an object constant. */
|
||||
static Stream<Arguments> 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<Arguments> 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<String> 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}")
|
||||
@@ -336,4 +454,4 @@ public class LogicTests{
|
||||
void crlfLabelsResolveToTheSameJumpLocationAsLfLabels(){
|
||||
assertDoesNotThrow(() -> load("loop:\r\njump loop always\r\n"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,12 @@ public class SchemaGenerator{
|
||||
|
||||
var root = getTypeDecl(field.getDeclaringClass());
|
||||
if(root != null) root.getFieldByName(field.getName()).ifPresent(fdec -> {
|
||||
String[] docAndDefault = determineJavadocAndDefault(field, fdec, fdec.getVariables().getFirst().orElseThrow());
|
||||
var variable = fdec.getVariables().stream()
|
||||
.filter(v -> v.getNameAsString().equals(field.getName()))
|
||||
.findFirst().orElse(null);
|
||||
if(variable == null) return;
|
||||
|
||||
String[] docAndDefault = determineJavadocAndDefault(field, fdec, variable);
|
||||
if(docAndDefault[0] != null) inner.put("doc", docAndDefault[0]);
|
||||
if(docAndDefault[1] != null) inner.put("default", docAndDefault[1]);
|
||||
});
|
||||
@@ -302,8 +307,14 @@ public class SchemaGenerator{
|
||||
initValue = "[]";
|
||||
}
|
||||
|
||||
//field
|
||||
if(initValue.contains(".") && !(baseField.getType().isArray())){
|
||||
//numeric literal: drop the Java-only suffix (f/F/d/D/L), keep the decimal point for JSON
|
||||
boolean numeric = initValue.matches("-?(\\d+\\.?\\d*|\\.\\d+)([eE][-+]?\\d+)?[fFdDlL]?");
|
||||
if(numeric){
|
||||
initValue = initValue.replaceAll("[fFdDlL]$", "");
|
||||
}
|
||||
|
||||
//field reference, e.g. Category.turret -> turret (never applied to numbers)
|
||||
if(!numeric && initValue.contains(".") && !(baseField.getType().isArray())){
|
||||
var split = initValue.split("\\.");
|
||||
initValue = split[split.length - 1];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user