diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 64b7650e62..85459446aa 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -7,8 +7,6 @@ assignees: ''
---
-**Note**: Do not report any new bugs directly relating to the v6 campaign. They will not be fixed or considered at this time.
-
**Platform**: *Android/iOS/Mac/Windows/Linux*
**Build**: *The build number under the title in the main menu. Required. "LATEST" IS NOT A VERSION, I NEED THE EXACT BUILD NUMBER OF YOUR GAME.*
diff --git a/README.md b/README.md
index 5c9c797297..13f620832f 100644
--- a/README.md
+++ b/README.md
@@ -9,34 +9,34 @@ _[Trello Board](https://trello.com/b/aE2tcUwF/mindustry-40-plans)_
_[Wiki](https://mindustrygame.github.io/wiki)_
_[Javadoc](https://mindustrygame.github.io/docs/)_
-### Contributing
+## Contributing
See [CONTRIBUTING](CONTRIBUTING.md).
-### Building
+## Building
Bleeding-edge builds are generated automatically for every commit. You can see them [here](https://github.com/Anuken/MindustryBuilds/releases).
If you'd rather compile on your own, follow these instructions.
First, make sure you have [JDK 14](https://adoptopenjdk.net/) installed. Open a terminal in the root directory, `cd` to the Mindustry folder and run the following commands:
-#### Windows
+### Windows
_Running:_ `gradlew desktop:run`
_Building:_ `gradlew desktop:dist`
_Sprite Packing:_ `gradlew tools:pack`
-#### Linux/Mac OS
+### Linux/Mac OS
_Running:_ `./gradlew desktop:run`
_Building:_ `./gradlew desktop:dist`
_Sprite Packing:_ `./gradlew tools:pack`
-#### Server
+### Server
Server builds are bundled with each released build (in Releases). If you'd rather compile on your own, replace 'desktop' with 'server', e.g. `gradlew server:dist`.
-#### Android
+### Android
1. Install the Android SDK [here.](https://developer.android.com/studio#downloads) Make sure you're downloading the "Command line tools only", as Android Studio is not required.
2. Set the `ANDROID_HOME` environment variable to point to your unzipped Android SDK directory.
@@ -44,7 +44,9 @@ Server builds are bundled with each released build (in Releases). If you'd rathe
To debug the application on a connected phone, run `gradlew android:installDebug android:run`.
-##### Troubleshooting
+### Troubleshooting
+
+#### Permission Denied
If the terminal returns `Permission denied` or `Command not found` on Mac/Linux, run `chmod +x ./gradlew` before running `./gradlew`. *This is a one-time procedure.*
@@ -53,11 +55,11 @@ If the terminal returns `Permission denied` or `Command not found` on Mac/Linux,
Gradle may take up to several minutes to download files. Be patient.
After building, the output .JAR file should be in `/desktop/build/libs/Mindustry.jar` for desktop builds, and in `/server/build/libs/server-release.jar` for server builds.
-### Feature Requests
+## Feature Requests
Post feature requests and feedback [here](https://github.com/Anuken/Mindustry-Suggestions/issues/new/choose).
-### Downloads
+## Downloads
[
}SmtWKuXGqYz\P?E:Y
ΤԢh)(%UDK(.%#V0FN#
\ No newline at end of file
diff --git a/core/assets/baseparts/1603214967392.msch b/core/assets/baseparts/1603214967392.msch
new file mode 100644
index 0000000000..0e30b20a82
--- /dev/null
+++ b/core/assets/baseparts/1603214967392.msch
@@ -0,0 +1 @@
+mschx%A ᧀZc\.z$dФ/t?3o`Ɲ.L<$NV!b>=e%80r"^!GKug9耦{S_@+$jW\oJSM ܅0?CThqW
\ No newline at end of file
diff --git a/core/assets/baseparts/1603214996033.msch b/core/assets/baseparts/1603214996033.msch
new file mode 100644
index 0000000000..83690987ae
--- /dev/null
+++ b/core/assets/baseparts/1603214996033.msch
@@ -0,0 +1,3 @@
+mschx%
+ ӪmicC/{bU~A>:n^Xvw?ŧ[56ů'gX|qa=SAsCNNA0Q=Mb9MIDҒbQAјٟZ}<
+sFU.BI
\ No newline at end of file
diff --git a/core/assets/baseparts/1603215024189.msch b/core/assets/baseparts/1603215024189.msch
new file mode 100644
index 0000000000..75d8474c96
Binary files /dev/null and b/core/assets/baseparts/1603215024189.msch differ
diff --git a/core/assets/baseparts/1603215113546.msch b/core/assets/baseparts/1603215113546.msch
new file mode 100644
index 0000000000..bf1020f89f
--- /dev/null
+++ b/core/assets/baseparts/1603215113546.msch
@@ -0,0 +1,2 @@
+mschx%[n A}"
t'C$؎]
c.9gFcK8XƸ}>O}c|tt#-)䃑dqPҒr$b@*b2rtҳRZґ@Wr#
\ No newline at end of file
diff --git a/core/assets/baseparts/1603215171294.msch b/core/assets/baseparts/1603215171294.msch
new file mode 100644
index 0000000000..eaef917ff3
--- /dev/null
+++ b/core/assets/baseparts/1603215171294.msch
@@ -0,0 +1,2 @@
+mschx%ᎃ Ai߃pB`M
+!0;060/oK8J\k a|Tk~Sq)O-h_|M%35V⾸Ӌ\[}ٱ#ⶼ@0-'hh0@W@JCi4bjp2gㄽ_]䡎Eӱ-K+.
\ No newline at end of file
diff --git a/core/assets/baseparts/1603215272794.msch b/core/assets/baseparts/1603215272794.msch
new file mode 100644
index 0000000000..b2351a3857
--- /dev/null
+++ b/core/assets/baseparts/1603215272794.msch
@@ -0,0 +1 @@
+mschxMKn D1P$9yvtCY_%Jno>1-~K؎i?#BI%q;R8W;r˖#v)!F\7ٔoIy{4ïvg=!;^`4E`
ah:I:!u0hRFC7:TW0t=z*] %wX#H7G4}mWW03Įb6
e>
\ No newline at end of file
diff --git a/core/assets/baseparts/1603215345320.msch b/core/assets/baseparts/1603215345320.msch
new file mode 100644
index 0000000000..8c97534bdf
--- /dev/null
+++ b/core/assets/baseparts/1603215345320.msch
@@ -0,0 +1,4 @@
+mschxEn@\E!dͲ:iҐqvfاȇP^]|g7Bw
+Vp]ln5'?|`npr};МC0O[vM߆4vpߑ'*HY~2dJNV(BLr+bHw-cKM52e*WR!KL{X#SAJR5dCV6r]m`t~H覵RvX
+2HNk{8'L^+y#
+pU%%%JAJ$?M
\ No newline at end of file
diff --git a/core/assets/baseparts/1603215415778.msch b/core/assets/baseparts/1603215415778.msch
new file mode 100644
index 0000000000..6f7f75ab97
--- /dev/null
+++ b/core/assets/baseparts/1603215415778.msch
@@ -0,0 +1,2 @@
+mschx-k
+1MуP
PҮEdM?o2c1e_BϚ/guI08bI~e.pRwGO`madh{Nނ:'"IZ}äz}o)"
\ No newline at end of file
diff --git a/core/assets/baseparts/1603215454977.msch b/core/assets/baseparts/1603215454977.msch
new file mode 100644
index 0000000000..c0a53057ed
Binary files /dev/null and b/core/assets/baseparts/1603215454977.msch differ
diff --git a/core/assets/baseparts/1603215491407.msch b/core/assets/baseparts/1603215491407.msch
new file mode 100644
index 0000000000..ba578a4a55
--- /dev/null
+++ b/core/assets/baseparts/1603215491407.msch
@@ -0,0 +1,2 @@
+mschx5ኃ01mj9(h~H½eufCn
+jgA7}~K>@
}cNOv2a=oc\D[=qt0&?S(Р(p=R$тJT&geJIMʴ*~#d|EE4I#tFxpzpzʤ3% h'/4ol```SfffG?J
(,
\ No newline at end of file
diff --git a/core/assets/baseparts/1603215563717.msch b/core/assets/baseparts/1603215563717.msch
new file mode 100644
index 0000000000..460c1d9f8b
Binary files /dev/null and b/core/assets/baseparts/1603215563717.msch differ
diff --git a/core/assets/baseparts/1603215697527.msch b/core/assets/baseparts/1603215697527.msch
new file mode 100644
index 0000000000..427e52f671
Binary files /dev/null and b/core/assets/baseparts/1603215697527.msch differ
diff --git a/core/assets/baseparts/1603215771822.msch b/core/assets/baseparts/1603215771822.msch
new file mode 100644
index 0000000000..68ee586ea5
Binary files /dev/null and b/core/assets/baseparts/1603215771822.msch differ
diff --git a/core/assets/baseparts/1603215801163.msch b/core/assets/baseparts/1603215801163.msch
new file mode 100644
index 0000000000..09b9033d84
--- /dev/null
+++ b/core/assets/baseparts/1603215801163.msch
@@ -0,0 +1 @@
+mschx-[ DJJaQMӵ~g&31dSo=-q[[LޭFqav.0[
SA/ciF(dPD~+
\ No newline at end of file
diff --git a/core/assets/baseparts/1603216038407.msch b/core/assets/baseparts/1603216038407.msch
new file mode 100644
index 0000000000..85865ba123
Binary files /dev/null and b/core/assets/baseparts/1603216038407.msch differ
diff --git a/core/assets/baseparts/1603216102310.msch b/core/assets/baseparts/1603216102310.msch
new file mode 100644
index 0000000000..a05dbc61ed
--- /dev/null
+++ b/core/assets/baseparts/1603216102310.msch
@@ -0,0 +1 @@
+mschx%[j0EoؓK]e258 ;SJI]">O}\_~Hy
!K)
%Q5KzFNR2L/9uۋX|iX9u+8pz&։mOh!>t^m1%(M6Ae)
\ No newline at end of file
diff --git a/core/assets/baseparts/1603216240041.msch b/core/assets/baseparts/1603216240041.msch
new file mode 100644
index 0000000000..c0960c09d5
--- /dev/null
+++ b/core/assets/baseparts/1603216240041.msch
@@ -0,0 +1,3 @@
+mschxMIR0EJk.cp
+*cZrF_\n?2^x(RvHg^}N'ς$6r4Tl"=ZނbA4W'&wt3-l`PC?6s}+iyf$15a-~Y/gD>X
\ No newline at end of file
diff --git a/core/assets/baseparts/1603222833941.msch b/core/assets/baseparts/1603222833941.msch
new file mode 100644
index 0000000000..565eecf779
Binary files /dev/null and b/core/assets/baseparts/1603222833941.msch differ
diff --git a/core/assets/baseparts/1603222912251.msch b/core/assets/baseparts/1603222912251.msch
new file mode 100644
index 0000000000..6b33abac34
Binary files /dev/null and b/core/assets/baseparts/1603222912251.msch differ
diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties
index 4a854f5c71..f492a6f473 100644
--- a/core/assets/bundles/bundle.properties
+++ b/core/assets/bundles/bundle.properties
@@ -100,8 +100,7 @@ committingchanges = Comitting Changes
done = Done
feature.unsupported = Your device does not support this feature.
-mods.alphainfo = Keep in mind that mods are in alpha, and[scarlet] may be very buggy[].\nReport any issues you find to the Mindustry GitHub or Discord.
-mods.alpha = [accent](Alpha)
+mods.alphainfo = Keep in mind that mods are in alpha, and[scarlet] may be very buggy[].\nReport any issues you find to the Mindustry GitHub.
mods = Mods
mods.none = [lightgray]No mods found!
mods.guide = Modding Guide
@@ -285,6 +284,7 @@ selectschematic = [accent][[{0}][] to select+copy
pausebuilding = [accent][[{0}][] to pause building
resumebuilding = [scarlet][[{0}][] to resume building
wave = [accent]Wave {0}
+wave.cap = [accent]Wave {0}/{1}
wave.waiting = [lightgray]Wave in {0}
wave.waveInProgress = [lightgray]Wave in progress
waiting = [lightgray]Waiting...
@@ -421,6 +421,7 @@ filters.empty = [lightgray]No filters! Add one with the button below.
filter.distort = Distort
filter.noise = Noise
filter.enemyspawn = Enemy Spawn Select
+filter.spawnpath = Path To Spawn
filter.corespawn = Core Select
filter.median = Median
filter.oremedian = Ore Median
@@ -445,6 +446,7 @@ filter.option.amount = Amount
filter.option.block = Block
filter.option.floor = Floor
filter.option.flooronto = Target Floor
+filter.option.target = Target
filter.option.wall = Wall
filter.option.ore = Ore
filter.option.floor2 = Secondary Floor
@@ -478,7 +480,7 @@ requirement.research = Research {0}
requirement.capture = Capture {0}
bestwave = [lightgray]Best Wave: {0}
launch.text = Launch
-campaign.multiplayer = While playing multiplayer in campaign, you can only research using items from [accent]your[] sectors, [scarlet]not[] the host's sector that you are on right now.\n\nTo get items to [accent]your[] sectors in multiplayer, use a [accent]launch pad[].
+research.multiplayer = Only the host can research items.
uncover = Uncover
configure = Configure Loadout
#TODO
@@ -512,6 +514,7 @@ weather.rain.name = Rain
weather.snow.name = Snow
weather.sandstorm.name = Sandstorm
weather.sporestorm.name = Sporestorm
+weather.fog.name = Fog
sectors.unexplored = [lightgray]Unexplored
sectors.resources = Resources:
@@ -521,6 +524,8 @@ sectors.resume = Resume
sectors.launch = Launch
sectors.select = Select
sectors.nonelaunch = [lightgray]none (sun)
+sectors.rename = Rename Sector
+sector.missingresources = [scarlet]Insufficient Core Resources
planet.serpulo.name = Serpulo
#TODO better name
@@ -569,6 +574,10 @@ settings.clear.confirm = Are you sure you want to clear this data?\nWhat is done
settings.clearall.confirm = [scarlet]WARNING![]\nThis will clear all data, including saves, maps, unlocks and keybinds.\nOnce you press 'ok' the game will wipe all data and automatically exit.
settings.clearsaves.confirm = Are you sure you want to clear all your saves?
settings.clearsaves = Clear Saves
+settings.clearresearch = Clear Research
+settings.clearresearch.confirm = Are you sure you want to clear all of your campaign research?
+settings.clearcampaignsaves = Clear Campaign Saves
+settings.clearcampaignsaves.confirm = Are you sure you want to clear all of your campaign saves?
paused = [accent]< Paused >
clear = Clear
banned = [scarlet]Banned
@@ -580,50 +589,73 @@ error.title = [scarlet]An error has occured
error.crashtitle = An error has occured
unit.nobuild = [scarlet]Unit can't build
lastaccessed = [lightgray]Last Accessed: {0}
-blocks.input = Input
-blocks.output = Output
-blocks.booster = Booster
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = Power Capacity
-blocks.powershot = Power/Shot
-blocks.damage = Damage
-blocks.targetsair = Targets Air
-blocks.targetsground = Targets Ground
-blocks.itemsmoved = Move Speed
-blocks.launchtime = Time Between Launches
-blocks.shootrange = Range
-blocks.size = Size
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Liquid Capacity
-blocks.powerrange = Power Range
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Max Connections
-blocks.poweruse = Power Use
-blocks.powerdamage = Power/Damage
-blocks.itemcapacity = Item Capacity
-blocks.memorycapacity = Memory Capacity
-blocks.basepowergeneration = Base Power Generation
-blocks.productiontime = Production Time
-blocks.repairtime = Block Full Repair Time
-blocks.speedincrease = Speed Increase
-blocks.range = Range
-blocks.drilltier = Drillables
-blocks.drillspeed = Base Drill Speed
-blocks.boosteffect = Boost Effect
-blocks.maxunits = Max Active Units
-blocks.health = Health
-blocks.buildtime = Build Time
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Build Cost
-blocks.inaccuracy = Inaccuracy
-blocks.shots = Shots
-blocks.reload = Shots/Second
-blocks.ammo = Ammo
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+
+stat.input = Input
+stat.output = Output
+stat.booster = Booster
+stat.tiles = Required Tiles
+stat.affinities = Affinities
+stat.powercapacity = Power Capacity
+stat.powershot = Power/Shot
+stat.damage = Damage
+stat.targetsair = Targets Air
+stat.targetsground = Targets Ground
+stat.itemsmoved = Move Speed
+stat.launchtime = Time Between Launches
+stat.shootrange = Range
+stat.size = Size
+stat.displaysize = Display Size
+stat.liquidcapacity = Liquid Capacity
+stat.powerrange = Power Range
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Max Connections
+stat.poweruse = Power Use
+stat.powerdamage = Power/Damage
+stat.itemcapacity = Item Capacity
+stat.memorycapacity = Memory Capacity
+stat.basepowergeneration = Base Power Generation
+stat.productiontime = Production Time
+stat.repairtime = Block Full Repair Time
+stat.speedincrease = Speed Increase
+stat.range = Range
+stat.drilltier = Drillables
+stat.drillspeed = Base Drill Speed
+stat.boosteffect = Boost Effect
+stat.maxunits = Max Active Units
+stat.health = Health
+stat.buildtime = Build Time
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Build Cost
+stat.inaccuracy = Inaccuracy
+stat.shots = Shots
+stat.reload = Shots/Second
+stat.ammo = Ammo
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
+stat.explosiveness = Explosiveness
+stat.basedeflectchance = Base Deflect Chance
+stat.lightningchance = Lightning Chance
+stat.lightningdamage = Lightning Damage
+stat.flammability = Flammability
+stat.radioactivity = Radioactivity
+stat.heatcapacity = HeatCapacity
+stat.viscosity = Viscosity
+stat.temperature = Temperature
+stat.speed = Speed
+stat.buildspeed = Build Speed
+stat.minespeed = Mine Speed
+stat.minetier = Mine Tier
+stat.payloadcapacity = Payload Capacity
+stat.commandlimit = Command Limit
+stat.abilities = Abilities
+
+ability.forcefield = Force Field
+ability.repairfield = Repair Field
+ability.statusfield = Status Field
+ability.unitspawn = {0} Factory
+ability.shieldregenfield = Shield Regen Field
bar.drilltierreq = Better Drill Required
bar.noresources = Missing Resources
@@ -664,6 +696,7 @@ bullet.multiplier = [stat]{0}[lightgray]x ammo multiplier
bullet.reload = [stat]{0}[lightgray]x fire rate
unit.blocks = blocks
+unit.blockssquared = blocks²
unit.powersecond = power units/second
unit.liquidsecond = liquid units/second
unit.itemssecond = items/second
@@ -695,7 +728,6 @@ setting.linear.name = Linear Filtering
setting.hints.name = Hints
setting.flow.name = Display Resource Flow Rate
setting.buildautopause.name = Auto-Pause Building
-setting.mapcenter.name = Auto Center Map To Player
setting.animatedwater.name = Animated Fluids
setting.animatedshields.name = Animated Shields
setting.antialias.name = Antialias[lightgray] (requires restart)[]
@@ -729,7 +761,6 @@ setting.fullscreen.name = Fullscreen
setting.borderlesswindow.name = Borderless Window[lightgray] (restart may be required)
setting.fps.name = Show FPS & Ping
setting.smoothcamera.name = Smooth Camera
-setting.blockselectkeys.name = Show Block Select Keys
setting.vsync.name = VSync
setting.pixelate.name = Pixelate
setting.minimap.name = Show Minimap
@@ -876,6 +907,7 @@ content.item.name = Items
content.liquid.name = Liquids
content.unit.name = Units
content.block.name = Blocks
+
item.copper.name = Copper
item.lead.name = Lead
item.coal.name = Coal
@@ -897,23 +929,6 @@ liquid.slag.name = Slag
liquid.oil.name = Oil
liquid.cryofluid.name = Cryofluid
-item.explosiveness = [lightgray]Explosiveness: {0}%
-item.flammability = [lightgray]Flammability: {0}%
-item.radioactivity = [lightgray]Radioactivity: {0}%
-
-unit.health = [lightgray]Health: {0}
-unit.speed = [lightgray]Speed: {0}
-unit.weapon = [lightgray]Weapon: {0}
-unit.itemcapacity = [lightgray]Item Capacity: {0}
-unit.minespeed = [lightgray]Mining Speed: {0}%
-unit.minepower = [lightgray]Mining Power: {0}
-unit.ability = [lightgray]Ability: {0}
-unit.buildspeed = [lightgray]Building Speed: {0}%
-
-liquid.heatcapacity = [lightgray]Heat Capacity: {0}
-liquid.viscosity = [lightgray]Viscosity: {0}
-liquid.temperature = [lightgray]Temperature: {0}
-
unit.dagger.name = Dagger
unit.mace.name = Mace
unit.fortress.name = Fortress
@@ -1325,5 +1340,4 @@ block.cyclone.description = A large anti-air and anti-ground turret. Fires explo
block.spectre.description = A massive dual-barreled cannon. Shoots large armor-piercing bullets at air and ground targets.
block.meltdown.description = A massive laser cannon. Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate.
block.repair-point.description = Continuously heals the closest damaged unit in its vicinity.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
-
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_be.properties b/core/assets/bundles/bundle_be.properties
index f62aba4377..590d8094f2 100644
--- a/core/assets/bundles/bundle_be.properties
+++ b/core/assets/bundles/bundle_be.properties
@@ -570,49 +570,49 @@ info.title = Інфармацыя
error.title = [crimson]Адбылася памылка
error.crashtitle = Адбылася памылка
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Уваход
-blocks.output = Выхад
-blocks.booster = Паскаральнік
-blocks.tiles = Неабходныя пліткі
-blocks.affinities = Павелічэнне эфектыўнасці
+stat.input = Уваход
+stat.output = Выхад
+stat.booster = Паскаральнік
+stat.tiles = Неабходныя пліткі
+stat.affinities = Павелічэнне эфектыўнасці
block.unknown = [lightgray]???
-blocks.powercapacity = Умяшчальнасць энергіі
-blocks.powershot = Энергія/Выстрэл
-blocks.damage = Страты
-blocks.targetsair = Паветраныя мэты
-blocks.targetsground = Наземныя мэты
-blocks.itemsmoved = Хуткасць перамяшчэння
-blocks.launchtime = Інтэрвал запускаў
-blocks.shootrange = Радыус дзеяння
-blocks.size = Памер
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Умяшчальнасць вадкасці
-blocks.powerrange = Далёкасць перадачы энергіі
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Колькасць злучэнняў
-blocks.poweruse = Спажывае энергіі
-blocks.powerdamage = Энергія/страты
-blocks.itemcapacity = Умяшчальнасць прадметаў
-blocks.basepowergeneration = Базавая генерацыя энергіі
-blocks.productiontime = Час вытворчасці
-blocks.repairtime = Час поўнай рэгенерацыі
-blocks.speedincrease = Павелічэнне хуткасці
-blocks.range = Радыус дзеяння
-blocks.drilltier = Бурит
-blocks.drillspeed = Базавая хуткасць свідравання
-blocks.boosteffect = паскараўся эфект
-blocks.maxunits = Максімальная колькасць актыўных адзінак
-blocks.health = Здароўе
-blocks.buildtime = Час будаўніцтва
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Кошт будаўніцтва
-blocks.inaccuracy = Роскід
-blocks.shots = Стрэлы
-blocks.reload = Стрэлы/секунду
-blocks.ammo = Боепрыпасы
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Умяшчальнасць энергіі
+stat.powershot = Энергія/Выстрэл
+stat.damage = Страты
+stat.targetsair = Паветраныя мэты
+stat.targetsground = Наземныя мэты
+stat.itemsmoved = Хуткасць перамяшчэння
+stat.launchtime = Інтэрвал запускаў
+stat.shootrange = Радыус дзеяння
+stat.size = Памер
+stat.displaysize = Display Size
+stat.liquidcapacity = Умяшчальнасць вадкасці
+stat.powerrange = Далёкасць перадачы энергіі
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Колькасць злучэнняў
+stat.poweruse = Спажывае энергіі
+stat.powerdamage = Энергія/страты
+stat.itemcapacity = Умяшчальнасць прадметаў
+stat.basepowergeneration = Базавая генерацыя энергіі
+stat.productiontime = Час вытворчасці
+stat.repairtime = Час поўнай рэгенерацыі
+stat.speedincrease = Павелічэнне хуткасці
+stat.range = Радыус дзеяння
+stat.drilltier = Бурит
+stat.drillspeed = Базавая хуткасць свідравання
+stat.boosteffect = паскараўся эфект
+stat.maxunits = Максімальная колькасць актыўных адзінак
+stat.health = Здароўе
+stat.buildtime = Час будаўніцтва
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Кошт будаўніцтва
+stat.inaccuracy = Роскід
+stat.shots = Стрэлы
+stat.reload = Стрэлы/секунду
+stat.ammo = Боепрыпасы
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Патрабуецца свідар лепей
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = Вялікая турэль, якая можа ве
block.spectre.description = Масіўная двуствольное гармата. Страляе буйнымі бранябойнымі кулямі па паветраных і наземных мэтах.
block.meltdown.description = Масіўная лазерная гармата. Зараджае і страляе пастаянным лазерным прамянём ў бліжэйшых ворагаў. Патрабуецца астуджальная вадкасць для працы.
block.repair-point.description = Бесперапынна лечыць бліжэйшую пашкоджаную баявую адзінку або мех у сваім радыусе.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_cs.properties b/core/assets/bundles/bundle_cs.properties
index 8bcd567380..dc8d7b55d1 100644
--- a/core/assets/bundles/bundle_cs.properties
+++ b/core/assets/bundles/bundle_cs.properties
@@ -20,7 +20,7 @@ gameover = Konec hry
gameover.pvp = Vyhrál tým [accent]{0}[]!
highscore = [accent]Nový rekord!
copied = Zkopírováno.
-indev.popup = [accent]v6[] is currently in [accent]alpha[].\n[lightgray]This means:[]\n[scarlet]- The campaign is completely unfinished[]\n- Content is missing\n - Most [scarlet]Unit AI[] does not work properly\n- Many units are unfinished\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[].
+indev.popup = Mindustry [accent]v6[] je aktuálně ve verzi [accent]beta[].\n[lightgray]To znamená:[]\n[scarlet]- Kampaň je nedokončená[]\n- SFX a hudba je nedokončená nebo chybí\n- Cokoli, co vidíte, se může změnit nebo být odstraněno.\n\nHlaste prosím chyby na [accent]Github[].
indev.notready = Tato část hry ještě není připravena
load.sound = Zvuky
@@ -100,8 +100,7 @@ committingchanges = Provádím změny
done = Hotovo
feature.unsupported = Tvoje zařízení nepodporuje tuto vlastnost hry.
-mods.alphainfo = Měj na paměti, že modifikace jsou stále v alfa fázi vývoje a mohou být [scarlet]velmi chybové[].\nNahlaš, prosím, jakékoliv závady na GitHub nebo Discord serveru Mindustry. Děkujeme!
-mods.alpha = [accent](Alfa)[]
+mods.alphainfo = Měj na paměti, že modifikace jsou stále v alfa fázi vývoje a mohou být [scarlet]velmi chybové[].\nNahlaš, prosím, jakékoliv závady na GitHub Mindustry. Děkujeme!
mods = Mody
mods.none = [lightgray]Modifikace nebyly nalezeny.[]
mods.guide = Průvodce modifikacemi
@@ -279,18 +278,21 @@ quit.confirm.tutorial = Jsi si jistý?Výuku je možné znovu spustit v [accent]
loading = [accent]Načítám...
reloading = [accent]Načítám modifikace...
saving = [accent]Ukládám...
-respawn = [accent][[{0}][] k znovyzrození v jádře
+respawn = [accent][[{0}][] k znovuzrození v jádře
cancelbuilding = [accent][[{0}][] vyčistí plán šablony
selectschematic = [accent][[{0}][] provede výběr a zkopírování
pausebuilding = [accent][[{0}][] zastaví stavění
resumebuilding = [scarlet][[{0}][] bude pokračovat ve stavění
wave = [accent]Vlna číslo {0}[]
+wave.cap = [accent]Vlna {0} z {1}[]
wave.waiting = [lightgray]Vlna za {0} vteřin[]
wave.waveInProgress = [lightgray]Vlna přichází![]
waiting = [lightgray]Čekám...[]
waiting.players = Čekání na hráče...
wave.enemies = [lightgray]{0} zbývajících nepřátel
wave.enemy = [lightgray]{0} zbývající nepřítel
+wave.guardianwarn = Počet vln do příchodu strážce: [accent]{0}[].
+wave.guardianwarn.one = [accent]Strážce přijde již příští vlnu![]
loadimage = Nahrát obrázek
saveimage = Uložit obrázek
unknown = Neznámý
@@ -329,6 +331,7 @@ editor.generation = Generace:
editor.ingame = Upravit ve hře
editor.publish.workshop = Vystavit ve Workshopu na Steamu
editor.newmap = Nová mapa
+editor.center = Vycentrovat
workshop = Workshop na Steamu
waves.title = Vlny
waves.remove = Odebrat
@@ -338,7 +341,7 @@ waves.waves = vln(y)
waves.perspawn = za zrození
waves.shields = štítů/vlnu
waves.to = do
-waves.guardian = Guardian
+waves.guardian = Strážce
waves.preview = Náhled
waves.edit = Upravit....
waves.copy = Uložit do schránky
@@ -475,7 +478,7 @@ requirement.research = Vynalezeno {0}
requirement.capture = Polapeno {0}
bestwave = [lightgray]Nejvyšší vlna: {0}
launch.text = Vyslat
-campaign.multiplayer = Když hraješ kampaň ve hře více hráčů, můžeš vynalézat pouze pomocí věcí ze [accent]svých[] sektorů, [scarlet]ne[] ze sektoru hostitele, kde jsi právě teď.\n\nAbys získal věci do [accent]svých[] sektorů ve hře více hráčů, použij [accent]vysílací plošinu[].
+research.multiplayer = Jen hostitel hry může vynalézat nové technologie.
uncover = Odkrýt mapu
configure = Přizpůsobit vybavení
#TODO
@@ -502,7 +505,7 @@ error.mismatch = Chyba při komunikaci se serverem:\nVerze klienta a serveru se
error.alreadyconnected = Připojeni k serveru.
error.mapnotfound = Soubor s mapou nebyl nalezen!
error.io = Vstupně/výstupní (I/O) chyba sítě.
-error.any = Ueznámá chyba sítě.
+error.any = Neznámá chyba sítě.
error.bloom = Chyba inicializace filtru Bloom.\nTvé zařízení ho nejspíš nepodporuje.
weather.rain.name = Déšť
@@ -517,7 +520,12 @@ sectors.stored = Uskladněno:
sectors.resume = Pokračovat
sectors.launch = Vyslat
sectors.select = Vybrat
-sectors.nonelaunch = [lightgray]žádné (slunce)[]
+sectors.nonelaunch = [lightgray]bez (slunce)[]
+sectors.rename = Přejmenovat sektor
+
+planet.serpulo.name = Serpulo
+#TODO better name
+planet.sun.name = Sol
#NOTE TO TRANSLATORS: don't bother editing these, they'll be removed and/or rewritten anyway
sector.groundZero.name = Základní tábor
@@ -560,8 +568,8 @@ settings.graphics = Grafika
settings.cleardata = Vymazat data hry...
settings.clear.confirm = Jsi si jistý, že chceš vymazat Tvá data ve hře?\nTento krok je nevratný!
settings.clearall.confirm = [scarlet]Varování![]\nToto vyresetuje všechna Tvá data ve hře, včetně uložení hry, map, odemknutého postupu v kampani a nastavení ovládání.\nJakmile stiskneš "OK", všechna data se vymažou a hra se automaticky ukončí.
-settings.clearsaves.confirm = Are you sure you want to clear all your saves?
-settings.clearsaves = Clear Saves
+settings.clearsaves.confirm = Opravdu chceš vymazat veškeré Tvé uložené hry?
+settings.clearsaves = Vymazat uložené hry
paused = [accent]< Pozastaveno >[]
clear = Vyčistit
banned = [scarlet]Zakázán[]
@@ -572,50 +580,52 @@ info.title = Informace
error.title = [scarlet]Objevila se chyba[]
error.crashtitle = Objevila se chyba
unit.nobuild = [scarlet]Jednotka nemůže stavět
-blocks.input = Vstup
-blocks.output = Výstup
-blocks.booster = Posilovač
-blocks.tiles = Vyžadované dlaždice
-blocks.affinities = Synergie
+
+lastaccessed = [lightgray]Naposledy použil: {0}
+stat.input = Vstup
+stat.output = Výstup
+stat.booster = Posilovač
+stat.tiles = Vyžadované dlaždice
+stat.affinities = Synergie
block.unknown = [lightgray]???[]
-blocks.powercapacity = Kapacita energie
-blocks.powershot = Energie na 1 výstřel
-blocks.damage = Poškození
-blocks.targetsair = Zaměřuje vzdušné jednotky
-blocks.targetsground = Zaměřuje pozemní jednotky
-blocks.itemsmoved = Rychlost pohybu
-blocks.launchtime = Čas mezi vysláním
-blocks.shootrange = Dostřel
-blocks.size = Velikost
-blocks.displaysize = Velikost zobrazovače
-blocks.liquidcapacity = Kapacita kapalin
-blocks.powerrange = Rozsah energie
-blocks.linkrange = Dosah napojení
-blocks.instructions = Instrukce
-blocks.powerconnections = Nejvyšší počet spojení
-blocks.poweruse = Spotřeba energie
-blocks.powerdamage = Energie na jednotku poškození
-blocks.itemcapacity = Kapacita předmětů
-blocks.memorycapacity = Kapacita paměti
-blocks.basepowergeneration = Základní generování energie
-blocks.productiontime = Čas produkce
-blocks.repairtime = Čas do úplné opravy
-blocks.speedincrease = Zvýšení rychlosti
-blocks.range = Dosah
-blocks.drilltier = Lze těžit
-blocks.drillspeed = Základní rychlost vrtu
-blocks.boosteffect = Účinek posílení
-blocks.maxunits = Nejvýše aktivních jednotek
-blocks.health = Životy
-blocks.buildtime = Čas stavby
-blocks.maxconsecutive = Nejvýše po sobě
-blocks.buildcost = Cena stavby
-blocks.inaccuracy = Nepřesnost
-blocks.shots = Střely
-blocks.reload = Střel za 1s
-blocks.ammo = Střelivo
-blocks.shieldhealth = Zdraví štítu
-blocks.cooldowntime = Čas na zchladnutí
+stat.powercapacity = Kapacita energie
+stat.powershot = Energie na 1 výstřel
+stat.damage = Poškození
+stat.targetsair = Zaměřuje vzdušné jednotky
+stat.targetsground = Zaměřuje pozemní jednotky
+stat.itemsmoved = Rychlost pohybu
+stat.launchtime = Čas mezi vysláním
+stat.shootrange = Dostřel
+stat.size = Velikost
+stat.displaysize = Velikost zobrazovače
+stat.liquidcapacity = Kapacita kapalin
+stat.powerrange = Rozsah energie
+stat.linkrange = Dosah napojení
+stat.instructions = Instrukce
+stat.powerconnections = Nejvyšší počet spojení
+stat.poweruse = Spotřeba energie
+stat.powerdamage = Energie na jednotku poškození
+stat.itemcapacity = Kapacita předmětů
+stat.memorycapacity = Kapacita paměti
+stat.basepowergeneration = Základní generování energie
+stat.productiontime = Čas produkce
+stat.repairtime = Čas do úplné opravy
+stat.speedincrease = Zvýšení rychlosti
+stat.range = Dosah
+stat.drilltier = Lze těžit
+stat.drillspeed = Základní rychlost vrtu
+stat.boosteffect = Účinek posílení
+stat.maxunits = Nejvýše aktivních jednotek
+stat.health = Životy
+stat.buildtime = Čas stavby
+stat.maxconsecutive = Nejvýše po sobě
+stat.buildcost = Cena stavby
+stat.inaccuracy = Nepřesnost
+stat.shots = Střely
+stat.reload = Střel za 1s
+stat.ammo = Střelivo
+stat.shieldhealth = Zdraví štítu
+stat.cooldowntime = Čas na zchladnutí
bar.drilltierreq = Je vyžadován lepší vrt
bar.noresources = Chybějí zdroje
@@ -627,6 +637,7 @@ bar.powerbalance = Energie: {0}
bar.powerstored = Uskladněno: {0}/{1}
bar.poweramount = Energie celkem: {0}
bar.poweroutput = Výstup energie: {0}
+bar.powerlines = Spojení: {0}/{1}
bar.items = Předměty: {0}
bar.capacity = Kapacita: {0}
bar.unitcap = {0} {1}/{2}
@@ -646,11 +657,13 @@ bullet.incendiary = [stat]zápalné
bullet.homing = [stat]samonaváděcí
bullet.shock = [stat]šokové
bullet.frag = [stat]trhavé
-bullet.knockback = [stat]{0}[lightgray] odhození
-bullet.freezing = [stat]mrazivé
-bullet.tarred = [stat]dehtové
-bullet.multiplier = [stat]{0}[lightgray]x více střel
-bullet.reload = [stat]{0}[lightgray]x rychlost střelby
+bullet.knockback = [stat]{0}[lightgray] odhození[]
+bullet.pierce = [stat]{0}[lightgray]x průrazné[]
+bullet.infinitepierce = [stat]průrazné[]
+bullet.freezing = [stat]zmrazující[]
+bullet.tarred = [stat]dehtující[]
+bullet.multiplier = [stat]{0}[lightgray]x více střel[]
+bullet.reload = [stat]{0}[lightgray]x rychlost střelby[]
unit.blocks = bloky
unit.powersecond = energie/sekunda
@@ -684,7 +697,6 @@ setting.linear.name = Lineární filtrování
setting.hints.name = Rady a tipy
setting.flow.name = Zobrazit rychlost toku zdroje [scarlet](experimentální)[]
setting.buildautopause.name = Automaticky pozastavit stavění
-setting.mapcenter.name = Auto Center Map To Player
setting.animatedwater.name = Animované tekutiny
setting.animatedshields.name = Animované štíty
setting.antialias.name = Použít antialias [lightgray](vyžaduje restart)[]
@@ -718,7 +730,6 @@ setting.fullscreen.name = Celá obrazovka
setting.borderlesswindow.name = Bezokrajové okno[lightgray] (může výt vyžadován restart)[]
setting.fps.name = Ukázat FPS a ping
setting.smoothcamera.name = Plynulá kamera
-setting.blockselectkeys.name = Ukázat klávesy při práci s blokem
setting.vsync.name = Vertikální synchronizace
setting.pixelate.name = Rozpixlovat
setting.minimap.name = Ukázat mapičku
@@ -761,7 +772,7 @@ keybind.press = Stiskni klávesu...
keybind.press.axis = Stiskni osu ovladače nebo klávesu...
keybind.screenshot.name = Snímek mapy
keybind.toggle_power_lines.name = Přepnout zobrazení energetického vedení
-keybind.toggle_block_status.name = Toggle Block Statuses
+keybind.toggle_block_status.name = Přepnout stav bloku
keybind.move_x.name = Pohyb vodorovně
keybind.move_y.name = Pohyb svisle
keybind.mouse_move.name = Následovat myš
@@ -943,6 +954,7 @@ block.cliff.name = Útes
block.sand-boulder.name = Pískovec
block.grass.name = Tráva
block.slag.name = Slag
+block.space.name = Vesmír
block.salt.name = Sůl
block.salt-wall.name = Solné skály
block.pebbles.name = Oblázky
@@ -988,8 +1000,9 @@ block.darksand-water.name = Voda s černým pískem
block.char.name = Dřevěné uhlí
block.dacite.name = Dacit
block.dacite-wall.name = Stěna dacitu
+block.dacite-boulder.name = Dacitový kámen
block.ice-snow.name = Zasněžený led
-block.stone-wall.name = Stone Wall
+block.stone-wall.name = Kamenné skály
block.ice-wall.name = Ledové skály
block.snow-wall.name = Sněhové skály
block.dune-wall.name = Písečné duny
@@ -1034,7 +1047,7 @@ block.hail.name = Kroupomet
block.lancer.name = Kopiník
block.conveyor.name = Dopravník
block.titanium-conveyor.name = Titanoový dopravník
-block.plastanium-conveyor.name = Plastanium Conveyor
+block.plastanium-conveyor.name = Plastanový přepravník
block.armored-conveyor.name = Obrněný dopravník
block.armored-conveyor.description = Přepravuje předměty stejně rychle jako titanový přepravník, ale má navíc brnění. Přijímá předměty ze srtan pouze z jiných přepravníků.
block.junction.name = Křižovatka
@@ -1261,7 +1274,7 @@ block.rotary-pump.description = Pokročilé čerpadlo, které za pomoci energie
block.thermal-pump.description = Ultimátní čerpadlo. Nejrychlejší čerpání kapalin.
block.conduit.description = Základní blok pro přepravu kapalin. Unáší kapaliny vpřed. Používá se s čerpadly, v některých vrtech a nebo ve spojení s jiným potrubím.
block.pulse-conduit.description = Pokročilý blok přepravy kapalin. Přepravuje kapaliny rychleji a má větší kapacitu, než základní potrubí.
-block.plated-conduit.description = Přenáší kapaliny stejně rychle jako pulzní potrubí, ale díky oplátování má větší výdržnost. Ze stran přijímá kapaliny pouze z dalších potrubí.\nV případě poškození má menší ztrátu kapaliny.
+block.plated-conduit.description = Přenáší kapaliny stejně rychle jako pulzní potrubí, ale díky oplátování má větší výdržnost. Ze stran přijímá kapaliny pouze z dalších potrubí.\nNedochází zde k úniku kapalin.
block.liquid-router.description = Přijímá kapaliny z jednoho směru a vypouští je rovnoměrně do zbylých tří směrů. Dokáže pojmout i určitý objem kapalin do vnitřího úložiště. Používá se při rozdělení kapaliny z jednoho zdroje směřující do různých cílů.
block.liquid-tank.description = Ukládá velké množství kapalin. Používá se pro vyrovnávání zásob vody, když je přítok nestabilní nebo jako záložní chlazení pro životně důležité stavby.
block.liquid-junction.description = Chová se jako most pro dvě křížící se potrubí. Používá se v situacích, kdy dvě rozdílná potrubí vedou rozdílný obsah přes jedno místo.
@@ -1312,4 +1325,4 @@ block.cyclone.description = Velká protiletecká a protipozemní střílna. Pál
block.spectre.description = Velká střílna s kanónem s dvěma hlavněmi. Střílí velké náboje, které pronikají brněním jak pozemních, tak vzdušných nepřátelských cílů.
block.meltdown.description = Masivní laserový kanón. Nabije se a pak pálí nepřetržitý laserový paprsek na nepřátele v okolí. Vyžaduje ke své funkci chlazení.
block.repair-point.description = Nepřetržitě léčí nejbližší poškozenou jednotku v poli své působnosti.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Poškozuje a ničí příchozí střely. Laserové střely ale zacílit neumí.
diff --git a/core/assets/bundles/bundle_da.properties b/core/assets/bundles/bundle_da.properties
index 0e9d2ce889..b65afebcd3 100644
--- a/core/assets/bundles/bundle_da.properties
+++ b/core/assets/bundles/bundle_da.properties
@@ -570,49 +570,49 @@ info.title = Info
error.title = [crimson]An error has occured
error.crashtitle = An error has occured
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Input
-blocks.output = Output
-blocks.booster = Booster
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
+stat.input = Input
+stat.output = Output
+stat.booster = Booster
+stat.tiles = Required Tiles
+stat.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = Power Capacity
-blocks.powershot = Power/Shot
-blocks.damage = Damage
-blocks.targetsair = Targets Air
-blocks.targetsground = Targets Ground
-blocks.itemsmoved = Move Speed
-blocks.launchtime = Time Between Launches
-blocks.shootrange = Range
-blocks.size = Size
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Liquid Capacity
-blocks.powerrange = Power Range
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Max Connections
-blocks.poweruse = Power Use
-blocks.powerdamage = Power/Damage
-blocks.itemcapacity = Item Capacity
-blocks.basepowergeneration = Base Power Generation
-blocks.productiontime = Production Time
-blocks.repairtime = Block Full Repair Time
-blocks.speedincrease = Speed Increase
-blocks.range = Range
-blocks.drilltier = Drillables
-blocks.drillspeed = Base Drill Speed
-blocks.boosteffect = Boost Effect
-blocks.maxunits = Max Active Units
-blocks.health = Health
-blocks.buildtime = Build Time
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Build Cost
-blocks.inaccuracy = Inaccuracy
-blocks.shots = Shots
-blocks.reload = Shots/Second
-blocks.ammo = Ammo
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Power Capacity
+stat.powershot = Power/Shot
+stat.damage = Damage
+stat.targetsair = Targets Air
+stat.targetsground = Targets Ground
+stat.itemsmoved = Move Speed
+stat.launchtime = Time Between Launches
+stat.shootrange = Range
+stat.size = Size
+stat.displaysize = Display Size
+stat.liquidcapacity = Liquid Capacity
+stat.powerrange = Power Range
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Max Connections
+stat.poweruse = Power Use
+stat.powerdamage = Power/Damage
+stat.itemcapacity = Item Capacity
+stat.basepowergeneration = Base Power Generation
+stat.productiontime = Production Time
+stat.repairtime = Block Full Repair Time
+stat.speedincrease = Speed Increase
+stat.range = Range
+stat.drilltier = Drillables
+stat.drillspeed = Base Drill Speed
+stat.boosteffect = Boost Effect
+stat.maxunits = Max Active Units
+stat.health = Health
+stat.buildtime = Build Time
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Build Cost
+stat.inaccuracy = Inaccuracy
+stat.shots = Shots
+stat.reload = Shots/Second
+stat.ammo = Ammo
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Better Drill Required
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = A large anti-air and anti-ground turret. Fires explo
block.spectre.description = A massive dual-barreled cannon. Shoots large armor-piercing bullets at air and ground targets.
block.meltdown.description = A massive laser cannon. Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate.
block.repair-point.description = Continuously heals the closest damaged unit in its vicinity.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_de.properties b/core/assets/bundles/bundle_de.properties
index 67311e3451..5d02ed2f85 100644
--- a/core/assets/bundles/bundle_de.properties
+++ b/core/assets/bundles/bundle_de.properties
@@ -570,49 +570,49 @@ info.title = Info
error.title = [crimson]Ein Fehler ist aufgetreten
error.crashtitle = Ein Fehler ist aufgetreten!
unit.nobuild = [scarlet]Einheit kann nicht bauen!
-blocks.input = Eingang
-blocks.output = Ausgang
-blocks.booster = Verstärkung
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
+stat.input = Eingang
+stat.output = Ausgang
+stat.booster = Verstärkung
+stat.tiles = Required Tiles
+stat.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = Kapazität
-blocks.powershot = Stromverbrauch/Schuss
-blocks.damage = Schaden
-blocks.targetsair = Visiert Lufteinheiten an
-blocks.targetsground = Visiert Bodeneinheiten an
-blocks.itemsmoved = Bewegungsgeschwindigkeit
-blocks.launchtime = Zeit zwischen Starts
-blocks.shootrange = Reichweite
-blocks.size = Größe
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Flüssigkeitskapazität
-blocks.powerrange = Stromreichweite
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Maximale Stromverbindungen
-blocks.poweruse = Stromverbrauch
-blocks.powerdamage = Stromverbrauch/Schadenspunkt
-blocks.itemcapacity = Materialkapazität
-blocks.basepowergeneration = Basis-Stromerzeugung
-blocks.productiontime = Produktionszeit
-blocks.repairtime = Zeit zur vollständigen Reparatur
-blocks.speedincrease = Geschwindigkeitserhöhung
-blocks.range = Reichweite
-blocks.drilltier = Abbaubare Erze
-blocks.drillspeed = Bohrgeschwindigkeit
-blocks.boosteffect = Verstärkungseffekt
-blocks.maxunits = Max. aktive Einheiten
-blocks.health = Lebenspunkte
-blocks.buildtime = Baudauer
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Baukosten
-blocks.inaccuracy = Ungenauigkeit
-blocks.shots = Schüsse
-blocks.reload = Schüsse/Sekunde
-blocks.ammo = Munition
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Kapazität
+stat.powershot = Stromverbrauch/Schuss
+stat.damage = Schaden
+stat.targetsair = Visiert Lufteinheiten an
+stat.targetsground = Visiert Bodeneinheiten an
+stat.itemsmoved = Bewegungsgeschwindigkeit
+stat.launchtime = Zeit zwischen Starts
+stat.shootrange = Reichweite
+stat.size = Größe
+stat.displaysize = Display Size
+stat.liquidcapacity = Flüssigkeitskapazität
+stat.powerrange = Stromreichweite
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Maximale Stromverbindungen
+stat.poweruse = Stromverbrauch
+stat.powerdamage = Stromverbrauch/Schadenspunkt
+stat.itemcapacity = Materialkapazität
+stat.basepowergeneration = Basis-Stromerzeugung
+stat.productiontime = Produktionszeit
+stat.repairtime = Zeit zur vollständigen Reparatur
+stat.speedincrease = Geschwindigkeitserhöhung
+stat.range = Reichweite
+stat.drilltier = Abbaubare Erze
+stat.drillspeed = Bohrgeschwindigkeit
+stat.boosteffect = Verstärkungseffekt
+stat.maxunits = Max. aktive Einheiten
+stat.health = Lebenspunkte
+stat.buildtime = Baudauer
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Baukosten
+stat.inaccuracy = Ungenauigkeit
+stat.shots = Schüsse
+stat.reload = Schüsse/Sekunde
+stat.ammo = Munition
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Besserer Bohrer Benötigt
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = Ein großer Schnellfeuer-Geschützturm.
block.spectre.description = Ein großer Geschützturm, der zwei starke Schüsse gleichzeitig abfeuert.
block.meltdown.description = Ein großer Geschützturm, der starke Strahlen mit großer Reichweite abfeuert.
block.repair-point.description = Heilt durchgehend die nächste befreundete, beschädigte Einheit in der Umgebung.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_es.properties b/core/assets/bundles/bundle_es.properties
index 8c538a6974..dd5c9d0951 100644
--- a/core/assets/bundles/bundle_es.properties
+++ b/core/assets/bundles/bundle_es.properties
@@ -2,14 +2,14 @@ credits.text = Creado por [royal]Anuken[] - [sky]anukendev@gmail.com[]
credits = Créditos
contributors = Traductores y Contribuidores
discord = ¡Únete al Discord de Mindustry!
-link.discord.description = La sala oficial del Discord de Mindustry
+link.discord.description = El servidor official de Discord de Mindustry
link.reddit.description = El subreddit de Mindustry
link.github.description = Código fuente del juego
link.changelog.description = Lista de actualizaciones
-link.dev-builds.description = Versiones de desarrollo inestables
+link.dev-builds.description = Versiones en desarrollo inestables
link.trello.description = Tablero de Trello oficial para las características planificadas
link.itch.io.description = itch.io es la página donde podes descargar las versiones para PC y web
-link.google-play.description = Ficha en la Google Play Store
+link.google-play.description = Página de Mindustry en Google Play Store
link.f-droid.description = Página de F-Droid del juego
link.wiki.description = Wiki oficial de Mindustry
link.suggestions.description = Sugerir nuevas funciones
@@ -18,10 +18,10 @@ screenshot = Captura de pantalla guardada en {0}
screenshot.invalid = Mapa demasiado grande, no hay suficiente memoria para la captura de pantalla.
gameover = Tu núcleo ha sido destruido.
gameover.pvp = ¡El equipo[accent] {0}[] ha ganado!
-highscore = [accent]¡Nueva mejor puntuación!
+highscore = [accent]¡Nuevo récord de puntuación!
copied = Copiado.
-indev.popup = [accent]v6[] is currently in [accent]alpha[].\n[lightgray]This means:[]\n[scarlet]- The campaign is completely unfinished[]\n- Content is missing\n - Most [scarlet]Unit AI[] does not work properly\n- Many units are unfinished\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[].
-indev.notready = This part of the game isn't ready yet
+indev.popup = La [accent]v6[] esta actualmente en la [accent]alpha[].\n[lightgray]Esto significa:[]\n[scarlet]- La campaña no esta completada[]\n- Falta contenido\n - La mayoría de la [scarlet]Inteligencia Artificial[] no funciona correctamente\n- Muchas unidades no están terminadas\n- Todo lo que ves puede ser modificado o eliminado en la versión final.\n\nReporta bugs o crasheos en [accent]Github[].
+indev.notready = Esta parte del juego no esta lista aún.
load.sound = Sonidos
load.map = Mapas
@@ -38,12 +38,12 @@ be.ignore = Ignorar
be.noupdates = No se encontraron actualizaciones.
be.check = Revisando actualizaciones
-schematic = Esquemático
-schematic.add = Guardar esquemático...
-schematics = Esquemáticos
-schematic.replace = Un esquemático con ese nombre ya existe. ¿Deseas remplazarlo?
-schematic.exists = Un esquemático con ese nombre ya existe.
-schematic.import = Importar esquemático...
+schematic = Esquema
+schematic.add = Guardar esquema...
+schematics = Esquemas
+schematic.replace = Un esquema con ese nombre ya existe. ¿Deseas remplazarlo?
+schematic.exists = Un esquema con ese nombre ya existe.
+schematic.import = Importar esquema...
schematic.exportfile = Exportar archivo
schematic.importfile = Importar archivo
schematic.browseworkshop = Buscar en el Steam Workshop
@@ -103,19 +103,19 @@ mods.alphainfo = Ten en cuenta que los mods estan en versión Alpha, y[scarlet]
mods.alpha = [accent](Alpha)
mods = Mods
mods.none = [lightgray]No se encontraron Mods!
-mods.guide = Guia de Modding
+mods.guide = Guía de Modding
mods.report = Reportar Error
mods.openfolder = Abrir carpeta de mods
-mods.reload = Reload
-mods.reloadexit = The game will now exit, to reload mods.
+mods.reload = Recargar
+mods.reloadexit = El juego se va a cerrar para recargar los mods.
mod.display = [gray]Mod:[orange] {0}
mod.enabled = [lightgray]Activado
mod.disabled = [scarlet]Desactivado
mod.disable = Desactivar
-mod.content = Content:
+mod.content = Contenido:
mod.delete.error = Fallo al elminar el mod. Quizás el archivo esta en uso.
mod.requiresversion = [scarlet]Requiere mínima versión del juego: [accent]{0}
-mod.outdated = [scarlet]Not compatible with V6 (no minGameVersion: 105)
+mod.outdated = [scarlet]No es compatible con la V6 (no minGameVersion: 105)
mod.missingdependencies = [scarlet]Dependencias faltantes: {0}
mod.erroredcontent = [scarlet]Errores de contenido
mod.errors = Ocurrieron fallos al cargar el contenido.
@@ -125,9 +125,9 @@ mod.enable = Activar
mod.requiresrestart = El juego se cerrará para aplicar los mods.
mod.reloadrequired = [scarlet]Se requiere actualizar
mod.import = Importar mod
-mod.import.file = Import File
+mod.import.file = Importar archivo
mod.import.github = Importar Mod de Github
-mod.jarwarn = [scarlet]JAR mods are inherently unsafe.[]\nMake sure you're importing this mod from a trustworthy source!
+mod.jarwarn = [scarlet]Los mods JAR pueden ser inseguros.[]\nAsegúrate de que los descargaste de una fuente segura!
mod.item.remove = Este objeto es parte del[accent] '{0}'[] mod. Para eliminarlo, desinstala ese mod.
mod.remove.confirm = Este mod va a ser eliminado.\n¿Quieres continuar?
mod.author = [lightgray]Autor:[] {0}
@@ -139,8 +139,8 @@ mod.scripts.disable = Tu dispositivo no soporta los mods con scripts. Debes desh
about.button = Acerca de
name = Nombre:
noname = Elige un[accent] nombre de jugador[] primero.
-planetmap = Planet Map
-launchcore = Launch Core
+planetmap = Mapa del planeta
+launchcore = Lanzar núcleo
filename = Nombre del archivo:
unlocked = ¡Nuevo Bloque Desbloqueado!
completed = [accent]Completado
@@ -278,7 +278,7 @@ quit.confirm.tutorial = ¿Estás seguro de que sabes qué estas haciendo?\nSe pu
loading = [accent]Cargando...
reloading = [accent]Recargando mods...
saving = [accent]Guardando...
-respawn = [accent][[{0}][] to respawn in core
+respawn = [accent][[{0}][] para reaparecer en el núcleo
cancelbuilding = [accent][[{0}][] para limpiar el plan
selectschematic = [accent][[{0}][] para seleccionar+copiar
pausebuilding = [accent][[{0}][] para pausar la construcción
@@ -346,9 +346,9 @@ waves.invalid = Oleadas inválidaas en el portapapeles.
waves.copied = Oleadas copiadas.
waves.none = No hay enemigos definidos.\nNótese que las listas de oleadas vacías se sustituirán por la lista por defecto.
-wavemode.counts = counts
-wavemode.totals = totals
-wavemode.health = health
+wavemode.counts = Cuentas
+wavemode.totals = Totales
+wavemode.health = Salud
editor.default = [lightgray]
details = Detalles...
@@ -415,8 +415,8 @@ toolmode.drawteams.description = Dibuja equipos en vez de bloques.
filters.empty = [lightgray]¡No hay filtros! Añade uno con el botón de abajo.
filter.distort = Distorsionar
filter.noise = Ruido
-filter.enemyspawn = Enemy Spawn Select
-filter.corespawn = Core Select
+filter.enemyspawn = Elegir punto de aparición enemigo
+filter.corespawn = Elegir Núcleo
filter.median = Median
filter.oremedian = Veta Median
filter.blend = Mezcla
@@ -436,7 +436,7 @@ filter.option.circle-scale = Escala del círculo
filter.option.octaves = Octaves
filter.option.falloff = Caída
filter.option.angle = Ángulo
-filter.option.amount = Amount
+filter.option.amount = Cantidad
filter.option.block = Bloque
filter.option.floor = Suelo
filter.option.flooronto = Suelo objetivo
@@ -508,31 +508,31 @@ error.io = Error I/O de conexión.
error.any = Error de red desconocido.
error.bloom = Error al cargar el bloom.\nPuede que tu dispositivo no soporte esta característica.
-weather.rain.name = Rain
-weather.snow.name = Snow
-weather.sandstorm.name = Sandstorm
-weather.sporestorm.name = Sporestorm
+weather.rain.name = Lluvia
+weather.snow.name = Nieve
+weather.sandstorm.name = Tormenta de arena
+weather.sporestorm.name = Tormenta de esporas
-sectors.unexplored = [lightgray]Unexplored
-sectors.resources = Resources:
-sectors.production = Production:
-sectors.stored = Stored:
-sectors.resume = Resume
-sectors.launch = Launch
-sectors.select = Select
-sectors.nonelaunch = [lightgray]none (sun)
+sectors.unexplored = [lightgray]No explorado
+sectors.resources = Recursos:
+sectors.production = Producción:
+sectors.stored = Almacenado:
+sectors.resume = Reanudar
+sectors.launch = Lanzar
+sectors.select = Elegir
+sectors.nonelaunch = [lightgray]ninguno (sun)
-sector.groundZero.name = Ground Zero
-sector.craters.name = The Craters
-sector.frozenForest.name = Frozen Forest
-sector.ruinousShores.name = Ruinous Shores
-sector.stainedMountains.name = Stained Mountains
-sector.desolateRift.name = Desolate Rift
-sector.nuclearComplex.name = Nuclear Production Complex
-sector.overgrowth.name = Overgrowth
-sector.tarFields.name = Tar Fields
-sector.saltFlats.name = Salt Flats
-sector.fungalPass.name = Fungal Pass
+sector.groundZero.name = Terreno Zero
+sector.craters.name = Los Cráteres
+sector.frozenForest.name = Bosque Congelado
+sector.ruinousShores.name = Costas Ruinosas
+sector.stainedMountains.name = Montañas manchadas
+sector.desolateRift.name = Grieta desolada
+sector.nuclearComplex.name = Complejo de producción nuclear
+sector.overgrowth.name = Crecimiento excesivo
+sector.tarFields.name = Campos de alquitrán
+sector.saltFlats.name = Llanuras de sal
+sector.fungalPass.name = Paso de hongos
sector.groundZero.description = The optimal location to begin once more. Low enemy threat. Few resources.\nGather as much lead and copper as possible.\nMove on.
sector.frozenForest.description = Even here, closer to mountains, the spores have spread. The frigid temperatures cannot contain them forever.\n\nBegin the venture into power. Build combustion generators. Learn to use menders.
@@ -558,65 +558,67 @@ settings.graphics = Gráficos
settings.cleardata = Limpiar Datos del Juego...
settings.clear.confirm = ¿Estas seguro de querer limpiar estos datos?\n¡Esta acción no puede deshacerse!
settings.clearall.confirm = [scarlet]ADVERTENCIA![]\nEsto va a eliminar todos tus datos, incluyendo guardados, mapas, desbloqueos y atajos de teclado.\nUna vez presiones 'ok', el juego va a borrrar todos tus datos y saldrá del juego automáticamente.
-settings.clearsaves.confirm = Are you sure you want to clear all your saves?
-settings.clearsaves = Clear Saves
+settings.clearsaves.confirm = Estas seguro de que quieres borrar tus partidas guardadas?
+settings.clearsaves = Limpiar partidas guardadas
paused = [accent] < Pausado >
clear = Limpiar
banned = [scarlet]Baneado
-unplaceable.sectorcaptured = [scarlet]Requires captured sector
+unplaceable.sectorcaptured = [scarlet]Necesita que el sector esté capturado.
yes = Sí
no = No
info.title = [accent]Información
error.title = [crimson]Un error ha ocurrido.
error.crashtitle = Un error ha ocurrido.
-unit.nobuild = [scarlet]Unit can't build
-blocks.input = Entrada
-blocks.output = Salida
-blocks.booster = Potenciador
-blocks.tiles = Tiles requeridos
-blocks.affinities = Afinidades
+
+unit.nobuild = [scarlet]La unidad no puede construir
block.unknown = [lightgray]???
-blocks.powercapacity = Capacidad de Energía
-blocks.powershot = Energía/Disparo
-blocks.damage = Daño
-blocks.targetsair = Apunta al Aire
-blocks.targetsground = Apunta a Tierra
-blocks.itemsmoved = Velocidad de movimiento
-blocks.launchtime = Tiempo entre lanzamientos
-blocks.shootrange = Rango de Disparo
-blocks.size = Tamaño
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Capacidad de Líquidos
-blocks.powerrange = Rango de Energía
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Conexiones maximas
-blocks.poweruse = Consumo de Energía
-blocks.powerdamage = Energía/Daño
-blocks.itemcapacity = Capacidad de Objetos
-blocks.basepowergeneration = Generación de energía base
-blocks.productiontime = Tiempo de producción
-blocks.repairtime = Tiempo para Reparar Bloque Completamente
-blocks.speedincrease = Aumento de Velocidad
-blocks.range = Rango
-blocks.drilltier = Taladrables
-blocks.drillspeed = Velocidad Base del Taladro
-blocks.boosteffect = Efecto del Potenciador
-blocks.maxunits = Máximo de Unidades Activas
-blocks.health = Vida
-blocks.buildtime = Tiempo de construcción
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Coste de construcción
-blocks.inaccuracy = Imprecisión
-blocks.shots = Disparos
-blocks.reload = Recarga
-blocks.ammo = Munición
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+
+stat.input = Entrada
+stat.output = Salida
+stat.booster = Potenciador
+stat.tiles = Tiles requeridos
+stat.affinities = Afinidades
+stat.powercapacity = Capacidad de Energía
+stat.powershot = Energía/Disparo
+stat.damage = Daño
+stat.targetsair = Apunta al Aire
+stat.targetsground = Apunta a Tierra
+stat.itemsmoved = Velocidad de movimiento
+stat.launchtime = Tiempo entre lanzamientos
+stat.shootrange = Rango de Disparo
+stat.size = Tamaño
+stat.displaysize = Tamaño mostrado
+stat.liquidcapacity = Capacidad de Líquidos
+stat.powerrange = Rango de Energía
+stat.linkrange = Rango de conexión
+stat.instructions = Instructions
+stat.powerconnections = Conexiones maximas
+stat.poweruse = Consumo de Energía
+stat.powerdamage = Energía/Daño
+stat.itemcapacity = Capacidad de Objetos
+stat.basepowergeneration = Generación de energía base
+stat.productiontime = Tiempo de producción
+stat.repairtime = Tiempo para Reparar Bloque Completamente
+stat.speedincrease = Aumento de Velocidad
+stat.range = Rango
+stat.drilltier = Taladrables
+stat.drillspeed = Velocidad Base del Taladro
+stat.boosteffect = Efecto del Potenciador
+stat.maxunits = Máximo de Unidades Activas
+stat.health = Vida
+stat.buildtime = Tiempo de construcción
+stat.maxconsecutive = Máximo consecutivo
+stat.buildcost = Coste de construcción
+stat.inaccuracy = Imprecisión
+stat.shots = Disparos
+stat.reload = Recarga
+stat.ammo = Munición
+stat.shieldhealth = Salud del escudo
+stat.cooldowntime = Tiempo de enfriamiento
bar.drilltierreq = Se requiere un mejor taladro.
-bar.noresources = Missing Resources
-bar.corereq = Core Base Required
+bar.noresources = Recursos faltantes
+bar.corereq = Se requiere de un núcleo base
bar.drillspeed = Velocidad del Taladro: {0}/s
bar.pumpspeed = Velocidad de bombeado: {0}/s
bar.efficiency = Eficiencia: {0}%
@@ -660,7 +662,7 @@ unit.persecond = /seg
unit.perminute = /min
unit.timesspeed = x velocidad
unit.percent = %
-unit.shieldhealth = shield health
+unit.shieldhealth = salud del escudo
unit.items = objetos
unit.thousands = k
unit.millions = M
@@ -677,13 +679,13 @@ setting.shadows.name = Sombras
setting.blockreplace.name = Sugerir bloques al construir
setting.linear.name = Filtrado Lineal
setting.hints.name = Pistas
-setting.flow.name = Display Resource Flow Rate[scarlet] (experimental)
+setting.flow.name = Mostrar flujo de recursos[scarlet] (experimental)
setting.buildautopause.name = Auto-pausar construcción
-setting.mapcenter.name = Auto Center Map To Player
+setting.mapcenter.name = Auto-centrar el mapa en el jugador
setting.animatedwater.name = Agua Animada
setting.animatedshields.name = Escudos Animados
-setting.antialias.name = Antialias[lightgray] (necesita reiniciar)[]
-setting.playerindicators.name = Player Indicators
+setting.antialias.name = Antialias[lightgray] (necesita un reinicio)[]
+setting.playerindicators.name = Indicadores de jugadores
setting.indicators.name = Indicadores de Aliados
setting.autotarget.name = Auto apuntado
setting.keyboard.name = Controles de Ratón+Teclado
@@ -702,7 +704,7 @@ setting.difficulty.name = Dificultad:
setting.screenshake.name = Movimiento de la Pantalla
setting.effects.name = Mostrar Efectos
setting.destroyedblocks.name = Mostrar bloques destruidos
-setting.blockstatus.name = Display Block Status
+setting.blockstatus.name = Mostrar estado de los bloques
setting.conveyorpathfinding.name = Colocación del transportador en búsqueda de caminos
setting.sensitivity.name = Sensibilidad del Control
setting.saveinterval.name = Intervalo del Autoguardado
@@ -712,7 +714,7 @@ setting.milliseconds = {0} milisegundos
setting.fullscreen.name = Pantalla Completa
setting.borderlesswindow.name = Ventana sin Bordes[lightgray] (podría requerir un reinicio)
setting.fps.name = Mostrar FPS
-setting.smoothcamera.name = Smooth Camera
+setting.smoothcamera.name = Cámara suave
setting.blockselectkeys.name = Mostrar teclas de selección de bloque
setting.vsync.name = Vsync (Limita los fps a los Hz de tu pantalla)
setting.pixelate.name = Pixelar [lightgray](podría reducir el rendimiento)
@@ -743,27 +745,27 @@ keybinds.mobile = [scarlet]Los accesos del teclado aquí mostrados no estan disp
category.general.name = General
category.view.name = Visión
category.multiplayer.name = Multijugador
-category.blocks.name = Block Select
+category.blocks.name = Seleccionar bloques
command.attack = Atacar
command.rally = Patrullar
command.retreat = Retirarse
-command.idle = Idle
-placement.blockselectkeys = \n[lightgray]Key: [{0},
-keybind.respawn.name = Respawn
-keybind.control.name = Control Unit
+command.idle = Esperar
+placement.blockselectkeys = \n[lightgray]LLaves: [{0},
+keybind.respawn.name = Reaparecer
+keybind.control.name = Controlar unidad
keybind.clear_building.name = Eliminar construcción
keybind.press = Presiona una tecla...
keybind.press.axis = Pulsa un eje o botón...
keybind.screenshot.name = Captura de pantalla de Mapa
keybind.toggle_power_lines.name = Activar láser de potencia
-keybind.toggle_block_status.name = Toggle Block Statuses
+keybind.toggle_block_status.name = Cambiar estado de los bloques
keybind.move_x.name = Mover x
keybind.move_y.name = Mover y
keybind.mouse_move.name = Seguír al ratón
-keybind.pan.name = Pan View
-keybind.boost.name = Boost
+keybind.pan.name = Vista Pan
+keybind.boost.name = Potenciar
keybind.schematic_select.name = Seleccionar región
-keybind.schematic_menu.name = Menu de esquématicos
+keybind.schematic_menu.name = Menu de esquemas
keybind.schematic_flip_x.name = Girar esquemático desde X
keybind.schematic_flip_y.name = Girar esquemático desde Y
keybind.category_prev.name = Categoría anterior
@@ -839,20 +841,20 @@ rules.buildspeedmultiplier = Multiplicador de velocidad de construcción
rules.deconstructrefundmultiplier = Multiplicador de Devolución de Desconstrucción
rules.waitForWaveToEnd = Las oleadas esperan a los enemigos
rules.dropzoneradius = Radio de zona de caída:[lightgray] (casillas)
-rules.unitammo = Units Require Ammo
+rules.unitammo = Las unidades necesitan munición
rules.title.waves = Oleadas
rules.title.resourcesbuilding = Recursos y Construcción
rules.title.enemy = Enemigos
rules.title.unit = Unidades
rules.title.experimental = Experimental
-rules.title.environment = Environment
+rules.title.environment = Entorno
rules.lighting = Iluminación
rules.fire = Fire
-rules.explosions = Block/Unit Explosion Damage
+rules.explosions = Daño de explosiones de Bloques/Unidades
rules.ambientlight = Iluminación ambiental
-rules.weather = Weather
-rules.weather.frequency = Frequency:
-rules.weather.duration = Duration:
+rules.weather = Clima
+rules.weather.frequency = Frecuencia:
+rules.weather.duration = Duración:
content.item.name = Objetos
content.liquid.name = Líquidos
@@ -886,18 +888,18 @@ item.radioactivity = [lightgray]Radioactividad: {0}
unit.health = [lightgray]Vida: {0}
unit.speed = [lightgray]Velocidad: {0}
unit.weapon = [lightgray]Weapon: {0}
-unit.itemcapacity = [lightgray]Item Capacity: {0}
-unit.minespeed = [lightgray]Mining Speed: {0}%
-unit.minepower = [lightgray]Mining Power: {0}
-unit.ability = [lightgray]Ability: {0}
-unit.buildspeed = [lightgray]Building Speed: {0}%
+unit.itemcapacity = [lightgray]Capacidad de ítems: {0}
+unit.minespeed = [lightgray]Velocidad de minado: {0}%
+unit.minepower = [lightgray]Poder de minado: {0}
+unit.ability = [lightgray]Habilidad: {0}
+unit.buildspeed = [lightgray]Velocidad de construcción: {0}%
liquid.heatcapacity = [lightgray]Capacidad Térmica: {0}
liquid.viscosity = [lightgray]Viscosidad: {0}
liquid.temperature = [lightgray]Temperatura: {0}
unit.dagger.name = Daga
-unit.mace.name = Mace
+unit.mace.name = Mazo
unit.fortress.name = Fortaleza
unit.nova.name = Nova
unit.pulsar.name = Pulsar
@@ -907,8 +909,8 @@ unit.atrax.name = Atrax
unit.spiroct.name = Spiroct
unit.arkyid.name = Arkyid
unit.toxopid.name = Toxopid
-unit.flare.name = Flare
-unit.horizon.name = Horizon
+unit.flare.name = Llama
+unit.horizon.name = Horizonte
unit.zenith.name = Zenith
unit.antumbra.name = Antumbra
unit.eclipse.name = Eclipse
@@ -925,33 +927,33 @@ unit.omura.name = Omura
unit.alpha.name = Alpha
unit.beta.name = Beta
unit.gamma.name = Gamma
-unit.scepter.name = Scepter
+unit.scepter.name = Cetro
unit.reign.name = Reign
unit.vela.name = Vela
-unit.corvus.name = Corvus
+unit.corvus.name = Corvo
-block.resupply-point.name = Resupply Point
+block.resupply-point.name = Punto de reabastecimiento
block.parallax.name = Parallax
-block.cliff.name = Cliff
+block.cliff.name = Acantilado
block.sand-boulder.name = Piedra de Arena
block.grass.name = Hierba
-block.slag.name = Slag
+block.slag.name = Escoria
block.salt.name = Sal
-block.salt-wall.name = Salt Wall
+block.salt-wall.name = Pared de sal
block.pebbles.name = Guijarros
block.tendrils.name = Zarcillos
-block.sand-wall.name = Sand Wall
+block.sand-wall.name = Pared de arena
block.spore-pine.name = Pino de esporas
-block.spore-wall.name = Spore Wall
+block.spore-wall.name = Pared de esporas
block.boulder.name = Boulder
-block.snow-boulder.name = Snow Boulder
+block.snow-boulder.name = Piedra nevosa
block.snow-pine.name = Pino de nieve
block.shale.name = Pizarra
block.shale-boulder.name = Piedra de Pizarra
block.moss.name = Musgo
block.shrubs.name = Arbustos
block.spore-moss.name = Musgo de esporas
-block.shale-wall.name = Shale Wall
+block.shale-wall.name = Pared de shale
block.scrap-wall.name = Muro de Chatarra
block.scrap-wall-large.name = Muro de Chatarra grande
block.scrap-wall-huge.name = Muro de Chatarra muy grande
@@ -979,17 +981,17 @@ block.craters.name = Cráteres
block.sand-water.name = Agua con Arena
block.darksand-water.name = Agua con Arena Oscura
block.char.name = Carbonizado
-block.dacite.name = Dacite
-block.dacite-wall.name = Dacite Wall
+block.dacite.name = Dacita
+block.dacite-wall.name = Pared de Dacita
block.ice-snow.name = Hielo Nieve
-block.stone-wall.name = Stone Wall
-block.ice-wall.name = Ice Wall
-block.snow-wall.name = Snow Wall
-block.dune-wall.name = Dune Wall
+block.stone-wall.name = Pared de piedra
+block.ice-wall.name = Pared de hielo
+block.snow-wall.name = Pared de nieve
+block.dune-wall.name = Pared de duna
block.pine.name = Pino
-block.dirt.name = Dirt
-block.dirt-wall.name = Dirt Wall
-block.mud.name = Mud
+block.dirt.name = Tierra
+block.dirt-wall.name = Pared de tierra
+block.mud.name = Lodo
block.white-tree-dead.name = Árbol Blanco Muerto
block.white-tree.name = Árbol Blanco
block.spore-cluster.name = Concentración de Esporas
@@ -1005,7 +1007,7 @@ block.dark-panel-4.name = Panel Oscuro 4
block.dark-panel-5.name = Panel Oscuro 5
block.dark-panel-6.name = Panel Oscuro 6
block.dark-metal.name = Metal Oscuro
-block.basalt.name = Basalt
+block.basalt.name = Basalto
block.hotrock.name = Roca Caliente
block.magmarock.name = Roca de Magma
block.copper-wall.name = Muro de Cobre
@@ -1117,34 +1119,34 @@ block.meltdown.name = Fusión de Reactor
block.container.name = Contenedor
block.launch-pad.name = Pad de Lanzamiento
block.launch-pad-large.name = Pad de Lanzamiento Grande
-block.segment.name = Segment
-block.command-center.name = Command Center
-block.ground-factory.name = Ground Factory
-block.air-factory.name = Air Factory
-block.naval-factory.name = Naval Factory
-block.additive-reconstructor.name = Additive Reconstructor
-block.multiplicative-reconstructor.name = Multiplicative Reconstructor
-block.exponential-reconstructor.name = Exponential Reconstructor
-block.tetrative-reconstructor.name = Tetrative Reconstructor
-block.payload-conveyor.name = Mass Conveyor
-block.payload-router.name = Payload Router
-block.disassembler.name = Disassembler
-block.silicon-crucible.name = Silicon Crucible
-block.overdrive-dome.name = Overdrive Dome
+block.segment.name = Segmento
+block.command-center.name = Centro de comando
+block.ground-factory.name = Fábrica terrestre
+block.air-factory.name = Fábrica aérea
+block.naval-factory.name = Fábrica naval
+block.additive-reconstructor.name = Reconstructor aditivo
+block.multiplicative-reconstructor.name = Reconstructor multiplicativo
+block.exponential-reconstructor.name = Reconstructor exponencial
+block.tetrative-reconstructor.name = Reconstructor tetrativo
+block.payload-conveyor.name = Cinta de transporte masivo
+block.payload-router.name = Enrutador Payload
+block.disassembler.name = Desmontador
+block.silicon-crucible.name = Crisol de Silicio
+block.overdrive-dome.name = Domo de sobremarcha
-block.switch.name = Switch
-block.micro-processor.name = Micro Processor
-block.logic-processor.name = Logic Processor
-block.hyper-processor.name = Hyper Processor
-block.logic-display.name = Logic Display
-block.large-logic-display.name = Large Logic Display
-block.memory-cell.name = Memory Cell
+block.switch.name = Cambio
+block.micro-processor.name = Micro Procesador
+block.logic-processor.name = Procesador Lógico
+block.hyper-processor.name = Hiper Procesador
+block.logic-display.name = Pantalla Lógica
+block.large-logic-display.name = Pantalla Lógica grande
+block.memory-cell.name = Célula de memoria
team.blue.name = Azul
team.crux.name = rojo
team.sharded.name = naranja
team.orange.name = Naranja
-team.derelict.name = derelict
+team.derelict.name = Abandonado
team.green.name = Verde
team.purple.name = Púrpura
@@ -1302,4 +1304,4 @@ block.cyclone.description = Una torre grande anti-aérea y anti-terrestre. Dispa
block.spectre.description = Un cañon masivo de dos barriles. Dispara balas perforantes a objetivos de aire y tierra.
block.meltdown.description = Un cañon láser masivo. Carga y dispara un rayo láser constante a enemigos cercanos. Requiere enfriamiento para operar.
block.repair-point.description = Repara la unidad dañada más cercana a su alrededor.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Daña y destruye proyectiles enemigos. No apunta a láseres.
diff --git a/core/assets/bundles/bundle_et.properties b/core/assets/bundles/bundle_et.properties
index d5ac8cfb74..62b0002df6 100644
--- a/core/assets/bundles/bundle_et.properties
+++ b/core/assets/bundles/bundle_et.properties
@@ -570,49 +570,49 @@ info.title = Info
error.title = [crimson]Viga
error.crashtitle = Viga
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Sisend
-blocks.output = Väljund
-blocks.booster = Kiirendaja
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
+stat.input = Sisend
+stat.output = Väljund
+stat.booster = Kiirendaja
+stat.tiles = Required Tiles
+stat.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = Energiamahtuvus
-blocks.powershot = Energia ühikut/lasu kohta
-blocks.damage = Hävituspunkte
-blocks.targetsair = Sihib õhku
-blocks.targetsground = Sihib maapinnale
-blocks.itemsmoved = Transportimise kiirus
-blocks.launchtime = Aeg lendutõusude vahel
-blocks.shootrange = Ulatus
-blocks.size = Suurus
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Vedelike mahutavus
-blocks.powerrange = Energia ulatus
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Max Connections
-blocks.poweruse = Energiatarve
-blocks.powerdamage = Energiatarve hävituspunkti kohta
-blocks.itemcapacity = Ressursside mahutavus
-blocks.basepowergeneration = Energiatootlus
-blocks.productiontime = Tootmisaeg
-blocks.repairtime = Täieliku parandamise aeg
-blocks.speedincrease = Kiiruse suurenemine
-blocks.range = Ulatus
-blocks.drilltier = Kaevandatav
-blocks.drillspeed = Puurimise kiirus
-blocks.boosteffect = Kiirendaja mõju
-blocks.maxunits = Maks. aktiivseid väeüksuseid
-blocks.health = Elud
-blocks.buildtime = Ehitamise aeg
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Ehitamise maksumus
-blocks.inaccuracy = Ebatäpsus
-blocks.shots = Laske
-blocks.reload = Lasku/s
-blocks.ammo = Laskemoon
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Energiamahtuvus
+stat.powershot = Energia ühikut/lasu kohta
+stat.damage = Hävituspunkte
+stat.targetsair = Sihib õhku
+stat.targetsground = Sihib maapinnale
+stat.itemsmoved = Transportimise kiirus
+stat.launchtime = Aeg lendutõusude vahel
+stat.shootrange = Ulatus
+stat.size = Suurus
+stat.displaysize = Display Size
+stat.liquidcapacity = Vedelike mahutavus
+stat.powerrange = Energia ulatus
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Max Connections
+stat.poweruse = Energiatarve
+stat.powerdamage = Energiatarve hävituspunkti kohta
+stat.itemcapacity = Ressursside mahutavus
+stat.basepowergeneration = Energiatootlus
+stat.productiontime = Tootmisaeg
+stat.repairtime = Täieliku parandamise aeg
+stat.speedincrease = Kiiruse suurenemine
+stat.range = Ulatus
+stat.drilltier = Kaevandatav
+stat.drillspeed = Puurimise kiirus
+stat.boosteffect = Kiirendaja mõju
+stat.maxunits = Maks. aktiivseid väeüksuseid
+stat.health = Elud
+stat.buildtime = Ehitamise aeg
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Ehitamise maksumus
+stat.inaccuracy = Ebatäpsus
+stat.shots = Laske
+stat.reload = Lasku/s
+stat.ammo = Laskemoon
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Nõuab paremat puuri
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = Suur lendavate ja maapealsete väeüksuste vastane k
block.spectre.description = Massiivne kaheraudne kahur, mis tulistab soomuskatteid läbistavaid mürske nii lendavate kui ka maapealsete väeüksuste pihta.
block.meltdown.description = Massiivne laserkahur, mis tekitab püsiva energiakiire. Vajab töötamiseks jahutusvedelikku.
block.repair-point.description = Parandab kõige lähemal asuvat liitlaste väeüksust.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_eu.properties b/core/assets/bundles/bundle_eu.properties
index 5ef1a41b71..7afde97031 100644
--- a/core/assets/bundles/bundle_eu.properties
+++ b/core/assets/bundles/bundle_eu.properties
@@ -570,49 +570,49 @@ info.title = Informazioa
error.title = [crimson]Errore bat gertatu da
error.crashtitle = Errore bat gertatu da
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Sarrera
-blocks.output = Irteera
-blocks.booster = Indargarria
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
+stat.input = Sarrera
+stat.output = Irteera
+stat.booster = Indargarria
+stat.tiles = Required Tiles
+stat.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = Energia-edukiera
-blocks.powershot = Energia/tiroko
-blocks.damage = Kaltea
-blocks.targetsair = Airera tirokatzen du
-blocks.targetsground = Lurrera tirokatzen du
-blocks.itemsmoved = Garraio-abiadura
-blocks.launchtime = Egozketen arteko denbora
-blocks.shootrange = Irismena
-blocks.size = Neurria
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Likido-edukiera
-blocks.powerrange = Energia irismena
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Gehieneko konexioak
-blocks.poweruse = Energia-erabilera
-blocks.powerdamage = Energia/Kaltea
-blocks.itemcapacity = Elementu-edukiera
-blocks.basepowergeneration = Oinarrizko energia sorrera
-blocks.productiontime = Eraikitze denbora
-blocks.repairtime = Blokearen konpontze denbora osoa
-blocks.speedincrease = Abiadura areagotzea
-blocks.range = Irismena
-blocks.drilltier = Ustiagarriak
-blocks.drillspeed = Oinarrizko ustiatze-abiadura
-blocks.boosteffect = Indartze-efektua
-blocks.maxunits = Gehieneko unitate aktiboak
-blocks.health = Osasuna
-blocks.buildtime = Eraikitze-denbora
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Eraikitze-kostua
-blocks.inaccuracy = Zehazgabetasuna
-blocks.shots = Tiroak
-blocks.reload = Tiroak/segundoko
-blocks.ammo = Munizioa
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Energia-edukiera
+stat.powershot = Energia/tiroko
+stat.damage = Kaltea
+stat.targetsair = Airera tirokatzen du
+stat.targetsground = Lurrera tirokatzen du
+stat.itemsmoved = Garraio-abiadura
+stat.launchtime = Egozketen arteko denbora
+stat.shootrange = Irismena
+stat.size = Neurria
+stat.displaysize = Display Size
+stat.liquidcapacity = Likido-edukiera
+stat.powerrange = Energia irismena
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Gehieneko konexioak
+stat.poweruse = Energia-erabilera
+stat.powerdamage = Energia/Kaltea
+stat.itemcapacity = Elementu-edukiera
+stat.basepowergeneration = Oinarrizko energia sorrera
+stat.productiontime = Eraikitze denbora
+stat.repairtime = Blokearen konpontze denbora osoa
+stat.speedincrease = Abiadura areagotzea
+stat.range = Irismena
+stat.drilltier = Ustiagarriak
+stat.drillspeed = Oinarrizko ustiatze-abiadura
+stat.boosteffect = Indartze-efektua
+stat.maxunits = Gehieneko unitate aktiboak
+stat.health = Osasuna
+stat.buildtime = Eraikitze-denbora
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Eraikitze-kostua
+stat.inaccuracy = Zehazgabetasuna
+stat.shots = Tiroak
+stat.reload = Tiroak/segundoko
+stat.ammo = Munizioa
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Zulagailu hobea behar da
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = Aire zein lurreko defentsarako dorre handia. Torpedo
block.spectre.description = Kanoi bikoitz erraldoia. Blindajea zulatu dezaketen bala handiak tirokatzen ditu aireko zein lurreko xedeei.
block.meltdown.description = Laser kanoi erraldoia. Etengabeko laser izpi bat kargatu eta jauritzen die inguruko etsaiei. Hozgarria behar du jarduteko.
block.repair-point.description = Etengabe konpontzen du inguruko kaltetutako unitate hurbilena.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_fi.properties b/core/assets/bundles/bundle_fi.properties
index ae351b8764..30a231333c 100644
--- a/core/assets/bundles/bundle_fi.properties
+++ b/core/assets/bundles/bundle_fi.properties
@@ -570,49 +570,49 @@ info.title = Informaatio
error.title = [crimson]An error has occured
error.crashtitle = An error has occured
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Sisääntulo
-blocks.output = Ulostulo
-blocks.booster = Tehostaja
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
+stat.input = Sisääntulo
+stat.output = Ulostulo
+stat.booster = Tehostaja
+stat.tiles = Required Tiles
+stat.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = Energiakapasiteetti
-blocks.powershot = Energiaa/Ammus
-blocks.damage = Vahinko
-blocks.targetsair = Hyökkää ilmaan
-blocks.targetsground = Hyökkää maahan
-blocks.itemsmoved = Liikkumisnopeus
-blocks.launchtime = Aika laukaisujen välillä
-blocks.shootrange = Kantama
-blocks.size = Koko
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Nestekapasiteetti
-blocks.powerrange = Energiakantama
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Maksimimäärä yhdistyksiä
-blocks.poweruse = Energian käyttö
-blocks.powerdamage = Energia/Vahinko
-blocks.itemcapacity = Tavarakapasiteetti
-blocks.basepowergeneration = Perus energiantuotto
-blocks.productiontime = Tuotantoaika
-blocks.repairtime = Kokonaisen palikan korjausaika
-blocks.speedincrease = Nopeuden kasvu
-blocks.range = Etäisyys
-blocks.drilltier = Porattavat
-blocks.drillspeed = Kanta Poran Nopeus
-blocks.boosteffect = Tehostamisem vaikutus
-blocks.maxunits = Maksimimäärä yksikköjä
-blocks.health = Elämäpisteet
-blocks.buildtime = Rakentamisaika
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Rakentamishinta
-blocks.inaccuracy = Epätarkkuus
-blocks.shots = Ammusta
-blocks.reload = Ammusta/sekunnissa
-blocks.ammo = Ammus
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Energiakapasiteetti
+stat.powershot = Energiaa/Ammus
+stat.damage = Vahinko
+stat.targetsair = Hyökkää ilmaan
+stat.targetsground = Hyökkää maahan
+stat.itemsmoved = Liikkumisnopeus
+stat.launchtime = Aika laukaisujen välillä
+stat.shootrange = Kantama
+stat.size = Koko
+stat.displaysize = Display Size
+stat.liquidcapacity = Nestekapasiteetti
+stat.powerrange = Energiakantama
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Maksimimäärä yhdistyksiä
+stat.poweruse = Energian käyttö
+stat.powerdamage = Energia/Vahinko
+stat.itemcapacity = Tavarakapasiteetti
+stat.basepowergeneration = Perus energiantuotto
+stat.productiontime = Tuotantoaika
+stat.repairtime = Kokonaisen palikan korjausaika
+stat.speedincrease = Nopeuden kasvu
+stat.range = Etäisyys
+stat.drilltier = Porattavat
+stat.drillspeed = Kanta Poran Nopeus
+stat.boosteffect = Tehostamisem vaikutus
+stat.maxunits = Maksimimäärä yksikköjä
+stat.health = Elämäpisteet
+stat.buildtime = Rakentamisaika
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Rakentamishinta
+stat.inaccuracy = Epätarkkuus
+stat.shots = Ammusta
+stat.reload = Ammusta/sekunnissa
+stat.ammo = Ammus
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Parempi pora vaadittu
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = A large anti-air and anti-ground turret. Fires explo
block.spectre.description = A massive dual-barreled cannon. Shoots large armor-piercing bullets at air and ground targets.
block.meltdown.description = A massive laser cannon. Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate.
block.repair-point.description = Continuously heals the closest damaged unit in its vicinity.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_fil.properties b/core/assets/bundles/bundle_fil.properties
index 86c3c0737a..0fa6608526 100644
--- a/core/assets/bundles/bundle_fil.properties
+++ b/core/assets/bundles/bundle_fil.properties
@@ -570,49 +570,49 @@ info.title = Info
error.title = [scarlet]An error has occured
error.crashtitle = An error has occured
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Input
-blocks.output = Output
-blocks.booster = Booster
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
+stat.input = Input
+stat.output = Output
+stat.booster = Booster
+stat.tiles = Required Tiles
+stat.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = Power Capacity
-blocks.powershot = Power/Shot
-blocks.damage = Damage
-blocks.targetsair = Targets Air
-blocks.targetsground = Targets Ground
-blocks.itemsmoved = Move Speed
-blocks.launchtime = Time Between Launches
-blocks.shootrange = Range
-blocks.size = Size
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Liquid Capacity
-blocks.powerrange = Power Range
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Max Connections
-blocks.poweruse = Power Use
-blocks.powerdamage = Power/Damage
-blocks.itemcapacity = Item Capacity
-blocks.basepowergeneration = Base Power Generation
-blocks.productiontime = Production Time
-blocks.repairtime = Block Full Repair Time
-blocks.speedincrease = Speed Increase
-blocks.range = Range
-blocks.drilltier = Drillables
-blocks.drillspeed = Base Drill Speed
-blocks.boosteffect = Boost Effect
-blocks.maxunits = Max Active Units
-blocks.health = Health
-blocks.buildtime = Build Time
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Build Cost
-blocks.inaccuracy = Inaccuracy
-blocks.shots = Shots
-blocks.reload = Shots/Second
-blocks.ammo = Ammo
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Power Capacity
+stat.powershot = Power/Shot
+stat.damage = Damage
+stat.targetsair = Targets Air
+stat.targetsground = Targets Ground
+stat.itemsmoved = Move Speed
+stat.launchtime = Time Between Launches
+stat.shootrange = Range
+stat.size = Size
+stat.displaysize = Display Size
+stat.liquidcapacity = Liquid Capacity
+stat.powerrange = Power Range
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Max Connections
+stat.poweruse = Power Use
+stat.powerdamage = Power/Damage
+stat.itemcapacity = Item Capacity
+stat.basepowergeneration = Base Power Generation
+stat.productiontime = Production Time
+stat.repairtime = Block Full Repair Time
+stat.speedincrease = Speed Increase
+stat.range = Range
+stat.drilltier = Drillables
+stat.drillspeed = Base Drill Speed
+stat.boosteffect = Boost Effect
+stat.maxunits = Max Active Units
+stat.health = Health
+stat.buildtime = Build Time
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Build Cost
+stat.inaccuracy = Inaccuracy
+stat.shots = Shots
+stat.reload = Shots/Second
+stat.ammo = Ammo
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Better Drill Required
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = A large anti-air and anti-ground turret. Fires explo
block.spectre.description = A massive dual-barreled cannon. Shoots large armor-piercing bullets at air and ground targets.
block.meltdown.description = A massive laser cannon. Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate.
block.repair-point.description = Continuously heals the closest damaged unit in its vicinity.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_fr.properties b/core/assets/bundles/bundle_fr.properties
index e7749d7347..925465c595 100644
--- a/core/assets/bundles/bundle_fr.properties
+++ b/core/assets/bundles/bundle_fr.properties
@@ -570,49 +570,49 @@ info.title = Info
error.title = [crimson]Une erreur s'est produite
error.crashtitle = Une erreur s'est produite
unit.nobuild = [scarlet]Cette unité ne peut construire
-blocks.input = Entrée
-blocks.output = Sortie
-blocks.booster = Booster
-blocks.tiles = Pré-requis
-blocks.affinities = Affinités
+stat.input = Entrée
+stat.output = Sortie
+stat.booster = Booster
+stat.tiles = Pré-requis
+stat.affinities = Affinités
block.unknown = [lightgray]???
-blocks.powercapacity = Capacité d'énergie
-blocks.powershot = Énergie/Tir
-blocks.damage = Dégâts
-blocks.targetsair = Cibles Aériennes
-blocks.targetsground = Cibles Terrestres
-blocks.itemsmoved = Vitesse de Déplacement
-blocks.launchtime = Temps entre chaque lancement
-blocks.shootrange = Portée de tir
-blocks.size = Taille
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Capacité liquide
-blocks.powerrange = Portée électrique
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Nombre maximal de connections
-blocks.poweruse = Énergie utilisée
-blocks.powerdamage = Dégâts d'énergie
-blocks.itemcapacity = Stockage
-blocks.basepowergeneration = Production d'énergie
-blocks.productiontime = Durée de production
-blocks.repairtime = Durée de réparation complète du Bloc
-blocks.speedincrease = Accélération
-blocks.range = Portée
-blocks.drilltier = Forable
-blocks.drillspeed = Vitesse de forage de base
-blocks.boosteffect = Effet du Boost
-blocks.maxunits = Unités actives max
-blocks.health = Santé
-blocks.buildtime = Durée de construction
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Coût de construction
-blocks.inaccuracy = Imprécision
-blocks.shots = Tirs
-blocks.reload = Tirs/Seconde
-blocks.ammo = Munitions
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Capacité d'énergie
+stat.powershot = Énergie/Tir
+stat.damage = Dégâts
+stat.targetsair = Cibles Aériennes
+stat.targetsground = Cibles Terrestres
+stat.itemsmoved = Vitesse de Déplacement
+stat.launchtime = Temps entre chaque lancement
+stat.shootrange = Portée de tir
+stat.size = Taille
+stat.displaysize = Display Size
+stat.liquidcapacity = Capacité liquide
+stat.powerrange = Portée électrique
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Nombre maximal de connections
+stat.poweruse = Énergie utilisée
+stat.powerdamage = Dégâts d'énergie
+stat.itemcapacity = Stockage
+stat.basepowergeneration = Production d'énergie
+stat.productiontime = Durée de production
+stat.repairtime = Durée de réparation complète du Bloc
+stat.speedincrease = Accélération
+stat.range = Portée
+stat.drilltier = Forable
+stat.drillspeed = Vitesse de forage de base
+stat.boosteffect = Effet du Boost
+stat.maxunits = Unités actives max
+stat.health = Santé
+stat.buildtime = Durée de construction
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Coût de construction
+stat.inaccuracy = Imprécision
+stat.shots = Tirs
+stat.reload = Tirs/Seconde
+stat.ammo = Munitions
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Meilleure Foreuse Requise
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = Une grande tourelle qui tire rapidement des débris
block.spectre.description = Une tourelle massive à double cannon et qui tire de puissantes balles perce-blindages simultanément.
block.meltdown.description = Une tourelle massive chargeant et tirant de puissants rayons lasers. Nécessite un liquide de refroidissement.
block.repair-point.description = Soigne en permanence l'unité endommagée la plus proche à proximité.
-block.segment.description = Endommage et détruit les tirs ennemis. Cependant, les lasers ne peuvent pas être ciblés.
+block.segment.description = Endommage et détruit les tirs ennemis. Cependant, les lasers ne peuvent pas être ciblés.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_fr_BE.properties b/core/assets/bundles/bundle_fr_BE.properties
index 02fe5e58b1..869da14c46 100644
--- a/core/assets/bundles/bundle_fr_BE.properties
+++ b/core/assets/bundles/bundle_fr_BE.properties
@@ -570,49 +570,49 @@ info.title = Info
error.title = [crimson]Une erreur s'est produite
error.crashtitle = Une erreur s'est produite
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Ressource(s) requise(s)
-blocks.output = Ressource(s) produite(s)
-blocks.booster = Booster
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
+stat.input = Ressource(s) requise(s)
+stat.output = Ressource(s) produite(s)
+stat.booster = Booster
+stat.tiles = Required Tiles
+stat.affinities = Affinities
block.unknown = [lightgray]Inconnu
-blocks.powercapacity = Capacité d'énergie
-blocks.powershot = Énergie/Tir
-blocks.damage = Damage
-blocks.targetsair = Cible les unités aériennes
-blocks.targetsground = Cible les unités terrestres
-blocks.itemsmoved = Vitesse de déplacement
-blocks.launchtime = Temps entre chaque lancement
-blocks.shootrange = Portée
-blocks.size = Taille
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Capacité en liquide
-blocks.powerrange = Distance de transmission
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Max Connections
-blocks.poweruse = Énergie utilisée
-blocks.powerdamage = Énergie/Dégâts
-blocks.itemcapacity = Stockage
-blocks.basepowergeneration = Production d'énergie de base
-blocks.productiontime = Temps de production
-blocks.repairtime = Temps pour la réparation totale du bloc
-blocks.speedincrease = Augmentation de la vitesse
-blocks.range = Portée
-blocks.drilltier = Forable
-blocks.drillspeed = Vitesse de forage de base
-blocks.boosteffect = Effet boostant
-blocks.maxunits = Maximum d'unitée active
-blocks.health = Santé
-blocks.buildtime = Temps de construction
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Coût de construction
-blocks.inaccuracy = Précision
-blocks.shots = Tirs
-blocks.reload = Tirs/Seconde
-blocks.ammo = Munition
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Capacité d'énergie
+stat.powershot = Énergie/Tir
+stat.damage = Damage
+stat.targetsair = Cible les unités aériennes
+stat.targetsground = Cible les unités terrestres
+stat.itemsmoved = Vitesse de déplacement
+stat.launchtime = Temps entre chaque lancement
+stat.shootrange = Portée
+stat.size = Taille
+stat.displaysize = Display Size
+stat.liquidcapacity = Capacité en liquide
+stat.powerrange = Distance de transmission
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Max Connections
+stat.poweruse = Énergie utilisée
+stat.powerdamage = Énergie/Dégâts
+stat.itemcapacity = Stockage
+stat.basepowergeneration = Production d'énergie de base
+stat.productiontime = Temps de production
+stat.repairtime = Temps pour la réparation totale du bloc
+stat.speedincrease = Augmentation de la vitesse
+stat.range = Portée
+stat.drilltier = Forable
+stat.drillspeed = Vitesse de forage de base
+stat.boosteffect = Effet boostant
+stat.maxunits = Maximum d'unitée active
+stat.health = Santé
+stat.buildtime = Temps de construction
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Coût de construction
+stat.inaccuracy = Précision
+stat.shots = Tirs
+stat.reload = Tirs/Seconde
+stat.ammo = Munition
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Better Drill Required
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = Une grande tourelle à tir rapide.
block.spectre.description = Une grande tourelle qui tire deux balles puissantes à la fois.
block.meltdown.description = Une grande tourelle qui tire de puissants faisceaux à longue portée.
block.repair-point.description = Soigne en permanence l'unité endommagée la plus proche à proximité.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_hu.properties b/core/assets/bundles/bundle_hu.properties
index b28d471cdd..c24c9a24ee 100644
--- a/core/assets/bundles/bundle_hu.properties
+++ b/core/assets/bundles/bundle_hu.properties
@@ -570,49 +570,49 @@ info.title = Info
error.title = [crimson]An error has occured
error.crashtitle = An error has occured
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Input
-blocks.output = Output
-blocks.booster = Booster
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
+stat.input = Input
+stat.output = Output
+stat.booster = Booster
+stat.tiles = Required Tiles
+stat.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = Power Capacity
-blocks.powershot = Power/Shot
-blocks.damage = Damage
-blocks.targetsair = Targets Air
-blocks.targetsground = Targets Ground
-blocks.itemsmoved = Move Speed
-blocks.launchtime = Time Between Launches
-blocks.shootrange = Range
-blocks.size = Size
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Liquid Capacity
-blocks.powerrange = Power Range
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Max Connections
-blocks.poweruse = Power Use
-blocks.powerdamage = Power/Damage
-blocks.itemcapacity = Item Capacity
-blocks.basepowergeneration = Base Power Generation
-blocks.productiontime = Production Time
-blocks.repairtime = Block Full Repair Time
-blocks.speedincrease = Speed Increase
-blocks.range = Range
-blocks.drilltier = Drillables
-blocks.drillspeed = Base Drill Speed
-blocks.boosteffect = Boost Effect
-blocks.maxunits = Max Active Units
-blocks.health = Health
-blocks.buildtime = Build Time
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Build Cost
-blocks.inaccuracy = Inaccuracy
-blocks.shots = Shots
-blocks.reload = Shots/Second
-blocks.ammo = Ammo
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Power Capacity
+stat.powershot = Power/Shot
+stat.damage = Damage
+stat.targetsair = Targets Air
+stat.targetsground = Targets Ground
+stat.itemsmoved = Move Speed
+stat.launchtime = Time Between Launches
+stat.shootrange = Range
+stat.size = Size
+stat.displaysize = Display Size
+stat.liquidcapacity = Liquid Capacity
+stat.powerrange = Power Range
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Max Connections
+stat.poweruse = Power Use
+stat.powerdamage = Power/Damage
+stat.itemcapacity = Item Capacity
+stat.basepowergeneration = Base Power Generation
+stat.productiontime = Production Time
+stat.repairtime = Block Full Repair Time
+stat.speedincrease = Speed Increase
+stat.range = Range
+stat.drilltier = Drillables
+stat.drillspeed = Base Drill Speed
+stat.boosteffect = Boost Effect
+stat.maxunits = Max Active Units
+stat.health = Health
+stat.buildtime = Build Time
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Build Cost
+stat.inaccuracy = Inaccuracy
+stat.shots = Shots
+stat.reload = Shots/Second
+stat.ammo = Ammo
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Better Drill Required
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = A large anti-air and anti-ground turret. Fires explo
block.spectre.description = A massive dual-barreled cannon. Shoots large armor-piercing bullets at air and ground targets.
block.meltdown.description = A massive laser cannon. Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate.
block.repair-point.description = Continuously heals the closest damaged unit in its vicinity.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_in_ID.properties b/core/assets/bundles/bundle_in_ID.properties
index d601b9e904..e9f6f933eb 100644
--- a/core/assets/bundles/bundle_in_ID.properties
+++ b/core/assets/bundles/bundle_in_ID.properties
@@ -572,50 +572,50 @@ info.title = Info
error.title = [crimson]Sebuah kesalahan telah terjadi
error.crashtitle = Sebuah kesalahan telah terjadi
unit.nobuild = [scarlet]Unit tidak dapat membangun
-blocks.input = Masukan
-blocks.output = Pengeluaran
-blocks.booster = Pendorong
-blocks.tiles = Kotak yang dibutuhkan
-blocks.affinities = Afinitas
+stat.input = Masukan
+stat.output = Pengeluaran
+stat.booster = Pendorong
+stat.tiles = Kotak yang dibutuhkan
+stat.affinities = Afinitas
block.unknown = [lightgray]???
-blocks.powercapacity = Kapasitas Tenaga
-blocks.powershot = Tenaga/Tembakan
-blocks.damage = Kerusakan
-blocks.targetsair = Menargetkan Udara
-blocks.targetsground = Menargetkan Darat
-blocks.itemsmoved = Kecepatan Gerak
-blocks.launchtime = Waktu Diantara Peluncuran
-blocks.shootrange = Jarak
-blocks.size = Ukuran
-blocks.displaysize = Ukuran Tampilan
-blocks.liquidcapacity = Kapasitas Zat Cair
-blocks.powerrange = Jarak Tenaga
-blocks.linkrange = Jarak Tautan
-blocks.instructions = Instruksi
-blocks.powerconnections = Koneksi Maksimal
-blocks.poweruse = Penggunaan Tenaga
-blocks.powerdamage = Tenaga/Pukulan
-blocks.itemcapacity = Kapasitas Item
-blocks.memorycapacity = Kapasitas Memori
-blocks.basepowergeneration = Basis Generasi Tenaga
-blocks.productiontime = Waktu Produksi
-blocks.repairtime = Waktu Memperbaiki Blok Penuh
-blocks.speedincrease = Tambahan Kecepatan
-blocks.range = Jarak
-blocks.drilltier = Sumber Daya yang Bisa di Bor
-blocks.drillspeed = Basis Kecepatan Bor
-blocks.boosteffect = Efek Pendorong
-blocks.maxunits = Maks Unit Aktif
-blocks.health = Darah
-blocks.buildtime = Waktu Pembuatan
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Biaya Bangunan
-blocks.inaccuracy = Jarak Melenceng
-blocks.shots = Tembakan
-blocks.reload = Tembakan/Detik
-blocks.ammo = Amunisi
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Kapasitas Tenaga
+stat.powershot = Tenaga/Tembakan
+stat.damage = Kerusakan
+stat.targetsair = Menargetkan Udara
+stat.targetsground = Menargetkan Darat
+stat.itemsmoved = Kecepatan Gerak
+stat.launchtime = Waktu Diantara Peluncuran
+stat.shootrange = Jarak
+stat.size = Ukuran
+stat.displaysize = Ukuran Tampilan
+stat.liquidcapacity = Kapasitas Zat Cair
+stat.powerrange = Jarak Tenaga
+stat.linkrange = Jarak Tautan
+stat.instructions = Instruksi
+stat.powerconnections = Koneksi Maksimal
+stat.poweruse = Penggunaan Tenaga
+stat.powerdamage = Tenaga/Pukulan
+stat.itemcapacity = Kapasitas Item
+stat.memorycapacity = Kapasitas Memori
+stat.basepowergeneration = Basis Generasi Tenaga
+stat.productiontime = Waktu Produksi
+stat.repairtime = Waktu Memperbaiki Blok Penuh
+stat.speedincrease = Tambahan Kecepatan
+stat.range = Jarak
+stat.drilltier = Sumber Daya yang Bisa di Bor
+stat.drillspeed = Basis Kecepatan Bor
+stat.boosteffect = Efek Pendorong
+stat.maxunits = Maks Unit Aktif
+stat.health = Darah
+stat.buildtime = Waktu Pembuatan
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Biaya Bangunan
+stat.inaccuracy = Jarak Melenceng
+stat.shots = Tembakan
+stat.reload = Tembakan/Detik
+stat.ammo = Amunisi
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Membutuhkan Bor yang Lebih Baik
bar.noresources = Sumber Daya Tidak Ditemukan
@@ -1310,4 +1310,4 @@ block.cyclone.description = Menara penembak beruntun besar.
block.spectre.description = Menara besar yang menembak dua peluru kuat sekaligus.
block.meltdown.description = Menara besar ini menembak sinar panjang yang kuat.
block.repair-point.description = Terus menerus memulihkan unit terluka disekitar.
-block.segment.description = Merusakkan dan menghancurkan proyektil yang datang. Proyektil laser tidak akan ditargetkan.
+block.segment.description = Merusakkan dan menghancurkan proyektil yang datang. Proyektil laser tidak akan ditargetkan.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_it.properties b/core/assets/bundles/bundle_it.properties
index c10f894851..5fc3245ed6 100644
--- a/core/assets/bundles/bundle_it.properties
+++ b/core/assets/bundles/bundle_it.properties
@@ -570,49 +570,49 @@ info.title = Info
error.title = [crimson]Si è verificato un errore
error.crashtitle = Si è verificato un errore
unit.nobuild = [scarlet]L'unità non può costruire
-blocks.input = Ingresso
-blocks.output = Uscita
-blocks.booster = Potenziamenti
-blocks.tiles = Blocchi Richiesti
-blocks.affinities = Affinità
+stat.input = Ingresso
+stat.output = Uscita
+stat.booster = Potenziamenti
+stat.tiles = Blocchi Richiesti
+stat.affinities = Affinità
block.unknown = [lightgray]???
-blocks.powercapacity = Capacità Energetica
-blocks.powershot = Danno/Colpo
-blocks.damage = Danno
-blocks.targetsair = Attacca Nemici Aerei
-blocks.targetsground = Attacca Nemici Terreni
-blocks.itemsmoved = Velocità di Movimento
-blocks.launchtime = Tempo fra Decolli
-blocks.shootrange = Raggio
-blocks.size = Dimensioni
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Capacità del Liquido
-blocks.powerrange = Raggio Energia
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Connessioni Massime
-blocks.poweruse = Utilizzo Energia
-blocks.powerdamage = Energia/Danno
-blocks.itemcapacity = Capacità
-blocks.basepowergeneration = Generazione Energia di Base
-blocks.productiontime = Tempo di Produzione
-blocks.repairtime = Tempo di Riparazione Completa
-blocks.speedincrease = Aumento Velocità
-blocks.range = Raggio
-blocks.drilltier = Scavabili
-blocks.drillspeed = Velocità di Scavo Stabile
-blocks.boosteffect = Effetto Boost
-blocks.maxunits = Unità Attive Max
-blocks.health = Salute
-blocks.buildtime = Tempo di Costruzione
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Costo di Costruzione
-blocks.inaccuracy = Inaccuratezza
-blocks.shots = Colpi
-blocks.reload = Ricarica
-blocks.ammo = Munizioni
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Capacità Energetica
+stat.powershot = Danno/Colpo
+stat.damage = Danno
+stat.targetsair = Attacca Nemici Aerei
+stat.targetsground = Attacca Nemici Terreni
+stat.itemsmoved = Velocità di Movimento
+stat.launchtime = Tempo fra Decolli
+stat.shootrange = Raggio
+stat.size = Dimensioni
+stat.displaysize = Display Size
+stat.liquidcapacity = Capacità del Liquido
+stat.powerrange = Raggio Energia
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Connessioni Massime
+stat.poweruse = Utilizzo Energia
+stat.powerdamage = Energia/Danno
+stat.itemcapacity = Capacità
+stat.basepowergeneration = Generazione Energia di Base
+stat.productiontime = Tempo di Produzione
+stat.repairtime = Tempo di Riparazione Completa
+stat.speedincrease = Aumento Velocità
+stat.range = Raggio
+stat.drilltier = Scavabili
+stat.drillspeed = Velocità di Scavo Stabile
+stat.boosteffect = Effetto Boost
+stat.maxunits = Unità Attive Max
+stat.health = Salute
+stat.buildtime = Tempo di Costruzione
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Costo di Costruzione
+stat.inaccuracy = Inaccuratezza
+stat.shots = Colpi
+stat.reload = Ricarica
+stat.ammo = Munizioni
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Miglior Trivella Richiesta
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = Una grande torretta a fuoco rapido.
block.spectre.description = Una grande torretta che spara due potenti proiettili contemporaneamente.
block.meltdown.description = Una grande torretta che spara un potente laser a lungo raggio.
block.repair-point.description = Cura continuamente l'unità danneggiata più vicina.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_ja.properties b/core/assets/bundles/bundle_ja.properties
index fdb915ff96..68c766e79b 100644
--- a/core/assets/bundles/bundle_ja.properties
+++ b/core/assets/bundles/bundle_ja.properties
@@ -570,49 +570,49 @@ info.title = 情報
error.title = [crimson]エラーが発生しました
error.crashtitle = エラーが発生しました
unit.nobuild = [scarlet]ユニットを構築できません
-blocks.input = 搬入
-blocks.output = 搬出
-blocks.booster = ブースト
-blocks.tiles = 必要なタイル
-blocks.affinities = 親和性
+stat.input = 搬入
+stat.output = 搬出
+stat.booster = ブースト
+stat.tiles = 必要なタイル
+stat.affinities = 親和性
block.unknown = [lightgray]???
-blocks.powercapacity = 電力容量
-blocks.powershot = 電力/ショット
-blocks.damage = ダメージ
-blocks.targetsair = 対空攻撃
-blocks.targetsground = 対地攻撃
-blocks.itemsmoved = 輸送速度
-blocks.launchtime = 発射の待機時間
-blocks.shootrange = 範囲
-blocks.size = 大きさ
-blocks.displaysize = Display Size
-blocks.liquidcapacity = 液体容量
-blocks.powerrange = 電力範囲
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = 最大接続数
-blocks.poweruse = 電力使用量
-blocks.powerdamage = 電力/ダメージ
-blocks.itemcapacity = アイテム容量
-blocks.basepowergeneration = 基本発電量
-blocks.productiontime = 製造速度
-blocks.repairtime = ブロックの完全修復速度
-blocks.speedincrease = 速度向上
-blocks.range = 範囲
-blocks.drilltier = ドリル
-blocks.drillspeed = 基本採掘速度
-blocks.boosteffect = ブースト効果
-blocks.maxunits = 最大ユニット数
-blocks.health = 耐久値
-blocks.buildtime = 建設時間
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = 建設費用
-blocks.inaccuracy = 誤差
-blocks.shots = ショット
-blocks.reload = リロード速度
-blocks.ammo = 弾薬
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = 電力容量
+stat.powershot = 電力/ショット
+stat.damage = ダメージ
+stat.targetsair = 対空攻撃
+stat.targetsground = 対地攻撃
+stat.itemsmoved = 輸送速度
+stat.launchtime = 発射の待機時間
+stat.shootrange = 範囲
+stat.size = 大きさ
+stat.displaysize = Display Size
+stat.liquidcapacity = 液体容量
+stat.powerrange = 電力範囲
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = 最大接続数
+stat.poweruse = 電力使用量
+stat.powerdamage = 電力/ダメージ
+stat.itemcapacity = アイテム容量
+stat.basepowergeneration = 基本発電量
+stat.productiontime = 製造速度
+stat.repairtime = ブロックの完全修復速度
+stat.speedincrease = 速度向上
+stat.range = 範囲
+stat.drilltier = ドリル
+stat.drillspeed = 基本採掘速度
+stat.boosteffect = ブースト効果
+stat.maxunits = 最大ユニット数
+stat.health = 耐久値
+stat.buildtime = 建設時間
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = 建設費用
+stat.inaccuracy = 誤差
+stat.shots = ショット
+stat.reload = リロード速度
+stat.ammo = 弾薬
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = より高性能なドリルを使用してください
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = 大型の連射型ターレットです。
block.spectre.description = 一度に2発の強力な弾を放つ大型のターレットです。
block.meltdown.description = 強力な長距離攻撃が可能な大型のターレットです。
block.repair-point.description = 近くの負傷したユニットを修復します。
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_ko.properties b/core/assets/bundles/bundle_ko.properties
index f03ff17264..82bb299642 100644
--- a/core/assets/bundles/bundle_ko.properties
+++ b/core/assets/bundles/bundle_ko.properties
@@ -570,49 +570,49 @@ info.title = 정보
error.title = [scarlet]오류가 발생했습니다.
error.crashtitle = 오류가 발생했습니다
unit.nobuild = [scarlet]이 유닛은 건설할 수 없습니다.
-blocks.input = 입력
-blocks.output = 출력
-blocks.booster = 가속
-blocks.tiles = 필요한 타일
-blocks.affinities = 친화력
+stat.input = 입력
+stat.output = 출력
+stat.booster = 가속
+stat.tiles = 필요한 타일
+stat.affinities = 친화력
block.unknown = [lightgray]???
-blocks.powercapacity = 전력 용량
-blocks.powershot = 전력/발
-blocks.damage = 공격력
-blocks.targetsair = 공중 공격
-blocks.targetsground = 지상 공격
-blocks.itemsmoved = 이동 속도
-blocks.launchtime = 출격 간격
-blocks.shootrange = 사거리
-blocks.size = 크기
-blocks.displaysize = Display Size
-blocks.liquidcapacity = 액체 용량
-blocks.powerrange = 전력 범위
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = 최대 연결 수
-blocks.poweruse = 전력 사용
-blocks.powerdamage = 전력/데미지
-blocks.itemcapacity = 저장 용량
-blocks.basepowergeneration = 기본 전력 생성량
-blocks.productiontime = 제작 시간
-blocks.repairtime = 전체 블록 수리시간
-blocks.speedincrease = 속도 증가
-blocks.range = 사거리
-blocks.drilltier = 드릴
-blocks.drillspeed = 기본 드릴 속도
-blocks.boosteffect = 가속 효과
-blocks.maxunits = 최대 활성 유닛수
-blocks.health = 체력
-blocks.buildtime = 건설 시간
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = 건설 재료
-blocks.inaccuracy = 오차각
-blocks.shots = 공격 속도
-blocks.reload = 발/초
-blocks.ammo = 탄약
-blocks.shieldhealth = 보호막 체력
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = 전력 용량
+stat.powershot = 전력/발
+stat.damage = 공격력
+stat.targetsair = 공중 공격
+stat.targetsground = 지상 공격
+stat.itemsmoved = 이동 속도
+stat.launchtime = 출격 간격
+stat.shootrange = 사거리
+stat.size = 크기
+stat.displaysize = Display Size
+stat.liquidcapacity = 액체 용량
+stat.powerrange = 전력 범위
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = 최대 연결 수
+stat.poweruse = 전력 사용
+stat.powerdamage = 전력/데미지
+stat.itemcapacity = 저장 용량
+stat.basepowergeneration = 기본 전력 생성량
+stat.productiontime = 제작 시간
+stat.repairtime = 전체 블록 수리시간
+stat.speedincrease = 속도 증가
+stat.range = 사거리
+stat.drilltier = 드릴
+stat.drillspeed = 기본 드릴 속도
+stat.boosteffect = 가속 효과
+stat.maxunits = 최대 활성 유닛수
+stat.health = 체력
+stat.buildtime = 건설 시간
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = 건설 재료
+stat.inaccuracy = 오차각
+stat.shots = 공격 속도
+stat.reload = 발/초
+stat.ammo = 탄약
+stat.shieldhealth = 보호막 체력
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = 더 좋은 드릴이 필요
bar.noresources = 자원 부족
@@ -1302,4 +1302,4 @@ block.cyclone.description = 대공 및 대지 포탑. 근처 유닛에게 폭발
block.spectre.description = 거대한 이중 배럴 대포. 공중 및 지상 목표물에 큰 관통 철갑탄을 발사합니다.
block.meltdown.description = 거대한 레이저 대포. 근처의 적에게 지속적인 레이버 빔을 충전하여 발사합니다. 냉각수가 있어야 작동합니다.
block.repair-point.description = 주변에서 가장 가까운 유닛을 지속적으로 치료합니다.
-block.segment.description = 날아오는 발사체를 요격합니다. 레이저는 목표 대상이 아닙니다.
+block.segment.description = 날아오는 발사체를 요격합니다. 레이저는 목표 대상이 아닙니다.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_lt.properties b/core/assets/bundles/bundle_lt.properties
index a318c53f5f..2ebd273b5a 100644
--- a/core/assets/bundles/bundle_lt.properties
+++ b/core/assets/bundles/bundle_lt.properties
@@ -570,49 +570,49 @@ info.title = Informacija
error.title = [crimson]Įvyko klaida
error.crashtitle = Įvyko klaida
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Įeiga
-blocks.output = Išeiga
-blocks.booster = Stiprintuvas
-blocks.tiles = Privalomi
-blocks.affinities = Affinities
+stat.input = Įeiga
+stat.output = Išeiga
+stat.booster = Stiprintuvas
+stat.tiles = Privalomi
+stat.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = Energijos Talpumas
-blocks.powershot = Energija per šūvį
-blocks.damage = Žala
-blocks.targetsair = Šaudo į oro taikinius
-blocks.targetsground = Šaudo į žemės taikinius
-blocks.itemsmoved = Judėjimo Greitis
-blocks.launchtime = Laikas Tarp Paleidimų
-blocks.shootrange = Atstumas
-blocks.size = Dydis
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Skysčių Talpumas
-blocks.powerrange = Energijos Skleidimo Atstumas
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Maks. Jungčių Kiekis
-blocks.poweruse = Energijos Suvartojimas
-blocks.powerdamage = Power/Damage
-blocks.itemcapacity = Daiktų Talpumas
-blocks.basepowergeneration = Bazinis Energijos Generavimas
-blocks.productiontime = Gamybos Laikas
-blocks.repairtime = Pilnas bloko sutaisymo laikas
-blocks.speedincrease = Greičio Padidėjimas
-blocks.range = Atstumas
-blocks.drilltier = Gręžiama
-blocks.drillspeed = Bazinis Grąžto Greitis
-blocks.boosteffect = Pastiprinimo Efektas
-blocks.maxunits = Maks. Aktyvių Vienetų Kiekis
-blocks.health = Gyvybės
-blocks.buildtime = Statymo Laikas
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Statymo Kaina
-blocks.inaccuracy = Netikslumas
-blocks.shots = Šūviai
-blocks.reload = Šūviai per sekundę
-blocks.ammo = Šoviniai
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Energijos Talpumas
+stat.powershot = Energija per šūvį
+stat.damage = Žala
+stat.targetsair = Šaudo į oro taikinius
+stat.targetsground = Šaudo į žemės taikinius
+stat.itemsmoved = Judėjimo Greitis
+stat.launchtime = Laikas Tarp Paleidimų
+stat.shootrange = Atstumas
+stat.size = Dydis
+stat.displaysize = Display Size
+stat.liquidcapacity = Skysčių Talpumas
+stat.powerrange = Energijos Skleidimo Atstumas
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Maks. Jungčių Kiekis
+stat.poweruse = Energijos Suvartojimas
+stat.powerdamage = Power/Damage
+stat.itemcapacity = Daiktų Talpumas
+stat.basepowergeneration = Bazinis Energijos Generavimas
+stat.productiontime = Gamybos Laikas
+stat.repairtime = Pilnas bloko sutaisymo laikas
+stat.speedincrease = Greičio Padidėjimas
+stat.range = Atstumas
+stat.drilltier = Gręžiama
+stat.drillspeed = Bazinis Grąžto Greitis
+stat.boosteffect = Pastiprinimo Efektas
+stat.maxunits = Maks. Aktyvių Vienetų Kiekis
+stat.health = Gyvybės
+stat.buildtime = Statymo Laikas
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Statymo Kaina
+stat.inaccuracy = Netikslumas
+stat.shots = Šūviai
+stat.reload = Šūviai per sekundę
+stat.ammo = Šoviniai
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Privalomas Geresnis Grąžtas
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = Didelis bokštas puolantis, tiek žemę, tiek orą.
block.spectre.description = Milžiniškas dvivamzdis bokštas. Šaudo didelius, kiaurai per šarvus einančius šovinius į taikinius esančius ant žemės ir ore.
block.meltdown.description = Milžiniška lazerinė patranka. Užsikrauna ir šaudo lazerinius spindulius į aplinkinius priešus. Veikimui reikalingas aušinimo skystis.
block.repair-point.description = Pastoviai gydo artimiausius netoliese esančius vienetus.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_nl.properties b/core/assets/bundles/bundle_nl.properties
index 634b6eb00e..41d6e8a8fc 100644
--- a/core/assets/bundles/bundle_nl.properties
+++ b/core/assets/bundles/bundle_nl.properties
@@ -570,49 +570,49 @@ info.title = Informatie
error.title = [crimson]Een fout is opgetreden
error.crashtitle = Een fout is opgetreden
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Input
-blocks.output = Output
-blocks.booster = Booster
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
+stat.input = Input
+stat.output = Output
+stat.booster = Booster
+stat.tiles = Required Tiles
+stat.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = Stroomcapaciteit
-blocks.powershot = Stroom/Schot
-blocks.damage = Schade
-blocks.targetsair = Luchtdoelwitten
-blocks.targetsground = Gronddoelwitten
-blocks.itemsmoved = Beweegingssnelheid
-blocks.launchtime = Tijd tussen lanceringen
-blocks.shootrange = Bereik
-blocks.size = Formaat
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Vloeistofcapaciteit
-blocks.powerrange = Stroombereik
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Maximale Hoeveelheid Connecties
-blocks.poweruse = Stroomverbruik
-blocks.powerdamage = Stroom/Schade
-blocks.itemcapacity = Materiaalcapaciteit
-blocks.basepowergeneration = Standaard Stroom Generatie
-blocks.productiontime = Productie Tijd
-blocks.repairtime = Volledige Blok Repareertijd
-blocks.speedincrease = Snelheidsverhoging
-blocks.range = Bereik
-blocks.drilltier = Valt te delven
-blocks.drillspeed = Standaard mine snelheid
-blocks.boosteffect = Boost Effect
-blocks.maxunits = Maximaal Actieve Units
-blocks.health = Levenspunten
-blocks.buildtime = Bouwtijd
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Bouwkosten
-blocks.inaccuracy = Onnauwkeurigheid
-blocks.shots = Shoten
-blocks.reload = Schoten/Seconde
-blocks.ammo = Ammunitie
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Stroomcapaciteit
+stat.powershot = Stroom/Schot
+stat.damage = Schade
+stat.targetsair = Luchtdoelwitten
+stat.targetsground = Gronddoelwitten
+stat.itemsmoved = Beweegingssnelheid
+stat.launchtime = Tijd tussen lanceringen
+stat.shootrange = Bereik
+stat.size = Formaat
+stat.displaysize = Display Size
+stat.liquidcapacity = Vloeistofcapaciteit
+stat.powerrange = Stroombereik
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Maximale Hoeveelheid Connecties
+stat.poweruse = Stroomverbruik
+stat.powerdamage = Stroom/Schade
+stat.itemcapacity = Materiaalcapaciteit
+stat.basepowergeneration = Standaard Stroom Generatie
+stat.productiontime = Productie Tijd
+stat.repairtime = Volledige Blok Repareertijd
+stat.speedincrease = Snelheidsverhoging
+stat.range = Bereik
+stat.drilltier = Valt te delven
+stat.drillspeed = Standaard mine snelheid
+stat.boosteffect = Boost Effect
+stat.maxunits = Maximaal Actieve Units
+stat.health = Levenspunten
+stat.buildtime = Bouwtijd
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Bouwkosten
+stat.inaccuracy = Onnauwkeurigheid
+stat.shots = Shoten
+stat.reload = Schoten/Seconde
+stat.ammo = Ammunitie
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Betere miner nodig
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = A large rapid fire turret.
block.spectre.description = A large turret which shoots two powerful bullets at once.
block.meltdown.description = A large turret which shoots powerful long-range beams.
block.repair-point.description = Continuously heals the closest damaged unit in its vicinity.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_nl_BE.properties b/core/assets/bundles/bundle_nl_BE.properties
index ce59b257f7..4f2ed1fdcd 100644
--- a/core/assets/bundles/bundle_nl_BE.properties
+++ b/core/assets/bundles/bundle_nl_BE.properties
@@ -570,49 +570,49 @@ info.title = Info
error.title = [crimson]An error has occured
error.crashtitle = An error has occured
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Input
-blocks.output = Output
-blocks.booster = Booster
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
+stat.input = Input
+stat.output = Output
+stat.booster = Booster
+stat.tiles = Required Tiles
+stat.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = Power Capacity
-blocks.powershot = Power/Shot
-blocks.damage = Damage
-blocks.targetsair = Targets Air
-blocks.targetsground = Targets Ground
-blocks.itemsmoved = Move Speed
-blocks.launchtime = Time Between Launches
-blocks.shootrange = Range
-blocks.size = Size
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Liquid Capacity
-blocks.powerrange = Power Range
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Max Connections
-blocks.poweruse = Power Use
-blocks.powerdamage = Power/Damage
-blocks.itemcapacity = Item Capacity
-blocks.basepowergeneration = Base Power Generation
-blocks.productiontime = Production Time
-blocks.repairtime = Block Full Repair Time
-blocks.speedincrease = Speed Increase
-blocks.range = Range
-blocks.drilltier = Drillables
-blocks.drillspeed = Base Drill Speed
-blocks.boosteffect = Boost Effect
-blocks.maxunits = Max Active Units
-blocks.health = Health
-blocks.buildtime = Build Time
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Build Cost
-blocks.inaccuracy = Inaccuracy
-blocks.shots = Shots
-blocks.reload = Shots/Second
-blocks.ammo = Ammo
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Power Capacity
+stat.powershot = Power/Shot
+stat.damage = Damage
+stat.targetsair = Targets Air
+stat.targetsground = Targets Ground
+stat.itemsmoved = Move Speed
+stat.launchtime = Time Between Launches
+stat.shootrange = Range
+stat.size = Size
+stat.displaysize = Display Size
+stat.liquidcapacity = Liquid Capacity
+stat.powerrange = Power Range
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Max Connections
+stat.poweruse = Power Use
+stat.powerdamage = Power/Damage
+stat.itemcapacity = Item Capacity
+stat.basepowergeneration = Base Power Generation
+stat.productiontime = Production Time
+stat.repairtime = Block Full Repair Time
+stat.speedincrease = Speed Increase
+stat.range = Range
+stat.drilltier = Drillables
+stat.drillspeed = Base Drill Speed
+stat.boosteffect = Boost Effect
+stat.maxunits = Max Active Units
+stat.health = Health
+stat.buildtime = Build Time
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Build Cost
+stat.inaccuracy = Inaccuracy
+stat.shots = Shots
+stat.reload = Shots/Second
+stat.ammo = Ammo
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Better Drill Required
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = A large rapid fire turret.
block.spectre.description = A large turret which shoots two powerful bullets at once.
block.meltdown.description = A large turret which shoots powerful long-range beams.
block.repair-point.description = Continuously heals the closest damaged unit in its vicinity.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_pl.properties b/core/assets/bundles/bundle_pl.properties
index f0c67c6a88..84bf25d5e2 100644
--- a/core/assets/bundles/bundle_pl.properties
+++ b/core/assets/bundles/bundle_pl.properties
@@ -14,14 +14,14 @@ link.f-droid.description = F-Droid catalogue listing
link.wiki.description = Oficjana Wiki Mindustry
link.suggestions.description = Zaproponuj nowe funkcje
linkfail = Nie udało się otworzyć linku!\nURL został skopiowany.
-screenshot = Zapisano zdjęcie w {0}
+screenshot = Zapisano zrzut ekranu w {0}
screenshot.invalid = Zrzut ekranu jest zbyt duży. Najprawdopodobniej brakuje miejsca w pamięci urządzenia.
gameover = Koniec Gry
gameover.pvp = Zwyciężyła drużyna [accent]{0}[]!
-highscore = [accent] Nowy rekord!
+highscore = [accent]Nowy rekord!
copied = Skopiowano.
-indev.popup = [accent]v6[] is currently in [accent]alpha[].\n[lightgray]This means:[]\n[scarlet]- The campaign is completely unfinished[]\n- Content is missing\n - Most [scarlet]Unit AI[] does not work properly\n- Many units are unfinished\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[].
-indev.notready = This part of the game isn't ready yet
+indev.popup = [accent]Wersja v6[] jest obecnie w [accent]alphie[].\n[lightgray]Oznacza to, że:[]\n[scarlet]- Kampania nie jest skończona[]\n- Brakuje zawartości\n - Większość [scarlet]SI jednostek[] nie działa poprawnie\n- Wiele jednostek jest niedokończonych\n- Wszystko to, co widzisz, może ulec zmianie lub usunięciu.\n\nZgłaszaj błędy i awarie na [accent]Githubie[].
+indev.notready = Ta część gry nie jest jeszcze ukończona
load.sound = Dźwięki
load.map = Mapy
@@ -55,6 +55,7 @@ schematic.saved = Schemat zapisany.
schematic.delete.confirm = Ten schemat zostanie usunięty.
schematic.rename = Zmień nazwę schematu
schematic.info = {0}x{1}, {2} bloków
+schematic.disabled = [scarlet]Schematy są wyłączone[]\nNie możesz używać schematów na tej [accent]mapie[] lub [accent]serwerze.
stat.wave = Fale powstrzymane:[accent] {0}
stat.enemiesDestroyed = Przeciwnicy zniszczeni:[accent] {0}
@@ -107,7 +108,7 @@ mods.guide = Poradnik do modów
mods.report = Zgłoś Błąd
mods.openfolder = Otwórz folder z modami
mods.reload = Przeładuj
-mods.reloadexit = The game will now exit, to reload mods.
+mods.reloadexit = Gra zostanie teraz zamknięta, aby ponownie załadować mody.
mod.display = [gray]Mod:[orange] {0}
mod.enabled = [lightgray]Włączony
mod.disabled = [scarlet]Wyłączony
@@ -115,7 +116,7 @@ mod.disable = Wyłącz
mod.content = Content:
mod.delete.error = Nie udało się usunąć moda. Plik może być w użyciu.
mod.requiresversion = [scarlet]Wymaga gry w wersji co najmniej: [accent]{0}
-mod.outdated = [scarlet]Not compatible with V6 (no minGameVersion: 105)
+mod.outdated = [scarlet]Niekompatybilne z wersją v6 (no minGameVersion: 105)
mod.missingdependencies = [scarlet]Brakujące zależności: {0}
mod.erroredcontent = [scarlet]Content Errors
mod.errors = Wystąpił błąd podczas ładowania treści.
@@ -127,7 +128,7 @@ mod.reloadrequired = [scarlet]Wymagany restart
mod.import = Importuj Mod
mod.import.file = Importuj Plik
mod.import.github = Importuj mod z GitHuba
-mod.jarwarn = [scarlet]JAR mods are inherently unsafe.[]\nMake sure you're importing this mod from a trustworthy source!
+mod.jarwarn = [scarlet]Mody JAR są niebezpieczne.[]\nUpewnij się, że importujesz ten mod z dobrze znanego źródła!
mod.item.remove = Ten przedmiot jest częścią moda[accent] '{0}'[]. Aby usunąć go, odinstaluj modyfikację.
mod.remove.confirm = Ten mod zostanie usunięty.
mod.author = [lightgray]Autor:[] {0}
@@ -148,12 +149,12 @@ techtree = Drzewo Technologiczne
research.list = [lightgray]Badania:
research = Badaj
researched = [lightgray]{0} zbadane.
-research.progress = {0}% complete
+research.progress = {0}% ukończone
players = {0} graczy
players.single = {0} gracz
-players.search = search
+players.search = wyszukaj
players.notfound = [gray]nie znaleziono graczy
-server.closing = [accent] Zamykanie serwera...
+server.closing = [accent]Zamykanie serwera...
server.kicked.kick = Zostałeś wyrzucony z serwera!
server.kicked.whitelist = Nie ma cię tu na białej liście.
server.kicked.serverClose = Serwer został zamknięty.
@@ -171,11 +172,11 @@ server.kicked.customClient = Ten serwer nie wspomaga wersji deweloperskich. Pobi
server.kicked.gameover = Koniec gry!
server.kicked.serverRestarting = Restart serwera.
server.versions = Twoja wersja gry:[accent] {0}[]\nWersja gry serwera:[accent] {1}[]
-host.info = Przycisk [accent]host[] hostuje serwer na porcie [scarlet]6567[]. \nKażdy w tej samej sieci [lightgray]wifi lub hotspocie[] powinien zobaczyć twój serwer.\n\nJeśli chcesz, aby każdy z twoim IP mógł dołączyć, musisz wykonać [accent]przekierowywanie portów[].\n\n[lightgray]Notka: Jeśli ktokolwiek ma problem z dołączeniem do gry lokalnej, upewnij się, że udostępniłeś Mindustry dostęp do sieci w ustawieniach zapory (firewall). Zauważ, że niektóre sieci publiczne mogą nie zezwalać na wykrycie serwerów.
-join.info = Tutaj możesz wpisać [accent]adres IP serwera[] aby do niego dołączyć lub wyszukać [accent]serwery w lokalnej sieci[], do których możesz dołączyć.\nGra wieloosobowa na LAN i WAN jest wspierana.\n\n[lightgray]Notka: Nie ma automatycznej listy wszystkich serwerów; jeśli chcesz dołączyć przez IP, musisz zapytać hosta o jego IP, które można znaleźć po wpisaniu "my ip" w przeglądarce na urządzeniu hosta.
+host.info = Przycisk [accent]host[] hostuje serwer na porcie [scarlet]6567[]. \nKażdy w tej samej sieci [lightgray]wifi lub hotspocie[] powinien zobaczyć twój serwer na ich liście serwerów.\n\nJeśli chcesz, aby każdy z twoim IP mógł dołączyć, musisz wykonać [accent]przekierowywanie portów[].\n\n[lightgray]Notka: Jeśli ktokolwiek ma problem z dołączeniem do gry lokalnej, upewnij się, że udostępniłeś Mindustry dostęp do sieci w ustawieniach zapory (firewall). Zauważ, że niektóre sieci publiczne mogą nie zezwalać na wykrycie serwerów.
+join.info = Tutaj możesz wpisać [accent]adres IP serwera[] aby do niego dołączyć lub wyszukać [accent]serwery w lokalnej sieci[] lub wyszukać [accent]publiczne[] serwery, do których możesz dołączyć.\nGra wieloosobowa na LAN i WAN jest wspierana.\n\n[lightgray]Jeśli chcesz dołączyć przez IP, musisz zapytać hosta o jego IP, które można znaleźć po wpisaniu "my ip" w przeglądarce na urządzeniu hosta.
hostserver = Stwórz Serwer
invitefriends = Zaproś Znajomych
-hostserver.mobile = Hostuj\nGrę
+hostserver.mobile = Hostuj Grę
host = Hostuj
hosting = [accent]Otwieranie serwera...
hosts.refresh = Odśwież
@@ -208,11 +209,11 @@ server.outdated.client = [crimson]Przestarzały klient![]
server.version = [gray]Wersja: {0}
server.custombuild = [accent]Zmodowany klient
confirmban = Jesteś pewny, że chcesz zbanować "{0}[white]"?
-confirmkick = Jesteś pewny, że chcesz wyrzucić {0}[white]"?
-confirmvotekick = Jesteś pewny, że chcesz głosować za wyrzuceniem {0}[white]"?
+confirmkick = Jesteś pewny, że chcesz wyrzucić "{0}[white]"?
+confirmvotekick = Jesteś pewny, że chcesz głosować za wyrzuceniem "{0}[white]"?
confirmunban = Jesteś pewny, że chcesz odbanować tego gracza?
-confirmadmin = Jesteś pewny, że chcesz dać rangę admina {0}[white]"?
-confirmunadmin = Jesteś pewny, że chcesz zabrać rangę admina {0}[white]"?
+confirmadmin = Jesteś pewny, że chcesz dać rangę admina "{0}[white]"?
+confirmunadmin = Jesteś pewny, że chcesz zabrać rangę admina "{0}[white]"?
joingame.title = Dołącz do gry
joingame.ip = IP:
disconnect = Rozłączono.
@@ -237,7 +238,7 @@ save.delete = Usuń
save.export = Eksportuj
save.import.invalid = [accent]Zapis gry jest niepoprawny!
save.import.fail = [crimson]Nie udało się zaimportować zapisu: [accent]{0}
-save.export.fail = [crimson]Nie można wyeksportować zapisu: [accent]{0}
+save.export.fail = [crimson]Nie udało się wyeksportować zapisu: [accent]{0}
save.import = Importuj Zapis
save.newslot = Zapisz nazwę:
save.rename = Zmień nazwę
@@ -255,14 +256,14 @@ save.wave = Fala {0}
save.mode = Tryb Gry: {0}
save.date = Ostatnio Zapisane: {0}
save.playtime = Czas gry: {0}
-warning = Uwaga
+warning = Uwaga.
confirm = Potwierdź
delete = Usuń
view.workshop = Pokaż w Warsztacie
workshop.listing = Edytuj pozycję w Warsztacie
ok = OK
open = Otwórz
-customize = Dostosuj
+customize = Dostosuj zasady
cancel = Anuluj
openlink = Otwórz Link
copylink = Kopiuj Link
@@ -272,19 +273,19 @@ data.import = Importuj Dane
data.openfolder = Otwórz folder danych
data.exported = Dane wyeksportowane.
data.invalid = Nieprawidłowe dane gry.
-data.import.confirm = Zaimportowanie zewnętrznych danych usunie[scarlet] wszystkie[] obecne dane gry.\n[accent]Nie można tego cofnąć![]\n\nGdy dane zostaną zimportowane, gra automatycznie się wyłączy.
+data.import.confirm = Zaimportowanie zewnętrznych danych nadpisze[scarlet] wszystkie[] obecne dane gry.\n[accent]Nie można tego cofnąć![]\n\nGdy dane zostaną zaimportowane, gra automatycznie się wyłączy.
quit.confirm = Czy na pewno chcesz wyjść?
quit.confirm.tutorial = Jesteś pewien?\nSamouczek może zostać powtórzony w[accent] Ustawienia->Gra->Ponów samouczek.[]
loading = [accent]Ładowanie...
reloading = [accent]Przeładowywanie Modów...
saving = [accent]Zapisywanie...
-respawn = [accent][[{0}][] to respawn in core
+respawn = [accent][[{0}][] by odrodzić się w rdzeniu
cancelbuilding = [accent][[{0}][] by wyczyścić plan
selectschematic = [accent][[{0}][] by wybrać+skopiować
pausebuilding = [accent][[{0}][] by wstrzymać budowę
resumebuilding = [scarlet][[{0}][] by kontynuować budowę
wave = [accent]Fala {0}
-wave.waiting = Fala za {0}
+wave.waiting = [lightgray]Fala za {0}
wave.waveInProgress = [lightgray]Fala w trakcie
waiting = [lightgray]Oczekiwanie...
waiting.players = Oczekiwanie na graczy...
@@ -295,7 +296,7 @@ saveimage = Zapisz Obraz
unknown = Nieznane
custom = Własne
builtin = Wbudowane
-map.delete.confirm = Jesteś pewny, że chcesz usunąć tę mapę? Nie będzie można jej przywrócić.
+map.delete.confirm = Jesteś pewny, że chcesz usunąć tę mapę? Nie będzie można jej przywrócić!
map.random = [accent]Losowa Mapa
map.nospawn = Ta mapa nie zawiera żadnego rdzenia! Dodaj [accent]pomarańczowy[] rdzeń do tej mapy w edytorze.
map.nospawn.pvp = Ta mapa nie ma żadnego rdzenia przeciwnika, aby mogli się zrespić przeciwnicy! Dodaj[scarlet] inny niż pomarańczowy[] rdzeń do mapy w edytorze.
@@ -309,7 +310,7 @@ workshop.info = Informacja o pozycji
changelog = Historia aktualizacji (opcjonalna):
eula = Umowa Użytkownika Końcowego (EULA) Steam
missing = Ta pozycja została przeniesiona bądź usunięta.\n[lightgray]Pozycja na Warsztacie została automatycznie odłączona.
-publishing = [accent]Trwa publikowanie...
+publishing = [accent]Publikowanie...
publish.confirm = Czy jesteś pewien, że chcesz to opublikować?\n\n[lightgray]Najpierw upewnij się, że zgadzasz się z umową EULA Warsztatu, w przeciwnym razie twoje pozycje nie będą widoczne!
publish.error = Błąd podczas publikowania pozycji: {0}
steam.error = Nie udało się zainicjować serwisów Steam.\nBłąd: {0}
@@ -346,6 +347,7 @@ waves.invalid = Nieprawidłowe fale w schowku.
waves.copied = Fale zostały skopiowane.
waves.none = Brak zdefiniowanych wrogów.\nPamiętaj, że puste układy fal zostaną automatycznie zastąpione układem domyślnym.
+#these are intentionally in lower case
wavemode.counts = counts
wavemode.totals = totals
wavemode.health = health
@@ -386,10 +388,10 @@ editor.export = Eksportuj...
editor.exportfile = Eksportuj Plik
editor.exportfile.description = Eksportuj plik mapy
editor.exportimage = Eksportuj Obraz Terenu
-editor.exportimage.description = Eksportuj plik obrazu terenu
+editor.exportimage.description = Eksportuj plik obrazu zawierający tylko podstawowy teren
editor.loadimage = Załaduj Teren
editor.saveimage = Zapisz Teren
-editor.unsaved = [scarlet]Masz niezapisane zmiany![]\nCzy na pewno chcesz wyjść?
+editor.unsaved = Czy na pewno chcesz wyjść?[]\n[scarlet]Wszelkie niezapisane zmiany zostaną utracone.
editor.resizemap = Zmień Rozmiar Mapy
editor.mapname = Nazwa Mapy:
editor.overwrite = [accent]Uwaga!\nSpowoduje to nadpisanie istniejącej mapy.
@@ -469,24 +471,19 @@ locked = Zablokowane
complete = [lightgray]Ukończone:
requirement.wave = Osiągnij falę {0} w {1}
requirement.core = Zniszcz Rdzeń wroga w {0}
-requirement.research = Research {0}
-requirement.capture = Capture {0}
-resume = Kontynuuj Strefę:\n[lightgray]{0}
+requirement.research = Zbadaj {0}
+requirement.capture = Zdobądź {0}
bestwave = [lightgray]Najwyższa fala: {0}
-launch = < WYSTRZEL >
-launch.text = Launch
-launch.title = Wystrzelenie udane
-launch.next = [lightgray]Następna okazja przy fali {0}
-launch.unable2 = [scarlet]WYSTRZELENIE niedostępne.[]
-launch.confirm = Spowoduje to wystrzelenie wszystkich surowców w rdzeniu.\nNie będziesz mógł wrócić do tej bazy.
-launch.skip.confirm = Jeśli teraz przejdziesz do kolejnej fali, nie będziesz miał możliwości wystrzelenia do czasu pokonania dalszych fal.
+launch.text = Wystrzel
+campaign.multiplayer = Podczas gry w trybie wieloosobowym w kampanii możesz badać używając tylko przedmiotów ze [accent]swoich[] sektorów, a [scarlet]nie[] sektoru hosta na którym aktualnie jesteś.\n\nAby zdobyć przedmioty dla [accent]swoich[] sektorów w trybie wieloosobowym, użyj [accent]wyrzutni[].
uncover = Odkryj
configure = Skonfiguruj Ładunek
+#TODO
loadout = Loadout
-resources = Resources
+resources = Zasoby
bannedblocks = Zabronione bloki
addall = Dodaj wszystkie
-launch.destination = Destination: {0}
+launch.destination = Cell: {0}
configure.invalid = Ilość musi być liczbą pomiędzy 0 a {0}.
zone.unlocked = [lightgray]Strefa {0} odblokowana.
zone.requirement.complete = Fala {0} osiągnięta:\n{1} Wymagania strefy zostały spełnione.
@@ -500,7 +497,7 @@ boss.health = Zdrowie Bossa
connectfail = [crimson]Nie można połączyć się z serwerem:\n\n[accent]{0}
error.unreachable = Serwer niedostępny.\nCzy adres jest wpisany poprawnie?
error.invalidaddress = Niepoprawny adres.
-error.timedout = Przekroczono limit czasu!\nUpewnij się, że host ma ustawione przekierowanie portu oraz poprawność wpisanego adresu!
+error.timedout = Przekroczono limit czasu!\nUpewnij się, że host ma ustawione przekierowanie portu oraz sprawdź poprawność wpisanego adresu!
error.mismatch = Błąd pakietu:\nprawdopodobne niedopasowanie klienta/serwera.\nUpewnij się, że ty i host macie najnowszą wersję Mindustry!
error.alreadyconnected = Jesteś już połączony.
error.mapnotfound = Plik mapy nie został znaleziony!
@@ -508,12 +505,12 @@ error.io = Błąd sieciowy I/O.
error.any = Nieznany błąd sieci.
error.bloom = Nie udało się załadować bloom.\nTwoje urządzenie może nie wspierać tej funkcji.
-weather.rain.name = Rain
-weather.snow.name = Snow
-weather.sandstorm.name = Sandstorm
-weather.sporestorm.name = Sporestorm
+weather.rain.name = Deszcz
+weather.snow.name = Śnieg
+weather.sandstorm.name = Burza piaskowa
+weather.sporestorm.name = Burza zarodników
-sectors.unexplored = [lightgray]Unexplored
+sectors.unexplored = [lightgray]Niezbadane
sectors.resources = Resources:
sectors.production = Production:
sectors.stored = Stored:
@@ -522,6 +519,7 @@ sectors.launch = Launch
sectors.select = Select
sectors.nonelaunch = [lightgray]none (sun)
+#NOTE TO TRANSLATORS: don't bother editing these, they'll be removed and/or rewritten anyway
sector.groundZero.name = Punkt Zerowy
sector.craters.name = Kratery
sector.frozenForest.name = Zamrożony Las
@@ -534,9 +532,13 @@ sector.tarFields.name = Pola Smołowe
sector.saltFlats.name = Solne Równiny
sector.fungalPass.name = Grzybowa Przełęcz
+#unused
+#sector.impact0078.name = Impact 0078
+#sector.crags.name = Crags
+
sector.groundZero.description = Optymalna lokalizacja, aby rozpocząć jeszcze raz. Niskie zagrożenie. Niewiele zasobów.\nZbierz jak najwięcej miedzi i ołowiu, tyle ile jest możliwe.\nPrzejdź do następnej strefy jak najszybciej.
-sector.frozenForest.description = Nawet tutaj, bliżej gór, zarodniki rozprzestrzeniły się. Niskie temperatury nie mogą ich zatrzymać na zawsze.\n\nRozpocznij przedsięwzięcie od władzy. Buduj generatory spalinowe. Naucz się korzystać z naprawiaczy.
-sector.saltFlats.description = Na obrzeżach pustyni spoczywają Solne Równiny. Można tu znaleźć niewiele surowców.\n\nWrogowie zbudowali tu bazę składującą surowce. Zniszcz ich rdżeń. Zniszcz wszystko co stanie ci na drodze.
+sector.frozenForest.description = Nawet tutaj, bliżej gór, zarodniki rozprzestrzeniły się. Niskie temperatury nie mogą ich zatrzymać na zawsze.\n\nRozpocznij przedsięwzięcie od prądu. Buduj generatory spalinowe. Naucz się korzystać z naprawiaczy.
+sector.saltFlats.description = Na obrzeżach pustyni spoczywają Solne Równiny. Można tu znaleźć niewiele surowców.\n\nWrogowie zbudowali tu bazę składującą surowce. Zniszcz ich rdzeń. Zniszcz wszystko co stanie ci na drodze.
sector.craters.description = W tym kraterze zebrała się woda. Pozostałość dawnych wojen. Odzyskaj ten teren. Wykop piasek. Wytop metaszkło. Pompuj wodę do działek obronnych i wierteł by je schłodzić
sector.ruinousShores.description = Za pustkowiami ciągnie się linia brzegowa. Kiedyś znajdowała się tu przybrzeżna linia obronna. Niewiele z niej zostało. Ostały się tylko podstawowe struktury obronne, z reszty został tylko złom.\nKontynuuj eksploracje. Odkryj pozostawioną tu technologię.
sector.stainedMountains.description = W głębi lądu leżą góry, jeszcze nieskażone przez zarodniki.\nWydobądź obfity tytan w tym obszarze. Dowiedz się, jak z niego korzystać.\n\nObecność wroga jest tutaj większa. Nie daj im czasu na wysłanie swoich najsilniejszych jednostek.
@@ -570,49 +572,51 @@ info.title = Informacje
error.title = [crimson]Wystąpił błąd
error.crashtitle = Wystąpił błąd
unit.nobuild = [scarlet]Jednostka nie może budować
-blocks.input = Wejście
-blocks.output = Wyjście
-blocks.booster = Wzmacniacz
-blocks.tiles = Wymagane Pola
-blocks.affinities = Uwydajnienie
+stat.input = Wejście
+stat.output = Wyjście
+stat.booster = Wzmacniacz
+stat.tiles = Wymagane Pola
+stat.affinities = Uwydajnienie
block.unknown = [lightgray]???
-blocks.powercapacity = Pojemność mocy
-blocks.powershot = moc/strzał
-blocks.damage = Obrażenia
-blocks.targetsair = Namierzanie wrogów powietrznych
-blocks.targetsground = Namierzanie wrogów lądowych
-blocks.itemsmoved = Prędkość poruszania się
-blocks.launchtime = Czas pomiędzy wystrzeleniami
-blocks.shootrange = Zasięg
-blocks.size = Rozmiar
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Pojemność cieczy
-blocks.powerrange = Zakres mocy
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Maksymalna ilość połączeń
-blocks.poweruse = Zużycie prądu
-blocks.powerdamage = Moc/Zniszczenia
-blocks.itemcapacity = Pojemność przedmiotów
-blocks.basepowergeneration = Podstawowa generacja mocy
-blocks.productiontime = Czas produkcji
-blocks.repairtime = Czas pełnej naprawy bloku
-blocks.speedincrease = Zwiększenie prędkości
-blocks.range = Zasięg
-blocks.drilltier = Co może wykopać
-blocks.drillspeed = Podstawowa szybkość kopania
-blocks.boosteffect = Efekt wzmocnienia
-blocks.maxunits = Maksymalna ilość jednostek
-blocks.health = Zdrowie
-blocks.buildtime = Czas budowy
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Koszt budowy
-blocks.inaccuracy = Niecelność
-blocks.shots = Strzały
-blocks.reload = Strzałów/sekundę
-blocks.ammo = Amunicja
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+
+stat.powercapacity = Pojemność mocy
+stat.powershot = moc/strzał
+stat.damage = Obrażenia
+stat.targetsair = Namierzanie wrogów powietrznych
+stat.targetsground = Namierzanie wrogów lądowych
+stat.itemsmoved = Prędkość poruszania się
+stat.launchtime = Czas pomiędzy wystrzeleniami
+stat.shootrange = Zasięg
+stat.size = Rozmiar
+stat.displaysize = Display Size
+stat.liquidcapacity = Pojemność cieczy
+stat.powerrange = Zakres mocy
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Maksymalna ilość połączeń
+stat.poweruse = Zużycie prądu
+stat.powerdamage = Moc/Zniszczenia
+stat.itemcapacity = Pojemność przedmiotów
+stat.memorycapacity = Memory Capacity
+stat.basepowergeneration = Podstawowa generacja mocy
+stat.productiontime = Czas produkcji
+stat.repairtime = Czas pełnej naprawy bloku
+stat.speedincrease = Zwiększenie prędkości
+stat.range = Zasięg
+stat.drilltier = Co może wykopać
+stat.drillspeed = Podstawowa szybkość kopania
+stat.boosteffect = Efekt wzmocnienia
+stat.maxunits = Maksymalna ilość jednostek
+stat.health = Zdrowie
+stat.buildtime = Czas budowy
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Koszt budowy
+stat.inaccuracy = Niecelność
+stat.shots = Strzały
+stat.reload = Strzałów/sekundę
+stat.ammo = Amunicja
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Wymagane Lepsze Wiertło
bar.noresources = Missing Resources
@@ -822,6 +826,7 @@ mode.custom = Własny tryb
rules.infiniteresources = Nieskończone zasoby
rules.reactorexplosions = Eksplozje reaktorów
+rules.schematic = Schematics Allowed
rules.wavetimer = Zegar fal
rules.waves = Fale
rules.attack = Tryb ataku
@@ -847,6 +852,7 @@ rules.title.unit = Jednostki
rules.title.experimental = Eksperymentalne
rules.title.environment = Environment
rules.lighting = Oświetlenie
+rules.enemyLights = Enemy Lights
rules.fire = Fire
rules.explosions = Block/Unit Explosion Damage
rules.ambientlight = Otaczające Światło
@@ -990,7 +996,7 @@ block.pine.name = Sosna
block.dirt.name = Dirt
block.dirt-wall.name = Dirt Wall
block.mud.name = Mud
-block.white-tree-dead.name = Białe Drzewo Martwe
+block.white-tree-dead.name = Białe Martwe Drzewo
block.white-tree.name = Białe Drzewo
block.spore-cluster.name = Skupisko Zarodników
block.metal-floor.name = Metalowa Podłoga
@@ -1075,6 +1081,7 @@ block.power-source.name = Źródło prądu
block.unloader.name = Ekstraktor
block.vault.name = Magazyn
block.wave.name = Strumień
+block.tsunami.name = Tsunami
block.swarmer.name = Działo Rojowe
block.salvo.name = Działo Salwowe
block.ripple.name = Działo Falowe
@@ -1114,6 +1121,7 @@ block.arc.name = Piorun
block.rtg-generator.name = Generator RTG
block.spectre.name = Huragan
block.meltdown.name = Rozpad
+block.foreshadow.name = Foreshadow
block.container.name = Kontener
block.launch-pad.name = Wyrzutnia
block.launch-pad-large.name = Duża Wyrzutnia
@@ -1139,6 +1147,7 @@ block.hyper-processor.name = Hyper Processor
block.logic-display.name = Logic Display
block.large-logic-display.name = Large Logic Display
block.memory-cell.name = Memory Cell
+block.memory-bank.name = Memory Bank
team.blue.name = niebieski
team.crux.name = czerwony
@@ -1166,7 +1175,7 @@ tutorial.breaking = Bloki często wymagają rozbiórki.\n[accent]Przytrzymaj pra
tutorial.breaking.mobile = Bloki często wymagają rozbiórki.\n[accent]Wybierz tryb dekonstrukcji[], a następnie dotknij blok by zacząć go niszczyć.\nZdekonstruuj obszarowo poprzez przytrzymanie palcem przez moment[] i przesunięcie go w jakimś kierunku.\nNaciśnij przycisk ptaszka by potwierdzić rozbiórkę.\n\n[accent]Zniszcz wszystkie bloki złomu na lewo od twojego rdzenia używając selekcji obszarowej.
tutorial.withdraw = Czasami, konieczne jest wyjmowanie przedmiotów prosto z bloków.\nBy tego dokonać, [accent]kliknij blok[] z przedmiotami w nim, potem [accent]kliknij przedmiot[] w inwentarzu.\nMożesz zebrać wiele przedmiotów naraz poprzez [accent]kliknięcie i przytrzymanie[].\n\n[accent]Zabierz trochę miedzi z rdzenia.[]
tutorial.deposit = Włóż przedmioty do bloków poprzez przeciągnięcie z twojego statku do danego bloku.\n\n[accent]Włóż miedź z powrotem do rdzenia .[]
-tutorial.waves = [lightgray] Wrogowie[] nadchodzą.\n\nBroń swój rdżeń przez 2 fale.[accent] Kliknij[] by strzelać.\nZbuduj wiecej działek i wierteł. Wydobądź więcej miedzi.
+tutorial.waves = [lightgray] Wrogowie[] nadchodzą.\n\nBroń swój rdzeń przez 2 fale.[accent] Kliknij[] by strzelać.\nZbuduj wiecej działek i wierteł. Wydobądź więcej miedzi.
tutorial.waves.mobile = [lightgray] Wrogowie[] nadchodzą.\n\nBroń swój rdzeń przez 2 fale. Twój statek będzie automatycznie atakował wrogów.\nZbuduj wiecej działek i wierteł. Wydobądź więcej miedzi.
tutorial.launch = Kiedy dotrzesz do określonej fali, masz możliwość[accent] wystrzelenia rdzenia[], pozostawiając struktury obronne za sobą i[accent] otrzymując wszystkie surowce znajdujące się w rdzeniu.[]\nSurowce te mogą potem zostać użyte do odkrywania nowych technologii.\n\n[accent]Naciśnij przycisk Wystrzału.
diff --git a/core/assets/bundles/bundle_pt_BR.properties b/core/assets/bundles/bundle_pt_BR.properties
index c2d8b20dcf..7f2659d839 100644
--- a/core/assets/bundles/bundle_pt_BR.properties
+++ b/core/assets/bundles/bundle_pt_BR.properties
@@ -570,49 +570,49 @@ info.title = [accent]Informação
error.title = [crimson]Ocorreu um Erro.
error.crashtitle = Ocorreu um Erro
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Entrada
-blocks.output = Saída
-blocks.booster = Apoio
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
+stat.input = Entrada
+stat.output = Saída
+stat.booster = Apoio
+stat.tiles = Required Tiles
+stat.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = Capacidade de Energia
-blocks.powershot = Energia/tiro
-blocks.damage = Dano
-blocks.targetsair = Mira no ar
-blocks.targetsground = Mira no chão
-blocks.itemsmoved = Velocidade de movimento
-blocks.launchtime = Tempo entre Disparos.
-blocks.shootrange = Alcance
-blocks.size = Tamanho
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Capacidade de Líquido
-blocks.powerrange = Alcance da Energia
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Conexões Máximas
-blocks.poweruse = Uso de energia
-blocks.powerdamage = Dano/Poder
-blocks.itemcapacity = Capacidade de Itens
-blocks.basepowergeneration = Geração de poder base
-blocks.productiontime = Tempo de produção
-blocks.repairtime = Tempo de reparo total do bloco
-blocks.speedincrease = Aumento de velocidade
-blocks.range = Distância
-blocks.drilltier = Brocas
-blocks.drillspeed = Velocidade base da Broca
-blocks.boosteffect = Efeito do Impulso
-blocks.maxunits = Máximo de unidades ativas
-blocks.health = Saúde
-blocks.buildtime = Tempo de construção
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Custo de construção
-blocks.inaccuracy = Imprecisão
-blocks.shots = Tiros
-blocks.reload = Tiros por segundo
-blocks.ammo = Munição
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Capacidade de Energia
+stat.powershot = Energia/tiro
+stat.damage = Dano
+stat.targetsair = Mira no ar
+stat.targetsground = Mira no chão
+stat.itemsmoved = Velocidade de movimento
+stat.launchtime = Tempo entre Disparos.
+stat.shootrange = Alcance
+stat.size = Tamanho
+stat.displaysize = Display Size
+stat.liquidcapacity = Capacidade de Líquido
+stat.powerrange = Alcance da Energia
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Conexões Máximas
+stat.poweruse = Uso de energia
+stat.powerdamage = Dano/Poder
+stat.itemcapacity = Capacidade de Itens
+stat.basepowergeneration = Geração de poder base
+stat.productiontime = Tempo de produção
+stat.repairtime = Tempo de reparo total do bloco
+stat.speedincrease = Aumento de velocidade
+stat.range = Distância
+stat.drilltier = Brocas
+stat.drillspeed = Velocidade base da Broca
+stat.boosteffect = Efeito do Impulso
+stat.maxunits = Máximo de unidades ativas
+stat.health = Saúde
+stat.buildtime = Tempo de construção
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Custo de construção
+stat.inaccuracy = Imprecisão
+stat.shots = Tiros
+stat.reload = Tiros por segundo
+stat.ammo = Munição
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Broca melhor necessária.
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = Uma grande torre que dispara balas explosivas que se
block.spectre.description = Um grande canhão massivo. Dispara grandes tiros perfuradores de blindagem em inimigos aéreos e terrestres.
block.meltdown.description = Um grande canhão laser massivo. Carrega e dispara um poderoso e persistente feixe nos seus inimigos. Requer uma refrigeração para ser operada.
block.repair-point.description = Continuamente repara a unidade danificada mais proxima.
-block.segment.description = Destrói projéteis inimigos. Projéteis de laser não são afetados.
+block.segment.description = Destrói projéteis inimigos. Projéteis de laser não são afetados.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_pt_PT.properties b/core/assets/bundles/bundle_pt_PT.properties
index 0b6948191b..c4b5070b3a 100644
--- a/core/assets/bundles/bundle_pt_PT.properties
+++ b/core/assets/bundles/bundle_pt_PT.properties
@@ -570,49 +570,49 @@ info.title = [accent]Informação
error.title = [crimson]Ocorreu um Erro.
error.crashtitle = Ocorreu um Erro
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Entrada
-blocks.output = Saida
-blocks.booster = Booster
-blocks.tiles = Telhas Requeridas
-blocks.affinities = Afinidades
+stat.input = Entrada
+stat.output = Saida
+stat.booster = Booster
+stat.tiles = Telhas Requeridas
+stat.affinities = Afinidades
block.unknown = [lightgray]???
-blocks.powercapacity = Capacidade de Energia
-blocks.powershot = Energia/tiro
-blocks.damage = Dano
-blocks.targetsair = Mirar no ar
-blocks.targetsground = Mirar no chão
-blocks.itemsmoved = Velocidade de movimento
-blocks.launchtime = Tempo entre tiros
-blocks.shootrange = Alcance
-blocks.size = Tamanho
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Capacidade de Líquido
-blocks.powerrange = Alcance da Energia
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Max Connections
-blocks.poweruse = Uso de energia
-blocks.powerdamage = Dano/Poder
-blocks.itemcapacity = Capacidade de Itens
-blocks.basepowergeneration = Geração de poder base
-blocks.productiontime = Tempo de produção
-blocks.repairtime = Tempo de reparo total do bloco
-blocks.speedincrease = Aumento de velocidade
-blocks.range = Distância
-blocks.drilltier = Furáveis
-blocks.drillspeed = Velocidade da broca base
-blocks.boosteffect = Efeito do Boost
-blocks.maxunits = Máximo de unidades ativas
-blocks.health = Saúde
-blocks.buildtime = Tempo de construção
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Custo de construção
-blocks.inaccuracy = Imprecisão
-blocks.shots = Tiros
-blocks.reload = Tiros por segundo
-blocks.ammo = Munição
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Capacidade de Energia
+stat.powershot = Energia/tiro
+stat.damage = Dano
+stat.targetsair = Mirar no ar
+stat.targetsground = Mirar no chão
+stat.itemsmoved = Velocidade de movimento
+stat.launchtime = Tempo entre tiros
+stat.shootrange = Alcance
+stat.size = Tamanho
+stat.displaysize = Display Size
+stat.liquidcapacity = Capacidade de Líquido
+stat.powerrange = Alcance da Energia
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Max Connections
+stat.poweruse = Uso de energia
+stat.powerdamage = Dano/Poder
+stat.itemcapacity = Capacidade de Itens
+stat.basepowergeneration = Geração de poder base
+stat.productiontime = Tempo de produção
+stat.repairtime = Tempo de reparo total do bloco
+stat.speedincrease = Aumento de velocidade
+stat.range = Distância
+stat.drilltier = Furáveis
+stat.drillspeed = Velocidade da broca base
+stat.boosteffect = Efeito do Boost
+stat.maxunits = Máximo de unidades ativas
+stat.health = Saúde
+stat.buildtime = Tempo de construção
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Custo de construção
+stat.inaccuracy = Imprecisão
+stat.shots = Tiros
+stat.reload = Tiros por segundo
+stat.ammo = Munição
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Broca melhor necessária.
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = Uma grande torre de tiro rapido.
block.spectre.description = Uma grande torre que da dois tiros poderosos ao mesmo tempo.
block.meltdown.description = Uma grande torre que atira dois raios poderosos ao mesmo tempo.
block.repair-point.description = Continuamente repara a unidade danificada mais proxima.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_ro.properties b/core/assets/bundles/bundle_ro.properties
index 053fbdc7d7..33ac8a8436 100644
--- a/core/assets/bundles/bundle_ro.properties
+++ b/core/assets/bundles/bundle_ro.properties
@@ -20,7 +20,7 @@ gameover = Jocul s-a încheiat
gameover.pvp = Echipa [accent] {0}[] este câștigătoare!
highscore = [accent]Scor maxim nou!
copied = Copiat.
-indev.popup = [accent]v6[] este momentan în [accent]alpha[].\n[lightgray]Asta înseamnă că:[]\n[scarlet]- Campania este complet neterminată[]\n- Majoritatea [scarlet]AI-ului unităților[] nu funcționează bine\n- Multe unități sunt neterminate\n- Modul campanie nu este terminat \n- Tot ce vedeți se poate schimba sau poate fi eliminat.\n\nPentru a raporta buguri și crashuri intrați pe [accent]Github[].
+indev.popup = [accent]v6[] este momentan în [accent]beta[].\n[lightgray]Asta înseamnă că:[]\n[scarlet]- Campania este complet neterminată[]\n- Efectele sonore și muzica sunt neterminate/lipsesc\n- Majoritatea [scarlet]AI-ului unităților[] nu funcționează bine\n- Multe unități sunt neterminate\n- Modul campanie nu este terminat \n- Tot ce vedeți se poate schimba sau poate fi eliminat.\n\nPentru a raporta buguri și crashuri intrați pe [accent]Github[].
indev.notready = Această secțiune a jocului nu este gata încă.
load.sound = Sunete
@@ -100,8 +100,7 @@ committingchanges = Se Încarcă Schimbările
done = Gata
feature.unsupported = Dispozitivul tău nu suportă această funcție.
-mods.alphainfo = Modurile sunt încă în alpha și[scarlet] pot avea multe buguri[].\nRaportați orice probleme apărute pe Githubul Mindustry sau pe Discord.
-mods.alpha = [accent](Alpha)
+mods.alphainfo = Modurile sunt încă în alpha și[scarlet] pot avea multe buguri[].\nRaportați orice probleme apărute pe Githubul Mindustry.
mods = Moduri
mods.none = [lightgray]Nu s-au găsit moduri!
mods.guide = Ghid de Modding
@@ -285,6 +284,7 @@ selectschematic = [accent][[{0}][] pt selectare+copiere
pausebuilding = [accent][[{0}][] pt a face o pauză de la construit
resumebuilding = [scarlet][[{0}][] pt a continua construitul
wave = [accent]Valul {0}
+wave.cap = [accent]Valul {0}/{1}
wave.waiting = [lightgray]Val în {0}
wave.waveInProgress = [lightgray]Val în desfășurare
waiting = [lightgray]În așteptare...
@@ -350,6 +350,7 @@ waves.invalid = Valuri invalide în clipboard.
waves.copied = Valuri copiate.
waves.none = Niciun inamic definit.\nDe reținut că o listă de valuri goală va fi înlocuită automat cu lista de valuri prestabilită.
+#intenționat cu literă mică
wavemode.counts = numere
wavemode.totals = totaluri
wavemode.health = viață
@@ -477,9 +478,10 @@ requirement.research = Cercetează {0}
requirement.capture = Capturează {0}
bestwave = [lightgray]Cel Mai Bun Val: {0}
launch.text = Lansează
-campaign.multiplayer = Când joci muliplayer în campanie, nu poți cerceta noi tehnologii decât folosind materiale din sectoarele [accent]tale[], [scarlet]nu[] din sectorul gazdei jocului, unde te afli acum.\n\nPt a transfera materialele către sectoarele [accent]tale[] în multiplayer, folosește o [accent]platformă de lansare[].
+research.multiplayer = Doar gazda poate cerceta noi tehnologii.
uncover = Descoperă
-configure = Configurează Încărcarea
+configure = Configurează Încărcarea
+#Spațiu Necesar
loadout = Încărcare
resources = Resurse
bannedblocks = Blocuri Interzise
@@ -510,6 +512,7 @@ weather.rain.name = Ploaie
weather.snow.name = Ninsoare
weather.sandstorm.name = Furtună de nisip
weather.sporestorm.name = Furtună de spori
+weather.fog.name = Ceață
sectors.unexplored = [lightgray]Neexplorat
sectors.resources = Resurse:
@@ -519,7 +522,14 @@ sectors.resume = Revino
sectors.launch = Lansare
sectors.select = Selectează
sectors.nonelaunch = [lightgray]nimic (soarele)
+sectors.rename = Redenumește Sectorul
+sector.missingresources = [scarlet]Resurse din Nucleu Insuficiente
+planet.serpulo.name = Serpulo
+#Spațiu Necesar
+planet.sun.name = Soare
+
+#Spațiu Necesar
sector.groundZero.name = Ground Zero
sector.craters.name = The Craters
sector.frozenForest.name = Frozen Forest
@@ -532,8 +542,12 @@ sector.tarFields.name = Tar Fields
sector.saltFlats.name = Salt Flats
sector.fungalPass.name = Fungal Pass
+#Spațiu
+#Absolut
+#Necesar
+
sector.groundZero.description = Locația optimă pt a începe încă odată. Risc de inamici scăzut. Puține resurse.\nAdună cât de mult plumb și cupru se poate.\nMergi mai departe.
-sector.frozenForest.description = Chiar și aici, aproape de munți, sperii s-au împrăștiat. Temperaturile reci nu-i pot reține la infinit.\n\nÎncepe călătoria către electricitate. Construiește generatoare de combustie. Învață să folosești reparatoare.
+sector.frozenForest.description = Chiar și aici, aproape de munți, sporii s-au împrăștiat. Temperaturile reci nu-i pot reține la infinit.\n\nÎncepe călătoria către electricitate. Construiește generatoare de combustie. Învață să folosești reparatoare.
sector.saltFlats.description = La periferia deșertului stau Salt Flats. Puține resurse pot fi găsite în această locație.\n\nInamicul a ridicat un complex-depozit aici. Distruge-le nucleul. Nu lăsa nimic în urmă.
sector.craters.description = Apa s-a acumulat în acest crater, rămășiță a vechilor războaie. Cucerește din nou zona. Adună nisip. Toarnă-l în metasticlă. Pompează apă pt a răci armele și burghiele.
sector.ruinousShores.description = După deșerturi vine țărmul. Odată, locația aceasta a avut un sistem de apărare de coastă. N-a rămas mult din el. Doar structurile de apărare cele mai de bază rămas în picioare, restul fiind redus la fier vechi.\nContinuă expansiunea în afară. Redescoperă tehnologia.
@@ -569,50 +583,73 @@ error.title = [scarlet]A apărut o eroare.
error.crashtitle = A apărut o eroare.
unit.nobuild = [scarlet]Unitatea nu poate construi.
lastaccessed = [lightgray]Ultima Accesare: {0}
-blocks.input = Necesită
-blocks.output = Produce
-blocks.booster = Booster
-blocks.tiles = Teren Necesar
-blocks.affinities = Efecte Teren
block.unknown = [lightgray]???
-blocks.powercapacity = Capacitate electrică
-blocks.powershot = Electricitate/Glonț
-blocks.damage = Forță
-blocks.targetsair = Lovește Aeronave
-blocks.targetsground = Lovește Artilerie
-blocks.itemsmoved = Viteza de Mișcare a Materialelor
-blocks.launchtime = Timp între Lansări
-blocks.shootrange = Rază
-blocks.size = Mărime
-blocks.displaysize = Mărimea Monitorului Logic
-blocks.liquidcapacity = Capacitate Lichid
-blocks.powerrange = Raza Electrică
-blocks.linkrange = Raza Legăturilor
-blocks.instructions = Instrucțiuni
-blocks.powerconnections = Maxim Conexiuni
-blocks.poweruse = Consum Electricitate
-blocks.powerdamage = Electricitate/Forța Glonțului
-blocks.itemcapacity = Capacitate Materiale
-blocks.memorycapacity = Capacitate Memorie
-blocks.basepowergeneration = Generare Electricitate (Bază)
-blocks.productiontime = Timp Producție
-blocks.repairtime = Durata Reparării Blocului
-blocks.speedincrease = Creștere Viteză
-blocks.range = Rază
-blocks.drilltier = Minabile
-blocks.drillspeed = Viteză Burghiu (Bază)
-blocks.boosteffect = Efect de Boost
-blocks.maxunits = Maxim Unități Active
-blocks.health = Viață
-blocks.buildtime = Timp Construcție
-blocks.maxconsecutive = Maxim Consecutive
-blocks.buildcost = Cost Construcție
-blocks.inaccuracy = Inacuratețe
-blocks.shots = Lovituri
-blocks.reload = Lovituri/Secundă
-blocks.ammo = Muniție
-blocks.shieldhealth = Viața Scutului
-blocks.cooldowntime = Timp de Reîncărcare
+
+stat.input = Necesită
+stat.output = Produce
+stat.booster = Booster
+stat.tiles = Teren Necesar
+stat.affinities = Efecte Teren
+stat.powercapacity = Capacitate electrică
+stat.powershot = Electricitate/Glonț
+stat.damage = Forță
+stat.targetsair = Lovește Aeronave
+stat.targetsground = Lovește Artilerie
+stat.itemsmoved = Viteză de Mișcare a Materialelor
+stat.launchtime = Timp între Lansări
+stat.shootrange = Rază
+stat.size = Mărime
+stat.displaysize = Mărime Monitor Logic
+stat.liquidcapacity = Capacitate Lichid
+stat.powerrange = Rază Electrică
+stat.linkrange = Rază Legături
+stat.instructions = Instrucțiuni
+stat.powerconnections = Maxim Conexiuni
+stat.poweruse = Consum Electricitate
+stat.powerdamage = Electricitate/Forța Glonțului
+stat.itemcapacity = Capacitate Materiale
+stat.memorycapacity = Capacitate Memorie
+stat.basepowergeneration = Generare Electricitate (Bază)
+stat.productiontime = Timp Producție
+stat.repairtime = Durată Reparare Bloc
+stat.speedincrease = Creștere Viteză
+stat.range = Rază
+stat.drilltier = Minabile
+stat.drillspeed = Viteză Burghiu (Bază)
+stat.boosteffect = Efect de Boost
+stat.maxunits = Maxim Unități Active
+stat.health = Viață
+stat.buildtime = Timp Construcție
+stat.maxconsecutive = Maxim Consecutive
+stat.buildcost = Cost Construcție
+stat.inaccuracy = Inacuratețe
+stat.shots = Lovituri
+stat.reload = Lovituri/Secundă
+stat.ammo = Muniție
+stat.shieldhealth = Viață Scut
+stat.cooldowntime = Timp de Reîncărcare
+stat.explosiveness = Explozivitate
+stat.basedeflectchance = Șansă de Reflexie
+stat.lightningchance = Șansă Fulger
+stat.lightningdamage = Forță Fulger
+stat.flammability = Inflamabilitate
+stat.radioactivity = Radioactivitate
+stat.heatcapacity = Capacitate de Căldură
+stat.viscosity = Vâscozitate
+stat.temperature = Temperatură
+stat.speed = Viteză
+stat.buildspeed = Viteză Construcție
+stat.minespeed = Viteză Minare
+stat.minetier = Putere Minare
+stat.payloadcapacity = Capacitate Încărcătură
+stat.commandlimit = Nr Unități Comandate
+stat.abilities = Abilități
+
+ability.forcefield = Câmp de Forță
+ability.repairfield = Câmp de Reparare
+ability.statusfield = Câmp Suprasolicitare Unități
+ability.unitspawn = {0} Fabrici
+ability.shieldregenfield = Câmp de Regenerare a Scutului
bar.drilltierreq = Burghiu Mai Bun Necesar
bar.noresources = Resurse lipsă
@@ -628,7 +665,7 @@ bar.powerlines = Conexiuni: {0}/{1}
bar.items = Materiale: {0}
bar.capacity = Capacitate: {0}
bar.unitcap = {0} {1}/{2}
-bar.limitreached = [scarlet] {0} / {1}[white] {2}\n[lightgray][[unit disabled]
+bar.limitreached = [scarlet] {0} / {1}[white] {2}\n[lightgray][[unitate dezactivată]
bar.liquid = Lichid
bar.heat = Căldură
bar.power = Electricitate
@@ -645,12 +682,15 @@ bullet.homing = [stat]cu radar
bullet.shock = [stat]șoc
bullet.frag = [stat]fragil
bullet.knockback = [stat]{0} [lightgray]împingere
+bullet.pierce = [stat]{0}[lightgray]x penetrare
+bullet.infinitepierce = penetrare [stat]
bullet.freezing = [stat]înghețat
bullet.tarred = [stat]lipicios
bullet.multiplier = [stat]{0}[lightgray]x multiplicator muniție
bullet.reload = [stat]{0}[lightgray]x lovituri
unit.blocks = blocuri
+unit.blockssquared = blocuri²
unit.powersecond = electricitate/secundă
unit.liquidsecond = unități lichid/secundă
unit.itemssecond = materiale/secundă
@@ -663,7 +703,7 @@ unit.persecond = /sec
unit.perminute = /min
unit.timesspeed = x viteză
unit.percent = %
-unit.shieldhealth = viața scutului
+unit.shieldhealth = viață scut
unit.items = materiale
unit.thousands = mii
unit.millions = mil
@@ -682,7 +722,6 @@ setting.linear.name = Filtrare Liniară
setting.hints.name = Indicii
setting.flow.name = Afișează Rata de Curgere a lichidelor
setting.buildautopause.name = Autopauză de la Construit
-setting.mapcenter.name = Auto Centrează Harta La Jucător
setting.animatedwater.name = Fluide Animate
setting.animatedshields.name = Scuturi Animate
setting.antialias.name = Antialiasing[lightgray] (necesită repornire)[]
@@ -716,7 +755,6 @@ setting.fullscreen.name = Ecran Complet
setting.borderlesswindow.name = Fereastră Fără Margine[lightgray] (repornirea poate fi necesară)
setting.fps.name = Vezi FPS & Ping
setting.smoothcamera.name = Cameră Graduală
-setting.blockselectkeys.name = Vezi Detalii Cheie cu Privire la Selectarea Blocurilor
setting.vsync.name = VSync
setting.pixelate.name = Pixelează
setting.minimap.name = Vezi Miniharta
@@ -726,7 +764,7 @@ setting.musicvol.name = Volumul Muzicii
setting.atmosphere.name = Vezi Atmosfera Planetelor
setting.ambientvol.name = Volum Ambiental
setting.mutemusic.name = Muzica pe Mut
-setting.sfxvol.name = Volum SFX
+setting.sfxvol.name = Volum Efecte Sonore
setting.mutesound.name = Sunetul pe Mut
setting.crashreport.name = Trimite Rapoarte de Crash anonime
setting.savecreate.name = Auto-Creează Salvări
@@ -863,6 +901,7 @@ content.item.name = Materiale
content.liquid.name = Lichide
content.unit.name = Unități
content.block.name = Blocuri
+
item.copper.name = Cupru
item.lead.name = Plumb
item.coal.name = Cărbune
@@ -884,23 +923,6 @@ liquid.slag.name = Zgură
liquid.oil.name = Petrol
liquid.cryofluid.name = Criofluid
-item.explosiveness = [lightgray]Explozivitate: {0}%
-item.flammability = [lightgray]Inflamabilitate: {0}%
-item.radioactivity = [lightgray]Radioactivitate: {0}%
-
-unit.health = [lightgray]Viață: {0}
-unit.speed = [lightgray]Viteză: {0}
-unit.weapon = [lightgray]Armă: {0}
-unit.itemcapacity = [lightgray]Capacitatea de Material: {0}
-unit.minespeed = [lightgray]Viteza de Minare: {0}%
-unit.minepower = [lightgray]Puterea Minării: {0}
-unit.ability = [lightgray]Abilitate: {0}
-unit.buildspeed = [lightgray]Viteza de Construcție: {0}%
-
-liquid.heatcapacity = [lightgray]Capacitatea de Căldură: {0}
-liquid.viscosity = [lightgray]Vâscozitatea: {0}
-liquid.temperature = [lightgray]Temperatura: {0}
-
unit.dagger.name = Dagger
unit.mace.name = Mace
unit.fortress.name = Fortress
@@ -986,6 +1008,7 @@ block.sand-water.name = Apă cu Nisip
block.darksand-water.name = Apă cu Nisip Negru
block.char.name = Turbă
block.dacite.name = Dacit
+block.dacite-boulder.name = Bolovan de Dacit
block.dacite-wall.name = Perete de Dacit
block.ice-snow.name = Gheață Înzăpezită
block.stone-wall.name = Perete de Piatră
@@ -1153,7 +1176,7 @@ team.blue.name = albastră
team.crux.name = roșie
team.sharded.name = portocalie
team.orange.name = portocalie
-team.derelict.name = abandonat
+team.derelict.name = abandonată
team.green.name = verde
team.purple.name = mov
diff --git a/core/assets/bundles/bundle_ru.properties b/core/assets/bundles/bundle_ru.properties
index 1e12db9ee4..078a1cf6f4 100644
--- a/core/assets/bundles/bundle_ru.properties
+++ b/core/assets/bundles/bundle_ru.properties
@@ -576,50 +576,50 @@ error.title = [scarlet]Произошла ошибка
error.crashtitle = Произошла ошибка
unit.nobuild = [scarlet]Боевая единица не может строить
lastaccessed = [lightgray]Последняя конфигурация от {0}
-blocks.input = Вход
-blocks.output = Выход
-blocks.booster = Ускоритель
-blocks.tiles = Необходимые плитки
-blocks.affinities = Увеличение эффективности
+stat.input = Вход
+stat.output = Выход
+stat.booster = Ускоритель
+stat.tiles = Необходимые плитки
+stat.affinities = Увеличение эффективности
block.unknown = [lightgray]???
-blocks.powercapacity = Вместимость энергии
-blocks.powershot = Энергия/Выстрел
-blocks.damage = Урон
-blocks.targetsair = Воздушные цели
-blocks.targetsground = Наземные цели
-blocks.itemsmoved = Скорость перемещения
-blocks.launchtime = Интервал запусков
-blocks.shootrange = Радиус действия
-blocks.size = Размер
-blocks.displaysize = Размер дисплея
-blocks.liquidcapacity = Вместимость жидкости
-blocks.powerrange = Дальность передачи энергии
-blocks.linkrange = Дальность связи
-blocks.instructions = Инструкции
-blocks.powerconnections = Количество соединений
-blocks.poweruse = Потребляет энергии
-blocks.powerdamage = Энергия/урон
-blocks.itemcapacity = Вместимость предметов
-blocks.memorycapacity = Размер памяти
-blocks.basepowergeneration = Базовая генерация энергии
-blocks.productiontime = Время производства
-blocks.repairtime = Время полной регенерации
-blocks.speedincrease = Увеличение скорости
-blocks.range = Радиус действия
-blocks.drilltier = Бурит
-blocks.drillspeed = Базовая скорость бурения
-blocks.boosteffect = Ускоряющий эффект
-blocks.maxunits = Максимальное количество активных единиц
-blocks.health = Прочность
-blocks.buildtime = Время строительства
-blocks.maxconsecutive = Макс. последовательность
-blocks.buildcost = Стоимость строительства
-blocks.inaccuracy = Разброс
-blocks.shots = Выстрелы
-blocks.reload = Выстрелы/секунду
-blocks.ammo = Боеприпасы
-blocks.shieldhealth = Прочность щита
-blocks.cooldowntime = Время восстановления
+stat.powercapacity = Вместимость энергии
+stat.powershot = Энергия/Выстрел
+stat.damage = Урон
+stat.targetsair = Воздушные цели
+stat.targetsground = Наземные цели
+stat.itemsmoved = Скорость перемещения
+stat.launchtime = Интервал запусков
+stat.shootrange = Радиус действия
+stat.size = Размер
+stat.displaysize = Размер дисплея
+stat.liquidcapacity = Вместимость жидкости
+stat.powerrange = Дальность передачи энергии
+stat.linkrange = Дальность связи
+stat.instructions = Инструкции
+stat.powerconnections = Количество соединений
+stat.poweruse = Потребляет энергии
+stat.powerdamage = Энергия/урон
+stat.itemcapacity = Вместимость предметов
+stat.memorycapacity = Размер памяти
+stat.basepowergeneration = Базовая генерация энергии
+stat.productiontime = Время производства
+stat.repairtime = Время полной регенерации
+stat.speedincrease = Увеличение скорости
+stat.range = Радиус действия
+stat.drilltier = Бурит
+stat.drillspeed = Базовая скорость бурения
+stat.boosteffect = Ускоряющий эффект
+stat.maxunits = Максимальное количество активных единиц
+stat.health = Прочность
+stat.buildtime = Время строительства
+stat.maxconsecutive = Макс. последовательность
+stat.buildcost = Стоимость строительства
+stat.inaccuracy = Разброс
+stat.shots = Выстрелы
+stat.reload = Выстрелы/секунду
+stat.ammo = Боеприпасы
+stat.shieldhealth = Прочность щита
+stat.cooldowntime = Время восстановления
bar.drilltierreq = Требуется бур получше
bar.noresources = Недостаточно ресурсов
@@ -1321,5 +1321,4 @@ block.cyclone.description = Большая турель, которая може
block.spectre.description = Массивная двуствольная пушка. Стреляет крупными бронебойными снарядами по воздушным и наземным целям.
block.meltdown.description = Массивная лазерная пушка. Заряжает и стреляет постоянным лазерным лучом в ближайших врагов. Требуется охлаждающая жидкость для работы.
block.repair-point.description = Непрерывно лечит ближайшую поврежденную боевую единицу или мех в своём радиусе.
-block.segment.description = Повреждает и разрушает приближающиеся снаряды. Не взаимодействует с лазерными лучами.
-
+block.segment.description = Повреждает и разрушает приближающиеся снаряды. Не взаимодействует с лазерными лучами.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_sv.properties b/core/assets/bundles/bundle_sv.properties
index 0d29e6a89e..8d3942eccb 100644
--- a/core/assets/bundles/bundle_sv.properties
+++ b/core/assets/bundles/bundle_sv.properties
@@ -570,49 +570,49 @@ info.title = Info
error.title = [crimson]An error has occured
error.crashtitle = An error has occured
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Inmatning
-blocks.output = Utmatning
-blocks.booster = Booster
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
+stat.input = Inmatning
+stat.output = Utmatning
+stat.booster = Booster
+stat.tiles = Required Tiles
+stat.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = Power Capacity
-blocks.powershot = Power/Shot
-blocks.damage = Skada
-blocks.targetsair = Targets Air
-blocks.targetsground = Targets Ground
-blocks.itemsmoved = Move Speed
-blocks.launchtime = Time Between Launches
-blocks.shootrange = Range
-blocks.size = Storlek
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Liquid Capacity
-blocks.powerrange = Power Range
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Max Connections
-blocks.poweruse = Power Use
-blocks.powerdamage = Power/Damage
-blocks.itemcapacity = Item Capacity
-blocks.basepowergeneration = Base Power Generation
-blocks.productiontime = Production Time
-blocks.repairtime = Block Full Repair Time
-blocks.speedincrease = Speed Increase
-blocks.range = Range
-blocks.drilltier = Drillables
-blocks.drillspeed = Base Drill Speed
-blocks.boosteffect = Boost Effect
-blocks.maxunits = Max Active Units
-blocks.health = Health
-blocks.buildtime = Build Time
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Build Cost
-blocks.inaccuracy = Inaccuracy
-blocks.shots = Skott
-blocks.reload = Shots/Second
-blocks.ammo = Ammunition
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Power Capacity
+stat.powershot = Power/Shot
+stat.damage = Skada
+stat.targetsair = Targets Air
+stat.targetsground = Targets Ground
+stat.itemsmoved = Move Speed
+stat.launchtime = Time Between Launches
+stat.shootrange = Range
+stat.size = Storlek
+stat.displaysize = Display Size
+stat.liquidcapacity = Liquid Capacity
+stat.powerrange = Power Range
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Max Connections
+stat.poweruse = Power Use
+stat.powerdamage = Power/Damage
+stat.itemcapacity = Item Capacity
+stat.basepowergeneration = Base Power Generation
+stat.productiontime = Production Time
+stat.repairtime = Block Full Repair Time
+stat.speedincrease = Speed Increase
+stat.range = Range
+stat.drilltier = Drillables
+stat.drillspeed = Base Drill Speed
+stat.boosteffect = Boost Effect
+stat.maxunits = Max Active Units
+stat.health = Health
+stat.buildtime = Build Time
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Build Cost
+stat.inaccuracy = Inaccuracy
+stat.shots = Skott
+stat.reload = Shots/Second
+stat.ammo = Ammunition
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Bättre Borr Krävs
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = A large anti-air and anti-ground turret. Fires explo
block.spectre.description = A massive dual-barreled cannon. Shoots large armor-piercing bullets at air and ground targets.
block.meltdown.description = A massive laser cannon. Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate.
block.repair-point.description = Continuously heals the closest damaged unit in its vicinity.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_th.properties b/core/assets/bundles/bundle_th.properties
index 6a89ac29ca..1bf27c3387 100644
--- a/core/assets/bundles/bundle_th.properties
+++ b/core/assets/bundles/bundle_th.properties
@@ -7,21 +7,21 @@ link.reddit.description = ซับเรดดิท (subreddit) ของ Mind
link.github.description = source code ของเกม
link.changelog.description = รายการที่อัปเดต
link.dev-builds.description = เวอร์ชั่นระหว่างพัฒนา (ไม่เสถียร)
-link.trello.description = Official Trello board for planned features
-link.itch.io.description = itch.io page with PC downloads
-link.google-play.description = Google Play store listing
-link.f-droid.description = F-Droid catalogue listing
-link.wiki.description = Official Mindustry wiki
-link.suggestions.description = Suggest new features
+link.trello.description = Trello board ทางการสำหรับฟีเจอร์ต่างๆที่วางแผนไว้
+link.itch.io.description = หน้าเว็บ itch.io สำหรับดาวน์โหลดบน PC
+link.google-play.description = หน้า Google Play store ของเกม
+link.f-droid.description = หน้าแคตาลอค F-Droid ของเกม
+link.wiki.description = วิกิของ Mindustry อย่างเป็นทางการ
+link.suggestions.description = เสนอฟีเจอร์ใหม่
linkfail = ไม่สามารถเปิดลิ้งค์ได้\nคัดลอก URL ลงในคลิปบอร์ดแล้ว
screenshot = Screenshot บันทึกที่ {0}
screenshot.invalid = แมพใหญ่เกินไป, หน่วยความจำอาจจะไม่พอสำหรับ screenshot.
-gameover = Game Over
+gameover = จบเกม
gameover.pvp = ทีมที่ชนะคือทีม[accent] {0}[]!
highscore = [accent]คะแนนสูงสุดใหม่!
copied = คัดลอกแล้ว.
-indev.popup = [accent]v6[] is currently in [accent]alpha[].\n[lightgray]This means:[]\n[scarlet]- The campaign is completely unfinished[]\n- Content is missing\n - Most [scarlet]Unit AI[] does not work properly\n- Many units are unfinished\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[].
-indev.notready = This part of the game isn't ready yet
+indev.popup = [accent]เวอร์ชั่น v6[] ณ ขณะนี้อยู่ในช่วง [accent]alpha[].\n[lightgray]นั้นหมายถึง:[]\n[scarlet]- เคมเปญไม่ยังเสร็จสมบูรณ์ []\n- เนื้อหาบางอย่างขาดหาย\n - [scarlet]AI ของยูนิต[] ส่วนใหญ่ทำงานได้แบบไม่สมบูรณ์\n- ยูนิตส่วนมากยังไม่เสร็จ\n- ที่อย่างที่เห็นอาจเปลี่ยนแปลงได้หรือลบออกโดยสิ้นเชิงในอนาคต\n\nแจ้งบัคหรือปัญหาที่พบเจอได้ที่ [accent]Github[].
+indev.notready = ส่วนนี้ของเกมยังไม่พร้อมให้ใช้งาน
load.sound = เสียง
load.map = แมพ
@@ -31,7 +31,7 @@ load.system = ระบบ
load.mod = มอด
load.scripts = สคริปต์
-be.update = A new Bleeding Edge build is available:
+be.update = เวอร์ชั้นล่าสุดออกแล้ว:
be.update.confirm = ดาวน์โหลดเวอร์ชั่นใหม่แล้วรีสตาร์ทเลยไหม?
be.updating = กำลังอัปเดต...
be.ignore = ยกเลิก
@@ -42,7 +42,7 @@ schematic = แผนผัง
schematic.add = กำลังบันทึกแผนผัง...
schematics = แผนผัง
schematic.replace = มีแผนผังที่ใช้ชื่อนี้แล้ว. แทนที่เลยไหม?
-schematic.exists = A schematic by that name already exists.
+schematic.exists = มีแผนผังในชื่อนั้นอยู่แล้ว
schematic.import = นำเข้าแผนผัง...
schematic.exportfile = ส่งออกไฟล์
schematic.importfile = นำเข้าไฟล์
@@ -62,17 +62,17 @@ stat.built = จำนวนสิ่งก่อสร้างที่สร
stat.destroyed = จำนวนสิ่งก่อสร้างของศัตรูที่ทำลายไปได้:[accent] {0}
stat.deconstructed = จำนวนสิ่งก่อสร้างที่ถูกทำลายไป:[accent] {0}
stat.delivered = ทรัพยากรที่ส่งไปได้:
-stat.playtime = Time Played:[accent] {0}
+stat.playtime = ระยะเวลาที่เล่นไป:[accent] {0}
stat.rank = ระดับ: [accent]{0}
-globalitems = [accent]Global Items
+globalitems = [accent]ไอเท็มโกลบอล
map.delete = คุณแน่ใจหรือว่าจะลบแมพชื่อ "[accent]{0}[]"?
level.highscore = คะแนนสูงสุด: [accent]{0}
level.select = เลือกด่าน
level.mode = เกมโหมด:
coreattack = < แกนกลางกำลังถูกโจมตี! >
nearpoint = [[ [scarlet]ออกจากดรอปพอยท์ด่วน IMMEDIATELY[] ]\nการทำลายล้างกำลังใกล้เข้ามา
-database = ฐานข้อมูหลัง
+database = ฐานข้อมูลหลัก
savegame = เซฟเกม
loadgame = โหลดเกม
joingame = เข้าร่วมเกม
@@ -90,12 +90,12 @@ maps.browse = ค้นหาแมพ
continue = ต่อ
maps.none = [lightgray]ไม่มีแมพ!
invalid = ไม่ถูกต้อง
-pickcolor = Pick Color
+pickcolor = เลือกสี
preparingconfig = กำลังเตรียม Config
-preparingcontent = กำลังเตรียม Content
-uploadingcontent = กำลังอัปโหลด Content
+preparingcontent = กำลังเตรียมเนื้อหา
+uploadingcontent = กำลังอัปโหลดเนื้อหา
uploadingpreviewfile = กำลังอัปโหลดไฟล์พรีวิว
-committingchanges = Comitting Changes
+committingchanges = กำลังทำการเปลี่ยนแปลง
done = เรียบร้อย
feature.unsupported = อุปกรณ์ของคุณไม่รองรับฟีเจอร์นี้
@@ -106,53 +106,53 @@ mods.none = [lightgray]ไม่พบมอด!
mods.guide = คู่มือการทำมอด
mods.report = รายงานบัค
mods.openfolder = เปิดมอดโฟลเดอร์
-mods.reload = Reload
-mods.reloadexit = The game will now exit, to reload mods.
+mods.reload = โหลดใหม่
+mods.reloadexit = เกมจะออกเพื่อจะโหลดมอด
mod.display = [gray]Mod:[orange] {0}
mod.enabled = [lightgray]เปิดใช้งาน
mod.disabled = [scarlet]ปิดใช้งาน
mod.disable = ปิดใช้งาน
-mod.content = Content:
+mod.content = เนื้อหา:
mod.delete.error = ไม่สามารถลบมอดได้. ไฟล์อาจอยู่ในระหว่างการใช้งาน.
-mod.requiresversion = [scarlet]Requires min game version: [accent]{0}
-mod.outdated = [scarlet]Not compatible with V6 (no minGameVersion: 105)
+mod.requiresversion = [scarlet]เวอร์ชั่นเกมขั้นต่ำที่ต้องการ: [accent]{0}
+mod.outdated = [scarlet]ไม่สามารถใช้ได้ในเวอร์ชั่น V6 (ไม่มี minGameVersion: 105)
mod.missingdependencies = [scarlet]dependencies หาย: {0}
-mod.erroredcontent = [scarlet]Content Errors
-mod.errors = Errors have occurred loading content.
-mod.noerrorplay = [scarlet]You have mods with errors.[] Either disable the affected mods or fix the errors before playing.
+mod.erroredcontent = [scarlet]เนื้อหาผิดพลาด
+mod.errors = มีข้อผิดพลาดเกิดขึ้นระหว่าโหลดเนื้อหา
+mod.noerrorplay = [scarlet]คุณมีมอดที่มีข้อผิดพลาด.[] กรุณาปิดมอดนั้นๆหรือแก้ไขข้อผิดพลาดก่อนที่จะเล่น
mod.nowdisabled = [scarlet]มอด '{0}' ไม่มี dependencies:[accent] {1}\n[lightgray]จำเป็นต้องโหลดมอดพวกนี้ก่อน\nมอดนี้จะถูกปิดใช้งานโดยอัตโนมัติ
mod.enable = เปิดใช้งาน
mod.requiresrestart = เกมจะปิดลงเพื่อใส่มอด
mod.reloadrequired = [scarlet]จำเป็นต้องรีโหลด
mod.import = นำเข้ามอด
-mod.import.file = Import File
+mod.import.file = นำเข้าไฟล์
mod.import.github = นำเข้ามอดจาก Github
-mod.jarwarn = [scarlet]JAR mods are inherently unsafe.[]\nMake sure you're importing this mod from a trustworthy source!
-mod.item.remove = This item is part of the[accent] '{0}'[] mod. To remove it, uninstall that mod.
+mod.jarwarn = [scarlet]มอดไฟล์ JAR นั้นค่อนข้างไม่ปลอดภัย.[]\nกรุณาเช็คให้แน่ใจว่าคุณนำเข้ามอดนี้จะแหล่งที่เชื่อถือได้!
+mod.item.remove = ไอเทมนี้เป็นส่วนหนึ่งของมอด[accent] '{0}'[]. หากต้องการนำออก กรุณาถอดการติดตั้งมอดนั้น
mod.remove.confirm = มอดนี้จะถูกลบ
mod.author = [lightgray]ผู้สร้าง:[] {0}
-mod.missing = เซฟนี้มีมอดที่คุณอัปเดตหรือไม่ได้ติดตั้งแล้ว. อาจทำให้เซฟเสีย. คุณแน่จะหรือว่าจะโหลดเซฟนี้?\n[lightgray]Mods:\n{0}
+mod.missing = เซฟนี้มีมอดที่คุณอัปเดตหรือไม่ได้ติดตั้งแล้ว. อาจทำให้เซฟเสีย. คุณแน่จะหรือว่าจะโหลดเซฟนี้?\n[lightgray]มอดที่ใช้:\n{0}
mod.preview.missing = ก่อนที่จะนำมอดไปลงใน workshop, คุณต้องใส่รูปพรีวิวก่อน\nใส่รูปชื่อ[accent] preview.png[] ลงในโฟลเดอร์ของมอดแล้วลองอีกครั้ง
mod.folder.missing = มอดที่อยู่ในรูปแบบโฟลเดอร์เท่านั้นที่สามารถลงใน workshop ได้\nunzip ไฟล์แล้วลบไฟล์ zip เก่า แล้วรีสตาร์ทเกมหรือรีโหลดมอด
-mod.scripts.disable = Your device does not support mods with scripts. You must disable these mods to play the game.
+mod.scripts.disable = เครื่องของคุณไม่รองรับมอดที่มี scripts. คุณจำเป็นต้องปิดมอดเหล่านี้ก่อนจึงจะสามารถเล่นได้.
about.button = เกี่ยวกับ
name = ชื่อ:
noname = ใส่ชื่อ[accent] ผู้เล่น[] ก่อน.
-planetmap = Planet Map
-launchcore = Launch Core
+planetmap = แผนที่ดาวเคราะห์
+launchcore = ส่ง Core
filename = ชื่อไฟล์:
-unlocked = content ใหม่ปลดล็อค!
+unlocked = เนื้อหาใหม่ปลดล็อค!
completed = [accent]สำเร็จ
techtree = ความคืบหน้าในการวิจัย
research.list = [lightgray]วิจัย:
research = วิจัย
researched = [lightgray]{0} วิจัยแล้ว.
-research.progress = {0}% complete
+research.progress = เสร็จแล้ว {0}%
players = {0} ผู้เล่น
players.single = {0} ผู้เล่น
-players.search = search
-players.notfound = [gray]no players found
+players.search = ค้นหา
+players.notfound = [gray]ไม่พบผู้เล่น
server.closing = [accent]กำลังปิดเซิฟเวอร์...
server.kicked.kick = คุณถูกเตะออกจากเซิฟเวอร์!
server.kicked.whitelist = คุณไม่ได้อยู่ใน whitelisted
@@ -168,8 +168,8 @@ server.kicked.nameInUse = มีคนที่ใช้ชืชื่อนี
server.kicked.nameEmpty = ชื่อของคุณไม่สามารถใช้ได้
server.kicked.idInUse = คุณเชื่อมต่อกับเซิฟเวอร์นี้อยู่แล้ว เราไม่อนุญาตให้เชื่อมต่อ 2 บัญชีในเซฟเวอร์เดียวกัน
server.kicked.customClient = เซิฟเวอร์นี้ไม่รองรับ builds ปรับแต่ง. กรุณาโหลดของ official.
-server.kicked.gameover = Game over!
-server.kicked.serverRestarting = The server is restarting.
+server.kicked.gameover = จบเกม!
+server.kicked.serverRestarting = เซิฟเวอร์กำลังเริ่มใหม่.
server.versions = เวอร์ชั่นของคุณ:[accent] {0}[]\nเวอร์ชั่นของเซิฟเวอร์:[accent] {1}[]
host.info = ปุ่ม [accent]โฮสต์[] นั้นโฮสต์เซฟเวอร์ที่พอร์ท [scarlet]6567[]. \nทุกคนที่อยู่ใน [lightgray]wifi หรือ local network[] เดียวกันจะสามารถเห็นเซิฟเวอร์ของคุณในลิสของเซิฟเวอร์ได้\n\nถ้าคุณต้องการให้ผู้เล่นอื่นๆสามารถเชื่อมต่อได้จากทุกที่โดยใช้ IP, จำเป็นจะต้องใช้การ [accent]port forwarding[] \n\n[lightgray]Note: ถ้าผู้เล่นคนใดมีปัญหาในการเชื่อมต่อ LAN ของคุณ เช็คให้แน่ใจว่าคุณได้อนุญาตให้ Mindustry เข้าถึง local network ของคุณในการตั้งค่า firewall. จำให้ว่า network สาธารณะบางครั้งไม่อนุญาตการค้นหาเซิฟเวอร์
join.info = คุณสามารถใส่ [accent]IP ของเซิฟเวอร์[] เพื่อที่จะเชื่อมต่อหรือค้นหา เซิฟเวอร์ที่ใช้[accent]local network[] จะสามารถเชื่อมโดยใช้\n LAN หรือ WAN ก็ได้\n\n[lightgray]โน้ต: เกมนี้ไม่มีระบบค้นหาเซิฟเวอร์ global ให้อัตโนมัติserver list; ถ้าคุณต้องการเชื่อมต่อกับเซิฟเวอร์โดยใช้ IP, คุณจำเป็นต้องถาม IP ผู้เล่นที่โฮสต์เซิฟเวอร์นั้นๆ.
@@ -185,9 +185,9 @@ server.refreshing = กำลังรีเฟรชเซิฟเวอร์
hosts.none = [lightgray]ไม่พบเซิฟเวอร์ใน local!
host.invalid = [scarlet]ไม่สามารถเชื่อมต่อกับโฮสต์ได้
-servers.local = Local Servers
-servers.remote = Remote Servers
-servers.global = Community Servers
+servers.local = เซิฟเวอร์ Local
+servers.remote = เซิฟเวอร์ Remote
+servers.global = เซิฟเวอร์ Community
trace = Trace ผู้เล่น/ แกะรอยผู้เล่น
trace.playername = ชื่อผู้เล่น: [accent]{0}
@@ -269,7 +269,7 @@ copylink = คัดลอกลิ้งค์
back = กลับ
data.export = ส่งออกข้อมูล
data.import = นำเข้าข้อมูล
-data.openfolder = Open Data Folder
+data.openfolder = เปิดโฟลเดอร์ข้อมูล
data.exported = ข้อมูลส่งออกแล้ว
data.invalid = นี่ไม่ใช่ข้อมูลเกมที่ถูกต้อง.
data.import.confirm = การนำเข้าข้อมูลจากภายนอกจะเขียนทับข้อมูลเก่า[scarlet]ทั้งหมด[]\n[accent]และไม่สามารถย้อนกลับได้![]\n\nหลังจากที่นำข้อมูลแล้วเกมจะปิดลงโดยทันที
@@ -278,7 +278,7 @@ quit.confirm.tutorial = คุณแน่ใจหรือว่าคุณ
loading = [accent]กำลังโหลด...
reloading = [accent]กำลังรีโหลดมอด...
saving = [accent]กำลังเซฟ...
-respawn = [accent][[{0}][] to respawn in core
+respawn = [accent][[{0}]][]เพื่อเกิดใหม่ที่ core
cancelbuilding = [accent][[{0}][]เพื่อเคลียแผน
selectschematic = [accent][[{0}][]เพื่อเลือกและคัดลอก
pausebuilding = [accent][[{0}][]เพื่อหยุดการสร้างชั่วคราว
@@ -315,7 +315,7 @@ publish.error = การเผยแพร่ไอเท็มดังต่
steam.error = ไม่สามารถเริ่ม Steam service ได้\nError: {0}
editor.brush = แปรง
-editor.openin = เปิดมน Editor
+editor.openin = เปิดใน Editor
editor.oregen = การเกิดของแร่
editor.oregen.info = การเกิดของแร่:
editor.mapinfo = ข้อมูลของแมพ
@@ -331,13 +331,13 @@ editor.newmap = แมพใหม่
workshop = Workshop
waves.title = Waves
waves.remove = ลบ
-waves.never =
+waves.never = <ไม่เคย>
waves.every = ทุกๆ
waves.waves = wave(s)
waves.perspawn = ต่อสปาวน์
-waves.shields = shields/wave
-waves.to = to
-waves.guardian = Guardian
+waves.shields = เกราะ/wave
+waves.to = ถึง
+waves.guardian = การ์เดียน
waves.preview = พรีวิว
waves.edit = แก้ไข...
waves.copy = คัดลอกไปยังคลิปบอร์ด
@@ -346,8 +346,8 @@ waves.invalid = waves ในคลิปบอร์ดไม่ถูกต้
waves.copied = คัดลอก Waves แล้ว
waves.none = ไม่ได้กำหนดศัตรู\nwave layouts เปล่าจะถูกแทนที่โดย layout ค่าเริ่มต้นของเกม
-wavemode.counts = counts
-wavemode.totals = totals
+wavemode.counts = จำนวน
+wavemode.totals = ทั้งหมด
wavemode.health = health
editor.default = [lightgray]<ค่าเริ่่มต้น>
@@ -415,8 +415,8 @@ toolmode.drawteams.description = วาดทีมแทนที่จะเ
filters.empty = [lightgray]ไม่มีฟิลเตอร์! เพิ่มด้วยปุ่มด้านล่างนี้
filter.distort = บิดเบือน
filter.noise = นอยส์
-filter.enemyspawn = Enemy Spawn Select
-filter.corespawn = Core Select
+filter.enemyspawn = เบือกที่เกิดศัตรู
+filter.corespawn = เลือก Core
filter.median = เฉลี่ย
filter.oremedian = เฉลี่ยแร่
filter.blend = ผสมผสาน
@@ -436,7 +436,7 @@ filter.option.circle-scale = สเกลวงกลม
filter.option.octaves = เลอะเลือน
filter.option.falloff = หลุด
filter.option.angle = มุม
-filter.option.amount = Amount
+filter.option.amount = จำนวน
filter.option.block = บล็อค
filter.option.floor = พื้น
filter.option.flooronto = พื้น Target
@@ -474,7 +474,7 @@ requirement.capture = Capture {0}
resume = เล่นต่อในโซน:\n[lightgray]{0}
bestwave = [lightgray]Wave สูงสุด: {0}
launch = < ส่ง >
-launch.text = Launch
+launch.text = ส่ง
launch.title = ส่งเรียบร้อย
launch.next = [lightgray]โอกาสครั้งหน้าที่ wave {0}
launch.unable2 = [scarlet]ไม่สามารถส่งได้[]
@@ -483,8 +483,8 @@ launch.skip.confirm = ถ้าคุณข้ามตอนนี้, คุ
uncover = เปิดเผย
configure = ตั้งค่า Loadout
loadout = Loadout
-resources = Resources
-bannedblocks = Banned Blocks
+resources = ทรัพยากร
+bannedblocks = บล็อคต้องห้าม
addall = เพิ่มทั้งหมด
launch.destination = Destination: {0}
configure.invalid = จำนวนต้อยู่ระหว่าง 0 ถึง {0}.
@@ -508,18 +508,18 @@ error.io = Network I/O error.
error.any = Unknown network error.
error.bloom = ไม่สามารถเริ่มต้น bloom ได้\nอุปกรณ์ของคุณอาจไม่รองรับ
-weather.rain.name = Rain
-weather.snow.name = Snow
-weather.sandstorm.name = Sandstorm
-weather.sporestorm.name = Sporestorm
+weather.rain.name = ฝน
+weather.snow.name = หิมะ
+weather.sandstorm.name = พายุทราย
+weather.sporestorm.name = พายุสปอร์
-sectors.unexplored = [lightgray]Unexplored
-sectors.resources = Resources:
-sectors.production = Production:
-sectors.stored = Stored:
-sectors.resume = Resume
-sectors.launch = Launch
-sectors.select = Select
+sectors.unexplored = [lightgray]ยังไม่ได้สำรวจ
+sectors.resources = ทรัพยากร:
+sectors.production = การผลิต:
+sectors.stored = เก็บ:
+sectors.resume = ทำต่อ
+sectors.launch = ส่ง
+sectors.select = เลือก
sectors.nonelaunch = [lightgray]none (sun)
sector.groundZero.name = Ground Zero
@@ -534,22 +534,22 @@ sector.tarFields.name = Tar Fields
sector.saltFlats.name = Salt Flats
sector.fungalPass.name = Fungal Pass
-sector.groundZero.description = The optimal location to begin once more. Low enemy threat. Few resources.\nGather as much lead and copper as possible.\nMove on.
-sector.frozenForest.description = Even here, closer to mountains, the spores have spread. The frigid temperatures cannot contain them forever.\n\nBegin the venture into power. Build combustion generators. Learn to use menders.
-sector.saltFlats.description = On the outskirts of the desert lie the Salt Flats. Few resources can be found in this location.\n\nThe enemy has erected a resource storage complex here. Eradicate their core. Leave nothing standing.
-sector.craters.description = Water has accumulated in this crater, relic of the old wars. Reclaim the area. Collect sand. Smelt metaglass. Pump water to cool turrets and drills.
-sector.ruinousShores.description = Past the wastes, is the shoreline. Once, this location housed a coastal defense array. Not much of it remains. Only the most basic defense structures have remained unscathed, everything else reduced to scrap.\nContinue the expansion outwards. Rediscover the technology.
-sector.stainedMountains.description = Further inland lie the mountains, yet untainted by spores.\nExtract the abundant titanium in this area. Learn how to use it.\n\nThe enemy presence is greater here. Do not give them time to send their strongest units.
-sector.overgrowth.description = This area is overgrown, closer to the source of the spores.\nThe enemy has established an outpost here. Build Titan units. Destroy it. Reclaim that which was lost.
-sector.tarFields.description = The outskirts of an oil production zone, between the mountains and desert. One of the few areas with usable tar reserves.\nAlthough abandoned, this area has some dangerous enemy forces nearby. Do not underestimate them.\n\n[lightgray]Research oil processing technology if possible.
-sector.desolateRift.description = An extremely dangerous zone. Plentiful resources, but little space. High risk of destruction. Leave as soon as possible. Do not be fooled by the long spacing between enemy attacks.
-sector.nuclearComplex.description = A former facility for the production and processing of thorium, reduced to ruins.\n[lightgray]Research the thorium and its many uses.\n\nThe enemy is present here in great numbers, constantly scouting for attackers.
-sector.fungalPass.description = A transition area between high mountains and lower, spore-ridden lands. A small enemy reconnaissance base is located here.\nDestroy it.\nUse Dagger and Crawler units. Take out the two cores.
+sector.groundZero.description = ที่ที่ดีที่สุดในการเริ่มต้นอีกครั้ง. ศัตรูมีน้อย. ทรัพยากรน้อยฃ.\nเก็บตะกั่วและทองแดงให้ได้มากที่สุด.\nแล้วไปต่อ.
+sector.frozenForest.description = แม้แต่ที่นี่, ที่ที่อยู่ใกล้ภูเขา, สปอร์ก็ยังแพร่มาถึงที่นี่. อากาศที่เย็นเยือกไม่สามารถหยุดยั้งพวกมันได้ตลอดไป.\n\nเริ่มต้นการใช้ไฟฟ้า. สร้างเครื่องกำเนิดไฟฟ้าเผาไหม้ถ่าน. เรียนรู้ที่จะใช้เครื่องซ่อมแซม.
+sector.saltFlats.description = ณ ขอบของทะเลทราย เป็นที่ตั้งของ Salt Flats. สามารถพบทรัพยากรบางอย่างได้ที่นี่.\n\nศัตรูได้ตั้งฐานเก็บทรัพยากรไว้ที่นี่. ทำลาย core ของพวกมัน. อย่าให้มีอะไรเหลือ.
+sector.craters.description = น้ำขังอยู่ในหลุมอุกกาบาศนี้, ที่นี้เป็นอนุสรณ์ของสองคราม. ยึดพื้นที่นี่มา. เก็บทราย. เผากระจกเมต้า. ปั๊มน้ำเพื่อมาหล่อเย็นป้อมปืนและแท่นขุดเจาะ.
+sector.ruinousShores.description = ต่อจากของเสียต่างๆ, เป็นที่ตั้งของชายฝั่ง. ครั้งก่อน, ที่นี่เคยเป็นที่ตั้งของฐานป้องกันชายฝั่ง. ณ ตอนนี้แทบจะไม่เหลือแล้ว. มีเหลือแค่ระบบการป้องกันพื้นฐาน, ทุกอย่างที่เหลือถูกทำลายเหลือเพียงแค่เศษเหล็ก.\nทำการขยายการสำรวจต่อไป. ค้นพบกับเทคโนโลยีอีกครั้ง.
+sector.stainedMountains.description = เข้าลึกไปในพื้นที่ จะพบกับภูเขา, ซึ่งยังไม่ถูกสปอร์แตะต้อง.\nขุดไทเทเนียมที่อุดมสมบูรณ์ในพื้นที่นี้. เรียนรู้ที่จะใช้มัน.\n\nมีศัตรูมากขึ้นในบริเวณนี้. อย่าปล่อยให้พวกมันปล่อยยูนิตที่แข็งแกร่งที่สุดของพวกมันออกมา.
+sector.overgrowth.description = พื้นที่นี้ถูกปกคลุมไปด้วยพืช, ใกล้กับแหล่งกำเนิของสปอร์.\nศัตรูได้ตั้งฐานเฝ้าระวังไว้ที่นี่. สร้างยูนิตไททัน. ทำลายฐานซะ. แล้วนำสิ่งที่ถูกยึดไปกลับคืนมา.
+sector.tarFields.description = ขอบของพื้นที่ผลิตน้ำมัน, อยู่ระหว่างภูเขาและทะเลทราย. หนึ่งในพื้นที่ที่มีแหล่งน้ำมันดิบที่ใช้ได้.\nแม้ว่าจะถูกทิ้งร้าง, พื้นที่นี้ยังคงมีทัพของศัตรูอยู่ใกล้ๆ. อย่าประมาทกับพวกมัน.\n\n[lightgray]วิจัยเทคโนโลยีการแปรรูปน้ำมันหากเป็นไปได้.
+sector.desolateRift.description = เป็นพื้นที่ที่อันตรายมาก. ทรัพยากรมากมาย, แต่พื้นที่น้อย. ความเสี่ยงการโดนทำลายล้างสูง. ออกไปจากที่นี่ให้ไวที่สุด. อย่าถูกหลอกโดนระยะเวลาระหว่างการโจมตีของศัตรูที่เว้นไว้นานกว่าปกติ.
+sector.nuclearComplex.description = สถานที่ผลิตและแปรรูปทอเรี่ยมเก่า, ถูกทำลายกลายเป็นซาก.\n[lightgray]วิจัยทอเรี่ยมและวิธีการใช้มัน.\n\nศัตรูในบริเวณนี้มีจำนวนมาก, ตรวจตราหาผู้บุกรุกอยู่ตลอดเวลา.
+sector.fungalPass.description = พื้นที่ระหว่างพื้นที่สูงและต่ำของภูเขา, พื้นที่นี้เต็มไปด้วยสปอร์. ฐานลาดตระเวนขนาดเล็กของศัตรูตั้งอยู่ที่นี่.\nทำลายมันซะ.\nใช้ยูนิตเด็กเกอร์และครอว์เลอร์. ทำลาย core ทั้งสองซะ.
settings.language = ภาษา
settings.data = ข้อมูลเกม
settings.reset = รีเซ็ตเป็นค่าเริ่มต้น
-settings.rebind = Rebind
+settings.rebind = แก้ไขปุ่ม
settings.resetKey = Reset
settings.controls = การควบคุม
settings.game = เกม
@@ -558,65 +558,65 @@ settings.graphics = กราฟิก
settings.cleardata = เคลียร์ข้อมูลเกม...
settings.clear.confirm = คุณแน่ใจหรือว่าจะเคลียร์ข้อมูลเกม?\nสิ่งที่ทำไปแล้วจะไม่สามารถย้อนกลับได้!
settings.clearall.confirm = [scarlet]คำเตือน![]\nการกระทำนี้จะลบข้อมูลทั้งหมด นั้นรวมไปถึงเซฟ, แมพ, สิ่งที่ปลดล็อคแล้วและ keybinds.\nเมื่อคุณกด 'โอเค' เกมจะลบข้อมูลทุกอย่างและออกโดยอัตโนมัติ
-settings.clearsaves.confirm = Are you sure you want to clear all your saves?
-settings.clearsaves = Clear Saves
+settings.clearsaves.confirm = คุณแน่ใจหรือว่าคุณต้องการเคลียร์เซฟทั้งหมด?
+settings.clearsaves = เคลียร์เซฟ
paused = [accent]< หยุดชั่วคราว >
clear = เคลียร์
banned = [scarlet]แบน
-unplaceable.sectorcaptured = [scarlet]Requires captured sector
+unplaceable.sectorcaptured = [scarlet]ต้องการ captured sector
yes = ใช่
no = ไม่
info.title = ข้อมูล
error.title = [crimson]มีบางอย่างผิดพลาดเกิดขึ้น
error.crashtitle = มีบางอย่างผิดพลาดเกิดขึ้น
-unit.nobuild = [scarlet]Unit can't build
-blocks.input = นำเข้า
-blocks.output = ส่งออก
-blocks.booster = บูสเตอร์
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
+unit.nobuild = [scarlet]ยูนิตไม่สามารถสร้างได้
+stat.input = นำเข้า
+stat.output = ส่งออก
+stat.booster = บูสเตอร์
+stat.tiles = ต้องการ Tiles
+stat.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = ความจุพลังงาน
-blocks.powershot = หน่วยพลังงาน/นัด
-blocks.damage = ดาเมจ
-blocks.targetsair = ยิงอากาศยาน
-blocks.targetsground = ยิงภาคพื้นดิน
-blocks.itemsmoved = ความเร็วเคลื่อนที่
-blocks.launchtime = เวลาระหว่างการส่ง
-blocks.shootrange = ระยะยิง
-blocks.size = ขนาด
-blocks.displaysize = Display Size
-blocks.liquidcapacity = จุของเหลว
-blocks.powerrange = ระยะพลังงาน
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = จำนวนการเชื่อมต่อสูงสุด
-blocks.poweruse = ใช้พลังงาน
-blocks.powerdamage = หน่วยพลังงาน/ดาเมจ
-blocks.itemcapacity = จุไอเท็ม
-blocks.basepowergeneration = กำเนิดพลังงานพื้นฐาน
-blocks.productiontime = เวลาที่ใช้ในการผลิต
-blocks.repairtime = เวลาที่ใช้ในการซ่อมแซมให้สมบูรณ์
-blocks.speedincrease = เพิ่มความเร็ว
-blocks.range = ระยะ
-blocks.drilltier = ขุดได้
-blocks.drillspeed = ความเร็วขุดพื้นฐาน
-blocks.boosteffect = แอฟเฟ็คของบูสต์
-blocks.maxunits = จำนวนยูนิตสูงสุด
-blocks.health = เลือด
-blocks.buildtime = เวลาในการสร้าง
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = ใช้
-blocks.inaccuracy = ความคลาดเคลื่อน
-blocks.shots = นัด
-blocks.reload = นัด/วินาที
-blocks.ammo = กระสุน
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = ความจุพลังงาน
+stat.powershot = หน่วยพลังงาน/นัด
+stat.damage = ดาเมจ
+stat.targetsair = ยิงอากาศยาน
+stat.targetsground = ยิงภาคพื้นดิน
+stat.itemsmoved = ความเร็วเคลื่อนที่
+stat.launchtime = เวลาระหว่างการส่ง
+stat.shootrange = ระยะยิง
+stat.size = ขนาด
+stat.displaysize = ขนาดที่โชว์
+stat.liquidcapacity = จุของเหลว
+stat.powerrange = ระยะพลังงาน
+stat.linkrange = Link Range
+stat.instructions = คำแนะนำ
+stat.powerconnections = จำนวนการเชื่อมต่อสูงสุด
+stat.poweruse = ใช้พลังงาน
+stat.powerdamage = หน่วยพลังงาน/ดาเมจ
+stat.itemcapacity = จุไอเท็ม
+stat.basepowergeneration = กำเนิดพลังงานพื้นฐาน
+stat.productiontime = เวลาที่ใช้ในการผลิต
+stat.repairtime = เวลาที่ใช้ในการซ่อมแซมให้สมบูรณ์
+stat.speedincrease = เพิ่มความเร็ว
+stat.range = ระยะ
+stat.drilltier = ขุดได้
+stat.drillspeed = ความเร็วขุดพื้นฐาน
+stat.boosteffect = แอฟเฟ็คของบูสต์
+stat.maxunits = จำนวนยูนิตสูงสุด
+stat.health = เลือด
+stat.buildtime = เวลาในการสร้าง
+stat.maxconsecutive = ติดต่อกันสูงสุด
+stat.buildcost = ใช้
+stat.inaccuracy = ความคลาดเคลื่อน
+stat.shots = นัด
+stat.reload = นัด/วินาที
+stat.ammo = กระสุน
+stat.shieldhealth = เลือดของเกราะ
+stat.cooldowntime = เวลา Cooldown
bar.drilltierreq = จำเป็นต้องใช้เครื่องขุดที่ดีกว่า
-bar.noresources = Missing Resources
-bar.corereq = Core Base Required
+bar.noresources = ทรัพยากรหาย
+bar.corereq = ฐาน Core ที่ต้องการ
bar.drillspeed = ความเร็วขุด: {0}/s
bar.pumpspeed = ความเร็วปั้ม: {0}/s
bar.efficiency = ประสิทธิภาพ: {0}%
@@ -627,7 +627,7 @@ bar.poweroutput = พลังงานออก: {0}
bar.items = ไอเท็ม: {0}
bar.capacity = ความจุ: {0}
bar.unitcap = {0} {1}/{2}
-bar.limitreached = [scarlet] {0} / {1}[white] {2}\n[lightgray][[unit disabled]
+bar.limitreached = [scarlet] {0} / {1}[white] {2}\n[lightgray][[ยูนิตถูกปิด]
bar.liquid = ของเหลว
bar.heat = ความร้อน
bar.power = พลังงาน
@@ -660,11 +660,11 @@ unit.persecond = /วินาที
unit.perminute = /min
unit.timesspeed = เท่าเร็วขึ้น
unit.percent = %
-unit.shieldhealth = shield health
+unit.shieldhealth = เลือดเกราะ
unit.items = ไอเท็ม
-unit.thousands = k
-unit.millions = mil
-unit.billions = b
+unit.thousands = พัน
+unit.millions = ล้าน
+unit.billions = พันล้าน
category.general = ทั่วไป
category.power = พลังงาน
category.liquids = ของเหลว
@@ -677,13 +677,13 @@ setting.shadows.name = เงา
setting.blockreplace.name = แนะนำบล็อคโดยอัตโนมัติ
setting.linear.name = การกรองเชิงเส้น
setting.hints.name = คำแนะนำ
-setting.flow.name = Display Resource Flow Rate[scarlet] (experimental)
+setting.flow.name = แสดงอัตราการไหลของทรัพยากร[scarlet] (รุ่นทดลอง)
setting.buildautopause.name = หยุดสร้างชั่วคราวแบบอัตโนมัติ
-setting.mapcenter.name = Auto Center Map To Player
+setting.mapcenter.name = ปรับแมพให้อยู่ตรงกลางตามผู้เล่นโดยอัตโนมัติ
setting.animatedwater.name = แอนิเมชั่นน้ำ
setting.animatedshields.name = แอนิเมชั่นเกราะ
setting.antialias.name = Antialias[lightgray] (จำเป็นต้องรีสตาร์ท)[]
-setting.playerindicators.name = Player Indicators
+setting.playerindicators.name = ตัวบอกผู้เล่น
setting.indicators.name = ตัวบอกศัตรู/พักพวก
setting.autotarget.name = เล็งเป้าอัตโนมัติ
setting.keyboard.name = การควบคุมแบบ เม้าส์+คีย์บอร์ด
@@ -702,25 +702,25 @@ setting.difficulty.name = ระดับความยาก:
setting.screenshake.name = การสั่นของจอ
setting.effects.name = แสดงเอฟเฟ็ค
setting.destroyedblocks.name = แสดงบล็อคที่ถูกทำลาย
-setting.blockstatus.name = Display Block Status
+setting.blockstatus.name = แสดงสเตตัสของบล็อค
setting.conveyorpathfinding.name = Pathfinding
setting.sensitivity.name = ความไวของตัวควบคุม
setting.saveinterval.name = ระยะห่าวระหว่างเซฟ
setting.seconds = {0} วินาที
-setting.blockselecttimeout.name = Block Select Timeout
-setting.milliseconds = {0} milliseconds
+setting.blockselecttimeout.name = การหมดเวลาในการเลือกบล็อค
+setting.milliseconds = {0} มิลลิวินาที
setting.fullscreen.name = เต็มจอ
setting.borderlesswindow.name = วินโดว์แบบไร้ขอบ[lightgray] (อาจจะต้องรีตาร์ท)
setting.fps.name = แสดง FPS และ Ping
-setting.smoothcamera.name = Smooth Camera
-setting.blockselectkeys.name = Show Block Select Keys
+setting.smoothcamera.name = กล้องแบบสมูท
+setting.blockselectkeys.name = แสดงปุ่มเลือกบล็อค
setting.vsync.name = VSync
setting.pixelate.name = Pixelate[lightgray] (ปิดใช้งานแอนิเมชั่น)
setting.minimap.name = แสดงมินิแมพ
-setting.coreitems.name = Display Core Items (WIP)
+setting.coreitems.name = แสดงไอเท็มใน Core (ยังไม่เสร็จสมบูรณ์)
setting.position.name = แสดงตำแหน่งของผู้เล่น
setting.musicvol.name = ระดับเสียงเพลง
-setting.atmosphere.name = Show Planet Atmosphere
+setting.atmosphere.name = แสดงชั้นบรรยากาศของดาวเคราะห์
setting.ambientvol.name = ระดับเสียงล้อมรอบ
setting.mutemusic.name = ปิดเพลง
setting.sfxvol.name = ระดับเสียง SFX
@@ -728,10 +728,10 @@ setting.mutesound.name = ปิดเสียง
setting.crashreport.name = ส่งรายงานการแครชแบบไม่ระบุตัวตน
setting.savecreate.name = สร้างเซฟโดยอัตโนมัติ
setting.publichost.name = การมองเห็นเซิฟเวอร์สาธารณะ
-setting.playerlimit.name = Player Limit
+setting.playerlimit.name = จัดกัดผู้เล่น
setting.chatopacity.name = ความโปร่งแสงของแชท
setting.lasersopacity.name = ความโปร่งแสงของเลเซอร์พลังงาน
-setting.bridgeopacity.name = Bridge Opacity
+setting.bridgeopacity.name = ความโปร่งแสงของสะพาน
setting.playerchat.name = แสดงบับเบิ้ลแชทของผู้เล่น
public.confirm = คุณต้องการให้เกมของคุณเปิดเป็นสาธารณะหรือไม่?\n[accent]ทุกคนจะสามารถเข้าร่วมเกมของคุณได้.\n[lightgray]คุณสามารถเปลี่ยนการตั้งค่านี้ได้ที่ ตั้งค่า->เกม->การมองเห็นเซิฟเวอร์สาธารณะ.
public.beta = เกมเวอร์ชั่นเบต้าไม่สามารถเปิดเซิฟเวอร์สาธารณะได้
@@ -743,54 +743,54 @@ keybinds.mobile = [scarlet]การตั้งค่าปุ่มส่ว
category.general.name = ทั่วไป
category.view.name = วิว
category.multiplayer.name = ผู้เล่นหลายคน
-category.blocks.name = Block Select
+category.blocks.name = เลือกบล็อค
command.attack = โจมตี
command.rally = ชุมนุม
command.retreat = ถอยกลับ
-command.idle = Idle
+command.idle = อยู่เฉยๆ
placement.blockselectkeys = \n[lightgray]Key: [{0},
-keybind.respawn.name = Respawn
-keybind.control.name = Control Unit
+keybind.respawn.name = เกิดใหม่
+keybind.control.name = ควบคุมยูนิต
keybind.clear_building.name = เคลียร์สิ่งก็สร้าง
keybind.press = กดปุ่มใดก็ได้...
keybind.press.axis = กดแกนหรือปุ่มใดก็ได้...
keybind.screenshot.name = แมพ Screenshot
-keybind.toggle_power_lines.name = Toggle Power Lasers
-keybind.toggle_block_status.name = Toggle Block Statuses
+keybind.toggle_power_lines.name = เปิดปิดเลเซอร์พลังงาน
+keybind.toggle_block_status.name = เปิดปิดสถานะของบล็อค
keybind.move_x.name = เคลื่อนที่ในแกน x
keybind.move_y.name = เคลี่อนที่ในแกน y
keybind.mouse_move.name = ตามเม้าส์
-keybind.pan.name = Pan View
-keybind.boost.name = Boost
+keybind.pan.name = แพนวิว
+keybind.boost.name = บูสต์
keybind.schematic_select.name = เลือกภูมิภาค
keybind.schematic_menu.name = เมนู Schematic
keybind.schematic_flip_x.name = กลับ Schematic ในแกน X
keybind.schematic_flip_y.name = กลับ Schematic ในแกน Y
-keybind.category_prev.name = Previous Category
-keybind.category_next.name = Next Category
-keybind.block_select_left.name = Block Select Left
-keybind.block_select_right.name = Block Select Right
-keybind.block_select_up.name = Block Select Up
-keybind.block_select_down.name = Block Select Down
-keybind.block_select_01.name = Category/Block Select 1
-keybind.block_select_02.name = Category/Block Select 2
-keybind.block_select_03.name = Category/Block Select 3
-keybind.block_select_04.name = Category/Block Select 4
-keybind.block_select_05.name = Category/Block Select 5
-keybind.block_select_06.name = Category/Block Select 6
-keybind.block_select_07.name = Category/Block Select 7
-keybind.block_select_08.name = Category/Block Select 8
-keybind.block_select_09.name = Category/Block Select 9
-keybind.block_select_10.name = Category/Block Select 10
+keybind.category_prev.name = หมวดหมู่ก่อนหน้า
+keybind.category_next.name = หมวดหมู่ถ้ดไป
+keybind.block_select_left.name = เลือกบล็อค ซ้าย
+keybind.block_select_right.name = เลือกบล็อค ขวา
+keybind.block_select_up.name = เลือกบล็อค ขึ้น
+keybind.block_select_down.name = เลือกบล็อค ลง
+keybind.block_select_01.name = หมวดหมู่/เลือกบล็อค 1
+keybind.block_select_02.name = หมวดหมู่/เลือกบล็อค 2
+keybind.block_select_03.name = หมวดหมู่/เลือกบล็อค 3
+keybind.block_select_04.name = หมวดหมู่/เลือกบล็อค 4
+keybind.block_select_05.name = หมวดหมู่/เลือกบล็อค 5
+keybind.block_select_06.name = หมวดหมู่/เลือกบล็อค 6
+keybind.block_select_07.name = หมวดหมู่/เลือกบล็อค 7
+keybind.block_select_08.name = หมวดหมู่/เลือกบล็อค 8
+keybind.block_select_09.name = หมวดหมู่/เลือกบล็อค 9
+keybind.block_select_10.name = หมวดหมู่/เลือกบล็อค 10
keybind.fullscreen.name = เปิด/ปิด Fullscreen
keybind.select.name = เลือก/ยิง
keybind.diagonal_placement.name = วางเป็นแนวทแยง
keybind.pick.name = เลือกบล็อค
keybind.break_block.name = ทุบบล็อค
keybind.deselect.name = ยกเลิกการเบือก
-keybind.pickupCargo.name = Pickup Cargo
-keybind.dropCargo.name = Drop Cargo
-keybind.command.name = Command
+keybind.pickupCargo.name = ยกของขึ้น
+keybind.dropCargo.name = วางของลง
+keybind.command.name = คำสั่ง
keybind.shoot.name = ยิง
keybind.zoom.name = ซูม
keybind.menu.name = เมนู
@@ -811,7 +811,7 @@ keybind.zoom_minimap.name = ซูมมินิแมพ
mode.help.title = คำอธิบายโหมด
mode.survival.name = เอาชีวิตรอด
mode.survival.description = โหมดปกติ. ทรัพยากรมีจำกัดและ wave มาโดยอัตโนมัติ.\n[gray]ต้องมีสปาวน์ของศัตรูเพื่อที่จะเล่น.
-mode.sandbox.name = Sandbox
+mode.sandbox.name = โหมดอิสระ
mode.sandbox.description = ทรัพยาดรไม่จำกัดและ wave ไม่จับเวลา.
mode.editor.name = Editor
mode.pvp.name = PvP
@@ -825,10 +825,10 @@ rules.reactorexplosions = การระเบิดของ
rules.wavetimer = ตัวนับเวลาปล่อยคลื่น(รอบ)
rules.waves = คลื่น(รอบ)
rules.attack = โหมดการโจมตี
-rules.buildai = AI Building
+rules.buildai = สิ่ก่อสร้างของ AI
rules.enemyCheat = AI (ทีมสีแดง) มีทรัพยากรไม่จำกัด
rules.blockhealthmultiplier = พหุคูณเลือดของบล็อค
-rules.blockdamagemultiplier = Block Damage Multiplier
+rules.blockdamagemultiplier = พหุคูณดาเมจของบล็อค
rules.unitbuildspeedmultiplier = พหุคูณความเร็วในการสร้างยูนิต
rules.unithealthmultiplier = พหุคูณเลือดของยูนิต
rules.unitdamagemultiplier = พหุคูณพลังโจมตีของยูนิต
@@ -836,23 +836,23 @@ rules.enemycorebuildradius = รัศมีห้ามสร้างบริ
rules.wavespacing = ระยะเวลาระหว่างคลื่น(รอบ):[lightgray] (วินาที)
rules.buildcostmultiplier = พหุคูณจำนวนทรัพยากรที่ใช้ในการสร้าง
rules.buildspeedmultiplier = พหุคูณความเร็วในการสร้าง
-rules.deconstructrefundmultiplier = Deconstruct Refund Multiplier
+rules.deconstructrefundmultiplier = พหุคูณการคืนทรัพยากรเมื่อทำการทำลายสิ่งก่อสร้าง
rules.waitForWaveToEnd = คลื่น(รอบ)รอศัตรู
rules.dropzoneradius = รัศมีจุดเกิดของศัตรู:[lightgray] (ช่อง)
-rules.unitammo = Units Require Ammo
+rules.unitammo = ยูนิตต้องใช้กระสุน
rules.title.waves = คลื่น(รอบ)
rules.title.resourcesbuilding = ทรัพยากรและสิ่งก่อสร้าง
rules.title.enemy = ศัตรู
rules.title.unit = ยูนิต
rules.title.experimental = Experimental
-rules.title.environment = Environment
-rules.lighting = Lighting
-rules.fire = Fire
-rules.explosions = Block/Unit Explosion Damage
-rules.ambientlight = Ambient Light
-rules.weather = Weather
-rules.weather.frequency = Frequency:
-rules.weather.duration = Duration:
+rules.title.environment = สิ่งแวดล้อม
+rules.lighting = แสง
+rules.fire = ไฟ
+rules.explosions = ดาเมจบล็อค/ยูนิตระเบิด
+rules.ambientlight = แสงจากแวดล้อม
+rules.weather = สภาพอากาศ
+rules.weather.frequency = ความถี่:
+rules.weather.duration = ระยะเวลา:
content.item.name = ไอเท็ม
content.liquid.name = ของเหลว
@@ -885,73 +885,73 @@ item.radioactivity = [lightgray]ค่ากัมมันตภาพรัง
unit.health = [lightgray]เลือด: {0}
unit.speed = [lightgray]ความเร็ว: {0}
-unit.weapon = [lightgray]Weapon: {0}
-unit.itemcapacity = [lightgray]Item Capacity: {0}
-unit.minespeed = [lightgray]Mining Speed: {0}%
-unit.minepower = [lightgray]Mining Power: {0}
-unit.ability = [lightgray]Ability: {0}
-unit.buildspeed = [lightgray]Building Speed: {0}%
+unit.weapon = [lightgray]อาวุธ: {0}
+unit.itemcapacity = [lightgray]ความจุไอเท็ม: {0}
+unit.minespeed = [lightgray]ความเร็วการขุด: {0}%
+unit.minepower = [lightgray]ความแรงการขุด: {0}
+unit.ability = [lightgray]ความสามารถ: {0}
+unit.buildspeed = [lightgray]ความเร็วการสร้าง: {0}%
liquid.heatcapacity = [lightgray]ความจุความร้อน: {0}
liquid.viscosity = [lightgray]ความหนืด: {0}
liquid.temperature = [lightgray]อุณหภูมิ: {0}
unit.dagger.name = แด็กเกอร์
-unit.mace.name = Mace
+unit.mace.name = เมส
unit.fortress.name = ฟอร์เทรส
-unit.nova.name = Nova
-unit.pulsar.name = Pulsar
-unit.quasar.name = Quasar
+unit.nova.name = โนว่า
+unit.pulsar.name = พอวซ่า
+unit.quasar.name = ควอซ่า
unit.crawler.name = ครอว์เลอร์
-unit.atrax.name = Atrax
-unit.spiroct.name = Spiroct
-unit.arkyid.name = Arkyid
-unit.toxopid.name = Toxopid
-unit.flare.name = Flare
-unit.horizon.name = Horizon
-unit.zenith.name = Zenith
-unit.antumbra.name = Antumbra
-unit.eclipse.name = Eclipse
-unit.mono.name = Mono
-unit.poly.name = Poly
-unit.mega.name = Mega
-unit.quad.name = Quad
-unit.oct.name = Oct
-unit.risso.name = Risso
-unit.minke.name = Minke
-unit.bryde.name = Bryde
-unit.sei.name = Sei
-unit.omura.name = Omura
-unit.alpha.name = Alpha
-unit.beta.name = Beta
-unit.gamma.name = Gamma
-unit.scepter.name = Scepter
-unit.reign.name = Reign
-unit.vela.name = Vela
-unit.corvus.name = Corvus
+unit.atrax.name = เอแทรซ
+unit.spiroct.name = สปิรอคท์
+unit.arkyid.name = อาร์คิดย์
+unit.toxopid.name = โทโสพิด
+unit.flare.name = แฟลร์
+unit.horizon.name = ฮอไรซอน
+unit.zenith.name = ซีนิท
+unit.antumbra.name = แอนทัมบรา
+unit.eclipse.name = อีคลิปส์
+unit.mono.name = โมโน
+unit.poly.name = โพลี
+unit.mega.name = เมก้า
+unit.quad.name = ควอด
+unit.oct.name = ออกค์
+unit.risso.name = ริสโส
+unit.minke.name = มิงค์
+unit.bryde.name = ไบรดย์
+unit.sei.name = ไซย์
+unit.omura.name = โอมูร่า
+unit.alpha.name = อัลฟ่า
+unit.beta.name = บีตเา
+unit.gamma.name = แกมม่า
+unit.scepter.name = สเซปเตอร์
+unit.reign.name = เรน
+unit.vela.name = เวล่า
+unit.corvus.name = คอร์วัส
-block.resupply-point.name = Resupply Point
-block.parallax.name = Parallax
-block.cliff.name = Cliff
+block.resupply-point.name = จุดเติมของ
+block.parallax.name = พาราแล็ซ
+block.cliff.name = หน้าผ่า
block.sand-boulder.name = ก้อนหินทราย
block.grass.name = หญ้า
block.slag.name = Slag
block.salt.name = เกลือ
-block.salt-wall.name = Salt Wall
+block.salt-wall.name = กำแพงเกลือ
block.pebbles.name = ก้อนกรวด
block.tendrils.name = ไม้เลื้อย
-block.sand-wall.name = Sand Wall
+block.sand-wall.name = กำแพงทราย
block.spore-pine.name = ต้นสนสปอร์
-block.spore-wall.name = Spore Wall
-block.boulder.name = Boulder
-block.snow-boulder.name = Snow Boulder
+block.spore-wall.name = กำแพงสปอร์
+block.boulder.name = ก้อยหินใหญ่
+block.snow-boulder.name = หินหิมะใหญ่
block.snow-pine.name = ต้นสนที่คลุมหิมะ
block.shale.name = หินดินดาน
block.shale-boulder.name = ก้อนหินดินดาน
block.moss.name = ตะไคร่น้ำ
block.shrubs.name = พุ่มไม้
block.spore-moss.name = พุ่มไม้สปอร์
-block.shale-wall.name = Shale Wall
+block.shale-wall.name = กำแพงหินดินดาน
block.scrap-wall.name = กำแพงเศษเหล็ก
block.scrap-wall-large.name = กำแพงเศษเหล็กขนาดใหญ่
block.scrap-wall-huge.name = กำแพงเศษเหล็กขนาดใหญ่มาก
@@ -969,7 +969,7 @@ block.deepwater.name = น้ำลึก
block.water.name = น้ำ
block.tainted-water.name = น้ำเสีย
block.darksand-tainted-water.name = น้ำเสียบนทรายดำ
-block.tar.name = น้ำมันดิน
+block.tar.name = น้ำมันดิบ
block.stone.name = หิน
block.sand.name = ทราย
block.darksand.name = ทรายดำ
@@ -979,17 +979,17 @@ block.craters.name = หลุมอุกกาบาต
block.sand-water.name = น้ำบนทราย
block.darksand-water.name = น้ำบนทรายดำ
block.char.name = ถ่าน
-block.dacite.name = Dacite
-block.dacite-wall.name = Dacite Wall
+block.dacite.name = ดาไซต์
+block.dacite-wall.name = กำแพงดาไซต์
block.ice-snow.name = น้ำแข็งหิมะ
-block.stone-wall.name = Stone Wall
-block.ice-wall.name = Ice Wall
-block.snow-wall.name = Snow Wall
-block.dune-wall.name = Dune Wall
+block.stone-wall.name = กำแพงหิน
+block.ice-wall.name = กำแพงน้ำแข็ง
+block.snow-wall.name = กำแพงหิมะ
+block.dune-wall.name = กำแพงเนินทราย
block.pine.name = ต้นสน
-block.dirt.name = Dirt
-block.dirt-wall.name = Dirt Wall
-block.mud.name = Mud
+block.dirt.name = ดิน
+block.dirt-wall.name = กำแพงดิน
+block.mud.name = โคลน
block.white-tree-dead.name = ต้นไม้ขาวที่ตายแล้ว
block.white-tree.name = ต้มไม้ขาว
block.spore-cluster.name = กลุ่มสปอร์
@@ -1005,7 +1005,7 @@ block.dark-panel-4.name = แผ่นดำ 4
block.dark-panel-5.name = แผ่นดำ 5
block.dark-panel-6.name = แผ่นดำ 6
block.dark-metal.name = เหล็กดำ
-block.basalt.name = Basalt
+block.basalt.name = บะซอลต์
block.hotrock.name = หินร้อน
block.magmarock.name = หินแมกม่า
block.copper-wall.name = กำแพงทองแดง
@@ -1027,7 +1027,7 @@ block.hail.name = แฮล
block.lancer.name = แลนเซอร์
block.conveyor.name = สายพาน
block.titanium-conveyor.name = สายพานไทเทเนี่ยม
-block.plastanium-conveyor.name = Plastanium Conveyor
+block.plastanium-conveyor.name = สายพานพสาตตาเนี่ยม
block.armored-conveyor.name = สายพานเสริมเกราะ
block.armored-conveyor.description = เคลื่อนย้ายไอเท็มได้เร็วเทียบเท่าสายพานไทเทเนี่ยม แต่มีเกราะที่แข็งแรงกว่า ไม่สามารถรับไอเท็มจากด้านข้างและจากสายพานชนิดอื่นนอกจากสายพานชนิดเดียวกัน.
block.junction.name = ทางแยก
@@ -1036,10 +1036,10 @@ block.distributor.name = ตัวแจกจ่าย
block.sorter.name = เครื่องแยก
block.inverted-sorter.name = เครื่องแยกกลับด้าน
block.message.name = ตัวเก็บข้อความ
-block.illuminator.name = Illuminator
-block.illuminator.description = A small, compact, configurable light source. Requires power to function.
+block.illuminator.name = ตัวเปล่งแสง
+block.illuminator.description = แหล่งกำเนิดแสงขนาดเล็ก สามารถดัดแปลงได้. จำเป็นต้องใช้พลังงานในการทำงาน.
block.overflow-gate.name = ประตูระบายไอเทม
-block.underflow-gate.name = Underflow Gate
+block.underflow-gate.name = ประตูระบายไอเท็มย้อนกลับ
block.silicon-smelter.name = เตาเผาซิลิกอน
block.phase-weaver.name = เครื่องทอใยเฟส
block.pulverizer.name = เครื่องบด
@@ -1055,7 +1055,7 @@ block.surge-tower.name = เสาเสิร์จ
block.diode.name = ไดโอดแบตเตอรี่
block.battery.name = แบตเตอรี่
block.battery-large.name = แบตเตอรี่ขนาดใหญ่
-block.combustion-generator.name = เครื่องกำเนิดไฟฟ้าโดยการสันดาป
+block.combustion-generator.name = เครื่องกำเนิดไฟฟ้าเผาไหม้ถ่าน
block.steam-generator.name = เครื่องกำเนิดไฟฟ้าไอน้ำ
block.differential-generator.name = เครื่องกำเนิดไฟฟ้าดิฟเฟอเร่นเตอร์
block.impact-reactor.name = เตาปฏิกรณ์อัดกระแทก
@@ -1118,33 +1118,33 @@ block.container.name = ตู้เก็บของ
block.launch-pad.name = ฐานส่งของ
block.launch-pad-large.name = ฐานส่งของขนาดใหญ่
block.segment.name = Segment
-block.command-center.name = Command Center
-block.ground-factory.name = Ground Factory
-block.air-factory.name = Air Factory
-block.naval-factory.name = Naval Factory
-block.additive-reconstructor.name = Additive Reconstructor
-block.multiplicative-reconstructor.name = Multiplicative Reconstructor
-block.exponential-reconstructor.name = Exponential Reconstructor
+block.command-center.name = ศูนย์ควบคุม
+block.ground-factory.name = โรงงานภาคพื้นดิน
+block.air-factory.name = โรงงานภาคอากาศ
+block.naval-factory.name = โรงงานทางน้ำ
+block.additive-reconstructor.name = Reconstructor แบบบวก
+block.multiplicative-reconstructor.name = Reconstructor แบบคูณ
+block.exponential-reconstructor.name = Reconstructor แบบเอ็กโพเนนเชียว
block.tetrative-reconstructor.name = Tetrative Reconstructor
-block.payload-conveyor.name = Mass Conveyor
-block.payload-router.name = Payload Router
-block.disassembler.name = Disassembler
-block.silicon-crucible.name = Silicon Crucible
-block.overdrive-dome.name = Overdrive Dome
+block.payload-conveyor.name = สายพาน Mass
+block.payload-router.name = ตัวเปลี่ยเส้นทาง Payload
+block.disassembler.name = ตัวชำแหละ
+block.silicon-crucible.name = เบ้าหลอมซิลิคอน
+block.overdrive-dome.name = โดม Overdrive
-block.switch.name = Switch
-block.micro-processor.name = Micro Processor
-block.logic-processor.name = Logic Processor
-block.hyper-processor.name = Hyper Processor
-block.logic-display.name = Logic Display
-block.large-logic-display.name = Large Logic Display
-block.memory-cell.name = Memory Cell
+block.switch.name = สวิชต์
+block.micro-processor.name = ตัวประมวลผล Micro
+block.logic-processor.name = ตัวประมวลผล Logic
+block.hyper-processor.name = ตัวประมวลผล Hyper
+block.logic-display.name = ตัวแสดง Logic
+block.large-logic-display.name = ตัวแสดง Logic ขนาดใหญ่
+block.memory-cell.name = เซลล์ความจำ
team.blue.name = น้ำเงิน
team.crux.name = แดง
team.sharded.name = ส้ม
team.orange.name = ส้ม
-team.derelict.name = derelict
+team.derelict.name = ไม่มี
team.green.name = เขียว
team.purple.name = ม่วง
@@ -1208,12 +1208,12 @@ block.spore-press.description = อัดกระเปาะสปอร์ด
block.pulverizer.description = บดเศษเหล็กให้เป็นทรายละเอียด.
block.coal-centrifuge.description = ทำให้น้ำมันแข็งตัวเป็นก้อนถ่านหิน.
block.incinerator.description = ทำลายไอเท็มหรือของเหลวทุกอย่างที่ได้รับมา.
-block.power-void.description = ทิ้งพลังงานทั้งหมดที่ได้รับ. เฉพาะ Sandbox เท่านั้น.
-block.power-source.description = ส่งออกพลังงานไม่จำกัด. เฉพาะ Sandbox เท่านั้น.
-block.item-source.description = ส่งออกไอเท็มไม่จำกัด. เฉพาะ Sandbox เท่านั้น.
-block.item-void.description = ทำลายทุกไอเท็ม . เฉพาะ Sandbox เท่านั้น.
-block.liquid-source.description = ส่งออกของเหลวไม่จำกัด. เฉพาะ Sandbox เท่านั้น.
-block.liquid-void.description = Removes any liquids. Sandbox only.
+block.power-void.description = ทิ้งพลังงานทั้งหมดที่ได้รับ. เฉพาะ โหมดอิสระ เท่านั้น.
+block.power-source.description = ส่งออกพลังงานไม่จำกัด. เฉพาะ โหมดอิสระ เท่านั้น.
+block.item-source.description = ส่งออกไอเท็มไม่จำกัด. เฉพาะ โหมดอิสระ เท่านั้น.
+block.item-void.description = ทำลายทุกไอเท็ม . เฉพาะ โหมดอิสระ เท่านั้น.
+block.liquid-source.description = ส่งออกของเหลวไม่จำกัด. เฉพาะ โหมดอิสระ เท่านั้น.
+block.liquid-void.description = ทิ้งของเหลวทุกชนิด. เฉพาะ โหมดอิสระ เท่านั้น.
block.copper-wall.description = บล็อคป้องกันราคาถูก.\nมีประโยชน์สำหรับป้องกัน core และป้อมปืนใน wave แรกๆ.
block.copper-wall-large.description = บล็อคป้องกันราคาถูก.\nมีประโยชน์สำหรับป้องกัน core และป้อมปืนใน wave แรกๆ.\nคลอบคลุมหลายข่อง.
block.titanium-wall.description = บล็อคป้องกันแข็งแกร่งปานกลาง.\nป้องกันศัตรูได้ในระดับหนึ่ง.
@@ -1222,8 +1222,8 @@ block.plastanium-wall.description = กำแพงพิเศษที่ส
block.plastanium-wall-large.description = กำแพงพิเศษที่สามารถดูดซับไฟฟ้าและป้องกันการต่อไฟกับโหนดพลังงานโดยอัตโนมัติได้.\nคลอบคลุมหลายช่อง.
block.thorium-wall.description = บล็อคป้องกันที่แข็งแรง.\nป้องกันศัตรูได้อย่างดี.
block.thorium-wall-large.description = บล็อคป้องกันที่แข็งแรง.\nป้องกันศัตรูได้อย่างดี.\nคลอบคลุมหลายช่อง.
-block.phase-wall.description = A wall coated with special phase-based reflective compound. Deflects most bullets upon impact.
-block.phase-wall-large.description = A wall coated with special phase-based reflective compound. Deflects most bullets upon impact.\nคลอบคลุมหลายช่อง.
+block.phase-wall.description = กำแพงที่เคลือบด้วยวัสดุสะท้อนพิเศษจำพวก phase. เบี่ยงเบนกระสุนส่วนใหญ่ที่รับมา.
+block.phase-wall-large.description = กำแพงที่เคลือบด้วยวัสดุสะท้อนพิเศษจำพวก phase. เบี่ยงเบนกระสุนส่วนใหญ่ที่รับมา.\nคลอบคลุมหลายช่อง.
block.surge-wall.description = บล็อคป้องกันที่มีทนทานสูง.\nสะสมพลังงานจากกระสุน, แล้วปล่อยออกมาแบบสุ่ม.
block.surge-wall-large.description = บล็อคป้องกันที่มีทนทานสูง.\nสะสมพลังงานจากกระสุน, แล้วปล่อยออกมาแบบสุ่ม.\nคลอบคลุมหลายช่อง.
block.door.description = ประตูขนาดเล็ก. สามารถเปิดได้โดยการกด.
@@ -1235,7 +1235,7 @@ block.force-projector.description = สร้างสนามพลังง
block.shock-mine.description = ดาเมจศัตรูที่เหยียบ. แถบจะล่องหนต่อศัตรู.
block.conveyor.description = บล็อคขนส่งไอเท็มพื้นฐาน. เคลื่อนไอเท็มไปข้างหน้าและใส่ลงบล็อคโดยอัตโนมัติ. สามารถหมุนได้.
block.titanium-conveyor.description = บล็อคขนส่งไอเท็มขั้นสูง. เคลื่อนไอเท็มเร็วกว่าสายพานทั่วไป.
-block.plastanium-conveyor.description = Moves items in batches.\nAccepts items at the back, and unloads them in three directions at the front.
+block.plastanium-conveyor.description = เคลื่อนย้ายไอเท็มเป็นชุด.\nรับไอดท็มจากด้านหลัง, และนำออกไปสามทางข้างหน้า.
block.junction.description = มีหน้าที่เป็นสะพานสำหรับสายพาน 2 สายข้ามกัน. มีประโยชน์สำหรับเวลาสายพาน 2 สายที่ขนไอเท็มมา 2 ชนิดไปยัง 2 สถานที่.
block.bridge-conveyor.description = บล็อคขนส่งไอเท็มขั้นสูง. ทำให้สามารถส่งไอเท็มข้ามบล็อคใดก็ได้ 3 ช่อง.
block.phase-conveyor.description = บล็อคขนส่งไอเท็มขั้นสูง. ใช้พลังงานเพื่อส่งไอเท็มไปยังสายพานเฟสอีกอัน ข้ามได้หลายช่อง.
@@ -1244,14 +1244,14 @@ block.inverted-sorter.description = แยกไอเท็มคล้าย
block.router.description = รับไอเท็มแล้วส่งออก 3 ทางเท่าๆกัน. มีประโยชน์สำหรับแยกไอเท็มจากแหล่งเดียวไปหลายที่.\n\n[scarlet]อย่าวางไว้ติดกับทางส่งไอเท็มเข้าเพราะของออกจะไปอุดตันได้.[]
block.distributor.description = เร้าเตอร์ขั้นสูง. แยกไอเท็มออก 7 ทางอย่างเท่าๆกัน.
block.overflow-gate.description = ของจะออกจากข้างๆเมื่อทางข้างหน้ถูกบล็อคเท่านั้น.
-block.underflow-gate.description = The opposite of an overflow gate. Outputs to the front if the left and right paths are blocked.
+block.underflow-gate.description = ตรงข้ามกับประตูระบายไอเท็ม. ส่งออกไอเท็มไปข้างหน้าหากทางซ้ายและขวาถูกบล็อค.
block.mass-driver.description = บล็อคขนส่งไอเท็มขั้นสุดยอด. รวบรวมไอเท็มจำนวนหนึ่งแล้วยิงไปหาแมสไดรเวอร์อีกอันที่อยู่ไกลออกไป. ต้องใช้พลังงานในการใช้งาน.
block.mechanical-pump.description = ปั๊มราคาถูก เอ้าพุธต์ช้า แต่ไม่ใช้พลังงาน.
block.rotary-pump.description = ปั๊มขั้นสูง. ปั๊มของเหลวได้มากขึ้นแค่ใช้พลังงาน.
block.thermal-pump.description = ปั๊มขั้นสุดยอด.
block.conduit.description = บล็อคขนส่งของเหลวพื้นฐาน. เคลื่อนของเหลวไปข้างหน้า. ใช้ร่วมกับปั๊มและรางน้ำอื่นๆ.
block.pulse-conduit.description = บล็อคขนส่งของเหลวขั้นสูง. เคลื่อนย้ายของเหลวเร็วขึ้นและเก็บเยอะกว่ารางน้ำธรรมดา.
-block.plated-conduit.description = Moves liquids at the same rate as pulse conduits, but possesses more armor. Does not accept fluids from the sides by anything other than conduits.\nLeaks less.
+block.plated-conduit.description = เคลื่อนย้ายของเหลวได้เร็วพอๆกับ ท่อน้ำพัลซ์, แต่มีเกราะที่หนากว่า. ไม่รับของเหลวจากด้านข้างจากอย่างอื่นนอกจากท่อน้ำด้วยกันเอง.\nรั่วน้อยกว่า.
block.liquid-router.description = รับของเหลวจากทางเดียวแล้วส่งออก 3 ทางเท่าๆกัน. สามารถเก็บของ้หลวได้จำนวนหนึ่ง. มีประโยชน์สำหรับการแยกของเหลวจากแหล่งเดียวไปหลายที่.
block.liquid-tank.description = เก็บของเหลวจำนวนมาก. ใช่สำหรับสร้างบัฟเฟอร์ในเวลาที่ความต้องการของทรัพยากรไม่คงที่หรือเป็นตัวเซฟสำหรับบล็อคที่จำเป็นต้องใช้การหล่อเย็น.
block.liquid-junction.description = ทำหน้าที่เป็นสะพานสำหรับรางน้ำ 2 รางที่ข้ามกันที่มีของเหลว 2 ชนิด ซึ่งต้องการจะไปคนละที่.
@@ -1302,4 +1302,4 @@ block.cyclone.description = ป้อมปืนต่อต้านอาก
block.spectre.description = ปืนใหญ่ลำกล้องคูขนาดยักษ์. ยิงกระสุนเจาะเกราะใส่ศัตรูทั้งบนอากาศและภาดพื้นดิน.
block.meltdown.description = ปืนใหญ่เลเซอร์ขนาดยักษ์. ชาร์จแล้วยิงลำแสงเลเซอร์ใส่ศัตรูที่อยู่ใกล้. จำเป็นต้องใช้สารหล่อเย็น.
block.repair-point.description = ซ่อมแซมยูนิตที่อยู่ในรัศมีอย่างต่อเนื่อง.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = ทำดาเมจและทำลายโปรเจกไตล์ที่กำลังเข้ามา. โปรเจกไตล์เลเซอร์จะไม่ถูกล็อคเป้าด้วยบล็อคนี้.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_tk.properties b/core/assets/bundles/bundle_tk.properties
index edfae05b29..cfac48c897 100644
--- a/core/assets/bundles/bundle_tk.properties
+++ b/core/assets/bundles/bundle_tk.properties
@@ -570,49 +570,49 @@ info.title = [accent]Bilgi
error.title = [crimson]Bir hata olustu
error.crashtitle = Bir hata olustu
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Input
-blocks.output = Output
-blocks.booster = Booster
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
+stat.input = Input
+stat.output = Output
+stat.booster = Booster
+stat.tiles = Required Tiles
+stat.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = Guc kapasitesi
-blocks.powershot = Guc/Saldiri hizi
-blocks.damage = Damage
-blocks.targetsair = Havayi hedef alir mi?
-blocks.targetsground = Targets Ground
-blocks.itemsmoved = Move Speed
-blocks.launchtime = Time Between Launches
-blocks.shootrange = Menzil
-blocks.size = Buyukluk
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Sivi kapasitesi
-blocks.powerrange = Menzil
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Max Connections
-blocks.poweruse = Guc kullanimi
-blocks.powerdamage = Power/Damage
-blocks.itemcapacity = Esya kapasitesi
-blocks.basepowergeneration = Base Power Generation
-blocks.productiontime = Production Time
-blocks.repairtime = Block Full Repair Time
-blocks.speedincrease = Speed Increase
-blocks.range = Range
-blocks.drilltier = Kazilabilirler
-blocks.drillspeed = Ana kazma hizi
-blocks.boosteffect = Boost Effect
-blocks.maxunits = Max Active Units
-blocks.health = Can
-blocks.buildtime = Build Time
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = Build Cost
-blocks.inaccuracy = sekme
-blocks.shots = vuruslar
-blocks.reload = Yeniden doldurma
-blocks.ammo = Ammo
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Guc kapasitesi
+stat.powershot = Guc/Saldiri hizi
+stat.damage = Damage
+stat.targetsair = Havayi hedef alir mi?
+stat.targetsground = Targets Ground
+stat.itemsmoved = Move Speed
+stat.launchtime = Time Between Launches
+stat.shootrange = Menzil
+stat.size = Buyukluk
+stat.displaysize = Display Size
+stat.liquidcapacity = Sivi kapasitesi
+stat.powerrange = Menzil
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Max Connections
+stat.poweruse = Guc kullanimi
+stat.powerdamage = Power/Damage
+stat.itemcapacity = Esya kapasitesi
+stat.basepowergeneration = Base Power Generation
+stat.productiontime = Production Time
+stat.repairtime = Block Full Repair Time
+stat.speedincrease = Speed Increase
+stat.range = Range
+stat.drilltier = Kazilabilirler
+stat.drillspeed = Ana kazma hizi
+stat.boosteffect = Boost Effect
+stat.maxunits = Max Active Units
+stat.health = Can
+stat.buildtime = Build Time
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = Build Cost
+stat.inaccuracy = sekme
+stat.shots = vuruslar
+stat.reload = Yeniden doldurma
+stat.ammo = Ammo
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Better Drill Required
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = A large rapid fire turret.
block.spectre.description = A large turret which shoots two powerful bullets at once.
block.meltdown.description = A large turret which shoots powerful long-range beams.
block.repair-point.description = Continuously heals the closest damaged unit in its vicinity.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_tr.properties b/core/assets/bundles/bundle_tr.properties
index 1fd6a6618e..395e062453 100644
--- a/core/assets/bundles/bundle_tr.properties
+++ b/core/assets/bundles/bundle_tr.properties
@@ -570,49 +570,49 @@ info.title = Bilgi
error.title = [crimson]Bir hata oldu
error.crashtitle = Bir hata oldu
unit.nobuild = [scarlet]Unit can't build
-blocks.input = Giriş
-blocks.output = Çıkış
-blocks.booster = Güçlendirici
-blocks.tiles = Required Tiles
-blocks.affinities = Affinities
+stat.input = Giriş
+stat.output = Çıkış
+stat.booster = Güçlendirici
+stat.tiles = Required Tiles
+stat.affinities = Affinities
block.unknown = [lightgray]???
-blocks.powercapacity = Enerji Kapasitesi
-blocks.powershot = Enerji/Atış
-blocks.damage = Hasar
-blocks.targetsair = Havayı Hedefler Mi
-blocks.targetsground = Yeri Hedefler Mi
-blocks.itemsmoved = Hareket Hızı
-blocks.launchtime = Fırlatmalar Arasındaki Süre
-blocks.shootrange = Menzil
-blocks.size = Boyut
-blocks.displaysize = Display Size
-blocks.liquidcapacity = Sıvı Kapasitesi
-blocks.powerrange = Enerji Menzili
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = Bağlantı sayısı
-blocks.poweruse = Enerji Kullanımı
-blocks.powerdamage = Enerji/Hasar
-blocks.itemcapacity = Eşya Kapasitesi
-blocks.basepowergeneration = Temel Enerji Üretimi
-blocks.productiontime = Üretim Süresi
-blocks.repairtime = Tamir Tamir Edilme Süresi
-blocks.speedincrease = Hız Artışı
-blocks.range = Menzil
-blocks.drilltier = Kazılabilenler
-blocks.drillspeed = Temel Matkap Hızı
-blocks.boosteffect = Hızlandırma Efekti
-blocks.maxunits = Maksimum Aktif Birim
-blocks.health = Can
-blocks.buildtime = İnşaat Süresi
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = İnşaat Fiyatı
-blocks.inaccuracy = İskalama Oranı
-blocks.shots = Atışlar
-blocks.reload = Atışlar/Sn
-blocks.ammo = Mermi
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = Enerji Kapasitesi
+stat.powershot = Enerji/Atış
+stat.damage = Hasar
+stat.targetsair = Havayı Hedefler Mi
+stat.targetsground = Yeri Hedefler Mi
+stat.itemsmoved = Hareket Hızı
+stat.launchtime = Fırlatmalar Arasındaki Süre
+stat.shootrange = Menzil
+stat.size = Boyut
+stat.displaysize = Display Size
+stat.liquidcapacity = Sıvı Kapasitesi
+stat.powerrange = Enerji Menzili
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = Bağlantı sayısı
+stat.poweruse = Enerji Kullanımı
+stat.powerdamage = Enerji/Hasar
+stat.itemcapacity = Eşya Kapasitesi
+stat.basepowergeneration = Temel Enerji Üretimi
+stat.productiontime = Üretim Süresi
+stat.repairtime = Tamir Tamir Edilme Süresi
+stat.speedincrease = Hız Artışı
+stat.range = Menzil
+stat.drilltier = Kazılabilenler
+stat.drillspeed = Temel Matkap Hızı
+stat.boosteffect = Hızlandırma Efekti
+stat.maxunits = Maksimum Aktif Birim
+stat.health = Can
+stat.buildtime = İnşaat Süresi
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = İnşaat Fiyatı
+stat.inaccuracy = İskalama Oranı
+stat.shots = Atışlar
+stat.reload = Atışlar/Sn
+stat.ammo = Mermi
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = Daha İyi Matkap Gerekli
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = Büyük bir anti hava ve anti kara tareti. Yakının
block.spectre.description = Dev bir çift namlulu top. Hava ve kara birimlerine iri, zırh delici mermiler atar.
block.meltdown.description = Dev bir lazer topu. Yüklenip yakındaki düşmanlara uzun süreli lazer ışınları yollar. Çalışması için soğutucu gerekir.
block.repair-point.description = Kendisine en yakın hasarlı birimi tamir eder.
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_uk_UA.properties b/core/assets/bundles/bundle_uk_UA.properties
index a78841184e..111c3f8f76 100644
--- a/core/assets/bundles/bundle_uk_UA.properties
+++ b/core/assets/bundles/bundle_uk_UA.properties
@@ -574,50 +574,50 @@ error.title = [crimson]Виникла помилка
error.crashtitle = Виникла помилка
unit.nobuild = [scarlet]Ця одиниця не може будувати
lastaccessed = [lightgray]Остання зміна від {0}
-blocks.input = Ввід
-blocks.output = Вивід
-blocks.booster = Прискорювач
-blocks.tiles = Необхідні плитки
-blocks.affinities = Збільшення ефективності
+stat.input = Ввід
+stat.output = Вивід
+stat.booster = Прискорювач
+stat.tiles = Необхідні плитки
+stat.affinities = Збільшення ефективності
block.unknown = [lightgray]???
-blocks.powercapacity = Місткість енергії
-blocks.powershot = Енергія за постріл
-blocks.damage = Шкода
-blocks.targetsair = Повітряні противники
-blocks.targetsground = Наземні противники
-blocks.itemsmoved = Швидкість переміщення
-blocks.launchtime = Час між запусками
-blocks.shootrange = Радіус дії
-blocks.size = Розмір
-blocks.displaysize = Розмір дисплею
-blocks.liquidcapacity = Рідинна місткість
-blocks.powerrange = Радіус передачі енергії
-blocks.linkrange = Радіус з’єднання
-blocks.instructions = Інструкції
-blocks.powerconnections = Максимальна кількість з’єднань
-blocks.poweruse = Енергії використовує
-blocks.powerdamage = Енергії за од. шкоди
-blocks.itemcapacity = Місткість предметів
-blocks.memorycapacity = Ємність пам’яті
-blocks.basepowergeneration = Базова генерація енергії
-blocks.productiontime = Час виробництва
-blocks.repairtime = Час повного відновлення блоку
-blocks.speedincrease = Збільшення швидкості
-blocks.range = Радіус дії
-blocks.drilltier = Видобуває
-blocks.drillspeed = Базова швидкість буріння
-blocks.boosteffect = Прискорювальний ефект
-blocks.maxunits = Максимальна кількість активних одиниць
-blocks.health = Здоров’я
-blocks.buildtime = Час будування
-blocks.maxconsecutive = Максимальна послідовність
-blocks.buildcost = Вартість будування
-blocks.inaccuracy = Розкид
-blocks.shots = Постріли
-blocks.reload = Постріли/секунду
-blocks.ammo = Боєприпаси
-blocks.shieldhealth = Міцність щита
-blocks.cooldowntime = Тривалість охолодження
+stat.powercapacity = Місткість енергії
+stat.powershot = Енергія за постріл
+stat.damage = Шкода
+stat.targetsair = Повітряні противники
+stat.targetsground = Наземні противники
+stat.itemsmoved = Швидкість переміщення
+stat.launchtime = Час між запусками
+stat.shootrange = Радіус дії
+stat.size = Розмір
+stat.displaysize = Розмір дисплею
+stat.liquidcapacity = Рідинна місткість
+stat.powerrange = Радіус передачі енергії
+stat.linkrange = Радіус з’єднання
+stat.instructions = Інструкції
+stat.powerconnections = Максимальна кількість з’єднань
+stat.poweruse = Енергії використовує
+stat.powerdamage = Енергії за од. шкоди
+stat.itemcapacity = Місткість предметів
+stat.memorycapacity = Ємність пам’яті
+stat.basepowergeneration = Базова генерація енергії
+stat.productiontime = Час виробництва
+stat.repairtime = Час повного відновлення блоку
+stat.speedincrease = Збільшення швидкості
+stat.range = Радіус дії
+stat.drilltier = Видобуває
+stat.drillspeed = Базова швидкість буріння
+stat.boosteffect = Прискорювальний ефект
+stat.maxunits = Максимальна кількість активних одиниць
+stat.health = Здоров’я
+stat.buildtime = Час будування
+stat.maxconsecutive = Максимальна послідовність
+stat.buildcost = Вартість будування
+stat.inaccuracy = Розкид
+stat.shots = Постріли
+stat.reload = Постріли/секунду
+stat.ammo = Боєприпаси
+stat.shieldhealth = Міцність щита
+stat.cooldowntime = Тривалість охолодження
bar.drilltierreq = Потребується кращий бур
bar.noresources = Бракує ресурсів
@@ -1317,4 +1317,4 @@ block.cyclone.description = Велика протиповітряна та пр
block.spectre.description = Масивна двоствольна гармата. Стріляє великими бронебійними кулями в повітряні та наземні цілі.
block.meltdown.description = Масивна лазерна гармата. Заряджає і стріляє лазерним променем у найближчих противників. Для роботи потрібен теплоносій.
block.repair-point.description = Безперервно ремонтує найближчу пошкоджену бойову одиницю.
-block.segment.description = Пошкоджує та руйнує вхідні снаряди. Окрім лазерних.
+block.segment.description = Пошкоджує та руйнує вхідні снаряди. Окрім лазерних.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_zh_CN.properties b/core/assets/bundles/bundle_zh_CN.properties
index 5c5c529ae2..5744d3d0fd 100644
--- a/core/assets/bundles/bundle_zh_CN.properties
+++ b/core/assets/bundles/bundle_zh_CN.properties
@@ -570,49 +570,49 @@ info.title = [accent]详情
error.title = [crimson]发生了一个错误
error.crashtitle = 发生了一个错误
unit.nobuild = [scarlet]单位未能建造
-blocks.input = 输入
-blocks.output = 输出
-blocks.booster = 增强物品/液体
-blocks.tiles = 所需地型
-blocks.affinities = 相关
+stat.input = 输入
+stat.output = 输出
+stat.booster = 增强物品/液体
+stat.tiles = 所需地型
+stat.affinities = 相关
block.unknown = [lightgray]???
-blocks.powercapacity = 能量容量
-blocks.powershot = 能量/发射
-blocks.damage = 伤害
-blocks.targetsair = 攻击空中单位
-blocks.targetsground = 攻击地面单位
-blocks.itemsmoved = 移动速度
-blocks.launchtime = 发射间隔时间
-blocks.shootrange = 范围
-blocks.size = 尺寸
-blocks.displaysize = 显示尺寸
-blocks.liquidcapacity = 液体容量
-blocks.powerrange = 能量范围
-blocks.linkrange = 连接范围
-blocks.instructions = 指令数量
-blocks.powerconnections = 最多连接
-blocks.poweruse = 使用能量
-blocks.powerdamage = 功率/损伤
-blocks.itemcapacity = 物品容量
-blocks.basepowergeneration = 基础能源输出
-blocks.productiontime = 生产时间
-blocks.repairtime = 建筑完全修复时间
-blocks.speedincrease = 提速
-blocks.range = 范围
-blocks.drilltier = 可钻探矿物
-blocks.drillspeed = 基础钻探速度
-blocks.boosteffect = 增强效果
-blocks.maxunits = 最大单位数量
-blocks.health = 生命值
-blocks.buildtime = 建造时间
-blocks.maxconsecutive = 最大连续
-blocks.buildcost = 建造花费
-blocks.inaccuracy = 误差
-blocks.shots = 发射数
-blocks.reload = 每秒发射数
-blocks.ammo = 弹药
-blocks.shieldhealth = 盾容
-blocks.cooldowntime = 冷却时间
+stat.powercapacity = 能量容量
+stat.powershot = 能量/发射
+stat.damage = 伤害
+stat.targetsair = 攻击空中单位
+stat.targetsground = 攻击地面单位
+stat.itemsmoved = 移动速度
+stat.launchtime = 发射间隔时间
+stat.shootrange = 范围
+stat.size = 尺寸
+stat.displaysize = 显示尺寸
+stat.liquidcapacity = 液体容量
+stat.powerrange = 能量范围
+stat.linkrange = 连接范围
+stat.instructions = 指令数量
+stat.powerconnections = 最多连接
+stat.poweruse = 使用能量
+stat.powerdamage = 功率/损伤
+stat.itemcapacity = 物品容量
+stat.basepowergeneration = 基础能源输出
+stat.productiontime = 生产时间
+stat.repairtime = 建筑完全修复时间
+stat.speedincrease = 提速
+stat.range = 范围
+stat.drilltier = 可钻探矿物
+stat.drillspeed = 基础钻探速度
+stat.boosteffect = 增强效果
+stat.maxunits = 最大单位数量
+stat.health = 生命值
+stat.buildtime = 建造时间
+stat.maxconsecutive = 最大连续
+stat.buildcost = 建造花费
+stat.inaccuracy = 误差
+stat.shots = 发射数
+stat.reload = 每秒发射数
+stat.ammo = 弹药
+stat.shieldhealth = 盾容
+stat.cooldowntime = 冷却时间
bar.drilltierreq = 需要更好的钻头
bar.noresources = 缺失资源
@@ -1302,4 +1302,4 @@ block.cyclone.description = 大型炮塔,对空对地,发射在敌人周围
block.spectre.description = 超大型炮塔,对空对地,一次射出两颗强大的破甲弹。
block.meltdown.description = 超大型激光炮塔,充能之后持续发射光束,需要冷却剂。
block.repair-point.description = 持续治疗其附近受损最严重的单位。
-block.segment.description = 摧毁袭来的除激光以外的子弹或导弹.
+block.segment.description = 摧毁袭来的除激光以外的子弹或导弹.
\ No newline at end of file
diff --git a/core/assets/bundles/bundle_zh_TW.properties b/core/assets/bundles/bundle_zh_TW.properties
index 85efa9a527..e495f4b768 100644
--- a/core/assets/bundles/bundle_zh_TW.properties
+++ b/core/assets/bundles/bundle_zh_TW.properties
@@ -570,49 +570,49 @@ info.title = 資訊
error.title = [crimson]發生錯誤
error.crashtitle = 發生錯誤
unit.nobuild = [scarlet]單位不能建造
-blocks.input = 輸入
-blocks.output = 輸出
-blocks.booster = 強化
-blocks.tiles = 需求方塊
-blocks.affinities = 親和方塊
+stat.input = 輸入
+stat.output = 輸出
+stat.booster = 強化
+stat.tiles = 需求方塊
+stat.affinities = 親和方塊
block.unknown = [lightgray]???
-blocks.powercapacity = 蓄電量
-blocks.powershot = 能量/射擊
-blocks.damage = 傷害
-blocks.targetsair = 攻擊空中目標
-blocks.targetsground = 攻擊地面目標
-blocks.itemsmoved = 移動速度
-blocks.launchtime = 發射間隔
-blocks.shootrange = 範圍
-blocks.size = 尺寸
-blocks.displaysize = Display Size
-blocks.liquidcapacity = 液體容量
-blocks.powerrange = 輸出範圍
-blocks.linkrange = Link Range
-blocks.instructions = Instructions
-blocks.powerconnections = 最大連接數
-blocks.poweruse = 能量使用
-blocks.powerdamage = 能量/傷害
-blocks.itemcapacity = 物品容量
-blocks.basepowergeneration = 基礎能量生產
-blocks.productiontime = 生產時間
-blocks.repairtime = 方塊完全修復時間
-blocks.speedincrease = 速度提升
-blocks.range = 範圍
-blocks.drilltier = 可鑽取礦物
-blocks.drillspeed = 基本鑽取速度
-blocks.boosteffect = 提升效應
-blocks.maxunits = 最大活躍單位
-blocks.health = 耐久度
-blocks.buildtime = 建設時間
-blocks.maxconsecutive = Max Consecutive
-blocks.buildcost = 建造成本
-blocks.inaccuracy = 誤差
-blocks.shots = 射擊數
-blocks.reload = 射擊次數/秒
-blocks.ammo = 彈藥
-blocks.shieldhealth = Shield Health
-blocks.cooldowntime = Cooldown Time
+stat.powercapacity = 蓄電量
+stat.powershot = 能量/射擊
+stat.damage = 傷害
+stat.targetsair = 攻擊空中目標
+stat.targetsground = 攻擊地面目標
+stat.itemsmoved = 移動速度
+stat.launchtime = 發射間隔
+stat.shootrange = 範圍
+stat.size = 尺寸
+stat.displaysize = Display Size
+stat.liquidcapacity = 液體容量
+stat.powerrange = 輸出範圍
+stat.linkrange = Link Range
+stat.instructions = Instructions
+stat.powerconnections = 最大連接數
+stat.poweruse = 能量使用
+stat.powerdamage = 能量/傷害
+stat.itemcapacity = 物品容量
+stat.basepowergeneration = 基礎能量生產
+stat.productiontime = 生產時間
+stat.repairtime = 方塊完全修復時間
+stat.speedincrease = 速度提升
+stat.range = 範圍
+stat.drilltier = 可鑽取礦物
+stat.drillspeed = 基本鑽取速度
+stat.boosteffect = 提升效應
+stat.maxunits = 最大活躍單位
+stat.health = 耐久度
+stat.buildtime = 建設時間
+stat.maxconsecutive = Max Consecutive
+stat.buildcost = 建造成本
+stat.inaccuracy = 誤差
+stat.shots = 射擊數
+stat.reload = 射擊次數/秒
+stat.ammo = 彈藥
+stat.shieldhealth = Shield Health
+stat.cooldowntime = Cooldown Time
bar.drilltierreq = 需要更好的鑽頭
bar.noresources = Missing Resources
@@ -1302,4 +1302,4 @@ block.cyclone.description = 一種對空和對地的大型砲塔。向附近單
block.spectre.description = 一種雙炮管的巨型砲塔。向空中及地面敵人發射大型的穿甲彈。
block.meltdown.description = 一種巨型激光砲塔。充能並發射持續性的激光光束。需要冷卻液以運作。
block.repair-point.description = 持續治療附近最近的受損單位。
-block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
+block.segment.description = Damages and destroys incoming projectiles. Laser projectiles are not targeted.
\ No newline at end of file
diff --git a/core/assets/contributors b/core/assets/contributors
index 69de5a3d8e..9f1cf8c9f4 100644
--- a/core/assets/contributors
+++ b/core/assets/contributors
@@ -95,3 +95,4 @@ ThePlayerA
YellOw139
PetrGasparik
LeoDog896
+Summet
diff --git a/core/assets/maps/archipelago.msav b/core/assets/maps/archipelago.msav
new file mode 100644
index 0000000000..24764ccf20
Binary files /dev/null and b/core/assets/maps/archipelago.msav differ
diff --git a/core/assets/maps/caldera.msav b/core/assets/maps/caldera.msav
index fae2a2e862..57bb5c382f 100644
Binary files a/core/assets/maps/caldera.msav and b/core/assets/maps/caldera.msav differ
diff --git a/core/assets/maps/craters.msav b/core/assets/maps/craters.msav
index b10b354bf0..04c1aa73d3 100644
Binary files a/core/assets/maps/craters.msav and b/core/assets/maps/craters.msav differ
diff --git a/core/assets/maps/fork.msav b/core/assets/maps/fork.msav
index f4bf6985fe..2fd62bd91b 100644
Binary files a/core/assets/maps/fork.msav and b/core/assets/maps/fork.msav differ
diff --git a/core/assets/maps/frozenForest.msav b/core/assets/maps/frozenForest.msav
index a2a1f52354..0eb9f1fe56 100644
Binary files a/core/assets/maps/frozenForest.msav and b/core/assets/maps/frozenForest.msav differ
diff --git a/core/assets/maps/fungalPass.msav b/core/assets/maps/fungalPass.msav
index c154c2e4db..1e3a26f520 100644
Binary files a/core/assets/maps/fungalPass.msav and b/core/assets/maps/fungalPass.msav differ
diff --git a/core/assets/maps/islands.msav b/core/assets/maps/islands.msav
index 1b833e98d0..90159d57e0 100644
Binary files a/core/assets/maps/islands.msav and b/core/assets/maps/islands.msav differ
diff --git a/core/assets/maps/moltenLake.msav b/core/assets/maps/moltenLake.msav
new file mode 100644
index 0000000000..a409307c6f
Binary files /dev/null and b/core/assets/maps/moltenLake.msav differ
diff --git a/core/assets/maps/mudFlats.msav b/core/assets/maps/mudFlats.msav
new file mode 100644
index 0000000000..1ba2e25ceb
Binary files /dev/null and b/core/assets/maps/mudFlats.msav differ
diff --git a/core/assets/maps/ruinousShores.msav b/core/assets/maps/ruinousShores.msav
index a0ef267a99..41e957c0ff 100644
Binary files a/core/assets/maps/ruinousShores.msav and b/core/assets/maps/ruinousShores.msav differ
diff --git a/core/assets/maps/saltFlats.msav b/core/assets/maps/saltFlats.msav
index 9a70ba342a..556b33700f 100644
Binary files a/core/assets/maps/saltFlats.msav and b/core/assets/maps/saltFlats.msav differ
diff --git a/core/assets/maps/shattered.msav b/core/assets/maps/shattered.msav
index a822e2d121..549e42cab7 100644
Binary files a/core/assets/maps/shattered.msav and b/core/assets/maps/shattered.msav differ
diff --git a/core/assets/maps/tarFields.msav b/core/assets/maps/tarFields.msav
index 06eaed164d..bf8b306f95 100644
Binary files a/core/assets/maps/tarFields.msav and b/core/assets/maps/tarFields.msav differ
diff --git a/core/assets/maps/tendrils.msav b/core/assets/maps/tendrils.msav
index 3034fb5ec1..825437d6c5 100644
Binary files a/core/assets/maps/tendrils.msav and b/core/assets/maps/tendrils.msav differ
diff --git a/core/assets/scripts/base.js b/core/assets/scripts/base.js
index c6d7be846b..ace7d878ee 100755
--- a/core/assets/scripts/base.js
+++ b/core/assets/scripts/base.js
@@ -9,8 +9,8 @@ const readBytes = path => Vars.mods.getScripts().readBytes(path)
const loadMusic = path => Vars.mods.getScripts().loadMusic(path)
const loadSound = path => Vars.mods.getScripts().loadSound(path)
-var scriptName = "base.js"
-var modName = "none"
+let scriptName = "base.js"
+let modName = "none"
const print = text => log(modName + "/" + scriptName, text);
diff --git a/core/assets/shaders/default.frag b/core/assets/shaders/default.frag
new file mode 100644
index 0000000000..93be3cffc9
--- /dev/null
+++ b/core/assets/shaders/default.frag
@@ -0,0 +1,9 @@
+varying lowp vec4 v_color;
+varying lowp vec4 v_mix_color;
+varying vec2 v_texCoords;
+uniform sampler2D u_texture;
+
+void main(){
+ vec4 c = texture2D(u_texture, v_texCoords);
+ gl_FragColor = v_color * mix(c, vec4(v_mix_color.rgb, c.a), v_mix_color.a);
+}
\ No newline at end of file
diff --git a/core/assets/shaders/planet.vert b/core/assets/shaders/planet.vert
index f500af0ecf..4723e2bfff 100755
--- a/core/assets/shaders/planet.vert
+++ b/core/assets/shaders/planet.vert
@@ -10,7 +10,7 @@ uniform vec3 u_ambientColor;
varying vec4 v_col;
-const vec3 diffuse = vec3(0);
+const vec3 diffuse = vec3(0.01);
const float shinefalloff = 4.0;
const float shinelen = 0.2;
diff --git a/core/assets/sprites/block_colors.png b/core/assets/sprites/block_colors.png
index 3e19c96e61..c297dccdf7 100644
Binary files a/core/assets/sprites/block_colors.png and b/core/assets/sprites/block_colors.png differ
diff --git a/core/assets/sprites/fallback/sprites5.png b/core/assets/sprites/fallback/sprites5.png
index e413db1a18..1b8a3ef066 100644
Binary files a/core/assets/sprites/fallback/sprites5.png and b/core/assets/sprites/fallback/sprites5.png differ
diff --git a/core/assets/sprites/fallback/sprites6.png b/core/assets/sprites/fallback/sprites6.png
index 94069305e4..a47c2d47eb 100644
Binary files a/core/assets/sprites/fallback/sprites6.png and b/core/assets/sprites/fallback/sprites6.png differ
diff --git a/core/assets/sprites/fallback/sprites7.png b/core/assets/sprites/fallback/sprites7.png
index 9e083fdec4..dd3d40dc80 100644
Binary files a/core/assets/sprites/fallback/sprites7.png and b/core/assets/sprites/fallback/sprites7.png differ
diff --git a/core/assets/sprites/fallback/sprites8.png b/core/assets/sprites/fallback/sprites8.png
index 4c47261514..212d169c38 100644
Binary files a/core/assets/sprites/fallback/sprites8.png and b/core/assets/sprites/fallback/sprites8.png differ
diff --git a/core/assets/sprites/fog.png b/core/assets/sprites/fog.png
new file mode 100644
index 0000000000..5121693e58
Binary files /dev/null and b/core/assets/sprites/fog.png differ
diff --git a/core/assets/sprites/sprites2.png b/core/assets/sprites/sprites2.png
index fba6d8fe48..a088daddcf 100644
Binary files a/core/assets/sprites/sprites2.png and b/core/assets/sprites/sprites2.png differ
diff --git a/core/assets/sprites/sprites3.png b/core/assets/sprites/sprites3.png
index 6e26e044e2..627f4e763c 100644
Binary files a/core/assets/sprites/sprites3.png and b/core/assets/sprites/sprites3.png differ
diff --git a/core/assets/sprites/sprites4.png b/core/assets/sprites/sprites4.png
index 4a76287a49..20eed12539 100644
Binary files a/core/assets/sprites/sprites4.png and b/core/assets/sprites/sprites4.png differ
diff --git a/core/assets/sprites/sprites5.png b/core/assets/sprites/sprites5.png
index a85adcfbb9..2fe5605d60 100644
Binary files a/core/assets/sprites/sprites5.png and b/core/assets/sprites/sprites5.png differ
diff --git a/core/src/mindustry/Vars.java b/core/src/mindustry/Vars.java
index 37ba22d3cb..2cf07cbea6 100644
--- a/core/src/mindustry/Vars.java
+++ b/core/src/mindustry/Vars.java
@@ -36,6 +36,8 @@ public class Vars implements Loadable{
public static boolean loadLocales = true;
/** Whether the logger is loaded. */
public static boolean loadedLogger = false, loadedFileLogger = false;
+ /** Whether to show the cliff button in the editor*/
+ public static boolean addCliffButton = false;
/** Maximum extra padding around deployment schematics. */
public static final int maxLoadoutSchematicPad = 5;
/** Maximum schematic size.*/
@@ -86,8 +88,10 @@ public class Vars implements Loadable{
public static final float logicItemTransferRange = 45f;
/** duration of time between turns in ticks */
public static final float turnDuration = 2 * Time.toMinutes;
- /** turns needed to destroy a sector completely */
- public static final float sectorDestructionTurns = 2f;
+ /** chance of an invasion per turn, 1 = 100% */
+ public static final float baseInvasionChance = 1f / 30f;
+ /** how many turns have to pass before invasions start */
+ public static final int invasionGracePeriod = 20;
/** min armor fraction damage; e.g. 0.05 = at least 5% damage */
public static final float minArmorDamage = 0.1f;
/** launch animation duration */
@@ -281,10 +285,10 @@ public class Vars implements Loadable{
if(loadedLogger) return;
String[] tags = {"[green][D][]", "[royal][I][]", "[yellow][W][]", "[scarlet][E][]", ""};
- String[] stags = {"&lc&fb[D]", "&lg&fb[I]", "&ly&fb[W]", "&lr&fb[E]", ""};
+ String[] stags = {"&lc&fb[D]", "&lb&fb[I]", "&ly&fb[W]", "&lr&fb[E]", ""};
Seq logBuffer = new Seq<>();
- Log.setLogger((level, text) -> {
+ Log.logger = (level, text) -> {
String result = text;
String rawText = Log.format(stags[level.ordinal()] + "&fr " + text);
System.out.println(rawText);
@@ -300,9 +304,9 @@ public class Vars implements Loadable{
}
}
- ui.scriptfrag.addMessage(Log.removeCodes(result));
+ ui.scriptfrag.addMessage(Log.removeColors(result));
}
- });
+ };
Events.on(ClientLoadEvent.class, e -> logBuffer.each(ui.scriptfrag::addMessage));
@@ -315,18 +319,19 @@ public class Vars implements Loadable{
settings.setAppName(appName);
Writer writer = settings.getDataDirectory().child("last_log.txt").writer(false);
- LogHandler log = Log.getLogger();
- Log.setLogger((level, text) -> {
+ LogHandler log = Log.logger;
+ //ignore it
+ Log.logger = (level, text) -> {
log.log(level, text);
try{
- writer.write("[" + Character.toUpperCase(level.name().charAt(0)) +"] " + Log.removeCodes(text) + "\n");
+ writer.write("[" + Character.toUpperCase(level.name().charAt(0)) +"] " + Log.removeColors(text) + "\n");
writer.flush();
}catch(IOException e){
e.printStackTrace();
//ignore it
}
- });
+ };
loadedFileLogger = true;
}
diff --git a/core/src/mindustry/ai/BaseAI.java b/core/src/mindustry/ai/BaseAI.java
index 3b45d8a17b..2c1fb11617 100644
--- a/core/src/mindustry/ai/BaseAI.java
+++ b/core/src/mindustry/ai/BaseAI.java
@@ -7,6 +7,7 @@ import arc.util.*;
import mindustry.*;
import mindustry.ai.BaseRegistry.*;
import mindustry.content.*;
+import mindustry.core.*;
import mindustry.game.*;
import mindustry.game.Schematic.*;
import mindustry.game.Teams.*;
@@ -23,7 +24,7 @@ public class BaseAI{
private static final Vec2 axis = new Vec2(), rotator = new Vec2();
private static final float correctPercent = 0.5f;
private static final float step = 5;
- private static final int attempts = 5;
+ private static final int attempts = 4;
private static final float emptyChance = 0.01f;
private static final int timerStep = 0, timerSpawn = 1;
@@ -40,11 +41,11 @@ public class BaseAI{
}
public void update(){
- if(timer.get(timerSpawn, 60) && data.hasCore()){
+ if(data.team.rules().aiCoreSpawn && timer.get(timerSpawn, 60 * 2.5f) && data.hasCore()){
CoreBlock block = (CoreBlock)data.core().block;
//create AI core unit
- if(!state.isEditor() && !Groups.unit.contains(u -> u.team() == data.team && u.type() == block.unitType)){
+ if(!state.isEditor() && !Groups.unit.contains(u -> u.team() == data.team && u.type == block.unitType)){
Unit unit = block.unitType.create(data.team);
unit.set(data.core());
unit.add();
@@ -68,9 +69,14 @@ public class BaseAI{
if(pos == null) return;
Tmp.v1.rnd(Mathf.random(range));
- int wx = (int)(world.toTile(pos.getX()) + Tmp.v1.x), wy = (int)(world.toTile(pos.getY()) + Tmp.v1.y);
+ int wx = (int)(World.toTile(pos.getX()) + Tmp.v1.x), wy = (int)(World.toTile(pos.getY()) + Tmp.v1.y);
Tile tile = world.tiles.getc(wx, wy);
+ //try not to block the spawn point
+ if(spawner.getSpawns().contains(t -> t.within(tile, tilesize * 40f))){
+ continue;
+ }
+
Seq parts = null;
//pick a completely random base part, and place it a random location
diff --git a/core/src/mindustry/ai/BlockIndexer.java b/core/src/mindustry/ai/BlockIndexer.java
index 6092c83910..a75b0758ea 100644
--- a/core/src/mindustry/ai/BlockIndexer.java
+++ b/core/src/mindustry/ai/BlockIndexer.java
@@ -8,6 +8,7 @@ import arc.struct.EnumSet;
import arc.struct.*;
import arc.util.*;
import mindustry.content.*;
+import mindustry.core.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.game.Teams.*;
@@ -179,8 +180,8 @@ public class BlockIndexer{
public boolean eachBlock(Team team, float wx, float wy, float range, Boolf pred, Cons cons){
intSet.clear();
- int tx = world.toTile(wx);
- int ty = world.toTile(wy);
+ int tx = World.toTile(wx);
+ int ty = World.toTile(wy);
int tileRange = (int)(range / tilesize + 1);
boolean any = false;
diff --git a/core/src/mindustry/ai/Pathfinder.java b/core/src/mindustry/ai/Pathfinder.java
index c24cecd49c..78a596bb9d 100644
--- a/core/src/mindustry/ai/Pathfinder.java
+++ b/core/src/mindustry/ai/Pathfinder.java
@@ -7,6 +7,7 @@ import arc.struct.*;
import arc.util.*;
import arc.util.async.*;
import mindustry.annotations.Annotations.*;
+import mindustry.core.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.gen.*;
@@ -85,9 +86,6 @@ public class Pathfinder implements Runnable{
tiles[tile.x][tile.y] = packTile(tile);
}
- //special preset which may help speed things up; this is optional
- preloadPath(getField(state.rules.waveTeam, costGround, fieldCore));
-
start();
});
@@ -105,7 +103,7 @@ public class Pathfinder implements Runnable{
boolean nearLiquid = false, nearSolid = false, nearGround = false;
for(int i = 0; i < 4; i++){
- Tile other = tile.getNearby(i);
+ Tile other = tile.nearby(i);
if(other != null){
if(other.floor().isLiquid) nearLiquid = true;
if(other.solid()) nearSolid = true;
@@ -114,7 +112,7 @@ public class Pathfinder implements Runnable{
}
return PathTile.get(
- tile.build == null ? 0 : Math.min((int)(tile.build.health / 40), 80),
+ tile.build == null || !tile.solid() ? 0 : Math.min((int)(tile.build.health / 40), 80),
tile.getTeamID(),
tile.solid(),
tile.floor().isLiquid,
@@ -444,7 +442,7 @@ public class Pathfinder implements Runnable{
@Override
public void getPositions(IntSeq out){
- out.add(Point2.pack(world.toTile(position.getX()), world.toTile(position.getY())));
+ out.add(Point2.pack(World.toTile(position.getX()), World.toTile(position.getY())));
}
}
@@ -453,7 +451,7 @@ public class Pathfinder implements Runnable{
* Data for a flow field to some set of destinations.
* Concrete subclasses must specify a way to fetch costs and destinations.
* */
- static abstract class Flowfield{
+ public static abstract class Flowfield{
/** Refresh rate in milliseconds. Return any number <= 0 to disable. */
protected int refreshRate;
/** Team this path is for. Set before using. */
@@ -462,7 +460,7 @@ public class Pathfinder implements Runnable{
protected PathCost cost = costTypes.get(costGround);
/** costs of getting to a specific tile */
- int[][] weights;
+ public int[][] weights;
/** search IDs of each position - the highest, most recent search is prioritized and overwritten */
int[][] searches;
/** search frontier, these are Pos objects */
diff --git a/core/src/mindustry/ai/WaveSpawner.java b/core/src/mindustry/ai/WaveSpawner.java
index 9cecf32ac1..c420972457 100644
--- a/core/src/mindustry/ai/WaveSpawner.java
+++ b/core/src/mindustry/ai/WaveSpawner.java
@@ -8,6 +8,7 @@ import arc.struct.*;
import arc.util.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
+import mindustry.core.*;
import mindustry.entities.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
@@ -23,11 +24,21 @@ public class WaveSpawner{
private Seq spawns = new Seq<>();
private boolean spawning = false;
private boolean any = false;
+ private Tile firstSpawn = null;
public WaveSpawner(){
Events.on(WorldLoadEvent.class, e -> reset());
}
+ @Nullable
+ public Tile getFirstSpawn(){
+ firstSpawn = null;
+ eachGroundSpawn((cx, cy) -> {
+ firstSpawn = world.tile(cx, cy);
+ });
+ return firstSpawn;
+ }
+
public int countSpawns(){
return spawns.size;
}
@@ -38,7 +49,7 @@ public class WaveSpawner{
/** @return true if the player is near a ground spawn point. */
public boolean playerNear(){
- return !player.dead() && spawns.contains(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, player.x, player.y) < state.rules.dropZoneRadius && player.team() != state.rules.waveTeam);
+ return state.hasSpawns() && !player.dead() && spawns.contains(g -> Mathf.dst(g.x * tilesize, g.y * tilesize, player.x, player.y) < state.rules.dropZoneRadius && player.team() != state.rules.waveTeam);
}
public void spawnEnemies(){
@@ -47,7 +58,7 @@ public class WaveSpawner{
for(SpawnGroup group : state.rules.spawns){
if(group.type == null) continue;
- int spawned = group.getUnitsSpawned(state.wave - 1);
+ int spawned = group.getSpawned(state.wave - 1);
if(group.type.flying){
float spread = margin / 1.5f;
@@ -69,7 +80,7 @@ public class WaveSpawner{
Unit unit = group.createUnit(state.rules.waveTeam, state.wave - 1);
unit.set(spawnX + Tmp.v1.x, spawnY + Tmp.v1.y);
- Time.run(Math.min(i * 5, 60 * 2), () -> spawnEffect(unit));
+ spawnEffect(unit);
}
});
}
@@ -89,9 +100,15 @@ public class WaveSpawner{
Time.run(40f, () -> Damage.damage(state.rules.waveTeam, x, y, state.rules.dropZoneRadius, 99999999f, true));
}
+ public void eachGroundSpawn(Intc2 cons){
+ eachGroundSpawn((x, y, shock) -> cons.get(World.toTile(x), World.toTile(y)));
+ }
+
private void eachGroundSpawn(SpawnConsumer cons){
- for(Tile spawn : spawns){
- cons.accept(spawn.worldx(), spawn.worldy(), true);
+ if(state.hasSpawns()){
+ for(Tile spawn : spawns){
+ cons.accept(spawn.worldx(), spawn.worldy(), true);
+ }
}
if(state.rules.attackMode && state.teams.isActive(state.rules.waveTeam) && !state.teams.playerCores().isEmpty()){
@@ -104,7 +121,7 @@ public class WaveSpawner{
//keep moving forward until the max step amount is reached
while(steps++ < maxSteps){
- int tx = world.toTile(core.x + Tmp.v1.x), ty = world.toTile(core.y + Tmp.v1.y);
+ int tx = World.toTile(core.x + Tmp.v1.x), ty = World.toTile(core.y + Tmp.v1.y);
any = false;
Geometry.circle(tx, ty, world.width(), world.height(), 3, (x, y) -> {
if(world.solid(x, y)){
@@ -161,7 +178,7 @@ public class WaveSpawner{
}
private void spawnEffect(Unit unit){
- Call.spawnEffect(unit.x, unit.y, unit.type());
+ Call.spawnEffect(unit.x, unit.y, unit.type);
Time.run(30f, unit::add);
}
diff --git a/core/src/mindustry/ai/types/BuilderAI.java b/core/src/mindustry/ai/types/BuilderAI.java
index 8e8c74f986..c3558ca58a 100644
--- a/core/src/mindustry/ai/types/BuilderAI.java
+++ b/core/src/mindustry/ai/types/BuilderAI.java
@@ -79,7 +79,7 @@ public class BuilderAI extends AIController{
float dist = Math.min(cons.dst(unit) - buildingRange, 0);
//make sure you can reach the request in time
- if(dist / unit.type().speed < cons.buildCost * 0.9f){
+ if(dist / unit.type.speed < cons.buildCost * 0.9f){
following = b;
found = true;
}
@@ -112,7 +112,7 @@ public class BuilderAI extends AIController{
@Override
public AIController fallback(){
- return unit.type().flying ? new FlyingAI() : new GroundAI();
+ return unit.type.flying ? new FlyingAI() : new GroundAI();
}
@Override
diff --git a/core/src/mindustry/ai/types/FlyingAI.java b/core/src/mindustry/ai/types/FlyingAI.java
index 0758f9016a..7262ae216a 100644
--- a/core/src/mindustry/ai/types/FlyingAI.java
+++ b/core/src/mindustry/ai/types/FlyingAI.java
@@ -12,11 +12,11 @@ public class FlyingAI extends AIController{
@Override
public void updateMovement(){
if(target != null && unit.hasWeapons() && command() == UnitCommand.attack){
- if(unit.type().weapons.first().rotate){
+ if(unit.type.weapons.first().rotate){
moveTo(target, unit.range() * 0.8f);
unit.lookAt(target);
}else{
- attack(100f);
+ attack(120f);
}
}
@@ -34,17 +34,15 @@ public class FlyingAI extends AIController{
Teamc result = target(x, y, range, air, ground);
if(result != null) return result;
- if(ground) result = targetFlag(x, y, BlockFlag.producer, true);
+ if(ground) result = targetFlag(x, y, BlockFlag.generator, true);
if(result != null) return result;
- if(ground) result = targetFlag(x, y, BlockFlag.turret, true);
+ if(ground) result = targetFlag(x, y, BlockFlag.core, true);
if(result != null) return result;
return null;
}
- //TODO clean up
-
protected void attack(float circleLength){
vec.set(target).sub(unit);
@@ -57,7 +55,7 @@ public class FlyingAI extends AIController{
vec.setAngle(Mathf.slerpDelta(unit.vel().angle(), vec.angle(), 0.6f));
}
- vec.setLength(unit.type().speed);
+ vec.setLength(unit.type.speed);
unit.moveAt(vec);
}
diff --git a/core/src/mindustry/ai/types/FormationAI.java b/core/src/mindustry/ai/types/FormationAI.java
index cbe12a565e..3c5a2b99b4 100644
--- a/core/src/mindustry/ai/types/FormationAI.java
+++ b/core/src/mindustry/ai/types/FormationAI.java
@@ -7,6 +7,7 @@ import mindustry.ai.formations.*;
import mindustry.entities.units.*;
import mindustry.gen.*;
import mindustry.type.*;
+import mindustry.world.blocks.storage.CoreBlock.*;
public class FormationAI extends AIController implements FormationMember{
public Unit leader;
@@ -26,15 +27,15 @@ public class FormationAI extends AIController implements FormationMember{
@Override
public void updateUnit(){
- UnitType type = unit.type();
+ UnitType type = unit.type;
if(leader.dead){
unit.resetController();
return;
}
- if(unit.type().canBoost && unit.canPassOn()){
- unit.elevation = Mathf.approachDelta(unit.elevation, 0f, 0.08f);
+ if(unit.type.canBoost){
+ unit.elevation = Mathf.approachDelta(unit.elevation, !unit.canPassOn() ? 1f : leader.type.canBoost ? leader.elevation : 0f, 0.08f);
}
unit.controlWeapons(true, leader.isShooting);
@@ -42,7 +43,7 @@ public class FormationAI extends AIController implements FormationMember{
unit.aim(leader.aimX(), leader.aimY());
- if(unit.type().rotateShooting){
+ if(unit.type.rotateShooting){
unit.lookAt(leader.aimX(), leader.aimY());
}else if(unit.moving()){
unit.lookAt(unit.vel.angle());
@@ -52,10 +53,36 @@ public class FormationAI extends AIController implements FormationMember{
float margin = 3f;
+ float speed = unit.realSpeed();
+
if(unit.dst(realtarget) <= margin){
- unit.vel.approachDelta(Vec2.ZERO, type.speed * type.accel / 2f);
+ unit.vel.approachDelta(Vec2.ZERO, speed * type.accel / 2f);
}else{
- unit.moveAt(realtarget.sub(unit).limit(type.speed));
+ unit.moveAt(realtarget.sub(unit).limit(speed));
+ }
+
+ if(unit instanceof Minerc mine && leader instanceof Minerc com){
+ if(mine.validMine(com.mineTile())){
+ mine.mineTile(com.mineTile());
+
+ CoreBuild core = unit.team.core();
+
+ if(core != null && com.mineTile().drop() != null && unit.within(core, unit.type.range) && !unit.acceptsItem(com.mineTile().drop())){
+ if(core.acceptStack(unit.stack.item, unit.stack.amount, unit) > 0){
+ Call.transferItemTo(unit.stack.item, unit.stack.amount, unit.x, unit.y, core);
+
+ unit.clearItem();
+ }
+ }
+ }else{
+ mine.mineTile(null);
+ }
+
+ }
+
+ if(unit instanceof Builderc build && leader instanceof Builderc com && com.activelyBuilding()){
+ build.clearBuilding();
+ build.addBuild(com.buildPlan());
}
}
@@ -69,7 +96,7 @@ public class FormationAI extends AIController implements FormationMember{
@Override
public float formationSize(){
- return unit.hitSize * 1f;
+ return unit.hitSize * 1.1f;
}
@Override
diff --git a/core/src/mindustry/ai/types/GroundAI.java b/core/src/mindustry/ai/types/GroundAI.java
index 157ed2eb9d..2a711235c9 100644
--- a/core/src/mindustry/ai/types/GroundAI.java
+++ b/core/src/mindustry/ai/types/GroundAI.java
@@ -13,8 +13,6 @@ import java.util.*;
import static mindustry.Vars.*;
public class GroundAI extends AIController{
- //static final float commandCooldown = 60f * 10;
- //float commandTimer = 60*3;
@Override
public void updateMovement(){
@@ -45,31 +43,17 @@ public class GroundAI extends AIController{
}
}
- if(unit.type().canBoost && !unit.onSolid()){
+ if(unit.type.canBoost && !unit.onSolid()){
unit.elevation = Mathf.approachDelta(unit.elevation, 0f, 0.08f);
}
- if(!Units.invalidateTarget(target, unit, unit.range()) && unit.type().rotateShooting){
- if(unit.type().hasWeapons()){
- unit.lookAt(Predict.intercept(unit, target, unit.type().weapons.first().bullet.speed));
+ if(!Units.invalidateTarget(target, unit, unit.range()) && unit.type.rotateShooting){
+ if(unit.type.hasWeapons()){
+ unit.lookAt(Predict.intercept(unit, target, unit.type.weapons.first().bullet.speed));
}
}else if(unit.moving()){
unit.lookAt(unit.vel().angle());
}
- //auto-command works but it's very buggy
- /*
- if(unit instanceof Commanderc){
- Commanderc c = (Commanderc)unit;
- //try to command when missing members
- if(c.controlling().size <= unit.type().commandLimit/2){
- commandTimer -= Time.delta;
-
- if(commandTimer <= 0){
- c.commandNearby(new SquareFormation(), u -> !(u.controller() instanceof FormationAI) && !(u instanceof Commanderc));
- commandTimer = commandCooldown;
- }
- }
- }*/
}
}
diff --git a/core/src/mindustry/ai/types/LogicAI.java b/core/src/mindustry/ai/types/LogicAI.java
index 76b81794a2..1166c2ff96 100644
--- a/core/src/mindustry/ai/types/LogicAI.java
+++ b/core/src/mindustry/ai/types/LogicAI.java
@@ -98,7 +98,7 @@ public class LogicAI extends AIController{
}
}
- if(unit.type().canBoost && !unit.type().flying){
+ if(unit.type.canBoost && !unit.type.flying){
unit.elevation = Mathf.approachDelta(unit.elevation, Mathf.num(boost || unit.onSolid()), 0.08f);
}
@@ -129,7 +129,7 @@ public class LogicAI extends AIController{
@Override
protected boolean shouldShoot(){
- return shoot && !(unit.type().canBoost && boost);
+ return shoot && !(unit.type.canBoost && boost);
}
//always aim for the main target
diff --git a/core/src/mindustry/ai/types/MinerAI.java b/core/src/mindustry/ai/types/MinerAI.java
index a03481768f..aa7d1403c5 100644
--- a/core/src/mindustry/ai/types/MinerAI.java
+++ b/core/src/mindustry/ai/types/MinerAI.java
@@ -19,12 +19,14 @@ public class MinerAI extends AIController{
if(!(unit instanceof Minerc miner) || core == null) return;
- if(miner.mineTile() != null && !miner.mineTile().within(unit, unit.type().range)){
+ if(miner.mineTile() != null && !miner.mineTile().within(unit, unit.type.range)){
miner.mineTile(null);
}
if(mining){
- targetItem = unit.team.data().mineItems.min(i -> indexer.hasOre(i) && miner.canMine(i), i -> core.items.get(i));
+ if(timer.get(timerTarget2, 60 * 4) || targetItem == null){
+ targetItem = unit.team.data().mineItems.min(i -> indexer.hasOre(i) && miner.canMine(i), i -> core.items.get(i));
+ }
//core full of the target item, do nothing
if(targetItem != null && core.acceptStack(targetItem, 1, unit) == 0){
@@ -34,7 +36,7 @@ public class MinerAI extends AIController{
}
//if inventory is full, drop it off.
- if(unit.stack.amount >= unit.type().itemCapacity || (targetItem != null && !unit.acceptsItem(targetItem))){
+ if(unit.stack.amount >= unit.type.itemCapacity || (targetItem != null && !unit.acceptsItem(targetItem))){
mining = false;
}else{
if(retarget() && targetItem != null){
@@ -42,9 +44,9 @@ public class MinerAI extends AIController{
}
if(ore != null){
- moveTo(ore, unit.type().range / 2f);
+ moveTo(ore, unit.type.range / 2f);
- if(unit.within(ore, unit.type().range)){
+ if(unit.within(ore, unit.type.range)){
miner.mineTile(ore);
}
@@ -61,7 +63,7 @@ public class MinerAI extends AIController{
return;
}
- if(unit.within(core, unit.type().range)){
+ if(unit.within(core, unit.type.range)){
if(core.acceptStack(unit.stack.item, unit.stack.amount, unit) > 0){
Call.transferItemTo(unit.stack.item, unit.stack.amount, unit.x, unit.y, core);
}
@@ -70,7 +72,7 @@ public class MinerAI extends AIController{
mining = true;
}
- circle(core, unit.type().range / 1.8f);
+ circle(core, unit.type.range / 1.8f);
}
}
diff --git a/core/src/mindustry/ai/types/RepairAI.java b/core/src/mindustry/ai/types/RepairAI.java
index 5f021ae828..36504f908d 100644
--- a/core/src/mindustry/ai/types/RepairAI.java
+++ b/core/src/mindustry/ai/types/RepairAI.java
@@ -12,7 +12,7 @@ public class RepairAI extends AIController{
if(target instanceof Building){
boolean shoot = false;
- if(target.within(unit, unit.type().range)){
+ if(target.within(unit, unit.type.range)){
unit.aim(target);
shoot = true;
}
@@ -23,8 +23,8 @@ public class RepairAI extends AIController{
}
if(target != null){
- if(!target.within(unit, unit.type().range * 0.65f)){
- moveTo(target, unit.type().range * 0.65f);
+ if(!target.within(unit, unit.type.range * 0.65f) && target instanceof Building){
+ moveTo(target, unit.type.range * 0.65f);
}
unit.lookAt(target);
@@ -33,12 +33,14 @@ public class RepairAI extends AIController{
@Override
protected void updateTargeting(){
- target = Units.findDamagedTile(unit.team, unit.x, unit.y);
+ Building target = Units.findDamagedTile(unit.team, unit.x, unit.y);
if(target instanceof ConstructBuild) target = null;
if(target == null){
super.updateTargeting();
+ }else{
+ this.target = target;
}
}
diff --git a/core/src/mindustry/ai/types/SuicideAI.java b/core/src/mindustry/ai/types/SuicideAI.java
index 2eae6e409f..0ef3ece228 100644
--- a/core/src/mindustry/ai/types/SuicideAI.java
+++ b/core/src/mindustry/ai/types/SuicideAI.java
@@ -21,7 +21,7 @@ public class SuicideAI extends GroundAI{
}
if(retarget()){
- target = target(unit.x, unit.y, unit.range(), unit.type().targetAir, unit.type().targetGround);
+ target = target(unit.x, unit.y, unit.range(), unit.type.targetAir, unit.type.targetGround);
}
Building core = unit.closestEnemyCore();
@@ -30,11 +30,11 @@ public class SuicideAI extends GroundAI{
if(!Units.invalidateTarget(target, unit, unit.range()) && unit.hasWeapons()){
rotate = true;
- shoot = unit.within(target, unit.type().weapons.first().bullet.range() +
+ shoot = unit.within(target, unit.type.weapons.first().bullet.range() +
(target instanceof Building ? ((Building)target).block.size * Vars.tilesize / 2f : ((Hitboxc)target).hitSize() / 2f));
- if(unit.type().hasWeapons()){
- unit.aimLook(Predict.intercept(unit, target, unit.type().weapons.first().bullet.speed));
+ if(unit.type.hasWeapons()){
+ unit.aimLook(Predict.intercept(unit, target, unit.type.weapons.first().bullet.speed));
}
//do not move toward walls or transport blocks
@@ -65,7 +65,7 @@ public class SuicideAI extends GroundAI{
if(!blocked){
moveToTarget = true;
//move towards target directly
- unit.moveAt(vec.set(target).sub(unit).limit(unit.type().speed));
+ unit.moveAt(vec.set(target).sub(unit).limit(unit.type.speed));
}
}
diff --git a/core/src/mindustry/async/PhysicsProcess.java b/core/src/mindustry/async/PhysicsProcess.java
index 07d44d4717..a60dab7f68 100644
--- a/core/src/mindustry/async/PhysicsProcess.java
+++ b/core/src/mindustry/async/PhysicsProcess.java
@@ -57,7 +57,7 @@ public class PhysicsProcess implements AsyncProcess{
PhysicRef ref = entity.physref();
ref.body.layer =
- entity.type().allowLegStep ? layerLegs :
+ entity.type.allowLegStep ? layerLegs :
entity.isGrounded() ? layerGround : layerFlying;
ref.x = entity.x();
ref.y = entity.y();
diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java
index 05ed572f7e..291e8ff745 100644
--- a/core/src/mindustry/content/Blocks.java
+++ b/core/src/mindustry/content/Blocks.java
@@ -14,6 +14,8 @@ import mindustry.world.blocks.*;
import mindustry.world.blocks.campaign.*;
import mindustry.world.blocks.defense.*;
import mindustry.world.blocks.defense.turrets.*;
+import mindustry.world.blocks.defense.turrets.PointDefenseTurret;
+import mindustry.world.blocks.defense.turrets.TractorBeamTurret;
import mindustry.world.blocks.distribution.*;
import mindustry.world.blocks.environment.*;
import mindustry.world.blocks.experimental.*;
@@ -37,8 +39,8 @@ public class Blocks implements ContentList{
//environment
air, spawn, cliff, deepwater, water, taintedWater, tar, slag, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, space,
dacite, stoneWall, dirtWall, sporeWall, iceWall, daciteWall, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster,
- iceSnow, sandWater, darksandWater, duneWall, sandWall, moss, sporeMoss, shale, shaleWall, shaleBoulder, sandBoulder, daciteBoulder, grass, salt,
- metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, basalt, magmarock, hotrock, snowWall, boulder, snowBoulder, saltWall,
+ iceSnow, sandWater, darksandWater, duneWall, sandWall, moss, sporeMoss, shale, shaleWall, shaleBoulder, sandBoulder, daciteBoulder, boulder, snowBoulder, grass, salt,
+ metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, basalt, magmarock, hotrock, snowWall, saltWall,
darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal,
pebbles, tendrils,
@@ -100,6 +102,7 @@ public class Blocks implements ContentList{
{
alwaysReplace = true;
hasShadow = false;
+ useColor = false;
}
@Override public void drawBase(Tile tile){}
@@ -119,6 +122,7 @@ public class Blocks implements ContentList{
spawn = new OverlayFloor("spawn"){
{
variants = 0;
+ needsSurface = false;
}
@Override
public void drawBase(Tile tile){}
@@ -315,6 +319,11 @@ public class Blocks implements ContentList{
attributes.set(Attribute.water, 0.3f);
}};
+ shale = new Floor("shale"){{
+ variants = 3;
+ attributes.set(Attribute.oil, 1f);
+ }};
+
stoneWall = new StaticWall("stone-wall"){{
variants = 2;
}};
@@ -323,15 +332,6 @@ public class Blocks implements ContentList{
variants = 2;
}};
- boulder = new Boulder("boulder"){{
- variants = 2;
- }};
-
- snowBoulder = new Boulder("snow-boulder"){{
- variants = 2;
- snow.asFloor().decoration = ice.asFloor().decoration = iceSnow.asFloor().decoration = this;
- }};
-
dirtWall = new StaticWall("dirt-wall"){{
variants = 2;
}};
@@ -361,6 +361,12 @@ public class Blocks implements ContentList{
saltWall = new StaticWall("salt-wall");
+ shrubs = new StaticWall("shrubs");
+
+ shaleWall = new StaticWall("shale-wall"){{
+ variants = 2;
+ }};
+
sporePine = new StaticTree("spore-pine"){{
variants = 0;
}};
@@ -373,8 +379,6 @@ public class Blocks implements ContentList{
variants = 0;
}};
- shrubs = new StaticWall("shrubs");
-
whiteTreeDead = new TreeBlock("white-tree-dead");
whiteTree = new TreeBlock("white-tree");
@@ -383,13 +387,13 @@ public class Blocks implements ContentList{
variants = 3;
}};
- shale = new Floor("shale"){{
- variants = 3;
- attributes.set(Attribute.oil, 1f);
+ boulder = new Boulder("boulder"){{
+ variants = 2;
}};
- shaleWall = new StaticWall("shale-wall"){{
+ snowBoulder = new Boulder("snow-boulder"){{
variants = 2;
+ snow.asFloor().decoration = ice.asFloor().decoration = iceSnow.asFloor().decoration = salt.asFloor().decoration = this;
}};
shaleBoulder = new Boulder("shale-boulder"){{
@@ -579,7 +583,7 @@ public class Blocks implements ContentList{
phaseWeaver = new GenericCrafter("phase-weaver"){{
requirements(Category.crafting, with(Items.silicon, 130, Items.lead, 120, Items.thorium, 75));
craftEffect = Fx.smeltsmoke;
- outputItem = new ItemStack(Items.phasefabric, 1);
+ outputItem = new ItemStack(Items.phaseFabric, 1);
craftTime = 120f;
size = 2;
hasPower = true;
@@ -593,7 +597,7 @@ public class Blocks implements ContentList{
surgeSmelter = new GenericSmelter("alloy-smelter"){{
requirements(Category.crafting, with(Items.silicon, 80, Items.lead, 80, Items.thorium, 70));
craftEffect = Fx.smeltsmoke;
- outputItem = new ItemStack(Items.surgealloy, 1);
+ outputItem = new ItemStack(Items.surgeAlloy, 1);
craftTime = 75f;
size = 3;
hasPower = true;
@@ -672,7 +676,7 @@ public class Blocks implements ContentList{
}};
disassembler = new Separator("disassembler"){{
- requirements(Category.crafting, with(Items.graphite, 140, Items.titanium, 100, Items.silicon, 150, Items.surgealloy, 70));
+ requirements(Category.crafting, with(Items.graphite, 140, Items.titanium, 100, Items.silicon, 150, Items.surgeAlloy, 70));
results = with(
Items.sand, 4,
Items.graphite, 2,
@@ -790,20 +794,22 @@ public class Blocks implements ContentList{
}};
phaseWall = new Wall("phase-wall"){{
- requirements(Category.defense, with(Items.phasefabric, 6));
+ requirements(Category.defense, with(Items.phaseFabric, 6));
health = 150 * wallHealthMultiplier;
- flashHit = deflect = true;
+ chanceDeflect = 10f;
+ flashHit = true;
}};
phaseWallLarge = new Wall("phase-wall-large"){{
requirements(Category.defense, ItemStack.mult(phaseWall.requirements, 4));
health = 150 * 4 * wallHealthMultiplier;
size = 2;
- flashHit = deflect = true;
+ chanceDeflect = 10f;
+ flashHit = true;
}};
surgeWall = new Wall("surge-wall"){{
- requirements(Category.defense, with(Items.surgealloy, 6));
+ requirements(Category.defense, with(Items.surgeAlloy, 6));
health = 230 * wallHealthMultiplier;
lightningChance = 0.05f;
}};
@@ -881,25 +887,25 @@ public class Blocks implements ContentList{
healPercent = 11f;
phaseBoost = 15f;
health = 80 * size * size;
- consumes.item(Items.phasefabric).boost();
+ consumes.item(Items.phaseFabric).boost();
}};
overdriveProjector = new OverdriveProjector("overdrive-projector"){{
requirements(Category.effect, with(Items.lead, 100, Items.titanium, 75, Items.silicon, 75, Items.plastanium, 30));
consumes.power(3.50f);
size = 2;
- consumes.item(Items.phasefabric).boost();
+ consumes.item(Items.phaseFabric).boost();
}};
overdriveDome = new OverdriveProjector("overdrive-dome"){{
- requirements(Category.effect, with(Items.lead, 200, Items.titanium, 130, Items.silicon, 130, Items.plastanium, 80, Items.surgealloy, 120));
+ requirements(Category.effect, with(Items.lead, 200, Items.titanium, 130, Items.silicon, 130, Items.plastanium, 80, Items.surgeAlloy, 120));
consumes.power(10f);
size = 3;
range = 200f;
speedBoost = 2.5f;
useTime = 300f;
hasBoost = false;
- consumes.items(with(Items.phasefabric, 1, Items.silicon, 1));
+ consumes.items(with(Items.phaseFabric, 1, Items.silicon, 1));
}};
forceProjector = new ForceProjector("force-projector"){{
@@ -912,15 +918,15 @@ public class Blocks implements ContentList{
cooldownLiquid = 1.2f;
cooldownBrokenBase = 0.35f;
- consumes.item(Items.phasefabric).boost();
+ consumes.item(Items.phaseFabric).boost();
consumes.power(4f);
}};
shockMine = new ShockMine("shock-mine"){{
requirements(Category.effect, with(Items.lead, 25, Items.silicon, 12));
hasShadow = false;
- health = 40;
- damage = 23;
+ health = 50;
+ damage = 25;
tileDamage = 7f;
length = 10;
tendrils = 4;
@@ -974,7 +980,7 @@ public class Blocks implements ContentList{
}};
phaseConveyor = new ItemBridge("phase-conveyor"){{
- requirements(Category.distribution, with(Items.phasefabric, 5, Items.silicon, 7, Items.lead, 10, Items.graphite, 10));
+ requirements(Category.distribution, with(Items.phaseFabric, 5, Items.silicon, 7, Items.lead, 10, Items.graphite, 10));
range = 12;
canOverdrive = false;
hasPower = true;
@@ -1100,7 +1106,7 @@ public class Blocks implements ContentList{
}};
phaseConduit = new LiquidBridge("phase-conduit"){{
- requirements(Category.liquid, with(Items.phasefabric, 5, Items.silicon, 7, Items.metaglass, 20, Items.titanium, 10));
+ requirements(Category.liquid, with(Items.phaseFabric, 5, Items.silicon, 7, Items.metaglass, 20, Items.titanium, 10));
range = 12;
hasPower = true;
canOverdrive = false;
@@ -1124,7 +1130,7 @@ public class Blocks implements ContentList{
}};
surgeTower = new PowerNode("surge-tower"){{
- requirements(Category.power, with(Items.titanium, 7, Items.lead, 10, Items.silicon, 15, Items.surgealloy, 15));
+ requirements(Category.power, with(Items.titanium, 7, Items.lead, 10, Items.silicon, 15, Items.surgeAlloy, 15));
size = 2;
maxNodes = 2;
laserRange = 40f;
@@ -1181,10 +1187,10 @@ public class Blocks implements ContentList{
}};
rtgGenerator = new DecayGenerator("rtg-generator"){{
- requirements(Category.power, with(Items.lead, 100, Items.silicon, 75, Items.phasefabric, 25, Items.plastanium, 75, Items.thorium, 50));
+ requirements(Category.power, with(Items.lead, 100, Items.silicon, 75, Items.phaseFabric, 25, Items.plastanium, 75, Items.thorium, 50));
size = 2;
powerProduction = 4.5f;
- itemDuration = 60 * 15f;
+ itemDuration = 60 * 18f;
}};
solarPanel = new SolarGenerator("solar-panel"){{
@@ -1193,7 +1199,7 @@ public class Blocks implements ContentList{
}};
largeSolarPanel = new SolarGenerator("solar-panel-large"){{
- requirements(Category.power, with(Items.lead, 100, Items.silicon, 145, Items.phasefabric, 15));
+ requirements(Category.power, with(Items.lead, 100, Items.silicon, 145, Items.phaseFabric, 15));
size = 3;
powerProduction = 0.95f;
}};
@@ -1210,7 +1216,7 @@ public class Blocks implements ContentList{
}};
impactReactor = new ImpactReactor("impact-reactor"){{
- requirements(Category.power, with(Items.lead, 500, Items.silicon, 300, Items.graphite, 400, Items.thorium, 100, Items.surgealloy, 250, Items.metaglass, 250));
+ requirements(Category.power, with(Items.lead, 500, Items.silicon, 300, Items.graphite, 400, Items.thorium, 100, Items.surgeAlloy, 250, Items.metaglass, 250));
size = 4;
health = 900;
powerProduction = 130f;
@@ -1353,19 +1359,21 @@ public class Blocks implements ContentList{
size = 5;
unitCapModifier = 20;
- researchCostMultiplier = 0.06f;
+ researchCostMultiplier = 0.05f;
}};
vault = new StorageBlock("vault"){{
requirements(Category.effect, with(Items.titanium, 250, Items.thorium, 125));
size = 3;
itemCapacity = 1000;
+ flags = EnumSet.of(BlockFlag.storage);
}};
container = new StorageBlock("container"){{
requirements(Category.effect, with(Items.titanium, 100));
size = 2;
itemCapacity = 300;
+ flags = EnumSet.of(BlockFlag.storage);
}};
unloader = new Unloader("unloader"){{
@@ -1549,7 +1557,7 @@ public class Blocks implements ContentList{
ammo(
Items.blastCompound, Bullets.missileExplosive,
Items.pyratite, Bullets.missileIncendiary,
- Items.surgealloy, Bullets.missileSurge
+ Items.surgeAlloy, Bullets.missileSurge
);
reloadTime = 30f;
shots = 4;
@@ -1588,7 +1596,7 @@ public class Blocks implements ContentList{
}};
segment = new PointDefenseTurret("segment"){{
- requirements(Category.turret, with(Items.silicon, 130, Items.thorium, 80, Items.phasefabric, 40));
+ requirements(Category.turret, with(Items.silicon, 130, Items.thorium, 80, Items.phaseFabric, 40));
health = 250 * size * size;
range = 160f;
@@ -1642,11 +1650,20 @@ public class Blocks implements ContentList{
float brange = range + 10f;
- ammo(Items.thorium, new ShrapnelBulletType(){{
+ ammo(
+ Items.thorium, new ShrapnelBulletType(){{
length = brange;
damage = 105f;
- ammoMultiplier = 6f;
- }});
+ ammoMultiplier = 5f;
+ }},
+ Items.titanium, new ShrapnelBulletType(){{
+ length = brange;
+ damage = 66f;
+ ammoMultiplier = 4f;
+ width = 17f;
+ reloadMultiplier = 1.3f;
+ }}
+ );
}};
ripple = new ItemTurret("ripple"){{
@@ -1685,7 +1702,7 @@ public class Blocks implements ContentList{
Items.metaglass, Bullets.fragGlass,
Items.blastCompound, Bullets.fragExplosive,
Items.plastanium, Bullets.fragPlastic,
- Items.surgealloy, Bullets.fragSurge
+ Items.surgeAlloy, Bullets.fragSurge
);
xRand = 4f;
reloadTime = 8f;
@@ -1703,9 +1720,9 @@ public class Blocks implements ContentList{
foreshadow = new ItemTurret("foreshadow"){{
float brange = range = 500f;
- requirements(Category.turret, with(Items.copper, 1000, Items.metaglass, 600, Items.surgealloy, 300, Items.plastanium, 200, Items.silicon, 600));
+ requirements(Category.turret, with(Items.copper, 1000, Items.metaglass, 600, Items.surgeAlloy, 300, Items.plastanium, 200, Items.silicon, 600));
ammo(
- Items.surgealloy, new PointBulletType(){{
+ Items.surgeAlloy, new PointBulletType(){{
shootEffect = Fx.instShoot;
hitEffect = Fx.instHit;
smokeEffect = Fx.smokeCloud;
@@ -1713,7 +1730,7 @@ public class Blocks implements ContentList{
despawnEffect = Fx.instBomb;
trailSpacing = 20f;
damage = 1350;
- tileDamageMultiplier = 0.5f;
+ tileDamageMultiplier = 0.3f;
speed = brange;
hitShake = 6f;
ammoMultiplier = 1f;
@@ -1743,7 +1760,7 @@ public class Blocks implements ContentList{
}};
spectre = new ItemTurret("spectre"){{
- requirements(Category.turret, with(Items.copper, 900, Items.graphite, 300, Items.surgealloy, 250, Items.plastanium, 175, Items.thorium, 250));
+ requirements(Category.turret, with(Items.copper, 900, Items.graphite, 300, Items.surgeAlloy, 250, Items.plastanium, 175, Items.thorium, 250));
ammo(
Items.graphite, Bullets.standardDenseBig,
Items.pyratite, Bullets.standardIncendiaryBig,
@@ -1769,7 +1786,7 @@ public class Blocks implements ContentList{
}};
meltdown = new LaserTurret("meltdown"){{
- requirements(Category.turret, with(Items.copper, 1200, Items.lead, 350, Items.graphite, 300, Items.surgealloy, 325, Items.silicon, 325));
+ requirements(Category.turret, with(Items.copper, 1200, Items.lead, 350, Items.graphite, 300, Items.surgeAlloy, 325, Items.silicon, 325));
shootEffect = Fx.shootBigSmoke2;
shootCone = 40f;
recoilAmount = 4f;
@@ -1877,7 +1894,7 @@ public class Blocks implements ContentList{
}};
exponentialReconstructor = new Reconstructor("exponential-reconstructor"){{
- requirements(Category.units, with(Items.lead, 2000, Items.silicon, 1000, Items.titanium, 2000, Items.thorium, 750, Items.plastanium, 450, Items.phasefabric, 600));
+ requirements(Category.units, with(Items.lead, 2000, Items.silicon, 1000, Items.titanium, 2000, Items.thorium, 750, Items.plastanium, 450, Items.phaseFabric, 600));
size = 7;
consumes.power(13f);
@@ -1898,11 +1915,11 @@ public class Blocks implements ContentList{
}};
tetrativeReconstructor = new Reconstructor("tetrative-reconstructor"){{
- requirements(Category.units, with(Items.lead, 4000, Items.silicon, 3000, Items.thorium, 1000, Items.plastanium, 600, Items.phasefabric, 600, Items.surgealloy, 800));
+ requirements(Category.units, with(Items.lead, 4000, Items.silicon, 3000, Items.thorium, 1000, Items.plastanium, 600, Items.phaseFabric, 600, Items.surgeAlloy, 800));
size = 9;
consumes.power(25f);
- consumes.items(with(Items.silicon, 1000, Items.plastanium, 600, Items.surgealloy, 500, Items.phasefabric, 350));
+ consumes.items(with(Items.silicon, 1000, Items.plastanium, 600, Items.surgeAlloy, 500, Items.phaseFabric, 350));
consumes.liquid(Liquids.cryofluid, 3f);
constructTime = 60f * 60f * 4;
@@ -1912,7 +1929,7 @@ public class Blocks implements ContentList{
new UnitType[]{UnitTypes.antumbra, UnitTypes.eclipse},
new UnitType[]{UnitTypes.arkyid, UnitTypes.toxopid},
new UnitType[]{UnitTypes.scepter, UnitTypes.reign},
- new UnitType[] {UnitTypes.sei, UnitTypes.omura},
+ new UnitType[]{UnitTypes.sei, UnitTypes.omura},
new UnitType[]{UnitTypes.quad, UnitTypes.oct},
new UnitType[]{UnitTypes.vela, UnitTypes.corvus}
);
@@ -2035,7 +2052,7 @@ public class Blocks implements ContentList{
}};
hyperProcessor = new LogicBlock("hyper-processor"){{
- requirements(Category.logic, with(Items.lead, 450, Items.silicon, 150, Items.thorium, 75, Items.surgealloy, 50));
+ requirements(Category.logic, with(Items.lead, 450, Items.silicon, 150, Items.thorium, 75, Items.surgeAlloy, 50));
consumes.liquid(Liquids.cryofluid, 0.08f);
hasLiquids = true;
@@ -2054,7 +2071,7 @@ public class Blocks implements ContentList{
}};
memoryBank = new MemoryBlock("memory-bank"){{
- requirements(Category.logic, with(Items.graphite, 80, Items.silicon, 80, Items.phasefabric, 30));
+ requirements(Category.logic, with(Items.graphite, 80, Items.silicon, 80, Items.phaseFabric, 30));
memoryCapacity = 512;
size = 2;
@@ -2069,7 +2086,7 @@ public class Blocks implements ContentList{
}};
largeLogicDisplay = new LogicDisplay("large-logic-display"){{
- requirements(Category.logic, with(Items.lead, 200, Items.silicon, 150, Items.metaglass, 100, Items.phasefabric, 75));
+ requirements(Category.logic, with(Items.lead, 200, Items.silicon, 150, Items.metaglass, 100, Items.phaseFabric, 75));
displaySize = 176;
diff --git a/core/src/mindustry/content/Bullets.java b/core/src/mindustry/content/Bullets.java
index 221dc44e8d..e2d42c0ef0 100644
--- a/core/src/mindustry/content/Bullets.java
+++ b/core/src/mindustry/content/Bullets.java
@@ -510,7 +510,7 @@ public class Bullets implements ContentList{
speed = 4f;
knockback = 1.3f;
puddleSize = 8f;
- damage = 6f;
+ damage = 5f;
drag = 0.001f;
ammoMultiplier = 2f;
statusDuration = 60f * 4f;
diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java
index 6ca6ccb24d..5d0c45348d 100644
--- a/core/src/mindustry/content/Fx.java
+++ b/core/src/mindustry/content/Fx.java
@@ -56,7 +56,7 @@ public class Fx{
mixcol(Pal.accent, 1f);
alpha(e.fout());
- rect(block ? ((BlockUnitc)select).tile().block.icon(Cicon.full) : select.type().icon(Cicon.full), select.x, select.y, block ? 0f : select.rotation - 90f);
+ rect(block ? ((BlockUnitc)select).tile().block.icon(Cicon.full) : select.type.icon(Cicon.full), select.x, select.y, block ? 0f : select.rotation - 90f);
alpha(1f);
Lines.stroke(e.fslope() * 1f);
Lines.square(select.x, select.y, e.fout() * select.hitSize * 2f, 45);
@@ -66,7 +66,7 @@ public class Fx{
}),
unitDespawn = new Effect(100f, e -> {
- if(!(e.data instanceof Unit) || e.data().type() == null) return;
+ if(!(e.data instanceof Unit) || e.data().type == null) return;
Unit select = e.data();
float scl = e.fout(Interp.pow2Out);
@@ -74,7 +74,7 @@ public class Fx{
Draw.scl *= scl;
mixcol(Pal.accent, 1f);
- rect(select.type().icon(Cicon.full), select.x, select.y, select.rotation - 90f);
+ rect(select.type.icon(Cicon.full), select.x, select.y, select.rotation - 90f);
reset();
Draw.scl = p;
@@ -1293,6 +1293,14 @@ public class Fx{
});
}),
+ coreBurn = new Effect(23, e -> {
+ randLenVectors(e.id, 5, e.fin() * 9f, (x, y) -> {
+ float len = e.fout() * 4f;
+ color(Pal.accent, Color.gray, e.fin());
+ Fill.circle(e.x + x, e.y + y, len/2f);
+ });
+ }),
+
plasticburn = new Effect(40, e -> {
randLenVectors(e.id, 5, 3f + e.fin() * 5f, (x, y) -> {
color(Color.valueOf("e9ead3"), Color.gray, e.fin());
diff --git a/core/src/mindustry/content/Items.java b/core/src/mindustry/content/Items.java
index e16784a61b..6d3964fd2c 100644
--- a/core/src/mindustry/content/Items.java
+++ b/core/src/mindustry/content/Items.java
@@ -5,7 +5,7 @@ import mindustry.ctype.*;
import mindustry.type.*;
public class Items implements ContentList{
- public static Item scrap, copper, lead, graphite, coal, titanium, thorium, silicon, plastanium, phasefabric, surgealloy,
+ public static Item scrap, copper, lead, graphite, coal, titanium, thorium, silicon, plastanium, phaseFabric, surgeAlloy,
sporePod, sand, blastCompound, pyratite, metaglass;
@Override
@@ -66,12 +66,12 @@ public class Items implements ContentList{
cost = 1.3f;
}};
- phasefabric = new Item("phase-fabric", Color.valueOf("f4ba6e")){{
+ phaseFabric = new Item("phase-fabric", Color.valueOf("f4ba6e")){{
cost = 1.3f;
radioactivity = 0.6f;
}};
- surgealloy = new Item("surge-alloy", Color.valueOf("f3e979")){{
+ surgeAlloy = new Item("surge-alloy", Color.valueOf("f3e979")){{
}};
sporePod = new Item("spore-pod", Color.valueOf("7457ce")){{
diff --git a/core/src/mindustry/content/SectorPresets.java b/core/src/mindustry/content/SectorPresets.java
index ff1f36bc22..e516bab740 100644
--- a/core/src/mindustry/content/SectorPresets.java
+++ b/core/src/mindustry/content/SectorPresets.java
@@ -18,7 +18,7 @@ public class SectorPresets implements ContentList{
groundZero = new SectorPreset("groundZero", serpulo, 15){{
alwaysUnlocked = true;
captureWave = 10;
- difficulty = 0;
+ difficulty = 1;
}};
saltFlats = new SectorPreset("saltFlats", serpulo, 101){{
@@ -26,23 +26,23 @@ public class SectorPresets implements ContentList{
}};
frozenForest = new SectorPreset("frozenForest", serpulo, 86){{
- captureWave = 40;
- difficulty = 1;
+ captureWave = 20;
+ difficulty = 2;
}};
craters = new SectorPreset("craters", serpulo, 18){{
- captureWave = 40;
+ captureWave = 20;
difficulty = 2;
}};
ruinousShores = new SectorPreset("ruinousShores", serpulo, 19){{
- captureWave = 40;
+ captureWave = 30;
difficulty = 3;
}};
stainedMountains = new SectorPreset("stainedMountains", serpulo, 20){{
captureWave = 30;
- difficulty = 2;
+ difficulty = 3;
}};
fungalPass = new SectorPreset("fungalPass", serpulo, 21){{
@@ -54,7 +54,7 @@ public class SectorPresets implements ContentList{
}};
tarFields = new SectorPreset("tarFields", serpulo, 23){{
- captureWave = 40;
+ captureWave = 50;
difficulty = 5;
}};
diff --git a/core/src/mindustry/content/TechTree.java b/core/src/mindustry/content/TechTree.java
index e9aa178388..63eb9f2679 100644
--- a/core/src/mindustry/content/TechTree.java
+++ b/core/src/mindustry/content/TechTree.java
@@ -161,7 +161,7 @@ public class TechTree implements ContentList{
node(Items.plastanium, with(Items.titanium, 10000, Items.silicon, 10000), () -> {
node(plastaniumCompressor, () -> {
- node(Items.phasefabric, with(Items.thorium, 15000, Items.sand, 30000, Items.silicon, 5000), () -> {
+ node(Items.phaseFabric, with(Items.thorium, 15000, Items.sand, 30000, Items.silicon, 5000), () -> {
node(phaseWeaver, () -> {
});
@@ -177,7 +177,7 @@ public class TechTree implements ContentList{
node(Items.scrap, with(Items.copper, 20000, Items.sand, 10000), () -> {
node(Liquids.slag, with(Items.scrap, 4000), () -> {
node(melter, () -> {
- node(Items.surgealloy, with(Items.thorium, 20000, Items.silicon, 30000, Items.lead, 40000), () -> {
+ node(Items.surgeAlloy, with(Items.thorium, 20000, Items.silicon, 30000, Items.lead, 40000), () -> {
node(surgeSmelter, () -> {
});
@@ -605,8 +605,6 @@ public class TechTree implements ContentList{
public final ItemStack[] finishedRequirements;
/** Extra objectives needed to research this. */
public Seq objectives = new Seq<>();
- /** Time required to research this content, in seconds. */
- public float time;
/** Nodes that depend on this node. */
public final Seq children = new Seq<>();
@@ -617,7 +615,6 @@ public class TechTree implements ContentList{
this.content = content;
this.requirements = requirements;
this.depth = parent == null ? 0 : parent.depth + 1;
- this.time = Seq.with(requirements).mapFloat(i -> i.item.cost * i.amount).sum() * 10;
this.finishedRequirements = new ItemStack[requirements.length];
//load up the requirements that have been finished if settings are available
@@ -632,6 +629,14 @@ public class TechTree implements ContentList{
all.add(this);
}
+ /** Resets finished requirements and saves. */
+ public void reset(){
+ for(ItemStack stack : finishedRequirements){
+ stack.amount = 0;
+ }
+ save();
+ }
+
/** Removes this node from the tech tree. */
public void remove(){
all.remove(this);
diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java
index 9a1b851118..549a31769f 100644
--- a/core/src/mindustry/content/UnitTypes.java
+++ b/core/src/mindustry/content/UnitTypes.java
@@ -10,6 +10,7 @@ import mindustry.entities.bullet.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
+import mindustry.world.meta.*;
import static mindustry.Vars.*;
@@ -275,7 +276,7 @@ public class UnitTypes implements ContentList{
armor = 1f;
commandLimit = 8;
- abilities.add(new HealFieldAbility(10f, 60f * 4, 60f));
+ abilities.add(new RepairFieldAbility(10f, 60f * 4, 60f));
ammoType = AmmoTypes.power;
weapons.add(new Weapon("heal-weapon"){{
@@ -304,7 +305,7 @@ public class UnitTypes implements ContentList{
mineSpeed = 5f;
commandLimit = 8;
- abilities.add(new ShieldFieldAbility(20f, 40f, 60f * 5, 60f));
+ abilities.add(new ShieldRegenFieldAbility(20f, 40f, 60f * 5, 60f));
ammoType = AmmoTypes.power;
weapons.add(new Weapon("heal-shotgun-weapon"){{
@@ -872,7 +873,6 @@ public class UnitTypes implements ContentList{
drag = 0.01f;
flying = true;
health = 75;
- faceTarget = false;
engineOffset = 5.5f;
range = 140f;
@@ -898,6 +898,7 @@ public class UnitTypes implements ContentList{
range = 140f;
faceTarget = false;
armor = 4f;
+ targetFlag = BlockFlag.factory;
weapons.add(new Weapon(){{
minShootVelocity = 0.75f;
@@ -978,6 +979,7 @@ public class UnitTypes implements ContentList{
engineOffset = 21;
engineSize = 5.3f;
hitSize = 56f;
+ targetFlag = BlockFlag.battery;
BulletType missiles = new MissileBulletType(2.7f, 10){{
width = 8f;
@@ -1052,6 +1054,7 @@ public class UnitTypes implements ContentList{
hitSize = 58f;
destructibleWreck = false;
armor = 13f;
+ targetFlag = BlockFlag.reactor;
BulletType fragBullet = new FlakBulletType(4f, 5){{
shootEffect = Fx.shootBig;
@@ -1142,7 +1145,7 @@ public class UnitTypes implements ContentList{
flying = true;
drag = 0.05f;
- speed = 1.9f;
+ speed = 2.6f;
rotateSpeed = 15f;
accel = 0.1f;
range = 130f;
@@ -1151,14 +1154,13 @@ public class UnitTypes implements ContentList{
engineOffset = 6.5f;
hitSize = 8f;
lowAltitude = true;
- isCounted = false;
ammoType = AmmoTypes.power;
mineTier = 2;
mineSpeed = 3.5f;
- abilities.add(new HealFieldAbility(5f, 60f * 5, 50f));
+ abilities.add(new RepairFieldAbility(5f, 60f * 5, 50f));
weapons.add(new Weapon("heal-weapon-mount"){{
top = false;
@@ -1197,9 +1199,8 @@ public class UnitTypes implements ContentList{
mineTier = 3;
health = 500;
- armor = 2f;
armor = 5f;
- speed = 1.8f;
+ speed = 2.3f;
accel = 0.06f;
drag = 0.017f;
lowAltitude = true;
@@ -1233,7 +1234,7 @@ public class UnitTypes implements ContentList{
quad = new UnitType("quad"){{
armor = 8f;
health = 6000;
- speed = 1.2f;
+ speed = 1.4f;
rotateSpeed = 2f;
accel = 0.05f;
drag = 0.017f;
@@ -1247,6 +1248,7 @@ public class UnitTypes implements ContentList{
buildSpeed = 2.5f;
range = 140f;
targetAir = false;
+ targetFlag = BlockFlag.battery;
ammoType = AmmoTypes.powerHigh;
@@ -1297,7 +1299,7 @@ public class UnitTypes implements ContentList{
oct = new UnitType("oct"){{
armor = 16f;
health = 24000;
- speed = 0.6f;
+ speed = 0.8f;
rotateSpeed = 1f;
accel = 0.04f;
drag = 0.018f;
@@ -1315,7 +1317,7 @@ public class UnitTypes implements ContentList{
ammoCapacity = 1300;
ammoResupplyAmount = 20;
- abilities.add(new ForceFieldAbility(140f, 4f, 7000f, 60f * 8), new HealFieldAbility(130f, 60f * 2, 140f));
+ abilities.add(new ForceFieldAbility(140f, 4f, 7000f, 60f * 8), new RepairFieldAbility(130f, 60f * 2, 140f));
}};
//endregion
@@ -1427,7 +1429,7 @@ public class UnitTypes implements ContentList{
trailY = -9f;
trailScl = 1.5f;
- abilities.add(new ShieldFieldAbility(20f, 40f, 60f * 4, 60f));
+ abilities.add(new ShieldRegenFieldAbility(20f, 40f, 60f * 4, 60f));
weapons.add(new Weapon("large-artillery"){{
reload = 65f;
@@ -1449,13 +1451,13 @@ public class UnitTypes implements ContentList{
trailMult = 0.8f;
hitEffect = Fx.massiveExplosion;
knockback = 1.5f;
- lifetime = 140f;
+ lifetime = 100f;
height = 15.5f;
width = 15f;
collidesTiles = false;
ammoMultiplier = 4f;
splashDamageRadius = 60f;
- splashDamage = 85f;
+ splashDamage = 80f;
backColor = Pal.missileYellowBack;
frontColor = Pal.missileYellow;
trailEffect = Fx.artilleryTrail;
@@ -1651,11 +1653,11 @@ public class UnitTypes implements ContentList{
mineTier = 1;
buildSpeed = 0.5f;
drag = 0.05f;
- speed = 2.8f;
+ speed = 3f;
rotateSpeed = 15f;
accel = 0.1f;
itemCapacity = 30;
- health = 120f;
+ health = 150f;
engineOffset = 6f;
hitSize = 8f;
commandLimit = 3;
@@ -1666,13 +1668,13 @@ public class UnitTypes implements ContentList{
y = 1f;
top = false;
- bullet = new BasicBulletType(2.5f, 9){{
+ bullet = new BasicBulletType(2.5f, 10){{
width = 7f;
height = 9f;
lifetime = 60f;
shootEffect = Fx.shootSmall;
smokeEffect = Fx.shootSmallSmoke;
- tileDamageMultiplier = 0.09f;
+ tileDamageMultiplier = 0.03f;
}};
}});
}};
@@ -1686,11 +1688,11 @@ public class UnitTypes implements ContentList{
mineTier = 1;
buildSpeed = 0.75f;
drag = 0.05f;
- speed = 3f;
+ speed = 3.3f;
rotateSpeed = 17f;
accel = 0.1f;
itemCapacity = 50;
- health = 150f;
+ health = 170f;
engineOffset = 6f;
hitSize = 9f;
rotateShooting = false;
@@ -1707,13 +1709,13 @@ public class UnitTypes implements ContentList{
shotDelay = 4f;
spacing = 0f;
- bullet = new BasicBulletType(3f, 9){{
+ bullet = new BasicBulletType(3f, 10){{
width = 7f;
height = 9f;
lifetime = 60f;
shootEffect = Fx.shootSmall;
smokeEffect = Fx.shootSmallSmoke;
- tileDamageMultiplier = 0.1f;
+ tileDamageMultiplier = 0.03f;
}};
}});
}};
@@ -1727,11 +1729,11 @@ public class UnitTypes implements ContentList{
mineTier = 2;
buildSpeed = 1f;
drag = 0.05f;
- speed = 3.5f;
+ speed = 3.55f;
rotateSpeed = 19f;
accel = 0.11f;
itemCapacity = 70;
- health = 190f;
+ health = 220f;
engineOffset = 6f;
hitSize = 10f;
commandLimit = 7;
@@ -1746,13 +1748,13 @@ public class UnitTypes implements ContentList{
inaccuracy = 3f;
shotDelay = 3f;
- bullet = new BasicBulletType(3.5f, 9){{
+ bullet = new BasicBulletType(3.5f, 10){{
width = 6.5f;
height = 11f;
lifetime = 70f;
shootEffect = Fx.shootSmall;
smokeEffect = Fx.shootSmallSmoke;
- tileDamageMultiplier = 0.1f;
+ tileDamageMultiplier = 0.03f;
homingPower = 0.04f;
}};
}});
diff --git a/core/src/mindustry/content/Weathers.java b/core/src/mindustry/content/Weathers.java
index 273fdb5899..b120b7ef2b 100644
--- a/core/src/mindustry/content/Weathers.java
+++ b/core/src/mindustry/content/Weathers.java
@@ -1,339 +1,89 @@
package mindustry.content;
-import arc.*;
import arc.graphics.*;
-import arc.graphics.Texture.*;
-import arc.graphics.g2d.*;
-import arc.math.*;
import arc.util.*;
import mindustry.ctype.*;
-import mindustry.gen.*;
import mindustry.type.*;
-import mindustry.world.*;
+import mindustry.type.weather.*;
import mindustry.world.meta.*;
-import static mindustry.Vars.*;
-
public class Weathers implements ContentList{
public static Weather
rain,
snow,
sandstorm,
- sporestorm;
+ sporestorm,
+ fog;
@Override
public void load(){
- snow = new Weather("snow"){
- TextureRegion region;
- float yspeed = 2f, xspeed = 0.25f, padding = 16f, size = 12f, density = 1200f;
+ snow = new ParticleWeather("snow"){{
+ sizeMax = 13f;
+ sizeMin = 2.6f;
+ density = 1200f;
+ attrs.set(Attribute.light, -0.15f);
+ }};
- {
- attrs.set(Attribute.light, -0.15f);
- }
+ rain = new RainWeather("rain"){{
+ attrs.set(Attribute.light, -0.2f);
+ attrs.set(Attribute.water, 0.2f);
+ status = StatusEffects.wet;
+ }};
- @Override
- public void load(){
- super.load();
+ sandstorm = new ParticleWeather("sandstorm"){{
+ color = noiseColor = Color.valueOf("f7cba4");
+ drawNoise = true;
+ useWindVector = true;
+ sizeMax = 140f;
+ sizeMin = 70f;
+ minAlpha = 0f;
+ maxAlpha = 0.2f;
+ density = 1500f;
+ baseSpeed = 6.1f;
+ attrs.set(Attribute.light, -0.1f);
+ attrs.set(Attribute.water, -0.1f);
+ opacityMultiplier = 0.8f;
+ force = 0.1f;
+ }};
- region = Core.atlas.find("circle-shadow");
- }
+ sporestorm = new ParticleWeather("sporestorm"){{
+ color = noiseColor = Color.valueOf("7457ce");
+ particleRegion = "circle";
+ drawNoise = true;
+ statusGround = false;
+ useWindVector = true;
+ sizeMax = 5f;
+ sizeMin = 2.5f;
+ minAlpha = 0.1f;
+ maxAlpha = 0.8f;
+ density = 2000f;
+ baseSpeed = 4.3f;
+ attrs.set(Attribute.spores, 1f);
+ attrs.set(Attribute.light, -0.15f);
+ status = StatusEffects.sporeSlowed;
+ opacityMultiplier = 0.85f;
+ force = 0.1f;
+ }};
- @Override
- public void drawOver(WeatherState state){
- rand.setSeed(0);
- Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
- Tmp.r1.grow(padding);
- Core.camera.bounds(Tmp.r2);
- int total = (int)(Tmp.r1.area() / density * state.intensity());
-
- for(int i = 0; i < total; i++){
- float scl = rand.random(0.5f, 1f);
- float scl2 = rand.random(0.5f, 1f);
- float sscl = rand.random(0.2f, 1f);
- float x = (rand.random(0f, world.unitWidth()) + Time.time() * xspeed * scl2);
- float y = (rand.random(0f, world.unitHeight()) - Time.time() * yspeed * scl);
-
- x += Mathf.sin(y, rand.random(30f, 80f), rand.random(1f, 7f));
-
- x -= Tmp.r1.x;
- y -= Tmp.r1.y;
- x = Mathf.mod(x, Tmp.r1.width);
- y = Mathf.mod(y, Tmp.r1.height);
- x += Tmp.r1.x;
- y += Tmp.r1.y;
-
- if(Tmp.r3.setCentered(x, y, size * sscl).overlaps(Tmp.r2)){
- Draw.rect(region, x, y, size * sscl, size * sscl);
- }
- }
- }
- };
-
- rain = new Weather("rain"){
- float yspeed = 5f, xspeed = 1.5f, padding = 16f, size = 40f, density = 1200f;
- TextureRegion[] splashes = new TextureRegion[12];
-
- {
- attrs.set(Attribute.light, -0.2f);
- attrs.set(Attribute.water, 0.2f);
- status = StatusEffects.wet;
- }
-
- @Override
- public void load(){
- super.load();
-
- for(int i = 0; i < splashes.length; i++){
- splashes[i] = Core.atlas.find("splash-" + i);
- }
- }
-
- @Override
- public void drawOver(WeatherState state){
- Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
- Tmp.r1.grow(padding);
- Core.camera.bounds(Tmp.r2);
- int total = (int)(Tmp.r1.area() / density * state.intensity());
- Lines.stroke(0.75f);
- float alpha = Draw.getColor().a;
- Draw.color(Color.royal, Color.white, 0.3f);
-
- for(int i = 0; i < total; i++){
- float scl = rand.random(0.5f, 1f);
- float scl2 = rand.random(0.5f, 1f);
- float sscl = rand.random(0.2f, 1f);
- float x = (rand.random(0f, world.unitWidth()) + Time.time() * xspeed * scl2);
- float y = (rand.random(0f, world.unitHeight()) - Time.time() * yspeed * scl);
- float tint = rand.random(1f) * alpha;
-
- x -= Tmp.r1.x;
- y -= Tmp.r1.y;
- x = Mathf.mod(x, Tmp.r1.width);
- y = Mathf.mod(y, Tmp.r1.height);
- x += Tmp.r1.x;
- y += Tmp.r1.y;
-
- if(Tmp.r3.setCentered(x, y, size * sscl).overlaps(Tmp.r2)){
- Draw.alpha(tint);
- Lines.lineAngle(x, y, Angles.angle(xspeed * scl2, - yspeed * scl), size*sscl/2f);
- }
- }
- }
-
- @Override
- public void drawUnder(WeatherState state){
- Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
- Tmp.r1.grow(padding);
- Core.camera.bounds(Tmp.r2);
- int total = (int)(Tmp.r1.area() / density * state.intensity()) / 2;
- Lines.stroke(0.75f);
-
- float t = Time.time() / 22f;
-
- for(int i = 0; i < total; i++){
- float offset = rand.random(0f, 1f);
- float time = t + offset;
-
- int pos = (int)((time));
- float life = time % 1f;
- float x = (rand.random(0f, world.unitWidth()) + pos*953);
- float y = (rand.random(0f, world.unitHeight()) - pos*453);
-
- x -= Tmp.r1.x;
- y -= Tmp.r1.y;
- x = Mathf.mod(x, Tmp.r1.width);
- y = Mathf.mod(y, Tmp.r1.height);
- x += Tmp.r1.x;
- y += Tmp.r1.y;
-
- if(Tmp.r3.setCentered(x, y, life * 4f).overlaps(Tmp.r2)){
- Tile tile = world.tileWorld(x, y);
-
- if(tile != null && tile.floor().liquidDrop == Liquids.water){
- Draw.color(Tmp.c1.set(tile.floor().mapColor).mul(1.5f).a(state.opacity()));
- Draw.rect(splashes[(int)(life * (splashes.length - 1))], x, y);
- }else if(tile != null && tile.floor().liquidDrop == null && !tile.floor().solid){
- Draw.color(Color.royal, Color.white, 0.3f);
- Draw.alpha(Mathf.slope(life) * state.opacity());
-
- float space = 45f;
- for(int j : new int[]{-1, 1}){
- Tmp.v1.trns(90f + j*space, 1f + 5f * life);
- Lines.lineAngle(x + Tmp.v1.x, y + Tmp.v1.y, 90f + j*space, 3f * (1f - life));
- }
- }
- }
- }
- }
- };
-
- sandstorm = new Weather("sandstorm"){
- TextureRegion region;
- float size = 140f, padding = size, invDensity = 1500f, baseSpeed = 6.1f;
- float force = 0.4f * 0;
- Color color = Color.valueOf("f7cba4");
- Texture noise;
-
- {
- attrs.set(Attribute.light, -0.1f);
- opacityMultiplier = 0.8f;
- }
-
- @Override
- public void load(){
- region = Core.atlas.find("circle-shadow");
- noise = new Texture("sprites/noiseAlpha.png");
- noise.setWrap(TextureWrap.repeat);
- noise.setFilter(TextureFilter.linear);
- }
-
- @Override
- public void dispose(){
- noise.dispose();
- }
-
- @Override
- public void update(WeatherState state){
- float speed = force * state.intensity;
- float windx = state.windVector.x * speed, windy = state.windVector.y * speed;
-
- for(Unit unit : Groups.unit){
- unit.impulse(windx, windy);
- }
- }
-
- @Override
- public void drawOver(WeatherState state){
- Draw.tint(color);
- float speed = baseSpeed * state.intensity;
- float windx = state.windVector.x * speed, windy = state.windVector.y * speed;
-
- float scale = 1f / 2000f;
- float scroll = Time.time() * scale;
- Tmp.tr1.texture = noise;
- Core.camera.bounds(Tmp.r1);
- Tmp.tr1.set(Tmp.r1.x*scale, Tmp.r1.y*scale, (Tmp.r1.x + Tmp.r1.width)*scale, (Tmp.r1.y + Tmp.r1.height)*scale);
- Tmp.tr1.scroll(-windx * scroll, windy * scroll);
- Draw.rect(Tmp.tr1, Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height);
-
- rand.setSeed(0);
- Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
- Tmp.r1.grow(padding);
- Core.camera.bounds(Tmp.r2);
- int total = (int)(Tmp.r1.area() / invDensity * state.intensity());
- Draw.tint(color);
- float baseAlpha = Draw.getColor().a;
-
- for(int i = 0; i < total; i++){
- float scl = rand.random(0.5f, 1f);
- float scl2 = rand.random(0.5f, 1f);
- float sscl = rand.random(0.5f, 1f);
- float x = (rand.random(0f, world.unitWidth()) + Time.time() * windx * scl2);
- float y = (rand.random(0f, world.unitHeight()) + Time.time() * windy * scl);
- float alpha = rand.random(0.2f);
-
- x += Mathf.sin(y, rand.random(30f, 80f), rand.random(1f, 7f));
-
- x -= Tmp.r1.x;
- y -= Tmp.r1.y;
- x = Mathf.mod(x, Tmp.r1.width);
- y = Mathf.mod(y, Tmp.r1.height);
- x += Tmp.r1.x;
- y += Tmp.r1.y;
-
- if(Tmp.r3.setCentered(x, y, size * sscl).overlaps(Tmp.r2)){
- Draw.alpha(alpha * baseAlpha);
- Draw.rect(region, x, y, size * sscl, size * sscl);
- }
- }
- }
- };
-
- sporestorm = new Weather("sporestorm"){
- TextureRegion region;
- float size = 5f, padding = size, invDensity = 2000f, baseSpeed = 4.3f, force = 0.28f * 0;
- Color color = Color.valueOf("7457ce");
- Texture noise;
-
- {
- attrs.set(Attribute.spores, 1f);
- attrs.set(Attribute.light, -0.15f);
- status = StatusEffects.sporeSlowed;
- statusGround = false;
- opacityMultiplier = 0.85f;
- }
-
- @Override
- public void load(){
- region = Core.atlas.find("circle-shadow");
- noise = new Texture("sprites/noiseAlpha.png");
- noise.setWrap(TextureWrap.repeat);
- noise.setFilter(TextureFilter.linear);
- }
-
- @Override
- public void update(WeatherState state){
- float speed = force * state.intensity;
- float windx = state.windVector.x * speed, windy = state.windVector.y * speed;
-
- for(Unit unit : Groups.unit){
- unit.impulse(windx, windy);
- }
- }
-
- @Override
- public void dispose(){
- noise.dispose();
- }
-
- @Override
- public void drawOver(WeatherState state){
- Draw.alpha(state.opacity * 0.8f);
- Draw.tint(color);
-
- float speed = baseSpeed * state.intensity;
- float windx = state.windVector.x * speed, windy = state.windVector.y * speed;
-
- float scale = 1f / 2000f;
- float scroll = Time.time() * scale;
- Tmp.tr1.texture = noise;
- Core.camera.bounds(Tmp.r1);
- Tmp.tr1.set(Tmp.r1.x*scale, Tmp.r1.y*scale, (Tmp.r1.x + Tmp.r1.width)*scale, (Tmp.r1.y + Tmp.r1.height)*scale);
- Tmp.tr1.scroll(-windx * scroll, windy * scroll);
- Draw.rect(Tmp.tr1, Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height);
-
- rand.setSeed(0);
- Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
- Tmp.r1.grow(padding);
- Core.camera.bounds(Tmp.r2);
- int total = (int)(Tmp.r1.area() / invDensity * state.intensity());
- Draw.tint(color);
- float baseAlpha = state.opacity;
- Draw.alpha(baseAlpha);
-
- for(int i = 0; i < total; i++){
- float scl = rand.random(0.5f, 1f);
- float scl2 = rand.random(0.5f, 1f);
- float sscl = rand.random(0.5f, 1f);
- float x = (rand.random(0f, world.unitWidth()) + Time.time() * windx * scl2);
- float y = (rand.random(0f, world.unitHeight()) + Time.time() * windy * scl);
- float alpha = rand.random(0.1f, 0.8f);
-
- x += Mathf.sin(y, rand.random(30f, 80f), rand.random(1f, 7f));
-
- x -= Tmp.r1.x;
- y -= Tmp.r1.y;
- x = Mathf.mod(x, Tmp.r1.width);
- y = Mathf.mod(y, Tmp.r1.height);
- x += Tmp.r1.x;
- y += Tmp.r1.y;
-
- if(Tmp.r3.setCentered(x, y, size * sscl).overlaps(Tmp.r2)){
- Draw.alpha(alpha * baseAlpha);
- Fill.circle(x, y, size * sscl / 2f);
- }
- }
- }
- };
+ fog = new ParticleWeather("fog"){{
+ duration = 15f * Time.toMinutes;
+ noiseLayers = 3;
+ noiseLayerSclM = 0.8f;
+ noiseLayerAlphaM = 0.7f;
+ noiseLayerSpeedM = 2f;
+ noiseLayerSclM = 0.6f;
+ baseSpeed = 0.05f;
+ color = noiseColor = Color.grays(0.4f);
+ noiseScale = 1100f;
+ noisePath = "fog";
+ drawParticles = false;
+ drawNoise = true;
+ useWindVector = false;
+ xspeed = 1f;
+ yspeed = 0.01f;
+ attrs.set(Attribute.light, -0.3f);
+ attrs.set(Attribute.water, 0.05f);
+ opacityMultiplier = 0.47f;
+ }};
}
}
diff --git a/core/src/mindustry/core/Control.java b/core/src/mindustry/core/Control.java
index efe2327074..3d904c1826 100644
--- a/core/src/mindustry/core/Control.java
+++ b/core/src/mindustry/core/Control.java
@@ -9,7 +9,6 @@ import arc.math.*;
import arc.scene.ui.*;
import arc.struct.*;
import arc.util.*;
-import mindustry.*;
import mindustry.audio.*;
import mindustry.content.*;
import mindustry.core.GameState.*;
@@ -25,7 +24,6 @@ import mindustry.maps.Map;
import mindustry.type.*;
import mindustry.ui.dialogs.*;
import mindustry.world.*;
-import mindustry.world.blocks.storage.CoreBlock.*;
import java.io.*;
import java.text.*;
@@ -37,7 +35,7 @@ import static mindustry.Vars.*;
/**
* Control module.
- * Handles all input, saving, keybinds and keybinds.
+ * Handles all input, saving and keybinds.
* Should not handle any logic-critical state.
* This class is not created in the headless server.
*/
@@ -160,9 +158,7 @@ public class Control implements ApplicationListener, Loadable{
//delete the save, it is gone.
if(saves.getCurrent() != null && !state.rules.tutorial){
- Sector sector = state.getSector();
- sector.save = null;
- saves.getCurrent().delete();
+ saves.getCurrent().save();
}
}
});
@@ -252,19 +248,6 @@ public class Control implements ApplicationListener, Loadable{
});
}
- //TODO move
- public void handleLaunch(CoreBuild tile){
- LaunchCorec ent = LaunchCore.create();
- ent.set(tile);
- ent.block(Blocks.coreShard);
- ent.lifetime(Vars.launchDuration);
- ent.add();
-
- //remove schematic requirements from core
- tile.items.remove(universe.getLastLoadout().requirements());
- tile.items.remove(universe.getLaunchResources());
- }
-
public void playSector(Sector sector){
playSector(sector, sector);
}
@@ -281,21 +264,29 @@ public class Control implements ApplicationListener, Loadable{
slot.load();
slot.setAutosave(true);
state.rules.sector = sector;
+ state.secinfo = state.rules.sector.info;
//if there is no base, simulate a new game and place the right loadout at the spawn position
- //TODO this is broken?
if(state.rules.defaultTeam.cores().isEmpty()){
- //kill all friendly units, since they should be dead anwyay
- for(Unit unit : Groups.unit){
- if(unit.team() == state.rules.defaultTeam){
- unit.remove();
- }
+ //no spawn set -> delete the sector save
+ if(sector.info.spawnPosition == 0){
+ //delete old save
+ sector.save = null;
+ slot.delete();
+ //play again
+ playSector(origin, sector);
+ return;
}
- Tile spawn = world.tile(sector.getSpawnPosition());
- //TODO PLACE CORRECT LOADOUT
- Schematics.placeLoadout(universe.getLastLoadout(), spawn.x, spawn.y);
+ //reset wave so things are more fair
+ state.wave = 1;
+
+ //kill all units, since they should be dead anwyay
+ Groups.unit.clear();
+
+ Tile spawn = world.tile(sector.info.spawnPosition);
+ Schematics.placeLaunchLoadout(spawn.x, spawn.y);
//set up camera/player locations
player.set(spawn.x * tilesize, spawn.y * tilesize);
@@ -317,7 +308,6 @@ public class Control implements ApplicationListener, Loadable{
}else{
net.reset();
logic.reset();
- sector.setSecondsPassed(0);
world.loadSector(sector);
state.rules.sector = sector;
//assign origin when launching
diff --git a/core/src/mindustry/core/GameState.java b/core/src/mindustry/core/GameState.java
index 949e40d02d..41f14074c8 100644
--- a/core/src/mindustry/core/GameState.java
+++ b/core/src/mindustry/core/GameState.java
@@ -23,7 +23,7 @@ public class GameState{
/** The current game rules. */
public Rules rules = new Rules();
/** Statistics for this save/game. Displayed after game over. */
- public Stats stats = new Stats();
+ public GameStats stats = new GameStats();
/** Global attributes of the environment, calculated by weather. */
public Attributes envAttrs = new Attributes();
/** Sector information. Only valid in the campaign. */
@@ -41,10 +41,17 @@ public class GameState{
}
public void set(State astate){
+ //cannot pause when in multiplayer
+ if(astate == State.paused && net.active()) return;
+
Events.fire(new StateChangeEvent(state, astate));
state = astate;
}
+ public boolean hasSpawns(){
+ return rules.waves && !(isCampaign() && rules.attackMode);
+ }
+
/** Note that being in a campaign does not necessarily mean having a sector. */
public boolean isCampaign(){
return rules.sector != null;
@@ -68,7 +75,7 @@ public class GameState{
}
public boolean isPlaying(){
- return state == State.playing;
+ return (state == State.playing) || (state == State.paused && !isPaused());
}
/** @return whether the current state is *not* the menu. */
diff --git a/core/src/mindustry/core/Logic.java b/core/src/mindustry/core/Logic.java
index df536552df..b8d736126b 100644
--- a/core/src/mindustry/core/Logic.java
+++ b/core/src/mindustry/core/Logic.java
@@ -5,16 +5,15 @@ import arc.math.*;
import arc.util.*;
import mindustry.annotations.Annotations.*;
import mindustry.core.GameState.*;
+import mindustry.ctype.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.game.Teams.*;
import mindustry.gen.*;
+import mindustry.maps.*;
import mindustry.type.*;
import mindustry.type.Weather.*;
import mindustry.world.*;
-import mindustry.world.blocks.*;
-import mindustry.world.blocks.ConstructBlock.*;
-import mindustry.world.blocks.storage.CoreBlock.*;
import java.util.*;
@@ -39,32 +38,7 @@ public class Logic implements ApplicationListener{
//skip null entities or un-rebuildables, for obvious reasons; also skip client since they can't modify these requests
if(tile.build == null || !tile.block().rebuildable || net.client()) return;
- if(block instanceof ConstructBlock){
-
- ConstructBuild entity = tile.bc();
-
- //update block to reflect the fact that something was being constructed
- if(entity.cblock != null && entity.cblock.synthetic()){
- block = entity.cblock;
- }else{
- //otherwise this was a deconstruction that was interrupted, don't want to rebuild that
- return;
- }
- }
-
- TeamData data = state.teams.get(tile.team());
-
- //remove existing blocks that have been placed here.
- //painful O(n) iteration + copy
- for(int i = 0; i < data.blocks.size; i++){
- BlockPlan b = data.blocks.get(i);
- if(b.x == tile.x && b.y == tile.y){
- data.blocks.removeIndex(i);
- break;
- }
- }
-
- data.blocks.addFirst(new BlockPlan(tile.x, tile.y, (short)tile.build.rotation, block.id, tile.build.config()));
+ tile.build.addPlan(true);
});
Events.on(BlockBuildEndEvent.class, event -> {
@@ -84,51 +58,61 @@ public class Logic implements ApplicationListener{
Events.on(LaunchItemEvent.class, e -> state.secinfo.handleItemExport(e.stack));
//when loading a 'damaged' sector, propagate the damage
- Events.on(WorldLoadEvent.class, e -> {
+ Events.on(SaveLoadEvent.class, e -> {
if(state.isCampaign()){
- long seconds = state.rules.sector.getSecondsPassed();
- CoreBuild core = state.rules.defaultTeam.core();
- //THE WAVES NEVER END
- state.rules.waves = true;
+ state.secinfo.write();
- //apply fractional damage based on how many turns have passed for this sector
- //float turnsPassed = seconds / (turnDuration / 60f);
+ //how much wave time has passed
+ int wavesPassed = state.secinfo.wavesPassed;
- //TODO sector damage disabled for now
- //if(state.rules.sector.hasWaves() && turnsPassed > 0 && state.rules.sector.hasBase()){
- // SectorDamage.apply(turnsPassed / sectorDestructionTurns);
- //}
-
- //add resources based on turns passed
- if(state.rules.sector.save != null && core != null){
- //update correct storage capacity
- state.rules.sector.save.meta.secinfo.storageCapacity = core.storageCapacity;
-
- //add new items received
- state.rules.sector.calculateReceivedItems().each((item, amount) -> core.items.add(item, amount));
-
- //clear received items
- state.rules.sector.setExtraItems(new ItemSeq());
-
- //validation
- for(Item item : content.items()){
- //ensure positive items
- if(core.items.get(item) < 0) core.items.set(item, 0);
- //cap the items
- if(core.items.get(item) > core.storageCapacity) core.items.set(item, core.storageCapacity);
- }
+ //wave has passed, remove all enemies, they are assumed to be dead
+ if(wavesPassed > 0){
+ Groups.unit.each(u -> {
+ if(u.team == state.rules.waveTeam){
+ u.remove();
+ }
+ });
}
- state.rules.sector.setSecondsPassed(0);
- }
+ //simulate passing of waves
+ if(wavesPassed > 0){
+ //simulate wave counter moving forward
+ state.wave += wavesPassed;
+ state.wavetime = state.rules.waveSpacing;
+ SectorDamage.applyCalculatedDamage();
+ }
+
+ //reset values
+ state.secinfo.damage = 0f;
+ state.secinfo.wavesPassed = 0;
+ state.secinfo.hasCore = true;
+ state.secinfo.secondsPassed = 0;
+
+ state.rules.sector.saveInfo();
+ }
+ });
+
+ Events.on(WorldLoadEvent.class, e -> {
//enable infinite ammo for wave team by default
state.rules.waveTeam.rules().infiniteAmmo = true;
+ if(state.isCampaign()){
+ //enable building AI
+ state.rules.waveTeam.rules().ai = true;
+ state.rules.waveTeam.rules().infiniteResources = true;
+ }
//save settings
Core.settings.manualSave();
});
+ //sync research
+ Events.on(ResearchEvent.class, e -> {
+ if(net.server()){
+ Call.researched(e.content);
+ }
+ });
+
}
/** Adds starting items, resets wave time, and sets state to playing. */
@@ -168,11 +152,6 @@ public class Logic implements ApplicationListener{
}
public void skipWave(){
- if(state.isCampaign()){
- //warp time spent forward because the wave was just skipped.
- state.secinfo.internalTimeSpent += state.wavetime;
- }
-
state.wavetime = 0;
}
@@ -199,12 +178,13 @@ public class Logic implements ApplicationListener{
state.rules.waves = false;
}
- //TODO capturing is disabled
- /*
//if there's a "win" wave and no enemies are present, win automatically
- if(state.rules.waves && state.enemies == 0 && state.rules.winWave > 0 && state.wave >= state.rules.winWave && !spawner.isSpawning()){
+ if(state.rules.waves && (state.enemies == 0 && state.rules.winWave > 0 && state.wave >= state.rules.winWave && !spawner.isSpawning()) ||
+ (state.rules.attackMode && state.rules.waveTeam.cores().isEmpty())){
//the sector has been conquered - waves get disabled
state.rules.waves = false;
+ //disable attack mode
+ state.rules.attackMode = false;
//fire capture event
Events.fire(new SectorCaptureEvent(state.rules.sector));
@@ -213,25 +193,19 @@ public class Logic implements ApplicationListener{
if(!headless){
control.saves.saveSector(state.rules.sector);
}
- }*/
+ }
}else{
if(!state.rules.attackMode && state.teams.playerCores().size == 0 && !state.gameOver){
state.gameOver = true;
Events.fire(new GameOverEvent(state.rules.waveTeam));
}else if(state.rules.attackMode){
- Team alive = null;
+ //count # of teams alive
+ int countAlive = state.teams.getActive().count(TeamData::hasCore);
- for(TeamData team : state.teams.getActive()){
- if(team.hasCore()){
- if(alive != null){
- return;
- }
- alive = team.team;
- }
- }
-
- if(alive != null && !state.gameOver){
- Events.fire(new GameOverEvent(alive));
+ if((countAlive <= 1 || (!state.rules.pvp && state.rules.defaultTeam.core() == null)) && !state.gameOver){
+ //find team that won
+ TeamData left = state.teams.getActive().find(TeamData::hasCore);
+ Events.fire(new GameOverEvent(left == null ? Team.derelict : left.team));
state.gameOver = true;
}
}
@@ -266,6 +240,15 @@ public class Logic implements ApplicationListener{
netClient.setQuiet();
}
+ //called when the remote server researches something
+ @Remote
+ public static void researched(Content content){
+ if(!(content instanceof UnlockableContent u)) return;
+
+ state.rules.researched.add(u.name);
+ ui.hudfrag.showUnlock(u);
+ }
+
@Override
public void dispose(){
//save the settings before quitting
@@ -283,7 +266,7 @@ public class Logic implements ApplicationListener{
if(state.isGame()){
if(!net.client()){
- state.enemies = Groups.unit.count(u -> u.team() == state.rules.waveTeam && u.type().isCounted);
+ state.enemies = Groups.unit.count(u -> u.team() == state.rules.waveTeam && u.type.isCounted);
}
if(!state.isPaused()){
diff --git a/core/src/mindustry/core/NetClient.java b/core/src/mindustry/core/NetClient.java
index ae8c7d9a7c..3c6214fd85 100644
--- a/core/src/mindustry/core/NetClient.java
+++ b/core/src/mindustry/core/NetClient.java
@@ -194,14 +194,14 @@ public class NetClient implements ApplicationListener{
}
//server console logging
- Log.info("&y@: &lb@", player.name, message);
+ Log.info("&fi@: @", "&lc" + player.name, "&lw" + message);
//invoke event for all clients but also locally
//this is required so other clients get the correct name even if they don't know who's sending it yet
Call.sendMessage(message, colorizeName(player.id(), player.name), player);
}else{
//log command to console but with brackets
- Log.info("<&y@: &lm@&lg>", player.name, message);
+ Log.info("<&fi@: @&fr>", "&lk" + player.name, "&lw" + message);
//a command was sent, now get the output
if(response.type != ResponseType.valid){
diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java
index 77ab732cf6..00f0bc78e8 100644
--- a/core/src/mindustry/core/NetServer.java
+++ b/core/src/mindustry/core/NetServer.java
@@ -18,6 +18,7 @@ import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.game.Teams.*;
import mindustry.gen.*;
+import mindustry.graphics.*;
import mindustry.net.*;
import mindustry.net.Administration.*;
import mindustry.net.Packets.*;
@@ -299,6 +300,15 @@ public class NetServer implements ApplicationListener{
}
});
+ clientCommands.register("a", "", "Send a message only to admins.", (args, player) -> {
+ if(!player.admin){
+ player.sendMessage("[scarlet]You must be admin to use this command.");
+ return;
+ }
+
+ Groups.player.each(Player::admin, a -> a.sendMessage(args[0], player, "[#" + Pal.adminChat.toString() + "]" + NetClient.colorizeName(player.id, player.name)));
+ });
+
//duration of a a kick in seconds
int kickDuration = 60 * 60;
//voting round duration in seconds
@@ -508,7 +518,8 @@ public class NetServer implements ApplicationListener{
Call.playerDisconnect(player.id());
}
- if(Config.showConnectMessages.bool()) Log.info("&lm[@] &lc@ has disconnected. &lg&fi(@)", player.uuid(), player.name, reason);
+ String message = Strings.format("&lb@&fi&lk has disconnected. &fi&lk[&lb@&fi&lk] (@)", player.name, player.uuid(), reason);
+ if(Config.showConnectMessages.bool()) Log.info(message);
}
player.remove();
@@ -575,7 +586,7 @@ public class NetServer implements ApplicationListener{
shooting = false;
}
- if(!player.dead() && (player.unit().type().flying || !player.unit().type().canBoost)){
+ if(!player.dead() && (player.unit().type.flying || !player.unit().type.canBoost)){
boosting = false;
}
@@ -629,7 +640,7 @@ public class NetServer implements ApplicationListener{
Unit unit = player.unit();
long elapsed = Time.timeSinceMillis(con.lastReceivedClientTime);
- float maxSpeed = ((player.unit().type().canBoost && player.unit().isFlying()) ? player.unit().type().boostMultiplier : 1f) * player.unit().type().speed;
+ float maxSpeed = ((player.unit().type.canBoost && player.unit().isFlying()) ? player.unit().type.boostMultiplier : 1f) * player.unit().type.speed;
if(unit.isGrounded()){
maxSpeed *= unit.floorSpeedMultiplier();
}
@@ -736,7 +747,8 @@ public class NetServer implements ApplicationListener{
if(Config.showConnectMessages.bool()){
Call.sendMessage("[accent]" + player.name + "[accent] has connected.");
- Log.info("&lm[@] &y@ has connected.", player.uuid(), player.name);
+ String message = Strings.format("&lb@&fi&lk has connected. &fi&lk[&lb@&fi&lk]", player.name, player.uuid());
+ Log.info(message);
}
if(!Config.motd.string().equalsIgnoreCase("off")){
@@ -785,7 +797,7 @@ public class NetServer implements ApplicationListener{
public void openServer(){
try{
net.host(Config.port.num());
- info("&lcOpened a server on port @.", Config.port.num());
+ info("Opened a server on port @.", Config.port.num());
}catch(BindException e){
Log.err("Unable to host: Port already in use! Make sure no other servers are running on the same port in your network.");
state.set(State.menu);
diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java
index 03a18c01ed..60beec266b 100644
--- a/core/src/mindustry/core/World.java
+++ b/core/src/mindustry/core/World.java
@@ -148,7 +148,17 @@ public class World{
return build(Math.round(x / tilesize), Math.round(y / tilesize));
}
- public int toTile(float coord){
+ /** Convert from world to logic tile coordinates. Whole numbers are at centers of tiles. */
+ public static float conv(float coord){
+ return coord / tilesize;
+ }
+
+ /** Convert from tile to world coordinates. */
+ public static float unconv(float coord){
+ return coord * tilesize;
+ }
+
+ public static int toTile(float coord){
return Math.round(coord / tilesize);
}
@@ -253,7 +263,7 @@ public class World{
setSectorRules(sector);
if(state.rules.defaultTeam.core() != null){
- sector.setSpawnPosition(state.rules.defaultTeam.core().pos());
+ sector.info.spawnPosition = state.rules.defaultTeam.core().pos();
}
}
@@ -267,8 +277,6 @@ public class World{
ObjectIntMap floorc = new ObjectIntMap<>();
ObjectSet content = new ObjectSet<>();
- float waterFloors = 0, totalFloors = 0;
-
for(Tile tile : world.tiles){
if(world.getDarkness(tile.x, tile.y) >= 3){
continue;
@@ -280,10 +288,6 @@ public class World{
if(liquid != null) content.add(liquid);
if(!tile.block().isStatic()){
- totalFloors ++;
- if(liquid == Liquids.water){
- waterFloors += tile.floor().isDeep() ? 1f : 0.7f;
- }
floorc.increment(tile.floor());
if(tile.overlay() != Blocks.air){
floorc.increment(tile.overlay());
@@ -306,7 +310,7 @@ public class World{
//TODO bad code
boolean hasSnow = floors[0].name.contains("ice") || floors[0].name.contains("snow");
- boolean hasRain = !hasSnow && floors[0].name.contains("water");
+ boolean hasRain = !hasSnow && content.contains(Liquids.water) && !floors[0].name.contains("sand");
boolean hasDesert = !hasSnow && !hasRain && floors[0].name.contains("sand");
boolean hasSpores = floors[0].name.contains("spore") || floors[0].name.contains("moss") || floors[0].name.contains("tainted");
@@ -316,6 +320,7 @@ public class World{
if(hasRain){
state.rules.weather.add(new WeatherEntry(Weathers.rain));
+ state.rules.weather.add(new WeatherEntry(Weathers.fog));
}
if(hasDesert){
@@ -326,9 +331,9 @@ public class World{
state.rules.weather.add(new WeatherEntry(Weathers.sporestorm));
}
- state.secinfo.resources = content.asArray();
- state.secinfo.resources.sort(Structs.comps(Structs.comparing(Content::getContentType), Structs.comparingInt(c -> c.id)));
-
+ sector.info.resources = content.asArray();
+ sector.info.resources.sort(Structs.comps(Structs.comparing(Content::getContentType), Structs.comparingInt(c -> c.id)));
+ sector.saveInfo();
}
public Context filterContext(Map map){
diff --git a/core/src/mindustry/ctype/UnlockableContent.java b/core/src/mindustry/ctype/UnlockableContent.java
index f6e6d0a2dc..cd2b6a21d5 100644
--- a/core/src/mindustry/ctype/UnlockableContent.java
+++ b/core/src/mindustry/ctype/UnlockableContent.java
@@ -10,11 +10,14 @@ import mindustry.game.EventType.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.ui.*;
+import mindustry.world.meta.*;
import static mindustry.Vars.*;
/** Base interface for an unlockable content type. */
public abstract class UnlockableContent extends MappableContent{
+ /** Stat storage for this content. Initialized on demand. */
+ public Stats stats = new Stats();
/** Localized, formal name. Never null. Set to internal name if not found in bundle. */
public String localizedName;
/** Localized description. May be null. */
@@ -38,6 +41,18 @@ public abstract class UnlockableContent extends MappableContent{
return minfo.mod == null ? description : description + "\n" + Core.bundle.format("mod.display", minfo.mod.meta.displayName());
}
+ /** Checks stat initialization state. Call before displaying stats. */
+ public void checkStats(){
+ if(!stats.intialized){
+ setStats();
+ stats.intialized = true;
+ }
+ }
+
+ /** Intializes stats on demand. Should only be called once. Only called before something is displayed. */
+ public void setStats(){
+ }
+
/** Generate any special icons for this content. Called asynchronously.*/
@CallSuper
public void createIcons(MultiPacker packer){
@@ -59,9 +74,11 @@ public abstract class UnlockableContent extends MappableContent{
cicons[icon.ordinal()] =
Core.atlas.find(getContentType().name() + "-" + name + "-" + icon.name(),
Core.atlas.find(getContentType().name() + "-" + name + "-full",
+ Core.atlas.find(name + "-" + icon.name(),
+ Core.atlas.find(name + "-full",
Core.atlas.find(name,
Core.atlas.find(getContentType().name() + "-" + name,
- Core.atlas.find(name + "1")))));
+ Core.atlas.find(name + "1")))))));
}
return cicons[icon.ordinal()];
}
@@ -73,7 +90,9 @@ public abstract class UnlockableContent extends MappableContent{
}
/** This should show all necessary info about this content in the specified table. */
- public abstract void displayInfo(Table table);
+ public void display(Table table){
+
+ }
/** Called when this content is unlocked. Use this to unlock other related content. */
public void onUnlock(){
@@ -95,16 +114,33 @@ public abstract class UnlockableContent extends MappableContent{
}
}
- public final boolean unlocked(){
+ /** Unlocks this content, but does not fire any events. */
+ public void quietUnlock(){
+ if(!unlocked()){
+ unlocked = true;
+ Core.settings.put(name + "-unlocked", true);
+ }
+ }
+
+ public boolean unlocked(){
+ if(net.client()) return state.rules.researched.contains(name);
return unlocked || alwaysUnlocked;
}
- /** @return whether this content is unlocked, or the player is in a custom (non-campaign) game. */
- public final boolean unlockedNow(){
- return unlocked || alwaysUnlocked || !state.isCampaign();
+ /** Locks this content again. */
+ public void clearUnlock(){
+ if(unlocked){
+ unlocked = false;
+ Core.settings.put(name + "-unlocked", false);
+ }
}
- public final boolean locked(){
+ /** @return whether this content is unlocked, or the player is in a custom (non-campaign) game. */
+ public boolean unlockedNow(){
+ return unlocked() || !state.isCampaign();
+ }
+
+ public boolean locked(){
return !unlocked();
}
}
diff --git a/core/src/mindustry/editor/EditorTile.java b/core/src/mindustry/editor/EditorTile.java
index 5ff533325d..f735bd790c 100644
--- a/core/src/mindustry/editor/EditorTile.java
+++ b/core/src/mindustry/editor/EditorTile.java
@@ -26,7 +26,7 @@ public class EditorTile extends Tile{
if(type instanceof OverlayFloor){
//don't place on liquids
- if(floor.hasSurface()){
+ if(floor.hasSurface() || !type.needsSurface){
setOverlayID(type.id);
}
return;
@@ -75,7 +75,7 @@ public class EditorTile extends Tile{
return;
}
- if(floor.isLiquid) return;
+ if(!floor.hasSurface() && overlay.asFloor().needsSurface) return;
if(overlay() == overlay) return;
op(OpType.overlay, this.overlay.id);
super.setOverlay(overlay);
@@ -105,9 +105,9 @@ public class EditorTile extends Tile{
}
@Override
- protected void changeEntity(Team team, Prov entityprov, int rotation){
+ protected void changeBuild(Team team, Prov entityprov, int rotation){
if(skip()){
- super.changeEntity(team, entityprov, rotation);
+ super.changeBuild(team, entityprov, rotation);
return;
}
diff --git a/core/src/mindustry/editor/EditorTool.java b/core/src/mindustry/editor/EditorTool.java
index 194ec97e4c..cd4b63935e 100644
--- a/core/src/mindustry/editor/EditorTool.java
+++ b/core/src/mindustry/editor/EditorTool.java
@@ -118,7 +118,7 @@ public enum EditorTool{
if(editor.drawBlock.isOverlay()){
Block dest = tile.overlay();
if(dest == editor.drawBlock) return;
- tester = t -> t.overlay() == dest && t.floor().hasSurface();
+ tester = t -> t.overlay() == dest && (t.floor().hasSurface() || !t.floor().needsSurface);
setter = t -> t.setOverlay(editor.drawBlock);
}else if(editor.drawBlock.isFloor()){
Block dest = tile.floor();
diff --git a/core/src/mindustry/editor/MapEditor.java b/core/src/mindustry/editor/MapEditor.java
index 49d174779b..1c33964e08 100644
--- a/core/src/mindustry/editor/MapEditor.java
+++ b/core/src/mindustry/editor/MapEditor.java
@@ -4,6 +4,7 @@ import arc.files.*;
import arc.func.*;
import arc.graphics.*;
import arc.math.*;
+import arc.math.geom.*;
import arc.struct.*;
import mindustry.content.*;
import mindustry.editor.DrawOperation.*;
@@ -180,6 +181,52 @@ public class MapEditor{
return false;
}
+ public void addCliffs(){
+ for(Tile tile : world.tiles){
+ if(!tile.block().isStatic() || tile.block() == Blocks.cliff) continue;
+
+ int rotation = 0;
+ for(int i = 0; i < 8; i++){
+ Tile other = world.tiles.get(tile.x + Geometry.d8[i].x, tile.y + Geometry.d8[i].y);
+ if(other != null && !other.block().isStatic()){
+ rotation |= (1 << i);
+ }
+ }
+
+ if(rotation != 0){
+ tile.setBlock(Blocks.cliff);
+ }
+
+ tile.data = (byte)rotation;
+ }
+
+ for(Tile tile : world.tiles){
+ if(tile.block() != Blocks.cliff && tile.block().isStatic()){
+ tile.setBlock(Blocks.air);
+ }
+ }
+ }
+
+ public void addFloorCliffs(){
+ for(Tile tile : world.tiles){
+ if(!tile.floor().hasSurface() || tile.block() == Blocks.cliff) continue;
+
+ int rotation = 0;
+ for(int i = 0; i < 8; i++){
+ Tile other = world.tiles.get(tile.x + Geometry.d8[i].x, tile.y + Geometry.d8[i].y);
+ if(other != null && !other.floor().hasSurface()){
+ rotation |= (1 << i);
+ }
+ }
+
+ if(rotation != 0){
+ tile.setBlock(Blocks.cliff);
+ }
+
+ tile.data = (byte)rotation;
+ }
+ }
+
public void drawCircle(int x, int y, Cons drawer){
for(int rx = -brushSize; rx <= brushSize; rx++){
for(int ry = -brushSize; ry <= brushSize; ry++){
diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java
index 4f7eb008fd..dfb49099ec 100644
--- a/core/src/mindustry/editor/MapEditorDialog.java
+++ b/core/src/mindustry/editor/MapEditorDialog.java
@@ -258,6 +258,11 @@ public class MapEditorDialog extends Dialog implements Disposable{
Groups.unit.clear();
Groups.build.clear();
logic.play();
+
+ if(player.team().core() == null){
+ player.set(world.width() * tilesize/2f, world.height() * tilesize/2f);
+ player.unit(UnitTypes.alpha.spawn(player.team(), player.x, player.y));
+ }
});
}
@@ -385,7 +390,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
}
public void build(){
- float size = 60f;
+ float size = 58f;
clearChildren();
table(cont -> {
@@ -559,10 +564,19 @@ public class MapEditorDialog extends Dialog implements Disposable{
mid.row();
- mid.table(t -> {
- t.button("@editor.center", Icon.move, Styles.cleart, () -> view.center()).growX().margin(9f);
- }).growX().top();
+ if(!mobile){
+ mid.table(t -> {
+ t.button("@editor.center", Icon.move, Styles.cleart, view::center).growX().margin(9f);
+ }).growX().top();
+ }
+ if(addCliffButton){
+ mid.row();
+
+ mid.table(t -> {
+ t.button("Cliffs", Icon.terrain, Styles.cleart, editor::addCliffs).growX().margin(9f);
+ }).growX().top();
+ }
}).margin(0).left().growY();
diff --git a/core/src/mindustry/editor/MapGenerateDialog.java b/core/src/mindustry/editor/MapGenerateDialog.java
index fae31dc7d5..34275afcd1 100644
--- a/core/src/mindustry/editor/MapGenerateDialog.java
+++ b/core/src/mindustry/editor/MapGenerateDialog.java
@@ -29,7 +29,8 @@ public class MapGenerateDialog extends BaseDialog{
private final Prov[] filterTypes = new Prov[]{
NoiseFilter::new, ScatterFilter::new, TerrainFilter::new, DistortFilter::new,
RiverNoiseFilter::new, OreFilter::new, OreMedianFilter::new, MedianFilter::new,
- BlendFilter::new, MirrorFilter::new, ClearFilter::new, CoreSpawnFilter::new, EnemySpawnFilter::new
+ BlendFilter::new, MirrorFilter::new, ClearFilter::new, CoreSpawnFilter::new,
+ EnemySpawnFilter::new, SpawnPathFilter::new
};
private final MapEditor editor;
private final boolean applied;
@@ -44,14 +45,13 @@ public class MapGenerateDialog extends BaseDialog{
private AsyncExecutor executor = new AsyncExecutor(1);
private AsyncResult result;
boolean generating;
- private GenTile returnTile = new GenTile();
- private GenTile[][] buffer1, buffer2;
+ private long[] buffer1, buffer2;
private Cons> applier;
CachedTile ctile = new CachedTile(){
//nothing.
@Override
- protected void changeEntity(Team team, Prov entityprov, int rotation){
+ protected void changeBuild(Team team, Prov entityprov, int rotation){
}
};
@@ -65,7 +65,7 @@ public class MapGenerateDialog extends BaseDialog{
shown(this::setup);
addCloseButton();
if(applied){
- buttons.button("@editor.apply", () -> {
+ buttons.button("@editor.apply", Icon.ok, () -> {
ui.loadAnd(() -> {
apply();
hide();
@@ -78,14 +78,14 @@ public class MapGenerateDialog extends BaseDialog{
update();
}).size(160f, 64f);
}
- buttons.button("@editor.randomize", () -> {
+ buttons.button("@editor.randomize", Icon.refresh, () -> {
for(GenerateFilter filter : filters){
filter.randomize();
}
update();
}).size(160f, 64f);
- buttons.button("@add", Icon.add, this::showAdd).height(64f).width(140f);
+ buttons.button("@add", Icon.add, this::showAdd).height(64f).width(150f);
if(!applied){
hidden(this::apply);
@@ -107,38 +107,36 @@ public class MapGenerateDialog extends BaseDialog{
/** Applies the specified filters to the editor. */
public void applyToEditor(Seq filters){
//writeback buffer
- GenTile[][] writeTiles = new GenTile[editor.width()][editor.height()];
-
- for(int x = 0; x < editor.width(); x++){
- for(int y = 0; y < editor.height(); y++){
- writeTiles[x][y] = new GenTile();
- }
- }
+ long[] writeTiles = new long[editor.width() * editor.height()];
for(GenerateFilter filter : filters){
input.begin(filter, editor.width(), editor.height(), editor::tile);
+
//write to buffer
for(int x = 0; x < editor.width(); x++){
for(int y = 0; y < editor.height(); y++){
Tile tile = editor.tile(x, y);
- input.apply(x, y, tile.floor(), tile.block(), tile.overlay());
+ input.apply(x, y, tile.block(), tile.floor(), tile.overlay());
filter.apply(input);
- writeTiles[x][y].set(input.floor, input.block, input.ore, tile.team());
+ writeTiles[x + y*world.width()] = PackTile.get(input.block.id, input.floor.id, input.overlay.id);
}
}
editor.load(() -> {
//read from buffer back into tiles
- for(int x = 0; x < editor.width(); x++){
- for(int y = 0; y < editor.height(); y++){
- Tile tile = editor.tile(x, y);
- GenTile write = writeTiles[x][y];
+ for(int i = 0; i < editor.width() * editor.height(); i++){
+ Tile tile = world.tiles.geti(i);
+ long write = writeTiles[i];
- tile.setFloor((Floor)content.block(write.floor));
- tile.setBlock(content.block(write.block));
- tile.setTeam(Team.get(write.team));
- tile.setOverlay(content.block(write.ore));
+ Block block = content.block(PackTile.block(write)), floor = content.block(PackTile.floor(write)), overlay = content.block(PackTile.overlay(write));
+
+ //don't mess up synthetic stuff.
+ if(!tile.synthetic() && !block.synthetic()){
+ tile.setBlock(block);
}
+
+ tile.setFloor((Floor)floor);
+ tile.setOverlay(overlay);
}
});
}
@@ -201,15 +199,8 @@ public class MapGenerateDialog extends BaseDialog{
rebuildFilters();
}
- GenTile[][] create(){
- GenTile[][] out = new GenTile[editor.width() / scaling][editor.height() / scaling];
-
- for(int x = 0; x < out.length; x++){
- for(int y = 0; y < out[0].length; y++){
- out[x][y] = new GenTile();
- }
- }
- return out;
+ long[] create(){
+ return new long[(editor.width() / scaling) * (editor.height() / scaling)];
}
void rebuildFilters(){
@@ -295,7 +286,7 @@ public class MapGenerateDialog extends BaseDialog{
for(Prov gen : filterTypes){
GenerateFilter filter = gen.get();
- if((!applied && filter.isBuffered()) || (filter.isPost() && applied)) continue;
+ if((filter.isPost() && applied)) continue;
selection.cont.button(filter.name(), () -> {
filters.add(filter);
@@ -317,9 +308,15 @@ public class MapGenerateDialog extends BaseDialog{
selection.show();
}
- GenTile dset(Tile tile){
- returnTile.set(tile);
- return returnTile;
+ long pack(Tile tile){
+ return PackTile.get(tile.blockID(), tile.floorID(), tile.overlayID());
+ }
+
+ Tile unpack(long tile){
+ ctile.setFloor((Floor)content.block(PackTile.floor(tile)));
+ ctile.setBlock(content.block(PackTile.block(tile)));
+ ctile.setOverlay(content.block(PackTile.overlay(tile)));
+ return ctile;
}
void apply(){
@@ -350,6 +347,7 @@ public class MapGenerateDialog extends BaseDialog{
result = executor.submit(() -> {
try{
+ int w = pixmap.getWidth();
world.setGenerating(true);
generating = true;
@@ -357,24 +355,24 @@ public class MapGenerateDialog extends BaseDialog{
//write to buffer1 for reading
for(int px = 0; px < pixmap.getWidth(); px++){
for(int py = 0; py < pixmap.getHeight(); py++){
- buffer1[px][py].set(editor.tile(px * scaling, py * scaling));
+ buffer1[px + py*w] = pack(editor.tile(px * scaling, py * scaling));
}
}
}
for(GenerateFilter filter : copy){
- input.begin(filter, editor.width(), editor.height(), (x, y) -> buffer1[Mathf.clamp(x / scaling, 0, pixmap.getWidth()-1)][Mathf.clamp(y / scaling, 0, pixmap.getHeight()-1)].tile());
+ input.begin(filter, editor.width(), editor.height(), (x, y) -> unpack(buffer1[Mathf.clamp(x / scaling, 0, pixmap.getWidth()-1) + w* Mathf.clamp(y / scaling, 0, pixmap.getHeight()-1)]));
//read from buffer1 and write to buffer2
pixmap.each((px, py) -> {
int x = px * scaling, y = py * scaling;
- GenTile tile = buffer1[px][py];
- input.apply(x, y, content.block(tile.floor), content.block(tile.block), content.block(tile.ore));
+ long tile = buffer1[px + py * w];
+ input.apply(x, y, content.block(PackTile.block(tile)), content.block(PackTile.floor(tile)), content.block(PackTile.overlay(tile)));
filter.apply(input);
- buffer2[px][py].set(input.floor, input.block, input.ore, Team.get(tile.team));
+ buffer2[px + py * w] = PackTile.get(input.block.id, input.floor.id, input.overlay.id);
});
- pixmap.each((px, py) -> buffer1[px][py].set(buffer2[px][py]));
+ pixmap.each((px, py) -> buffer1[px + py*w] = buffer2[px + py*w]);
}
for(int px = 0; px < pixmap.getWidth(); px++){
@@ -383,10 +381,10 @@ public class MapGenerateDialog extends BaseDialog{
//get result from buffer1 if there's filters left, otherwise get from editor directly
if(filters.isEmpty()){
Tile tile = editor.tile(px * scaling, py * scaling);
- color = MapIO.colorFor(tile.floor(), tile.block(), tile.overlay(), Team.derelict);
+ color = MapIO.colorFor(tile.block(), tile.floor(), tile.overlay(), Team.derelict);
}else{
- GenTile tile = buffer1[px][py];
- color = MapIO.colorFor(content.block(tile.floor), content.block(tile.block), content.block(tile.ore), Team.derelict);
+ long tile = buffer1[px + py*w];
+ color = MapIO.colorFor(content.block(PackTile.block(tile)), content.block(PackTile.floor(tile)), content.block(PackTile.overlay(tile)), Team.derelict);
}
pixmap.draw(px, pixmap.getHeight() - 1 - py, color);
}
@@ -406,39 +404,4 @@ public class MapGenerateDialog extends BaseDialog{
world.setGenerating(false);
});
}
-
- private class GenTile{
- public byte team;
- public short block, floor, ore;
-
- GenTile(){
- }
-
- public void set(Block floor, Block wall, Block ore, Team team){
- this.floor = floor.id;
- this.block = wall.id;
- this.ore = !floor.asFloor().hasSurface() ? 0 : ore.id;
- this.team = (byte)team.id;
- }
-
- public void set(GenTile other){
- this.floor = other.floor;
- this.block = other.block;
- this.ore = other.ore;
- this.team = other.team;
- }
-
- public GenTile set(Tile other){
- set(other.floor(), other.block(), other.overlay(), other.team());
- return this;
- }
-
- Tile tile(){
- ctile.setFloor((Floor)content.block(floor));
- ctile.setBlock(content.block(block));
- ctile.setOverlay(content.block(ore));
- ctile.setTeam(Team.get(team));
- return ctile;
- }
- }
}
diff --git a/core/src/mindustry/editor/WaveGraph.java b/core/src/mindustry/editor/WaveGraph.java
index 14b2416085..2436c62c2a 100644
--- a/core/src/mindustry/editor/WaveGraph.java
+++ b/core/src/mindustry/editor/WaveGraph.java
@@ -154,7 +154,7 @@ public class WaveGraph extends Table{
int sum = 0;
for(SpawnGroup spawn : groups){
- int spawned = spawn.getUnitsSpawned(i);
+ int spawned = spawn.getSpawned(i);
values[index][spawn.type.id] += spawned;
if(spawned > 0){
used.add(spawn.type);
diff --git a/core/src/mindustry/editor/WaveInfoDialog.java b/core/src/mindustry/editor/WaveInfoDialog.java
index d5b957e143..ae5f985766 100644
--- a/core/src/mindustry/editor/WaveInfoDialog.java
+++ b/core/src/mindustry/editor/WaveInfoDialog.java
@@ -159,7 +159,7 @@ public class WaveInfoDialog extends BaseDialog{
t.margin(0).defaults().pad(3).padLeft(5f).growX().left();
t.button(b -> {
b.left();
- b.image(group.type.icon(mindustry.ui.Cicon.medium)).size(32f).padRight(3);
+ b.image(group.type.icon(Cicon.medium)).size(32f).padRight(3).scaling(Scaling.fit);
b.add(group.type.localizedName).color(Pal.accent);
b.add().growX();
@@ -262,7 +262,7 @@ public class WaveInfoDialog extends BaseDialog{
if(type.isHidden()) continue;
p.button(t -> {
t.left();
- t.image(type.icon(Cicon.medium)).size(40f).padRight(2f);
+ t.image(type.icon(Cicon.medium)).size(8 * 4).scaling(Scaling.fit).padRight(2f);
t.add(type.localizedName);
}, () -> {
lastType = type;
diff --git a/core/src/mindustry/entities/Damage.java b/core/src/mindustry/entities/Damage.java
index e22891eba5..b6c9abe807 100644
--- a/core/src/mindustry/entities/Damage.java
+++ b/core/src/mindustry/entities/Damage.java
@@ -9,6 +9,7 @@ import arc.struct.*;
import arc.util.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
+import mindustry.core.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
import mindustry.gen.*;
@@ -82,7 +83,7 @@ public class Damage{
furthest = null;
- boolean found = world.raycast(b.tileX(), b.tileY(), world.toTile(b.x + Tmp.v1.x), world.toTile(b.y + Tmp.v1.y),
+ boolean found = world.raycast(b.tileX(), b.tileY(), World.toTile(b.x + Tmp.v1.x), World.toTile(b.y + Tmp.v1.y),
(x, y) -> (furthest = world.tile(x, y)) != null && furthest.team() != b.team && furthest.block().absorbLasers);
return found && furthest != null ? Math.max(6f, b.dst(furthest.worldx(), furthest.worldy())) : length;
diff --git a/core/src/mindustry/entities/Fires.java b/core/src/mindustry/entities/Fires.java
index 2906b4e7d7..754a8766b9 100644
--- a/core/src/mindustry/entities/Fires.java
+++ b/core/src/mindustry/entities/Fires.java
@@ -23,14 +23,14 @@ public class Fires{
if(fire == null){
fire = Fire.create();
- fire.tile(tile);
- fire.lifetime(baseLifetime);
+ fire.tile = tile;
+ fire.lifetime = baseLifetime;
fire.set(tile.worldx(), tile.worldy());
fire.add();
map.put(tile.pos(), fire);
}else{
- fire.lifetime(baseLifetime);
- fire.time(0f);
+ fire.lifetime = baseLifetime;
+ fire.time = 0f;
}
}
diff --git a/core/src/mindustry/entities/Lightning.java b/core/src/mindustry/entities/Lightning.java
index 738bfa1f1e..2d647bfb1e 100644
--- a/core/src/mindustry/entities/Lightning.java
+++ b/core/src/mindustry/entities/Lightning.java
@@ -5,6 +5,7 @@ import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import mindustry.content.*;
+import mindustry.core.*;
import mindustry.entities.bullet.*;
import mindustry.game.*;
import mindustry.gen.*;
@@ -48,7 +49,7 @@ public class Lightning{
bhit = false;
Vec2 from = lines.get(lines.size - 2);
Vec2 to = lines.get(lines.size - 1);
- world.raycastEach(world.toTile(from.getX()), world.toTile(from.getY()), world.toTile(to.getX()), world.toTile(to.getY()), (wx, wy) -> {
+ world.raycastEach(World.toTile(from.getX()), World.toTile(from.getY()), World.toTile(to.getX()), World.toTile(to.getY()), (wx, wy) -> {
Tile tile = world.tile(wx, wy);
if(tile != null && tile.block().insulated){
diff --git a/core/src/mindustry/entities/Units.java b/core/src/mindustry/entities/Units.java
index 1babb75e33..e4591a0ed0 100644
--- a/core/src/mindustry/entities/Units.java
+++ b/core/src/mindustry/entities/Units.java
@@ -126,7 +126,7 @@ public class Units{
nearby(x, y, width, height, unit -> {
if(boolResult) return;
- if((unit.isGrounded() && !unit.type().hovering) == ground){
+ if((unit.isGrounded() && !unit.type.hovering) == ground){
unit.hitbox(hitrect);
if(hitrect.overlaps(x, y, width, height)){
diff --git a/core/src/mindustry/entities/abilities/Ability.java b/core/src/mindustry/entities/abilities/Ability.java
index 466bfc1980..cb6e94547b 100644
--- a/core/src/mindustry/entities/abilities/Ability.java
+++ b/core/src/mindustry/entities/abilities/Ability.java
@@ -1,5 +1,6 @@
package mindustry.entities.abilities;
+import arc.*;
import mindustry.gen.*;
public abstract class Ability implements Cloneable{
@@ -14,4 +15,9 @@ public abstract class Ability implements Cloneable{
throw new RuntimeException("java sucks", e);
}
}
+
+ /** @return localized ability name; mods should override this. */
+ public String localized(){
+ return Core.bundle.get("ability." + getClass().getSimpleName().replace("Ability", "").toLowerCase());
+ }
}
diff --git a/core/src/mindustry/entities/abilities/ForceFieldAbility.java b/core/src/mindustry/entities/abilities/ForceFieldAbility.java
index fa9fa5e2c8..d341191a74 100644
--- a/core/src/mindustry/entities/abilities/ForceFieldAbility.java
+++ b/core/src/mindustry/entities/abilities/ForceFieldAbility.java
@@ -94,7 +94,7 @@ public class ForceFieldAbility extends Ability{
}
}
- private void checkRadius(Unit unit){
+ public void checkRadius(Unit unit){
//timer2 is used to store radius scale as an effect
realRad = radiusScale * radius;
}
diff --git a/core/src/mindustry/entities/abilities/HealFieldAbility.java b/core/src/mindustry/entities/abilities/RepairFieldAbility.java
similarity index 86%
rename from core/src/mindustry/entities/abilities/HealFieldAbility.java
rename to core/src/mindustry/entities/abilities/RepairFieldAbility.java
index 90f800ec84..8df0a96e2c 100644
--- a/core/src/mindustry/entities/abilities/HealFieldAbility.java
+++ b/core/src/mindustry/entities/abilities/RepairFieldAbility.java
@@ -5,7 +5,7 @@ import mindustry.content.*;
import mindustry.entities.*;
import mindustry.gen.*;
-public class HealFieldAbility extends Ability{
+public class RepairFieldAbility extends Ability{
public float amount = 1, reload = 100, range = 60;
public Effect healEffect = Fx.heal;
public Effect activeEffect = Fx.healWaveDynamic;
@@ -13,9 +13,9 @@ public class HealFieldAbility extends Ability{
protected float timer;
protected boolean wasHealed = false;
- HealFieldAbility(){}
+ RepairFieldAbility(){}
- public HealFieldAbility(float amount, float reload, float range){
+ public RepairFieldAbility(float amount, float reload, float range){
this.amount = amount;
this.reload = reload;
this.range = range;
diff --git a/core/src/mindustry/entities/abilities/ShieldFieldAbility.java b/core/src/mindustry/entities/abilities/ShieldRegenFieldAbility.java
similarity index 86%
rename from core/src/mindustry/entities/abilities/ShieldFieldAbility.java
rename to core/src/mindustry/entities/abilities/ShieldRegenFieldAbility.java
index 739751f6c1..8af8d2390a 100644
--- a/core/src/mindustry/entities/abilities/ShieldFieldAbility.java
+++ b/core/src/mindustry/entities/abilities/ShieldRegenFieldAbility.java
@@ -5,7 +5,7 @@ import mindustry.content.*;
import mindustry.entities.*;
import mindustry.gen.*;
-public class ShieldFieldAbility extends Ability{
+public class ShieldRegenFieldAbility extends Ability{
public float amount = 1, max = 100f, reload = 100, range = 60;
public Effect applyEffect = Fx.shieldApply;
public Effect activeEffect = Fx.shieldWave;
@@ -13,9 +13,9 @@ public class ShieldFieldAbility extends Ability{
protected float timer;
protected boolean applied = false;
- ShieldFieldAbility(){}
+ ShieldRegenFieldAbility(){}
- public ShieldFieldAbility(float amount, float max, float reload, float range){
+ public ShieldRegenFieldAbility(float amount, float max, float reload, float range){
this.amount = amount;
this.max = max;
this.reload = reload;
diff --git a/core/src/mindustry/entities/abilities/UnitSpawnAbility.java b/core/src/mindustry/entities/abilities/UnitSpawnAbility.java
index 74140114d9..95eb3bcf5b 100644
--- a/core/src/mindustry/entities/abilities/UnitSpawnAbility.java
+++ b/core/src/mindustry/entities/abilities/UnitSpawnAbility.java
@@ -1,5 +1,6 @@
package mindustry.entities.abilities;
+import arc.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.util.*;
@@ -56,4 +57,9 @@ public class UnitSpawnAbility extends Ability{
});
}
}
+
+ @Override
+ public String localized(){
+ return Core.bundle.format("ability.unitspawn", type.localizedName);
+ }
}
diff --git a/core/src/mindustry/entities/bullet/BulletType.java b/core/src/mindustry/entities/bullet/BulletType.java
index 0c3a605f1b..8e06cf466e 100644
--- a/core/src/mindustry/entities/bullet/BulletType.java
+++ b/core/src/mindustry/entities/bullet/BulletType.java
@@ -104,6 +104,8 @@ public abstract class BulletType extends Content{
public float incendChance = 1f;
public float homingPower = 0f;
public float homingRange = 50f;
+ /** Use a negative value to disable homing delay. */
+ public float homingDelay = -1f;
public Color lightningColor = Pal.surge;
public int lightning;
@@ -137,6 +139,15 @@ public abstract class BulletType extends Content{
this(1f, 1f);
}
+ /** @return estimated damage per shot. this can be very inaccurate. */
+ public float estimateDPS(){
+ float sum = damage + splashDamage*0.75f;
+ if(fragBullet != null && fragBullet != this){
+ sum += fragBullet.estimateDPS() * fragBullets / 2f;
+ }
+ return sum;
+ }
+
/** Returns maximum distance the bullet this bullet type has can travel. */
public float range(){
return Math.max(speed * lifetime * (1f - drag), range);
@@ -251,7 +262,7 @@ public abstract class BulletType extends Content{
}
public void update(Bullet b){
- if(homingPower > 0.0001f){
+ if(homingPower > 0.0001f && b.time >= homingDelay){
Teamc target = Units.closestTarget(b.team, b.x, b.y, homingRange, e -> (e.isGrounded() && collidesGround) || (e.isFlying() && collidesAir), t -> collidesGround);
if(target != null){
b.vel.setAngle(Mathf.slerpDelta(b.rotation(), b.angleTo(target), homingPower));
diff --git a/core/src/mindustry/entities/bullet/ContinuousLaserBulletType.java b/core/src/mindustry/entities/bullet/ContinuousLaserBulletType.java
index a862671040..4c52105b26 100644
--- a/core/src/mindustry/entities/bullet/ContinuousLaserBulletType.java
+++ b/core/src/mindustry/entities/bullet/ContinuousLaserBulletType.java
@@ -44,6 +44,12 @@ public class ContinuousLaserBulletType extends BulletType{
this(0);
}
+ @Override
+ public float estimateDPS(){
+ //assume firing duration is about 100 by default, may not be accurate there's no way of knowing in this method
+ return damage * 100f / 5f;
+ }
+
@Override
public float range(){
return length;
diff --git a/core/src/mindustry/entities/bullet/LaserBulletType.java b/core/src/mindustry/entities/bullet/LaserBulletType.java
index ad5965f3b8..6d43baf95c 100644
--- a/core/src/mindustry/entities/bullet/LaserBulletType.java
+++ b/core/src/mindustry/entities/bullet/LaserBulletType.java
@@ -39,6 +39,11 @@ public class LaserBulletType extends BulletType{
this(1f);
}
+ @Override
+ public float estimateDPS(){
+ return super.estimateDPS() * 2f;
+ }
+
@Override
public void init(){
super.init();
diff --git a/core/src/mindustry/entities/bullet/LiquidBulletType.java b/core/src/mindustry/entities/bullet/LiquidBulletType.java
index 2d3de79977..5da33f95e0 100644
--- a/core/src/mindustry/entities/bullet/LiquidBulletType.java
+++ b/core/src/mindustry/entities/bullet/LiquidBulletType.java
@@ -22,6 +22,8 @@ public class LiquidBulletType extends BulletType{
if(liquid != null){
this.liquid = liquid;
this.status = liquid.effect;
+ lightColor = liquid.lightColor;
+ lightOpacity = liquid.lightColor.a;
}
ammoMultiplier = 1f;
diff --git a/core/src/mindustry/entities/comp/BuilderComp.java b/core/src/mindustry/entities/comp/BuilderComp.java
index 0aafd4d0c0..0ef4d8bed0 100644
--- a/core/src/mindustry/entities/comp/BuilderComp.java
+++ b/core/src/mindustry/entities/comp/BuilderComp.java
@@ -207,7 +207,8 @@ abstract class BuilderComp implements Unitc{
BuildPlan plan = buildPlan();
Tile tile = world.tile(plan.x, plan.y);
- if((!within(tile, buildingRange) && !state.isEditor()) || tile == null){
+
+ if(tile == null || (!within(tile, buildingRange) && !state.isEditor())){
return;
}
diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java
index 15d79a8942..84b6160d25 100644
--- a/core/src/mindustry/entities/comp/BuildingComp.java
+++ b/core/src/mindustry/entities/comp/BuildingComp.java
@@ -17,16 +17,19 @@ import arc.util.io.*;
import mindustry.annotations.Annotations.*;
import mindustry.audio.*;
import mindustry.content.*;
+import mindustry.core.*;
import mindustry.ctype.*;
import mindustry.entities.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
+import mindustry.game.Teams.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.logic.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.*;
+import mindustry.world.blocks.ConstructBlock.*;
import mindustry.world.blocks.environment.*;
import mindustry.world.blocks.payloads.*;
import mindustry.world.blocks.power.*;
@@ -191,6 +194,36 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
//endregion
//region utility methods
+ public void addPlan(boolean checkPrevious){
+ if(!block.rebuildable) return;
+
+ if(self() instanceof ConstructBuild entity){
+ //update block to reflect the fact that something was being constructed
+ if(entity.cblock != null && entity.cblock.synthetic()){
+ block = entity.cblock;
+ }else{
+ //otherwise this was a deconstruction that was interrupted, don't want to rebuild that
+ return;
+ }
+ }
+
+ TeamData data = state.teams.get(team);
+
+ if(checkPrevious){
+ //remove existing blocks that have been placed here.
+ //painful O(n) iteration + copy
+ for(int i = 0; i < data.blocks.size; i++){
+ BlockPlan b = data.blocks.get(i);
+ if(b.x == tile.x && b.y == tile.y){
+ data.blocks.removeIndex(i);
+ break;
+ }
+ }
+ }
+
+ data.blocks.addFirst(new BlockPlan(tile.x, tile.y, (short)rotation, block.id, config()));
+ }
+
/** Configure with the current, local player. */
public void configure(Object value){
//save last used config
@@ -431,7 +464,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
*/
public boolean movePayload(Payload todump){
int trns = block.size/2 + 1;
- Tile next = tile.getNearby(Geometry.d4(rotation).x * trns, Geometry.d4(rotation).y * trns);
+ Tile next = tile.nearby(Geometry.d4(rotation).x * trns, Geometry.d4(rotation).y * trns);
if(next != null && next.build != null && next.build.team == team && next.build.acceptPayload(self(), todump)){
next.build.handlePayload(self(), todump);
@@ -514,7 +547,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
public float moveLiquidForward(boolean leaks, Liquid liquid){
- Tile next = tile.getNearby(rotation);
+ Tile next = tile.nearby(rotation);
if(next == null) return 0;
@@ -766,9 +799,9 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}
public void drawCracks(){
- if(!damaged() || block.size > Block.maxCrackSize) return;
+ if(!damaged() || block.size > BlockRenderer.maxCrackSize) return;
int id = pos();
- TextureRegion region = Block.cracks[block.size - 1][Mathf.clamp((int)((1f - healthf()) * Block.crackRegions), 0, Block.crackRegions-1)];
+ TextureRegion region = renderer.blocks.cracks[block.size - 1][Mathf.clamp((int)((1f - healthf()) * BlockRenderer.crackRegions), 0, BlockRenderer.crackRegions-1)];
Draw.colorl(0.2f, 0.1f + (1f - healthf())* 0.6f);
Draw.rect(region, x, y, (id%4)*90);
Draw.color();
@@ -878,7 +911,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
/** Called when arbitrary configuration is applied to a tile. */
public void configured(@Nullable Unit builder, @Nullable Object value){
//null is of type void.class; anonymous classes use their superclass.
- Class> type = value == null ? void.class : value.getClass().isAnonymousClass() ? value.getClass().getSuperclass() : value.getClass();
+ Class> type = value == null ? void.class : value.getClass().isAnonymousClass() || value.getClass().getSimpleName().startsWith("adapter") ? value.getClass().getSuperclass() : value.getClass();
if(builder != null && builder.isPlayer()){
lastAccessed = builder.getPlayer().name;
@@ -1234,8 +1267,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
@Override
public double sense(LAccess sensor){
return switch(sensor){
- case x -> x;
- case y -> y;
+ case x -> World.conv(x);
+ case y -> World.conv(y);
case team -> team.id;
case health -> health;
case maxHealth -> maxHealth;
@@ -1244,8 +1277,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
case totalItems -> items == null ? 0 : items.total();
case totalLiquids -> liquids == null ? 0 : liquids.total();
case totalPower -> power == null || !block.consumes.hasPower() ? 0 : power.status * (block.consumes.getPower().buffered ? block.consumes.getPower().capacity : 1f);
- case itemCapacity -> block.itemCapacity;
- case liquidCapacity -> block.liquidCapacity;
+ case itemCapacity -> block.hasItems ? block.itemCapacity : 0;
+ case liquidCapacity -> block.hasLiquids ? block.liquidCapacity : 0;
case powerCapacity -> block.consumes.hasPower() ? block.consumes.getPower().capacity : 0f;
case powerNetIn -> power == null ? 0 : power.graph.getLastScaledPowerIn() * 60;
case powerNetOut -> power == null ? 0 : power.graph.getLastScaledPowerOut() * 60;
@@ -1263,7 +1296,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
case type -> block;
case firstItem -> items == null ? null : items.first();
case config -> block.configurations.containsKey(Item.class) || block.configurations.containsKey(Liquid.class) ? config() : null;
- case payloadType -> getPayload() instanceof UnitPayload p1 ? p1.unit.type() : getPayload() instanceof BuildPayload p2 ? p2.block() : null;
+ case payloadType -> getPayload() instanceof UnitPayload p1 ? p1.unit.type : getPayload() instanceof BuildPayload p2 ? p2.block() : null;
default -> noSensed;
};
diff --git a/core/src/mindustry/entities/comp/BulletComp.java b/core/src/mindustry/entities/comp/BulletComp.java
index d9aa007c5e..5a08710762 100644
--- a/core/src/mindustry/entities/comp/BulletComp.java
+++ b/core/src/mindustry/entities/comp/BulletComp.java
@@ -7,6 +7,7 @@ import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import mindustry.annotations.Annotations.*;
+import mindustry.core.*;
import mindustry.entities.bullet.*;
import mindustry.game.*;
import mindustry.game.Teams.*;
@@ -110,7 +111,7 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
type.update(self());
if(type.collidesTiles && type.collides && type.collidesGround){
- world.raycastEach(world.toTile(lastX()), world.toTile(lastY()), tileX(), tileY(), (x, y) -> {
+ world.raycastEach(World.toTile(lastX()), World.toTile(lastY()), tileX(), tileY(), (x, y) -> {
Building tile = world.build(x, y);
if(tile == null || !isAdded()) return false;
diff --git a/core/src/mindustry/entities/comp/CommanderComp.java b/core/src/mindustry/entities/comp/CommanderComp.java
index b0fbddcf85..2fe2bf83a0 100644
--- a/core/src/mindustry/entities/comp/CommanderComp.java
+++ b/core/src/mindustry/entities/comp/CommanderComp.java
@@ -30,7 +30,7 @@ abstract class CommanderComp implements Entityc, Posc{
public void update(){
if(formation != null){
- formation.anchor.set(x, y, /*rotation*/ 0); //TODO rotation set to 0 because rotating is pointless
+ formation.anchor.set(x, y, 0);
formation.updateSlots();
}
}
@@ -59,7 +59,7 @@ abstract class CommanderComp implements Entityc, Posc{
units.clear();
Units.nearby(team, x, y, 150f, u -> {
- if(u.isAI() && include.get(u) && u != self() && u.type().flying == type.flying && u.hitSize <= hitSize * 1.1f){
+ if(u.isAI() && include.get(u) && u != self() && u.type.flying == type.flying && u.hitSize <= hitSize * 1.1f){
units.add(u);
}
});
@@ -74,7 +74,7 @@ abstract class CommanderComp implements Entityc, Posc{
void command(Formation formation, Seq units){
clearCommand();
- float spacing = hitSize * 0.65f;
+ float spacing = hitSize * 0.8f;
minFormationSpeed = type.speed;
controlling.addAll(units);
@@ -82,7 +82,7 @@ abstract class CommanderComp implements Entityc, Posc{
FormationAI ai;
unit.controller(ai = new FormationAI(self(), formation));
spacing = Math.max(spacing, ai.formationSize());
- minFormationSpeed = Math.min(minFormationSpeed, unit.type().speed);
+ minFormationSpeed = Math.min(minFormationSpeed, unit.type.speed);
}
this.formation = formation;
@@ -106,7 +106,7 @@ abstract class CommanderComp implements Entityc, Posc{
//reset controlled units
for(Unit unit : controlling){
if(unit.controller().isBeingControlled(self())){
- unit.controller(unit.type().createController());
+ unit.controller(unit.type.createController());
}
}
diff --git a/core/src/mindustry/entities/comp/FireComp.java b/core/src/mindustry/entities/comp/FireComp.java
index ea67ca9e19..84fcb6b3b5 100644
--- a/core/src/mindustry/entities/comp/FireComp.java
+++ b/core/src/mindustry/entities/comp/FireComp.java
@@ -16,7 +16,7 @@ import static mindustry.Vars.*;
@EntityDef(value = {Firec.class}, pooled = true)
@Component(base = true)
abstract class FireComp implements Timedc, Posc, Firec, Syncc{
- private static final float spreadChance = 0.05f, fireballChance = 0.07f;
+ private static final float spreadChance = 0.04f, fireballChance = 0.06f;
@Import float time, lifetime, x, y;
diff --git a/core/src/mindustry/entities/comp/MinerComp.java b/core/src/mindustry/entities/comp/MinerComp.java
index 6bac9dbd60..764e6ed4d3 100644
--- a/core/src/mindustry/entities/comp/MinerComp.java
+++ b/core/src/mindustry/entities/comp/MinerComp.java
@@ -54,7 +54,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{
}
}
- if(core == null || !validMine(mineTile)){
+ if(!validMine(mineTile)){
mineTile = null;
mineTimer = 0f;
}else if(mining()){
@@ -69,7 +69,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc, Unitc{
if(mineTimer >= 50f + item.hardness*15f){
mineTimer = 0;
- if(within(core, mineTransferRange) && core.acceptStack(item, 1, this) == 1 && offloadImmediately()){
+ if(core != null && within(core, mineTransferRange) && core.acceptStack(item, 1, this) == 1 && offloadImmediately()){
Call.transferItemTo(item, 1,
mineTile.worldx() + Mathf.range(tilesize / 2f),
mineTile.worldy() + Mathf.range(tilesize / 2f), core);
diff --git a/core/src/mindustry/entities/comp/PayloadComp.java b/core/src/mindustry/entities/comp/PayloadComp.java
index ac1f4fa323..e2945d08f7 100644
--- a/core/src/mindustry/entities/comp/PayloadComp.java
+++ b/core/src/mindustry/entities/comp/PayloadComp.java
@@ -6,6 +6,7 @@ import arc.util.*;
import mindustry.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
+import mindustry.core.*;
import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.type.*;
@@ -120,7 +121,7 @@ abstract class PayloadComp implements Posc, Rotc, Hitboxc, Unitc{
/** @return whether the tile has been successfully placed. */
boolean dropBlock(BuildPayload payload){
Building tile = payload.build;
- int tx = Vars.world.toTile(x - tile.block.offset), ty = Vars.world.toTile(y - tile.block.offset);
+ int tx = World.toTile(x - tile.block.offset), ty = World.toTile(y - tile.block.offset);
Tile on = Vars.world.tile(tx, ty);
if(on != null && Build.validPlace(tile.block, tile.team, tx, ty, tile.rotation, false)){
int rot = (int)((rotation + 45f) / 90f) % 4;
diff --git a/core/src/mindustry/entities/comp/PlayerComp.java b/core/src/mindustry/entities/comp/PlayerComp.java
index 4ee481b032..736a1b68e5 100644
--- a/core/src/mindustry/entities/comp/PlayerComp.java
+++ b/core/src/mindustry/entities/comp/PlayerComp.java
@@ -79,7 +79,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
admin = typing = false;
textFadeTime = 0f;
if(!dead()){
- unit.controller(unit.type().createController());
+ unit.controller(unit.type.createController());
unit = Nulls.unit;
}
}
@@ -91,7 +91,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
@Replace
public float clipSize(){
- return unit.isNull() ? 20 : unit.type().hitSize * 2f;
+ return unit.isNull() ? 20 : unit.type.hitSize * 2f;
}
@Override
@@ -123,7 +123,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
deathTimer = 0;
//update some basic state to sync things
- if(unit.type().canBoost){
+ if(unit.type.canBoost){
Tile tile = unit.tileOn();
unit.elevation = Mathf.approachDelta(unit.elevation, (tile != null && tile.solid()) || boosting ? 1f : 0f, 0.08f);
}
@@ -177,7 +177,7 @@ abstract class PlayerComp implements UnitController, Entityc, Syncc, Timerc, Dra
if(this.unit != Nulls.unit){
//un-control the old unit
- this.unit.controller(this.unit.type().createController());
+ this.unit.controller(this.unit.type.createController());
}
this.unit = unit;
if(unit != Nulls.unit){
diff --git a/core/src/mindustry/entities/comp/PosComp.java b/core/src/mindustry/entities/comp/PosComp.java
index 15c665739e..6446c0f91f 100644
--- a/core/src/mindustry/entities/comp/PosComp.java
+++ b/core/src/mindustry/entities/comp/PosComp.java
@@ -2,9 +2,9 @@ package mindustry.entities.comp;
import arc.math.geom.*;
import arc.util.*;
-import mindustry.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
+import mindustry.core.*;
import mindustry.world.*;
import mindustry.world.blocks.environment.*;
@@ -32,11 +32,11 @@ abstract class PosComp implements Position{
}
int tileX(){
- return Vars.world.toTile(x);
+ return World.toTile(x);
}
int tileY(){
- return Vars.world.toTile(y);
+ return World.toTile(y);
}
/** Returns air if this unit is on a non-air top block. */
diff --git a/core/src/mindustry/entities/comp/PuddleComp.java b/core/src/mindustry/entities/comp/PuddleComp.java
index 669ee7e1f2..a447bd633a 100644
--- a/core/src/mindustry/entities/comp/PuddleComp.java
+++ b/core/src/mindustry/entities/comp/PuddleComp.java
@@ -74,7 +74,7 @@ abstract class PuddleComp implements Posc, Puddlec, Drawc{
unit.apply(liquid.effect, 60 * 2);
if(unit.vel.len() > 0.1){
- Fx.ripple.at(unit.x, unit.y, unit.type().rippleScale, liquid.color);
+ Fx.ripple.at(unit.x, unit.y, unit.type.rippleScale, liquid.color);
}
}
}
@@ -98,7 +98,7 @@ abstract class PuddleComp implements Posc, Puddlec, Drawc{
boolean onLiquid = tile.floor().isLiquid;
float f = Mathf.clamp(amount / (maxLiquid / 1.5f));
float smag = onLiquid ? 0.8f : 0f;
- float sscl = 20f;
+ float sscl = 25f;
Draw.color(tmp.set(liquid.color).shiftValue(-0.05f));
Fill.circle(x + Mathf.sin(Time.time() + seeds * 532, sscl, smag), y + Mathf.sin(Time.time() + seeds * 53, sscl, smag), f * 8f);
diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java
index 1cf0f7e216..11efcf9948 100644
--- a/core/src/mindustry/entities/comp/UnitComp.java
+++ b/core/src/mindustry/entities/comp/UnitComp.java
@@ -1,6 +1,7 @@
package mindustry.entities.comp;
import arc.*;
+import arc.func.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
@@ -10,6 +11,7 @@ import arc.util.*;
import mindustry.ai.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
+import mindustry.core.*;
import mindustry.ctype.*;
import mindustry.entities.*;
import mindustry.entities.abilities.*;
@@ -36,7 +38,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
@Import int id;
private UnitController controller;
- private UnitType type;
+ UnitType type;
boolean spawnedByCore;
double flag;
@@ -70,6 +72,12 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
return Mathf.lerp(1f, type.canBoost ? type.boostMultiplier : 1f, elevation) * type.speed;
}
+ /** Iterates through this unit and everything it is controlling. */
+ public void eachGroup(Cons cons){
+ cons.get(self());
+ controlling().each(cons);
+ }
+
@Override
public float range(){
return type.range;
@@ -88,12 +96,14 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
case rotation -> rotation;
case health -> health;
case maxHealth -> maxHealth;
- case x -> x;
- case y -> y;
+ case ammo -> !state.rules.unitAmmo ? type.ammoCapacity : ammo;
+ case ammoCapacity -> type.ammoCapacity;
+ case x -> World.conv(x);
+ case y -> World.conv(y);
case team -> team.id;
case shooting -> isShooting() ? 1 : 0;
- case shootX -> aimX();
- case shootY -> aimY();
+ case shootX -> World.conv(aimX());
+ case shootY -> World.conv(aimY());
case flag -> flag;
case payloadCount -> self() instanceof Payloadc pay ? pay.payloads().size : 0;
default -> 0;
@@ -108,7 +118,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
case firstItem -> stack().amount == 0 ? null : item();
case payloadType -> self() instanceof Payloadc pay ?
(pay.payloads().isEmpty() ? null :
- pay.payloads().peek() instanceof UnitPayload p1 ? p1.unit.type() :
+ pay.payloads().peek() instanceof UnitPayload p1 ? p1.unit.type :
pay.payloads().peek() instanceof BuildPayload p2 ? p2.block() : null) : null;
default -> noSensed;
};
@@ -161,22 +171,12 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
@Override
public void set(UnitType def, UnitController controller){
- type(type);
+ if(this.type != def){
+ setType(def);
+ }
controller(controller);
}
- @Override
- public void type(UnitType type){
- if(this.type == type) return;
-
- setStats(type);
- }
-
- @Override
- public UnitType type(){
- return type;
- }
-
/** @return pathfinder path type for calculating costs */
public int pathType(){
return Pathfinder.costGround;
@@ -206,7 +206,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
return Units.getCap(team);
}
- public void setStats(UnitType type){
+ public void setType(UnitType type){
this.type = type;
this.maxHealth = type.health;
this.drag = type.drag;
@@ -224,7 +224,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
@Override
public void afterSync(){
//set up type info after reading
- setStats(this.type);
+ setType(this.type);
controller.unit(self());
}
@@ -284,7 +284,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
drag = type.drag * (isGrounded() ? (floorOn().dragMultiplier) : 1f);
//apply knockback based on spawns
- if(team != state.rules.waveTeam){
+ if(team != state.rules.waveTeam && state.hasSpawns()){
float relativeSize = state.rules.dropZoneRadius + hitSize/2f + 1f;
for(Tile spawn : spawner.getSpawns()){
if(within(spawn.worldx(), spawn.worldy(), relativeSize)){
diff --git a/core/src/mindustry/entities/comp/WeaponsComp.java b/core/src/mindustry/entities/comp/WeaponsComp.java
index d891dbc1e4..dec0105c14 100644
--- a/core/src/mindustry/entities/comp/WeaponsComp.java
+++ b/core/src/mindustry/entities/comp/WeaponsComp.java
@@ -166,7 +166,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{
Weapon weapon = mount.weapon;
float baseX = this.x, baseY = this.y;
- boolean delay = weapon.firstShotDelay > 0f;
+ boolean delay = weapon.firstShotDelay + weapon.shotDelay > 0f;
(delay ? weapon.chargeSound : weapon.shootSound).at(x, y, Mathf.random(0.8f, 1.0f));
diff --git a/core/src/mindustry/entities/units/AIController.java b/core/src/mindustry/entities/units/AIController.java
index b02fa5dc00..ca005fe25d 100644
--- a/core/src/mindustry/entities/units/AIController.java
+++ b/core/src/mindustry/entities/units/AIController.java
@@ -95,7 +95,7 @@ public class AIController implements UnitController{
if(tile == targetTile || (costType == Pathfinder.costWater && !targetTile.floor().isLiquid)) return;
- unit.moveAt(vec.trns(unit.angleTo(targetTile), unit.type().speed));
+ unit.moveAt(vec.trns(unit.angleTo(targetTile), unit.type.speed));
}
protected void updateWeapons(){
@@ -105,7 +105,7 @@ public class AIController implements UnitController{
boolean ret = retarget();
if(ret){
- target = findTarget(unit.x, unit.y, unit.range(), unit.type().targetAir, unit.type().targetGround);
+ target = findTarget(unit.x, unit.y, unit.range(), unit.type.targetAir, unit.type.targetGround);
}
if(invalid(target)){
@@ -119,7 +119,7 @@ public class AIController implements UnitController{
float mountX = unit.x + Angles.trnsx(rotation, weapon.x, weapon.y),
mountY = unit.y + Angles.trnsy(rotation, weapon.x, weapon.y);
- if(unit.type().singleTarget){
+ if(unit.type.singleTarget){
targets[i] = target;
}else{
if(ret){
@@ -176,7 +176,7 @@ public class AIController implements UnitController{
}
protected void circle(Position target, float circleLength){
- circle(target, circleLength, unit.type().speed);
+ circle(target, circleLength, unit.type.speed);
}
protected void circle(Position target, float circleLength, float speed){
diff --git a/core/src/mindustry/game/DefaultWaves.java b/core/src/mindustry/game/DefaultWaves.java
index 0ce0d3a6a2..adc2107f84 100644
--- a/core/src/mindustry/game/DefaultWaves.java
+++ b/core/src/mindustry/game/DefaultWaves.java
@@ -18,6 +18,7 @@ public class DefaultWaves{
new SpawnGroup(dagger){{
end = 10;
unitScaling = 2f;
+ max = 30;
}},
new SpawnGroup(crawler){{
@@ -38,13 +39,14 @@ public class DefaultWaves{
unitScaling = 1.7f;
spacing = 2;
max = 4;
- shieldScaling = 15f;
+ shieldScaling = 25f;
}},
new SpawnGroup(pulsar){{
begin = 13;
spacing = 3;
unitScaling = 0.5f;
+ max = 25;
}},
new SpawnGroup(mace){{
@@ -60,8 +62,8 @@ public class DefaultWaves{
unitScaling = 1;
unitAmount = 4;
spacing = 2;
- shieldScaling = 10f;
- max = 20;
+ shieldScaling = 20f;
+ max = 14;
}},
new SpawnGroup(mace){{
@@ -77,11 +79,12 @@ public class DefaultWaves{
spacing = 3;
unitScaling = 1;
max = 10;
- shieldScaling = 10f;
+ shieldScaling = 30f;
+ shields = 100;
effect = StatusEffects.overdrive;
}},
- new SpawnGroup(mace){{
+ new SpawnGroup(pulsar){{
begin = 120;
spacing = 2;
unitScaling = 3;
@@ -94,6 +97,7 @@ public class DefaultWaves{
unitScaling = 1;
spacing = 2;
shieldScaling = 20f;
+ max = 20;
}},
new SpawnGroup(quasar){{
@@ -111,6 +115,7 @@ public class DefaultWaves{
unitAmount = 1;
unitScaling = 3;
effect = StatusEffects.shielded;
+ max = 25;
}},
new SpawnGroup(fortress){{
@@ -122,7 +127,7 @@ public class DefaultWaves{
shieldScaling = 30;
}},
- new SpawnGroup(dagger){{
+ new SpawnGroup(nova){{
begin = 35;
spacing = 3;
unitAmount = 4;
@@ -138,6 +143,7 @@ public class DefaultWaves{
effect = StatusEffects.overdrive;
items = new ItemStack(Items.pyratite, 100);
end = 130;
+ max = 30;
}},
new SpawnGroup(horizon){{
@@ -156,6 +162,7 @@ public class DefaultWaves{
shields = 100f;
shieldScaling = 10f;
effect = StatusEffects.overdrive;
+ max = 20;
}},
new SpawnGroup(zenith){{
@@ -172,7 +179,7 @@ public class DefaultWaves{
unitAmount = 2;
unitScaling = 3;
spacing = 4;
- shieldScaling = 20;
+ shieldScaling = 30;
}},
new SpawnGroup(atrax){{
@@ -180,7 +187,7 @@ public class DefaultWaves{
unitAmount = 4;
unitScaling = 1;
spacing = 3;
- shieldScaling = 5f;
+ shieldScaling = 10f;
}},
new SpawnGroup(scepter){{
@@ -188,7 +195,7 @@ public class DefaultWaves{
unitAmount = 1;
unitScaling = 1;
spacing = 30;
- shieldScaling = 10f;
+ shieldScaling = 30f;
}},
new SpawnGroup(reign){{
@@ -196,7 +203,7 @@ public class DefaultWaves{
unitAmount = 1;
unitScaling = 1;
spacing = 40;
- shieldScaling = 20f;
+ shieldScaling = 30f;
}},
new SpawnGroup(antumbra){{
@@ -204,7 +211,7 @@ public class DefaultWaves{
unitAmount = 1;
unitScaling = 1;
spacing = 40;
- shieldScaling = 20f;
+ shieldScaling = 30f;
}},
new SpawnGroup(vela){{
@@ -212,7 +219,7 @@ public class DefaultWaves{
unitAmount = 1;
unitScaling = 1;
spacing = 30;
- shieldScaling = 20f;
+ shieldScaling = 30f;
}},
new SpawnGroup(corvus){{
@@ -230,10 +237,10 @@ public class DefaultWaves{
unitScaling = 3;
spacing = 4;
shields = 40f;
- shieldScaling = 20f;
+ shieldScaling = 30f;
}},
- new SpawnGroup(atrax){{
+ new SpawnGroup(toxopid){{
begin = 210;
unitAmount = 1;
unitScaling = 1;
@@ -246,19 +253,17 @@ public class DefaultWaves{
return spawns == null ? new Seq<>() : spawns;
}
- //TODO move elsewhere
public static Seq generate(float difficulty){
return generate(new Rand(), difficulty);
}
- //TODO move elsewhere
public static Seq generate(Rand rand, float difficulty){
UnitType[][] species = {
{dagger, mace, fortress, scepter, reign},
{nova, pulsar, quasar, vela, corvus},
{crawler, atrax, spiroct, arkyid, toxopid},
//{risso, minke, bryde, sei, omura}, //questionable choices
- //{mono, poly, mega, quad, oct}, //do not attack
+ {flare, horizon, difficulty > 0.5 ? poly : zenith, quad, quad},
{flare, horizon, zenith, antumbra, eclipse}
};
@@ -290,7 +295,7 @@ public class DefaultWaves{
begin = f;
end = f + next >= cap ? never : f + next;
max = 14;
- unitScaling = rand.random(1f, 2f);
+ unitScaling = rand.random(1f, 3f);
shields = shieldAmount;
shieldScaling = shieldsPerWave;
spacing = space;
@@ -329,7 +334,7 @@ public class DefaultWaves{
while(step <= cap){
createProgression.get(step);
- step += (int)(rand.random(12, 25) * Mathf.lerp(1f, 0.4f, difficulty));
+ step += (int)(rand.random(13, 25) * Mathf.lerp(1f, 0.5f, difficulty));
}
int bossWave = (int)(rand.random(30, 60) * Mathf.lerp(1f, 0.7f, difficulty));
diff --git a/core/src/mindustry/game/EventType.java b/core/src/mindustry/game/EventType.java
index 272c26363f..1ab946c4ac 100644
--- a/core/src/mindustry/game/EventType.java
+++ b/core/src/mindustry/game/EventType.java
@@ -35,7 +35,13 @@ public class EventType{
preDraw,
postDraw,
uiDrawBegin,
- uiDrawEnd
+ uiDrawEnd,
+ //before/after bloom used, skybox or planets drawn
+ universeDrawBegin,
+ //skybox drawn and bloom is enabled - use Vars.renderer.planets
+ universeDraw,
+ //planets drawn and bloom disabled
+ universeDrawEnd
}
public static class WinEvent{}
@@ -73,6 +79,15 @@ public class EventType{
}
}
+ /** Called when a sector is destroyed by waves when you're not there. */
+ public static class SectorInvasionEvent{
+ public final Sector sector;
+
+ public SectorInvasionEvent(Sector sector){
+ this.sector = sector;
+ }
+ }
+
public static class LaunchItemEvent{
public final ItemStack stack;
@@ -214,8 +229,8 @@ public class EventType{
}
/**
- * Called when block building begins by placing down the BuildBlock.
- * The tile's block will nearly always be a BuildBlock.
+ * Called when block building begins by placing down the ConstructBlock.
+ * The tile's block will nearly always be a ConstructBlock.
*/
public static class BlockBuildBeginEvent{
public final Tile tile;
@@ -247,7 +262,7 @@ public class EventType{
/**
* Called when a player or drone begins building something.
- * This does not necessarily happen when a new BuildBlock is created.
+ * This does not necessarily happen when a new ConstructBlock is created.
*/
public static class BuildSelectEvent{
public final Tile tile;
diff --git a/core/src/mindustry/game/Stats.java b/core/src/mindustry/game/GameStats.java
similarity index 96%
rename from core/src/mindustry/game/Stats.java
rename to core/src/mindustry/game/GameStats.java
index 1d175607ba..8108f2ddad 100644
--- a/core/src/mindustry/game/Stats.java
+++ b/core/src/mindustry/game/GameStats.java
@@ -6,7 +6,7 @@ import mindustry.type.*;
//TODO more stats:
//- units constructed
-public class Stats{
+public class GameStats{
/** Total items delivered to global resoure counter. Campaign only. */
public ObjectIntMap- itemsDelivered = new ObjectIntMap<>();
/** Enemy (red team) units destroyed. */
@@ -40,7 +40,7 @@ public class Stats{
//weigh used fractions
float frac = 0f;
- Seq
- obtainable = zone.save == null ? new Seq<>() : zone.save.meta.secinfo.resources.select(i -> i instanceof Item).as();
+ Seq
- obtainable = zone.save == null ? new Seq<>() : zone.info.resources.select(i -> i instanceof Item).as();
for(Item item : obtainable){
frac += Mathf.clamp((float)itemsDelivered.get(item, 0) / capacity) / (float)obtainable.size;
}
diff --git a/core/src/mindustry/game/Gamemode.java b/core/src/mindustry/game/Gamemode.java
index 9de5e71052..f2bb95130a 100644
--- a/core/src/mindustry/game/Gamemode.java
+++ b/core/src/mindustry/game/Gamemode.java
@@ -23,7 +23,6 @@ public enum Gamemode{
rules.waveTimer = true;
rules.waveSpacing /= 2f;
- rules.teams.get(rules.waveTeam).ai = true;
rules.teams.get(rules.waveTeam).infiniteResources = true;
}, map -> map.teams.contains(state.rules.waveTeam.id)),
pvp(rules -> {
diff --git a/core/src/mindustry/game/Objectives.java b/core/src/mindustry/game/Objectives.java
index a4097c51fc..7fc844a180 100644
--- a/core/src/mindustry/game/Objectives.java
+++ b/core/src/mindustry/game/Objectives.java
@@ -28,7 +28,6 @@ public class Objectives{
}
}
- //TODO fix
public static class SectorComplete extends SectorObjective{
public SectorComplete(SectorPreset zone){
@@ -39,12 +38,12 @@ public class Objectives{
@Override
public boolean complete(){
- return preset.sector.save != null && preset.sector.save.meta.wave >= preset.sector.save.meta.rules.winWave;
+ return preset.sector.save != null && preset.sector.save.meta.wave >= preset.captureWave;
}
@Override
public String display(){
- return Core.bundle.format("requirement.wave", preset.sector.save == null ? "" : preset.sector.save.meta.rules.winWave, preset.localizedName);
+ return Core.bundle.format("requirement.capture", preset.localizedName);
}
}
diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java
index a101fe8592..2a927cc59b 100644
--- a/core/src/mindustry/game/Rules.java
+++ b/core/src/mindustry/game/Rules.java
@@ -82,6 +82,8 @@ public class Rules{
public Seq weather = new Seq<>(1);
/** Blocks that cannot be placed. */
public ObjectSet bannedBlocks = new ObjectSet<>();
+ /** Unlocked content names. Only used in multiplayer when the campaign is enabled. */
+ public ObjectSet researched = new ObjectSet<>();
/** Whether ambient lighting is enabled. */
public boolean lighting = false;
/** Whether enemy lighting is visible.
@@ -104,6 +106,8 @@ public class Rules{
public boolean ai;
/** TODO Tier of blocks/designs that the AI uses for building. [0, 1]*/
public float aiTier = 0f;
+ /** Whether, when AI is enabled, ships should be spawned from the core. */
+ public boolean aiCoreSpawn = true;
/** If true, blocks don't require power or resources. */
public boolean cheat;
/** If true, resources are not consumed when building. */
diff --git a/core/src/mindustry/game/Schematics.java b/core/src/mindustry/game/Schematics.java
index 596a571d3a..20fe7c36c4 100644
--- a/core/src/mindustry/game/Schematics.java
+++ b/core/src/mindustry/game/Schematics.java
@@ -16,6 +16,7 @@ import arc.util.pooling.*;
import arc.util.serialization.*;
import mindustry.*;
import mindustry.content.*;
+import mindustry.core.*;
import mindustry.ctype.*;
import mindustry.entities.units.*;
import mindustry.game.EventType.*;
@@ -608,8 +609,8 @@ public class Schematics implements Loadable{
wx = wy;
wy = -x;
}
- req.x = (short)(world.toTile(wx - req.block.offset) + ox);
- req.y = (short)(world.toTile(wy - req.block.offset) + oy);
+ req.x = (short)(World.toTile(wx - req.block.offset) + ox);
+ req.y = (short)(World.toTile(wy - req.block.offset) + oy);
req.rotation = (byte)Mathf.mod(req.rotation + direction, 4);
});
diff --git a/core/src/mindustry/game/SectorInfo.java b/core/src/mindustry/game/SectorInfo.java
index b66dc5bf95..3b2b4df3dd 100644
--- a/core/src/mindustry/game/SectorInfo.java
+++ b/core/src/mindustry/game/SectorInfo.java
@@ -5,6 +5,7 @@ import arc.struct.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.ctype.*;
+import mindustry.maps.*;
import mindustry.type.*;
import mindustry.world.*;
import mindustry.world.blocks.storage.CoreBlock.*;
@@ -25,9 +26,9 @@ public class SectorInfo{
/** Export statistics. */
public ObjectMap
- export = new ObjectMap<>();
/** Items stored in all cores. */
- public ItemSeq coreItems = new ItemSeq();
+ public ItemSeq items = new ItemSeq();
/** The best available core type. */
- public Block bestCoreType = Blocks.air;
+ public Block bestCoreType = Blocks.coreShard;
/** Max storage capacity. */
public int storageCapacity = 0;
/** Whether a core is available here. */
@@ -38,8 +39,27 @@ public class SectorInfo{
public @Nullable Sector destination;
/** Resources known to occur at this sector. */
public Seq resources = new Seq<>();
- /** Time spent at this sector. Do not use unless you know what you're doing. */
- public transient float internalTimeSpent;
+ /** Whether waves are enabled here. */
+ public boolean waves = true;
+ /** Whether attack mode is enabled here. */
+ public boolean attack = false;
+ /** Wave # from state */
+ public int wave = 1, winWave = -1;
+ /** Time between waves. */
+ public float waveSpacing = 60 * 60 * 2;
+ /** Damage dealt to sector. */
+ public float damage;
+ /** How many waves have passed while the player was away. */
+ public int wavesPassed;
+ /** Packed core spawn position. */
+ public int spawnPosition;
+ /** How long the player has been playing elsewhere. */
+ public float secondsPassed;
+ /** Display name. */
+ public @Nullable String name;
+
+ /** Special variables for simulation. */
+ public float sumHealth, sumRps, sumDps, waveHealthBase, waveHealthSlope, waveDpsBase, waveDpsSlope;
/** Counter refresh state. */
private transient Interval time = new Interval();
@@ -79,26 +99,68 @@ public class SectorInfo{
return export.get(item, ExportStat::new).mean;
}
+ /** Write contents of meta into main storage. */
+ public void write(){
+ //enable attack mode when there's a core.
+ if(state.rules.waveTeam.core() != null){
+ attack = true;
+ winWave = 0;
+ }
+
+ //if there are infinite waves and no win wave, add a win wave.
+ if(waves && winWave <= 0 && !attack){
+ winWave = 30;
+ }
+
+ state.wave = wave;
+ state.rules.waves = waves;
+ state.rules.waveSpacing = waveSpacing;
+ state.rules.winWave = winWave;
+ state.rules.attackMode = attack;
+
+ CoreBuild entity = state.rules.defaultTeam.core();
+ if(entity != null){
+ entity.items.clear();
+ entity.items.add(items);
+ //ensure capacity.
+ entity.items.each((i, a) -> entity.items.set(i, Math.min(a, entity.storageCapacity)));
+ }
+ }
+
/** Prepare data for writing to a save. */
public void prepare(){
//update core items
- coreItems.clear();
+ items.clear();
CoreBuild entity = state.rules.defaultTeam.core();
if(entity != null){
ItemModule items = entity.items;
for(int i = 0; i < items.length(); i++){
- coreItems.set(content.item(i), items.get(i));
+ this.items.set(content.item(i), items.get(i));
}
+
+ spawnPosition = entity.pos();
}
+ waveSpacing = state.rules.waveSpacing;
+ wave = state.wave;
+ winWave = state.rules.winWave;
+ waves = state.rules.waves;
+ attack = state.rules.attackMode;
hasCore = entity != null;
bestCoreType = !hasCore ? Blocks.air : state.rules.defaultTeam.cores().max(e -> e.block.size).block;
storageCapacity = entity != null ? entity.storageCapacity : 0;
+ secondsPassed = 0;
+ wavesPassed = 0;
+ damage = 0;
- //update sector's internal time spent counter
- state.rules.sector.setTimeSpent(internalTimeSpent);
+ if(state.rules.sector != null){
+ state.rules.sector.info = this;
+ state.rules.sector.saveInfo();
+ }
+
+ SectorDamage.writeParameters(this);
}
/** Update averages of various stats, updates some special sector logic.
@@ -107,14 +169,6 @@ public class SectorInfo{
//updating in multiplayer as a client doesn't make sense
if(net.client()) return;
- internalTimeSpent += Time.delta;
-
- //autorun turns
- if(internalTimeSpent >= turnDuration){
- internalTimeSpent = 0;
- universe.runTurn();
- }
-
CoreBuild ent = state.rules.defaultTeam.core();
//refresh throughput
diff --git a/core/src/mindustry/game/SpawnGroup.java b/core/src/mindustry/game/SpawnGroup.java
index f9ae7c74d3..86ba7b6324 100644
--- a/core/src/mindustry/game/SpawnGroup.java
+++ b/core/src/mindustry/game/SpawnGroup.java
@@ -9,6 +9,8 @@ import mindustry.gen.*;
import mindustry.io.legacy.*;
import mindustry.type.*;
+import java.util.*;
+
import static mindustry.Vars.*;
/**
@@ -52,8 +54,8 @@ public class SpawnGroup implements Serializable{
//serialization use only
}
- /** Returns the amount of units spawned on a specific wave. */
- public int getUnitsSpawned(int wave){
+ /** @return amount of units spawned on a specific wave. */
+ public int getSpawned(int wave){
if(spacing == 0) spacing = 1;
if(wave < begin || wave > end || (wave - begin) % spacing != 0){
return 0;
@@ -61,6 +63,11 @@ public class SpawnGroup implements Serializable{
return Math.min(unitAmount + (int)(((wave - begin) / spacing) / unitScaling), max);
}
+ /** @return amount of shields each unit has at a specific wave. */
+ public float getShield(int wave){
+ return Math.max(shields + shieldScaling*(wave - begin), 0);
+ }
+
/**
* Creates a unit, and assigns correct values based on this group's data.
* This method does not add() the unit.
@@ -76,7 +83,7 @@ public class SpawnGroup implements Serializable{
unit.addItem(items.item, items.amount);
}
- unit.shield(Math.max(shields + shieldScaling*(wave - begin), 0));
+ unit.shield = getShield(wave);
return unit;
}
@@ -133,4 +140,20 @@ public class SpawnGroup implements Serializable{
", items=" + items +
'}';
}
+
+ @Override
+ public boolean equals(Object o){
+ if(this == o) return true;
+ if(o == null || getClass() != o.getClass()) return false;
+ SpawnGroup group = (SpawnGroup)o;
+ return end == group.end && begin == group.begin && spacing == group.spacing && max == group.max
+ && Float.compare(group.unitScaling, unitScaling) == 0 && Float.compare(group.shields, shields) == 0
+ && Float.compare(group.shieldScaling, shieldScaling) == 0 && unitAmount == group.unitAmount &&
+ type == group.type && effect == group.effect && Structs.eq(items, group.items);
+ }
+
+ @Override
+ public int hashCode(){
+ return Arrays.hashCode(new Object[]{type, end, begin, spacing, max, unitScaling, shields, shieldScaling, unitAmount, effect, items});
+ }
}
diff --git a/core/src/mindustry/game/Team.java b/core/src/mindustry/game/Team.java
index 1234c7b2d7..cbed06f4e7 100644
--- a/core/src/mindustry/game/Team.java
+++ b/core/src/mindustry/game/Team.java
@@ -31,9 +31,9 @@ public class Team implements Comparable{
Color.valueOf("ffd37f"), Color.valueOf("eab678"), Color.valueOf("d4816b")),
crux = new Team(2, "crux", Color.valueOf("f25555"),
Color.valueOf("fc8e6c"), Color.valueOf("f25555"), Color.valueOf("a04553")),
- green = new Team(3, "green", Color.valueOf("4dd98b")),
- purple = new Team(4, "purple", Color.valueOf("9a4bdf")),
- blue = new Team(5, "blue", Color.royal.cpy());
+ green = new Team(3, "green", Color.valueOf("54d67d")),
+ purple = new Team(4, "purple", Color.valueOf("995bb0")),
+ blue = new Team(5, "blue", Color.valueOf("5a4deb"));
static{
Mathf.rand.setSeed(8);
diff --git a/core/src/mindustry/game/Teams.java b/core/src/mindustry/game/Teams.java
index aa390c5d26..6a2972f074 100644
--- a/core/src/mindustry/game/Teams.java
+++ b/core/src/mindustry/game/Teams.java
@@ -131,7 +131,7 @@ public class Teams{
}
private void count(Unit unit){
- unit.team.data().updateCount(unit.type(), 1);
+ unit.team.data().updateCount(unit.type, 1);
if(unit instanceof Payloadc){
((Payloadc)unit).payloads().each(p -> {
@@ -178,15 +178,15 @@ public class Teams{
data.units.add(unit);
data.presentFlag = true;
- if(data.unitsByType == null || data.unitsByType.length <= unit.type().id){
+ if(data.unitsByType == null || data.unitsByType.length <= unit.type.id){
data.unitsByType = new Seq[content.units().size];
}
- if(data.unitsByType[unit.type().id] == null){
- data.unitsByType[unit.type().id] = new Seq<>();
+ if(data.unitsByType[unit.type.id] == null){
+ data.unitsByType[unit.type.id] = new Seq<>();
}
- data.unitsByType[unit.type().id].add(unit);
+ data.unitsByType[unit.type.id].add(unit);
count(unit);
}
diff --git a/core/src/mindustry/game/Universe.java b/core/src/mindustry/game/Universe.java
index 892b93b731..9fa93eb840 100644
--- a/core/src/mindustry/game/Universe.java
+++ b/core/src/mindustry/game/Universe.java
@@ -6,6 +6,8 @@ import arc.struct.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.game.EventType.*;
+import mindustry.io.legacy.*;
+import mindustry.maps.*;
import mindustry.type.*;
import mindustry.world.blocks.storage.*;
@@ -17,6 +19,7 @@ public class Universe{
private int netSeconds;
private float secondCounter;
private int turn;
+ private float turnCounter;
private Schematic lastLoadout;
private ItemSeq lastLaunchResources = new ItemSeq();
@@ -53,17 +56,19 @@ public class Universe{
}
}
- /** @return sectors attacked on the current planet, minus the ones that are being played on right now. */
- public Seq getAttacked(Planet planet){
- return planet.sectors.select(s -> s.hasWaves() && s.hasBase() && !s.isBeingPlayed() && s.getSecondsPassed() > 1);
- }
-
/** Update planet rotations, global time and relevant state. */
public void update(){
//only update time when not in multiplayer
if(!net.client()){
secondCounter += Time.delta / 60f;
+ turnCounter += Time.delta;
+
+ //auto-run turns
+ if(turnCounter >= turnDuration){
+ turnCounter = 0;
+ runTurn();
+ }
if(secondCounter >= 1){
seconds += (int)secondCounter;
@@ -132,42 +137,81 @@ public class Universe{
//update relevant sectors
for(Planet planet : content.planets()){
for(Sector sector : planet.sectors){
- if(sector.hasSave()){
- int spent = (int)(sector.getTimeSpent() / 60);
- int actuallyPassed = Math.max(newSecondsPassed - spent, 0);
+ if(sector.hasSave() && sector.hasBase()){
//increment seconds passed for this sector by the time that just passed with this turn
if(!sector.isBeingPlayed()){
- sector.setSecondsPassed(sector.getSecondsPassed() + actuallyPassed);
+ //increment time
+ sector.info.secondsPassed += turnDuration/60f;
+
+ int wavesPassed = (int)(sector.info.secondsPassed*60f / sector.info.waveSpacing);
+ boolean attacked = sector.info.waves;
+
+ if(attacked){
+ sector.info.wavesPassed = wavesPassed;
+ }
+
+ float damage = attacked ? SectorDamage.getDamage(sector.info) : 0f;
+
+ //damage never goes down until the player visits the sector, so use max
+ sector.info.damage = Math.max(sector.info.damage, damage);
- //TODO sector damage disabled for now
//check if the sector has been attacked too many times...
- /*if(sector.hasBase() && sector.hasWaves() && sector.getSecondsPassed() * 60f > turnDuration * sectorDestructionTurns){
+ if(attacked && damage >= 0.999f){
//fire event for losing the sector
Events.fire(new SectorLoseEvent(sector));
- //if so, just delete the save for now. it's lost.
- //TODO don't delete it later maybe
- sector.save.delete();
- //clear recieved
- sector.setExtraItems(new ItemSeq());
- sector.save = null;
- }*/
+ //sector is dead.
+ sector.info.items.clear();
+ sector.info.damage = 1f;
+ sector.info.hasCore = false;
+ sector.info.production.clear();
+ }else if(attacked && wavesPassed > 0 && sector.info.winWave > 1 && sector.info.wave + wavesPassed >= sector.info.winWave && !sector.hasEnemyBase()){
+ //autocapture the sector
+ sector.info.waves = false;
+
+ //fire the event
+ Events.fire(new SectorCaptureEvent(sector));
+ }
+
+ float scl = sector.getProductionScale();
+
+ //export to another sector
+ if(sector.info.destination != null){
+ Sector to = sector.info.destination;
+ if(to.hasBase()){
+ ItemSeq items = new ItemSeq();
+ //calculated exported items to this sector
+ sector.info.export.each((item, stat) -> items.add(item, (int)(stat.mean * newSecondsPassed * scl)));
+ to.addItems(items);
+ }
+ }
+
+ //add production, making sure that it's capped
+ sector.info.production.each((item, stat) -> sector.info.items.add(item, Math.min((int)(stat.mean * newSecondsPassed * scl), sector.info.storageCapacity - sector.info.items.get(item))));
+
+ sector.saveInfo();
}
- //export to another sector
- if(sector.save != null && sector.save.meta != null && sector.save.meta.secinfo != null && sector.save.meta.secinfo.destination != null){
- Sector to = sector.save.meta.secinfo.destination;
- if(to.save != null){
- ItemSeq items = new ItemSeq();
- //calculated exported items to this sector
- sector.save.meta.secinfo.export.each((item, stat) -> items.add(item, (int)(stat.mean * newSecondsPassed)));
- to.addItems(items);
+ //queue random invasions
+ if(!sector.isAttacked() && turn > invasionGracePeriod){
+ //invasion chance depends on # of nearby bases
+ if(Mathf.chance(baseInvasionChance * sector.near().count(Sector::hasEnemyBase))){
+ int waveMax = Math.max(sector.info.winWave, sector.isBeingPlayed() ? state.wave : 0) + Mathf.random(2, 5) * 5;
+
+ //assign invasion-related things
+ if(sector.isBeingPlayed()){
+ state.rules.winWave = waveMax;
+ state.rules.waves = true;
+ }else{
+ sector.info.winWave = waveMax;
+ sector.info.waves = true;
+ sector.saveInfo();
+ }
+
+ Events.fire(new SectorInvasionEvent(sector));
}
}
-
- //reset time spent to 0
- sector.setTimeSpent(0f);
}
}
}
@@ -184,7 +228,7 @@ public class Universe{
for(Planet planet : content.planets()){
for(Sector sector : planet.sectors){
if(sector.hasSave()){
- count.add(sector.calculateItems());
+ count.add(sector.items());
}
}
}
@@ -217,6 +261,10 @@ public class Universe{
private void load(){
seconds = Core.settings.getInt("utimei");
turn = Core.settings.getInt("turn");
+
+ if(Core.settings.has("unlocks")){
+ LegacyIO.readResearch();
+ }
}
}
diff --git a/core/src/mindustry/graphics/BlockRenderer.java b/core/src/mindustry/graphics/BlockRenderer.java
index a36230f0aa..7e90fba3ff 100644
--- a/core/src/mindustry/graphics/BlockRenderer.java
+++ b/core/src/mindustry/graphics/BlockRenderer.java
@@ -20,11 +20,14 @@ import static arc.Core.*;
import static mindustry.Vars.*;
public class BlockRenderer implements Disposable{
+ public static final int crackRegions = 8, maxCrackSize = 9;
+
private static final int initialRequests = 32 * 32;
private static final int expandr = 9;
private static final Color shadowColor = new Color(0, 0, 0, 0.71f);
public final FloorRenderer floor = new FloorRenderer();
+ public TextureRegion[][] cracks;
private Seq tileview = new Seq<>(false, initialRequests, Tile.class);
private Seq lightview = new Seq<>(false, initialRequests, Tile.class);
@@ -35,11 +38,20 @@ public class BlockRenderer implements Disposable{
private FrameBuffer dark = new FrameBuffer();
private Seq outArray2 = new Seq<>();
private Seq shadowEvents = new Seq<>();
- private IntSet processedEntities = new IntSet(), processedLinks = new IntSet();
+ private IntSet procEntities = new IntSet(), procLinks = new IntSet(), procLights = new IntSet();
private boolean displayStatus = false;
public BlockRenderer(){
+ Events.on(ClientLoadEvent.class, e -> {
+ cracks = new TextureRegion[maxCrackSize][crackRegions];
+ for(int size = 1; size <= maxCrackSize; size++){
+ for(int i = 0; i < crackRegions; i++){
+ cracks[size - 1][i] = Core.atlas.find("cracks-" + size + "-" + i);
+ }
+ }
+ });
+
Events.on(WorldLoadEvent.class, event -> {
shadowEvents.clear();
lastCamY = lastCamX = -99; //invalidate camera position so blocks get updated
@@ -179,8 +191,9 @@ public class BlockRenderer implements Disposable{
tileview.clear();
lightview.clear();
- processedEntities.clear();
- processedLinks.clear();
+ procEntities.clear();
+ procLinks.clear();
+ procLights.clear();
int minx = Math.max(avgx - rangex - expandr, 0);
int miny = Math.max(avgy - rangey - expandr, 0);
@@ -197,25 +210,25 @@ public class BlockRenderer implements Disposable{
tile = tile.build.tile;
}
- if(block != Blocks.air && block.cacheLayer == CacheLayer.normal && (tile.build == null || !processedEntities.contains(tile.build.id))){
+ if(block != Blocks.air && block.cacheLayer == CacheLayer.normal && (tile.build == null || !procEntities.contains(tile.build.id))){
if(block.expanded || !expanded){
- if(tile.build == null || processedLinks.add(tile.build.id)){
+ if(tile.build == null || procLinks.add(tile.build.id)){
tileview.add(tile);
if(tile.build != null){
- processedEntities.add(tile.build.id);
- processedLinks.add(tile.build.id);
+ procEntities.add(tile.build.id);
+ procLinks.add(tile.build.id);
}
}
}
//lights are drawn even in the expanded range
- if(tile.build != null || tile.block().emitLight){
+ if(((tile.build != null && procLights.add(tile.build.pos())) || tile.block().emitLight)){
lightview.add(tile);
}
if(tile.build != null && tile.build.power != null && tile.build.power.links.size > 0){
for(Building other : tile.build.getPowerConnections(outArray2)){
- if(other.block instanceof PowerNode && processedLinks.add(other.id)){ //TODO need a generic way to render connections!
+ if(other.block instanceof PowerNode && procLinks.add(other.id)){ //TODO need a generic way to render connections!
tileview.add(other.tile);
}
}
@@ -223,7 +236,7 @@ public class BlockRenderer implements Disposable{
}
//special case for floors
- if(block == Blocks.air && tile.floor().emitLight){
+ if((block == Blocks.air && tile.floor().emitLight) && procLights.add(tile.pos())){
lightview.add(tile);
}
}
@@ -280,7 +293,7 @@ public class BlockRenderer implements Disposable{
entity.drawLight();
}else if(tile.block().emitLight){
tile.block().drawEnvironmentLight(tile);
- }else if(tile.floor().emitLight){
+ }else if(tile.floor().emitLight && !tile.block().solid && world.getDarkness(tile.x, tile.y) < 3){ //only draw floor light under non-solid blocks
tile.floor().drawEnvironmentLight(tile);
}
}
diff --git a/core/src/mindustry/graphics/LightRenderer.java b/core/src/mindustry/graphics/LightRenderer.java
index 10ffa727b6..0a05c7409b 100644
--- a/core/src/mindustry/graphics/LightRenderer.java
+++ b/core/src/mindustry/graphics/LightRenderer.java
@@ -100,7 +100,6 @@ public class LightRenderer{
Draw.vert(ledge.texture, vertices, 0, vertices.length);
-
Vec2 v3 = Tmp.v2.trnsExact(rot, stroke);
u = ledge.u;
diff --git a/core/src/mindustry/graphics/MinimapRenderer.java b/core/src/mindustry/graphics/MinimapRenderer.java
index cdb84e9044..b3c39bfa27 100644
--- a/core/src/mindustry/graphics/MinimapRenderer.java
+++ b/core/src/mindustry/graphics/MinimapRenderer.java
@@ -96,7 +96,7 @@ public class MinimapRenderer implements Disposable{
Draw.mixcol(unit.team().color, 1f);
float scale = Scl.scl(1f) / 2f * scaling * 32f;
- Draw.rect(unit.type().icon(Cicon.full), x + rx, y + ry, scale, scale, unit.rotation() - 90);
+ Draw.rect(unit.type.icon(Cicon.full), x + rx, y + ry, scale, scale, unit.rotation() - 90);
Draw.reset();
//only disable player names in multiplayer
@@ -158,7 +158,7 @@ public class MinimapRenderer implements Disposable{
private int colorFor(Tile tile){
if(tile == null) return 0;
int bc = tile.block().minimapColor(tile);
- Color color = Tmp.c1.set(bc == 0 ? MapIO.colorFor(tile.floor(), tile.block(), tile.overlay(), tile.team()) : bc);
+ Color color = Tmp.c1.set(bc == 0 ? MapIO.colorFor(tile.block(), tile.floor(), tile.overlay(), tile.team()) : bc);
color.mul(1f - Mathf.clamp(world.getDarkness(tile.x, tile.y) / 4f));
return color.rgba();
diff --git a/core/src/mindustry/graphics/OverlayRenderer.java b/core/src/mindustry/graphics/OverlayRenderer.java
index 19569ed1a3..9bb3a95fa3 100644
--- a/core/src/mindustry/graphics/OverlayRenderer.java
+++ b/core/src/mindustry/graphics/OverlayRenderer.java
@@ -85,7 +85,7 @@ public class OverlayRenderer{
//special selection for block "units"
Fill.square(select.x, select.y, ((BlockUnitc)select).tile().block.size * tilesize/2f);
}else{
- Draw.rect(select.type().icon(Cicon.full), select.x(), select.y(), select.rotation() - 90);
+ Draw.rect(select.type.icon(Cicon.full), select.x(), select.y(), select.rotation() - 90);
}
Lines.stroke(unitFade);
@@ -121,10 +121,12 @@ public class OverlayRenderer{
Lines.stroke(2f);
Draw.color(Color.gray, Color.lightGray, Mathf.absin(Time.time(), 8f, 1f));
- for(Tile tile : spawner.getSpawns()){
- if(tile.within(player.x, player.y, state.rules.dropZoneRadius + spawnerMargin)){
- Draw.alpha(Mathf.clamp(1f - (player.dst(tile) - state.rules.dropZoneRadius) / spawnerMargin));
- Lines.dashCircle(tile.worldx(), tile.worldy(), state.rules.dropZoneRadius);
+ if(state.hasSpawns()){
+ for(Tile tile : spawner.getSpawns()){
+ if(tile.within(player.x, player.y, state.rules.dropZoneRadius + spawnerMargin)){
+ Draw.alpha(Mathf.clamp(1f - (player.dst(tile) - state.rules.dropZoneRadius) / spawnerMargin));
+ Lines.dashCircle(tile.worldx(), tile.worldy(), state.rules.dropZoneRadius);
+ }
}
}
diff --git a/core/src/mindustry/graphics/Pal.java b/core/src/mindustry/graphics/Pal.java
index 753bbbbbed..8bb3cd9e70 100644
--- a/core/src/mindustry/graphics/Pal.java
+++ b/core/src/mindustry/graphics/Pal.java
@@ -94,5 +94,7 @@ public class Pal{
redDust = Color.valueOf("ffa480"),
redderDust = Color.valueOf("ff7b69"),
- plasticSmoke = Color.valueOf("f1e479");
+ plasticSmoke = Color.valueOf("f1e479"),
+
+ adminChat = Color.valueOf("ff4000");
}
diff --git a/core/src/mindustry/graphics/g3d/PlanetGrid.java b/core/src/mindustry/graphics/g3d/PlanetGrid.java
index e4972e3eb7..380f937658 100644
--- a/core/src/mindustry/graphics/g3d/PlanetGrid.java
+++ b/core/src/mindustry/graphics/g3d/PlanetGrid.java
@@ -22,15 +22,16 @@ public class PlanetGrid{
{5, 3, 10, 1, 4}, {2, 5, 4, 0, 11}, {3, 7, 6, 1, 8}, {7, 2, 9, 0, 6}
};
- public final int size;
- public final Ptile[] tiles;
- public final Corner[] corners;
- public final Edge[] edges;
+ public int size;
+ public Ptile[] tiles;
+ public Corner[] corners;
+ public Edge[] edges;
- PlanetGrid(int size){
+ //this is protected so if you want to make strange grids you should know what you're doing.
+ protected PlanetGrid(int size){
this.size = size;
- tiles = new Ptile[Buildingount(size)];
+ tiles = new Ptile[tileCount(size)];
for(int i = 0; i < tiles.length; i++){
tiles[i] = new Ptile(i, i < 12 ? 5 : 6);
}
@@ -67,7 +68,7 @@ public class PlanetGrid{
return result;
}
- static PlanetGrid initialGrid(){
+ public static PlanetGrid initialGrid(){
PlanetGrid grid = new PlanetGrid(0);
for(Ptile t : grid.tiles){
@@ -111,7 +112,7 @@ public class PlanetGrid{
return grid;
}
- static PlanetGrid subdividedGrid(PlanetGrid prev){
+ public static PlanetGrid subdividedGrid(PlanetGrid prev){
PlanetGrid grid = new PlanetGrid(prev.size + 1);
int prevTiles = prev.tiles.length;
@@ -207,7 +208,7 @@ public class PlanetGrid{
return -1;
}
- static int Buildingount(int size){
+ static int tileCount(int size){
return 10 * Mathf.pow(3, size) + 2;
}
@@ -220,12 +221,12 @@ public class PlanetGrid{
}
public static class Ptile{
- public final int id;
- public final int edgeCount;
+ public int id;
+ public int edgeCount;
- public final Ptile[] tiles;
- public final Corner[] corners;
- public final Edge[] edges;
+ public Ptile[] tiles;
+ public Corner[] corners;
+ public Edge[] edges;
public Vec3 v = new Vec3();
@@ -240,11 +241,11 @@ public class PlanetGrid{
}
public static class Corner{
- public final int id;
- public final Ptile[] tiles = new Ptile[3];
- public final Corner[] corners = new Corner[3];
- public final Edge[] edges = new Edge[3];
- public final Vec3 v = new Vec3();
+ public int id;
+ public Ptile[] tiles = new Ptile[3];
+ public Corner[] corners = new Corner[3];
+ public Edge[] edges = new Edge[3];
+ public Vec3 v = new Vec3();
public Corner(int id){
this.id = id;
@@ -252,9 +253,9 @@ public class PlanetGrid{
}
public static class Edge{
- public final int id;
- public final Ptile[] tiles = new Ptile[2];
- public final Corner[] corners = new Corner[2];
+ public int id;
+ public Ptile[] tiles = new Ptile[2];
+ public Corner[] corners = new Corner[2];
public Edge(int id){
this.id = id;
diff --git a/core/src/mindustry/graphics/g3d/PlanetRenderer.java b/core/src/mindustry/graphics/g3d/PlanetRenderer.java
index e3eb74a7b5..405d668333 100644
--- a/core/src/mindustry/graphics/g3d/PlanetRenderer.java
+++ b/core/src/mindustry/graphics/g3d/PlanetRenderer.java
@@ -10,6 +10,7 @@ import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import mindustry.content.*;
+import mindustry.game.EventType.*;
import mindustry.graphics.*;
import mindustry.graphics.g3d.PlanetGrid.*;
import mindustry.type.*;
@@ -38,19 +39,19 @@ public class PlanetRenderer implements Disposable{
public float zoom = 1f;
private final Mesh[] outlines = new Mesh[10];
- private final PlaneBatch3D projector = new PlaneBatch3D();
- private final Mat3D mat = new Mat3D();
- private final FrameBuffer buffer = new FrameBuffer(2, 2, true);
- private PlanetInterfaceRenderer irenderer;
+ public final PlaneBatch3D projector = new PlaneBatch3D();
+ public final Mat3D mat = new Mat3D();
+ public final FrameBuffer buffer = new FrameBuffer(2, 2, true);
+ public PlanetInterfaceRenderer irenderer;
- private final Bloom bloom = new Bloom(Core.graphics.getWidth()/4, Core.graphics.getHeight()/4, true, false){{
+ public final Bloom bloom = new Bloom(Core.graphics.getWidth()/4, Core.graphics.getHeight()/4, true, false){{
setThreshold(0.8f);
blurPasses = 6;
}};
- private final Mesh atmosphere = MeshBuilder.buildHex(Color.white, 2, false, 1.5f);
+ public final Mesh atmosphere = MeshBuilder.buildHex(Color.white, 2, false, 1.5f);
//seed: 8kmfuix03fw
- private final CubemapMesh skybox = new CubemapMesh(new Cubemap("cubemaps/stars/"));
+ public final CubemapMesh skybox = new CubemapMesh(new Cubemap("cubemaps/stars/"));
public PlanetRenderer(){
camPos.set(0, 0f, camLength);
@@ -82,14 +83,20 @@ public class PlanetRenderer implements Disposable{
projector.proj(cam.combined);
batch.proj(cam.combined);
+ Events.fire(Trigger.universeDrawBegin);
+
beginBloom();
skybox.render(cam.combined);
+ Events.fire(Trigger.universeDraw);
+
renderPlanet(solarSystem);
endBloom();
+ Events.fire(Trigger.universeDrawEnd);
+
Gl.enable(Gl.blend);
irenderer.renderProjections();
@@ -100,18 +107,21 @@ public class PlanetRenderer implements Disposable{
cam.update();
}
- private void beginBloom(){
+ public void beginBloom(){
bloom.resize(Core.graphics.getWidth() / 4, Core.graphics.getHeight() / 4);
bloom.capture();
}
- private void endBloom(){
+ public void endBloom(){
bloom.render();
}
- private void renderPlanet(Planet planet){
+
+ public void renderPlanet(Planet planet){
+ if(!planet.visible()) return;
+
//render planet at offsetted position in the world
- planet.mesh.render(cam.combined, planet.getTransform(mat));
+ planet.draw(cam.combined, planet.getTransform(mat));
renderOrbit(planet);
@@ -137,8 +147,8 @@ public class PlanetRenderer implements Disposable{
}
}
- private void renderOrbit(Planet planet){
- if(planet.parent == null) return;
+ public void renderOrbit(Planet planet){
+ if(planet.parent == null || !planet.visible()) return;
Vec3 center = planet.parent.position;
float radius = planet.orbitRadius;
@@ -147,7 +157,7 @@ public class PlanetRenderer implements Disposable{
batch.flush(Gl.lineLoop);
}
- private void renderSectors(Planet planet){
+ public void renderSectors(Planet planet){
//apply transformed position
batch.proj().mul(planet.getTransform(mat));
@@ -268,7 +278,7 @@ public class PlanetRenderer implements Disposable{
}
}
- private Mesh outline(int size){
+ public Mesh outline(int size){
if(outlines[size] == null){
outlines[size] = MeshBuilder.buildHex(new HexMesher(){
@Override
diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java
index 7099f254dd..049853c864 100644
--- a/core/src/mindustry/input/DesktopInput.java
+++ b/core/src/mindustry/input/DesktopInput.java
@@ -12,6 +12,7 @@ import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.*;
+import mindustry.core.*;
import mindustry.entities.units.*;
import mindustry.game.EventType.*;
import mindustry.game.*;
@@ -352,9 +353,7 @@ public class DesktopInput extends InputHandler{
ui.planet.show();
}).visible(() -> state.isCampaign()).tooltip("@planetmap");
- table.button(Icon.up, Styles.clearPartiali, () -> {
- ui.planet.showLaunch(state.getSector(), player.team().core());
- }).visible(() -> state.isCampaign()).tooltip("@launchcore").disabled(b -> player.team().core() == null);
+ table.add();
}
void pollInput(){
@@ -363,7 +362,7 @@ public class DesktopInput extends InputHandler{
Tile selected = tileAt(Core.input.mouseX(), Core.input.mouseY());
int cursorX = tileX(Core.input.mouseX());
int cursorY = tileY(Core.input.mouseY());
- int rawCursorX = world.toTile(Core.input.mouseWorld().x), rawCursorY = world.toTile(Core.input.mouseWorld().y);
+ int rawCursorX = World.toTile(Core.input.mouseWorld().x), rawCursorY = World.toTile(Core.input.mouseWorld().y);
// automatically pause building if the current build queue is empty
if(Core.settings.getBool("buildautopause") && isBuilding && !player.builder().isBuilding()){
@@ -599,11 +598,11 @@ public class DesktopInput extends InputHandler{
}
protected void updateMovement(Unit unit){
- boolean omni = unit.type().omniMovement;
+ boolean omni = unit.type.omniMovement;
boolean ground = unit.isGrounded();
- float strafePenalty = ground ? 1f : Mathf.lerp(1f, unit.type().strafePenalty, Angles.angleDist(unit.vel().angle(), unit.rotation()) / 180f);
- float baseSpeed = unit.type().speed;
+ float strafePenalty = ground ? 1f : Mathf.lerp(1f, unit.type.strafePenalty, Angles.angleDist(unit.vel().angle(), unit.rotation()) / 180f);
+ float baseSpeed = unit.type.speed;
//limit speed to minimum formation speed to preserve formation
if(unit.isCommanding()){
@@ -611,7 +610,7 @@ public class DesktopInput extends InputHandler{
baseSpeed = unit.minFormationSpeed * 0.95f;
}
- float speed = baseSpeed * Mathf.lerp(1f, unit.isCommanding() ? 1f : unit.type().canBoost ? unit.type().boostMultiplier : 1f, unit.elevation) * strafePenalty;
+ float speed = baseSpeed * Mathf.lerp(1f, unit.type.canBoost ? unit.type.boostMultiplier : 1f, unit.elevation) * strafePenalty;
float xa = Core.input.axis(Binding.move_x);
float ya = Core.input.axis(Binding.move_y);
boolean boosted = (unit instanceof Mechc && unit.isFlying());
@@ -622,7 +621,7 @@ public class DesktopInput extends InputHandler{
}
float mouseAngle = Angles.mouseAngle(unit.x, unit.y);
- boolean aimCursor = omni && player.shooting && unit.type().hasWeapons() && unit.type().faceTarget && !boosted && unit.type().rotateShooting;
+ boolean aimCursor = omni && player.shooting && unit.type.hasWeapons() && unit.type.faceTarget && !boosted && unit.type.rotateShooting;
if(aimCursor){
unit.lookAt(mouseAngle);
@@ -637,11 +636,11 @@ public class DesktopInput extends InputHandler{
}else{
unit.moveAt(Tmp.v2.trns(unit.rotation, movement.len()));
if(!movement.isZero() && ground){
- unit.vel.rotateTo(movement.angle(), unit.type().rotateSpeed);
+ unit.vel.rotateTo(movement.angle(), unit.type.rotateSpeed);
}
}
- unit.aim(unit.type().faceTarget ? Core.input.mouseWorld() : Tmp.v1.trns(unit.rotation, Core.input.mouseWorld().dst(unit)).add(unit.x, unit.y));
+ unit.aim(unit.type.faceTarget ? Core.input.mouseWorld() : Tmp.v1.trns(unit.rotation, Core.input.mouseWorld().dst(unit)).add(unit.x, unit.y));
unit.controlWeapons(true, player.shooting && !boosted);
player.boosting = Core.input.keyDown(Binding.boost) && !movement.isZero();
@@ -660,7 +659,7 @@ public class DesktopInput extends InputHandler{
}
}
- //update commander inut
+ //update commander unit
if(Core.input.keyTap(Binding.command)){
Call.unitCommand(player);
}
diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java
index eebe40e15b..adeb6d3c2b 100644
--- a/core/src/mindustry/input/InputHandler.java
+++ b/core/src/mindustry/input/InputHandler.java
@@ -16,6 +16,7 @@ import arc.util.*;
import mindustry.ai.formations.patterns.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
+import mindustry.core.*;
import mindustry.entities.*;
import mindustry.entities.units.*;
import mindustry.game.EventType.*;
@@ -125,24 +126,62 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
@Remote(called = Loc.server, targets = Loc.both, forward = true)
public static void requestItem(Player player, Building tile, Item item, int amount){
if(player == null || tile == null || !tile.interactable(player.team()) || !player.within(tile, buildingRange) || player.dead()) return;
- amount = Math.min(player.unit().maxAccepted(item), amount);
- int fa = amount;
-
- if(amount == 0) return;
if(net.server() && (!Units.canInteract(player, tile) ||
!netServer.admins.allowAction(player, ActionType.withdrawItem, tile.tile(), action -> {
action.item = item;
- action.itemAmount = fa;
+ action.itemAmount = amount;
}))) throw new ValidateException(player, "Player cannot request items.");
- int removed = tile.removeStack(item, amount);
+ //remove item for every controlling unit
+ player.unit().eachGroup(unit -> {
+ int removed = Math.min(unit.maxAccepted(item), tile.removeStack(item, amount));
- player.unit().addItem(item, removed);
- Events.fire(new WithdrawEvent(tile, player, item, amount));
- for(int j = 0; j < Mathf.clamp(removed / 3, 1, 8); j++){
- Time.run(j * 3f, () -> Call.transferItemEffect(item, tile.x, tile.y, player.unit()));
+ unit.addItem(item, removed);
+
+ for(int j = 0; j < Mathf.clamp(removed / 3, 1, 8); j++){
+ Time.run(j * 3f, () -> Call.transferItemEffect(item, tile.x, tile.y, unit));
+ }
+
+ if(unit == player.unit()){
+ Events.fire(new WithdrawEvent(tile, player, item, amount));
+ }
+ });
+ }
+
+ @Remote(targets = Loc.both, forward = true, called = Loc.server)
+ public static void transferInventory(Player player, Building tile){
+ if(player == null || tile == null || !player.within(tile, buildingRange) || tile.items == null || player.dead()) return;
+
+ if(net.server() && (player.unit().stack.amount <= 0 || !Units.canInteract(player, tile) ||
+ !netServer.admins.allowAction(player, ActionType.depositItem, tile.tile, action -> {
+ action.itemAmount = player.unit().stack.amount;
+ action.item = player.unit().item();
+ }))){
+ throw new ValidateException(player, "Player cannot transfer an item.");
}
+
+ //deposit for every controlling unit
+ player.unit().eachGroup(unit -> {
+ Item item = unit.item();
+ int accepted = tile.acceptStack(item, unit.stack.amount, unit);
+ unit.stack.amount -= accepted;
+
+ tile.getStackOffset(item, stackTrns);
+ tile.handleStack(item, accepted, unit);
+
+ createItemTransfer(
+ item,
+ accepted,
+ unit.x + Angles.trnsx(unit.rotation + 180f, backTrns), unit.y + Angles.trnsy(unit.rotation + 180f, backTrns),
+ new Vec2(tile.x + stackTrns.x, tile.y + stackTrns.y),
+ () -> {}
+ );
+
+ if(unit == player.unit()){
+ Events.fire(new DepositEvent(tile, player, item, accepted));
+ }
+ });
}
@Remote(variants = Variant.one)
@@ -158,7 +197,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
Payloadc pay = (Payloadc)unit;
if(target.isAI() && target.isGrounded() && pay.canPickup(target)
- && target.within(unit, unit.type().hitSize * 2f + target.type().hitSize * 2f)){
+ && target.within(unit, unit.type.hitSize * 2f + target.type.hitSize * 2f)){
Call.pickedUnitPayload(unit, target);
}
}
@@ -240,6 +279,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
pay.set(x, y);
pay.dropLastPayload();
pay.set(prevx, prevy);
+ pay.controlling().each(u -> {
+ if(u instanceof Payloadc){
+ Call.payloadDropped(u, u.x, u.y);
+ }
+ });
}
}
@@ -270,37 +314,6 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
tile.noSleep();
}
- @Remote(targets = Loc.both, forward = true, called = Loc.server)
- public static void transferInventory(Player player, Building tile){
- if(player == null || tile == null || !player.within(tile, buildingRange) || tile.items == null || player.dead()) return;
-
- if(net.server() && (player.unit().stack.amount <= 0 || !Units.canInteract(player, tile) ||
- !netServer.admins.allowAction(player, ActionType.depositItem, tile.tile, action -> {
- action.itemAmount = player.unit().stack.amount;
- action.item = player.unit().item();
- }))){
- throw new ValidateException(player, "Player cannot transfer an item.");
- }
-
- Item item = player.unit().item();
- int amount = player.unit().stack.amount;
- int accepted = tile.acceptStack(item, amount, player.unit());
- player.unit().stack.amount -= accepted;
-
- Core.app.post(() -> Events.fire(new DepositEvent(tile, player, item, accepted)));
-
- tile.getStackOffset(item, stackTrns);
- tile.handleStack(item, accepted, player.unit());
-
- createItemTransfer(
- item,
- amount,
- player.x + Angles.trnsx(player.unit().rotation + 180f, backTrns), player.y + Angles.trnsy(player.unit().rotation + 180f, backTrns),
- new Vec2(tile.x + stackTrns.x, tile.y + stackTrns.y),
- () -> {}
- );
- }
-
@Remote(targets = Loc.both, called = Loc.both, forward = true)
public static void tileConfig(@Nullable Player player, Building tile, @Nullable Object value){
if(tile == null) return;
@@ -365,7 +378,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
if(commander.isCommanding()){
commander.clearCommand();
- }else if(player.unit().type().commandLimit > 0){
+ }else if(player.unit().type.commandLimit > 0){
//TODO try out some other formations
commander.commandNearby(new CircleFormation());
@@ -398,17 +411,17 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
}
if(player.shooting && !wasShooting && player.unit().hasWeapons() && state.rules.unitAmmo && player.unit().ammo <= 0){
- player.unit().type().weapons.first().noAmmoSound.at(player.unit());
+ player.unit().type.weapons.first().noAmmoSound.at(player.unit());
}
wasShooting = player.shooting;
if(!player.dead()){
- controlledType = player.unit().type();
+ controlledType = player.unit().type;
}
if(controlledType != null && player.dead()){
- Unit unit = Units.closest(player.team(), player.x, player.y, u -> !u.isPlayer() && u.type() == controlledType && !u.dead);
+ Unit unit = Units.closest(player.team(), player.x, player.y, u -> !u.isPlayer() && u.type == controlledType && !u.dead);
if(unit != null){
Call.unitControl(player, unit);
@@ -418,9 +431,9 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
public void checkUnit(){
if(controlledType != null){
- Unit unit = Units.closest(player.team(), player.x, player.y, u -> !u.isPlayer() && u.type() == controlledType && !u.dead);
+ Unit unit = Units.closest(player.team(), player.x, player.y, u -> !u.isPlayer() && u.type == controlledType && !u.dead);
if(unit == null && controlledType == UnitTypes.block){
- unit = world.buildWorld(player.x, player.y) instanceof ControlBlock ? ((ControlBlock)world.buildWorld(player.x, player.y)).unit() : null;
+ unit = world.buildWorld(player.x, player.y) instanceof ControlBlock cont && cont.canControl() ? cont.unit() : null;
}
if(unit != null){
@@ -437,7 +450,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
Unit unit = player.unit();
if(!(unit instanceof Payloadc pay)) return;
- Unit target = Units.closest(player.team(), pay.x(), pay.y(), unit.type().hitSize * 2.5f, u -> u.isAI() && u.isGrounded() && pay.canPickup(u) && u.within(unit, u.hitSize + unit.hitSize * 1.2f));
+ Unit target = Units.closest(player.team(), pay.x(), pay.y(), unit.type.hitSize * 2.5f, u -> u.isAI() && u.isGrounded() && pay.canPickup(u) && u.within(unit, u.hitSize + unit.hitSize * 1.2f));
if(target != null){
Call.requestUnitPayload(player, target);
}else{
@@ -568,8 +581,8 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
wx = wy;
wy = -x;
}
- req.x = world.toTile(wx - req.block.offset) + ox;
- req.y = world.toTile(wy - req.block.offset) + oy;
+ req.x = World.toTile(wx - req.block.offset) + ox;
+ req.y = World.toTile(wy - req.block.offset) + oy;
req.rotation = Mathf.mod(req.rotation + direction, 4);
});
}
@@ -934,11 +947,11 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
}
int rawTileX(){
- return world.toTile(Core.input.mouseWorld().x);
+ return World.toTile(Core.input.mouseWorld().x);
}
int rawTileY(){
- return world.toTile(Core.input.mouseWorld().y);
+ return World.toTile(Core.input.mouseWorld().y);
}
int tileX(float cursorX){
@@ -946,7 +959,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
if(selectedBlock()){
vec.sub(block.offset, block.offset);
}
- return world.toTile(vec.x);
+ return World.toTile(vec.x);
}
int tileY(float cursorY){
@@ -954,7 +967,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
if(selectedBlock()){
vec.sub(block.offset, block.offset);
}
- return world.toTile(vec.y);
+ return World.toTile(vec.y);
}
public boolean selectedBlock(){
@@ -984,8 +997,8 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
}
Building tile = world.buildWorld(Core.input.mouseWorld().x, Core.input.mouseWorld().y);
- if(tile instanceof ControlBlock && tile.team == player.team()){
- return ((ControlBlock)tile).unit();
+ if(tile instanceof ControlBlock cont && cont.canControl() && tile.team == player.team()){
+ return cont.unit();
}
return null;
diff --git a/core/src/mindustry/input/MobileInput.java b/core/src/mindustry/input/MobileInput.java
index 19f458ea88..63df6c151b 100644
--- a/core/src/mindustry/input/MobileInput.java
+++ b/core/src/mindustry/input/MobileInput.java
@@ -14,6 +14,7 @@ import arc.struct.*;
import arc.util.*;
import mindustry.*;
import mindustry.content.*;
+import mindustry.core.*;
import mindustry.entities.*;
import mindustry.entities.units.*;
import mindustry.game.EventType.*;
@@ -23,6 +24,7 @@ import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.*;
+import mindustry.world.blocks.*;
import static mindustry.Vars.*;
import static mindustry.input.PlaceMode.*;
@@ -85,7 +87,7 @@ public class MobileInput extends InputHandler implements GestureListener{
if(tile != null && player.team().isEnemy(tile.team)){
player.miner().mineTile(null);
target = tile;
- }else if(tile != null && player.unit().type().canHeal && tile.team == player.team() && tile.damaged()){
+ }else if(tile != null && player.unit().type.canHeal && tile.team == player.team() && tile.damaged()){
player.miner().mineTile(null);
target = tile;
}
@@ -405,14 +407,14 @@ public class MobileInput extends InputHandler implements GestureListener{
protected int schemOriginX(){
Tmp.v1.setZero();
selectRequests.each(r -> Tmp.v1.add(r.drawx(), r.drawy()));
- return world.toTile(Tmp.v1.scl(1f / selectRequests.size).x);
+ return World.toTile(Tmp.v1.scl(1f / selectRequests.size).x);
}
@Override
protected int schemOriginY(){
Tmp.v1.setZero();
selectRequests.each(r -> Tmp.v1.add(r.drawx(), r.drawy()));
- return world.toTile(Tmp.v1.scl(1f / selectRequests.size).y);
+ return World.toTile(Tmp.v1.scl(1f / selectRequests.size).y);
}
@Override
@@ -834,10 +836,10 @@ public class MobileInput extends InputHandler implements GestureListener{
protected void updateMovement(Unit unit){
Rect rect = Tmp.r3;
- UnitType type = unit.type();
+ UnitType type = unit.type;
if(type == null) return;
- boolean omni = unit.type().omniMovement;
+ boolean omni = unit.type.omniMovement;
boolean legs = unit.isGrounded();
boolean allowHealing = type.canHeal;
boolean validHealTarget = allowHealing && target instanceof Building && ((Building)target).isValid() && target.team() == unit.team &&
@@ -855,7 +857,7 @@ public class MobileInput extends InputHandler implements GestureListener{
float attractDst = 15f;
float strafePenalty = legs ? 1f : Mathf.lerp(1f, type.strafePenalty, Angles.angleDist(unit.vel.angle(), unit.rotation) / 180f);
- float baseSpeed = unit.type().speed;
+ float baseSpeed = unit.type.speed;
//limit speed to minimum formation speed to preserve formation
if(unit.isCommanding()){
@@ -863,7 +865,7 @@ public class MobileInput extends InputHandler implements GestureListener{
baseSpeed = unit.minFormationSpeed * 0.98f;
}
- float speed = baseSpeed * Mathf.lerp(1f, unit.isCommanding() ? 1f : type.canBoost ? type.boostMultiplier : 1f, unit.elevation) * strafePenalty;
+ float speed = baseSpeed * Mathf.lerp(1f, type.canBoost ? type.boostMultiplier : 1f, unit.elevation) * strafePenalty;
float range = unit.hasWeapons() ? unit.range() : 0f;
float bulletSpeed = unit.hasWeapons() ? type.weapons.first().bullet.speed : 0f;
float mouseAngle = unit.angleTo(unit.aimX(), unit.aimY());
@@ -935,7 +937,7 @@ public class MobileInput extends InputHandler implements GestureListener{
unit.aim(player.mouseX = Core.input.mouseWorldX(), player.mouseY = Core.input.mouseWorldY());
}else if(target == null){
player.shooting = false;
- if(Core.settings.getBool("autotarget")){
+ if(Core.settings.getBool("autotarget") && !(player.unit() instanceof BlockUnitUnit u && u.tile() instanceof ControlBlock c && !c.shouldAutoTarget())){
target = Units.closestTarget(unit.team, unit.x, unit.y, range, u -> u.team != Team.derelict, u -> u.team != Team.derelict);
if(allowHealing && target == null){
diff --git a/core/src/mindustry/io/JsonIO.java b/core/src/mindustry/io/JsonIO.java
index 39c3a1a821..eb3815ba76 100644
--- a/core/src/mindustry/io/JsonIO.java
+++ b/core/src/mindustry/io/JsonIO.java
@@ -165,6 +165,18 @@ public class JsonIO{
}
});
+ json.setSerializer(UnitType.class, new Serializer<>(){
+ @Override
+ public void write(Json json, UnitType object, Class knownType){
+ json.writeValue(object.name);
+ }
+
+ @Override
+ public UnitType read(Json json, JsonValue jsonData, Class type){
+ return Vars.content.getByName(ContentType.unit, jsonData.asString());
+ }
+ });
+
json.setSerializer(ItemStack.class, new Serializer<>(){
@Override
public void write(Json json, ItemStack object, Class knownType){
diff --git a/core/src/mindustry/io/MapIO.java b/core/src/mindustry/io/MapIO.java
index f88ebf9a37..f964e2c933 100644
--- a/core/src/mindustry/io/MapIO.java
+++ b/core/src/mindustry/io/MapIO.java
@@ -80,7 +80,7 @@ public class MapIO{
@Override
public void setBlock(Block type){
super.setBlock(type);
- int c = colorFor(Blocks.air, block(), Blocks.air, team());
+ int c = colorFor(block(), Blocks.air, Blocks.air, team());
if(c != black){
walls.draw(x, floors.getHeight() - 1 - y, c);
floors.draw(x, floors.getHeight() - 1 - y + 1, shade);
@@ -119,7 +119,7 @@ public class MapIO{
if(overlayID != 0){
floors.draw(x, floors.getHeight() - 1 - y, colorFor(Blocks.air, Blocks.air, content.block(overlayID), Team.derelict));
}else{
- floors.draw(x, floors.getHeight() - 1 - y, colorFor(content.block(floorID), Blocks.air, Blocks.air, Team.derelict));
+ floors.draw(x, floors.getHeight() - 1 - y, colorFor(Blocks.air, content.block(floorID), Blocks.air, Team.derelict));
}
if(content.block(overlayID) == Blocks.spawn){
map.spawns ++;
@@ -141,17 +141,17 @@ public class MapIO{
for(int x = 0; x < pixmap.getWidth(); x++){
for(int y = 0; y < pixmap.getHeight(); y++){
Tile tile = tiles.getn(x, y);
- pixmap.draw(x, pixmap.getHeight() - 1 - y, colorFor(tile.floor(), tile.block(), tile.overlay(), tile.team()));
+ pixmap.draw(x, pixmap.getHeight() - 1 - y, colorFor(tile.block(), tile.floor(), tile.overlay(), tile.team()));
}
}
return pixmap;
}
- public static int colorFor(Block floor, Block wall, Block ore, Team team){
+ public static int colorFor(Block wall, Block floor, Block overlay, Team team){
if(wall.synthetic()){
return team.color.rgba();
}
- return (wall.solid ? wall.mapColor : ore == Blocks.air ? floor.mapColor : ore.mapColor).rgba();
+ return (wall.solid ? wall.mapColor : !overlay.useColor ? floor.mapColor : overlay.mapColor).rgba();
}
public static Pixmap writeImage(Tiles tiles){
diff --git a/core/src/mindustry/io/SaveMeta.java b/core/src/mindustry/io/SaveMeta.java
index f2e039f634..c6133889bc 100644
--- a/core/src/mindustry/io/SaveMeta.java
+++ b/core/src/mindustry/io/SaveMeta.java
@@ -14,12 +14,10 @@ public class SaveMeta{
public Map map;
public int wave;
public Rules rules;
- public SectorInfo secinfo;
public StringMap tags;
public String[] mods;
- public boolean hasProduction;
- public SaveMeta(int version, long timestamp, long timePlayed, int build, String map, int wave, Rules rules, SectorInfo secinfo, StringMap tags){
+ public SaveMeta(int version, long timestamp, long timePlayed, int build, String map, int wave, Rules rules, StringMap tags){
this.version = version;
this.build = build;
this.timestamp = timestamp;
@@ -29,8 +27,5 @@ public class SaveMeta{
this.rules = rules;
this.tags = tags;
this.mods = JsonIO.read(String[].class, tags.get("mods", "[]"));
- this.secinfo = secinfo;
-
- secinfo.production.each((e, amount) -> hasProduction |= amount.mean > 0.001f);
}
}
diff --git a/core/src/mindustry/io/SaveVersion.java b/core/src/mindustry/io/SaveVersion.java
index cacac7700a..b76a5156e8 100644
--- a/core/src/mindustry/io/SaveVersion.java
+++ b/core/src/mindustry/io/SaveVersion.java
@@ -40,7 +40,6 @@ public abstract class SaveVersion extends SaveFileReader{
map.get("mapname"),
map.getInt("wave"),
JsonIO.read(Rules.class, map.get("rules", "{}")),
- JsonIO.read(SectorInfo.class, map.get("secinfo", "{}")),
map
);
}
@@ -74,6 +73,7 @@ public abstract class SaveVersion extends SaveFileReader{
//prepare campaign data for writing
if(state.isCampaign()){
state.secinfo.prepare();
+ state.rules.sector.saveInfo();
}
//flush tech node progress
@@ -89,7 +89,6 @@ public abstract class SaveVersion extends SaveFileReader{
"wave", state.wave,
"wavetime", state.wavetime,
"stats", JsonIO.write(state.stats),
- "secinfo", state.isCampaign() ? JsonIO.write(state.secinfo) : "{}",
"rules", JsonIO.write(state.rules),
"mods", JsonIO.write(mods.getModStrings().toArray(String.class)),
"width", world.width(),
@@ -106,15 +105,14 @@ public abstract class SaveVersion extends SaveFileReader{
state.wave = map.getInt("wave");
state.wavetime = map.getFloat("wavetime", state.rules.waveSpacing);
- state.stats = JsonIO.read(Stats.class, map.get("stats", "{}"));
- state.secinfo = JsonIO.read(SectorInfo.class, map.get("secinfo", "{}"));
+ state.stats = JsonIO.read(GameStats.class, map.get("stats", "{}"));
state.rules = JsonIO.read(Rules.class, map.get("rules", "{}"));
if(state.rules.spawns.isEmpty()) state.rules.spawns = defaultWaves.get();
lastReadBuild = map.getInt("build", -1);
- //load time spent on sector into state
+ //load in sector info
if(state.rules.sector != null){
- state.secinfo.internalTimeSpent = state.rules.sector.getStoredTimeSpent();
+ state.secinfo = state.rules.sector.info;
}
if(!headless){
diff --git a/core/src/mindustry/io/TypeIO.java b/core/src/mindustry/io/TypeIO.java
index 669cd65d53..2c2c19dcfc 100644
--- a/core/src/mindustry/io/TypeIO.java
+++ b/core/src/mindustry/io/TypeIO.java
@@ -185,7 +185,7 @@ public class TypeIO{
return unit == null ? Nulls.unit : unit;
}else if(type == 1){ //block
Building tile = world.build(id);
- return tile instanceof ControlBlock ? ((ControlBlock)tile).unit() : Nulls.unit;
+ return tile instanceof ControlBlock cont ? cont.unit() : Nulls.unit;
}
return Nulls.unit;
}
@@ -450,6 +450,16 @@ public class TypeIO{
return color.set(read.i());
}
+ public static void writeContent(Writes write, Content cont){
+ write.b(cont.getContentType().ordinal());
+ write.s(cont.id);
+ }
+
+ public static Content readContent(Reads read){
+ byte id = read.b();
+ return content.getByID(ContentType.all[id], read.s());
+ }
+
public static void writeLiquid(Writes write, Liquid liquid){
write.s(liquid == null ? -1 : liquid.id);
}
diff --git a/core/src/mindustry/io/legacy/LegacyIO.java b/core/src/mindustry/io/legacy/LegacyIO.java
index 545487d8ca..15cb756081 100644
--- a/core/src/mindustry/io/legacy/LegacyIO.java
+++ b/core/src/mindustry/io/legacy/LegacyIO.java
@@ -2,6 +2,8 @@ package mindustry.io.legacy;
import arc.*;
import arc.struct.*;
+import mindustry.*;
+import mindustry.ctype.*;
import mindustry.ui.dialogs.JoinDialog.*;
import java.io.*;
@@ -48,4 +50,35 @@ public class LegacyIO{
return arr;
}
+ public static void readResearch(){
+ try{
+ byte[] bytes = Core.settings.getBytes("unlocks");
+ DataInputStream stream = new DataInputStream(new ByteArrayInputStream(bytes));
+
+ int length = stream.readInt();
+ if(length > 0){
+ stream.readUTF(); //name of key type
+ stream.readUTF(); //name of value type
+
+ //each element is an array list
+ for(int i = 0; i < length; i++){
+ ContentType type = ContentType.all[stream.readInt()];
+ int arrLength = stream.readInt();
+ if(arrLength > 0){
+ stream.readUTF(); //type of contents (String)
+ for(int j = 0; j < arrLength; j++){
+ String name = stream.readUTF();
+ Content out = Vars.content.getByName(type, name);
+ if(out instanceof UnlockableContent u){
+ u.quietUnlock();
+ }
+ }
+ }
+ }
+ }
+ }catch(Exception e){
+ e.printStackTrace();
+ }
+ }
+
}
diff --git a/core/src/mindustry/logic/Controllable.java b/core/src/mindustry/logic/Controllable.java
index 3785eae4b6..025559b4b9 100644
--- a/core/src/mindustry/logic/Controllable.java
+++ b/core/src/mindustry/logic/Controllable.java
@@ -1,7 +1,10 @@
package mindustry.logic;
+import mindustry.game.*;
+
/** An object that can be controlled with logic. */
public interface Controllable{
void control(LAccess type, double p1, double p2, double p3, double p4);
void control(LAccess type, Object p1, double p2, double p3, double p4);
+ Team team();
}
diff --git a/core/src/mindustry/logic/LAccess.java b/core/src/mindustry/logic/LAccess.java
index 5dc881a778..0d678554d1 100644
--- a/core/src/mindustry/logic/LAccess.java
+++ b/core/src/mindustry/logic/LAccess.java
@@ -15,6 +15,8 @@ public enum LAccess{
powerNetCapacity,
powerNetIn,
powerNetOut,
+ ammo,
+ ammoCapacity,
health,
maxHealth,
heat,
diff --git a/core/src/mindustry/logic/LAssembler.java b/core/src/mindustry/logic/LAssembler.java
index 4f72d121aa..57c2004320 100644
--- a/core/src/mindustry/logic/LAssembler.java
+++ b/core/src/mindustry/logic/LAssembler.java
@@ -189,16 +189,28 @@ public class LAssembler{
return putConst("___" + symbol, symbol.substring(1, symbol.length() - 1).replace("\\n", "\n")).id;
}
+ //remove spaces for non-strings
+ symbol = symbol.replace(' ', '_');
+
try{
- double value = Double.parseDouble(symbol);
+ double value = parseDouble(symbol);
+ if(Double.isNaN(value) || Double.isInfinite(value)) value = 0;
+
//this creates a hidden const variable with the specified value
- String key = "___" + value;
- return putConst(key, value).id;
+ return putConst("___" + value, value).id;
}catch(NumberFormatException e){
return putVar(symbol).id;
}
}
+ double parseDouble(String symbol) throws NumberFormatException{
+ //parse hex/binary syntax
+ if(symbol.startsWith("0b")) return Long.parseLong(symbol.substring(2), 2);
+ if(symbol.startsWith("0x")) return Long.parseLong(symbol.substring(2), 16);
+
+ return Double.parseDouble(symbol);
+ }
+
/** Adds a constant value by name. */
public BVar putConst(String name, Object value){
BVar var = putVar(name);
diff --git a/core/src/mindustry/logic/LCanvas.java b/core/src/mindustry/logic/LCanvas.java
index ed98bee8ff..e16aab6621 100644
--- a/core/src/mindustry/logic/LCanvas.java
+++ b/core/src/mindustry/logic/LCanvas.java
@@ -305,7 +305,7 @@ public class LCanvas extends Table{
statements.finishLayout();
}
});
- }).growX();
+ }).growX().height(38);
row();
diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java
index a8c5de8a9d..a10cd2d0b2 100644
--- a/core/src/mindustry/logic/LExecutor.java
+++ b/core/src/mindustry/logic/LExecutor.java
@@ -7,6 +7,7 @@ import arc.util.noise.*;
import mindustry.*;
import mindustry.ai.types.*;
import mindustry.content.*;
+import mindustry.core.*;
import mindustry.ctype.*;
import mindustry.entities.*;
import mindustry.game.*;
@@ -46,6 +47,7 @@ public class LExecutor{
public LongSeq graphicsBuffer = new LongSeq();
public StringBuilder textBuffer = new StringBuilder();
public Building[] links = {};
+ public IntSet linkIds = new IntSet();
public Team team = Team.derelict;
public boolean initialized(){
@@ -110,12 +112,12 @@ public class LExecutor{
public double num(int index){
Var v = vars[index];
- return v.isobj ? v.objval != null ? 1 : 0 : v.numval;
+ return v.isobj ? v.objval != null ? 1 : 0 : Double.isNaN(v.numval) || Double.isInfinite(v.numval) ? 0 : v.numval;
}
public float numf(int index){
Var v = vars[index];
- return v.isobj ? v.objval != null ? 1 : 0 : (float)v.numval;
+ return v.isobj ? v.objval != null ? 1 : 0 : Double.isNaN(v.numval) || Double.isInfinite(v.numval) ? 0 : (float)v.numval;
}
public int numi(int index){
@@ -129,7 +131,7 @@ public class LExecutor{
public void setnum(int index, double value){
Var v = vars[index];
if(v.constant) return;
- v.numval = value;
+ v.numval = Double.isNaN(value) || Double.isInfinite(value) ? 0 : value;
v.objval = null;
v.isobj = false;
}
@@ -211,9 +213,9 @@ public class LExecutor{
public LLocate locate = LLocate.building;
public BlockFlag flag = BlockFlag.core;
public int enemy, ore;
- public int outX, outY, outFound;
+ public int outX, outY, outFound, outBuild;
- public UnitLocateI(LLocate locate, BlockFlag flag, int enemy, int ore, int outX, int outY, int outFound){
+ public UnitLocateI(LLocate locate, BlockFlag flag, int enemy, int ore, int outX, int outY, int outFound, int outBuild){
this.locate = locate;
this.flag = flag;
this.enemy = enemy;
@@ -263,13 +265,14 @@ public class LExecutor{
if(res != null && (!build || res.build != null)){
cache.found = true;
//set result if found
- exec.setnum(outX, cache.x = build ? res.build.x : res.worldx());
- exec.setnum(outY, cache.y = build ? res.build.y : res.worldy());
+ exec.setnum(outX, cache.x = World.conv(build ? res.build.x : res.worldx()));
+ exec.setnum(outY, cache.y = World.conv(build ? res.build.y : res.worldy()));
exec.setnum(outFound, 1);
}else{
cache.found = false;
exec.setnum(outFound, 0);
}
+ exec.setobj(outFound, res != null && res.build != null && res.build.team == exec.team ? res.build : null);
}else{
exec.setbool(outFound, cache.found);
exec.setnum(outX, cache.x);
@@ -332,14 +335,15 @@ public class LExecutor{
//only control standard AI units
if(unitObj instanceof Unit unit && ai != null){
ai.controlTimer = LogicAI.logicControlTimeout;
+ float x1 = World.unconv(exec.numf(p1)), y1 = World.unconv(exec.numf(p2)), d1 = World.unconv(exec.numf(p3));
switch(type){
case move, stop, approach -> {
ai.control = type;
- ai.moveX = exec.numf(p1);
- ai.moveY = exec.numf(p2);
+ ai.moveX = x1;
+ ai.moveY = y1;
if(type == LUnitControl.approach){
- ai.moveRad = exec.numf(p3);
+ ai.moveRad = d1;
}
//stop mining/building
@@ -353,13 +357,13 @@ public class LExecutor{
}
}
case within -> {
- exec.setnum(p4, unit.within(exec.numf(p1), exec.numf(p2), exec.numf(p3)) ? 1 : 0);
+ exec.setnum(p4, unit.within(x1, y1, d1) ? 1 : 0);
}
case pathfind -> {
ai.control = type;
}
case target -> {
- ai.posTarget.set(exec.numf(p1), exec.numf(p2));
+ ai.posTarget.set(x1, y1);
ai.aimControl = type;
ai.mainTarget = null;
ai.shoot = exec.bool(p3);
@@ -376,7 +380,7 @@ public class LExecutor{
unit.flag = exec.num(p1);
}
case mine -> {
- Tile tile = world.tileWorld(exec.numf(p1), exec.numf(p2));
+ Tile tile = world.tileWorld(x1, y1);
if(unit instanceof Minerc miner){
miner.mineTile(miner.validMine(tile) ? tile : null);
}
@@ -395,7 +399,7 @@ public class LExecutor{
if(unit instanceof Payloadc pay){
//units
if(exec.bool(p1)){
- Unit result = Units.closest(unit.team, unit.x, unit.y, unit.type().hitSize * 2f, u -> u.isAI() && u.isGrounded() && pay.canPickup(u) && u.within(unit, u.hitSize + unit.hitSize * 1.2f));
+ Unit result = Units.closest(unit.team, unit.x, unit.y, unit.type.hitSize * 2f, u -> u.isAI() && u.isGrounded() && pay.canPickup(u) && u.within(unit, u.hitSize + unit.hitSize * 1.2f));
if(result != null){
Call.pickedUnitPayload(unit, result);
@@ -420,7 +424,7 @@ public class LExecutor{
}
case build -> {
if(unit instanceof Builderc builder && exec.obj(p3) instanceof Block block){
- int x = world.toTile(exec.numf(p1)), y = world.toTile(exec.numf(p2));
+ int x = World.toTile(x1), y = World.toTile(y1);
int rot = exec.numi(p4);
//reset state of last request when necessary
@@ -433,25 +437,25 @@ public class LExecutor{
ai.plan.set(x, y, rot, block);
ai.plan.config = null;
+ builder.clearBuilding();
+
if(ai.plan.tile() != null){
- builder.clearBuilding();
builder.updateBuilding(true);
builder.addBuild(ai.plan);
}
}
}
case getBlock -> {
- float x = exec.numf(p1), y = exec.numf(p2);
float range = Math.max(unit.range(), buildingRange);
- if(!unit.within(x, y, range)){
+ if(!unit.within(x1, y1, range)){
exec.setobj(p3, null);
- exec.setnum(p4, 0);
+ exec.setobj(p4, null);
}else{
- Tile tile = world.tileWorld(x, y);
+ Tile tile = world.tileWorld(x1, y1);
//any environmental solid block is returned as StoneWall, aka "@solid"
Block block = tile == null ? null : !tile.synthetic() ? (tile.solid() ? Blocks.stoneWall : Blocks.air) : tile.block();
exec.setobj(p3, block);
- exec.setnum(p4, tile != null && tile.build != null ? tile.build.rotation : 0);
+ exec.setobj(p4, tile != null && tile.build != null ? tile.build : null);
}
}
case itemDrop -> {
@@ -474,7 +478,7 @@ public class LExecutor{
Building build = exec.building(p1);
int amount = exec.numi(p3);
- if(build != null && exec.obj(p2) instanceof Item item && unit.within(build, logicItemTransferRange)){
+ if(build != null && build.items != null && exec.obj(p2) instanceof Item item && unit.within(build, logicItemTransferRange)){
int taken = Math.min(build.items.get(item), Math.min(amount, unit.maxAccepted(item)));
if(taken > 0){
@@ -509,11 +513,11 @@ public class LExecutor{
@Override
public void run(LExecutor exec){
Object obj = exec.obj(target);
- if(obj instanceof Controllable cont){
+ if(obj instanceof Building b && b.team == exec.team && exec.linkIds.contains(b.id)){
if(type.isObj){
- cont.control(type, exec.obj(p1), exec.num(p2), exec.num(p3), exec.num(p4));
+ b.control(type, exec.obj(p1), exec.num(p2), exec.num(p3), exec.num(p4));
}else{
- cont.control(type, exec.num(p1), exec.num(p2), exec.num(p3), exec.num(p4));
+ b.control(type, exec.num(p1), exec.num(p2), exec.num(p3), exec.num(p4));
}
}
}
@@ -606,6 +610,7 @@ public class LExecutor{
Object target = exec.obj(from);
Object sense = exec.obj(type);
+ //TODO should remote enemy buildings be senseable?
if(target instanceof Senseable se){
if(sense instanceof Content){
exec.setnum(to, se.sense(((Content)sense)));
@@ -737,7 +742,7 @@ public class LExecutor{
v.objval = f.objval;
v.isobj = true;
}else{
- v.numval = f.numval;
+ v.numval = Double.isNaN(f.numval) || Double.isInfinite(f.numval) ? 0 : f.numval;
v.isobj = false;
}
}
diff --git a/core/src/mindustry/logic/LStatements.java b/core/src/mindustry/logic/LStatements.java
index ba4d31e9a1..517d53bcc6 100644
--- a/core/src/mindustry/logic/LStatements.java
+++ b/core/src/mindustry/logic/LStatements.java
@@ -704,7 +704,7 @@ public class LStatements{
@RegisterStatement("ubind")
public static class UnitBindStatement extends LStatement{
- public String type = "@mono";
+ public String type = "@poly";
@Override
public void build(Table table){
@@ -819,7 +819,7 @@ public class LStatements{
public LLocate locate = LLocate.building;
public BlockFlag flag = BlockFlag.core;
public String enemy = "true", ore = "@copper";
- public String outX = "outx", outY = "outy", outFound = "found";
+ public String outX = "outx", outY = "outy", outFound = "found", outBuild = "building";
@Override
public void build(Table table){
@@ -905,6 +905,8 @@ public class LStatements{
table.add(" found ").left();
fields(table, outFound, str -> outFound = str);
+ table.add(" building ").left();
+ fields(table, outBuild, str -> outBuild = str);
}
@@ -915,7 +917,7 @@ public class LStatements{
@Override
public LInstruction build(LAssembler builder){
- return new UnitLocateI(locate, flag, builder.var(enemy), builder.var(ore), builder.var(outX), builder.var(outY), builder.var(outFound));
+ return new UnitLocateI(locate, flag, builder.var(enemy), builder.var(ore), builder.var(outX), builder.var(outY), builder.var(outFound), builder.var(outBuild));
}
}
}
diff --git a/core/src/mindustry/logic/LUnitControl.java b/core/src/mindustry/logic/LUnitControl.java
index 2166b00690..b4c7f8254c 100644
--- a/core/src/mindustry/logic/LUnitControl.java
+++ b/core/src/mindustry/logic/LUnitControl.java
@@ -15,7 +15,7 @@ public enum LUnitControl{
mine("x", "y"),
flag("value"),
build("x", "y", "block", "rotation"),
- getBlock("x", "y", "result", "resRot"),
+ getBlock("x", "y", "type", "building"),
within("x", "y", "radius", "result");
public final String[] params;
diff --git a/core/src/mindustry/maps/Maps.java b/core/src/mindustry/maps/Maps.java
index 7741f0942f..28e571cf72 100644
--- a/core/src/mindustry/maps/Maps.java
+++ b/core/src/mindustry/maps/Maps.java
@@ -29,7 +29,7 @@ import static mindustry.Vars.*;
public class Maps{
/** List of all built-in maps. Filenames only. */
- private static String[] defaultMapNames = {"maze", "fortress", "labyrinth", "islands", "tendrils", "caldera", "wasteland", "shattered", "fork", "triad", "veins", "glacier"};
+ private static String[] defaultMapNames = {"maze", "fortress", "labyrinth", "islands", "tendrils", "caldera", "wasteland", "shattered", "fork", "triad", "mudFlats", "moltenLake", "archipelago", "veins", "glacier"};
/** Maps tagged as PvP */
static final String[] pvpMaps = {"veins", "glacier"};
/** All maps stored in an ordered array. */
@@ -82,9 +82,7 @@ public class Maps{
}
public Maps(){
- Events.on(ClientLoadEvent.class, event -> {
- maps.sort();
- });
+ Events.on(ClientLoadEvent.class, event -> maps.sort());
if(Core.assets != null){
((CustomLoader)Core.assets.getLoader(ContentLoader.class)).loaded = this::createAllPreviews;
diff --git a/core/src/mindustry/maps/SectorDamage.java b/core/src/mindustry/maps/SectorDamage.java
index 5f4e267d74..eaa42a8293 100644
--- a/core/src/mindustry/maps/SectorDamage.java
+++ b/core/src/mindustry/maps/SectorDamage.java
@@ -3,11 +3,19 @@ package mindustry.maps;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
+import arc.util.*;
import mindustry.ai.*;
import mindustry.content.*;
import mindustry.entities.*;
+import mindustry.entities.abilities.*;
+import mindustry.game.*;
import mindustry.gen.*;
+import mindustry.logic.*;
+import mindustry.type.*;
import mindustry.world.*;
+import mindustry.world.blocks.defense.*;
+import mindustry.world.blocks.defense.turrets.*;
+import mindustry.world.blocks.defense.turrets.Turret.*;
import mindustry.world.blocks.storage.*;
import static mindustry.Vars.*;
@@ -15,6 +23,300 @@ import static mindustry.Vars.*;
public class SectorDamage{
//direct damage is for testing only
private static final boolean direct = false, rubble = true;
+ private static final int maxWavesSimulated = 50;
+
+ /** @return calculated capture progress of the enemy */
+ public static float getDamage(SectorInfo info){
+ float health = info.sumHealth;
+ int wavesPassed = info.wavesPassed;
+ int wave = info.wave;
+ float waveSpace = info.waveSpacing;
+
+ //this approach is O(n), it simulates every wave passing.
+ //other approaches can assume all the waves come as one, but that's not as fair.
+ if(wavesPassed > 0){
+ int waveBegin = wave;
+ int waveEnd = wave + wavesPassed;
+
+ //do not simulate every single wave if there's too many
+ if(wavesPassed > maxWavesSimulated){
+ waveBegin = waveEnd - maxWavesSimulated;
+ }
+
+ for(int i = waveBegin; i <= waveEnd; i++){
+
+ float efficiency = health / info.sumHealth;
+ float dps = info.sumDps * efficiency;
+ float rps = info.sumRps * efficiency;
+
+ float enemyDps = info.waveDpsBase + info.waveDpsSlope * (i);
+ float enemyHealth = info.waveHealthBase + info.waveHealthSlope * (i);
+
+ //happens due to certain regressions
+ if(enemyHealth < 0 || enemyDps < 0) continue;
+
+ //calculate time to destroy both sides
+ float timeDestroyEnemy = dps <= 0.0001f ? Float.POSITIVE_INFINITY : enemyHealth / dps; //if dps == 0, this is infinity
+ float timeDestroyBase = health / (enemyDps - rps); //if regen > enemyDps this is negative
+
+ //sector is lost, enemy took too long.
+ if(timeDestroyEnemy > timeDestroyBase){
+ health = 0f;
+ break;
+ }
+
+ //otherwise, the enemy shoots for timeDestroyEnemy seconds, so calculate damage taken
+ float damageTaken = timeDestroyEnemy * (enemyDps - rps);
+
+ //damage the base.
+ health -= damageTaken;
+
+ //regen health after wave.
+ health = Math.min(health + rps / 60f * waveSpace, info.sumHealth);
+ }
+ }
+
+ return 1f - Mathf.clamp(health / info.sumHealth);
+ }
+
+ /** Applies wave damage based on sector parameters. */
+ public static void applyCalculatedDamage(){
+ //calculate base damage fraction
+ float damage = getDamage(state.secinfo);
+
+ //scaled damage has a power component to make it seem a little more realistic (as systems fail, enemy capturing gets easier and easier)
+ float scaled = Mathf.pow(damage, 1.5f);
+
+ //apply damage to units
+ float unitDamage = damage * state.secinfo.sumHealth;
+ Tile spawn = spawner.getFirstSpawn();
+
+ //damage only units near the spawn point
+ if(spawn != null){
+ Seq allies = new Seq<>();
+ for(Unit ally : Groups.unit){
+ if(ally.team == state.rules.defaultTeam && ally.within(spawn, state.rules.dropZoneRadius * 2.5f)){
+ allies.add(ally);
+ }
+ }
+
+ allies.sort(u -> u.dst2(spawn));
+
+ //damage units one by one, not uniformly
+ for(var u : allies){
+ if(u.health < unitDamage){
+ u.remove();
+ unitDamage -= u.health;
+ }else{
+ u.health -= unitDamage;
+ break;
+ }
+ }
+ }
+
+ if(state.secinfo.wavesPassed > 0){
+ //simply remove each block in the spawner range if a wave passed
+ for(Tile spawner : spawner.getSpawns()){
+ spawner.circle((int)(state.rules.dropZoneRadius / tilesize), tile -> {
+ if(tile.team() == state.rules.defaultTeam){
+ if(rubble && tile.floor().hasSurface() && Mathf.chance(0.4)){
+ Effect.rubble(tile.build.x, tile.build.y, tile.block().size);
+ }
+
+ tile.remove();
+ }
+ });
+ }
+ }
+
+ //finally apply scaled damage
+ apply(scaled);
+ }
+
+ /** Calculates damage simulation parameters before a game is saved. */
+ public static void writeParameters(SectorInfo info){
+ Building core = state.rules.defaultTeam.core();
+ Seq spawns = new Seq<>();
+ spawner.eachGroundSpawn((x, y) -> spawns.add(world.tile(x, y)));
+
+ if(spawns.isEmpty() && state.rules.waveTeam.core() != null){
+ spawns.add(state.rules.waveTeam.core().tile);
+ }
+
+ if(core == null || spawns.isEmpty()) return;
+
+ Tile start = spawns.first();
+
+ Time.mark();
+ var field = pathfinder.getField(state.rules.waveTeam, Pathfinder.costGround, Pathfinder.fieldCore);
+ Seq path = new Seq<>();
+ boolean found = false;
+
+ if(field != null && field.weights != null){
+ int[][] weights = field.weights;
+ int count = 0;
+ Tile current = start;
+ while(count < world.width() * world.height()){
+ int minCost = Integer.MAX_VALUE;
+ int cx = current.x, cy = current.y;
+ for(Point2 p : Geometry.d4){
+ int nx = cx + p.x, ny = cy + p.y;
+
+ Tile other = world.tile(nx, ny);
+ if(other != null && weights[nx][ny] < minCost && weights[nx][ny] != -1){
+ minCost = weights[nx][ny];
+ current = other;
+ }
+ }
+
+ path.add(current);
+
+ if(current.build == core){
+ found = true;
+ break;
+ }
+
+ count ++;
+ }
+ }
+
+ if(!found){
+ path = Astar.pathfind(start, core.tile, SectorDamage::cost, t -> !(t.block().isStatic() && t.solid()));
+ }
+
+ //create sparse tile array for fast range query
+ int sparseSkip = 5, sparseSkip2 = 3;
+ //TODO if this is slow, use a quadtree
+ Seq sparse = new Seq<>(path.size / sparseSkip + 1);
+ Seq sparse2 = new Seq<>(path.size / sparseSkip2 + 1);
+
+ for(int i = 0; i < path.size; i++){
+ if(i % sparseSkip == 0){
+ sparse.add(path.get(i));
+ }
+ if(i % sparseSkip2 == 0){
+ sparse2.add(path.get(i));
+ }
+ }
+
+ //regen is in health per second
+ //dps is per second
+ float sumHealth = 0f, sumRps = 0f, sumDps = 0f;
+ float totalPathBuild = 0;
+
+ //first, calculate the total health of blocks in the path
+
+ //radius around the path that gets counted
+ int radius = 7;
+ IntSet counted = new IntSet();
+
+ for(Tile t : sparse2){
+
+ //radius is square.
+ for(int dx = -radius; dx <= radius; dx++){
+ for(int dy = -radius; dy <= radius; dy++){
+ int wx = dx + t.x, wy = dy + t.y;
+ if(wx >= 0 && wy >= 0 && wx < world.width() && wy < world.height()){
+ Tile tile = world.rawTile(wx, wy);
+
+ if(tile.build != null && tile.team() == state.rules.defaultTeam && counted.add(tile.pos())){
+ //health is divided by block size, because multiblocks are counted multiple times.
+ sumHealth += tile.build.health / tile.block().size;
+ totalPathBuild += 1f / tile.block().size;
+ }
+ }
+ }
+ }
+ }
+
+ float avgHealth = totalPathBuild <= 1 ? sumHealth : sumHealth / totalPathBuild;
+
+ //block dps + regen + extra health/shields
+ for(Building build : Groups.build){
+ float e = build.efficiency();
+ if(e > 0.08f){
+ if(build.team == state.rules.defaultTeam && build instanceof Ranged ranged && sparse.contains(t -> t.within(build, ranged.range() + radius*tilesize))){
+ if(build.block instanceof Turret t && build instanceof TurretBuild b && b.hasAmmo()){
+ sumDps += t.shots / t.reloadTime * 60f * b.peekAmmo().estimateDPS() * e;
+ }
+
+ if(build.block instanceof MendProjector m){
+ sumRps += m.healPercent / m.reload * avgHealth * 60f / 100f * e;
+ }
+
+ if(build.block instanceof ForceProjector f){
+ sumHealth += f.breakage * e;
+ sumRps += 1f * e;
+ }
+ }
+ }
+ }
+
+ float curEnemyHealth = 0f, curEnemyDps = 0f;
+
+ //unit regen + health + dps
+ for(Unit unit : Groups.unit){
+ //skip player
+ if(unit.isPlayer()) continue;
+
+ if(unit.team == state.rules.defaultTeam){
+ //scale health based on armor - yes, this is inaccurate, but better than nothing
+ float healthMult = 1f + Mathf.clamp(unit.armor / 20f);
+
+ sumHealth += unit.health*healthMult + unit.shield;
+ sumDps += unit.type.dpsEstimate;
+ if(unit.abilities.find(a -> a instanceof RepairFieldAbility) instanceof RepairFieldAbility h){
+ sumRps += h.amount / h.reload * 60f;
+ }
+ }else{
+ curEnemyDps += unit.type.dpsEstimate;
+ curEnemyHealth += unit.health;
+ }
+ }
+
+ //calculate DPS and health for the next few waves and store in list
+ var reg = new LinearRegression();
+ Seq waveDps = new Seq<>(), waveHealth = new Seq<>();
+
+ for(int wave = state.wave, i = 0; i < 3; wave += (1 + i++)){
+ float sumWaveDps = 0f, sumWaveHealth = 0f;
+
+ //first wave has to take into account current dps
+ if(wave == state.wave){
+ sumWaveDps += curEnemyDps;
+ sumWaveHealth += curEnemyHealth;
+ }
+
+ for(SpawnGroup group : state.rules.spawns){
+ float healthMult = 1f + Mathf.clamp(group.type.armor / 20f);
+ StatusEffect effect = (group.effect == null ? StatusEffects.none : group.effect);
+ int spawned = group.getSpawned(wave);
+ if(spawned <= 0) continue;
+ sumWaveHealth += spawned * (group.getShield(wave) + group.type.health * effect.healthMultiplier * healthMult);
+ sumWaveDps += spawned * group.type.dpsEstimate * effect.damageMultiplier;
+ }
+ waveDps.add(new Vec2(wave, sumWaveDps));
+ waveHealth.add(new Vec2(wave, sumWaveHealth));
+ }
+
+ //calculate linear regression of the wave data and store it
+ reg.calculate(waveHealth);
+ info.waveHealthBase = reg.intercept;
+ info.waveHealthSlope = reg.slope;
+
+ reg.calculate(waveDps);
+ info.waveDpsBase = reg.intercept;
+ info.waveDpsSlope = reg.slope;
+
+ //enemy units like to aim for a lot of non-essential things, so increase resulting health slightly
+ info.sumHealth = sumHealth * 1.2f;
+ //players tend to have longer range units/turrets, so assume DPS is higher
+ info.sumDps = sumDps * 1.5f;
+ info.sumRps = sumRps;
+
+ //finally, find an equation to put it all together and produce a 0-1 number
+ //due to the way most defenses are structured, this number will likely need a ^4 power or so
+ }
public static void apply(float fraction){
Tiles tiles = world.tiles;
@@ -35,23 +337,71 @@ public class SectorDamage{
if(core != null && !frontier.isEmpty()){
for(Tile spawner : frontier){
//find path from spawn to core
- //TODO this is broken
Seq path = Astar.pathfind(spawner, core.tile, SectorDamage::cost, t -> !(t.block().isStatic() && t.solid()));
- int amount = (int)(path.size * fraction);
- for(int i = 0; i < amount; i++){
- Tile t = path.get(i);
- Geometry.circle(t.x, t.y, tiles.width, tiles.height, 5, (cx, cy) -> {
- Tile other = tiles.getn(cx, cy);
- //just remove all the buildings in the way - as long as they're not cores!
- if(other.build != null && other.team() == state.rules.defaultTeam && !(other.block() instanceof CoreBlock)){
- if(rubble && !other.floor().solid && !other.floor().isLiquid && Mathf.chance(0.4)){
- Effect.rubble(other.build.x, other.build.y, other.block().size);
- }
+ Seq removal = new Seq<>();
- other.remove();
+ int radius = 3;
+
+ //only penetrate a certain % by health, not by distance
+ float totalHealth = damage >= 1f ? 1f : path.sumf(t -> {
+ float s = 0;
+ for(int dx = -radius; dx <= radius; dx++){
+ for(int dy = -radius; dy <= radius; dy++){
+ int wx = dx + t.x, wy = dy + t.y;
+ if(wx >= 0 && wy >= 0 && wx < world.width() && wy < world.height() && Mathf.within(dx, dy, radius)){
+ Tile other = world.rawTile(wx, wy);
+ s += other.team() == state.rules.defaultTeam ? other.build.health / other.block().size : 0f;
+ }
}
- });
+ }
+ return s;
+ });
+ float targetHealth = totalHealth * fraction;
+ float healthCount = 0;
+
+ out:
+ for(int i = 0; i < path.size && (healthCount < targetHealth || damage >= 1f); i++){
+ Tile t = path.get(i);
+
+ for(int dx = -radius; dx <= radius; dx++){
+ for(int dy = -radius; dy <= radius; dy++){
+ int wx = dx + t.x, wy = dy + t.y;
+ if(wx >= 0 && wy >= 0 && wx < world.width() && wy < world.height() && Mathf.within(dx, dy, radius)){
+ Tile other = world.rawTile(wx, wy);
+
+ //just remove all the buildings in the way - as long as they're not cores
+ if(other.build != null && other.team() == state.rules.defaultTeam && !(other.block() instanceof CoreBlock)){
+ if(rubble && !other.floor().solid && !other.floor().isLiquid && Mathf.chance(0.4)){
+ Effect.rubble(other.build.x, other.build.y, other.block().size);
+ }
+
+ //since the whole block is removed, count the whole health
+ healthCount += other.build.health;
+
+ removal.add(other.build);
+
+ if(healthCount >= targetHealth && damage < 0.999f){
+ break out;
+ }
+ }
+ }
+ }
+ }
}
+
+ for(Building r : removal){
+ if(r.tile.build == r){
+ r.addPlan(false);
+ r.tile.remove();
+ }
+ }
+ }
+ }
+
+ //kill every core if damage is maximum
+ if(fraction >= 1){
+ for(Building c : state.rules.defaultTeam.cores().copy()){
+ c.tile.remove();
}
}
@@ -90,6 +440,7 @@ public class SectorDamage{
Effect.rubble(other.build.x, other.build.y, other.block().size);
}
+ other.build.addPlan(false);
other.remove();
}
}
diff --git a/core/src/mindustry/maps/filters/ClearFilter.java b/core/src/mindustry/maps/filters/ClearFilter.java
index 3769d7f77d..4da2564a79 100644
--- a/core/src/mindustry/maps/filters/ClearFilter.java
+++ b/core/src/mindustry/maps/filters/ClearFilter.java
@@ -11,7 +11,7 @@ public class ClearFilter extends GenerateFilter{
@Override
public FilterOption[] options(){
- return Structs.arr(new BlockOption("block", () -> block, b -> block = b, wallsOnly));
+ return Structs.arr(new BlockOption("block", () -> block, b -> block = b, b -> oresOnly.get(b) || wallsOnly.get(b)));
}
@Override
@@ -20,5 +20,9 @@ public class ClearFilter extends GenerateFilter{
if(in.block == block){
in.block = Blocks.air;
}
+
+ if(in.overlay == block){
+ in.overlay = Blocks.air;
+ }
}
}
diff --git a/core/src/mindustry/maps/filters/DistortFilter.java b/core/src/mindustry/maps/filters/DistortFilter.java
index 32c8f18a14..daedca1765 100644
--- a/core/src/mindustry/maps/filters/DistortFilter.java
+++ b/core/src/mindustry/maps/filters/DistortFilter.java
@@ -26,6 +26,6 @@ public class DistortFilter extends GenerateFilter{
in.floor = tile.floor();
if(!tile.block().synthetic() && !in.block.synthetic()) in.block = tile.block();
- in.ore = tile.overlay();
+ in.overlay = tile.overlay();
}
}
diff --git a/core/src/mindustry/maps/filters/FilterOption.java b/core/src/mindustry/maps/filters/FilterOption.java
index dedebfe713..e7059f3032 100644
--- a/core/src/mindustry/maps/filters/FilterOption.java
+++ b/core/src/mindustry/maps/filters/FilterOption.java
@@ -20,9 +20,10 @@ public abstract class FilterOption{
public static final Boolf floorsOnly = b -> (b instanceof Floor && !(b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(Cicon.full));
public static final Boolf wallsOnly = b -> (!b.synthetic() && !(b instanceof Floor)) && !headless && Core.atlas.isFound(b.icon(Cicon.full)) && b.inEditor;
public static final Boolf floorsOptional = b -> b == Blocks.air || ((b instanceof Floor && !(b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(Cicon.full)));
- public static final Boolf wallsOptional = b -> b == Blocks.air || ((!b.synthetic() && !(b instanceof Floor)) && !headless && Core.atlas.isFound(b.icon(Cicon.full)));
+ public static final Boolf wallsOptional = b -> (b == Blocks.air || ((!b.synthetic() && !(b instanceof Floor)) && !headless && Core.atlas.isFound(b.icon(Cicon.full)))) && b.inEditor;
public static final Boolf wallsOresOptional = b -> b == Blocks.air || (((!b.synthetic() && !(b instanceof Floor)) || (b instanceof OverlayFloor)) && !headless && Core.atlas.isFound(b.icon(Cicon.full))) && b.inEditor;
- public static final Boolf oresOnly = b -> b instanceof OverlayFloor && !headless && Core.atlas.isFound(b.icon(mindustry.ui.Cicon.full));
+ public static final Boolf oresOnly = b -> b instanceof OverlayFloor && !headless && Core.atlas.isFound(b.icon(Cicon.full));
+ public static final Boolf oresFloorsOptional = b -> (b instanceof Floor) && !headless && Core.atlas.isFound(b.icon(Cicon.full));
public static final Boolf anyOptional = b -> (floorsOnly.get(b) || wallsOnly.get(b) || oresOnly.get(b) || b == Blocks.air) && b.inEditor;
public abstract void build(Table table);
diff --git a/core/src/mindustry/maps/filters/GenerateFilter.java b/core/src/mindustry/maps/filters/GenerateFilter.java
index c884d5296e..47d8420936 100644
--- a/core/src/mindustry/maps/filters/GenerateFilter.java
+++ b/core/src/mindustry/maps/filters/GenerateFilter.java
@@ -5,7 +5,10 @@ import arc.math.*;
import arc.scene.ui.*;
import arc.util.*;
import arc.util.noise.*;
+import mindustry.*;
+import mindustry.annotations.Annotations.*;
import mindustry.content.*;
+import mindustry.gen.*;
import mindustry.world.*;
public abstract class GenerateFilter{
@@ -15,15 +18,42 @@ public abstract class GenerateFilter{
public void apply(Tiles tiles, GenerateInput in){
this.in = in;
- for(Tile tile : tiles){
- in.apply(tile.x, tile.y, tile.floor(), tile.block(), tile.overlay());
- apply();
- tile.setFloor(in.floor.asFloor());
- tile.setOverlay(!in.floor.asFloor().hasSurface() ? Blocks.air : in.ore);
+ if(isBuffered()){
+ //buffer of tiles used, each tile packed into a long struct
+ long[] buffer = new long[tiles.width * tiles.height];
- if(!tile.block().synthetic() && !in.block.synthetic()){
- tile.setBlock(in.block);
+ //save to buffer
+ for(int i = 0; i < tiles.width * tiles.height; i++){
+ Tile tile = tiles.geti(i);
+ buffer[i] = PackTile.get(tile.blockID(), tile.floorID(), tile.overlayID());
+ }
+
+ for(int i = 0; i < tiles.width * tiles.height; i++){
+ Tile tile = tiles.geti(i);
+ long b = buffer[i];
+
+ in.apply(tile.x, tile.y, Vars.content.block(PackTile.block(b)), Vars.content.block(PackTile.floor(b)), Vars.content.block(PackTile.overlay(b)));
+ apply();
+
+ tile.setFloor(in.floor.asFloor());
+ tile.setOverlay(!in.floor.asFloor().hasSurface() ? Blocks.air : in.overlay);
+
+ if(!tile.block().synthetic() && !in.block.synthetic()){
+ tile.setBlock(in.block);
+ }
+ }
+ }else{
+ for(Tile tile : tiles){
+ in.apply(tile.x, tile.y, tile.block(), tile.floor(), tile.overlay());
+ apply();
+
+ tile.setFloor(in.floor.asFloor());
+ tile.setOverlay(!in.floor.asFloor().hasSurface() ? Blocks.air : in.overlay);
+
+ if(!tile.block().synthetic() && !in.block.synthetic()){
+ tile.setBlock(in.block);
+ }
}
}
}
@@ -89,16 +119,16 @@ public abstract class GenerateFilter{
public int x, y, width, height;
/** output parameters */
- public Block floor, block, ore;
+ public Block floor, block, overlay;
Simplex noise = new Simplex();
RidgedPerlin pnoise = new RidgedPerlin(0, 1);
TileProvider buffer;
- public void apply(int x, int y, Block floor, Block block, Block ore){
+ public void apply(int x, int y, Block block, Block floor, Block overlay){
this.floor = floor;
this.block = block;
- this.ore = ore;
+ this.overlay = overlay;
this.x = x;
this.y = y;
}
@@ -119,4 +149,9 @@ public abstract class GenerateFilter{
Tile get(int x, int y);
}
}
+
+ @Struct
+ class PackTileStruct{
+ short block, floor, overlay;
+ }
}
diff --git a/core/src/mindustry/maps/filters/MirrorFilter.java b/core/src/mindustry/maps/filters/MirrorFilter.java
index 8d2e22bdbe..3ebdb45a71 100644
--- a/core/src/mindustry/maps/filters/MirrorFilter.java
+++ b/core/src/mindustry/maps/filters/MirrorFilter.java
@@ -39,7 +39,7 @@ public class MirrorFilter extends GenerateFilter{
if(!tile.block().synthetic()){
in.block = tile.block();
}
- in.ore = tile.overlay();
+ in.overlay = tile.overlay();
}
}
diff --git a/core/src/mindustry/maps/filters/NoiseFilter.java b/core/src/mindustry/maps/filters/NoiseFilter.java
index 857be64369..63e98e3ad9 100644
--- a/core/src/mindustry/maps/filters/NoiseFilter.java
+++ b/core/src/mindustry/maps/filters/NoiseFilter.java
@@ -9,7 +9,7 @@ import static mindustry.maps.filters.FilterOption.*;
public class NoiseFilter extends GenerateFilter{
float scl = 40, threshold = 0.5f, octaves = 3f, falloff = 0.5f;
- Block floor = Blocks.stone, block = Blocks.stoneWall;
+ Block floor = Blocks.stone, block = Blocks.stoneWall, target = Blocks.air;
@Override
public FilterOption[] options(){
@@ -18,8 +18,9 @@ public class NoiseFilter extends GenerateFilter{
new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f),
new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f),
new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f),
- new BlockOption("floor", () -> floor, b -> floor = b, floorsOnly),
- new BlockOption("wall", () -> block, b -> block = b, wallsOnly)
+ new BlockOption("target", () -> target, b -> target = b, anyOptional),
+ new BlockOption("floor", () -> floor, b -> floor = b, floorsOptional),
+ new BlockOption("wall", () -> block, b -> block = b, wallsOptional)
);
}
@@ -27,9 +28,9 @@ public class NoiseFilter extends GenerateFilter{
public void apply(){
float noise = noise(in.x, in.y, scl, 1f, octaves, falloff);
- if(noise > threshold){
- in.floor = floor;
- if(wallsOnly.get(in.block)) in.block = block;
+ if(noise > threshold && (target == Blocks.air || in.floor == target || in.block == target)){
+ if(floor != Blocks.air) in.floor = floor;
+ if(block != Blocks.air && in.block != Blocks.air) in.block = block;
}
}
}
diff --git a/core/src/mindustry/maps/filters/OreFilter.java b/core/src/mindustry/maps/filters/OreFilter.java
index 491bbf0123..3d9aee7e6e 100644
--- a/core/src/mindustry/maps/filters/OreFilter.java
+++ b/core/src/mindustry/maps/filters/OreFilter.java
@@ -9,7 +9,7 @@ import static mindustry.maps.filters.FilterOption.*;
public class OreFilter extends GenerateFilter{
public float scl = 23, threshold = 0.81f, octaves = 2f, falloff = 0.3f;
- public Block ore = Blocks.oreCopper;
+ public Block ore = Blocks.oreCopper, target = Blocks.air;
@Override
public FilterOption[] options(){
@@ -18,7 +18,8 @@ public class OreFilter extends GenerateFilter{
new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f),
new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f),
new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f),
- new BlockOption("ore", () -> ore, b -> ore = b, oresOnly)
+ new BlockOption("ore", () -> ore, b -> ore = b, oresOnly),
+ new BlockOption("target", () -> target, b -> target = b, oresFloorsOptional)
);
}
@@ -26,8 +27,8 @@ public class OreFilter extends GenerateFilter{
public void apply(){
float noise = noise(in.x, in.y, scl, 1f, octaves, falloff);
- if(noise > threshold && in.ore != Blocks.spawn){
- in.ore = ore;
+ if(noise > threshold && in.overlay != Blocks.spawn && (target == Blocks.air || in.floor == target || in.overlay == target)){
+ in.overlay = ore;
}
}
}
diff --git a/core/src/mindustry/maps/filters/OreMedianFilter.java b/core/src/mindustry/maps/filters/OreMedianFilter.java
index c9fd8d91c6..27a10548af 100644
--- a/core/src/mindustry/maps/filters/OreMedianFilter.java
+++ b/core/src/mindustry/maps/filters/OreMedianFilter.java
@@ -29,14 +29,14 @@ public class OreMedianFilter extends GenerateFilter{
@Override
public void apply(){
- if(in.ore == Blocks.spawn) return;
+ if(in.overlay == Blocks.spawn) return;
int cx = (in.x / 2) * 2;
int cy = (in.y / 2) * 2;
- if(in.ore != Blocks.air){
- if(!(in.tile(cx + 1, cy).overlay() == in.ore && in.tile(cx, cy).overlay() == in.ore && in.tile(cx + 1, cy + 1).overlay() == in.ore && in.tile(cx, cy + 1).overlay() == in.ore &&
+ if(in.overlay != Blocks.air){
+ if(!(in.tile(cx + 1, cy).overlay() == in.overlay && in.tile(cx, cy).overlay() == in.overlay && in.tile(cx + 1, cy + 1).overlay() == in.overlay && in.tile(cx, cy + 1).overlay() == in.overlay &&
!in.tile(cx + 1, cy).block().isStatic() && !in.tile(cx, cy).block().isStatic() && !in.tile(cx + 1, cy + 1).block().isStatic() && !in.tile(cx, cy + 1).block().isStatic())){
- in.ore = Blocks.air;
+ in.overlay = Blocks.air;
}
}
@@ -58,6 +58,6 @@ public class OreMedianFilter extends GenerateFilter{
int index = Math.min((int)(blocks.size * percentile), blocks.size - 1);
int overlay = blocks.get(index);
- in.ore = Vars.content.block(overlay);
+ in.overlay = Vars.content.block(overlay);
}
}
diff --git a/core/src/mindustry/maps/filters/ScatterFilter.java b/core/src/mindustry/maps/filters/ScatterFilter.java
index 4b90275b1f..67d2b0229e 100644
--- a/core/src/mindustry/maps/filters/ScatterFilter.java
+++ b/core/src/mindustry/maps/filters/ScatterFilter.java
@@ -27,7 +27,7 @@ public class ScatterFilter extends GenerateFilter{
if(!block.isOverlay()){
in.block = block;
}else{
- in.ore = block;
+ in.overlay = block;
}
}
diff --git a/core/src/mindustry/maps/filters/SpawnPathFilter.java b/core/src/mindustry/maps/filters/SpawnPathFilter.java
new file mode 100644
index 0000000000..8384024186
--- /dev/null
+++ b/core/src/mindustry/maps/filters/SpawnPathFilter.java
@@ -0,0 +1,64 @@
+package mindustry.maps.filters;
+
+import arc.math.*;
+import arc.struct.*;
+import arc.util.*;
+import mindustry.*;
+import mindustry.ai.*;
+import mindustry.content.*;
+import mindustry.maps.filters.FilterOption.*;
+import mindustry.world.*;
+import mindustry.world.blocks.storage.*;
+
+import static mindustry.Vars.*;
+
+/** Selects X spawns from the spawn pool.*/
+public class SpawnPathFilter extends GenerateFilter{
+ int radius = 3;
+
+ @Override
+ public FilterOption[] options(){
+ return Structs.arr(
+ new SliderOption("radius", () -> radius, f -> radius = (int)f, 1, 20).display()
+ );
+ }
+
+ @Override
+ public void apply(Tiles tiles, GenerateInput in){
+ Tile core = null;
+ var spawns = new Seq();
+
+ for(Tile tile : tiles){
+ if(tile.overlay() == Blocks.spawn){
+ spawns.add(tile);
+ }
+ if(tile.block() instanceof CoreBlock && tile.team() != Vars.state.rules.waveTeam){
+ core = tile;
+ }
+ }
+
+ if(core != null && spawns.any()){
+ for(var spawn : spawns){
+ var path = Astar.pathfind(core.x, core.y, spawn.x, spawn.y, t -> t.solid() ? 100 : 1, Astar.manhattan, tile -> !tile.floor().isDeep());
+ for(var tile : path){
+ for(int x = -radius; x <= radius; x++){
+ for(int y = -radius; y <= radius; y++){
+ int wx = tile.x + x, wy = tile.y + y;
+ if(Structs.inBounds(wx, wy, world.width(), world.height()) && Mathf.within(x, y, radius)){
+ Tile other = tiles.getn(wx, wy);
+ if(!other.synthetic()){
+ other.setBlock(Blocks.air);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean isPost(){
+ return true;
+ }
+}
diff --git a/core/src/mindustry/maps/filters/TerrainFilter.java b/core/src/mindustry/maps/filters/TerrainFilter.java
index cc0ba82b54..4caea2041a 100644
--- a/core/src/mindustry/maps/filters/TerrainFilter.java
+++ b/core/src/mindustry/maps/filters/TerrainFilter.java
@@ -31,11 +31,10 @@ public class TerrainFilter extends GenerateFilter{
float noise = noise(in.x, in.y, scl, magnitude, octaves, falloff) + Mathf.dst((float)in.x / in.width, (float)in.y / in.height, 0.5f, 0.5f) * circleScl;
in.floor = floor;
- in.ore = Blocks.air;
if(noise >= threshold){
in.block = block;
- }else{
+ }else if(!in.block.synthetic()){
in.block = Blocks.air;
}
}
diff --git a/core/src/mindustry/maps/generators/BasicGenerator.java b/core/src/mindustry/maps/generators/BasicGenerator.java
index e20350e6d3..1ef6d31297 100644
--- a/core/src/mindustry/maps/generators/BasicGenerator.java
+++ b/core/src/mindustry/maps/generators/BasicGenerator.java
@@ -248,7 +248,7 @@ public abstract class BasicGenerator implements WorldGenerator{
for(int x = -rad; x <= rad; x++){
for(int y = -rad; y <= rad; y++){
int wx = cx + x, wy = cy + y;
- if(Structs.inBounds(wx, wy, width, height) && Mathf.dst(x, y, 0, 0) <= rad){
+ if(Structs.inBounds(wx, wy, width, height) && Mathf.within(x, y, rad)){
Tile other = tiles.getn(wx, wy);
other.setBlock(Blocks.air);
}
diff --git a/core/src/mindustry/maps/generators/PlanetGenerator.java b/core/src/mindustry/maps/generators/PlanetGenerator.java
index 2f0bd37058..4b5884014b 100644
--- a/core/src/mindustry/maps/generators/PlanetGenerator.java
+++ b/core/src/mindustry/maps/generators/PlanetGenerator.java
@@ -25,6 +25,11 @@ public abstract class PlanetGenerator extends BasicGenerator implements HexMeshe
if(noise < 0.15){
for(Ptile other : tile.tiles){
+ //no sectors near start sector!
+ if(sector.planet.getSector(other).id == sector.planet.startSector){
+ return;
+ }
+
if(sector.planet.getSector(other).generateEnemyBase){
any = false;
break;
diff --git a/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java b/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java
index ee2f6b437c..4c7bd49a4e 100644
--- a/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java
+++ b/core/src/mindustry/maps/planet/SerpuloPlanetGenerator.java
@@ -277,7 +277,7 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
//hotrock tweaks
if(floor == Blocks.hotrock){
- if(rand.chance(0.3)){
+ if(Math.abs(0.5f - noise(x - 90, y, 4, 0.8, 80)) > 0.035){
floor = Blocks.basalt;
}else{
ore = Blocks.air;
@@ -412,12 +412,12 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
if(sector.hasEnemyBase()){
basegen.generate(tiles, enemies.map(r -> tiles.getn(r.x, r.y)), tiles.get(spawn.x, spawn.y), state.rules.waveTeam, sector, difficulty);
- state.rules.attackMode = true;
+ state.rules.attackMode = sector.info.attack = true;
}else{
- state.rules.winWave = 15 * (int)Math.max(difficulty * 10, 1);
+ state.rules.winWave = sector.info.winWave = 10 + 5 * (int)Math.max(difficulty * 10, 1);
}
- state.rules.waves = true;
+ state.rules.waves = sector.info.waves = true;
//TODO better waves
state.rules.spawns = DefaultWaves.generate(difficulty);
diff --git a/core/src/mindustry/mod/ContentParser.java b/core/src/mindustry/mod/ContentParser.java
index b9c119ee32..0d88d01034 100644
--- a/core/src/mindustry/mod/ContentParser.java
+++ b/core/src/mindustry/mod/ContentParser.java
@@ -190,6 +190,7 @@ public class ContentParser{
"mindustry.world.blocks.defense",
"mindustry.world.blocks.defense.turrets",
"mindustry.world.blocks.distribution",
+ "mindustry.world.blocks.environment",
"mindustry.world.blocks.liquid",
"mindustry.world.blocks.logic",
"mindustry.world.blocks.power",
@@ -260,8 +261,8 @@ public class ContentParser{
//TODO test this!
read(() -> {
//add reconstructor type
- if(value.hasChild("requirements")){
- JsonValue rec = value.remove("requirements");
+ if(value.has("requirements")){
+ JsonValue rec = value.remove("requirements");
//intermediate class for parsing
class UnitReq{
@@ -286,11 +287,36 @@ public class ContentParser{
}
+ //read extra default waves
+ if(value.has("waves")){
+ JsonValue waves = value.remove("waves");
+ SpawnGroup[] groups = parser.readValue(SpawnGroup[].class, waves);
+ for(SpawnGroup group : groups){
+ group.type = unit;
+ }
+
+ Vars.defaultWaves.get().addAll(groups);
+ }
+
readFields(unit, value, true);
});
return unit;
},
+ ContentType.weather, (TypeParser)(mod, name, value) -> {
+ Weather item;
+ if(locate(ContentType.weather, name) != null){
+ item = locate(ContentType.weather, name);
+ readBundle(ContentType.weather, name, value);
+ }else{
+ readBundle(ContentType.weather, name, value);
+ Class extends Weather> type = resolve(getType(value), "mindustry.type.weather");
+ item = make(type);
+ }
+ currentContent = item;
+ read(() -> readFields(item, value));
+ return item;
+ },
ContentType.item, parser(ContentType.item, Item::new),
ContentType.liquid, parser(ContentType.liquid, Liquid::new)
//ContentType.sector, parser(ContentType.sector, SectorPreset::new)
diff --git a/core/src/mindustry/mod/Mods.java b/core/src/mindustry/mod/Mods.java
index 12c33c7480..a596f3e7ae 100644
--- a/core/src/mindustry/mod/Mods.java
+++ b/core/src/mindustry/mod/Mods.java
@@ -629,7 +629,7 @@ public class Mods implements Loadable{
}
//make sure the main class exists before loading it; if it doesn't just don't put it there
- if(mainFile.exists()){
+ if(mainFile.exists() && Core.settings.getBool("mod-" + meta.name.toLowerCase().replace(" ", "-") + "-enabled", true)){
//mobile versions don't support class mods
if(ios){
throw new IllegalArgumentException("Java class mods are not supported on iOS.");
diff --git a/core/src/mindustry/mod/Scripts.java b/core/src/mindustry/mod/Scripts.java
index 1aa260e8fa..f372586863 100644
--- a/core/src/mindustry/mod/Scripts.java
+++ b/core/src/mindustry/mod/Scripts.java
@@ -59,12 +59,12 @@ public class Scripts implements Disposable{
if(o instanceof Undefined) o = "undefined";
return String.valueOf(o);
}catch(Throwable t){
- return getError(t);
+ return getError(t, false);
}
}
- private String getError(Throwable t){
- t.printStackTrace();
+ private String getError(Throwable t, boolean log){
+ if(log) Log.err(t);
return t.getClass().getSimpleName() + (t.getMessage() == null ? "" : ": " + t.getMessage());
}
@@ -138,7 +138,7 @@ public class Scripts implements Disposable{
if(currentMod != null){
file = currentMod.name + "/" + file;
}
- log(LogLevel.err, file, "" + getError(t));
+ log(LogLevel.err, file, "" + getError(t, true));
return false;
}
}
diff --git a/core/src/mindustry/net/Administration.java b/core/src/mindustry/net/Administration.java
index f185744c28..ccf5f76755 100644
--- a/core/src/mindustry/net/Administration.java
+++ b/core/src/mindustry/net/Administration.java
@@ -577,7 +577,10 @@ public class Administration{
autosave("Whether the periodically save the map when playing.", false),
autosaveAmount("The maximum amount of autosaves. Older ones get replaced.", 10),
autosaveSpacing("Spacing between autosaves in seconds.", 60 * 5),
- debug("Enable debug logging", false, () -> Log.setLogLevel(debug() ? LogLevel.debug : LogLevel.info));
+ debug("Enable debug logging", false, () -> {
+ LogLevel level = debug() ? LogLevel.debug : LogLevel.info;
+ Log.level = level;
+ });
public static final Config[] all = values();
diff --git a/core/src/mindustry/net/NetworkIO.java b/core/src/mindustry/net/NetworkIO.java
index 3a32d5cb6b..f4494e1c4f 100644
--- a/core/src/mindustry/net/NetworkIO.java
+++ b/core/src/mindustry/net/NetworkIO.java
@@ -3,7 +3,9 @@ package mindustry.net;
import arc.*;
import arc.util.*;
import arc.util.io.*;
+import mindustry.content.*;
import mindustry.core.*;
+import mindustry.ctype.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.io.*;
@@ -21,6 +23,18 @@ public class NetworkIO{
public static void writeWorld(Player player, OutputStream os){
try(DataOutputStream stream = new DataOutputStream(os)){
+ //write all researched content to rules if hosting
+ if(state.isCampaign()){
+ state.rules.researched.clear();
+ for(ContentType type : ContentType.all){
+ for(Content c : content.getBy(type)){
+ if(c instanceof UnlockableContent u && u.unlocked() && TechTree.get(u) != null){
+ state.rules.researched.add(u.name);
+ }
+ }
+ }
+ }
+
stream.writeUTF(JsonIO.write(state.rules));
SaveIO.getSaveWriter().writeStringMap(stream, state.map.tags);
diff --git a/core/src/mindustry/type/AmmoTypes.java b/core/src/mindustry/type/AmmoTypes.java
index 5b7c885519..761bcbc8d0 100644
--- a/core/src/mindustry/type/AmmoTypes.java
+++ b/core/src/mindustry/type/AmmoTypes.java
@@ -41,15 +41,15 @@ public class AmmoTypes implements ContentList{
@Override
public void resupply(Unit unit){
float range = unit.hitSize + 60f;
- Tile closest = Vars.indexer.findClosestFlag(unit.x, unit.y, unit.team, BlockFlag.powerRes);
+ Tile closest = Vars.indexer.findClosestFlag(unit.x, unit.y, unit.team, BlockFlag.battery);
if(closest != null && closest.build != null && unit.within(closest.build, range) && closest.build.power != null){
var build = closest.build;
if(build.block.consumes.hasPower() && build.block.consumes.getPower().buffered){
float amount = closest.build.power.status * build.block.consumes.getPower().capacity;
- float powerPerAmmo = totalPower / unit.type().ammoCapacity;
- float ammoRequired = unit.type().ammoCapacity - unit.ammo;
+ float powerPerAmmo = totalPower / unit.type.ammoCapacity;
+ float ammoRequired = unit.type.ammoCapacity - unit.ammo;
float powerRequired = ammoRequired * powerPerAmmo;
float powerTaken = Math.min(amount, powerRequired);
diff --git a/core/src/mindustry/type/Item.java b/core/src/mindustry/type/Item.java
index 9329efb47e..f52323d655 100644
--- a/core/src/mindustry/type/Item.java
+++ b/core/src/mindustry/type/Item.java
@@ -1,16 +1,15 @@
package mindustry.type;
import arc.graphics.*;
-import arc.scene.ui.layout.*;
import arc.struct.*;
import mindustry.ctype.*;
-import mindustry.ui.*;
import mindustry.world.blocks.environment.*;
+import mindustry.world.meta.*;
import static mindustry.Vars.*;
public class Item extends UnlockableContent{
- public final Color color;
+ public Color color;
/** how explosive this item is. */
public float explosiveness = 0f;
@@ -36,8 +35,10 @@ public class Item extends UnlockableContent{
}
@Override
- public void displayInfo(Table table){
- ContentDisplay.displayItem(table, this);
+ public void setStats(){
+ stats.addPercent(Stat.explosiveness, explosiveness);
+ stats.addPercent(Stat.flammability, flammability);
+ stats.addPercent(Stat.radioactivity, radioactivity);
}
@Override
diff --git a/core/src/mindustry/type/ItemSeq.java b/core/src/mindustry/type/ItemSeq.java
index 0407f6a3f8..49055fb5b9 100644
--- a/core/src/mindustry/type/ItemSeq.java
+++ b/core/src/mindustry/type/ItemSeq.java
@@ -21,6 +21,13 @@ public class ItemSeq implements Iterable, Serializable{
stacks.each(this::add);
}
+ public ItemSeq copy(){
+ ItemSeq out = new ItemSeq();
+ out.total = total;
+ System.arraycopy(values, 0, out.values, 0, values.length);
+ return out;
+ }
+
public void each(ItemConsumer cons){
for(int i = 0; i < values.length; i++){
if(values[i] != 0){
@@ -46,6 +53,19 @@ public class ItemSeq implements Iterable, Serializable{
return values[item.id] > 0;
}
+ public boolean has(ItemSeq seq){
+ for(int i = 0; i < values.length; i++){
+ if(seq.values[i] > values[i]){
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean has(Item item, int amount){
+ return values[item.id] >= amount;
+ }
+
public int get(Item item){
return values[item.id];
}
diff --git a/core/src/mindustry/type/ItemStack.java b/core/src/mindustry/type/ItemStack.java
index d5f4097b58..e2e0d2d5f4 100644
--- a/core/src/mindustry/type/ItemStack.java
+++ b/core/src/mindustry/type/ItemStack.java
@@ -64,6 +64,13 @@ public class ItemStack implements Comparable{
return item.compareTo(itemStack.item);
}
+ @Override
+ public boolean equals(Object o){
+ if(this == o) return true;
+ if(!(o instanceof ItemStack stack)) return false;
+ return amount == stack.amount && item == stack.item;
+ }
+
@Override
public String toString(){
return "ItemStack{" +
diff --git a/core/src/mindustry/type/Liquid.java b/core/src/mindustry/type/Liquid.java
index 19e77a9987..e62805e60b 100644
--- a/core/src/mindustry/type/Liquid.java
+++ b/core/src/mindustry/type/Liquid.java
@@ -1,15 +1,14 @@
package mindustry.type;
import arc.graphics.*;
-import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.content.*;
import mindustry.ctype.*;
-import mindustry.ui.*;
+import mindustry.world.meta.*;
public class Liquid extends UnlockableContent{
/** Color used in pipes and on the ground. */
- public final Color color;
+ public Color color;
/** Color used in bars. */
public @Nullable Color barColor;
/** Color used to draw lights. Note that the alpha channel is used to dictate brightness. */
@@ -46,8 +45,12 @@ public class Liquid extends UnlockableContent{
}
@Override
- public void displayInfo(Table table){
- ContentDisplay.displayLiquid(table, this);
+ public void setStats(){
+ stats.addPercent(Stat.explosiveness, explosiveness);
+ stats.addPercent(Stat.flammability, flammability);
+ stats.addPercent(Stat.temperature, temperature);
+ stats.addPercent(Stat.heatCapacity, heatCapacity);
+ stats.addPercent(Stat.viscosity, viscosity);
}
@Override
diff --git a/core/src/mindustry/type/Planet.java b/core/src/mindustry/type/Planet.java
index 6153aa4721..4550ae6805 100644
--- a/core/src/mindustry/type/Planet.java
+++ b/core/src/mindustry/type/Planet.java
@@ -5,7 +5,6 @@ import arc.func.*;
import arc.graphics.*;
import arc.math.*;
import arc.math.geom.*;
-import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import arc.util.noise.*;
@@ -177,7 +176,7 @@ public class Planet extends UnlockableContent{
public void updateBaseCoverage(){
for(Sector sector : sectors){
float sum = 1f;
- for(Sector other : sector.inRange(2)){
+ for(Sector other : sector.near()){
if(other.generateEnemyBase){
sum += 1f;
}
@@ -204,6 +203,10 @@ public class Planet extends UnlockableContent{
@Override
public void init(){
+ for(Sector sector : sectors){
+ sector.loadInfo();
+ }
+
if(generator != null){
Noise.setSeed(id + 1);
@@ -255,13 +258,16 @@ public class Planet extends UnlockableContent{
return true;
}
- @Override
- public void displayInfo(Table table){
-
- }
-
@Override
public ContentType getContentType(){
return ContentType.planet;
}
+
+ public boolean visible(){
+ return true;
+ }
+
+ public void draw(Mat3D projection, Mat3D transform){
+ mesh.render(projection, transform);
+ }
}
diff --git a/core/src/mindustry/type/Sector.java b/core/src/mindustry/type/Sector.java
index 4c1df28945..d9d54ba91c 100644
--- a/core/src/mindustry/type/Sector.java
+++ b/core/src/mindustry/type/Sector.java
@@ -7,6 +7,7 @@ import arc.struct.*;
import arc.util.*;
import mindustry.*;
import mindustry.game.Saves.*;
+import mindustry.game.*;
import mindustry.graphics.g3d.PlanetGrid.*;
import mindustry.world.modules.*;
@@ -14,8 +15,7 @@ import static mindustry.Vars.*;
/** A small section of a planet. */
public class Sector{
- private static final Seq tmpSeq1 = new Seq<>(), tmpSeq2 = new Seq<>(), tmpSeq3 = new Seq<>();
- private static final ObjectSet tmpSet = new ObjectSet<>();
+ private static final Seq tmpSeq1 = new Seq<>();
public final SectorRect rect;
public final Plane plane;
@@ -25,6 +25,7 @@ public class Sector{
public @Nullable SaveSlot save;
public @Nullable SectorPreset preset;
+ public SectorInfo info = new SectorInfo();
/** Number 0-1 indicating the difficulty based on nearby bases. */
public float baseCoverage;
@@ -38,60 +39,69 @@ public class Sector{
this.id = tile.id;
}
- public Seq inRange(int range){
- //TODO cleanup/remove
- if(true){
- tmpSeq1.clear();
- neighbors(tmpSeq1::add);
-
- return tmpSeq1;
+ /** @return a copy of the items in this sector - may be core items, or stored data. */
+ public ItemSeq getItems(){
+ if(isBeingPlayed()){
+ ItemSeq out = new ItemSeq();
+ if(state.rules.defaultTeam.core() != null) out.add(state.rules.defaultTeam.core().items);
+ return out;
+ }else{
+ return info.items;
}
-
- tmpSeq1.clear();
- tmpSeq2.clear();
- tmpSet.clear();
-
- tmpSeq1.add(this);
- tmpSet.add(this);
- for(int i = 0; i < range; i++){
- while(!tmpSeq1.isEmpty()){
- Sector sec = tmpSeq1.pop();
- tmpSet.add(sec);
- sec.neighbors(other -> {
- if(tmpSet.add(other)){
- tmpSeq2.add(other);
- }
- });
- }
- tmpSeq1.clear();
- tmpSeq1.addAll(tmpSeq2);
- }
-
- tmpSeq3.clear().addAll(tmpSeq2);
- return tmpSeq3;
}
- public void neighbors(Cons cons){
+ public Seq near(){
+ tmpSeq1.clear();
+ for(Ptile tile : tile.tiles){
+ tmpSeq1.add(planet.getSector(tile));
+ }
+
+ return tmpSeq1;
+ }
+
+ public void near(Cons cons){
for(Ptile tile : tile.tiles){
cons.get(planet.getSector(tile));
}
}
/** @return whether this sector can be landed on at all.
- * Only sectors adjacent to non-wave sectors can be landed on.
- * TODO also preset sectors*/
+ * Only sectors adjacent to non-wave sectors can be landed on. */
public boolean unlocked(){
return hasBase() || (preset != null && preset.alwaysUnlocked);
}
+ public void saveInfo(){
+ Core.settings.putJson(planet.name + "-s-" + id + "-info", info);
+ }
+
+ public void loadInfo(){
+ info = Core.settings.getJson(planet.name + "-s-" + id + "-info", SectorInfo.class, SectorInfo::new);
+ }
+
+ /** Removes any sector info. */
+ public void clearInfo(){
+ info = new SectorInfo();
+ Core.settings.remove(planet.name + "-s-" + id + "-info");
+ }
+
+ public float getProductionScale(){
+ return Math.max(1f - info.damage, 0);
+ }
+
+ public boolean isAttacked(){
+ if(isBeingPlayed()) return state.rules.waves;
+ return save != null && info.waves && info.hasCore;
+ }
+
/** @return whether the player has a base here. */
public boolean hasBase(){
- return save != null && !save.meta.tags.getBool("nocores");
+ return save != null && info.hasCore;
}
/** @return whether the enemy has a generated base here. */
public boolean hasEnemyBase(){
- return generateEnemyBase && (save == null || save.meta.rules.waves);
+ return generateEnemyBase && (save == null || info.waves);
}
public boolean isBeingPlayed(){
@@ -99,13 +109,18 @@ public class Sector{
return Vars.state.isGame() && Vars.state.rules.sector == this && !Vars.state.gameOver;
}
- public boolean isCaptured(){
- return save != null && !save.meta.rules.waves;
+ public String name(){
+ if(preset != null) return preset.localizedName;
+ return info.name == null ? id + "" : info.name;
}
- /** @return whether waves are present - if true, any bases here will be attacked. */
- public boolean hasWaves(){
- return save != null && save.meta.rules.waves;
+ public void setName(String name){
+ info.name = name;
+ saveInfo();
+ }
+
+ public boolean isCaptured(){
+ return save != null && !info.waves;
}
public boolean hasSave(){
@@ -130,19 +145,16 @@ public class Sector{
return res % 2 == 0 ? res : res + 1;
}
- //TODO this should be stored in a more efficient structure, and be updated each turn
- public ItemSeq getExtraItems(){
- return Core.settings.getJson(key("extra-items"), ItemSeq.class, ItemSeq::new);
- }
-
- public void setExtraItems(ItemSeq stacks){
- Core.settings.putJson(key("extra-items"), stacks);
- }
-
public void addItem(Item item, int amount){
removeItem(item, -amount);
}
+ public void removeItems(ItemSeq items){
+ ItemSeq copy = items.copy();
+ copy.each((i, a) -> copy.set(i, -a));
+ addItems(copy);
+ }
+
public void removeItem(Item item, int amount){
ItemSeq seq = new ItemSeq();
seq.add(item, -amount);
@@ -156,137 +168,27 @@ public class Sector{
int cap = state.rules.defaultTeam.core().storageCapacity;
items.each((item, amount) -> storage.add(item, Math.min(cap - storage.get(item), amount)));
}
- }else{
- ItemSeq recv = getExtraItems();
-
- if(save != null){
- //"shave off" extra items
-
- ItemSeq count = new ItemSeq();
-
- //add items already present
- count.add(save.meta.secinfo.coreItems);
-
- count.add(calculateReceivedItems());
-
- int capacity = save.meta.secinfo.storageCapacity;
-
- //when over capacity, add that to the extra items
- count.each((i, a) -> {
- if(a > capacity){
- recv.remove(i, (a - capacity));
- }
- });
- }
-
- recv.add(items);
-
- setExtraItems(recv);
+ }else if(hasBase()){
+ items.each((item, amount) -> info.items.add(item, Math.min(info.storageCapacity - info.items.get(item), amount)));
+ saveInfo();
}
}
- public ItemSeq calculateItems(){
+ /** @return items currently in this sector, taking into account playing state. */
+ public ItemSeq items(){
ItemSeq count = new ItemSeq();
//for sectors being played on, add items directly
if(isBeingPlayed()){
count.add(state.rules.defaultTeam.items());
- }else if(save != null){
+ }else{
//add items already present
- count.add(save.meta.secinfo.coreItems);
-
- count.add(calculateReceivedItems());
-
- int capacity = save.meta.secinfo.storageCapacity;
-
- //validation
- count.each((item, amount) -> {
- //ensure positive items
- if(amount < 0) count.set(item, 0);
- //cap the items
- if(amount > capacity) count.set(item, capacity);
- });
+ count.add(info.items);
}
return count;
}
- public ItemSeq calculateReceivedItems(){
- ItemSeq count = new ItemSeq();
-
- if(save != null){
- long seconds = getSecondsPassed();
-
- //add produced items
- save.meta.secinfo.production.each((item, stat) -> count.add(item, (int)(stat.mean * seconds)));
-
- //add received items
- count.add(getExtraItems());
- }
-
- return count;
- }
-
- //TODO these methods should maybe move somewhere else and/or be contained in a data object
- public void setSpawnPosition(int position){
- put("spawn-position", position);
- }
-
- /** Only valid after this sector has been landed on once. */
- //TODO move to sector data?
- public int getSpawnPosition(){
- return Core.settings.getInt(key("spawn-position"), Point2.pack(world.width() / 2, world.height() / 2));
- }
-
- /** @return time spent in this sector this turn in ticks. */
- public float getTimeSpent(){
- //return currently counting time spent if being played on
- if(isBeingPlayed()) return state.secinfo.internalTimeSpent;
-
- //else return the stored value
- return getStoredTimeSpent();
- }
-
- public void setTimeSpent(float time){
- put("time-spent", time);
-
- //update counting time
- if(isBeingPlayed()){
- state.secinfo.internalTimeSpent = time;
- }
- }
-
- public String displayTimeRemaining(){
- float amount = Vars.turnDuration - getTimeSpent();
- int seconds = (int)(amount / 60);
- int sf = seconds % 60;
- return (seconds / 60) + ":" + (sf < 10 ? "0" : "") + sf;
- }
-
- /** @return the stored amount of time spent in this sector this turn in ticks.
- * Do not use unless you know what you're doing. */
- public float getStoredTimeSpent(){
- return Core.settings.getFloat(key("time-spent"));
- }
-
- public void setSecondsPassed(int number){
- put("secondsi-passed", number);
- }
-
- /** @return how much time has passed in this sector without the player resuming here.
- * Used for resource production calculations. */
- public int getSecondsPassed(){
- return Core.settings.getInt(key("secondsi-passed"));
- }
-
- private String key(String key){
- return planet.name + "-s-" + id + "-" + key;
- }
-
- private void put(String key, Object value){
- Core.settings.put(key(key), value);
- }
-
public String toString(){
return planet.name + "#" + id;
}
diff --git a/core/src/mindustry/type/SectorPreset.java b/core/src/mindustry/type/SectorPreset.java
index 923d023b25..0e9b90fb30 100644
--- a/core/src/mindustry/type/SectorPreset.java
+++ b/core/src/mindustry/type/SectorPreset.java
@@ -2,7 +2,6 @@ package mindustry.type;
import arc.func.*;
import arc.graphics.g2d.*;
-import arc.scene.ui.layout.*;
import mindustry.ctype.*;
import mindustry.game.*;
import mindustry.gen.*;
@@ -23,6 +22,7 @@ public class SectorPreset extends UnlockableContent{
super(name);
this.generator = new FileMapGenerator(name);
this.planet = planet;
+ sector %= planet.sectors.size;
this.sector = planet.sectors.get(sector);
planet.preset(sector, this);
@@ -38,11 +38,6 @@ public class SectorPreset extends UnlockableContent{
return true;
}
- //neither of these are implemented, as zones are not displayed in a normal fashion... yet
- @Override
- public void displayInfo(Table table){
- }
-
@Override
public ContentType getContentType(){
return ContentType.sector;
diff --git a/core/src/mindustry/type/StatusEffect.java b/core/src/mindustry/type/StatusEffect.java
index eb0bedb60c..90488c62ea 100644
--- a/core/src/mindustry/type/StatusEffect.java
+++ b/core/src/mindustry/type/StatusEffect.java
@@ -56,7 +56,7 @@ public class StatusEffect extends MappableContent{
}
if(effect != Fx.none && Mathf.chanceDelta(effectChance)){
- Tmp.v1.rnd(unit.type().hitSize /2f);
+ Tmp.v1.rnd(unit.type.hitSize /2f);
effect.at(unit.x + Tmp.v1.x, unit.y + Tmp.v1.y);
}
}
diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java
index 661e735fa7..8a2d274b44 100644
--- a/core/src/mindustry/type/UnitType.java
+++ b/core/src/mindustry/type/UnitType.java
@@ -28,6 +28,8 @@ import mindustry.world.blocks.environment.*;
import mindustry.world.blocks.payloads.*;
import mindustry.world.blocks.units.*;
import mindustry.world.consumers.*;
+import mindustry.world.meta.*;
+import mindustry.world.meta.values.*;
import static mindustry.Vars.*;
@@ -41,7 +43,7 @@ public class UnitType extends UnlockableContent{
public Prov extends UnitController> defaultController = () -> !flying ? new GroundAI() : new FlyingAI();
public float speed = 1.1f, boostMultiplier = 1f, rotateSpeed = 5f, baseRotateSpeed = 5f;
public float drag = 0.3f, accel = 0.5f, landShake = 0f, rippleScale = 1f, fallSpeed = 0.018f;
- public float health = 200f, range = -1, armor = 0f;
+ public float health = 200f, range = -1, armor = 0f, maxRange = -1f;
public float crashDamageMultiplier = 1f;
public boolean targetAir = true, targetGround = true;
public boolean faceTarget = true, rotateShooting = true, isCounted = true, lowAltitude = false;
@@ -58,6 +60,7 @@ public class UnitType extends UnlockableContent{
public Effect fallEffect = Fx.fallSmoke;
public Effect fallThrusterEffect = Fx.fallSmoke;
public Seq abilities = new Seq<>();
+ public BlockFlag targetFlag = BlockFlag.generator;
public int legCount = 4, legGroupSize = 2;
public float legLength = 10f, legSpeed = 0.1f, legTrns = 1f, legBaseOffset = 0f, legMoveSpace = 1f, legExtension = 0, legPairOffset = 0, legLengthScl = 1f, kinematicScl = 1f, maxStretch = 1.75f;
@@ -79,6 +82,8 @@ public class UnitType extends UnlockableContent{
public int mineTier = -1;
public float buildSpeed = 1f, mineSpeed = 1f;
+ /** This is a VERY ROUGH estimate of unit DPS. */
+ public float dpsEstimate = -1;
public float clipSize = -1;
public boolean canDrown = true;
public float engineOffset = 5f, engineSize = 2.5f;
@@ -115,7 +120,7 @@ public class UnitType extends UnlockableContent{
public Unit create(Team team){
Unit unit = constructor.get();
unit.team = team;
- unit.type(this);
+ unit.setType(this);
unit.ammo = ammoCapacity; //fill up on ammo upon creation
unit.elevation = flying ? 1f : 0;
unit.heal();
@@ -154,11 +159,11 @@ public class UnitType extends UnlockableContent{
table.table(bars -> {
bars.defaults().growX().height(20f).pad(4);
- bars.add(new Bar("blocks.health", Pal.health, unit::healthf).blink(Color.white));
+ bars.add(new Bar("stat.health", Pal.health, unit::healthf).blink(Color.white));
bars.row();
if(state.rules.unitAmmo){
- bars.add(new Bar(ammoType.icon + " " + Core.bundle.get("blocks.ammo"), ammoType.barColor, () -> unit.ammo / ammoCapacity));
+ bars.add(new Bar(ammoType.icon + " " + Core.bundle.get("stat.ammo"), ammoType.barColor, () -> unit.ammo / ammoCapacity));
bars.row();
}
}).growX();
@@ -166,6 +171,8 @@ public class UnitType extends UnlockableContent{
if(unit.controller() instanceof LogicAI){
table.row();
table.add(Blocks.microProcessor.emoji() + " " + Core.bundle.get("units.processorcontrol")).growX().left();
+ table.row();
+ table.label(() -> Iconc.settings + " " + (long)unit.flag + "").color(Color.lightGray).growX().wrap().left();
}
table.row();
@@ -186,10 +193,37 @@ public class UnitType extends UnlockableContent{
}
}
-
@Override
- public void displayInfo(Table table){
- ContentDisplay.displayUnit(table, this);
+ public void setStats(){
+ Unit inst = constructor.get();
+
+ stats.add(Stat.health, health);
+ stats.add(Stat.speed, speed);
+ stats.add(Stat.itemCapacity, health);
+ stats.add(Stat.range, (int)(maxRange / tilesize), StatUnit.blocks);
+ stats.add(Stat.commandLimit, commandLimit);
+ //TODO abilities, maybe try something like DPS
+
+ if(abilities.any()){
+ var unique = new ObjectSet();
+
+ for(Ability a : abilities){
+ if(unique.add(a.localized())){
+ stats.add(Stat.abilities, a.localized());
+ }
+ }
+ }
+
+ if(inst instanceof Minerc && mineTier >= 1){
+ stats.addPercent(Stat.mineSpeed, mineSpeed);
+ stats.add(Stat.mineTier, new BlockFilterValue(b -> b instanceof Floor f && f.itemDrop != null && f.itemDrop.hardness <= mineTier && !f.playerUnmineable));
+ }
+ if(inst instanceof Builderc){
+ stats.addPercent(Stat.buildSpeed, buildSpeed);
+ }
+ if(inst instanceof Payloadc){
+ stats.add(Stat.payloadCapacity, (payloadCapacity / (tilesize * tilesize)), StatUnit.blocksSquared);
+ }
}
@CallSuper
@@ -216,7 +250,16 @@ public class UnitType extends UnlockableContent{
if(range < 0){
range = Float.MAX_VALUE;
for(Weapon weapon : weapons){
- range = Math.min(range, weapon.bullet.range() + hitSize /2f);
+ range = Math.min(range, weapon.bullet.range() + hitSize / 2f);
+ maxRange = Math.max(maxRange, weapon.bullet.range() + hitSize / 2f);
+ }
+ }
+
+ if(maxRange < 0){
+ maxRange = 0f;
+
+ for(Weapon weapon : weapons){
+ maxRange = Math.max(maxRange, weapon.bullet.range() + hitSize / 2f);
}
}
@@ -266,6 +309,17 @@ public class UnitType extends UnlockableContent{
ammoCapacity = Math.max(1, (int)(shotsPerSecond * targetSeconds));
}
+
+ //calculate estimated DPS for one target based on weapons
+ if(dpsEstimate < 0){
+ dpsEstimate = weapons.sumf(w -> (w.bullet.estimateDPS() / w.reload) * w.shots * 60f);
+
+ //suicide enemy
+ if(weapons.contains(w -> w.bullet.killShooter)){
+ //scale down DPS to be insignificant
+ dpsEstimate /= 100f;
+ }
+ }
}
@CallSuper
@@ -309,7 +363,7 @@ public class UnitType extends UnlockableContent{
if(stacks != null){
ItemStack[] out = new ItemStack[stacks.length];
for(int i = 0; i < out.length; i++){
- out[i] = new ItemStack(stacks[i].item, UI.roundAmount((int)(Math.pow(stacks[i].amount, 1.1) * 50)));
+ out[i] = new ItemStack(stacks[i].item, UI.roundAmount((int)(Math.pow(stacks[i].amount, 1) * 50)));
}
return out;
@@ -436,7 +490,7 @@ public class UnitType extends UnlockableContent{
applyColor(unit);
//draw back items
- if(unit.hasItem() && unit.itemTime > 0.01f){
+ if(unit.item() != null && unit.itemTime > 0.01f){
float size = (itemSize + Mathf.absin(Time.time(), 5f, 1f)) * unit.itemTime;
Draw.mixcol(Pal.accent, Mathf.absin(Time.time(), 5f, 0.5f));
diff --git a/core/src/mindustry/type/Weather.java b/core/src/mindustry/type/Weather.java
index 8fb30aecb6..4d17ab7c0e 100644
--- a/core/src/mindustry/type/Weather.java
+++ b/core/src/mindustry/type/Weather.java
@@ -1,16 +1,18 @@
package mindustry.type;
+import arc.*;
import arc.func.*;
+import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
-import arc.scene.ui.layout.*;
import arc.util.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.ctype.*;
import mindustry.gen.*;
import mindustry.graphics.*;
+import mindustry.world.*;
import mindustry.world.blocks.*;
import static mindustry.Vars.*;
@@ -91,9 +93,136 @@ public abstract class Weather extends UnlockableContent{
}
- @Override
- public void displayInfo(Table table){
- //do not
+ public void drawParticles(TextureRegion region, Color color,
+ float sizeMin, float sizeMax,
+ float density, float intensity, float opacity,
+ float windx, float windy,
+ float minAlpha, float maxAlpha,
+ float sinSclMin, float sinSclMax, float sinMagMin, float sinMagMax){
+ rand.setSeed(0);
+ Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
+ Tmp.r1.grow(sizeMax * 1.5f);
+ Core.camera.bounds(Tmp.r2);
+ int total = (int)(Tmp.r1.area() / density * intensity);
+ Draw.color(color, opacity);
+
+ for(int i = 0; i < total; i++){
+ float scl = rand.random(0.5f, 1f);
+ float scl2 = rand.random(0.5f, 1f);
+ float size = rand.random(sizeMin, sizeMax);
+ float x = (rand.random(0f, world.unitWidth()) + Time.time() * windx * scl2);
+ float y = (rand.random(0f, world.unitHeight()) + Time.time() * windy * scl);
+ float alpha = rand.random(minAlpha, maxAlpha);
+
+ x += Mathf.sin(y, rand.random(sinSclMin, sinSclMax), rand.random(sinMagMin, sinMagMax));
+
+ x -= Tmp.r1.x;
+ y -= Tmp.r1.y;
+ x = Mathf.mod(x, Tmp.r1.width);
+ y = Mathf.mod(y, Tmp.r1.height);
+ x += Tmp.r1.x;
+ y += Tmp.r1.y;
+
+ if(Tmp.r3.setCentered(x, y, size).overlaps(Tmp.r2)){
+ Draw.alpha(alpha * opacity);
+ Draw.rect(region, x, y, size, size);
+ }
+ }
+ }
+
+ public void drawRain(float sizeMin, float sizeMax, float xspeed, float yspeed, float density, float intensity, float stroke, Color color){
+ float padding = sizeMax*0.9f;
+
+ Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
+ Tmp.r1.grow(padding);
+ Core.camera.bounds(Tmp.r2);
+ int total = (int)(Tmp.r1.area() / density * intensity);
+ Lines.stroke(stroke);
+ float alpha = Draw.getColor().a;
+ Draw.color(color);
+
+ for(int i = 0; i < total; i++){
+ float scl = rand.random(0.5f, 1f);
+ float scl2 = rand.random(0.5f, 1f);
+ float size = rand.random(sizeMin, sizeMax);
+ float x = (rand.random(0f, world.unitWidth()) + Time.time() * xspeed * scl2);
+ float y = (rand.random(0f, world.unitHeight()) - Time.time() * yspeed * scl);
+ float tint = rand.random(1f) * alpha;
+
+ x -= Tmp.r1.x;
+ y -= Tmp.r1.y;
+ x = Mathf.mod(x, Tmp.r1.width);
+ y = Mathf.mod(y, Tmp.r1.height);
+ x += Tmp.r1.x;
+ y += Tmp.r1.y;
+
+ if(Tmp.r3.setCentered(x, y, size).overlaps(Tmp.r2)){
+ Draw.alpha(tint);
+ Lines.lineAngle(x, y, Angles.angle(xspeed * scl2, - yspeed * scl), size/2f);
+ }
+ }
+ }
+
+ public void drawSplashes(TextureRegion[] splashes, float padding, float density, float intensity, float opacity, float timeScale, float stroke, Color color, Liquid splasher){
+ Tmp.r1.setCentered(Core.camera.position.x, Core.camera.position.y, Core.graphics.getWidth() / renderer.minScale(), Core.graphics.getHeight() / renderer.minScale());
+ Tmp.r1.grow(padding);
+ Core.camera.bounds(Tmp.r2);
+ int total = (int)(Tmp.r1.area() / density * intensity) / 2;
+ Lines.stroke(stroke);
+
+ float t = Time.time() / timeScale;
+
+ for(int i = 0; i < total; i++){
+ float offset = rand.random(0f, 1f);
+ float time = t + offset;
+
+ int pos = (int)((time));
+ float life = time % 1f;
+ float x = (rand.random(0f, world.unitWidth()) + pos*953);
+ float y = (rand.random(0f, world.unitHeight()) - pos*453);
+
+ x -= Tmp.r1.x;
+ y -= Tmp.r1.y;
+ x = Mathf.mod(x, Tmp.r1.width);
+ y = Mathf.mod(y, Tmp.r1.height);
+ x += Tmp.r1.x;
+ y += Tmp.r1.y;
+
+ if(Tmp.r3.setCentered(x, y, life * 4f).overlaps(Tmp.r2)){
+ Tile tile = world.tileWorld(x, y);
+
+ //only create splashes on specific liquid.
+ if(tile != null && tile.floor().liquidDrop == splasher){
+ Draw.color(Tmp.c1.set(tile.floor().mapColor).mul(1.5f).a(opacity));
+ Draw.rect(splashes[(int)(life * (splashes.length - 1))], x, y);
+ }else if(tile != null && tile.floor().liquidDrop == null && !tile.floor().solid){
+ Draw.color(color);
+ Draw.alpha(Mathf.slope(life) * opacity);
+
+ float space = 45f;
+ for(int j : new int[]{-1, 1}){
+ Tmp.v1.trns(90f + j*space, 1f + 5f * life);
+ Lines.lineAngle(x + Tmp.v1.x, y + Tmp.v1.y, 90f + j*space, 3f * (1f - life));
+ }
+ }
+ }
+ }
+ }
+
+ public void drawNoise(Texture noise, Color color, float noisescl, float opacity, float baseSpeed, float intensity, float vwindx, float vwindy, float offset){
+ Draw.alpha(opacity);
+ Draw.tint(color);
+
+ float speed = baseSpeed * intensity;
+ float windx = vwindx * speed, windy = vwindy * speed;
+
+ float scale = 1f / noisescl;
+ float scroll = Time.time() * scale + offset;
+ Tmp.tr1.texture = noise;
+ Core.camera.bounds(Tmp.r1);
+ Tmp.tr1.set(Tmp.r1.x*scale, Tmp.r1.y*scale, (Tmp.r1.x + Tmp.r1.width)*scale, (Tmp.r1.y + Tmp.r1.height)*scale);
+ Tmp.tr1.scroll(-windx * scroll, -windy * scroll);
+ Draw.rect(Tmp.tr1, Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height);
}
@Override
diff --git a/core/src/mindustry/type/weather/ParticleWeather.java b/core/src/mindustry/type/weather/ParticleWeather.java
new file mode 100644
index 0000000000..060e9cbe62
--- /dev/null
+++ b/core/src/mindustry/type/weather/ParticleWeather.java
@@ -0,0 +1,90 @@
+package mindustry.type.weather;
+
+import arc.*;
+import arc.graphics.*;
+import arc.graphics.Texture.*;
+import arc.graphics.g2d.*;
+import arc.util.*;
+import mindustry.gen.*;
+import mindustry.type.*;
+
+public class ParticleWeather extends Weather{
+ public String particleRegion = "circle-shadow";
+ public Color color = Color.white.cpy();
+ public TextureRegion region;
+ public float yspeed = -2f, xspeed = 0.25f, padding = 16f, sizeMin = 2.4f, sizeMax = 12f, density = 1200f, minAlpha = 1f, maxAlpha = 1f, force = 0, noiseScale = 2000f, baseSpeed = 6.1f;
+ public float sinSclMin = 30f, sinSclMax = 80f, sinMagMin = 1f, sinMagMax = 7f;
+
+ public Color noiseColor = color;
+ public boolean drawNoise = false, drawParticles = true, useWindVector = false;
+ public int noiseLayers = 1;
+ public float noiseLayerSpeedM = 1.1f, noiseLayerAlphaM = 0.8f, noiseLayerSclM = 0.99f, noiseLayerColorM = 1f;
+ public String noisePath = "noiseAlpha";
+ public @Nullable Texture noise;
+
+ public ParticleWeather(String name){
+ super(name);
+ }
+
+ @Override
+ public void load(){
+ super.load();
+
+ region = Core.atlas.find(particleRegion);
+
+ //load noise texture
+ //TODO mod support
+ if(drawNoise){
+ Core.assets.load("sprites/" + noisePath + ".png", Texture.class);
+ }
+ }
+
+ @Override
+ public void update(WeatherState state){
+ float speed = force * state.intensity;
+ if(speed > 0.001f){
+ float windx = state.windVector.x * speed, windy = state.windVector.y * speed;
+
+ for(Unit unit : Groups.unit){
+ unit.impulse(windx, windy);
+ }
+ }
+ }
+
+ @Override
+ public void drawOver(WeatherState state){
+
+ float windx, windy;
+ if(useWindVector){
+ float speed = baseSpeed * state.intensity;
+ windx = state.windVector.x * speed;
+ windy = state.windVector.y * speed;
+ }else{
+ windx = this.xspeed;
+ windy = this.yspeed;
+ }
+
+ if(drawNoise){
+ if(noise == null){
+ noise = Core.assets.get("sprites/" + noisePath + ".png", Texture.class);
+ noise.setWrap(TextureWrap.repeat);
+ noise.setFilter(TextureFilter.linear);
+ }
+
+ float sspeed = 1f, sscl = 1f, salpha = 1f, offset = 0f;
+ Color col = Tmp.c1.set(noiseColor);
+ for(int i = 0; i < noiseLayers; i++){
+ drawNoise(noise, noiseColor, noiseScale * sscl, state.opacity * salpha * opacityMultiplier, baseSpeed * sspeed, state.intensity, windx, windy, offset);
+ sspeed *= noiseLayerSpeedM;
+ salpha *= noiseLayerAlphaM;
+ sscl *= noiseLayerSclM;
+ offset += 0.29f;
+ col.mul(noiseLayerColorM);
+ }
+ }
+
+ if(drawParticles){
+ drawParticles(region, color, sizeMin, sizeMax, density, state.intensity, state.opacity, windx, windy, minAlpha, maxAlpha, sinSclMin, sinSclMax, sinMagMin, sinMagMax);
+ }
+ }
+}
diff --git a/core/src/mindustry/type/weather/RainWeather.java b/core/src/mindustry/type/weather/RainWeather.java
new file mode 100644
index 0000000000..78fd096062
--- /dev/null
+++ b/core/src/mindustry/type/weather/RainWeather.java
@@ -0,0 +1,38 @@
+package mindustry.type.weather;
+
+import arc.*;
+import arc.graphics.*;
+import arc.graphics.g2d.*;
+import mindustry.content.*;
+import mindustry.gen.*;
+import mindustry.type.*;
+
+public class RainWeather extends Weather{
+ public float yspeed = 5f, xspeed = 1.5f, padding = 16f, density = 1200f, stroke = 0.75f, sizeMin = 8f, sizeMax = 40f, splashTimeScale = 22f;
+ public Liquid liquid = Liquids.water;
+ public TextureRegion[] splashes = new TextureRegion[12];
+ public Color color = Color.valueOf("7a95eaff");
+
+ public RainWeather(String name){
+ super(name);
+ }
+
+ @Override
+ public void load(){
+ super.load();
+
+ for(int i = 0; i < splashes.length; i++){
+ splashes[i] = Core.atlas.find("splash-" + i);
+ }
+ }
+
+ @Override
+ public void drawOver(WeatherState state){
+ drawRain(sizeMin, sizeMax, xspeed, yspeed, density, state.intensity, stroke, color);
+ }
+
+ @Override
+ public void drawUnder(WeatherState state){
+ drawSplashes(splashes, sizeMax, density, state.intensity, state.opacity, splashTimeScale, stroke, color, liquid);
+ }
+}
diff --git a/core/src/mindustry/ui/ContentDisplay.java b/core/src/mindustry/ui/ContentDisplay.java
deleted file mode 100644
index 6eefedcd53..0000000000
--- a/core/src/mindustry/ui/ContentDisplay.java
+++ /dev/null
@@ -1,165 +0,0 @@
-package mindustry.ui;
-
-import arc.*;
-import arc.graphics.*;
-import arc.scene.ui.layout.*;
-import arc.struct.*;
-import arc.util.*;
-import mindustry.gen.*;
-import mindustry.graphics.*;
-import mindustry.type.*;
-import mindustry.world.*;
-import mindustry.world.meta.*;
-
-public class ContentDisplay{
-
- public static void displayBlock(Table table, Block block){
-
- table.table(title -> {
- int size = 8 * 6;
-
- title.image(block.icon(Cicon.xlarge)).size(size);
- title.add("[accent]" + block.localizedName).padLeft(5);
- });
-
- table.row();
-
- table.image().height(3).color(Color.lightGray).pad(8).padLeft(0).padRight(0).fillX();
-
- table.row();
-
- if(block.description != null){
- table.add(block.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX();
- table.row();
-
- table.image().height(3).color(Color.lightGray).pad(8).padLeft(0).padRight(0).fillX();
- table.row();
- }
-
- BlockStats stats = block.stats;
-
- for(StatCategory cat : stats.toMap().keys()){
- OrderedMap> map = stats.toMap().get(cat);
-
- if(map.size == 0) continue;
-
- table.add("@category." + cat.name()).color(Pal.accent).fillX();
- table.row();
-
- for(BlockStat stat : map.keys()){
- table.table(inset -> {
- inset.left();
- inset.add("[lightgray]" + stat.localized() + ":[] ").left();
- Seq arr = map.get(stat);
- for(StatValue value : arr){
- value.display(inset);
- inset.add().size(10f);
- }
-
- }).fillX().padLeft(10);
- table.row();
- }
- }
- }
-
- public static void displayItem(Table table, Item item){
-
- table.table(title -> {
- title.image(item.icon(Cicon.xlarge)).size(8 * 6);
- title.add("[accent]" + item.localizedName).padLeft(5);
- });
-
- table.row();
-
- table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX();
-
- table.row();
-
- if(item.description != null){
- table.add(item.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX();
- table.row();
-
- table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX();
- table.row();
- }
-
- table.left().defaults().fillX();
-
- table.add(Core.bundle.format("item.explosiveness", (int)(item.explosiveness * 100)));
- table.row();
- table.add(Core.bundle.format("item.flammability", (int)(item.flammability * 100)));
- table.row();
- table.add(Core.bundle.format("item.radioactivity", (int)(item.radioactivity * 100)));
- table.row();
- }
-
- public static void displayLiquid(Table table, Liquid liquid){
-
- table.table(title -> {
- title.image(liquid.icon(Cicon.xlarge)).size(8 * 6);
- title.add("[accent]" + liquid.localizedName).padLeft(5);
- });
-
- table.row();
-
- table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX();
-
- table.row();
-
- if(liquid.description != null){
- table.add(liquid.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX();
- table.row();
-
- table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX();
- table.row();
- }
-
- table.left().defaults().fillX();
-
- table.add(Core.bundle.format("item.explosiveness", (int)(liquid.explosiveness * 100)));
- table.row();
- table.add(Core.bundle.format("item.flammability", (int)(liquid.flammability * 100)));
- table.row();
- table.add(Core.bundle.format("liquid.heatcapacity", (int)(liquid.heatCapacity * 100)));
- table.row();
- table.add(Core.bundle.format("liquid.temperature", (int)(liquid.temperature * 100)));
- table.row();
- table.add(Core.bundle.format("liquid.viscosity", (int)(liquid.viscosity * 100)));
- table.row();
- }
-
- public static void displayUnit(Table table, UnitType unit){
- table.table(title -> {
- title.image(unit.icon(Cicon.xlarge)).size(8 * 6).scaling(Scaling.fit);
- title.add("[accent]" + unit.localizedName).padLeft(5);
- });
-
- table.row();
-
- table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX();
-
- table.row();
-
- if(unit.description != null){
- table.add(unit.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX();
- table.row();
-
- table.image().height(3).color(Color.lightGray).pad(15).padLeft(0).padRight(0).fillX();
- table.row();
- }
-
- table.left().defaults().fillX();
-
- Unit inst = unit.constructor.get();
-
- //TODO more stats
- table.add(Core.bundle.format("unit.health", unit.health)).row();
- table.add(Core.bundle.format("unit.speed", Strings.fixed(unit.speed, 1))).row();
- table.add(Core.bundle.format("unit.itemcapacity", unit.itemCapacity)).row();
-
- if(inst instanceof Minerc) table.add(Core.bundle.format("unit.minespeed", (int)(unit.mineSpeed * 100f))).row();
- if(inst instanceof Builderc) table.add(Core.bundle.format("unit.buildspeed", (int)(unit.buildSpeed * 100f))).row();
-
- table.row();
- }
-}
diff --git a/core/src/mindustry/ui/IntFormat.java b/core/src/mindustry/ui/IntFormat.java
index 2ca0e9de1f..fab10cd67f 100644
--- a/core/src/mindustry/ui/IntFormat.java
+++ b/core/src/mindustry/ui/IntFormat.java
@@ -10,7 +10,7 @@ import arc.func.*;
public class IntFormat{
private final StringBuilder builder = new StringBuilder();
private final String text;
- private int lastValue = Integer.MIN_VALUE;
+ private int lastValue = Integer.MIN_VALUE, lastValue2 = Integer.MIN_VALUE;
private Func converter = String::valueOf;
public IntFormat(String text){
@@ -30,4 +30,14 @@ public class IntFormat{
lastValue = value;
return builder;
}
+
+ public CharSequence get(int value1, int value2){
+ if(lastValue != value1 || lastValue2 != value2){
+ builder.setLength(0);
+ builder.append(Core.bundle.format(text, value1, value2));
+ }
+ lastValue = value1;
+ lastValue2 = value2;
+ return builder;
+ }
}
diff --git a/core/src/mindustry/ui/Styles.java b/core/src/mindustry/ui/Styles.java
index 13e97202e5..802a18004b 100644
--- a/core/src/mindustry/ui/Styles.java
+++ b/core/src/mindustry/ui/Styles.java
@@ -23,6 +23,7 @@ import static mindustry.gen.Tex.*;
@StyleDefaults
public class Styles{
+ //TODO all these names are inconsistent and not descriptive
public static Drawable black, black9, black8, black6, black3, black5, none, flatDown, flatOver;
public static ButtonStyle defaultb, waveb;
public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, infot, clearPartialt, clearTogglet, clearToggleMenut, togglet, transt, fullTogglet, logict;
diff --git a/core/src/mindustry/ui/dialogs/ContentInfoDialog.java b/core/src/mindustry/ui/dialogs/ContentInfoDialog.java
index 0ee1960f9f..89cf556cb1 100644
--- a/core/src/mindustry/ui/dialogs/ContentInfoDialog.java
+++ b/core/src/mindustry/ui/dialogs/ContentInfoDialog.java
@@ -1,8 +1,14 @@
package mindustry.ui.dialogs;
+import arc.graphics.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
+import arc.struct.*;
+import arc.util.*;
import mindustry.ctype.*;
+import mindustry.graphics.*;
+import mindustry.ui.*;
+import mindustry.world.meta.*;
public class ContentInfoDialog extends BaseDialog{
@@ -18,11 +24,62 @@ public class ContentInfoDialog extends BaseDialog{
Table table = new Table();
table.margin(10);
- content.displayInfo(table);
+ //initialize stats if they haven't been yet
+ content.checkStats();
+
+ table.table(title1 -> {
+ int size = 8 * 6;
+
+ title1.image(content.icon(Cicon.xlarge)).size(size).scaling(Scaling.fit);
+ title1.add("[accent]" + content.localizedName).padLeft(5);
+ });
+
+ table.row();
+
+ table.image().height(3).color(Color.lightGray).pad(8).padLeft(0).padRight(0).fillX();
+
+ table.row();
+
+ if(content.description != null){
+ table.add(content.displayDescription()).padLeft(5).padRight(5).width(400f).wrap().fillX();
+ table.row();
+
+ table.image().height(3).color(Color.lightGray).pad(8).padLeft(0).padRight(0).fillX();
+ table.row();
+ }
+
+ Stats stats = content.stats;
+
+ for(StatCat cat : stats.toMap().keys()){
+ OrderedMap> map = stats.toMap().get(cat);
+
+ if(map.size == 0) continue;
+
+ //TODO check
+ if(stats.useCategories){
+ table.add("@category." + cat.name()).color(Pal.accent).fillX();
+ table.row();
+ }
+
+ for(Stat stat : map.keys()){
+ table.table(inset -> {
+ inset.left();
+ inset.add("[lightgray]" + stat.localized() + ":[] ").left();
+ Seq arr = map.get(stat);
+ for(StatValue value : arr){
+ value.display(inset);
+ inset.add().size(10f);
+ }
+
+ }).fillX().padLeft(10);
+ table.row();
+ }
+ }
ScrollPane pane = new ScrollPane(table);
cont.add(pane);
show();
}
+
}
diff --git a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java
index 42fac7be72..4d6a4483f9 100644
--- a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java
+++ b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java
@@ -134,7 +134,7 @@ public class CustomRulesDialog extends BaseDialog{
check("@rules.waves", b -> rules.waves = b, () -> rules.waves);
check("@rules.wavetimer", b -> rules.waveTimer = b, () -> rules.waveTimer);
check("@rules.waitForWaveToEnd", b -> rules.waitEnemies = b, () -> rules.waitEnemies);
- number("@rules.wavespacing", false, f -> rules.waveSpacing = f * 60f, () -> rules.waveSpacing / 60f, () -> true);
+ number("@rules.wavespacing", false, f -> rules.waveSpacing = f * 60f, () -> rules.waveSpacing / 60f, () -> true, 1, Float.MAX_VALUE);
number("@rules.dropzoneradius", false, f -> rules.dropZoneRadius = f * tilesize, () -> rules.dropZoneRadius / tilesize, () -> true);
title("@rules.title.resourcesbuilding");
@@ -142,7 +142,7 @@ public class CustomRulesDialog extends BaseDialog{
check("@rules.reactorexplosions", b -> rules.reactorExplosions = b, () -> rules.reactorExplosions);
check("@rules.schematic", b-> rules.schematicsAllowed = b, () -> rules.schematicsAllowed);
number("@rules.buildcostmultiplier", false, f -> rules.buildCostMultiplier = f, () -> rules.buildCostMultiplier, () -> !rules.infiniteResources);
- number("@rules.buildspeedmultiplier", f -> rules.buildSpeedMultiplier = f, () -> rules.buildSpeedMultiplier);
+ number("@rules.buildspeedmultiplier", f -> rules.buildSpeedMultiplier = f, () -> rules.buildSpeedMultiplier, 0.00001f, 10000f);
number("@rules.deconstructrefundmultiplier", false, f -> rules.deconstructRefundMultiplier = f, () -> rules.deconstructRefundMultiplier, () -> !rules.infiniteResources);
number("@rules.blockhealthmultiplier", f -> rules.blockHealthMultiplier = f, () -> rules.blockHealthMultiplier);
number("@rules.blockdamagemultiplier", f -> rules.blockDamageMultiplier = f, () -> rules.blockDamageMultiplier);
@@ -162,7 +162,7 @@ public class CustomRulesDialog extends BaseDialog{
check("@rules.unitammo", b -> rules.unitAmmo = b, () -> rules.unitAmmo);
number("@rules.unithealthmultiplier", f -> rules.unitHealthMultiplier = f, () -> rules.unitHealthMultiplier);
number("@rules.unitdamagemultiplier", f -> rules.unitDamageMultiplier = f, () -> rules.unitDamageMultiplier);
- number("@rules.unitbuildspeedmultiplier", f -> rules.unitBuildSpeedMultiplier = f, () -> rules.unitBuildSpeedMultiplier);
+ number("@rules.unitbuildspeedmultiplier", f -> rules.unitBuildSpeedMultiplier = f, () -> rules.unitBuildSpeedMultiplier, 0.00001f, 100f);
title("@rules.title.enemy");
check("@rules.attack", b -> rules.attackMode = b, () -> rules.attackMode);
@@ -189,10 +189,22 @@ public class CustomRulesDialog extends BaseDialog{
}
void number(String text, Floatc cons, Floatp prov){
- number(text, false, cons, prov, () -> true);
+ number(text, false, cons, prov, () -> true, 0, Float.MAX_VALUE);
+ }
+
+ void number(String text, Floatc cons, Floatp prov, float min, float max){
+ number(text, false, cons, prov, () -> true, min, max);
}
void number(String text, boolean integer, Floatc cons, Floatp prov, Boolp condition){
+ number(text, integer, cons, prov, condition, 0, Float.MAX_VALUE);
+ }
+
+ void number(String text, Floatc cons, Floatp prov, Boolp condition){
+ number(text, false, cons, prov, condition, 0, Float.MAX_VALUE);
+ }
+
+ void number(String text, boolean integer, Floatc cons, Floatp prov, Boolp condition, float min, float max){
main.table(t -> {
t.left();
t.add(text).left().padRight(5)
@@ -200,7 +212,7 @@ public class CustomRulesDialog extends BaseDialog{
t.field((integer ? (int)prov.get() : prov.get()) + "", s -> cons.get(Strings.parseFloat(s)))
.padRight(100f)
.update(a -> a.setDisabled(!condition.get()))
- .valid(Strings::canParsePositiveFloat).width(120f).left().addInputDialog();
+ .valid(f -> Strings.canParsePositiveFloat(f) && Strings.parseFloat(f) >= min && Strings.parseFloat(f) <= max).width(120f).left().addInputDialog();
}).padTop(0);
main.row();
}
diff --git a/core/src/mindustry/ui/dialogs/FileChooser.java b/core/src/mindustry/ui/dialogs/FileChooser.java
index 2c8f2954b9..555df63e33 100644
--- a/core/src/mindustry/ui/dialogs/FileChooser.java
+++ b/core/src/mindustry/ui/dialogs/FileChooser.java
@@ -4,6 +4,7 @@ import arc.*;
import arc.files.*;
import arc.func.*;
import arc.graphics.g2d.*;
+import arc.input.*;
import arc.scene.event.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
@@ -45,6 +46,16 @@ public class FileChooser extends BaseDialog{
cont.clear();
setupWidgets();
});
+
+ keyDown(KeyCode.enter, () -> {
+ ok.fireClick();
+ });
+
+ keyDown(key -> {
+ if(key == KeyCode.escape || key == KeyCode.back){
+ Core.app.post(this::hide);
+ }
+ });
}
private void setupWidgets(){
diff --git a/core/src/mindustry/ui/dialogs/GameOverDialog.java b/core/src/mindustry/ui/dialogs/GameOverDialog.java
index b9967e6564..ceea590826 100644
--- a/core/src/mindustry/ui/dialogs/GameOverDialog.java
+++ b/core/src/mindustry/ui/dialogs/GameOverDialog.java
@@ -2,7 +2,7 @@ package mindustry.ui.dialogs;
import arc.*;
import mindustry.game.EventType.*;
-import mindustry.game.Stats.*;
+import mindustry.game.GameStats.*;
import mindustry.game.*;
import mindustry.type.*;
import mindustry.ui.*;
diff --git a/core/src/mindustry/ui/dialogs/HostDialog.java b/core/src/mindustry/ui/dialogs/HostDialog.java
index 25300fc0b1..1282d47b7d 100644
--- a/core/src/mindustry/ui/dialogs/HostDialog.java
+++ b/core/src/mindustry/ui/dialogs/HostDialog.java
@@ -76,13 +76,15 @@ public class HostDialog extends BaseDialog{
platform.updateLobby();
});
}));
+
+ if(Version.modifier.contains("beta") || Version.modifier.contains("alpha")){
+ Core.settings.put("publichost", false);
+ platform.updateLobby();
+ Core.settings.getBoolOnce("betapublic", () -> ui.showInfo("@public.beta"));
+ }
}
- if(Version.modifier.contains("beta")){
- Core.settings.put("publichost", false);
- platform.updateLobby();
- Core.settings.getBoolOnce("betapublic", () -> ui.showInfo("@public.beta"));
- }
+
}catch(IOException e){
ui.showException("@server.error", e);
}
diff --git a/core/src/mindustry/ui/dialogs/JoinDialog.java b/core/src/mindustry/ui/dialogs/JoinDialog.java
index 1c80418708..aa4d9c22c8 100644
--- a/core/src/mindustry/ui/dialogs/JoinDialog.java
+++ b/core/src/mindustry/ui/dialogs/JoinDialog.java
@@ -367,8 +367,10 @@ public class JoinDialog extends BaseDialog{
local.row();
- TextButton button = local.button("", Styles.cleart, () -> safeConnect(host.address, host.port, host.version))
- .width(w).pad(5f).get();
+ TextButton button = local.button("", Styles.cleart, () -> {
+ Events.fire(new ClientPreConnectEvent(host));
+ safeConnect(host.address, host.port, host.version);
+ }).width(w).pad(5f).get();
button.clearChildren();
buildServer(host, button);
}
@@ -379,8 +381,10 @@ public class JoinDialog extends BaseDialog{
global.row();
- TextButton button = global.button("", Styles.cleart, () -> safeConnect(host.address, host.port, host.version))
- .width(w).pad(5f).get();
+ TextButton button = global.button("", Styles.cleart, () -> {
+ Events.fire(new ClientPreConnectEvent(host));
+ safeConnect(host.address, host.port, host.version);
+ }).width(w).pad(5f).get();
button.clearChildren();
buildServer(host, button);
}
diff --git a/core/src/mindustry/ui/dialogs/LaunchLoadoutDialog.java b/core/src/mindustry/ui/dialogs/LaunchLoadoutDialog.java
index acb240d7c9..6cb50dbf36 100644
--- a/core/src/mindustry/ui/dialogs/LaunchLoadoutDialog.java
+++ b/core/src/mindustry/ui/dialogs/LaunchLoadoutDialog.java
@@ -2,6 +2,7 @@ package mindustry.ui.dialogs;
import arc.*;
import arc.func.*;
+import arc.input.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
@@ -29,18 +30,27 @@ public class LaunchLoadoutDialog extends BaseDialog{
super("@configure");
}
- public void show(CoreBlock core, Building build, Runnable confirm){
+ public void show(CoreBlock core, Sector sector, Runnable confirm){
cont.clear();
buttons.clear();
- addCloseButton();
+ buttons.defaults().size(160f, 64f);
+ buttons.button("@back", Icon.left, this::hide);
+
+ keyDown(key -> {
+ if(key == KeyCode.escape || key == KeyCode.back){
+ Core.app.post(this::hide);
+ }
+ });
+
+ ItemSeq sitems = sector.getItems();
//updates sum requirements
Runnable update = () -> {
total.clear();
selected.requirements().each(total::add);
universe.getLaunchResources().each(total::add);
- valid = build.items.has(total);
+ valid = sitems.has(total);
};
Cons
rebuild = table -> {
@@ -57,8 +67,8 @@ public class LaunchLoadoutDialog extends BaseDialog{
String amountStr = "[lightgray]" + (al + " + [accent]" + as + "[lightgray]");
table.add(
- build.items.has(s.item, s.amount) ? amountStr :
- "[scarlet]" + (Math.min(build.items.get(s.item), s.amount) + "[lightgray]/" + amountStr)).padLeft(2).left().padRight(4);
+ sitems.has(s.item, s.amount) ? amountStr :
+ "[scarlet]" + (Math.min(sitems.get(s.item), s.amount) + "[lightgray]/" + amountStr)).padLeft(2).left().padRight(4);
if(++i % 4 == 0){
table.row();
@@ -79,7 +89,7 @@ public class LaunchLoadoutDialog extends BaseDialog{
update.run();
rebuildItems.run();
});
- });
+ }).width(204);
buttons.button("@launch.text", Icon.ok, () -> {
universe.updateLoadout(core, selected);
@@ -100,7 +110,7 @@ public class LaunchLoadoutDialog extends BaseDialog{
selected = s;
update.run();
rebuildItems.run();
- }).group(group).pad(4).disabled(!build.items.has(s.requirements())).checked(s == selected).size(200f);
+ }).group(group).pad(4).disabled(!sitems.has(s.requirements())).checked(s == selected).size(200f);
if(++i % cols == 0){
t.row();
@@ -110,6 +120,8 @@ public class LaunchLoadoutDialog extends BaseDialog{
cont.row();
cont.add(items);
+ cont.row();
+ cont.add("@sector.missingresources").visible(() -> !valid);
update.run();
rebuildItems.run();
diff --git a/core/src/mindustry/ui/dialogs/PausedDialog.java b/core/src/mindustry/ui/dialogs/PausedDialog.java
index f09e2fe185..fce68f3044 100644
--- a/core/src/mindustry/ui/dialogs/PausedDialog.java
+++ b/core/src/mindustry/ui/dialogs/PausedDialog.java
@@ -34,14 +34,6 @@ public class PausedDialog extends BaseDialog{
});
if(!mobile){
- //TODO localize
- //TODO capturing is disabled, remove?
- //cont.label(() -> state.getSector() == null ? "" :
- //("[lightgray]Next turn in [accent]" + state.getSector().displayTimeRemaining() +
- // (state.rules.winWave > 0 && !state.getSector().isCaptured() ? "\n[lightgray]Reach wave[accent] " + state.rules.winWave + "[] to capture" : "")))
- // .visible(() -> state.getSector() != null).colspan(2);
- cont.row();
-
float dw = 220f;
cont.defaults().width(dw).height(55).pad(5f);
@@ -86,10 +78,7 @@ public class PausedDialog extends BaseDialog{
cont.buttonRow("@load", Icon.download, load::show).disabled(b -> net.active());
}else if(state.isCampaign()){
- cont.buttonRow("@launchcore", Icon.up, () -> {
- hide();
- ui.planet.showLaunch(state.getSector(), player.team().core());
- }).disabled(b -> player.team().core() == null);
+ cont.buttonRow("@research", Icon.tree, ui.research::show);
cont.row();
diff --git a/core/src/mindustry/ui/dialogs/PlanetDialog.java b/core/src/mindustry/ui/dialogs/PlanetDialog.java
index 4d24bbe8b8..00c68b4a0e 100644
--- a/core/src/mindustry/ui/dialogs/PlanetDialog.java
+++ b/core/src/mindustry/ui/dialogs/PlanetDialog.java
@@ -13,6 +13,7 @@ import arc.scene.event.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.util.*;
+import mindustry.content.*;
import mindustry.core.*;
import mindustry.ctype.*;
import mindustry.game.*;
@@ -22,7 +23,6 @@ import mindustry.graphics.g3d.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.blocks.storage.*;
-import mindustry.world.blocks.storage.CoreBlock.*;
import static mindustry.Vars.*;
import static mindustry.graphics.g3d.PlanetRenderer.*;
@@ -40,7 +40,6 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
public int launchRange;
public float zoom = 1f, selectAlpha = 1f;
public @Nullable Sector selected, hovered, launchSector;
- public CoreBuild launcher;
public Mode mode = look;
public boolean launching;
public Cons listener = s -> {};
@@ -91,9 +90,16 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
mode = look;
selected = hovered = launchSector = null;
launching = false;
+
+ zoom = 1f;
+ planets.zoom = 1f;
+ selectAlpha = 0f;
+ launchSector = state.getSector();
+
if(planets.planet.getLastSector() != null){
lookAt(planets.planet.getLastSector());
}
+
return super.show();
}
@@ -106,7 +112,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
//update view to sector
lookAt(sector);
zoom = 1f;
- planets.zoom = 2f;
+ planets.zoom = 1f;
selectAlpha = 0f;
launchSector = sector;
@@ -115,37 +121,33 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
super.show();
}
- public void showLaunch(Sector sector, CoreBuild launcher){
- if(launcher == null) return;
-
- this.launcher = launcher;
- selected = null;
- hovered = null;
- launching = false;
-
- //update view to sector
- lookAt(sector);
- zoom = 1f;
- planets.zoom = 2f;
- selectAlpha = 0f;
- launchRange = ((CoreBlock)launcher.block).launchRange;
- launchSector = sector;
-
- mode = launch;
-
- super.show();
- }
-
- private void lookAt(Sector sector){
+ void lookAt(Sector sector){
planets.camPos.set(Tmp.v33.set(sector.tile.v).rotate(Vec3.Y, -sector.planet.getRotation()));
}
boolean canSelect(Sector sector){
if(mode == select) return sector.hasBase();
- return mode == launch &&
- (sector.tile.v.within(launchSector.tile.v, (launchRange + 0.5f) * planets.planet.sectorApproxRadius*2) //within range
- || (sector.preset != null && sector.preset.unlocked())); //is an unlocked preset
+ return sector.hasBase() || sector.near().contains(Sector::hasBase) //near an occupied sector
+ || (sector.preset != null && sector.preset.unlocked()); //is an unlocked preset
+ }
+
+ Sector findLauncher(Sector to){
+ //directly nearby.
+ if(to.near().contains(launchSector)) return launchSector;
+
+ Sector launchFrom = launchSector;
+ if(launchFrom == null){
+ //TODO pick one with the most resources
+ launchFrom = to.near().find(Sector::hasBase);
+ if(launchFrom == null && to.preset != null){
+ if(launchSector != null) return launchSector;
+ launchFrom = planets.planet.sectors.min(s -> !s.hasBase() ? Float.MAX_VALUE : s.tile.v.dst2(to.tile.v));
+ if(!launchFrom.hasBase()) launchFrom = null;
+ }
+ }
+
+ return launchFrom;
}
@Override
@@ -157,9 +159,6 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
if(selectAlpha > 0.01f){
if(canSelect(sec) || sec.unlocked()){
- if(sec.baseCoverage > 0){
- planets.fill(sec, Tmp.c1.set(Team.crux.color).a(0.5f * sec.baseCoverage * selectAlpha), -0.002f);
- }
Color color =
sec.hasBase() ? Team.sharded.color :
@@ -177,8 +176,10 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
}
}
- if(launchSector != null){
- planets.fill(launchSector, hoverColor, -0.001f);
+ Sector current = state.getSector() != null && state.getSector().isBeingPlayed() ? state.getSector() : null;
+
+ if(current != null){
+ planets.fill(current, hoverColor, -0.001f);
}
//draw hover border
@@ -195,9 +196,10 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
planets.batch.flush(Gl.triangles);
- if(mode == launch || mode == select){
- if(hovered != launchSector && hovered != null && canSelect(hovered)){
- planets.drawArc(planet, launchSector.tile.v, hovered.tile.v);
+ if(hovered != null && !hovered.hasBase()){
+ Sector launchFrom = findLauncher(hovered);
+ if(launchFrom != null && hovered != launchFrom && canSelect(hovered)){
+ planets.drawArc(planet, launchFrom.tile.v, hovered.tile.v);
}
}
@@ -217,9 +219,9 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
public void renderProjections(){
if(hovered != null){
planets.drawPlane(hovered, () -> {
- Draw.color(Color.white, Pal.accent, Mathf.absin(5f, 1f));
+ Draw.color(hovered.isAttacked() ? Pal.remove : Color.white, Pal.accent, Mathf.absin(5f, 1f));
- TextureRegion icon = hovered.locked() && !canSelect(hovered) ? Icon.lock.getRegion() : null;
+ TextureRegion icon = hovered.locked() && !canSelect(hovered) ? Icon.lock.getRegion() : hovered.isAttacked() ? Icon.warning.getRegion() : null;
if(icon != null){
Draw.rect(icon, 0, 0);
@@ -244,7 +246,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
addListener(new ElementGestureListener(){
@Override
public void tap(InputEvent event, float x, float y, int count, KeyCode button){
- if(hovered != null && ((mode == launch ? canSelect(hovered) && hovered != launchSector : hovered.unlocked()) || debugSelect)){
+ if(hovered != null && ((mode == look ? canSelect(hovered) && hovered != launchSector : hovered.unlocked()) || debugSelect)){
selected = hovered;
}
@@ -263,9 +265,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
},
new Table(t -> {
t.touchable = Touchable.disabled;
- //TODO localize
t.top();
- t.label(() -> mode == select ? "@sectors.select" : mode == launch ? "Select Launch Sector" : "").style(Styles.outlineLabel).color(Pal.accent);
+ t.label(() -> mode == select ? "@sectors.select" : "").style(Styles.outlineLabel).color(Pal.accent);
}),
new Table(t -> {
t.right();
@@ -322,7 +323,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
stable.toFront();
//smooth camera toward the sector
- if(mode == launch && launching){
+ if(mode == look && launching){
float len = planets.camPos.len();
planets.camPos.slerp(Tmp.v31.set(selected.tile.v).rotate(Vec3.Y,-selected.planet.getRotation()).setLength(len), 0.1f);
}
@@ -352,69 +353,76 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
stable.clear();
stable.background(Styles.black6);
- stable.add("[accent]" + (sector.preset == null ? sector.id : sector.preset.localizedName)).row();
+ stable.table(title -> {
+ title.add("[accent]" + sector.name());
+ if(sector.preset == null){
+ title.button(Icon.pencilSmall, Styles.clearPartiali, () -> {
+ ui.showTextInput("@sectors.rename", "@name", 20, sector.name(), v -> {
+ sector.setName(v);
+ updateSelected();
+ });
+ }).size(40f).padLeft(4);
+ }
+ }).row();
+
stable.image().color(Pal.accent).fillX().height(3f).pad(3f).row();
stable.add(sector.save != null ? sector.save.getPlayTime() : "@sectors.unexplored").row();
- if(sector.hasWaves() || sector.hasEnemyBase()){
+
+ if(sector.isAttacked() || !sector.hasBase()){
stable.add("[accent]Difficulty: " + (int)(sector.baseCoverage * 10)).row();
}
- //TODO sector damage is disabled, remove when finalized
- /*
- if(sector.hasBase() && sector.hasWaves()){
+ if(sector.isAttacked()){
//TODO localize when finalized
//these mechanics are likely to change and as such are not added to the bundle
stable.add("[scarlet]Under attack!");
stable.row();
- stable.add("[accent]" + Mathf.ceil(sectorDestructionTurns - (sector.getSecondsPassed() * 60) / turnDuration) + " turn(s)\nuntil destruction");
+ stable.add("[accent]" + (int)(sector.info.damage * 100) + "% damaged");
stable.row();
- }*/
+ }
- if(sector.save != null){
+ if(sector.save != null && sector.info.resources.any()){
stable.add("@sectors.resources").row();
stable.table(t -> {
-
- if(sector.save != null && sector.save.meta.secinfo != null && sector.save.meta.secinfo.resources.any()){
- t.left();
- int idx = 0;
- int max = 5;
- for(UnlockableContent c : sector.save.meta.secinfo.resources){
- t.image(c.icon(Cicon.small)).padRight(3);
- if(++idx % max == 0) t.row();
- }
- }else{
- t.add("@unknown").color(Color.lightGray);
+ t.left();
+ int idx = 0;
+ int max = 5;
+ for(UnlockableContent c : sector.info.resources){
+ t.image(c.icon(Cicon.small)).padRight(3);
+ if(++idx % max == 0) t.row();
}
-
-
}).fillX().row();
}
//production
- if(sector.hasBase() && sector.save.meta.hasProduction){
- stable.add("@sectors.production").row();
- stable.table(t -> {
- t.left();
+ if(sector.hasBase()){
+ Table t = new Table().left();
- sector.save.meta.secinfo.production.each((item, stat) -> {
- int total = (int)(stat.mean * 60);
- if(total > 1){
- t.image(item.icon(Cicon.small)).padRight(3);
- t.add(UI.formatAmount(total) + " " + Core.bundle.get("unit.perminute")).color(Color.lightGray);
- t.row();
- }
- });
- }).row();
+ float scl = sector.getProductionScale();
+
+ sector.info.production.each((item, stat) -> {
+ int total = (int)(stat.mean * 60 * scl);
+ if(total > 1){
+ t.image(item.icon(Cicon.small)).padRight(3);
+ t.add(UI.formatAmount(total) + " " + Core.bundle.get("unit.perminute")).color(Color.lightGray);
+ t.row();
+ }
+ });
+
+ if(t.getChildren().any()){
+ stable.add("@sectors.production").row();
+ stable.add(t).row();
+ }
}
//stored resources
- if(sector.hasBase() && sector.save.meta.secinfo.coreItems.total > 0){
+ if(sector.hasBase() && sector.info.items.total > 0){
stable.add("@sectors.stored").row();
stable.table(t -> {
t.left();
t.table(res -> {
- ItemSeq items = sector.calculateItems();
+ ItemSeq items = sector.items();
int i = 0;
for(ItemStack stack : items){
@@ -446,17 +454,26 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
}
}
- if(mode == launch && !sector.hasBase()){
- Sector current = state.rules.sector;
+ if(mode == look && !sector.hasBase()){
shouldHide = false;
- loadouts.show((CoreBlock)launcher.block, launcher, () -> {
- control.handleLaunch(launcher);
- launching = true;
- zoom = 0.5f;
+ Sector from = findLauncher(sector);
+ if(from == null){
+ //free launch.
+ control.playSector(sector);
+ }else{
+ CoreBlock block = from.info.bestCoreType instanceof CoreBlock b ? b : (CoreBlock)Blocks.coreShard;
- ui.hudfrag.showLaunchDirect();
- Time.runTask(launchDuration, () -> control.playSector(current, sector));
- });
+ loadouts.show(block, from, () -> {
+ from.removeItems(universe.getLastLoadout().requirements());
+ from.removeItems(universe.getLaunchResources());
+
+ launching = true;
+ zoom = 0.5f;
+
+ ui.hudfrag.showLaunchDirect();
+ Time.runTask(launchDuration, () -> control.playSector(from, sector));
+ });
+ }
}else if(mode == select){
listener.get(sector);
}else{
@@ -484,7 +501,6 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
selected = null;
}
}
-
}
});
@@ -494,8 +510,6 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
public enum Mode{
/** Look around for existing sectors. Can only deploy. */
look,
- /** Launch to a new location. */
- launch,
/** Select a sector for some purpose. */
select
}
diff --git a/core/src/mindustry/ui/dialogs/ResearchDialog.java b/core/src/mindustry/ui/dialogs/ResearchDialog.java
index 9c5e6fd3ed..b79aacbce5 100644
--- a/core/src/mindustry/ui/dialogs/ResearchDialog.java
+++ b/core/src/mindustry/ui/dialogs/ResearchDialog.java
@@ -60,7 +60,7 @@ public class ResearchDialog extends BaseDialog{
for(Planet planet : content.planets()){
for(Sector sector : planet.sectors){
if(sector.hasSave()){
- ItemSeq cached = sector.calculateItems();
+ ItemSeq cached = sector.items();
add(cached);
cache.put(sector, cached);
}
@@ -164,13 +164,10 @@ public class ResearchDialog extends BaseDialog{
@Override
public Dialog show(){
- Core.app.post(() -> {
- if(net.client()){
- //TODO make this not display every time
- //TODO rework this in the future
- ui.showInfo("@campaign.multiplayer");
- }
- });
+ if(net.client()){
+ ui.showInfo("@research.multiplayer");
+ return null;
+ }
return super.show();
}
diff --git a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java
index 8dd9753fda..d58b930e77 100644
--- a/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java
+++ b/core/src/mindustry/ui/dialogs/SettingsMenuDialog.java
@@ -14,8 +14,11 @@ import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
+import mindustry.content.*;
+import mindustry.content.TechTree.*;
import mindustry.core.GameState.*;
import mindustry.core.*;
+import mindustry.ctype.*;
import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.graphics.*;
@@ -116,6 +119,37 @@ public class SettingsMenuDialog extends SettingsDialog{
t.row();
+ t.button("@settings.clearresearch", Icon.trash, style, () -> {
+ ui.showConfirm("@confirm", "@settings.clearresearch.confirm", () -> {
+ for(TechNode node : TechTree.all){
+ node.reset();
+ }
+ content.each(c -> {
+ if(c instanceof UnlockableContent u){
+ u.clearUnlock();
+ }
+ });
+ });
+ }).marginLeft(4);
+
+ t.row();
+
+ t.button("@settings.clearcampaignsaves", Icon.trash, style, () -> {
+ ui.showConfirm("@confirm", "@settings.clearcampaignsaves.confirm", () -> {
+ for(var planet : content.planets()){
+ for(var sec : planet.sectors){
+ sec.clearInfo();
+ if(sec.save != null){
+ sec.save.delete();
+ sec.save = null;
+ }
+ }
+ }
+ });
+ }).marginLeft(4);
+
+ t.row();
+
t.button("@data.export", Icon.upload, style, () -> {
if(ios){
Fi file = Core.files.local("mindustry-data-export.zip");
@@ -250,7 +284,6 @@ public class SettingsMenuDialog extends SettingsDialog{
if(!mobile){
game.checkPref("buildautopause", false);
}
- game.checkPref("mapcenter", true);
if(steam){
game.sliderPref("playerlimit", 16, 2, 32, i -> {
@@ -292,7 +325,7 @@ public class SettingsMenuDialog extends SettingsDialog{
}
return s + "%";
});
- graphics.sliderPref("bridgeopacity", 75, 0, 100, 5, s -> s + "%");
+ graphics.sliderPref("bridgeopacity", 100, 0, 100, 5, s -> s + "%");
if(!mobile){
graphics.checkPref("vsync", true, b -> Core.graphics.setVSync(b));
@@ -340,9 +373,6 @@ public class SettingsMenuDialog extends SettingsDialog{
graphics.checkPref("smoothcamera", true);
graphics.checkPref("position", false);
graphics.checkPref("fps", false);
- if(!mobile){
- graphics.checkPref("blockselectkeys", true);
- }
graphics.checkPref("playerindicators", true);
graphics.checkPref("indicators", true);
graphics.checkPref("animatedwater", true);
diff --git a/core/src/mindustry/ui/fragments/HudFragment.java b/core/src/mindustry/ui/fragments/HudFragment.java
index f56d507c4d..d51c83881d 100644
--- a/core/src/mindustry/ui/fragments/HudFragment.java
+++ b/core/src/mindustry/ui/fragments/HudFragment.java
@@ -54,7 +54,7 @@ public class HudFragment extends Fragment{
outer:
for(int i = state.wave - 1; i <= state.wave + max; i++){
for(SpawnGroup group : state.rules.spawns){
- if(group.effect == StatusEffects.boss && group.getUnitsSpawned(i) > 0){
+ if(group.effect == StatusEffects.boss && group.getSpawned(i) > 0){
int diff = (i + 2) - state.wave;
//increments at which to warn about incoming guardian
@@ -71,12 +71,17 @@ public class HudFragment extends Fragment{
//TODO details and stuff
Events.on(SectorCaptureEvent.class, e ->{
//TODO localize
- showToast("Sector[accent] captured[]!");
+ showToast("Sector [accent]" + (e.sector.isBeingPlayed() ? "" : e.sector.name() + " ") + "[white]captured!");
});
//TODO localize
Events.on(SectorLoseEvent.class, e -> {
- showToast(Icon.warning, "Sector " + e.sector.id + " [scarlet]lost!");
+ showToast(Icon.warning, "Sector [accent]" + e.sector.name() + "[white] lost!");
+ });
+
+ //TODO localize
+ Events.on(SectorInvasionEvent.class, e -> {
+ showToast(Icon.warning, "Sector [accent]" + e.sector.name() + "[white] under attack!");
});
Events.on(ResetEvent.class, e -> {
@@ -589,6 +594,7 @@ public class HudFragment extends Fragment{
StringBuilder ibuild = new StringBuilder();
IntFormat wavef = new IntFormat("wave");
+ IntFormat wavefc = new IntFormat("wave.cap");
IntFormat enemyf = new IntFormat("wave.enemy");
IntFormat enemiesf = new IntFormat("wave.enemies");
IntFormat waitingf = new IntFormat("wave.waiting", i -> {
@@ -706,7 +712,7 @@ public class HudFragment extends Fragment{
t.add(new SideBar(() -> player.unit().healthf(), () -> true, true)).width(bw).growY().padRight(pad);
t.image(() -> player.icon()).scaling(Scaling.bounded).grow().maxWidth(54f);
t.add(new SideBar(() -> player.dead() ? 0f : player.displayAmmo() ? player.unit().ammof() : player.unit().healthf(), () -> !player.displayAmmo(), false)).width(bw).growY().padLeft(pad).update(b -> {
- b.color.set(player.displayAmmo() ? player.dead() || player.unit() instanceof BlockUnitc ? Pal.ammo : player.unit().type().ammoType.color : Pal.health);
+ b.color.set(player.displayAmmo() ? player.dead() || player.unit() instanceof BlockUnitc ? Pal.ammo : player.unit().type.ammoType.color : Pal.health);
});
t.getChildren().get(1).toFront();
@@ -714,7 +720,11 @@ public class HudFragment extends Fragment{
table.labelWrap(() -> {
builder.setLength(0);
- builder.append(wavef.get(state.wave));
+ if(state.rules.winWave > 1 && state.rules.winWave >= state.wave && state.isCampaign()){
+ builder.append(wavefc.get(state.wave, state.rules.winWave));
+ }else{
+ builder.append(wavef.get(state.wave));
+ }
builder.append("\n");
if(state.enemies > 0){
@@ -727,7 +737,7 @@ public class HudFragment extends Fragment{
}
if(state.rules.waveTimer){
- builder.append((logic.isWaitingWave() ? Core.bundle.get("wave.waveInProgress") : ( waitingf.get((int)(state.wavetime/60)))));
+ builder.append((logic.isWaitingWave() ? Core.bundle.get("wave.waveInProgress") : (waitingf.get((int)(state.wavetime/60)))));
}else if(state.enemies == 0){
builder.append(Core.bundle.get("waiting"));
}
diff --git a/core/src/mindustry/ui/fragments/MinimapFragment.java b/core/src/mindustry/ui/fragments/MinimapFragment.java
index 43ad3163b0..0bb3632a61 100644
--- a/core/src/mindustry/ui/fragments/MinimapFragment.java
+++ b/core/src/mindustry/ui/fragments/MinimapFragment.java
@@ -111,12 +111,11 @@ public class MinimapFragment extends Fragment{
}
public void toggle(){
- if(Core.settings.getBool("mapcenter")){
- float size = baseSize * zoom * world.width();
- float ratio = (float)renderer.minimap.getTexture().height / renderer.minimap.getTexture().width;
- panx = (size/2f - player.x() / (world.width() * tilesize) * size) / zoom;
- pany = (size*ratio/2f - player.y() / (world.height() * tilesize) * size*ratio) / zoom;
- }
+ float size = baseSize * zoom * world.width();
+ float ratio = (float)renderer.minimap.getTexture().height / renderer.minimap.getTexture().width;
+ float px = player.dead() ? Core.camera.position.x : player.x, py = player.dead() ? Core.camera.position.y : player.y;
+ panx = (size/2f - px / (world.width() * tilesize) * size) / zoom;
+ pany = (size*ratio/2f - py / (world.height() * tilesize) * size*ratio) / zoom;
shown = !shown;
}
}
diff --git a/core/src/mindustry/ui/fragments/PlacementFragment.java b/core/src/mindustry/ui/fragments/PlacementFragment.java
index 7b53a24012..25c009ff63 100644
--- a/core/src/mindustry/ui/fragments/PlacementFragment.java
+++ b/core/src/mindustry/ui/fragments/PlacementFragment.java
@@ -289,7 +289,7 @@ public class PlacementFragment extends Fragment{
topTable.table(header -> {
String keyCombo = "";
- if(!mobile && Core.settings.getBool("blockselectkeys")){
+ if(!mobile){
Seq blocks = getByCategory(currentCategory);
for(int i = 0; i < blocks.size; i++){
if(blocks.get(i) == displayBlock && (i + 1) / 10 - 1 < blockSelect.length){
diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java
index 95d9a426e0..f74e9bb099 100644
--- a/core/src/mindustry/world/Block.java
+++ b/core/src/mindustry/world/Block.java
@@ -14,6 +14,7 @@ import arc.struct.*;
import arc.util.*;
import arc.util.pooling.*;
import mindustry.annotations.Annotations.*;
+import mindustry.content.*;
import mindustry.core.*;
import mindustry.ctype.*;
import mindustry.entities.*;
@@ -35,8 +36,6 @@ import java.util.*;
import static mindustry.Vars.*;
public class Block extends UnlockableContent{
- public static final int crackRegions = 8, maxCrackSize = 9;
-
public boolean hasItems;
public boolean hasLiquids;
public boolean hasPower;
@@ -52,7 +51,6 @@ public class Block extends UnlockableContent{
public float liquidCapacity = 10f;
public float liquidPressure = 1f;
- public final BlockStats stats = new BlockStats();
public final BlockBars bars = new BlockBars();
public final Consumers consumes = new Consumers();
@@ -102,6 +100,8 @@ public class Block extends UnlockableContent{
public boolean autoResetEnabled = true;
/** if true, the block stops updating when disabled */
public boolean noUpdateDisabled = false;
+ /** Whether to use this block's color in the minimap. Only used for overlays. */
+ public boolean useColor = true;
/** tile entity health */
public int health = -1;
/** base block explosiveness */
@@ -212,8 +212,6 @@ public class Block extends UnlockableContent{
public @Load("@-team") TextureRegion teamRegion;
public TextureRegion[] teamRegions;
- //TODO make this not static
- public static TextureRegion[][] cracks;
protected static final Seq tempTiles = new Seq<>();
protected static final Seq tempTileEnts = new Seq<>();
@@ -324,27 +322,30 @@ public class Block extends UnlockableContent{
return update || destructible;
}
+ @Override
public void setStats(){
- stats.add(BlockStat.size, "@x@", size, size);
- stats.add(BlockStat.health, health, StatUnit.none);
+ super.setStats();
+
+ stats.add(Stat.size, "@x@", size, size);
+ stats.add(Stat.health, health, StatUnit.none);
if(canBeBuilt()){
- stats.add(BlockStat.buildTime, buildCost / 60, StatUnit.seconds);
- stats.add(BlockStat.buildCost, new ItemListValue(false, requirements));
+ stats.add(Stat.buildTime, buildCost / 60, StatUnit.seconds);
+ stats.add(Stat.buildCost, new ItemListValue(false, requirements));
}
if(instantTransfer){
- stats.add(BlockStat.maxConsecutive, 2, StatUnit.none);
+ stats.add(Stat.maxConsecutive, 2, StatUnit.none);
}
consumes.display(stats);
- // Note: Power stats are added by the consumers.
- if(hasLiquids) stats.add(BlockStat.liquidCapacity, liquidCapacity, StatUnit.liquidUnits);
- if(hasItems && itemCapacity > 0) stats.add(BlockStat.itemCapacity, itemCapacity, StatUnit.items);
+ //Note: Power stats are added by the consumers.
+ if(hasLiquids) stats.add(Stat.liquidCapacity, liquidCapacity, StatUnit.liquidUnits);
+ if(hasItems && itemCapacity > 0) stats.add(Stat.itemCapacity, itemCapacity, StatUnit.items);
}
public void setBars(){
- bars.add("health", entity -> new Bar("blocks.health", Pal.health, entity::healthf).blink(Color.white));
+ bars.add("health", entity -> new Bar("stat.health", Pal.health, entity::healthf).blink(Color.white));
if(hasLiquids){
Func current;
@@ -352,7 +353,7 @@ public class Block extends UnlockableContent{
Liquid liquid = consumes.get(ConsumeType.liquid).liquid;
current = entity -> liquid;
}else{
- current = entity -> entity.liquids.current();
+ current = entity -> entity.liquids == null ? Liquids.water : entity.liquids.current();
}
bars.add("liquid", entity -> new Bar(() -> entity.liquids.get(current.get(entity)) <= 0.001f ? Core.bundle.get("bar.liquid") : current.get(entity).localizedName,
() -> current.get(entity).barColor(), () -> entity.liquids.get(current.get(entity)) / liquidCapacity));
@@ -621,7 +622,7 @@ public class Block extends UnlockableContent{
public ItemStack[] researchRequirements(){
ItemStack[] out = new ItemStack[requirements.length];
for(int i = 0; i < out.length; i++){
- int quantity = 40 + Mathf.round(Mathf.pow(requirements[i].amount, 1.25f) * 20 * researchCostMultiplier, 10);
+ int quantity = 40 + Mathf.round(Mathf.pow(requirements[i].amount, 1.15f) * 20 * researchCostMultiplier, 10);
out[i] = new ItemStack(requirements[i].item, UI.roundAmount(quantity));
}
@@ -637,11 +638,6 @@ public class Block extends UnlockableContent{
}
}
- @Override
- public void displayInfo(Table table){
- ContentDisplay.displayBlock(table, this);
- }
-
@Override
public ContentType getContentType(){
return ContentType.block;
@@ -672,9 +668,10 @@ public class Block extends UnlockableContent{
if(consumes.has(ConsumeType.item)) hasItems = true;
if(consumes.has(ConsumeType.liquid)) hasLiquids = true;
- setStats();
setBars();
+ stats.useCategories = true;
+
consumes.init();
if(!outputsPower && consumes.hasPower() && consumes.getPower().buffered){
@@ -687,15 +684,6 @@ public class Block extends UnlockableContent{
public void load(){
region = Core.atlas.find(name);
- if(cracks == null || (cracks[0][0].texture != null && cracks[0][0].texture.isDisposed())){
- cracks = new TextureRegion[maxCrackSize][crackRegions];
- for(int size = 1; size <= maxCrackSize; size++){
- for(int i = 0; i < crackRegions; i++){
- cracks[size - 1][i] = Core.atlas.find("cracks-" + size + "-" + i);
- }
- }
- }
-
ContentRegions.loadRegions(this);
//load specific team regions
diff --git a/core/src/mindustry/world/Build.java b/core/src/mindustry/world/Build.java
index 070ddab553..98409e6d18 100644
--- a/core/src/mindustry/world/Build.java
+++ b/core/src/mindustry/world/Build.java
@@ -45,7 +45,7 @@ public class Build{
Core.app.post(() -> Events.fire(new BlockBuildBeginEvent(tile, team, true)));
}
- /** Places a BuildBlock at this location. */
+ /** Places a ConstructBlock at this location. */
@Remote(called = Loc.server)
public static void beginPlace(Block result, Team team, int x, int y, int rotation){
if(!validPlace(result, team, x, y, rotation)){
diff --git a/core/src/mindustry/world/CachedTile.java b/core/src/mindustry/world/CachedTile.java
index 3c14ade132..5777ece759 100644
--- a/core/src/mindustry/world/CachedTile.java
+++ b/core/src/mindustry/world/CachedTile.java
@@ -21,7 +21,7 @@ public class CachedTile extends Tile{
}
@Override
- protected void changeEntity(Team team, Prov entityprov, int rotation){
+ protected void changeBuild(Team team, Prov entityprov, int rotation){
build = null;
Block block = block();
diff --git a/core/src/mindustry/world/Tile.java b/core/src/mindustry/world/Tile.java
index 7478f81db4..18696d8930 100644
--- a/core/src/mindustry/world/Tile.java
+++ b/core/src/mindustry/world/Tile.java
@@ -45,7 +45,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{
this.block = wall;
//update entity and create it if needed
- changeEntity(Team.derelict, wall::newBuilding, 0);
+ changeBuild(Team.derelict, wall::newBuilding, 0);
changed();
}
@@ -186,7 +186,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{
this.block = type;
preChanged();
- changeEntity(team, entityprov, (byte)Mathf.mod(rotation, 4));
+ changeBuild(team, entityprov, (byte)Mathf.mod(rotation, 4));
if(build != null){
build.team(team);
@@ -267,6 +267,10 @@ public class Tile implements Position, QuadTreeObject, Displayable{
Geometry.circle(x, y, world.width(), world.height(), radius, cons);
}
+ public void circle(int radius, Cons cons){
+ circle(radius, (x, y) -> cons.get(world.rawTile(x, y)));
+ }
+
public void recache(){
if(!headless && !world.isGenerating()){
renderer.blocks.floor.recacheTile(this);
@@ -332,6 +336,11 @@ public class Tile implements Position, QuadTreeObject, Displayable{
recache();
}
+ /** Sets the overlay without a recache. */
+ public void setOverlayQuiet(Block block){
+ this.overlay = (Floor)block;
+ }
+
public void clearOverlay(){
setOverlayID((short)0);
}
@@ -421,15 +430,15 @@ public class Tile implements Position, QuadTreeObject, Displayable{
getHitbox(rect);
}
- public Tile getNearby(Point2 relative){
+ public Tile nearby(Point2 relative){
return world.tile(x + relative.x, y + relative.y);
}
- public Tile getNearby(int dx, int dy){
+ public Tile nearby(int dx, int dy){
return world.tile(x + dx, y + dy);
}
- public Tile getNearby(int rotation){
+ public Tile nearby(int rotation){
if(rotation == 0) return world.tile(x + 1, y);
if(rotation == 1) return world.tile(x, y + 1);
if(rotation == 2) return world.tile(x - 1, y);
@@ -437,7 +446,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{
return null;
}
- public Building getNearbyEntity(int rotation){
+ public Building nearbyBuild(int rotation){
if(rotation == 0) return world.build(x + 1, y);
if(rotation == 1) return world.build(x, y + 1);
if(rotation == 2) return world.build(x - 1, y);
@@ -494,7 +503,7 @@ public class Tile implements Position, QuadTreeObject, Displayable{
}
}
- protected void changeEntity(Team team, Prov entityprov, int rotation){
+ protected void changeBuild(Team team, Prov entityprov, int rotation){
if(build != null){
int size = build.block.size;
build.remove();
diff --git a/core/src/mindustry/world/blocks/Autotiler.java b/core/src/mindustry/world/blocks/Autotiler.java
index 2989436fac..027ac93b31 100644
--- a/core/src/mindustry/world/blocks/Autotiler.java
+++ b/core/src/mindustry/world/blocks/Autotiler.java
@@ -133,7 +133,7 @@ public interface Autotiler{
for(int i = 0; i < 4; i++){
int realDir = Mathf.mod(rotation - i, 4);
- if(blends(tile, rotation, directional, i, world) && (tile != null && tile.getNearbyEntity(realDir) != null && !tile.getNearbyEntity(realDir).block.squareSprite)){
+ if(blends(tile, rotation, directional, i, world) && (tile != null && tile.nearbyBuild(realDir) != null && !tile.nearbyBuild(realDir).block.squareSprite)){
blendresult[4] |= (1 << i);
}
}
@@ -194,7 +194,7 @@ public interface Autotiler{
// TODO docs -- use for direction?
default boolean blends(Tile tile, int rotation, int direction){
- Building other = tile.getNearbyEntity(Mathf.mod(rotation - direction, 4));
+ Building other = tile.nearbyBuild(Mathf.mod(rotation - direction, 4));
return other != null && other.team == tile.team() && blends(tile, rotation, other.tileX(), other.tileY(), other.rotation, other.block);
}
diff --git a/core/src/mindustry/world/blocks/ConstructBlock.java b/core/src/mindustry/world/blocks/ConstructBlock.java
index c228397a32..cefdfa6887 100644
--- a/core/src/mindustry/world/blocks/ConstructBlock.java
+++ b/core/src/mindustry/world/blocks/ConstructBlock.java
@@ -42,7 +42,7 @@ public class ConstructBlock extends Block{
consBlocks[size - 1] = this;
}
- /** Returns a BuildBlock by size. */
+ /** Returns a ConstructBlock by size. */
public static ConstructBlock get(int size){
if(size > maxSize) throw new IllegalArgumentException("No. Don't place ConstructBlock of size greater than " + maxSize);
return consBlocks[size - 1];
diff --git a/core/src/mindustry/world/blocks/ControlBlock.java b/core/src/mindustry/world/blocks/ControlBlock.java
index 6724ff9205..7688cdab6a 100644
--- a/core/src/mindustry/world/blocks/ControlBlock.java
+++ b/core/src/mindustry/world/blocks/ControlBlock.java
@@ -10,4 +10,14 @@ public interface ControlBlock{
default boolean isControlled(){
return unit().isPlayer();
}
+
+ /** @return whether this block can be controlled at all. */
+ default boolean canControl(){
+ return true;
+ }
+
+ /** @return whether targets should automatically be selected (on mobile) */
+ default boolean shouldAutoTarget(){
+ return true;
+ }
}
diff --git a/core/src/mindustry/world/blocks/campaign/LaunchPad.java b/core/src/mindustry/world/blocks/campaign/LaunchPad.java
index 093fff4f70..ff069acc48 100644
--- a/core/src/mindustry/world/blocks/campaign/LaunchPad.java
+++ b/core/src/mindustry/world/blocks/campaign/LaunchPad.java
@@ -42,7 +42,7 @@ public class LaunchPad extends Block{
public void setStats(){
super.setStats();
- stats.add(BlockStat.launchTime, launchTime / 60f, StatUnit.seconds);
+ stats.add(Stat.launchTime, launchTime / 60f, StatUnit.seconds);
}
@Override
@@ -115,16 +115,16 @@ public class LaunchPad extends Block{
public void display(Table table){
super.display(table);
+ if(!state.isCampaign()) return;
+
table.row();
table.label(() -> {
Sector dest = state.secinfo.getRealDestination();
return Core.bundle.format("launch.destination",
dest == null ? Core.bundle.get("sectors.nonelaunch") :
- dest.preset == null ?
- "[accent]Sector " + dest.id :
- "[accent]" + dest.preset.localizedName);
- }).pad(4);
+ "[accent]" + dest.name());
+ }).pad(4).wrap().width(200f).left();
}
@Override
@@ -213,7 +213,7 @@ public class LaunchPad extends Block{
//actually launch the items upon removal
if(team() == state.rules.defaultTeam){
if(destsec != null && (destsec != state.rules.sector || net.client())){
- ItemSeq dest = destsec.getExtraItems();
+ ItemSeq dest = new ItemSeq();
for(ItemStack stack : stacks){
dest.add(stack);
@@ -223,7 +223,7 @@ public class LaunchPad extends Block{
Events.fire(new LaunchItemEvent(stack));
}
- destsec.setExtraItems(dest);
+ destsec.addItems(dest);
}
}
}
diff --git a/core/src/mindustry/world/blocks/defense/ForceProjector.java b/core/src/mindustry/world/blocks/defense/ForceProjector.java
index b508e90965..46fb01d7d5 100644
--- a/core/src/mindustry/world/blocks/defense/ForceProjector.java
+++ b/core/src/mindustry/world/blocks/defense/ForceProjector.java
@@ -12,6 +12,7 @@ import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.gen.*;
import mindustry.graphics.*;
+import mindustry.logic.*;
import mindustry.world.*;
import mindustry.world.consumers.*;
import mindustry.world.meta.*;
@@ -60,11 +61,11 @@ public class ForceProjector extends Block{
@Override
public void setStats(){
super.setStats();
- stats.add(BlockStat.shieldHealth, breakage, StatUnit.none);
- stats.add(BlockStat.cooldownTime, (int) (breakage / cooldownBrokenBase / 60f), StatUnit.seconds);
- stats.add(BlockStat.powerUse, basePowerDraw * 60f, StatUnit.powerSecond);
- stats.add(BlockStat.boostEffect, phaseRadiusBoost / tilesize, StatUnit.blocks);
- stats.add(BlockStat.boostEffect, phaseShieldBoost, StatUnit.shieldHealth);
+ stats.add(Stat.shieldHealth, breakage, StatUnit.none);
+ stats.add(Stat.cooldownTime, (int) (breakage / cooldownBrokenBase / 60f), StatUnit.seconds);
+ stats.add(Stat.powerUse, basePowerDraw * 60f, StatUnit.powerSecond);
+ stats.add(Stat.boostEffect, phaseRadiusBoost / tilesize, StatUnit.blocks);
+ stats.add(Stat.boostEffect, phaseShieldBoost, StatUnit.shieldHealth);
}
@Override
@@ -80,11 +81,16 @@ public class ForceProjector extends Block{
Draw.color();
}
- public class ForceBuild extends Building{
+ public class ForceBuild extends Building implements Ranged{
public boolean broken = true;
public float buildup, radscl, hit, warmup, phaseHeat;
public ForceDraw drawer;
+ @Override
+ public float range(){
+ return realRadius();
+ }
+
@Override
public void created(){
super.created();
diff --git a/core/src/mindustry/world/blocks/defense/MendProjector.java b/core/src/mindustry/world/blocks/defense/MendProjector.java
index a2efa6e8b0..cf71928f26 100644
--- a/core/src/mindustry/world/blocks/defense/MendProjector.java
+++ b/core/src/mindustry/world/blocks/defense/MendProjector.java
@@ -9,6 +9,7 @@ import mindustry.annotations.Annotations.*;
import mindustry.content.*;
import mindustry.gen.*;
import mindustry.graphics.*;
+import mindustry.logic.*;
import mindustry.world.*;
import mindustry.world.meta.*;
@@ -43,11 +44,11 @@ public class MendProjector extends Block{
public void setStats(){
super.setStats();
- stats.add(BlockStat.repairTime, (int)(100f / healPercent * reload / 60f), StatUnit.seconds);
- stats.add(BlockStat.range, range / tilesize, StatUnit.blocks);
+ stats.add(Stat.repairTime, (int)(100f / healPercent * reload / 60f), StatUnit.seconds);
+ stats.add(Stat.range, range / tilesize, StatUnit.blocks);
- stats.add(BlockStat.boostEffect, phaseRangeBoost / tilesize, StatUnit.blocks);
- stats.add(BlockStat.boostEffect, (phaseBoost + healPercent) / healPercent, StatUnit.timesSpeed);
+ stats.add(Stat.boostEffect, phaseRangeBoost / tilesize, StatUnit.blocks);
+ stats.add(Stat.boostEffect, (phaseBoost + healPercent) / healPercent, StatUnit.timesSpeed);
}
@Override
@@ -55,11 +56,16 @@ public class MendProjector extends Block{
Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.accent);
}
- public class MendBuild extends Building{
+ public class MendBuild extends Building implements Ranged{
float heat;
float charge = Mathf.random(reload);
float phaseHeat;
+ @Override
+ public float range(){
+ return range;
+ }
+
@Override
public void updateTile(){
heat = Mathf.lerpDelta(heat, consValid() || cheating() ? 1f : 0f, 0.08f);
diff --git a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java
index 56010c7c0f..7cadaede81 100644
--- a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java
+++ b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java
@@ -8,6 +8,7 @@ import arc.util.io.*;
import mindustry.annotations.Annotations.*;
import mindustry.gen.*;
import mindustry.graphics.*;
+import mindustry.logic.*;
import mindustry.world.*;
import mindustry.world.meta.*;
@@ -50,21 +51,26 @@ public class OverdriveProjector extends Block{
public void setStats(){
super.setStats();
- stats.add(BlockStat.speedIncrease, (int)(100f * speedBoost), StatUnit.percent);
- stats.add(BlockStat.range, range / tilesize, StatUnit.blocks);
- stats.add(BlockStat.productionTime, useTime / 60f, StatUnit.seconds);
+ stats.add(Stat.speedIncrease, (int)(100f * speedBoost), StatUnit.percent);
+ stats.add(Stat.range, range / tilesize, StatUnit.blocks);
+ stats.add(Stat.productionTime, useTime / 60f, StatUnit.seconds);
if(hasBoost){
- stats.add(BlockStat.boostEffect, phaseRangeBoost / tilesize, StatUnit.blocks);
- stats.add(BlockStat.boostEffect, (int)((speedBoost + speedBoostPhase) * 100f), StatUnit.percent);
+ stats.add(Stat.boostEffect, phaseRangeBoost / tilesize, StatUnit.blocks);
+ stats.add(Stat.boostEffect, (int)((speedBoost + speedBoostPhase) * 100f), StatUnit.percent);
}
}
- public class OverdriveBuild extends Building{
+ public class OverdriveBuild extends Building implements Ranged{
float heat;
float charge = Mathf.random(reload);
float phaseHeat;
+ @Override
+ public float range(){
+ return range;
+ }
+
@Override
public void drawLight(){
Drawf.light(team, x, y, 50f * efficiency(), baseColor, 0.7f * efficiency());
diff --git a/core/src/mindustry/world/blocks/defense/Wall.java b/core/src/mindustry/world/blocks/defense/Wall.java
index abb941b899..a23a2583cd 100644
--- a/core/src/mindustry/world/blocks/defense/Wall.java
+++ b/core/src/mindustry/world/blocks/defense/Wall.java
@@ -17,16 +17,17 @@ import static mindustry.Vars.*;
public class Wall extends Block{
public int variants = 0;
- public float lightningChance = -0.001f;
+ /** Lighting chance. -1 to disable */
+ public float lightningChance = -1f;
public float lightningDamage = 20f;
public int lightningLength = 17;
public Color lightningColor = Pal.surge;
public Sound lightningSound = Sounds.spark;
- public float chanceDeflect = 10f;
+ /** Bullet deflection chance. -1 to disable */
+ public float chanceDeflect = -1f;
public boolean flashHit;
public Color flashColor = Color.white;
- public boolean deflect;
public Sound deflectSound = Sounds.none;
public Wall(String name){
@@ -38,6 +39,17 @@ public class Wall extends Block{
canOverdrive = false;
}
+ @Override
+ public void setStats(){
+ super.setStats();
+
+ if(chanceDeflect > 0f) stats.add(Stat.baseDeflectChance, chanceDeflect, StatUnit.none);
+ if(lightningChance > 0f){
+ stats.add(Stat.lightningChance, lightningChance * 100f, StatUnit.percent);
+ stats.add(Stat.lightningDamage, lightningDamage, StatUnit.none);
+ }
+ }
+
@Override
public void load(){
super.load();
@@ -96,7 +108,7 @@ public class Wall extends Block{
hit = 1f;
//create lightning if necessary
- if(lightningChance > 0){
+ if(lightningChance > 0f){
if(Mathf.chance(lightningChance)){
Lightning.create(team, lightningColor, lightningDamage, x, y, bullet.rotation() + 180f, lightningLength);
lightningSound.at(tile, Mathf.random(0.9f, 1.1f));
@@ -104,7 +116,7 @@ public class Wall extends Block{
}
//deflect bullets if necessary
- if(deflect){
+ if(chanceDeflect > 0f){
//slow bullets are not deflected
if(bullet.vel().len() <= 0.1f || !bullet.type.reflectable) return true;
diff --git a/core/src/mindustry/world/blocks/defense/turrets/BaseTurret.java b/core/src/mindustry/world/blocks/defense/turrets/BaseTurret.java
new file mode 100644
index 0000000000..e10b1612e9
--- /dev/null
+++ b/core/src/mindustry/world/blocks/defense/turrets/BaseTurret.java
@@ -0,0 +1,67 @@
+package mindustry.world.blocks.defense.turrets;
+
+import mindustry.content.*;
+import mindustry.entities.*;
+import mindustry.gen.*;
+import mindustry.graphics.*;
+import mindustry.logic.*;
+import mindustry.world.*;
+import mindustry.world.consumers.*;
+import mindustry.world.meta.*;
+
+import static mindustry.Vars.*;
+
+public abstract class BaseTurret extends Block{
+ public float range = 80f;
+ public float rotateSpeed = 5;
+
+ public boolean acceptCoolant = true;
+ /** Effect displayed when coolant is used. */
+ public Effect coolEffect = Fx.fuelburn;
+ /** How much reload is lowered by for each unit of liquid of heat capacity. */
+ public float coolantMultiplier = 5f;
+
+ public BaseTurret(String name){
+ super(name);
+
+ update = true;
+ solid = true;
+ outlineIcon = true;
+ }
+
+ @Override
+ public void init(){
+ if(acceptCoolant && !consumes.has(ConsumeType.liquid)){
+ hasLiquids = true;
+ consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.2f)).update(false).boost();
+ }
+
+ super.init();
+ }
+
+ @Override
+ public void drawPlace(int x, int y, int rotation, boolean valid){
+ Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.placing);
+ }
+
+ @Override
+ public void setStats(){
+ super.setStats();
+
+ stats.add(Stat.shootRange, range / tilesize, StatUnit.blocks);
+ }
+
+ public class BaseTurretBuild extends Building implements Ranged{
+ public float rotation = 90;
+
+ @Override
+ public float range(){
+ return range;
+ }
+
+ @Override
+ public void drawSelect(){
+ Drawf.dashCircle(x, y, range, team.color);
+ }
+ }
+}
diff --git a/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java
index ea94a670b9..7550f23e79 100644
--- a/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java
+++ b/core/src/mindustry/world/blocks/defense/turrets/ItemTurret.java
@@ -19,7 +19,6 @@ import mindustry.world.meta.values.*;
import static mindustry.Vars.*;
public class ItemTurret extends Turret{
- public int maxAmmo = 30;
public ObjectMap- ammoTypes = new ObjectMap<>();
public ItemTurret(String name){
@@ -36,14 +35,18 @@ public class ItemTurret extends Turret{
public void setStats(){
super.setStats();
- stats.remove(BlockStat.itemCapacity);
- stats.add(BlockStat.ammo, new AmmoListValue<>(ammoTypes));
+ stats.remove(Stat.itemCapacity);
+ stats.add(Stat.ammo, new AmmoListValue<>(ammoTypes));
+ }
+
+ @Override
+ public void init(){
consumes.add(new ConsumeItemFilter(i -> ammoTypes.containsKey(i)){
@Override
public void build(Building tile, Table table){
MultiReqImage image = new MultiReqImage();
content.items().each(i -> filter.get(i) && i.unlockedNow(), item -> image.add(new ReqImage(new ItemImage(item.icon(Cicon.medium)),
- () -> tile != null && !((ItemTurretBuild)tile).ammo.isEmpty() && ((ItemEntry)((ItemTurretBuild)tile).ammo.peek()).item == item)));
+ () -> tile != null && !((ItemTurretBuild)tile).ammo.isEmpty() && ((ItemEntry)((ItemTurretBuild)tile).ammo.peek()).item == item)));
table.add(image).size(8 * 4);
}
@@ -55,10 +58,12 @@ public class ItemTurret extends Turret{
}
@Override
- public void display(BlockStats stats){
+ public void display(Stats stats){
//don't display
}
});
+
+ super.init();
}
public class ItemTurretBuild extends TurretBuild{
@@ -84,7 +89,7 @@ public class ItemTurret extends Turret{
public void displayBars(Table bars){
super.displayBars(bars);
- bars.add(new Bar("blocks.ammo", Pal.ammo, () -> (float)totalAmmo / maxAmmo)).growX();
+ bars.add(new Bar("stat.ammo", Pal.ammo, () -> (float)totalAmmo / maxAmmo)).growX();
bars.row();
}
diff --git a/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java b/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java
index c47a279414..3aefcdd33c 100644
--- a/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java
+++ b/core/src/mindustry/world/blocks/defense/turrets/LaserTurret.java
@@ -33,11 +33,11 @@ public class LaserTurret extends PowerTurret{
public void setStats(){
super.setStats();
- stats.remove(BlockStat.booster);
- stats.add(BlockStat.input, new BoosterListValue(reloadTime, consumes.get(ConsumeType.liquid).amount, coolantMultiplier, false, l -> consumes.liquidfilters.get(l.id)));
- stats.remove(BlockStat.damage);
+ stats.remove(Stat.booster);
+ stats.add(Stat.input, new BoosterListValue(reloadTime, consumes.get(ConsumeType.liquid).amount, coolantMultiplier, false, l -> consumes.liquidfilters.get(l.id)));
+ stats.remove(Stat.damage);
//damages every 5 ticks, at least in meltdown's case
- stats.add(BlockStat.damage, shootType.damage * 60f / 5f, StatUnit.perSecond);
+ stats.add(Stat.damage, shootType.damage * 60f / 5f, StatUnit.perSecond);
}
public class LaserTurretBuild extends PowerTurretBuild{
diff --git a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java
index e34d221d53..25725cd0a9 100644
--- a/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java
+++ b/core/src/mindustry/world/blocks/defense/turrets/LiquidTurret.java
@@ -8,6 +8,7 @@ import mindustry.entities.bullet.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
+import mindustry.world.*;
import mindustry.world.consumers.*;
import mindustry.world.meta.*;
import mindustry.world.meta.values.*;
@@ -35,7 +36,11 @@ public class LiquidTurret extends Turret{
public void setStats(){
super.setStats();
- stats.add(BlockStat.ammo, new AmmoListValue<>(ammoTypes));
+ stats.add(Stat.ammo, new AmmoListValue<>(ammoTypes));
+ }
+
+ @Override
+ public void init(){
consumes.add(new ConsumeLiquidFilter(i -> ammoTypes.containsKey(i), 1f){
@Override
public boolean valid(Building entity){
@@ -48,10 +53,12 @@ public class LiquidTurret extends Turret{
}
@Override
- public void display(BlockStats stats){
+ public void display(Stats stats){
}
});
+
+ super.init();
}
public class LiquidTurretBuild extends TurretBuild{
@@ -83,7 +90,9 @@ public class LiquidTurret extends Turret{
int tr = (int)(range / tilesize);
for(int x = -tr; x <= tr; x++){
for(int y = -tr; y <= tr; y++){
- if(Fires.has(x + tile.x, y + tile.y)){
+ Tile other = world.tileWorld(x + tile.x, y + tile.y);
+ //do not extinguish fires on other team blocks
+ if(other != null && Fires.has(x + tile.x, y + tile.y) && (other.build == null || other.team() == team)){
target = Fires.get(x + tile.x, y + tile.y);
return;
}
diff --git a/core/src/mindustry/world/blocks/defense/PointDefenseTurret.java b/core/src/mindustry/world/blocks/defense/turrets/PointDefenseTurret.java
similarity index 76%
rename from core/src/mindustry/world/blocks/defense/PointDefenseTurret.java
rename to core/src/mindustry/world/blocks/defense/turrets/PointDefenseTurret.java
index 06746bcfaa..0184f9ff7a 100644
--- a/core/src/mindustry/world/blocks/defense/PointDefenseTurret.java
+++ b/core/src/mindustry/world/blocks/defense/turrets/PointDefenseTurret.java
@@ -1,4 +1,4 @@
-package mindustry.world.blocks.defense;
+package mindustry.world.blocks.defense.turrets;
import arc.graphics.*;
import arc.graphics.g2d.*;
@@ -11,12 +11,9 @@ import mindustry.content.*;
import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.graphics.*;
-import mindustry.world.*;
import mindustry.world.meta.*;
-import static mindustry.Vars.*;
-
-public class PointDefenseTurret extends Block{
+public class PointDefenseTurret extends ReloadTurret{
public final int timerTarget = timers++;
public float retargetTime = 5f;
@@ -27,9 +24,6 @@ public class PointDefenseTurret extends Block{
public Effect hitEffect = Fx.pointHit;
public Effect shootEffect = Fx.sparkShoot;
- public float range = 80f;
- public float reloadTime = 30f;
- public float rotateSpeed = 20;
public float shootCone = 5f;
public float bulletDamage = 10f;
public float shootLength = 3f;
@@ -37,13 +31,12 @@ public class PointDefenseTurret extends Block{
public PointDefenseTurret(String name){
super(name);
- outlineIcon = true;
- update = true;
- }
+ rotateSpeed = 20f;
+ reloadTime = 30f;
- @Override
- public void drawPlace(int x, int y, int rotation, boolean valid){
- Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.accent);
+ coolantMultiplier = 2f;
+ //disabled due to version mismatch problems
+ acceptCoolant = false;
}
@Override
@@ -55,12 +48,10 @@ public class PointDefenseTurret extends Block{
public void setStats(){
super.setStats();
- stats.add(BlockStat.shootRange, range / tilesize, StatUnit.blocks);
- stats.add(BlockStat.reload, 60f / reloadTime, StatUnit.none);
+ stats.add(Stat.reload, 60f / reloadTime, StatUnit.none);
}
- public class PointDefenseBuild extends Building{
- public float rotation = 90, reload;
+ public class PointDefenseBuild extends ReloadTurretBuild{
public @Nullable Bullet target;
@Override
@@ -76,14 +67,18 @@ public class PointDefenseTurret extends Block{
target = null;
}
+ if(acceptCoolant){
+ updateCooling();
+ }
+
//look at target
if(target != null && target.within(this, range) && target.team != team && target.type() != null && target.type().hittable){
float dest = angleTo(target);
rotation = Angles.moveToward(rotation, dest, rotateSpeed * edelta());
- reload -= edelta();
+ reload += edelta();
//shoot when possible
- if(Angles.within(rotation, dest, shootCone) && reload <= 0f){
+ if(Angles.within(rotation, dest, shootCone) && reload >= reloadTime){
if(target.damage() > bulletDamage){
target.damage(target.damage() - bulletDamage);
}else{
@@ -95,18 +90,13 @@ public class PointDefenseTurret extends Block{
beamEffect.at(x + Tmp.v1.x, y + Tmp.v1.y, rotation, color, new Vec2().set(target));
shootEffect.at(x + Tmp.v1.x, y + Tmp.v1.y, rotation, color);
hitEffect.at(target.x, target.y, color);
- reload = reloadTime;
+ reload = 0;
}
}else{
target = null;
}
}
- @Override
- public void drawSelect(){
- Drawf.dashCircle(x, y, range, Pal.accent);
- }
-
@Override
public void draw(){
Draw.rect(baseRegion, x, y);
diff --git a/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java b/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java
index f8b49195da..bf365f4439 100644
--- a/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java
+++ b/core/src/mindustry/world/blocks/defense/turrets/PowerTurret.java
@@ -1,6 +1,7 @@
package mindustry.world.blocks.defense.turrets;
import mindustry.entities.bullet.*;
+import mindustry.logic.*;
import mindustry.world.meta.*;
public class PowerTurret extends Turret{
@@ -15,7 +16,7 @@ public class PowerTurret extends Turret{
@Override
public void setStats(){
super.setStats();
- stats.add(BlockStat.damage, shootType.damage, StatUnit.none);
+ stats.add(Stat.damage, shootType.damage, StatUnit.none);
}
@Override
@@ -33,6 +34,15 @@ public class PowerTurret extends Turret{
super.updateTile();
}
+ @Override
+ public double sense(LAccess sensor){
+ return switch(sensor){
+ case ammo -> power.status;
+ case ammoCapacity -> 1;
+ default -> super.sense(sensor);
+ };
+ }
+
@Override
public BulletType useAmmo(){
//nothing used directly
diff --git a/core/src/mindustry/world/blocks/defense/turrets/ReloadTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ReloadTurret.java
new file mode 100644
index 0000000000..33538771a1
--- /dev/null
+++ b/core/src/mindustry/world/blocks/defense/turrets/ReloadTurret.java
@@ -0,0 +1,49 @@
+package mindustry.world.blocks.defense.turrets;
+
+import arc.math.*;
+import arc.util.*;
+import mindustry.type.*;
+import mindustry.world.consumers.*;
+import mindustry.world.meta.*;
+import mindustry.world.meta.values.*;
+
+import static mindustry.Vars.*;
+
+public abstract class ReloadTurret extends BaseTurret{
+ public float reloadTime = 10f;
+
+ public ReloadTurret(String name){
+ super(name);
+ }
+
+ @Override
+ public void setStats(){
+ super.setStats();
+
+ if(acceptCoolant){
+ stats.add(Stat.booster, new BoosterListValue(reloadTime, consumes.get(ConsumeType.liquid).amount, coolantMultiplier, true, l -> consumes.liquidfilters.get(l.id)));
+ }
+ }
+
+ public class ReloadTurretBuild extends BaseTurretBuild{
+ public float reload;
+
+ protected void updateCooling(){
+ float maxUsed = consumes.get(ConsumeType.liquid).amount;
+
+ Liquid liquid = liquids.current();
+
+ float used = Math.min(Math.min(liquids.get(liquid), maxUsed * Time.delta), Math.max(0, ((reloadTime - reload) / coolantMultiplier) / liquid.heatCapacity)) * baseReloadSpeed();
+ reload += used * liquid.heatCapacity * coolantMultiplier;
+ liquids.remove(liquid, used);
+
+ if(Mathf.chance(0.06 * used)){
+ coolEffect.at(x + Mathf.range(size * tilesize / 2f), y + Mathf.range(size * tilesize / 2f));
+ }
+ }
+
+ protected float baseReloadSpeed(){
+ return efficiency();
+ }
+ }
+}
diff --git a/core/src/mindustry/world/blocks/defense/TractorBeamTurret.java b/core/src/mindustry/world/blocks/defense/turrets/TractorBeamTurret.java
similarity index 70%
rename from core/src/mindustry/world/blocks/defense/TractorBeamTurret.java
rename to core/src/mindustry/world/blocks/defense/turrets/TractorBeamTurret.java
index 1f74360ed5..debe26f7e6 100644
--- a/core/src/mindustry/world/blocks/defense/TractorBeamTurret.java
+++ b/core/src/mindustry/world/blocks/defense/turrets/TractorBeamTurret.java
@@ -1,4 +1,4 @@
-package mindustry.world.blocks.defense;
+package mindustry.world.blocks.defense.turrets;
import arc.graphics.*;
import arc.graphics.g2d.*;
@@ -9,12 +9,13 @@ import mindustry.annotations.Annotations.*;
import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.graphics.*;
-import mindustry.world.*;
+import mindustry.type.*;
+import mindustry.world.consumers.*;
import mindustry.world.meta.*;
import static mindustry.Vars.*;
-public class TractorBeamTurret extends Block{
+public class TractorBeamTurret extends BaseTurret{
public final int timerTarget = timers++;
public float retargetTime = 5f;
@@ -22,8 +23,6 @@ public class TractorBeamTurret extends Block{
public @Load("@-laser") TextureRegion laser;
public @Load("@-laser-end") TextureRegion laserEnd;
- public float range = 80f;
- public float rotateSpeed = 10;
public float shootCone = 6f;
public float laserWidth = 0.6f;
public float force = 0.3f;
@@ -35,14 +34,11 @@ public class TractorBeamTurret extends Block{
public TractorBeamTurret(String name){
super(name);
- update = true;
- solid = true;
- outlineIcon = true;
- }
+ rotateSpeed = 10f;
+ coolantMultiplier = 1f;
- @Override
- public void drawPlace(int x, int y, int rotation, boolean valid){
- Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.accent);
+ //disabled due to version mismatch problems
+ acceptCoolant = false;
}
@Override
@@ -54,17 +50,16 @@ public class TractorBeamTurret extends Block{
public void setStats(){
super.setStats();
- stats.add(BlockStat.shootRange, range / tilesize, StatUnit.blocks);
- stats.add(BlockStat.targetsAir, targetAir);
- stats.add(BlockStat.targetsGround, targetGround);
- stats.add(BlockStat.damage, damage * 60f, StatUnit.perSecond);
+ stats.add(Stat.targetsAir, targetAir);
+ stats.add(Stat.targetsGround, targetGround);
+ stats.add(Stat.damage, damage * 60f, StatUnit.perSecond);
}
- public class TractorBeamBuild extends Building{
- public float rotation = 90;
+ public class TractorBeamBuild extends BaseTurretBuild{
public @Nullable Unit target;
public float lastX, lastY, strength;
public boolean any;
+ public float coolant = 1f;
@Override
public void updateTile(){
@@ -74,8 +69,25 @@ public class TractorBeamTurret extends Block{
target = Units.closestEnemy(team, x, y, range, u -> u.checkTarget(targetAir, targetGround));
}
+ //consume coolant
+ if(target != null && acceptCoolant){
+ float maxUsed = consumes.get(ConsumeType.liquid).amount;
+
+ Liquid liquid = liquids.current();
+
+ float used = Math.min(Math.min(liquids.get(liquid), maxUsed * Time.delta), Math.max(0, (1f / coolantMultiplier) / liquid.heatCapacity));
+
+ liquids.remove(liquid, used);
+
+ if(Mathf.chance(0.06 * used)){
+ coolEffect.at(x + Mathf.range(size * tilesize / 2f), y + Mathf.range(size * tilesize / 2f));
+ }
+
+ coolant = 1f + (used * liquid.heatCapacity * coolantMultiplier);
+ }
+
//look at target
- if(target != null && target.within(this, range) && target.team() != team && target.type().flying && efficiency() > 0.01f){
+ if(target != null && target.within(this, range) && target.team() != team && target.type.flying && efficiency() > 0.01f){
any = true;
float dest = angleTo(target);
rotation = Angles.moveToward(rotation, dest, rotateSpeed * edelta());
@@ -98,8 +110,8 @@ public class TractorBeamTurret extends Block{
}
@Override
- public void drawSelect(){
- Drawf.dashCircle(x, y, range, Pal.accent);
+ public float efficiency() {
+ return super.efficiency() * coolant;
}
@Override
diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java
index 411ee782ec..58abb26b12 100644
--- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java
+++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java
@@ -12,6 +12,7 @@ import arc.util.*;
import arc.util.io.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
+import mindustry.core.*;
import mindustry.entities.*;
import mindustry.entities.Units.*;
import mindustry.entities.bullet.*;
@@ -20,15 +21,13 @@ import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.logic.*;
import mindustry.type.*;
-import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.consumers.*;
import mindustry.world.meta.*;
-import mindustry.world.meta.values.*;
import static mindustry.Vars.*;
-public abstract class Turret extends Block{
+public abstract class Turret extends ReloadTurret{
//after being logic-controlled and this amount of time passes, the turret will resume normal AI
public final static float logicControlCooldown = 60 * 2;
@@ -41,10 +40,9 @@ public abstract class Turret extends Block{
public Effect ammoUseEffect = Fx.none;
public Sound shootSound = Sounds.shoot;
+ public int maxAmmo = 30;
public int ammoPerShot = 1;
public float ammoEjectBack = 1f;
- public float range = 50f;
- public float reloadTime = 10f;
public float inaccuracy = 0f;
public float velocityInaccuracy = 0f;
public int shots = 1;
@@ -52,7 +50,6 @@ public abstract class Turret extends Block{
public float recoilAmount = 1f;
public float restitution = 0.02f;
public float cooldown = 0.02f;
- public float rotateSpeed = 5f; //in degrees per tick
public float shootCone = 8f;
public float shootShake = 0f;
public float xRand = 0f;
@@ -62,11 +59,7 @@ public abstract class Turret extends Block{
public boolean alternate = false;
public boolean targetAir = true;
public boolean targetGround = true;
- public boolean acceptCoolant = true;
- /** How much reload is lowered by for each unit of liquid of heat capacity. */
- public float coolantMultiplier = 5f;
- /** Effect displayed when coolant is used. */
- public Effect coolEffect = Fx.fuelburn;
+
public Sortf unitSort = Unit::dst2;
protected Vec2 tr = new Vec2();
@@ -106,15 +99,10 @@ public abstract class Turret extends Block{
public void setStats(){
super.setStats();
- stats.add(BlockStat.shootRange, range / tilesize, StatUnit.blocks);
- stats.add(BlockStat.inaccuracy, (int)inaccuracy, StatUnit.degrees);
- stats.add(BlockStat.reload, 60f / reloadTime * shots, StatUnit.none);
- stats.add(BlockStat.targetsAir, targetAir);
- stats.add(BlockStat.targetsGround, targetGround);
-
- if(acceptCoolant){
- stats.add(BlockStat.booster, new BoosterListValue(reloadTime, consumes.get(ConsumeType.liquid).amount, coolantMultiplier, true, l -> consumes.liquidfilters.get(l.id)));
- }
+ stats.add(Stat.inaccuracy, (int)inaccuracy, StatUnit.degrees);
+ stats.add(Stat.reload, 60f / reloadTime * shots, StatUnit.none);
+ stats.add(Stat.targetsAir, targetAir);
+ stats.add(Stat.targetsGround, targetGround);
}
@Override
@@ -132,32 +120,22 @@ public abstract class Turret extends Block{
return new TextureRegion[]{baseRegion, region};
}
- @Override
- public void drawPlace(int x, int y, int rotation, boolean valid){
- Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.placing);
- }
-
public static abstract class AmmoEntry{
public int amount;
public abstract BulletType type();
}
- public class TurretBuild extends Building implements ControlBlock, Ranged{
+ public class TurretBuild extends ReloadTurretBuild implements ControlBlock{
public Seq ammo = new Seq<>();
public int totalAmmo;
- public float reload, rotation = 90, recoil, heat, logicControlTime = -1;
+ public float recoil, heat, logicControlTime = -1;
public int shotCounter;
public boolean logicShooting = false;
public @Nullable Posc target;
public Vec2 targetPos = new Vec2();
public BlockUnitc unit = Nulls.blockUnit;
- @Override
- public float range(){
- return range;
- }
-
@Override
public void created(){
unit = (BlockUnitc)UnitTypes.block.create(team);
@@ -167,7 +145,7 @@ public abstract class Turret extends Block{
@Override
public void control(LAccess type, double p1, double p2, double p3, double p4){
if(type == LAccess.shoot && !unit.isPlayer()){
- targetPos.set((float)p1, (float)p2);
+ targetPos.set(World.unconv((float)p1), World.unconv((float)p2));
logicControlTime = logicControlCooldown;
logicShooting = !Mathf.zero(p3);
}
@@ -192,9 +170,11 @@ public abstract class Turret extends Block{
@Override
public double sense(LAccess sensor){
return switch(sensor){
+ case ammo -> totalAmmo;
+ case ammoCapacity -> maxAmmo;
case rotation -> rotation;
- case shootX -> targetPos.x;
- case shootY -> targetPos.y;
+ case shootX -> World.conv(targetPos.x);
+ case shootY -> World.conv(targetPos.y);
case shooting -> (isControlled() ? unit.isShooting() : logicControlled() ? logicShooting : validateTarget()) ? 1 : 0;
default -> super.sense(sensor);
};
@@ -297,11 +277,6 @@ public abstract class Turret extends Block{
}
}
- @Override
- public void drawSelect(){
- Drawf.dashCircle(x, y, range, team.color);
- }
-
@Override
public void handleLiquid(Building source, Liquid liquid, float amount){
if(acceptCoolant && liquids.currentAmount() <= 0.001f){
@@ -311,20 +286,6 @@ public abstract class Turret extends Block{
super.handleLiquid(source, liquid, amount);
}
- protected void updateCooling(){
- float maxUsed = consumes.get(ConsumeType.liquid).amount;
-
- Liquid liquid = liquids.current();
-
- float used = Math.min(Math.min(liquids.get(liquid), maxUsed * Time.delta), Math.max(0, ((reloadTime - reload) / coolantMultiplier) / liquid.heatCapacity)) * baseReloadSpeed();
- reload += used * liquid.heatCapacity * coolantMultiplier;
- liquids.remove(liquid, used);
-
- if(Mathf.chance(0.06 * used)){
- coolEffect.at(x + Mathf.range(size * tilesize / 2f), y + Mathf.range(size * tilesize / 2f));
- }
- }
-
protected boolean validateTarget(){
return !Units.invalidateTarget(target, team, x, y) || isControlled() || logicControlled();
}
@@ -449,10 +410,6 @@ public abstract class Turret extends Block{
ammoUseEffect.at(x - Angles.trnsx(rotation, ammoEjectBack), y - Angles.trnsy(rotation, ammoEjectBack), rotation);
}
- protected float baseReloadSpeed(){
- return efficiency();
- }
-
@Override
public void write(Writes write){
super.write(write);
diff --git a/core/src/mindustry/world/blocks/distribution/Conveyor.java b/core/src/mindustry/world/blocks/distribution/Conveyor.java
index 457e7e65e7..b7d973cfe7 100644
--- a/core/src/mindustry/world/blocks/distribution/Conveyor.java
+++ b/core/src/mindustry/world/blocks/distribution/Conveyor.java
@@ -52,7 +52,7 @@ public class Conveyor extends Block implements Autotiler{
super.setStats();
//have to add a custom calculated speed, since the actual movement speed is apparently not linear
- stats.add(BlockStat.itemsMoved, displayedSpeed, StatUnit.itemsSecond);
+ stats.add(Stat.itemsMoved, displayedSpeed, StatUnit.itemsSecond);
}
@Override
@@ -67,7 +67,7 @@ public class Conveyor extends Block implements Autotiler{
@Override
public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
- return (otherblock.outputsItems() || lookingAt(tile, rotation, otherx, othery, otherblock))
+ return (otherblock.outputsItems() || (lookingAt(tile, rotation, otherx, othery, otherblock) && otherblock.hasItems))
&& lookingAtEither(tile, rotation, otherx, othery, otherrot, otherblock);
}
@@ -156,7 +156,7 @@ public class Conveyor extends Block implements Autotiler{
lastInserted = build.lastInserted;
mid = build.mid;
minitem = build.minitem;
- items.addAll(build.items);
+ items.add(build.items);
}
}
@@ -183,7 +183,7 @@ public class Conveyor extends Block implements Autotiler{
@Override
public void unitOn(Unit unit){
- if(clogHeat > 0.5f) return;
+ if(clogHeat > 0.5f || !enabled) return;
noSleep();
diff --git a/core/src/mindustry/world/blocks/distribution/ItemBridge.java b/core/src/mindustry/world/blocks/distribution/ItemBridge.java
index 2d09c69eba..6e310d0e55 100644
--- a/core/src/mindustry/world/blocks/distribution/ItemBridge.java
+++ b/core/src/mindustry/world/blocks/distribution/ItemBridge.java
@@ -202,7 +202,7 @@ public class ItemBridge extends Block{
for(int i = 1; i <= range; i++){
for(int j = 0; j < 4; j++){
- Tile other = tile.getNearby(Geometry.d4[j].x * i, Geometry.d4[j].y * i);
+ Tile other = tile.nearby(Geometry.d4[j].x * i, Geometry.d4[j].y * i);
if(linkValid(tile, other)){
boolean linked = other.pos() == link;
@@ -336,16 +336,18 @@ public class ItemBridge extends Block{
Tile other = world.tile(link);
+ if(items.total() >= itemCapacity) return false;
+
+ if(linked(source)) return true;
+
if(linkValid(tile, other)){
int rel = relativeTo(other);
int rel2 = relativeTo(Edges.getFacingEdge(source, this));
- if(rel == rel2) return false;
- }else{
- return linked(source) && items.total() < itemCapacity;
+ return rel != rel2;
}
- return items.total() < itemCapacity;
+ return false;
}
@Override
@@ -359,16 +361,18 @@ public class ItemBridge extends Block{
Tile other = world.tile(link);
+ if(!(liquids.current() == liquid || liquids.get(liquids.current()) < 0.2f)) return false;
+
+ if(linked(source)) return true;
+
if(linkValid(tile, other)){
int rel = relativeTo(other.x, other.y);
int rel2 = relativeTo(Edges.getFacingEdge(source, this));
- if(rel == rel2) return false;
- }else if(!(linked(source))){
- return false;
+ return rel != rel2;
}
- return (liquids.current() == liquid || liquids.get(liquids.current()) < 0.2f);
+ return false;
}
protected boolean linked(Building source){
diff --git a/core/src/mindustry/world/blocks/distribution/MassDriver.java b/core/src/mindustry/world/blocks/distribution/MassDriver.java
index 1776ed7522..9191e7dfe1 100644
--- a/core/src/mindustry/world/blocks/distribution/MassDriver.java
+++ b/core/src/mindustry/world/blocks/distribution/MassDriver.java
@@ -105,6 +105,10 @@ public class MassDriver extends Block{
Building link = world.build(this.link);
boolean hasLink = linkValid();
+ if(hasLink){
+ this.link = link.pos();
+ }
+
//reload regardless of state
if(reload > 0f){
reload = Mathf.clamp(reload - edelta() / reloadTime);
diff --git a/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java b/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java
index 7c0bbb7821..08035d9c84 100644
--- a/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java
+++ b/core/src/mindustry/world/blocks/distribution/PayloadConveyor.java
@@ -87,7 +87,7 @@ public class PayloadConveyor extends Block{
}
int ntrns = 1 + size/2;
- Tile next = tile.getNearby(Geometry.d4(rotation).x * ntrns, Geometry.d4(rotation).y * ntrns);
+ Tile next = tile.nearby(Geometry.d4(rotation).x * ntrns, Geometry.d4(rotation).y * ntrns);
blocked = (next != null && next.solid() && !next.block().outputsPayload) || (this.next != null && (this.next.rotation + 2)%4 == rotation);
}
diff --git a/core/src/mindustry/world/blocks/distribution/Router.java b/core/src/mindustry/world/blocks/distribution/Router.java
index 5b107d5a0e..766a1bafff 100644
--- a/core/src/mindustry/world/blocks/distribution/Router.java
+++ b/core/src/mindustry/world/blocks/distribution/Router.java
@@ -1,9 +1,12 @@
package mindustry.world.blocks.distribution;
+import arc.math.*;
+import arc.util.*;
import mindustry.content.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.*;
+import mindustry.world.blocks.*;
import mindustry.world.meta.*;
public class Router extends Block{
@@ -20,10 +23,30 @@ public class Router extends Block{
noUpdateDisabled = true;
}
- public class RouterBuild extends Building{
+ public class RouterBuild extends Building implements ControlBlock{
public Item lastItem;
public Tile lastInput;
public float time;
+ public @Nullable BlockUnitc unit;
+
+ @Override
+ public Unit unit(){
+ if(unit == null){
+ unit = (BlockUnitc)UnitTypes.block.create(team);
+ unit.tile(this);
+ }
+ return (Unit)unit;
+ }
+
+ @Override
+ public boolean canControl(){
+ return size == 1;
+ }
+
+ @Override
+ public boolean shouldAutoTarget(){
+ return false;
+ }
@Override
public void updateTile(){
@@ -72,6 +95,23 @@ public class Router extends Block{
}
public Building getTileTarget(Item item, Tile from, boolean set){
+ if(unit != null && isControlled()){
+ unit.health(health);
+ unit.ammo(unit.type().ammoCapacity * (items.total() > 0 ? 1f : 0f));
+ unit.team(team);
+
+ int angle = Mathf.mod((int)((angleTo(unit.aimX(), unit.aimY()) + 45) / 90), 4);
+
+ if(unit.isShooting()){
+ Building other = nearby(angle);
+ if(other != null && other.acceptItem(this, item)){
+ return other;
+ }
+ }
+
+ return null;
+ }
+
int counter = rotation;
for(int i = 0; i < proximity.size; i++){
Building other = proximity.get((i + counter) % proximity.size);
diff --git a/core/src/mindustry/world/blocks/distribution/StackConveyor.java b/core/src/mindustry/world/blocks/distribution/StackConveyor.java
index e7095a686c..f3c400ad9b 100644
--- a/core/src/mindustry/world/blocks/distribution/StackConveyor.java
+++ b/core/src/mindustry/world/blocks/distribution/StackConveyor.java
@@ -53,7 +53,7 @@ public class StackConveyor extends Block implements Autotiler{
public void setStats(){
super.setStats();
- stats.add(BlockStat.itemsMoved, Mathf.round(itemCapacity * speed * 60), StatUnit.itemsSecond);
+ stats.add(Stat.itemsMoved, Mathf.round(itemCapacity * speed * 60), StatUnit.itemsSecond);
}
@Override
@@ -203,7 +203,7 @@ public class StackConveyor extends Block implements Autotiler{
if(front() instanceof StackConveyorBuild e && e.team == team){
// sleep if its occupied
if(e.link == -1){
- e.items.addAll(items);
+ e.items.add(items);
e.lastItem = lastItem;
e.link = tile.pos();
// ▲ to | from ▼
diff --git a/core/src/mindustry/world/blocks/environment/Floor.java b/core/src/mindustry/world/blocks/environment/Floor.java
index a70056717a..113617cc63 100644
--- a/core/src/mindustry/world/blocks/environment/Floor.java
+++ b/core/src/mindustry/world/blocks/environment/Floor.java
@@ -64,6 +64,8 @@ public class Floor extends Block{
public Block wall = Blocks.air;
/** Decoration block. Usually a rock. May be air. */
public Block decoration = Blocks.air;
+ /** Whether this overlay needs a surface to be on. False for floating blocks, like spawns. */
+ public boolean needsSurface = true;
protected TextureRegion[][] edges;
protected Seq blenders = new Seq<>();
@@ -183,7 +185,7 @@ public class Floor extends Block{
for(int i = 0; i < 8; i++){
Point2 point = Geometry.d8[i];
- Tile other = tile.getNearby(point);
+ Tile other = tile.nearby(point);
if(other != null && other.floor().cacheLayer == layer && other.floor().edges() != null){
if(!blended.getAndSet(other.floor().id)){
blenders.add(other.floor());
@@ -200,7 +202,7 @@ public class Floor extends Block{
for(int i = 0; i < 8; i++){
Point2 point = Geometry.d8[i];
- Tile other = tile.getNearby(point);
+ Tile other = tile.nearby(point);
if(other != null && doEdge(other.floor()) && other.floor().cacheLayer == cacheLayer && other.floor().edges() != null){
if(!blended.getAndSet(other.floor().id)){
blenders.add(other.floor());
@@ -217,7 +219,7 @@ public class Floor extends Block{
for(Block block : blenders){
for(int i = 0; i < 8; i++){
Point2 point = Geometry.d8[i];
- Tile other = tile.getNearby(point);
+ Tile other = tile.nearby(point);
if(other != null && other.floor() == block){
TextureRegion region = edge((Floor)block, 1 - point.x, 1 - point.y);
Draw.rect(region, tile.worldx(), tile.worldy());
@@ -229,7 +231,7 @@ public class Floor extends Block{
//'new' style of edges with shadows instead of colors, not used currently
protected void drawEdgesFlat(Tile tile, boolean sameLayer){
for(int i = 0; i < 4; i++){
- Tile other = tile.getNearby(i);
+ Tile other = tile.nearby(i);
if(other != null && doEdge(other.floor())){
Color color = other.floor().mapColor;
Draw.color(color.r, color.g, color.b, 1f);
diff --git a/core/src/mindustry/world/blocks/environment/OreBlock.java b/core/src/mindustry/world/blocks/environment/OreBlock.java
index 943d91076d..c08a3eccce 100644
--- a/core/src/mindustry/world/blocks/environment/OreBlock.java
+++ b/core/src/mindustry/world/blocks/environment/OreBlock.java
@@ -20,6 +20,7 @@ public class OreBlock extends OverlayFloor{
this.itemDrop = ore;
this.variants = 3;
this.mapColor.set(ore.color);
+ this.useColor = true;
}
/** For mod use only!*/
diff --git a/core/src/mindustry/world/blocks/environment/OverlayFloor.java b/core/src/mindustry/world/blocks/environment/OverlayFloor.java
index f7a92ceeb3..4c57943aed 100644
--- a/core/src/mindustry/world/blocks/environment/OverlayFloor.java
+++ b/core/src/mindustry/world/blocks/environment/OverlayFloor.java
@@ -9,6 +9,7 @@ public class OverlayFloor extends Floor{
public OverlayFloor(String name){
super(name);
+ useColor = false;
}
@Override
diff --git a/core/src/mindustry/world/blocks/environment/StaticTree.java b/core/src/mindustry/world/blocks/environment/StaticTree.java
index 78c6133d2f..9b1a7063f4 100644
--- a/core/src/mindustry/world/blocks/environment/StaticTree.java
+++ b/core/src/mindustry/world/blocks/environment/StaticTree.java
@@ -21,7 +21,7 @@ public class StaticTree extends StaticWall{
float oy = 0;
for(int i = 0; i < 4; i++){
- if(tile.getNearby(i) != null && tile.getNearby(i).block() instanceof StaticWall){
+ if(tile.nearby(i) != null && tile.nearby(i).block() instanceof StaticWall){
if(i == 0){
r.setWidth(r.width - crop);
diff --git a/core/src/mindustry/world/blocks/experimental/BlockForge.java b/core/src/mindustry/world/blocks/experimental/BlockForge.java
index 52509674a7..251c6820a0 100644
--- a/core/src/mindustry/world/blocks/experimental/BlockForge.java
+++ b/core/src/mindustry/world/blocks/experimental/BlockForge.java
@@ -99,7 +99,7 @@ public class BlockForge extends PayloadAcceptor{
public void buildConfiguration(Table table){
Seq blocks = Vars.content.blocks().select(b -> b.isVisible() && b.size <= 2);
- ItemSelection.buildTable(table, blocks, () -> recipe, block -> recipe = block);
+ ItemSelection.buildTable(table, blocks, () -> recipe, this::configure);
}
@Override
diff --git a/core/src/mindustry/world/blocks/liquid/LiquidJunction.java b/core/src/mindustry/world/blocks/liquid/LiquidJunction.java
index 09e5b70bb0..80881e2c17 100644
--- a/core/src/mindustry/world/blocks/liquid/LiquidJunction.java
+++ b/core/src/mindustry/world/blocks/liquid/LiquidJunction.java
@@ -14,7 +14,7 @@ public class LiquidJunction extends LiquidBlock{
@Override
public void setStats(){
super.setStats();
- stats.remove(BlockStat.liquidCapacity);
+ stats.remove(Stat.liquidCapacity);
}
@Override
diff --git a/core/src/mindustry/world/blocks/logic/LogicBlock.java b/core/src/mindustry/world/blocks/logic/LogicBlock.java
index aecf5d4149..488c44604d 100644
--- a/core/src/mindustry/world/blocks/logic/LogicBlock.java
+++ b/core/src/mindustry/world/blocks/logic/LogicBlock.java
@@ -8,6 +8,7 @@ import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.*;
+import mindustry.core.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.io.*;
@@ -116,8 +117,8 @@ public class LogicBlock extends Block{
public void setStats(){
super.setStats();
- stats.add(BlockStat.linkRange, range / 8, StatUnit.blocks);
- stats.add(BlockStat.instructions, instructionsPerTick * 60, StatUnit.perSecond);
+ stats.add(Stat.linkRange, range / 8, StatUnit.blocks);
+ stats.add(Stat.instructions, instructionsPerTick * 60, StatUnit.perSecond);
}
@Override
@@ -278,10 +279,13 @@ public class LogicBlock extends Block{
//store link objects
executor.links = new Building[links.count(l -> l.valid && l.active)];
+ executor.linkIds.clear();
int index = 0;
for(LogicLink link : links){
if(link.active && link.valid){
- executor.links[index ++] = world.build(link.x, link.y);
+ Building build = world.build(link.x, link.y);
+ executor.links[index ++] = build;
+ if(build != null) executor.linkIds.add(build.id);
}
}
@@ -304,8 +308,8 @@ public class LogicBlock extends Block{
}
asm.getVar("@this").value = this;
- asm.putConst("@thisx", x);
- asm.putConst("@thisy", y);
+ asm.putConst("@thisx", World.conv(x));
+ asm.putConst("@thisy", World.conv(y));
executor.load(asm);
}catch(Exception e){
diff --git a/core/src/mindustry/world/blocks/logic/LogicDisplay.java b/core/src/mindustry/world/blocks/logic/LogicDisplay.java
index cb062259b8..505791e1b0 100644
--- a/core/src/mindustry/world/blocks/logic/LogicDisplay.java
+++ b/core/src/mindustry/world/blocks/logic/LogicDisplay.java
@@ -38,7 +38,7 @@ public class LogicDisplay extends Block{
public void setStats(){
super.setStats();
- stats.add(BlockStat.displaySize, "@x@", displaySize, displaySize);
+ stats.add(Stat.displaySize, "@x@", displaySize, displaySize);
}
public class LogicDisplayBuild extends Building{
diff --git a/core/src/mindustry/world/blocks/logic/MemoryBlock.java b/core/src/mindustry/world/blocks/logic/MemoryBlock.java
index d215238ced..0329744168 100644
--- a/core/src/mindustry/world/blocks/logic/MemoryBlock.java
+++ b/core/src/mindustry/world/blocks/logic/MemoryBlock.java
@@ -18,7 +18,7 @@ public class MemoryBlock extends Block{
public void setStats(){
super.setStats();
- stats.add(BlockStat.memoryCapacity, memoryCapacity, StatUnit.none);
+ stats.add(Stat.memoryCapacity, memoryCapacity, StatUnit.none);
}
public class MemoryBuild extends Building{
diff --git a/core/src/mindustry/world/blocks/logic/SwitchBlock.java b/core/src/mindustry/world/blocks/logic/SwitchBlock.java
index bca47a306a..d27cebb1b3 100644
--- a/core/src/mindustry/world/blocks/logic/SwitchBlock.java
+++ b/core/src/mindustry/world/blocks/logic/SwitchBlock.java
@@ -37,6 +37,11 @@ public class SwitchBlock extends Block{
}
}
+ @Override
+ public Boolean config(){
+ return enabled;
+ }
+
@Override
public byte version(){
return 1;
diff --git a/core/src/mindustry/world/blocks/payloads/UnitPayload.java b/core/src/mindustry/world/blocks/payloads/UnitPayload.java
index 724df792fa..2292244864 100644
--- a/core/src/mindustry/world/blocks/payloads/UnitPayload.java
+++ b/core/src/mindustry/world/blocks/payloads/UnitPayload.java
@@ -43,7 +43,7 @@ public class UnitPayload implements Payload{
@Override
public boolean dump(){
- if(!Units.canCreate(unit.team, unit.type())){
+ if(!Units.canCreate(unit.team, unit.type)){
deactiveTime = 1f;
return false;
}
@@ -74,7 +74,7 @@ public class UnitPayload implements Payload{
@Override
public void draw(){
Drawf.shadow(unit.x, unit.y, 20);
- Draw.rect(unit.type().icon(Cicon.full), unit.x, unit.y, unit.rotation - 90);
+ Draw.rect(unit.type.icon(Cicon.full), unit.x, unit.y, unit.rotation - 90);
//draw warning
if(deactiveTime > 0){
diff --git a/core/src/mindustry/world/blocks/power/Battery.java b/core/src/mindustry/world/blocks/power/Battery.java
index 7c1f364b37..e78cb31b3a 100644
--- a/core/src/mindustry/world/blocks/power/Battery.java
+++ b/core/src/mindustry/world/blocks/power/Battery.java
@@ -20,7 +20,7 @@ public class Battery extends PowerDistributor{
super(name);
outputsPower = true;
consumesPower = true;
- flags = EnumSet.of(BlockFlag.powerRes);
+ flags = EnumSet.of(BlockFlag.battery);
}
public class BatteryBuild extends Building{
diff --git a/core/src/mindustry/world/blocks/power/ImpactReactor.java b/core/src/mindustry/world/blocks/power/ImpactReactor.java
index a24fecf2b4..f5dc985d1e 100644
--- a/core/src/mindustry/world/blocks/power/ImpactReactor.java
+++ b/core/src/mindustry/world/blocks/power/ImpactReactor.java
@@ -55,7 +55,7 @@ public class ImpactReactor extends PowerGenerator{
super.setStats();
if(hasItems){
- stats.add(BlockStat.productionTime, itemDuration / 60f, StatUnit.seconds);
+ stats.add(Stat.productionTime, itemDuration / 60f, StatUnit.seconds);
}
}
diff --git a/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java b/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java
index 2d82bfa4c7..12b3f6d691 100644
--- a/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java
+++ b/core/src/mindustry/world/blocks/power/ItemLiquidGenerator.java
@@ -72,7 +72,7 @@ public class ItemLiquidGenerator extends PowerGenerator{
super.setStats();
if(hasItems){
- stats.add(BlockStat.productionTime, itemDuration / 60f, StatUnit.seconds);
+ stats.add(Stat.productionTime, itemDuration / 60f, StatUnit.seconds);
}
}
diff --git a/core/src/mindustry/world/blocks/power/NuclearReactor.java b/core/src/mindustry/world/blocks/power/NuclearReactor.java
index ac449d90db..85fe183993 100644
--- a/core/src/mindustry/world/blocks/power/NuclearReactor.java
+++ b/core/src/mindustry/world/blocks/power/NuclearReactor.java
@@ -5,6 +5,7 @@ import arc.graphics.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
+import arc.struct.*;
import arc.util.*;
import arc.util.io.*;
import mindustry.annotations.Annotations.*;
@@ -47,6 +48,7 @@ public class NuclearReactor extends PowerGenerator{
hasItems = true;
hasLiquids = true;
rebuildable = false;
+ flags = EnumSet.of(BlockFlag.reactor);
}
@Override
@@ -54,7 +56,7 @@ public class NuclearReactor extends PowerGenerator{
super.setStats();
if(hasItems){
- stats.add(BlockStat.productionTime, itemDuration / 60f, StatUnit.seconds);
+ stats.add(Stat.productionTime, itemDuration / 60f, StatUnit.seconds);
}
}
diff --git a/core/src/mindustry/world/blocks/power/PowerGenerator.java b/core/src/mindustry/world/blocks/power/PowerGenerator.java
index 2307093f27..ae9453d675 100644
--- a/core/src/mindustry/world/blocks/power/PowerGenerator.java
+++ b/core/src/mindustry/world/blocks/power/PowerGenerator.java
@@ -12,13 +12,13 @@ import mindustry.world.meta.*;
public class PowerGenerator extends PowerDistributor{
/** The amount of power produced per tick in case of an efficiency of 1.0, which represents 100%. */
public float powerProduction;
- public BlockStat generationType = BlockStat.basePowerGeneration;
+ public Stat generationType = Stat.basePowerGeneration;
public PowerGenerator(String name){
super(name);
sync = true;
baseExplosiveness = 5f;
- flags = EnumSet.of(BlockFlag.producer);
+ flags = EnumSet.of(BlockFlag.generator);
}
@Override
diff --git a/core/src/mindustry/world/blocks/power/PowerNode.java b/core/src/mindustry/world/blocks/power/PowerNode.java
index 5d033c99b7..042b03099e 100644
--- a/core/src/mindustry/world/blocks/power/PowerNode.java
+++ b/core/src/mindustry/world/blocks/power/PowerNode.java
@@ -124,8 +124,8 @@ public class PowerNode extends PowerBlock{
public void setStats(){
super.setStats();
- stats.add(BlockStat.powerRange, laserRange, StatUnit.blocks);
- stats.add(BlockStat.powerConnections, maxNodes, StatUnit.none);
+ stats.add(Stat.powerRange, laserRange, StatUnit.blocks);
+ stats.add(Stat.powerConnections, maxNodes, StatUnit.none);
}
@Override
diff --git a/core/src/mindustry/world/blocks/power/ThermalGenerator.java b/core/src/mindustry/world/blocks/power/ThermalGenerator.java
index e29b7a6bdb..154bd02a0c 100644
--- a/core/src/mindustry/world/blocks/power/ThermalGenerator.java
+++ b/core/src/mindustry/world/blocks/power/ThermalGenerator.java
@@ -22,7 +22,7 @@ public class ThermalGenerator extends PowerGenerator{
public void setStats(){
super.setStats();
- stats.add(BlockStat.tiles, attribute, floating);
+ stats.add(Stat.tiles, attribute, floating);
}
@Override
diff --git a/core/src/mindustry/world/blocks/production/AttributeSmelter.java b/core/src/mindustry/world/blocks/production/AttributeSmelter.java
index 987b14e63b..c2650ab030 100644
--- a/core/src/mindustry/world/blocks/production/AttributeSmelter.java
+++ b/core/src/mindustry/world/blocks/production/AttributeSmelter.java
@@ -37,7 +37,7 @@ public class AttributeSmelter extends GenericSmelter{
public void setStats(){
super.setStats();
- stats.add(BlockStat.affinities, attribute, boostScale);
+ stats.add(Stat.affinities, attribute, boostScale);
}
public class AttributeSmelterBuild extends SmelterBuild{
diff --git a/core/src/mindustry/world/blocks/production/Cultivator.java b/core/src/mindustry/world/blocks/production/Cultivator.java
index 2dc97d82f6..a5aede4e25 100644
--- a/core/src/mindustry/world/blocks/production/Cultivator.java
+++ b/core/src/mindustry/world/blocks/production/Cultivator.java
@@ -42,7 +42,7 @@ public class Cultivator extends GenericCrafter{
public void setStats(){
super.setStats();
- stats.add(BlockStat.affinities, attribute);
+ stats.add(Stat.affinities, attribute);
}
@Override
diff --git a/core/src/mindustry/world/blocks/production/Drill.java b/core/src/mindustry/world/blocks/production/Drill.java
index 7b86f1d1f5..ef4ab64b27 100644
--- a/core/src/mindustry/world/blocks/production/Drill.java
+++ b/core/src/mindustry/world/blocks/production/Drill.java
@@ -16,7 +16,9 @@ import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.*;
+import mindustry.world.blocks.environment.*;
import mindustry.world.meta.*;
+import mindustry.world.meta.values.*;
import static mindustry.Vars.*;
@@ -135,29 +137,11 @@ public class Drill extends Block{
public void setStats(){
super.setStats();
- stats.add(BlockStat.drillTier, table -> {
- Seq list = content.blocks().select(b -> b.isFloor() && b.asFloor().itemDrop != null && b.asFloor().itemDrop.hardness <= tier);
+ stats.add(Stat.drillTier, new BlockFilterValue(b -> b instanceof Floor f && f.itemDrop != null && f.itemDrop.hardness <= tier));
- table.table(l -> {
- l.left();
-
- for(int i = 0; i < list.size; i++){
- Block item = list.get(i);
-
- l.image(item.icon(Cicon.small)).size(8 * 3).padRight(2).padLeft(2).padTop(3).padBottom(3);
- l.add(item.localizedName).left().padLeft(1).padRight(4);
- if(i % 5 == 4){
- l.row();
- }
- }
- });
-
-
- });
-
- stats.add(BlockStat.drillSpeed, 60f / drillTime * size * size, StatUnit.itemsSecond);
+ stats.add(Stat.drillSpeed, 60f / drillTime * size * size, StatUnit.itemsSecond);
if(liquidBoostIntensity != 1){
- stats.add(BlockStat.boostEffect, liquidBoostIntensity * liquidBoostIntensity, StatUnit.timesSpeed);
+ stats.add(Stat.boostEffect, liquidBoostIntensity * liquidBoostIntensity, StatUnit.timesSpeed);
}
}
diff --git a/core/src/mindustry/world/blocks/production/Fracker.java b/core/src/mindustry/world/blocks/production/Fracker.java
index d894cf05b5..d2dbd5bf69 100644
--- a/core/src/mindustry/world/blocks/production/Fracker.java
+++ b/core/src/mindustry/world/blocks/production/Fracker.java
@@ -21,7 +21,7 @@ public class Fracker extends SolidPump{
public void setStats(){
super.setStats();
- stats.add(BlockStat.productionTime, itemUseTime / 60f, StatUnit.seconds);
+ stats.add(Stat.productionTime, itemUseTime / 60f, StatUnit.seconds);
}
@Override
@@ -45,7 +45,7 @@ public class Fracker extends SolidPump{
Draw.rect(region, x, y);
super.drawCracks();
- Drawf.liquid(liquidRegion, x, y, liquids.total() / liquidCapacity, result.color);
+ Drawf.liquid(liquidRegion, x, y, liquids.get(result) / liquidCapacity, result.color);
Draw.rect(rotatorRegion, x, y, pumpTime);
Draw.rect(topRegion, x, y);
diff --git a/core/src/mindustry/world/blocks/production/GenericCrafter.java b/core/src/mindustry/world/blocks/production/GenericCrafter.java
index 434c9f4b65..c992be7d78 100644
--- a/core/src/mindustry/world/blocks/production/GenericCrafter.java
+++ b/core/src/mindustry/world/blocks/production/GenericCrafter.java
@@ -2,6 +2,7 @@ package mindustry.world.blocks.production;
import arc.graphics.g2d.*;
import arc.math.*;
+import arc.struct.*;
import arc.util.io.*;
import mindustry.content.*;
import mindustry.entities.*;
@@ -23,9 +24,6 @@ public class GenericCrafter extends Block{
public DrawBlock drawer = new DrawBlock();
- //public Cons drawer = null;
- //public Prov drawIcons = null;
-
public GenericCrafter(String name){
super(name);
update = true;
@@ -34,6 +32,7 @@ public class GenericCrafter extends Block{
idleSound = Sounds.machine;
sync = true;
idleSoundVolume = 0.03f;
+ flags = EnumSet.of(BlockFlag.factory);
}
@Override
@@ -44,14 +43,14 @@ public class GenericCrafter extends Block{
}
super.setStats();
- stats.add(BlockStat.productionTime, craftTime / 60f, StatUnit.seconds);
+ stats.add(Stat.productionTime, craftTime / 60f, StatUnit.seconds);
if(outputItem != null){
- stats.add(BlockStat.output, outputItem);
+ stats.add(Stat.output, outputItem);
}
if(outputLiquid != null){
- stats.add(BlockStat.output, outputLiquid.liquid, outputLiquid.amount, false);
+ stats.add(Stat.output, outputLiquid.liquid, outputLiquid.amount, false);
}
}
diff --git a/core/src/mindustry/world/blocks/production/LiquidConverter.java b/core/src/mindustry/world/blocks/production/LiquidConverter.java
index 84868d9b61..8a9725d42d 100644
--- a/core/src/mindustry/world/blocks/production/LiquidConverter.java
+++ b/core/src/mindustry/world/blocks/production/LiquidConverter.java
@@ -26,8 +26,8 @@ public class LiquidConverter extends GenericCrafter{
@Override
public void setStats(){
super.setStats();
- stats.remove(BlockStat.output);
- stats.add(BlockStat.output, outputLiquid.liquid, outputLiquid.amount * craftTime, false);
+ stats.remove(Stat.output);
+ stats.add(Stat.output, outputLiquid.liquid, outputLiquid.amount * craftTime, false);
}
public class LiquidConverterBuild extends GenericCrafterBuild{
diff --git a/core/src/mindustry/world/blocks/production/PayloadAcceptor.java b/core/src/mindustry/world/blocks/production/PayloadAcceptor.java
index 75cfde865f..3b4693c250 100644
--- a/core/src/mindustry/world/blocks/production/PayloadAcceptor.java
+++ b/core/src/mindustry/world/blocks/production/PayloadAcceptor.java
@@ -95,7 +95,7 @@ public class PayloadAcceptor extends Block{
updatePayload();
payRotation = Mathf.slerpDelta(payRotation, rotate ? rotdeg() : 90f, 0.3f);
- payVector.approachDelta(Vec2.ZERO, payloadSpeed);
+ payVector.approach(Vec2.ZERO, payloadSpeed * delta());
return hasArrived();
}
@@ -105,7 +105,7 @@ public class PayloadAcceptor extends Block{
updatePayload();
- payVector.trns(rotdeg(), payVector.len() + edelta() * payloadSpeed);
+ payVector.trns(rotdeg(), payVector.len() + delta() * payloadSpeed);
payRotation = rotdeg();
if(payVector.len() >= size * tilesize/2f){
diff --git a/core/src/mindustry/world/blocks/production/Pump.java b/core/src/mindustry/world/blocks/production/Pump.java
index fa2f67999f..c4a6313129 100644
--- a/core/src/mindustry/world/blocks/production/Pump.java
+++ b/core/src/mindustry/world/blocks/production/Pump.java
@@ -26,7 +26,7 @@ public class Pump extends LiquidBlock{
@Override
public void setStats(){
super.setStats();
- stats.add(BlockStat.output, 60f * pumpAmount * size * size, StatUnit.liquidSecond);
+ stats.add(Stat.output, 60f * pumpAmount * size * size, StatUnit.liquidSecond);
}
@Override
diff --git a/core/src/mindustry/world/blocks/production/Separator.java b/core/src/mindustry/world/blocks/production/Separator.java
index bcf66984e3..d9b355cc70 100644
--- a/core/src/mindustry/world/blocks/production/Separator.java
+++ b/core/src/mindustry/world/blocks/production/Separator.java
@@ -41,14 +41,14 @@ public class Separator extends Block{
super.setStats();
- stats.add(BlockStat.output, new ItemFilterValue(item -> {
+ stats.add(Stat.output, new ItemFilterValue(item -> {
for(ItemStack i : results){
if(item == i.item) return true;
}
return false;
}));
- stats.add(BlockStat.productionTime, craftTime / 60f, StatUnit.seconds);
+ stats.add(Stat.productionTime, craftTime / 60f, StatUnit.seconds);
}
public class SeparatorBuild extends Building{
diff --git a/core/src/mindustry/world/blocks/production/SolidPump.java b/core/src/mindustry/world/blocks/production/SolidPump.java
index 3b29665fde..d49a6499ac 100644
--- a/core/src/mindustry/world/blocks/production/SolidPump.java
+++ b/core/src/mindustry/world/blocks/production/SolidPump.java
@@ -53,10 +53,10 @@ public class SolidPump extends Pump{
public void setStats(){
super.setStats();
- stats.remove(BlockStat.output);
- stats.add(BlockStat.output, result, 60f * pumpAmount, true);
+ stats.remove(Stat.output);
+ stats.add(Stat.output, result, 60f * pumpAmount, true);
if(attribute != null){
- stats.add(baseEfficiency > 0.0001f ? BlockStat.affinities : BlockStat.tiles, attribute);
+ stats.add(baseEfficiency > 0.0001f ? Stat.affinities : Stat.tiles, attribute);
}
}
diff --git a/core/src/mindustry/world/blocks/sandbox/PowerVoid.java b/core/src/mindustry/world/blocks/sandbox/PowerVoid.java
index c423ba6caf..e97622c609 100644
--- a/core/src/mindustry/world/blocks/sandbox/PowerVoid.java
+++ b/core/src/mindustry/world/blocks/sandbox/PowerVoid.java
@@ -11,8 +11,8 @@ public class PowerVoid extends PowerBlock{
}
@Override
- public void init(){
- super.init();
- stats.remove(BlockStat.powerUse);
+ public void setStats(){
+ super.setStats();
+ stats.remove(Stat.powerUse);
}
}
diff --git a/core/src/mindustry/world/blocks/storage/CoreBlock.java b/core/src/mindustry/world/blocks/storage/CoreBlock.java
index bdb16eb674..039c7cc3cf 100644
--- a/core/src/mindustry/world/blocks/storage/CoreBlock.java
+++ b/core/src/mindustry/world/blocks/storage/CoreBlock.java
@@ -47,7 +47,7 @@ public class CoreBlock extends StorageBlock{
update = true;
hasItems = true;
priority = TargetPriority.core;
- flags = EnumSet.of(BlockFlag.core, BlockFlag.producer, BlockFlag.unitModifier);
+ flags = EnumSet.of(BlockFlag.core, BlockFlag.unitModifier);
unitCapModifier = 10;
activeSound = Sounds.respawning;
activeSoundVolume = 1f;
@@ -77,12 +77,16 @@ public class CoreBlock extends StorageBlock{
public void setStats(){
super.setStats();
- stats.add(BlockStat.buildTime, 0, StatUnit.seconds);
+ stats.add(Stat.buildTime, 0, StatUnit.seconds);
+ }
- bars.add("capacity", (CoreBuild e) ->
- new Bar(
- () -> Core.bundle.format("bar.capacity", UI.formatAmount(e.storageCapacity)),
- () -> Pal.items,
+ @Override
+ public void setBars(){
+ super.setBars();
+
+ bars.add("capacity", (CoreBuild e) -> new Bar(
+ () -> Core.bundle.format("bar.capacity", UI.formatAmount(e.storageCapacity)),
+ () -> Pal.items,
() -> e.items.total() / ((float)e.storageCapacity * content.items().count(i -> i.unlockedNow()))
));
}
@@ -196,6 +200,21 @@ public class CoreBlock extends StorageBlock{
return false;
}
+ @Override
+ public void onDestroyed(){
+ super.onDestroyed();
+
+ //add a spawn to the map for future reference - waves should be disabled, so it shouldn't matter
+ if(state.isCampaign() && team == state.rules.waveTeam){
+ //do not recache
+ tile.setOverlayQuiet(Blocks.spawn);
+
+ if(!spawner.getSpawns().contains(tile)){
+ spawner.getSpawns().add(tile);
+ }
+ }
+ }
+
@Override
public void drawLight(){
Drawf.light(team, x, y, 30f * size, Pal.accent, 0.5f + Mathf.absin(20f, 0.1f));
@@ -310,23 +329,6 @@ public class CoreBlock extends StorageBlock{
}
}
- @Override
- public void onDestroyed(){
- super.onDestroyed();
-
- if(state.isCampaign() && team == state.rules.waveTeam){
- //do not recache
- world.setGenerating(true);
- tile.setOverlay(Blocks.spawn);
- world.setGenerating(false);
-
- if(!spawner.getSpawns().contains(tile)){
- spawner.getSpawns().add(tile);
- }
- spawner.doShockwave(x, y);
- }
- }
-
@Override
public void placed(){
super.placed();
@@ -335,7 +337,7 @@ public class CoreBlock extends StorageBlock{
@Override
public void itemTaken(Item item){
- if(state.isCampaign()){
+ if(state.isCampaign() && team == state.rules.defaultTeam){
//update item taken amount
state.secinfo.handleCoreItem(item, -1);
}
@@ -344,6 +346,9 @@ public class CoreBlock extends StorageBlock{
@Override
public void handleItem(Building source, Item item){
if(net.server() || !net.active()){
+ if(team == state.rules.defaultTeam){
+ state.secinfo.handleCoreItem(item, 1);
+ }
if(items.get(item) >= getMaximumAccepted(item)){
//create item incineration effect at random intervals
diff --git a/core/src/mindustry/world/blocks/storage/StorageBlock.java b/core/src/mindustry/world/blocks/storage/StorageBlock.java
index 50eb65a270..b7581b4dfb 100644
--- a/core/src/mindustry/world/blocks/storage/StorageBlock.java
+++ b/core/src/mindustry/world/blocks/storage/StorageBlock.java
@@ -11,6 +11,7 @@ import mindustry.world.blocks.storage.CoreBlock.*;
import mindustry.world.meta.*;
public class StorageBlock extends Block{
+
public StorageBlock(String name){
super(name);
hasItems = true;
@@ -26,11 +27,11 @@ public class StorageBlock extends Block{
}
public static void incinerateEffect(Building self, Building source){
- if(Mathf.chance(0.1)){
+ if(Mathf.chance(0.3)){
Tile edge = Edges.getFacingEdge(source, self);
Tile edge2 = Edges.getFacingEdge(self, source);
if(edge != null && edge2 != null){
- Fx.fuelburn.at((edge.worldx() + edge2.worldx())/2f, (edge.worldy() + edge2.worldy())/2f);
+ Fx.coreBurn.at((edge.worldx() + edge2.worldx())/2f, (edge.worldy() + edge2.worldy())/2f);
}
}
}
@@ -46,7 +47,9 @@ public class StorageBlock extends Block{
@Override
public void handleItem(Building source, Item item){
if(linkedCore != null){
- incinerateEffect(this, source);
+ if(linkedCore.items.get(item) >= ((CoreBuild)linkedCore).storageCapacity){
+ incinerateEffect(this, source);
+ }
((CoreBuild)linkedCore).noEffect = true;
linkedCore.handleItem(source, item);
}else{
@@ -70,7 +73,7 @@ public class StorageBlock extends Block{
public void overwrote(Seq previous){
for(Building other : previous){
if(other.items != null){
- items.addAll(other.items);
+ items.add(other.items);
}
}
diff --git a/core/src/mindustry/world/blocks/units/Reconstructor.java b/core/src/mindustry/world/blocks/units/Reconstructor.java
index 5b5696bf4c..9374e0d801 100644
--- a/core/src/mindustry/world/blocks/units/Reconstructor.java
+++ b/core/src/mindustry/world/blocks/units/Reconstructor.java
@@ -63,7 +63,23 @@ public class Reconstructor extends UnitBlock{
public void setStats(){
super.setStats();
- stats.add(BlockStat.productionTime, constructTime / 60f, StatUnit.seconds);
+ stats.add(Stat.productionTime, constructTime / 60f, StatUnit.seconds);
+ stats.add(Stat.output, table -> {
+ table.row();
+ for(var upgrade : upgrades){
+ float size = 8*3;
+ if(upgrade[0].unlockedNow() && upgrade[1].unlockedNow()){
+ table.image(upgrade[0].icon(Cicon.small)).size(size).padRight(4).padLeft(10).scaling(Scaling.fit).right();
+ table.add(upgrade[0].localizedName).left();
+
+ table.add("[lightgray] -> ");
+
+ table.image(upgrade[1].icon(Cicon.small)).size(size).padRight(4).scaling(Scaling.fit);
+ table.add(upgrade[1].localizedName).left();
+ table.row();
+ }
+ }
+ });
}
@Override
@@ -90,7 +106,7 @@ public class Reconstructor extends UnitBlock{
return this.payload == null
&& relativeTo(source) != rotation
&& payload instanceof UnitPayload
- && hasUpgrade(((UnitPayload)payload).unit.type());
+ && hasUpgrade(((UnitPayload)payload).unit.type);
}
@Override
@@ -114,9 +130,9 @@ public class Reconstructor extends UnitBlock{
if(constructing() && hasArrived()){
Draw.draw(Layer.blockOver, () -> {
Draw.alpha(1f - progress/ constructTime);
- Draw.rect(payload.unit.type().icon(Cicon.full), x, y, rotdeg() - 90);
+ Draw.rect(payload.unit.type.icon(Cicon.full), x, y, rotdeg() - 90);
Draw.reset();
- Drawf.construct(this, upgrade(payload.unit.type()), rotdeg() - 90f, progress / constructTime, speedScl, time);
+ Drawf.construct(this, upgrade(payload.unit.type), rotdeg() - 90f, progress / constructTime, speedScl, time);
});
}else{
Draw.z(Layer.blockOver);
@@ -135,7 +151,7 @@ public class Reconstructor extends UnitBlock{
if(payload != null){
//check if offloading
- if(!hasUpgrade(payload.unit.type())){
+ if(!hasUpgrade(payload.unit.type)){
moveOutPayload();
}else{ //update progress
if(moveInPayload()){
@@ -146,7 +162,7 @@ public class Reconstructor extends UnitBlock{
//upgrade the unit
if(progress >= constructTime){
- payload.unit = upgrade(payload.unit.type()).create(payload.unit.team());
+ payload.unit = upgrade(payload.unit.type).create(payload.unit.team());
progress = 0;
Effect.shake(2f, 3f, this);
Fx.producesmoke.at(this);
@@ -168,12 +184,12 @@ public class Reconstructor extends UnitBlock{
public UnitType unit(){
if(payload == null) return null;
- UnitType t = upgrade(payload.unit.type());
+ UnitType t = upgrade(payload.unit.type);
return t != null && t.unlockedNow() ? t : null;
}
public boolean constructing(){
- return payload != null && hasUpgrade(payload.unit.type());
+ return payload != null && hasUpgrade(payload.unit.type);
}
public boolean hasUpgrade(UnitType type){
diff --git a/core/src/mindustry/world/blocks/units/RepairPoint.java b/core/src/mindustry/world/blocks/units/RepairPoint.java
index abcc4bf738..789f7a8901 100644
--- a/core/src/mindustry/world/blocks/units/RepairPoint.java
+++ b/core/src/mindustry/world/blocks/units/RepairPoint.java
@@ -42,7 +42,7 @@ public class RepairPoint extends Block{
@Override
public void setStats(){
super.setStats();
- stats.add(BlockStat.range, repairRadius / tilesize, StatUnit.blocks);
+ stats.add(Stat.range, repairRadius / tilesize, StatUnit.blocks);
}
@Override
diff --git a/core/src/mindustry/world/blocks/units/ResupplyPoint.java b/core/src/mindustry/world/blocks/units/ResupplyPoint.java
index 2714be2358..6402b20147 100644
--- a/core/src/mindustry/world/blocks/units/ResupplyPoint.java
+++ b/core/src/mindustry/world/blocks/units/ResupplyPoint.java
@@ -65,10 +65,10 @@ public class ResupplyPoint extends Block{
public static boolean resupply(Team team, float x, float y, float range, float ammoAmount, Color ammoColor, Boolf valid){
if(!state.rules.unitAmmo) return false;
- Unit unit = Units.closest(team, x, y, range, u -> u.type().ammoType instanceof ItemAmmoType && u.ammo <= u.type().ammoCapacity - ammoAmount && valid.get(u));
+ Unit unit = Units.closest(team, x, y, range, u -> u.type.ammoType instanceof ItemAmmoType && u.ammo <= u.type.ammoCapacity - ammoAmount && valid.get(u));
if(unit != null){
Fx.itemTransfer.at(x, y, ammoAmount / 2f, ammoColor, unit);
- unit.ammo = Math.min(unit.ammo + ammoAmount, unit.type().ammoCapacity);
+ unit.ammo = Math.min(unit.ammo + ammoAmount, unit.type.ammoCapacity);
return true;
}
diff --git a/core/src/mindustry/world/blocks/units/UnitFactory.java b/core/src/mindustry/world/blocks/units/UnitFactory.java
index 74248f9932..500385966e 100644
--- a/core/src/mindustry/world/blocks/units/UnitFactory.java
+++ b/core/src/mindustry/world/blocks/units/UnitFactory.java
@@ -14,6 +14,7 @@ import mindustry.entities.*;
import mindustry.entities.units.*;
import mindustry.gen.*;
import mindustry.graphics.*;
+import mindustry.logic.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.blocks.*;
@@ -86,7 +87,7 @@ public class UnitFactory extends UnitBlock{
public void setStats(){
super.setStats();
- stats.remove(BlockStat.itemCapacity);
+ stats.remove(Stat.itemCapacity);
}
@Override
@@ -122,6 +123,12 @@ public class UnitFactory extends UnitBlock{
return currentPlan == -1 ? 0 : progress / plans.get(currentPlan).time;
}
+ @Override
+ public Object senseObject(LAccess sensor){
+ if(sensor == LAccess.config) return currentPlan == -1 ? null : plans.get(currentPlan).unit;
+ return super.senseObject(sensor);
+ }
+
@Override
public void buildConfiguration(Table table){
Seq units = Seq.with(plans).map(u -> u.unit).filter(u -> u.unlockedNow());
diff --git a/core/src/mindustry/world/consumers/Consume.java b/core/src/mindustry/world/consumers/Consume.java
index 410d041a03..3066dbb9bb 100644
--- a/core/src/mindustry/world/consumers/Consume.java
+++ b/core/src/mindustry/world/consumers/Consume.java
@@ -69,5 +69,5 @@ public abstract class Consume{
public abstract boolean valid(Building entity);
- public abstract void display(BlockStats stats);
+ public abstract void display(Stats stats);
}
diff --git a/core/src/mindustry/world/consumers/ConsumeItemDynamic.java b/core/src/mindustry/world/consumers/ConsumeItemDynamic.java
index a2dd079c20..0c18e77741 100644
--- a/core/src/mindustry/world/consumers/ConsumeItemDynamic.java
+++ b/core/src/mindustry/world/consumers/ConsumeItemDynamic.java
@@ -73,7 +73,7 @@ public class ConsumeItemDynamic extends Consume{
}
@Override
- public void display(BlockStats stats){
+ public void display(Stats stats){
//should be handled by the block
}
}
diff --git a/core/src/mindustry/world/consumers/ConsumeItemFilter.java b/core/src/mindustry/world/consumers/ConsumeItemFilter.java
index e9e98041c4..93d70a46f3 100644
--- a/core/src/mindustry/world/consumers/ConsumeItemFilter.java
+++ b/core/src/mindustry/world/consumers/ConsumeItemFilter.java
@@ -70,7 +70,7 @@ public class ConsumeItemFilter extends Consume{
}
@Override
- public void display(BlockStats stats){
- stats.add(booster ? BlockStat.booster : BlockStat.input, new ItemFilterValue(filter));
+ public void display(Stats stats){
+ stats.add(booster ? Stat.booster : Stat.input, new ItemFilterValue(filter));
}
}
diff --git a/core/src/mindustry/world/consumers/ConsumeItems.java b/core/src/mindustry/world/consumers/ConsumeItems.java
index 01909e2a14..f43746db87 100644
--- a/core/src/mindustry/world/consumers/ConsumeItems.java
+++ b/core/src/mindustry/world/consumers/ConsumeItems.java
@@ -63,7 +63,7 @@ public class ConsumeItems extends Consume{
}
@Override
- public void display(BlockStats stats){
- stats.add(booster ? BlockStat.booster : BlockStat.input, new ItemListValue(items));
+ public void display(Stats stats){
+ stats.add(booster ? Stat.booster : Stat.input, new ItemListValue(items));
}
}
diff --git a/core/src/mindustry/world/consumers/ConsumeLiquid.java b/core/src/mindustry/world/consumers/ConsumeLiquid.java
index 90f3bf0687..839b59c607 100644
--- a/core/src/mindustry/world/consumers/ConsumeLiquid.java
+++ b/core/src/mindustry/world/consumers/ConsumeLiquid.java
@@ -45,7 +45,7 @@ public class ConsumeLiquid extends ConsumeLiquidBase{
}
@Override
- public void display(BlockStats stats){
- stats.add(booster ? BlockStat.booster : BlockStat.input, liquid, amount * timePeriod, timePeriod == 60);
+ public void display(Stats stats){
+ stats.add(booster ? Stat.booster : Stat.input, liquid, amount * timePeriod, timePeriod == 60);
}
}
diff --git a/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java b/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java
index 962023488b..851cf75fd2 100644
--- a/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java
+++ b/core/src/mindustry/world/consumers/ConsumeLiquidFilter.java
@@ -49,7 +49,7 @@ public class ConsumeLiquidFilter extends ConsumeLiquidBase{
}
@Override
- public void display(BlockStats stats){
- stats.add(booster ? BlockStat.booster : BlockStat.input, new LiquidFilterValue(filter, amount * timePeriod, timePeriod == 60f));
+ public void display(Stats stats){
+ stats.add(booster ? Stat.booster : Stat.input, new LiquidFilterValue(filter, amount * timePeriod, timePeriod == 60f));
}
}
diff --git a/core/src/mindustry/world/consumers/ConsumePower.java b/core/src/mindustry/world/consumers/ConsumePower.java
index 2dc55dbb11..67b23d6c4c 100644
--- a/core/src/mindustry/world/consumers/ConsumePower.java
+++ b/core/src/mindustry/world/consumers/ConsumePower.java
@@ -54,11 +54,11 @@ public class ConsumePower extends Consume{
}
@Override
- public void display(BlockStats stats){
+ public void display(Stats stats){
if(buffered){
- stats.add(BlockStat.powerCapacity, capacity, StatUnit.none);
+ stats.add(Stat.powerCapacity, capacity, StatUnit.none);
}else{
- stats.add(BlockStat.powerUse, usage * 60f, StatUnit.powerSecond);
+ stats.add(Stat.powerUse, usage * 60f, StatUnit.powerSecond);
}
}
diff --git a/core/src/mindustry/world/consumers/Consumers.java b/core/src/mindustry/world/consumers/Consumers.java
index 4ce410aa04..a811a24d52 100644
--- a/core/src/mindustry/world/consumers/Consumers.java
+++ b/core/src/mindustry/world/consumers/Consumers.java
@@ -109,7 +109,7 @@ public class Consumers{
return optionalResults;
}
- public void display(BlockStats stats){
+ public void display(Stats stats){
for(Consume c : map){
if(c != null){
c.display(stats);
diff --git a/core/src/mindustry/world/meta/BlockFlag.java b/core/src/mindustry/world/meta/BlockFlag.java
index 5c9bf2e920..ca4ded3db3 100644
--- a/core/src/mindustry/world/meta/BlockFlag.java
+++ b/core/src/mindustry/world/meta/BlockFlag.java
@@ -4,18 +4,24 @@ package mindustry.world.meta;
public enum BlockFlag{
/** Enemy core; primary target for all units. */
core,
- /** Producer of important goods. */
- producer,
- /** A turret. */
+ /** Vault/container/etc */
+ storage,
+ /** Something that generates power. */
+ generator,
+ /** Any turret. */
turret,
+ /** A block that transforms resources. */
+ factory,
/** Repair point. */
repair,
/** Rally point. */
rally,
/** Block that stored power for resupply. */
- powerRes,
+ battery,
/** Block used for resupply. */
resupply,
+ /** Any reactor block. */
+ reactor,
/** Any block that boosts unit capacity. */
unitModifier;
diff --git a/core/src/mindustry/world/meta/BlockStat.java b/core/src/mindustry/world/meta/BlockStat.java
deleted file mode 100644
index 05e45acbfe..0000000000
--- a/core/src/mindustry/world/meta/BlockStat.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package mindustry.world.meta;
-
-import arc.*;
-
-import java.util.*;
-
-/** Describes one type of stat for a block. */
-public enum BlockStat{
- health(StatCategory.general),
- size(StatCategory.general),
- displaySize(StatCategory.general),
- buildTime(StatCategory.general),
- buildCost(StatCategory.general),
- memoryCapacity(StatCategory.general),
-
- itemCapacity(StatCategory.items),
- itemsMoved(StatCategory.items),
- launchTime(StatCategory.items),
- maxConsecutive(StatCategory.items),
-
- liquidCapacity(StatCategory.liquids),
-
- powerCapacity(StatCategory.power),
- powerUse(StatCategory.power),
- powerDamage(StatCategory.power),
- powerRange(StatCategory.power),
- powerConnections(StatCategory.power),
- basePowerGeneration(StatCategory.power),
-
- tiles(StatCategory.crafting),
- input(StatCategory.crafting),
- output(StatCategory.crafting),
- productionTime(StatCategory.crafting),
- drillTier(StatCategory.crafting),
- drillSpeed(StatCategory.crafting),
- maxUnits(StatCategory.crafting),
- linkRange(StatCategory.crafting),
- instructions(StatCategory.crafting),
-
- speedIncrease(StatCategory.shooting),
- repairTime(StatCategory.shooting),
- range(StatCategory.shooting),
- shootRange(StatCategory.shooting),
- inaccuracy(StatCategory.shooting),
- shots(StatCategory.shooting),
- reload(StatCategory.shooting),
- powerShot(StatCategory.shooting),
- targetsAir(StatCategory.shooting),
- targetsGround(StatCategory.shooting),
- damage(StatCategory.shooting),
- ammo(StatCategory.shooting),
- shieldHealth(StatCategory.shooting),
- cooldownTime(StatCategory.shooting),
-
- booster(StatCategory.optional),
- boostEffect(StatCategory.optional),
- affinities(StatCategory.optional);
-
- public final StatCategory category;
-
- BlockStat(StatCategory category){
- this.category = category;
- }
-
- public String localized(){
- return Core.bundle.get("blocks." + name().toLowerCase(Locale.ROOT));
- }
-}
diff --git a/core/src/mindustry/world/meta/Stat.java b/core/src/mindustry/world/meta/Stat.java
new file mode 100644
index 0000000000..2a8d88a7d1
--- /dev/null
+++ b/core/src/mindustry/world/meta/Stat.java
@@ -0,0 +1,88 @@
+package mindustry.world.meta;
+
+import arc.*;
+
+import java.util.*;
+
+/** Describes one type of stat for content. */
+public enum Stat{
+ health,
+ size,
+ displaySize,
+ buildTime,
+ buildCost,
+ memoryCapacity,
+ explosiveness,
+ flammability,
+ radioactivity,
+ heatCapacity,
+ viscosity,
+ temperature,
+ speed,
+ buildSpeed,
+ mineSpeed,
+ mineTier,
+ payloadCapacity,
+ commandLimit,
+ baseDeflectChance,
+ lightningChance,
+ lightningDamage,
+ abilities,
+
+ itemCapacity(StatCat.items),
+ itemsMoved(StatCat.items),
+ launchTime(StatCat.items),
+ maxConsecutive(StatCat.items),
+
+ liquidCapacity(StatCat.liquids),
+
+ powerCapacity(StatCat.power),
+ powerUse(StatCat.power),
+ powerDamage(StatCat.power),
+ powerRange(StatCat.power),
+ powerConnections(StatCat.power),
+ basePowerGeneration(StatCat.power),
+
+ tiles(StatCat.crafting),
+ input(StatCat.crafting),
+ output(StatCat.crafting),
+ productionTime(StatCat.crafting),
+ drillTier(StatCat.crafting),
+ drillSpeed(StatCat.crafting),
+ maxUnits(StatCat.crafting),
+ linkRange(StatCat.crafting),
+ instructions(StatCat.crafting),
+
+ speedIncrease(StatCat.shooting),
+ repairTime(StatCat.shooting),
+ range(StatCat.shooting),
+ shootRange(StatCat.shooting),
+ inaccuracy(StatCat.shooting),
+ shots(StatCat.shooting),
+ reload(StatCat.shooting),
+ powerShot(StatCat.shooting),
+ targetsAir(StatCat.shooting),
+ targetsGround(StatCat.shooting),
+ damage(StatCat.shooting),
+ ammo(StatCat.shooting),
+ shieldHealth(StatCat.shooting),
+ cooldownTime(StatCat.shooting),
+
+ booster(StatCat.optional),
+ boostEffect(StatCat.optional),
+ affinities(StatCat.optional);
+
+ public final StatCat category;
+
+ Stat(StatCat category){
+ this.category = category;
+ }
+
+ Stat(){
+ this.category = StatCat.general;
+ }
+
+ public String localized(){
+ return Core.bundle.get("stat." + name().toLowerCase(Locale.ROOT));
+ }
+}
diff --git a/core/src/mindustry/world/meta/StatCategory.java b/core/src/mindustry/world/meta/StatCat.java
similarity index 91%
rename from core/src/mindustry/world/meta/StatCategory.java
rename to core/src/mindustry/world/meta/StatCat.java
index e6c91b04bb..8dfd42d3c5 100644
--- a/core/src/mindustry/world/meta/StatCategory.java
+++ b/core/src/mindustry/world/meta/StatCat.java
@@ -3,7 +3,7 @@ package mindustry.world.meta;
import arc.*;
/** A specific category for a stat. */
-public enum StatCategory{
+public enum StatCat{
general,
power,
liquids,
diff --git a/core/src/mindustry/world/meta/StatUnit.java b/core/src/mindustry/world/meta/StatUnit.java
index 42825f0379..b2a866be3e 100644
--- a/core/src/mindustry/world/meta/StatUnit.java
+++ b/core/src/mindustry/world/meta/StatUnit.java
@@ -9,6 +9,7 @@ import java.util.*;
*/
public enum StatUnit{
blocks,
+ blocksSquared,
powerSecond,
liquidSecond,
itemsSecond,
diff --git a/core/src/mindustry/world/meta/BlockStats.java b/core/src/mindustry/world/meta/Stats.java
similarity index 55%
rename from core/src/mindustry/world/meta/BlockStats.java
rename to core/src/mindustry/world/meta/Stats.java
index ff93a217a9..68f96ff260 100644
--- a/core/src/mindustry/world/meta/BlockStats.java
+++ b/core/src/mindustry/world/meta/Stats.java
@@ -2,54 +2,71 @@ package mindustry.world.meta;
import arc.struct.ObjectMap.*;
import arc.struct.*;
+import arc.util.*;
import mindustry.*;
import mindustry.type.*;
import mindustry.world.*;
import mindustry.world.meta.values.*;
/** Hold and organizes a list of block stats. */
-public class BlockStats{
- private final OrderedMap>> map = new OrderedMap<>();
+public class Stats{
+ /** Whether to display stats with categories. If false, categories are completely ignored during display. */
+ public boolean useCategories = false;
+ /** Whether these stats are initialized yet. */
+ public boolean intialized = false;
+
+ @Nullable
+ private OrderedMap>> map;
private boolean dirty;
/** Adds a single float value with this stat, formatted to 2 decimal places. */
- public void add(BlockStat stat, float value, StatUnit unit){
+ public void add(Stat stat, float value, StatUnit unit){
add(stat, new NumberValue(value, unit));
}
+ /** Adds a single float value with this stat and no unit. */
+ public void add(Stat stat, float value){
+ add(stat, value, StatUnit.none);
+ }
+
+ /** Adds an integer percent stat value. Value is assumed to be in the 0-1 range. */
+ public void addPercent(Stat stat, float value){
+ add(stat, new NumberValue((int)(value * 100), StatUnit.percent));
+ }
+
/** Adds a single y/n boolean value. */
- public void add(BlockStat stat, boolean value){
+ public void add(Stat stat, boolean value){
add(stat, new BooleanValue(value));
}
/** Adds an item value. */
- public void add(BlockStat stat, Item item){
+ public void add(Stat stat, Item item){
add(stat, new ItemListValue(new ItemStack(item, 1)));
}
/** Adds an item value. */
- public void add(BlockStat stat, ItemStack item){
+ public void add(Stat stat, ItemStack item){
add(stat, new ItemListValue(item));
}
/** Adds an item value. */
- public void add(BlockStat stat, Liquid liquid, float amount, boolean perSecond){
+ public void add(Stat stat, Liquid liquid, float amount, boolean perSecond){
add(stat, new LiquidValue(liquid, amount, perSecond));
}
- public void add(BlockStat stat, Attribute attr){
+ public void add(Stat stat, Attribute attr){
add(stat, attr, false, 1f);
}
- public void add(BlockStat stat, Attribute attr, float scale){
+ public void add(Stat stat, Attribute attr, float scale){
add(stat, attr, false, scale);
}
- public void add(BlockStat stat, Attribute attr, boolean floating){
+ public void add(Stat stat, Attribute attr, boolean floating){
add(stat, attr, floating, 1f);
}
- public void add(BlockStat stat, Attribute attr, boolean floating, float scale){
+ public void add(Stat stat, Attribute attr, boolean floating, float scale){
for(Block block : Vars.content.blocks()){
if(!block.isFloor() || block.asFloor().attributes.get(attr) == 0 || (block.asFloor().isLiquid && !floating)) continue;
add(stat, new FloorEfficiencyValue(block.asFloor(), block.asFloor().attributes.get(attr) * scale));
@@ -57,12 +74,14 @@ public class BlockStats{
}
/** Adds a single string value with this stat. */
- public void add(BlockStat stat, String format, Object... args){
+ public void add(Stat stat, String format, Object... args){
add(stat, new StringValue(format, args));
}
/** Adds a stat value. */
- public void add(BlockStat stat, StatValue value){
+ public void add(Stat stat, StatValue value){
+ if(map == null) map = new OrderedMap<>();
+
if(!map.containsKey(stat.category)){
map.put(stat.category, new OrderedMap<>());
}
@@ -73,7 +92,9 @@ public class BlockStats{
}
/** Removes a stat, if it exists. */
- public void remove(BlockStat stat){
+ public void remove(Stat stat){
+ if(map == null) map = new OrderedMap<>();
+
if(!map.containsKey(stat.category) || !map.get(stat.category).containsKey(stat)){
throw new RuntimeException("No stat entry found: \"" + stat + "\" in block.");
}
@@ -83,11 +104,13 @@ public class BlockStats{
dirty = true;
}
- public OrderedMap>> toMap(){
+ public OrderedMap>> toMap(){
+ if(map == null) map = new OrderedMap<>();
+
//sort stats by index if they've been modified
if(dirty){
map.orderedKeys().sort();
- for(Entry>> entry : map.entries()){
+ for(Entry>> entry : map.entries()){
entry.value.orderedKeys().sort();
}
diff --git a/core/src/mindustry/world/meta/values/BlockFilterValue.java b/core/src/mindustry/world/meta/values/BlockFilterValue.java
new file mode 100644
index 0000000000..3c4d0fe56e
--- /dev/null
+++ b/core/src/mindustry/world/meta/values/BlockFilterValue.java
@@ -0,0 +1,37 @@
+package mindustry.world.meta.values;
+
+import arc.func.*;
+import arc.scene.ui.layout.*;
+import arc.struct.*;
+import mindustry.ui.*;
+import mindustry.world.*;
+import mindustry.world.meta.*;
+
+import static mindustry.Vars.*;
+
+public class BlockFilterValue implements StatValue{
+ public final Boolf pred;
+
+ public BlockFilterValue(Boolf pred){
+ this.pred = pred;
+ }
+
+ @Override
+ public void display(Table table){
+ Seq list = content.blocks().select(pred);
+
+ table.table(l -> {
+ l.left();
+
+ for(int i = 0; i < list.size; i++){
+ Block item = list.get(i);
+
+ l.image(item.icon(Cicon.small)).size(8 * 3).padRight(2).padLeft(2).padTop(3).padBottom(3);
+ l.add(item.localizedName).left().padLeft(1).padRight(4);
+ if(i % 5 == 4){
+ l.row();
+ }
+ }
+ });
+ }
+}
diff --git a/core/src/mindustry/world/meta/values/BlockListValue.java b/core/src/mindustry/world/meta/values/BlockListValue.java
new file mode 100644
index 0000000000..a1cd5adffe
--- /dev/null
+++ b/core/src/mindustry/world/meta/values/BlockListValue.java
@@ -0,0 +1,33 @@
+package mindustry.world.meta.values;
+
+import arc.scene.ui.layout.*;
+import arc.struct.*;
+import mindustry.ui.*;
+import mindustry.world.*;
+import mindustry.world.meta.*;
+
+public class BlockListValue implements StatValue{
+ public final Seq list;
+
+ public BlockListValue(Seq list){
+ this.list = list;
+ }
+
+ @Override
+ public void display(Table table){
+
+ table.table(l -> {
+ l.left();
+
+ for(int i = 0; i < list.size; i++){
+ Block item = list.get(i);
+
+ l.image(item.icon(Cicon.small)).size(8 * 3).padRight(2).padLeft(2).padTop(3).padBottom(3);
+ l.add(item.localizedName).left().padLeft(1).padRight(4);
+ if(i % 5 == 4){
+ l.row();
+ }
+ }
+ });
+ }
+}
diff --git a/core/src/mindustry/world/modules/ItemModule.java b/core/src/mindustry/world/modules/ItemModule.java
index 16d49484f0..6cd96985cb 100644
--- a/core/src/mindustry/world/modules/ItemModule.java
+++ b/core/src/mindustry/world/modules/ItemModule.java
@@ -243,6 +243,16 @@ public class ItemModule extends BlockModule{
}
}
+ public void add(ItemSeq stacks){
+ stacks.each(this::add);
+ }
+
+ public void add(ItemModule items){
+ for(int i = 0; i < items.items.length; i++){
+ add(i, items.items[i]);
+ }
+ }
+
public void add(Item item, int amount){
add(item.id, amount);
}
@@ -261,12 +271,6 @@ public class ItemModule extends BlockModule{
}
}
- public void addAll(ItemModule items){
- for(int i = 0; i < items.items.length; i++){
- add(i, items.items[i]);
- }
- }
-
public void remove(Item item, int amount){
amount = Math.min(amount, items[item.id]);
diff --git a/desktop/src/mindustry/desktop/DesktopLauncher.java b/desktop/src/mindustry/desktop/DesktopLauncher.java
index bd9ec3e81b..76b72e3ca3 100644
--- a/desktop/src/mindustry/desktop/DesktopLauncher.java
+++ b/desktop/src/mindustry/desktop/DesktopLauncher.java
@@ -227,7 +227,9 @@ public class DesktopLauncher extends ClientLauncher{
@Override
public void updateLobby(){
- SVars.net.updateLobby();
+ if(SVars.net != null){
+ SVars.net.updateLobby();
+ }
}
@Override
diff --git a/desktop/src/mindustry/desktop/steam/SStats.java b/desktop/src/mindustry/desktop/steam/SStats.java
index 7e7c9ecef3..9338aafc5b 100644
--- a/desktop/src/mindustry/desktop/steam/SStats.java
+++ b/desktop/src/mindustry/desktop/steam/SStats.java
@@ -7,7 +7,7 @@ import mindustry.*;
import mindustry.content.*;
import mindustry.entities.units.*;
import mindustry.game.EventType.*;
-import mindustry.game.Stats.*;
+import mindustry.game.GameStats.*;
import mindustry.gen.*;
import mindustry.type.*;
@@ -60,7 +60,7 @@ public class SStats implements SteamUserStatsCallback{
// active10Phantoms.complete();
//}
- if(Groups.unit.count(u -> u.type() == UnitTypes.crawler && u.team() == player.team()) >= 50){
+ if(Groups.unit.count(u -> u.type == UnitTypes.crawler && u.team() == player.team()) >= 50){
active50Crawlers.complete();
}
diff --git a/fastlane/metadata/android/en-US/changelogs/29672.txt b/fastlane/metadata/android/en-US/changelogs/29672.txt
new file mode 100644
index 0000000000..04c1a277ad
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/29672.txt
@@ -0,0 +1,6 @@
+- Fixed "host game" crash, as well as some other prominent bugs
+- Logic: Breaking change: All coordinates are now in tiles, not in "world units"
+- Logic: Added sensors for ammo (units/turrets)
+- Campaign: Added research button in mobile multiplayer (check pause menu)
+- Campaign: Added tech tree sharing in multiplayer - only the host can research
+- Campaign: Re-added sector invasions, any sector near an enemy base can be invaded
diff --git a/gradle.properties b/gradle.properties
index 5a37b2f0ab..f73761a7bf 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,3 +1,3 @@
org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m
-archash=dfcb9ab4b9f9bb977ed3cff4b8a16c22e076368a
+archash=f8ef0f3a72de0f79ca49da895fed0b6889cd597e
diff --git a/jitpack.yml b/jitpack.yml
new file mode 100644
index 0000000000..e1dfa83815
--- /dev/null
+++ b/jitpack.yml
@@ -0,0 +1,4 @@
+before_install:
+ - wget https://github.com/sormuras/bach/raw/master/install-jdk.sh
+ - source install-jdk.sh --feature 14
+ - jshell --version
\ No newline at end of file
diff --git a/server/src/mindustry/server/ServerControl.java b/server/src/mindustry/server/ServerControl.java
index 48f529b187..7e1be67c52 100644
--- a/server/src/mindustry/server/ServerControl.java
+++ b/server/src/mindustry/server/ServerControl.java
@@ -30,6 +30,7 @@ import java.time.*;
import java.time.format.*;
import java.util.*;
+import static arc.util.ColorCodes.*;
import static arc.util.Log.*;
import static mindustry.Vars.*;
@@ -37,7 +38,7 @@ public class ServerControl implements ApplicationListener{
private static final int roundExtraTime = 12;
private static final int maxLogLength = 1024 * 512;
- protected static String[] tags = {"&lc&fb[D]", "&lg&fb[I]", "&ly&fb[W]", "&lr&fb[E]", ""};
+ protected static String[] tags = {"&lc&fb[D]&fr", "&lb&fb[I]&fr", "&ly&fb[W]&fr", "&lr&fb[E]", ""};
protected static DateTimeFormatter dateTime = DateTimeFormatter.ofPattern("MM-dd-yyyy HH:mm:ss"),
autosaveDate = DateTimeFormatter.ofPattern("MM-dd-yyyy_HH-mm-ss");
@@ -74,22 +75,27 @@ public class ServerControl implements ApplicationListener{
lastMode = Gamemode.survival;
}
- Log.setLogger((level, text) -> {
- String result = "[" + dateTime.format(LocalDateTime.now()) + "] " + format(tags[level.ordinal()] + " " + text + "&fr");
+ logger = (level1, text) -> {
+ String result = bold + lightBlack + "[" + dateTime.format(LocalDateTime.now()) + "] " + reset + format(tags[level1.ordinal()] + " " + text + "&fr");
System.out.println(result);
if(Config.logging.bool()){
- logToFile("[" + dateTime.format(LocalDateTime.now()) + "] " + formatColors(tags[level.ordinal()] + " " + text + "&fr", false));
+ logToFile("[" + dateTime.format(LocalDateTime.now()) + "] " + formatColors(tags[level1.ordinal()] + " " + text + "&fr", false));
}
if(socketOutput != null){
try{
socketOutput.println(formatColors(text + "&fr", false));
- }catch(Throwable e){
- err("Error occurred logging to socket: @", e.getClass().getSimpleName());
+ }catch(Throwable e1){
+ err("Error occurred logging to socket: @", e1.getClass().getSimpleName());
}
}
- });
+ };
+
+ formatter = (text, useColors, arg) -> {
+ text = Strings.format(text.replace("@", "&fb&lb@&fr"), arg);
+ return useColors ? addColors(text) : removeColors(text);
+ };
Time.setDeltaProvider(() -> Core.graphics.getDeltaTime() * 60f);
@@ -115,12 +121,12 @@ public class ServerControl implements ApplicationListener{
if(args.length > 0){
commands.addAll(Strings.join(" ", args).split(","));
- info("&lmFound @ command-line arguments to parse.", commands.size);
+ info("Found @ command-line arguments to parse.", commands.size);
}
if(!Config.startCommands.string().isEmpty()){
String[] startup = Strings.join(" ", Config.startCommands.string()).split(",");
- info("&lmFound @ startup commands.", startup.length);
+ info("Found @ startup commands.", startup.length);
commands.addAll(startup);
}
@@ -128,7 +134,7 @@ public class ServerControl implements ApplicationListener{
CommandResponse response = handler.handleMessage(s);
if(response.type != ResponseType.valid){
err("Invalid command argument sent: '@': @", s, response.type.name());
- err("Argument usage: &lc , ");
+ err("Argument usage: &lb , ");
}
}
});
@@ -141,7 +147,7 @@ public class ServerControl implements ApplicationListener{
if(Version.build == -1){
warn("&lyYour server is running a custom build, which means that client checking is disabled.");
- warn("&lyIt is highly advised to specify which version you're using by building with gradle args &lc-Pbuildversion=&lm&ly.");
+ warn("&lyIt is highly advised to specify which version you're using by building with gradle args &lb&fb-Pbuildversion=&lr");
}
//set up default shuffle mode
@@ -154,9 +160,9 @@ public class ServerControl implements ApplicationListener{
Events.on(GameOverEvent.class, event -> {
if(inExtraRound) return;
if(state.rules.waves){
- info("&lcGame over! Reached wave &ly@&lc with &ly@&lc players online on map &ly@&lc.", state.wave, Groups.player.size(), Strings.capitalize(state.map.name()));
+ info("Game over! Reached wave @ with @ players online on map @.", state.wave, Groups.player.size(), Strings.capitalize(state.map.name()));
}else{
- info("&lcGame over! Team &ly@&lc is victorious with &ly@&lc players online on map &ly@&lc.", event.winner.name, Groups.player.size(), Strings.capitalize(state.map.name()));
+ info("Game over! Team @ is victorious with @ players online on map @.", event.winner.name, Groups.player.size(), Strings.capitalize(state.map.name()));
}
//set next map to be played
@@ -209,11 +215,11 @@ public class ServerControl implements ApplicationListener{
String fileName = "auto_" + mapName + "_" + date + "." + saveExtension;
Fi file = saveDirectory.child(fileName);
- info("&lbAutosaving...");
+ info("Autosaving...");
try{
SaveIO.save(file);
- info("&lbAutosave completed.");
+ info("Autosave completed.");
}catch(Throwable e){
err("Autosave failed.", e);
}
@@ -241,25 +247,25 @@ public class ServerControl implements ApplicationListener{
Timer.schedule(() -> Core.settings.forceSave(), saveInterval, saveInterval);
if(!mods.list().isEmpty()){
- info("&lc@ mods loaded.", mods.list().size);
+ info("@ mods loaded.", mods.list().size);
}
toggleSocket(Config.socketInput.bool());
- info("&lcServer loaded. Type &ly'help'&lc for help.");
+ info("Server loaded. Type @ for help.", "'help'");
}
private void registerCommands(){
handler.register("help", "Displays this command list.", arg -> {
info("Commands:");
for(Command command : handler.getCommandList()){
- info(" &y" + command.text + (command.paramText.isEmpty() ? "" : " ") + command.paramText + " - &lm" + command.description);
+ info(" &b&lb " + command.text + (command.paramText.isEmpty() ? "" : " &lc&fi") + command.paramText + "&fr - &lw" + command.description);
}
});
handler.register("version", "Displays server version info.", arg -> {
- info("&lmVersion: &lyMindustry @-@ @ / build @", Version.number, Version.modifier, Version.type, Version.build + (Version.revision == 0 ? "" : "." + Version.revision));
- info("&lmJava Version: &ly@", System.getProperty("java.version"));
+ info("Version: Mindustry @-@ @ / build @", Version.number, Version.modifier, Version.type, Version.build + (Version.revision == 0 ? "" : "." + Version.revision));
+ info("Java Version: @", System.getProperty("java.version"));
});
handler.register("exit", "Exit the server application.", arg -> {
@@ -299,7 +305,7 @@ public class ServerControl implements ApplicationListener{
result = maps.all().find(map -> map.name().equalsIgnoreCase(arg[0].replace('_', ' ')) || map.name().equalsIgnoreCase(arg[0]));
if(result == null){
- err("No map with name &y'@'&lr found.", arg[0]);
+ err("No map with name '@' found.", arg[0]);
return;
}
}else{
@@ -329,21 +335,21 @@ public class ServerControl implements ApplicationListener{
if(!maps.all().isEmpty()){
info("Maps:");
for(Map map : maps.all()){
- info(" &ly@: &lb&fi@ / @x@", map.name(), map.custom ? "Custom" : "Default", map.width, map.height);
+ info(" @: &fi@ / @x@", map.name(), map.custom ? "Custom" : "Default", map.width, map.height);
}
}else{
info("No maps found.");
}
- info("&lyMap directory: &lb&fi@", customMapDirectory.file().getAbsoluteFile().toString());
+ info("Map directory: &fi@", customMapDirectory.file().getAbsoluteFile().toString());
});
handler.register("reloadmaps", "Reload all maps from disk.", arg -> {
int beforeMaps = maps.all().size;
maps.reload();
if(maps.all().size > beforeMaps){
- info("&lc@&ly new map(s) found and reloaded.", maps.all().size - beforeMaps);
+ info("@ new map(s) found and reloaded.", maps.all().size - beforeMaps);
}else{
- info("&lyMaps reloaded.");
+ info("Maps reloaded.");
}
});
@@ -352,23 +358,23 @@ public class ServerControl implements ApplicationListener{
info("Status: &rserver closed");
}else{
info("Status:");
- info(" &lyPlaying on map &fi@&fb &lb/&ly Wave @", Strings.capitalize(state.map.name()), state.wave);
+ info(" Playing on map &fi@ / Wave @", Strings.capitalize(state.map.name()), state.wave);
if(state.rules.waves){
- info("&ly @ enemies.", state.enemies);
+ info(" @ enemies.", state.enemies);
}else{
- info("&ly @ seconds until next wave.", (int)(state.wavetime / 60));
+ info(" @ seconds until next wave.", (int)(state.wavetime / 60));
}
- info(" &ly@ FPS, @ MB used.", Core.graphics.getFramesPerSecond(), Core.app.getJavaHeap() / 1024 / 1024);
+ info(" @ FPS, @ MB used.", Core.graphics.getFramesPerSecond(), Core.app.getJavaHeap() / 1024 / 1024);
if(Groups.player.size() > 0){
- info(" &lyPlayers: @", Groups.player.size());
+ info(" Players: @", Groups.player.size());
for(Player p : Groups.player){
- info(" &y@ / @", p.name(), p.uuid());
+ info(" @ / @", p.name, p.uuid());
}
}else{
- info(" &lyNo players connected.");
+ info(" No players connected.");
}
}
});
@@ -377,30 +383,30 @@ public class ServerControl implements ApplicationListener{
if(!mods.list().isEmpty()){
info("Mods:");
for(LoadedMod mod : mods.list()){
- info(" &ly@ &lcv@", mod.meta.displayName(), mod.meta.version);
+ info(" @ &fi@", mod.meta.displayName(), mod.meta.version);
}
}else{
info("No mods found.");
}
- info("&lyMod directory: &lb&fi@", modDirectory.file().getAbsoluteFile().toString());
+ info("Mod directory: &fi@", modDirectory.file().getAbsoluteFile().toString());
});
handler.register("mod", "", "Display information about a loaded plugin.", arg -> {
LoadedMod mod = mods.list().find(p -> p.meta.name.equalsIgnoreCase(arg[0]));
if(mod != null){
- info("Name: &ly@", mod.meta.displayName());
- info("Internal Name: &ly@", mod.name);
- info("Version: &ly@", mod.meta.version);
- info("Author: &ly@", mod.meta.author);
- info("Path: &ly@", mod.file.path());
- info("Description: &ly@", mod.meta.description);
+ info("Name: @", mod.meta.displayName());
+ info("Internal Name: @", mod.name);
+ info("Version: @", mod.meta.version);
+ info("Author: @", mod.meta.author);
+ info("Path: @", mod.file.path());
+ info("Description: @", mod.meta.description);
}else{
- info("No mod with name &ly'@'&lg found.");
+ info("No mod with name '@' found.");
}
});
handler.register("js", "", "Run arbitrary Javascript.", arg -> {
- info("&lc" + mods.getScripts().runConsole(arg[0]));
+ info("&fi&lw&fb" + mods.getScripts().runConsole(arg[0]));
});
handler.register("say", "", "Send a message to all players.", arg -> {
@@ -411,7 +417,7 @@ public class ServerControl implements ApplicationListener{
Call.sendMessage("[scarlet][[Server]:[] " + arg[0]);
- info("&lyServer: &lb@", arg[0]);
+ info("&fi&lcServer: &fr@", "&lw" + arg[0]);
});
@@ -426,7 +432,7 @@ public class ServerControl implements ApplicationListener{
JsonValue base = JsonIO.json().fromJson(null, rules);
if(arg.length == 0){
- Log.info("&lyRules:\n@", JsonIO.print(rules));
+ Log.info("Rules:\n@", JsonIO.print(rules));
}else if(arg.length == 1){
Log.err("Invalid usage. Specify which rule to remove or add.");
}else{
@@ -438,7 +444,7 @@ public class ServerControl implements ApplicationListener{
boolean remove = arg[0].equals("remove");
if(remove){
if(base.has(arg[1])){
- Log.info("Rule &lc'@'&lg removed.", arg[1]);
+ Log.info("Rule '@' removed.", arg[1]);
base.remove(arg[1]);
}else{
Log.err("Rule not defined, so not removed.");
@@ -462,7 +468,7 @@ public class ServerControl implements ApplicationListener{
base.remove(value.name);
}
base.addChild(arg[1], value);
- Log.info("Changed rule: &ly@", value.toString().replace("\n", " "));
+ Log.info("Changed rule: @", value.toString().replace("\n", " "));
}catch(Throwable e){
Log.err("Error parsing rule JSON: @", e.getMessage());
}
@@ -501,7 +507,7 @@ public class ServerControl implements ApplicationListener{
handler.register("playerlimit", "[off/somenumber]", "Set the server player limit.", arg -> {
if(arg.length == 0){
- info("Player limit is currently &lc@.", netServer.admins.getPlayerLimit() == 0 ? "off" : netServer.admins.getPlayerLimit());
+ info("Player limit is currently @.", netServer.admins.getPlayerLimit() == 0 ? "off" : netServer.admins.getPlayerLimit());
return;
}
if(arg[0].equals("off")){
@@ -521,11 +527,11 @@ public class ServerControl implements ApplicationListener{
handler.register("config", "[name] [value...]", "Configure server settings.", arg -> {
if(arg.length == 0){
- info("&lyAll config values:");
+ info("All config values:");
for(Config c : Config.all){
- Log.info("&ly| &lc@:&lm @", c.name(), c.get());
- Log.info("&ly| | @", c.description);
- Log.info("&ly|");
+ Log.info("&lk| @: @", c.name(), "&lc&fi" + c.get());
+ Log.info("&lk| | &lw" + c.description);
+ Log.info("&lk|");
}
return;
}
@@ -533,7 +539,7 @@ public class ServerControl implements ApplicationListener{
try{
Config c = Config.valueOf(arg[0]);
if(arg.length == 1){
- Log.info("&lc'@'&lg is currently &lc@.", c.name(), c.get());
+ Log.info("'@' is currently @.", c.name(), c.get());
}else{
if(c.isBool()){
c.set(arg[1].equals("on") || arg[1].equals("true"));
@@ -548,7 +554,7 @@ public class ServerControl implements ApplicationListener{
c.set(arg[1]);
}
- Log.info("&lc@&lg set to &lc@.", c.name(), c.get());
+ Log.info("@ set to @.", c.name(), c.get());
Core.settings.forceSave();
}
}catch(IllegalArgumentException e){
@@ -558,9 +564,9 @@ public class ServerControl implements ApplicationListener{
handler.register("subnet-ban", "[add/remove] [address]", "Ban a subnet. This simply rejects all connections with IPs starting with some string.", arg -> {
if(arg.length == 0){
- Log.info("Subnets banned: &lc@", netServer.admins.getSubnetBans().isEmpty() ? "" : "");
+ Log.info("Subnets banned: @", netServer.admins.getSubnetBans().isEmpty() ? "" : "");
for(String subnet : netServer.admins.getSubnetBans()){
- Log.info("&ly " + subnet + "");
+ Log.info("&lw " + subnet + "");
}
}else if(arg.length == 1){
err("You must provide a subnet to add or remove.");
@@ -572,7 +578,7 @@ public class ServerControl implements ApplicationListener{
}
netServer.admins.addSubnetBan(arg[1]);
- Log.info("Banned &ly@&lc**", arg[1]);
+ Log.info("Banned @**", arg[1]);
}else if(arg[0].equals("remove")){
if(!netServer.admins.getSubnetBans().contains(arg[1])){
err("That subnet isn't banned.");
@@ -580,7 +586,7 @@ public class ServerControl implements ApplicationListener{
}
netServer.admins.removeSubnetBan(arg[1]);
- Log.info("Unbanned &ly@&lc**", arg[1]);
+ Log.info("Unbanned @**", arg[1]);
}else{
err("Incorrect usage. You must provide add/remove as the second argument.");
}
@@ -589,12 +595,12 @@ public class ServerControl implements ApplicationListener{
handler.register("whitelisted", "List the entire whitelist.", arg -> {
if(netServer.admins.getWhitelisted().isEmpty()){
- info("&lyNo whitelisted players found.");
+ info("No whitelisted players found.");
return;
}
- info("&lyWhitelist:");
- netServer.admins.getWhitelisted().each(p -> Log.info("- &ly@", p.lastName));
+ info("Whitelist:");
+ netServer.admins.getWhitelisted().each(p -> info("- @", p.lastName));
});
handler.register("whitelist-add", "", "Add a player to the whitelist by ID.", arg -> {
@@ -605,7 +611,7 @@ public class ServerControl implements ApplicationListener{
}
netServer.admins.whitelist(arg[0]);
- info("Player &ly'@'&lg has been whitelisted.", info.lastName);
+ info("Player '@' has been whitelisted.", info.lastName);
});
handler.register("whitelist-remove", "", "Remove a player to the whitelist by ID.", arg -> {
@@ -616,18 +622,18 @@ public class ServerControl implements ApplicationListener{
}
netServer.admins.unwhitelist(arg[0]);
- info("Player &ly'@'&lg has been un-whitelisted.", info.lastName);
+ info("Player '@' has been un-whitelisted.", info.lastName);
});
handler.register("shuffle", "[none/all/custom/builtin]", "Set map shuffling mode.", arg -> {
if(arg.length == 0){
- info("Shuffle mode current set to &ly'@'&lg.", maps.getShuffleMode());
+ info("Shuffle mode current set to '@'.", maps.getShuffleMode());
}else{
try{
ShuffleMode mode = ShuffleMode.valueOf(arg[0]);
Core.settings.put("shufflemode", mode.name());
maps.setShuffleMode(mode);
- info("Shuffle mode set to &ly'@'&lg.", arg[0]);
+ info("Shuffle mode set to '@'.", arg[0]);
}catch(Exception e){
err("Invalid shuffle mode.");
}
@@ -638,7 +644,7 @@ public class ServerControl implements ApplicationListener{
Map res = maps.all().find(map -> map.name().equalsIgnoreCase(arg[0].replace('_', ' ')) || map.name().equalsIgnoreCase(arg[0]));
if(res != null){
nextMapOverride = res;
- Log.info("Next map set to &ly'@'.", res.name());
+ Log.info("Next map set to '@'.", res.name());
}else{
Log.err("No map '@' found.", arg[0]);
}
@@ -694,9 +700,9 @@ public class ServerControl implements ApplicationListener{
if(bans.size == 0){
info("No ID-banned players have been found.");
}else{
- info("&lyBanned players [ID]:");
+ info("Banned players [ID]:");
for(PlayerInfo info : bans){
- info(" &ly @ / Last known name: '@'", info.id, info.lastName);
+ info(" @ / Last known name: '@'", info.id, info.lastName);
}
}
@@ -705,13 +711,13 @@ public class ServerControl implements ApplicationListener{
if(ipbans.size == 0){
info("No IP-banned players have been found.");
}else{
- info("&lmBanned players [IP]:");
+ info("Banned players [IP]:");
for(String string : ipbans){
PlayerInfo info = netServer.admins.findByIP(string);
if(info != null){
- info(" &lm '@' / Last known name: '@' / ID: '@'", string, info.lastName, info.id);
+ info(" '@' / Last known name: '@' / ID: '@'", string, info.lastName, info.id);
}else{
- info(" &lm '@' (No known name or info)", string);
+ info(" '@' (No known name or info)", string);
}
}
}
@@ -765,7 +771,7 @@ public class ServerControl implements ApplicationListener{
netServer.admins.unAdminPlayer(target.id);
}
if(playert != null) playert.admin = add;
- info("Changed admin status of player: &ly@", target.lastName);
+ info("Changed admin status of player: @", target.lastName);
}else{
err("Nobody with that name or ID could be found. If adding an admin by name, make sure they're online; otherwise, use their UUID.");
}
@@ -777,7 +783,7 @@ public class ServerControl implements ApplicationListener{
if(admins.size == 0){
info("No admins have been found.");
}else{
- info("&lyAdmins:");
+ info("Admins:");
for(PlayerInfo info : admins){
info(" &lm @ / ID: '@' / IP: '@'", info.lastName, info.id, info.lastIP);
}
@@ -788,10 +794,10 @@ public class ServerControl implements ApplicationListener{
if(Groups.player.size() == 0){
info("No players are currently in the server.");
}else{
- info("&lyPlayers: @", Groups.player.size());
+ info("Players: @", Groups.player.size());
for(Player user : Groups.player){
PlayerInfo userInfo = user.getInfo();
- info(" &lm @ / ID: '@' / IP: '@' / Admin: '@'", userInfo.lastName, userInfo.id, userInfo.lastIP, userInfo.admin);
+ info(" &lm @ / ID: @ / IP: @ / Admin: @", userInfo.lastName, userInfo.id, userInfo.lastIP, userInfo.admin);
}
}
});
@@ -849,7 +855,7 @@ public class ServerControl implements ApplicationListener{
info("Save files: ");
for(Fi file : saveDirectory.list()){
if(file.extension().equals(saveExtension)){
- info("| &ly@", file.nameWithoutExtension());
+ info("| @", file.nameWithoutExtension());
}
}
});
@@ -860,7 +866,7 @@ public class ServerControl implements ApplicationListener{
return;
}
- info("&lyCore destroyed.");
+ info("Core destroyed.");
inExtraRound = false;
Events.fire(new GameOverEvent(Team.crux));
});
@@ -870,16 +876,16 @@ public class ServerControl implements ApplicationListener{
ObjectSet infos = netServer.admins.findByName(arg[0]);
if(infos.size > 0){
- info("&lgPlayers found: @", infos.size);
+ info("Players found: @", infos.size);
int i = 0;
for(PlayerInfo info : infos){
- info("&lc[@] Trace info for player '@' / UUID @", i++, info.lastName, info.id);
- info(" &lyall names used: @", info.names);
- info(" &lyIP: @", info.lastIP);
- info(" &lyall IPs used: @", info.ips);
- info(" &lytimes joined: @", info.timesJoined);
- info(" &lytimes kicked: @", info.timesKicked);
+ info("[@] Trace info for player '@' / UUID @", i++, info.lastName, info.id);
+ info(" all names used: @", info.names);
+ info(" IP: @", info.lastIP);
+ info(" all IPs used: @", info.ips);
+ info(" times joined: @", info.timesJoined);
+ info(" times kicked: @", info.timesKicked);
}
}else{
info("Nobody with that name could be found.");
@@ -891,11 +897,11 @@ public class ServerControl implements ApplicationListener{
ObjectSet infos = netServer.admins.searchNames(arg[0]);
if(infos.size > 0){
- info("&lgPlayers found: @", infos.size);
+ info("Players found: @", infos.size);
int i = 0;
for(PlayerInfo info : infos){
- info("- &lc[@] &ly'@'&lc / &lm@", i++, info.lastName, info.id);
+ info("- [@] '@' / @", i++, info.lastName, info.id);
}
}else{
info("Nobody with that name could be found.");
@@ -906,10 +912,10 @@ public class ServerControl implements ApplicationListener{
int pre = (int)(Core.app.getJavaHeap() / 1024 / 1024);
System.gc();
int post = (int)(Core.app.getJavaHeap() / 1024 / 1024);
- info("&ly@&lg MB collected. Memory usage now at &ly@&lg MB.", pre - post, post);
+ info("@ MB collected. Memory usage now at @ MB.", pre - post, post);
});
- handler.register("yes", "Run the above \"did you mean\" suggestion.", arg -> {
+ handler.register("yes", "Run the last suggested incorrect command.", arg -> {
if(yes == null){
err("There is nothing to say yes to.");
}else{
@@ -1036,7 +1042,7 @@ public class ServerControl implements ApplicationListener{
serverSocket.bind(new InetSocketAddress(Config.socketInputAddress.string(), Config.socketInputPort.num()));
while(true){
Socket client = serverSocket.accept();
- info("&lmReceived command socket connection: &lb@", serverSocket.getLocalSocketAddress());
+ info("&lkReceived command socket connection: &fi@", serverSocket.getLocalSocketAddress());
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
socketOutput = new PrintWriter(client.getOutputStream(), true);
String line;
@@ -1044,7 +1050,7 @@ public class ServerControl implements ApplicationListener{
String result = line;
Core.app.post(() -> handleCommandString(result));
}
- info("&lmLost command socket connection: &lb@", serverSocket.getLocalSocketAddress());
+ info("&lkLost command socket connection: &fi@", serverSocket.getLocalSocketAddress());
socketOutput = null;
}
}catch(BindException b){
diff --git a/server/src/mindustry/server/ServerLauncher.java b/server/src/mindustry/server/ServerLauncher.java
index 4c8a2bb8e6..ad274954ea 100644
--- a/server/src/mindustry/server/ServerLauncher.java
+++ b/server/src/mindustry/server/ServerLauncher.java
@@ -29,10 +29,10 @@ public class ServerLauncher implements ApplicationListener{
Vars.platform = new Platform(){};
Vars.net = new Net(platform.getNet());
- Log.setLogger((level, text) -> {
- String result = "[" + dateTime.format(LocalDateTime.now()) + "] " + format(tags[level.ordinal()] + " " + text + "&fr");
- System.out.println(result);
- });
+ logger = (level1, text) -> {
+ String result = "[" + dateTime.format(LocalDateTime.now()) + "] " + format(tags[level1.ordinal()] + " " + text + "&fr");
+ System.out.println(result);
+ };
new HeadlessApplication(new ServerLauncher(), null, throwable -> CrashSender.send(throwable, f -> {}));
}catch(Throwable t){
CrashSender.send(t, f -> {});
diff --git a/servers_be.json b/servers_be.json
index ae667423c5..e96fbcaf99 100644
--- a/servers_be.json
+++ b/servers_be.json
@@ -9,7 +9,7 @@
"address": "md.surrealment.com"
},
{
- "address": "routerchain.ddns.net"
+ "address": "routerchain.ddns.net:6568"
},
{
"address": "mindustry.pl:6660"
diff --git a/tests/src/test/java/ApplicationTests.java b/tests/src/test/java/ApplicationTests.java
index 01cf659df2..7dbff14310 100644
--- a/tests/src/test/java/ApplicationTests.java
+++ b/tests/src/test/java/ApplicationTests.java
@@ -36,7 +36,7 @@ public class ApplicationTests{
try{
boolean[] begins = {false};
Throwable[] exceptionThrown = {null};
- Log.setUseColors(false);
+ Log.useColors = false;
ApplicationCore core = new ApplicationCore(){
@Override
@@ -145,7 +145,7 @@ public class ApplicationTests{
tile.build.items.add(Items.coal, 5);
tile.build.items.add(Items.titanium, 50);
assertEquals(tile.build.items.total(), 55);
- tile.build.items.remove(Items.phasefabric, 10);
+ tile.build.items.remove(Items.phaseFabric, 10);
tile.build.items.remove(Items.titanium, 10);
assertEquals(tile.build.items.total(), 45);
}
diff --git a/tests/src/test/java/SectorTests.java b/tests/src/test/java/SectorTests.java
index 4110670eed..6f07e77313 100644
--- a/tests/src/test/java/SectorTests.java
+++ b/tests/src/test/java/SectorTests.java
@@ -66,7 +66,7 @@ public class SectorTests{
outer:
for(int i = 1; i <= 1000; i++){
for(SpawnGroup spawn : spawns){
- if(spawn.effect == StatusEffects.boss && spawn.getUnitsSpawned(i) > 0){
+ if(spawn.effect == StatusEffects.boss && spawn.getSpawned(i) > 0){
bossWave = i;
break outer;
}
@@ -84,7 +84,7 @@ public class SectorTests{
for(int i = 1; i <= bossWave; i++){
int total = 0;
for(SpawnGroup spawn : spawns){
- total += spawn.getUnitsSpawned(i);
+ total += spawn.getSpawned(i);
}
assertNotEquals(0, total, "Sector " + zone + " has no spawned enemies at wave " + i);
diff --git a/tests/src/test/java/power/FakeGraphics.java b/tests/src/test/java/power/FakeGraphics.java
index 378f675224..5f64aa61f3 100644
--- a/tests/src/test/java/power/FakeGraphics.java
+++ b/tests/src/test/java/power/FakeGraphics.java
@@ -63,11 +63,6 @@ public class FakeGraphics extends Graphics{
return 0;
}
- @Override
- public float getRawDeltaTime(){
- return 0;
- }
-
@Override
public int getFramesPerSecond(){
return 0;
diff --git a/tests/src/test/java/power/PowerTestFixture.java b/tests/src/test/java/power/PowerTestFixture.java
index 7bd7e821b2..ceed02b530 100644
--- a/tests/src/test/java/power/PowerTestFixture.java
+++ b/tests/src/test/java/power/PowerTestFixture.java
@@ -37,7 +37,7 @@ public class PowerTestFixture{
Vars.state = new GameState();
Vars.tree = new FileTree();
content.createBaseContent();
- Log.setUseColors(false);
+ Log.useColors = false;
Time.setDeltaProvider(() -> 0.5f);
}
diff --git a/tools/src/mindustry/tools/Generators.java b/tools/src/mindustry/tools/Generators.java
index d8f67eee8c..645b2ea7f0 100644
--- a/tools/src/mindustry/tools/Generators.java
+++ b/tools/src/mindustry/tools/Generators.java
@@ -153,9 +153,9 @@ public class Generators{
ImagePacker.generate("cracks", () -> {
RidgedPerlin r = new RidgedPerlin(1, 3);
- for(int size = 1; size <= Block.maxCrackSize; size++){
+ for(int size = 1; size <= BlockRenderer.maxCrackSize; size++){
int dim = size * 32;
- int steps = Block.crackRegions;
+ int steps = BlockRenderer.crackRegions;
for(int i = 0; i < steps; i++){
float fract = i / (float)steps;
diff --git a/tools/src/mindustry/tools/ImagePacker.java b/tools/src/mindustry/tools/ImagePacker.java
index 2533f99af9..1142de8a26 100644
--- a/tools/src/mindustry/tools/ImagePacker.java
+++ b/tools/src/mindustry/tools/ImagePacker.java
@@ -28,10 +28,10 @@ public class ImagePacker{
Vars.headless = true;
ArcNativesLoader.load();
- Log.setLogger(new NoopLogHandler());
+ Log.logger = new NoopLogHandler();
Vars.content = new ContentLoader();
Vars.content.createBaseContent();
- Log.setLogger(new DefaultLogHandler());
+ Log.logger = new DefaultLogHandler();
Fi.get("../../../assets-raw/sprites_out").walk(path -> {
if(!path.extEquals("png")) return;