Merge branch 'master' of https://github.com/Anuken/Mindustry into v105

This commit is contained in:
Petr Gašparík
2020-09-21 10:05:24 +02:00
174 changed files with 16037 additions and 12418 deletions
@@ -77,7 +77,11 @@ public class EntityProcess extends BaseProcessor{
for(Smethod elem : component.methods()){ for(Smethod elem : component.methods()){
if(elem.is(Modifier.ABSTRACT) || elem.is(Modifier.NATIVE)) continue; if(elem.is(Modifier.ABSTRACT) || elem.is(Modifier.NATIVE)) continue;
//get all statements in the method, store them //get all statements in the method, store them
methodBlocks.put(elem.descString(), elem.tree().getBody().toString()); methodBlocks.put(elem.descString(), elem.tree().getBody().toString()
//replace all self() invocations with this
.replaceAll("this\\.<(.*)>self\\(\\)", "this")
.replaceAll("self\\(\\)", "this")
);
} }
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 B

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 B

After

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 637 B

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 904 B

After

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 984 B

After

Width:  |  Height:  |  Size: 893 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

-1
View File
@@ -4,6 +4,5 @@
flattenPaths: true, flattenPaths: true,
maxWidth: 4096, maxWidth: 4096,
maxHeight: 4096, maxHeight: 4096,
minHeight: 2048,
fast: true fast: true
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

+13 -2
View File
@@ -20,7 +20,8 @@ gameover = Game Over
gameover.pvp = The[accent] {0}[] team is victorious! gameover.pvp = The[accent] {0}[] team is victorious!
highscore = [accent]New highscore! highscore = [accent]New highscore!
copied = Copied. copied = Copied.
indevpopup = [accent]v6[] is currently in [accent]alpha[].\n[lightgray]This means:[]\n[scarlet]- The campaign is completely unfinished[]\n- Content is missing\n - Most [scarlet]Unit AI[] does not work properly\n- Many units are unfinished\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[]. indev.popup = [accent]v6[] is currently in [accent]alpha[].\n[lightgray]This means:[]\n[scarlet]- The campaign is completely unfinished[]\n- Content is missing\n - Most [scarlet]Unit AI[] does not work properly\n- Many units are unfinished\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[].
indev.notready = This part of the game isn't ready yet
load.sound = Sounds load.sound = Sounds
load.map = Maps load.map = Maps
@@ -615,6 +616,8 @@ blocks.inaccuracy = Inaccuracy
blocks.shots = Shots blocks.shots = Shots
blocks.reload = Shots/Second blocks.reload = Shots/Second
blocks.ammo = Ammo blocks.ammo = Ammo
blocks.shieldhealth = Shield Health
blocks.cooldowntime = Cooldown Time
bar.drilltierreq = Better Drill Required bar.drilltierreq = Better Drill Required
bar.noresources = Missing Resources bar.noresources = Missing Resources
@@ -662,6 +665,7 @@ unit.persecond = /sec
unit.perminute = /min unit.perminute = /min
unit.timesspeed = x speed unit.timesspeed = x speed
unit.percent = % unit.percent = %
unit.shieldhealth = shield health
unit.items = items unit.items = items
unit.thousands = k unit.thousands = k
unit.millions = mil unit.millions = mil
@@ -789,6 +793,9 @@ keybind.diagonal_placement.name = Diagonal Placement
keybind.pick.name = Pick Block keybind.pick.name = Pick Block
keybind.break_block.name = Break Block keybind.break_block.name = Break Block
keybind.deselect.name = Deselect keybind.deselect.name = Deselect
keybind.pickupCargo.name = Pickup Cargo
keybind.dropCargo.name = Drop Cargo
keybind.command.name = Command
keybind.shoot.name = Shoot keybind.shoot.name = Shoot
keybind.zoom.name = Zoom keybind.zoom.name = Zoom
keybind.menu.name = Menu keybind.menu.name = Menu
@@ -876,9 +883,11 @@ liquid.water.name = Water
liquid.slag.name = Slag liquid.slag.name = Slag
liquid.oil.name = Oil liquid.oil.name = Oil
liquid.cryofluid.name = Cryofluid liquid.cryofluid.name = Cryofluid
item.explosiveness = [lightgray]Explosiveness: {0}% item.explosiveness = [lightgray]Explosiveness: {0}%
item.flammability = [lightgray]Flammability: {0}% item.flammability = [lightgray]Flammability: {0}%
item.radioactivity = [lightgray]Radioactivity: {0}% item.radioactivity = [lightgray]Radioactivity: {0}%
unit.health = [lightgray]Health: {0} unit.health = [lightgray]Health: {0}
unit.speed = [lightgray]Speed: {0} unit.speed = [lightgray]Speed: {0}
unit.weapon = [lightgray]Weapon: {0} unit.weapon = [lightgray]Weapon: {0}
@@ -914,6 +923,8 @@ unit.mega.name = Mega
unit.risso.name = Risso unit.risso.name = Risso
unit.minke.name = Minke unit.minke.name = Minke
unit.bryde.name = Bryde unit.bryde.name = Bryde
unit.sei.name = Sei
unit.omura.name = Omura
unit.alpha.name = Alpha unit.alpha.name = Alpha
unit.beta.name = Beta unit.beta.name = Beta
unit.gamma.name = Gamma unit.gamma.name = Gamma
@@ -979,6 +990,7 @@ block.dune-wall.name = Dune Wall
block.pine.name = Pine block.pine.name = Pine
block.dirt.name = Dirt block.dirt.name = Dirt
block.dirt-wall.name = Dirt Wall block.dirt-wall.name = Dirt Wall
block.mud.name = Mud
block.white-tree-dead.name = White Tree Dead block.white-tree-dead.name = White Tree Dead
block.white-tree.name = White Tree block.white-tree.name = White Tree
block.spore-cluster.name = Spore Cluster block.spore-cluster.name = Spore Cluster
@@ -997,7 +1009,6 @@ block.dark-metal.name = Dark Metal
block.basalt.name = Basalt block.basalt.name = Basalt
block.hotrock.name = Hot Rock block.hotrock.name = Hot Rock
block.magmarock.name = Magma Rock block.magmarock.name = Magma Rock
block.cliffs.name = Cliffs
block.copper-wall.name = Copper Wall block.copper-wall.name = Copper Wall
block.copper-wall-large.name = Large Copper Wall block.copper-wall-large.name = Large Copper Wall
block.titanium-wall.name = Titanium Wall block.titanium-wall.name = Titanium Wall
+34 -27
View File
@@ -803,7 +803,7 @@ rules.title.unit = 유닛
rules.title.experimental = 실험적인 기능 rules.title.experimental = 실험적인 기능
rules.title.environment = 환경 rules.title.environment = 환경
rules.lighting = 조명 rules.lighting = 조명
rules.ambientlight = 주변 조명 rules.ambientlight = 자연 조명
rules.solarpowermultiplier = 태양광 발전 배수 rules.solarpowermultiplier = 태양광 발전 배수
content.item.name = 자원 content.item.name = 자원
@@ -856,17 +856,20 @@ unit.crawler.name = 크롤러
unit.atrax.name = 아트락스 unit.atrax.name = 아트락스
unit.spiroct.name = 스피록트 unit.spiroct.name = 스피록트
unit.arkyid.name = 아키드 unit.arkyid.name = 아키드
unit.flare.name = 화염 unit.toxipod.name = 독소포드
unit.horizon.name = 수평선 unit.flare.name = 플레어
unit.zenith.name = 천정 unit.horizon.name = 호라이즌
unit.antumbra.name = 그림자 unit.zenith.name = 제니스
unit.eclipse.name = 일식 unit.antumbra.name = 안텀브라
unit.eclipse.name = 이클립스
unit.mono.name = 모노 unit.mono.name = 모노
unit.poly.name = 폴리 unit.poly.name = 폴리
unit.mega.name = 메가 unit.mega.name = 메가
unit.risso.name = 리소 unit.risso.name = 리소
unit.minke.name = 민케 unit.minke.name = 민케
unit.bryde.name = 브리드 unit.bryde.name = 브리드
unit.sei.name = 세이
unit.omura.name = 오무라
unit.alpha.name = 알파 unit.alpha.name = 알파
unit.beta.name = 베타 unit.beta.name = 베타
unit.gamma.name = 감마 unit.gamma.name = 감마
@@ -877,21 +880,21 @@ block.sand-boulder.name = 사암
block.grass.name = 잔디 block.grass.name = 잔디
block.slag.name = 광재 block.slag.name = 광재
block.salt.name = 소금 block.salt.name = 소금
block.saltrocks.name = 소금 바위 block.salt-wall.name = 소금
block.pebbles.name = 조약돌 block.pebbles.name = 조약돌
block.tendrils.name = 덩굴 block.tendrils.name = 덩굴
block.sandrocks.name = 모래 바위 block.sand-wall.name = 모래
block.spore-pine.name = 포자 덮인 소나무 block.spore-pine.name = 포자 덮인 소나무
block.sporerocks.name = 포자 바위 block.spore-wall.name = 포자
block.rock.name = block.boulder.name =
block.snowrock.name = 눈덩이 block.snow-boulder.name = 눈덩이
block.snow-pine.name = 눈 덮인 소나무 block.snow-pine.name = 눈 덮인 소나무
block.shale.name = 이판암 block.shale.name = 이판암
block.shale-boulder.name = 둥근 이판암 block.shale-boulder.name = 둥근 이판암
block.moss.name = 이끼 block.moss.name = 이끼
block.shrubs.name = 관목 block.shrubs.name = 관목
block.spore-moss.name = 포자 이끼 block.spore-moss.name = 포자 이끼
block.shalerocks.name = 이판암 바위 block.shale-wall.name = 이판암
block.scrap-wall.name = 조각벽 block.scrap-wall.name = 조각벽
block.scrap-wall-large.name = 대형 조각벽 block.scrap-wall-large.name = 대형 조각벽
block.scrap-wall-huge.name = 거대한 조각 벽 block.scrap-wall-huge.name = 거대한 조각 벽
@@ -910,6 +913,7 @@ block.water.name = 물
block.tainted-water.name = 오염된 물 block.tainted-water.name = 오염된 물
block.darksand-tainted-water.name = 오염된 젖은 검은 모래 block.darksand-tainted-water.name = 오염된 젖은 검은 모래
block.tar.name = 석유 block.tar.name = 석유
block.mud.name = 진흙
block.stone.name = 바위 block.stone.name = 바위
block.sand.name = 모래 block.sand.name = 모래
block.darksand.name = 검은 모래 block.darksand.name = 검은 모래
@@ -919,13 +923,16 @@ block.craters.name = 구덩이
block.sand-water.name = 젖은 모래 block.sand-water.name = 젖은 모래
block.darksand-water.name = 젖은 검은 모래 block.darksand-water.name = 젖은 검은 모래
block.char.name = block.char.name =
block.holostone.name = 홀로스톤 block.dacite.name = 데이사이트
block.dacite-wall.name = 데이사이트 벽
block.ice-snow.name = 얼음눈 block.ice-snow.name = 얼음눈
block.rocks.name = block.stone-wall.name =
block.icerocks.name = 얼음바위 block.ice-wall.name = 얼음
block.snowrocks.name = 바위 block.snow-wall.name =
block.dunerocks.name = 모래 block.dune-wall.name = 모래
block.pine.name = 소나무 block.pine.name = 소나무
block.dirt.name =
block.dirt-wall.name = 흙 벽
block.white-tree-dead.name = 죽은 하얀나무 block.white-tree-dead.name = 죽은 하얀나무
block.white-tree.name = 하얀 나무 block.white-tree.name = 하얀 나무
block.spore-cluster.name = 포자낭 block.spore-cluster.name = 포자낭
@@ -941,7 +948,7 @@ block.dark-panel-4.name = 어두운 패널 4
block.dark-panel-5.name = 어두운 패널 5 block.dark-panel-5.name = 어두운 패널 5
block.dark-panel-6.name = 어두운 패널 6 block.dark-panel-6.name = 어두운 패널 6
block.dark-metal.name = 어두운 금속제 block.dark-metal.name = 어두운 금속제
block.ignarock.name = 얼은 바위 block.basalt.name = 현무암
block.hotrock.name = 뜨거운 바위 block.hotrock.name = 뜨거운 바위
block.magmarock.name = 용암 바위 block.magmarock.name = 용암 바위
block.cliffs.name = 절벽 block.cliffs.name = 절벽
@@ -1011,7 +1018,7 @@ block.power-void.name = 방전장치
block.power-source.name = 전력 공급기 block.power-source.name = 전력 공급기
block.unloader.name = 언로더 block.unloader.name = 언로더
block.vault.name = 창고 block.vault.name = 창고
block.wave.name = 웨이브 block.wave.name = 파도
block.swarmer.name = 스워머 block.swarmer.name = 스워머
block.salvo.name = 살보 block.salvo.name = 살보
block.ripple.name = 립플 block.ripple.name = 립플
@@ -1019,7 +1026,7 @@ block.phase-conveyor.name = 메타 컨베이어
block.bridge-conveyor.name = 다리 컨베이어 block.bridge-conveyor.name = 다리 컨베이어
block.plastanium-compressor.name = 플라스터늄 압축기 block.plastanium-compressor.name = 플라스터늄 압축기
block.pyratite-mixer.name = 파이라타이트 혼합기 block.pyratite-mixer.name = 파이라타이트 혼합기
block.blast-mixer.name = 화합물 혼합기 block.blast-mixer.name = 폭발물 혼합기
block.solar-panel.name = 태양 전지판 block.solar-panel.name = 태양 전지판
block.solar-panel-large.name = 대형 태양 전지판 block.solar-panel-large.name = 대형 태양 전지판
block.oil-extractor.name = 석유 추출기 block.oil-extractor.name = 석유 추출기
@@ -1062,11 +1069,11 @@ block.additive-reconstructor.name = 첨가물 재구성기
block.multiplicative-reconstructor.name = 다중 재구성기 block.multiplicative-reconstructor.name = 다중 재구성기
block.exponential-reconstructor.name = 지수 재구성기 block.exponential-reconstructor.name = 지수 재구성기
block.tetrative-reconstructor.name = 정서 재구성기 block.tetrative-reconstructor.name = 정서 재구성기
block.payload-conveyor.name = 매스 컨베이어 block.payload-conveyor.name = 화물 컨베이어
block.payload-router.name = 화물 분배기 block.payload-router.name = 화물 분배기
block.disassembler.name = 분해기 block.disassembler.name = 가속 분해기
block.silicon-crucible.name = 실리콘 도가니 block.silicon-crucible.name = 실리콘 도가니
block.large-overdrive-projector.name = 대형 과부하 프로젝터 block.overdrive-dome.name = 대형 과부하 프로젝터
team.blue.name = 파랑색 팀 team.blue.name = 파랑색 팀
team.crux.name = 빨강색 팀 team.crux.name = 빨강색 팀
team.sharded.name = 주황색 팀 team.sharded.name = 주황색 팀
@@ -1099,7 +1106,7 @@ tutorial.launch = 특정 웨이브에 도달하면 [accent]코어로 출격[]
item.copper.description = 가장 기본적인 건설 재료. 모든 유형의 블록에서 광범위하게 사용됩니다. item.copper.description = 가장 기본적인 건설 재료. 모든 유형의 블록에서 광범위하게 사용됩니다.
item.lead.description = 기본 초반 재료. 전자 및 액체 수송 블록에서 광범위하게 사용되는 자원입니다. item.lead.description = 기본 초반 재료. 전자 및 액체 수송 블록에서 광범위하게 사용되는 자원입니다.
item.metaglass.description = 초강력 유리 화합물. 액체 분배 및 저장에 광범위하게 사용됩니다. item.metaglass.description = 초강력 방탄 유리. 액체 분배 및 저장에 광범위하게 사용됩니다.
item.graphite.description = 탄약 및 전기 부품에 사용되는 무기질 탄소. item.graphite.description = 탄약 및 전기 부품에 사용되는 무기질 탄소.
item.sand.description = 제련에서 합금 또는 플럭스에서 광범위하게 사용되는 일반적인 재료. item.sand.description = 제련에서 합금 또는 플럭스에서 광범위하게 사용되는 일반적인 재료.
item.coal.description = 화석화된 식물 물질. 씨앗이 나오기 훨씬 전에 형성되었습니다. 연료 및 자원 생산에 광범위하게 사용됩니다. item.coal.description = 화석화된 식물 물질. 씨앗이 나오기 훨씬 전에 형성되었습니다. 연료 및 자원 생산에 광범위하게 사용됩니다.
@@ -1127,7 +1134,7 @@ block.plastanium-compressor.description = 석유와 티타늄으로 플라스터
block.phase-weaver.description = 방사성 토륨과 모래에서 메타를 합성합니다. 작동하려면 엄청난 양의 전력이 필요합니다. block.phase-weaver.description = 방사성 토륨과 모래에서 메타를 합성합니다. 작동하려면 엄청난 양의 전력이 필요합니다.
block.alloy-smelter.description = 티타늄, 납, 실리콘, 구리를 결합하여 설금을 생산합니다. block.alloy-smelter.description = 티타늄, 납, 실리콘, 구리를 결합하여 설금을 생산합니다.
block.cryofluidmixer.description = 물과 미세 티타늄 분말을 냉각수로 혼합합니다. 토륨 원자로 사용에 필수적입니다. block.cryofluidmixer.description = 물과 미세 티타늄 분말을 냉각수로 혼합합니다. 토륨 원자로 사용에 필수적입니다.
block.blast-mixer.description = 포자 클러스터를 파이라타이트와 분쇄하고 혼합하여 화합물을 만듭니다. block.blast-mixer.description = 포자 클러스터를 파이라타이트와 분쇄하고 혼합하여 폭발물을 만듭니다.
block.pyratite-mixer.description = 석탄, 납, 모래를 가연성이 높은 파이라타이트로 만듭니다. block.pyratite-mixer.description = 석탄, 납, 모래를 가연성이 높은 파이라타이트로 만듭니다.
block.melter.description = 웨이브 포탑에서 추가 처리 또는 사용을 위해 고철을 광재로 녹입니다. block.melter.description = 웨이브 포탑에서 추가 처리 또는 사용을 위해 고철을 광재로 녹입니다.
block.separator.description = 광재를 미네랄 성분으로 분리합니다. 그리고 냉각된 결과를 출력합니다. block.separator.description = 광재를 미네랄 성분으로 분리합니다. 그리고 냉각된 결과를 출력합니다.
@@ -1194,7 +1201,7 @@ block.combustion-generator.description = 석탄과 같은 가연성 물질을
block.thermal-generator.description = 열이 있는 곳에 설치하면 전력이 생성됩니다. block.thermal-generator.description = 열이 있는 곳에 설치하면 전력이 생성됩니다.
block.steam-generator.description = 고급 연소 발전기. 더 효율적이지만 증기를 생성하기 위해 물이 필요합니다. block.steam-generator.description = 고급 연소 발전기. 더 효율적이지만 증기를 생성하기 위해 물이 필요합니다.
block.differential-generator.description = 많은 양의 전력을 생성합니다. 냉각수와 불타는 파이라타이트의 온도 차이를 이용합니다. block.differential-generator.description = 많은 양의 전력을 생성합니다. 냉각수와 불타는 파이라타이트의 온도 차이를 이용합니다.
block.rtg-generator.description = 간단하고 안정적인 발전기. 붕괴하는 방사성 화합물의 열을 이용하여 느린 속도로 전력을 생성합니다. block.rtg-generator.description = 간단하고 안정적인 발전기. 붕괴하는 방사성 물의 열을 이용하여 느린 속도로 전력을 생성합니다.
block.solar-panel.description = 태양으로부터 소량의 전력을 생성합니다. block.solar-panel.description = 태양으로부터 소량의 전력을 생성합니다.
block.solar-panel-large.description = 표준 태양 전지판보다 훨씬 더 효율적인 버전. block.solar-panel-large.description = 표준 태양 전지판보다 훨씬 더 효율적인 버전.
block.thorium-reactor.description = 토륨으로부터 상당한 양의 전력을 생산합니다. 지속적인 냉각이 필요하며, 충분한 양의 냉각수가 공급되지 않으면 크게 폭발합니다. 전력 출력은 토륨의 양에 따라 달라집니다. block.thorium-reactor.description = 토륨으로부터 상당한 양의 전력을 생산합니다. 지속적인 냉각이 필요하며, 충분한 양의 냉각수가 공급되지 않으면 크게 폭발합니다. 전력 출력은 토륨의 양에 따라 달라집니다.
@@ -1228,5 +1235,5 @@ block.ripple.description = 매우 강력한 포병 포탑. 원거리에 있는
block.cyclone.description = 대공 및 대지 포탑. 근처 유닛에게 폭발성 덩어리를 발사합니다. block.cyclone.description = 대공 및 대지 포탑. 근처 유닛에게 폭발성 덩어리를 발사합니다.
block.spectre.description = 거대한 이중 배럴 대포. 공중 및 지상 목표물에 큰 관통 철갑탄을 발사합니다. block.spectre.description = 거대한 이중 배럴 대포. 공중 및 지상 목표물에 큰 관통 철갑탄을 발사합니다.
block.meltdown.description = 거대한 레이저 대포. 근처의 적에게 지속적인 레이버 빔을 충전하여 발사합니다. 냉각수가 있어야 작동합니다. block.meltdown.description = 거대한 레이저 대포. 근처의 적에게 지속적인 레이버 빔을 충전하여 발사합니다. 냉각수가 있어야 작동합니다.
block.repair-point.description = 주변에서 가장 가까운 유닛을 지속적으로 치료합니다. block.repair-point.description = 주변에서 가장 가까운 유닛을 지속적으로 치료합니다.
block.segment.description = 날아오는 발사체를 요격합니다. 레이저는 목표 대상이 아닙니다. block.segment.description = 날아오는 발사체를 요격합니다. 레이저는 목표 대상이 아닙니다.
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -20,7 +20,8 @@ gameover = Игра окончена
gameover.pvp = [accent]{0}[] команда победила! gameover.pvp = [accent]{0}[] команда победила!
highscore = [accent]Новый рекорд! highscore = [accent]Новый рекорд!
copied = Скопировано. copied = Скопировано.
indevpopup = [accent]v6[] находится на стадии [accent]alpha[].\n[lightgray]Это означает следующее:[]\n- Отсутствие контента.\n- Большинство [scarlet]ИИ единиц[] не работает.\n- Множество единиц не готово.\n- Кампания не завершена.\n- Всё, что вы видите, может быть изменено или удалено.\n\nСообщайте о багах и вылетах на [accent]Github[]. indev.popup = [accent]v6[] находится на стадии [accent]alpha[].\n[lightgray]Это означает следующее:[]\n- Отсутствие контента.\n- Большинство [scarlet]ИИ единиц[] не работает.\n- Множество единиц не готово.\n- Кампания не завершена.\n- Всё, что вы видите, может быть изменено или удалено.\n\nСообщайте о багах и вылетах на [accent]Github[].
indev.notready = Эта часть игры ещё не готова
load.sound = Звуки load.sound = Звуки
load.map = Карты load.map = Карты
+2 -1
View File
@@ -20,7 +20,8 @@ gameover = Гра завершена
gameover.pvp = [accent]{0}[] команда перемогла! gameover.pvp = [accent]{0}[] команда перемогла!
highscore = [accent]Новий рекорд! highscore = [accent]Новий рекорд!
copied = Скопійовано. copied = Скопійовано.
indevpopup = Наразі [accent]6.0[] знаходиться у стадії [accent]альфа[].\n[lightgray]Це означає наступне:[]\n- Не вистачає наповнення гри;\n- Більшість [scarlet]ШІ бойових одиниць[] не працює належним чином;\n- Багато одиниць [scarlet]відсутні[] або незавершені;\n- Кампанія повністю не є завершеною;\n- Усе, що ви бачите, може змінитися або видалитися.\n\nПовідомляйте про вади або збої на [accent]Github[], а про помилки в перекладі в Discord. indev.popup = Наразі [accent]6.0[] знаходиться у стадії [accent]альфа[].\n[lightgray]Це означає наступне:[]\n- Не вистачає наповнення гри;\n- Більшість [scarlet]ШІ бойових одиниць[] не працює належним чином;\n- Багато одиниць [scarlet]відсутні[] або незавершені;\n- Кампанія повністю не є завершеною;\n- Усе, що ви бачите, може змінитися або видалитися.\n\nПовідомляйте про вади або збої на [accent]Github[], а про помилки в перекладі в Discord.
indev.notready = Ця частина гри ще не готова
load.sound = Звуки load.sound = Звуки
load.map = Мапи load.map = Мапи
+1
View File
@@ -90,3 +90,4 @@ DeltaNedas
GioIacca9 GioIacca9
SnakkiZXZ SnakkiZXZ
sk7725 sk7725
ThePlayerA
+4
View File
@@ -311,3 +311,7 @@
63433=dacite-wall|block-dacite-wall-medium 63433=dacite-wall|block-dacite-wall-medium
63432=dacite-boulder|block-dacite-boulder-medium 63432=dacite-boulder|block-dacite-boulder-medium
63431=large-logic-display|block-large-logic-display-medium 63431=large-logic-display|block-large-logic-display-medium
63430=omura|unit-omura-medium
63429=mud|block-mud-medium
63428=sei|unit-sei-medium
63427=quad|unit-quad-medium
Binary file not shown.
+1
View File
@@ -74,6 +74,7 @@ importPackage(Packages.mindustry.gen)
importPackage(Packages.mindustry.graphics) importPackage(Packages.mindustry.graphics)
importPackage(Packages.mindustry.graphics.g3d) importPackage(Packages.mindustry.graphics.g3d)
importPackage(Packages.mindustry.input) importPackage(Packages.mindustry.input)
importPackage(Packages.mindustry.io)
importPackage(Packages.mindustry.logic) importPackage(Packages.mindustry.logic)
importPackage(Packages.mindustry.maps) importPackage(Packages.mindustry.maps)
importPackage(Packages.mindustry.maps.filters) importPackage(Packages.mindustry.maps.filters)
+29
View File
@@ -0,0 +1,29 @@
#define HIGHP
#define NSCALE 180.0 / 2.0
uniform sampler2D u_texture;
uniform sampler2D u_noise;
uniform vec2 u_campos;
uniform vec2 u_resolution;
uniform float u_time;
varying vec2 v_texCoords;
void main(){
vec2 c = v_texCoords.xy;
vec2 coords = vec2(c.x * u_resolution.x + u_campos.x, c.y * u_resolution.y + u_campos.y);
float btime = u_time / 70000.0;
float noise = sin((texture2D(u_noise, (coords) / NSCALE + vec2(btime) * vec2(-0.9, 0.8)).r + texture2D(u_noise, (coords) / NSCALE + vec2(abs(sin(btime)) * 1.1) * vec2(-0.8, -1.0)).r) / 2.0);
vec4 color = texture2D(u_texture, c);
if(noise > 0.54 && noise < 0.68){
color.rgb *= 1.4;
}else if(!(noise > 0.40 && noise < 0.54)){
color.rgb *= 1.2;
}
gl_FragColor = color;
}
+4 -6
View File
@@ -22,12 +22,10 @@ void main(){
float noise = (texture2D(u_noise, (coords) / NSCALE + vec2(btime) * vec2(-0.9, 0.8)).r + texture2D(u_noise, (coords) / NSCALE + vec2(btime * 1.1) * vec2(0.8, -1.0)).r) / 2.0; float noise = (texture2D(u_noise, (coords) / NSCALE + vec2(btime) * vec2(-0.9, 0.8)).r + texture2D(u_noise, (coords) / NSCALE + vec2(btime * 1.1) * vec2(0.8, -1.0)).r) / 2.0;
vec4 color = texture2D(u_texture, c); vec4 color = texture2D(u_texture, c);
if(color.a > 0.1){ if(noise > 0.6){
if(noise > 0.6){ color.rgb = S2;
color.rgb = S2; }else if (noise > 0.54){
}else if (noise > 0.54){ color.rgb = S1;
color.rgb = S1;
}
} }
gl_FragColor = color; gl_FragColor = color;
+1 -1
View File
@@ -20,7 +20,7 @@ void main(){
vec4 color = texture2D(u_texture, c); vec4 color = texture2D(u_texture, c);
if(!(noise > 0.54 && noise < 0.58)){ if(!(noise > 0.54 && noise < 0.58)){
color.rgb *= 0.6; color.rgb *= vec3(0.6, 0.6, 0.7);
} }
gl_FragColor = color; gl_FragColor = color;
Binary file not shown.

Before

Width:  |  Height:  |  Size: 811 B

After

Width:  |  Height:  |  Size: 810 B

File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 647 KiB

After

Width:  |  Height:  |  Size: 639 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 958 KiB

After

Width:  |  Height:  |  Size: 760 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 365 KiB

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 KiB

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 317 KiB

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 415 KiB

After

Width:  |  Height:  |  Size: 416 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 314 KiB

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 418 KiB

After

Width:  |  Height:  |  Size: 420 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

+7 -38
View File
@@ -33,7 +33,7 @@ public class BlockIndexer{
/** Maps each team ID to a quarant. A quadrant is a grid of bits, where each bit is set if and only if there is a block of that team in that quadrant. */ /** Maps each team ID to a quarant. A quadrant is a grid of bits, where each bit is set if and only if there is a block of that team in that quadrant. */
private GridBits[] structQuadrants; private GridBits[] structQuadrants;
/** Stores all damaged tile entities by team. */ /** Stores all damaged tile entities by team. */
private BuildingArray[] damagedTiles = new BuildingArray[Team.all.length]; private ObjectSet<Building>[] damagedTiles = new ObjectSet[Team.all.length];
/** All ores available on this map. */ /** All ores available on this map. */
private ObjectSet<Item> allOres = new ObjectSet<>(); private ObjectSet<Item> allOres = new ObjectSet<>();
/** Stores teams that are present here as tiles. */ /** Stores teams that are present here as tiles. */
@@ -70,7 +70,7 @@ public class BlockIndexer{
Events.on(WorldLoadEvent.class, event -> { Events.on(WorldLoadEvent.class, event -> {
scanOres.clear(); scanOres.clear();
scanOres.addAll(Item.getAllOres()); scanOres.addAll(Item.getAllOres());
damagedTiles = new BuildingArray[Team.all.length]; damagedTiles = new ObjectSet[Team.all.length];
flagMap = new TileArray[Team.all.length][BlockFlag.all.length]; flagMap = new TileArray[Team.all.length][BlockFlag.all.length];
unitCaps = new int[Team.all.length]; unitCaps = new int[Team.all.length];
activeTeams = new Seq<>(Team.class); activeTeams = new Seq<>(Team.class);
@@ -139,14 +139,14 @@ public class BlockIndexer{
} }
/** Returns all damaged tiles by team. */ /** Returns all damaged tiles by team. */
public BuildingArray getDamaged(Team team){ public ObjectSet<Building> getDamaged(Team team){
returnArray.clear(); breturnArray.clear();
if(damagedTiles[team.id] == null){ if(damagedTiles[team.id] == null){
damagedTiles[team.id] = new BuildingArray(); damagedTiles[team.id] = new ObjectSet<>();
} }
BuildingArray set = damagedTiles[team.id]; ObjectSet<Building> set = damagedTiles[team.id];
for(Building build : set){ for(Building build : set){
if((!build.isValid() || build.team != team || !build.damaged()) || build.block instanceof ConstructBlock){ if((!build.isValid() || build.team != team || !build.damaged()) || build.block instanceof ConstructBlock){
breturnArray.add(build); breturnArray.add(build);
@@ -214,7 +214,7 @@ public class BlockIndexer{
public void notifyTileDamaged(Building entity){ public void notifyTileDamaged(Building entity){
if(damagedTiles[entity.team.id] == null){ if(damagedTiles[entity.team.id] == null){
damagedTiles[entity.team.id] = new BuildingArray(); damagedTiles[entity.team.id] = new ObjectSet<Building>();
} }
damagedTiles[entity.team.id].add(entity); damagedTiles[entity.team.id].add(entity);
@@ -476,35 +476,4 @@ public class BlockIndexer{
return tiles.iterator(); return tiles.iterator();
} }
} }
//TODO copy-pasted code, generics would be nice here
public static class BuildingArray implements Iterable<Building>{
private Seq<Building> tiles = new Seq<>(false, 16);
private IntSet contained = new IntSet();
public void add(Building tile){
if(contained.add(tile.pos())){
tiles.add(tile);
}
}
public void remove(Building tile){
if(contained.remove(tile.pos())){
tiles.remove(tile);
}
}
public int size(){
return tiles.size;
}
public Building first(){
return tiles.first();
}
@Override
public Iterator<Building> iterator(){
return tiles.iterator();
}
}
} }
+1 -1
View File
@@ -59,7 +59,7 @@ public class Pathfinder implements Runnable{
Flowfield[][][] cache; Flowfield[][][] cache;
/** tile data, see PathTileStruct */ /** tile data, see PathTileStruct */
int[][] tiles; int[][] tiles = new int[0][0];
/** unordered array of path data for iteration only. DO NOT iterate or access this in the main thread. */ /** unordered array of path data for iteration only. DO NOT iterate or access this in the main thread. */
Seq<Flowfield> threadList = new Seq<>(), mainList = new Seq<>(); Seq<Flowfield> threadList = new Seq<>(), mainList = new Seq<>();
/** handles task scheduling on the update thread. */ /** handles task scheduling on the update thread. */
@@ -5,20 +5,14 @@ import arc.math.geom.*;
import mindustry.ai.formations.*; import mindustry.ai.formations.*;
public class CircleFormation extends FormationPattern{ public class CircleFormation extends FormationPattern{
/** The radius of one member. This is needed to determine how close we can pack a given number of members around circle. */
public float memberRadius;
/** Angle offset. */ /** Angle offset. */
public float angleOffset = 0; public float angleOffset = 0;
public CircleFormation(float memberRadius){
this.memberRadius = memberRadius;
}
@Override @Override
public Vec3 calculateSlotLocation(Vec3 outLocation, int slotNumber){ public Vec3 calculateSlotLocation(Vec3 outLocation, int slotNumber){
if(slots > 1){ if(slots > 1){
float angle = (360f * slotNumber) / slots; float angle = (360f * slotNumber) / slots;
float radius = memberRadius / (float)Math.sin(180f / slots * Mathf.degRad); float radius = spacing / (float)Math.sin(180f / slots * Mathf.degRad);
outLocation.set(Angles.trnsx(angle, radius), Angles.trnsy(angle, radius), angle); outLocation.set(Angles.trnsx(angle, radius), Angles.trnsy(angle, radius), angle);
}else{ }else{
outLocation.set(0, 0, 360f * slotNumber); outLocation.set(0, 0, 360f * slotNumber);
+1 -2
View File
@@ -1,7 +1,6 @@
package mindustry.ai.types; package mindustry.ai.types;
import arc.math.*; import arc.math.*;
import arc.util.*;
import mindustry.entities.units.*; import mindustry.entities.units.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.world.meta.*; import mindustry.world.meta.*;
@@ -59,7 +58,7 @@ public class FlyingAI extends AIController{
vec.setAngle(Mathf.slerpDelta(unit.vel().angle(), vec.angle(), 0.6f)); vec.setAngle(Mathf.slerpDelta(unit.vel().angle(), vec.angle(), 0.6f));
} }
vec.setLength(unit.type().speed * Time.delta); vec.setLength(unit.type().speed);
unit.moveAt(vec); unit.moveAt(vec);
} }
+19 -18
View File
@@ -2,10 +2,10 @@ package mindustry.ai.types;
import arc.math.geom.*; import arc.math.geom.*;
import arc.util.ArcAnnotate.*; import arc.util.ArcAnnotate.*;
import mindustry.*;
import mindustry.ai.formations.*; import mindustry.ai.formations.*;
import mindustry.entities.units.*; import mindustry.entities.units.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.type.*;
public class FormationAI extends AIController implements FormationMember{ public class FormationAI extends AIController implements FormationMember{
public Unit leader; public Unit leader;
@@ -25,39 +25,40 @@ public class FormationAI extends AIController implements FormationMember{
@Override @Override
public void updateUnit(){ public void updateUnit(){
UnitType type = unit.type();
if(leader.dead){ if(leader.dead){
unit.resetController(); unit.resetController();
return; return;
} }
unit.controlWeapons(leader.isRotate(), leader.isShooting); unit.controlWeapons(true, leader.isShooting);
// unit.moveAt(Tmp.v1.set(deltaX, deltaY).limit(unit.type().speed)); // unit.moveAt(Tmp.v1.set(deltaX, deltaY).limit(unit.type().speed));
if(leader.isShooting){
unit.aimLook(leader.aimX(), leader.aimY()); unit.aim(leader.aimX(), leader.aimY());
}else{
if(!leader.moving() || !unit.type().rotateShooting){ if(unit.type().rotateShooting){
if(unit.moving()){ unit.lookAt(leader.aimX(), leader.aimY());
unit.lookAt(unit.vel.angle()); }else if(unit.moving()){
} unit.lookAt(unit.vel.angle());
}else{
unit.lookAt(leader.rotation);
}
} }
Vec2 realtarget = vec.set(target); Vec2 realtarget = vec.set(target);
if(unit.isGrounded() && Vars.world.raycast(unit.tileX(), unit.tileY(), leader.tileX(), leader.tileY(), Vars.world::solid)){ float margin = 3f;
//TODO pathfind
//realtarget.set(Vars.pathfinder.getTargetTile(unit.tileOn(), unit.team, leader));
}
unit.moveAt(realtarget.sub(unit).limit(unit.type().speed)); if(unit.dst(realtarget) <= margin){
unit.vel.approachDelta(Vec2.ZERO, type.speed * type.accel / 2f);
}else{
unit.moveAt(realtarget.sub(unit).limit(type.speed));
}
} }
@Override @Override
public void removed(Unit unit){ public void removed(Unit unit){
if(formation != null){ if(formation != null){
formation.removeMember(this); formation.removeMember(this);
unit.resetController();
} }
} }
@@ -67,7 +68,7 @@ public class FormationAI extends AIController implements FormationMember{
//TODO return formation size //TODO return formation size
//eturn ((Commanderc)unit).formation(). //eturn ((Commanderc)unit).formation().
} }
return unit.hitSize * 1.7f; return unit.hitSize * 1f;
} }
@Override @Override
+2 -2
View File
@@ -49,10 +49,10 @@ public class GroundAI extends AIController{
unit.elevation = Mathf.approachDelta(unit.elevation, 0f, 0.08f); unit.elevation = Mathf.approachDelta(unit.elevation, 0f, 0.08f);
} }
if(!Units.invalidateTarget(target, unit, unit.range())){ if(!Units.invalidateTarget(target, unit, unit.range()) && unit.type().rotateShooting){
if(unit.type().hasWeapons()){ if(unit.type().hasWeapons()){
//TODO certain units should not look at the target, e.g. ships //TODO certain units should not look at the target, e.g. ships
unit.aimLook(Predict.intercept(unit, target, unit.type().weapons.first().bullet.speed)); unit.lookAt(Predict.intercept(unit, target, unit.type().weapons.first().bullet.speed));
} }
}else if(unit.moving()){ }else if(unit.moving()){
unit.lookAt(unit.vel().angle()); unit.lookAt(unit.vel().angle());
+1 -1
View File
@@ -44,7 +44,7 @@ public class MinerAI extends AIController{
} }
if(ore != null){ if(ore != null){
moveTo(ore, unit.type().range / 1.5f); moveTo(ore, unit.type().range / 2f);
if(unit.within(ore, unit.type().range)){ if(unit.within(ore, unit.type().range)){
miner.mineTile(ore); miner.mineTile(ore);
+2 -2
View File
@@ -12,8 +12,8 @@ public class RepairAI extends AIController{
boolean shoot = false; boolean shoot = false;
if(target != null){ if(target != null){
if(!target.within(unit, unit.type().range)){ if(!target.within(unit, unit.type().range * 0.8f)){
moveTo(target, unit.type().range * 0.9f); moveTo(target, unit.type().range * 0.8f);
}else{ }else{
unit.aim(target); unit.aim(target);
shoot = true; shoot = true;
@@ -35,6 +35,7 @@ public class PhysicsProcess implements AsyncProcess{
refs.removeAll(ref -> { refs.removeAll(ref -> {
if(!ref.entity.isAdded()){ if(!ref.entity.isAdded()){
physics.destroyBody(ref.body); physics.destroyBody(ref.body);
ref.entity.physref(null);
return true; return true;
} }
return false; return false;
+15 -2
View File
@@ -5,6 +5,7 @@ import mindustry.*;
import mindustry.game.*; import mindustry.game.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.world.blocks.payloads.*;
import java.util.*; import java.util.*;
@@ -48,6 +49,19 @@ public class TeamIndexProcess implements AsyncProcess{
activeCounts[team.id][type.id] += amount; activeCounts[team.id][type.id] += amount;
} }
private void count(Unit unit){
updateCount(unit.team, unit.type(), 1);
if(!unit.deactivated) updateActiveCount(unit.team, unit.type(), 1);
if(unit instanceof Payloadc){
((Payloadc)unit).payloads().each(p -> {
if(p instanceof UnitPayload){
count(((UnitPayload)p).unit);
}
});
}
}
@Override @Override
public void reset(){ public void reset(){
counts = new int[Team.all.length]; counts = new int[Team.all.length];
@@ -71,8 +85,7 @@ public class TeamIndexProcess implements AsyncProcess{
for(Unit unit : Groups.unit){ for(Unit unit : Groups.unit){
tree(unit.team).insert(unit); tree(unit.team).insert(unit);
updateCount(unit.team, unit.type(), 1); count(unit);
if(!unit.deactivated) updateActiveCount(unit.team, unit.type(), 1);
} }
} }
+21 -8
View File
@@ -34,7 +34,7 @@ public class Blocks implements ContentList{
public static Block public static Block
//environment //environment
air, spawn, cliff, deepwater, water, taintedWater, tar, slag, stone, craters, charr, sand, darksand, dirt, ice, snow, darksandTaintedWater, air, spawn, cliff, deepwater, water, taintedWater, tar, slag, stone, craters, charr, sand, darksand, dirt, mud, ice, snow, darksandTaintedWater,
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, grass, salt, iceSnow, sandWater, darksandWater, duneWall, sandWall, moss, sporeMoss, shale, shaleWall, shaleBoulder, sandBoulder, daciteBoulder, grass, salt,
metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, basalt, magmarock, hotrock, snowWall, boulder, snowBoulder, saltWall, metalFloor, metalFloorDamaged, metalFloor2, metalFloor3, metalFloor5, basalt, magmarock, hotrock, snowWall, boulder, snowBoulder, saltWall,
@@ -260,6 +260,16 @@ public class Blocks implements ContentList{
dirt = new Floor("dirt"); dirt = new Floor("dirt");
mud = new Floor("mud"){{
speedMultiplier = 0.6f;
variants = 3;
status = StatusEffects.muddy;
statusDuration = 30f;
attributes.set(Attribute.water, 2f);
cacheLayer = CacheLayer.mud;
albedo = 0.35f;
}};
((ShallowLiquid)darksandTaintedWater).set(Blocks.taintedWater, Blocks.darksand); ((ShallowLiquid)darksandTaintedWater).set(Blocks.taintedWater, Blocks.darksand);
((ShallowLiquid)sandWater).set(Blocks.water, Blocks.sand); ((ShallowLiquid)sandWater).set(Blocks.water, Blocks.sand);
((ShallowLiquid)darksandWater).set(Blocks.water, Blocks.darksand); ((ShallowLiquid)darksandWater).set(Blocks.water, Blocks.darksand);
@@ -327,11 +337,12 @@ public class Blocks implements ContentList{
duneWall = new StaticWall("dune-wall"){{ duneWall = new StaticWall("dune-wall"){{
variants = 2; variants = 2;
basalt.asFloor().wall = this; basalt.asFloor().wall = darksandWater.asFloor().wall = darksandTaintedWater.asFloor().wall = this;
}}; }};
sandWall = new StaticWall("sand-wall"){{ sandWall = new StaticWall("sand-wall"){{
variants = 2; variants = 2;
sandWater.asFloor().wall = this;
}}; }};
saltWall = new StaticWall("salt-wall"); saltWall = new StaticWall("salt-wall");
@@ -791,7 +802,7 @@ public class Blocks implements ContentList{
}}; }};
door = new Door("door"){{ door = new Door("door"){{
requirements(Category.defense, with(Items.graphite, 6, Items.silicon, 4)); requirements(Category.defense, with(Items.titanium, 6, Items.silicon, 4));
health = 100 * wallHealthMultiplier; health = 100 * wallHealthMultiplier;
}}; }};
@@ -1011,7 +1022,7 @@ public class Blocks implements ContentList{
mechanicalPump = new Pump("mechanical-pump"){{ mechanicalPump = new Pump("mechanical-pump"){{
requirements(Category.liquid, with(Items.copper, 15, Items.metaglass, 10)); requirements(Category.liquid, with(Items.copper, 15, Items.metaglass, 10));
pumpAmount = 0.1f; pumpAmount = 0.11f;
}}; }};
rotaryPump = new Pump("rotary-pump"){{ rotaryPump = new Pump("rotary-pump"){{
@@ -1136,7 +1147,7 @@ public class Blocks implements ContentList{
requirements(Category.power, with(Items.copper, 35, Items.graphite, 25, Items.lead, 40, Items.silicon, 30)); requirements(Category.power, with(Items.copper, 35, Items.graphite, 25, Items.lead, 40, Items.silicon, 30));
powerProduction = 5.5f; powerProduction = 5.5f;
itemDuration = 90f; itemDuration = 90f;
consumes.liquid(Liquids.water, 0.06f); consumes.liquid(Liquids.water, 0.07f);
hasLiquids = true; hasLiquids = true;
size = 2; size = 2;
}}; }};
@@ -1269,7 +1280,7 @@ public class Blocks implements ContentList{
hasItems = true; hasItems = true;
consumes.power(0.80f); consumes.power(0.80f);
consumes.liquid(Liquids.water, 0.18f); consumes.liquid(Liquids.water, 0.2f);
}}; }};
oilExtractor = new Fracker("oil-extractor"){{ oilExtractor = new Fracker("oil-extractor"){{
@@ -1645,7 +1656,7 @@ public class Blocks implements ContentList{
}}; }};
spectre = new ItemTurret("spectre"){{ spectre = new ItemTurret("spectre"){{
requirements(Category.turret, with(Items.copper, 350, Items.graphite, 300, Items.surgealloy, 250, Items.plastanium, 175, Items.thorium, 250)); requirements(Category.turret, with(Items.copper, 900, Items.graphite, 300, Items.surgealloy, 250, Items.plastanium, 175, Items.thorium, 250));
ammo( ammo(
Items.graphite, Bullets.standardDenseBig, Items.graphite, Bullets.standardDenseBig,
Items.pyratite, Bullets.standardIncendiaryBig, Items.pyratite, Bullets.standardIncendiaryBig,
@@ -1671,7 +1682,7 @@ public class Blocks implements ContentList{
}}; }};
meltdown = new LaserTurret("meltdown"){{ meltdown = new LaserTurret("meltdown"){{
requirements(Category.turret, with(Items.copper, 250, Items.lead, 350, Items.graphite, 300, Items.surgealloy, 325, Items.silicon, 325)); requirements(Category.turret, with(Items.copper, 1200, Items.lead, 350, Items.graphite, 300, Items.surgealloy, 325, Items.silicon, 325));
shootEffect = Fx.shootBigSmoke2; shootEffect = Fx.shootBigSmoke2;
shootCone = 40f; shootCone = 40f;
recoilAmount = 4f; recoilAmount = 4f;
@@ -1793,6 +1804,7 @@ public class Blocks implements ContentList{
{UnitTypes.zenith, UnitTypes.antumbra}, {UnitTypes.zenith, UnitTypes.antumbra},
{UnitTypes.spiroct, UnitTypes.arkyid}, {UnitTypes.spiroct, UnitTypes.arkyid},
{UnitTypes.fortress, UnitTypes.scepter}, {UnitTypes.fortress, UnitTypes.scepter},
{UnitTypes.bryde, UnitTypes.sei},
}; };
}}; }};
@@ -1811,6 +1823,7 @@ public class Blocks implements ContentList{
{UnitTypes.antumbra, UnitTypes.eclipse}, {UnitTypes.antumbra, UnitTypes.eclipse},
{UnitTypes.arkyid, UnitTypes.toxopid}, {UnitTypes.arkyid, UnitTypes.toxopid},
{UnitTypes.scepter, UnitTypes.reign}, {UnitTypes.scepter, UnitTypes.reign},
{UnitTypes.sei, UnitTypes.omura}
}; };
}}; }};
+3 -3
View File
@@ -269,13 +269,13 @@ public class Bullets implements ContentList{
status = StatusEffects.burning; status = StatusEffects.burning;
}}; }};
missileSurge = new MissileBulletType(3.7f, 20){{ missileSurge = new MissileBulletType(3.7f, 18){{
width = 8f; width = 8f;
height = 8f; height = 8f;
shrinkY = 0f; shrinkY = 0f;
drag = -0.01f; drag = -0.01f;
splashDamageRadius = 28f; splashDamageRadius = 25f;
splashDamage = 35f; splashDamage = 25f;
hitEffect = Fx.blastExplosion; hitEffect = Fx.blastExplosion;
despawnEffect = Fx.blastExplosion; despawnEffect = Fx.blastExplosion;
lightning = 2; lightning = 2;
+83 -3
View File
@@ -290,6 +290,22 @@ public class Fx{
Lines.spikes(e.x, e.y, 1f + e.fin() * 6f, e.fout() * 4f, 6); Lines.spikes(e.x, e.y, 1f + e.fin() * 6f, e.fout() * 4f, 6);
}), }),
healBomb = new Effect(40f, 100f, e -> {
color(Pal.heal);
stroke(e.fout() * 2f);
Lines.circle(e.x, e.y, 4f + e.finpow() * 65f);
color(Pal.heal);
for(int i = 0; i < 4; i++){
Drawf.tri(e.x, e.y, 6f, 100f * e.fout(), i*90);
}
color();
for(int i = 0; i < 4; i++){
Drawf.tri(e.x, e.y, 3f, 35f * e.fout(), i*90);
}
}),
healWave = new Effect(22, e -> { healWave = new Effect(22, e -> {
color(Pal.heal); color(Pal.heal);
stroke(e.fout() * 2f); stroke(e.fout() * 2f);
@@ -686,6 +702,13 @@ public class Fx{
Fill.circle(e.x, e.y, e.fout() * 1f); Fill.circle(e.x, e.y, e.fout() * 1f);
}), }),
muddy = new Effect(80f, e -> {
color(Color.valueOf("432722"));
alpha(Mathf.clamp(e.fin() * 2f));
Fill.circle(e.x, e.y, e.fout() * 1f);
}),
sapped = new Effect(40f, e -> { sapped = new Effect(40f, e -> {
color(Pal.sap); color(Pal.sap);
@@ -989,6 +1012,53 @@ public class Fx{
}).ground(400f), }).ground(400f),
railShoot = new Effect(24f, e -> {
e.scaled(10f, b -> {
color(Color.white, Color.lightGray, b.fin());
stroke(b.fout() * 3f + 0.2f);
Lines.circle(b.x, b.y, b.fin() * 50f);
});
color(Pal.orangeSpark);
for(int i : Mathf.signs){
Drawf.tri(e.x, e.y, 13f * e.fout(), 85f, e.rotation + 90f * i);
}
}),
railTrail = new Effect(16f, e -> {
color(Pal.orangeSpark);
for(int i : Mathf.signs){
Drawf.tri(e.x, e.y, 10f * e.fout(), 24f, e.rotation + 90 + 90f * i);
}
}),
railHit = new Effect(18f, 200f, e -> {
if(true){
color(Pal.orangeSpark);
for(int i : Mathf.signs){
Drawf.tri(e.x, e.y, 10f * e.fout(), 60f, e.rotation + 140f * i);
}
}else{
e.scaled(7f, b -> {
color(Color.white, Color.lightGray, b.fin());
stroke(b.fout() * 2f + 0.2f);
Lines.circle(b.x, b.y, b.fin() * 28f);
});
color(Pal.orangeSpark);
float rot = e.rotation + Mathf.randomSeedRange(e.id, 20f);
float w = 9f * e.fout();
Drawf.tri(e.x, e.y, w, 100f, rot);
Drawf.tri(e.x, e.y, w, 10f, rot + 180f);
}
}),
lancerLaserShoot = new Effect(21f, e -> { lancerLaserShoot = new Effect(21f, e -> {
color(Pal.lancerLaser); color(Pal.lancerLaser);
@@ -1000,7 +1070,7 @@ public class Fx{
lancerLaserShootSmoke = new Effect(26f, e -> { lancerLaserShootSmoke = new Effect(26f, e -> {
color(Color.white); color(Color.white);
float length = e.data == null ? 70f : (Float)e.data; float length = e.data == null || !(e.data instanceof Float) ? 70f : (Float)e.data;
randLenVectors(e.id, 7, length, e.rotation, 0f, (x, y) -> { randLenVectors(e.id, 7, length, e.rotation, 0f, (x, y) -> {
lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fout() * 9f); lineAngle(e.x + x, e.y + y, Mathf.angle(x, y), e.fout() * 9f);
@@ -1070,6 +1140,15 @@ public class Fx{
}); });
}), }),
cloudsmoke = new Effect(70, e -> {
randLenVectors(e.id, 12, 15f + e.fin() * 45f, (x, y) -> {
float size = e.fslope() * 2f;
color(Color.gray);
alpha(e.fslope());
Fill.circle(e.x + x, e.y + y, size);
});
}),
nuclearcloud = new Effect(90, 200f, e -> { nuclearcloud = new Effect(90, 200f, e -> {
randLenVectors(e.id, 10, e.finpow() * 90f, (x, y) -> { randLenVectors(e.id, 10, e.finpow() * 90f, (x, y) -> {
float size = e.fout() * 14f; float size = e.fout() * 14f;
@@ -1295,10 +1374,11 @@ public class Fx{
}), }),
//TODO fix false in constructor
ripple = new Effect(30, e -> { ripple = new Effect(30, e -> {
e.lifetime = 30f*e.rotation;
color(Tmp.c1.set(e.color).mul(1.5f)); color(Tmp.c1.set(e.color).mul(1.5f));
stroke(e.fout() + 0.4f); stroke(e.fout() * 1.4f);
Lines.circle(e.x, e.y, (2f + e.fin() * 4f) * e.rotation); Lines.circle(e.x, e.y, (2f + e.fin() * 4f) * e.rotation);
}).ground(), }).ground(),
@@ -9,7 +9,7 @@ import mindustry.type.StatusEffect;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class StatusEffects implements ContentList{ public class StatusEffects implements ContentList{
public static StatusEffect none, burning, freezing, wet, melting, sapped, tarred, overdrive, overclock, shielded, shocked, blasted, corroded, boss, sporeSlowed; public static StatusEffect none, burning, freezing, wet, muddy, melting, sapped, tarred, overdrive, overclock, shielded, shocked, blasted, corroded, boss, sporeSlowed;
@Override @Override
public void load(){ public void load(){
@@ -62,6 +62,13 @@ public class StatusEffects implements ContentList{
opposite(burning); opposite(burning);
}); });
}}; }};
muddy = new StatusEffect("muddy"){{
color = Color.valueOf("46382a");
speedMultiplier = 0.94f;
effect = Fx.muddy;
effectChance = 0.09f;
}};
melting = new StatusEffect("melting"){{ melting = new StatusEffect("melting"){{
speedMultiplier = 0.8f; speedMultiplier = 0.8f;
+11 -25
View File
@@ -1,18 +1,15 @@
package mindustry.content; package mindustry.content;
import arc.*; import arc.*;
import arc.math.*;
import arc.struct.*; import arc.struct.*;
import arc.util.ArcAnnotate.*; import arc.util.ArcAnnotate.*;
import mindustry.core.*;
import mindustry.ctype.*; import mindustry.ctype.*;
import mindustry.game.Objectives.*; import mindustry.game.Objectives.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.world.*;
import static mindustry.content.Blocks.*; import static mindustry.content.Blocks.*;
import static mindustry.content.SectorPresets.*;
import static mindustry.content.SectorPresets.craters; import static mindustry.content.SectorPresets.craters;
import static mindustry.content.SectorPresets.*;
import static mindustry.content.UnitTypes.*; import static mindustry.content.UnitTypes.*;
import static mindustry.type.ItemStack.*; import static mindustry.type.ItemStack.*;
@@ -422,7 +419,11 @@ public class TechTree implements ContentList{
node(risso, () -> { node(risso, () -> {
node(minke, () -> { node(minke, () -> {
node(bryde, () -> { node(bryde, () -> {
node(sei, () -> {
node(omura, () -> {
});
});
}); });
}); });
}); });
@@ -522,42 +523,27 @@ public class TechTree implements ContentList{
}); });
} }
private static void setup(){ public static void setup(){
TechNode.context = null; TechNode.context = null;
map = new ObjectMap<>(); map = new ObjectMap<>();
all = new Seq<>(); all = new Seq<>();
} }
private static TechNode node(UnlockableContent content, Runnable children){ public static TechNode node(UnlockableContent content, Runnable children){
ItemStack[] requirements; return node(content, content.researchRequirements(), children);
if(content instanceof Block){
Block block = (Block)content;
requirements = new ItemStack[block.requirements.length];
for(int i = 0; i < requirements.length; i++){
int quantity = 40 + Mathf.round(Mathf.pow(block.requirements[i].amount, 1.25f) * 20, 10);
requirements[i] = new ItemStack(block.requirements[i].item, UI.roundAmount(quantity));
}
}else{
requirements = ItemStack.empty;
}
return node(content, requirements, children);
} }
private static TechNode node(UnlockableContent content, ItemStack[] requirements, Runnable children){ public static TechNode node(UnlockableContent content, ItemStack[] requirements, Runnable children){
return new TechNode(content, requirements, children); return new TechNode(content, requirements, children);
} }
private static TechNode node(UnlockableContent content, Seq<Objective> objectives, Runnable children){ public static TechNode node(UnlockableContent content, Seq<Objective> objectives, Runnable children){
TechNode node = new TechNode(content, empty, children); TechNode node = new TechNode(content, empty, children);
node.objectives = objectives; node.objectives = objectives;
return node; return node;
} }
private static TechNode node(UnlockableContent block){ public static TechNode node(UnlockableContent block){
return node(block, () -> {}); return node(block, () -> {});
} }
+223 -8
View File
@@ -38,11 +38,14 @@ public class UnitTypes implements ContentList{
//air + building + mining + payload //air + building + mining + payload
public static @EntityDef({Unitc.class, Builderc.class, Minerc.class, Payloadc.class}) UnitType mega; public static @EntityDef({Unitc.class, Builderc.class, Minerc.class, Payloadc.class}) UnitType mega;
//air + building + payload TODO implement
public static @EntityDef({Unitc.class, Builderc.class, Payloadc.class}) UnitType quad, oct;
//air + building + mining //air + building + mining
public static @EntityDef({Unitc.class, Builderc.class, Minerc.class}) UnitType alpha, beta, gamma; public static @EntityDef({Unitc.class, Builderc.class, Minerc.class}) UnitType alpha, beta, gamma;
//water //water + commander
public static @EntityDef({Unitc.class, WaterMovec.class, Commanderc.class}) UnitType risso, minke, bryde; public static @EntityDef({Unitc.class, WaterMovec.class, Commanderc.class}) UnitType risso, minke, bryde, sei, omura;
//special block unit type //special block unit type
public static @EntityDef({Unitc.class, BlockUnitc.class}) UnitType block; public static @EntityDef({Unitc.class, BlockUnitc.class}) UnitType block;
@@ -61,6 +64,7 @@ public class UnitTypes implements ContentList{
reload = 14f; reload = 14f;
x = 4f; x = 4f;
y = 2f; y = 2f;
top = false;
ejectEffect = Fx.shellEjectSmall; ejectEffect = Fx.shellEjectSmall;
bullet = Bullets.standardCopper; bullet = Bullets.standardCopper;
}}); }});
@@ -75,6 +79,7 @@ public class UnitTypes implements ContentList{
immunities.add(StatusEffects.burning); immunities.add(StatusEffects.burning);
weapons.add(new Weapon("flamethrower"){{ weapons.add(new Weapon("flamethrower"){{
top = false;
shootSound = Sounds.flame; shootSound = Sounds.flame;
shootY = 2f; shootY = 2f;
reload = 14f; reload = 14f;
@@ -106,6 +111,7 @@ public class UnitTypes implements ContentList{
mechFrontSway = 0.55f; mechFrontSway = 0.55f;
weapons.add(new Weapon("artillery"){{ weapons.add(new Weapon("artillery"){{
top = false;
y = 1f; y = 1f;
x = 9f; x = 9f;
reload = 60f; reload = 60f;
@@ -142,6 +148,7 @@ public class UnitTypes implements ContentList{
weapons.add( weapons.add(
new Weapon("scepter-weapon"){{ new Weapon("scepter-weapon"){{
top = false;
y = 1f; y = 1f;
x = 16f; x = 16f;
shootY = 8f; shootY = 8f;
@@ -201,6 +208,7 @@ public class UnitTypes implements ContentList{
weapons.add( weapons.add(
new Weapon("reign-weapon"){{ new Weapon("reign-weapon"){{
top = false;
y = 1f; y = 1f;
x = 21.5f; x = 21.5f;
shootY = 11f; shootY = 11f;
@@ -259,6 +267,7 @@ public class UnitTypes implements ContentList{
abilities.add(new HealFieldAbility(10f, 60f * 4, 60f)); abilities.add(new HealFieldAbility(10f, 60f * 4, 60f));
weapons.add(new Weapon("heal-weapon"){{ weapons.add(new Weapon("heal-weapon"){{
top = false;
shootY = 2f; shootY = 2f;
reload = 24f; reload = 24f;
x = 4.5f; x = 4.5f;
@@ -274,7 +283,7 @@ public class UnitTypes implements ContentList{
itemCapacity = 60; itemCapacity = 60;
canBoost = true; canBoost = true;
boostMultiplier = 1.5f; boostMultiplier = 1.5f;
speed = 0.48f; speed = 0.62f;
hitsize = 10f; hitsize = 10f;
health = 320f; health = 320f;
buildSpeed = 0.9f; buildSpeed = 0.9f;
@@ -287,6 +296,7 @@ public class UnitTypes implements ContentList{
abilities.add(new ShieldFieldAbility(20f, 40f, 60f * 5, 60f)); abilities.add(new ShieldFieldAbility(20f, 40f, 60f * 5, 60f));
weapons.add(new Weapon("heal-shotgun-weapon"){{ weapons.add(new Weapon("heal-shotgun-weapon"){{
top = false;
x = 5f; x = 5f;
shake = 2.2f; shake = 2.2f;
y = 0.5f; y = 0.5f;
@@ -336,6 +346,7 @@ public class UnitTypes implements ContentList{
abilities.add(new ForceFieldAbility(60f, 0.3f, 400f, 60f * 6)); abilities.add(new ForceFieldAbility(60f, 0.3f, 400f, 60f * 6));
weapons.add(new Weapon("beam-weapon"){{ weapons.add(new Weapon("beam-weapon"){{
top = false;
shake = 2f; shake = 2f;
shootY = 4f; shootY = 4f;
x = 6.5f; x = 6.5f;
@@ -406,6 +417,7 @@ public class UnitTypes implements ContentList{
groundLayer = Layer.legUnit - 1f; groundLayer = Layer.legUnit - 1f;
weapons.add(new Weapon("eruption"){{ weapons.add(new Weapon("eruption"){{
top = false;
shootY = 3f; shootY = 3f;
reload = 10f; reload = 10f;
ejectEffect = Fx.none; ejectEffect = Fx.none;
@@ -668,8 +680,8 @@ public class UnitTypes implements ContentList{
width = height = 25f; width = height = 25f;
collidesTiles = collides = true; collidesTiles = collides = true;
ammoMultiplier = 4f; ammoMultiplier = 4f;
splashDamageRadius = 95f; splashDamageRadius = 90f;
splashDamage = 90f; splashDamage = 75f;
backColor = Pal.sapBulletBack; backColor = Pal.sapBulletBack;
frontColor = lightningColor = Pal.sapBullet; frontColor = lightningColor = Pal.sapBullet;
lightning = 5; lightning = 5;
@@ -690,7 +702,7 @@ public class UnitTypes implements ContentList{
width = height = 20f; width = height = 20f;
collidesTiles = false; collidesTiles = false;
splashDamageRadius = 80f; splashDamageRadius = 80f;
splashDamage = 45f; splashDamage = 40f;
backColor = Pal.sapBulletBack; backColor = Pal.sapBulletBack;
frontColor = lightningColor = Pal.sapBullet; frontColor = lightningColor = Pal.sapBullet;
lightning = 2; lightning = 2;
@@ -735,6 +747,7 @@ public class UnitTypes implements ContentList{
accel = 0.08f; accel = 0.08f;
drag = 0.016f; drag = 0.016f;
flying = true; flying = true;
hitsize = 9f;
targetAir = false; targetAir = false;
engineOffset = 7.8f; engineOffset = 7.8f;
range = 140f; range = 140f;
@@ -1001,6 +1014,7 @@ public class UnitTypes implements ContentList{
abilities.add(new HealFieldAbility(5f, 60f * 5, 50f)); abilities.add(new HealFieldAbility(5f, 60f * 5, 50f));
weapons.add(new Weapon("heal-weapon-mount"){{ weapons.add(new Weapon("heal-weapon-mount"){{
top = false;
y = -2.5f; y = -2.5f;
x = 3.5f; x = 3.5f;
reload = 30f; reload = 30f;
@@ -1033,6 +1047,8 @@ public class UnitTypes implements ContentList{
mineTier = 2; mineTier = 2;
health = 500; health = 500;
armor = 2f;
armor = 5f;
speed = 1.8f; speed = 1.8f;
accel = 0.06f; accel = 0.06f;
drag = 0.017f; drag = 0.017f;
@@ -1062,6 +1078,65 @@ public class UnitTypes implements ContentList{
}}); }});
}}; }};
quad = new UnitType("quad"){{
mineTier = 2;
armor = 4f;
health = 7000;
speed = 1.2f;
rotateSpeed = 2f;
accel = 0.05f;
drag = 0.017f;
lowAltitude = false;
flying = true;
engineOffset = 12f;
engineSize = 6f;
rotateShooting = false;
hitsize = 32f;
payloadCapacity = (3 * 3) * (8 * 8);
buildSpeed = 2.5f;
range = 140f;
weapons.add(
new Weapon(){{
x = y = 0f;
mirror = false;
reload = 60f;
minShootVelocity = 0.01f;
bullet = new BasicBulletType(){{
sprite = "large-bomb";
width = height = 120/4f;
backColor = Pal.heal;
frontColor = Color.white;
mixColorTo = Color.white;
shootCone = 180f;
ejectEffect = Fx.none;
ignoreRotation = true;
shootSound = Sounds.none;
despawnShake = 4f;
collidesAir = false;
lifetime = 70f;
despawnEffect = Fx.healBomb;
hitEffect = Fx.massiveExplosion;
keepVelocity = false;
spin = 2f;
shrinkX = shrinkY = 0.7f;
speed = 0.001f;
collides = false;
splashDamage = 230f;
splashDamageRadius = 90f;
}};
}});
}};
//endregion //endregion
//region naval attack //region naval attack
@@ -1125,6 +1200,7 @@ public class UnitTypes implements ContentList{
accel = 0.3f; accel = 0.3f;
rotateSpeed = 2.6f; rotateSpeed = 2.6f;
immunities = ObjectSet.with(StatusEffects.wet); immunities = ObjectSet.with(StatusEffects.wet);
rotateShooting = false;
trailLength = 20; trailLength = 20;
trailX = 5.5f; trailX = 5.5f;
@@ -1164,7 +1240,7 @@ public class UnitTypes implements ContentList{
accel = 0.2f; accel = 0.2f;
rotateSpeed = 1.8f; rotateSpeed = 1.8f;
drag = 0.17f; drag = 0.17f;
hitsize = 14f; hitsize = 16f;
armor = 6f; armor = 6f;
immunities = ObjectSet.with(StatusEffects.wet); immunities = ObjectSet.with(StatusEffects.wet);
rotateShooting = false; rotateShooting = false;
@@ -1186,7 +1262,7 @@ public class UnitTypes implements ContentList{
shootY = 7f; shootY = 7f;
shake = 5f; shake = 5f;
recoil = 4f; recoil = 4f;
occlusion = 17f; occlusion = 12f;
shots = 1; shots = 1;
inaccuracy = 3f; inaccuracy = 3f;
@@ -1252,6 +1328,142 @@ public class UnitTypes implements ContentList{
}}); }});
}}; }};
sei = new UnitType("sei"){{
health = 10000;
armor = 12f;
speed = 0.73f;
drag = 0.17f;
hitsize = 39f;
accel = 0.2f;
rotateSpeed = 1.3f;
immunities = ObjectSet.with(StatusEffects.wet);
rotateShooting = false;
trailLength = 50;
trailX = 18f;
trailY = -21f;
trailScl = 3f;
weapons.add(new Weapon("sei-launcher"){{
x = 0f;
y = 0f;
rotate = true;
rotateSpeed = 4f;
mirror = false;
occlusion = 20f;
shootY = 2f;
recoil = 4f;
reload = 45f;
shots = 6;
spacing = 10f;
velocityRnd = 0.4f;
inaccuracy = 7f;
ejectEffect = Fx.none;
shake = 3f;
shootSound = Sounds.shootBig;
xRand = 8f;
shotDelay = 1f;
bullet = new MissileBulletType(4.2f, 25){{
homingPower = 0.12f;
width = 8f;
height = 8f;
shrinkX = shrinkY = 0f;
drag = -0.003f;
homingRange = 80f;
keepVelocity = false;
splashDamageRadius = 25f;
splashDamage = 25f;
lifetime = 56f;
trailColor = Pal.bulletYellowBack;
backColor = Pal.bulletYellowBack;
frontColor = Pal.bulletYellow;
hitEffect = Fx.blastExplosion;
despawnEffect = Fx.blastExplosion;
weaveScale = 8f;
weaveMag = 2f;
}};
}});
weapons.add(new Weapon("large-bullet-mount"){{
reload = 80f;
cooldownTime = 90f;
x = 70f/4f;
y = -66f/4f;
rotateSpeed = 4f;
rotate = true;
shootY = 7f;
shake = 2f;
recoil = 3f;
occlusion = 12f;
ejectEffect = Fx.shellEjectBig;
shots = 3;
shotDelay = 4f;
inaccuracy = 1f;
bullet = new BasicBulletType(7f, 50){{
width = 13f;
height = 19f;
shootEffect = Fx.shootBig;
lifetime = 30f;
}};
}});
}};
omura = new UnitType("omura"){{
health = 22000;
speed = 0.62f;
drag = 0.18f;
hitsize = 50f;
armor = 16f;
accel = 0.19f;
rotateSpeed = 0.9f;
immunities = ObjectSet.with(StatusEffects.wet);
rotateShooting = false;
float spawnTime = 60f * 25f;
abilities.add(new UnitSpawnAbility(flare, spawnTime, 19.25f, -31.75f), new UnitSpawnAbility(flare, spawnTime, -19.25f, -31.75f));
trailLength = 70;
trailX = 23f;
trailY = -32f;
trailScl = 3.5f;
weapons.add(new Weapon("omura-cannon"){{
reload = 110f;
cooldownTime = 90f;
mirror = false;
x = 0f;
y = -3.5f;
rotateSpeed = 1.4f;
rotate = true;
shootY = 23f;
shake = 6f;
recoil = 10.5f;
occlusion = 50f;
shots = 1;
ejectEffect = Fx.none;
bullet = new RailBulletType(){{
shootEffect = Fx.railShoot;
speed = 67f;
lifetime = 8f;
pierceEffect = Fx.railHit;
updateEffect = Fx.railTrail;
hitEffect = Fx.massiveExplosion;
smokeEffect = Fx.shootBig2;
damage = 1250;
pierceDamageFactor = 0.5f;
}};
}});
}};
//endregion //endregion
//region core //region core
@@ -1276,6 +1488,7 @@ public class UnitTypes implements ContentList{
reload = 17f; reload = 17f;
x = 2.75f; x = 2.75f;
y = 1f; y = 1f;
top = false;
bullet = new BasicBulletType(2.5f, 9){{ bullet = new BasicBulletType(2.5f, 9){{
width = 7f; width = 7f;
@@ -1308,6 +1521,7 @@ public class UnitTypes implements ContentList{
lowAltitude = true; lowAltitude = true;
weapons.add(new Weapon("small-mount-weapon"){{ weapons.add(new Weapon("small-mount-weapon"){{
top = false;
reload = 20f; reload = 20f;
x = 3f; x = 3f;
y = 0.5f; y = 0.5f;
@@ -1345,6 +1559,7 @@ public class UnitTypes implements ContentList{
hitsize = 10f; hitsize = 10f;
weapons.add(new Weapon("small-mount-weapon"){{ weapons.add(new Weapon("small-mount-weapon"){{
top = false;
reload = 15f; reload = 15f;
x = 1f; x = 1f;
y = 2f; y = 2f;
+7 -2
View File
@@ -191,6 +191,10 @@ public class Control implements ApplicationListener, Loadable{
} }
void resetCamera(){
}
@Override @Override
public void loadAsync(){ public void loadAsync(){
Draw.scl = 1f / Core.atlas.find("scale_marker").width; Draw.scl = 1f / Core.atlas.find("scale_marker").width;
@@ -280,6 +284,7 @@ public class Control implements ApplicationListener, Loadable{
try{ try{
net.reset(); net.reset();
slot.load(); slot.load();
slot.setAutosave(true);
state.rules.sector = sector; state.rules.sector = sector;
//if there is no base, simulate a new game and place the right loadout at the spawn position //if there is no base, simulate a new game and place the right loadout at the spawn position
@@ -329,7 +334,7 @@ public class Control implements ApplicationListener, Loadable{
} }
public void playTutorial(){ public void playTutorial(){
ui.showInfo("There is no tutorial yet."); ui.showInfo("@indev.notready");
//TODO implement //TODO implement
//ui.showInfo("death"); //ui.showInfo("death");
/* /*
@@ -429,7 +434,7 @@ public class Control implements ApplicationListener, Loadable{
//just a regular reminder //just a regular reminder
if(!OS.prop("user.name").equals("anuke") && !OS.hasEnv("iknowwhatimdoing")){ if(!OS.prop("user.name").equals("anuke") && !OS.hasEnv("iknowwhatimdoing")){
app.post(() -> app.post(() -> { app.post(() -> app.post(() -> {
ui.showStartupInfo("@indevpopup"); ui.showStartupInfo("@indev.popup");
})); }));
} }
+1 -1
View File
@@ -17,7 +17,7 @@ public class GameState{
/** Wave countdown in ticks. */ /** Wave countdown in ticks. */
public float wavetime; public float wavetime;
/** Whether the game is in game over state. */ /** Whether the game is in game over state. */
public boolean gameOver = false, launched = false, serverPaused = false; public boolean gameOver = false, launched = false, serverPaused = false, wasTimeout;
/** Map that is currently being played on. */ /** Map that is currently being played on. */
public @NonNull Map map = emptyMap; public @NonNull Map map = emptyMap;
/** The current game rules. */ /** The current game rules. */
+8 -1
View File
@@ -337,7 +337,14 @@ public class Logic implements ApplicationListener{
//force pausing when the player is out of sector time //force pausing when the player is out of sector time
if(state.isOutOfTime()){ if(state.isOutOfTime()){
state.set(State.paused); if(!state.wasTimeout){
universe.displayTimeEnd();
state.wasTimeout = true;
}
//if no turn was run.
if(state.isOutOfTime()){
state.set(State.paused);
}
} }
if(!state.isPaused()){ if(!state.isPaused()){
+7 -3
View File
@@ -338,8 +338,6 @@ public class NetClient implements ApplicationListener{
@Remote(variants = Variant.both) @Remote(variants = Variant.both)
public static void setRules(Rules rules){ public static void setRules(Rules rules){
state.rules = rules; state.rules = rules;
//campaign is not valid in multiplayer
state.rules.sector = null;
} }
@Remote(variants = Variant.both) @Remote(variants = Variant.both)
@@ -442,7 +440,7 @@ public class NetClient implements ApplicationListener{
} }
@Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true) @Remote(variants = Variant.one, priority = PacketPriority.low, unreliable = true)
public static void stateSnapshot(float waveTime, int wave, int enemies, boolean paused, boolean gameOver, short coreDataLen, byte[] coreData){ public static void stateSnapshot(float waveTime, int wave, int enemies, boolean paused, boolean gameOver, int timeData, short coreDataLen, byte[] coreData){
try{ try{
if(wave > state.wave){ if(wave > state.wave){
state.wave = wave; state.wave = wave;
@@ -455,6 +453,8 @@ public class NetClient implements ApplicationListener{
state.enemies = enemies; state.enemies = enemies;
state.serverPaused = paused; state.serverPaused = paused;
universe.updateNetSeconds(timeData);
netClient.byteStream.setBytes(net.decompressSnapshot(coreData, coreDataLen)); netClient.byteStream.setBytes(net.decompressSnapshot(coreData, coreDataLen));
DataInputStream input = netClient.dataStream; DataInputStream input = netClient.dataStream;
@@ -549,6 +549,10 @@ public class NetClient implements ApplicationListener{
quiet = true; quiet = true;
} }
public void clearRemovedEntity(int id){
removed.remove(id);
}
public void addRemovedEntity(int id){ public void addRemovedEntity(int id){
removed.add(id); removed.add(id);
} }
+27 -27
View File
@@ -593,38 +593,38 @@ public class NetServer implements ApplicationListener{
if(player.isBuilder()){ if(player.isBuilder()){
player.builder().clearBuilding(); player.builder().clearBuilding();
player.builder().updateBuilding(building); player.builder().updateBuilding(building);
if(requests != null){
for(BuildPlan req : requests){
if(req == null) continue;
Tile tile = world.tile(req.x, req.y);
if(tile == null || (!req.breaking && req.block == null)) continue;
//auto-skip done requests
if(req.breaking && tile.block() == Blocks.air){
continue;
}else if(!req.breaking && tile.block() == req.block && (!req.block.rotate || (tile.build != null && tile.build.rotation == req.rotation))){
continue;
}else if(con.rejectedRequests.contains(r -> r.breaking == req.breaking && r.x == req.x && r.y == req.y)){ //check if request was recently rejected, and skip it if so
continue;
}else if(!netServer.admins.allowAction(player, req.breaking ? ActionType.breakBlock : ActionType.placeBlock, tile, action -> { //make sure request is allowed by the server
action.block = req.block;
action.rotation = req.rotation;
action.config = req.config;
})){
//force the player to remove this request if that's not the case
Call.removeQueueBlock(player.con, req.x, req.y, req.breaking);
con.rejectedRequests.add(req);
continue;
}
player.builder().plans().addLast(req);
}
}
} }
if(player.isMiner()){ if(player.isMiner()){
player.miner().mineTile(mining); player.miner().mineTile(mining);
} }
if(requests != null){
for(BuildPlan req : requests){
if(req == null) continue;
Tile tile = world.tile(req.x, req.y);
if(tile == null || (!req.breaking && req.block == null)) continue;
//auto-skip done requests
if(req.breaking && tile.block() == Blocks.air){
continue;
}else if(!req.breaking && tile.block() == req.block && (!req.block.rotate || (tile.build != null && tile.build.rotation == req.rotation))){
continue;
}else if(con.rejectedRequests.contains(r -> r.breaking == req.breaking && r.x == req.x && r.y == req.y)){ //check if request was recently rejected, and skip it if so
continue;
}else if(!netServer.admins.allowAction(player, req.breaking ? ActionType.breakBlock : ActionType.placeBlock, tile, action -> { //make sure request is allowed by the server
action.block = req.block;
action.rotation = req.rotation;
action.config = req.config;
})){
//force the player to remove this request if that's not the case
Call.removeQueueBlock(player.con, req.x, req.y, req.breaking);
con.rejectedRequests.add(req);
continue;
}
player.builder().plans().addLast(req);
}
}
con.rejectedRequests.clear(); con.rejectedRequests.clear();
if(!player.dead()){ if(!player.dead()){
@@ -846,7 +846,7 @@ public class NetServer implements ApplicationListener{
byte[] stateBytes = syncStream.toByteArray(); byte[] stateBytes = syncStream.toByteArray();
//write basic state data. //write basic state data.
Call.stateSnapshot(player.con, state.wavetime, state.wave, state.enemies, state.serverPaused, state.gameOver, (short)stateBytes.length, net.compressSnapshot(stateBytes)); Call.stateSnapshot(player.con, state.wavetime, state.wave, state.enemies, state.serverPaused, state.gameOver, universe.seconds(), (short)stateBytes.length, net.compressSnapshot(stateBytes));
viewport.setSize(player.con.viewWidth, player.con.viewHeight).setCenter(player.con.viewX, player.con.viewY); viewport.setSize(player.con.viewWidth, player.con.viewHeight).setCenter(player.con.viewX, player.con.viewY);
+80 -5
View File
@@ -5,11 +5,13 @@ import arc.func.*;
import arc.math.*; import arc.math.*;
import arc.math.geom.*; import arc.math.geom.*;
import arc.struct.*; import arc.struct.*;
import arc.struct.ObjectIntMap.*;
import arc.util.ArcAnnotate.*; import arc.util.ArcAnnotate.*;
import arc.util.*; import arc.util.*;
import arc.util.noise.*; import arc.util.noise.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.core.GameState.*; import mindustry.core.GameState.*;
import mindustry.ctype.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.game.*; import mindustry.game.*;
import mindustry.game.Teams.*; import mindustry.game.Teams.*;
@@ -19,7 +21,6 @@ import mindustry.maps.*;
import mindustry.maps.filters.*; import mindustry.maps.filters.*;
import mindustry.maps.filters.GenerateFilter.*; import mindustry.maps.filters.GenerateFilter.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.type.Sector.*;
import mindustry.type.Weather.*; import mindustry.type.Weather.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.environment.*; import mindustry.world.blocks.environment.*;
@@ -33,11 +34,17 @@ public class World{
public @NonNull Tiles tiles = new Tiles(0, 0); public @NonNull Tiles tiles = new Tiles(0, 0);
private boolean generating, invalidMap; private boolean generating, invalidMap;
private ObjectMap<Map, Runnable> customMapLoaders = new ObjectMap<>();
public World(){ public World(){
} }
/** Adds a custom handler function for loading a custom map - usually a generated one. */
public void addMapLoader(Map map, Runnable loader){
customMapLoaders.put(map, loader);
}
public boolean isInvalidMap(){ public boolean isInvalidMap(){
return invalidMap; return invalidMap;
} }
@@ -255,9 +262,71 @@ public class World{
state.rules.weather.clear(); state.rules.weather.clear();
if(sector.is(SectorAttribute.rainy)) state.rules.weather.add(new WeatherEntry(Weathers.rain)); //apply weather based on terrain
if(sector.is(SectorAttribute.snowy)) state.rules.weather.add(new WeatherEntry(Weathers.snow)); ObjectIntMap<Block> floorc = new ObjectIntMap<>();
if(sector.is(SectorAttribute.desert)) state.rules.weather.add(new WeatherEntry(Weathers.sandstorm)); ObjectSet<UnlockableContent> content = new ObjectSet<>();
float waterFloors = 0, totalFloors = 0;
for(Tile tile : world.tiles){
if(world.getDarkness(tile.x, tile.y) >= 3){
continue;
}
Liquid liquid = tile.floor().liquidDrop;
if(tile.floor().itemDrop != null) content.add(tile.floor().itemDrop);
if(tile.overlay().itemDrop != null) content.add(tile.overlay().itemDrop);
if(liquid != null) content.add(liquid);
if(!tile.block().isStatic()){
totalFloors ++;
if(liquid == Liquids.water){
waterFloors += tile.floor().isDeep() ? 1f : 0.7f;
}
floorc.increment(tile.floor());
if(tile.overlay() != Blocks.air){
floorc.increment(tile.overlay());
}
}
}
//sort counts in descending order
Seq<Entry<Block>> entries = floorc.entries().toArray();
entries.sort(e -> -e.value);
//remove all blocks occuring < 30 times - unimportant
entries.removeAll(e -> e.value < 30);
Block[] floors = new Block[entries.size];
int[] floorCounts = new int[entries.size];
for(int i = 0; i < entries.size; i++){
floorCounts[i] = entries.get(i).value;
floors[i] = entries.get(i).key;
}
//TODO bad code
boolean hasSnow = floors[0].name.contains("ice") || floors[0].name.contains("snow");
boolean hasRain = !hasSnow && floors[0].name.contains("water");
boolean hasDesert = !hasSnow && !hasRain && floors[0].name.contains("sand");
boolean hasSpores = floors[0].name.contains("spore") || floors[0].name.contains("moss") || floors[0].name.contains("tainted");
if(hasSnow){
state.rules.weather.add(new WeatherEntry(Weathers.snow));
}
if(hasRain){
state.rules.weather.add(new WeatherEntry(Weathers.rain));
}
if(hasDesert){
state.rules.weather.add(new WeatherEntry(Weathers.sandstorm));
}
if(hasSpores){
state.rules.weather.add(new WeatherEntry(Weathers.sporestorm));
}
state.secinfo.resources = content.asArray();
state.secinfo.resources.sort(Structs.comps(Structs.comparing(Content::getContentType), Structs.comparingInt(c -> c.id)));
} }
@@ -270,6 +339,12 @@ public class World{
} }
public void loadMap(Map map, Rules checkRules){ public void loadMap(Map map, Rules checkRules){
//load using custom loader if possible
if(customMapLoaders.containsKey(map)){
customMapLoaders.get(map).run();
return;
}
try{ try{
SaveIO.load(map.file, new FilterContext(map)); SaveIO.load(map.file, new FilterContext(map));
}catch(Throwable e){ }catch(Throwable e){
@@ -444,7 +519,7 @@ public class World{
dark = Math.max((edgeBlend - edgeDst) * (4f / edgeBlend), dark); dark = Math.max((edgeBlend - edgeDst) * (4f / edgeBlend), dark);
} }
if(state.hasSector()){ if(state.hasSector() && state.getSector().preset == null){
int circleBlend = 14; int circleBlend = 14;
//quantized angle //quantized angle
float offset = state.getSector().rect.rotation + 90; float offset = state.getSector().rect.rotation + 90;
@@ -8,6 +8,7 @@ import arc.util.ArcAnnotate.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.ui.*; import mindustry.ui.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@@ -30,7 +31,7 @@ public abstract class UnlockableContent extends MappableContent{
this.localizedName = Core.bundle.get(getContentType() + "." + this.name + ".name", this.name); this.localizedName = Core.bundle.get(getContentType() + "." + this.name + ".name", this.name);
this.description = Core.bundle.getOrNull(getContentType() + "." + this.name + ".description"); this.description = Core.bundle.getOrNull(getContentType() + "." + this.name + ".description");
this.unlocked = Core.settings != null && Core.settings.getBool(name + "-unlocked", false); this.unlocked = Core.settings != null && Core.settings.getBool(this.name + "-unlocked", false);
} }
public String displayDescription(){ public String displayDescription(){
@@ -43,6 +44,11 @@ public abstract class UnlockableContent extends MappableContent{
} }
/** @return items needed to research this content */
public ItemStack[] researchRequirements(){
return ItemStack.empty;
}
public String emoji(){ public String emoji(){
return Fonts.getUnicodeStr(name); return Fonts.getUnicodeStr(name);
} }
+5 -1
View File
@@ -64,8 +64,12 @@ public class DrawOperation{
if(type == OpType.floor.ordinal()){ if(type == OpType.floor.ordinal()){
tile.setFloor((Floor)content.block(to)); tile.setFloor((Floor)content.block(to));
}else if(type == OpType.block.ordinal()){ }else if(type == OpType.block.ordinal()){
tile.getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y));
Block block = content.block(to); Block block = content.block(to);
tile.setBlock(block, tile.team(), tile.build == null ? 0 : tile.build.rotation); tile.setBlock(block, tile.team(), tile.build == null ? 0 : tile.build.rotation);
tile.getLinkedTiles(t -> editor.renderer.updatePoint(t.x, t.y));
}else if(type == OpType.rotation.ordinal()){ }else if(type == OpType.rotation.ordinal()){
if(tile.build != null) tile.build.rotation = to; if(tile.build != null) tile.build.rotation = to;
}else if(type == OpType.team.ordinal()){ }else if(type == OpType.team.ordinal()){
@@ -74,7 +78,7 @@ public class DrawOperation{
tile.setOverlayID(to); tile.setOverlayID(to);
} }
}); });
editor.renderer().updatePoint(tile.x, tile.y); editor.renderer.updatePoint(tile.x, tile.y);
} }
@Struct @Struct
+22 -9
View File
@@ -20,7 +20,7 @@ public class EditorTile extends Tile{
@Override @Override
public void setFloor(@NonNull Floor type){ public void setFloor(@NonNull Floor type){
if(state.isGame()){ if(skip()){
super.setFloor(type); super.setFloor(type);
return; return;
} }
@@ -41,20 +41,25 @@ public class EditorTile extends Tile{
@Override @Override
public void setBlock(Block type, Team team, int rotation){ public void setBlock(Block type, Team team, int rotation){
if(state.isGame()){ if(skip()){
super.setBlock(type, team, rotation); super.setBlock(type, team, rotation);
return; return;
} }
if(this.block == type && (build == null || build.rotation == rotation)){
update();
return;
}
op(OpType.block, block.id); op(OpType.block, block.id);
if(rotation != 0) op(OpType.rotation, (byte)rotation); if(rotation != 0) op(OpType.rotation, (byte)rotation);
if(team() != Team.derelict) op(OpType.team, (byte)team().id); if(team != Team.derelict) op(OpType.team, (byte)team.id);
super.setBlock(type, team, rotation); super.setBlock(type, team, rotation);
} }
@Override @Override
public void setTeam(Team team){ public void setTeam(Team team){
if(state.isGame()){ if(skip()){
super.setTeam(team); super.setTeam(team);
return; return;
} }
@@ -66,7 +71,7 @@ public class EditorTile extends Tile{
@Override @Override
public void setOverlay(Block overlay){ public void setOverlay(Block overlay){
if(state.isGame()){ if(skip()){
super.setOverlay(overlay); super.setOverlay(overlay);
return; return;
} }
@@ -79,23 +84,23 @@ public class EditorTile extends Tile{
@Override @Override
protected void fireChanged(){ protected void fireChanged(){
if(state.isGame()){ if(skip()){
super.fireChanged(); super.fireChanged();
}else{ }else{
ui.editor.editor.renderer().updatePoint(x, y); update();
} }
} }
@Override @Override
public void recache(){ public void recache(){
if(state.isGame()){ if(skip()){
super.recache(); super.recache();
} }
} }
@Override @Override
protected void changeEntity(Team team, Prov<Building> entityprov, int rotation){ protected void changeEntity(Team team, Prov<Building> entityprov, int rotation){
if(state.isGame()){ if(skip()){
super.changeEntity(team, entityprov, rotation); super.changeEntity(team, entityprov, rotation);
return; return;
} }
@@ -116,6 +121,14 @@ public class EditorTile extends Tile{
} }
} }
private void update(){
ui.editor.editor.renderer.updatePoint(x, y);
}
private boolean skip(){
return state.isGame() || ui.editor.editor.isLoading();
}
private void op(OpType type, short value){ private void op(OpType type, short value){
ui.editor.editor.addTileOp(TileOp.get(x, y, (byte)type.ordinal(), value)); ui.editor.editor.addTileOp(TileOp.get(x, y, (byte)type.ordinal(), value));
} }
+1 -1
View File
@@ -17,7 +17,7 @@ public enum EditorTool{
if(!Structs.inBounds(x, y, editor.width(), editor.height())) return; if(!Structs.inBounds(x, y, editor.width(), editor.height())) return;
Tile tile = editor.tile(x, y); Tile tile = editor.tile(x, y);
editor.drawBlock = tile.block() == Blocks.air ? tile.overlay() == Blocks.air ? tile.floor() : tile.overlay() : tile.block(); editor.drawBlock = tile.block() == Blocks.air || !tile.block().inEditor ? tile.overlay() == Blocks.air ? tile.floor() : tile.overlay() : tile.block();
} }
}, },
line(KeyCode.l, "replace", "orthogonal"){ line(KeyCode.l, "replace", "orthogonal"){
+14 -12
View File
@@ -18,10 +18,10 @@ import static mindustry.Vars.*;
public class MapEditor{ public class MapEditor{
public static final int[] brushSizes = {1, 2, 3, 4, 5, 9, 15, 20}; public static final int[] brushSizes = {1, 2, 3, 4, 5, 9, 15, 20};
private final Context context = new Context(); public StringMap tags = new StringMap();
private StringMap tags = new StringMap(); public MapRenderer renderer = new MapRenderer(this);
private MapRenderer renderer = new MapRenderer(this);
private final Context context = new Context();
private OperationStack stack = new OperationStack(); private OperationStack stack = new OperationStack();
private DrawOperation currentOp; private DrawOperation currentOp;
private boolean loading; private boolean loading;
@@ -31,8 +31,8 @@ public class MapEditor{
public Block drawBlock = Blocks.stone; public Block drawBlock = Blocks.stone;
public Team drawTeam = Team.sharded; public Team drawTeam = Team.sharded;
public StringMap getTags(){ public boolean isLoading(){
return tags; return loading;
} }
public void beginEdit(int width, int height){ public void beginEdit(int width, int height){
@@ -52,7 +52,7 @@ public class MapEditor{
if(map.file.parent().parent().name().equals("1127400") && steam){ if(map.file.parent().parent().name().equals("1127400") && steam){
tags.put("steamid", map.file.parent().name()); tags.put("steamid", map.file.parent().name());
} }
MapIO.loadMap(map, context); load(() -> MapIO.loadMap(map, context));
renderer.resize(width(), height()); renderer.resize(width(), height());
loading = false; loading = false;
} }
@@ -210,10 +210,6 @@ public class MapEditor{
} }
} }
public MapRenderer renderer(){
return renderer;
}
public void resize(int width, int height){ public void resize(int width, int height){
clearOp(); clearOp();
@@ -227,8 +223,14 @@ public class MapEditor{
int px = offsetX + x, py = offsetY + y; int px = offsetX + x, py = offsetY + y;
if(previous.in(px, py)){ if(previous.in(px, py)){
tiles.set(x, y, previous.getn(px, py)); tiles.set(x, y, previous.getn(px, py));
tiles.getn(x, y).x = (short)x; Tile tile = tiles.getn(x, y);
tiles.getn(x, y).y = (short)y; tile.x = (short)x;
tile.y = (short)y;
if(tile.build != null && tile.isCenter()){
tile.build.x = x * tilesize + tile.block().offset;
tile.build.y = y * tilesize + tile.block().offset;
}
}else{ }else{
tiles.set(x, y, new EditorTile(x, y, Blocks.stone.id, (short)0, (short)0)); tiles.set(x, y, new EditorTile(x, y, Blocks.stone.id, (short)0, (short)0));
} }
+16 -16
View File
@@ -116,9 +116,9 @@ public class MapEditorDialog extends Dialog implements Disposable{
t.button("@editor.export", Icon.upload, () -> createDialog("@editor.export", t.button("@editor.export", Icon.upload, () -> createDialog("@editor.export",
"@editor.exportfile", "@editor.exportfile.description", Icon.file, "@editor.exportfile", "@editor.exportfile.description", Icon.file,
(Runnable)() -> platform.export(editor.getTags().get("name", "unknown"), mapExtension, file -> MapIO.writeMap(file, editor.createMap(file))), (Runnable)() -> platform.export(editor.tags.get("name", "unknown"), mapExtension, file -> MapIO.writeMap(file, editor.createMap(file))),
"@editor.exportimage", "@editor.exportimage.description", Icon.fileImage, "@editor.exportimage", "@editor.exportimage.description", Icon.fileImage,
(Runnable)() -> platform.export(editor.getTags().get("name", "unknown"), "png", file -> { (Runnable)() -> platform.export(editor.tags.get("name", "unknown"), "png", file -> {
Pixmap out = MapIO.writeImage(editor.tiles()); Pixmap out = MapIO.writeImage(editor.tiles());
file.writePNG(out); file.writePNG(out);
out.dispose(); out.dispose();
@@ -129,16 +129,16 @@ public class MapEditorDialog extends Dialog implements Disposable{
if(steam){ if(steam){
menu.cont.button("@editor.publish.workshop", Icon.link, () -> { menu.cont.button("@editor.publish.workshop", Icon.link, () -> {
Map builtin = maps.all().find(m -> m.name().equals(editor.getTags().get("name", "").trim())); Map builtin = maps.all().find(m -> m.name().equals(editor.tags.get("name", "").trim()));
if(editor.getTags().containsKey("steamid") && builtin != null && !builtin.custom){ if(editor.tags.containsKey("steamid") && builtin != null && !builtin.custom){
platform.viewListingID(editor.getTags().get("steamid")); platform.viewListingID(editor.tags.get("steamid"));
return; return;
} }
Map map = save(); Map map = save();
if(editor.getTags().containsKey("steamid") && map != null){ if(editor.tags.containsKey("steamid") && map != null){
platform.viewListing(map); platform.viewListing(map);
return; return;
} }
@@ -156,7 +156,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
} }
platform.publish(map); platform.publish(map);
}).padTop(-3).size(swidth * 2f + 10, 60f).update(b -> b.setText(editor.getTags().containsKey("steamid") ? editor.getTags().get("author").equals(player.name) ? "@workshop.listing" : "@view.workshop" : "@editor.publish.workshop")); }).padTop(-3).size(swidth * 2f + 10, 60f).update(b -> b.setText(editor.tags.containsKey("steamid") ? editor.tags.get("author").equals(player.name) ? "@workshop.listing" : "@view.workshop" : "@editor.publish.workshop"));
menu.cont.row(); menu.cont.row();
} }
@@ -235,7 +235,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
state.rules = (lastSavedRules == null ? new Rules() : lastSavedRules); state.rules = (lastSavedRules == null ? new Rules() : lastSavedRules);
lastSavedRules = null; lastSavedRules = null;
saved = false; saved = false;
editor.renderer().updateAll(); editor.renderer.updateAll();
} }
private void playtest(){ private void playtest(){
@@ -264,10 +264,10 @@ public class MapEditorDialog extends Dialog implements Disposable{
public @Nullable Map save(){ public @Nullable Map save(){
boolean isEditor = state.rules.editor; boolean isEditor = state.rules.editor;
state.rules.editor = false; state.rules.editor = false;
String name = editor.getTags().get("name", "").trim(); String name = editor.tags.get("name", "").trim();
editor.getTags().put("rules", JsonIO.write(state.rules)); editor.tags.put("rules", JsonIO.write(state.rules));
editor.getTags().remove("width"); editor.tags.remove("width");
editor.getTags().remove("height"); editor.tags.remove("height");
player.clearUnit(); player.clearUnit();
@@ -281,7 +281,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
if(map != null && !map.custom){ if(map != null && !map.custom){
handleSaveBuiltin(map); handleSaveBuiltin(map);
}else{ }else{
returned = maps.saveMap(editor.getTags()); returned = maps.saveMap(editor.tags);
ui.showInfoFade("@editor.saved"); ui.showInfoFade("@editor.saved");
} }
} }
@@ -352,7 +352,7 @@ public class MapEditorDialog extends Dialog implements Disposable{
@Override @Override
public void dispose(){ public void dispose(){
editor.renderer().dispose(); editor.renderer.dispose();
} }
public void beginEditMap(Fi file){ public void beginEditMap(Fi file){
@@ -614,12 +614,12 @@ public class MapEditorDialog extends Dialog implements Disposable{
Tile tile = editor.tile(x, y); Tile tile = editor.tile(x, y);
if(tile.block().breakable && tile.block() instanceof Boulder){ if(tile.block().breakable && tile.block() instanceof Boulder){
tile.setBlock(Blocks.air); tile.setBlock(Blocks.air);
editor.renderer().updatePoint(x, y); editor.renderer.updatePoint(x, y);
} }
if(tile.overlay() != Blocks.air && tile.overlay() != Blocks.spawn){ if(tile.overlay() != Blocks.air && tile.overlay() != Blocks.spawn){
tile.setOverlay(Blocks.air); tile.setOverlay(Blocks.air);
editor.renderer().updatePoint(x, y); editor.renderer.updatePoint(x, y);
} }
} }
} }
@@ -144,7 +144,7 @@ public class MapGenerateDialog extends BaseDialog{
} }
//reset undo stack as generation... messes things up //reset undo stack as generation... messes things up
editor.renderer().updateAll(); editor.renderer.updateAll();
editor.clearOp(); editor.clearOp();
} }
+3 -3
View File
@@ -29,7 +29,7 @@ public class MapInfoDialog extends BaseDialog{
private void setup(){ private void setup(){
cont.clear(); cont.clear();
ObjectMap<String, String> tags = editor.getTags(); ObjectMap<String, String> tags = editor.tags;
cont.pane(t -> { cont.pane(t -> {
t.add("@editor.mapname").padRight(8).left(); t.add("@editor.mapname").padRight(8).left();
@@ -73,8 +73,8 @@ public class MapInfoDialog extends BaseDialog{
t.row(); t.row();
t.add("@editor.generation").padRight(8).left(); t.add("@editor.generation").padRight(8).left();
t.button("@edit", () -> { t.button("@edit", () -> {
generate.show(Vars.maps.readFilters(editor.getTags().get("genfilters", "")), generate.show(Vars.maps.readFilters(editor.tags.get("genfilters", "")),
filters -> editor.getTags().put("genfilters", JsonIO.write(filters))); filters -> editor.tags.put("genfilters", JsonIO.write(filters)));
hide(); hide();
}).left().width(200f); }).left().width(200f);
+1 -1
View File
@@ -116,7 +116,7 @@ public class MapRenderer implements Disposable{
wx * tilesize + wall.offset + (tilesize - width) / 2f, wx * tilesize + wall.offset + (tilesize - width) / 2f,
wy * tilesize + wall.offset + (tilesize - height) / 2f, wy * tilesize + wall.offset + (tilesize - height) / 2f,
width, height, width, height,
tile.build == null || !wall.rotate ? 0 : tile.build.rotdeg() - 90); tile.build == null || !wall.rotate ? 0 : tile.build.rotdeg());
}else{ }else{
region = floor.editorVariantRegions()[Mathf.randomSeed(idxWall, 0, floor.editorVariantRegions().length - 1)]; region = floor.editorVariantRegions()[Mathf.randomSeed(idxWall, 0, floor.editorVariantRegions().length - 1)];
+1 -1
View File
@@ -248,7 +248,7 @@ public class MapView extends Element implements GestureListener{
Draw.color(Pal.remove); Draw.color(Pal.remove);
Lines.stroke(2f); Lines.stroke(2f);
Lines.rect(centerx - sclwidth / 2 - 1, centery - sclheight / 2 - 1, sclwidth + 2, sclheight + 2); Lines.rect(centerx - sclwidth / 2 - 1, centery - sclheight / 2 - 1, sclwidth + 2, sclheight + 2);
editor.renderer().draw(centerx - sclwidth / 2, centery - sclheight / 2, sclwidth, sclheight); editor.renderer.draw(centerx - sclwidth / 2, centery - sclheight / 2, sclwidth, sclheight);
Draw.reset(); Draw.reset();
if(grid){ if(grid){
+10 -8
View File
@@ -40,7 +40,7 @@ public class Effect{
} }
public Effect(float life, Cons<EffectContainer> renderer){ public Effect(float life, Cons<EffectContainer> renderer){
this(life, 32f, renderer); this(life,50f, renderer);
} }
public Effect ground(){ public Effect ground(){
@@ -86,12 +86,14 @@ public class Effect{
create(this, x, y, rotation, Color.white, data); create(this, x, y, rotation, Color.white, data);
} }
public void render(int id, Color color, float life, float rotation, float x, float y, Object data){ public float render(int id, Color color, float life, float lifetime, float rotation, float x, float y, Object data){
container.set(id, color, life, lifetime, rotation, x, y, data); container.set(id, color, life, lifetime, rotation, x, y, data);
Draw.z(ground ? Layer.debris : Layer.effect); Draw.z(ground ? Layer.debris : Layer.effect);
Draw.reset(); Draw.reset();
renderer.get(container); renderer.get(container);
Draw.reset(); Draw.reset();
return container.lifetime;
} }
public static @Nullable Effect get(int id){ public static @Nullable Effect get(int id){
@@ -125,13 +127,13 @@ public class Effect{
if(view.overlaps(pos)){ if(view.overlaps(pos)){
EffectState entity = EffectState.create(); EffectState entity = EffectState.create();
entity.effect(effect); entity.effect = effect;
entity.rotation(rotation); entity.rotation = rotation;
entity.data(data); entity.data = (data);
entity.lifetime(effect.lifetime); entity.lifetime = (effect.lifetime);
entity.set(x, y); entity.set(x, y);
entity.color().set(color); entity.color.set(color);
if(data instanceof Posc) entity.parent((Posc)data); if(data instanceof Posc) entity.parent = ((Posc)data);
entity.add(); entity.add();
} }
} }
+10
View File
@@ -1,5 +1,6 @@
package mindustry.entities; package mindustry.entities;
import arc.*;
import arc.func.*; import arc.func.*;
import arc.math.geom.*; import arc.math.geom.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
@@ -18,6 +19,15 @@ public class Units{
private static float cdist; private static float cdist;
private static boolean boolResult; private static boolean boolResult;
@Remote(called = Loc.server)
public static void unitCapDeath(Unit unit){
if(unit != null){
unit.dead = true;
Fx.unitCapKill.at(unit);
Core.app.post(() -> Call.unitDeath(unit.id));
}
}
@Remote(called = Loc.server) @Remote(called = Loc.server)
public static void unitDeath(int uid){ public static void unitDeath(int uid){
Unit unit = Groups.unit.getByID(uid); Unit unit = Groups.unit.getByID(uid);
@@ -2,7 +2,16 @@ package mindustry.entities.abilities;
import mindustry.gen.*; import mindustry.gen.*;
public interface Ability{ public abstract class Ability implements Cloneable{
default void update(Unit unit){} public void update(Unit unit){}
default void draw(Unit unit){} public void draw(Unit unit){}
public Ability copy(){
try{
return (Ability)clone();
}catch(CloneNotSupportedException e){
//I am disgusted
throw new RuntimeException("java sucks", e);
}
}
} }
@@ -11,7 +11,7 @@ import mindustry.content.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
public class ForceFieldAbility implements Ability{ public class ForceFieldAbility extends Ability{
/** Shield radius. */ /** Shield radius. */
public float radius = 60f; public float radius = 60f;
/** Shield regen speed in damage/tick. */ /** Shield regen speed in damage/tick. */
@@ -21,18 +21,22 @@ public class ForceFieldAbility implements Ability{
/** Cooldown after the shield is broken, in ticks. */ /** Cooldown after the shield is broken, in ticks. */
public float cooldown = 60f * 5; public float cooldown = 60f * 5;
private float realRad; /** State: radius scaling. */
private Unit paramUnit; protected float radiusScale;
private final Cons<Shielderc> shieldConsumer = trait -> {
private static float realRad;
private static Unit paramUnit;
private static ForceFieldAbility paramField;
private static final Cons<Shielderc> shieldConsumer = trait -> {
if(trait.team() != paramUnit.team && Intersector.isInsideHexagon(paramUnit.x, paramUnit.y, realRad * 2f, trait.x(), trait.y()) && paramUnit.shield > 0){ if(trait.team() != paramUnit.team && Intersector.isInsideHexagon(paramUnit.x, paramUnit.y, realRad * 2f, trait.x(), trait.y()) && paramUnit.shield > 0){
trait.absorb(); trait.absorb();
Fx.absorb.at(trait); Fx.absorb.at(trait);
//break shield //break shield
if(paramUnit.shield <= trait.damage()){ if(paramUnit.shield <= trait.damage()){
paramUnit.shield -= cooldown * regen; paramUnit.shield -= paramField.cooldown * paramField.regen;
Fx.shieldBreak.at(paramUnit.x, paramUnit.y, radius, paramUnit.team.color); Fx.shieldBreak.at(paramUnit.x, paramUnit.y, paramField.radius, paramUnit.team.color);
} }
paramUnit.shield -= trait.damage(); paramUnit.shield -= trait.damage();
@@ -56,13 +60,14 @@ public class ForceFieldAbility implements Ability{
} }
if(unit.shield > 0){ if(unit.shield > 0){
unit.timer2 = Mathf.lerpDelta(unit.timer2, 1f, 0.06f); radiusScale = Mathf.lerpDelta(radiusScale, 1f, 0.06f);
paramUnit = unit; paramUnit = unit;
paramField = this;
checkRadius(unit); checkRadius(unit);
Groups.bullet.intersect(unit.x - realRad, unit.y - realRad, realRad * 2f, realRad * 2f, shieldConsumer); Groups.bullet.intersect(unit.x - realRad, unit.y - realRad, realRad * 2f, realRad * 2f, shieldConsumer);
}else{ }else{
unit.timer2 = 0f; radiusScale = 0f;
} }
} }
@@ -89,6 +94,6 @@ public class ForceFieldAbility implements Ability{
private void checkRadius(Unit unit){ private void checkRadius(Unit unit){
//timer2 is used to store radius scale as an effect //timer2 is used to store radius scale as an effect
realRad = unit.timer2 * radius; realRad = radiusScale * radius;
} }
} }
@@ -5,12 +5,13 @@ import mindustry.content.*;
import mindustry.entities.*; import mindustry.entities.*;
import mindustry.gen.*; import mindustry.gen.*;
public class HealFieldAbility implements Ability{ public class HealFieldAbility extends Ability{
public float amount = 1, reload = 100, range = 60; public float amount = 1, reload = 100, range = 60;
public Effect healEffect = Fx.heal; public Effect healEffect = Fx.heal;
public Effect activeEffect = Fx.healWave; public Effect activeEffect = Fx.healWave;
private boolean wasHealed = false; protected float timer;
protected boolean wasHealed = false;
HealFieldAbility(){} HealFieldAbility(){}
@@ -22,9 +23,9 @@ public class HealFieldAbility implements Ability{
@Override @Override
public void update(Unit unit){ public void update(Unit unit){
unit.timer1 += Time.delta; timer += Time.delta;
if(unit.timer1 >= reload){ if(timer >= reload){
wasHealed = false; wasHealed = false;
Units.nearby(unit.team, unit.x, unit.y, range, other -> { Units.nearby(unit.team, unit.x, unit.y, range, other -> {
@@ -39,7 +40,7 @@ public class HealFieldAbility implements Ability{
activeEffect.at(unit); activeEffect.at(unit);
} }
unit.timer1 = 0f; timer = 0f;
} }
} }
} }
@@ -5,12 +5,13 @@ import mindustry.content.*;
import mindustry.entities.*; import mindustry.entities.*;
import mindustry.gen.*; import mindustry.gen.*;
public class ShieldFieldAbility implements Ability{ public class ShieldFieldAbility extends Ability{
public float amount = 1, max = 100f, reload = 100, range = 60; public float amount = 1, max = 100f, reload = 100, range = 60;
public Effect applyEffect = Fx.shieldApply; public Effect applyEffect = Fx.shieldApply;
public Effect activeEffect = Fx.shieldWave; public Effect activeEffect = Fx.shieldWave;
private boolean applied = false; protected float timer;
protected boolean applied = false;
ShieldFieldAbility(){} ShieldFieldAbility(){}
@@ -23,9 +24,9 @@ public class ShieldFieldAbility implements Ability{
@Override @Override
public void update(Unit unit){ public void update(Unit unit){
unit.timer1 += Time.delta; timer += Time.delta;
if(unit.timer1 >= reload){ if(timer >= reload){
applied = false; applied = false;
Units.nearby(unit.team, unit.x, unit.y, range, other -> { Units.nearby(unit.team, unit.x, unit.y, range, other -> {
@@ -41,7 +42,7 @@ public class ShieldFieldAbility implements Ability{
activeEffect.at(unit); activeEffect.at(unit);
} }
unit.timer1 = 0f; timer = 0f;
} }
} }
} }
@@ -7,12 +7,14 @@ import mindustry.entities.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.type.*; import mindustry.type.*;
public class StatusFieldAbility implements Ability{ public class StatusFieldAbility extends Ability{
public @NonNull StatusEffect effect; public @NonNull StatusEffect effect;
public float duration = 60, reload = 100, range = 20; public float duration = 60, reload = 100, range = 20;
public Effect applyEffect = Fx.heal; public Effect applyEffect = Fx.heal;
public Effect activeEffect = Fx.overdriveWave; public Effect activeEffect = Fx.overdriveWave;
protected float timer;
StatusFieldAbility(){} StatusFieldAbility(){}
public StatusFieldAbility(@NonNull StatusEffect effect, float duration, float reload, float range){ public StatusFieldAbility(@NonNull StatusEffect effect, float duration, float reload, float range){
@@ -24,9 +26,9 @@ public class StatusFieldAbility implements Ability{
@Override @Override
public void update(Unit unit){ public void update(Unit unit){
unit.timer2 += Time.delta; timer += Time.delta;
if(unit.timer2 >= reload){ if(timer >= reload){
Units.nearby(unit.team, unit.x, unit.y, range, other -> { Units.nearby(unit.team, unit.x, unit.y, range, other -> {
other.apply(effect, duration); other.apply(effect, duration);
@@ -34,7 +36,7 @@ public class StatusFieldAbility implements Ability{
activeEffect.at(unit); activeEffect.at(unit);
unit.timer2 = 0f; timer = 0f;
} }
} }
} }
@@ -0,0 +1,60 @@
package mindustry.entities.abilities;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.util.ArcAnnotate.*;
import arc.util.*;
import mindustry.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.ui.*;
public class UnitSpawnAbility extends Ability{
public @NonNull UnitType type;
public float spawnTime = 60f, spawnX, spawnY;
public Effect spawnEffect = Fx.spawn;
protected float timer;
public UnitSpawnAbility(@NonNull UnitType type, float spawnTime, float spawnX, float spawnY){
this.type = type;
this.spawnTime = spawnTime;
this.spawnX = spawnX;
this.spawnY = spawnY;
}
public UnitSpawnAbility(){
}
@Override
public void update(Unit unit){
timer += Time.delta;
if(timer >= spawnTime && Units.canCreate(unit.team, type)){
float x = unit.x + Angles.trnsx(unit.rotation, spawnY, spawnX), y = unit.y + Angles.trnsy(unit.rotation, spawnY, spawnX);
spawnEffect.at(x, y);
Unit u = type.create(unit.team);
u.set(x, y);
u.rotation = unit.rotation;
if(!Vars.net.client()){
u.add();
}
timer = 0f;
}
}
@Override
public void draw(Unit unit){
if(Units.canCreate(unit.team, type)){
Draw.draw(Draw.z(), () -> {
float x = unit.x + Angles.trnsx(unit.rotation, spawnY, spawnX), y = unit.y + Angles.trnsy(unit.rotation, spawnY, spawnX);
Drawf.construct(x, y, type.icon(Cicon.full), unit.rotation - 90, timer / spawnTime, 1f, timer);
});
}
}
}
@@ -1,16 +1,17 @@
package mindustry.entities.bullet; package mindustry.entities.bullet;
import arc.Core; import arc.*;
import arc.graphics.Color; import arc.graphics.*;
import arc.graphics.g2d.Draw; import arc.graphics.g2d.*;
import arc.graphics.g2d.TextureRegion;
import arc.math.*; import arc.math.*;
import arc.util.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.Pal; import mindustry.graphics.*;
/** An extended BulletType for most ammo-based bullets shot from turrets and units. */ /** An extended BulletType for most ammo-based bullets shot from turrets and units. */
public class BasicBulletType extends BulletType{ public class BasicBulletType extends BulletType{
public Color backColor = Pal.bulletYellowBack, frontColor = Pal.bulletYellow; public Color backColor = Pal.bulletYellowBack, frontColor = Pal.bulletYellow;
public Color mixColorFrom = new Color(1f, 1f, 1f, 0f), mixColorTo = new Color(1f, 1f, 1f, 0f);
public float width = 5f, height = 7f; public float width = 5f, height = 7f;
public float shrinkX = 0f, shrinkY = 0.5f; public float shrinkX = 0f, shrinkY = 0.5f;
public float spin = 0; public float spin = 0;
@@ -45,10 +46,15 @@ public class BasicBulletType extends BulletType{
float width = this.width * ((1f - shrinkX) + shrinkX * b.fout()); float width = this.width * ((1f - shrinkX) + shrinkX * b.fout());
float offset = -90 + (spin != 0 ? Mathf.randomSeed(b.id, 360f) + b.time * spin : 0f); float offset = -90 + (spin != 0 ? Mathf.randomSeed(b.id, 360f) + b.time * spin : 0f);
Color mix = Tmp.c1.set(mixColorFrom).lerp(mixColorTo, b.fin());
Draw.mixcol(mix, mix.a);
Draw.color(backColor); Draw.color(backColor);
Draw.rect(backRegion, b.x, b.y, width, height, b.rotation() + offset); Draw.rect(backRegion, b.x, b.y, width, height, b.rotation() + offset);
Draw.color(frontColor); Draw.color(frontColor);
Draw.rect(frontRegion, b.x, b.y, width, height, b.rotation() + offset); Draw.rect(frontRegion, b.x, b.y, width, height, b.rotation() + offset);
Draw.color();
Draw.reset();
} }
} }
@@ -24,7 +24,7 @@ public abstract class BulletType extends Content{
public float hitSize = 4; public float hitSize = 4;
public float drawSize = 40f; public float drawSize = 40f;
public float drag = 0f; public float drag = 0f;
public boolean pierce; public boolean pierce, pierceBuilding;
public Effect hitEffect, despawnEffect; public Effect hitEffect, despawnEffect;
/** Effect created when shooting. */ /** Effect created when shooting. */
@@ -69,6 +69,8 @@ public abstract class BulletType extends Content{
public boolean scaleVelocity; public boolean scaleVelocity;
/** Whether this bullet can be hit by point defense. */ /** Whether this bullet can be hit by point defense. */
public boolean hittable = true; public boolean hittable = true;
/** Whether this bullet can be reflected. */
public boolean reflectable = true;
//additional effects //additional effects
@@ -100,7 +102,7 @@ public abstract class BulletType extends Content{
public float weaveScale = 1f; public float weaveScale = 1f;
public float weaveMag = -1f; public float weaveMag = -1f;
public float hitShake = 0f; public float hitShake = 0f, despawnShake = 0f;
public int puddles; public int puddles;
public float puddleRange; public float puddleRange;
@@ -131,10 +133,14 @@ public abstract class BulletType extends Content{
return true; return true;
} }
public void hitTile(Bullet b, Building tile){ public void hitTile(Bullet b, Building tile, float initialHealth){
hit(b); hit(b);
} }
public void hitEntity(Bullet b, Hitboxc other, float initialHealth){
}
public void hit(Bullet b){ public void hit(Bullet b){
hit(b, b.x, b.y); hit(b, b.x, b.y);
} }
@@ -181,6 +187,8 @@ public abstract class BulletType extends Content{
despawnEffect.at(b.x, b.y, b.rotation(), hitColor); despawnEffect.at(b.x, b.y, b.rotation(), hitColor);
hitSound.at(b); hitSound.at(b);
Effect.shake(despawnShake, despawnShake, b);
if(fragBullet != null || splashDamageRadius > 0 || lightning > 0){ if(fragBullet != null || splashDamageRadius > 0 || lightning > 0){
hit(b); hit(b);
} }
@@ -43,7 +43,7 @@ public class HealBulletType extends BulletType{
} }
@Override @Override
public void hitTile(Bullet b, Building tile){ public void hitTile(Bullet b, Building tile, float initialHealth){
super.hit(b); super.hit(b);
if(tile.team == b.team && !(tile.block instanceof ConstructBlock)){ if(tile.team == b.team && !(tile.block instanceof ConstructBlock)){
@@ -0,0 +1,52 @@
package mindustry.entities.bullet;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.gen.*;
public class RailBulletType extends BulletType{
public Effect pierceEffect = Fx.hitBulletSmall, updateEffect = Fx.none;
/** Multiplier of damage decreased per health pierced. */
public float pierceDamageFactor = 1f;
public RailBulletType(){
pierceBuilding = true;
pierce = true;
reflectable = false;
hitEffect = Fx.none;
despawnEffect = Fx.none;
}
void handle(Bullet b, Posc pos, float initialHealth){
float sub = initialHealth*pierceDamageFactor;
if(sub >= b.damage){
//cause a despawn
b.remove();
}
//subtract health from each consecutive pierce
b.damage -= Math.min(b.damage, sub);
if(b.damage > 0){
pierceEffect.at(pos.getX(), pos.getY(), b.rotation());
}
hitEffect.at(pos.getX(), pos.getY());
}
@Override
public void update(Bullet b){
updateEffect.at(b.x, b.y, b.rotation());
}
@Override
public void hitEntity(Bullet b, Hitboxc entity, float initialHealth){
handle(b, entity, initialHealth);
}
@Override
public void hitTile(Bullet b, Building tile, float initialHealth){
handle(b, tile, initialHealth);
}
}
@@ -39,10 +39,15 @@ public class SapBulletType extends BulletType{
Draw.reset(); Draw.reset();
Drawf.light(b.team, b.x, b.y, b.x + Tmp.v1.x, b.y + Tmp.v1.y, 15f * b.fout(), lightColor, 0.6f); Drawf.light(b.team, b.x, b.y, Tmp.v1.x, Tmp.v1.y, 15f * b.fout(), lightColor, 0.6f);
} }
} }
@Override
public void drawLight(Bullet b){
}
@Override @Override
public float range(){ public float range(){
return length; return length;
@@ -108,9 +108,9 @@ abstract class BuilderComp implements Unitc{
ConstructBuild entity = tile.bc(); ConstructBuild entity = tile.bc();
if(current.breaking){ if(current.breaking){
entity.deconstruct(base(), core, 1f / entity.buildCost * Time.delta * type().buildSpeed * state.rules.buildSpeedMultiplier); entity.deconstruct(self(), core, 1f / entity.buildCost * Time.delta * type().buildSpeed * state.rules.buildSpeedMultiplier);
}else{ }else{
entity.construct(base(), core, 1f / entity.buildCost * Time.delta * type().buildSpeed * state.rules.buildSpeedMultiplier, current.config); entity.construct(self(), core, 1f / entity.buildCost * Time.delta * type().buildSpeed * state.rules.buildSpeedMultiplier, current.config);
} }
current.stuck = Mathf.equal(current.progress, entity.progress); current.stuck = Mathf.equal(current.progress, entity.progress);
@@ -80,7 +80,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
if(block.hasPower){ if(block.hasPower){
//reinit power graph //reinit power graph
power.graph = new PowerGraph(); power.graph = new PowerGraph();
power.graph.add(base()); power.graph.add(self());
} }
} }
this.rotation = rotation; this.rotation = rotation;
@@ -94,7 +94,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
created(); created();
return base(); return self();
} }
/** Sets up all the necessary variables, but does not add this entity anywhere. */ /** Sets up all the necessary variables, but does not add this entity anywhere. */
@@ -111,17 +111,17 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
maxHealth(block.health); maxHealth(block.health);
timer(new Interval(block.timers)); timer(new Interval(block.timers));
cons = new ConsumeModule(base()); cons = new ConsumeModule(self());
if(block.hasItems) items = new ItemModule(); if(block.hasItems) items = new ItemModule();
if(block.hasLiquids) liquids = new LiquidModule(); if(block.hasLiquids) liquids = new LiquidModule();
if(block.hasPower){ if(block.hasPower){
power = new PowerModule(); power = new PowerModule();
power.graph.add(base()); power.graph.add(self());
} }
initialized = true; initialized = true;
return base(); return self();
} }
@Override @Override
@@ -195,17 +195,17 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
public void configure(Object value){ public void configure(Object value){
//save last used config //save last used config
block.lastConfig = value; block.lastConfig = value;
Call.tileConfig(player, base(), value); Call.tileConfig(player, self(), value);
} }
/** Configure from a server. */ /** Configure from a server. */
public void configureAny(Object value){ public void configureAny(Object value){
Call.tileConfig(null, base(), value); Call.tileConfig(null, self(), value);
} }
/** Deselect this tile from configuration. */ /** Deselect this tile from configuration. */
public void deselect(){ public void deselect(){
if(!headless && control.input.frag.config.getSelectedTile() == base()){ if(!headless && control.input.frag.config.getSelectedTile() == self()){
control.input.frag.config.hideConfig(); control.input.frag.config.hideConfig();
} }
} }
@@ -372,7 +372,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
/** Returns the amount of items this block can accept. */ /** Returns the amount of items this block can accept. */
public int acceptStack(Item item, int amount, Teamc source){ public int acceptStack(Item item, int amount, Teamc source){
if(acceptItem(base(), item) && block.hasItems && (source == null || source.team() == team)){ if(acceptItem(self(), item) && block.hasItems && (source == null || source.team() == team)){
return Math.min(getMaximumAccepted(item) - items.get(item), amount); return Math.min(getMaximumAccepted(item) - items.get(item), amount);
}else{ }else{
return 0; return 0;
@@ -425,8 +425,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
int trns = block.size/2 + 1; int trns = block.size/2 + 1;
Tile next = tile.getNearby(Geometry.d4(rotation).x * trns, Geometry.d4(rotation).y * trns); Tile next = tile.getNearby(Geometry.d4(rotation).x * trns, Geometry.d4(rotation).y * trns);
if(next != null && next.build != null && next.build.team == team && next.build.acceptPayload(base(), todump)){ if(next != null && next.build != null && next.build.team == team && next.build.acceptPayload(self(), todump)){
next.build.handlePayload(base(), todump); next.build.handlePayload(self(), todump);
return true; return true;
} }
@@ -446,8 +446,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
for(int i = 0; i < proximity.size; i++){ for(int i = 0; i < proximity.size; i++){
Building other = proximity.get((i + dump) % proximity.size); Building other = proximity.get((i + dump) % proximity.size);
if(other.team == team && other.acceptPayload(base(), todump)){ if(other.team == team && other.acceptPayload(self(), todump)){
other.handlePayload(base(), todump); other.handlePayload(self(), todump);
incrementDump(proximity.size); incrementDump(proximity.size);
return true; return true;
} }
@@ -480,7 +480,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
for(int i = 0; i < proximity.size; i++){ for(int i = 0; i < proximity.size; i++){
incrementDump(proximity.size); incrementDump(proximity.size);
Building other = proximity.get((i + dump) % proximity.size); Building other = proximity.get((i + dump) % proximity.size);
other = other.getLiquidDestination(base(), liquid); other = other.getLiquidDestination(self(), liquid);
if(other != null && other.team == team && other.block.hasLiquids && canDumpLiquid(other, liquid) && other.liquids != null){ if(other != null && other.team == team && other.block.hasLiquids && canDumpLiquid(other, liquid) && other.liquids != null){
float ofract = other.liquids.get(liquid) / other.block.liquidCapacity; float ofract = other.liquids.get(liquid) / other.block.liquidCapacity;
@@ -499,8 +499,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
public void transferLiquid(Building next, float amount, Liquid liquid){ public void transferLiquid(Building next, float amount, Liquid liquid){
float flow = Math.min(next.block.liquidCapacity - next.liquids.get(liquid) - 0.001f, amount); float flow = Math.min(next.block.liquidCapacity - next.liquids.get(liquid) - 0.001f, amount);
if(next.acceptLiquid(base(), liquid, flow)){ if(next.acceptLiquid(self(), liquid, flow)){
next.handleLiquid(base(), liquid, flow); next.handleLiquid(self(), liquid, flow);
liquids.remove(liquid, flow); liquids.remove(liquid, flow);
} }
} }
@@ -523,7 +523,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
public float moveLiquid(Building next, Liquid liquid){ public float moveLiquid(Building next, Liquid liquid){
if(next == null) return 0; if(next == null) return 0;
next = next.getLiquidDestination(base(), liquid); next = next.getLiquidDestination(self(), liquid);
if(next.team == team && next.block.hasLiquids && liquids.get(liquid) > 0f){ if(next.team == team && next.block.hasLiquids && liquids.get(liquid) > 0f){
float ofract = next.liquids.get(liquid) / next.block.liquidCapacity; float ofract = next.liquids.get(liquid) / next.block.liquidCapacity;
@@ -531,8 +531,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
float flow = Math.min(Mathf.clamp((fract - ofract) * (1f)) * (block.liquidCapacity), liquids.get(liquid)); float flow = Math.min(Mathf.clamp((fract - ofract) * (1f)) * (block.liquidCapacity), liquids.get(liquid));
flow = Math.min(flow, next.block.liquidCapacity - next.liquids.get(liquid) - 0.001f); flow = Math.min(flow, next.block.liquidCapacity - next.liquids.get(liquid) - 0.001f);
if(flow > 0f && ofract <= fract && next.acceptLiquid(base(), liquid, flow)){ if(flow > 0f && ofract <= fract && next.acceptLiquid(self(), liquid, flow)){
next.handleLiquid(base(), liquid, flow); next.handleLiquid(self(), liquid, flow);
liquids.remove(liquid, flow); liquids.remove(liquid, flow);
return flow; return flow;
}else if(next.liquids.currentAmount() / next.block.liquidCapacity > 0.1f && fract > 0.1f){ }else if(next.liquids.currentAmount() / next.block.liquidCapacity > 0.1f && fract > 0.1f){
@@ -558,7 +558,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
} }
public Building getLiquidDestination(Building from, Liquid liquid){ public Building getLiquidDestination(Building from, Liquid liquid){
return base(); return self();
} }
public @Nullable Payload getPayload(){ public @Nullable Payload getPayload(){
@@ -580,13 +580,13 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
for(int i = 0; i < proximity.size; i++){ for(int i = 0; i < proximity.size; i++){
incrementDump(proximity.size); incrementDump(proximity.size);
Building other = proximity.get((i + dump) % proximity.size); Building other = proximity.get((i + dump) % proximity.size);
if(other.team == team && other.acceptItem(base(), item) && canDump(other, item)){ if(other.team == team && other.acceptItem(self(), item) && canDump(other, item)){
other.handleItem(base(), item); other.handleItem(self(), item);
return; return;
} }
} }
handleItem(base(), item); handleItem(self(), item);
} }
/** /**
@@ -598,8 +598,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
for(int i = 0; i < proximity.size; i++){ for(int i = 0; i < proximity.size; i++){
incrementDump(proximity.size); incrementDump(proximity.size);
Building other = proximity.get((i + dump) % proximity.size); Building other = proximity.get((i + dump) % proximity.size);
if(other.team == team && other.acceptItem(base(), item) && canDump(other, item)){ if(other.team == team && other.acceptItem(self(), item) && canDump(other, item)){
other.handleItem(base(), item); other.handleItem(self(), item);
return true; return true;
} }
} }
@@ -631,16 +631,16 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
for(int ii = 0; ii < content.items().size; ii++){ for(int ii = 0; ii < content.items().size; ii++){
Item item = content.item(ii); Item item = content.item(ii);
if(other.team == team && items.has(item) && other.acceptItem(base(), item) && canDump(other, item)){ if(other.team == team && items.has(item) && other.acceptItem(self(), item) && canDump(other, item)){
other.handleItem(base(), item); other.handleItem(self(), item);
items.remove(item, 1); items.remove(item, 1);
incrementDump(proximity.size); incrementDump(proximity.size);
return true; return true;
} }
} }
}else{ }else{
if(other.team == team && other.acceptItem(base(), todump) && canDump(other, todump)){ if(other.team == team && other.acceptItem(self(), todump) && canDump(other, todump)){
other.handleItem(base(), todump); other.handleItem(self(), todump);
items.remove(todump, 1); items.remove(todump, 1);
incrementDump(proximity.size); incrementDump(proximity.size);
return true; return true;
@@ -665,8 +665,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
/** Try offloading an item to a nearby container in its facing direction. Returns true if success. */ /** Try offloading an item to a nearby container in its facing direction. Returns true if success. */
public boolean moveForward(Item item){ public boolean moveForward(Item item){
Building other = front(); Building other = front();
if(other != null && other.team == team && other.acceptItem(base(), item)){ if(other != null && other.team == team && other.acceptItem(self(), item)){
other.handleItem(base(), item); other.handleItem(self(), item);
return true; return true;
} }
return false; return false;
@@ -696,7 +696,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
return; return;
} }
power.graph.remove(base()); power.graph.remove(self());
for(int i = 0; i < power.links.size; i++){ for(int i = 0; i < power.links.size; i++){
Tile other = world.tile(power.links.get(i)); Tile other = world.tile(power.links.get(i));
if(other != null && other.build != null && other.build.power != null){ if(other != null && other.build != null && other.build.power != null){
@@ -833,8 +833,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
tempTiles.clear(); tempTiles.clear();
Geometry.circle(tileX(), tileY(), range, (x, y) -> { Geometry.circle(tileX(), tileY(), range, (x, y) -> {
Building other = world.build(x, y); Building other = world.build(x, y);
if(other != null && other.block instanceof PowerNode && ((PowerNode)other.block).linkValid(other, base()) && !PowerNode.insulated(other, base()) if(other != null && other.block instanceof PowerNode && ((PowerNode)other.block).linkValid(other, self()) && !PowerNode.insulated(other, self())
&& !other.proximity().contains(this.<Building>base()) && && !other.proximity().contains(this.<Building>self()) &&
!(block.outputsPower && proximity.contains(p -> p.power != null && p.power.graph == other.power.graph))){ !(block.outputsPower && proximity.contains(p -> p.power != null && p.power.graph == other.power.graph))){
tempTiles.add(other.tile); tempTiles.add(other.tile);
} }
@@ -1037,13 +1037,13 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
table.left(); table.left();
for(Consume cons : block.consumes.all()){ for(Consume cons : block.consumes.all()){
if(cons.isOptional() && cons.isBoost()) continue; if(cons.isOptional() && cons.isBoost()) continue;
cons.build(base(), table); cons.build(self(), table);
} }
} }
public void displayBars(Table table){ public void displayBars(Table table){
for(Func<Building, Bar> bar : block.bars.list()){ for(Func<Building, Bar> bar : block.bars.list()){
table.add(bar.get(base())).growX(); table.add(bar.get(self())).growX();
table.row(); table.row();
} }
} }
@@ -1069,7 +1069,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
* @return whether or not this block should be deselected. * @return whether or not this block should be deselected.
*/ */
public boolean onConfigureTileTapped(Building other){ public boolean onConfigureTileTapped(Building other){
return base() != other; return self() != other;
} }
/** Returns whether this config menu should show when the specified player taps it. */ /** Returns whether this config menu should show when the specified player taps it. */
@@ -1128,7 +1128,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
} }
for(Building other : tmpTiles){ for(Building other : tmpTiles){
other.proximity.remove(base(), true); other.proximity.remove(self(), true);
other.onProximityUpdate(); other.onProximityUpdate();
} }
} }
@@ -1144,8 +1144,8 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
if(other == null || !(other.tile.interactable(team))) continue; if(other == null || !(other.tile.interactable(team))) continue;
//add this tile to proximity of nearby tiles //add this tile to proximity of nearby tiles
if(!other.proximity.contains(base(), true)){ if(!other.proximity.contains(self(), true)){
other.proximity.add(base()); other.proximity.add(self());
} }
tmpTiles.add(other); tmpTiles.add(other);
@@ -1184,13 +1184,13 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
@Replace @Replace
@Override @Override
public boolean isValid(){ public boolean isValid(){
return tile.build == base() && !dead(); return tile.build == self() && !dead();
} }
@Replace @Replace
@Override @Override
public void kill(){ public void kill(){
Call.tileDestroyed(base()); Call.tileDestroyed(self());
} }
@Replace @Replace
@@ -1204,10 +1204,10 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
damage /= state.rules.blockHealthMultiplier; damage /= state.rules.blockHealthMultiplier;
} }
Call.tileDamage(base(), health - handleDamage(damage)); Call.tileDamage(self(), health - handleDamage(damage));
if(health <= 0){ if(health <= 0){
Call.tileDestroyed(base()); Call.tileDestroyed(self());
} }
} }
@@ -1292,7 +1292,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
} }
if(block.idleSound != Sounds.none && shouldIdleSound()){ if(block.idleSound != Sounds.none && shouldIdleSound()){
loops.play(block.idleSound, base(), block.idleSoundVolume); loops.play(block.idleSound, self(), block.idleSoundVolume);
} }
if(enabled || !block.noUpdateDisabled){ if(enabled || !block.noUpdateDisabled){
@@ -44,17 +44,17 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
@Override @Override
public void drawBullets(){ public void drawBullets(){
type.draw(base()); type.draw(self());
} }
@Override @Override
public void add(){ public void add(){
type.init(base()); type.init(self());
} }
@Override @Override
public void remove(){ public void remove(){
type.despawned(base()); type.despawned(self());
collided.clear(); collided.clear();
} }
@@ -92,10 +92,12 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
@MethodPriority(100) @MethodPriority(100)
@Override @Override
public void collision(Hitboxc other, float x, float y){ public void collision(Hitboxc other, float x, float y){
type.hit(base(), x, y); type.hit(self(), x, y);
float health = 0f;
if(other instanceof Healthc){ if(other instanceof Healthc){
Healthc h = (Healthc)other; Healthc h = (Healthc)other;
health = h.health();
h.damage(damage); h.damage(damage);
} }
@@ -111,30 +113,40 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
}else{ }else{
collided.add(other.id()); collided.add(other.id());
} }
type.hitEntity(self(), other, health);
} }
@Override @Override
public void update(){ public void update(){
type.update(base()); type.update(self());
if(type.collidesTiles && type.collides && type.collidesGround){ if(type.collidesTiles && type.collides && type.collidesGround){
world.raycastEach(world.toTile(lastX()), world.toTile(lastY()), tileX(), tileY(), (x, y) -> { world.raycastEach(world.toTile(lastX()), world.toTile(lastY()), tileX(), tileY(), (x, y) -> {
Building tile = world.build(x, y); Building tile = world.build(x, y);
if(tile == null) return false; if(tile == null || !isAdded()) return false;
if(tile.collide(base()) && type.collides(base(), tile) && !tile.dead() && (type.collidesTeam || tile.team != team)){ if(tile.collide(self()) && type.collides(self(), tile) && !tile.dead() && (type.collidesTeam || tile.team != team) && !(type.pierceBuilding && collided.contains(tile.id))){
boolean remove = false; boolean remove = false;
float health = tile.health;
if(tile.team != team){ if(tile.team != team){
remove = tile.collision(base()); remove = tile.collision(self());
} }
if(remove || type.collidesTeam){ if(remove || type.collidesTeam){
type.hitTile(base(), tile); if(!type.pierceBuilding){
remove(); remove();
}else{
collided.add(tile.id);
}
} }
return true;
type.hitTile(self(), tile, health);
return !type.pierceBuilding;
} }
return false; return false;
@@ -146,8 +158,8 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw
public void draw(){ public void draw(){
Draw.z(Layer.bullet); Draw.z(Layer.bullet);
type.draw(base()); type.draw(self());
type.drawLight(base()); type.drawLight(self());
} }
/** Sets the bullet's rotation in degrees. */ /** Sets the bullet's rotation in degrees. */

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