Compare commits

...

111 Commits

Author SHA1 Message Date
Anuken
07d11f02d8 Fixed #4869 2021-03-05 22:16:29 -05:00
Anuken
fce30e6ae5 Sync based on system time 2021-03-05 17:22:44 -05:00
Anuken
24195dac81 Added Voz-Duh's large launch pad sprite (#4861) 2021-03-05 14:27:15 -05:00
Joshua Fan
830fe03898 Add buildSpeedMultiplier status effect (#4816)
* Make disarmed status effect prevent building

* Revert disarmed changes, add buildSpeedMultiplier status

* Add buildSpeedMultiplier to StatusComp
2021-03-05 14:09:46 -05:00
Anuken
4690aae197 Fixed cores being replaceable 2021-03-05 14:00:53 -05:00
Anuken
b82dca89b3 Merge remote-tracking branch 'origin/master' 2021-03-05 12:06:44 -05:00
Anuken
dce79a621a Close connections immediately on kick 2021-03-05 12:06:40 -05:00
buthed010203
d6f00a5d2d Remove dead servers from v5 server list (#4858)
From what I can see, atnanner is the only network that still hosts any v5 servers, all the others are either on v6 or are offline.
2021-03-05 11:59:44 -05:00
Anuken
545b75a091 [Модификация] Доступен -> Доступна 2021-03-05 11:38:57 -05:00
Anuken
979daca221 Merge remote-tracking branch 'origin/master' 2021-03-05 11:36:15 -05:00
Anuken
fb2fed7c28 mod.multiplayer.compatible RU 2021-03-05 11:36:11 -05:00
YellOw139
0ec71750b7 [Bundle][RO] Update (#4750)
* [Bundle][RO] Update

This PR was tested in-game and is ready to merge at any time.

Changelog:

- New strings/changes up to commit f78719afc0
- Typo fixes & various other improvements

* WIP

* typo

* Speaking logically

* Update core/assets/bundles/bundle_ro.properties

Co-authored-by: MLGTASTICa <61350382+MLGTASTICa@users.noreply.github.com>

* Opted for a better term: controlor, not controller

* double-tap

* Times joined & kicked

Co-authored-by: MLGTASTICa <61350382+MLGTASTICa@users.noreply.github.com>
2021-03-05 11:30:55 -05:00
BlueTechno
51f7858b78 Added "armor" and "buildingdamage" stats (#4794)
Also fixed the description of the separator (so it matches the english description)
2021-03-05 11:30:45 -05:00
PolgarSasa
ab83b872a2 Update bundle_hu.properties (#4790) 2021-03-05 11:30:39 -05:00
Sharlotte
879adb7458 [KO] Update bundle_ko.properties (#4803)
* Update bundle_ko.properties

* translated recent changing

* https://github.com/Anuken/Mindustry/pull/4844

* Update bundle_ko.properties

* Add files via upload

* unofficial details
2021-03-05 11:29:26 -05:00
Catchears
39cbd607ef update german translation (#4826)
* update german translation to 781410ea04

* change from stuffyAI

* update german translation to ae838b9392
2021-03-05 11:29:18 -05:00
Antsiferov Andrew
7478cdf4a4 [Bundle][RU] actual L10n (#4748)
* 3 new, 1 deleted

New:
rules.unitcapvariable
rules.unitcap
laccess.color

Deleted:
lenum.color

* 1 line changed

rules.unitcap

* 2 new, 1 deleted

New:
mods.initfailed
setting.modcrashdisable.name

Deleted:
mods.alphainfo
-
Отключение модов после вылета на старте

* Fixed #4715

* Content parser class discovery improvements

* Use github build status (#4718)

Why does this still use travis? It was ditched months ago

* Make status colors the same (#4719)

It bothers me ok

* Better splash damage handling for small radii

* Fixed #4729

* Uncap content names in resolution

* Fixed UnitReq parsing

* Fixed #4732

* Allow JSON mod content types from other class loaders

* Better JSON null validation / Disable mods on startup crash

* Logic tooltips on mobile devices w/ long-press

* Add Survival and PvP servers (#4736)

* Update servers_v6.json (#4735)

add 1 more server for CxZx

* arc

* Balance tweaks

* Fixing remaining typos\errors in bundle_fr (#4397)

* Fixing remaining typos errors in bundle_fr

There are some errors that had managed to get through the verification. Imma chase them down!

* added logic hints and some typo fixes

* Fixing 2 typos in bundle.properties

L1548: Color statement affects every following draw operations.

* smolfixes

* Fixed "fix" in #4397

* [Bundle][RO] Update (#4725)

* [Bundle][RO] Update

This PR was tested in-game and is ready to merge at any time.

Changelog:

- New strings/changes up to commit 1ef7ae7079
- Typo fixes & various other improvements

* Reducing confusion

* Update bundle_ro.properties

* Fixing typos and descriptions [bundle_es.properties] (#4727)

* Fixing and descriptions [bundle_es.properties]

* Forgot something

* Update Logic Draw Hints (#4734)

Wrapped up some previous logic hints, too.

* german translation for build 125, full android translation (#4703)

* update german translation to 631e4d9eef

* update android translation to e816f6110d

with regard to 5ec5f1aa93

* improve translation with ideas from others

* update german steam discription to e86a3e9d09

* update german translation to 1ef7ae7079 (diff-5e346bcec4e8e1d545e035b1e438472bc51937398ac3e8e81308605ec82aea2c)

* changes from stuffyAI

* cross-platform as suggested by stuffyAI

* stuffyAI

genau, hast recht

Co-authored-by: stuffyAI <59014072+stuffyAI@users.noreply.github.com>

Co-authored-by: stuffyAI <59014072+stuffyAI@users.noreply.github.com>

* Update bundle_vi.properties (#4724)

* Fixed mod crash disable setting name

* Various fixes

* Steam icon changes

* arc

* Update Vietnamese Translation. (#4660)

* Update translation, fix some typo

* About 150 lines to do left.

* Typos fix #_1

* Typos fix + add trans

* Update to lastest commit.

* Base logic translation.

* a lot of typo ...

* some update from main bundle.

* Add more logic hint.

* translated recent update (#4742)

* Move update function of resupply point 5x1 spaces back (#4746)

* Remove stray spaces from accelerator (#4465)

* 10 new lines
graphicstype.clear
graphicstype.color
graphicstype.stroke
graphicstype.line
graphicstype.rect
graphicstype.linerect
graphicstype.poly
graphicstype.linepoly
graphicstype.triangle
graphicstype.image

* 1 line changed
lenum.stop (typo)

* 6 new lines

logic.nounitbuild
laccess.controller
laccess.dead
laccess.controlled
laccess.commanded
lenum.idle

* 1 new line

setting.doubletapmine.name

* 2 new, 2 changed

New:
trace.times.joined
trace.times.kicked

Changed:
unit.seconds
unit.minutes

* 1 line changed

trace.times.joined

* 1 new line

mod.multiplayercompatable
-
quick commit before potential merge, might fix it later

Co-authored-by: Vanguard <55051135+XEN0PHIL@users.noreply.github.com>
Co-authored-by: Anuken <arnukren@gmail.com>
Co-authored-by: buthed010203 <naguiar010203@gmail.com>
Co-authored-by: Fatonndev <56699208+Fatonndev@users.noreply.github.com>
Co-authored-by: CxZxRainzz <78591136+CxZxRainzz@users.noreply.github.com>
Co-authored-by: Phinner <62483793+Phinner@users.noreply.github.com>
Co-authored-by: YellOw139 <70975516+YellOw139@users.noreply.github.com>
Co-authored-by: BlueThecno <69437358+BlueThecno@users.noreply.github.com>
Co-authored-by: 彭瑞暄 <raymondpeng0725@gmail.com>
Co-authored-by: Catchears <57631841+Catchears@users.noreply.github.com>
Co-authored-by: stuffyAI <59014072+stuffyAI@users.noreply.github.com>
Co-authored-by: Arnyyx <74717260+Arnyyx@users.noreply.github.com>
Co-authored-by: Ngọc Lam <33188123+NgLamVN@users.noreply.github.com>
Co-authored-by: Sharlotte <60801210+Sharlottes@users.noreply.github.com>
Co-authored-by: Patrick 'Quezler' Mounier <Quezler@me.com>
2021-03-05 11:28:28 -05:00
Patrick 'Quezler' Mounier
b75a8d5260 Fix typo to preserve sanity (#4857)
* compatable > compatible

* compatable > compatible
2021-03-05 11:27:51 -05:00
MEEP of Faith
120c694a42 Mention Foreshadow's special targeting in its description. (#4419)
* Mention Foreshadow special targetting.

* Better wording
2021-03-05 11:25:58 -05:00
MEEP of Faith
569293e577 Shadow with width/height (#4609) 2021-03-05 11:21:23 -05:00
Anuken
4f0f2499be mod.multiplayercompatable in gray 2021-03-05 11:19:55 -05:00
MEEP of Faith
d34dd0c603 Add message for mods that have hidden = true (#4717)
* Multiplayer compatability message

* Make more sense?
2021-03-05 11:17:55 -05:00
Anuken
b6c645b701 Better DefenderAI / Vela building / Anuken/Mindustry-Suggestions/issues/2074 2021-03-05 11:10:12 -05:00
MEEP of Faith
0c28bb7dcf DefenderAI that makes octs follow units (#4757) 2021-03-05 10:21:26 -05:00
Anuken
2bb303e709 Fixed #4856 2021-03-04 18:41:30 -05:00
Anuken
cc65feb392 Added ConnectionEvent 2021-03-04 18:39:47 -05:00
Anuken
c12b9ee3e3 Minor network packet handling tweaks 2021-03-04 17:58:28 -05:00
Anuken
d863c971c2 Gradle update / Mech animation fixes / Formation movement tweaks 2021-03-04 13:40:50 -05:00
MEEP of Faith
3ccdf45ed1 Is this what you wanted sk? (#4848) 2021-03-04 10:38:47 -05:00
Javier Domingo Cansino
efa5c5db7b Enable client to use a different data dir through env MINDUSTRY_DATA_DIR (#4851) 2021-03-04 10:34:23 -05:00
Anuken
d73cf9fcff Prevent early return in PowerNode config render 2021-03-03 14:42:41 -05:00
Anuken
93dafc82eb Fixed #4847 2021-03-03 12:44:56 -05:00
Anuken
87142b06c3 Merge branch 'master' of https://github.com/Anuken/Mindustry 2021-03-03 10:49:57 -05:00
Anuken
3075616b03 arc 2021-03-03 10:49:52 -05:00
buthed010203
019898dfc3 Turrets can properly replace eachother, cores can replace conveyors and minor cleanup. (#4841) 2021-03-03 09:15:50 -05:00
Patrick 'Quezler' Mounier
ae838b9392 Trace times joined & kicked (#4844)
* Trace times joined & kicked

* Make mindustry.* import obsolete
2021-03-03 09:09:05 -05:00
Anuken
4d9a30b7c7 Merge remote-tracking branch 'origin/master' 2021-03-02 18:45:22 -05:00
Anuken
ea82773157 Non-overdriveable core / Spurious mod warning fix 2021-03-02 18:45:18 -05:00
buthed010203
8289da1415 Nuclear reactor schem priority of -5 (#4840)
* Nuclear reactor schem priority of -5
2021-03-02 10:49:22 -05:00
Anuken
19eb6334b7 Merge remote-tracking branch 'origin/master' 2021-03-02 09:28:42 -05:00
Anuken
e992be1bfb Higher LogicBlock schem priority 2021-03-02 09:28:38 -05:00
MEEP of Faith
7e216d198e Remove duplicates and mild formatting. (#4837)
* Remove duplicate definitions in UnitTypes

* If Tsunami is indented, so should the others

It looks nicer as well.
2021-03-02 09:28:04 -05:00
MEEP of Faith
a89d50e74d Cursor should not change for other teams when hovering over doors and construction. (#4838)
* Cursor should not change for other teams.

* Use Built-in interaction check

Co-authored-by: Patrick 'Quezler' Mounier <Quezler@me.com>

* Building should use built-in check, same treatment for ConstructBlock

Co-authored-by: Patrick 'Quezler' Mounier <Quezler@me.com>
2021-03-02 09:25:15 -05:00
Anuken
05dc13c922 Fixed #4830 2021-03-01 13:06:47 -05:00
Patrick 'Quezler' Mounier
1de4dd1bfe Call super.drawPlace for menders & overdrives (#4831) 2021-03-01 13:02:27 -05:00
Anuken
72aa87128e Merge remote-tracking branch 'origin/master' 2021-03-01 11:58:59 -05:00
Anuken
8f91576f85 Fixed script loading for Turkish locale 2021-03-01 11:58:53 -05:00
Patrick 'Quezler' Mounier
4019c49fff Log who skipped the wave to the console (#4825) 2021-03-01 09:47:23 -05:00
Anuken
5f83c92829 Fixed #4824 / Fixed #4827 / Fixed #4829 2021-03-01 09:45:40 -05:00
Anuken
4c9cda7e40 Cleanup 2021-02-28 17:33:08 -05:00
Sunny Kim
01f7b1c9a6 New overdrive visuals for colorblind users (#4807) 2021-02-28 17:32:28 -05:00
Anuken
1a30edc55f Merge remote-tracking branch 'origin/master' 2021-02-28 17:17:08 -05:00
Anuken
49bccffd7c Link previews for power blocks near nodes 2021-02-28 17:17:03 -05:00
Patrick 'Quezler' Mounier
526157a514 Draw to-be affected blocks when placing projectors (#4818) 2021-02-28 13:58:06 -05:00
FiliusPatris
d025ba63e1 Display map names with underscores (#4819)
This makes it obvious how to specify map names with spaces. It also
allows for copy-pasting form the output of `maps`.
2021-02-28 13:27:47 -05:00
genNAowl
662515ce2e Make RepairPoints implement Ranged (#4813)
Co-authored-by: Leonwang4234 <62972692+Leonwang4234@users.noreply.github.com>
2021-02-28 09:19:35 -05:00
Joshua Fan
c55ff4ad5e Desktop double-click mining: fix click on mined tile to cancel (#4815) 2021-02-28 09:19:27 -05:00
Anuken
666c0f3582 Merge remote-tracking branch 'origin/master' 2021-02-27 15:10:39 -05:00
Anuken
0c00760ae0 Fixed result duplication in logic UI 2021-02-27 15:10:34 -05:00
Patrick 'Quezler' Mounier
2146b35e5a eacho ther (#4810)
* eacho ther

* Update Tile.java
2021-02-27 10:21:11 -05:00
Anuken
44d10a355e Improved power node link preview check 2021-02-27 10:16:54 -05:00
buthed010203
5037c4e00e Fix a few issues w/ double tap mining (#4798)
Currently, double tap mining consumes clicks so it prevents the player from configuring any block if they click twice within 500ms. The double tap mining was also using the `selected` var which could have been null causing a crash. This is a very messy solution but it does the job good enough
2021-02-27 10:12:00 -05:00
buthed010203
e4ecfc4ee7 Fixed #4791 since it is 100% a bug (#4801)
* Fixed #4719 since it is 100% a bug

This fix is somewhat janky as it checks if the rotation matches the exact original rotation but the likelihood of someone needing bridges along a belt rotated 1 or -1 times is super low. https://aethex.is-a.fail/t13ETd.webm

* unjank rotation

* fix potential crash, styling

* Use mathf.mod
2021-02-26 19:06:27 -05:00
Anuken
ae6be1db3b UnitSpawnAbility 'type' field JSON compat / Fixed health bar out of bounds 2021-02-26 18:51:14 -05:00
Anuken
d06eee99ba Merge remote-tracking branch 'origin/master' 2021-02-26 13:13:41 -05:00
Anuken
8349c8a5b8 Fixed #4802 2021-02-26 13:13:37 -05:00
Darkness6030
2df7484649 Add servers to global list (#4761)
* Add servers to global list
2021-02-26 11:13:51 -05:00
Anuken
1bb97cae39 Fixed #4792 2021-02-25 18:34:24 -05:00
Anuken
f5ac3ff7b0 null controller for dead units 2021-02-25 10:54:05 -05:00
Anuken
f6eba3edae Synchronized settings / Dead units sense as non-controlled 2021-02-25 09:12:17 -05:00
Joshua Fan
781410ea04 Double-tap to mine, tap anywhere to cancel (#4469)
* Double-tap to mine, tap anywhere to cancel

* Make comment consistent

* Remove desktop left-click mining cancel, prioritize mobile unit control over mining

* Mobile: double-tap doesn't configure blocks if unit was double-tapped; control unit detected in first tap of double-tap

* Add 'double-tap to mine' setting (default off)

* Desktop: cancel mining when mined tile is clicked

* Comment typo

* Prevent redundant condition check

* Cleanup

Co-authored-by: Anuken <arnukren@gmail.com>
2021-02-25 08:43:40 -05:00
Anuken
c0d9712beb Fixed #4784 2021-02-25 08:39:35 -05:00
Anuken
0672878920 Fixed #4781 2021-02-24 15:27:22 -05:00
Anuken
b0cdac59f0 Merge remote-tracking branch 'origin/master' 2021-02-24 15:01:48 -05:00
Anuken
4b6a83dd82 Improved auto-bridging with conveyors 2021-02-24 15:01:44 -05:00
Minxyzgo
25ae7b97aa schematic uses camera position (#4775)
* Update InputHandler.java

* Update InputHandler.java

* Update MobileInput.java

* Update InputHandler.java

* Update MobileInput.java
2021-02-24 12:25:38 -05:00
Anuken
afbde49fa2 Fixed #4776 / Fixed #4772 2021-02-24 09:52:53 -05:00
Anuken
befda9baaa Merge branch 'master' of https://github.com/Anuken/Mindustry 2021-02-23 17:07:45 -05:00
Anuken
502c7eb388 arc 2021-02-23 17:07:40 -05:00
Antsiferov Andrew
ad2a18f929 Fix player.locale to be default (#4768)
* fix player.locale == default

* Update NetClient.java
2021-02-23 14:53:23 -05:00
Anuken
830eb86a0f Better power node linking visualization 2021-02-23 12:53:43 -05:00
Anuken
e5413cebdc Fixed #4766 2021-02-23 11:29:51 -05:00
Anuken
1a75951840 Merge remote-tracking branch 'origin/master' 2021-02-23 10:47:58 -05:00
Anuken
08e36aca98 Crafter progress modulo / Segment buff 2021-02-23 10:47:54 -05:00
Patrick 'Quezler' Mounier
aabbfd624a Add disarmed status effect that disarms (#4762)
* Add disarmed status effect that disarms

* Update core/src/mindustry/entities/comp/StatusComp.java

Co-authored-by: Anuken <arnukren@gmail.com>

* Rename disarms -> disarm

Co-authored-by: Anuken <arnukren@gmail.com>
2021-02-23 09:51:43 -05:00
Anuken
2f836d779a Update servers_v6.json 2021-02-22 10:22:28 -05:00
Anuken
d7f848f8cd contXXXXX constants -> ctrl 2021-02-22 10:18:42 -05:00
Anuken
6f7f980563 Merge remote-tracking branch 'origin/master' 2021-02-22 10:15:43 -05:00
Anuken
e2515fc4bf Automatic conveyor/conduit bridging 2021-02-22 10:15:40 -05:00
UnCaughT
d06a7bb7a2 Update servers_v6.json (#4756)
The server now has a new domain.
2021-02-22 10:09:55 -05:00
Sharlotte
dbdfdac94b translated yesterday update (#4755)
* translated newest bundle updates
* ps. why did i forgot 1ef7ae7079 (diff-5e346bcec4e8e1d545e035b1e438472bc51937398ac3e8e81308605ec82aea2c) this commit previous translation update?
2021-02-22 09:19:46 -05:00
Anuken
3b2a0cfd66 Removed RCR due to lack of moderation 2021-02-22 09:05:27 -05:00
Anuken
5b652ae51f Added guidelines for inappropriate server content 2021-02-22 09:04:22 -05:00
Anuken
9e8a2b8296 Minor bridge linking fix 2021-02-21 20:07:20 -05:00
Anuken
e6787c5146 Controlled sensor improvements 2021-02-21 12:28:00 -05:00
Anuken
d8552915f7 Cleanup 2021-02-21 10:35:33 -05:00
Anuken
61d9dea487 Logic config replication / logicUnitBuild rule / Copy-able ConstructBlocks 2021-02-21 10:23:46 -05:00
Anuken
02d8f679b5 Merge remote-tracking branch 'origin/master' 2021-02-21 09:22:05 -05:00
Anuken
544828d9fb Logic controller & dead`` sensors 2021-02-21 09:22:02 -05:00
liuxilu
ca726d579e unit boosting sensor (#4738) 2021-02-21 09:20:36 -05:00
Anuken
8257fb5e11 Merge remote-tracking branch 'origin/master' 2021-02-21 08:54:10 -05:00
Anuken
0d287e6d59 Water Extractor: Use metaglass to be consistent with pumps 2021-02-21 08:53:47 -05:00
Patrick 'Quezler' Mounier
4d9dc66a96 Remove stray spaces from accelerator (#4465) 2021-02-20 12:52:56 -05:00
Patrick 'Quezler' Mounier
868d4e05f7 Move update function of resupply point 5x1 spaces back (#4746) 2021-02-20 12:51:12 -05:00
Anuken
a3bf39d86b Minor cleanup 2021-02-20 10:08:15 -05:00
Sharlotte
d76795e0ae translated recent update (#4742) 2021-02-20 10:07:29 -05:00
Ngọc Lam
a2e075ee54 Update Vietnamese Translation. (#4660)
* Update translation, fix some typo

* About 150 lines to do left.

* Typos fix #_1

* Typos fix + add trans

* Update to lastest commit.

* Base logic translation.

* a lot of typo ...

* some update from main bundle.

* Add more logic hint.
2021-02-20 10:07:19 -05:00
Anuken
2df2a0971a arc 2021-02-20 09:49:49 -05:00
Anuken
158e23bd5e Steam icon changes 2021-02-19 19:43:37 -05:00
Anuken
467402ef73 Various fixes 2021-02-19 19:20:04 -05:00
Anuken
f78719afc0 Fixed mod crash disable setting name 2021-02-19 19:10:27 -05:00
106 changed files with 2044 additions and 1148 deletions

View File

@@ -8,14 +8,15 @@ You may want to add your server to this list. The steps for getting this done ar
1. **Ensure your server is properly moderated.** For the most part, this applies to survival servers, but PvP servers can be affected as well. 1. **Ensure your server is properly moderated.** For the most part, this applies to survival servers, but PvP servers can be affected as well.
You'll need to either hire some moderators, or make use of (currently non-existent) anti-grief and anti-curse plugins. You'll need to either hire some moderators, or make use of (currently non-existent) anti-grief and anti-curse plugins.
*Consider enabling a rate limit:* `config messageRateLimit 2` will make it so that players can only send messages every 2 seconds, for example. *Consider enabling a rate limit:* `config messageRateLimit 2` will make it so that players can only send messages every 2 seconds, for example.
2. **Set an appropriate MOTD, name and description.** This is set with `config <name/desc/motd> <value>`. "Appropriate" means that: 2. Make sure that your server is able to handle inappropriate content - this includes NSFW display/sorter art and abusive messages. **Servers that allow such content will be removed immediately.** Consider banning display blocks if it is a problem for your server: `rules add bannedBlocks ["logic-display", "large-logic-display"]`.
3. **Set an appropriate MOTD, name and description.** This is set with `config <name/desc/motd> <value>`. "Appropriate" means that:
- Your name or description must reflect the type of server you're hosting. - Your name or description must reflect the type of server you're hosting.
Since new players may be exposed to the server list early on, put in a phrase like "Co-op survival" or "PvP" so players know what they're getting into. Yes, this is also displayed in the server mode info text, but having extra info in the name doesn't hurt. Since new players may be exposed to the server list early on, put in a phrase like "Co-op survival" or "PvP" so players know what they're getting into. Yes, this is also displayed in the server mode info text, but having extra info in the name doesn't hurt.
- Make sure players know where to refer to for server support. It should be fairly clear that the server owner is not me, but you. - Make sure players know where to refer to for server support. It should be fairly clear that the server owner is not me, but you.
- Try to be professional in your text; use common sense. - Try to be professional in your text; use common sense.
3. **Get some good maps.** *(optional, but highly recommended)*. Add some maps to your server and set the map rotation to custom-only. You can get maps from the Steam workshop by subscribing and exporting them; using the `#maps` channel on Discord is also an option. 4. **Get some good maps.** *(optional, but highly recommended)*. Add some maps to your server and set the map rotation to custom-only. You can get maps from the Steam workshop by subscribing and exporting them; using the `#maps` channel on Discord is also an option.
4. **Check your server configuration.** *(optional)* I would recommend adding a message rate limit of 1 second (`config messageRateLimit 1`), and disabling connect/disconnect messages to reduce spam (`config showConnectMessages false`). 5. **Check your server configuration.** *(optional)* I would recommend adding a message rate limit of 1 second (`config messageRateLimit 1`), and disabling connect/disconnect messages to reduce spam (`config showConnectMessages false`).
5. Finally, **submit a pull request** to add your server's IP to the list. 6. Finally, **submit a pull request** to add your server's IP to the list.
This should be fairly straightforward: Press the edit button on the [server file](https://github.com/Anuken/Mindustry/blob/master/servers_v6.json), then add a JSON object with a single key, indicating your server address. This should be fairly straightforward: Press the edit button on the [server file](https://github.com/Anuken/Mindustry/blob/master/servers_v6.json), then add a JSON object with a single key, indicating your server address.
For example, if your server address is `google.com`, you would add a comma after the last entry and insert: For example, if your server address is `google.com`, you would add a comma after the last entry and insert:
```json ```json

View File

@@ -63,7 +63,7 @@ public class RemoteProcess extends BaseProcessor{
classes = new Seq<>(); classes = new Seq<>();
Seq<Smethod> orderedElements = elements.copy(); Seq<Smethod> orderedElements = elements.copy();
orderedElements.sortComparing(Object::toString); orderedElements.sort((a, b) -> -a.toString().compareTo(b.toString()));
//create methods //create methods
for(Smethod element : orderedElements){ for(Smethod element : orderedElements){
@@ -71,12 +71,12 @@ public class RemoteProcess extends BaseProcessor{
//check for static //check for static
if(!element.is(Modifier.STATIC) || !element.is(Modifier.PUBLIC)){ if(!element.is(Modifier.STATIC) || !element.is(Modifier.PUBLIC)){
err("All @Remote methods must be public and static: ", element); err("All @Remote methods must be public and static", element);
} }
//can't generate none methods //can't generate none methods
if(annotation.targets() == Loc.none){ if(annotation.targets() == Loc.none){
err("A @Remote method's targets() cannot be equal to 'none':", element); err("A @Remote method's targets() cannot be equal to 'none'", element);
} }
//get and create class entry if needed //get and create class entry if needed

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 338 B

After

Width:  |  Height:  |  Size: 514 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 359 B

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 290 B

After

Width:  |  Height:  |  Size: 430 B

View File

@@ -126,6 +126,7 @@ mod.installed = [[Installed]
mod.display = [gray]Mod:[orange] {0} mod.display = [gray]Mod:[orange] {0}
mod.enabled = [lightgray]Enabled mod.enabled = [lightgray]Enabled
mod.disabled = [scarlet]Disabled mod.disabled = [scarlet]Disabled
mod.multiplayer.compatible = [gray]Multiplayer Compatible
mod.disable = Disable mod.disable = Disable
mod.content = Content: mod.content = Content:
mod.delete.error = Unable to delete mod. File may be in use. mod.delete.error = Unable to delete mod. File may be in use.
@@ -216,9 +217,11 @@ server.hidden = Hidden
trace = Trace Player trace = Trace Player
trace.playername = Player name: [accent]{0} trace.playername = Player name: [accent]{0}
trace.ip = IP: [accent]{0} trace.ip = IP: [accent]{0}
trace.id = Unique ID: [accent]{0} trace.id = ID: [accent]{0}
trace.mobile = Mobile Client: [accent]{0} trace.mobile = Mobile Client: [accent]{0}
trace.modclient = Custom Client: [accent]{0} trace.modclient = Custom Client: [accent]{0}
trace.times.joined = Times Joined: [accent]{0}
trace.times.kicked = Times Kicked: [accent]{0}
invalidid = Invalid client ID! Submit a bug report. invalidid = Invalid client ID! Submit a bug report.
server.bans = Bans server.bans = Bans
server.bans.none = No banned players found! server.bans.none = No banned players found!
@@ -800,7 +803,8 @@ setting.logichints.name = Logic Hints
setting.flow.name = Display Resource Flow Rate setting.flow.name = Display Resource Flow Rate
setting.backgroundpause.name = Pause In Background setting.backgroundpause.name = Pause In Background
setting.buildautopause.name = Auto-Pause Building setting.buildautopause.name = Auto-Pause Building
setting.modcrashdisable = Disable Mods On Startup Crash setting.doubletapmine.name = Double-Tap to Mine
setting.modcrashdisable.name = Disable Mods On Startup Crash
setting.animatedwater.name = Animated Surfaces setting.animatedwater.name = Animated Surfaces
setting.animatedshields.name = Animated Shields setting.animatedshields.name = Animated Shields
setting.antialias.name = Antialias[lightgray] (requires restart)[] setting.antialias.name = Antialias[lightgray] (requires restart)[]
@@ -1456,7 +1460,7 @@ block.ripple.description = Shoots clusters of shells at ground enemies over long
block.cyclone.description = Fires explosive clumps of flak at nearby enemies. block.cyclone.description = Fires explosive clumps of flak at nearby enemies.
block.spectre.description = Fires large armor-piercing bullets at air and ground targets. block.spectre.description = Fires large armor-piercing bullets at air and ground targets.
block.meltdown.description = Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate. block.meltdown.description = Charges and fires a persistent laser beam at nearby enemies. Requires coolant to operate.
block.foreshadow.description = Fires a large single-target bolt over long distances. block.foreshadow.description = Fires a large single-target bolt over long distances. Prioritizes enemies with higher max health.
block.repair-point.description = Continuously repairs the closest damaged unit in its vicinity. block.repair-point.description = Continuously repairs 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.
block.parallax.description = Fires a tractor beam that pulls in air targets, damaging them in the process. block.parallax.description = Fires a tractor beam that pulls in air targets, damaging them in the process.
@@ -1537,6 +1541,8 @@ lst.unitcontrol = Control the currently bound unit.
lst.unitradar = Locate units around the currently bound unit. lst.unitradar = Locate units around the currently bound unit.
lst.unitlocate = Locate a specific type of position/building anywhere on the map.\nRequires a bound unit. lst.unitlocate = Locate a specific type of position/building anywhere on the map.\nRequires a bound unit.
logic.nounitbuild = [red]Unit building logic is not allowed here.
lenum.type = Type of building/unit.\ne.g. for any router, this will return [accent]@router[].\nNot a string. lenum.type = Type of building/unit.\ne.g. for any router, this will return [accent]@router[].\nNot a string.
lenum.shoot = Shoot at a position. lenum.shoot = Shoot at a position.
lenum.shootp = Shoot at a unit/building with velocity prediction. lenum.shootp = Shoot at a unit/building with velocity prediction.
@@ -1544,6 +1550,10 @@ lenum.configure = Building configuration, e.g. sorter item.
lenum.enabled = Whether the block is enabled. lenum.enabled = Whether the block is enabled.
laccess.color = Illuminator color. laccess.color = Illuminator color.
laccess.controller = Unit controller. If processor controlled, returns processor.\nIf in a formation, returns leader.\nOtherwise, returns the unit itself.
laccess.dead = Whether a unit/building is dead or no longer valid.
laccess.controlled = Returns:\n[accent]@ctrlProcessor[] if unit controller is processor\n[accent]@ctrlPlayer[] if unit/building controller is player\n[accent]@ctrlFormation[] if unit is in formation\nOtherwise, 0.
laccess.commanded = [red]Deprecated. Will be removed![]\nUse [accent]controlled[] instead.
graphicstype.clear = Fill the display with a color. graphicstype.clear = Fill the display with a color.
graphicstype.color = Set color for next drawing operations. graphicstype.color = Set color for next drawing operations.
@@ -1579,7 +1589,7 @@ lenum.sin = Sine, in degrees.
lenum.cos = Cosine, in degrees. lenum.cos = Cosine, in degrees.
lenum.tan = Tangent, in degrees. lenum.tan = Tangent, in degrees.
#not a typo, look up 'range notation' #not a typo, look up 'range notation'
lenum.rand = Random number in range [0, value). lenum.rand = Random decimal in range [0, value).
lenum.log = Natural logarithm (ln). lenum.log = Natural logarithm (ln).
lenum.log10 = Base 10 logarithm. lenum.log10 = Base 10 logarithm.
lenum.noise = 2D simplex noise. lenum.noise = 2D simplex noise.
@@ -1637,6 +1647,7 @@ unitlocate.outx = Output X coordinate.
unitlocate.outy = Output Y coordinate. unitlocate.outy = Output Y coordinate.
unitlocate.group = Building group to look for. unitlocate.group = Building group to look for.
lenum.idle = Don't move, but keep building/mining.\nThe default state.
lenum.stop = Stop moving/mining/building. lenum.stop = Stop moving/mining/building.
lenum.move = Move to exact position. lenum.move = Move to exact position.
lenum.approach = Approach a position with a radius. lenum.approach = Approach a position with a radius.

View File

@@ -113,7 +113,7 @@ committingchanges = Veränderungen werden übernommen
done = Fertig done = Fertig
feature.unsupported = Dein System unterstützt dieses Feature nicht. feature.unsupported = Dein System unterstützt dieses Feature nicht.
mods.alphainfo = Vergiss nicht, dass Mods in der Alpha sind und[scarlet] sehr fehlerhaft sein können[].\nMelde alle Probleme auf GitHub oder Discord. mods.initfailed = [red]⚠[] Die vorherige Mindustry-Instanz konnte nicht starten. Dies lag wahrscheinlich an fehlerhaften Mods.\n\nDamit das Spiel starten kann, [red]wurden alle Mods deaktiviert.[]\n\nWenn du nicht willst, dass das passiert, kannst du es unter [accent]Einstellungen->Spiel->Mods bei Absturz deaktivieren[] ändern.
mods = Mods mods = Mods
mods.none = [lightgray]Keine Mods gefunden! mods.none = [lightgray]Keine Mods gefunden!
mods.guide = Modding-Anleitung mods.guide = Modding-Anleitung
@@ -216,9 +216,11 @@ server.hidden = Versteckt
trace = Spieler verfolgen trace = Spieler verfolgen
trace.playername = Spielername: [accent]{0} trace.playername = Spielername: [accent]{0}
trace.ip = IP: [accent]{0} trace.ip = IP: [accent]{0}
trace.id = Eindeutige ID: [accent]{0} trace.id = ID: [accent]{0}
trace.mobile = Mobiler Client: [accent]{0} trace.mobile = Mobiler Client: [accent]{0}
trace.modclient = Gemoddeter Client: [accent]{0} trace.modclient = Gemoddeter Client: [accent]{0}
trace.times.joined = Beigetreten: [accent]{0}[] Mal
trace.times.kicked = Rausgeworfen: [accent]{0}[] Mal
invalidid = Ungültige Client-ID! Berichte den Fehler. invalidid = Ungültige Client-ID! Berichte den Fehler.
server.bans = Verbannungen server.bans = Verbannungen
server.bans.none = Keine verbannten Spieler gefunden! server.bans.none = Keine verbannten Spieler gefunden!
@@ -800,6 +802,8 @@ setting.logichints.name = Logiktipps
setting.flow.name = Ressourcen-Fluss anzeigen setting.flow.name = Ressourcen-Fluss anzeigen
setting.backgroundpause.name = Im Hintergrund pausieren setting.backgroundpause.name = Im Hintergrund pausieren
setting.buildautopause.name = Bauen automatisch pausieren setting.buildautopause.name = Bauen automatisch pausieren
setting.doubletapmine.name = Doppeltippen zum Abbauen
setting.modcrashdisable.name = Mods bei Absturz deaktivieren
setting.animatedwater.name = Animiertes Wasser setting.animatedwater.name = Animiertes Wasser
setting.animatedshields.name = Animierte Schilde setting.animatedshields.name = Animierte Schilde
setting.antialias.name = Antialias[lightgray] (Neustart erforderlich)[] setting.antialias.name = Antialias[lightgray] (Neustart erforderlich)[]
@@ -1536,6 +1540,8 @@ lst.unitcontrol = Steuert [accent]@unit[].
lst.unitradar = Findet Einheiten in der Nähe von [accent]@unit[]. lst.unitradar = Findet Einheiten in der Nähe von [accent]@unit[].
lst.unitlocate = Findet mit [accent]@unit[] bestimmte Positionen / Blöcke auf der ganzen Karte. lst.unitlocate = Findet mit [accent]@unit[] bestimmte Positionen / Blöcke auf der ganzen Karte.
logic.nounitbuild = [red]Logik, die Blöcke baut, ist hier nicht erlaubt.
lenum.type = Englischer Name eines Blocks / einer Einheit. Ein Verteiler gibt [accent]@router[] wieder.\nKein string. lenum.type = Englischer Name eines Blocks / einer Einheit. Ein Verteiler gibt [accent]@router[] wieder.\nKein string.
lenum.shoot = Schießt auf eine Position. lenum.shoot = Schießt auf eine Position.
lenum.shootp = Schießt auf eine Einheit / einen Block und sagt deren Position voraus. lenum.shootp = Schießt auf eine Einheit / einen Block und sagt deren Position voraus.
@@ -1543,6 +1549,10 @@ lenum.configure = Blockkonfiguration, z.B. das ausgewählte Item in einem Sortie
lenum.enabled = Ob der Block an oder aus ist. lenum.enabled = Ob der Block an oder aus ist.
laccess.color = Illuminiererfarbe. laccess.color = Illuminiererfarbe.
laccess.controller = Einheitensteurer. Gibt "processor" zurück, wenn die Einheit prozessorgesteuert ist,.\nGibt den Steuerer zurück, wenn die Einheit Teil einer Formation ist.\nSonst wird einfach die Einheit zurückgegeben.
laccess.dead = Ob ein Block / eine Einheit tot oder nicht mehr gültig ist.
laccess.controlled = Gibt zurück:\n[accent]@ctrlProcessor[] wenn die Einheit prozessorgesteuert ist\n[accent]@ctrlPlayer[] wenn die Einheit / der Block von einem Spieler gesteuert wird\n[accent]@ctrlFormation[] wenn die Einheit Teil einer Formation ist\nSonst 0.
laccess.commanded = [red]Veraltet. Wird bald entfernt![]\nBenutze stattdessen [accent]controlled[].
graphicstype.stroke = Setzt die Linienbreite fest. graphicstype.stroke = Setzt die Linienbreite fest.
graphicstype.line = Zeichnet eine Linie. graphicstype.line = Zeichnet eine Linie.
@@ -1554,6 +1564,7 @@ graphicstype.poly = Füllt ein gleichmäßiges Polygon.
graphicstype.linepoly = Zeichnet den Umriss eines gleichmäßigen Polygons. graphicstype.linepoly = Zeichnet den Umriss eines gleichmäßigen Polygons.
graphicstype.triangle = Zeichnet ein Dreieck. graphicstype.triangle = Zeichnet ein Dreieck.
graphicstype.image = Zeichnet ein Bild von einem englischen Namen.\nz.B. [accent]@router[] oder [accent]@dagger[]. graphicstype.image = Zeichnet ein Bild von einem englischen Namen.\nz.B. [accent]@router[] oder [accent]@dagger[].
lenum.always = Immer. lenum.always = Immer.
lenum.idiv = Division mit ganzen Zahlen. lenum.idiv = Division mit ganzen Zahlen.
lenum.div = Division.\nGibt bei Teilung durch null [accent]null[] zurück. lenum.div = Division.\nGibt bei Teilung durch null [accent]null[] zurück.
@@ -1635,6 +1646,7 @@ unitlocate.outx = Variable für die X-Koordinate.
unitlocate.outy = Variable für die Y-Koordinate. unitlocate.outy = Variable für die Y-Koordinate.
unitlocate.group = Gesuchter Blocktyp. unitlocate.group = Gesuchter Blocktyp.
lenum.idle = Bewegt sich nicht, baut aber weiter ab.\nDer normale Zustand.
lenum.stop = Bewegung / Abbau / Bau abbrechen. lenum.stop = Bewegung / Abbau / Bau abbrechen.
lenum.move = Geht zu diese Position. lenum.move = Geht zu diese Position.
lenum.approach = Geht auf einen Punkt mit einem bestimmten Radius zu. lenum.approach = Geht auf einen Punkt mit einem bestimmten Radius zu.

View File

@@ -678,6 +678,7 @@ stat.drillspeed = Velocidad del Taladro
stat.boosteffect = Efecto de Potenciador stat.boosteffect = Efecto de Potenciador
stat.maxunits = Máximo de Unidades Activas stat.maxunits = Máximo de Unidades Activas
stat.health = Vida stat.health = Vida
stat.armor = Armadura
stat.buildtime = Tiempo de construcción stat.buildtime = Tiempo de construcción
stat.maxconsecutive = Máximo consecutivo stat.maxconsecutive = Máximo consecutivo
stat.buildcost = Coste de construcción stat.buildcost = Coste de construcción
@@ -745,6 +746,7 @@ bullet.sapping = [stat]Oxidante
bullet.homing = [stat]Rastreadora bullet.homing = [stat]Rastreadora
bullet.shock = [stat]Electrizante bullet.shock = [stat]Electrizante
bullet.frag = [stat]De fragmentación bullet.frag = [stat]De fragmentación
bullet.buildingdamage = [stat]{0}%[lightgray]daño a estructuras
bullet.knockback = [stat]{0}[lightgray] Empuje bullet.knockback = [stat]{0}[lightgray] Empuje
bullet.pierce = [stat]{0}[lightgray]x penetración bullet.pierce = [stat]{0}[lightgray]x penetración
bullet.infinitepierce = [stat]Penetrante bullet.infinitepierce = [stat]Penetrante
@@ -1337,7 +1339,7 @@ block.cryofluid-mixer.description = Combina agua y titanio en líquido criogéni
block.blast-mixer.description = Usa esporas para transformar pirotita en un objeto menos inflamable pero más explosivo: el compuesto explosivo. block.blast-mixer.description = Usa esporas para transformar pirotita en un objeto menos inflamable pero más explosivo: el compuesto explosivo.
block.pyratite-mixer.description = Mezcla carbón, plomo y arena en pirotita altamente inflamable. block.pyratite-mixer.description = Mezcla carbón, plomo y arena en pirotita altamente inflamable.
block.melter.description = Calienta chatarra a temperaturas muy altas para obtener magma. block.melter.description = Calienta chatarra a temperaturas muy altas para obtener magma.
block.separator.description = Expone piedra a la presión del agua para obtener diversos minerales contenidos en la piedra. block.separator.description = Separa el magma en sus componentes minerales.
block.spore-press.description = Comprime esporas en petróleo. block.spore-press.description = Comprime esporas en petróleo.
block.pulverizer.description = Despedaza la chatarra en arena. Útil cuando no hay arena natural. block.pulverizer.description = Despedaza la chatarra en arena. Útil cuando no hay arena natural.
block.coal-centrifuge.description = Solidifica petróleo en piezas de carbón. block.coal-centrifuge.description = Solidifica petróleo en piezas de carbón.

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@ link.changelog.description = 업데이트 내용 목록
link.dev-builds.description = 불안정한 개발 버전 link.dev-builds.description = 불안정한 개발 버전
link.trello.description = 출시 예정 기능 계획을 게시한 공식 Trello 보드 link.trello.description = 출시 예정 기능 계획을 게시한 공식 Trello 보드
link.itch.io.description = PC 다운로드가 있는 itch.io 페이지 link.itch.io.description = PC 다운로드가 있는 itch.io 페이지
link.google-play.description = Google Play 스토어 목록 link.google-play.description = oogle Play 스토어 목록
link.f-droid.description = F-Droid 카탈로그 목록 link.f-droid.description = F-Droid 카탈로그 목록
link.wiki.description = 공식 Mindustry 위키 link.wiki.description = 공식 Mindustry 위키
link.suggestions.description = 새 기능 제안하기 link.suggestions.description = 새 기능 제안하기
@@ -113,7 +113,7 @@ committingchanges = 바뀐 점 적용
done = 완료 done = 완료
feature.unsupported = 기기가 이 기능을 지원하지 않습니다. feature.unsupported = 기기가 이 기능을 지원하지 않습니다.
mods.alphainfo = 현재 모드는 정식 출시 버전이 아니며, [scarlet]오류가 많을 수 있습니다[].\n발견한 문제는 Mindustry Github 또는 Discord에 보고하세요. mods.initfailed = [red]⚠[]이전 Mindustry 인스턴스를 초기화하지 못했습니다. 잘못된 모드로 인해 발생한 것일 수 있습니다.\n\n 게임 충돌 무한반복을 막기 위해, [red]모든 모드가 비활성화되었습니다.[]\n\n이 시스템을 비활성화할려면, [accent]설정->게임->로딩 중 충돌 시 모드 비활성화[]설정을 끄세요.
mods = 모드 mods = 모드
mods.none = [lightgray]모드를 찾을 수 없습니다! mods.none = [lightgray]모드를 찾을 수 없습니다!
mods.guide = 모드 제작 가이드 mods.guide = 모드 제작 가이드
@@ -219,6 +219,8 @@ trace.ip = IP: [accent]{0}
trace.id = UUID: [accent]{0} trace.id = UUID: [accent]{0}
trace.mobile = 모바일 클라이언트: [accent]{0} trace.mobile = 모바일 클라이언트: [accent]{0}
trace.modclient = 사용자 지정 클라이언트: [accent]{0} trace.modclient = 사용자 지정 클라이언트: [accent]{0}
trace.times.joined = 입장 횟수: [accent]{0}
trace.times.kicked = 추방 횟수: [accent]{0}
invalidid = 잘못된 클라이언트 ID입니다! 버그 보고서를 보내주세요. invalidid = 잘못된 클라이언트 ID입니다! 버그 보고서를 보내주세요.
server.bans = 차단 목록 server.bans = 차단 목록
server.bans.none = 차단된 플레이어를 찾을 수 없습니다! server.bans.none = 차단된 플레이어를 찾을 수 없습니다!
@@ -800,6 +802,8 @@ setting.logichints.name = 로직 힌트 표시
setting.flow.name = 자원 흐름량 표시 setting.flow.name = 자원 흐름량 표시
setting.backgroundpause.name = 백그라운드에서 일시정지 setting.backgroundpause.name = 백그라운드에서 일시정지
setting.buildautopause.name = 건설 자동 일시정지 setting.buildautopause.name = 건설 자동 일시정지
setting.doubletapmine.name = 연속 터치로 채광
setting.modcrashdisable.name = 로딩 중 충돌 시 모드 비활성화
setting.animatedwater.name = 액체 애니메이션 효과 setting.animatedwater.name = 액체 애니메이션 효과
setting.animatedshields.name = 보호막 애니메이션 효과 setting.animatedshields.name = 보호막 애니메이션 효과
setting.antialias.name = 위신호 제거 필터[lightgray] (재시작 필요)[] setting.antialias.name = 위신호 제거 필터[lightgray] (재시작 필요)[]
@@ -1536,12 +1540,30 @@ lst.unitcontrol = 현재 지정된 유닛을 조종하기
lst.unitradar = 현재 지정된 유닛 주변의 유닛 검색하기 lst.unitradar = 현재 지정된 유닛 주변의 유닛 검색하기
lst.unitlocate = 특정 유형의 위치/건물을 지도상에서 찾기\n지정된 유닛이 필요합니다. lst.unitlocate = 특정 유형의 위치/건물을 지도상에서 찾기\n지정된 유닛이 필요합니다.
lenum.type = 건물/유닛의 타입\n예로 분배기는 [accent]@router[]를 반환할 것입니다.\n문자열이 아니라. logic.nounitbuild = [red]유닛의 건물 로직은 여기서 허용되지 않습니다.
lenum.type = 건물/유닛의 타입\n예로 분배기는 문자열이 아니라 [accent]@router[]를 반환합니다.
lenum.shoot = 특정 위치에 발사 lenum.shoot = 특정 위치에 발사
lenum.shootp = 목표물 속도를 예측하여 발사 lenum.shootp = 목표물 속도를 예측하여 발사
lenum.configure = 필터의 아이템같은 건물의 설정 lenum.configure = 필터의 아이템같은 건물의 설정
lenum.enabled = 블록의 활성 여부 lenum.enabled = 블록의 활성 여부
lenum.color = 조명 색 설정 lenum.color = 조명 색 설정
laccess.controller = 유닛 제어자. 프로세서가 제어하면, 프로세서를 반환합니다.\n다른 유닛에 의해 지휘되면(G키), 지휘하는 유닛을 반환합니다.\n그 외에는 자신을 반환합니다.
laccess.dead = 유닛 또는 건물 사망/무효 여부
laccess.controlled = 만약 유닛 제어자가 프로세서라면 [accent]@ctrlProcessor[]를 반환합니다.\n만약 유닛/건물 제어자가 플레이어라면 [accent]@ctrlPlayer[]를 반환합니다.\n만약 유닛이 다른 유닛에 의해 지휘되면(G키)[accent]@ctrlFormation[]를 반환합니다.\n그 외에는 0을 반환합니다.
laccess.commanded = [red]이제 사용되지 않으며, 곧 제거될 예정입니다![]\n대신 [accent]controlled[]를 사용하세요.
graphicstype.clear = 이 색으로 화면을 채우기
graphicstype.color = 아래 그래픽 실행문들의 색 설정하기
graphicstype.stroke = 선 굵기 설정하기
graphicstype.line = 선분 그리기
graphicstype.rect = 직사각형 채우기
graphicstype.linerect = 직사각형 외곽선 그리기
graphicstype.poly = 정다각형 채우기
graphicstype.linepoly = 정다각형 외곽선 그리기
graphicstype.triangle = 삼각형 채우기
graphicstype.image = 일부 콘텐츠의 이미지 그리기\n예: [accent]@router[] 또는 [accent]@dagger[].
lenum.always = 항상 참 lenum.always = 항상 참
lenum.idiv = 정수 나누기 lenum.idiv = 정수 나누기
@@ -1566,7 +1588,7 @@ lenum.sin = 사인(도)
lenum.cos = 코사인(도) lenum.cos = 코사인(도)
lenum.tan = 탄젠트(도) lenum.tan = 탄젠트(도)
#not a typo, look up 'range notation' #not a typo, look up 'range notation'
lenum.rand = 범위 내 난수[0 ~ 값) lenum.rand = 범위 내 십진법 난수[0 ~ 값)
lenum.log = 자연 로그(진수) lenum.log = 자연 로그(진수)
lenum.log10 = 상수 로그 lenum.log10 = 상수 로그
lenum.noise = 2D 심플렉스 노이즈 lenum.noise = 2D 심플렉스 노이즈
@@ -1596,7 +1618,7 @@ lenum.rally = 지휘소
lenum.battery = 배터리 lenum.battery = 배터리
lenum.resupply = 보급 지점.\n[accent]"유닛 탄약 필요"[]가 활성화되었을 때만 유의미합니다. lenum.resupply = 보급 지점.\n[accent]"유닛 탄약 필요"[]가 활성화되었을 때만 유의미합니다.
lenum.reactor = 핵융합로/토륨 원자로 lenum.reactor = 핵융합로/토륨 원자로
lenum.turret = 포탑 lenum.turret = 포탑
sensor.in = 감지할 건물/유닛 sensor.in = 감지할 건물/유닛
@@ -1624,6 +1646,7 @@ unitlocate.outx = X좌표
unitlocate.outy = Y좌표 unitlocate.outy = Y좌표
unitlocate.group = 찾을 건물 집단 unitlocate.group = 찾을 건물 집단
lenum.idle = 채광/건설 제외 이동만 중단\n기본 상태입니다.
lenum.stop = 이동/채광/건설 중단 lenum.stop = 이동/채광/건설 중단
lenum.move = 특정 위치로 이동 lenum.move = 특정 위치로 이동
lenum.approach = 특정 위치로 반지름만큼 접근 lenum.approach = 특정 위치로 반지름만큼 접근
@@ -1640,3 +1663,205 @@ lenum.build = 구조물 건설
lenum.getblock = 특정 좌표의 빌딩과 블록을 반환합니다.\n위치는 유닛의 인지 범위 내여야 합니다.\n자연 지형은 [accent]@solid[]의 타입을 가집니다. lenum.getblock = 특정 좌표의 빌딩과 블록을 반환합니다.\n위치는 유닛의 인지 범위 내여야 합니다.\n자연 지형은 [accent]@solid[]의 타입을 가집니다.
lenum.within = 좌표 주변 유닛 발견 여부 lenum.within = 좌표 주변 유닛 발견 여부
lenum.boost = 이륙 시작/중단 lenum.boost = 이륙 시작/중단
#1665 줄 매칭
#-------------비공식 번역주-------------
#팁, 패치 기록, 약간의 관련 드립을 넣는 곳입니다. 이미 쓰여진 줄이 있다면 \n\n를 입력한 다음 작성하고 끝에 깃허브 작성자 닉네임(또는 디스코드)을 적어주세요.
#심각한 노잼, 뇌절, 무례한 말들을 적지 말아주세요, 이는 목적이 어떠하든 공통적으로 적용됩니다(친근함 유도를 위한 평어 x). 다음 패치에 업데이트되어 그 언어를 쓰는 모든 유저가 보게 됩니다.
#양이 너무 많으면 사족을 더 붙이는걸 추천하지 않습니다.
#이 비공식 번역주는 공식 디테일이 추가되면 언제든지 삭제될 수 있습니다.
#비어있는 디테일은 아래 details가 전부이므로 추가 또는 삭제를 따로 안하셔도 됩니다.
#유색코드가 아닌, 흑백 색코드만 사용 가능합니다. 되도록이면 그냥 안쓰시는걸 추천.
#관련 문의는 공식 디스코드에서 절 불러주세요. Sharlotte#0018
#아이템
item.metaglass.details = 쓰임세가 가장 적은 아이템
item.graphite.details =
item.sand.details =
item.titanium.details =
item.thorium.details =
item.silicon.details =
item.plastanium.details =
item.phase-fabric.details =
item.surge-alloy.details =
item.blast-compound.details = 화력 발전기에 넣어보세요.
item.pyratite.details =
#액체
liquid.water.details =
liquid.slag.details =
liquid.oil.details =
liquid.cryofluid.details = 티타늄을 갈아서 물에 희석했다는 소문이 있다.
#블록
block.resupply-point.details =
block.armored-conveyor.details =
block.illuminator.details =
block.message.details =
block.graphite-press.details =
block.multi-press.details =
block.silicon-smelter.details =
block.kiln.details =
block.plastanium-compressor.details = 석유를 정말 많이 먹는다.
block.phase-weaver.details =
block.alloy-smelter.details =
block.cryofluid-mixer.details =
block.blast-mixer.details =
block.pyratite-mixer.details =
block.melter.details =
block.separator.details =
block.spore-press.details =
block.pulverizer.details =
block.coal-centrifuge.details = 가성비가 매우 뛰어나다.
block.incinerator.details =
block.power-void.details =
block.power-source.details =
block.item-source.details =
block.item-void.details =
block.liquid-source.details =
block.liquid-void.details =
block.copper-wall.details =
block.copper-wall-large.details =
block.titanium-wall.details =
block.titanium-wall-large.details =
block.plastanium-wall.details =
block.plastanium-wall-large.details =
block.thorium-wall.details =
block.thorium-wall-large.details =
block.phase-wall.details =
block.phase-wall-large.details =
block.surge-wall.details =
block.surge-wall-large.details =
block.door.details =
block.door-large.details =
block.mender.details =
block.mend-projector.details =
block.overdrive-projector.details =
block.force-projector.details =
block.shock-mine.details =
block.conveyor.details =
block.titanium-conveyor.details =
block.plastanium-conveyor.details =
block.junction.details =
block.bridge-conveyor.details = 티타늄 컨베이어보다 빠르다.
block.phase-conveyor.details =
block.sorter.details = 자원을 분류하여 주변 블록에 건내는 과정이 거의 한순간에 일어난다.
block.inverted-sorter.details =
block.distributor.details =
block.overflow-gate.details =
block.underflow-gate.details =
block.mass-driver.details = 발사할려면 최소 아이템 10개가 필요하다.
block.mechanical-pump.details =
block.rotary-pump.details =
block.thermal-pump.details =
block.conduit.details =
block.pulse-conduit.details =
block.plated-conduit.details =
block.liquid-router.details =
block.liquid-tank.details =
block.liquid-junction.details =
block.bridge-conduit.details =
block.phase-conduit.details =
block.power-node.details =
block.power-node-large.details =
block.surge-tower.details =
block.diode.details =
block.battery.details =
block.battery-large.details =
block.combustion-generator.details =
block.thermal-generator.details =
block.steam-generator.details =
block.differential-generator.details =
block.rtg-generator.details =
block.solar-panel.details =
block.solar-panel-large.details =
block.thorium-reactor.details =
block.impact-reactor.details =
block.mechanical-drill.details =
block.pneumatic-drill.details =
block.laser-drill.details =
block.blast-drill.details =
block.water-extractor.details =
block.cultivator.details =
block.cultivator.details =
block.oil-extractor.details =
block.vault.details =
block.container.details =
block.unloader.details =
block.launch-pad.details =
block.duo.details =
block.scatter.details =
block.scorch.details =
block.hail.details = 일점사하면 립플보다 더 뛰어난 정확도와 연사력을 보여준다.
block.wave.details =
block.lancer.details =
block.arc.details =
block.swarmer.details =
block.salvo.details =
block.fuse.details =
block.ripple.details =
block.cyclone.details =
block.spectre.details =
block.meltdown.details =
block.foreshadow.details =
block.repair-point.details =
block.segment.details =
block.parallax.details =
block.tsunami.details =
block.silicon-crucible.details =
block.disassembler.details =
block.overdrive-dome.details =
block.payload-conveyor.details =
block.payload-router.details =
block.command-center.details =
block.ground-factory.details =
block.air-factory.details = 건설&연구 재료는 구리와 납뿐이지만, 정작 유닛을 생산할 땐 실리콘이 필요하다.
block.naval-factory.details =
block.additive-reconstructor.details =
block.multiplicative-reconstructor.details =
block.exponential-reconstructor.details =
block.tetrative-reconstructor.details =
block.switch.details =
block.micro-processor.details =
block.logic-processor.details =
block.hyper-processor.details =
block.memory-cell.details =
block.memory-bank.details =
block.logic-display.details =
block.large-logic-display.details =
block.interplanetary-accelerator.details =
#유닛
unit.dagger.details = 이전에 디거란 이명으로 종교가 생겼었다.
unit.mace.details =
unit.fortress.details =
unit.scepter.details =
unit.reign.details =
unit.nova.details =
unit.pulsar.details =
unit.quasar.details =
unit.vela.details =
unit.corvus.details = 정말 느리다.
unit.crawler.details = 최근에 자폭 AI가 향상되면서 컨베이어로 자폭을 유도할 수 없게 되었다.
unit.atrax.details =
unit.spiroct.details =
unit.arkyid.details =
unit.toxopid.details =
unit.flare.details =
unit.horizon.details =
unit.zenith.details =
unit.antumbra.details =
unit.eclipse.details =
unit.mono.details =
unit.poly.details =
unit.mega.details =
unit.quad.details =
unit.oct.details =
unit.risso.details = 뭉치면 연사력이 무시무시하다.
unit.minke.details =
unit.bryde.details =
unit.sei.details =
unit.omura.details =
unit.alpha.details =
unit.beta.details =
unit.gamma.details =

View File

@@ -216,9 +216,11 @@ server.hidden = Ascunse
trace = Urmărește Jucător trace = Urmărește Jucător
trace.playername = Nume jucător: [accent]{0} trace.playername = Nume jucător: [accent]{0}
trace.ip = IP: [accent]{0} trace.ip = IP: [accent]{0}
trace.id = ID unic: [accent]{0} trace.id = ID: [accent]{0}
trace.mobile = Client Mobil: [accent]{0} trace.mobile = Client Mobil: [accent]{0}
trace.modclient = Client Personalizat: [accent]{0} trace.modclient = Client Personalizat: [accent]{0}
trace.times.joined = A Intrat: de [accent]{0}[] ori
trace.times.kicked = Dat Afară: de [accent]{0}[] ori
invalidid = ID client invalid! Raportează bugul. invalidid = ID client invalid! Raportează bugul.
server.bans = Interziși server.bans = Interziși
server.bans.none = Nu s-au găsit jucători intreziși! server.bans.none = Nu s-au găsit jucători intreziși!
@@ -800,7 +802,8 @@ setting.logichints.name = Indicii Procesoare Logice
setting.flow.name = Afișează Rata de Curgere a lichidelor setting.flow.name = Afișează Rata de Curgere a lichidelor
setting.buildautopause.name = Autopauză de la Construit setting.buildautopause.name = Autopauză de la Construit
setting.backgroundpause.name = Pune Pauză în Fundal setting.backgroundpause.name = Pune Pauză în Fundal
setting.modcrashdisable = Dezactivează Modurile în Cazul unui Crash la Pornire setting.doubletapmine.name = Dublu-Click pt a Mina
setting.modcrashdisable.name = Dezactivează Modurile în Cazul unui Crash la Pornire
setting.animatedwater.name = Suprafețe Animate setting.animatedwater.name = Suprafețe Animate
setting.animatedshields.name = Scuturi Animate setting.animatedshields.name = Scuturi Animate
setting.antialias.name = Antialiasing[lightgray] (necesită repornire)[] setting.antialias.name = Antialiasing[lightgray] (necesită repornire)[]
@@ -1537,16 +1540,22 @@ lst.unitcontrol = Controlează unitatea controlată de procesor.
lst.unitradar = Localizează unitățile din jurul unității controlate de procesor. lst.unitradar = Localizează unitățile din jurul unității controlate de procesor.
lst.unitlocate = Localizează o poziție/clădire specifică oriunde pe hartă.\nNecesită o unitate controlată de procesor. lst.unitlocate = Localizează o poziție/clădire specifică oriunde pe hartă.\nNecesită o unitate controlată de procesor.
logic.nounitbuild = [red]Nu ai voie să construiești cu unitățile folosind procesoare.
lenum.type = Tipul clădirii/unității.\nde ex.: pt orice Router, va returna [accent]@router[].\nNu e un șir de caractere. lenum.type = Tipul clădirii/unității.\nde ex.: pt orice Router, va returna [accent]@router[].\nNu e un șir de caractere.
lenum.shoot = Lovește către o locație. lenum.shoot = Lovește către o locație.
lenum.shootp = Lovește către o unitate/clădire. Anticipează viteza țintei și a proiectilului. lenum.shootp = Lovește către o unitate/clădire. Anticipează viteza țintei și a proiectilului.
lenum.configure = Configurașia clădirii, de ex. materialul selectat pt Sortator. lenum.configure = Configurația clădirii, de ex. materialul selectat pt Sortator.
lenum.enabled = Specifică dacă clădirea este pornită. lenum.enabled = Specifică dacă clădirea este pornită.
laccess.color = Culoarea iluminatorului. laccess.color = Culoarea iluminatorului.
laccess.controller = Controlorul unității. Dacă e controlată de procesor, returnează procesorul.\nDacă e într-o formație, returnează liderul.\nAltfel, returnează unitatea însăși.
laccess.dead = Specifică dacă o unitate sau clădire a murit/nu mai e validă.
laccess.controlled = Returnează:\n[accent]@ctrlProcessor[] dacă controlorul unității e procesor\n[accent]@ctrlPlayer[] dacă controlorul unității/clădirii e jucător\n[accent]@ctrlFormation[] dacă unitatea e într-o formație\nAltfel dă 0.
laccess.commanded = [red]Învechit. Se va șterge![]\nFolosește [accent]controlled[].
graphicstype.clear = Umple monitorul cu o culoare. graphicstype.clear = Umple monitorul cu o culoare.
graphicstype.color = Setează culoarea pt următoarea instrucțiune Draw. graphicstype.color = Setează culoarea pt următoarele instrucțiuni Draw.
graphicstype.stroke = Setează grosimea liniei. graphicstype.stroke = Setează grosimea liniei.
graphicstype.line = Desenează un segment de linie. graphicstype.line = Desenează un segment de linie.
graphicstype.rect = Desenează un dreptunghi. graphicstype.rect = Desenează un dreptunghi.
@@ -1579,7 +1588,7 @@ lenum.sin = Sinus în grade.
lenum.cos = Cosinus în grade. lenum.cos = Cosinus în grade.
lenum.tan = Tangentă în grade. lenum.tan = Tangentă în grade.
#cea de mai jos nu-i o greșeală, caută pe net notarea intervalelor în matematică #cea de mai jos nu-i o greșeală, caută pe net notarea intervalelor în matematică
lenum.rand = Număr aleatoriu în intervalul [0, val). lenum.rand = Număr natural aleatoriu în intervalul [0, val).
lenum.log = Logaritm natural (ln). lenum.log = Logaritm natural (ln).
lenum.log10 = Logaritm în baza 10. lenum.log10 = Logaritm în baza 10.
lenum.noise = 2D simplex noise. lenum.noise = 2D simplex noise.
@@ -1637,6 +1646,7 @@ unitlocate.outx = Coordonata X a obiectului detectat.
unitlocate.outy = Coordonata Y a obiectului detectat. unitlocate.outy = Coordonata Y a obiectului detectat.
unitlocate.group = Grupul clădirilor de detectat. unitlocate.group = Grupul clădirilor de detectat.
lenum.idle = Nu mișca, dar continuă să construiești/minezi.\nModul prestabilit.
lenum.stop = Oprește acțiunea curentă. Nu mișca/mina/construi. lenum.stop = Oprește acțiunea curentă. Nu mișca/mina/construi.
lenum.move = Mergi la această poziție. lenum.move = Mergi la această poziție.
lenum.approach = Apropie-te la o anumită distanță de poziție. lenum.approach = Apropie-te la o anumită distanță de poziție.

View File

@@ -113,7 +113,7 @@ committingchanges = Внесение изменений
done = Готово done = Готово
feature.unsupported = Ваше устройство не поддерживает эту возможность. feature.unsupported = Ваше устройство не поддерживает эту возможность.
mods.alphainfo = Имейте в виду, что модификации находятся в альфа-версии и [scarlet]могут содержать много ошибок[]. Докладывайте о любых проблемах, которые вы найдете в Mindustry Github. mods.initfailed = [red]⚠[] Не удалось инициализировать предыдущий запуск Mindustry. Это могло быть вызвано неисправными модификациями.\n\nЧтобы предотвратить зацикленные вылеты игры, [red]все модификации были отключены.[]\n\nЧтобы отключить эту функцию, выключите её в [accent]Настройки->Игра->Отключение модификаций после вылета при запуске[].
mods = Модификации mods = Модификации
mods.none = [lightgray]Модификации не найдены! mods.none = [lightgray]Модификации не найдены!
mods.guide = Руководство по модификациям mods.guide = Руководство по модификациям
@@ -126,6 +126,7 @@ mod.installed = [[Установлено]
mod.display = [gray]Модификация:[orange] {0} mod.display = [gray]Модификация:[orange] {0}
mod.enabled = [lightgray]Включён mod.enabled = [lightgray]Включён
mod.disabled = [scarlet]Выключен mod.disabled = [scarlet]Выключен
mod.multiplayer.compatible = [gray]Доступна в игре по сети
mod.disable = Выкл. mod.disable = Выкл.
mod.content = Содержимое: mod.content = Содержимое:
mod.delete.error = Невозможно удалить модификацию. Возможно, файл используется. mod.delete.error = Невозможно удалить модификацию. Возможно, файл используется.
@@ -217,6 +218,8 @@ trace = Отслеживать игрока
trace.playername = Имя игрока: [accent]{0} trace.playername = Имя игрока: [accent]{0}
trace.ip = IP: [accent]{0} trace.ip = IP: [accent]{0}
trace.id = ID: [accent]{0} trace.id = ID: [accent]{0}
trace.times.joined = Присоединялся раз: [accent]{0}
trace.times.kicked = Был выгнан раз: [accent]{0}
trace.mobile = Мобильный клиент: [accent]{0} trace.mobile = Мобильный клиент: [accent]{0}
trace.modclient = Пользовательский клиент: [accent]{0} trace.modclient = Пользовательский клиент: [accent]{0}
invalidid = Недопустимый ID клиента! Отправьте отчёт об ошибке. invalidid = Недопустимый ID клиента! Отправьте отчёт об ошибке.
@@ -771,8 +774,8 @@ unit.itemssecond = предметов/секунду
unit.liquidunits = жидкостных единиц unit.liquidunits = жидкостных единиц
unit.powerunits = энерг. единиц unit.powerunits = энерг. единиц
unit.degrees = ° unit.degrees = °
unit.seconds = сек. unit.seconds = сек
unit.minutes = мин. unit.minutes = мин
unit.persecond = /сек unit.persecond = /сек
unit.perminute = /мин unit.perminute = /мин
unit.timesspeed = x скорость unit.timesspeed = x скорость
@@ -800,6 +803,8 @@ setting.logichints.name = Подсказки для логики
setting.flow.name = Показывать скорость потока ресурсов setting.flow.name = Показывать скорость потока ресурсов
setting.backgroundpause.name = Фоновая пауза setting.backgroundpause.name = Фоновая пауза
setting.buildautopause.name = Автоматическая приостановка строительства setting.buildautopause.name = Автоматическая приостановка строительства
setting.doubletapmine.name = Добыча руды двойным нажатием
setting.modcrashdisable.name = Отключение модификаций после вылета при запуске
setting.animatedwater.name = Анимированные поверхности setting.animatedwater.name = Анимированные поверхности
setting.animatedshields.name = Анимированные щиты setting.animatedshields.name = Анимированные щиты
setting.antialias.name = Сглаживание[lightgray] (требует перезапуска)[] setting.antialias.name = Сглаживание[lightgray] (требует перезапуска)[]
@@ -1536,6 +1541,8 @@ lst.unitcontrol = Управляет привязанной в данный мо
lst.unitradar = Обнаруживает единицы вокруг привязанной в данный момент единицы. lst.unitradar = Обнаруживает единицы вокруг привязанной в данный момент единицы.
lst.unitlocate = Обнаруживает позицию/постройку определённого типа где-либо на карте. Требует привязанную единицу. lst.unitlocate = Обнаруживает позицию/постройку определённого типа где-либо на карте. Требует привязанную единицу.
logic.nounitbuild = [red]Строительство с помощью процессоров здесь запрещено.
lenum.type = Тип постройки/единицы. \nНапример, для маршрутизатора это будет [accent]@router[].\nНе строка. lenum.type = Тип постройки/единицы. \nНапример, для маршрутизатора это будет [accent]@router[].\nНе строка.
lenum.shoot = Стрельба в определённую позицию. lenum.shoot = Стрельба в определённую позицию.
lenum.shootp = Стрельба в единицу/постройку с расчётом скорости. lenum.shootp = Стрельба в единицу/постройку с расчётом скорости.
@@ -1543,6 +1550,21 @@ lenum.configure = Конфигурация постройки, например,
lenum.enabled = Включён ли блок. lenum.enabled = Включён ли блок.
laccess.color = Цвет осветителя. laccess.color = Цвет осветителя.
laccess.controller = Командующий единицей. Если единица управляется процессором, возвращает процессор. Если в строю, возращает командуещего.\nВ противном случае возвращает саму единицу.
laccess.dead = Является ли единица/постройка неработающей или несуществующей.
laccess.controlled = Возвращает:\n[accent]@ctrlProcessor[] если единица управляется процессором\n[accent]@ctrlPlayer[] если единица/постройка управляется игроком\n[accent]@ctrlFormation[] если единица в строю\nВ противном случае — 0.
laccess.commanded = [red]Устарело. Будет удалено![]\nВместо этого, используйте [accent]controlled[].
graphicstype.clear = Заливка дисплея цветом.
graphicstype.color = Установка цвета для следующих операций отрисовки.
graphicstype.stroke = Установка толщины линии.
graphicstype.line = Отрисовка отрезка.
graphicstype.rect = Отрисовка закрашенного прямоугольника.
graphicstype.linerect = Отрисовка контура прямоугольника.
graphicstype.poly = Отрисовка закрашенного правильного многоугольника.
graphicstype.linepoly = Отрисовка контура правильного многоугольника.
graphicstype.triangle = Отрисовка закрашенного треугольника.
graphicstype.image = Отрисовка внутриигровых спрайтов.\nНапример: [accent]@router[] или [accent]@dagger[].
lenum.always = Всегда истина. lenum.always = Всегда истина.
lenum.idiv = Целочисленное деление. lenum.idiv = Целочисленное деление.
@@ -1625,7 +1647,8 @@ unitlocate.outx = Вывод X координаты.
unitlocate.outy = Вывод Y координаты. unitlocate.outy = Вывод Y координаты.
unitlocate.group = Группа построек для поиска. unitlocate.group = Группа построек для поиска.
lenum.stop = Остановка передвижения/копания/стротельства. lenum.idle = Остановка движения, но продолжение строительства/копания.\nСостояние по умолчанию.
lenum.stop = Остановка передвижения/копания/строительства.
lenum.move = Перемещение в определённую позицию. lenum.move = Перемещение в определённую позицию.
lenum.approach = Приближение к позиции с указанным радиусом. lenum.approach = Приближение к позиции с указанным радиусом.
lenum.pathfind = Перемещение к точке появления врагов. lenum.pathfind = Перемещение к точке появления врагов.

View File

@@ -13,6 +13,7 @@ link.google-play.description = Google Play store listing
link.f-droid.description = F-Droid listing link.f-droid.description = F-Droid listing
link.wiki.description = Mindustry wiki chính thức link.wiki.description = Mindustry wiki chính thức
link.suggestions.description = Đề xuất các tính năng mới link.suggestions.description = Đề xuất các tính năng mới
link.bug.description = Tìm thấy lỗi? Báo cáo nó ở đây
linkfail = Không mở được liên kết!\nURL đã được sao chép vào bộ nhớ tạm. linkfail = Không mở được liên kết!\nURL đã được sao chép vào bộ nhớ tạm.
screenshot = Ảnh chụp màn hình được lưu vào {0} screenshot = Ảnh chụp màn hình được lưu vào {0}
screenshot.invalid = Bản đồ quá lớn, có khả năng không đủ bộ nhớ để chụp ảnh màn hình. screenshot.invalid = Bản đồ quá lớn, có khả năng không đủ bộ nhớ để chụp ảnh màn hình.
@@ -40,6 +41,14 @@ be.ignore = Bỏ qua
be.noupdates = Không tìm thấy bản cập nhật mới. be.noupdates = Không tìm thấy bản cập nhật mới.
be.check = Kiểm tra các bản cập nhật. be.check = Kiểm tra các bản cập nhật.
mods.browser = Duyệt mod
mods.browser.selected = Mod Đã chọn
mods.browser.add = Cài đặt
mods.browser.reinstall = Cài đặt lại
mods.github.open = Repo
mods.browser.sortdate = Sắp xếp theo gần đây
mods.browser.sortstars = Sắp xếp theo sao
schematic = Bản thiết kế schematic = Bản thiết kế
schematic.add = Lưu bản thiết kế... schematic.add = Lưu bản thiết kế...
schematics = Các bản thiết kế schematics = Các bản thiết kế
@@ -50,7 +59,7 @@ schematic.exportfile = Xuất tệp
schematic.importfile = Nhập tệp schematic.importfile = Nhập tệp
schematic.browseworkshop = Duyệt qua Workshop schematic.browseworkshop = Duyệt qua Workshop
schematic.copy = Sao chép vào bộ nhớ tạm schematic.copy = Sao chép vào bộ nhớ tạm
schematic.copy.import = Nhập từ bộ nhớ tạm schematic.copy.import = Thêm từ bộ nhớ tạm
schematic.shareworkshop = Chia sẻ từ Workshop schematic.shareworkshop = Chia sẻ từ Workshop
schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Lật bản thiết kế schematic.flip = [accent][[{0}][]/[accent][[{1}][]: Lật bản thiết kế
schematic.saved = Đã lưu bản thiết kế. schematic.saved = Đã lưu bản thiết kế.
@@ -75,14 +84,15 @@ level.highscore = Điểm cao nhất: [accent]{0}
level.select = Chọn cấp độ level.select = Chọn cấp độ
level.mode = Chế độ: level.mode = Chế độ:
coreattack = < Căn cứ đang bị tấn công! > coreattack = < Căn cứ đang bị tấn công! >
nearpoint = [[ [scarlet]RỜI KHỎI ĐIỂM THẢ NGAY LẬP TỨC[] ]\nsự hủy diệt sắp xảy ra nearpoint = [[ [scarlet]RỜI KHỎI KHU VỰC ĐÁP NGAY LẬP TỨC[] ]\nsự hủy diệt sắp xảy ra
database = Cơ sở dữ liệu database = Cơ sở dữ liệu
savegame = Lưu trò chơi savegame = Lưu trò chơi
loadgame = Tải trò chơi loadgame = Tải lại màn chơi
joingame = Tham gia trò chơi joingame = Tham gia trò chơi
customgame = Tùy chỉnh customgame = Tùy chỉnh
newgame = Trò chơi mới newgame = Trò chơi mới
none = <trống> none = <trống>
none.found = [lightgray]<không tìm thấy>
minimap = Bản đồ nhỏ minimap = Bản đồ nhỏ
position = Vị trí position = Vị trí
close = Đóng close = Đóng
@@ -90,9 +100,9 @@ website = Website
quit = Thoát quit = Thoát
save.quit = Lưu & Thoát save.quit = Lưu & Thoát
maps = Bản đồ maps = Bản đồ
maps.browse = Duyệt bản đồ maps.browse = Chọn bản đồ
continue = Tiếp tục continue = Tiếp tục
maps.none = [lightgray]Không có bản đồ nào được tìm thấy! maps.none = [lightgray]Không tìm thấy bản đồ!
invalid = Không hợp lệ invalid = Không hợp lệ
pickcolor = Chọn màu pickcolor = Chọn màu
preparingconfig = Đang chuẩn bị cấu hình preparingconfig = Đang chuẩn bị cấu hình
@@ -103,14 +113,16 @@ committingchanges = Đang cập nhật các thay đổi
done = Hoàn tất done = Hoàn tất
feature.unsupported = Thiết bị của bạn không hỗ trợ tính năng này. feature.unsupported = Thiết bị của bạn không hỗ trợ tính năng này.
mods.alphainfo = Hãy nhớ rằng các bản mod đang ở giai đoạn alpha, và[scarlet] có thể chứa rất rất lỗi[].\nBáo cáo bất kỳ vấn đề nào bạn gặp phải tại Mindustry GitHub. mods.initfailed = [red]⚠[] Mindustry không khởi chạy được. Điều này có thể do các mod bị lỗi.\n\nĐể tránh gặp sự cố liên tiếp, [red]tất cả các mod đã bị tắt.[]\n\nĐể tắt tính năng này, vào [accent]Cài đặt->Trò chơi->Tắt các mod khi gặp sự cố trong khởi động[].
mods = Mods mods = Mods
mods.none = [lightgray]Không có mod nào được tìm thấy! mods.none = [lightgray]Không tìm thấy mod!
mods.guide = Hướng dẫn mod mods.guide = Hướng dẫn mod
mods.report = Báo lỗi mods.report = Báo lỗi
mods.openfolder = Mở thư mục mods.openfolder = Mở thư mục
mods.viewcontent = Xem nội dung
mods.reload = Tải lại mods.reload = Tải lại
mods.reloadexit = Trò chơi sẽ đóng để tải lại mod. mods.reloadexit = Trò chơi sẽ đóng để mod được tải.
mod.installed = [[Đã cài đặt]
mod.display = [gray]Mod:[orange] {0} mod.display = [gray]Mod:[orange] {0}
mod.enabled = [lightgray]Đã Bật mod.enabled = [lightgray]Đã Bật
mod.disabled = [scarlet]Đã Tắt mod.disabled = [scarlet]Đã Tắt
@@ -122,21 +134,21 @@ mod.outdated = [scarlet]Không tương thích với V6 (no minGameVersion: 105)
mod.missingdependencies = [scarlet]Thiếu phụ thuộc: {0} mod.missingdependencies = [scarlet]Thiếu phụ thuộc: {0}
mod.erroredcontent = [scarlet]Lỗi nội dung mod.erroredcontent = [scarlet]Lỗi nội dung
mod.errors = Đã xảy ra lỗi khi tải nội dung. mod.errors = Đã xảy ra lỗi khi tải nội dung.
mod.noerrorplay = [scarlet]Bạn có mod bị lỗi.[]Tắt các mod bị ảnh hưởng hoặc sửa chữa các lỗi trước khi chơi. mod.noerrorplay = [scarlet]Bạn có mod bị lỗi.[]Tắt các mod bị lỗi hoặc sửa các lỗi trước khi chơi.
mod.nowdisabled = [scarlet]Mod '{0}' cần mod này để chạy:[accent] {1}\n[lightgray]Trước tiên bạn cần tải các mod này xuống.\nBản mod này sẽ tự động tắt. mod.nowdisabled = [scarlet]Mod '{0}' cần mod này để chạy:[accent] {1}\n[lightgray]Trước tiên bạn cần tải các mod này xuống.\nBản mod này sẽ tự động tắt.
mod.enable = Bật mod.enable = Bật
mod.requiresrestart = Trò chơi sẽ đóng để áp dụng các thay đổi của mod. mod.requiresrestart = Trò chơi sẽ đóng để áp dụng các thay đổi của mod.
mod.reloadrequired = [scarlet]Yêu cầu khởi động lại mod.reloadrequired = [scarlet]Yêu cầu khởi động lại
mod.import = Nhập Mod mod.import = Thêm Mod
mod.import.file = Nhập tệp mod.import.file = Thêm từ tệp
mod.import.github = Nhập từ GitHub mod.import.github = Thêm từ GitHub
mod.jarwarn = [scarlet]JAR mod vốn dĩ không an toàn.[]\nĐảm bảo rằng bạn đang nhập bản mod này từ một nguồn đáng tin cậy! mod.jarwarn = [scarlet]Các JAR mod vốn dĩ không an toàn.[]\nĐảm bảo rằng bạn đang thêm mod này từ một nguồn đáng tin cậy!
mod.item.remove = Mục này là một phần của[accent] '{0}'[] mod. Để xóa nó, hãy gỡ cài đặt mod này. mod.item.remove = Mục này là một phần của[accent] '{0}'[] mod. Để xóa nó, hãy gỡ cài đặt mod này.
mod.remove.confirm = Mod này sẽ bị xóa. mod.remove.confirm = Mod này sẽ bị xóa.
mod.author = [lightgray]Tác giả:[] {0} mod.author = [lightgray]Tác giả:[] {0}
mod.missing = Bản lưu này chứa các mod mà bạn đã cập nhật gần đây hoặc không còn cài đặt nữa. Có thể gây ra lỗi khi mở. Bạn có chắc muốn mở nó?\n[lightgray]Mods:\n{0} mod.missing = Bản lưu này chứa các mod mà bạn đã cập nhật gần đây hoặc không được cài đặt. Có thể gây ra lỗi khi mở. Bạn có chắc muốn mở nó?\n[lightgray]Mods:\n{0}
mod.preview.missing = Trước khi xuất bản bản mod này lên workshop, bạn phải thêm hình ảnh xem trước.\nĐặt một hình ảnh có tên[accent] preview.png[] vào thư mục của mod và thử lại. mod.preview.missing = Trước khi đăng bản mod này lên workshop, bạn phải thêm hình ảnh xem trước.\nĐặt một hình ảnh có tên[accent] preview.png[] vào thư mục của mod và thử lại.
mod.folder.missing = Chỉ có thể xuất bản các mod ở dạng thư mục lên workshop.\nĐể chuyển đổi bất kỳ mod nào thành một thư mục, chỉ cần giải nén tệp của nó vào một thư mục và xóa tệp nén cũ, sau đó khởi động lại trò chơi của bạn hoặc tải lại các bản mod của bạn. mod.folder.missing = Chỉ có thể đăng các mod ở dạng thư mục lên workshop.\nĐể chuyển đổi bất kỳ mod nào thành một thư mục, chỉ cần giải nén tệp của nó vào một thư mục và xóa tệp nén cũ, sau đó khởi động lại trò chơi của bạn hoặc tải lại các bản mod của bạn.
mod.scripts.disable = Thiết bị của bạn không hổ trợ mod chứa scripts này. Bạn phải tắt các mod này để chơi trò chơi. mod.scripts.disable = Thiết bị của bạn không hổ trợ mod chứa scripts này. Bạn phải tắt các mod này để chơi trò chơi.
about.button = Thông tin about.button = Thông tin
@@ -196,6 +208,7 @@ servers.local = Máy chủ cục bộ
servers.remote = Máy chủ tùy chỉnh servers.remote = Máy chủ tùy chỉnh
servers.global = Máy chủ từ cộng đồng servers.global = Máy chủ từ cộng đồng
servers.disclaimer = Nhà phát triển [accent]không[] sở hữu và kiểm soát máy chủ cộng đồng.\n\nMáy chủ có thể chứa nội dung do người dùng tạo và không phù hợp với mọi lứa tuổi.
servers.showhidden = Hiển thị Máy chủ Ẩn servers.showhidden = Hiển thị Máy chủ Ẩn
server.shown = Hiện server.shown = Hiện
server.hidden = Ẩn server.hidden = Ẩn
@@ -279,6 +292,7 @@ cancel = Hủy
openlink = Mở link openlink = Mở link
copylink = Sao chép link copylink = Sao chép link
back = Quay lại back = Quay lại
max = Tối đa
crash.export = Xuất Crash Logs crash.export = Xuất Crash Logs
crash.none = Không có Crash Logs nào được tìm thấy. crash.none = Không có Crash Logs nào được tìm thấy.
crash.exported = Crash logs đã được xuất. crash.exported = Crash logs đã được xuất.
@@ -298,6 +312,7 @@ cancelbuilding = [accent][[{0}][] để hủy xây
selectschematic = [accent][[{0}][] to để chọn+sao chép selectschematic = [accent][[{0}][] to để chọn+sao chép
pausebuilding = [accent][[{0}][] để tạm dừng xây dựng pausebuilding = [accent][[{0}][] để tạm dừng xây dựng
resumebuilding = [scarlet][[{0}][] để tiếp tục xây dựng resumebuilding = [scarlet][[{0}][] để tiếp tục xây dựng
enablebuilding = [scarlet][[{0}][] để bật xây dựng
showui = UI hidden.\nPress [accent][[{0}][] để hiện UI. showui = UI hidden.\nPress [accent][[{0}][] để hiện UI.
wave = [accent]Đợt {0} wave = [accent]Đợt {0}
wave.cap = [accent]Đợt {0}/{1} wave.cap = [accent]Đợt {0}/{1}
@@ -353,7 +368,6 @@ editor.center = Trung tâm
workshop = Workshop workshop = Workshop
waves.title = Đợt waves.title = Đợt
waves.remove = Xóa waves.remove = Xóa
waves.never = <vô hạn>
waves.every = mỗi waves.every = mỗi
waves.waves = đợt waves.waves = đợt
waves.perspawn = mỗi lần xuất hiện waves.perspawn = mỗi lần xuất hiện
@@ -382,7 +396,7 @@ editor.removeunit = Xóa kẻ địch
editor.teams = Đội editor.teams = Đội
editor.errorload = Lỗi khi tải tệp. editor.errorload = Lỗi khi tải tệp.
editor.errorsave = Lỗi khi lưu tệp. editor.errorsave = Lỗi khi lưu tệp.
editor.errorimage = Đó là một hình ảnh, không phải bản đồ.\n\nNếu bạn muốn nhập một bản đồ 3.5/build 40, sử dụng nút 'Nhập bản đồ thay thế' trong trình chỉnh sửa. editor.errorimage = Đó là một hình ảnh, không phải bản đồ.
editor.errorlegacy = Bản đồ này quá cũ, và sử dụng định dạng bản đồ cũ không còn được hỗ trợ. editor.errorlegacy = Bản đồ này quá cũ, và sử dụng định dạng bản đồ cũ không còn được hỗ trợ.
editor.errornot = Đây không phải là tệp bản đồ. editor.errornot = Đây không phải là tệp bản đồ.
editor.errorheader = Tệp bản đồ này không hợp lệ hoặc bị hỏng. editor.errorheader = Tệp bản đồ này không hợp lệ hoặc bị hỏng.
@@ -672,9 +686,10 @@ stat.drillspeed = Tốc độ khoang cơ bản
stat.boosteffect = Hiệu ứng tăng cường stat.boosteffect = Hiệu ứng tăng cường
stat.maxunits = Số quân lính hoạt động tối đa stat.maxunits = Số quân lính hoạt động tối đa
stat.health = Độ bền stat.health = Độ bền
stat.armor = Giáp
stat.buildtime = Thời gian xây stat.buildtime = Thời gian xây
stat.maxconsecutive = Đầu ra tối đa stat.maxconsecutive = Đầu ra tối đa
stat.buildcost = Chi phí stat.buildcost = Yêu cầu
stat.inaccuracy = Độ lệch stat.inaccuracy = Độ lệch
stat.shots = Phát bắn stat.shots = Phát bắn
stat.reload = Phát bắn/Giây stat.reload = Phát bắn/Giây
@@ -687,6 +702,7 @@ stat.lightningchance = Tỷ lệ phóng điện
stat.lightningdamage = Sát thương tia điện stat.lightningdamage = Sát thương tia điện
stat.flammability = Dễ cháy stat.flammability = Dễ cháy
stat.radioactivity = Phóng xạ stat.radioactivity = Phóng xạ
stat.charge = Phóng điện
stat.heatcapacity = Nhiệt dung stat.heatcapacity = Nhiệt dung
stat.viscosity = Độ nhớt stat.viscosity = Độ nhớt
stat.temperature = Nhiệt độ stat.temperature = Nhiệt độ
@@ -699,6 +715,7 @@ stat.commandlimit = Giới hạn lệnh
stat.abilities = Khả năng stat.abilities = Khả năng
stat.canboost = Nâng cấp stat.canboost = Nâng cấp
stat.flying = Bay stat.flying = Bay
stat.ammouse = Sử dụng đạn
ability.forcefield = Tạo khiên ability.forcefield = Tạo khiên
ability.repairfield = Sửa chữa/Xây dựng ability.repairfield = Sửa chữa/Xây dựng
@@ -713,6 +730,7 @@ bar.corereq = Yêu cầu căn cứ
bar.drillspeed = Tốc độ khoan: {0}/giây bar.drillspeed = Tốc độ khoan: {0}/giây
bar.pumpspeed = Tốc độ bơm: {0}/giây bar.pumpspeed = Tốc độ bơm: {0}/giây
bar.efficiency = Hiệu suất: {0}% bar.efficiency = Hiệu suất: {0}%
bar.boost = Tăng tốc: {0}%
bar.powerbalance = Năng lượng: {0}/giây bar.powerbalance = Năng lượng: {0}/giây
bar.powerstored = Lưu trữ: {0}/{1} bar.powerstored = Lưu trữ: {0}/{1}
bar.poweramount = Năng lượng: {0} bar.poweramount = Năng lượng: {0}
@@ -721,7 +739,6 @@ bar.powerlines = Số lượng kết nối: {0}/{1}
bar.items = Vật phẩm: {0} bar.items = Vật phẩm: {0}
bar.capacity = Sức chứa: {0} bar.capacity = Sức chứa: {0}
bar.unitcap = {0} {1}/{2} bar.unitcap = {0} {1}/{2}
bar.limitreached = [scarlet] {0} / {1}[white] {2}\n[lightgray][[quân lính bị vô hiệu hóa]
bar.liquid = Chất lỏng bar.liquid = Chất lỏng
bar.heat = Nhiệt độ bar.heat = Nhiệt độ
bar.power = Năng lượng bar.power = Năng lượng
@@ -737,6 +754,7 @@ bullet.incendiary = [stat]cháy
bullet.sapping = [stat]sapping bullet.sapping = [stat]sapping
bullet.homing = [stat]truy đuổi bullet.homing = [stat]truy đuổi
bullet.shock = [stat]sốc bullet.shock = [stat]sốc
bullet.buildingdamage = [stat]{0}%[lightgray] sát thương khối
bullet.frag = [stat]phá mảnh bullet.frag = [stat]phá mảnh
bullet.knockback = [stat]{0}[lightgray] bật lùi bullet.knockback = [stat]{0}[lightgray] bật lùi
bullet.pierce = [stat]{0}[lightgray]x xuyên giáp bullet.pierce = [stat]{0}[lightgray]x xuyên giáp
@@ -763,9 +781,10 @@ unit.timesspeed = x tốc độ
unit.percent = % unit.percent = %
unit.shieldhealth = độ bền khiên unit.shieldhealth = độ bền khiên
unit.items = vật phẩm unit.items = vật phẩm
unit.thousands = nghìn unit.thousands = k
unit.millions = triệu unit.millions = mil
unit.billions = tỷ unit.billions = b
unit.pershot = /shot
category.purpose = Mô tả category.purpose = Mô tả
category.general = Chung category.general = Chung
category.power = Năng lượng category.power = Năng lượng
@@ -782,6 +801,7 @@ setting.hints.name = Gợi ý
setting.flow.name = Hiện thị tốc độ chuyền tài nguyên setting.flow.name = Hiện thị tốc độ chuyền tài nguyên
setting.backgroundpause.name = Tạm dừng trong nền setting.backgroundpause.name = Tạm dừng trong nền
setting.buildautopause.name = Tự động dừng xây dựng setting.buildautopause.name = Tự động dừng xây dựng
setting.modcrashdisable.name = Tắt các mod khi gặp sự cố trong khởi động
setting.animatedwater.name = Hiệu ứng nước setting.animatedwater.name = Hiệu ứng nước
setting.animatedshields.name = Hiệu ứng khiên setting.animatedshields.name = Hiệu ứng khiên
setting.antialias.name = Khử răng cưa[lightgray] (yêu cầu khởi động lại)[] setting.antialias.name = Khử răng cưa[lightgray] (yêu cầu khởi động lại)[]
@@ -833,7 +853,9 @@ setting.chatopacity.name = Độ mờ trò chuyện
setting.lasersopacity.name = Độ mờ kết nối năng lượng setting.lasersopacity.name = Độ mờ kết nối năng lượng
setting.bridgeopacity.name = Độ mờ cầu setting.bridgeopacity.name = Độ mờ cầu
setting.playerchat.name = Hiển thị bong bóng trò chuyện của người chơi setting.playerchat.name = Hiển thị bong bóng trò chuyện của người chơi
setting.showweather.name = Hiển thị đồ họa thời tiết
public.confirm = Bạn có muốn công khai trò chơi của mình không?\n[accent]Bất kỳ ai cũng có thể tham gia trò chơi của bạn.\n[lightgray]Điều này có thể được thay đổi sau trong Cài đặt-> Trò chơi-> Hiển thị trò chơi công khai. public.confirm = Bạn có muốn công khai trò chơi của mình không?\n[accent]Bất kỳ ai cũng có thể tham gia trò chơi của bạn.\n[lightgray]Điều này có thể được thay đổi sau trong Cài đặt-> Trò chơi-> Hiển thị trò chơi công khai.
public.confirm.really = Nếu bạn muốn chơi với bạn bè, sử dụng [green]Invite Friend[] thay vì [scarlet]Public server[]!\nBạn có chắc chắn muốn làm trò chơi của mình [scarlet]công khai[]?
public.beta = Lưu ý rằng phiên bản beta của trò chơi không thể tạo sảnh công khai. public.beta = Lưu ý rằng phiên bản beta của trò chơi không thể tạo sảnh công khai.
uiscale.reset = Kích thước UI đã được thay đổi.\nNhấn "OK" để xác nhận.\n[scarlet]Hoàn lại và thoát trong[accent] {0}[] giây... uiscale.reset = Kích thước UI đã được thay đổi.\nNhấn "OK" để xác nhận.\n[scarlet]Hoàn lại và thoát trong[accent] {0}[] giây...
uiscale.cancel = Hủy & Thoát uiscale.cancel = Hủy & Thoát
@@ -908,6 +930,7 @@ keybind.toggle_menus.name = Ẩn/Hiện Menus
keybind.chat_history_prev.name = Lịch sử trò chuyện trước keybind.chat_history_prev.name = Lịch sử trò chuyện trước
keybind.chat_history_next.name = Lịch sử trò chuyện sau keybind.chat_history_next.name = Lịch sử trò chuyện sau
keybind.chat_scroll.name = Cuộn trò chuyện keybind.chat_scroll.name = Cuộn trò chuyện
keybind.chat_mode.name = Thay đổi chế độ trò chuyện
keybind.drop_unit.name = Thả quân keybind.drop_unit.name = Thả quân
keybind.zoom_minimap.name = Thu phóng bản đồ mini keybind.zoom_minimap.name = Thu phóng bản đồ mini
mode.help.title = Mô tả chế độ mode.help.title = Mô tả chế độ
@@ -924,6 +947,7 @@ mode.custom = Tùy chỉnh luật
rules.infiniteresources = Tài nguyên vô hạn rules.infiniteresources = Tài nguyên vô hạn
rules.reactorexplosions = Nổ lò phản ứng rules.reactorexplosions = Nổ lò phản ứng
rules.coreincinerates = Hủy vật phẩm khi căn cứ đầy
rules.schematic = Cho phép dùng bản thiết kế rules.schematic = Cho phép dùng bản thiết kế
rules.wavetimer = Đếm ngược đợt rules.wavetimer = Đếm ngược đợt
rules.waves = Đợt rules.waves = Đợt
@@ -935,6 +959,8 @@ rules.blockdamagemultiplier = Hệ số sát thương của khối
rules.unitbuildspeedmultiplier = Hệ số tốc độ sản xuất lính rules.unitbuildspeedmultiplier = Hệ số tốc độ sản xuất lính
rules.unithealthmultiplier = Hệ số máu của quân lính rules.unithealthmultiplier = Hệ số máu của quân lính
rules.unitdamagemultiplier = Hệ số sát thương của quân lính rules.unitdamagemultiplier = Hệ số sát thương của quân lính
rules.unitcapvariable = Căn cứ tăng giới hạn quân lính
rules.unitcap = Giới hạn quân lính
rules.enemycorebuildradius = Bán kính không xây dựng trong căn cứ của kẻ địch:[lightgray] (ô) rules.enemycorebuildradius = Bán kính không xây dựng trong căn cứ của kẻ địch:[lightgray] (ô)
rules.wavespacing = Thời gian giữa các đợt:[lightgray] (giây) rules.wavespacing = Thời gian giữa các đợt:[lightgray] (giây)
rules.buildcostmultiplier = Hệ số chi phí xây dựng rules.buildcostmultiplier = Hệ số chi phí xây dựng
@@ -956,6 +982,7 @@ rules.explosions = Sát thương nổ của Khối/Quân lính
rules.ambientlight = Ánh sáng môi trường rules.ambientlight = Ánh sáng môi trường
rules.weather = Thời tiết rules.weather = Thời tiết
rules.weather.frequency = Tần suất: rules.weather.frequency = Tần suất:
rules.weather.always = Luôn luôn
rules.weather.duration = Thời gian: rules.weather.duration = Thời gian:
content.item.name = Vật phẩm content.item.name = Vật phẩm
@@ -1162,7 +1189,7 @@ block.item-void.name = Hủy vật phẩm
block.liquid-source.name = Nguồn chất lỏng block.liquid-source.name = Nguồn chất lỏng
block.liquid-void.name = Hủy chất lỏng block.liquid-void.name = Hủy chất lỏng
block.power-void.name = Hủy năng lượng block.power-void.name = Hủy năng lượng
block.power-source.name = Vô hạn năng lượng block.power-source.name = Nguồn năng lượng
block.unloader.name = Điểm dỡ hàng block.unloader.name = Điểm dỡ hàng
block.vault.name = Nhà kho block.vault.name = Nhà kho
block.wave.name = Wave block.wave.name = Wave
@@ -1282,6 +1309,9 @@ hint.payloadDrop.mobile = [accent]Nhấn và giữ[] tại một khu vực trố
hint.waveFire = [accent]Wave[] súng có nước làm đạn dược sẽ tự động dập tắt các đám cháy gần đó. hint.waveFire = [accent]Wave[] súng có nước làm đạn dược sẽ tự động dập tắt các đám cháy gần đó.
hint.generator = \uf879 [accent]Máy phát điện đốt cháy[] đốt than và truyền năng lượng cho các khối liền kề.\n\nPhạm vi truyền tải năng lượng có thể được mở rộng với \uf87f [accent]Chốt điện[]. hint.generator = \uf879 [accent]Máy phát điện đốt cháy[] đốt than và truyền năng lượng cho các khối liền kề.\n\nPhạm vi truyền tải năng lượng có thể được mở rộng với \uf87f [accent]Chốt điện[].
hint.guardian = [accent]Boss[] được bọc giáp. Sử dụng loại đạn yếu chẳng hạn như [accent]Đồng[] và [accent]Chì[] là [scarlet]không hiệu quả[].\n\nSử dụng súng tiên tiến hơn hoặc sử dụng \uf835 [accent]Than chì làm đạn [] \uf861Duo/\uf859Salvo đạn dược để hạ gục Boss. hint.guardian = [accent]Boss[] được bọc giáp. Sử dụng loại đạn yếu chẳng hạn như [accent]Đồng[] và [accent]Chì[] là [scarlet]không hiệu quả[].\n\nSử dụng súng tiên tiến hơn hoặc sử dụng \uf835 [accent]Than chì làm đạn [] \uf861Duo/\uf859Salvo đạn dược để hạ gục Boss.
hint.coreUpgrade = Các căn cứ có thể được nâng cấp bằng cách [accent]đặt căn cứ cấp cao hơn trên chúng[].\n\nĐặt một căn cứ  [accent]Trụ sở[] trên căn cứ  [accent]Cơ sở[]. Đảm bảo không có vật cản gần đó.
hint.presetLaunch = Khác khu vực đáp [accent] xám[], như [accent]Frozen Forest[], có thể được phóng đến từ bất cứ đâu. Nó không yêu cầu chiếm các khu vực lân cận.\n\n[accent]Các khu vực được đánh số[], chẳng hạn như cái này, là [accent]không bắt buộc[].
hint.coopCampaign = Khi chơi chiến dịch[accent]co-op[], các vật phẩm được sản xuất trong bản đồ hiện tại cũng sẽ được gửi [accent]đến các khu vực của bạn[].\n\nBất kỳ nghiên cứu mới nào được thực hiện đều được lưu lại.
item.copper.description = Dùng trong tất cả các khu xây dựng và các loại đạn dược. item.copper.description = Dùng trong tất cả các khu xây dựng và các loại đạn dược.
item.copper.details = Đồng, là kim loại phổ biến trên Serpulo. Có cấu trúc yếu trừ khi được tôi luyện. item.copper.details = Đồng, là kim loại phổ biến trên Serpulo. Có cấu trúc yếu trừ khi được tôi luyện.
@@ -1350,10 +1380,10 @@ block.surge-wall.description = Bảo vệ công trình khỏi đạn của kẻ
block.surge-wall-large.description = Bảo vệ nhiều công trình khỏi đạn của kẻ thù, đôi khi tạo ra tia điện khi bị bắn. block.surge-wall-large.description = Bảo vệ nhiều công trình khỏi đạn của kẻ thù, đôi khi tạo ra tia điện khi bị bắn.
block.door.description = Một bức tường có thể đóng mở. block.door.description = Một bức tường có thể đóng mở.
block.door-large.description = Một bức tường có thể đóng mở. block.door-large.description = Một bức tường có thể đóng mở.
block.mender.description = Sửa chữa định kỳ các khối trong vùng lân cận.\nSử dụng silicon để tăng phạm vi và hiệu quả. block.mender.description = Sửa chữa định kỳ các khối trong vùng lân cận.\nSử dụng Phase Fabric để tăng phạm vi và hiệu quả.
block.mend-projector.description = Sửa chữa các khối lân cận.\nSử dụng silicon để tăng phạm vi và hiệu quả. block.mend-projector.description = Sửa chữa các khối lân cận.\nSử dụng Phase Fabric để tăng phạm vi và hiệu quả.
block.overdrive-projector.description = Tăng tốc độ làm việc của các công trình lân cận.\nSử dụng phase fabric để tăng phạm vi và hiệu quả. block.overdrive-projector.description = Tăng tốc độ làm việc của các công trình lân cận.\nSử dụng phase fabric để tăng phạm vi và hiệu quả.
block.force-projector.description = Tạo ra một trường lực lục giác xung quanh nó, bảo vệ các tòa nhà và quân lính bên trong khỏi bị hư hại.\nQuá nóng nếu chịu quá nhiều sát thương. Sử dụng chất làm mát để giảm nhiệt độ. Sử dụng Phase fabric để tăng kích thước lá chắn. block.force-projector.description = Tạo ra một trường lực lục giác xung quanh nó, bảo vệ các công trình và quân lính bên trong khỏi bị hư hại.\nQuá nóng nếu chịu quá nhiều sát thương. Sử dụng chất làm mát để giảm nhiệt độ. Sử dụng Phase fabric để tăng kích thước lá chắn.
block.shock-mine.description = Giải phóng tia điện khi tiếp xúc với quân lính đối phương. block.shock-mine.description = Giải phóng tia điện khi tiếp xúc với quân lính đối phương.
block.conveyor.description = Vận chuyển vật phẩm về phía trước. block.conveyor.description = Vận chuyển vật phẩm về phía trước.
block.titanium-conveyor.description = Vận chuyển vật phẩm về phía trước. Nhanh hơn băng chuyền tiêu chuẩn. block.titanium-conveyor.description = Vận chuyển vật phẩm về phía trước. Nhanh hơn băng chuyền tiêu chuẩn.
@@ -1366,9 +1396,9 @@ block.inverted-sorter.description = Giống như máy phân loại, nhưng vật
block.router.description = Phân phối các vật phẩm đầu vào thành 3 hướng đầu ra như nhau. block.router.description = Phân phối các vật phẩm đầu vào thành 3 hướng đầu ra như nhau.
block.router.details = Không khuyên dùng cạnh đầu vào dây chuyền vì sẽ bị kẹt bởi đầu ra. block.router.details = Không khuyên dùng cạnh đầu vào dây chuyền vì sẽ bị kẹt bởi đầu ra.
block.distributor.description = Phân phối các vật phẩm đầu vào thành 7 hướng đầu ra như nhau. block.distributor.description = Phân phối các vật phẩm đầu vào thành 7 hướng đầu ra như nhau.
block.overflow-gate.description = Chỉ đưa vật phẩm ra 2 phía nếu phía trước bị chặn, không thể đặt cạnh nhau. block.overflow-gate.description = Chỉ đưa vật phẩm ra 2 phía nếu phía trước bị chặn.
block.underflow-gate.description = Ngược với cổng tràn, chỉ đưa vật phẩm đến trước khi hai bên bị chặn, không thể đặt cạnh nhau. block.underflow-gate.description = Ngược với cổng tràn, chỉ đưa vật phẩm đến trước khi hai bên bị chặn.
block.mass-driver.description = Cấu trúc vận chuyển vật phẩm tầm xa. Thu thập các lô vật phẩm và bắn chúng cho các mass driver khác. block.mass-driver.description = Cấu trúc vận chuyển vật phẩm tầm xa. Thu thập các lô vật phẩm và bắn chúng cho các máy phóng điện từ khác.
block.mechanical-pump.description = Bơm chất lỏng, không yêu cầu năng lượng. block.mechanical-pump.description = Bơm chất lỏng, không yêu cầu năng lượng.
block.rotary-pump.description = Bơm chất lỏng, yêu cầu năng lượng. block.rotary-pump.description = Bơm chất lỏng, yêu cầu năng lượng.
block.thermal-pump.description = Bơm chất lỏng. block.thermal-pump.description = Bơm chất lỏng.
@@ -1488,3 +1518,139 @@ unit.omura.description = Bắn đạn từ trường xuyên giáp tầm xa vào
unit.alpha.description = Bảo vệ căn cứ cơ sở khỏi kẻ thù. Có thể xây dựng. unit.alpha.description = Bảo vệ căn cứ cơ sở khỏi kẻ thù. Có thể xây dựng.
unit.beta.description = Bảo vệ căn cứ trụ sở khỏi kẻ thù. Có thể xây dựng. unit.beta.description = Bảo vệ căn cứ trụ sở khỏi kẻ thù. Có thể xây dựng.
unit.gamma.description = Bảo vệ căn cứ trung tâm khỏi kẻ thù. Có thể xây dựng. unit.gamma.description = Bảo vệ căn cứ trung tâm khỏi kẻ thù. Có thể xây dựng.
lst.read = Đọc một số từ bộ nhớ được liên kết.
lst.write = Ghi một số vào bộ nhớ được liên kết.
lst.print = Thêm văn bản vào bộ nhớ in.\nKhông hiển thị gì cho đến khi sử dụng [accent]Print Flush[].
lst.draw = Thêm một thao tác vào bộ nhớ vẽ.\nKhông hiển thị gì cho đến khi sử dụng [accent]Draw Flush[].
lst.drawflush = Chuyển các thao tác [accent]Draw[] đến màng hình.
lst.printflush = Chuyển các thao tác [accent]Print[] đến khối tin nhắn.
lst.getlink = Nhận liên kết bộ xử lý theo thứ tự. Bắt đầu từ 0.
lst.control = Điều khiển một khối.
lst.radar = Định vị các quân lính trong phạm vi xung quanh một khối.
lst.sensor = Lấy dữ liệu từ một khối hoặc quân lính.
lst.set = Đặt một biến.
lst.operation = Thực hiện thao tác trên 1-2 biến.
lst.end = Chuyển đến lệnh đầu tiên.
lst.jump = Chuyển qua lệnh khác nếu điều kiện đúng.
lst.unitbind = Bind to the next unit of a type, and store it in [accent]@unit[].
lst.unitcontrol = Control the currently bound unit.
lst.unitradar = Locate units around the currently bound unit.
lst.unitlocate = Locate a specific type of position/building anywhere on the map.\nRequires a bound unit.
lenum.type = Type of building/unit.\ne.g. for any router, this will return [accent]@router[].\nNot a string.
lenum.shoot = Bắn vào vị trí xác định.
lenum.shootp = Shoot at a unit/building with velocity prediction.
lenum.configure = Building configuration, e.g. sorter item.
lenum.enabled = Bất cứ khi nào khối hoạt động.
laccess.color = Màu đèn chiếu sáng.
graphicstype.clear = Tô màu cho màn hình.
graphicstype.color = Đặt màu cho thao tác vẽ tiếp theo.
graphicstype.stroke = Đặt chiều rộng đoạn thẳng.
graphicstype.line = Vẽ đoạn thẳng.
graphicstype.rect = Tô một hình chữ nhật.
graphicstype.linerect = Vẽ đường viền hình chữ nhật.
graphicstype.poly = Tô vào đa giác đều.
graphicstype.linepoly = Vẽ đường viền đa giác đều.
graphicstype.triangle = Tô một hình tam giác.
graphicstype.image = Vẽ hình ảnh một số nội dung.\nVd: [accent]@router[] hoặc [accent]@dagger[].
lenum.always = Luôn đúng.
lenum.idiv = Chia lấy phần nguyên.
lenum.div = Phép chia.\nTrả về [accent]null[] khi chia cho 0.
lenum.mod = Chia lấy phần dư.
lenum.equal = Equal. Coerces types.\nNon-null objects compared with numbers become 1, otherwise 0.
lenum.notequal = Not equal. Coerces types.
lenum.strictequal = Strict equality. Does not coerce types.\nCan be used to check for [accent]null[].
lenum.shl = Bit-shift left.
lenum.shr = Bit-shift right.
lenum.or = Bitwise OR.
lenum.land = Logical AND.
lenum.and = Bitwise AND.
lenum.not = Bitwise flip.
lenum.xor = Bitwise XOR.
lenum.min = Số nhỏ nhất giữa hai số.
lenum.max = Số lớn nhất giữa hai số.
lenum.angle = Góc của vectơ tính bằng độ.
lenum.len = Chiều dài của vectơ.
lenum.sin = Sin, tính bằng độ.
lenum.cos = Cos, tính bằng độ.
lenum.tan = Tan, tính bằng độ.
#not a typo, look up 'range notation'
lenum.rand = Số ngẫu nhiên trong phạm vi [0, giá trị).
lenum.log = Lôgarit tự nhiên (ln).
lenum.log10 = Lôgarit cơ số 10.
lenum.noise = 2D simplex noise.
lenum.abs = Giá trị tuyệt đối.
lenum.sqrt = Căn bậc hai.
lenum.any = Bất kì quân lính.
lenum.ally = Quân lính cùng đội.
lenum.attacker = Quân lính với vũ khí.
lenum.enemy = Quân lính địch.
lenum.boss = Boss.
lenum.flying = Không quân.
lenum.ground = Bộ binh.
lenum.player = Quân lính do người chơi điều khiển.
lenum.ore = Ore deposit.
lenum.damaged = Damaged ally building.
lenum.spawn = Enemy spawn point.\nMay be a core or a position.
lenum.building = Building in a specific group.
lenum.core = Bất kì căn cứ.
lenum.storage = Khối lưu trữ, Ví dụ Nhà kho.
lenum.generator = Khối có thể tạo ra năng lượng.
lenum.factory = Khối có thể biến đổi vật phẩm.
lenum.repair = Điểm sửa chữa.
lenum.rally = Trung tâm chỉ huy.
lenum.battery = Bất kì pin.
lenum.resupply = Điểm tiếp tế.\nChỉ phù hợp khi [accent]"Quân lính cần đạn"[] được bật.
lenum.reactor = Lò phản ứng Thorium\Nhiệt hạch.
lenum.turret = Bất kì súng.
sensor.in = The building/unit to sense.
radar.from = Building to sense from.\nSensor range is limited by building range.
radar.target = Filter for units to sense.
radar.and = Additional filters.
radar.order = Sorting order. 0 to reverse.
radar.sort = Metric to sort results by.
radar.output = Variable to write output unit to.
unitradar.target = Filter for units to sense.
unitradar.and = Additional filters.
unitradar.order = Sorting order. 0 to reverse.
unitradar.sort = Metric to sort results by.
unitradar.output = Variable to write output unit to.
control.of = Building to control.
control.unit = Unit/building to aim at.
control.shoot = Whether to shoot.
unitlocate.enemy = Whether to locate enemy buildings.
unitlocate.found = Whether the object was found.
unitlocate.building = Output variable for located building.
unitlocate.outx = Output X coordinate.
unitlocate.outy = Output Y coordinate.
unitlocate.group = Building group to look for.
lenum.stop = Dừng di chuyển/Đào/Xây dựng.
lenum.move = Di chuyển đến vị trí xác định.
lenum.approach = Approach a position with a radius.
lenum.pathfind = Tìm đường đến nơi tạo ra kẻ địch.
lenum.target = Bắn vào vị trí xác định.
lenum.targetp = Shoot a target with velocity prediction.
lenum.itemdrop = Thả vật phẩm.
lenum.itemtake = Lấy vật phẩm từ khối.
lenum.paydrop = Thả khối hàng hiện tại.
lenum.paytake = Nhất khối hàng tại vị trí hiện tại.
lenum.flag = Numeric unit flag.
lenum.mine = Đào tại vị trí.
lenum.build = Xây công trình.
lenum.getblock = Fetch a building and type at coordinates.\nUnit must be in range of position.\nSolid non-buildings will have the type [accent]@solid[].
lenum.within = Kiểm tra xem quân lính có gần vị trí không.
lenum.boost = Start/stop boosting.

View File

@@ -34,6 +34,11 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
@Override @Override
public void setup(){ public void setup(){
String dataDir = OS.env("MINDUSTRY_DATA_DIR");
if(dataDir != null){
Core.settings.setDataDirectory(files.absolute(dataDir));
}
checkLaunch(); checkLaunch();
loadLogger(); loadLogger();

View File

@@ -0,0 +1,40 @@
package mindustry.ai.types;
import arc.math.*;
import mindustry.entities.*;
import mindustry.entities.comp.*;
import mindustry.entities.units.*;
import mindustry.gen.*;
import mindustry.world.meta.*;
public class DefenderAI extends AIController{
@Override
public void updateMovement(){
if(target != null){
moveTo(target, (target instanceof Sized s ? s.hitSize()/2f * 1.1f : 0f) + unit.hitSize/2f + 15f, 50f);
unit.lookAt(target);
}
}
@Override
protected void updateTargeting(){
if(retarget()) target = findTarget(unit.x, unit.y, unit.range(), true, true);
}
@Override
protected Teamc findTarget(float x, float y, float range, boolean air, boolean ground){
//find unit to follow if not in rally mode
if(command() != UnitCommand.rally){
//Sort by max health and closer target.
var result = Units.closest(unit.team, x, y, Math.max(range, 400f), u -> !u.dead() && u.type != unit.type, (u, tx, ty) -> -u.maxHealth + Mathf.dst2(u.x, u.y, tx, ty) / 800f);
if(result != null) return result;
}
//find rally point
var block = targetFlag(unit.x, unit.y, BlockFlag.rally, false);
if(block != null) return block;
//return core if found
return unit.closestCore();
}
}

View File

@@ -13,7 +13,7 @@ public class FlyingAI extends AIController{
public void updateMovement(){ public void updateMovement(){
if(target != null && unit.hasWeapons() && command() == UnitCommand.attack){ if(target != null && unit.hasWeapons() && command() == UnitCommand.attack){
if(!unit.type.circleTarget){ if(!unit.type.circleTarget){
moveTo(target, unit.range() * 0.8f); moveTo(target, unit.type.range * 0.8f);
unit.lookAt(target); unit.lookAt(target);
}else{ }else{
attack(120f); attack(120f);

View File

@@ -48,7 +48,7 @@ public class FormationAI extends AIController implements FormationMember{
Vec2 realtarget = vec.set(target).add(leader.vel); Vec2 realtarget = vec.set(target).add(leader.vel);
float speed = unit.realSpeed() * unit.floorSpeedMultiplier() * Time.delta; float speed = unit.realSpeed() * Time.delta;
unit.approach(Mathf.arrive(unit.x, unit.y, realtarget.x, realtarget.y, unit.vel, speed, 0f, speed, 1f).scl(1f / Time.delta)); unit.approach(Mathf.arrive(unit.x, unit.y, realtarget.x, realtarget.y, unit.vel, speed, 0f, speed, 1f).scl(1f / Time.delta));
if(unit.canMine() && leader.canMine()){ if(unit.canMine() && leader.canMine()){

View File

@@ -19,7 +19,7 @@ public class LogicAI extends AIController{
/** Time after which the unit resets its controlled and reverts to a normal unit. */ /** Time after which the unit resets its controlled and reverts to a normal unit. */
public static final float logicControlTimeout = 10f * 60f; public static final float logicControlTimeout = 10f * 60f;
public LUnitControl control = LUnitControl.stop; public LUnitControl control = LUnitControl.idle;
public float moveX, moveY, moveRad; public float moveX, moveY, moveRad;
public float itemTimer, payTimer, controlTimer = logicControlTimeout, targetTimer; public float itemTimer, payTimer, controlTimer = logicControlTimeout, targetTimer;
@Nullable @Nullable

View File

@@ -1285,7 +1285,7 @@ public class Blocks implements ContentList{
}}; }};
waterExtractor = new SolidPump("water-extractor"){{ waterExtractor = new SolidPump("water-extractor"){{
requirements(Category.production, with(Items.copper, 30, Items.graphite, 30, Items.lead, 30)); requirements(Category.production, with(Items.metaglass, 30, Items.graphite, 30, Items.lead, 30));
result = Liquids.water; result = Liquids.water;
pumpAmount = 0.11f; pumpAmount = 0.11f;
size = 2; size = 2;
@@ -1370,16 +1370,12 @@ public class Blocks implements ContentList{
requirements(Category.effect, with(Items.titanium, 250, Items.thorium, 125)); requirements(Category.effect, with(Items.titanium, 250, Items.thorium, 125));
size = 3; size = 3;
itemCapacity = 1000; itemCapacity = 1000;
flags = EnumSet.of(BlockFlag.storage);
group = BlockGroup.transportation;
}}; }};
container = new StorageBlock("container"){{ container = new StorageBlock("container"){{
requirements(Category.effect, with(Items.titanium, 100)); requirements(Category.effect, with(Items.titanium, 100));
size = 2; size = 2;
itemCapacity = 300; itemCapacity = 300;
flags = EnumSet.of(BlockFlag.storage);
group = BlockGroup.transportation;
}}; }};
unloader = new Unloader("unloader"){{ unloader = new Unloader("unloader"){{
@@ -1606,12 +1602,12 @@ public class Blocks implements ContentList{
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; health = 250 * size * size;
range = 160f; range = 180f;
hasPower = true; hasPower = true;
consumes.powerCond(8f, (PointDefenseBuild b) -> b.target != null); consumes.powerCond(8f, (PointDefenseBuild b) -> b.target != null);
size = 2; size = 2;
shootLength = 5f; shootLength = 5f;
bulletDamage = 25f; bulletDamage = 30f;
reloadTime = 9f; reloadTime = 9f;
}}; }};
@@ -1624,7 +1620,6 @@ public class Blocks implements ContentList{
Liquids.oil, Bullets.heavyOilShot Liquids.oil, Bullets.heavyOilShot
); );
size = 3; size = 3;
recoilAmount = 0f;
reloadTime = 2f; reloadTime = 2f;
shots = 2; shots = 2;
velocityInaccuracy = 0.1f; velocityInaccuracy = 0.1f;

View File

@@ -12,7 +12,7 @@ import mindustry.graphics.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class StatusEffects implements ContentList{ public class StatusEffects implements ContentList{
public static StatusEffect none, burning, freezing, unmoving, slow, wet, muddy, melting, sapped, tarred, overdrive, overclock, shielded, shocked, blasted, corroded, boss, sporeSlowed; public static StatusEffect none, burning, freezing, unmoving, slow, wet, muddy, melting, sapped, tarred, overdrive, overclock, shielded, shocked, blasted, corroded, boss, sporeSlowed, disarmed;
@Override @Override
public void load(){ public void load(){
@@ -173,5 +173,10 @@ public class StatusEffects implements ContentList{
color = Pal.plastanium; color = Pal.plastanium;
damage = 0.1f; damage = 0.1f;
}}; }};
disarmed = new StatusEffect("disarmed"){{
color = Color.valueOf("e9ead3");
disarm = true;
}};
} }
} }

View File

@@ -322,9 +322,8 @@ public class UnitTypes implements ContentList{
x = 5f; x = 5f;
shake = 2.2f; shake = 2.2f;
y = 0.5f; y = 0.5f;
shootY = 5f;
shootY = 2.5f; shootY = 2.5f;
reload = 38f; reload = 38f;
shots = 3; shots = 3;
inaccuracy = 35; inaccuracy = 35;
@@ -359,7 +358,6 @@ public class UnitTypes implements ContentList{
quasar = new UnitType("quasar"){{ quasar = new UnitType("quasar"){{
mineTier = 3; mineTier = 3;
hitSize = 12f;
boostMultiplier = 2f; boostMultiplier = 2f;
health = 650f; health = 650f;
buildSpeed = 1.7f; buildSpeed = 1.7f;
@@ -407,19 +405,20 @@ public class UnitTypes implements ContentList{
rotateSpeed = 1.6f; rotateSpeed = 1.6f;
canDrown = false; canDrown = false;
mechFrontSway = 1f; mechFrontSway = 1f;
buildSpeed = 3f;
mechStepParticles = true; mechStepParticles = true;
mechStepShake = 0.15f; mechStepShake = 0.15f;
ammoType = AmmoTypes.powerHigh; ammoType = AmmoTypes.powerHigh;
speed = 0.35f; speed = 0.38f;
boostMultiplier = 2.1f; boostMultiplier = 2.2f;
engineOffset = 12f; engineOffset = 12f;
engineSize = 6f; engineSize = 6f;
lowAltitude = true; lowAltitude = true;
health = 7200f; health = 7500f;
armor = 8f; armor = 9f;
canBoost = true; canBoost = true;
landShake = 4f; landShake = 4f;
immunities = ObjectSet.with(StatusEffects.burning); immunities = ObjectSet.with(StatusEffects.burning);
@@ -443,8 +442,8 @@ public class UnitTypes implements ContentList{
cooldownTime = 200f; cooldownTime = 200f;
bullet = new ContinuousLaserBulletType(){{ bullet = new ContinuousLaserBulletType(){{
damage = 26f; damage = 28f;
length = 170f; length = 175f;
hitEffect = Fx.hitMeltHeal; hitEffect = Fx.hitMeltHeal;
drawSize = 420f; drawSize = 420f;
lifetime = 160f; lifetime = 160f;
@@ -454,7 +453,7 @@ public class UnitTypes implements ContentList{
shootEffect = Fx.greenLaserChargeSmall; shootEffect = Fx.greenLaserChargeSmall;
incendChance = 0.08f; incendChance = 0.09f;
incendSpread = 5f; incendSpread = 5f;
incendAmount = 1; incendAmount = 1;
@@ -471,7 +470,6 @@ public class UnitTypes implements ContentList{
}}; }};
corvus = new UnitType("corvus"){{ corvus = new UnitType("corvus"){{
mineTier = 1;
hitSize = 29f; hitSize = 29f;
health = 18000f; health = 18000f;
armor = 9f; armor = 9f;
@@ -1373,6 +1371,8 @@ public class UnitTypes implements ContentList{
}}; }};
oct = new UnitType("oct"){{ oct = new UnitType("oct"){{
defaultController = DefenderAI::new;
armor = 16f; armor = 16f;
health = 24000; health = 24000;
speed = 0.8f; speed = 0.8f;

View File

@@ -26,6 +26,7 @@ import mindustry.world.*;
import mindustry.world.modules.*; import mindustry.world.modules.*;
import java.io.*; import java.io.*;
import java.util.*;
import java.util.zip.*; import java.util.zip.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@@ -65,6 +66,13 @@ public class NetClient implements ApplicationListener{
reset(); reset();
//connection after reset
if(!net.client()){
Log.info("Connection canceled.");
disconnectQuietly();
return;
}
ui.loadfrag.hide(); ui.loadfrag.hide();
ui.loadfrag.show("@connecting.data"); ui.loadfrag.show("@connecting.data");
@@ -73,9 +81,14 @@ public class NetClient implements ApplicationListener{
disconnectQuietly(); disconnectQuietly();
}); });
ConnectPacket c = new ConnectPacket(); String locale = Core.settings.getString("locale");
if(locale.equals("default")){
locale = Locale.getDefault().toString();
}
var c = new ConnectPacket();
c.name = player.name; c.name = player.name;
c.locale = Core.settings.getString("locale"); c.locale = locale;
c.mods = mods.getModStrings(); c.mods = mods.getModStrings();
c.mobile = mobile; c.mobile = mobile;
c.versionType = Version.type; c.versionType = Version.type;
@@ -175,6 +188,10 @@ public class NetClient implements ApplicationListener{
//called when a server receives a chat message from a player //called when a server receives a chat message from a player
@Remote(called = Loc.server, targets = Loc.client) @Remote(called = Loc.server, targets = Loc.client)
public static void sendChatMessage(Player player, String message){ public static void sendChatMessage(Player player, String message){
//do not receive chat messages from clients that are too young or not registered
if(net.server() && player != null && (Time.timeSinceMillis(player.con.connectTime) < 500 || !player.con.hasConnected || !player.isAdded())) return;
if(message.length() > maxTextLength){ if(message.length() > maxTextLength){
throw new ValidateException(player, "Player has sent a message above the text limit."); throw new ValidateException(player, "Player has sent a message above the text limit.");
} }
@@ -185,7 +202,7 @@ public class NetClient implements ApplicationListener{
CommandResponse response = netServer.clientCommands.handleMessage(message, player); CommandResponse response = netServer.clientCommands.handleMessage(message, player);
if(response.type == ResponseType.noCommand){ //no command to handle if(response.type == ResponseType.noCommand){ //no command to handle
message = netServer.admins.filterMessage(player, message); message = netServer.admins.filterMessage(player, message);
//supress chat message if it's filtered out //suppress chat message if it's filtered out
if(message == null){ if(message == null){
return; return;
} }
@@ -620,7 +637,7 @@ public class NetClient implements ApplicationListener{
lastSent++, lastSent++,
uid, uid,
player.dead(), player.dead(),
unit.x, unit.y, player.dead() ? player.x : unit.x, player.dead() ? player.y : unit.y,
player.unit().aimX(), player.unit().aimY(), player.unit().aimX(), player.unit().aimY(),
unit.rotation, unit.rotation,
unit instanceof Mechc m ? m.baseRotation() : 0, unit instanceof Mechc m ? m.baseRotation() : 0,

View File

@@ -35,8 +35,8 @@ import static mindustry.Vars.*;
public class NetServer implements ApplicationListener{ public class NetServer implements ApplicationListener{
/** note that snapshots are compressed, so the max snapshot size here is above the typical UDP safe limit */ /** note that snapshots are compressed, so the max snapshot size here is above the typical UDP safe limit */
private static final int maxSnapshotSize = 800, timerBlockSync = 0; private static final int maxSnapshotSize = 800, timerBlockSync = 0, serverSyncTime = 200;
private static final float serverSyncTime = 12, blockSyncTime = 60 * 6; private static final float blockSyncTime = 60 * 6;
private static final FloatBuffer fbuffer = FloatBuffer.allocate(20); private static final FloatBuffer fbuffer = FloatBuffer.allocate(20);
private static final Vec2 vector = new Vec2(); private static final Vec2 vector = new Vec2();
private static final Rect viewport = new Rect(); private static final Rect viewport = new Rect();
@@ -81,6 +81,8 @@ public class NetServer implements ApplicationListener{
public NetServer(){ public NetServer(){
net.handleServer(Connect.class, (con, connect) -> { net.handleServer(Connect.class, (con, connect) -> {
Events.fire(new ConnectionEvent(con));
if(admins.isIPBanned(connect.addressTCP) || admins.isSubnetBanned(connect.addressTCP)){ if(admins.isIPBanned(connect.addressTCP) || admins.isSubnetBanned(connect.addressTCP)){
con.kick(KickReason.banned); con.kick(KickReason.banned);
} }
@@ -93,10 +95,14 @@ public class NetServer implements ApplicationListener{
}); });
net.handleServer(ConnectPacket.class, (con, packet) -> { net.handleServer(ConnectPacket.class, (con, packet) -> {
if(con.kicked) return;
if(con.address.startsWith("steam:")){ if(con.address.startsWith("steam:")){
packet.uuid = con.address.substring("steam:".length()); packet.uuid = con.address.substring("steam:".length());
} }
con.connectTime = Time.millis();
String uuid = packet.uuid; String uuid = packet.uuid;
byte[] buuid = Base64Coder.decode(uuid); byte[] buuid = Base64Coder.decode(uuid);
CRC32 crc = new CRC32(); CRC32 crc = new CRC32();
@@ -196,7 +202,7 @@ public class NetServer implements ApplicationListener{
} }
if(packet.locale == null){ if(packet.locale == null){
packet.locale = "en_US"; packet.locale = "en";
} }
String ip = con.address; String ip = con.address;
@@ -249,7 +255,8 @@ public class NetServer implements ApplicationListener{
}); });
net.handleServer(InvokePacket.class, (con, packet) -> { net.handleServer(InvokePacket.class, (con, packet) -> {
if(con.player == null) return; if(con.player == null || con.kicked) return;
try{ try{
RemoteReadServer.readPacket(packet.reader(), packet.type, con.player); RemoteReadServer.readPacket(packet.reader(), packet.type, con.player);
}catch(ValidateException e){ }catch(ValidateException e){
@@ -725,6 +732,7 @@ public class NetServer implements ApplicationListener{
//no verification is done, so admins can hypothetically spam waves //no verification is done, so admins can hypothetically spam waves
//not a real issue, because server owners may want to do just that //not a real issue, because server owners may want to do just that
logic.skipWave(); logic.skipWave();
info("&lc@ has skipped the wave.", player.name);
}else if(action == AdminAction.ban){ }else if(action == AdminAction.ban){
netServer.admins.banPlayerIP(other.con.address); netServer.admins.banPlayerIP(other.con.address);
netServer.admins.banPlayerID(other.con.uuid); netServer.admins.banPlayerID(other.con.uuid);
@@ -734,7 +742,8 @@ public class NetServer implements ApplicationListener{
other.kick(KickReason.kick); other.kick(KickReason.kick);
info("&lc@ has kicked @.", player.name, other.name); info("&lc@ has kicked @.", player.name, other.name);
}else if(action == AdminAction.trace){ }else if(action == AdminAction.trace){
TraceInfo info = new TraceInfo(other.con.address, other.uuid(), other.con.modclient, other.con.mobile); PlayerInfo stats = netServer.admins.getInfo(other.uuid());
TraceInfo info = new TraceInfo(other.con.address, other.uuid(), other.con.modclient, other.con.mobile, stats.timesJoined, stats.timesKicked);
if(player.con != null){ if(player.con != null){
Call.traceInfo(player.con, other, info); Call.traceInfo(player.con, other, info);
}else{ }else{
@@ -746,6 +755,8 @@ public class NetServer implements ApplicationListener{
@Remote(targets = Loc.client) @Remote(targets = Loc.client)
public static void connectConfirm(Player player){ public static void connectConfirm(Player player){
if(player.con.kicked) return;
player.add(); player.add();
if(player.con == null || player.con.hasConnected) return; if(player.con == null || player.con.hasConnected) return;
@@ -956,9 +967,11 @@ public class NetServer implements ApplicationListener{
return; return;
} }
NetConnection connection = player.con; var connection = player.con;
if(!player.timer(0, serverSyncTime) || !connection.hasConnected) return; if(Time.timeSinceMillis(connection.syncTime) < serverSyncTime || !connection.hasConnected) return;
connection.syncTime = Time.millis();
try{ try{
writeEntitySnapshot(player); writeEntitySnapshot(player);

View File

@@ -248,7 +248,7 @@ public class Units{
return result; return result;
} }
/** Returns the closest ally of this team. Filter by predicate. */ /** Returns the closest ally of this team in a range. Filter by predicate. */
public static Unit closest(Team team, float x, float y, float range, Boolf<Unit> predicate){ public static Unit closest(Team team, float x, float y, float range, Boolf<Unit> predicate){
result = null; result = null;
cdist = 0f; cdist = 0f;
@@ -266,6 +266,24 @@ public class Units{
return result; return result;
} }
/** Returns the closest ally of this team in a range. Filter by predicate. */
public static Unit closest(Team team, float x, float y, float range, Boolf<Unit> predicate, Sortf sort){
result = null;
cdist = 0f;
nearby(team, x, y, range, e -> {
if(!predicate.get(e)) return;
float dist = sort.cost(e, x, y);
if(result == null || dist < cdist){
result = e;
cdist = dist;
}
});
return result;
}
/** Returns the closest ally of this team. Filter by predicate. /** Returns the closest ally of this team. Filter by predicate.
* Unlike the closest() function, this only guarantees that unit hitboxes overlap the range. */ * Unlike the closest() function, this only guarantees that unit hitboxes overlap the range. */
public static Unit closestOverlap(Team team, float x, float y, float range, Boolf<Unit> predicate){ public static Unit closestOverlap(Team team, float x, float y, float range, Boolf<Unit> predicate){

View File

@@ -15,14 +15,14 @@ import mindustry.ui.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class UnitSpawnAbility extends Ability{ public class UnitSpawnAbility extends Ability{
public UnitType type; public UnitType unit;
public float spawnTime = 60f, spawnX, spawnY; public float spawnTime = 60f, spawnX, spawnY;
public Effect spawnEffect = Fx.spawn; public Effect spawnEffect = Fx.spawn;
protected float timer; protected float timer;
public UnitSpawnAbility(UnitType type, float spawnTime, float spawnX, float spawnY){ public UnitSpawnAbility(UnitType unit, float spawnTime, float spawnX, float spawnY){
this.type = type; this.unit = unit;
this.spawnTime = spawnTime; this.spawnTime = spawnTime;
this.spawnX = spawnX; this.spawnX = spawnX;
this.spawnY = spawnY; this.spawnY = spawnY;
@@ -35,10 +35,10 @@ public class UnitSpawnAbility extends Ability{
public void update(Unit unit){ public void update(Unit unit){
timer += Time.delta * state.rules.unitBuildSpeedMultiplier; timer += Time.delta * state.rules.unitBuildSpeedMultiplier;
if(timer >= spawnTime && Units.canCreate(unit.team, type)){ if(timer >= spawnTime && Units.canCreate(unit.team, this.unit)){
float x = unit.x + Angles.trnsx(unit.rotation, spawnY, spawnX), y = unit.y + Angles.trnsy(unit.rotation, spawnY, spawnX); float x = unit.x + Angles.trnsx(unit.rotation, spawnY, spawnX), y = unit.y + Angles.trnsy(unit.rotation, spawnY, spawnX);
spawnEffect.at(x, y); spawnEffect.at(x, y);
Unit u = type.create(unit.team); Unit u = this.unit.create(unit.team);
u.set(x, y); u.set(x, y);
u.rotation = unit.rotation; u.rotation = unit.rotation;
if(!Vars.net.client()){ if(!Vars.net.client()){
@@ -51,16 +51,16 @@ public class UnitSpawnAbility extends Ability{
@Override @Override
public void draw(Unit unit){ public void draw(Unit unit){
if(Units.canCreate(unit.team, type)){ if(Units.canCreate(unit.team, this.unit)){
Draw.draw(Draw.z(), () -> { Draw.draw(Draw.z(), () -> {
float x = unit.x + Angles.trnsx(unit.rotation, spawnY, spawnX), y = unit.y + Angles.trnsy(unit.rotation, spawnY, spawnX); float x = unit.x + Angles.trnsx(unit.rotation, spawnY, spawnX), y = unit.y + Angles.trnsy(unit.rotation, spawnY, spawnX);
Drawf.construct(x, y, type.icon(Cicon.full), unit.rotation - 90, timer / spawnTime, 1f, timer); Drawf.construct(x, y, this.unit.icon(Cicon.full), unit.rotation - 90, timer / spawnTime, 1f, timer);
}); });
} }
} }
@Override @Override
public String localized(){ public String localized(){
return Core.bundle.format("ability.unitspawn", type.localizedName); return Core.bundle.format("ability.unitspawn", unit.localizedName);
} }
} }

View File

@@ -26,10 +26,10 @@ import java.util.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@Component @Component
abstract class BuilderComp implements Posc, Teamc, Rotc{ abstract class BuilderComp implements Posc, Statusc, Teamc, Rotc{
static final Vec2[] vecs = new Vec2[]{new Vec2(), new Vec2(), new Vec2(), new Vec2()}; static final Vec2[] vecs = new Vec2[]{new Vec2(), new Vec2(), new Vec2(), new Vec2()};
@Import float x, y, rotation; @Import float x, y, rotation, buildSpeedMultiplier;
@Import UnitType type; @Import UnitType type;
@Import Team team; @Import Team team;
@@ -41,7 +41,7 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{
private transient float buildAlpha = 0f; private transient float buildAlpha = 0f;
public boolean canBuild(){ public boolean canBuild(){
return type.buildSpeed > 0; return type.buildSpeed > 0 && buildSpeedMultiplier > 0;
} }
@Override @Override
@@ -126,9 +126,9 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{
//otherwise, update it. //otherwise, update it.
if(current.breaking){ if(current.breaking){
entity.deconstruct(self(), core, 1f / entity.buildCost * Time.delta * type.buildSpeed * state.rules.buildSpeedMultiplier); entity.deconstruct(self(), core, 1f / entity.buildCost * Time.delta * type.buildSpeed * buildSpeedMultiplier * state.rules.buildSpeedMultiplier);
}else{ }else{
entity.construct(self(), core, 1f / entity.buildCost * Time.delta * type.buildSpeed * state.rules.buildSpeedMultiplier, current.config); entity.construct(self(), core, 1f / entity.buildCost * Time.delta * type.buildSpeed * buildSpeedMultiplier * state.rules.buildSpeedMultiplier, current.config);
} }
current.stuck = Mathf.equal(current.progress, entity.progress); current.stuck = Mathf.equal(current.progress, entity.progress);

View File

@@ -910,24 +910,12 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
public void placed(){ public void placed(){
if(net.client()) return; if(net.client()) return;
if(block.consumesPower || block.outputsPower){ if((block.consumesPower || block.outputsPower) && block.hasPower){
int range = 12; PowerNode.getNodeLinks(tile, block, team, other -> {
tempTiles.clear(); if(!other.power.links.contains(pos())){
Geometry.circle(tileX(), tileY(), range, (x, y) -> { other.configureAny(pos());
Building other = world.build(x, y);
if(other != null && other.block instanceof PowerNode node && node.linkValid(other, self()) && !PowerNode.insulated(other, self())
&& !other.proximity().contains(this.<Building>self()) &&
!(block.outputsPower && proximity.contains(p -> p.power != null && p.power.graph == other.power.graph))){
tempTiles.add(other.tile);
} }
}); });
tempTiles.sort(Structs.comparingFloat(t -> t.dst2(tile)));
if(!tempTiles.isEmpty()){
Tile toLink = tempTiles.first();
if(!toLink.build.power.links.contains(pos())){
toLink.build.configureAny(pos());
}
}
} }
} }
@@ -964,6 +952,12 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
if(block.configurations.containsKey(type)){ if(block.configurations.containsKey(type)){
block.configurations.get(type).get(this, value); block.configurations.get(type).get(this, value);
}else if(value instanceof Building build){
//copy config of another building
var conf = build.config();
if(conf != null && !(conf instanceof Building)){
configured(builder, conf);
}
} }
} }
@@ -1148,7 +1142,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
/** Returns whether or not a hand cursor should be shown over this block. */ /** Returns whether or not a hand cursor should be shown over this block. */
public Cursor getCursor(){ public Cursor getCursor(){
return block.configurable && team == player.team() ? SystemCursor.hand : SystemCursor.arrow; return block.configurable && interactable(player.team()) ? SystemCursor.hand : SystemCursor.arrow;
} }
/** /**
@@ -1312,7 +1306,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
return switch(sensor){ return switch(sensor){
case x -> World.conv(x); case x -> World.conv(x);
case y -> World.conv(y); case y -> World.conv(y);
//case dead -> !isValid(); //TODO 126 case dead -> !isValid() ? 1 : 0;
case team -> team.id; case team -> team.id;
case health -> health; case health -> health;
case maxHealth -> maxHealth; case maxHealth -> maxHealth;
@@ -1331,8 +1325,9 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
case powerNetStored -> power == null ? 0 : power.graph.getLastPowerStored(); case powerNetStored -> power == null ? 0 : power.graph.getLastPowerStored();
case powerNetCapacity -> power == null ? 0 : power.graph.getLastCapacity(); case powerNetCapacity -> power == null ? 0 : power.graph.getLastCapacity();
case enabled -> enabled ? 1 : 0; case enabled -> enabled ? 1 : 0;
case controlled -> this instanceof ControlBlock c ? c.isControlled() ? 1 : 0 : 0; case controlled -> this instanceof ControlBlock c && c.isControlled() ? GlobalConstants.ctrlPlayer : 0;
case payloadCount -> getPayload() != null ? 1 : 0; case payloadCount -> getPayload() != null ? 1 : 0;
case size -> block.size;
default -> Float.NaN; //gets converted to null in logic default -> Float.NaN; //gets converted to null in logic
}; };
} }

View File

@@ -78,16 +78,16 @@ abstract class MechComp implements Posc, Flyingc, Hitboxc, Unitc, Mechc, Elevati
@Override @Override
public void moveAt(Vec2 vector, float acceleration){ public void moveAt(Vec2 vector, float acceleration){
if(!vector.isZero()){
//mark walking state when moving in a controlled manner //mark walking state when moving in a controlled manner
if(!vector.isZero()){
walked = true; walked = true;
} }
} }
@Override @Override
public void approach(Vec2 vector){ public void approach(Vec2 vector){
if(!vector.isZero(0.09f)){
//mark walking state when moving in a controlled manner //mark walking state when moving in a controlled manner
if(!vector.isZero(0.001f)){
walked = true; walked = true;
} }
} }

View File

@@ -19,7 +19,8 @@ abstract class StatusComp implements Posc, Flyingc{
private Seq<StatusEntry> statuses = new Seq<>(); private Seq<StatusEntry> statuses = new Seq<>();
private transient Bits applied = new Bits(content.getBy(ContentType.status).size); private transient Bits applied = new Bits(content.getBy(ContentType.status).size);
@ReadOnly transient float speedMultiplier = 1, damageMultiplier = 1, healthMultiplier = 1, reloadMultiplier = 1; @ReadOnly transient float speedMultiplier = 1, damageMultiplier = 1, healthMultiplier = 1, reloadMultiplier = 1, buildSpeedMultiplier = 1;
@ReadOnly transient boolean disarmed = false;
@Import UnitType type; @Import UnitType type;
@@ -110,7 +111,8 @@ abstract class StatusComp implements Posc, Flyingc{
} }
applied.clear(); applied.clear();
speedMultiplier = damageMultiplier = healthMultiplier = reloadMultiplier = 1f; speedMultiplier = damageMultiplier = healthMultiplier = reloadMultiplier = buildSpeedMultiplier = 1f;
disarmed = false;
if(statuses.isEmpty()) return; if(statuses.isEmpty()) return;
@@ -132,6 +134,10 @@ abstract class StatusComp implements Posc, Flyingc{
healthMultiplier *= entry.effect.healthMultiplier; healthMultiplier *= entry.effect.healthMultiplier;
damageMultiplier *= entry.effect.damageMultiplier; damageMultiplier *= entry.effect.damageMultiplier;
reloadMultiplier *= entry.effect.reloadMultiplier; reloadMultiplier *= entry.effect.reloadMultiplier;
buildSpeedMultiplier *= entry.effect.buildSpeedMultiplier;
disarmed |= entry.effect.disarm;
entry.effect.update(self(), entry.time); entry.effect.update(self(), entry.time);
} }
} }

View File

@@ -32,7 +32,7 @@ import static mindustry.Vars.*;
@Component(base = true) @Component(base = true)
abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Commanderc, Displayable, Senseable, Ranged, Minerc, Builderc{ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, Itemsc, Rotc, Unitc, Weaponsc, Drawc, Boundedc, Syncc, Shieldc, Commanderc, Displayable, Senseable, Ranged, Minerc, Builderc{
@Import boolean hovering, dead; @Import boolean hovering, dead, disarmed;
@Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo, minFormationSpeed; @Import float x, y, rotation, elevation, maxHealth, drag, armor, hitSize, health, ammo, minFormationSpeed;
@Import Team team; @Import Team team;
@Import int id; @Import int id;
@@ -128,9 +128,10 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
case ammoCapacity -> type.ammoCapacity; case ammoCapacity -> type.ammoCapacity;
case x -> World.conv(x); case x -> World.conv(x);
case y -> World.conv(y); case y -> World.conv(y);
//case dead -> dead || !isAdded(); //TODO 126 case dead -> dead || !isAdded() ? 1 : 0;
case team -> team.id; case team -> team.id;
case shooting -> isShooting() ? 1 : 0; case shooting -> isShooting() ? 1 : 0;
case boosting -> type.canBoost && isFlying() ? 1 : 0;
case range -> range() / tilesize; case range -> range() / tilesize;
case shootX -> World.conv(aimX()); case shootX -> World.conv(aimX());
case shootY -> World.conv(aimY()); case shootY -> World.conv(aimY());
@@ -138,9 +139,14 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
case mineX -> mining() ? mineTile.x : -1; case mineX -> mining() ? mineTile.x : -1;
case mineY -> mining() ? mineTile.y : -1; case mineY -> mining() ? mineTile.y : -1;
case flag -> flag; case flag -> flag;
case controlled -> controller instanceof LogicAI || controller instanceof Player ? 1 : 0; case controlled -> !isValid() ? 0 :
case commanded -> controller instanceof FormationAI ? 1 : 0; controller instanceof LogicAI ? GlobalConstants.ctrlProcessor :
controller instanceof Player ? GlobalConstants.ctrlPlayer :
controller instanceof FormationAI ? GlobalConstants.ctrlFormation :
0;
case commanded -> controller instanceof FormationAI && isValid() ? 1 : 0;
case payloadCount -> self() instanceof Payloadc pay ? pay.payloads().size : 0; case payloadCount -> self() instanceof Payloadc pay ? pay.payloads().size : 0;
case size -> hitSize / tilesize;
default -> Float.NaN; default -> Float.NaN;
}; };
} }
@@ -151,13 +157,13 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
case type -> type; case type -> type;
case name -> controller instanceof Player p ? p.name : null; case name -> controller instanceof Player p ? p.name : null;
case firstItem -> stack().amount == 0 ? null : item(); case firstItem -> stack().amount == 0 ? null : item();
case controller -> !isValid() ? null : controller instanceof LogicAI log ? log.controller : controller instanceof FormationAI form ? form.leader : this;
case payloadType -> self() instanceof Payloadc pay ? case payloadType -> self() instanceof Payloadc pay ?
(pay.payloads().isEmpty() ? null : (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; pay.payloads().peek() instanceof BuildPayload p2 ? p2.block() : null) : null;
default -> noSensed; default -> noSensed;
}; };
} }
@Override @Override
@@ -176,7 +182,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
@Replace @Replace
public boolean canShoot(){ public boolean canShoot(){
//cannot shoot while boosting //cannot shoot while boosting
return !(type.canBoost && isFlying()); return !disarmed && !(type.canBoost && isFlying());
} }
@Override @Override

View File

@@ -16,6 +16,7 @@ import static mindustry.Vars.*;
@Component @Component
abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{
@Import float x, y, rotation, reloadMultiplier; @Import float x, y, rotation, reloadMultiplier;
@Import boolean disarmed;
@Import Vec2 vel; @Import Vec2 vel;
@Import UnitType type; @Import UnitType type;
@@ -81,7 +82,7 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{
} }
boolean canShoot(){ boolean canShoot(){
return true; return !disarmed;
} }
@Override @Override

View File

@@ -62,6 +62,10 @@ public class BuildPlan implements Position{
} }
public boolean placeable(Team team){
return Build.validPlace(block, team, x, y, rotation);
}
public boolean isRotation(Team team){ public boolean isRotation(Team team){
if(breaking) return false; if(breaking) return false;
Tile tile = tile(); Tile tile = tile();

View File

@@ -383,6 +383,15 @@ public class EventType{
} }
} }
/** Called when a connection is established to a client. */
public static class ConnectionEvent{
public final NetConnection connection;
public ConnectionEvent(NetConnection connection){
this.connection = connection;
}
}
/** Called after connecting; when a player receives world data and is ready to play.*/ /** Called after connecting; when a player receives world data and is ready to play.*/
public static class PlayerJoin{ public static class PlayerJoin{
public final Player player; public final Player player;

View File

@@ -50,6 +50,8 @@ public class Rules{
public float unitBuildSpeedMultiplier = 1f; public float unitBuildSpeedMultiplier = 1f;
/** How much damage any other units deal. */ /** How much damage any other units deal. */
public float unitDamageMultiplier = 1f; public float unitDamageMultiplier = 1f;
/** Whether to allow units to build with logic. */
public boolean logicUnitBuild = true;
/** How much health blocks start with. */ /** How much health blocks start with. */
public float blockHealthMultiplier = 1f; public float blockHealthMultiplier = 1f;
/** How much damage blocks (turrets) deal. */ /** How much damage blocks (turrets) deal. */

View File

@@ -27,6 +27,7 @@ import mindustry.input.Placement.*;
import mindustry.io.*; import mindustry.io.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.*; import mindustry.world.blocks.*;
import mindustry.world.blocks.ConstructBlock.*;
import mindustry.world.blocks.distribution.*; import mindustry.world.blocks.distribution.*;
import mindustry.world.blocks.legacy.*; import mindustry.world.blocks.legacy.*;
import mindustry.world.blocks.power.*; import mindustry.world.blocks.power.*;
@@ -357,10 +358,11 @@ public class Schematics implements Loadable{
for(int cx = x; cx <= x2; cx++){ for(int cx = x; cx <= x2; cx++){
for(int cy = y; cy <= y2; cy++){ for(int cy = y; cy <= y2; cy++){
Building linked = world.build(cx, cy); Building linked = world.build(cx, cy);
Block realBlock = linked == null ? null : linked instanceof ConstructBuild cons ? cons.cblock : linked.block;
if(linked != null && (linked.block.isVisible() || linked.block() instanceof CoreBlock) && !(linked.block instanceof ConstructBlock)){ if(linked != null && (realBlock.isVisible() || realBlock instanceof CoreBlock)){
int top = linked.block.size/2; int top = realBlock.size/2;
int bot = linked.block.size % 2 == 1 ? -linked.block.size/2 : -(linked.block.size - 1)/2; int bot = realBlock.size % 2 == 1 ? -realBlock.size/2 : -(realBlock.size - 1)/2;
minx = Math.min(linked.tileX() + bot, minx); minx = Math.min(linked.tileX() + bot, minx);
miny = Math.min(linked.tileY() + bot, miny); miny = Math.min(linked.tileY() + bot, miny);
maxx = Math.max(linked.tileX() + top, maxx); maxx = Math.max(linked.tileX() + top, maxx);
@@ -385,12 +387,13 @@ public class Schematics implements Loadable{
for(int cx = ox; cx <= ox2; cx++){ for(int cx = ox; cx <= ox2; cx++){
for(int cy = oy; cy <= oy2; cy++){ for(int cy = oy; cy <= oy2; cy++){
Building tile = world.build(cx, cy); Building tile = world.build(cx, cy);
Block realBlock = tile == null ? null : tile instanceof ConstructBuild cons ? cons.cblock : tile.block;
if(tile != null && !counted.contains(tile.pos()) && !(tile.block instanceof ConstructBlock) if(tile != null && !counted.contains(tile.pos())
&& (tile.block.isVisible() || tile.block instanceof CoreBlock)){ && (realBlock.isVisible() || realBlock instanceof CoreBlock)){
Object config = tile.config(); Object config = tile instanceof ConstructBuild cons ? cons.lastConfig : tile.config();
tiles.add(new Stile(tile.block, tile.tileX() + offsetX, tile.tileY() + offsetY, config, (byte)tile.rotation)); tiles.add(new Stile(realBlock, tile.tileX() + offsetX, tile.tileY() + offsetY, config, (byte)tile.rotation));
counted.add(tile.pos()); counted.add(tile.pos());
} }
} }

View File

@@ -112,6 +112,12 @@ public class Drawf{
Draw.color(); Draw.color();
} }
public static void shadow(TextureRegion region, float x, float y, float width, float height, float rotation){
Draw.color(Pal.shadow);
Draw.rect(region, x, y, width, height, rotation);
Draw.color();
}
public static void liquid(TextureRegion region, float x, float y, float alpha, Color color, float rotation){ public static void liquid(TextureRegion region, float x, float y, float alpha, Color color, float rotation){
Draw.color(color, alpha); Draw.color(color, alpha);
Draw.rect(region, x, y, rotation); Draw.rect(region, x, y, rotation);

View File

@@ -44,6 +44,10 @@ public class DesktopInput extends InputHandler{
public boolean deleting = false, shouldShoot = false, panning = false; public boolean deleting = false, shouldShoot = false, panning = false;
/** Mouse pan speed. */ /** Mouse pan speed. */
public float panScale = 0.005f, panSpeed = 4.5f, panBoostSpeed = 11f; public float panScale = 0.005f, panSpeed = 4.5f, panBoostSpeed = 11f;
/** Delta time between consecutive clicks. */
public long selectMillis = 0;
/** Previously selected tile. */
public Tile prevSelected;
boolean showHint(){ boolean showHint(){
return ui.hudfrag.shown && Core.settings.getBool("hints") && selectRequests.isEmpty() && return ui.hudfrag.shown && Core.settings.getBool("hints") && selectRequests.isEmpty() &&
@@ -489,13 +493,15 @@ public class DesktopInput extends InputHandler{
deleting = true; deleting = true;
}else if(selected != null){ }else if(selected != null){
//only begin shooting if there's no cursor event //only begin shooting if there's no cursor event
if(!tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && !tileTapped(selected.build) && !player.unit().activelyBuilding() && !droppingItem && if(!tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && !tileTapped(selected.build) && !player.unit().activelyBuilding() && !droppingItem
!tryBeginMine(selected) && player.unit().mineTile == null && !Core.scene.hasKeyboard()){ && !(tryStopMine(selected) || (!settings.getBool("doubletapmine") || selected == prevSelected && Time.timeSinceMillis(selectMillis) < 500) && tryBeginMine(selected)) && !Core.scene.hasKeyboard()){
player.shooting = shouldShoot; player.shooting = shouldShoot;
} }
}else if(!Core.scene.hasKeyboard()){ //if it's out of bounds, shooting is just fine }else if(!Core.scene.hasKeyboard()){ //if it's out of bounds, shooting is just fine
player.shooting = shouldShoot; player.shooting = shouldShoot;
} }
selectMillis = Time.millis();
prevSelected = selected;
}else if(Core.input.keyTap(Binding.deselect) && isPlacing()){ }else if(Core.input.keyTap(Binding.deselect) && isPlacing()){
block = null; block = null;
mode = none; mode = none;

View File

@@ -30,11 +30,10 @@ import mindustry.net.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.ui.fragments.*; import mindustry.ui.fragments.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.ConstructBlock.*; import mindustry.world.blocks.ConstructBlock.*;
import mindustry.world.blocks.*;
import mindustry.world.blocks.distribution.*; import mindustry.world.blocks.distribution.*;
import mindustry.world.blocks.payloads.*; import mindustry.world.blocks.payloads.*;
import mindustry.world.blocks.power.*;
import mindustry.world.blocks.storage.CoreBlock.*; import mindustry.world.blocks.storage.CoreBlock.*;
import mindustry.world.meta.*; import mindustry.world.meta.*;
@@ -771,7 +770,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
Draw.reset(); Draw.reset();
Draw.mixcol(!valid ? Pal.breakInvalid : Color.white, (!valid ? 0.4f : 0.24f) + Mathf.absin(Time.globalTime, 6f, 0.28f)); Draw.mixcol(!valid ? Pal.breakInvalid : Color.white, (!valid ? 0.4f : 0.24f) + Mathf.absin(Time.globalTime, 6f, 0.28f));
Draw.alpha(1f); Draw.alpha(1f);
request.block.drawRequestConfigTop(request, selectRequests); request.block.drawRequestConfigTop(request, cons -> {
selectRequests.each(cons);
lineRequests.each(cons);
});
Draw.reset(); Draw.reset();
} }
@@ -867,6 +869,8 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
req.block = replace; req.block = replace;
} }
}); });
block.handlePlacementLine(lineRequests);
} }
} }
@@ -944,8 +948,24 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
/** Tries to begin mining a tile, returns true if successful. */ /** Tries to begin mining a tile, returns true if successful. */
boolean tryBeginMine(Tile tile){ boolean tryBeginMine(Tile tile){
if(canMine(tile)){ if(canMine(tile)){
//if a block is clicked twice, reset it player.unit().mineTile = tile;
player.unit().mineTile = player.unit().mineTile == tile ? null : tile; return true;
}
return false;
}
/** Tries to stop mining, returns true if mining was stopped. */
boolean tryStopMine(){
if(player.unit().mining()){
player.unit().mineTile = null;
return true;
}
return false;
}
boolean tryStopMine(Tile tile){
if(player.unit().mineTile == tile){
player.unit().mineTile = null;
return true; return true;
} }
return false; return false;

View File

@@ -71,6 +71,8 @@ public class MobileInput extends InputHandler implements GestureListener{
public Teamc target; public Teamc target;
/** Payload target being moved to. Can be a position (for dropping), or a unit/block. */ /** Payload target being moved to. Can be a position (for dropping), or a unit/block. */
public Position payloadTarget; public Position payloadTarget;
/** Unit last tapped, or null if last tap was not on a unit. */
public Unit unitTapped;
//region utility methods //region utility methods
@@ -314,6 +316,7 @@ public class MobileInput extends InputHandler implements GestureListener{
request.block.drawPlan(request, allRequests(), validPlace(request.x, request.y, request.block, request.rotation) && getRequest(request.x, request.y, request.block.size, null) == null); request.block.drawPlan(request, allRequests(), validPlace(request.x, request.y, request.block, request.rotation) && getRequest(request.x, request.y, request.block.size, null) == null);
drawSelected(request.x, request.y, request.block, Pal.accent); drawSelected(request.x, request.y, request.block, Pal.accent);
} }
lineRequests.each(this::drawOverRequest);
}else if(mode == breaking){ }else if(mode == breaking){
drawBreakSelection(lineStartX, lineStartY, tileX, tileY); drawBreakSelection(lineStartX, lineStartY, tileX, tileY);
} }
@@ -423,7 +426,7 @@ public class MobileInput extends InputHandler implements GestureListener{
@Override @Override
public void useSchematic(Schematic schem){ public void useSchematic(Schematic schem){
selectRequests.clear(); selectRequests.clear();
selectRequests.addAll(schematics.toRequests(schem, player.tileX(), player.tileY())); selectRequests.addAll(schematics.toRequests(schem, World.toTile(Core.camera.position.x), World.toTile(Core.camera.position.y)));
lastSchematic = schem; lastSchematic = schem;
} }
@@ -598,11 +601,7 @@ public class MobileInput extends InputHandler implements GestureListener{
//add to selection queue if it's a valid BREAK position //add to selection queue if it's a valid BREAK position
selectRequests.add(new BuildPlan(linked.x, linked.y)); selectRequests.add(new BuildPlan(linked.x, linked.y));
}else{ }else{
if(!canTapPlayer(worldx, worldy) && !tileTapped(linked.build)){ //control units
tryBeginMine(cursor);
}
//control units.
if(count == 2){ if(count == 2){
//reset payload target //reset payload target
payloadTarget = null; payloadTarget = null;
@@ -610,12 +609,20 @@ public class MobileInput extends InputHandler implements GestureListener{
if(!player.dead() && Mathf.within(worldx, worldy, player.unit().x, player.unit().y, player.unit().hitSize * 0.6f + 8f) && player.unit().type.commandLimit > 0){ if(!player.dead() && Mathf.within(worldx, worldy, player.unit().x, player.unit().y, player.unit().hitSize * 0.6f + 8f) && player.unit().type.commandLimit > 0){
Call.unitCommand(player); Call.unitCommand(player);
}else{ }else{
//control a unit/block //control a unit/block detected on first tap of double-tap
Unit on = selectedUnit(); if(unitTapped != null){
if(on != null){ Call.unitControl(player, unitTapped);
Call.unitControl(player, on); }else if(!tryBeginMine(cursor)){
tileTapped(linked.build);
} }
} }
return false;
}
unitTapped = selectedUnit();
//prevent mining if placing/breaking blocks
if(!tryStopMine() && !canTapPlayer(worldx, worldy) && !tileTapped(linked.build) && mode == none && !Core.settings.getBool("doubletapmine")){
tryBeginMine(cursor);
} }
} }

View File

@@ -6,22 +6,24 @@ import arc.math.*;
import arc.math.geom.*; import arc.math.geom.*;
import arc.struct.*; import arc.struct.*;
import arc.util.pooling.*; import arc.util.pooling.*;
import mindustry.entities.units.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.distribution.*; import mindustry.world.blocks.distribution.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class Placement{ public class Placement{
private final static Seq<Point2> tmpPoints = new Seq<>(), tmpPoints2 = new Seq<>(); private static final Seq<BuildPlan> plans1 = new Seq<>();
private static final Seq<Point2> tmpPoints = new Seq<>(), tmpPoints2 = new Seq<>();
private static final NormalizeResult result = new NormalizeResult(); private static final NormalizeResult result = new NormalizeResult();
private static final NormalizeDrawResult drawResult = new NormalizeDrawResult(); private static final NormalizeDrawResult drawResult = new NormalizeDrawResult();
private static Bresenham2 bres = new Bresenham2(); private static final Bresenham2 bres = new Bresenham2();
private static Seq<Point2> points = new Seq<>(); private static final Seq<Point2> points = new Seq<>();
//for pathfinding //for pathfinding
private static IntFloatMap costs = new IntFloatMap(); private static final IntFloatMap costs = new IntFloatMap();
private static IntIntMap parents = new IntIntMap(); private static final IntIntMap parents = new IntIntMap();
private static IntSet closed = new IntSet(); private static final IntSet closed = new IntSet();
/** Normalize a diagonal line into points. */ /** Normalize a diagonal line into points. */
public static Seq<Point2> pathfindLine(boolean conveyors, int startX, int startY, int endX, int endY){ public static Seq<Point2> pathfindLine(boolean conveyors, int startX, int startY, int endX, int endY){
@@ -75,7 +77,7 @@ public class Placement{
var base = tmpPoints2; var base = tmpPoints2;
var result = tmpPoints.clear(); var result = tmpPoints.clear();
base.selectFrom(points, p -> p == points.first() || p == points.peek() || Build.validPlace(block, player.team(), p.x, p.y, rotation, false)); base.selectFrom(points, p -> p == points.first() || p == points.peek() || Build.validPlace(block, player.team(), p.x, p.y, rotation));
boolean addedLast = false; boolean addedLast = false;
outer: outer:
@@ -106,6 +108,67 @@ public class Placement{
points.addAll(result); points.addAll(result);
} }
public static void calculateBridges(Seq<BuildPlan> plans, ItemBridge bridge){
//check for orthogonal placement + unlocked state
if(!(plans.first().x == plans.peek().x || plans.first().y == plans.peek().y || !bridge.unlockedNow())){
return;
}
Boolf<BuildPlan> placeable = plan -> (plan.placeable(player.team())) ||
(plan.tile() != null && plan.tile().block() == plan.block); //don't count the same block as inaccessible
var result = plans1.clear();
var team = player.team();
var rotated = plans.first().tile() != null && plans.first().tile().absoluteRelativeTo(plans.peek().x, plans.peek().y) == Mathf.mod(plans.first().rotation + 2, 4);
outer:
for(int i = 0; i < plans.size;){
var cur = plans.get(i);
result.add(cur);
//gap found
if(i < plans.size - 1 && placeable.get(cur) && !placeable.get(plans.get(i + 1))){
//find the closest valid position within range
for(int j = i + 1; j < plans.size; j++){
var other = plans.get(j);
//out of range now, set to current position and keep scanning forward for next occurrence
if(!bridge.positionsValid(cur.x, cur.y, other.x, other.y)){
//add 'missed' conveyors
for(int k = i + 1; k < j; k++){
result.add(plans.get(k));
}
i = j;
continue outer;
}else if(other.placeable(team)){
//found a link, assign bridges
cur.block = bridge;
other.block = bridge;
if(rotated){
other.config = new Point2(cur.x - other.x, cur.y - other.y);
}else{
cur.config = new Point2(other.x - cur.x, other.y - cur.y);
}
i = j;
continue outer;
}
}
//if it got here, that means nothing was found. this likely means there's a bunch of stuff at the end; add it and bail out
for(int j = i + 1; j < plans.size; j++){
result.add(plans.get(j));
}
break;
}else{
i ++;
}
}
plans.set(result);
}
private static float tileHeuristic(Tile tile, Tile other){ private static float tileHeuristic(Tile tile, Tile other){
Block block = control.input.block; Block block = control.input.block;

View File

@@ -572,10 +572,12 @@ public class TypeIO{
writeString(write, trace.uuid); writeString(write, trace.uuid);
write.b(trace.modded ? (byte)1 : 0); write.b(trace.modded ? (byte)1 : 0);
write.b(trace.mobile ? (byte)1 : 0); write.b(trace.mobile ? (byte)1 : 0);
write.i(trace.timesJoined);
write.i(trace.timesKicked);
} }
public static TraceInfo readTraceInfo(Reads read){ public static TraceInfo readTraceInfo(Reads read){
return new TraceInfo(readString(read), readString(read), read.b() == 1, read.b() == 1); return new TraceInfo(readString(read), readString(read), read.b() == 1, read.b() == 1, read.i(), read.i());
} }
public static void writeStringData(DataOutput buffer, String string) throws IOException{ public static void writeStringData(DataOutput buffer, String string) throws IOException{

View File

@@ -1,8 +1,10 @@
package mindustry.logic; package mindustry.logic;
import arc.util.*;
public enum ConditionOp{ public enum ConditionOp{
equal("==", (a, b) -> Math.abs(a - b) < 0.000001, (a, b) -> a == b), equal("==", (a, b) -> Math.abs(a - b) < 0.000001, Structs::eq),
notEqual("not", (a, b) -> Math.abs(a - b) >= 0.000001, (a, b) -> a != b), notEqual("not", (a, b) -> Math.abs(a - b) >= 0.000001, (a, b) -> !Structs.eq(a, b)),
lessThan("<", (a, b) -> a < b), lessThan("<", (a, b) -> a < b),
lessThanEq("<=", (a, b) -> a <= b), lessThanEq("<=", (a, b) -> a <= b),
greaterThan(">", (a, b) -> a > b), greaterThan(">", (a, b) -> a > b),

View File

@@ -9,6 +9,8 @@ import mindustry.world.*;
/** Stores global constants for logic processors. */ /** Stores global constants for logic processors. */
public class GlobalConstants{ public class GlobalConstants{
public static final int ctrlProcessor = 1, ctrlPlayer = 2, ctrlFormation = 3;
private ObjectIntMap<String> namesToIds = new ObjectIntMap<>(); private ObjectIntMap<String> namesToIds = new ObjectIntMap<>();
private Seq<Var> vars = new Seq<>(Var.class); private Seq<Var> vars = new Seq<>(Var.class);
@@ -19,6 +21,12 @@ public class GlobalConstants{
put("true", 1); put("true", 1);
put("null", null); put("null", null);
//special enums
put("@ctrlProcessor", ctrlProcessor);
put("@ctrlPlayer", ctrlPlayer);
put("@ctrlFormation", ctrlFormation);
//store base content //store base content
for(Item item : Vars.content.items()){ for(Item item : Vars.content.items()){

View File

@@ -27,9 +27,11 @@ public enum LAccess{
y, y,
shootX, shootX,
shootY, shootY,
//dead, //TODO 126 size,
dead,
range, range,
shooting, shooting,
boosting,
mineX, mineX,
mineY, mineY,
mining, mining,
@@ -37,6 +39,7 @@ public enum LAccess{
type, type,
flag, flag,
controlled, controlled,
controller,
commanded, commanded,
name, name,
config, config,

View File

@@ -447,7 +447,7 @@ public class LExecutor{
} }
} }
case build -> { case build -> {
if(unit.canBuild() && exec.obj(p3) instanceof Block block){ if(state.rules.logicUnitBuild && unit.canBuild() && exec.obj(p3) instanceof Block block){
int x = World.toTile(x1 - block.offset/tilesize), y = World.toTile(y1 - block.offset/tilesize); int x = World.toTile(x1 - block.offset/tilesize), y = World.toTile(y1 - block.offset/tilesize);
int rot = exec.numi(p4); int rot = exec.numi(p4);
@@ -458,12 +458,14 @@ public class LExecutor{
ai.plan.stuck = false; ai.plan.stuck = false;
} }
var conf = exec.obj(p5);
ai.plan.set(x, y, rot, block); ai.plan.set(x, y, rot, block);
ai.plan.config = exec.obj(p5) instanceof Content c ? c : null; ai.plan.config = conf instanceof Content c ? c : conf instanceof Building b ? b : null;
unit.clearBuilding(); unit.clearBuilding();
Tile tile = ai.plan.tile();
if(ai.plan.tile() != null){ if(tile != null && !(tile.block() == block && tile.build != null && tile.build.rotation == rot)){
unit.updateBuilding = true; unit.updateBuilding = true;
unit.addBuild(ai.plan); unit.addBuild(ai.plan);
} }

View File

@@ -603,7 +603,7 @@ public class LStatements{
table.add(" = "); table.add(" = ");
if(op.unary){ if(op.unary){
opButton(table); opButton(table, table);
field(table, a, str -> a = str); field(table, a, str -> a = str);
}else{ }else{
@@ -617,35 +617,35 @@ public class LStatements{
table.table(c -> { table.table(c -> {
c.color.set(color()); c.color.set(color());
c.left(); c.left();
funcs(c); funcs(c, table);
}).colspan(2).left(); }).colspan(2).left();
}else{ }else{
funcs(table); funcs(table, table);
} }
}else{ }else{
field(table, a, str -> a = str); field(table, a, str -> a = str);
opButton(table); opButton(table, table);
field(table, b, str -> b = str); field(table, b, str -> b = str);
} }
} }
} }
void funcs(Table table){ void funcs(Table table, Table parent){
opButton(table); opButton(table, parent);
field(table, a, str -> a = str); field(table, a, str -> a = str);
field(table, b, str -> b = str); field(table, b, str -> b = str);
} }
void opButton(Table table){ void opButton(Table table, Table parent){
table.button(b -> { table.button(b -> {
b.label(() -> op.symbol); b.label(() -> op.symbol);
b.clicked(() -> showSelect(b, LogicOp.all, op, o -> { b.clicked(() -> showSelect(b, LogicOp.all, op, o -> {
op = o; op = o;
rebuild(table); rebuild(parent);
})); }));
}, Styles.logict, () -> {}).size(64f, 40f).pad(4f).color(table.color); }, Styles.logict, () -> {}).size(64f, 40f).pad(4f).color(table.color);
} }
@@ -829,7 +829,11 @@ public class LStatements{
table.button(b -> { table.button(b -> {
b.label(() -> type.name()); b.label(() -> type.name());
b.clicked(() -> showSelect(b, LUnitControl.all, type, t -> { b.clicked(() -> showSelect(b, LUnitControl.all, type, t -> {
if(t == LUnitControl.build && !Vars.state.rules.logicUnitBuild){
Vars.ui.showInfo("@logic.nounitbuild");
}else{
type = t; type = t;
}
rebuild(table); rebuild(table);
}, 2, cell -> cell.size(120, 50))); }, 2, cell -> cell.size(120, 50)));
}, Styles.logict, () -> {}).size(120, 40).color(table.color).left().padLeft(2); }, Styles.logict, () -> {}).size(120, 40).color(table.color).left().padLeft(2);

View File

@@ -1,6 +1,7 @@
package mindustry.logic; package mindustry.logic;
public enum LUnitControl{ public enum LUnitControl{
idle,
stop, stop,
move("x", "y"), move("x", "y"),
approach("x", "y", "radius"), approach("x", "y", "radius"),

View File

@@ -338,7 +338,7 @@ public class SerpuloPlanetGenerator extends PlanetGenerator{
} }
}else if(floor != Blocks.basalt && floor != Blocks.ice && floor.asFloor().hasSurface()){ }else if(floor != Blocks.basalt && floor != Blocks.ice && floor.asFloor().hasSurface()){
float noise = noise(x + 782, y, 5, 0.75f, 260f, 1f); float noise = noise(x + 782, y, 5, 0.75f, 260f, 1f);
if(noise > 0.67f && !enemies.contains(e -> Mathf.within(x, y, e.x, e.y, 8))){ if(noise > 0.67f && !roomseq.contains(e -> Mathf.within(x, y, e.x, e.y, 14))){
if(noise > 0.72f){ if(noise > 0.72f){
floor = noise > 0.78f ? Blocks.taintedWater : (floor == Blocks.sand ? Blocks.sandWater : Blocks.darksandTaintedWater); floor = noise > 0.78f ? Blocks.taintedWater : (floor == Blocks.sand ? Blocks.sandWater : Blocks.darksandTaintedWater);
}else{ }else{

View File

@@ -14,6 +14,13 @@ public class ClassMap{
classes.put("MinerAI", mindustry.ai.types.MinerAI.class); classes.put("MinerAI", mindustry.ai.types.MinerAI.class);
classes.put("RepairAI", mindustry.ai.types.RepairAI.class); classes.put("RepairAI", mindustry.ai.types.RepairAI.class);
classes.put("SuicideAI", mindustry.ai.types.SuicideAI.class); classes.put("SuicideAI", mindustry.ai.types.SuicideAI.class);
classes.put("Ability", mindustry.entities.abilities.Ability.class);
classes.put("ForceFieldAbility", mindustry.entities.abilities.ForceFieldAbility.class);
classes.put("MoveLightningAbility", mindustry.entities.abilities.MoveLightningAbility.class);
classes.put("RepairFieldAbility", mindustry.entities.abilities.RepairFieldAbility.class);
classes.put("ShieldRegenFieldAbility", mindustry.entities.abilities.ShieldRegenFieldAbility.class);
classes.put("StatusFieldAbility", mindustry.entities.abilities.StatusFieldAbility.class);
classes.put("UnitSpawnAbility", mindustry.entities.abilities.UnitSpawnAbility.class);
classes.put("ArtilleryBulletType", mindustry.entities.bullet.ArtilleryBulletType.class); classes.put("ArtilleryBulletType", mindustry.entities.bullet.ArtilleryBulletType.class);
classes.put("BasicBulletType", mindustry.entities.bullet.BasicBulletType.class); classes.put("BasicBulletType", mindustry.entities.bullet.BasicBulletType.class);
classes.put("BombBulletType", mindustry.entities.bullet.BombBulletType.class); classes.put("BombBulletType", mindustry.entities.bullet.BombBulletType.class);

View File

@@ -92,6 +92,16 @@ public class ContentParser{
readFields(result, data); readFields(result, data);
return result; return result;
}); });
put(Weather.class, (type, data) -> {
if(data.isString()){
return field(Weathers.class, data);
}
var bc = resolve(data.getString("type", ""), ParticleWeather.class);
data.remove("type");
Weather result = make(bc);
readFields(result, data);
return result;
});
put(DrawBlock.class, (type, data) -> { put(DrawBlock.class, (type, data) -> {
if(data.isString()){ if(data.isString()){
//try to instantiate //try to instantiate
@@ -211,7 +221,7 @@ public class ContentParser{
throw new IllegalArgumentException("When defining properties for an existing block, you must not re-declare its type. The original type will be used. Block: " + name); throw new IllegalArgumentException("When defining properties for an existing block, you must not re-declare its type. The original type will be used. Block: " + name);
} }
}else{ }else{
block = make(resolve(getType(value), Block.class), mod + "-" + name); block = make(resolve(value.getString("type", ""), Block.class), mod + "-" + name);
} }
currentContent = block; currentContent = block;
@@ -291,6 +301,7 @@ public class ContentParser{
if(value.has("controller")){ if(value.has("controller")){
unit.defaultController = supply(resolve(value.getString("controller"), FlyingAI.class)); unit.defaultController = supply(resolve(value.getString("controller"), FlyingAI.class));
value.remove("controller");
} }
//read extra default waves //read extra default waves

View File

@@ -24,6 +24,7 @@ import mindustry.type.*;
import mindustry.ui.*; import mindustry.ui.*;
import java.io.*; import java.io.*;
import java.util.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@@ -526,7 +527,7 @@ public class Mods implements Loadable{
if(mod.root.child("content").exists()){ if(mod.root.child("content").exists()){
Fi contentRoot = mod.root.child("content"); Fi contentRoot = mod.root.child("content");
for(ContentType type : ContentType.all){ for(ContentType type : ContentType.all){
Fi folder = contentRoot.child(type.name().toLowerCase() + "s"); Fi folder = contentRoot.child(type.name().toLowerCase(Locale.ROOT) + "s");
if(folder.exists()){ if(folder.exists()){
for(Fi file : folder.findAll(f -> f.extension().equals("json") || f.extension().equals("hjson"))){ for(Fi file : folder.findAll(f -> f.extension().equals("json") || f.extension().equals("hjson"))){
runs.add(new LoadRun(type, file, mod)); runs.add(new LoadRun(type, file, mod));
@@ -646,8 +647,8 @@ public class Mods implements Loadable{
ModMeta meta = json.fromJson(ModMeta.class, Jval.read(metaf.readString()).toString(Jformat.plain)); ModMeta meta = json.fromJson(ModMeta.class, Jval.read(metaf.readString()).toString(Jformat.plain));
meta.cleanup(); meta.cleanup();
String camelized = meta.name.replace(" ", ""); String camelized = meta.name.replace(" ", "");
String mainClass = meta.main == null ? camelized.toLowerCase() + "." + camelized + "Mod" : meta.main; String mainClass = meta.main == null ? camelized.toLowerCase(Locale.ROOT) + "." + camelized + "Mod" : meta.main;
String baseName = meta.name.toLowerCase().replace(" ", "-"); String baseName = meta.name.toLowerCase(Locale.ROOT).replace(" ", "-");
var other = mods.find(m -> m.name.equals(baseName)); var other = mods.find(m -> m.name.equals(baseName));
@@ -771,7 +772,7 @@ public class Mods implements Loadable{
this.loader = loader; this.loader = loader;
this.main = main; this.main = main;
this.meta = meta; this.meta = meta;
this.name = meta.name.toLowerCase().replace(" ", "-"); this.name = meta.name.toLowerCase(Locale.ROOT).replace(" ", "-");
} }
/** @return whether this is a java class mod. */ /** @return whether this is a java class mod. */

View File

@@ -18,6 +18,7 @@ import rhino.module.provider.*;
import java.io.*; import java.io.*;
import java.net.*; import java.net.*;
import java.util.*;
import java.util.regex.*; import java.util.regex.*;
public class Scripts implements Disposable{ public class Scripts implements Disposable{
@@ -32,7 +33,7 @@ public class Scripts implements Disposable{
LoadedMod currentMod = null; LoadedMod currentMod = null;
public static boolean allowClass(String type){ public static boolean allowClass(String type){
return !blacklist.contains(type.toLowerCase()::contains) || whitelist.contains(type.toLowerCase()::contains); return !blacklist.contains(t -> type.toLowerCase(Locale.ROOT).contains(t)) || whitelist.contains(t -> type.toLowerCase(Locale.ROOT).contains(t));
} }
public Scripts(){ public Scripts(){

View File

@@ -479,9 +479,7 @@ public class Administration{
autosave("Whether the periodically save the map when playing.", false), autosave("Whether the periodically save the map when playing.", false),
autosaveAmount("The maximum amount of autosaves. Older ones get replaced.", 10), autosaveAmount("The maximum amount of autosaves. Older ones get replaced.", 10),
autosaveSpacing("Spacing between autosaves in seconds.", 60 * 5), autosaveSpacing("Spacing between autosaves in seconds.", 60 * 5),
debug("Enable debug logging", false, () -> { debug("Enable debug logging", false, () -> Log.level = debug() ? LogLevel.debug : LogLevel.info);
Log.level = debug() ? LogLevel.debug : LogLevel.info;
});
public static final Config[] all = values(); public static final Config[] all = values();
@@ -586,12 +584,15 @@ public class Administration{
public static class TraceInfo{ public static class TraceInfo{
public String ip, uuid; public String ip, uuid;
public boolean modded, mobile; public boolean modded, mobile;
public int timesJoined, timesKicked;
public TraceInfo(String ip, String uuid, boolean modded, boolean mobile){ public TraceInfo(String ip, String uuid, boolean modded, boolean mobile, int timesJoined, int timesKicked){
this.ip = ip; this.ip = ip;
this.uuid = uuid; this.uuid = uuid;
this.modded = modded; this.modded = modded;
this.mobile = mobile; this.mobile = mobile;
this.timesJoined = timesJoined;
this.timesKicked = timesKicked;
} }
} }

View File

@@ -337,7 +337,7 @@ public class Net{
*/ */
void discoverServers(Cons<Host> callback, Runnable done); void discoverServers(Cons<Host> callback, Runnable done);
/** Ping a host. If an error occured, failed() should be called with the exception. */ /** Ping a host. If an error occurred, failed() should be called with the exception. */
void pingHost(String address, int port, Cons<Host> valid, Cons<Exception> failed); void pingHost(String address, int port, Cons<Host> valid, Cons<Exception> failed);
/** Host a server at specified port. */ /** Host a server at specified port. */

View File

@@ -18,7 +18,10 @@ public abstract class NetConnection{
public boolean mobile, modclient; public boolean mobile, modclient;
public @Nullable Player player; public @Nullable Player player;
public boolean kicked = false; public boolean kicked = false;
public long syncTime;
/** When this connection was established. */
public long connectTime = Time.millis();
/** ID of last received client snapshot. */ /** ID of last received client snapshot. */
public int lastReceivedClientSnapshot = -1; public int lastReceivedClientSnapshot = -1;
/** Timestamp of last received snapshot. */ /** Timestamp of last received snapshot. */
@@ -47,7 +50,7 @@ public abstract class NetConnection{
Call.kick(this, reason); Call.kick(this, reason);
Time.runTask(2f, this::close); close();
netServer.admins.save(); netServer.admins.save();
kicked = true; kicked = true;
@@ -68,7 +71,7 @@ public abstract class NetConnection{
Call.kick(this, reason); Call.kick(this, reason);
Time.runTask(2f, this::close); close();
netServer.admins.save(); netServer.admins.save();
kicked = true; kicked = true;

View File

@@ -15,10 +15,14 @@ public class StatusEffect extends MappableContent{
public float damageMultiplier = 1f; public float damageMultiplier = 1f;
/** Unit health multiplier. */ /** Unit health multiplier. */
public float healthMultiplier = 1f; public float healthMultiplier = 1f;
/** Unit speed multiplier */ /** Unit speed multiplier. */
public float speedMultiplier = 1f; public float speedMultiplier = 1f;
/** Unit speed multiplier */ /** Unit reload multiplier. */
public float reloadMultiplier = 1f; public float reloadMultiplier = 1f;
/** Unit build speed multiplier. */
public float buildSpeedMultiplier = 1f;
/** Unit weapon(s) disabled. */
public boolean disarm = false;
/** Damage per frame. */ /** Damage per frame. */
public float damage; public float damage;
/** Chance of effect appearing. */ /** Chance of effect appearing. */

View File

@@ -193,7 +193,7 @@ public class UnitType extends UnlockableContent{
if(unit.controller() instanceof LogicAI){ if(unit.controller() instanceof LogicAI){
table.row(); table.row();
table.add(Blocks.microProcessor.emoji() + " " + Core.bundle.get("units.processorcontrol")).growX().left(); table.add(Blocks.microProcessor.emoji() + " " + Core.bundle.get("units.processorcontrol")).growX().wrap().left();
table.row(); table.row();
table.label(() -> Iconc.settings + " " + (long)unit.flag + "").color(Color.lightGray).growX().wrap().left(); table.label(() -> Iconc.settings + " " + (long)unit.flag + "").color(Color.lightGray).growX().wrap().left();
} }

View File

@@ -463,8 +463,10 @@ public class JoinDialog extends BaseDialog{
net.reset(); net.reset();
Vars.netClient.beginConnecting(); Vars.netClient.beginConnecting();
net.connect(lastIp = ip, lastPort = port, () -> { net.connect(lastIp = ip, lastPort = port, () -> {
if(net.client()){
hide(); hide();
add.hide(); add.hide();
}
}); });
}); });
} }
@@ -568,7 +570,7 @@ public class JoinDialog extends BaseDialog{
if(isIpv6 && ip.lastIndexOf("]:") != -1 && ip.lastIndexOf("]:") != ip.length() - 1){ if(isIpv6 && ip.lastIndexOf("]:") != -1 && ip.lastIndexOf("]:") != ip.length() - 1){
int idx = ip.indexOf("]:"); int idx = ip.indexOf("]:");
this.ip = ip.substring(1, idx); this.ip = ip.substring(1, idx);
this.port = Integer.parseInt(ip.substring(idx + 2, ip.length())); this.port = Integer.parseInt(ip.substring(idx + 2));
}else if(!isIpv6 && ip.lastIndexOf(':') != -1 && ip.lastIndexOf(':') != ip.length() - 1){ }else if(!isIpv6 && ip.lastIndexOf(':') != -1 && ip.lastIndexOf(':') != ip.length() - 1){
int idx = ip.lastIndexOf(':'); int idx = ip.lastIndexOf(':');
this.ip = ip.substring(0, idx); this.ip = ip.substring(0, idx);

View File

@@ -59,7 +59,7 @@ public class LoadoutDialog extends BaseDialog{
public void maxItems() { public void maxItems() {
for(ItemStack stack : stacks){ for(ItemStack stack : stacks){
stack.amount = total == null ? capacity : Math.min(capacity, total.get(stack.item)); stack.amount = total == null ? capacity : Math.max(Math.min(capacity, total.get(stack.item)), 0);
} }
} }

View File

@@ -278,6 +278,9 @@ public class ModsDialog extends BaseDialog{
}else if(mod.hasContentErrors()){ }else if(mod.hasContentErrors()){
text.labelWrap("@mod.erroredcontent").growX(); text.labelWrap("@mod.erroredcontent").growX();
text.row(); text.row();
}else if(mod.meta.hidden){
text.labelWrap("@mod.multiplayer.compatible").growX();
text.row();
} }
}).top().growX(); }).top().growX();
@@ -304,7 +307,7 @@ public class ModsDialog extends BaseDialog{
if(steam && !mod.hasSteamID()){ if(steam && !mod.hasSteamID()){
right.row(); right.row();
right.button(Icon.download, Styles.clearTransi, () -> { right.button(Icon.export, Styles.clearTransi, () -> {
platform.publish(mod); platform.publish(mod);
}).size(50f); }).size(50f);
} }

View File

@@ -327,6 +327,8 @@ public class SettingsMenuDialog extends SettingsDialog{
game.checkPref("buildautopause", false); game.checkPref("buildautopause", false);
} }
game.checkPref("doubletapmine", false);
if(!ios){ if(!ios){
game.checkPref("modcrashdisable", true); game.checkPref("modcrashdisable", true);
} }

View File

@@ -32,6 +32,10 @@ public class TraceDialog extends BaseDialog{
table.row(); table.row();
table.add(Core.bundle.format("trace.mobile", info.mobile)); table.add(Core.bundle.format("trace.mobile", info.mobile));
table.row(); table.row();
table.add(Core.bundle.format("trace.times.joined", info.timesJoined));
table.row();
table.add(Core.bundle.format("trace.times.kicked", info.timesKicked));
table.row();
table.add().pad(5); table.add().pad(5);
table.row(); table.row();

View File

@@ -643,6 +643,8 @@ public class HudFragment extends Fragment{
void drawInner(Color color, float fract){ void drawInner(Color color, float fract){
if(fract < 0) return; if(fract < 0) return;
fract = Mathf.clamp(fract);
if(flip){ if(flip){
x += width; x += width;
width = -width; width = -width;

View File

@@ -171,7 +171,7 @@ public class MenuFragment extends Fragment{
new Buttoni("@customgame", Icon.terrain, () -> checkPlay(ui.custom::show)), new Buttoni("@customgame", Icon.terrain, () -> checkPlay(ui.custom::show)),
new Buttoni("@loadgame", Icon.download, () -> checkPlay(ui.load::show)) new Buttoni("@loadgame", Icon.download, () -> checkPlay(ui.load::show))
), ),
new Buttoni("@editor", Icon.terrain, () -> checkPlay(ui.maps::show)), steam ? new Buttoni("@workshop", Icon.book, platform::openWorkshop) : null, new Buttoni("@editor", Icon.terrain, () -> checkPlay(ui.maps::show)), steam ? new Buttoni("@workshop", Icon.steam, platform::openWorkshop) : null,
new Buttoni("@mods", Icon.book, ui.mods::show), new Buttoni("@mods", Icon.book, ui.mods::show),
//not enough space for this button //not enough space for this button
//new Buttoni("@schematics", Icon.paste, ui.schematics::show), //new Buttoni("@schematics", Icon.paste, ui.schematics::show),

View File

@@ -26,6 +26,7 @@ import mindustry.graphics.MultiPacker.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.ui.*; import mindustry.ui.*;
import mindustry.world.blocks.environment.*; import mindustry.world.blocks.environment.*;
import mindustry.world.blocks.power.*;
import mindustry.world.consumers.*; import mindustry.world.consumers.*;
import mindustry.world.meta.*; import mindustry.world.meta.*;
import mindustry.world.meta.values.*; import mindustry.world.meta.values.*;
@@ -122,6 +123,8 @@ public class Block extends UnlockableContent{
public boolean fillsTile = true; public boolean fillsTile = true;
/** whether this block can be replaced in all cases */ /** whether this block can be replaced in all cases */
public boolean alwaysReplace = false; public boolean alwaysReplace = false;
/** if false, this block can never be replaced. */
public boolean replaceable = true;
/** The block group. Unless {@link #canReplace} is overriden, blocks in the same group can replace each other. */ /** The block group. Unless {@link #canReplace} is overriden, blocks in the same group can replace each other. */
public BlockGroup group = BlockGroup.none; public BlockGroup group = BlockGroup.none;
/** List of block flags. Used for AI indexing. */ /** List of block flags. Used for AI indexing. */
@@ -255,6 +258,26 @@ public class Block extends UnlockableContent{
/** Drawn when you are placing a block. */ /** Drawn when you are placing a block. */
public void drawPlace(int x, int y, int rotation, boolean valid){ public void drawPlace(int x, int y, int rotation, boolean valid){
drawPotentialLinks(x, y);
}
public void drawPotentialLinks(int x, int y){
if((consumesPower || outputsPower) && hasPower){
Tile tile = world.tile(x, y);
if(tile != null){
PowerNode.getNodeLinks(tile, this, player.team(), other -> {
PowerNode node = (PowerNode)other.block;
Draw.color(node.laserColor1, Renderer.laserOpacity * 0.5f);
node.drawLaser(tile.team(), x * tilesize + offset, y * tilesize + offset, other.x, other.y, size, other.block.size);
Drawf.square(other.x, other.y, other.block.size * tilesize / 2f + 2f, Pal.place);
PowerNode.insulators(other.tileX(), other.tileY(), tile.x, tile.y, cause -> {
Drawf.square(cause.x, cause.y, cause.block.size * tilesize / 2f + 2f, Pal.plastanium);
});
});
}
}
} }
public float drawPlaceText(String text, int x, int y, boolean valid){ public float drawPlaceText(String text, int x, int y, boolean valid){
@@ -389,7 +412,7 @@ public class Block extends UnlockableContent{
public boolean canReplace(Block other){ public boolean canReplace(Block other){
if(other.alwaysReplace) return true; if(other.alwaysReplace) return true;
return (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group && return other.replaceable && (other != this || rotate) && this.group != BlockGroup.none && other.group == this.group &&
(size == other.size || (size >= other.size && ((subclass != null && subclass == other.subclass) || group.anyReplace))); (size == other.size || (size >= other.size && ((subclass != null && subclass == other.subclass) || group.anyReplace)));
} }
@@ -403,6 +426,11 @@ public class Block extends UnlockableContent{
} }
/** Mutates the given list of requests used during line placement. */
public void handlePlacementLine(Seq<BuildPlan> plans){
}
public Object nextConfig(){ public Object nextConfig(){
if(saveConfig && lastConfig != null){ if(saveConfig && lastConfig != null){
return lastConfig; return lastConfig;
@@ -599,6 +627,14 @@ public class Block extends UnlockableContent{
return cacheLayer == CacheLayer.walls; return cacheLayer == CacheLayer.walls;
} }
public void setupRequirements(Category cat, ItemStack[] stacks){
requirements(cat, stacks);
}
public void setupRequirements(Category cat, BuildVisibility visible, ItemStack[] stacks){
requirements(cat, visible, stacks);
}
public void requirements(Category cat, ItemStack[] stacks, boolean unlocked){ public void requirements(Category cat, ItemStack[] stacks, boolean unlocked){
requirements(cat, BuildVisibility.shown, stacks); requirements(cat, BuildVisibility.shown, stacks);
this.alwaysUnlocked = unlocked; this.alwaysUnlocked = unlocked;

View File

@@ -491,6 +491,11 @@ public class Tile implements Position, QuadTreeObject, Displayable{
return block.solid && block.fillsTile && !block.synthetic() ? data : 0; return block.solid && block.fillsTile && !block.synthetic() ? data : 0;
} }
/** @return true if these tiles are right next to each other. */
public boolean adjacentTo(Tile tile){
return relativeTo(tile) != -1;
}
protected void preChanged(){ protected void preChanged(){
if(build != null){ if(build != null){
//only call removed() for the center block - this only gets called once. //only call removed() for the center block - this only gets called once.

View File

@@ -172,7 +172,7 @@ public class ConstructBlock extends Block{
@Override @Override
public Cursor getCursor(){ public Cursor getCursor(){
return SystemCursor.hand; return interactable(player.team()) ? SystemCursor.hand : SystemCursor.arrow;
} }
@Override @Override

View File

@@ -126,7 +126,7 @@ public class Door extends Wall{
@Override @Override
public Cursor getCursor(){ public Cursor getCursor(){
return SystemCursor.hand; return interactable(player.team()) ? SystemCursor.hand : SystemCursor.arrow;
} }
@Override @Override

View File

@@ -54,7 +54,11 @@ public class MendProjector extends Block{
@Override @Override
public void drawPlace(int x, int y, int rotation, boolean valid){ public void drawPlace(int x, int y, int rotation, boolean valid){
Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.accent); super.drawPlace(x, y, rotation, valid);
Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, baseColor);
indexer.eachBlock(player.team(), x * tilesize + offset, y * tilesize + offset, range, other -> true, other -> Drawf.selected(other, Tmp.c1.set(baseColor).a(Mathf.absin(4f, 1f))));
} }
public class MendBuild extends Building implements Ranged{ public class MendBuild extends Building implements Ranged{

View File

@@ -4,6 +4,7 @@ import arc.*;
import arc.graphics.*; import arc.graphics.*;
import arc.graphics.g2d.*; import arc.graphics.g2d.*;
import arc.math.*; import arc.math.*;
import arc.math.geom.*;
import arc.util.*; import arc.util.*;
import arc.util.io.*; import arc.util.io.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
@@ -47,7 +48,11 @@ public class OverdriveProjector extends Block{
@Override @Override
public void drawPlace(int x, int y, int rotation, boolean valid){ public void drawPlace(int x, int y, int rotation, boolean valid){
Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.accent); super.drawPlace(x, y, rotation, valid);
Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, baseColor);
indexer.eachBlock(player.team(), x * tilesize + offset, y * tilesize + offset, range, other -> other.block.canOverdrive, other -> Drawf.selected(other, Tmp.c1.set(baseColor).a(Mathf.absin(4f, 1f))));
} }
@Override @Override
@@ -132,7 +137,14 @@ public class OverdriveProjector extends Block{
Draw.rect(topRegion, x, y); Draw.rect(topRegion, x, y);
Draw.alpha(1f); Draw.alpha(1f);
Lines.stroke((2f * f + 0.1f) * heat); Lines.stroke((2f * f + 0.1f) * heat);
Lines.square(x, y, Math.min(1f + (1f - f) * size * tilesize / 2f, size * tilesize/2f));
float r = Math.max(0f, Mathf.clamp(2f - f * 2f) * size * tilesize / 2f - f - 0.2f), w = Mathf.clamp(0.5f - f) * size * tilesize;
Lines.beginLine();
for(int i = 0; i < 4; i++){
Lines.linePoint(x + Geometry.d4(i).x * r + Geometry.d4(i).y * w, y + Geometry.d4(i).y * r - Geometry.d4(i).x * w);
if(f < 0.5f) Lines.linePoint(x + Geometry.d4(i).x * r - Geometry.d4(i).y * w, y + Geometry.d4(i).y * r + Geometry.d4(i).x * w);
}
Lines.endLine(true);
Draw.reset(); Draw.reset();
} }

View File

@@ -1,5 +1,6 @@
package mindustry.world.blocks.defense.turrets; package mindustry.world.blocks.defense.turrets;
import arc.struct.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.entities.*; import mindustry.entities.*;
import mindustry.gen.*; import mindustry.gen.*;
@@ -27,6 +28,9 @@ public class BaseTurret extends Block{
update = true; update = true;
solid = true; solid = true;
outlineIcon = true; outlineIcon = true;
priority = TargetPriority.turret;
group = BlockGroup.turrets;
flags = EnumSet.of(BlockFlag.turret);
} }
@Override @Override
@@ -41,6 +45,8 @@ public class BaseTurret extends Block{
@Override @Override
public void drawPlace(int x, int y, int rotation, boolean valid){ public void drawPlace(int x, int y, int rotation, boolean valid){
super.drawPlace(x, y, rotation, valid);
Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.placing); Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, range, Pal.placing);
} }

View File

@@ -93,12 +93,6 @@ public class Turret extends ReloadTurret{
public Turret(String name){ public Turret(String name){
super(name); super(name);
priority = TargetPriority.turret;
update = true;
solid = true;
group = BlockGroup.turrets;
flags = EnumSet.of(BlockFlag.turret);
outlineIcon = true;
liquidCapacity = 20f; liquidCapacity = 20f;
} }

View File

@@ -12,6 +12,7 @@ import mindustry.content.*;
import mindustry.entities.units.*; import mindustry.entities.units.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.input.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.ui.*; import mindustry.ui.*;
import mindustry.world.*; import mindustry.world.*;
@@ -71,6 +72,17 @@ public class Conveyor extends Block implements Autotiler{
&& lookingAtEither(tile, rotation, otherx, othery, otherrot, otherblock); && lookingAtEither(tile, rotation, otherx, othery, otherrot, otherblock);
} }
//stack conveyors should be bridged over, not replaced
@Override
public boolean canReplace(Block other){
return super.canReplace(other) && !(other instanceof StackConveyor);
}
@Override
public void handlePlacementLine(Seq<BuildPlan> plans){
Placement.calculateBridges(plans, (ItemBridge)Blocks.itemBridge);
}
@Override @Override
public TextureRegion[] icons(){ public TextureRegion[] icons(){
return new TextureRegion[]{regions[0][0]}; return new TextureRegion[]{regions[0][0]};

View File

@@ -1,6 +1,5 @@
package mindustry.world.blocks.distribution; package mindustry.world.blocks.distribution;
import arc.*;
import arc.graphics.*; import arc.graphics.*;
import arc.graphics.g2d.*; import arc.graphics.g2d.*;
import arc.math.*; import arc.math.*;
@@ -32,10 +31,7 @@ public class ItemBridge extends Block{
public @Load("@-arrow") TextureRegion arrowRegion; public @Load("@-arrow") TextureRegion arrowRegion;
//for autolink //for autolink
@Nullable public @Nullable ItemBridgeBuild lastBuild;
public ItemBridgeBuild lastBuild;
@Nullable
public BuildPlan lastPlan;
public ItemBridge(String name){ public ItemBridge(String name){
super(name); super(name);
@@ -94,6 +90,8 @@ public class ItemBridge extends Block{
@Override @Override
public void drawPlace(int x, int y, int rotation, boolean valid){ public void drawPlace(int x, int y, int rotation, boolean valid){
super.drawPlace(x, y, rotation, valid);
Tile link = findLink(x, y); Tile link = findLink(x, y);
Lines.stroke(2f, Pal.placing); Lines.stroke(2f, Pal.placing);
@@ -151,12 +149,14 @@ public class ItemBridge extends Block{
} }
@Override @Override
public void onNewPlan(BuildPlan plan){ public void handlePlacementLine(Seq<BuildPlan> plans){
if(lastPlan != null && lastPlan.config == null && positionsValid(lastPlan.x, lastPlan.y, plan.x, plan.y)){ for(int i = 0; i < plans.size - 1; i++){
lastPlan.config = new Point2(plan.x - lastPlan.x, plan.y - lastPlan.y); var cur = plans.get(i);
var next = plans.get(i + 1);
if(positionsValid(cur.x, cur.y, next.x, next.y)){
cur.config = new Point2(next.x - cur.x, next.y - cur.y);
}
} }
lastPlan = plan;
} }
@Override @Override
@@ -176,12 +176,12 @@ public class ItemBridge extends Block{
public void playerPlaced(Object config){ public void playerPlaced(Object config){
super.playerPlaced(config); super.playerPlaced(config);
if(config != null) return; if(config == null){
Tile link = findLink(tile.x, tile.y); Tile link = findLink(tile.x, tile.y);
if(linkValid(tile, link) && !proximity.contains(link.build)){ if(linkValid(tile, link) && !proximity.contains(link.build)){
link.build.configure(tile.pos()); link.build.configure(tile.pos());
} }
}
lastBuild = this; lastBuild = this;
} }

View File

@@ -57,6 +57,8 @@ public class MassDriver extends Block{
@Override @Override
public void drawPlace(int x, int y, int rotation, boolean valid){ public void drawPlace(int x, int y, int rotation, boolean valid){
super.drawPlace(x, y, rotation, valid);
Drawf.dashCircle(x * tilesize, y * tilesize, range, Pal.accent); Drawf.dashCircle(x * tilesize, y * tilesize, range, Pal.accent);
//check if a mass driver is selected while placing this driver //check if a mass driver is selected while placing this driver

View File

@@ -105,7 +105,7 @@ public class BlockForge extends PayloadAcceptor{
consume(); consume();
payload = new BuildPayload(recipe, team); payload = new BuildPayload(recipe, team);
payVector.setZero(); payVector.setZero();
progress = 0f; progress %= 1f;
} }
} }

View File

@@ -13,6 +13,7 @@ import mindustry.content.*;
import mindustry.entities.units.*; import mindustry.entities.units.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.input.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.*; import mindustry.world.blocks.*;
@@ -69,6 +70,11 @@ public class Conduit extends LiquidBlock implements Autotiler{
return otherblock.hasLiquids && (otherblock.outputsLiquid || (lookingAt(tile, rotation, otherx, othery, otherblock))) && lookingAtEither(tile, rotation, otherx, othery, otherrot, otherblock); return otherblock.hasLiquids && (otherblock.outputsLiquid || (lookingAt(tile, rotation, otherx, othery, otherblock))) && lookingAtEither(tile, rotation, otherx, othery, otherrot, otherblock);
} }
@Override
public void handlePlacementLine(Seq<BuildPlan> plans){
Placement.calculateBridges(plans, (ItemBridge)Blocks.bridgeConduit);
}
@Override @Override
public TextureRegion[] icons(){ public TextureRegion[] icons(){
return new TextureRegion[]{Core.atlas.find("conduit-bottom"), topRegions[0]}; return new TextureRegion[]{Core.atlas.find("conduit-bottom"), topRegions[0]};

View File

@@ -39,6 +39,7 @@ public class LogicBlock extends Block{
solid = true; solid = true;
configurable = true; configurable = true;
group = BlockGroup.logic; group = BlockGroup.logic;
schematicPriority = 5;
config(byte[].class, (LogicBuild build, byte[] data) -> build.readCompressed(data, true)); config(byte[].class, (LogicBuild build, byte[] data) -> build.readCompressed(data, true));

View File

@@ -54,6 +54,7 @@ public class NuclearReactor extends PowerGenerator{
hasLiquids = true; hasLiquids = true;
rebuildable = false; rebuildable = false;
flags = EnumSet.of(BlockFlag.reactor, BlockFlag.generator); flags = EnumSet.of(BlockFlag.reactor, BlockFlag.generator);
schematicPriority = -5;
} }
@Override @Override

View File

@@ -27,7 +27,7 @@ public class PowerNode extends PowerBlock{
protected static BuildPlan otherReq; protected static BuildPlan otherReq;
protected final static ObjectSet<PowerGraph> graphs = new ObjectSet<>(); protected final static ObjectSet<PowerGraph> graphs = new ObjectSet<>();
protected final static Seq<Point2> tmpPoints = new Seq<>(), tmpPoints2 = new Seq<>(); protected static int returnInt = 0;
public @Load("laser") TextureRegion laser; public @Load("laser") TextureRegion laser;
public @Load("laser-end") TextureRegion laserEnd; public @Load("laser-end") TextureRegion laserEnd;
@@ -144,6 +144,9 @@ public class PowerNode extends PowerBlock{
Drawf.circles(x * tilesize + offset, y * tilesize + offset, laserRange * tilesize); Drawf.circles(x * tilesize + offset, y * tilesize + offset, laserRange * tilesize);
getPotentialLinks(tile, other -> { getPotentialLinks(tile, other -> {
Draw.color(laserColor1, Renderer.laserOpacity * 0.5f);
drawLaser(tile.team(), x * tilesize + offset, y * tilesize + offset, other.x, other.y, size, other.block.size);
Drawf.square(other.x, other.y, other.block.size * tilesize / 2f + 2f, Pal.place); Drawf.square(other.x, other.y, other.block.size * tilesize / 2f + 2f, Pal.place);
insulators(tile.x, tile.y, other.tileX(), other.tileY(), cause -> { insulators(tile.x, tile.y, other.tileX(), other.tileY(), cause -> {
@@ -164,7 +167,7 @@ public class PowerNode extends PowerBlock{
Draw.alpha(Renderer.laserOpacity); Draw.alpha(Renderer.laserOpacity);
} }
protected void drawLaser(Team team, float x1, float y1, float x2, float y2, int size1, int size2){ public void drawLaser(Team team, float x1, float y1, float x2, float y2, int size1, int size2){
float angle1 = Angles.angle(x1, y1, x2, y2), float angle1 = Angles.angle(x1, y1, x2, y2),
vx = Mathf.cosDeg(angle1), vy = Mathf.sinDeg(angle1), vx = Mathf.cosDeg(angle1), vy = Mathf.sinDeg(angle1),
len1 = size1 * tilesize / 2f - 1.5f, len2 = size2 * tilesize / 2f - 1.5f; len1 = size1 * tilesize / 2f - 1.5f, len2 = size2 * tilesize / 2f - 1.5f;
@@ -172,6 +175,11 @@ public class PowerNode extends PowerBlock{
Drawf.laser(team, laser, laserEnd, x1 + vx*len1, y1 + vy*len1, x2 - vx*len2, y2 - vy*len2, 0.25f); Drawf.laser(team, laser, laserEnd, x1 + vx*len1, y1 + vy*len1, x2 - vx*len2, y2 - vy*len2, 0.25f);
} }
protected boolean overlaps(float srcx, float srcy, Tile other, Block otherBlock, float range){
return Intersector.overlaps(Tmp.cr1.set(srcx, srcy, range), Tmp.r1.setCentered(other.worldx() + otherBlock.offset, other.worldy() + otherBlock.offset,
otherBlock.size * tilesize, otherBlock.size * tilesize));
}
protected boolean overlaps(float srcx, float srcy, Tile other, float range){ protected boolean overlaps(float srcx, float srcy, Tile other, float range){
return Intersector.overlaps(Tmp.cr1.set(srcx, srcy, range), other.getHitbox(Tmp.r1)); return Intersector.overlaps(Tmp.cr1.set(srcx, srcy, range), other.getHitbox(Tmp.r1));
} }
@@ -193,10 +201,23 @@ public class PowerNode extends PowerBlock{
Boolf<Building> valid = other -> other != null && other.tile() != tile && other.power != null && Boolf<Building> valid = other -> other != null && other.tile() != tile && other.power != null &&
(other.block.outputsPower || other.block.consumesPower || other.block instanceof PowerNode) && (other.block.outputsPower || other.block.consumesPower || other.block instanceof PowerNode) &&
overlaps(tile.x * tilesize + offset, tile.y * tilesize + offset, other.tile(), laserRange * tilesize) && other.team == player.team() overlaps(tile.x * tilesize + offset, tile.y * tilesize + offset, other.tile(), laserRange * tilesize) && other.team == player.team()
&& !other.proximity.contains(e -> e.tile == tile) && !graphs.contains(other.power.graph); && !graphs.contains(other.power.graph) &&
!Structs.contains(Edges.getEdges(size), p -> { //do not link to adjacent buildings
var t = world.tile(tile.x + p.x, tile.y + p.y);
return t != null && t.build == other;
});
tempTileEnts.clear(); tempTileEnts.clear();
graphs.clear(); graphs.clear();
//add conducting graphs to prevent double link
for(var p : Edges.getEdges(size)){
Tile other = tile.nearby(p);
if(other != null && other.team() == player.team() && other.build != null && other.build.power != null){
graphs.add(other.build.power.graph);
}
}
if(tile.build != null && tile.build.power != null){ if(tile.build != null && tile.build.power != null){
graphs.add(tile.build.power.graph); graphs.add(tile.build.power.graph);
} }
@@ -214,6 +235,57 @@ public class PowerNode extends PowerBlock{
return Float.compare(a.dst2(tile), b.dst2(tile)); return Float.compare(a.dst2(tile), b.dst2(tile));
}); });
returnInt = 0;
tempTileEnts.each(valid, t -> {
if(returnInt ++ < maxNodes){
graphs.add(t.power.graph);
others.get(t);
}
});
}
//TODO code duplication w/ method above?
/** Iterates through linked nodes of a block at a tile. All returned buildings are power nodes. */
public static void getNodeLinks(Tile tile, Block block, Team team, Cons<Building> others){
Boolf<Building> valid = other -> other != null && other.tile() != tile && other.block instanceof PowerNode node &&
other.power.links.size < node.maxNodes &&
node.overlaps(other.x, other.y, tile, block, node.laserRange * tilesize) && other.team == team
&& !graphs.contains(other.power.graph) &&
!Structs.contains(Edges.getEdges(block.size), p -> { //do not link to adjacent buildings
var t = world.tile(tile.x + p.x, tile.y + p.y);
return t != null && t.build == other;
});
tempTileEnts.clear();
graphs.clear();
//add conducting graphs to prevent double link
for(var p : Edges.getEdges(block.size)){
Tile other = tile.nearby(p);
if(other != null && other.team() == team && other.build != null && other.build.power != null
&& !(block.consumesPower && other.block().consumesPower && !block.outputsPower && !other.block().outputsPower)){
graphs.add(other.build.power.graph);
}
}
if(tile.build != null && tile.build.power != null){
graphs.add(tile.build.power.graph);
}
Geometry.circle(tile.x, tile.y, 13, (x, y) -> {
Building other = world.build(x, y);
if(valid.get(other) && !tempTileEnts.contains(other)){
tempTileEnts.add(other);
}
});
tempTileEnts.sort((a, b) -> {
int type = -Boolean.compare(a.block instanceof PowerNode, b.block instanceof PowerNode);
if(type != 0) return type;
return Float.compare(a.dst2(tile), b.dst2(tile));
});
tempTileEnts.each(valid, t -> { tempTileEnts.each(valid, t -> {
graphs.add(t.power.graph); graphs.add(t.power.graph);
others.get(t); others.get(t);
@@ -235,7 +307,7 @@ public class PowerNode extends PowerBlock{
} }
}); });
if(otherReq == null || otherReq.block == null) return; if(otherReq == null || otherReq.block == null) continue;
drawLaser(player == null ? Team.sharded : player.team(), req.drawx(), req.drawy(), otherReq.drawx(), otherReq.drawy(), size, otherReq.block.size); drawLaser(player == null ? Team.sharded : player.team(), req.drawx(), req.drawy(), otherReq.drawx(), otherReq.drawy(), size, otherReq.block.size);
} }

View File

@@ -27,6 +27,8 @@ public class ThermalGenerator extends PowerGenerator{
@Override @Override
public void drawPlace(int x, int y, int rotation, boolean valid){ public void drawPlace(int x, int y, int rotation, boolean valid){
super.drawPlace(x, y, rotation, valid);
drawPlaceText(Core.bundle.formatFloat("bar.efficiency", sumAttribute(attribute, x, y) * 100, 1), x, y, valid); drawPlaceText(Core.bundle.formatFloat("bar.efficiency", sumAttribute(attribute, x, y) * 100, 1), x, y, valid);
} }

View File

@@ -47,6 +47,8 @@ public class Cultivator extends GenericCrafter{
@Override @Override
public void drawPlace(int x, int y, int rotation, boolean valid){ public void drawPlace(int x, int y, int rotation, boolean valid){
super.drawPlace(x, y, rotation, valid);
drawPlaceText(Core.bundle.formatFloat("bar.efficiency", (1 + sumAttribute(attribute, x, y)) * 100, 1), x, y, valid); drawPlaceText(Core.bundle.formatFloat("bar.efficiency", (1 + sumAttribute(attribute, x, y)) * 100, 1), x, y, valid);
} }

View File

@@ -113,6 +113,8 @@ public class Drill extends Block{
@Override @Override
public void drawPlace(int x, int y, int rotation, boolean valid){ public void drawPlace(int x, int y, int rotation, boolean valid){
super.drawPlace(x, y, rotation, valid);
Tile tile = world.tile(x, y); Tile tile = world.tile(x, y);
if(tile == null) return; if(tile == null) return;

View File

@@ -119,7 +119,7 @@ public class GenericCrafter extends Block{
} }
craftEffect.at(x, y); craftEffect.at(x, y);
progress = 0f; progress %= 1f;
} }
if(outputItem != null && timer(timerDump, dumpTime)){ if(outputItem != null && timer(timerDump, dumpTime)){

View File

@@ -31,6 +31,8 @@ public class Pump extends LiquidBlock{
@Override @Override
public void drawPlace(int x, int y, int rotation, boolean valid){ public void drawPlace(int x, int y, int rotation, boolean valid){
super.drawPlace(x, y, rotation, valid);
Tile tile = world.tile(x, y); Tile tile = world.tile(x, y);
if(tile == null) return; if(tile == null) return;

View File

@@ -35,6 +35,8 @@ public class SolidPump extends Pump{
@Override @Override
public void drawPlace(int x, int y, int rotation, boolean valid){ public void drawPlace(int x, int y, int rotation, boolean valid){
drawPotentialLinks(x, y);
if(attribute != null){ if(attribute != null){
drawPlaceText(Core.bundle.formatFloat("bar.efficiency", Math.max(sumAttribute(attribute, x, y) / size / size + baseEfficiency, 0f) * 100 * percentSolid(x, y), 1), x, y, valid); drawPlaceText(Core.bundle.formatFloat("bar.efficiency", Math.max(sumAttribute(attribute, x, y) / size / size + baseEfficiency, 0f) * 100 * percentSolid(x, y), 1), x, y, valid);
} }

View File

@@ -50,8 +50,9 @@ public class CoreBlock extends StorageBlock{
unitCapModifier = 10; unitCapModifier = 10;
loopSound = Sounds.respawning; loopSound = Sounds.respawning;
loopSoundVolume = 1f; loopSoundVolume = 1f;
group = BlockGroup.none;
drawDisabled = false; drawDisabled = false;
canOverdrive = false;
replaceable = false;
} }
@Remote(called = Loc.server) @Remote(called = Loc.server)

View File

@@ -20,7 +20,8 @@ public class StorageBlock extends Block{
solid = true; solid = true;
update = false; update = false;
destructible = true; destructible = true;
group = BlockGroup.storage; group = BlockGroup.transportation;
flags = EnumSet.of(BlockFlag.storage);
} }
@Override @Override

View File

@@ -175,7 +175,7 @@ public class Reconstructor extends UnitBlock{
//upgrade the unit //upgrade the unit
if(progress >= constructTime){ 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; progress %= 1f;
Effect.shake(2f, 3f, this); Effect.shake(2f, 3f, this);
Fx.producesmoke.at(this); Fx.producesmoke.at(this);
consume(); consume();

View File

@@ -11,6 +11,7 @@ import mindustry.annotations.Annotations.*;
import mindustry.entities.*; import mindustry.entities.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.logic.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.meta.*; import mindustry.world.meta.*;
@@ -38,6 +39,7 @@ public class RepairPoint extends Block{
flags = EnumSet.of(BlockFlag.repair); flags = EnumSet.of(BlockFlag.repair);
hasPower = true; hasPower = true;
outlineIcon = true; outlineIcon = true;
expanded = true;
} }
@Override @Override
@@ -54,6 +56,8 @@ public class RepairPoint extends Block{
@Override @Override
public void drawPlace(int x, int y, int rotation, boolean valid){ public void drawPlace(int x, int y, int rotation, boolean valid){
super.drawPlace(x, y, rotation, valid);
Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, repairRadius, Pal.accent); Drawf.dashCircle(x * tilesize + offset, y * tilesize + offset, repairRadius, Pal.accent);
} }
@@ -62,7 +66,7 @@ public class RepairPoint extends Block{
return new TextureRegion[]{baseRegion, region}; return new TextureRegion[]{baseRegion, region};
} }
public class RepairPointBuild extends Building{ public class RepairPointBuild extends Building implements Ranged{
public Unit target; public Unit target;
public float strength, rotation = 90; public float strength, rotation = 90;
@@ -125,6 +129,11 @@ public class RepairPoint extends Block{
return Mathf.equal(efficiency(), 0f, 0.01f) ? BlockStatus.noInput : cons.status(); return Mathf.equal(efficiency(), 0f, 0.01f) ? BlockStatus.noInput : cons.status();
} }
@Override
public float range(){
return repairRadius;
}
@Override @Override
public void write(Writes write){ public void write(Writes write){
super.write(write); super.write(write);

View File

@@ -225,7 +225,7 @@ public class UnitFactory extends UnitBlock{
UnitPlan plan = plans.get(currentPlan); UnitPlan plan = plans.get(currentPlan);
if(progress >= plan.time && consValid()){ if(progress >= plan.time && consValid()){
progress = 0f; progress %= 1f;
payload = new UnitPayload(plan.unit.create(team)); payload = new UnitPayload(plan.unit.create(team));
payVector.setZero(); payVector.setZero();

View File

@@ -1,7 +1,7 @@
package mindustry.world.meta; package mindustry.world.meta;
public enum BlockGroup{ public enum BlockGroup{
none, walls(true), projectors(true), turrets, transportation(true), power, liquids(true), drills, storage, units, logic(true); none, walls(true), projectors(true), turrets(true), transportation(true), power, liquids(true), drills, units, logic(true);
/** if true, any block in this category replaces any other block in this category. */ /** if true, any block in this category replaces any other block in this category. */
public final boolean anyReplace; public final boolean anyReplace;

View File

@@ -64,8 +64,7 @@ public class DesktopLauncher extends ClientLauncher{
if(useSteam){ if(useSteam){
//delete leftover dlls //delete leftover dlls
Fi file = new Fi("."); for(Fi other : new Fi(".").parent().list()){
for(Fi other : file.parent().list()){
if(other.name().contains("steam") && (other.extension().equals("dll") || other.extension().equals("so") || other.extension().equals("dylib"))){ if(other.name().contains("steam") && (other.extension().equals("dll") || other.extension().equals("so") || other.extension().equals("dylib"))){
other.delete(); other.delete();
} }

View File

@@ -0,0 +1,7 @@
[This is a truncated changelog, see Github for full notes]
This is a minor update that reduces building splash damage for certain projectiles and fixes various mods issues.
While build 125 servers should be compatible with 125.1 clients, updating is still recommended.
- Fixed player health bar glitching out at negative health
- Fixed large power nodes sometimes not connecting to placed blocks
- Made unit payloads draw with correct cell colors

View File

@@ -0,0 +1,9 @@
[This is a truncated changelog, see Github for full notes]
- Various minor bugfixes
- Made water extractor use metaglass for building, to be consistent with pumps
- Added automatic conveyor/conduit bridging over obstacles
- Added 'defender' AI for Oct; follows nearby units
- Cores can now replace most transport blocks; turrets can now replace each other
- Improved bridge & power node linking previews
- Buffed Segment & Vela
- Logic: More hints

View File

@@ -0,0 +1,7 @@
[대부분의 변경점이 생략되었습니다. 모든 변경점을 볼려면 Github를 보세요.]
이 업데이트는 특정 발사체에 대한 건물 광역 피해를 줄이고 다양한 모드 문제를 해결한 사소한 업데이트입니다.
빌드 125버전 서버는 125.1버전 클라이언트와 호환되어야 하지만 여전히 업데이트를 권장합니다.
- 플레이어 체력바가 음수에서 깨지는 현상 고침
- 대형 전력 노드가 가끔 설치된 블록에 연결하지 않는 현상 고침
- 올바른 셀 색상으로 유닛 화물을 그리게 함

View File

@@ -1,3 +1,3 @@
org.gradle.daemon=true org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m org.gradle.jvmargs=-Xms256m -Xmx1024m
archash=a9c305d4f920e46a7b92c3fedc8f76d9c2fb38de archash=1b24d685ea94dd40244be869e70671080e950825

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@@ -42,6 +42,9 @@ task dist(type: Jar, dependsOn: configurations.runtimeClasspath){
exclude("zones/**") exclude("zones/**")
exclude("icons/**") exclude("icons/**")
exclude("bundles/**") exclude("bundles/**")
exclude("cubemaps/**")
exclude("cursors/**")
exclude("shaders/**")
manifest{ manifest{
attributes 'Main-Class': project.mainClassName attributes 'Main-Class': project.mainClassName

Some files were not shown because too many files have changed in this diff Show More