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

This commit is contained in:
Petr Gašparík
2020-11-25 18:20:42 +01:00
55 changed files with 276 additions and 131 deletions
+4 -2
View File
@@ -21,6 +21,8 @@ jobs:
- name: Update docs - name: Update docs
run: | run: |
cd ../ cd ../
git config --global user.email "cli@github.com"
git config --global user.name "Github Actions"
git clone --depth=1 https://github.com/MindustryGame/docs.git git clone --depth=1 https://github.com/MindustryGame/docs.git
cp -a Mindustry/core/build/docs/javadoc/. docs/ cp -a Mindustry/core/build/docs/javadoc/. docs/
cd docs cd docs
@@ -48,12 +50,12 @@ jobs:
uses: svenstaro/upload-release-action@v2 uses: svenstaro/upload-release-action@v2
with: with:
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
file: desktop/libs/Mindustry.jar file: desktop/build/libs/Mindustry.jar
tag: ${{ github.ref }} tag: ${{ github.ref }}
- name: Upload server artifacts - name: Upload server artifacts
uses: svenstaro/upload-release-action@v2 uses: svenstaro/upload-release-action@v2
with: with:
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
file: server/libs/server-release.jar file: server/build/libs/server-release.jar
tag: ${{ github.ref }} tag: ${{ github.ref }}
+1
View File
@@ -15,6 +15,7 @@ jobs:
- name: Run unit tests - name: Run unit tests
run: ./gradlew test run: ./gradlew test
- name: Trigger BE build - name: Trigger BE build
if: ${{ github.repository == 'Anuken/Mindustry' }}
run: | run: |
git clone --depth=1 --branch=master https://github.com/Anuken/MindustryBuilds ../MindustryBuilds git clone --depth=1 --branch=master https://github.com/Anuken/MindustryBuilds ../MindustryBuilds
cd ../MindustryBuilds cd ../MindustryBuilds
+9 -2
View File
@@ -22,7 +22,6 @@ gameover.pvp = The[accent] {0}[] team is victorious!
gameover.waiting = [accent]Waiting for next map... gameover.waiting = [accent]Waiting for next map...
highscore = [accent]New highscore! highscore = [accent]New highscore!
copied = Copied. copied = Copied.
indev.popup = [accent]v6[] is currently in [accent]beta[].\n[lightgray]This means:[]\n[scarlet]- The campaign is unfinished[]\n- Everything you see is subject to change or removal.\n\nReport bugs or crashes on [accent]Github[].
indev.notready = This part of the game isn't ready yet indev.notready = This part of the game isn't ready yet
indev.campaign = [accent]You've reached the end of the campaign![]\n\nThis is as far as the content goes. Interplanetary travel will be added in future updates. indev.campaign = [accent]You've reached the end of the campaign![]\n\nThis is as far as the content goes. Interplanetary travel will be added in future updates.
@@ -147,6 +146,7 @@ planetmap = Planet Map
launchcore = Launch Core launchcore = Launch Core
filename = File Name: filename = File Name:
unlocked = New content unlocked! unlocked = New content unlocked!
available = New research available!
completed = [accent]Completed completed = [accent]Completed
techtree = Tech Tree techtree = Tech Tree
research.list = [lightgray]Research: research.list = [lightgray]Research:
@@ -230,6 +230,7 @@ disconnect.timeout = Timed out.
disconnect.data = Failed to load world data! disconnect.data = Failed to load world data!
cantconnect = Unable to join game ([accent]{0}[]). cantconnect = Unable to join game ([accent]{0}[]).
connecting = [accent]Connecting... connecting = [accent]Connecting...
reconnecting = [accent]Reconnecting...
connecting.data = [accent]Loading world data... connecting.data = [accent]Loading world data...
server.port = Port: server.port = Port:
server.addressinuse = Address already in use! server.addressinuse = Address already in use!
@@ -593,6 +594,11 @@ sector.tarFields.description = The outskirts of an oil production zone, between
sector.desolateRift.description = An extremely dangerous zone. Plentiful resources, but little space. High risk of destruction. Leave as soon as possible. Do not be fooled by the long spacing between enemy attacks. sector.desolateRift.description = An extremely dangerous zone. Plentiful resources, but little space. High risk of destruction. Leave as soon as possible. Do not be fooled by the long spacing between enemy attacks.
sector.nuclearComplex.description = A former facility for the production and processing of thorium, reduced to ruins.\n[lightgray]Research the thorium and its many uses.\n\nThe enemy is present here in great numbers, constantly scouting for attackers. sector.nuclearComplex.description = A former facility for the production and processing of thorium, reduced to ruins.\n[lightgray]Research the thorium and its many uses.\n\nThe enemy is present here in great numbers, constantly scouting for attackers.
sector.fungalPass.description = A transition area between high mountains and lower, spore-ridden lands. A small enemy reconnaissance base is located here.\nDestroy it.\nUse Dagger and Crawler units. Take out the two cores. sector.fungalPass.description = A transition area between high mountains and lower, spore-ridden lands. A small enemy reconnaissance base is located here.\nDestroy it.\nUse Dagger and Crawler units. Take out the two cores.
sector.biomassFacility.description = The origin of spores. This is the facility in which they were researched and initially produced.\nResearch the technology contained within. Cultivate spores for the production of fuel and plastics.\n\n[lightgray]Upon this facility's demise, the spores were released. Nothing in the local ecosystem could compete with such an invasive organism.
sector.windsweptIslands.description = Further past the shoreline is this remote chain of islands. Records show they once had [accent]Plastanium[]-producing structures.\n\nFend off the enemy's naval units. Establish a base on the islands. Research these factories.
sector.extractionOutpost.description = A remote outpost, constructed by the enemy for the purpose of launching resources to other sectors.\n\nCross-sector transport technology is essential for further conquest. Destroy the base. Research their Launch Pads.
sector.impact0078.description = Here lie remnants of the interstellar transport vessel that first entered this system.\n\nSalvage as much as possible from the wreckage. Research any intact technology.
sector.planetaryTerminal.description = The final target.\n\nThis coastal base contains a structure capable of launching Cores to local planets. It is extremely well guarded.\n\nProduce naval units. Eliminate the enemy as quickly as possible. Research the launch structure.
settings.language = Language settings.language = Language
settings.data = Game Data settings.data = Game Data
@@ -1261,7 +1267,7 @@ hint.schematicSelect = Hold [accent][[F][] and drag to select blocks to copy and
hint.conveyorPathfind = Hold [accent][[L-Ctrl][] while dragging conveyors to automatically generate a path. hint.conveyorPathfind = Hold [accent][[L-Ctrl][] while dragging conveyors to automatically generate a path.
hint.conveyorPathfind.mobile = Enable \ue844 [accent]diagonal mode[] and drag conveyors to automatically generate a path. hint.conveyorPathfind.mobile = Enable \ue844 [accent]diagonal mode[] and drag conveyors to automatically generate a path.
hint.boost = Hold [accent][[L-Shift][] to fly over obstacles with your current unit.\n\nOnly a few ground units have boosters. hint.boost = Hold [accent][[L-Shift][] to fly over obstacles with your current unit.\n\nOnly a few ground units have boosters.
hint.command = Press [accent][[G][] to command nearby units into formation. hint.command = Press [accent][[G][] to command nearby units of [accent]similar type[] into formation.\n\nTo command ground units, you must first control another ground unit.
hint.command.mobile = [accent][[Double-tap][] your unit to command nearby units into formation. hint.command.mobile = [accent][[Double-tap][] your unit to command nearby units into formation.
hint.payloadPickup = Press [accent][[[] to pick up small blocks or units. hint.payloadPickup = Press [accent][[[] to pick up small blocks or units.
hint.payloadPickup.mobile = [accent]Tap and hold[] a small block or unit to pick it up. hint.payloadPickup.mobile = [accent]Tap and hold[] a small block or unit to pick it up.
@@ -1269,6 +1275,7 @@ hint.payloadDrop = Press [accent]][] to drop a payload.
hint.payloadDrop.mobile = [accent]Tap and hold[] an empty location to drop a payload there. hint.payloadDrop.mobile = [accent]Tap and hold[] an empty location to drop a payload there.
hint.waveFire = [accent]Wave[] turrets with water as ammunition will automatically put out nearby fires. hint.waveFire = [accent]Wave[] turrets with water as ammunition will automatically put out nearby fires.
hint.generator = \uf879 [accent]Combustion Generators[] burn coal and transmit power to adjacent blocks.\n\nPower transmission range can be extended with \uf87f [accent]Power Nodes[]. hint.generator = \uf879 [accent]Combustion Generators[] burn coal and transmit power to adjacent blocks.\n\nPower transmission range can be extended with \uf87f [accent]Power Nodes[].
hint.guardian = [accent]Guardian[] units are armored. Weak ammo such as [accent]Copper[] and [accent]Lead[] is [scarlet]not effective[].\n\nUse higher tier turrets or \uf835 [accent]Graphite[] \uf861Duo/\uf859Salvo ammunition to take Guardians down.
item.copper.description = Used in all types of construction and ammunition. item.copper.description = Used in all types of construction and ammunition.
item.copper.details = Copper. Abnormally abundant metal on Serpulo. Structurally weak unless reinforced. item.copper.details = Copper. Abnormally abundant metal on Serpulo. Structurally weak unless reinforced.
+2 -1
View File
@@ -100,4 +100,5 @@ MEEP of Faith
jalastram (freesound.org) jalastram (freesound.org)
newlocknew (freesound.org) newlocknew (freesound.org)
dsmolenaers (freesound.org) dsmolenaers (freesound.org)
Headphaze (freesound.org) Headphaze (freesound.org)
VolasYouKnow
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -88,7 +88,7 @@ public class Vars implements Loadable{
/** duration of time between turns in ticks */ /** duration of time between turns in ticks */
public static final float turnDuration = 2 * Time.toMinutes; public static final float turnDuration = 2 * Time.toMinutes;
/** chance of an invasion per turn, 1 = 100% */ /** chance of an invasion per turn, 1 = 100% */
public static final float baseInvasionChance = 1f / 50f; public static final float baseInvasionChance = 1f / 75f;
/** how many turns have to pass before invasions start */ /** how many turns have to pass before invasions start */
public static final int invasionGracePeriod = 20; public static final int invasionGracePeriod = 20;
/** min armor fraction damage; e.g. 0.05 = at least 5% damage */ /** min armor fraction damage; e.g. 0.05 = at least 5% damage */
+5
View File
@@ -17,6 +17,7 @@ import mindustry.gen.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.blocks.defense.*; import mindustry.world.blocks.defense.*;
import mindustry.world.blocks.distribution.*;
import mindustry.world.blocks.production.*; import mindustry.world.blocks.production.*;
import mindustry.world.blocks.storage.*; import mindustry.world.blocks.storage.*;
import mindustry.world.blocks.storage.CoreBlock.*; import mindustry.world.blocks.storage.CoreBlock.*;
@@ -271,6 +272,10 @@ public class BaseAI{
} }
Tile o = world.tile(tile.x + p.x, tile.y + p.y); Tile o = world.tile(tile.x + p.x, tile.y + p.y);
if(o != null && (o.block() instanceof PayloadAcceptor || o.block() instanceof PayloadConveyor)){
break;
}
if(o != null && o.team() == data.team && !(o.block() instanceof Wall)){ if(o != null && o.team() == data.team && !(o.block() instanceof Wall)){
any = true; any = true;
break; break;
+4 -1
View File
@@ -1,5 +1,6 @@
package mindustry.ai.types; package mindustry.ai.types;
import arc.math.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import mindustry.entities.*; import mindustry.entities.*;
@@ -83,8 +84,10 @@ public class BuilderAI extends AIController{
}); });
} }
float rebuildTime = (unit.team.rules().ai ? Mathf.lerp(15f, 2f, unit.team.rules().aiTier) : 2f) * 60f;
//find new request //find new request
if(!unit.team.data().blocks.isEmpty() && following == null && timer.get(timerTarget3, 60 * 2f)){ if(!unit.team.data().blocks.isEmpty() && following == null && timer.get(timerTarget3, rebuildTime)){
Queue<BlockPlan> blocks = unit.team.data().blocks; Queue<BlockPlan> blocks = unit.team.data().blocks;
BlockPlan block = blocks.first(); BlockPlan block = blocks.first();
+10 -9
View File
@@ -363,7 +363,7 @@ public class Blocks implements ContentList{
sandWall = new StaticWall("sand-wall"){{ sandWall = new StaticWall("sand-wall"){{
variants = 2; variants = 2;
sandWater.asFloor().wall = this; sandWater.asFloor().wall = water.asFloor().wall = deepwater.asFloor().wall = this;
}}; }};
saltWall = new StaticWall("salt-wall"); saltWall = new StaticWall("salt-wall");
@@ -1195,7 +1195,7 @@ public class Blocks implements ContentList{
size = 2; size = 2;
ambientSound = Sounds.smelter; ambientSound = Sounds.smelter;
ambientSoundVolume = 0.05f; ambientSoundVolume = 0.06f;
}}; }};
differentialGenerator = new SingleTypeGenerator("differential-generator"){{ differentialGenerator = new SingleTypeGenerator("differential-generator"){{
@@ -1216,7 +1216,7 @@ public class Blocks implements ContentList{
requirements(Category.power, with(Items.lead, 100, Items.silicon, 75, Items.phaseFabric, 25, Items.plastanium, 75, Items.thorium, 50)); requirements(Category.power, with(Items.lead, 100, Items.silicon, 75, Items.phaseFabric, 25, Items.plastanium, 75, Items.thorium, 50));
size = 2; size = 2;
powerProduction = 4.5f; powerProduction = 4.5f;
itemDuration = 60 * 15f; itemDuration = 60 * 14f;
}}; }};
solarPanel = new SolarGenerator("solar-panel"){{ solarPanel = new SolarGenerator("solar-panel"){{
@@ -1377,7 +1377,7 @@ public class Blocks implements ContentList{
itemCapacity = 9000; itemCapacity = 9000;
size = 4; size = 4;
unitCapModifier = 14; unitCapModifier = 16;
researchCostMultiplier = 0.04f; researchCostMultiplier = 0.04f;
}}; }};
@@ -1389,7 +1389,7 @@ public class Blocks implements ContentList{
itemCapacity = 13000; itemCapacity = 13000;
size = 5; size = 5;
unitCapModifier = 20; unitCapModifier = 24;
researchCostMultiplier = 0.05f; researchCostMultiplier = 0.05f;
}}; }};
@@ -1517,12 +1517,12 @@ public class Blocks implements ContentList{
lancer = new ChargeTurret("lancer"){{ lancer = new ChargeTurret("lancer"){{
requirements(Category.turret, with(Items.copper, 25, Items.lead, 50, Items.silicon, 45)); requirements(Category.turret, with(Items.copper, 25, Items.lead, 50, Items.silicon, 45));
range = 155f; range = 165f;
chargeTime = 50f; chargeTime = 40f;
chargeMaxDelay = 30f; chargeMaxDelay = 30f;
chargeEffects = 7; chargeEffects = 7;
recoilAmount = 2f; recoilAmount = 2f;
reloadTime = 90f; reloadTime = 80f;
cooldown = 0.03f; cooldown = 0.03f;
powerUse = 6f; powerUse = 6f;
shootShake = 2f; shootShake = 2f;
@@ -1544,6 +1544,7 @@ public class Blocks implements ContentList{
lifetime = 16f; lifetime = 16f;
drawSize = 400f; drawSize = 400f;
collidesAir = false; collidesAir = false;
length = 173f;
}}; }};
}}; }};
@@ -1557,7 +1558,7 @@ public class Blocks implements ContentList{
reloadTime = 35f; reloadTime = 35f;
shootCone = 40f; shootCone = 40f;
rotateSpeed = 8f; rotateSpeed = 8f;
powerUse = 3f; powerUse = 3.3f;
targetAir = false; targetAir = false;
range = 90f; range = 90f;
shootEffect = Fx.lightningShoot; shootEffect = Fx.lightningShoot;
+1
View File
@@ -72,6 +72,7 @@ public class Items implements ContentList{
}}; }};
surgeAlloy = new Item("surge-alloy", Color.valueOf("f3e979")){{ surgeAlloy = new Item("surge-alloy", Color.valueOf("f3e979")){{
cost = 1.2f;
}}; }};
sporePod = new Item("spore-pod", Color.valueOf("7457ce")){{ sporePod = new Item("spore-pod", Color.valueOf("7457ce")){{
@@ -24,10 +24,11 @@ public class SectorPresets implements ContentList{
saltFlats = new SectorPreset("saltFlats", serpulo, 101){{ saltFlats = new SectorPreset("saltFlats", serpulo, 101){{
difficulty = 5; difficulty = 5;
useAI = false;
}}; }};
frozenForest = new SectorPreset("frozenForest", serpulo, 86){{ frozenForest = new SectorPreset("frozenForest", serpulo, 86){{
captureWave = 20; captureWave = 15;
difficulty = 2; difficulty = 2;
}}; }};
+9 -6
View File
@@ -121,7 +121,7 @@ public class TechTree implements ContentList{
}); });
node(waterExtractor, () -> { node(waterExtractor, Seq.with(new SectorComplete(saltFlats)), () -> {
node(oilExtractor, () -> { node(oilExtractor, () -> {
}); });
@@ -198,10 +198,10 @@ public class TechTree implements ContentList{
}); });
}); });
}); });
});
node(illuminator, () -> { node(illuminator, () -> {
});
}); });
}); });
@@ -421,7 +421,7 @@ public class TechTree implements ContentList{
}); });
node(additiveReconstructor, Seq.with(new SectorComplete(biomassFacility)), () -> { node(additiveReconstructor, Seq.with(new SectorComplete(biomassFacility)), () -> {
node(multiplicativeReconstructor, Seq.with(new SectorComplete(overgrowth)), () -> { node(multiplicativeReconstructor, () -> {
node(exponentialReconstructor, () -> { node(exponentialReconstructor, () -> {
node(tetrativeReconstructor, () -> { node(tetrativeReconstructor, () -> {
@@ -484,6 +484,7 @@ public class TechTree implements ContentList{
new Research(bryde), new Research(bryde),
new Research(spectre), new Research(spectre),
new Research(launchPad), new Research(launchPad),
new Research(massDriver),
new Research(impactReactor), new Research(impactReactor),
new Research(additiveReconstructor), new Research(additiveReconstructor),
new Research(exponentialReconstructor) new Research(exponentialReconstructor)
@@ -507,7 +508,9 @@ public class TechTree implements ContentList{
node(saltFlats, Seq.with( node(saltFlats, Seq.with(
new SectorComplete(windsweptIslands), new SectorComplete(windsweptIslands),
new Research(commandCenter),
new Research(groundFactory), new Research(groundFactory),
new Research(additiveReconstructor),
new Research(airFactory), new Research(airFactory),
new Research(door), new Research(door),
new Research(waterExtractor) new Research(waterExtractor)
@@ -645,7 +648,7 @@ public class TechTree implements ContentList{
static TechNode node(UnlockableContent content, ItemStack[] requirements, Seq<Objective> objectives, Runnable children){ static TechNode node(UnlockableContent content, ItemStack[] requirements, Seq<Objective> objectives, Runnable children){
TechNode node = new TechNode(context, content, requirements); TechNode node = new TechNode(context, content, requirements);
if(objectives != null){ if(objectives != null){
node.objectives = objectives; node.objectives.addAll(objectives);
} }
TechNode prev = context; TechNode prev = context;
+3 -3
View File
@@ -556,7 +556,7 @@ public class UnitTypes implements ContentList{
range = 40f; range = 40f;
weapons.add(new Weapon(){{ weapons.add(new Weapon(){{
reload = 12f; reload = 24f;
shootCone = 180f; shootCone = 180f;
ejectEffect = Fx.none; ejectEffect = Fx.none;
shootSound = Sounds.explosion; shootSound = Sounds.explosion;
@@ -1321,7 +1321,7 @@ public class UnitTypes implements ContentList{
sprite = "large-bomb"; sprite = "large-bomb";
width = height = 120/4f; width = height = 120/4f;
range = 30f; maxRange = 30f;
ignoreRotation = true; ignoreRotation = true;
backColor = Pal.heal; backColor = Pal.heal;
@@ -1413,12 +1413,12 @@ public class UnitTypes implements ContentList{
ejectEffect = Fx.casing1; ejectEffect = Fx.casing1;
shootSound = Sounds.missile; shootSound = Sounds.missile;
bullet = new MissileBulletType(2.7f, 12, "missile"){{ bullet = new MissileBulletType(2.7f, 12, "missile"){{
keepVelocity = true;
width = 8f; width = 8f;
height = 8f; height = 8f;
shrinkY = 0f; shrinkY = 0f;
drag = -0.003f; drag = -0.003f;
homingRange = 60f; homingRange = 60f;
keepVelocity = false;
splashDamageRadius = 25f; splashDamageRadius = 25f;
splashDamage = 10f; splashDamage = 10f;
lifetime = 80f; lifetime = 80f;
+24 -3
View File
@@ -6,6 +6,7 @@ import arc.audio.*;
import arc.graphics.g2d.*; import arc.graphics.g2d.*;
import arc.input.*; import arc.input.*;
import arc.math.*; import arc.math.*;
import arc.scene.style.*;
import arc.scene.ui.*; import arc.scene.ui.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
@@ -16,14 +17,17 @@ import mindustry.core.GameState.*;
import mindustry.entities.*; import mindustry.entities.*;
import mindustry.game.EventType.*; import mindustry.game.EventType.*;
import mindustry.game.*; import mindustry.game.*;
import mindustry.game.Objectives.*;
import mindustry.game.Saves.*; import mindustry.game.Saves.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.input.*; import mindustry.input.*;
import mindustry.io.*; import mindustry.io.*;
import mindustry.io.SaveIO.*; import mindustry.io.SaveIO.*;
import mindustry.maps.*;
import mindustry.maps.Map; import mindustry.maps.Map;
import mindustry.net.*; import mindustry.net.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.ui.*;
import mindustry.ui.dialogs.*; import mindustry.ui.dialogs.*;
import mindustry.world.*; import mindustry.world.*;
@@ -124,10 +128,18 @@ public class Control implements ApplicationListener, Loadable{
} }
})); }));
Events.on(UnlockEvent.class, e -> ui.hudfrag.showUnlock(e.content));
Events.on(UnlockEvent.class, e -> { Events.on(UnlockEvent.class, e -> {
ui.hudfrag.showUnlock(e.content);
checkAutoUnlocks(); checkAutoUnlocks();
if(e.content instanceof SectorPreset){
for(TechNode node : TechTree.all){
if(!node.content.unlocked() && node.objectives.contains(o -> o instanceof SectorComplete sec && sec.preset == e.content) && !node.objectives.contains(o -> !o.complete())){
ui.hudfrag.showToast(new TextureRegionDrawable(node.content.icon(Cicon.large)), bundle.get("available"));
}
}
}
}); });
Events.on(SectorCaptureEvent.class, e -> { Events.on(SectorCaptureEvent.class, e -> {
@@ -311,8 +323,17 @@ public class Control implements ApplicationListener, Loadable{
return; return;
} }
//set spawn for sector damage to use
Tile spawn = world.tile(sector.info.spawnPosition);
spawn.setBlock(Blocks.coreShard, state.rules.defaultTeam);
//add extra damage.
SectorDamage.apply(1f);
//reset wave so things are more fair //reset wave so things are more fair
state.wave = 1; state.wave = 1;
//set up default wave time
state.wavetime = state.rules.waveSpacing * 2f;
//reset win wave?? //reset win wave??
state.rules.winWave = state.rules.attackMode ? -1 : sector.preset != null ? sector.preset.captureWave : 40; state.rules.winWave = state.rules.attackMode ? -1 : sector.preset != null ? sector.preset.captureWave : 40;
@@ -320,8 +341,8 @@ public class Control implements ApplicationListener, Loadable{
//kill all units, since they should be dead anyway //kill all units, since they should be dead anyway
Groups.unit.clear(); Groups.unit.clear();
Groups.fire.clear(); Groups.fire.clear();
Groups.puddle.clear();
Tile spawn = world.tile(sector.info.spawnPosition);
Schematics.placeLaunchLoadout(spawn.x, spawn.y); Schematics.placeLaunchLoadout(spawn.x, spawn.y);
//set up camera/player locations //set up camera/player locations
+1 -2
View File
@@ -33,9 +33,8 @@ public class GameState{
/** Current game state. */ /** Current game state. */
private State state = State.menu; private State state = State.menu;
//TODO optimize
public Unit boss(){ public Unit boss(){
return Groups.unit.find(u -> u.isBoss() && u.team == rules.waveTeam); return teams.boss;
} }
public void set(State astate){ public void set(State astate){
+1 -1
View File
@@ -107,7 +107,7 @@ public class Logic implements ApplicationListener{
if(!(state.getSector().preset != null && !state.getSector().preset.useAI)){ if(!(state.getSector().preset != null && !state.getSector().preset.useAI)){
state.rules.waveTeam.rules().ai = true; state.rules.waveTeam.rules().ai = true;
} }
state.rules.waveTeam.rules().aiTier = state.getSector().threat; state.rules.waveTeam.rules().aiTier = state.getSector().threat * 0.8f;
state.rules.waveTeam.rules().infiniteResources = true; state.rules.waveTeam.rules().infiniteResources = true;
} }
+5
View File
@@ -257,6 +257,11 @@ public class NetClient implements ApplicationListener{
public static void kick(KickReason reason){ public static void kick(KickReason reason){
netClient.disconnectQuietly(); netClient.disconnectQuietly();
logic.reset(); logic.reset();
if(reason == KickReason.serverRestarting){
ui.join.reconnect();
return;
}
if(!reason.quiet){ if(!reason.quiet){
if(reason.extraText() != null){ if(reason.extraText() != null){
@@ -12,5 +12,6 @@ class GroupDefs<G>{
@GroupDef(value = Syncc.class, mapping = true) G sync; @GroupDef(value = Syncc.class, mapping = true) G sync;
@GroupDef(value = Drawc.class) G draw; @GroupDef(value = Drawc.class) G draw;
@GroupDef(value = Firec.class) G fire; @GroupDef(value = Firec.class) G fire;
@GroupDef(value = Puddlec.class) G puddle;
@GroupDef(value = WeatherStatec.class) G weather; @GroupDef(value = WeatherStatec.class) G weather;
} }
@@ -78,7 +78,7 @@ public abstract class BulletType extends Content{
* Do not change unless you know what you're doing. */ * Do not change unless you know what you're doing. */
public boolean backMove = true; public boolean backMove = true;
/** Bullet range override. */ /** Bullet range override. */
public float range = -1f; public float maxRange = -1f;
/** % of block health healed **/ /** % of block health healed **/
public float healPercent = 0f; public float healPercent = 0f;
/** whether to make fire on impact */ /** whether to make fire on impact */
@@ -154,7 +154,7 @@ public abstract class BulletType extends Content{
/** Returns maximum distance the bullet this bullet type has can travel. */ /** Returns maximum distance the bullet this bullet type has can travel. */
public float range(){ public float range(){
return Math.max(speed * lifetime * (1f - drag), range); return Math.max(speed * lifetime * (1f - drag), maxRange);
} }
public boolean collides(Bullet bullet, Building tile){ public boolean collides(Bullet bullet, Building tile){
@@ -317,11 +317,11 @@ public abstract class BulletType extends Content{
} }
public Bullet create(Bullet parent, float x, float y, float angle){ public Bullet create(Bullet parent, float x, float y, float angle){
return create(parent.owner(), parent.team, x, y, angle); return create(parent.owner, parent.team, x, y, angle);
} }
public Bullet create(Bullet parent, float x, float y, float angle, float velocityScl, float lifeScale){ public Bullet create(Bullet parent, float x, float y, float angle, float velocityScl, float lifeScale){
return create(parent.owner(), parent.team, x, y, angle, velocityScl, lifeScale); return create(parent.owner, parent.team, x, y, angle, velocityScl, lifeScale);
} }
public Bullet create(Bullet parent, float x, float y, float angle, float velocityScl){ public Bullet create(Bullet parent, float x, float y, float angle, float velocityScl){
@@ -61,7 +61,7 @@ public class SapBulletType extends BulletType{
b.data = target; b.data = target;
if(target != null){ if(target != null){
float result = Math.min(target.health(), damage); float result = Math.max(Math.min(target.health(), damage), 0);
if(b.owner instanceof Healthc h){ if(b.owner instanceof Healthc h){
h.heal(result * sapStrength); h.heal(result * sapStrength);
@@ -397,8 +397,8 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
/** Actually destroys the unit, removing it and creating explosions. **/ /** Actually destroys the unit, removing it and creating explosions. **/
public void destroy(){ public void destroy(){
float explosiveness = 2f + item().explosiveness * stack().amount / 2f; float explosiveness = 2f + item().explosiveness * stack().amount / 2.4f;
float flammability = item().flammability * stack().amount / 2f; float flammability = item().flammability * stack().amount / 2.4f;
Damage.dynamicExplosion(x, y, flammability, explosiveness, 0f, bounds() / 2f, Pal.darkFlame, state.rules.damageExplosions); Damage.dynamicExplosion(x, y, flammability, explosiveness, 0f, bounds() / 2f, Pal.darkFlame, state.rules.damageExplosions);
float shake = hitSize / 3f; float shake = hitSize / 3f;
@@ -91,6 +91,10 @@ abstract class WeaponsComp implements Teamc, Posc, Rotc, Velc, Statusc{
mount.bullet.time = mount.bullet.lifetime - 10f; mount.bullet.time = mount.bullet.lifetime - 10f;
mount.bullet = null; mount.bullet = null;
} }
if(mount.sound != null){
mount.sound.stop();
}
} }
} }
+1
View File
@@ -18,6 +18,7 @@ public class EventType{
impactPower, impactPower,
thoriumReactorOverheat, thoriumReactorOverheat,
fireExtinguish, fireExtinguish,
acceleratorUse,
newGame, newGame,
tutorialComplete, tutorialComplete,
flameAmmo, flameAmmo,
+2 -10
View File
@@ -48,7 +48,8 @@ public class Objectives{
} }
} }
public static class SectorComplete extends SectorObjective{ public static class SectorComplete implements Objective{
public SectorPreset preset;
public SectorComplete(SectorPreset zone){ public SectorComplete(SectorPreset zone){
this.preset = zone; this.preset = zone;
@@ -67,11 +68,6 @@ public class Objectives{
} }
} }
//TODO merge
public abstract static class SectorObjective implements Objective{
public SectorPreset preset;
}
/** Defines a specific objective for a game. */ /** Defines a specific objective for a game. */
public interface Objective{ public interface Objective{
@@ -86,9 +82,5 @@ public class Objectives{
default void build(Table table){ default void build(Table table){
} }
default SectorPreset zone(){
return this instanceof SectorObjective ? ((SectorObjective)this).preset : null;
}
} }
} }
+5
View File
@@ -127,6 +127,9 @@ public class Schematics implements Loadable{
newSchematic.tags.putAll(target.tags); newSchematic.tags.putAll(target.tags);
newSchematic.file = target.file; newSchematic.file = target.file;
loadouts.each((block, list) -> list.remove(target));
checkLoadout(target, true);
try{ try{
write(newSchematic, target.file); write(newSchematic, target.file);
}catch(Exception e){ }catch(Exception e){
@@ -134,6 +137,8 @@ public class Schematics implements Loadable{
Log.err(e); Log.err(e);
ui.showException(e); ui.showException(e);
} }
} }
private @Nullable Schematic loadFile(Fi file){ private @Nullable Schematic loadFile(Fi file){
+7
View File
@@ -26,6 +26,8 @@ public class Teams{
public Seq<TeamData> active = new Seq<>(); public Seq<TeamData> active = new Seq<>();
/** Teams with block or unit presence. */ /** Teams with block or unit presence. */
public Seq<TeamData> present = new Seq<>(TeamData.class); public Seq<TeamData> present = new Seq<>(TeamData.class);
/** Current boss unit. */
public @Nullable Unit boss;
public Teams(){ public Teams(){
active.add(get(Team.crux)); active.add(get(Team.crux));
@@ -144,6 +146,7 @@ public class Teams{
public void updateTeamStats(){ public void updateTeamStats(){
present.clear(); present.clear();
boss = null;
for(Team team : Team.all){ for(Team team : Team.all){
TeamData data = team.data(); TeamData data = team.data();
@@ -178,6 +181,10 @@ public class Teams{
data.units.add(unit); data.units.add(unit);
data.presentFlag = true; data.presentFlag = true;
if(unit.team == state.rules.waveTeam && unit.isBoss()){
boss = unit;
}
if(data.unitsByType == null || data.unitsByType.length <= unit.type.id){ if(data.unitsByType == null || data.unitsByType.length <= unit.type.id){
data.unitsByType = new Seq[content.units().size]; data.unitsByType = new Seq[content.units().size];
} }
+3 -1
View File
@@ -208,6 +208,8 @@ public class Universe{
//add production, making sure that it's capped //add production, making sure that it's capped
sector.info.production.each((item, stat) -> sector.info.items.add(item, Math.min((int)(stat.mean * newSecondsPassed * scl), sector.info.storageCapacity - sector.info.items.get(item)))); sector.info.production.each((item, stat) -> sector.info.items.add(item, Math.min((int)(stat.mean * newSecondsPassed * scl), sector.info.storageCapacity - sector.info.items.get(item))));
//prevent negative values with unloaders
sector.info.items.checkNegative();
sector.saveInfo(); sector.saveInfo();
} }
@@ -216,7 +218,7 @@ public class Universe{
if(!sector.isAttacked() && turn > invasionGracePeriod && sector.info.hasSpawns){ if(!sector.isAttacked() && turn > invasionGracePeriod && sector.info.hasSpawns){
//invasion chance depends on # of nearby bases //invasion chance depends on # of nearby bases
if(Mathf.chance(baseInvasionChance * Math.min(sector.near().count(Sector::hasEnemyBase), 1))){ if(Mathf.chance(baseInvasionChance * Math.min(sector.near().count(Sector::hasEnemyBase), 1))){
int waveMax = Math.max(sector.info.winWave, sector.isBeingPlayed() ? state.wave : sector.info.wave + sector.info.wavesPassed) + Mathf.random(2, 5) * 5; int waveMax = Math.max(sector.info.winWave, sector.isBeingPlayed() ? state.wave : sector.info.wave + sector.info.wavesPassed) + Mathf.random(2, 4) * 5;
//assign invasion-related things //assign invasion-related things
if(sector.isBeingPlayed()){ if(sector.isBeingPlayed()){
+8 -8
View File
@@ -10,7 +10,7 @@ import mindustry.type.*;
import static mindustry.content.UnitTypes.*; import static mindustry.content.UnitTypes.*;
public class Waves{ public class Waves{
public static final int waveVersion = 3; public static final int waveVersion = 4;
private Seq<SpawnGroup> spawns; private Seq<SpawnGroup> spawns;
@@ -277,7 +277,7 @@ public class Waves{
int cap = 150; int cap = 150;
float shieldStart = 30, shieldsPerWave = 20 + difficulty*30f; float shieldStart = 30, shieldsPerWave = 20 + difficulty*30f;
float[] scaling = {1, 1, 1.5f, 3f, 4f}; float[] scaling = {1, 1.5f, 3f, 4f, 5f};
Intc createProgression = start -> { Intc createProgression = start -> {
//main sequence //main sequence
@@ -286,7 +286,7 @@ public class Waves{
for(int i = start; i < cap;){ for(int i = start; i < cap;){
int f = i; int f = i;
int next = rand.random(8, 16) + (int)Mathf.lerp(4f, 0f, difficulty) + curTier * 4; int next = rand.random(8, 16) + (int)Mathf.lerp(5f, 0f, difficulty) + curTier * 4;
float shieldAmount = Math.max((i - shieldStart) * shieldsPerWave, 0); float shieldAmount = Math.max((i - shieldStart) * shieldsPerWave, 0);
int space = start == 0 ? 1 : rand.random(1, 2); int space = start == 0 ? 1 : rand.random(1, 2);
@@ -298,7 +298,7 @@ public class Waves{
begin = f; begin = f;
end = f + next >= cap ? never : f + next; end = f + next >= cap ? never : f + next;
max = 13; max = 13;
unitScaling = (difficulty < 0.4f ? rand.random(2.5f, 4f) : rand.random(1f, 4f)) * scaling[ctier]; unitScaling = (difficulty < 0.4f ? rand.random(2.5f, 5f) : rand.random(1f, 4f)) * scaling[ctier];
shields = shieldAmount; shields = shieldAmount;
shieldScaling = shieldsPerWave; shieldScaling = shieldsPerWave;
spacing = space; spacing = space;
@@ -310,7 +310,7 @@ public class Waves{
begin = f + next - 1; begin = f + next - 1;
end = f + next + rand.random(6, 10); end = f + next + rand.random(6, 10);
max = 6; max = 6;
unitScaling = rand.random(1f, 2f); unitScaling = rand.random(2f, 4f);
spacing = rand.random(2, 4); spacing = rand.random(2, 4);
shields = shieldAmount/2f; shields = shieldAmount/2f;
shieldScaling = shieldsPerWave; shieldScaling = shieldsPerWave;
@@ -340,10 +340,10 @@ public class Waves{
step += (int)(rand.random(15, 30) * Mathf.lerp(1f, 0.5f, difficulty)); step += (int)(rand.random(15, 30) * Mathf.lerp(1f, 0.5f, difficulty));
} }
int bossWave = (int)(rand.random(50, 70) * Mathf.lerp(1f, 0.5f, difficulty)); int bossWave = (int)(rand.random(50, 70) * Mathf.lerp(1f, 0.7f, difficulty));
int bossSpacing = (int)(rand.random(25, 40) * Mathf.lerp(1f, 0.6f, difficulty)); int bossSpacing = (int)(rand.random(25, 40) * Mathf.lerp(1f, 0.6f, difficulty));
int bossTier = difficulty < 0.5 ? 3 : 4; int bossTier = difficulty < 0.6 ? 3 : 4;
//main boss progression //main boss progression
out.add(new SpawnGroup(Structs.random(species)[bossTier]){{ out.add(new SpawnGroup(Structs.random(species)[bossTier]){{
@@ -411,7 +411,7 @@ public class Waves{
} }
//shift back waves on higher difficulty for a harder start //shift back waves on higher difficulty for a harder start
int shift = Math.max((int)(difficulty * 15 - 5), 0); int shift = Math.max((int)(difficulty * 14 - 5), 0);
for(SpawnGroup group : out){ for(SpawnGroup group : out){
group.begin -= shift; group.begin -= shift;
+28 -15
View File
@@ -47,6 +47,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
/** Maximum line length. */ /** Maximum line length. */
final static int maxLength = 100; final static int maxLength = 100;
final static Rect r1 = new Rect(), r2 = new Rect(); final static Rect r1 = new Rect(), r2 = new Rect();
final static Seq<Point2> tmpPoints = new Seq<>(), tmpPoints2 = new Seq<>();
public final OverlayFragment frag = new OverlayFragment(); public final OverlayFragment frag = new OverlayFragment();
@@ -1164,27 +1165,39 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
points = Placement.normalizeLine(startX, startY, endX, endY); points = Placement.normalizeLine(startX, startY, endX, endY);
} }
if(block instanceof PowerNode){ if(block instanceof PowerNode node){
Seq<Point2> skip = new Seq<>(); var base = tmpPoints2;
var result = tmpPoints.clear();
for(int i = 1; i < points.size; i++){ base.selectFrom(points, p -> p == points.first() || p == points.peek() || Build.validPlace(block, player.team(), p.x, p.y, rotation, false));
int overlaps = 0; boolean addedLast = false;
Point2 point = points.get(i);
//check with how many powernodes the *next* tile will overlap outer:
for(int j = 0; j < i; j++){ for(int i = 0; i < base.size;){
if(!skip.contains(points.get(j)) && ((PowerNode)block).overlaps(world.tile(point.x, point.y), world.tile(points.get(j).x, points.get(j).y))){ var point = base.get(i);
overlaps++; result.add(point);
if(i == base.size - 1) addedLast = true;
//find the furthest node that overlaps this one
for(int j = base.size - 1; j > i; j--){
var other = base.get(j);
boolean over = node.overlaps(world.tile(point.x, point.y), world.tile(other.x, other.y));
if(over){
//add node to list and start searching for node that overlaps the next one
i = j;
continue outer;
} }
} }
//if it's more than one, it can bridge the gap //if it got here, that means nothing was found. try to proceed to the next node anyway
if(overlaps > 1){ i ++;
skip.add(points.get(i-1));
}
} }
//remove skipped points
points.removeAll(skip); if(!addedLast) result.add(base.peek());
points.clear();
points.addAll(result);
} }
float angle = Angles.angle(startX, startY, endX, endY); float angle = Angles.angle(startX, startY, endX, endY);
+1 -26
View File
@@ -241,35 +241,10 @@ public class Placement{
} }
public static class NormalizeDrawResult{ public static class NormalizeDrawResult{
float x, y, x2, y2; public float x, y, x2, y2;
} }
public static class NormalizeResult{ public static class NormalizeResult{
public int x, y, x2, y2, rotation; public int x, y, x2, y2, rotation;
boolean isX(){
return Math.abs(x2 - x) > Math.abs(y2 - y);
}
/**
* Returns length of greater edge of the selection.
*/
int getLength(){
return Math.max(x2 - x, y2 - y);
}
/**
* Returns the X position of a specific index along this area as a line.
*/
int getScaledX(int i){
return x + (x2 - x > y2 - y ? i : 0);
}
/**
* Returns the Y position of a specific index along this area as a line.
*/
int getScaledY(int i){
return y + (x2 - x > y2 - y ? 0 : i);
}
} }
} }
+14 -2
View File
@@ -286,7 +286,8 @@ public abstract class SaveVersion extends SaveFileReader{
public void writeEntities(DataOutput stream) throws IOException{ public void writeEntities(DataOutput stream) throws IOException{
//write team data with entities. //write team data with entities.
Seq<TeamData> data = state.teams.getActive(); Seq<TeamData> data = state.teams.getActive().copy();
if(!data.contains(Team.sharded.data())) data.add(Team.sharded.data());
stream.writeInt(data.size); stream.writeInt(data.size);
for(TeamData team : data){ for(TeamData team : data){
stream.writeInt(team.team.id); stream.writeInt(team.team.id);
@@ -313,12 +314,23 @@ public abstract class SaveVersion extends SaveFileReader{
public void readEntities(DataInput stream) throws IOException{ public void readEntities(DataInput stream) throws IOException{
int teamc = stream.readInt(); int teamc = stream.readInt();
for(int i = 0; i < teamc; i++){ for(int i = 0; i < teamc; i++){
Team team = Team.get(stream.readInt()); Team team = Team.get(stream.readInt());
TeamData data = team.data(); TeamData data = team.data();
int blocks = stream.readInt(); int blocks = stream.readInt();
data.blocks.clear();
data.blocks.ensureCapacity(Math.min(blocks, 1000));
var reads = Reads.get(stream);
var set = new IntSet();
for(int j = 0; j < blocks; j++){ for(int j = 0; j < blocks; j++){
data.blocks.addLast(new BlockPlan(stream.readShort(), stream.readShort(), stream.readShort(), content.block(stream.readShort()).id, TypeIO.readObject(Reads.get(stream)))); short x = stream.readShort(), y = stream.readShort(), rot = stream.readShort(), bid = stream.readShort();
var obj = TypeIO.readObject(reads);
//cannot have two in the same position
if(set.add(Point2.pack(x, y))){
data.blocks.addLast(new BlockPlan(x, y, rot, content.block(bid).id, obj));
}
} }
} }
+18 -14
View File
@@ -21,7 +21,7 @@ import mindustry.world.blocks.storage.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
public class SectorDamage{ public class SectorDamage{
public static final int maxRetWave = 30, maxWavesSimulated = 50; public static final int maxRetWave = 40, maxWavesSimulated = 50;
//direct damage is for testing only //direct damage is for testing only
private static final boolean direct = false, rubble = true; private static final boolean direct = false, rubble = true;
@@ -111,23 +111,26 @@ public class SectorDamage{
float damage = getDamage(state.rules.sector.info); float damage = getDamage(state.rules.sector.info);
//scaled damage has a power component to make it seem a little more realistic (as systems fail, enemy capturing gets easier and easier) //scaled damage has a power component to make it seem a little more realistic (as systems fail, enemy capturing gets easier and easier)
float scaled = Mathf.pow(damage, 1.6f); float scaled = Mathf.pow(damage, 1.2f);
//apply damage to units
float unitDamage = damage * state.rules.sector.info.sumHealth;
Tile spawn = spawner.getFirstSpawn(); Tile spawn = spawner.getFirstSpawn();
//damage only units near the spawn point //damage only units near the spawn point
if(spawn != null){ if(spawn != null){
Seq<Unit> allies = new Seq<>(); Seq<Unit> allies = new Seq<>();
float sumUnitHealth = 0f;
for(Unit ally : Groups.unit){ for(Unit ally : Groups.unit){
if(ally.team == state.rules.defaultTeam && ally.within(spawn, state.rules.dropZoneRadius * 2.5f)){ if(ally.team == state.rules.defaultTeam && ally.within(spawn, state.rules.dropZoneRadius * 2.5f)){
allies.add(ally); allies.add(ally);
sumUnitHealth += ally.health;
} }
} }
allies.sort(u -> u.dst2(spawn)); allies.sort(u -> u.dst2(spawn));
//apply damage to units
float unitDamage = damage * sumUnitHealth;
//damage units one by one, not uniformly //damage units one by one, not uniformly
for(var u : allies){ for(var u : allies){
if(u.health < unitDamage){ if(u.health < unitDamage){
@@ -335,9 +338,9 @@ public class SectorDamage{
info.waveDpsSlope = reg.slope; info.waveDpsSlope = reg.slope;
//enemy units like to aim for a lot of non-essential things, so increase resulting health slightly //enemy units like to aim for a lot of non-essential things, so increase resulting health slightly
info.sumHealth = sumHealth * 1.3f; info.sumHealth = sumHealth * 1.2f;
//players tend to have longer range units/turrets, so assume DPS is higher //players tend to have longer range units/turrets, so assume DPS is higher
info.sumDps = sumDps * 1.3f; info.sumDps = sumDps * 1.2f;
info.sumRps = sumRps; info.sumRps = sumRps;
info.wavesSurvived = getWavesSurvived(info); info.wavesSurvived = getWavesSurvived(info);
@@ -348,13 +351,12 @@ public class SectorDamage{
Queue<Tile> frontier = new Queue<>(); Queue<Tile> frontier = new Queue<>();
float[][] values = new float[tiles.width][tiles.height]; float[][] values = new float[tiles.width][tiles.height];
float damage = fraction*80; //arbitrary damage value
//phase one: find all spawnpoints //phase one: find all spawnpoints
for(Tile tile : tiles){ for(Tile tile : tiles){
if((tile.block() instanceof CoreBlock && tile.team() == state.rules.waveTeam) || tile.overlay() == Blocks.spawn){ if((tile.block() instanceof CoreBlock && tile.team() == state.rules.waveTeam) || tile.overlay() == Blocks.spawn){
frontier.add(tile); frontier.add(tile);
values[tile.x][tile.y] = damage; values[tile.x][tile.y] = fraction * 26;
} }
} }
@@ -368,14 +370,16 @@ public class SectorDamage{
int radius = 3; int radius = 3;
//only penetrate a certain % by health, not by distance //only penetrate a certain % by health, not by distance
float totalHealth = damage >= 1f ? 1f : path.sumf(t -> { float totalHealth = fraction >= 1f ? 1f : path.sumf(t -> {
float s = 0; float s = 0;
for(int dx = -radius; dx <= radius; dx++){ for(int dx = -radius; dx <= radius; dx++){
for(int dy = -radius; dy <= radius; dy++){ for(int dy = -radius; dy <= radius; dy++){
int wx = dx + t.x, wy = dy + t.y; int wx = dx + t.x, wy = dy + t.y;
if(wx >= 0 && wy >= 0 && wx < world.width() && wy < world.height() && Mathf.within(dx, dy, radius)){ if(wx >= 0 && wy >= 0 && wx < world.width() && wy < world.height() && Mathf.within(dx, dy, radius)){
Tile other = world.rawTile(wx, wy); Tile other = world.rawTile(wx, wy);
s += other.team() == state.rules.defaultTeam ? other.build.health / other.block().size : 0f; if(!(other.block() instanceof CoreBlock)){
s += other.team() == state.rules.defaultTeam ? other.build.health / other.block().size : 0f;
}
} }
} }
} }
@@ -385,7 +389,7 @@ public class SectorDamage{
float healthCount = 0; float healthCount = 0;
out: out:
for(int i = 0; i < path.size && (healthCount < targetHealth || damage >= 1f); i++){ for(int i = 0; i < path.size && (healthCount < targetHealth || fraction >= 1f); i++){
Tile t = path.get(i); Tile t = path.get(i);
for(int dx = -radius; dx <= radius; dx++){ for(int dx = -radius; dx <= radius; dx++){
@@ -405,7 +409,7 @@ public class SectorDamage{
removal.add(other.build); removal.add(other.build);
if(healthCount >= targetHealth && damage < 0.999f){ if(healthCount >= targetHealth && fraction < 0.999f){
break out; break out;
} }
} }
@@ -430,10 +434,10 @@ public class SectorDamage{
} }
} }
float falloff = (damage) / (Math.max(tiles.width, tiles.height) * Mathf.sqrt2); float falloff = (fraction) / (Math.max(tiles.width, tiles.height) * Mathf.sqrt2);
int peak = 0; int peak = 0;
if(damage > 0.1f){ if(fraction > 0.15f){
//phase two: propagate the damage //phase two: propagate the damage
while(!frontier.isEmpty()){ while(!frontier.isEmpty()){
peak = Math.max(peak, frontier.size); peak = Math.max(peak, frontier.size);
@@ -55,7 +55,7 @@ public class BaseGenerator{
BasePart coreschem = bases.cores.getFrac(difficulty); BasePart coreschem = bases.cores.getFrac(difficulty);
int passes = difficulty < 0.4 ? 1 : difficulty < 0.8 ? 2 : 3; int passes = difficulty < 0.4 ? 1 : difficulty < 0.8 ? 2 : 3;
Block wall = wallsSmall.getFrac(difficulty), wallLarge = wallsLarge.getFrac(difficulty); Block wall = wallsSmall.getFrac(difficulty * 0.91f), wallLarge = wallsLarge.getFrac(difficulty * 0.91f);
for(Tile tile : cores){ for(Tile tile : cores){
tile.clearOverlay(); tile.clearOverlay();
+2 -2
View File
@@ -182,12 +182,12 @@ public class Planet extends UnlockableContent{
float sum = 1f; float sum = 1f;
for(Sector other : sector.near()){ for(Sector other : sector.near()){
if(other.generateEnemyBase){ if(other.generateEnemyBase){
sum += 1f; sum += 0.9f;
} }
} }
if(sector.hasEnemyBase()){ if(sector.hasEnemyBase()){
sum += 1.9f; sum += 0.88f;
} }
sector.threat = sector.preset == null ? Math.min(sum / 5f, 1.2f) : Mathf.clamp(sector.preset.difficulty / 10f); sector.threat = sector.preset == null ? Math.min(sum / 5f, 1.2f) : Mathf.clamp(sector.preset.difficulty / 10f);
+1 -1
View File
@@ -328,7 +328,7 @@ public class UnitType extends UnlockableContent{
//suicide enemy //suicide enemy
if(weapons.contains(w -> w.bullet.killShooter)){ if(weapons.contains(w -> w.bullet.killShooter)){
//scale down DPS to be insignificant //scale down DPS to be insignificant
dpsEstimate /= 20f; dpsEstimate /= 25f;
} }
} }
} }
+27 -1
View File
@@ -8,6 +8,7 @@ import arc.scene.ui.*;
import arc.scene.ui.layout.*; import arc.scene.ui.layout.*;
import arc.struct.*; import arc.struct.*;
import arc.util.*; import arc.util.*;
import arc.util.Timer.*;
import arc.util.serialization.*; import arc.util.serialization.*;
import mindustry.*; import mindustry.*;
import mindustry.core.*; import mindustry.core.*;
@@ -33,6 +34,10 @@ public class JoinDialog extends BaseDialog{
int refreshes; int refreshes;
boolean showHidden; boolean showHidden;
String lastIp;
int lastPort;
Task ping;
public JoinDialog(){ public JoinDialog(){
super("@joingame"); super("@joingame");
@@ -445,13 +450,34 @@ public class JoinDialog extends BaseDialog{
logic.reset(); logic.reset();
net.reset(); net.reset();
Vars.netClient.beginConnecting(); Vars.netClient.beginConnecting();
net.connect(ip, port, () -> { net.connect(lastIp = ip, lastPort = port, () -> {
hide(); hide();
add.hide(); add.hide();
}); });
}); });
} }
public void reconnect(){
if(lastIp == null || lastIp.isEmpty()) return;
ui.loadfrag.show("@reconnecting");
ping = Timer.schedule(() -> {
net.pingHost(lastIp, lastPort, host -> {
if(ping == null) return;
ping.cancel();
ping = null;
connect(lastIp, lastPort);
}, exception -> {});
}, 1, 1);
ui.loadfrag.setButton(() -> {
ui.loadfrag.hide();
if(ping == null) return;
ping.cancel();
ping = null;
});
}
void safeConnect(String ip, int port, int version){ void safeConnect(String ip, int port, int version){
if(version != Version.build && Version.build != -1 && version != -1){ if(version != Version.build && Version.build != -1 && version != -1){
ui.showInfo("[scarlet]" + (version > Version.build ? KickReason.clientOutdated : KickReason.serverOutdated).toString() + "\n[]" + ui.showInfo("[scarlet]" + (version > Version.build ? KickReason.clientOutdated : KickReason.serverOutdated).toString() + "\n[]" +
@@ -140,6 +140,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
return this; return this;
} }
rebuildButtons();
mode = look; mode = look;
selected = hovered = launchSector = null; selected = hovered = launchSector = null;
launching = false; launching = false;
@@ -167,6 +168,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
} }
newPresets.reverse(); newPresets.reverse();
updateSelected();
if(planets.planet.getLastSector() != null){ if(planets.planet.getLastSector() != null){
lookAt(planets.planet.getLastSector()); lookAt(planets.planet.getLastSector());
@@ -150,7 +150,7 @@ public class HintsFragment extends Fragment{
depositItems(() -> player.unit().hasItem(), () -> !player.unit().hasItem()), depositItems(() -> player.unit().hasItem(), () -> !player.unit().hasItem()),
desktopPause(visibleDesktop, () -> isTutorial.get() && !Vars.net.active(), () -> Core.input.keyTap(Binding.pause)), desktopPause(visibleDesktop, () -> isTutorial.get() && !Vars.net.active(), () -> Core.input.keyTap(Binding.pause)),
research(isTutorial, () -> ui.research.isShown()), research(isTutorial, () -> ui.research.isShown()),
unitControl(() -> state.rules.defaultTeam.data().units.size > 1 && !net.active(), () -> !player.dead() && !player.unit().spawnedByCore), unitControl(() -> state.rules.defaultTeam.data().units.size > 2 && !net.active() && !player.dead(), () -> !player.dead() && !player.unit().spawnedByCore),
respawn(visibleMobile, () -> !player.dead() && !player.unit().spawnedByCore, () -> !player.dead() && player.unit().spawnedByCore), respawn(visibleMobile, () -> !player.dead() && !player.unit().spawnedByCore, () -> !player.dead() && player.unit().spawnedByCore),
launch(() -> isTutorial.get() && state.rules.sector.isCaptured(), () -> ui.planet.isShown()), launch(() -> isTutorial.get() && state.rules.sector.isCaptured(), () -> ui.planet.isShown()),
schematicSelect(visibleDesktop, () -> ui.hints.placedBlocks.contains(Blocks.router), () -> Core.input.keyRelease(Binding.schematic_select) || Core.input.keyTap(Binding.pick)), schematicSelect(visibleDesktop, () -> ui.hints.placedBlocks.contains(Blocks.router), () -> Core.input.keyRelease(Binding.schematic_select) || Core.input.keyTap(Binding.pick)),
@@ -161,6 +161,7 @@ public class HintsFragment extends Fragment{
payloadDrop(() -> !player.unit().dead && player.unit() instanceof Payloadc p && p.payloads().any(), () -> player.unit() instanceof Payloadc p && p.payloads().isEmpty()), payloadDrop(() -> !player.unit().dead && player.unit() instanceof Payloadc p && p.payloads().any(), () -> player.unit() instanceof Payloadc p && p.payloads().isEmpty()),
waveFire(() -> Groups.fire.size() > 0 && Blocks.wave.unlockedNow(), () -> indexer.getAllied(state.rules.defaultTeam, BlockFlag.extinguisher).size() > 0), waveFire(() -> Groups.fire.size() > 0 && Blocks.wave.unlockedNow(), () -> indexer.getAllied(state.rules.defaultTeam, BlockFlag.extinguisher).size() > 0),
generator(() -> control.input.block == Blocks.combustionGenerator, () -> ui.hints.placedBlocks.contains(Blocks.combustionGenerator)), generator(() -> control.input.block == Blocks.combustionGenerator, () -> ui.hints.placedBlocks.contains(Blocks.combustionGenerator)),
guardian(() -> state.boss() != null && state.boss().armor >= 4, () -> state.boss() == null),
; ;
@Nullable @Nullable
@@ -1,5 +1,6 @@
package mindustry.world.blocks.campaign; package mindustry.world.blocks.campaign;
import arc.*;
import arc.Graphics.*; import arc.Graphics.*;
import arc.Graphics.Cursor.*; import arc.Graphics.Cursor.*;
import arc.graphics.g2d.*; import arc.graphics.g2d.*;
@@ -8,6 +9,7 @@ import arc.scene.ui.layout.*;
import arc.util.*; import arc.util.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.game.EventType.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.type.*; import mindustry.type.*;
@@ -91,6 +93,7 @@ public class Accelerator extends Block{
if(!state.isCampaign() || !consValid()) return; if(!state.isCampaign() || !consValid()) return;
ui.showInfo("@indev.campaign"); ui.showInfo("@indev.campaign");
Events.fire(Trigger.acceleratorUse);
} }
@Override @Override
@@ -19,6 +19,7 @@ import mindustry.graphics.*;
import mindustry.type.*; import mindustry.type.*;
import mindustry.ui.*; import mindustry.ui.*;
import mindustry.world.*; import mindustry.world.*;
import mindustry.world.consumers.*;
import mindustry.world.meta.*; import mindustry.world.meta.*;
import static mindustry.Vars.*; import static mindustry.Vars.*;
@@ -38,6 +39,7 @@ public class LaunchPad extends Block{
solid = true; solid = true;
update = true; update = true;
configurable = true; configurable = true;
drawDisabled = false;
} }
@Override @Override
@@ -61,6 +63,12 @@ public class LaunchPad extends Block{
return !state.isCampaign() || net.client() ? SystemCursor.arrow : super.getCursor(); return !state.isCampaign() || net.client() ? SystemCursor.arrow : super.getCursor();
} }
//cannot be disabled
@Override
public float efficiency(){
return power != null && (block.consumes.has(ConsumeType.power) && !block.consumes.getPower().buffered) ? power.status : 1f;
}
@Override @Override
public void draw(){ public void draw(){
super.draw(); super.draw();
@@ -60,6 +60,7 @@ public class MendProjector extends Block{
float heat; float heat;
float charge = Mathf.random(reload); float charge = Mathf.random(reload);
float phaseHeat; float phaseHeat;
float smoothEfficiency;
@Override @Override
public float range(){ public float range(){
@@ -68,6 +69,7 @@ public class MendProjector extends Block{
@Override @Override
public void updateTile(){ public void updateTile(){
smoothEfficiency = Mathf.lerpDelta(smoothEfficiency, efficiency(), 0.08f);
heat = Mathf.lerpDelta(heat, consValid() || cheating() ? 1f : 0f, 0.08f); heat = Mathf.lerpDelta(heat, consValid() || cheating() ? 1f : 0f, 0.08f);
charge += heat * delta(); charge += heat * delta();
@@ -115,7 +117,7 @@ public class MendProjector extends Block{
@Override @Override
public void drawLight(){ public void drawLight(){
Drawf.light(team, x, y, 50f * efficiency(), baseColor, 0.7f * efficiency()); Drawf.light(team, x, y, 50f * smoothEfficiency, baseColor, 0.7f * smoothEfficiency);
} }
@Override @Override
@@ -65,6 +65,7 @@ public class OverdriveProjector extends Block{
float heat; float heat;
float charge = Mathf.random(reload); float charge = Mathf.random(reload);
float phaseHeat; float phaseHeat;
float smoothEfficiency;
@Override @Override
public float range(){ public float range(){
@@ -73,11 +74,12 @@ public class OverdriveProjector extends Block{
@Override @Override
public void drawLight(){ public void drawLight(){
Drawf.light(team, x, y, 50f * efficiency(), baseColor, 0.7f * efficiency()); Drawf.light(team, x, y, 50f * smoothEfficiency, baseColor, 0.7f * smoothEfficiency);
} }
@Override @Override
public void updateTile(){ public void updateTile(){
smoothEfficiency = Mathf.lerpDelta(smoothEfficiency, efficiency(), 0.08f);
heat = Mathf.lerpDelta(heat, consValid() ? 1f : 0f, 0.08f); heat = Mathf.lerpDelta(heat, consValid() ? 1f : 0f, 0.08f);
charge += heat * Time.delta; charge += heat * Time.delta;
@@ -10,7 +10,6 @@ import arc.util.io.*;
import mindustry.annotations.Annotations.*; import mindustry.annotations.Annotations.*;
import mindustry.content.*; import mindustry.content.*;
import mindustry.entities.units.*; import mindustry.entities.units.*;
import mindustry.game.*;
import mindustry.gen.*; import mindustry.gen.*;
import mindustry.graphics.*; import mindustry.graphics.*;
import mindustry.type.*; import mindustry.type.*;
@@ -92,6 +92,11 @@ public class ItemLiquidGenerator extends PowerGenerator{
return generateTime > 0; return generateTime > 0;
} }
@Override
public float ambientVolume(){
return Mathf.clamp(productionEfficiency);
}
@Override @Override
public void updateTile(){ public void updateTile(){
//Note: Do not use this delta when calculating the amount of power or the power efficiency, but use it for resource consumption if necessary. //Note: Do not use this delta when calculating the amount of power or the power efficiency, but use it for resource consumption if necessary.
@@ -268,6 +268,26 @@ public class CoreBlock extends StorageBlock{
} }
} }
@Override
public void handleStack(Item item, int amount, Teamc source){
super.handleStack(item, amount, source);
if(team == state.rules.defaultTeam && state.isCampaign()){
state.rules.sector.info.handleCoreItem(item, amount);
}
}
@Override
public int removeStack(Item item, int amount){
int result = super.removeStack(item, amount);
if(team == state.rules.defaultTeam && state.isCampaign()){
state.rules.sector.info.handleCoreItem(item, -result);
}
return result;
}
@Override @Override
public void drawSelect(){ public void drawSelect(){
Lines.stroke(1f, Pal.accent); Lines.stroke(1f, Pal.accent);
@@ -53,15 +53,12 @@ public class UnitFactory extends UnitBlock{
@Override @Override
public void init(){ public void init(){
capacities = new int[Vars.content.items().size]; capacities = new int[Vars.content.items().size];
itemCapacity = 0;
for(UnitPlan plan : plans){ for(UnitPlan plan : plans){
for(ItemStack stack : plan.requirements){ for(ItemStack stack : plan.requirements){
capacities[stack.item.id] = Math.max(capacities[stack.item.id], stack.amount * 2); capacities[stack.item.id] = Math.max(capacities[stack.item.id], stack.amount * 2);
itemCapacity = Math.max(itemCapacity, stack.amount * 2);
} }
} }
for(int i : capacities){
itemCapacity += i;
}
super.init(); super.init();
} }
@@ -61,6 +61,7 @@ public enum SAchievement{
coolTurret, coolTurret,
enablePixelation, enablePixelation,
openWiki, openWiki,
useAccelerator,
; ;
private final SStat stat; private final SStat stat;
@@ -215,6 +215,8 @@ public class SStats implements SteamUserStatsCallback{
} }
}); });
trigger(Trigger.acceleratorUse, useAccelerator);
trigger(Trigger.impactPower, powerupImpactReactor); trigger(Trigger.impactPower, powerupImpactReactor);
trigger(Trigger.flameAmmo, useFlameAmmo); trigger(Trigger.flameAmmo, useFlameAmmo);
@@ -0,0 +1,10 @@
Only a few days left until stable 6.0 release now. The campaign should now be playable; I've done a playthrough and fixed all the bugs and irregularities I encountered.
Aside from internal modding API changes and potential bugfixes, 6.0 should not have any more additions.
- Added basalt boulder decoration block
- Added hint about generator use & power transfer
- Made power node placement smarter
- Buffed Lancer turret
Campaign:
@@ -0,0 +1,2 @@
- Fixed broken blocks increasing exponentially, leading to runaway memory usage/lag
- Fixed incorrect planet dialog layout on certain devices
+1 -1
View File
@@ -1,3 +1,3 @@
org.gradle.daemon=true org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx1024m org.gradle.jvmargs=-Xms256m -Xmx1024m
archash=9446f0f01b2a1b25abf870a32bf839bc486b12e3 archash=6742c2b110eeecd1934c42b5b1c87b00c911ecc4
@@ -1003,8 +1003,7 @@ public class ServerControl implements ApplicationListener{
private void logToFile(String text){ private void logToFile(String text){
if(currentLogFile != null && currentLogFile.length() > maxLogLength){ if(currentLogFile != null && currentLogFile.length() > maxLogLength){
String date = DateTimeFormatter.ofPattern("MM-dd-yyyy | HH:mm:ss").format(LocalDateTime.now()); currentLogFile.writeString("[End of log file. Date: " + dateTime.format(LocalDateTime.now()) + "]\n", true);
currentLogFile.writeString("[End of log file. Date: " + date + "]\n", true);
currentLogFile = null; currentLogFile = null;
} }