Compare commits

..

90 Commits
v116 ... v118

Author SHA1 Message Date
Anuken
2a6b0fd0ce Fixed vaults not counting withdrawn items 2020-11-27 18:09:47 -05:00
Anuken
47e622dee3 (more) Campaign balancing 2020-11-27 18:07:10 -05:00
Anuken
99125e9218 Merge remote-tracking branch 'origin/master' 2020-11-27 17:37:28 -05:00
Anuken
66918f0322 Campaign balancing 2020-11-27 17:37:22 -05:00
Anuken
b8a2c609cb Merge pull request #3629 from Catchears/typo
typo
2020-11-27 16:19:16 -05:00
Wiki Updater
968277477a typo 2020-11-27 22:18:08 +01:00
Anuken
d06b32c20b Added boss to sector damage calculations 2020-11-27 14:18:09 -05:00
Anuken
525dc0cd7e Added bosses for sectors missing them 2020-11-27 12:35:20 -05:00
Anuken
8b6fc7f3ac Fixed #3628 2020-11-27 12:27:56 -05:00
Anuken
8dd66fb942 Campaign tweaks 2020-11-27 11:56:01 -05:00
Anuken
e39eceee28 Allow research even if sector was attacked after capture 2020-11-26 21:48:45 -05:00
Anuken
869c329fbf Fixed Nuclear Complex gen / Increased damage simulation harshness 2020-11-26 21:29:22 -05:00
Anuken
c8b425116e Fixed Impact0078 ore gen / Misc campaign fixes 2020-11-26 20:46:17 -05:00
Anuken
0a290d2e10 Auto-rebuilding of broken attack sector blocks on restart 2020-11-26 20:19:13 -05:00
Anuken
9863cbc991 Disabled unit explosion team damage 2020-11-26 19:30:49 -05:00
Anuken
91c50ae126 Disabled explosion fires for item flammability <= 1
coming soon: spore bombing?
2020-11-26 19:25:26 -05:00
Anuken
dae46ceb6d Campaign bugfixes / Balancing 2020-11-26 18:53:20 -05:00
Anuken
6b3919e8f7 Added Call#setItem 2020-11-26 16:49:01 -05:00
Anuken
20637fa358 Merge remote-tracking branch 'origin/master' 2020-11-26 15:32:01 -05:00
Anuken
1d8ec9abd9 Campaign bugfixes 2020-11-26 15:31:58 -05:00
Anuken
d3f58c0e83 Campaign bugfixes 2020-11-26 15:31:19 -05:00
Anuken
84474040c0 Fungal Pass map fixes 2020-11-26 14:24:35 -05:00
Anuken
3fe4ae38b6 Misc cleanup 2020-11-26 12:53:19 -05:00
Anuken
465219540c Added prompt for loading legacy research data 2020-11-26 10:22:01 -05:00
Anuken
e1ddf115e0 Merged turret types 2020-11-25 20:41:38 -05:00
Anuken
56f1d0548e Merge remote-tracking branch 'origin/master' 2020-11-25 20:23:24 -05:00
Anuken
38471d68d7 Fixed Salt Flats being deadlocked 2020-11-25 20:23:17 -05:00
Anuken
17a571f22a Merge pull request #3604 from sk7725/patch-30
[KO]Quick Fix
2020-11-25 20:06:10 -05:00
Sunny Kim
dd9c3fc8d6 Update bundle_ko.properties 2020-11-26 10:01:15 +09:00
Sunny Kim
a70e29127b [KO]quick patch 2020-11-26 09:59:07 +09:00
Anuken
6be2b6021b Merge pull request #3603 from skykatik/patch-12
Some typos
2020-11-25 18:28:30 -05:00
Skat
488147759a Some typos 2020-11-26 02:04:08 +03:00
Anuken
9a7d359626 Merge pull request #3579 from Quezler/patch-68
Remove stray newline
2020-11-25 17:49:40 -05:00
Anuken
0437d50a5c Merge pull request #3598 from summetdev/patch-8
Remove unused imports
2020-11-25 17:49:24 -05:00
Anuken
f49f151901 Merge pull request #3601 from genNAowl/projector-block-group
Add Projectors Blockgroup
2020-11-25 17:27:56 -05:00
Leonwang4234
2b8c11c451 projectors blockgroup 2020-11-25 14:19:56 -08:00
Anuken
11d864f2b5 Merge remote-tracking branch 'origin/master' 2020-11-25 16:25:43 -05:00
Anuken
977b55bf32 Testing BE builds 2020-11-25 16:25:39 -05:00
Anuken
b06be81f1e Merge pull request #3600 from summetdev/patch-10
GitHub Actions: Manual Triggers
2020-11-25 16:24:33 -05:00
Anuken
93313664f0 Testing BE builds 2020-11-25 16:14:39 -05:00
Antsiferov Andrew
25cb2b0abf Add workflow_dispatch event 2020-11-26 00:09:17 +03:00
Anuken
b841af3a48 Testing BE builds 2020-11-25 16:09:11 -05:00
Anuken
709f43b83c Testing BE builds 2020-11-25 16:00:35 -05:00
Anuken
aabc094dd9 Testing BE builds 2020-11-25 15:47:44 -05:00
Anuken
58acc0a970 Merge remote-tracking branch 'origin/master' 2020-11-25 15:42:56 -05:00
Anuken
c874089f27 Bugfixes 2020-11-25 15:42:51 -05:00
Antsiferov Andrew
4ac26d86f5 Remove unused imports 2020-11-25 20:04:32 +00:00
Anuken
010e5341dc Merge pull request #3596 from Catchears/ai
Fix ai schematics with power weapons and steam gens
2020-11-25 14:14:28 -05:00
Wiki Updater
51790e0bf9 fix ai schematics with power weapons and steam gens 2020-11-25 19:52:36 +01:00
Anuken
40b67349d9 Fixed quotes 2020-11-25 11:56:10 -05:00
Anuken
735cb74483 Merge remote-tracking branch 'origin/master' 2020-11-25 11:15:50 -05:00
Anuken
bc55e43def Fixed #3591 2020-11-25 11:15:46 -05:00
Anuken
084d7e8355 Merge pull request #3583 from Quezler/patch-69
automatic reconnect
2020-11-25 11:14:04 -05:00
Anuken
22e60612ac Merge remote-tracking branch 'origin/master' 2020-11-25 11:09:33 -05:00
Anuken
b271c4be32 Fixed deploy CI, again 2020-11-25 11:09:29 -05:00
Patrick 'Quezler' Mounier
f26b3358ef Update core/src/mindustry/ui/dialogs/JoinDialog.java
Co-authored-by: Anuken <arnukren@gmail.com>
2020-11-25 17:08:03 +01:00
Patrick 'Quezler' Mounier
3d6390a76a Set the ping to null when canceling manually as well 2020-11-25 16:51:57 +01:00
Patrick 'Quezler' Mounier
ff20928bec Anukify reconnect logic 2020-11-25 16:49:36 +01:00
Anuken
59387389a4 Merge pull request #3563 from skykatik/patch-11
Deleted unnecessary DateTimeFormatter declaration
2020-11-25 10:33:46 -05:00
Anuken
fb200c6d11 arc 2020-11-25 10:16:40 -05:00
Anuken
8418770bbf Merge remote-tracking branch 'origin/master' 2020-11-25 10:15:22 -05:00
Anuken
eaa7b04c3d Fixed CI / Fixed exponentially increasing broken blocks 2020-11-25 10:15:14 -05:00
Anuken
6131ef23fc Merge pull request #3578 from Quezler/patch-67
Remove unused import
2020-11-25 09:36:41 -05:00
Patrick 'Quezler' Mounier
b002d8b446 Update bundle.properties 2020-11-25 10:42:13 +01:00
Patrick 'Quezler' Mounier
f5e06cca54 Update NetClient.java 2020-11-25 10:41:41 +01:00
Patrick 'Quezler' Mounier
642b877ab0 Update JoinDialog.java 2020-11-25 10:40:42 +01:00
Patrick 'Quezler' Mounier
8ee3f2b2e6 Remove stray newline 2020-11-25 09:38:04 +01:00
Patrick 'Quezler' Mounier
40bf0741f0 Remove unused import 2020-11-25 09:36:12 +01:00
Anuken
6633b07fb2 Merge pull request #3561 from Volas171/patch-2
Update contributors
2020-11-24 18:55:00 -05:00
Volas171
e65971db47 h 2020-11-24 18:30:59 -05:00
Anuken
5fd66d38bb Fixed #3573 2020-11-24 18:15:40 -05:00
Anuken
15f33b45c7 Salt Flats should probably require additive reconstructors 2020-11-24 18:12:45 -05:00
Anuken
17e66f1008 Final campaign tweaks 2020-11-24 17:17:55 -05:00
Anuken
bcaf5e4c3d Campaign balance / Smarter power node placement 2020-11-24 16:33:36 -05:00
Anuken
6fd36d97f0 Balancing 2020-11-24 12:53:55 -05:00
Anuken
61bec243dc Campaign balance 2020-11-24 12:35:04 -05:00
Anuken
7d43856735 Bugfixes 2020-11-24 10:23:28 -05:00
Anuken
058b2ddfce Fixed #3565 2020-11-24 09:00:34 -05:00
Skat
1637360952 Deleted unnecessary DateTimeFormatter declaration 2020-11-24 13:00:08 +03:00
Volas171
97254a6672 Update contributors 2020-11-23 22:27:08 -05:00
Anuken
2282cb89b1 Fixed sector damage calculations / Campaign balance 2020-11-23 18:09:20 -05:00
Anuken
06929ee8f3 Fixed boss hint not disappearing 2020-11-23 15:47:15 -05:00
Anuken
ec19381c4e Fixed campaign bases having ridiculous wall tiers 2020-11-23 15:41:10 -05:00
Anuken
4a52392ce9 Added hint about guards & armor 2020-11-23 13:09:42 -05:00
Anuken
dcbe06229c Campaign fixes & balance 2020-11-23 10:36:41 -05:00
Anuken
075be1a862 Fixed #3540 / Fixed #3544 / Fixed #3542 2020-11-23 09:12:36 -05:00
Anuken
8d91a9b014 Fixed sectors not auto-unlocking 2020-11-22 22:03:23 -05:00
Anuken
ecea8eab01 Various tweaks and bugfixes 2020-11-22 21:20:33 -05:00
Anuken
3db2fea32b CI fix 2020-11-22 17:34:49 -05:00
Anuken
335e7489ce Fixed colors appearing in server logs 2020-11-22 17:33:10 -05:00
139 changed files with 10146 additions and 9680 deletions

View File

@@ -17,10 +17,12 @@ jobs:
java-version: 14 java-version: 14
- name: Create artifacts - name: Create artifacts
run: | run: |
./gradlew desktop:dist server:dist core:javadoc -Pbuildversion=${GITHUB_REF:1}" ./gradlew desktop:dist server:dist core:javadoc -Pbuildversion=${GITHUB_REF:1}
- name: Update docs - name: Update docs
run: | run: |
cd ../ cd ../
git config --global user.email "cli@github.com"
git config --global user.name "Github Actions"
git clone --depth=1 https://github.com/MindustryGame/docs.git git clone --depth=1 https://github.com/MindustryGame/docs.git
cp -a Mindustry/core/build/docs/javadoc/. docs/ cp -a Mindustry/core/build/docs/javadoc/. docs/
cd docs cd docs
@@ -48,12 +50,12 @@ jobs:
uses: svenstaro/upload-release-action@v2 uses: svenstaro/upload-release-action@v2
with: with:
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
file: desktop/libs/Mindustry.jar file: desktop/build/libs/Mindustry.jar
tag: ${{ github.ref }} tag: ${{ github.ref }}
- name: Upload server artifacts - name: Upload server artifacts
uses: svenstaro/upload-release-action@v2 uses: svenstaro/upload-release-action@v2
with: with:
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
file: server/libs/server-release.jar file: server/build/libs/server-release.jar
tag: ${{ github.ref }} tag: ${{ github.ref }}

View File

@@ -1,6 +1,6 @@
name: Tests name: Tests
on: [push] on: [push, workflow_dispatch]
jobs: jobs:
buildJava14: buildJava14:
@@ -15,6 +15,7 @@ jobs:
- name: Run unit tests - name: Run unit tests
run: ./gradlew test run: ./gradlew test
- name: Trigger BE build - name: Trigger BE build
if: ${{ github.repository == 'Anuken/Mindustry' }}
run: | run: |
git clone --depth=1 --branch=master https://github.com/Anuken/MindustryBuilds ../MindustryBuilds git clone --depth=1 --branch=master https://github.com/Anuken/MindustryBuilds ../MindustryBuilds
cd ../MindustryBuilds cd ../MindustryBuilds

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
version="1.1"
id="svg542"
sodipodi:docname="planet.svg"
inkscape:version="1.0.1 (0767f8302a, 2020-10-17)">
<metadata
id="metadata548">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs546" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1316"
id="namedview544"
showgrid="false"
inkscape:pagecheckerboard="true"
inkscape:zoom="15.75"
inkscape:cx="-16.385458"
inkscape:cy="16.16535"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg542" />
<path
id="polygon2"
style="fill:#ffffff"
d="M 5.5 0 L 5 0.5 L 4.5 1 L 3.5 1 L 3 1.5 L 2.5 2 L 2 2.5 L 1.5 3 L 1 3.5 L 1 4.5 L 0.5 5 L 0 5.5 L 0 6.5 L 0 7.5 L 0 8.5 L 0 9.5 L 0 10.5 L 0.5 11 L 1 11.5 L 1 12.5 L 1.5 13 L 2 13.5 L 2.5 14 L 3 14.5 L 3.5 15 L 4.5 15 L 5 15.5 L 5.5 16 L 6.5 16 L 7.5 16 L 8.5 16 L 9.5 16 L 10.5 16 L 11 15.5 L 11.5 15 L 12.5 15 L 13 14.5 L 13.5 14 L 14 13.5 L 14.5 13 L 15 12.5 L 15 11.5 L 15.5 11 L 16 10.5 L 16 9.5 L 16 8.5 L 16 7.5 L 16 6.5 L 16 5.5 L 15.5 5 L 15 4.5 L 15 3.5 L 14.5 3 L 14 2.5 L 13.5 2 L 13 1.5 L 12.5 1 L 11.5 1 L 11 0.5 L 10.5 0 L 9.5 0 L 8.5 0 L 7.5 0 L 6.5 0 L 5.5 0 z M 6.5 1 L 7 1.5 L 7.5 2 L 8.5 2 L 9 2.5 L 9 3.5 L 9.5 4 L 10 4.5 L 10.5 5 L 11 5.5 L 11.5 6 L 12.5 6 L 13.5 6 L 14.5 6 L 15 6.5 L 15 7.5 L 15 8.5 L 15 9.5 L 14.5 10 L 14 10.5 L 14 11.5 L 13.5 12 L 13 12.5 L 12.5 13 L 12 13.5 L 11.5 14 L 10.5 14 L 10 14.5 L 9.5 15 L 8.5 15 L 8 14.5 L 7.5 14 L 7 13.5 L 7 12.5 L 7.5 12 L 8 11.5 L 8.5 11 L 9 10.5 L 9 9.5 L 9 8.5 L 8.5 8 L 8 7.5 L 7.5 7 L 6.5 7 L 5.5 7 L 4.5 7 L 4 7.5 L 3.5 8 L 3 8.5 L 2.5 9 L 2 9.5 L 1.5 10 L 1 9.5 L 1 8.5 L 1 7.5 L 1 6.5 L 1.5 6 L 2 5.5 L 2 4.5 L 2.5 4 L 3 3.5 L 3.5 3 L 4 2.5 L 4.5 2 L 5.5 2 L 6 1.5 L 6.5 1 z M 11.5 9 L 11 9.5 L 11 10.5 L 11.5 11 L 12.5 11 L 13 10.5 L 13 9.5 L 12.5 9 L 11.5 9 z " />
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 578 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 682 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 B

View File

@@ -1,2 +1,3 @@
mschxœ-k mschxњ-Ќ‹
1 „ÇMÅîуôPÅ В0 EoЧКєўТЏЄ®И ¶Ґ«Ёџ.CfІJ‡<NЗ*Ш»Г<C2BB>lцЮѕиmЖ0№ељзTжЂN)>]6!NОРьж0,)Ь‡&ЩІЌцbKqщЌу~И$њя+А­Vh¶•т №} ¶U
кwZР;¤$ґ ]Сґ…]P,(І»ЉЎkҐ№ъЕ¶,e

View File

@@ -22,9 +22,8 @@ gameover.pvp = The[accent] {0}[] team is victorious!
gameover.waiting = [accent]Waiting for next map... gameover.waiting = [accent]Waiting for next map...
highscore = [accent]New highscore! highscore = [accent]New highscore!
copied = Copied. copied = Copied.
indev.popup = [accent]v6[] is currently in [accent]beta[].\n[lightgray]This means:[]\n[scarlet]- The campaign is unfinished[]\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[].
indev.notready = This part of the game isn't ready yet indev.notready = This part of the game isn't ready yet
indev.campaign = [accent]You've reached the end of the campaign![]\n\nThis is as far as the content goes. Interplanetary travel will be added in future updates. indev.campaign = [accent]Congratulations! You've reached the end of the campaign![]\n\nThis is as far as the content goes right now. Interplanetary travel will be added in future updates.
load.sound = Sounds load.sound = Sounds
load.map = Maps load.map = Maps
@@ -147,8 +146,12 @@ planetmap = Planet Map
launchcore = Launch Core launchcore = Launch Core
filename = File Name: filename = File Name:
unlocked = New content unlocked! unlocked = New content unlocked!
available = New research available!
completed = [accent]Completed completed = [accent]Completed
techtree = Tech Tree techtree = Tech Tree
research.legacy = [accent]5.0[] research data found.\nDo you want to [accent]load this data[], or [accent]discard it[] and restart research in the new campaign (recommended)?
research.load = Load
research.discard = Discard
research.list = [lightgray]Research: research.list = [lightgray]Research:
research = Research research = Research
researched = [lightgray]{0} researched. researched = [lightgray]{0} researched.
@@ -230,6 +233,7 @@ disconnect.timeout = Timed out.
disconnect.data = Failed to load world data! disconnect.data = Failed to load world data!
cantconnect = Unable to join game ([accent]{0}[]). cantconnect = Unable to join game ([accent]{0}[]).
connecting = [accent]Connecting... connecting = [accent]Connecting...
reconnecting = [accent]Reconnecting...
connecting.data = [accent]Loading world data... connecting.data = [accent]Loading world data...
server.port = Port: server.port = Port:
server.addressinuse = Address already in use! server.addressinuse = Address already in use!
@@ -501,7 +505,6 @@ map.multiplayer = Only the host can view sectors.
uncover = Uncover uncover = Uncover
configure = Configure Loadout configure = Configure Loadout
#TODO
loadout = Loadout loadout = Loadout
resources = Resources resources = Resources
bannedblocks = Banned Blocks bannedblocks = Banned Blocks
@@ -509,12 +512,6 @@ addall = Add All
launch.from = Launching From: [accent]{0} launch.from = Launching From: [accent]{0}
launch.destination = Destination: {0} launch.destination = Destination: {0}
configure.invalid = Amount must be a number between 0 and {0}. configure.invalid = Amount must be a number between 0 and {0}.
zone.unlocked = [lightgray]{0} unlocked.
zone.requirement.complete = Requirement for {0} completed:[lightgray]\n{1}
zone.resources = [lightgray]Resources Detected:
zone.objective = [lightgray]Objective: [accent]{0}
zone.objective.survival = Survive
zone.objective.attack = Destroy Enemy Core
add = Add... add = Add...
boss.health = Guardian Health boss.health = Guardian Health
@@ -600,6 +597,11 @@ sector.tarFields.description = The outskirts of an oil production zone, between
sector.desolateRift.description = An extremely dangerous zone. Plentiful resources, but little space. High risk of destruction. Leave as soon as possible. Do not be fooled by the long spacing between enemy attacks. sector.desolateRift.description = An extremely dangerous zone. Plentiful resources, but little space. High risk of destruction. Leave as soon as possible. Do not be fooled by the long spacing between enemy attacks.
sector.nuclearComplex.description = A former facility for the production and processing of thorium, reduced to ruins.\n[lightgray]Research the thorium and its many uses.\n\nThe enemy is present here in great numbers, constantly scouting for attackers. sector.nuclearComplex.description = A former facility for the production and processing of thorium, reduced to ruins.\n[lightgray]Research the thorium and its many uses.\n\nThe enemy is present here in great numbers, constantly scouting for attackers.
sector.fungalPass.description = A transition area between high mountains and lower, spore-ridden lands. A small enemy reconnaissance base is located here.\nDestroy it.\nUse Dagger and Crawler units. Take out the two cores. sector.fungalPass.description = A transition area between high mountains and lower, spore-ridden lands. A small enemy reconnaissance base is located here.\nDestroy it.\nUse Dagger and Crawler units. Take out the two cores.
sector.biomassFacility.description = The origin of spores. This is the facility in which they were researched and initially produced.\nResearch the technology contained within. Cultivate spores for the production of fuel and plastics.\n\n[lightgray]Upon this facility's demise, the spores were released. Nothing in the local ecosystem could compete with such an invasive organism.
sector.windsweptIslands.description = Further past the shoreline is this remote chain of islands. Records show they once had [accent]Plastanium[]-producing structures.\n\nFend off the enemy's naval units. Establish a base on the islands. Research these factories.
sector.extractionOutpost.description = A remote outpost, constructed by the enemy for the purpose of launching resources to other sectors.\n\nCross-sector transport technology is essential for further conquest. Destroy the base. Research their Launch Pads.
sector.impact0078.description = Here lie remnants of the interstellar transport vessel that first entered this system.\n\nSalvage as much as possible from the wreckage. Research any intact technology.
sector.planetaryTerminal.description = The final target.\n\nThis coastal base contains a structure capable of launching Cores to local planets. It is extremely well guarded.\n\nProduce naval units. Eliminate the enemy as quickly as possible. Research the launch structure.
settings.language = Language settings.language = Language
settings.data = Game Data settings.data = Game Data
@@ -813,7 +815,7 @@ setting.smoothcamera.name = Smooth Camera
setting.vsync.name = VSync setting.vsync.name = VSync
setting.pixelate.name = Pixelate setting.pixelate.name = Pixelate
setting.minimap.name = Show Minimap setting.minimap.name = Show Minimap
setting.coreitems.name = Display Core Items (WIP) setting.coreitems.name = Display Core Items
setting.position.name = Show Player Position setting.position.name = Show Player Position
setting.musicvol.name = Music Volume setting.musicvol.name = Music Volume
setting.atmosphere.name = Show Planet Atmosphere setting.atmosphere.name = Show Planet Atmosphere
@@ -894,6 +896,7 @@ keybind.pause.name = Pause
keybind.pause_building.name = Pause/Resume Building keybind.pause_building.name = Pause/Resume Building
keybind.minimap.name = Minimap keybind.minimap.name = Minimap
keybind.planet_map.name = Planet Map keybind.planet_map.name = Planet Map
keybind.research.name = Research
keybind.chat.name = Chat keybind.chat.name = Chat
keybind.player_list.name = Player List keybind.player_list.name = Player List
keybind.console.name = Console keybind.console.name = Console
@@ -1018,6 +1021,7 @@ block.resupply-point.name = Resupply Point
block.parallax.name = Parallax block.parallax.name = Parallax
block.cliff.name = Cliff block.cliff.name = Cliff
block.sand-boulder.name = Sand Boulder block.sand-boulder.name = Sand Boulder
block.basalt-boulder.name = Basalt Boulder
block.grass.name = Grass block.grass.name = Grass
block.slag.name = Slag block.slag.name = Slag
block.space.name = Space block.space.name = Space
@@ -1266,13 +1270,15 @@ hint.schematicSelect = Hold [accent][[F][] and drag to select blocks to copy and
hint.conveyorPathfind = Hold [accent][[L-Ctrl][] while dragging conveyors to automatically generate a path. hint.conveyorPathfind = Hold [accent][[L-Ctrl][] while dragging conveyors to automatically generate a path.
hint.conveyorPathfind.mobile = Enable \ue844 [accent]diagonal mode[] and drag conveyors to automatically generate a path. hint.conveyorPathfind.mobile = Enable \ue844 [accent]diagonal mode[] and drag conveyors to automatically generate a path.
hint.boost = Hold [accent][[L-Shift][] to fly over obstacles with your current unit.\n\nOnly a few ground units have boosters. hint.boost = Hold [accent][[L-Shift][] to fly over obstacles with your current unit.\n\nOnly a few ground units have boosters.
hint.command = Press [accent][[G][] to command nearby units into formation. hint.command = Press [accent][[G][] to command nearby units of [accent]similar type[] into formation.\n\nTo command ground units, you must first control another ground unit.
hint.command.mobile = [accent][[Double-tap][] your unit to command nearby units into formation. hint.command.mobile = [accent][[Double-tap][] your unit to command nearby units into formation.
hint.payloadPickup = Press [accent][[[] to pick up small blocks or units. hint.payloadPickup = Press [accent][[[] to pick up small blocks or units.
hint.payloadPickup.mobile = [accent]Tap and hold[] a small block or unit to pick it up. hint.payloadPickup.mobile = [accent]Tap and hold[] a small block or unit to pick it up.
hint.payloadDrop = Press [accent]][] to drop a payload. hint.payloadDrop = Press [accent]][] to drop a payload.
hint.payloadDrop.mobile = [accent]Tap and hold[] an empty location to drop a payload there. hint.payloadDrop.mobile = [accent]Tap and hold[] an empty location to drop a payload there.
hint.waveFire = [accent]Wave[] turrets with water as ammunition will automatically put out nearby fires. hint.waveFire = [accent]Wave[] turrets with water as ammunition will automatically put out nearby fires.
hint.generator = \uf879 [accent]Combustion Generators[] burn coal and transmit power to adjacent blocks.\n\nPower transmission range can be extended with \uf87f [accent]Power Nodes[].
hint.guardian = [accent]Guardian[] units are armored. Weak ammo such as [accent]Copper[] and [accent]Lead[] is [scarlet]not effective[].\n\nUse higher tier turrets or \uf835 [accent]Graphite[] \uf861Duo/\uf859Salvo ammunition to take Guardians down.
item.copper.description = Used in all types of construction and ammunition. item.copper.description = Used in all types of construction and ammunition.
item.copper.details = Copper. Abnormally abundant metal on Serpulo. Structurally weak unless reinforced. item.copper.details = Copper. Abnormally abundant metal on Serpulo. Structurally weak unless reinforced.
@@ -1454,7 +1460,7 @@ unit.reign.description = Fires a barrage of massive piercing bullets at all near
unit.nova.description = Fires laser bolts that damage enemies and repair allied structures. Capable of flight. unit.nova.description = Fires laser bolts that damage enemies and repair allied structures. Capable of flight.
unit.pulsar.description = Fires arcs of electricity that damage enemies and repair allied structures. Capable of flight. unit.pulsar.description = Fires arcs of electricity that damage enemies and repair allied structures. Capable of flight.
unit.quasar.description = Fires piercing laser beams that damage enemies and repair allied structures. Capable of flight. Shielded. unit.quasar.description = Fires piercing laser beams that damage enemies and repair allied structures. Capable of flight. Shielded.
unit.vela.description = Fires a massive continuous laser beam that damages enemies, causes fires and repair allied structures. Capable of flight. unit.vela.description = Fires a massive continuous laser beam that damages enemies, causes fires and repairs allied structures. Capable of flight.
unit.corvus.description = Fires a massive laser blast that damages enemies and repairs allied structures. Can step over most terrain. unit.corvus.description = Fires a massive laser blast that damages enemies and repairs allied structures. Can step over most terrain.
unit.crawler.description = Runs toward enemies and self-destructs, causing a large explosion. unit.crawler.description = Runs toward enemies and self-destructs, causing a large explosion.
unit.atrax.description = Fires debilitating orbs of slag at ground targets. Can step over most terrain. unit.atrax.description = Fires debilitating orbs of slag at ground targets. Can step over most terrain.

View File

@@ -19,8 +19,8 @@ screenshot.invalid = 맵이 너무 커서 스크린샷에 사용될 메모리가
gameover = 게임 오버 gameover = 게임 오버
gameover.pvp = [accent]{0}[] 팀이 승리했습니다! gameover.pvp = [accent]{0}[] 팀이 승리했습니다!
highscore = [accent]새로운 최고 점수! highscore = [accent]새로운 최고 점수!
copied = 복사됨. copied = 복사
indev.popup = 현재 [accent]v6[] 버전은 [accent]알파[] 단계입니다.\n[lightgray]이 말은:[]\n- [scarlet]캠페인이 아직 완전히 개발되지 않음[]\n- 몇몇 컨텐츠가 빠짐\n- 대부분의 [scarlet]유닛 AI[]가 작동하지 않음\n- 많은 유닛들이 아직 미완성\n- 보이는 것은 모두 바뀌거나 제거될 수 있음\n\n[accent]Github[] 에서 버그 또는 강제종료 오류를 신고 해 주세요. indev.popup = 현재 [accent]v6[] 버전은 [accent]베타[] 단계입니다.\n\n[accent]Github[] 에서 버그 또는 강제종료 오류를 신고 해 주세요.
indev.notready = 이 부분은 아직 준비가 되지 않았습니다. indev.notready = 이 부분은 아직 준비가 되지 않았습니다.
load.sound = 소리 load.sound = 소리
@@ -71,15 +71,15 @@ map.delete = 정말로 "[accent]{0}[]" 맵을 삭제하시겠습니까?
level.highscore = 최고 점수: [accent]{0} level.highscore = 최고 점수: [accent]{0}
level.select = 맵 선택 level.select = 맵 선택
level.mode = 게임 모드: level.mode = 게임 모드:
coreattack = < 코어가 공격 받고 있습니다! > coreattack = < 코어가 공격 받고 있습니다! >
nearpoint = [[ [scarlet]즉시 스폰지점에서 떠나세요[] ]\n전멸 임박 nearpoint = [[ [scarlet]즉시 스폰지점에서 떠나세요[] ]\n인근 건물들과 유닛들은 초토화됩니다!
database = 코어 데이터베이스 database = 코어 데이터베이스
savegame = 게임 저장 savegame = 게임 저장
loadgame = 게임 불러오기 loadgame = 게임 불러오기
joingame = 게임 참여 joingame = 게임 참여
customgame = 사용자 지정 게임 customgame = 사용자 지정 게임
newgame = 새 게임 newgame = 새 게임
none = <없음> none = < 없음 >
minimap = 미니맵 minimap = 미니맵
position = 위치 position = 위치
close = 닫기 close = 닫기
@@ -291,8 +291,8 @@ waiting = [lightgray]대기중...
waiting.players = 상대 플레이어를 기다리는 중... waiting.players = 상대 플레이어를 기다리는 중...
wave.enemies = [lightgray]적 유닛 {0}명 남음 wave.enemies = [lightgray]적 유닛 {0}명 남음
wave.enemy = [lightgray]{0}명 남음 wave.enemy = [lightgray]{0}명 남음
wave.guardianwarn = [accent]{0}[] 단계 후에 가디언이 접근합니다. wave.guardianwarn = [accent]{0}[] 단계 후에 수호자가 접근합니다.
wave.guardianwarn.one = [accent]{0}[] 단계 후에 가디언이 접근합니다. wave.guardianwarn.one = [accent]{0}[] 단계 후에 수호자가 접근합니다.
loadimage = 사진 불러오기 loadimage = 사진 불러오기
saveimage = 사진 저장 saveimage = 사진 저장
unknown = 알 수 없음 unknown = 알 수 없음
@@ -335,13 +335,13 @@ editor.center = 중앙
workshop = 창작마당 workshop = 창작마당
waves.title = 단계 waves.title = 단계
waves.remove = 삭제 waves.remove = 삭제
waves.never = 여기까지 유닛생성 waves.never = 여기까지 유닛 생성
waves.every = waves.every =
waves.waves = 단계마다 waves.waves = 단계마다
waves.perspawn = 마리 생성 waves.perspawn = 마리 생성
waves.shields = 보호막/단계 waves.shields = 방어막/단계
waves.to = 부터 waves.to = 부터
waves.guardian = 가디언 waves.guardian = 수호자
waves.preview = 미리보기 waves.preview = 미리보기
waves.edit = 편집 waves.edit = 편집
waves.copy = 클립보드로 복사 waves.copy = 클립보드로 복사
@@ -495,7 +495,7 @@ zone.objective = [lightgray]목표: [accent]{0}
zone.objective.survival = 생존 zone.objective.survival = 생존
zone.objective.attack = 적 코어 파괴 zone.objective.attack = 적 코어 파괴
add = 추가... add = 추가...
boss.health = 보스 체력 boss.health = 수호자 체력
connectfail = [scarlet]연결 오류:\n\n[accent]{0} connectfail = [scarlet]연결 오류:\n\n[accent]{0}
error.unreachable = 서버에 연결하지 못했습니다.\n서버 주소가 정확히 입력되었나요? error.unreachable = 서버에 연결하지 못했습니다.\n서버 주소가 정확히 입력되었나요?
@@ -522,11 +522,11 @@ sectors.resume = 재개
sectors.launch = 출격 sectors.launch = 출격
sectors.select = 선택 sectors.select = 선택
sectors.nonelaunch = [lightgray]없음 (sun) sectors.nonelaunch = [lightgray]없음 (sun)
sectors.rename = Rename Sector sectors.rename = 구역 명명
sector.missingresources = [scarlet]Insufficient Core Resources sector.missingresources = [scarlet]자원 부족
planet.serpulo.name = Serpulo planet.serpulo.name = 세르플
planet.sun.name = Sun planet.sun.name = 태양
sector.groundZero.name = 전초기지 sector.groundZero.name = 전초기지
sector.craters.name = 크레이터 sector.craters.name = 크레이터
@@ -561,26 +561,26 @@ settings.controls = 조작
settings.game = 게임 settings.game = 게임
settings.sound = 소리 settings.sound = 소리
settings.graphics = 그래픽 settings.graphics = 그래픽
settings.cleardata = 게임 데이터 초기화... settings.cleardata = 게임 데이터 초기화
settings.clear.confirm = 정말로 이 데이터를 지우시겠습니까?\n완료된 작업은 취소할 수 없습니다! settings.clear.confirm = 정말로 이 데이터를 지우시겠습니까?\n되돌릴 수 없습니다!
settings.clearall.confirm = [scarlet]경고![]\n이 작업은 저장된 맵, 맵파일, 잠금 해제된 목록과 키 매핑, 그리고 모든 데이터를 삭제합니다.\n확인 버튼을 다시 눌러 모든 데이터를 삭제하고 게임에서 나갑니다. settings.clearall.confirm = [scarlet]경고![]\n이 작업은 저장된 맵, 맵파일, 잠금 해제된 목록과 키 매핑, 그리고 모든 데이터를 삭제합니다.\n확인 버튼을 다시 눌러 모든 데이터를 삭제하고 게임에서 나갑니다.
settings.clearsaves.confirm = 정말로 모든 저장을 삭제 하시겠습니까? settings.clearsaves.confirm = 정말로 모든 저장된 파일들을 삭제하시겠습니까?
settings.clearsaves = 저장 초기화 settings.clearsaves = 저장 초기화
settings.clearresearch = Clear Research settings.clearresearch = 연구 초기화
settings.clearresearch.confirm = Are you sure you want to clear all of your campaign research? settings.clearresearch.confirm = 정말로 모든 연구를 삭제하시겠습니까?
settings.clearcampaignsaves = Clear Campaign Saves settings.clearcampaignsaves = 캠페인 맵 초기화
settings.clearcampaignsaves.confirm = Are you sure you want to clear all of your campaign saves? settings.clearcampaignsaves.confirm = 정말로 캠페인을 초기화하시겠습니까?
paused = [accent]< 일시정지 > paused = [accent]< 일시정지 >
clear = 초기화 clear = 초기화
banned = [scarlet]차단됨 banned = [scarlet]차단됨
unplaceable.sectorcaptured = [scarlet]점령된 구역이 필요합니다 unplaceable.sectorcaptured = [scarlet]구역 점령 필요
yes = yes =
no = 아니오 no = 아니오
info.title = 정보 info.title = 정보
error.title = [scarlet]오류가 발생했습니다. error.title = [scarlet]오류가 발생했습니다.
error.crashtitle = 오류가 발생했습니다 error.crashtitle = 오류가 발생했습니다
unit.nobuild = [scarlet]이 유닛은 건설할 수 없습니다. unit.nobuild = [scarlet]건설 불가
lastaccessed = [lightgray]마지막 접근: {0} lastaccessed = [lightgray]마지막 조작: {0}
block.unknown = [lightgray]??? block.unknown = [lightgray]???
stat.input = 입력 stat.input = 입력
@@ -588,70 +588,70 @@ stat.output = 출력
stat.booster = 가속 stat.booster = 가속
stat.tiles = 필요한 타일 stat.tiles = 필요한 타일
stat.affinities = 친화력 stat.affinities = 친화력
stat.powercapacity = Power Capacity stat.powercapacity = 전력량
stat.powershot = Power/Shot stat.powershot = 전력량/발
stat.damage = Damage stat.damage = 공격력
stat.targetsair = Targets Air stat.targetsair = 공중 공격
stat.targetsground = Targets Ground stat.targetsground = 지상 공격
stat.itemsmoved = Move Speed stat.itemsmoved = 이동 속도
stat.launchtime = Time Between Launches stat.launchtime = 발사 간격
stat.shootrange = Range stat.shootrange = 사거리
stat.size = Size stat.size = 크기
stat.displaysize = Display Size stat.displaysize = 화면 크기
stat.liquidcapacity = Liquid Capacity stat.liquidcapacity = 액체 수용량
stat.powerrange = Power Range stat.powerrange = 전선 길이
stat.linkrange = Link Range stat.linkrange = 감지 길이
stat.instructions = Instructions stat.instructions = 최대 명령어 수
stat.powerconnections = Max Connections stat.powerconnections = 최대 연결 개수
stat.poweruse = Power Use stat.poweruse = 전력 요구량
stat.powerdamage = Power/Damage stat.powerdamage = 전력량/피해량
stat.itemcapacity = Item Capacity stat.itemcapacity = 자원 수용량
stat.memorycapacity = Memory Capacity stat.memorycapacity = 변수 개수
stat.basepowergeneration = Base Power Generation stat.basepowergeneration = 기본 발전량
stat.productiontime = Production Time stat.productiontime = 소요 시간
stat.repairtime = Block Full Repair Time stat.repairtime = 건물 완전 복구 시간
stat.speedincrease = Speed Increase stat.speedincrease = 속도 증가
stat.range = Range stat.range = 사거리
stat.drilltier = Drillables stat.drilltier = 채굴 가능 자원
stat.drillspeed = Base Drill Speed stat.drillspeed = 기본 채굴 속도
stat.boosteffect = Boost Effect stat.boosteffect = 버프 효과
stat.maxunits = Max Active Units stat.maxunits = 최대 유닛 수
stat.health = Health stat.health = 체력
stat.buildtime = Build Time stat.buildtime = 건설 시간
stat.maxconsecutive = Max Consecutive stat.maxconsecutive = 최대 체인 길이
stat.buildcost = Build Cost stat.buildcost = 건설 비용
stat.inaccuracy = Inaccuracy stat.inaccuracy = 오차각
stat.shots = Shots stat.shots = 발사 당 탄
stat.reload = Shots/Second stat.reload = 발/초
stat.ammo = Ammo stat.ammo = 탄약
stat.shieldhealth = Shield Health stat.shieldhealth = 보호막 체력
stat.cooldowntime = Cooldown Time stat.cooldowntime = 쿨타임
stat.explosiveness = Explosiveness stat.explosiveness = 폭발성
stat.basedeflectchance = Base Deflect Chance stat.basedeflectchance = 기본 반사 확률
stat.lightningchance = Lightning Chance stat.lightningchance = 전격 확률
stat.lightningdamage = Lightning Damage stat.lightningdamage = 전격 공격량
stat.flammability = Flammability stat.flammability = 휘발성
stat.radioactivity = Radioactivity stat.radioactivity = 방사성
stat.heatcapacity = HeatCapacity stat.heatcapacity = 열용량
stat.viscosity = Viscosity stat.viscosity = 점성
stat.temperature = Temperature stat.temperature = 온도
stat.speed = Speed stat.speed = 속도
stat.buildspeed = Build Speed stat.buildspeed = 건설 속도
stat.minespeed = Mine Speed stat.minespeed = 채굴 속도
stat.minetier = Mine Tier stat.minetier = 채굴 티어
stat.payloadcapacity = Payload Capacity stat.payloadcapacity = 화물 수용량
stat.commandlimit = Command Limit stat.commandlimit = 지휘 한계
stat.abilities = Abilities stat.abilities = 능력
ability.forcefield = Force Field ability.forcefield = 보호막
ability.repairfield = Repair Field ability.repairfield = 수리장
ability.statusfield = Status Field ability.statusfield = 버프장
ability.unitspawn = {0} Factory ability.unitspawn = {0} 공장
ability.shieldregenfield = Shield Regen Field ability.shieldregenfield = 방어막 복구장
bar.drilltierreq = 더 좋은 드릴이 필요 bar.drilltierreq = 더 좋은 드릴이 필요
bar.noresources = 자원 부족 bar.noresources = 자원 부족
bar.corereq = 코어 기지 필요 bar.corereq = 코어 필요
bar.drillspeed = 드릴 속도: {0}/s bar.drillspeed = 드릴 속도: {0}/s
bar.pumpspeed = 펌프 속도: {0}/s bar.pumpspeed = 펌프 속도: {0}/s
bar.efficiency = 효율: {0}% bar.efficiency = 효율: {0}%
@@ -688,7 +688,7 @@ bullet.multiplier = [stat]{0}[lightgray]x 탄약 배수
bullet.reload = [stat]{0}[lightgray]x 발사 속도 bullet.reload = [stat]{0}[lightgray]x 발사 속도
unit.blocks = 블록 unit.blocks = 블록
unit.blockssquared = blocks² unit.blockssquared = 블록²
unit.powersecond = 전력/초 unit.powersecond = 전력/초
unit.liquidsecond = 액체/초 unit.liquidsecond = 액체/초
unit.itemssecond = 개/초 unit.itemssecond = 개/초
@@ -701,7 +701,7 @@ unit.persecond = /초
unit.perminute = /분 unit.perminute = /분
unit.timesspeed = x 배 unit.timesspeed = x 배
unit.percent = % unit.percent = %
unit.shieldhealth = 보호막 체력 unit.shieldhealth = 방어막 체력
unit.items = 자원 unit.items = 자원
unit.thousands = unit.thousands =
unit.millions = 백만 unit.millions = 백만
@@ -711,7 +711,7 @@ category.power = 전력
category.liquids = 액체 category.liquids = 액체
category.items = 자원 category.items = 자원
category.crafting = 입력/출력 category.crafting = 입력/출력
category.function = Function category.function = 기능
category.optional = 보조 자원 category.optional = 보조 자원
setting.landscape.name = 가로화면 잠금 setting.landscape.name = 가로화면 잠금
setting.shadows.name = 그림자 setting.shadows.name = 그림자
@@ -722,7 +722,7 @@ setting.flow.name = 자원 흐름량 표시
setting.buildautopause.name = 건설 자동 일시정지 setting.buildautopause.name = 건설 자동 일시정지
setting.animatedwater.name = 액체 애니메이션 효과 setting.animatedwater.name = 액체 애니메이션 효과
setting.animatedshields.name = 보호막 애니메이션 효과 setting.animatedshields.name = 보호막 애니메이션 효과
setting.antialias.name = 안티 에일리어싱[lightgray] (재시작 필요)[] setting.antialias.name = 위신호 제거 필터[lightgray] (재시작 필요)[]
setting.playerindicators.name = 플레이어 위치 표시기 setting.playerindicators.name = 플레이어 위치 표시기
setting.indicators.name = 적 위치 표시기 setting.indicators.name = 적 위치 표시기
setting.autotarget.name = 자동 조준 setting.autotarget.name = 자동 조준
@@ -734,10 +734,10 @@ setting.fpscap.text = {0} FPS
setting.uiscale.name = UI 스케일링[lightgray] (재시작 필요)[] setting.uiscale.name = UI 스케일링[lightgray] (재시작 필요)[]
setting.swapdiagonal.name = 항상 대각선 배치 setting.swapdiagonal.name = 항상 대각선 배치
setting.difficulty.training = 훈련 setting.difficulty.training = 훈련
setting.difficulty.easy = 쉬움 setting.difficulty.easy = 무난
setting.difficulty.normal = 보통 setting.difficulty.normal = 보통
setting.difficulty.hard = 어려움 setting.difficulty.hard = 혼돈
setting.difficulty.insane = 미침 setting.difficulty.insane = 박멸
setting.difficulty.name = 난이도: setting.difficulty.name = 난이도:
setting.screenshake.name = 화면 흔들림 setting.screenshake.name = 화면 흔들림
setting.effects.name = 효과 보임 setting.effects.name = 효과 보임
@@ -769,7 +769,7 @@ setting.savecreate.name = 자동 저장 활성화
setting.publichost.name = 멀티플레이 공용 서버로 표시 setting.publichost.name = 멀티플레이 공용 서버로 표시
setting.playerlimit.name = 플레이어 제한 setting.playerlimit.name = 플레이어 제한
setting.chatopacity.name = 채팅창 투명도 setting.chatopacity.name = 채팅창 투명도
setting.lasersopacity.name = 력 레이저 투명도 setting.lasersopacity.name = 투명도
setting.bridgeopacity.name = 터널 투명도 setting.bridgeopacity.name = 터널 투명도
setting.playerchat.name = 채팅 말풍선 표시 setting.playerchat.name = 채팅 말풍선 표시
public.confirm = 게임을 모두에게 공개하시겠습니까?\n[accent]모든 플레이어가 게임에 참여할 수 있습니다.\n[lightgray]설정->게임->멀티플레이 공용 서버로 표시에서 나중에 변경할 수 있습니다.\n\n[sky]번역자 추가[]\n[accent]친구끼리 하려고 이 기능을 활성화 한 뒤에, 친구 외에 다른 플레이어가 들어왔을 때\n해당 플레이어를 차단하는 행위는 비매너를 넘어서는 얌체 행위 그 자체입니다.\n정말로 [scarlet]많은 다른 플레이어들이 오길 원한다[]면 확인하세요. public.confirm = 게임을 모두에게 공개하시겠습니까?\n[accent]모든 플레이어가 게임에 참여할 수 있습니다.\n[lightgray]설정->게임->멀티플레이 공용 서버로 표시에서 나중에 변경할 수 있습니다.\n\n[sky]번역자 추가[]\n[accent]친구끼리 하려고 이 기능을 활성화 한 뒤에, 친구 외에 다른 플레이어가 들어왔을 때\n해당 플레이어를 차단하는 행위는 비매너를 넘어서는 얌체 행위 그 자체입니다.\n정말로 [scarlet]많은 다른 플레이어들이 오길 원한다[]면 확인하세요.
@@ -794,8 +794,8 @@ keybind.clear_building.name = 설계도 초기화
keybind.press = 키를 누르세요... keybind.press = 키를 누르세요...
keybind.press.axis = 마우스 휠 또는 키를 누르세요... keybind.press.axis = 마우스 휠 또는 키를 누르세요...
keybind.screenshot.name = 맵 스크린샷 keybind.screenshot.name = 맵 스크린샷
keybind.toggle_power_lines.name = 력 레이저 토글 keybind.toggle_power_lines.name = 선 가시도 설정
keybind.toggle_block_status.name = 블록 상태 토글 keybind.toggle_block_status.name = 블록 상태 가시도
keybind.move_x.name = X축 이동 keybind.move_x.name = X축 이동
keybind.move_y.name = Y축 이동 keybind.move_y.name = Y축 이동
keybind.mouse_move.name = 커서를 따라서 이동 keybind.mouse_move.name = 커서를 따라서 이동

View File

@@ -551,7 +551,7 @@ sectors.rename = Переименовать сектор
sectors.enemybase = [scarlet]Вражеская база sectors.enemybase = [scarlet]Вражеская база
sectors.vulnerable = [scarlet]Уязвим sectors.vulnerable = [scarlet]Уязвим
sectors.underattack = [scarlet]Атакован! [accent]{0}% повреждений sectors.underattack = [scarlet]Атакован! [accent]{0}% повреждений
sectors.survives = [accent]Продержался {0} волн(ы) sectors.survives = [accent]Продержиться {0} волн(ы)
sector.curcapture = Сектор захвачен sector.curcapture = Сектор захвачен
sector.curlost = Сектор потерян sector.curlost = Сектор потерян

View File

@@ -101,3 +101,4 @@ jalastram (freesound.org)
newlocknew (freesound.org) newlocknew (freesound.org)
dsmolenaers (freesound.org) dsmolenaers (freesound.org)
Headphaze (freesound.org) Headphaze (freesound.org)
VolasYouKnow

View File

@@ -317,3 +317,4 @@
63419=legacy-unit-factory-air|block-legacy-unit-factory-air-medium 63419=legacy-unit-factory-air|block-legacy-unit-factory-air-medium
63418=legacy-unit-factory-ground|block-legacy-unit-factory-ground-medium 63418=legacy-unit-factory-ground|block-legacy-unit-factory-ground-medium
63417=interplanetary-accelerator|block-interplanetary-accelerator-medium 63417=interplanetary-accelerator|block-interplanetary-accelerator-medium
63416=basalt-boulder|block-basalt-boulder-medium

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 828 B

After

Width:  |  Height:  |  Size: 831 B

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 675 KiB

After

Width:  |  Height:  |  Size: 667 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 437 KiB

After

Width:  |  Height:  |  Size: 440 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 MiB

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 KiB

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 438 KiB

After

Width:  |  Height:  |  Size: 438 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

@@ -88,7 +88,7 @@ public class Vars implements Loadable{
/** duration of time between turns in ticks */ /** duration of time between turns in ticks */
public static final float turnDuration = 2 * Time.toMinutes; public static final float turnDuration = 2 * Time.toMinutes;
/** chance of an invasion per turn, 1 = 100% */ /** chance of an invasion per turn, 1 = 100% */
public static final float baseInvasionChance = 1f / 50f; public static final float baseInvasionChance = 1f / 100f;
/** how many turns have to pass before invasions start */ /** how many turns have to pass before invasions start */
public static final int invasionGracePeriod = 20; public static final int invasionGracePeriod = 20;
/** min armor fraction damage; e.g. 0.05 = at least 5% damage */ /** min armor fraction damage; e.g. 0.05 = at least 5% damage */

View File

@@ -17,6 +17,7 @@ import mindustry.gen.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.defense.*; import mindustry.world.blocks.defense.*;
import mindustry.world.blocks.distribution.*;
import mindustry.world.blocks.production.*; import mindustry.world.blocks.production.*;
import mindustry.world.blocks.storage.*; import mindustry.world.blocks.storage.*;
import mindustry.world.blocks.storage.CoreBlock.*; import mindustry.world.blocks.storage.CoreBlock.*;
@@ -54,11 +55,12 @@ public class BaseAI{
public void update(){ public void update(){
if(data.team.rules().aiCoreSpawn && timer.get(timerSpawn, 60 * 2.5f) && data.hasCore()){ if(data.team.rules().aiCoreSpawn && timer.get(timerSpawn, 60 * 2.5f) && data.hasCore()){
CoreBlock block = (CoreBlock)data.core().block; CoreBlock block = (CoreBlock)data.core().block;
int coreUnits = Groups.unit.count(u -> u.team == data.team && u.type == block.unitType);
//create AI core unit //create AI core unit(s)
if(!state.isEditor() && !Groups.unit.contains(u -> u.team() == data.team && u.type == block.unitType)){ if(!state.isEditor() && coreUnits < data.cores.size){
Unit unit = block.unitType.create(data.team); Unit unit = block.unitType.create(data.team);
unit.set(data.core()); unit.set(data.cores.random());
unit.add(); unit.add();
Fx.spawn.at(unit); Fx.spawn.at(unit);
} }
@@ -271,6 +273,10 @@ public class BaseAI{
} }
Tile o = world.tile(tile.x + p.x, tile.y + p.y); Tile o = world.tile(tile.x + p.x, tile.y + p.y);
if(o != null && (o.block() instanceof PayloadAcceptor || o.block() instanceof PayloadConveyor)){
break;
}
if(o != null && o.team() == data.team && !(o.block() instanceof Wall)){ if(o != null && o.team() == data.team && !(o.block() instanceof Wall)){
any = true; any = true;
break; break;

View File

@@ -1,5 +1,6 @@
package mindustry.ai.types; package mindustry.ai.types;
import arc.math.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.entities.*; import mindustry.entities.*;
@@ -45,7 +46,7 @@ public class BuilderAI extends AIController{
BuildPlan req = unit.buildPlan(); BuildPlan req = unit.buildPlan();
boolean valid = boolean valid =
(req.tile().build instanceof ConstructBuild && req.tile().<ConstructBuild>bc().cblock == req.block) || (req.tile() != null && req.tile().build instanceof ConstructBuild && req.tile().<ConstructBuild>bc().cblock == req.block) ||
(req.breaking ? (req.breaking ?
Build.validBreak(unit.team(), req.x, req.y) : Build.validBreak(unit.team(), req.x, req.y) :
Build.validPlace(req.block, unit.team(), req.x, req.y, req.rotation)); Build.validPlace(req.block, unit.team(), req.x, req.y, req.rotation));
@@ -83,8 +84,10 @@ public class BuilderAI extends AIController{
}); });
} }
float rebuildTime = (unit.team.rules().ai ? Mathf.lerp(15f, 2f, unit.team.rules().aiTier) : 2f) * 60f;
//find new request //find new request
if(!unit.team.data().blocks.isEmpty() && following == null && timer.get(timerTarget3, 60 * 2f)){ if(!unit.team.data().blocks.isEmpty() && following == null && timer.get(timerTarget3, rebuildTime)){
Queue<BlockPlan> blocks = unit.team.data().blocks; Queue<BlockPlan> blocks = unit.team.data().blocks;
BlockPlan block = blocks.first(); BlockPlan block = blocks.first();

View File

@@ -67,7 +67,7 @@ public class FormationAI extends AIController implements FormationMember{
if(core != null && leader.mineTile.drop() != null && unit.within(core, unit.type.range) && !unit.acceptsItem(leader.mineTile.drop())){ if(core != null && leader.mineTile.drop() != null && unit.within(core, unit.type.range) && !unit.acceptsItem(leader.mineTile.drop())){
if(core.acceptStack(unit.stack.item, unit.stack.amount, unit) > 0){ if(core.acceptStack(unit.stack.item, unit.stack.amount, unit) > 0){
Call.transferItemTo(unit.stack.item, unit.stack.amount, unit.x, unit.y, core); Call.transferItemTo(unit, unit.stack.item, unit.stack.amount, unit.x, unit.y, core);
unit.clearItem(); unit.clearItem();
} }

View File

@@ -65,7 +65,7 @@ public class MinerAI extends AIController{
if(unit.within(core, unit.type.range)){ if(unit.within(core, unit.type.range)){
if(core.acceptStack(unit.stack.item, unit.stack.amount, unit) > 0){ if(core.acceptStack(unit.stack.item, unit.stack.amount, unit) > 0){
Call.transferItemTo(unit.stack.item, unit.stack.amount, unit.x, unit.y, core); Call.transferItemTo(unit, unit.stack.item, unit.stack.amount, unit.x, unit.y, core);
} }
unit.clearItem(); unit.clearItem();

View File

@@ -14,8 +14,6 @@ import mindustry.world.blocks.*;
import mindustry.world.blocks.campaign.*; import mindustry.world.blocks.campaign.*;
import mindustry.world.blocks.defense.*; import mindustry.world.blocks.defense.*;
import mindustry.world.blocks.defense.turrets.*; import mindustry.world.blocks.defense.turrets.*;
import mindustry.world.blocks.defense.turrets.PointDefenseTurret;
import mindustry.world.blocks.defense.turrets.TractorBeamTurret;
import mindustry.world.blocks.distribution.*; import mindustry.world.blocks.distribution.*;
import mindustry.world.blocks.environment.*; import mindustry.world.blocks.environment.*;
import mindustry.world.blocks.experimental.*; import mindustry.world.blocks.experimental.*;
@@ -39,7 +37,7 @@ public class Blocks implements ContentList{
//environment //environment
air, spawn, cliff, deepwater, water, taintedWater, tar, slag, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, space, air, spawn, cliff, deepwater, water, taintedWater, tar, slag, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater, space,
dacite, stoneWall, dirtWall, sporeWall, iceWall, daciteWall, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster, dacite, stoneWall, dirtWall, sporeWall, iceWall, daciteWall, sporePine, snowPine, pine, shrubs, whiteTree, whiteTreeDead, sporeCluster,
iceSnow, sandWater, darksandWater, duneWall, sandWall, moss, sporeMoss, shale, shaleWall, shaleBoulder, sandBoulder, daciteBoulder, boulder, snowBoulder, grass, salt, iceSnow, sandWater, darksandWater, duneWall, sandWall, moss, sporeMoss, shale, shaleWall, shaleBoulder, sandBoulder, daciteBoulder, boulder, snowBoulder, basaltBoulder, grass, salt,
metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, basalt, magmarock, hotrock, snowWall, saltWall, metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, basalt, magmarock, hotrock, snowWall, saltWall,
darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal, darkPanel1, darkPanel2, darkPanel3, darkPanel4, darkPanel5, darkPanel6, darkMetal,
pebbles, tendrils, pebbles, tendrils,
@@ -363,7 +361,7 @@ public class Blocks implements ContentList{
sandWall = new StaticWall("sand-wall"){{ sandWall = new StaticWall("sand-wall"){{
variants = 2; variants = 2;
sandWater.asFloor().wall = this; sandWater.asFloor().wall = water.asFloor().wall = deepwater.asFloor().wall = this;
}}; }};
saltWall = new StaticWall("salt-wall"); saltWall = new StaticWall("salt-wall");
@@ -415,6 +413,10 @@ public class Blocks implements ContentList{
variants = 2; variants = 2;
}}; }};
basaltBoulder = new Boulder("basalt-boulder"){{
variants = 2;
}};
moss = new Floor("moss"){{ moss = new Floor("moss"){{
variants = 3; variants = 3;
attributes.set(Attribute.spores, 0.15f); attributes.set(Attribute.spores, 0.15f);
@@ -1153,7 +1155,7 @@ public class Blocks implements ContentList{
}}; }};
battery = new Battery("battery"){{ battery = new Battery("battery"){{
requirements(Category.power, with(Items.copper, 4, Items.lead, 20)); requirements(Category.power, with(Items.copper, 5, Items.lead, 20));
consumes.powerBuffered(4000f); consumes.powerBuffered(4000f);
}}; }};
@@ -1191,7 +1193,7 @@ public class Blocks implements ContentList{
size = 2; size = 2;
ambientSound = Sounds.smelter; ambientSound = Sounds.smelter;
ambientSoundVolume = 0.05f; ambientSoundVolume = 0.06f;
}}; }};
differentialGenerator = new SingleTypeGenerator("differential-generator"){{ differentialGenerator = new SingleTypeGenerator("differential-generator"){{
@@ -1212,18 +1214,18 @@ public class Blocks implements ContentList{
requirements(Category.power, with(Items.lead, 100, Items.silicon, 75, Items.phaseFabric, 25, Items.plastanium, 75, Items.thorium, 50)); requirements(Category.power, with(Items.lead, 100, Items.silicon, 75, Items.phaseFabric, 25, Items.plastanium, 75, Items.thorium, 50));
size = 2; size = 2;
powerProduction = 4.5f; powerProduction = 4.5f;
itemDuration = 60 * 15f; itemDuration = 60 * 14f;
}}; }};
solarPanel = new SolarGenerator("solar-panel"){{ solarPanel = new SolarGenerator("solar-panel"){{
requirements(Category.power, with(Items.lead, 10, Items.silicon, 15)); requirements(Category.power, with(Items.lead, 10, Items.silicon, 15));
powerProduction = 0.08f; powerProduction = 0.1f;
}}; }};
largeSolarPanel = new SolarGenerator("solar-panel-large"){{ largeSolarPanel = new SolarGenerator("solar-panel-large"){{
requirements(Category.power, with(Items.lead, 100, Items.silicon, 145, Items.phaseFabric, 15)); requirements(Category.power, with(Items.lead, 80, Items.silicon, 110, Items.phaseFabric, 15));
size = 3; size = 3;
powerProduction = 1f; powerProduction = 1.3f;
}}; }};
thoriumReactor = new NuclearReactor("thorium-reactor"){{ thoriumReactor = new NuclearReactor("thorium-reactor"){{
@@ -1354,7 +1356,7 @@ public class Blocks implements ContentList{
//region storage //region storage
coreShard = new CoreBlock("core-shard"){{ coreShard = new CoreBlock("core-shard"){{
requirements(Category.effect, BuildVisibility.editorOnly, with(Items.copper, 1000, Items.lead, 1000)); requirements(Category.effect, BuildVisibility.editorOnly, with(Items.copper, 1000, Items.lead, 800));
alwaysUnlocked = true; alwaysUnlocked = true;
unitType = UnitTypes.alpha; unitType = UnitTypes.alpha;
@@ -1373,7 +1375,7 @@ public class Blocks implements ContentList{
itemCapacity = 9000; itemCapacity = 9000;
size = 4; size = 4;
unitCapModifier = 14; unitCapModifier = 16;
researchCostMultiplier = 0.04f; researchCostMultiplier = 0.04f;
}}; }};
@@ -1385,8 +1387,8 @@ public class Blocks implements ContentList{
itemCapacity = 13000; itemCapacity = 13000;
size = 5; size = 5;
unitCapModifier = 20; unitCapModifier = 24;
researchCostMultiplier = 0.05f; researchCostMultiplier = 0.06f;
}}; }};
vault = new StorageBlock("vault"){{ vault = new StorageBlock("vault"){{
@@ -1511,14 +1513,14 @@ public class Blocks implements ContentList{
flags = EnumSet.of(BlockFlag.turret, BlockFlag.extinguisher); flags = EnumSet.of(BlockFlag.turret, BlockFlag.extinguisher);
}}; }};
lancer = new ChargeTurret("lancer"){{ lancer = new PowerTurret("lancer"){{
requirements(Category.turret, with(Items.copper, 25, Items.lead, 50, Items.silicon, 45)); requirements(Category.turret, with(Items.copper, 25, Items.lead, 50, Items.silicon, 45));
range = 155f; range = 165f;
chargeTime = 50f; chargeTime = 40f;
chargeMaxDelay = 30f; chargeMaxDelay = 30f;
chargeEffects = 7; chargeEffects = 7;
recoilAmount = 2f; recoilAmount = 2f;
reloadTime = 90f; reloadTime = 80f;
cooldown = 0.03f; cooldown = 0.03f;
powerUse = 6f; powerUse = 6f;
shootShake = 2f; shootShake = 2f;
@@ -1540,6 +1542,7 @@ public class Blocks implements ContentList{
lifetime = 16f; lifetime = 16f;
drawSize = 400f; drawSize = 400f;
collidesAir = false; collidesAir = false;
length = 173f;
}}; }};
}}; }};
@@ -1553,7 +1556,7 @@ public class Blocks implements ContentList{
reloadTime = 35f; reloadTime = 35f;
shootCone = 40f; shootCone = 40f;
rotateSpeed = 8f; rotateSpeed = 8f;
powerUse = 3f; powerUse = 3.3f;
targetAir = false; targetAir = false;
range = 90f; range = 90f;
shootEffect = Fx.lightningShoot; shootEffect = Fx.lightningShoot;

View File

@@ -37,7 +37,7 @@ public class Bullets implements ContentList{
waterShot, cryoShot, slagShot, oilShot, heavyWaterShot, heavyCryoShot, heavySlagShot, heavyOilShot, waterShot, cryoShot, slagShot, oilShot, heavyWaterShot, heavyCryoShot, heavySlagShot, heavyOilShot,
//environment, misc. //environment, misc.
damageLightning, damageLightningGround, fireball, basicFlame, pyraFlame, driverBolt, healBullet, healBulletBig; damageLightning, damageLightningGround, fireball, basicFlame, pyraFlame, driverBolt;
@Override @Override
public void load(){ public void load(){
@@ -374,20 +374,6 @@ public class Bullets implements ContentList{
knockback = 0.7f; knockback = 0.7f;
}}; }};
healBullet = new LaserBoltBulletType(5.2f, 13){{
healPercent = 3f;
collidesTeam = true;
backColor = Pal.heal;
frontColor = Color.white;
}};
healBulletBig = new LaserBoltBulletType(5.2f, 15){{
healPercent = 5.5f;
collidesTeam = true;
backColor = Pal.heal;
frontColor = Color.white;
}};
fireball = new BulletType(1f, 4){ fireball = new BulletType(1f, 4){
{ {
pierce = true; pierce = true;

View File

@@ -72,6 +72,7 @@ public class Items implements ContentList{
}}; }};
surgeAlloy = new Item("surge-alloy", Color.valueOf("f3e979")){{ surgeAlloy = new Item("surge-alloy", Color.valueOf("f3e979")){{
cost = 1.2f;
}}; }};
sporePod = new Item("spore-pod", Color.valueOf("7457ce")){{ sporePod = new Item("spore-pod", Color.valueOf("7457ce")){{

View File

@@ -24,10 +24,11 @@ public class SectorPresets implements ContentList{
saltFlats = new SectorPreset("saltFlats", serpulo, 101){{ saltFlats = new SectorPreset("saltFlats", serpulo, 101){{
difficulty = 5; difficulty = 5;
useAI = false;
}}; }};
frozenForest = new SectorPreset("frozenForest", serpulo, 86){{ frozenForest = new SectorPreset("frozenForest", serpulo, 86){{
captureWave = 20; captureWave = 15;
difficulty = 2; difficulty = 2;
}}; }};
@@ -82,7 +83,7 @@ public class SectorPresets implements ContentList{
}}; }};
desolateRift = new SectorPreset("desolateRift", serpulo, 123){{ desolateRift = new SectorPreset("desolateRift", serpulo, 123){{
captureWave = 30; captureWave = 18;
difficulty = 8; difficulty = 8;
}}; }};

View File

@@ -98,11 +98,11 @@ public class TechTree implements ContentList{
node(platedConduit, () -> { node(platedConduit, () -> {
}); });
});
node(rotaryPump, () -> { node(rotaryPump, () -> {
node(thermalPump, () -> { node(thermalPump, () -> {
});
}); });
}); });
}); });
@@ -121,7 +121,7 @@ public class TechTree implements ContentList{
}); });
node(waterExtractor, () -> { node(waterExtractor, Seq.with(new SectorComplete(saltFlats)), () -> {
node(oilExtractor, () -> { node(oilExtractor, () -> {
}); });
@@ -198,10 +198,10 @@ public class TechTree implements ContentList{
}); });
}); });
}); });
});
node(illuminator, () -> { node(illuminator, () -> {
});
}); });
}); });
@@ -421,8 +421,8 @@ public class TechTree implements ContentList{
}); });
node(additiveReconstructor, Seq.with(new SectorComplete(biomassFacility)), () -> { node(additiveReconstructor, Seq.with(new SectorComplete(biomassFacility)), () -> {
node(multiplicativeReconstructor, Seq.with(new SectorComplete(overgrowth)), () -> { node(multiplicativeReconstructor, () -> {
node(exponentialReconstructor, () -> { node(exponentialReconstructor, Seq.with(new SectorComplete(overgrowth)), () -> {
node(tetrativeReconstructor, () -> { node(tetrativeReconstructor, () -> {
}); });
@@ -471,7 +471,8 @@ public class TechTree implements ContentList{
node(desolateRift, Seq.with( node(desolateRift, Seq.with(
new SectorComplete(impact0078), new SectorComplete(impact0078),
new Research(thermalGenerator), new Research(thermalGenerator),
new Research(thoriumReactor) new Research(thoriumReactor),
new Research(coreNucleus)
), () -> { ), () -> {
node(planetaryTerminal, Seq.with( node(planetaryTerminal, Seq.with(
new SectorComplete(desolateRift), new SectorComplete(desolateRift),
@@ -484,6 +485,7 @@ public class TechTree implements ContentList{
new Research(bryde), new Research(bryde),
new Research(spectre), new Research(spectre),
new Research(launchPad), new Research(launchPad),
new Research(massDriver),
new Research(impactReactor), new Research(impactReactor),
new Research(additiveReconstructor), new Research(additiveReconstructor),
new Research(exponentialReconstructor) new Research(exponentialReconstructor)
@@ -507,10 +509,11 @@ public class TechTree implements ContentList{
node(saltFlats, Seq.with( node(saltFlats, Seq.with(
new SectorComplete(windsweptIslands), new SectorComplete(windsweptIslands),
new Research(commandCenter),
new Research(groundFactory), new Research(groundFactory),
new Research(additiveReconstructor),
new Research(airFactory), new Research(airFactory),
new Research(door), new Research(door)
new Research(waterExtractor)
), () -> { ), () -> {
}); });
@@ -551,7 +554,9 @@ public class TechTree implements ContentList{
node(nuclearComplex, Seq.with( node(nuclearComplex, Seq.with(
new SectorComplete(fungalPass), new SectorComplete(fungalPass),
new Research(thermalGenerator), new Research(thermalGenerator),
new Research(laserDrill) new Research(laserDrill),
new Research(Items.plastanium),
new Research(swarmer)
), () -> { ), () -> {
}); });
@@ -613,7 +618,9 @@ public class TechTree implements ContentList{
}); });
nodeProduce(Liquids.oil, () -> { nodeProduce(Liquids.oil, () -> {
nodeProduce(Items.plastanium, () -> {
});
}); });
}); });
}); });
@@ -641,7 +648,7 @@ public class TechTree implements ContentList{
static TechNode node(UnlockableContent content, ItemStack[] requirements, Seq<Objective> objectives, Runnable children){ static TechNode node(UnlockableContent content, ItemStack[] requirements, Seq<Objective> objectives, Runnable children){
TechNode node = new TechNode(context, content, requirements); TechNode node = new TechNode(context, content, requirements);
if(objectives != null){ if(objectives != null){
node.objectives = objectives; node.objectives.addAll(objectives);
} }
TechNode prev = context; TechNode prev = context;

View File

@@ -292,6 +292,7 @@ public class UnitTypes implements ContentList{
shootSound = Sounds.lasershoot; shootSound = Sounds.lasershoot;
bullet = new LaserBoltBulletType(5.2f, 14){{ bullet = new LaserBoltBulletType(5.2f, 14){{
lifetime = 37f;
healPercent = 5f; healPercent = 5f;
collidesTeam = true; collidesTeam = true;
backColor = Pal.heal; backColor = Pal.heal;
@@ -311,7 +312,7 @@ public class UnitTypes implements ContentList{
mineTier = 2; mineTier = 2;
mineSpeed = 5f; mineSpeed = 5f;
commandLimit = 8; commandLimit = 9;
abilities.add(new ShieldRegenFieldAbility(20f, 40f, 60f * 5, 60f)); abilities.add(new ShieldRegenFieldAbility(20f, 40f, 60f * 5, 60f));
ammoType = AmmoTypes.power; ammoType = AmmoTypes.power;
@@ -556,7 +557,7 @@ public class UnitTypes implements ContentList{
range = 40f; range = 40f;
weapons.add(new Weapon(){{ weapons.add(new Weapon(){{
reload = 12f; reload = 24f;
shootCone = 180f; shootCone = 180f;
ejectEffect = Fx.none; ejectEffect = Fx.none;
shootSound = Sounds.explosion; shootSound = Sounds.explosion;
@@ -619,7 +620,7 @@ public class UnitTypes implements ContentList{
drag = 0.4f; drag = 0.4f;
hitSize = 12f; hitSize = 12f;
rotateSpeed = 3f; rotateSpeed = 3f;
health = 800; health = 900;
immunities = ObjectSet.with(StatusEffects.burning, StatusEffects.melting); immunities = ObjectSet.with(StatusEffects.burning, StatusEffects.melting);
legCount = 6; legCount = 6;
legLength = 13f; legLength = 13f;
@@ -650,7 +651,7 @@ public class UnitTypes implements ContentList{
bullet = new SapBulletType(){{ bullet = new SapBulletType(){{
sapStrength = 0.4f; sapStrength = 0.4f;
length = 75f; length = 75f;
damage = 18; damage = 20;
shootEffect = Fx.shootSmall; shootEffect = Fx.shootSmall;
hitColor = color = Color.valueOf("bf92f9"); hitColor = color = Color.valueOf("bf92f9");
despawnEffect = Fx.none; despawnEffect = Fx.none;
@@ -670,7 +671,7 @@ public class UnitTypes implements ContentList{
bullet = new SapBulletType(){{ bullet = new SapBulletType(){{
sapStrength = 0.8f; sapStrength = 0.8f;
length = 40f; length = 40f;
damage = 15; damage = 16;
shootEffect = Fx.shootSmall; shootEffect = Fx.shootSmall;
hitColor = color = Color.valueOf("bf92f9"); hitColor = color = Color.valueOf("bf92f9");
despawnEffect = Fx.none; despawnEffect = Fx.none;
@@ -975,7 +976,7 @@ public class UnitTypes implements ContentList{
zenith = new UnitType("zenith"){{ zenith = new UnitType("zenith"){{
health = 700; health = 700;
speed = 1.7f; speed = 1.8f;
accel = 0.04f; accel = 0.04f;
drag = 0.016f; drag = 0.016f;
flying = true; flying = true;
@@ -997,7 +998,7 @@ public class UnitTypes implements ContentList{
velocityRnd = 0.2f; velocityRnd = 0.2f;
shootSound = Sounds.missile; shootSound = Sounds.missile;
bullet = new MissileBulletType(3f, 12){{ bullet = new MissileBulletType(3f, 14){{
width = 8f; width = 8f;
height = 8f; height = 8f;
shrinkY = 0f; shrinkY = 0f;
@@ -1005,7 +1006,7 @@ public class UnitTypes implements ContentList{
homingRange = 60f; homingRange = 60f;
keepVelocity = false; keepVelocity = false;
splashDamageRadius = 25f; splashDamageRadius = 25f;
splashDamage = 10f; splashDamage = 14f;
lifetime = 60f; lifetime = 60f;
trailColor = Pal.unitBack; trailColor = Pal.unitBack;
backColor = Pal.unitBack; backColor = Pal.unitBack;
@@ -1251,8 +1252,8 @@ public class UnitTypes implements ContentList{
mineTier = 3; mineTier = 3;
mineSpeed = 4f; mineSpeed = 4f;
health = 500; health = 460;
armor = 5f; armor = 3f;
speed = 2.5f; speed = 2.5f;
accel = 0.06f; accel = 0.06f;
drag = 0.017f; drag = 0.017f;
@@ -1264,6 +1265,7 @@ public class UnitTypes implements ContentList{
engineSize = 3f; engineSize = 3f;
payloadCapacity = (2 * 2) * tilePayload; payloadCapacity = (2 * 2) * tilePayload;
buildSpeed = 2.6f; buildSpeed = 2.6f;
isCounted = false;
ammoType = AmmoTypes.power; ammoType = AmmoTypes.power;
@@ -1274,7 +1276,13 @@ public class UnitTypes implements ContentList{
x = 8f; x = 8f;
y = -6f; y = -6f;
rotate = true; rotate = true;
bullet = Bullets.healBulletBig; bullet = new LaserBoltBulletType(5.2f, 10){{
lifetime = 35f;
healPercent = 5.5f;
collidesTeam = true;
backColor = Pal.heal;
frontColor = Color.white;
}};
}}, }},
new Weapon("heal-weapon-mount"){{ new Weapon("heal-weapon-mount"){{
shootSound = Sounds.lasershoot; shootSound = Sounds.lasershoot;
@@ -1282,7 +1290,13 @@ public class UnitTypes implements ContentList{
x = 4f; x = 4f;
y = 5f; y = 5f;
rotate = true; rotate = true;
bullet = Bullets.healBullet; bullet = new LaserBoltBulletType(5.2f, 8){{
lifetime = 35f;
healPercent = 3f;
collidesTeam = true;
backColor = Pal.heal;
frontColor = Color.white;
}};
}}); }});
}}; }};
@@ -1321,7 +1335,7 @@ public class UnitTypes implements ContentList{
sprite = "large-bomb"; sprite = "large-bomb";
width = height = 120/4f; width = height = 120/4f;
range = 30f; maxRange = 30f;
ignoreRotation = true; ignoreRotation = true;
backColor = Pal.heal; backColor = Pal.heal;
@@ -1349,7 +1363,7 @@ public class UnitTypes implements ContentList{
collides = false; collides = false;
healPercent = 15f; healPercent = 15f;
splashDamage = 240f; splashDamage = 230f;
splashDamageRadius = 120f; splashDamageRadius = 120f;
}}; }};
}}); }});
@@ -1413,12 +1427,12 @@ public class UnitTypes implements ContentList{
ejectEffect = Fx.casing1; ejectEffect = Fx.casing1;
shootSound = Sounds.missile; shootSound = Sounds.missile;
bullet = new MissileBulletType(2.7f, 12, "missile"){{ bullet = new MissileBulletType(2.7f, 12, "missile"){{
keepVelocity = true;
width = 8f; width = 8f;
height = 8f; height = 8f;
shrinkY = 0f; shrinkY = 0f;
drag = -0.003f; drag = -0.003f;
homingRange = 60f; homingRange = 60f;
keepVelocity = false;
splashDamageRadius = 25f; splashDamageRadius = 25f;
splashDamage = 10f; splashDamage = 10f;
lifetime = 80f; lifetime = 80f;

View File

@@ -53,10 +53,11 @@ public class Weathers implements ContentList{
baseSpeed = 5.4f; baseSpeed = 5.4f;
attrs.set(Attribute.light, -0.1f); attrs.set(Attribute.light, -0.1f);
attrs.set(Attribute.water, -0.1f); attrs.set(Attribute.water, -0.1f);
opacityMultiplier = 0.5f; opacityMultiplier = 0.35f;
force = 0.1f; force = 0.1f;
sound = Sounds.wind; sound = Sounds.wind;
soundVol = 0.3f; soundVol = 0.8f;
duration = 7f * Time.toMinutes;
}}; }};
sporestorm = new ParticleWeather("sporestorm"){{ sporestorm = new ParticleWeather("sporestorm"){{
@@ -77,7 +78,8 @@ public class Weathers implements ContentList{
opacityMultiplier = 0.75f; opacityMultiplier = 0.75f;
force = 0.1f; force = 0.1f;
sound = Sounds.wind; sound = Sounds.wind;
soundVol = 0.3f; soundVol = 0.7f;
duration = 7f * Time.toMinutes;
}}; }};
fog = new ParticleWeather("fog"){{ fog = new ParticleWeather("fog"){{

View File

@@ -6,6 +6,7 @@ import arc.audio.*;
import arc.graphics.g2d.*; import arc.graphics.g2d.*;
import arc.input.*; import arc.input.*;
import arc.math.*; import arc.math.*;
import arc.scene.style.*;
import arc.scene.ui.*; import arc.scene.ui.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
@@ -16,14 +17,17 @@ import mindustry.core.GameState.*;
import mindustry.entities.*; import mindustry.entities.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.game.*; import mindustry.game.*;
import mindustry.game.Objectives.*;
import mindustry.game.Saves.*; import mindustry.game.Saves.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.input.*; import mindustry.input.*;
import mindustry.io.*; import mindustry.io.*;
import mindustry.io.SaveIO.*; import mindustry.io.SaveIO.*;
import mindustry.maps.*;
import mindustry.maps.Map; import mindustry.maps.Map;
import mindustry.net.*; import mindustry.net.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.ui.*;
import mindustry.ui.dialogs.*; import mindustry.ui.dialogs.*;
import mindustry.world.*; import mindustry.world.*;
@@ -124,10 +128,18 @@ public class Control implements ApplicationListener, Loadable{
} }
})); }));
Events.on(UnlockEvent.class, e -> ui.hudfrag.showUnlock(e.content));
Events.on(UnlockEvent.class, e -> { Events.on(UnlockEvent.class, e -> {
ui.hudfrag.showUnlock(e.content);
checkAutoUnlocks(); checkAutoUnlocks();
if(e.content instanceof SectorPreset){
for(TechNode node : TechTree.all){
if(!node.content.unlocked() && node.objectives.contains(o -> o instanceof SectorComplete sec && sec.preset == e.content) && !node.objectives.contains(o -> !o.complete())){
ui.hudfrag.showToast(new TextureRegionDrawable(node.content.icon(Cicon.large)), bundle.get("available"));
}
}
}
}); });
Events.on(SectorCaptureEvent.class, e -> { Events.on(SectorCaptureEvent.class, e -> {
@@ -223,7 +235,7 @@ public class Control implements ApplicationListener, Loadable{
for(TechNode node : TechTree.all){ for(TechNode node : TechTree.all){
if(!node.content.unlocked() && node.requirements.length == 0 && !node.objectives.contains(o -> !o.complete())){ if(!node.content.unlocked() && node.requirements.length == 0 && !node.objectives.contains(o -> !o.complete())){
node.content.unlocked(); node.content.unlock();
} }
} }
} }
@@ -311,17 +323,45 @@ public class Control implements ApplicationListener, Loadable{
return; return;
} }
//set spawn for sector damage to use
Tile spawn = world.tile(sector.info.spawnPosition);
spawn.setBlock(Blocks.coreShard, state.rules.defaultTeam);
//add extra damage.
SectorDamage.apply(1f);
//reset wave so things are more fair //reset wave so things are more fair
state.wave = 1; state.wave = 1;
//set up default wave time
state.wavetime = state.rules.waveSpacing * 2f;
//reset captured state
sector.info.wasCaptured = false;
//re-enable waves
state.rules.waves = true;
//reset win wave?? //reset win wave??
state.rules.winWave = state.rules.attackMode ? -1 : sector.preset != null ? sector.preset.captureWave : 40; state.rules.winWave = state.rules.attackMode ? -1 : sector.preset != null ? sector.preset.captureWave : 40;
//if there's still an enemy base left, fix it
if(state.rules.attackMode){
//replace all broken blocks
for(var plan : state.rules.waveTeam.data().blocks){
Tile tile = world.tile(plan.x, plan.y);
if(tile != null){
tile.setBlock(content.block(plan.block), state.rules.waveTeam, plan.rotation);
if(plan.config != null && tile.build != null){
tile.build.configure(plan.config);
}
}
}
state.rules.waveTeam.data().blocks.clear();
}
//kill all units, since they should be dead anyway //kill all units, since they should be dead anyway
Groups.unit.clear(); Groups.unit.clear();
Groups.fire.clear(); Groups.fire.clear();
Groups.puddle.clear();
Tile spawn = world.tile(sector.info.spawnPosition);
Schematics.placeLaunchLoadout(spawn.x, spawn.y); Schematics.placeLaunchLoadout(spawn.x, spawn.y);
//set up camera/player locations //set up camera/player locations

View File

@@ -33,9 +33,8 @@ public class GameState{
/** Current game state. */ /** Current game state. */
private State state = State.menu; private State state = State.menu;
//TODO optimize
public Unit boss(){ public Unit boss(){
return Groups.unit.find(u -> u.isBoss() && u.team == rules.waveTeam); return teams.boss;
} }
public void set(State astate){ public void set(State astate){

View File

@@ -107,8 +107,15 @@ public class Logic implements ApplicationListener{
if(!(state.getSector().preset != null && !state.getSector().preset.useAI)){ if(!(state.getSector().preset != null && !state.getSector().preset.useAI)){
state.rules.waveTeam.rules().ai = true; state.rules.waveTeam.rules().ai = true;
} }
state.rules.waveTeam.rules().aiTier = state.getSector().threat; state.rules.waveTeam.rules().aiTier = state.getSector().threat * 0.8f;
state.rules.waveTeam.rules().infiniteResources = true; state.rules.waveTeam.rules().infiniteResources = true;
//fill enemy cores by default.
for(var core : state.rules.waveTeam.cores()){
for(Item item : content.items()){
core.items.set(item, core.block.itemCapacity);
}
}
} }
//save settings //save settings
@@ -260,6 +267,8 @@ public class Logic implements ApplicationListener{
if(state.rules.sector == null) return; if(state.rules.sector == null) return;
state.rules.sector.info.wasCaptured = true;
//fire capture event //fire capture event
Events.fire(new SectorCaptureEvent(state.rules.sector)); Events.fire(new SectorCaptureEvent(state.rules.sector));

View File

@@ -41,7 +41,7 @@ public class NetClient implements ApplicationListener{
private boolean connecting = false; private boolean connecting = false;
/** If true, no message will be shown on disconnect. */ /** If true, no message will be shown on disconnect. */
private boolean quiet = false; private boolean quiet = false;
/** Whether to supress disconnect events completely.*/ /** Whether to suppress disconnect events completely.*/
private boolean quietReset = false; private boolean quietReset = false;
/** Counter for data timeout. */ /** Counter for data timeout. */
private float timeoutTime = 0f; private float timeoutTime = 0f;
@@ -258,6 +258,11 @@ public class NetClient implements ApplicationListener{
netClient.disconnectQuietly(); netClient.disconnectQuietly();
logic.reset(); logic.reset();
if(reason == KickReason.serverRestarting){
ui.join.reconnect();
return;
}
if(!reason.quiet){ if(!reason.quiet){
if(reason.extraText() != null){ if(reason.extraText() != null){
ui.showText(reason.toString(), reason.extraText()); ui.showText(reason.toString(), reason.extraText());

View File

@@ -422,7 +422,7 @@ public class NetServer implements ApplicationListener{
currentlyKicking[0] = session; currentlyKicking[0] = session;
} }
}else{ }else{
player.sendMessage("[scarlet]No player[orange]'" + args[0] + "'[scarlet] found."); player.sendMessage("[scarlet]No player [orange]'" + args[0] + "'[scarlet] found.");
} }
} }
}); });
@@ -447,6 +447,11 @@ public class NetServer implements ApplicationListener{
return; return;
} }
if(currentlyKicking[0].target.team() != player.team()){
player.sendMessage("[scarlet]You can't vote for other teams.");
return;
}
if(!arg[0].toLowerCase().equals("y") && !arg[0].toLowerCase().equals("n")){ if(!arg[0].toLowerCase().equals("y") && !arg[0].toLowerCase().equals("n")){
player.sendMessage("[scarlet]Vote either 'y' (yes) or 'n' (no)."); player.sendMessage("[scarlet]Vote either 'y' (yes) or 'n' (no).");
return; return;

View File

@@ -311,7 +311,7 @@ public class World{
//TODO bad code //TODO bad code
boolean hasSnow = floors[0].name.contains("ice") || floors[0].name.contains("snow"); boolean hasSnow = floors[0].name.contains("ice") || floors[0].name.contains("snow");
boolean hasRain = !hasSnow && content.contains(Liquids.water) && !floors[0].name.contains("sand"); boolean hasRain = !hasSnow && content.contains(Liquids.water) && !floors[0].name.contains("sand");
boolean hasDesert = !hasSnow && !hasRain && floors[0].name.contains("sand"); boolean hasDesert = !hasSnow && !hasRain && floors[0] == Blocks.sand;
boolean hasSpores = floors[0].name.contains("spore") || floors[0].name.contains("moss") || floors[0].name.contains("tainted"); boolean hasSpores = floors[0].name.contains("spore") || floors[0].name.contains("moss") || floors[0].name.contains("tainted");
if(hasSnow){ if(hasSnow){

View File

@@ -31,7 +31,7 @@ public abstract class Content implements Comparable<Content>, Disposable{
*/ */
public void load(){} public void load(){}
/** @return whether an error ocurred during mod loading. */ /** @return whether an error occurred during mod loading. */
public boolean hasErrored(){ public boolean hasErrored(){
return minfo.error != null; return minfo.error != null;
} }

View File

@@ -110,7 +110,7 @@ public abstract class UnlockableContent extends MappableContent{
/** Makes this piece of content unlocked; if it already unlocked, nothing happens. */ /** Makes this piece of content unlocked; if it already unlocked, nothing happens. */
public void unlock(){ public void unlock(){
if(!unlocked()){ if(!net.client() && !unlocked()){
unlocked = true; unlocked = true;
Core.settings.put(name + "-unlocked", true); Core.settings.put(name + "-unlocked", true);

View File

@@ -17,7 +17,7 @@ import mindustry.ui.*;
public class WaveGraph extends Table{ public class WaveGraph extends Table{
public Seq<SpawnGroup> groups = new Seq<>(); public Seq<SpawnGroup> groups = new Seq<>();
public int from, to = 20; public int from = 0, to = 20;
private Mode mode = Mode.counts; private Mode mode = Mode.counts;
private int[][] values; private int[][] values;
@@ -114,7 +114,7 @@ public class WaveGraph extends Table{
Lines.line(cx, cy, cx, cy + len); Lines.line(cx, cy, cx, cy + len);
if(i == values.length/2){ if(i == values.length/2){
font.draw("" + (i + from), cx, cy - 2f, Align.center); font.draw("" + (i + from + 1), cx, cy - 2f, Align.center);
} }
} }
font.setColor(Color.white); font.setColor(Color.white);

View File

@@ -2,7 +2,6 @@ package mindustry.entities;
import arc.*; import arc.*;
import arc.func.*; import arc.func.*;
import arc.graphics.*;
import arc.math.*; import arc.math.*;
import arc.math.geom.*; import arc.math.geom.*;
import arc.struct.*; import arc.struct.*;
@@ -33,15 +32,22 @@ public class Damage{
private static Unit tmpUnit; private static Unit tmpUnit;
/** Creates a dynamic explosion based on specified parameters. */ /** Creates a dynamic explosion based on specified parameters. */
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, Color color, boolean damage){ public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, boolean damage){
dynamicExplosion(x, y, flammability, explosiveness, power, radius, damage, true, null);
}
/** Creates a dynamic explosion based on specified parameters. */
public static void dynamicExplosion(float x, float y, float flammability, float explosiveness, float power, float radius, boolean damage, boolean fire, @Nullable Team ignoreTeam){
if(damage){ if(damage){
for(int i = 0; i < Mathf.clamp(power / 20, 0, 6); i++){ for(int i = 0; i < Mathf.clamp(power / 20, 0, 6); i++){
int branches = 5 + Mathf.clamp((int)(power / 30), 1, 20); int branches = 5 + Mathf.clamp((int)(power / 30), 1, 20);
Time.run(i * 2f + Mathf.random(4f), () -> Lightning.create(Team.derelict, Pal.power, 3, x, y, Mathf.random(360f), branches + Mathf.range(2))); Time.run(i * 2f + Mathf.random(4f), () -> Lightning.create(Team.derelict, Pal.power, 3, x, y, Mathf.random(360f), branches + Mathf.range(2)));
} }
for(int i = 0; i < Mathf.clamp(flammability / 4, 0, 30); i++){ if(fire){
Time.run(i / 2f, () -> Call.createBullet(Bullets.fireball, Team.derelict, x, y, Mathf.random(360f), Bullets.fireball.damage, 1, 1)); for(int i = 0; i < Mathf.clamp(flammability / 4, 0, 30); i++){
Time.run(i / 2f, () -> Call.createBullet(Bullets.fireball, Team.derelict, x, y, Mathf.random(360f), Bullets.fireball.damage, 1, 1));
}
} }
int waves = Mathf.clamp((int)(explosiveness / 4), 0, 30); int waves = Mathf.clamp((int)(explosiveness / 4), 0, 30);
@@ -49,7 +55,7 @@ public class Damage{
for(int i = 0; i < waves; i++){ for(int i = 0; i < waves; i++){
int f = i; int f = i;
Time.run(i * 2f, () -> { Time.run(i * 2f, () -> {
Damage.damage(x, y, Mathf.clamp(radius + explosiveness, 0, 50f) * ((f + 1f) / waves), explosiveness / 2f); Damage.damage(ignoreTeam, x, y, Mathf.clamp(radius + explosiveness, 0, 50f) * ((f + 1f) / waves), explosiveness / 2f, false);
Fx.blockExplosionSmoke.at(x + Mathf.range(radius), y + Mathf.range(radius)); Fx.blockExplosionSmoke.at(x + Mathf.range(radius), y + Mathf.range(radius));
}); });
} }

View File

@@ -12,5 +12,6 @@ class GroupDefs<G>{
@GroupDef(value = Syncc.class, mapping = true) G sync; @GroupDef(value = Syncc.class, mapping = true) G sync;
@GroupDef(value = Drawc.class) G draw; @GroupDef(value = Drawc.class) G draw;
@GroupDef(value = Firec.class) G fire; @GroupDef(value = Firec.class) G fire;
@GroupDef(value = Puddlec.class) G puddle;
@GroupDef(value = WeatherStatec.class) G weather; @GroupDef(value = WeatherStatec.class) G weather;
} }

View File

@@ -78,7 +78,7 @@ public abstract class BulletType extends Content{
* Do not change unless you know what you're doing. */ * Do not change unless you know what you're doing. */
public boolean backMove = true; public boolean backMove = true;
/** Bullet range override. */ /** Bullet range override. */
public float range = -1f; public float maxRange = -1f;
/** % of block health healed **/ /** % of block health healed **/
public float healPercent = 0f; public float healPercent = 0f;
/** whether to make fire on impact */ /** whether to make fire on impact */
@@ -154,7 +154,7 @@ public abstract class BulletType extends Content{
/** Returns maximum distance the bullet this bullet type has can travel. */ /** Returns maximum distance the bullet this bullet type has can travel. */
public float range(){ public float range(){
return Math.max(speed * lifetime * (1f - drag), range); return Math.max(speed * lifetime * (1f - drag), maxRange);
} }
public boolean collides(Bullet bullet, Building tile){ public boolean collides(Bullet bullet, Building tile){
@@ -317,11 +317,11 @@ public abstract class BulletType extends Content{
} }
public Bullet create(Bullet parent, float x, float y, float angle){ public Bullet create(Bullet parent, float x, float y, float angle){
return create(parent.owner(), parent.team, x, y, angle); return create(parent.owner, parent.team, x, y, angle);
} }
public Bullet create(Bullet parent, float x, float y, float angle, float velocityScl, float lifeScale){ public Bullet create(Bullet parent, float x, float y, float angle, float velocityScl, float lifeScale){
return create(parent.owner(), parent.team, x, y, angle, velocityScl, lifeScale); return create(parent.owner, parent.team, x, y, angle, velocityScl, lifeScale);
} }
public Bullet create(Bullet parent, float x, float y, float angle, float velocityScl){ public Bullet create(Bullet parent, float x, float y, float angle, float velocityScl){

View File

@@ -61,7 +61,7 @@ public class SapBulletType extends BulletType{
b.data = target; b.data = target;
if(target != null){ if(target != null){
float result = Math.min(target.health(), damage); float result = Math.max(Math.min(target.health(), damage), 0);
if(b.owner instanceof Healthc h){ if(b.owner instanceof Healthc h){
h.heal(result * sapStrength); h.heal(result * sapStrength);

View File

@@ -139,7 +139,7 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{
boolean shouldSkip(BuildPlan request, @Nullable Building core){ boolean shouldSkip(BuildPlan request, @Nullable Building core){
//requests that you have at least *started* are considered //requests that you have at least *started* are considered
if(state.rules.infiniteResources || team().rules().infiniteResources || request.breaking || core == null) return false; if(state.rules.infiniteResources || team().rules().infiniteResources || request.breaking || core == null) return false;
return (request.stuck && !core.items.has(request.block.requirements)) || (Structs.contains(request.block.requirements, i -> !core.items.has(i.item)) && !request.initialized); return (request.stuck && !core.items.has(request.block.requirements)) || (Structs.contains(request.block.requirements, i -> !core.items.has(i.item) && Mathf.round(i.amount * state.rules.buildCostMultiplier) > 0) && !request.initialized);
} }
void removeBuild(int x, int y, boolean breaking){ void removeBuild(int x, int y, boolean breaking){

View File

@@ -435,7 +435,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
} }
/** Handle a stack input. */ /** Handle a stack input. */
public void handleStack(Item item, int amount, Teamc source){ public void handleStack(Item item, int amount, @Nullable Teamc source){
noSleep(); noSleep();
items.add(item, amount); items.add(item, amount);
} }
@@ -519,6 +519,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
public void dumpLiquid(Liquid liquid){ public void dumpLiquid(Liquid liquid){
int dump = this.cdump; int dump = this.cdump;
if(liquids.get(liquid) <= 0.0001f) return;
if(!net.client() && state.isCampaign() && team == state.rules.defaultTeam) liquid.unlock(); if(!net.client() && state.isCampaign() && team == state.rules.defaultTeam) liquid.unlock();
for(int i = 0; i < proximity.size; i++){ for(int i = 0; i < proximity.size; i++){
@@ -970,34 +972,13 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
}); });
} }
Damage.dynamicExplosion(x, y, flammability, explosiveness * 3.5f, power, tilesize * block.size / 2f, Pal.darkFlame, state.rules.damageExplosions); Damage.dynamicExplosion(x, y, flammability, explosiveness * 3.5f, power, tilesize * block.size / 2f, state.rules.damageExplosions);
if(!floor().solid && !floor().isLiquid){ if(!floor().solid && !floor().isLiquid){
Effect.rubble(x, y, block.size); Effect.rubble(x, y, block.size);
} }
} }
/**
* Returns the flammability of the Used for fire calculations.
* Takes flammability of floor liquid into account.
*/
public float getFlammability(){
if(!block.hasItems){
if(floor().isLiquid && !block.solid){
return floor().liquidDrop.flammability;
}
return 0;
}else{
float result = items.sum((item, amount) -> item.flammability * amount);
if(block.hasLiquids){
result += liquids.sum((liquid, amount) -> liquid.flammability * amount / 3f);
}
return result;
}
}
public String getDisplayName(){ public String getDisplayName(){
return block.localizedName; return block.localizedName;
} }

View File

@@ -26,7 +26,7 @@ abstract class FireComp implements Timedc, Posc, Firec, Syncc{
@Override @Override
public void update(){ public void update(){
if(Mathf.chance(0.1 * Time.delta)){ if(Mathf.chance(0.09 * Time.delta)){
Fx.fire.at(x + Mathf.range(4f), y + Mathf.range(4f)); Fx.fire.at(x + Mathf.range(4f), y + Mathf.range(4f));
} }
@@ -59,7 +59,7 @@ abstract class FireComp implements Timedc, Posc, Firec, Syncc{
} }
if(baseFlammability < 0 || block != tile.block()){ if(baseFlammability < 0 || block != tile.block()){
baseFlammability = tile.build == null ? 0 : tile.build.getFlammability(); baseFlammability = tile.build == null ? 0 : tile.getFlammability();
block = tile.block(); block = tile.block();
} }
@@ -77,12 +77,12 @@ abstract class FireComp implements Timedc, Posc, Firec, Syncc{
} }
} }
if(Mathf.chance(0.1 * Time.delta)){ if(Mathf.chance(0.025 * Time.delta)){
Puddlec p = Puddles.get(tile); Puddlec p = Puddles.get(tile);
puddleFlammability = p != null ? p.getFlammability() / 3f : 0; puddleFlammability = p != null ? p.getFlammability() / 3f : 0;
if(damage){ if(damage){
entity.damage(0.4f); entity.damage(1.6f);
} }
Damage.damageUnits(null, tile.worldx(), tile.worldy(), tilesize, 3f, Damage.damageUnits(null, tile.worldx(), tile.worldy(), tilesize, 3f,
unit -> !unit.isFlying() && !unit.isImmune(StatusEffects.burning), unit -> !unit.isFlying() && !unit.isImmune(StatusEffects.burning),

View File

@@ -46,8 +46,8 @@ abstract class FlyingComp implements Posc, Velc, Healthc, Hitboxc{
} }
void wobble(){ void wobble(){
x += Mathf.sin(Time.time() + id() * 99, 25f, 0.05f) * Time.delta * elevation; x += Mathf.sin(Time.time() + (id() % 10) * 12, 25f, 0.05f) * Time.delta * elevation;
y += Mathf.cos(Time.time() + id() * 99, 25f, 0.05f) * Time.delta * elevation; y += Mathf.cos(Time.time() + (id() % 10) * 12, 25f, 0.05f) * Time.delta * elevation;
} }
void moveAt(Vec2 vector, float acceleration){ void moveAt(Vec2 vector, float acceleration){

View File

@@ -55,7 +55,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc{
if(core != null && mineTile != null && mineTile.drop() != null && !acceptsItem(mineTile.drop()) && within(core, mineTransferRange) && !offloadImmediately()){ if(core != null && mineTile != null && mineTile.drop() != null && !acceptsItem(mineTile.drop()) && within(core, mineTransferRange) && !offloadImmediately()){
int accepted = core.acceptStack(item(), stack().amount, this); int accepted = core.acceptStack(item(), stack().amount, this);
if(accepted > 0){ if(accepted > 0){
Call.transferItemTo(item(), accepted, Call.transferItemTo(self(), item(), accepted,
mineTile.worldx() + Mathf.range(tilesize / 2f), mineTile.worldx() + Mathf.range(tilesize / 2f),
mineTile.worldy() + Mathf.range(tilesize / 2f), core); mineTile.worldy() + Mathf.range(tilesize / 2f), core);
clearItem(); clearItem();
@@ -77,7 +77,7 @@ abstract class MinerComp implements Itemsc, Posc, Teamc, Rotc, Drawc{
mineTimer = 0; mineTimer = 0;
if(core != null && within(core, mineTransferRange) && core.acceptStack(item, 1, this) == 1 && offloadImmediately()){ if(core != null && within(core, mineTransferRange) && core.acceptStack(item, 1, this) == 1 && offloadImmediately()){
Call.transferItemTo(item, 1, Call.transferItemTo(self(), item, 1,
mineTile.worldx() + Mathf.range(tilesize / 2f), mineTile.worldx() + Mathf.range(tilesize / 2f),
mineTile.worldy() + Mathf.range(tilesize / 2f), core); mineTile.worldy() + Mathf.range(tilesize / 2f), core);
}else if(acceptsItem(item)){ }else if(acceptsItem(item)){

View File

@@ -397,9 +397,12 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
/** Actually destroys the unit, removing it and creating explosions. **/ /** Actually destroys the unit, removing it and creating explosions. **/
public void destroy(){ public void destroy(){
float explosiveness = 2f + item().explosiveness * stack().amount / 2f; float explosiveness = 2f + item().explosiveness * stack().amount * 1.53f;
float flammability = item().flammability * stack().amount / 2f; float flammability = item().flammability * stack().amount / 1.9f;
Damage.dynamicExplosion(x, y, flammability, explosiveness, 0f, bounds() / 2f, Pal.darkFlame, state.rules.damageExplosions);
if(!spawnedByCore){
Damage.dynamicExplosion(x, y, flammability, explosiveness, 0f, bounds() / 2f, state.rules.damageExplosions, item().flammability > 1, team);
}
float shake = hitSize / 3f; float shake = hitSize / 3f;
@@ -415,7 +418,7 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
} }
//if this unit crash landed (was flying), damage stuff in a radius //if this unit crash landed (was flying), damage stuff in a radius
if(type.flying){ if(type.flying && !spawnedByCore){
Damage.damage(team,x, y, Mathf.pow(hitSize, 0.94f) * 1.25f, Mathf.pow(hitSize, 0.75f) * type.crashDamageMultiplier * 5f, true, false, true); Damage.damage(team,x, y, Mathf.pow(hitSize, 0.94f) * 1.25f, Mathf.pow(hitSize, 0.75f) * type.crashDamageMultiplier * 5f, true, false, true);
} }

View File

@@ -91,6 +91,10 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{
mount.bullet.time = mount.bullet.lifetime - 10f; mount.bullet.time = mount.bullet.lifetime - 10f;
mount.bullet = null; mount.bullet = null;
} }
if(mount.sound != null){
mount.sound.stop();
}
} }
} }

View File

@@ -18,6 +18,7 @@ public class EventType{
impactPower, impactPower,
thoriumReactorOverheat, thoriumReactorOverheat,
fireExtinguish, fireExtinguish,
acceleratorUse,
newGame, newGame,
tutorialComplete, tutorialComplete,
flameAmmo, flameAmmo,

View File

@@ -48,7 +48,8 @@ public class Objectives{
} }
} }
public static class SectorComplete extends SectorObjective{ public static class SectorComplete implements Objective{
public SectorPreset preset;
public SectorComplete(SectorPreset zone){ public SectorComplete(SectorPreset zone){
this.preset = zone; this.preset = zone;
@@ -58,7 +59,7 @@ public class Objectives{
@Override @Override
public boolean complete(){ public boolean complete(){
return preset.sector.save != null && !preset.sector.isAttacked() && preset.sector.hasBase(); return preset.sector.save != null && (!preset.sector.isAttacked() || preset.sector.info.wasCaptured) && preset.sector.hasBase();
} }
@Override @Override
@@ -67,11 +68,6 @@ public class Objectives{
} }
} }
//TODO merge
public abstract static class SectorObjective implements Objective{
public SectorPreset preset;
}
/** Defines a specific objective for a game. */ /** Defines a specific objective for a game. */
public interface Objective{ public interface Objective{
@@ -86,9 +82,5 @@ public class Objectives{
default void build(Table table){ default void build(Table table){
} }
default SectorPreset zone(){
return this instanceof SectorObjective ? ((SectorObjective)this).preset : null;
}
} }
} }

View File

@@ -127,6 +127,9 @@ public class Schematics implements Loadable{
newSchematic.tags.putAll(target.tags); newSchematic.tags.putAll(target.tags);
newSchematic.file = target.file; newSchematic.file = target.file;
loadouts.each((block, list) -> list.remove(target));
checkLoadout(target, true);
try{ try{
write(newSchematic, target.file); write(newSchematic, target.file);
}catch(Exception e){ }catch(Exception e){
@@ -134,6 +137,8 @@ public class Schematics implements Loadable{
Log.err(e); Log.err(e);
ui.showException(e); ui.showException(e);
} }
} }
private @Nullable Schematic loadFile(Fi file){ private @Nullable Schematic loadFile(Fi file){

View File

@@ -33,6 +33,8 @@ public class SectorInfo{
public int storageCapacity = 0; public int storageCapacity = 0;
/** Whether a core is available here. */ /** Whether a core is available here. */
public boolean hasCore = true; public boolean hasCore = true;
/** Whether this sector was ever fully captured. */
public boolean wasCaptured = false;
/** Sector that was launched from. */ /** Sector that was launched from. */
public @Nullable Sector origin; public @Nullable Sector origin;
/** Launch destination. */ /** Launch destination. */
@@ -69,7 +71,9 @@ public class SectorInfo{
public boolean shown = false; public boolean shown = false;
/** Special variables for simulation. */ /** Special variables for simulation. */
public float sumHealth, sumRps, sumDps, waveHealthBase, waveHealthSlope, waveDpsBase, waveDpsSlope; public float sumHealth, sumRps, sumDps, waveHealthBase, waveHealthSlope, waveDpsBase, waveDpsSlope, bossHealth, bossDps;
/** Wave where first boss shows up. */
public int bossWave = -1;
/** Counter refresh state. */ /** Counter refresh state. */
private transient Interval time = new Interval(); private transient Interval time = new Interval();

View File

@@ -26,6 +26,8 @@ public class Teams{
public Seq<TeamData> active = new Seq<>(); public Seq<TeamData> active = new Seq<>();
/** Teams with block or unit presence. */ /** Teams with block or unit presence. */
public Seq<TeamData> present = new Seq<>(TeamData.class); public Seq<TeamData> present = new Seq<>(TeamData.class);
/** Current boss unit. */
public @Nullable Unit boss;
public Teams(){ public Teams(){
active.add(get(Team.crux)); active.add(get(Team.crux));
@@ -144,6 +146,7 @@ public class Teams{
public void updateTeamStats(){ public void updateTeamStats(){
present.clear(); present.clear();
boss = null;
for(Team team : Team.all){ for(Team team : Team.all){
TeamData data = team.data(); TeamData data = team.data();
@@ -178,6 +181,10 @@ public class Teams{
data.units.add(unit); data.units.add(unit);
data.presentFlag = true; data.presentFlag = true;
if(unit.team == state.rules.waveTeam && unit.isBoss()){
boss = unit;
}
if(data.unitsByType == null || data.unitsByType.length <= unit.type.id){ if(data.unitsByType == null || data.unitsByType.length <= unit.type.id){
data.unitsByType = new Seq[content.units().size]; data.unitsByType = new Seq[content.units().size];
} }

View File

@@ -6,7 +6,7 @@ import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.io.legacy.*; import mindustry.game.SectorInfo.*;
import mindustry.maps.*; import mindustry.maps.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.world.blocks.storage.*; import mindustry.world.blocks.storage.*;
@@ -27,13 +27,6 @@ public class Universe{
public Universe(){ public Universe(){
load(); load();
//load legacy research
Events.on(ClientLoadEvent.class, e -> {
if(Core.settings.has("unlocks")){
LegacyIO.readResearch();
}
});
//update base coverage on capture //update base coverage on capture
Events.on(SectorCaptureEvent.class, e -> { Events.on(SectorCaptureEvent.class, e -> {
if(!net.client() && state.isCampaign()){ if(!net.client() && state.isCampaign()){
@@ -188,6 +181,7 @@ public class Universe{
}else if(attacked && wavesPassed > 0 && sector.info.winWave > 1 && sector.info.wave + wavesPassed >= sector.info.winWave && !sector.hasEnemyBase()){ }else if(attacked && wavesPassed > 0 && sector.info.winWave > 1 && sector.info.wave + wavesPassed >= sector.info.winWave && !sector.hasEnemyBase()){
//autocapture the sector //autocapture the sector
sector.info.waves = false; sector.info.waves = false;
sector.info.wasCaptured = true;
//fire the event //fire the event
Events.fire(new SectorCaptureEvent(sector)); Events.fire(new SectorCaptureEvent(sector));
@@ -206,8 +200,17 @@ public class Universe{
} }
} }
sector.info.export.each((item, amount) -> {
if(sector.info.items.get(item) <= 0 && sector.info.production.get(item, ExportStat::new).mean <= 0){
//disable export when production is negative.
sector.info.export.get(item).mean = 0f;
}
});
//add production, making sure that it's capped //add production, making sure that it's capped
sector.info.production.each((item, stat) -> sector.info.items.add(item, Math.min((int)(stat.mean * newSecondsPassed * scl), sector.info.storageCapacity - sector.info.items.get(item)))); sector.info.production.each((item, stat) -> sector.info.items.add(item, Math.min((int)(stat.mean * newSecondsPassed * scl), sector.info.storageCapacity - sector.info.items.get(item))));
//prevent negative values with unloaders
sector.info.items.checkNegative();
sector.saveInfo(); sector.saveInfo();
} }
@@ -216,7 +219,7 @@ public class Universe{
if(!sector.isAttacked() && turn > invasionGracePeriod && sector.info.hasSpawns){ if(!sector.isAttacked() && turn > invasionGracePeriod && sector.info.hasSpawns){
//invasion chance depends on # of nearby bases //invasion chance depends on # of nearby bases
if(Mathf.chance(baseInvasionChance * Math.min(sector.near().count(Sector::hasEnemyBase), 1))){ if(Mathf.chance(baseInvasionChance * Math.min(sector.near().count(Sector::hasEnemyBase), 1))){
int waveMax = Math.max(sector.info.winWave, sector.isBeingPlayed() ? state.wave : sector.info.wave + sector.info.wavesPassed) + Mathf.random(2, 5) * 5; int waveMax = Math.max(sector.info.winWave, sector.isBeingPlayed() ? state.wave : sector.info.wave + sector.info.wavesPassed) + Mathf.random(2, 4) * 5;
//assign invasion-related things //assign invasion-related things
if(sector.isBeingPlayed()){ if(sector.isBeingPlayed()){

View File

@@ -10,7 +10,7 @@ import mindustry.type.*;
import static mindustry.content.UnitTypes.*; import static mindustry.content.UnitTypes.*;
public class Waves{ public class Waves{
public static final int waveVersion = 3; public static final int waveVersion = 4;
private Seq<SpawnGroup> spawns; private Seq<SpawnGroup> spawns;
@@ -277,7 +277,7 @@ public class Waves{
int cap = 150; int cap = 150;
float shieldStart = 30, shieldsPerWave = 20 + difficulty*30f; float shieldStart = 30, shieldsPerWave = 20 + difficulty*30f;
float[] scaling = {1, 1, 1.5f, 3f, 4f}; float[] scaling = {1, 1.5f, 3f, 4f, 5f};
Intc createProgression = start -> { Intc createProgression = start -> {
//main sequence //main sequence
@@ -286,7 +286,7 @@ public class Waves{
for(int i = start; i < cap;){ for(int i = start; i < cap;){
int f = i; int f = i;
int next = rand.random(8, 16) + (int)Mathf.lerp(4f, 0f, difficulty) + curTier * 4; int next = rand.random(8, 16) + (int)Mathf.lerp(5f, 0f, difficulty) + curTier * 4;
float shieldAmount = Math.max((i - shieldStart) * shieldsPerWave, 0); float shieldAmount = Math.max((i - shieldStart) * shieldsPerWave, 0);
int space = start == 0 ? 1 : rand.random(1, 2); int space = start == 0 ? 1 : rand.random(1, 2);
@@ -298,7 +298,7 @@ public class Waves{
begin = f; begin = f;
end = f + next >= cap ? never : f + next; end = f + next >= cap ? never : f + next;
max = 13; max = 13;
unitScaling = (difficulty < 0.4f ? rand.random(2.5f, 4f) : rand.random(1f, 4f)) * scaling[ctier]; unitScaling = (difficulty < 0.4f ? rand.random(2.5f, 5f) : rand.random(1f, 4f)) * scaling[ctier];
shields = shieldAmount; shields = shieldAmount;
shieldScaling = shieldsPerWave; shieldScaling = shieldsPerWave;
spacing = space; spacing = space;
@@ -310,7 +310,7 @@ public class Waves{
begin = f + next - 1; begin = f + next - 1;
end = f + next + rand.random(6, 10); end = f + next + rand.random(6, 10);
max = 6; max = 6;
unitScaling = rand.random(1f, 2f); unitScaling = rand.random(2f, 4f);
spacing = rand.random(2, 4); spacing = rand.random(2, 4);
shields = shieldAmount/2f; shields = shieldAmount/2f;
shieldScaling = shieldsPerWave; shieldScaling = shieldsPerWave;
@@ -340,10 +340,10 @@ public class Waves{
step += (int)(rand.random(15, 30) * Mathf.lerp(1f, 0.5f, difficulty)); step += (int)(rand.random(15, 30) * Mathf.lerp(1f, 0.5f, difficulty));
} }
int bossWave = (int)(rand.random(50, 70) * Mathf.lerp(1f, 0.5f, difficulty)); int bossWave = (int)(rand.random(50, 70) * Mathf.lerp(1f, 0.7f, difficulty));
int bossSpacing = (int)(rand.random(25, 40) * Mathf.lerp(1f, 0.6f, difficulty)); int bossSpacing = (int)(rand.random(25, 40) * Mathf.lerp(1f, 0.6f, difficulty));
int bossTier = difficulty < 0.5 ? 3 : 4; int bossTier = difficulty < 0.6 ? 3 : 4;
//main boss progression //main boss progression
out.add(new SpawnGroup(Structs.random(species)[bossTier]){{ out.add(new SpawnGroup(Structs.random(species)[bossTier]){{
@@ -411,7 +411,7 @@ public class Waves{
} }
//shift back waves on higher difficulty for a harder start //shift back waves on higher difficulty for a harder start
int shift = Math.max((int)(difficulty * 15 - 5), 0); int shift = Math.max((int)(difficulty * 14 - 5), 0);
for(SpawnGroup group : out){ for(SpawnGroup group : out){
group.begin -= shift; group.begin -= shift;

View File

@@ -58,6 +58,7 @@ public enum Binding implements KeyBind{
fullscreen(KeyCode.f11), fullscreen(KeyCode.f11),
pause(KeyCode.space), pause(KeyCode.space),
minimap(KeyCode.m), minimap(KeyCode.m),
research(KeyCode.b),
planet_map(KeyCode.n), planet_map(KeyCode.n),
toggle_menus(KeyCode.c), toggle_menus(KeyCode.c),
screenshot(KeyCode.p), screenshot(KeyCode.p),

View File

@@ -240,6 +240,7 @@ public class DesktopInput extends InputHandler{
if(state.isGame() && !scene.hasDialog() && !(scene.getKeyboardFocus() instanceof TextField)){ if(state.isGame() && !scene.hasDialog() && !(scene.getKeyboardFocus() instanceof TextField)){
if(Core.input.keyTap(Binding.minimap)) ui.minimapfrag.toggle(); if(Core.input.keyTap(Binding.minimap)) ui.minimapfrag.toggle();
if(Core.input.keyTap(Binding.planet_map) && state.isCampaign()) ui.planet.toggle(); if(Core.input.keyTap(Binding.planet_map) && state.isCampaign()) ui.planet.toggle();
if(Core.input.keyTap(Binding.research) && state.isCampaign()) ui.research.toggle();
} }
if(state.isMenu() || Core.scene.hasDialog()) return; if(state.isMenu() || Core.scene.hasDialog()) return;

View File

@@ -47,6 +47,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
/** Maximum line length. */ /** Maximum line length. */
final static int maxLength = 100; final static int maxLength = 100;
final static Rect r1 = new Rect(), r2 = new Rect(); final static Rect r1 = new Rect(), r2 = new Rect();
final static Seq<Point2> tmpPoints = new Seq<>(), tmpPoints2 = new Seq<>();
public final OverlayFragment frag = new OverlayFragment(); public final OverlayFragment frag = new OverlayFragment();
@@ -95,18 +96,17 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
} }
@Remote(called = Loc.server, unreliable = true) @Remote(called = Loc.server, unreliable = true)
public static void transferItemTo(Item item, int amount, float x, float y, Building build){ public static void setItem(Building build, Item item, int amount){
if(build == null || build.items == null) return; if(build == null || build.items == null) return;
for(int i = 0; i < Mathf.clamp(amount / 5, 1, 8); i++){ build.items.set(item, amount);
Time.run(i * 3, () -> createItemTransfer(item, amount, x, y, build, () -> {}));
}
build.items.add(item, amount);
} }
@Remote(called = Loc.server, unreliable = true) @Remote(called = Loc.server, unreliable = true)
public static void transferItemTo(Unit unit, Item item, int amount, float x, float y, Building build){ public static void transferItemTo(@Nullable Unit unit, Item item, int amount, float x, float y, Building build){
if(build == null || build.items == null) return; if(build == null || build.items == null) return;
unit.stack.amount = Math.max(unit.stack.amount - amount, 0);
if(unit != null) unit.stack.amount = Math.max(unit.stack.amount - amount, 0);
for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){ for(int i = 0; i < Mathf.clamp(amount / 3, 1, 8); i++){
Time.run(i * 3, () -> createItemTransfer(item, amount, x, y, build, () -> {})); Time.run(i * 3, () -> createItemTransfer(item, amount, x, y, build, () -> {}));
} }
@@ -1164,27 +1164,39 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
points = Placement.normalizeLine(startX, startY, endX, endY); points = Placement.normalizeLine(startX, startY, endX, endY);
} }
if(block instanceof PowerNode){ if(block instanceof PowerNode node){
Seq<Point2> skip = new Seq<>(); var base = tmpPoints2;
var result = tmpPoints.clear();
for(int i = 1; i < points.size; i++){ base.selectFrom(points, p -> p == points.first() || p == points.peek() || Build.validPlace(block, player.team(), p.x, p.y, rotation, false));
int overlaps = 0; boolean addedLast = false;
Point2 point = points.get(i);
//check with how many powernodes the *next* tile will overlap outer:
for(int j = 0; j < i; j++){ for(int i = 0; i < base.size;){
if(!skip.contains(points.get(j)) && ((PowerNode)block).overlaps(world.tile(point.x, point.y), world.tile(points.get(j).x, points.get(j).y))){ var point = base.get(i);
overlaps++; result.add(point);
if(i == base.size - 1) addedLast = true;
//find the furthest node that overlaps this one
for(int j = base.size - 1; j > i; j--){
var other = base.get(j);
boolean over = node.overlaps(world.tile(point.x, point.y), world.tile(other.x, other.y));
if(over){
//add node to list and start searching for node that overlaps the next one
i = j;
continue outer;
} }
} }
//if it's more than one, it can bridge the gap //if it got here, that means nothing was found. try to proceed to the next node anyway
if(overlaps > 1){ i ++;
skip.add(points.get(i-1));
}
} }
//remove skipped points
points.removeAll(skip); if(!addedLast) result.add(base.peek());
points.clear();
points.addAll(result);
} }
float angle = Angles.angle(startX, startY, endX, endY); float angle = Angles.angle(startX, startY, endX, endY);

View File

@@ -241,35 +241,10 @@ public class Placement{
} }
public static class NormalizeDrawResult{ public static class NormalizeDrawResult{
float x, y, x2, y2; public float x, y, x2, y2;
} }
public static class NormalizeResult{ public static class NormalizeResult{
public int x, y, x2, y2, rotation; public int x, y, x2, y2, rotation;
boolean isX(){
return Math.abs(x2 - x) > Math.abs(y2 - y);
}
/**
* Returns length of greater edge of the selection.
*/
int getLength(){
return Math.max(x2 - x, y2 - y);
}
/**
* Returns the X position of a specific index along this area as a line.
*/
int getScaledX(int i){
return x + (x2 - x > y2 - y ? i : 0);
}
/**
* Returns the Y position of a specific index along this area as a line.
*/
int getScaledY(int i){
return y + (x2 - x > y2 - y ? 0 : i);
}
} }
} }

View File

@@ -286,7 +286,8 @@ public abstract class SaveVersion extends SaveFileReader{
public void writeEntities(DataOutput stream) throws IOException{ public void writeEntities(DataOutput stream) throws IOException{
//write team data with entities. //write team data with entities.
Seq<TeamData> data = state.teams.getActive(); Seq<TeamData> data = state.teams.getActive().copy();
if(!data.contains(Team.sharded.data())) data.add(Team.sharded.data());
stream.writeInt(data.size); stream.writeInt(data.size);
for(TeamData team : data){ for(TeamData team : data){
stream.writeInt(team.team.id); stream.writeInt(team.team.id);
@@ -313,12 +314,23 @@ public abstract class SaveVersion extends SaveFileReader{
public void readEntities(DataInput stream) throws IOException{ public void readEntities(DataInput stream) throws IOException{
int teamc = stream.readInt(); int teamc = stream.readInt();
for(int i = 0; i < teamc; i++){ for(int i = 0; i < teamc; i++){
Team team = Team.get(stream.readInt()); Team team = Team.get(stream.readInt());
TeamData data = team.data(); TeamData data = team.data();
int blocks = stream.readInt(); int blocks = stream.readInt();
data.blocks.clear();
data.blocks.ensureCapacity(Math.min(blocks, 1000));
var reads = Reads.get(stream);
var set = new IntSet();
for(int j = 0; j < blocks; j++){ for(int j = 0; j < blocks; j++){
data.blocks.addLast(new BlockPlan(stream.readShort(), stream.readShort(), stream.readShort(), content.block(stream.readShort()).id, TypeIO.readObject(Reads.get(stream)))); short x = stream.readShort(), y = stream.readShort(), rot = stream.readShort(), bid = stream.readShort();
var obj = TypeIO.readObject(reads);
//cannot have two in the same position
if(set.add(Point2.pack(x, y))){
data.blocks.addLast(new BlockPlan(x, y, rot, content.block(bid).id, obj));
}
} }
} }

View File

@@ -302,6 +302,14 @@ public class Maps{
flooronto = Blocks.sand; flooronto = Blocks.sand;
block = Blocks.sandBoulder; block = Blocks.sandBoulder;
}}, }},
new ScatterFilter(){{
flooronto = Blocks.darksand;
block = Blocks.basaltBoulder;
}},
new ScatterFilter(){{
flooronto = Blocks.basalt;
block = Blocks.basaltBoulder;
}},
new ScatterFilter(){{ new ScatterFilter(){{
flooronto = Blocks.dacite; flooronto = Blocks.dacite;
block = Blocks.daciteBoulder; block = Blocks.daciteBoulder;

View File

@@ -21,7 +21,7 @@ import mindustry.world.blocks.storage.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class SectorDamage{ public class SectorDamage{
public static final int maxRetWave = 30, maxWavesSimulated = 50; public static final int maxRetWave = 40, maxWavesSimulated = 50;
//direct damage is for testing only //direct damage is for testing only
private static final boolean direct = false, rubble = true; private static final boolean direct = false, rubble = true;
@@ -68,6 +68,11 @@ public class SectorDamage{
float enemyDps = info.waveDpsBase + info.waveDpsSlope * (i); float enemyDps = info.waveDpsBase + info.waveDpsSlope * (i);
float enemyHealth = info.waveHealthBase + info.waveHealthSlope * (i); float enemyHealth = info.waveHealthBase + info.waveHealthSlope * (i);
if(info.bossWave == i){
enemyDps += info.bossDps;
enemyHealth += info.bossHealth;
}
//happens due to certain regressions //happens due to certain regressions
if(enemyHealth < 0 || enemyDps < 0) continue; if(enemyHealth < 0 || enemyDps < 0) continue;
@@ -111,23 +116,26 @@ public class SectorDamage{
float damage = getDamage(state.rules.sector.info); float damage = getDamage(state.rules.sector.info);
//scaled damage has a power component to make it seem a little more realistic (as systems fail, enemy capturing gets easier and easier) //scaled damage has a power component to make it seem a little more realistic (as systems fail, enemy capturing gets easier and easier)
float scaled = Mathf.pow(damage, 1.6f); float scaled = Mathf.pow(damage, 1.2f);
//apply damage to units
float unitDamage = damage * state.rules.sector.info.sumHealth;
Tile spawn = spawner.getFirstSpawn(); Tile spawn = spawner.getFirstSpawn();
//damage only units near the spawn point //damage only units near the spawn point
if(spawn != null){ if(spawn != null){
Seq<Unit> allies = new Seq<>(); Seq<Unit> allies = new Seq<>();
float sumUnitHealth = 0f;
for(Unit ally : Groups.unit){ for(Unit ally : Groups.unit){
if(ally.team == state.rules.defaultTeam && ally.within(spawn, state.rules.dropZoneRadius * 2.5f)){ if(ally.team == state.rules.defaultTeam && ally.within(spawn, state.rules.dropZoneRadius * 2.5f)){
allies.add(ally); allies.add(ally);
sumUnitHealth += ally.health;
} }
} }
allies.sort(u -> u.dst2(spawn)); allies.sort(u -> u.dst2(spawn));
//apply damage to units
float unitDamage = damage * sumUnitHealth;
//damage units one by one, not uniformly //damage units one by one, not uniformly
for(var u : allies){ for(var u : allies){
if(u.health < unitDamage){ if(u.health < unitDamage){
@@ -302,6 +310,7 @@ public class SectorDamage{
//calculate DPS and health for the next few waves and store in list //calculate DPS and health for the next few waves and store in list
var reg = new LinearRegression(); var reg = new LinearRegression();
SpawnGroup bossGroup = null;
Seq<Vec2> waveDps = new Seq<>(), waveHealth = new Seq<>(); Seq<Vec2> waveDps = new Seq<>(), waveHealth = new Seq<>();
for(int wave = state.wave; wave < state.wave + 10; wave ++){ for(int wave = state.wave; wave < state.wave + 10; wave ++){
@@ -317,6 +326,11 @@ public class SectorDamage{
float healthMult = 1f + Mathf.clamp(group.type.armor / 20f); float healthMult = 1f + Mathf.clamp(group.type.armor / 20f);
StatusEffect effect = (group.effect == null ? StatusEffects.none : group.effect); StatusEffect effect = (group.effect == null ? StatusEffects.none : group.effect);
int spawned = group.getSpawned(wave); int spawned = group.getSpawned(wave);
//save the boss group
if(group.effect == StatusEffects.boss){
bossGroup = group;
continue;
}
if(spawned <= 0) continue; if(spawned <= 0) continue;
sumWaveHealth += spawned * (group.getShield(wave) + group.type.health * effect.healthMultiplier * healthMult); sumWaveHealth += spawned * (group.getShield(wave) + group.type.health * effect.healthMultiplier * healthMult);
sumWaveDps += spawned * group.type.dpsEstimate * effect.damageMultiplier; sumWaveDps += spawned * group.type.dpsEstimate * effect.damageMultiplier;
@@ -325,6 +339,21 @@ public class SectorDamage{
waveHealth.add(new Vec2(wave, sumWaveHealth)); waveHealth.add(new Vec2(wave, sumWaveHealth));
} }
if(bossGroup != null){
float bossMult = 1.1f;
//calculate first boss appearaance
for(int wave = state.wave; wave < state.wave + 60; wave++){
int spawned = bossGroup.getSpawned(wave - 1);
if(spawned > 0){
//set up relevant stats
info.bossWave = wave;
info.bossDps = spawned * bossGroup.type.dpsEstimate * StatusEffects.boss.damageMultiplier * bossMult;
info.bossHealth = spawned * (bossGroup.getShield(wave) + bossGroup.type.health * StatusEffects.boss.healthMultiplier * (1f + Mathf.clamp(bossGroup.type.armor / 20f))) * bossMult;
break;
}
}
}
//calculate linear regression of the wave data and store it //calculate linear regression of the wave data and store it
reg.calculate(waveHealth); reg.calculate(waveHealth);
info.waveHealthBase = reg.intercept; info.waveHealthBase = reg.intercept;
@@ -335,9 +364,9 @@ public class SectorDamage{
info.waveDpsSlope = reg.slope; info.waveDpsSlope = reg.slope;
//enemy units like to aim for a lot of non-essential things, so increase resulting health slightly //enemy units like to aim for a lot of non-essential things, so increase resulting health slightly
info.sumHealth = sumHealth * 1.3f; info.sumHealth = sumHealth * 1.05f;
//players tend to have longer range units/turrets, so assume DPS is higher //players tend to have longer range units/turrets, so assume DPS is higher
info.sumDps = sumDps * 1.3f; info.sumDps = sumDps * 1.05f;
info.sumRps = sumRps; info.sumRps = sumRps;
info.wavesSurvived = getWavesSurvived(info); info.wavesSurvived = getWavesSurvived(info);
@@ -348,13 +377,12 @@ public class SectorDamage{
Queue<Tile> frontier = new Queue<>(); Queue<Tile> frontier = new Queue<>();
float[][] values = new float[tiles.width][tiles.height]; float[][] values = new float[tiles.width][tiles.height];
float damage = fraction*80; //arbitrary damage value
//phase one: find all spawnpoints //phase one: find all spawnpoints
for(Tile tile : tiles){ for(Tile tile : tiles){
if((tile.block() instanceof CoreBlock && tile.team() == state.rules.waveTeam) || tile.overlay() == Blocks.spawn){ if((tile.block() instanceof CoreBlock && tile.team() == state.rules.waveTeam) || tile.overlay() == Blocks.spawn){
frontier.add(tile); frontier.add(tile);
values[tile.x][tile.y] = damage; values[tile.x][tile.y] = fraction * 24;
} }
} }
@@ -368,14 +396,16 @@ public class SectorDamage{
int radius = 3; int radius = 3;
//only penetrate a certain % by health, not by distance //only penetrate a certain % by health, not by distance
float totalHealth = damage >= 1f ? 1f : path.sumf(t -> { float totalHealth = fraction >= 1f ? 1f : path.sumf(t -> {
float s = 0; float s = 0;
for(int dx = -radius; dx <= radius; dx++){ for(int dx = -radius; dx <= radius; dx++){
for(int dy = -radius; dy <= radius; dy++){ for(int dy = -radius; dy <= radius; dy++){
int wx = dx + t.x, wy = dy + t.y; int wx = dx + t.x, wy = dy + t.y;
if(wx >= 0 && wy >= 0 && wx < world.width() && wy < world.height() && Mathf.within(dx, dy, radius)){ if(wx >= 0 && wy >= 0 && wx < world.width() && wy < world.height() && Mathf.within(dx, dy, radius)){
Tile other = world.rawTile(wx, wy); Tile other = world.rawTile(wx, wy);
s += other.team() == state.rules.defaultTeam ? other.build.health / other.block().size : 0f; if(!(other.block() instanceof CoreBlock)){
s += other.team() == state.rules.defaultTeam ? other.build.health / other.block().size : 0f;
}
} }
} }
} }
@@ -385,7 +415,7 @@ public class SectorDamage{
float healthCount = 0; float healthCount = 0;
out: out:
for(int i = 0; i < path.size && (healthCount < targetHealth || damage >= 1f); i++){ for(int i = 0; i < path.size && (healthCount < targetHealth || fraction >= 1f); i++){
Tile t = path.get(i); Tile t = path.get(i);
for(int dx = -radius; dx <= radius; dx++){ for(int dx = -radius; dx <= radius; dx++){
@@ -405,7 +435,7 @@ public class SectorDamage{
removal.add(other.build); removal.add(other.build);
if(healthCount >= targetHealth && damage < 0.999f){ if(healthCount >= targetHealth && fraction < 0.999f){
break out; break out;
} }
} }
@@ -430,10 +460,10 @@ public class SectorDamage{
} }
} }
float falloff = (damage) / (Math.max(tiles.width, tiles.height) * Mathf.sqrt2); float falloff = (fraction) / (Math.max(tiles.width, tiles.height) * Mathf.sqrt2);
int peak = 0; int peak = 0;
if(damage > 0.1f){ if(fraction > 0.15f){
//phase two: propagate the damage //phase two: propagate the damage
while(!frontier.isEmpty()){ while(!frontier.isEmpty()){
peak = Math.max(peak, frontier.size); peak = Math.max(peak, frontier.size);

View File

@@ -7,7 +7,7 @@ import mindustry.world.*;
import static mindustry.maps.filters.FilterOption.*; import static mindustry.maps.filters.FilterOption.*;
public class ScatterFilter extends GenerateFilter{ public class ScatterFilter extends GenerateFilter{
protected float chance = 0.014f; protected float chance = 0.013f;
protected Block flooronto = Blocks.air, floor = Blocks.air, block = Blocks.air; protected Block flooronto = Blocks.air, floor = Blocks.air, block = Blocks.air;
@Override @Override

View File

@@ -55,7 +55,7 @@ public class BaseGenerator{
BasePart coreschem = bases.cores.getFrac(difficulty); BasePart coreschem = bases.cores.getFrac(difficulty);
int passes = difficulty < 0.4 ? 1 : difficulty < 0.8 ? 2 : 3; int passes = difficulty < 0.4 ? 1 : difficulty < 0.8 ? 2 : 3;
Block wall = wallsSmall.getFrac(difficulty), wallLarge = wallsLarge.getFrac(difficulty); Block wall = wallsSmall.getFrac(difficulty * 0.91f), wallLarge = wallsLarge.getFrac(difficulty * 0.91f);
for(Tile tile : cores){ for(Tile tile : cores){
tile.clearOverlay(); tile.clearOverlay();

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