Merge remote-tracking branch 'origin/master'

This commit is contained in:
Joshua Fan 2020-12-05 22:56:34 -08:00
commit dd6ae80817
24 changed files with 208 additions and 120 deletions

View file

@ -1283,6 +1283,7 @@ hint.guardian = [accent]Guardian[] units are armored. Weak ammo such as [accent]
hint.coreUpgrade = Cores can be upgraded by [accent]placing higher-tier cores over them[].\n\nPlace a  [accent]Foundation[] core over the  [accent]Shard[] core. Make sure it is free from nearby obstructions.
hint.presetLaunch = Gray [accent]landing zone sectors[], such as [accent]Frozen Forest[], can be launched to from anywhere. They do not require capture of nearby territory.\n\n[accent]Numbered sectors[], such as this one, are [accent]optional[].
hint.coreIncinerate = After the core is filled to capacity with an item, any extra items of that type it receives will be [accent]incinerated[].
hint.coopCampaign = When playing the [accent]co-op campaign[], items that are produced in the current map will also be sent [accent]to your local sectors[].\n\nAny new research done by the host also carries over.
item.copper.description = Used in all types of construction and ammunition.
item.copper.details = Copper. Abnormally abundant metal on Serpulo. Structurally weak unless reinforced.

View file

@ -1,5 +1,5 @@
credits.text = 만든이: [royal]Anuken[] - [sky]anukendev@gmail.com[]
credits = 제작
credits = 제작
contributors = 번역가와 기여자
discord = Mindustry Discord 서버에 가입하세요!
link.discord.description = Mindustry Discord 공식 대화방
@ -15,7 +15,7 @@ link.wiki.description = 공식 Mindustry 위키
link.suggestions.description = 새 기능 제안하기
linkfail = 링크를 열지 못했습니다!\nURL이 클립보드에 복사되었습니다.
screenshot = 스크린 캡처가 {0} 에 저장되었습니다.
screenshot.invalid = 맵이 너무 커서 스크린 캡처에 사용될 메모리가 부족할 수 있습니다.
screenshot.invalid = 맵이 너무 커서 스크린 캡처에 사용될 메모리가 부족니다.
gameover = 게임 오버
gameover.disconnect = 연결 끊김
gameover.pvp = [accent]{0}[] 팀이 승리했습니다!
@ -75,7 +75,7 @@ level.highscore = 최고 점수: [accent]{0}
level.select = 맵 선택
level.mode = 게임 모드:
coreattack = < 코어가 공격을 받고 있습니다! >
nearpoint = [[ [scarlet]즉시 적 소환구역에서 떠나세요[] ]\n인근 건물들과 유닛들은 초토화됩니다!
nearpoint = [[ [scarlet]즉시 적 소환구역에서 떠나십시오[] ]\n단계가 시작하는 순간 인근 건물들과 유닛들이 전멸됩니다!
database = 코어 데이터베이스
savegame = 게임 저장
loadgame = 게임 불러오기
@ -149,7 +149,7 @@ unlocked = 새로운 콘텐츠가 해금되었습니다!
available = 새로운 콘텐츠 해금이 가능합니다!
completed = [accent]완료됨
techtree = 연구 기록
research.legacy = [accent]5.0[] 연구 데이터를 찾았습니다.\n[accent]이 데이터를 불러오시겠습니까?[], 아니면 이 데이터를 무시하고 캠페인을 새로 시작하시겠습니까? [accent]무시한 데이터는 삭제됩니다.[] (권장됨)?
research.legacy = [accent]5.0[] 연구 데이터를 찾았습니다.\n[accent]이 데이터를 불러오시겠습니까?[], 아니면 이 데이터를 무시하고 캠페인을 새로 시작하시겠습니까? [accent]무시한 데이터는 삭제됩니다.[] (권장됨)
research.load = 불러오기
research.discard = 무시하기
research.list = [lightgray]연구:
@ -167,7 +167,7 @@ server.kicked.serverClose = 서버 닫힘.
server.kicked.vote = 당신은 투표로 추방되었습니다. 안녕히 가세요!
server.kicked.clientOutdated = 구버전 클라이언트입니다! 게임을 업데이트하세요!
server.kicked.serverOutdated = 구버전 서버입니다! 호스트에게 업데이트를 요청하세요!
server.kicked.banned = 당신은 이 서버에서 차단되었습니다.
server.kicked.banned = 당신은 이 서버에서 영구적으로 차단되었습니다.
server.kicked.typeMismatch = 이 서버는 현재 빌드 유형과 호환되지 않습니다.
server.kicked.playerLimit = 서버의 인원이 꽉 찼습니다. 빈 슬롯이 생길 때까지 기다려주세요.
server.kicked.recentKick = 최근에 추방되었습니다.\n추방 쿨타임이 끝날 때까지 기다리세요.
@ -196,6 +196,7 @@ servers.local = 로컬 서버
servers.remote = 원격 서버
servers.global = 커뮤니티 서버
servers.disclaimer = 커뮤니티 서버는 개발자가 소유하거나 제어하지 [accent]않습니다[].\n\n서버들은 전연령대에 적합하지 않은 사용자 지정 콘텐츠를 보유할 수도 있습니다.
servers.showhidden = 서버 숨기기 / 보이기
server.shown = 서버 숨기기
server.hidden = 서버 보이기
@ -222,8 +223,8 @@ confirmban = 정말로 "{0}[white]" 을(를) 차단하시겠습니까?
confirmkick = 정말로 "{0}[white]" 을(를) 추방하시겠습니까?
confirmvotekick = 정말로 "{0}[white]" 을(를) 투표로 추방하시겠습니까?
confirmunban = 정말로 이 플레이어를 차단 해제하시겠습니까?
confirmadmin = 정말로 "{0}[white]" 을(를) 관리자로 만들겠습니까?
confirmunadmin = 정말로 "{0}[white]"의 관리자 상태를 제거하시겠습니까?
confirmadmin = 정말로 "{0}[white]" 을(를) 관리자로 임명하겠습니까?
confirmunadmin = 정말로 "{0}[white]"의 관리자를 박탈하시겠습니까?
joingame.title = 게임 참가
joingame.ip = 주소:
disconnect = 연결이 끊어졌습니다.
@ -293,11 +294,11 @@ quit.confirm.tutorial = 튜토리얼을 종료하시겠습니까?\n튜토리얼
loading = [accent]불러오는중...
reloading = [accent]모드 새로고침하는중...
saving = [accent]저장중...
respawn = [accent][[{0}][] 키를 눌러 코어에서 부활
cancelbuilding = [accent][[{0}][] 를 눌러 계획 초기화
selectschematic = [accent][[{0}][] 를 눌러 선택+복사
pausebuilding = [accent][[{0}][] 를 눌러 건설 일시중지
resumebuilding = [scarlet][[{0}][] 를 눌러 건설 재개
respawn = [accent][[{0}][] 키를 눌러 코어에서 부활하세요.
cancelbuilding = [accent][[{0}][] 를 눌러 건설 계획 초기화하세요.
selectschematic = [accent][[{0}][] 를 눌러 선택+복사하세요.
pausebuilding = [accent][[{0}][] 를 눌러 건설 일시중지하세요.
resumebuilding = [scarlet][[{0}][] 를 눌러 건설 재개하세요.
showui = UI를 .\n[accent][[{0}][] 키를 눌러 UI를 활성화하세요.
wave = [accent]{0} 단계
wave.cap = [accent]단계 {0}/{1}
@ -386,7 +387,7 @@ editor.errorimage = 이것은 맵이 아니라 사진입니다.\n\n3.5/build 40
editor.errorlegacy = 이 맵은 너무 오래되어 더 이상 지원되지 않는 구형 맵 형식을 사용합니다.
editor.errornot = 맵 파일이 아닙니다.
editor.errorheader = 이 맵 파일은 유효하지 않거나 손상되었습니다.
editor.errorname = 맵에 이름이 지정되어 있지 않습니다. 저장 파일을 불러오려 합니까?
editor.errorname = 맵에 이름이 지정되어 있지 않습니다. 저장 파일을 불러오려고 시도하는 건가요?
editor.update = 업데이트
editor.randomize = 무작위
editor.apply = 적용
@ -427,7 +428,7 @@ toolmode.replaceall.description = 맵에 있는 모든 블록을 재배치합니
toolmode.orthogonal = 직각
toolmode.orthogonal.description = 직각으로 블록을 배치합니다.
toolmode.square = 정사각형
toolmode.square.description = 정사각형 형태의 브러시.
toolmode.square.description = 정사각형 형태의 브러시로 교체합니다.
toolmode.eraseores = 자원 초기화
toolmode.eraseores.description = 자원만 초기화합니다.
toolmode.fillteams = 팀 채우기
@ -486,7 +487,7 @@ memory2 = Mem:\n {0}mb +\n {1}mb
language.restart = 언어 설정을 적용하려면 게임을 다시 시작하세요.
settings = 설정
tutorial = 튜토리얼
tutorial.retake = 튜토리얼 다시 시작
tutorial.retake = 튜토리얼 다시 시작하기
editor = 편집기
mapeditor = 맵 편집기
@ -500,8 +501,8 @@ requirement.research = {0} 연구
requirement.capture = {0} 점령
bestwave = [lightgray]최고 단계: {0}
launch.text = 출격
research.multiplayer = 캠페인 멀티 플레이 시에는 해당 캠페인 서버의 주최자만 연구할 수 있습니다.
map.multiplayer = 캠페인 멀티 플레이 시에는 해당 캠페인 서버의 주최자만 다른 섹터들을 보고, 이동이 가능합니다.
research.multiplayer = 캠페인 멀티 플레이 시에는 해당 캠페인 서버의 호스트만 연구할 수 있습니다.
map.multiplayer = 캠페인 멀티 플레이 시에는 해당 캠페인 서버의 호스트만 다른 섹터들을 보고, 이동이 가능합니다.
uncover = 지역 개방
configure = 초기자원 설정
@ -518,7 +519,7 @@ boss.health = 수호자 체력
connectfail = [scarlet]연결 오류:\n\n[accent]{0}
error.unreachable = 서버에 연결하지 못했습니다.\n서버 주소가 정확히 입력되었나요?
error.invalidaddress = 잘못된 주소입니다.
error.timedout = 시간 초과!\n서버에 포트 포워딩이 설정되어 있고 주소가 올바른지 확인하십시오.
error.timedout = 시간 초과!\n서버에 포트 포워딩이 설정되어 있고 주소가 올바른지 확인하세요.
error.mismatch = 패킷 오류\n클라이언트/서버 버전이 일치하지 않습니다.\n접속하려는 서버가 최신 버전인지 확인하세요!
error.alreadyconnected = 이미 접속 중입니다.
error.mapnotfound = 맵 파일을 찾을 수 없습니다!
@ -535,7 +536,7 @@ weather.fog.name = 안개
sectors.unexplored = [lightgray]미개척지
sectors.resources = 자원:
sectors.production = 분당 자원 생산량:
sectors.export = Export:
sectors.export = 분당 자원 수출량:
sectors.time = 지역 진행 시간:
sectors.threat = 지역 위험도:
sectors.wave = 진행 중 단계:
@ -546,7 +547,7 @@ sectors.select = 선택
sectors.nonelaunch = [lightgray]없음 (sun)
sectors.rename = 구역 이름 변경
sectors.enemybase = [scarlet]적 기지
sectors.vulnerable = [scarlet]]취약
sectors.vulnerable = [scarlet]취약
sectors.underattack = [scarlet]공격받고 있습니다! [accent]{0}% 손상됨.
sectors.survives = [accent]{0} 단계 이상 버티세요.
sectors.go = 지역 진입
@ -566,14 +567,14 @@ threat.eradication = 극한
planets = 태양계
planet.serpulo.name = 세르
planet.serpulo.name = 세르
planet.sun.name = 태양
sector.impact0078.name = 폐허 : Impact 0078
sector.groundZero.name = Zero 전초기지
sector.craters.name = 크레이터
sector.frozenForest.name = 얼어붙은 숲
sector.ruinousShores.name = 폐허 : 해안가
sector.ruinousShores.name = 파괴된 해안가
sector.stainedMountains.name = 얼룩진 산맥
sector.desolateRift.name = 황폐한 협곡
sector.nuclearComplex.name = 핵 생산 단지
@ -606,15 +607,15 @@ sector.planetaryTerminal.description = 이 행성에서의 마지막 전투를
settings.language = 언어
settings.data = 게임 데이터
settings.reset = 설정 초기화
settings.rebind = 키 설정
settings.resetKey = 초기화
settings.rebind = 조작키 설정
settings.resetKey = 조작키 설정 초기화
settings.controls = 조작
settings.game = 게임
settings.sound = 소리
settings.graphics = 그래픽
settings.cleardata = 게임 데이터 초기화
settings.clear.confirm = 정말로 이 데이터를 지우시겠습니까?\n되돌릴 수 없습니다!
settings.clearall.confirm = [scarlet]경고![]\n이 작업은 저장된 맵, 맵파일, 잠금 해제된 목록과 키 매핑, 그리고 모든 데이터를 삭제합니다.\n확인 버튼을 다시 눌러 모든 데이터를 삭제하고 게임에서 나갑니다.
settings.clearall.confirm = [scarlet]경고![]\n이 작업은 저장된 맵, 맵파일, 잠금 해제된 목록과 조작키 설정, 그리고 모든 데이터를 삭제합니다.\n확인 버튼을 다시 눌러 모든 데이터를 삭제하고 게임에서 나갑니다.
settings.clearsaves.confirm = 정말로 모든 저장된 파일들을 삭제하시겠습니까?
settings.clearsaves = 저장 초기화
settings.clearresearch = 연구 초기화
@ -628,7 +629,7 @@ yes = O
no = X
info.title = 정보
error.title = [scarlet]오류가 발생했습니다.
error.crashtitle = 오류가 발생했습니다
error.crashtitle = 오류가 발생했습니다.
unit.nobuild = [scarlet]건설 불가
lastaccessed = [lightgray]마지막 조작: {0}
block.unknown = [lightgray]???
@ -698,9 +699,9 @@ stat.abilities = 능력
stat.canboost = 부스터
stat.flying = 비행
ability.forcefield = 수호 역장
ability.repairfield = 수리 파동
ability.statusfield = 강화 오오라
ability.forcefield = 보호막 필드
ability.repairfield = 수리 필드
ability.statusfield = 상태이상 필드
ability.unitspawn = {0} 공장
ability.shieldregenfield = 방어막 복구 필드
ability.movelightning = 가속 전격
@ -837,7 +838,7 @@ uiscale.reset = UI 스케일이 변경되었습니다.\n"확인"버튼을 눌러
uiscale.cancel = 취소 후 나가기
setting.bloom.name = 화려한 효과
keybind.title = 조작키 설정
keybinds.mobile = [scarlet]대부분의 키 맵핑은 모바일에서 작동하지 않습니다. 기본 이동만 지원됩니다.
keybinds.mobile = [scarlet]대부분의 조작키 설정은 모바일에서 작동하지 않습니다. 기본 이동만 지원됩니다.
category.general.name = 일반
category.view.name = 보기
category.multiplayer.name = 멀티플레이어
@ -992,8 +993,8 @@ unit.quasar.name = 퀘이사
unit.crawler.name = 크롤러
unit.atrax.name = 아트락스
unit.spiroct.name = 스피록트
unit.arkyid.name = 알카이
unit.toxopid.name = 톡소피드
unit.arkyid.name = 아키
unit.toxopid.name = 톡소피드
unit.flare.name = 플레어
unit.horizon.name = 호라이즌
unit.zenith.name = 제니스
@ -1005,7 +1006,7 @@ unit.mega.name = 메가
unit.quad.name = 쿼드
unit.oct.name = 옥트
unit.risso.name = 리소
unit.minke.name =
unit.minke.name =
unit.bryde.name = 브라이드
unit.sei.name = 세이
unit.omura.name = 오무라
@ -1013,9 +1014,9 @@ unit.alpha.name = 알파
unit.beta.name = 베타
unit.gamma.name = 감마
unit.scepter.name = 셉터
unit.reign.name =
unit.reign.name = 레인
unit.vela.name = 벨라
unit.corvus.name = 코르
unit.corvus.name = 코르
block.resupply-point.name = 보급 지점
block.parallax.name = 패럴랙스
@ -1058,7 +1059,7 @@ block.deepwater.name = 깊은 물
block.water.name =
block.tainted-water.name = 오염된 물
block.darksand-tainted-water.name = 오염된 젖은 검은 모래
block.tar.name = 석유
block.tar.name = 타르
block.stone.name = 바위
block.sand.name = 모래
block.darksand.name = 검은 모래
@ -1198,7 +1199,7 @@ block.cyclone.name = 사이클론
block.fuse.name = 퓨즈
block.shock-mine.name = 전격 지뢰
block.overdrive-projector.name = 과부하 프로젝터
block.force-projector.name = 포스 프로젝터
block.force-projector.name = 보호막 프로젝터
block.arc.name = 아크
block.rtg-generator.name = RTG 발전기
block.spectre.name = 스펙터
@ -1257,7 +1258,7 @@ hint.placeDrill = 드릴을 설치하려면 오른쪽 아래의 \ue85e [accent]
hint.placeDrill.mobile = 오른쪽 아래 메뉴의 \ue85e [accent]드릴[]을 선택하고, \uf870 [accent]드릴[] 를 선택해서 구리 광석 위를 누르십시오.\n\n설치를 완료하려면 오른쪽 아래의 \ue800 [accent]완료 버튼[]을 누르십시오.
hint.placeConveyor = 컨베이어는 아이템을 드릴에서 다른 블록으로 이동시켜줍니다. \ue814 [accent]분배[] 카테고리에서 \uf896 [accent]컨베이어[]를 선택하십시오.\n\n클릭하거나 드래그로 다수의 컨베이어를 설치할 수 있습니다.\n클릭하고 놓지 않은채로 마우스 [accent]휠을 돌리면 돌아갑니다.
hint.placeConveyor.mobile = 컨베이어는 아이템을 드릴에서 다른 블록으로 이동시켜줍니다. \ue814 [accent]분배[] 카테고리에서 \uf896 [accent]컨베이어[]를 선택하십시오.\n\n여러개의 컨베이어를 놓으려면 손가락으로 누른채로 끌어서 설치 범위를 지정하십시오.
hint.placeTurret = 적에게서 당신의 기지를 막아내려면 \uf861 [accent]포탑[]를 설치하십시오.\n\n포탑 탄약 필요 - 지금은 \uf838구리가 필요합니다.\n컨베이어를 사용해 드릴에 구리를 공급하십시오.
hint.placeTurret = 적에게서 당신의 기지를 막아내려면 \uf861 [accent]포탑[]를 설치하십시오.\n\n포탑 탄약 필요 - 지금은 \uf838 구리가 필요합니다.\n컨베이어를 사용해 드릴에 구리를 공급하십시오.
hint.breaking = 블록을 부수려면 [accent]오른클릭[]이나 드래그를 하십시오.
hint.breaking.mobile = 블럭을 부수려면 오른쪽 아래의 \ue817 [accent]망치[]를 눌러 해체 모드를 활성화 하십시오.\n\n손가락으로 누른채로 끌어서 해체 범위를 지정하십시오.
hint.research = 새 기술을 연구하려면 \ue875 [accent]연구[]버튼을 누르십시오.
@ -1279,9 +1280,12 @@ hint.payloadDrop.mobile = 다시 내려놓으려면 빈 공간에서 [accent]화
hint.waveFire = [accent]Wave[]포탑에 탄약으로 물을 넣으면 주변의 불을 자동으로 꺼줍니다.
hint.generator = \uf879 [accent]화력 발전기[]는 석탄을 태워서 주변 블록에 전력을 전달합니다.\n\n \uf87f 더 넓은 범위의 블록에 전력을 전달하려면 [accent]Power Nodes[]를 사용하십시오.
hint.guardian = [accent]수호자[] 유닛들은 방어력을 가집니다. [accent]구리[]와 [accent]납[]같은 약한 탄약으로는 [scarlet]아무런 효과도 없습니다[].\n\n그런 수호자를 없애려면 높은 단계의 포탑 또는 \uf835 [accent]흑연[]을 탄약으로 넣은 \uf861듀오/\uf859살보를 사용하십시오.
hint.coreUpgrade = 코어는 [accent]상위 코어를 위에 설치함[]으로써 업그레이드될 수 있습니다.\n\n [accent]기반[] 코어를  [accent]조각[] 코어 위에 설치하십시오. 주변에 장애물이 없는지도 확인하십시오.
hint.presetLaunch = [accent]얼어붙은 숲[]과 같은 회색[accent]캠페인 지역[]은 어디에서나 출격해서 올 수 있습니다. 주변 지역을 점령하지 않아도 됩니다.\n\n이와 같은 [accent]네임드 지역[]들은 [accent]선택적[]입니다.
hint.coreIncinerate = 코어가 아이템으로 가득 찬 후에 받는 모든 아이템들은 [accent]소각[]될 것입니다.
item.copper.description = 가장 기본적인 건설 재료. 모든 유형의 블록에서 광범위하게 사용됩니다.
item.copper.details = 평범한 구리. 세르풀로에 비정상적으로 많이 분포되어 있습니다. 별다른 보강재 없이는 구조적 문제 때문에 내구성이 비교적 약합니다.
item.copper.details = 평범한 구리. 세르로에 비정상적으로 많이 분포되어 있습니다. 별다른 보강재 없이는 구조적 문제 때문에 내구성이 비교적 약합니다.
item.lead.description = 기본 초반 재료. 전자 및 액체 수송 블록에서 광범위하게 사용되는 자원입니다.
item.lead.details = 밀도가 높으며 반응성이 적은 자원. 배터리에 주로 사용됩니다.
item.metaglass.description = 초강력 방탄유리. 액체 분배 및 저장에 광범위하게 사용됩니다.
@ -1398,7 +1402,7 @@ block.laser-drill.description = 레이저 기술을 통해 더욱 빠르게 채
block.blast-drill.description = 최상위 드릴. 많은 양의 전력이 필요합니다.
block.water-extractor.description = 지하수를 추출합니다. 물을 구하기 어려운 곳에서 사용합니다.
block.cultivator.description = 대기 중의 작은 농도의 포자를 산업용 포자로 배양합니다.
block.cultivator.details = 재발견된 기술. 가장 효율적으로 대량의 유기체를 생산할 때 사용된다. 과거, 세르플을 뒤덮은 포자의 최초 배양지로 판단된다.
block.cultivator.details = 재발견된 기술. 가장 효율적으로 대량의 유기체를 생산할 때 사용된다. 과거, 세르플을 뒤덮은 포자의 최초 배양지로 판단된다.
block.oil-extractor.description = 석유를 추출하기 위해 많은 양의 전력과 모래 및 물을 사용합니다.
block.core-shard.description = 기지의 핵심입니다. 파괴되면 해당 지역과의 모든 연결이 끊어집니다. 이런 일이 일어나지 않도록 하십시오.
block.core-shard.details = 첫 번째 버전. 휴대용. 자가복제 가능. 일회용 출격 추진기를 가졌으며, 행성간 이동에는 부적합함.
@ -1410,23 +1414,23 @@ block.vault.description = 각 유형의 많은 양의 자원을 저장합니다.
block.container.description = 각 유형의 자원을 소량 저장합니다. 언로더 블록을 사용하여 컨테이너에서 자원을 빼낼 수 있습니다.
block.unloader.description = 근처의 비 수송 블록에서 자원을 빼냅니다. 눌러서 빼낼 자원을 변경할 수 있십니다.
block.launch-pad.description = 코어 출격 없이도 자원을 묶어 출격시킬 수 있습니다.
block.duo.description = 작고 저렴한 포탑. 지상 유닛에 유용합니다.
block.scatter.description = 저렴한 대공 포탑. 적군에게 납덩어리, 고철, 또는 강화 유리 조각 덩어리를 뿌립니다.
block.scorch.description = 주변의 모든 적을 불태웁니다. 근거리에서 매우 효과적입니다.
block.hail.description = 작은 장거리 포병 포탑입니다.
block.wave.description = 중형 포탑. 적에게 액체를 발사합니다. 물이 공급되면 자동으로 화재를 진압합니다.
block.lancer.description = 중형 대지 레이저 포탑. 강력한 에너지 빔을 충전하여 발사합니다.
block.arc.description = 작은 근거리 전격 포탑. 적에게 전격 아크를 발사합니다.
block.swarmer.description = 중형 미사일 포탑. 공중과 지상의 적을 모두 공격하며, 유도탄을 발사합니다.
block.salvo.description = 더 큰 고급 듀오 포탑입니다. 적에게 총알을 빠르게 발사합니다.
block.fuse.description = 넓은 근거리 파편 포탑. 근처의 적에게 3개의 관통 총알을 발사합니다.
block.ripple.description = 매우 강력한 포병 포탑. 원거리에 있는 적에게 포탄 무리를 쏘세요.
block.cyclone.description = 대공 및 대지 포탑. 근처 적에게 폭발탄을 발사합니다.
block.spectre.description = 거대한 이중 배럴 대포. 공중 및 지상 목표물에 큰 관통 철갑탄을 발사합니다.
block.meltdown.description = 거대한 레이저 대포. 근처의 적에게 지속적인 레이저 빔을 충전하여 발사합니다. 냉각수가 있어야 작동합니다.
block.foreshadow.description = 긴 거리에 걸친 거대한 단일 목표 볼트를 발사합니다.
block.repair-point.description = 주변에서 가장 가까운 유닛을 지속적으로 치료합니다.
block.segment.description = 날아오는 발사체를 요격합니다. 레이저는 목표 대상이 아닙니다.
block.duo.description = 적에게 탄환을 교대하며 발사합니다.
block.scatter.description = 적군에게 납, 고철, 또는 강화 유리 조각 덩어리를 발사합니다.
block.scorch.description = 주변의 모든 지상 적을 불태웁니다. 근거리에서 매우 효과적입니다.
block.hail.description = 장거리에 걸쳐 지상 적에게 작은 포탄을 발사합니다.
block.wave.description = 적에게 액체 줄기를 발사합니다. 물이 공급되면 자동으로 화재를 진압합니다.
block.lancer.description = 지상 목표물에게 강력한 에너지 빔을 충전하여 발사합니다.
block.arc.description = 지상 목표물에게 전격 아크를 발사합니다.
block.swarmer.description = 적에게 유도탄을 발사합니다.
block.salvo.description = 적에게 총알을 빠르게 일제히 발사합니다.
block.fuse.description = 주변 적에게 3개의 단거리 관통 레이저를 발사합니다.
block.ripple.description = 장거리에 걸쳐 지상 적에게 포탄 무리를 발사합니다.
block.cyclone.description = 근처 적에게 폭발 파편 덩어리를 발사합니다.
block.spectre.description = 공중 및 지상 목표물에 큰 관통 철갑탄을 발사합니다.
block.meltdown.description = 주변 적에게 지속적인 레이저 빔을 충전하여 발사합니다. 냉각 액체가 있어야 작동합니다.
block.foreshadow.description = 장거리에 걸친 거대한 단일 목표 저격탄을 발사합니다.
block.repair-point.description = 인근에 가장 가까운 유닛을 지속적으로 치료합니다.
block.segment.description = 날아오는 발사체를 요격합니다. 큰 발사체에겐 조준되지 않습니다.
block.parallax.description = 공중 목표물을 끌어오는 견인 광선을 발사하며, 견인 과정에서 데미지를 줍니다.
block.tsunami.description = 적에게 강력한 액체 줄기를 발사합니다. 물이 공급되면 자동으로 주변의 화재를 진압합니다.
block.silicon-crucible.description = 추가적으로 파이라타이트를 사용하여 더 높은 온도에서 석탄과 모래를 제련합니다. 뜨거운 곳에서 더 효율적입니다.
@ -1452,7 +1456,7 @@ block.logic-display.description = 프로세서를 이용해 그래픽을 출력
block.large-logic-display.description = 프로세서를 이용해 그래픽을 출력할 수 있습니다.
block.interplanetary-accelerator.description = 거대한 전자기 레일건 타워. 코어를 행성 간 이동을 위한 탈출 속도까지 가속합니다.
unit.dagger.description = 주변 모든 적에게 일반적인 탄환을 발사합니다.
unit.dagger.description = 주변 모든 적에게 일반적인 탄환을 발사합니다.
unit.mace.description = 주변 모든 적에게 화염 줄기를 발사합니다.
unit.fortress.description = 지상 목표물에 장거리 포탄을 발사합니다.
unit.scepter.description = 주변 모든 적에게 장전된 탄환을 일제히 발사합니다.
@ -1465,8 +1469,8 @@ unit.corvus.description = 적에게 피해를 주고, 아군 구조물을 수리
unit.crawler.description = 적에게 달려들어서 거대한 폭발을 일으키는 자폭을 합니다.
unit.atrax.description = 지상 목표물을 약화하는 광재 구체를 발사합니다. 대부분의 지형 위를 밟을 수 있습니다.
unit.spiroct.description = 적에게 흡혈 레이저 빔을 발사하며, 흡혈을 통해 체력을 회복합니다. 대부분의 지형 위를 밟을 수 있습니다.
unit.arkyid.description = 적에게 흡혈 레이저 빔을 발사하며, 흡혈을 통해 체력을 회복합니다. 대부분의 지형 위를 밟을 수 있습니다.
unit.toxopid.description = 적에게 큰 전기 확산탄과 관통 레이저를 발사합니다. 대부분의 지형 위를 밟을 수 있습니다.
unit.arkyid.description = 적에게 흡혈 레이저 빔을 발사하며, 흡혈을 통해 체력을 회복합니다. 대부분의 지형 위를 밟을 수 있습니다.
unit.toxopid.description = 적에게 큰 전격 포탄 무리와 관통 레이저를 발사합니다. 대부분의 지형 위를 밟을 수 있습니다.
unit.flare.description = 지상 목표물에 일반적인 탄환을 발사합니다.
unit.horizon.description = 지상 목표물에 폭탄을 투하합니다.
unit.zenith.description = 주변 모든 적에게 미사일을 살포합니다.

View file

@ -47,8 +47,6 @@ public class Vars implements Loadable{
public static final int bufferSize = 8192;
/** global charset, since Android doesn't support the Charsets class */
public static final Charset charset = Charset.forName("UTF-8");
/** mods suggested for import */
public static final String[] suggestedMods = {""};
/** main application name, capitalized */
public static final String appName = "Mindustry";
/** URL for itch.io donations. */

View file

@ -341,7 +341,7 @@ public class Control implements ApplicationListener, Loadable{
state.rules.waves = true;
//reset win wave??
state.rules.winWave = state.rules.attackMode ? -1 : sector.preset != null ? sector.preset.captureWave : state.rules.winWave > state.wave ? state.rules.winWave : 40;
state.rules.winWave = state.rules.attackMode ? -1 : sector.preset != null && sector.preset.captureWave > 0 ? sector.preset.captureWave : state.rules.winWave > state.wave ? state.rules.winWave : 40;
//if there's still an enemy base left, fix it
if(state.rules.attackMode){

View file

@ -153,6 +153,18 @@ public class Logic implements ApplicationListener{
}
});
//send out items to each client
Events.on(TurnEvent.class, e -> {
if(net.server() && state.isCampaign()){
int[] out = new int[content.items().size];
state.getSector().info.production.each((item, stat) -> {
out[item.id] = Math.max(0, (int)(stat.mean * turnDuration / 60));
});
Call.sectorProduced(out);
}
});
}
/** Adds starting items, resets wave time, and sets state to playing. */
@ -243,8 +255,10 @@ public class Logic implements ApplicationListener{
}
private void updateWeather(){
state.rules.weather.removeAll(w -> w.weather == null);
for(WeatherEntry entry : state.rules.weather){
if(entry.weather == null) continue;
//update cooldown
entry.cooldown -= Time.delta;
@ -295,8 +309,46 @@ public class Logic implements ApplicationListener{
public static void researched(Content content){
if(!(content instanceof UnlockableContent u)) return;
var node = u.node();
//unlock all direct dependencies on client, permanently
while(node != null){
node.content.unlock();
node = node.parent;
}
state.rules.researched.add(u.name);
Events.fire(new UnlockEvent(u));
}
//called when the remote server runs a turn and produces something
@Remote
public static void sectorProduced(int[] amounts){
if(!state.isCampaign()) return;
Planet planet = state.rules.sector.planet;
boolean any = false;
for(Item item : content.items()){
int am = amounts[item.id];
if(am > 0){
int sumMissing = planet.sectors.sum(s -> s.hasBase() ? s.info.storageCapacity - s.info.items.get(item) : 0);
if(sumMissing == 0) continue;
//how much % to add
double percent = Math.min((double)am / sumMissing, 1);
for(Sector sec : planet.sectors){
if(sec.hasBase()){
int added = (int)Math.ceil(((sec.info.storageCapacity - sec.info.items.get(item)) * percent));
sec.info.items.add(item, added);
any = true;
}
}
}
}
if(any){
for(Sector sec : planet.sectors){
sec.saveInfo();
}
}
}
@Override

View file

@ -615,6 +615,7 @@ public class World{
GenerateInput input = new GenerateInput();
for(GenerateFilter filter : filters){
filter.randomize();
input.begin(filter, width(), height(), (x, y) -> tiles.getn(x, y));
filter.apply(tiles, input);
}

View file

@ -117,7 +117,7 @@ public abstract class UnlockableContent extends MappableContent{
/** Makes this piece of content unlocked; if it already unlocked, nothing happens. */
public void unlock(){
if(!net.client() && !unlocked()){
if(!unlocked && !alwaysUnlocked){
unlocked = true;
Core.settings.put(name + "-unlocked", true);
@ -135,7 +135,7 @@ public abstract class UnlockableContent extends MappableContent{
}
public boolean unlocked(){
if(net != null && net.client()) return alwaysUnlocked || state.rules.researched.contains(name);
if(net != null && net.client()) return unlocked || alwaysUnlocked || state.rules.researched.contains(name);
return unlocked || alwaysUnlocked;
}

View file

@ -130,7 +130,7 @@ public class SectorInfo{
}
//if there are infinite waves and no win wave, add a win wave.
if(waves && winWave <= 0 && !attack){
if(winWave <= 0 && !attack){
winWave = 30;
}

View file

@ -547,6 +547,22 @@ public class TypeIO{
return read.b(new byte[length]);
}
public static void writeInts(Writes write, int[] ints){
write.s((short)ints.length);
for(int i : ints){
write.i(i);
}
}
public static int[] readInts(Reads read){
short length = read.s();
int[] out = new int[length];
for(int i = 0; i < length; i++){
out[i] = read.i();
}
return out;
}
public static void writeTraceInfo(Writes write, TraceInfo trace){
writeString(write, trace.ip);
writeString(write, trace.uuid);

View file

@ -114,6 +114,7 @@ public abstract class LStatement{
t.actions(Actions.alpha(0), Actions.fadeIn(0.3f, Interp.fade));
t.top().pane(inner -> {
inner.marginRight(24f);
inner.top();
hideCons.get(inner, hide);
}).top();

View file

@ -528,7 +528,9 @@ public class LStatements{
stack.clearChildren();
stack.addChild(tables[selected]);
t.pack();
t.parent.parent.pack();
t.parent.parent.invalidateHierarchy();
}).size(80f, 50f).growX().checked(selected == fi).group(group);
}
t.row();

View file

@ -23,24 +23,27 @@ public abstract class GenerateFilter{
//buffer of tiles used, each tile packed into a long struct
long[] buffer = new long[tiles.width * tiles.height];
//save to buffer
for(int i = 0; i < tiles.width * tiles.height; i++){
Tile tile = tiles.geti(i);
buffer[i] = PackTile.get(tile.blockID(), tile.floorID(), tile.overlayID());
in.apply(tile.x, tile.y, tile.block(), tile.floor(), tile.overlay());
apply();
buffer[i] = PackTile.get(in.block.id, in.floor.id, in.overlay.id);
}
//write to buffer
for(int i = 0; i < tiles.width * tiles.height; i++){
Tile tile = tiles.geti(i);
long b = buffer[i];
in.apply(tile.x, tile.y, Vars.content.block(PackTile.block(b)), Vars.content.block(PackTile.floor(b)), Vars.content.block(PackTile.overlay(b)));
apply();
Block block = Vars.content.block(PackTile.block(b)), floor = Vars.content.block(PackTile.floor(b)), overlay = Vars.content.block(PackTile.overlay(b));
tile.setFloor(in.floor.asFloor());
tile.setOverlay(!in.floor.asFloor().hasSurface() && in.overlay.asFloor().needsSurface ? Blocks.air : in.overlay);
tile.setFloor(floor.asFloor());
tile.setOverlay(!floor.asFloor().hasSurface() && overlay.asFloor().needsSurface ? Blocks.air : overlay);
if(!tile.block().synthetic() && !in.block.synthetic()){
tile.setBlock(in.block);
if(!tile.block().synthetic() && !block.synthetic()){
tile.setBlock(block);
}
}
}else{

View file

@ -68,7 +68,7 @@ public class ArcNetProvider implements NetProvider{
}
});
server = new Server(8192, 8192, new PacketSerializer());
server = new Server(32768, 8192, new PacketSerializer());
server.setMulticast(multicastGroup, multicastPort);
server.setDiscoveryHandler((address, handler) -> {
ByteBuffer buffer = NetworkIO.writeServerData();

View file

@ -67,7 +67,7 @@ public class Fonts{
}
public static int cursorScale(){
return Math.max(1, Mathf.round(Scl.scl(1f)));
return 1;
}
public static void loadFonts(){

View file

@ -105,13 +105,9 @@ public class ModsDialog extends BaseDialog{
t.button("@mod.import.github", Icon.github, bstyle, () -> {
dialog.hide();
var modString = Core.settings.getString("lastmod", "");
var suggested = Structs.random(suggestedMods);
ui.showTextInput("@mod.import.github", "", 64, modString.isEmpty() ? suggested : modString, text -> {
if(!modString.isEmpty() || !Structs.eq(suggested, text)){
Core.settings.put("lastmod", text);
}
ui.showTextInput("@mod.import.github", "", 64, Core.settings.getString("lastmod", ""), text -> {
Core.settings.put("lastmod", text);
ui.loadfrag.show();
//Try to download the 6.0 branch first, but if it doesn't exist, try master.

View file

@ -254,6 +254,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
boolean canSelect(Sector sector){
if(mode == select) return sector.hasBase();
if(sector.hasBase()) return true;
//preset sectors can only be selected once unlocked
if(sector.preset != null){
TechNode node = sector.preset.node();
@ -709,7 +710,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
stable.image().color(Pal.accent).fillX().height(3f).pad(3f).row();
boolean locked = sector.preset != null && sector.preset.locked() && sector.preset.node() != null;
boolean locked = sector.preset != null && sector.preset.locked() && !sector.hasBase() && sector.preset.node() != null;
if(locked){
stable.table(r -> {
@ -805,7 +806,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
return;
}
if(sector.preset != null && sector.preset.locked()){
if(sector.preset != null && sector.preset.locked() && !sector.hasBase()){
return;
}

View file

@ -172,16 +172,6 @@ public class ResearchDialog extends BaseDialog{
});
}
@Override
public Dialog show(){
if(net.client()){
ui.showInfo("@research.multiplayer");
return this;
}
return super.show();
}
void treeLayout(){
float spacing = 20f;
LayoutNode node = new LayoutNode(root, null);
@ -439,6 +429,14 @@ public class ResearchDialog extends BaseDialog{
void unlock(TechNode node){
node.content.unlock();
//unlock parent nodes in multiplayer.
TechNode parent = node.parent;
while(parent != null){
parent.content.unlock();
parent = parent.parent;
}
checkNodes(root);
hoverNode = null;
treeLayout();

View file

@ -173,6 +173,7 @@ public class HintsFragment extends Fragment{
&& SectorPresets.frozenForest.sector.save == null,
() -> state.isCampaign() && state.getSector().preset == SectorPresets.frozenForest),
coreIncinerate(() -> state.isCampaign() && state.rules.defaultTeam.core() != null && state.rules.defaultTeam.core().items.get(Items.copper) >= state.rules.defaultTeam.core().storageCapacity - 10, () -> false),
coopCampaign(() -> net.client() && state.isCampaign() && SectorPresets.groundZero.sector.hasBase(), () -> false),
;
@Nullable

View file

@ -318,9 +318,10 @@ public class LogicBlock extends Block{
//store any older variables
for(Var var : executor.vars){
if(!var.constant){
boolean unit = var.name.equals("@unit");
if(!var.constant || unit){
BVar dest = asm.getVar(var.name);
if(dest != null && !dest.constant){
if(dest != null && (!dest.constant || unit)){
dest.value = var.isobj ? var.objval : var.numval;
}
}

View file

@ -6,6 +6,7 @@ import arc.graphics.g2d.*;
import arc.math.*;
import arc.math.geom.*;
import arc.struct.*;
import arc.util.*;
import mindustry.*;
import mindustry.annotations.Annotations.*;
import mindustry.content.*;
@ -246,17 +247,18 @@ public class CoreBlock extends StorageBlock{
}
state.teams.registerCore(this);
storageCapacity = itemCapacity + proximity().sum(e -> isContainer(e) && owns(e) ? e.block.itemCapacity : 0);
proximity.each(e -> isContainer(e) && owns(e), t -> {
storageCapacity = itemCapacity + proximity().sum(e -> owns(e) ? e.block.itemCapacity : 0);
proximity.each(e -> owns(e), t -> {
t.items = items;
((StorageBuild)t).linkedCore = this;
});
for(Building other : state.teams.cores(team)){
if(other.tile() == tile) continue;
storageCapacity += other.block.itemCapacity + other.proximity().sum(e -> isContainer(e) && owns(other, e) ? e.block.itemCapacity : 0);
storageCapacity += other.block.itemCapacity + other.proximity().sum(e -> owns(e) && owns(other, e) ? e.block.itemCapacity : 0);
}
//Team.sharded.core().items.set(Items.surgeAlloy, 12000)
if(!world.isGenerating()){
for(Item item : content.items()){
items.set(item, Math.min(items.get(item), storageCapacity));
@ -303,24 +305,19 @@ public class CoreBlock extends StorageBlock{
Draw.rect("block-select", t.x + offset * p.x, t.y + offset * p.y, i * 90);
}
};
if(proximity.contains(e -> isContainer(e) && e.items == items)){
if(proximity.contains(e -> owns(e) && e.items == items)){
outline.get(this);
}
proximity.each(e -> isContainer(e) && e.items == items, outline);
proximity.each(e -> owns(e) && e.items == items, outline);
Draw.reset();
}
public boolean isContainer(Building tile){
return tile instanceof StorageBuild && (((StorageBuild)tile).linkedCore == this || ((StorageBuild)tile).linkedCore == null);
}
public boolean owns(Building tile){
return tile instanceof StorageBuild && (((StorageBuild)tile).linkedCore == this || ((StorageBuild)tile).linkedCore == null);
return owns(this, tile);
}
public boolean owns(Building core, Building tile){
return tile instanceof StorageBuild && (((StorageBuild)tile).linkedCore == core || ((StorageBuild)tile).linkedCore == null);
return tile instanceof StorageBuild b && (b.linkedCore == core || b.linkedCore == null);
}
public boolean incinerate(){
@ -340,7 +337,7 @@ public class CoreBlock extends StorageBlock{
int total = proximity.count(e -> e.items != null && e.items == items);
float fract = 1f / total / state.teams.cores(team).size;
proximity.each(e -> isContainer(e) && e.items == items && owns(e), t -> {
proximity.each(e -> owns(e) && e.items == items && owns(e), t -> {
StorageBuild ent = (StorageBuild)t;
ent.linkedCore = null;
ent.items = new ItemModule();

View file

@ -91,14 +91,16 @@ public class StorageBlock extends Block{
@Override
public void overwrote(Seq<Building> previous){
for(Building other : previous){
if(other.items != null){
items.add(other.items);
//only add prev items when core is not linked
if(linkedCore == null){
for(Building other : previous){
if(other.items != null && other.items != items){
items.add(other.items);
}
}
}
//ensure item counts are not too high
items.each((i, a) -> items.set(i, Math.min(a, itemCapacity)));
items.each((i, a) -> items.set(i, Math.min(a, itemCapacity)));
}
}
@Override

View file

@ -31,8 +31,8 @@ public class SNet implements SteamNetworkingCallback, SteamMatchmakingCallback,
final NetProvider provider;
final PacketSerializer serializer = new PacketSerializer();
final ByteBuffer writeBuffer = ByteBuffer.allocateDirect(1024 * 4);
final ByteBuffer readBuffer = ByteBuffer.allocateDirect(1024 * 4);
final ByteBuffer writeBuffer = ByteBuffer.allocateDirect(16384);
final ByteBuffer readBuffer = ByteBuffer.allocateDirect(16384);
final CopyOnWriteArrayList<SteamConnection> connections = new CopyOnWriteArrayList<>();
final IntMap<SteamConnection> steamConnections = new IntMap<>(); //maps steam ID -> valid net connection
@ -131,9 +131,10 @@ public class SNet implements SteamNetworkingCallback, SteamMatchmakingCallback,
writeBuffer.limit(writeBuffer.capacity());
writeBuffer.position(0);
serializer.write(writeBuffer, object);
int length = writeBuffer.position();
writeBuffer.flip();
snet.sendP2PPacket(currentServer, writeBuffer, mode == SendMode.tcp ? P2PSend.Reliable : P2PSend.UnreliableNoDelay, 0);
snet.sendP2PPacket(currentServer, writeBuffer, mode == SendMode.tcp || length >= 1200 ? P2PSend.Reliable : P2PSend.UnreliableNoDelay, 0);
}catch(Exception e){
net.showError(e);
}

View file

@ -0,0 +1,9 @@
[This is a truncated changelog, see Github for full notes]
- Fixed certain sectors having infinite waves in very specific situations
- Fixed various crashes
- Fixed community servers not displaying on Linux
- Fixed some logic UI bugs
- Fixed Distort filter not working in map post-generation
- Fixed clients in multiplayer not getting item unlocks
- Fixed enemy AI blocking ground unit paths in some circumstances
- Made night in campaign slightly less dark

View file

@ -46,5 +46,9 @@
{
"name": "Surrealment",
"address": ["md.surrealment.com"]
},
{
"name": "MindustryBR",
"address": ["mindustryptbr.ddns.net", "mindustryptbr.ddns.net:4444", "mindustryptbr.myddns.me:6666", "mindustryptbr.myddns.me:5555"]
}
]