diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index cf01e4bc68..56d3fe6dd7 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -1,6 +1,6 @@
name: Tests
-on: [push]
+on: [push, workflow_dispatch]
jobs:
buildJava14:
diff --git a/core/assets-raw/fontgen/extra/planet.svg b/core/assets-raw/fontgen/extra/planet.svg
new file mode 100644
index 0000000000..17cd9fc3cd
--- /dev/null
+++ b/core/assets-raw/fontgen/extra/planet.svg
@@ -0,0 +1,55 @@
+
+
diff --git a/core/assets-raw/icons/planet.png b/core/assets-raw/icons/planet.png
new file mode 100644
index 0000000000..6a5c136add
Binary files /dev/null and b/core/assets-raw/icons/planet.png differ
diff --git a/core/assets/baseparts/1591385293703.msch b/core/assets/baseparts/1591385293703.msch
index d48006b7be..a4e028a60b 100644
Binary files a/core/assets/baseparts/1591385293703.msch and b/core/assets/baseparts/1591385293703.msch differ
diff --git a/core/assets/baseparts/1591385372367.msch b/core/assets/baseparts/1591385372367.msch
index a45bad9e2d..c49595751c 100644
Binary files a/core/assets/baseparts/1591385372367.msch and b/core/assets/baseparts/1591385372367.msch differ
diff --git a/core/assets/baseparts/1599594352859.msch b/core/assets/baseparts/1599594352859.msch
index 3b73103fa9..1649a971f7 100644
Binary files a/core/assets/baseparts/1599594352859.msch and b/core/assets/baseparts/1599594352859.msch differ
diff --git a/core/assets/baseparts/1603215272794.msch b/core/assets/baseparts/1603215272794.msch
index b2351a3857..1e953643c8 100644
Binary files a/core/assets/baseparts/1603215272794.msch and b/core/assets/baseparts/1603215272794.msch differ
diff --git a/core/assets/baseparts/1603215415778.msch b/core/assets/baseparts/1603215415778.msch
index 6f7f75ab97..67141f4632 100644
--- a/core/assets/baseparts/1603215415778.msch
+++ b/core/assets/baseparts/1603215415778.msch
@@ -1,2 +1,3 @@
-mschxœ-‹k
-1„ÇMÅîуôPÅ
²PÛÒ®èÕEdM¬?’o2“Á€cý1e_BðÏš‚/g®—²äuI08åôàâbšÙI~eŒõ.p«ú°RöÚÆù×wÙGÿO`ÁÁîÑmȾadh{ÑN²Þ‚:õŒ‚Ä'Õ"IZ}ä°í²z}‰o)"
\ No newline at end of file
+mschxœ-‹
+Â0Eo×ʺ¢Òª®È ¶¥«¨Ÿ.Cf²J‡]6!NÎÐüæ0,‚)܇&Ù²öbKqùó~È$œÿ+À‘Vh¶•ò¹} ¶U
+êwZÐ'È;¤$´]ÑUô´…]P,(²»Š‘¡k¥¹úŶ,e
\ No newline at end of file
diff --git a/core/assets/baseparts/1603219511695.msch b/core/assets/baseparts/1603219511695.msch
index ad1b208119..743c38b401 100644
Binary files a/core/assets/baseparts/1603219511695.msch and b/core/assets/baseparts/1603219511695.msch differ
diff --git a/core/assets/baseparts/1603222833941.msch b/core/assets/baseparts/1603222833941.msch
index 565eecf779..60862cf01a 100644
Binary files a/core/assets/baseparts/1603222833941.msch and b/core/assets/baseparts/1603222833941.msch differ
diff --git a/core/assets/baseparts/1605279968000.msch b/core/assets/baseparts/1605279968000.msch
index 7eb0cd3b7e..0c00c2d356 100644
Binary files a/core/assets/baseparts/1605279968000.msch and b/core/assets/baseparts/1605279968000.msch differ
diff --git a/core/assets/baseparts/1605281215706.msch b/core/assets/baseparts/1605281215706.msch
index 27c39cfdf1..a53b8591fe 100644
Binary files a/core/assets/baseparts/1605281215706.msch and b/core/assets/baseparts/1605281215706.msch differ
diff --git a/core/assets/baseparts/1605284013998.msch b/core/assets/baseparts/1605284013998.msch
index 31c282985c..f08053df87 100644
Binary files a/core/assets/baseparts/1605284013998.msch and b/core/assets/baseparts/1605284013998.msch differ
diff --git a/core/assets/baseparts/752921320802746461.msch b/core/assets/baseparts/752921320802746461.msch
index e0333bb511..4c27dc4fa2 100644
Binary files a/core/assets/baseparts/752921320802746461.msch and b/core/assets/baseparts/752921320802746461.msch differ
diff --git a/core/assets/baseparts/753646105383927950.msch b/core/assets/baseparts/753646105383927950.msch
index 500ab29da2..00b0121a42 100644
Binary files a/core/assets/baseparts/753646105383927950.msch and b/core/assets/baseparts/753646105383927950.msch differ
diff --git a/core/assets/baseparts/753938078997151744.msch b/core/assets/baseparts/753938078997151744.msch
index 6a666a246c..cba3746e5b 100644
Binary files a/core/assets/baseparts/753938078997151744.msch and b/core/assets/baseparts/753938078997151744.msch differ
diff --git a/core/assets/baseparts/773974064850272309.msch b/core/assets/baseparts/773974064850272309.msch
index b9109ca782..8455943a23 100644
Binary files a/core/assets/baseparts/773974064850272309.msch and b/core/assets/baseparts/773974064850272309.msch differ
diff --git a/core/assets/baseparts/774013552553754635.msch b/core/assets/baseparts/774013552553754635.msch
index cb900f4073..68969a7975 100644
Binary files a/core/assets/baseparts/774013552553754635.msch and b/core/assets/baseparts/774013552553754635.msch differ
diff --git a/core/assets/bundles/bundle_ko.properties b/core/assets/bundles/bundle_ko.properties
index 0cc0f1d3b7..975aa49558 100644
--- a/core/assets/bundles/bundle_ko.properties
+++ b/core/assets/bundles/bundle_ko.properties
@@ -19,8 +19,8 @@ screenshot.invalid = ë§µì´ ë„ˆë¬´ 커서 스í¬ë¦°ìƒ·ì— 사용ë 메모리가
gameover = 게임 오버
gameover.pvp = [accent]{0}[] íŒ€ì´ ìŠ¹ë¦¬í–ˆìŠµë‹ˆë‹¤!
highscore = [accent]새로운 ìµœê³ ì 수!
-copied = 복사ë¨.
-indev.popup = 현재 [accent]v6[] ë²„ì „ì€ [accent]알파[] 단계입니다.\n[lightgray]ì´ ë§ì€:[]\n- [scarlet]ìº íŽ˜ì¸ì´ ì•„ì§ ì™„ì „ížˆ 개발ë˜ì§€ 않ìŒ[]\n- 몇몇 컨í…ì¸ ê°€ ë¹ ì§\n- ëŒ€ë¶€ë¶„ì˜ [scarlet]ìœ ë‹› AI[]ê°€ ìž‘ë™í•˜ì§€ 않ìŒ\n- ë§Žì€ ìœ ë‹›ë“¤ì´ ì•„ì§ ë¯¸ì™„ì„±\n- ë³´ì´ëŠ” ê²ƒì€ ëª¨ë‘ ë°”ë€Œê±°ë‚˜ ì œê±°ë 수 있ìŒ\n\n[accent]Github[] ì—서 버그 ë˜ëŠ” ê°•ì œì¢…ë£Œ 오류를 ì‹ ê³ í•´ 주세요.
+copied = 복사
+indev.popup = 현재 [accent]v6[] ë²„ì „ì€ [accent]ë² íƒ€[] 단계입니다.\n\n[accent]Github[] ì—서 버그 ë˜ëŠ” ê°•ì œì¢…ë£Œ 오류를 ì‹ ê³ í•´ 주세요.
indev.notready = ì´ ë¶€ë¶„ì€ ì•„ì§ ì¤€ë¹„ê°€ ë˜ì§€ 않았습니다.
load.sound = 소리
@@ -71,15 +71,15 @@ map.delete = ì •ë§ë¡œ "[accent]{0}[]" ë§µì„ ì‚ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?
level.highscore = ìµœê³ ì 수: [accent]{0}
level.select = ë§µ ì„ íƒ
level.mode = 게임 모드:
-coreattack = < 코어가 공격 ë°›ê³ ìžˆìŠµë‹ˆë‹¤! >
-nearpoint = [[ [scarlet]즉시 스í°ì§€ì ì—서 ë– ë‚˜ì„¸ìš”[] ]\nì „ë©¸ 임박
+coreattack = < 코어가 ê³µê²©ì„ ë°›ê³ ìžˆìŠµë‹ˆë‹¤! >
+nearpoint = [[ [scarlet]즉시 스í°ì§€ì ì—서 ë– ë‚˜ì„¸ìš”[] ]\nì¸ê·¼ 건물들과 ìœ ë‹›ë“¤ì€ ì´ˆí† í™”ë©ë‹ˆë‹¤!
database = 코어 ë°ì´í„°ë² ì´ìФ
savegame = 게임 ì €ìž¥
loadgame = 게임 불러오기
joingame = 게임 참여
customgame = ì‚¬ìš©ìž ì§€ì • 게임
newgame = 새 게임
-none = <ì—†ìŒ>
+none = < ì—†ìŒ >
minimap = 미니맵
position = 위치
close = 닫기
@@ -291,8 +291,8 @@ waiting = [lightgray]대기중...
waiting.players = ìƒëŒ€ í”Œë ˆì´ì–´ë¥¼ 기다리는 중...
wave.enemies = [lightgray]ì ìœ ë‹› {0}명 남ìŒ
wave.enemy = [lightgray]{0}명 남ìŒ
-wave.guardianwarn = [accent]{0}[] 단계 í›„ì— ê°€ë””ì–¸ì´ ì ‘ê·¼í•©ë‹ˆë‹¤.
-wave.guardianwarn.one = [accent]{0}[] 단계 í›„ì— ê°€ë””ì–¸ì´ ì ‘ê·¼í•©ë‹ˆë‹¤.
+wave.guardianwarn = [accent]{0}[] 단계 í›„ì— ìˆ˜í˜¸ìžê°€ ì ‘ê·¼í•©ë‹ˆë‹¤.
+wave.guardianwarn.one = [accent]{0}[] 단계 í›„ì— ìˆ˜í˜¸ìžê°€ ì ‘ê·¼í•©ë‹ˆë‹¤.
loadimage = 사진 불러오기
saveimage = 사진 ì €ìž¥
unknown = 알 수 ì—†ìŒ
@@ -335,13 +335,13 @@ editor.center = 중앙
workshop = 창작마당
waves.title = 단계
waves.remove = ì‚ì œ
-waves.never = 여기까지 ìœ ë‹›ìƒì„±
+waves.never = 여기까지 ìœ ë‹› ìƒì„±
waves.every = 매
waves.waves = 단계마다
waves.perspawn = 마리 ìƒì„±
-waves.shields = 보호막/단계
+waves.shields = 방어막/단계
waves.to = 부터
-waves.guardian = 가디언
+waves.guardian = 수호ìž
waves.preview = 미리보기
waves.edit = 편집
waves.copy = í´ë¦½ë³´ë“œë¡œ 복사
@@ -495,7 +495,7 @@ zone.objective = [lightgray]목표: [accent]{0}
zone.objective.survival = ìƒì¡´
zone.objective.attack = ì 코어 파괴
add = 추가...
-boss.health = 보스 ì²´ë ¥
+boss.health = ìˆ˜í˜¸ìž ì²´ë ¥
connectfail = [scarlet]연결 오류:\n\n[accent]{0}
error.unreachable = ì„œë²„ì— ì—°ê²°í•˜ì§€ 못했습니다.\n서버 주소가 ì •í™•ížˆ ìž…ë ¥ë˜ì—ˆë‚˜ìš”?
@@ -522,11 +522,11 @@ sectors.resume = 재개
sectors.launch = 출격
sectors.select = ì„ íƒ
sectors.nonelaunch = [lightgray]ì—†ìŒ (sun)
-sectors.rename = Rename Sector
-sector.missingresources = [scarlet]Insufficient Core Resources
+sectors.rename = êµ¬ì— ëª…ëª…
+sector.missingresources = [scarlet]ìžì› 부족
-planet.serpulo.name = Serpulo
-planet.sun.name = Sun
+planet.serpulo.name = 세르플
+planet.sun.name = 태양
sector.groundZero.name = ì „ì´ˆê¸°ì§€
sector.craters.name = í¬ë ˆì´í„°
@@ -561,26 +561,26 @@ settings.controls = ì¡°ìž‘
settings.game = 게임
settings.sound = 소리
settings.graphics = 그래픽
-settings.cleardata = 게임 ë°ì´í„° 초기화...
-settings.clear.confirm = ì •ë§ë¡œ ì´ ë°ì´í„°ë¥¼ ì§€ìš°ì‹œê² ìŠµë‹ˆê¹Œ?\nì™„ë£Œëœ ìž‘ì—…ì€ ì·¨ì†Œí• ìˆ˜ 없습니다!
+settings.cleardata = 게임 ë°ì´í„° 초기화
+settings.clear.confirm = ì •ë§ë¡œ ì´ ë°ì´í„°ë¥¼ ì§€ìš°ì‹œê² ìŠµë‹ˆê¹Œ?\në˜ëŒë¦´ 수 없습니다!
settings.clearall.confirm = [scarlet]ê²½ê³ ![]\nì´ ìž‘ì—…ì€ ì €ìž¥ëœ ë§µ, 맵파ì¼, ìž ê¸ˆ í•´ì œëœ ëª©ë¡ê³¼ 키 매핑, ê·¸ë¦¬ê³ ëª¨ë“ ë°ì´í„°ë¥¼ ì‚ì œí•©ë‹ˆë‹¤.\ní™•ì¸ ë²„íŠ¼ì„ ë‹¤ì‹œ 눌러 ëª¨ë“ ë°ì´í„°ë¥¼ ì‚ì œí•˜ê³ ê²Œìž„ì—서 나갑니다.
-settings.clearsaves.confirm = ì •ë§ë¡œ ëª¨ë“ ì €ìž¥ì„ ì‚ì œ í•˜ì‹œê² ìŠµë‹ˆê¹Œ?
+settings.clearsaves.confirm = ì •ë§ë¡œ ëª¨ë“ ì €ìž¥ëœ íŒŒì¼ë“¤ì„ ì‚ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?
settings.clearsaves = ì €ìž¥ 초기화
-settings.clearresearch = Clear Research
-settings.clearresearch.confirm = Are you sure you want to clear all of your campaign research?
-settings.clearcampaignsaves = Clear Campaign Saves
-settings.clearcampaignsaves.confirm = Are you sure you want to clear all of your campaign saves?
+settings.clearresearch = 연구 초기화
+settings.clearresearch.confirm = ì •ë§ë¡œ ëª¨ë“ ì—°êµ¬ë¥¼ ì‚ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?
+settings.clearcampaignsaves = ìº íŽ˜ì¸ ë§µ 초기화
+settings.clearcampaignsaves.confirm = ì •ë§ë¡œ ìº íŽ˜ì¸ì„ ì´ˆê¸°í™”í•˜ì‹œê² ìŠµë‹ˆê¹Œ?
paused = [accent]< ì¼ì‹œì •ì§€ >
clear = 초기화
banned = [scarlet]차단ë¨
-unplaceable.sectorcaptured = [scarlet]ì ë ¹ëœ êµ¬ì—ì´ í•„ìš”í•©ë‹ˆë‹¤
+unplaceable.sectorcaptured = [scarlet]êµ¬ì— ì ë ¹ í•„ìš”
yes = 예
no = 아니오
info.title = ì •ë³´
error.title = [scarlet]오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤.
error.crashtitle = 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤
-unit.nobuild = [scarlet]ì´ ìœ ë‹›ì€ ê±´ì„¤í• ìˆ˜ 없습니다.
-lastaccessed = [lightgray]마지막 ì ‘ê·¼: {0}
+unit.nobuild = [scarlet]건설 불가
+lastaccessed = [lightgray]마지막 조작: {0}
block.unknown = [lightgray]???
stat.input = ìž…ë ¥
@@ -588,70 +588,70 @@ stat.output = ì¶œë ¥
stat.booster = ê°€ì†
stat.tiles = 필요한 타ì¼
stat.affinities = ì¹œí™”ë ¥
-stat.powercapacity = Power Capacity
-stat.powershot = Power/Shot
-stat.damage = Damage
-stat.targetsair = Targets Air
-stat.targetsground = Targets Ground
-stat.itemsmoved = Move Speed
-stat.launchtime = Time Between Launches
-stat.shootrange = Range
-stat.size = Size
-stat.displaysize = Display Size
-stat.liquidcapacity = Liquid Capacity
-stat.powerrange = Power Range
-stat.linkrange = Link Range
-stat.instructions = Instructions
-stat.powerconnections = Max Connections
-stat.poweruse = Power Use
-stat.powerdamage = Power/Damage
-stat.itemcapacity = Item Capacity
-stat.memorycapacity = Memory Capacity
-stat.basepowergeneration = Base Power Generation
-stat.productiontime = Production Time
-stat.repairtime = Block Full Repair Time
-stat.speedincrease = Speed Increase
-stat.range = Range
-stat.drilltier = Drillables
-stat.drillspeed = Base Drill Speed
-stat.boosteffect = Boost Effect
-stat.maxunits = Max Active Units
-stat.health = Health
-stat.buildtime = Build Time
-stat.maxconsecutive = Max Consecutive
-stat.buildcost = Build Cost
-stat.inaccuracy = Inaccuracy
-stat.shots = Shots
-stat.reload = Shots/Second
-stat.ammo = Ammo
-stat.shieldhealth = Shield Health
-stat.cooldowntime = Cooldown Time
-stat.explosiveness = Explosiveness
-stat.basedeflectchance = Base Deflect Chance
-stat.lightningchance = Lightning Chance
-stat.lightningdamage = Lightning Damage
-stat.flammability = Flammability
-stat.radioactivity = Radioactivity
-stat.heatcapacity = HeatCapacity
-stat.viscosity = Viscosity
-stat.temperature = Temperature
-stat.speed = Speed
-stat.buildspeed = Build Speed
-stat.minespeed = Mine Speed
-stat.minetier = Mine Tier
-stat.payloadcapacity = Payload Capacity
-stat.commandlimit = Command Limit
-stat.abilities = Abilities
+stat.powercapacity = ì „ë ¥ëŸ‰
+stat.powershot = ì „ë ¥ëŸ‰/ë°œ
+stat.damage = ê³µê²©ë ¥
+stat.targetsair = 공중 공격
+stat.targetsground = ì§€ìƒ ê³µê²©
+stat.itemsmoved = ì´ë™ ì†ë„
+stat.launchtime = 발사 간격
+stat.shootrange = 사거리
+stat.size = í¬ê¸°
+stat.displaysize = 화면 í¬ê¸°
+stat.liquidcapacity = 액체 수용량
+stat.powerrange = ì „ì„ ê¸¸ì´
+stat.linkrange = ê°ì§€ 길ì´
+stat.instructions = 최대 ëª…ë ¹ì–´ 수
+stat.powerconnections = 최대 연결 개수
+stat.poweruse = ì „ë ¥ 요구량
+stat.powerdamage = ì „ë ¥ëŸ‰/피해량
+stat.itemcapacity = ìžì› 수용량
+stat.memorycapacity = 변수 개수
+stat.basepowergeneration = 기본 ë°œì „ëŸ‰
+stat.productiontime = 소요 시간
+stat.repairtime = 건물 ì™„ì „ 복구 시간
+stat.speedincrease = ì†ë„ ì¦ê°€
+stat.range = 사거리
+stat.drilltier = 채굴 가능 ìžì›
+stat.drillspeed = 기본 채굴 ì†ë„
+stat.boosteffect = 버프 효과
+stat.maxunits = 최대 ìœ ë‹› 수
+stat.health = ì²´ë ¥
+stat.buildtime = 건설 시간
+stat.maxconsecutive = 최대 ì²´ì¸ ê¸¸ì´
+stat.buildcost = 건설 비용
+stat.inaccuracy = 오차ê°
+stat.shots = 발사 당 탄
+stat.reload = 발/초
+stat.ammo = 탄약
+stat.shieldhealth = 보호막 ì²´ë ¥
+stat.cooldowntime = 쿨타임
+stat.explosiveness = í발성
+stat.basedeflectchance = 기본 반사 확ë¥
+stat.lightningchance = ì „ê²© 확ë¥
+stat.lightningdamage = ì „ê²© 공격량
+stat.flammability = 휘발성
+stat.radioactivity = 방사성
+stat.heatcapacity = 열용량
+stat.viscosity = ì 성
+stat.temperature = 온ë„
+stat.speed = ì†ë„
+stat.buildspeed = 건설 ì†ë„
+stat.minespeed = 채굴 ì†ë„
+stat.minetier = 채굴 티어
+stat.payloadcapacity = 화물 수용량
+stat.commandlimit = 지휘 한계
+stat.abilities = ëŠ¥ë ¥
-ability.forcefield = Force Field
-ability.repairfield = Repair Field
-ability.statusfield = Status Field
-ability.unitspawn = {0} Factory
-ability.shieldregenfield = Shield Regen Field
+ability.forcefield = 보호막
+ability.repairfield = 수리장
+ability.statusfield = 버프장
+ability.unitspawn = {0} 공장
+ability.shieldregenfield = 방어막 복구장
bar.drilltierreq = ë” ì¢‹ì€ ë“œë¦´ì´ í•„ìš”
bar.noresources = ìžì› 부족
-bar.corereq = 코어 기지 필요
+bar.corereq = 코어 필요
bar.drillspeed = 드릴 ì†ë„: {0}/s
bar.pumpspeed = 펌프 ì†ë„: {0}/s
bar.efficiency = 효율: {0}%
@@ -688,7 +688,7 @@ bullet.multiplier = [stat]{0}[lightgray]x 탄약 배수
bullet.reload = [stat]{0}[lightgray]x 발사 ì†ë„
unit.blocks = 블ë¡
-unit.blockssquared = blocks²
+unit.blockssquared = 블ë¡Â²
unit.powersecond = ì „ë ¥/ì´ˆ
unit.liquidsecond = ì•¡ì²´/ì´ˆ
unit.itemssecond = 개/초
@@ -701,7 +701,7 @@ unit.persecond = /ì´ˆ
unit.perminute = /ë¶„
unit.timesspeed = x ë°°
unit.percent = %
-unit.shieldhealth = 보호막 ì²´ë ¥
+unit.shieldhealth = 방어막 ì²´ë ¥
unit.items = ìžì›
unit.thousands = 천
unit.millions = 백만
@@ -711,7 +711,7 @@ category.power = ì „ë ¥
category.liquids = ì•¡ì²´
category.items = ìžì›
category.crafting = ìž…ë ¥/ì¶œë ¥
-category.function = Function
+category.function = 기능
category.optional = ë³´ì¡° ìžì›
setting.landscape.name = 가로화면 ìž ê¸ˆ
setting.shadows.name = 그림ìž
@@ -722,7 +722,7 @@ setting.flow.name = ìžì› í름량 표시
setting.buildautopause.name = 건설 ìžë™ ì¼ì‹œì •ì§€
setting.animatedwater.name = ì•¡ì²´ ì• ë‹ˆë©”ì´ì…˜ 효과
setting.animatedshields.name = 보호막 ì• ë‹ˆë©”ì´ì…˜ 효과
-setting.antialias.name = 안티 ì—ì¼ë¦¬ì–´ì‹±[lightgray] (재시작 í•„ìš”)[]
+setting.antialias.name = ìœ„ì‹ í˜¸ ì œê±° í•„í„°[lightgray] (재시작 í•„ìš”)[]
setting.playerindicators.name = í”Œë ˆì´ì–´ 위치 표시기
setting.indicators.name = ì 위치 표시기
setting.autotarget.name = ìžë™ 조준
@@ -734,10 +734,10 @@ setting.fpscap.text = {0} FPS
setting.uiscale.name = UI 스케ì¼ë§[lightgray] (재시작 í•„ìš”)[]
setting.swapdiagonal.name = í•ìƒ ëŒ€ê°ì„ 배치
setting.difficulty.training = í›ˆë ¨
-setting.difficulty.easy = 쉬움
+setting.difficulty.easy = 무난
setting.difficulty.normal = 보통
-setting.difficulty.hard = ì–´ë ¤ì›€
-setting.difficulty.insane = 미침
+setting.difficulty.hard = 혼ëˆ
+setting.difficulty.insane = 박멸
setting.difficulty.name = 난ì´ë„:
setting.screenshake.name = 화면 í”들림
setting.effects.name = 효과 보임
@@ -769,7 +769,7 @@ setting.savecreate.name = ìžë™ ì €ìž¥ 활성화
setting.publichost.name = ë©€í‹°í”Œë ˆì´ ê³µìš© 서버로 표시
setting.playerlimit.name = í”Œë ˆì´ì–´ ì œí•œ
setting.chatopacity.name = 채팅창 투명ë„
-setting.lasersopacity.name = ì „ë ¥ ë ˆì´ì € 투명ë„
+setting.lasersopacity.name = ì „ì„ íˆ¬ëª…ë„
setting.bridgeopacity.name = í„°ë„ íˆ¬ëª…ë„
setting.playerchat.name = 채팅 ë§í’ì„ í‘œì‹œ
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.axis = 마우스 íœ ë˜ëŠ” 키를 누르세요...
keybind.screenshot.name = ë§µ 스í¬ë¦°ìƒ·
-keybind.toggle_power_lines.name = ì „ë ¥ ë ˆì´ì € í† ê¸€
-keybind.toggle_block_status.name = ë¸”ë¡ ìƒíƒœ í† ê¸€
+keybind.toggle_power_lines.name = ì „ì„ ê°€ì‹œë„ ì„¤ì •
+keybind.toggle_block_status.name = ë¸”ë¡ ìƒíƒœ 가시ë„
keybind.move_x.name = Xì¶• ì´ë™
keybind.move_y.name = Yì¶• ì´ë™
keybind.mouse_move.name = 커서를 ë”°ë¼ì„œ ì´ë™
diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java
index 8fa2510a57..363256dc83 100644
--- a/core/src/mindustry/content/Blocks.java
+++ b/core/src/mindustry/content/Blocks.java
@@ -14,8 +14,6 @@ import mindustry.world.blocks.*;
import mindustry.world.blocks.campaign.*;
import mindustry.world.blocks.defense.*;
import mindustry.world.blocks.defense.turrets.*;
-import mindustry.world.blocks.defense.turrets.PointDefenseTurret;
-import mindustry.world.blocks.defense.turrets.TractorBeamTurret;
import mindustry.world.blocks.distribution.*;
import mindustry.world.blocks.environment.*;
import mindustry.world.blocks.experimental.*;
@@ -1221,13 +1219,13 @@ public class Blocks implements ContentList{
solarPanel = new SolarGenerator("solar-panel"){{
requirements(Category.power, with(Items.lead, 10, Items.silicon, 15));
- powerProduction = 0.08f;
+ powerProduction = 0.1f;
}};
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;
- powerProduction = 1f;
+ powerProduction = 1.3f;
}};
thoriumReactor = new NuclearReactor("thorium-reactor"){{
@@ -1515,7 +1513,7 @@ public class Blocks implements ContentList{
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));
range = 165f;
chargeTime = 40f;
diff --git a/core/src/mindustry/content/TechTree.java b/core/src/mindustry/content/TechTree.java
index cf77c5819b..98ff7fd6e8 100644
--- a/core/src/mindustry/content/TechTree.java
+++ b/core/src/mindustry/content/TechTree.java
@@ -512,8 +512,7 @@ public class TechTree implements ContentList{
new Research(groundFactory),
new Research(additiveReconstructor),
new Research(airFactory),
- new Research(door),
- new Research(waterExtractor)
+ new Research(door)
), () -> {
});
diff --git a/core/src/mindustry/core/NetClient.java b/core/src/mindustry/core/NetClient.java
index 85bbfd6f95..32b058997b 100644
--- a/core/src/mindustry/core/NetClient.java
+++ b/core/src/mindustry/core/NetClient.java
@@ -41,7 +41,7 @@ public class NetClient implements ApplicationListener{
private boolean connecting = false;
/** If true, no message will be shown on disconnect. */
private boolean quiet = false;
- /** Whether to supress disconnect events completely.*/
+ /** Whether to suppress disconnect events completely.*/
private boolean quietReset = false;
/** Counter for data timeout. */
private float timeoutTime = 0f;
@@ -345,7 +345,7 @@ public class NetClient implements ApplicationListener{
ui.showInfoToast(message, duration);
}
-
+
@Remote(variants = Variant.both)
public static void warningToast(int unicode, String text){
if(text == null || Fonts.icon.getData().getGlyph((char)unicode) == null) return;
diff --git a/core/src/mindustry/core/NetServer.java b/core/src/mindustry/core/NetServer.java
index 5c4c12dea1..c0a35c625b 100644
--- a/core/src/mindustry/core/NetServer.java
+++ b/core/src/mindustry/core/NetServer.java
@@ -422,7 +422,7 @@ public class NetServer implements ApplicationListener{
currentlyKicking[0] = session;
}
}else{
- player.sendMessage("[scarlet]No player[orange]'" + args[0] + "'[scarlet] found.");
+ player.sendMessage("[scarlet]No player [orange]'" + args[0] + "'[scarlet] found.");
}
}
});
diff --git a/core/src/mindustry/ctype/Content.java b/core/src/mindustry/ctype/Content.java
index c56f465824..71bf965e3f 100644
--- a/core/src/mindustry/ctype/Content.java
+++ b/core/src/mindustry/ctype/Content.java
@@ -31,7 +31,7 @@ public abstract class Content implements Comparable, Disposable{
*/
public void load(){}
- /** @return whether an error ocurred during mod loading. */
+ /** @return whether an error occurred during mod loading. */
public boolean hasErrored(){
return minfo.error != null;
}
diff --git a/core/src/mindustry/ctype/UnlockableContent.java b/core/src/mindustry/ctype/UnlockableContent.java
index 7848882206..9a87e622b4 100644
--- a/core/src/mindustry/ctype/UnlockableContent.java
+++ b/core/src/mindustry/ctype/UnlockableContent.java
@@ -110,7 +110,7 @@ public abstract class UnlockableContent extends MappableContent{
/** Makes this piece of content unlocked; if it already unlocked, nothing happens. */
public void unlock(){
- if(!unlocked()){
+ if(!net.client() && !unlocked()){
unlocked = true;
Core.settings.put(name + "-unlocked", true);
diff --git a/core/src/mindustry/mod/Mods.java b/core/src/mindustry/mod/Mods.java
index 0930cf1a60..f505358a40 100644
--- a/core/src/mindustry/mod/Mods.java
+++ b/core/src/mindustry/mod/Mods.java
@@ -677,7 +677,7 @@ public class Mods implements Loadable{
public Seq missingDependencies = new Seq<>();
/** Script files to run. */
public Seq scripts = new Seq<>();
- /** Content with intialization code. */
+ /** Content with initialization code. */
public ObjectSet erroredContent = new ObjectSet<>();
/** Current state of this mod. */
public ModState state = ModState.enabled;
@@ -708,7 +708,7 @@ public class Mods implements Loadable{
return !erroredContent.isEmpty();
}
- /** @return whether this mod is supported by the game verison */
+ /** @return whether this mod is supported by the game version */
public boolean isSupported(){
if(isOutdated()) return false;
diff --git a/core/src/mindustry/world/blocks/defense/ForceProjector.java b/core/src/mindustry/world/blocks/defense/ForceProjector.java
index 078bc02807..f17ac79b96 100644
--- a/core/src/mindustry/world/blocks/defense/ForceProjector.java
+++ b/core/src/mindustry/world/blocks/defense/ForceProjector.java
@@ -48,6 +48,7 @@ public class ForceProjector extends Block{
super(name);
update = true;
solid = true;
+ group = BlockGroup.projectors;
hasPower = true;
hasLiquids = true;
hasItems = true;
diff --git a/core/src/mindustry/world/blocks/defense/MendProjector.java b/core/src/mindustry/world/blocks/defense/MendProjector.java
index 1c171edfdc..1c0231f434 100644
--- a/core/src/mindustry/world/blocks/defense/MendProjector.java
+++ b/core/src/mindustry/world/blocks/defense/MendProjector.java
@@ -31,6 +31,7 @@ public class MendProjector extends Block{
super(name);
solid = true;
update = true;
+ group = BlockGroup.projectors;
hasPower = true;
hasItems = true;
}
diff --git a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java
index 7e645e5a2e..cc2c60288e 100644
--- a/core/src/mindustry/world/blocks/defense/OverdriveProjector.java
+++ b/core/src/mindustry/world/blocks/defense/OverdriveProjector.java
@@ -32,6 +32,7 @@ public class OverdriveProjector extends Block{
super(name);
solid = true;
update = true;
+ group = BlockGroup.projectors;
hasPower = true;
hasItems = true;
canOverdrive = false;
diff --git a/core/src/mindustry/world/blocks/defense/turrets/ChargeTurret.java b/core/src/mindustry/world/blocks/defense/turrets/ChargeTurret.java
deleted file mode 100644
index 15feaf0379..0000000000
--- a/core/src/mindustry/world/blocks/defense/turrets/ChargeTurret.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package mindustry.world.blocks.defense.turrets;
-
-import arc.audio.*;
-import arc.math.*;
-import arc.util.*;
-import mindustry.content.*;
-import mindustry.entities.*;
-import mindustry.entities.bullet.*;
-import mindustry.type.*;
-import mindustry.gen.*;
-
-import static mindustry.Vars.*;
-
-public class ChargeTurret extends PowerTurret{
- public float chargeTime = 30f;
- public int chargeEffects = 5;
- public float chargeMaxDelay = 10f;
- public Effect chargeEffect = Fx.none;
- public Effect chargeBeginEffect = Fx.none;
- public Sound chargeSound = Sounds.none;
-
- public ChargeTurret(String name){
- super(name);
- }
-
- public class ChargeTurretBuild extends PowerTurretBuild{
- public boolean shooting;
-
- @Override
- public void shoot(BulletType ammo){
- useAmmo();
-
- tr.trns(rotation, size * tilesize / 2f);
- chargeBeginEffect.at(x + tr.x, y + tr.y, rotation);
- chargeSound.at(x + tr.x, y + tr.y, 1);
-
- for(int i = 0; i < chargeEffects; i++){
- Time.run(Mathf.random(chargeMaxDelay), () -> {
- if(!isValid()) return;
- tr.trns(rotation, size * tilesize / 2f);
- chargeEffect.at(x + tr.x, y + tr.y, rotation);
- });
- }
-
- shooting = true;
-
- Time.run(chargeTime, () -> {
- if(!isValid()) return;
- tr.trns(rotation, size * tilesize / 2f);
- recoil = recoilAmount;
- heat = 1f;
- bullet(ammo, rotation + Mathf.range(inaccuracy));
- effects();
- shooting = false;
- });
- }
-
- @Override
- public boolean shouldTurn(){
- return !shooting;
- }
- }
-}
diff --git a/core/src/mindustry/world/blocks/defense/turrets/Turret.java b/core/src/mindustry/world/blocks/defense/turrets/Turret.java
index 3d1af1e5ce..9e41023c01 100644
--- a/core/src/mindustry/world/blocks/defense/turrets/Turret.java
+++ b/core/src/mindustry/world/blocks/defense/turrets/Turret.java
@@ -40,6 +40,7 @@ public abstract class Turret extends ReloadTurret{
public Effect ammoUseEffect = Fx.none;
public Sound shootSound = Sounds.shoot;
+ //general info
public int maxAmmo = 30;
public int ammoPerShot = 1;
public float ammoEjectBack = 1f;
@@ -61,6 +62,14 @@ public abstract class Turret extends ReloadTurret{
public boolean targetAir = true;
public boolean targetGround = true;
+ //charging
+ public float chargeTime = -1f;
+ public int chargeEffects = 5;
+ public float chargeMaxDelay = 10f;
+ public Effect chargeEffect = Fx.none;
+ public Effect chargeBeginEffect = Fx.none;
+ public Sound chargeSound = Sounds.none;
+
public Sortf unitSort = Unit::dst2;
protected Vec2 tr = new Vec2();
@@ -136,7 +145,7 @@ public abstract class Turret extends ReloadTurret{
public @Nullable Posc target;
public Vec2 targetPos = new Vec2();
public BlockUnitc unit = Nulls.blockUnit;
- public boolean wasShooting;
+ public boolean wasShooting, charging;
@Override
public void created(){
@@ -313,7 +322,7 @@ public abstract class Turret extends ReloadTurret{
}
public boolean shouldTurn(){
- return true;
+ return !charging;
}
/** Consume ammo and return a type. */
@@ -352,11 +361,37 @@ public abstract class Turret extends ReloadTurret{
}
protected void shoot(BulletType type){
- recoil = recoilAmount;
- heat = 1f;
- //when burst spacing is enabled, use the burst pattern
- if(burstSpacing > 0.0001f){
+ //when charging is enabled, use the charge shoot pattern
+ if(chargeTime > 0){
+ useAmmo();
+
+ tr.trns(rotation, size * tilesize / 2f);
+ chargeBeginEffect.at(x + tr.x, y + tr.y, rotation);
+ chargeSound.at(x + tr.x, y + tr.y, 1);
+
+ for(int i = 0; i < chargeEffects; i++){
+ Time.run(Mathf.random(chargeMaxDelay), () -> {
+ if(!isValid()) return;
+ tr.trns(rotation, size * tilesize / 2f);
+ chargeEffect.at(x + tr.x, y + tr.y, rotation);
+ });
+ }
+
+ charging = true;
+
+ Time.run(chargeTime, () -> {
+ if(!isValid()) return;
+ tr.trns(rotation, size * tilesize / 2f);
+ recoil = recoilAmount;
+ heat = 1f;
+ bullet(type, rotation + Mathf.range(inaccuracy));
+ effects();
+ charging = false;
+ });
+
+ //when burst spacing is enabled, use the burst pattern
+ }else if(burstSpacing > 0.0001f){
for(int i = 0; i < shots; i++){
Time.run(burstSpacing * i, () -> {
if(!isValid() || !hasAmmo()) return;
@@ -367,6 +402,8 @@ public abstract class Turret extends ReloadTurret{
bullet(type, rotation + Mathf.range(inaccuracy));
effects();
useAmmo();
+ recoil = recoilAmount;
+ heat = 1f;
});
}
@@ -388,6 +425,8 @@ public abstract class Turret extends ReloadTurret{
shotCounter++;
+ recoil = recoilAmount;
+ heat = 1f;
effects();
useAmmo();
}
diff --git a/core/src/mindustry/world/blocks/distribution/StackConveyor.java b/core/src/mindustry/world/blocks/distribution/StackConveyor.java
index b35f1630fb..4d6ca5d614 100644
--- a/core/src/mindustry/world/blocks/distribution/StackConveyor.java
+++ b/core/src/mindustry/world/blocks/distribution/StackConveyor.java
@@ -178,7 +178,6 @@ public class StackConveyor extends Block implements Autotiler{
}
proxUpdating = false;
}
-
}
@Override
diff --git a/core/src/mindustry/world/meta/BlockGroup.java b/core/src/mindustry/world/meta/BlockGroup.java
index 240e164ab3..8b73938ec8 100644
--- a/core/src/mindustry/world/meta/BlockGroup.java
+++ b/core/src/mindustry/world/meta/BlockGroup.java
@@ -1,5 +1,5 @@
package mindustry.world.meta;
public enum BlockGroup{
- none, walls, turrets, transportation, power, liquids, drills, storage, units, logic
+ none, walls, projectors, turrets, transportation, power, liquids, drills, storage, units, logic
}
diff --git a/desktop/src/mindustry/desktop/steam/SAchievement.java b/desktop/src/mindustry/desktop/steam/SAchievement.java
index 092f486249..71e04a2c3c 100644
--- a/desktop/src/mindustry/desktop/steam/SAchievement.java
+++ b/desktop/src/mindustry/desktop/steam/SAchievement.java
@@ -3,8 +3,7 @@ package mindustry.desktop.steam;
public enum SAchievement{
kill1kEnemies(SStat.unitsDestroyed, 1000),
kill100kEnemies(SStat.unitsDestroyed, 100_000),
- launch10kItems(SStat.itemsLaunched, 10_000),
- launch1milItems(SStat.itemsLaunched, 1_000_000),
+ launch100kItems(SStat.itemsLaunched, 100_000),
produce1kMin(SStat.maxProduction, 1000),
produce20kMin(SStat.maxProduction, 20_000),
@@ -14,11 +13,7 @@ public enum SAchievement{
launch30Times(SStat.timesLaunched, 30),
captureBackground,
survive100Waves(SStat.maxWavesSurvived, 100),
- //this seems near-impossible?
- //survive500Waves(SStat.maxWavesSurvived, 500),
researchAll,
- //TODO
- //useAllUnits,
shockWetEnemy,
killEnemyPhaseWall,
researchRouter,
@@ -43,13 +38,12 @@ public enum SAchievement{
buildAllUnits(SStat.unitTypesBuilt, 30),
buildT5,
pickupT5,
- activeAllT5,
active10Polys,
dieExclusion,
drown,
fillCoreAllCampaign,
hostServer10(SStat.maxPlayersServer, 10),
- buildMeltdownSpectreForeshadow,
+ buildMeltdownSpectre, //technically inaccurate
launchItemPad,
chainRouters,
circleConveyor,
@@ -62,6 +56,7 @@ public enum SAchievement{
enablePixelation,
openWiki,
useAccelerator,
+
;
private final SStat stat;
diff --git a/desktop/src/mindustry/desktop/steam/SStats.java b/desktop/src/mindustry/desktop/steam/SStats.java
index 822efe33cc..49bed6a511 100644
--- a/desktop/src/mindustry/desktop/steam/SStats.java
+++ b/desktop/src/mindustry/desktop/steam/SStats.java
@@ -65,13 +65,6 @@ public class SStats implements SteamUserStatsCallback{
active10Polys.complete();
}
- tmpSet.clear();
- tmpSet.addAll(t5s);
- Groups.unit.each(u -> tmpSet.remove(u.type));
- if(tmpSet.size == 0){
- activeAllT5.complete();
- }
-
for(Building entity : player.team().cores()){
if(!content.items().contains(i -> entity.items.get(i) < entity.block.itemCapacity)){
fillCoreAllCampaign.complete();
@@ -141,7 +134,7 @@ public class SStats implements SteamUserStatsCallback{
if(blocksBuilt.add(e.tile.block().name)){
if(blocksBuilt.contains("meltdown") && blocksBuilt.contains("spectre") && blocksBuilt.contains("foreshadow")){
- buildMeltdownSpectreForeshadow.complete();
+ buildMeltdownSpectre.complete();
}
save();
diff --git a/gradle.properties b/gradle.properties
index 151ff7ea34..e5c7e5fe4d 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,3 +1,3 @@
org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m
-archash=6742c2b110eeecd1934c42b5b1c87b00c911ecc4
+archash=7a2a357f6cfdc3725ce581093a0ced91f4474222