diff --git a/core/assets-raw/sprites/blocks/turrets/arc-heat.png b/core/assets-raw/sprites/blocks/turrets/arc-heat.png index de36f57ce4..5b981cd6bb 100644 Binary files a/core/assets-raw/sprites/blocks/turrets/arc-heat.png and b/core/assets-raw/sprites/blocks/turrets/arc-heat.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/fuse-heat.png b/core/assets-raw/sprites/blocks/turrets/fuse-heat.png new file mode 100644 index 0000000000..a8b34b4381 Binary files /dev/null and b/core/assets-raw/sprites/blocks/turrets/fuse-heat.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/hail-heat.png b/core/assets-raw/sprites/blocks/turrets/hail-heat.png index daad1ac936..ef3805e18e 100644 Binary files a/core/assets-raw/sprites/blocks/turrets/hail-heat.png and b/core/assets-raw/sprites/blocks/turrets/hail-heat.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/lancer-heat.png b/core/assets-raw/sprites/blocks/turrets/lancer-heat.png index 1327410b66..d1494ebefb 100644 Binary files a/core/assets-raw/sprites/blocks/turrets/lancer-heat.png and b/core/assets-raw/sprites/blocks/turrets/lancer-heat.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/meltdown-heat.png b/core/assets-raw/sprites/blocks/turrets/meltdown-heat.png index e9b1fc0ed3..3c58dffce0 100644 Binary files a/core/assets-raw/sprites/blocks/turrets/meltdown-heat.png and b/core/assets-raw/sprites/blocks/turrets/meltdown-heat.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/ripple-heat.png b/core/assets-raw/sprites/blocks/turrets/ripple-heat.png index 6b88b97cb3..a2aa7bc521 100644 Binary files a/core/assets-raw/sprites/blocks/turrets/ripple-heat.png and b/core/assets-raw/sprites/blocks/turrets/ripple-heat.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/salvo-heat.png b/core/assets-raw/sprites/blocks/turrets/salvo-heat.png index 5022fafc1d..75573a5f93 100644 Binary files a/core/assets-raw/sprites/blocks/turrets/salvo-heat.png and b/core/assets-raw/sprites/blocks/turrets/salvo-heat.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/scorch-heat.png b/core/assets-raw/sprites/blocks/turrets/scorch-heat.png index 84863ae266..ede4fe6657 100644 Binary files a/core/assets-raw/sprites/blocks/turrets/scorch-heat.png and b/core/assets-raw/sprites/blocks/turrets/scorch-heat.png differ diff --git a/core/assets-raw/sprites/blocks/turrets/spectre-heat.png b/core/assets-raw/sprites/blocks/turrets/spectre-heat.png new file mode 100644 index 0000000000..2054d87448 Binary files /dev/null and b/core/assets-raw/sprites/blocks/turrets/spectre-heat.png differ diff --git a/core/assets-raw/sprites/teams/team-derelict.png b/core/assets-raw/sprites/teams/team-derelict.png index 38ac90dcb1..7123f12eae 100644 Binary files a/core/assets-raw/sprites/teams/team-derelict.png and b/core/assets-raw/sprites/teams/team-derelict.png differ diff --git a/core/assets-raw/sprites/ui/sideline-over.9.png b/core/assets-raw/sprites/ui/sideline-over.9.png new file mode 100644 index 0000000000..fec86b6d35 Binary files /dev/null and b/core/assets-raw/sprites/ui/sideline-over.9.png differ diff --git a/core/assets-raw/sprites/ui/sideline.9.png b/core/assets-raw/sprites/ui/sideline.9.png new file mode 100644 index 0000000000..4a5413a685 Binary files /dev/null and b/core/assets-raw/sprites/ui/sideline.9.png differ diff --git a/core/assets-raw/sprites/ui/underline-over.9.png b/core/assets-raw/sprites/ui/underline-over.9.png new file mode 100644 index 0000000000..d138927c1a Binary files /dev/null and b/core/assets-raw/sprites/ui/underline-over.9.png differ diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 2d722ad20d..1cfa312e7f 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -345,9 +345,9 @@ custom = Custom builtin = Built-In map.delete.confirm = Are you sure you want to delete this map? This action cannot be undone! map.random = [accent]Random Map -map.nospawn = This map does not have any cores for the player to spawn in! Add a[accent] orange[] core to this map in the editor. +map.nospawn = This map does not have any cores for the player to spawn in! Add a [#{0}]{1}[] core to this map in the editor. map.nospawn.pvp = This map does not have any enemy cores for player to spawn into! Add[scarlet] non-orange[] cores to this map in the editor. -map.nospawn.attack = This map does not have any enemy cores for player to attack! Add[scarlet] red[] cores to this map in the editor. +map.nospawn.attack = This map does not have any enemy cores for player to attack! Add [#{0}]{1}[] cores to this map in the editor. map.invalid = Error loading map: corrupted or invalid map file. workshop.update = Update Item workshop.error = Error fetching workshop details: {0} @@ -564,6 +564,8 @@ weather.sandstorm.name = Sandstorm weather.sporestorm.name = Sporestorm weather.fog.name = Fog +sectorlist = Sectors +sectorlist.attacked = {0} under attack sectors.unexplored = [lightgray]Unexplored sectors.resources = Resources: sectors.production = Production: @@ -1001,6 +1003,7 @@ rules.wavetimer = Wave Timer rules.waves = Waves rules.attack = Attack Mode rules.buildai = AI Building +rules.aitier = AI Tier rules.cleanupdeadteams = Clean Up Defeated Team Buildings (PvP) rules.corecapture = Capture Core On Destruction rules.polygoncoreprotection = Polygonal Core Protection @@ -1020,12 +1023,15 @@ rules.deconstructrefundmultiplier = Deconstruct Refund Multiplier rules.waitForWaveToEnd = Waves Wait for Enemies rules.dropzoneradius = Drop Zone Radius:[lightgray] (tiles) rules.unitammo = Units Require Ammo +rules.enemyteam = Enemy Team +rules.playerteam = Player Team rules.title.waves = Waves rules.title.resourcesbuilding = Resources & Building rules.title.enemy = Enemies rules.title.unit = Units rules.title.experimental = Experimental rules.title.environment = Environment +rules.title.teams = Teams rules.lighting = Lighting rules.enemyLights = Enemy Lights rules.fire = Fire diff --git a/core/src/mindustry/audio/SoundControl.java b/core/src/mindustry/audio/SoundControl.java index 5b29b62a85..dde449ecae 100644 --- a/core/src/mindustry/audio/SoundControl.java +++ b/core/src/mindustry/audio/SoundControl.java @@ -130,7 +130,12 @@ public class SoundControl{ Core.audio.soundBus.play(); setupFilters(); }else{ - Core.audio.soundBus.replay(); + //stopping a single audio bus stops everything else, yay! + Core.audio.soundBus.stop(); + //play music bus again, as it was stopped above + Core.audio.musicBus.play(); + + Core.audio.soundBus.play(); } } diff --git a/core/src/mindustry/content/Blocks.java b/core/src/mindustry/content/Blocks.java index fd7534c3ff..c5e5fddbd9 100644 --- a/core/src/mindustry/content/Blocks.java +++ b/core/src/mindustry/content/Blocks.java @@ -1975,7 +1975,7 @@ public class Blocks implements ContentList{ despawnEffect = Fx.instBomb; trailSpacing = 20f; damage = 1350; - buildingDamageMultiplier = 0.25f; + buildingDamageMultiplier = 0.2f; speed = brange; hitShake = 6f; ammoMultiplier = 1f; @@ -2049,7 +2049,7 @@ public class Blocks implements ContentList{ loopSound = Sounds.beam; loopSoundVolume = 2f; - shootType = new ContinuousLaserBulletType(75){{ + shootType = new ContinuousLaserBulletType(78){{ length = 200f; hitEffect = Fx.hitMeltdown; hitColor = Pal.meltdownHit; @@ -2230,9 +2230,9 @@ public class Blocks implements ContentList{ payloadPropulsionTower = new PayloadMassDriver("payload-propulsion-tower"){{ requirements(Category.units, with(Items.thorium, 300, Items.silicon, 200, Items.plastanium, 200, Items.phaseFabric, 50)); size = 5; - reloadTime = 140f; + reloadTime = 130f; chargeTime = 100f; - range = 600f; + range = 1000f; maxPayloadSize = 3.5f; consumes.power(6f); }}; diff --git a/core/src/mindustry/content/Bullets.java b/core/src/mindustry/content/Bullets.java index abef6c9c16..d04f78d622 100644 --- a/core/src/mindustry/content/Bullets.java +++ b/core/src/mindustry/content/Bullets.java @@ -3,6 +3,7 @@ package mindustry.content; import arc.graphics.*; import mindustry.ctype.*; import mindustry.entities.bullet.*; +import mindustry.entities.effect.*; import mindustry.graphics.*; public class Bullets implements ContentList{ @@ -110,6 +111,7 @@ public class Bullets implements ContentList{ backColor = Pal.lightOrange; makeFire = true; trailEffect = Fx.incendTrail; + ammoMultiplier = 4f; }}; artilleryExplosive = new ArtilleryBulletType(2f, 20, "shell"){{ @@ -120,7 +122,7 @@ public class Bullets implements ContentList{ collidesTiles = false; ammoMultiplier = 4f; splashDamageRadius = 45f * 0.75f; - splashDamage = 50f; + splashDamage = 55f; backColor = Pal.missileYellowBack; frontColor = Pal.missileYellow; @@ -317,20 +319,26 @@ public class Bullets implements ContentList{ standardHoming = new BasicBulletType(3f, 12, "bullet"){{ width = 7f; height = 9f; - homingPower = 0.08f; + homingPower = 0.1f; reloadMultiplier = 1.5f; ammoMultiplier = 5; lifetime = 60f; }}; - standardIncendiary = new BasicBulletType(3.2f, 11, "bullet"){{ + standardIncendiary = new BasicBulletType(3.2f, 16, "bullet"){{ width = 10f; height = 12f; frontColor = Pal.lightishOrange; backColor = Pal.lightOrange; status = StatusEffects.burning; + hitEffect = new MultiEffect(Fx.hitBulletSmall, Fx.fireHit); + + ammoMultiplier = 5; + + splashDamage = 10f; + splashDamageRadius = 22f; + makeFire = true; - inaccuracy = 3f; lifetime = 60f; }}; @@ -361,12 +369,15 @@ public class Bullets implements ContentList{ frontColor = Pal.lightishOrange; backColor = Pal.lightOrange; status = StatusEffects.burning; + hitEffect = new MultiEffect(Fx.hitBulletSmall, Fx.fireHit); shootEffect = Fx.shootBig; makeFire = true; pierceCap = 2; pierceBuilding = true; - knockback = 0.7f; + knockback = 0.6f; ammoMultiplier = 3; + splashDamage = 15f; + splashDamageRadius = 24f; }}; fireball = new FireBulletType(1f, 4); @@ -386,7 +397,7 @@ public class Bullets implements ContentList{ hittable = false; }}; - pyraFlame = new BulletType(4f, 50f){{ + pyraFlame = new BulletType(4f, 60f){{ ammoMultiplier = 6f; hitSize = 7f; lifetime = 18f; diff --git a/core/src/mindustry/content/Fx.java b/core/src/mindustry/content/Fx.java index f8564761b1..862fcb3e5c 100644 --- a/core/src/mindustry/content/Fx.java +++ b/core/src/mindustry/content/Fx.java @@ -880,6 +880,16 @@ public class Fx{ Drawf.light(Team.derelict, e.x, e.y, 20f * e.fslope(), Pal.lightFlame, 0.5f); }), + fireHit = new Effect(35f, e -> { + color(Pal.lightFlame, Pal.darkFlame, e.fin()); + + randLenVectors(e.id, 3, 2f + e.fin() * 10f, (x, y) -> { + Fill.circle(e.x + x, e.y + y, 0.2f + e.fout() * 1.6f); + }); + + color(); + }), + fireSmoke = new Effect(35f, e -> { color(Color.gray); diff --git a/core/src/mindustry/content/StatusEffects.java b/core/src/mindustry/content/StatusEffects.java index 793c5e3e42..8a43965754 100644 --- a/core/src/mindustry/content/StatusEffects.java +++ b/core/src/mindustry/content/StatusEffects.java @@ -21,7 +21,7 @@ public class StatusEffects implements ContentList{ burning = new StatusEffect("burning"){{ color = Color.valueOf("ffc455"); - damage = 0.12f; //over 8 seconds, this would be ~60 damage + damage = 0.167f; effect = Fx.burning; transitionDamage = 8f; diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index 63ad6ebde5..cdacb52843 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -1137,7 +1137,7 @@ public class UnitTypes implements ContentList{ hitSize = 58f; destructibleWreck = false; armor = 13f; - targetFlags = new BlockFlag[]{BlockFlag.reactor, BlockFlag.core, null}; + targetFlags = new BlockFlag[]{BlockFlag.reactor, BlockFlag.battery, BlockFlag.core, null}; ammoType = new ItemAmmoType(Items.thorium); BulletType fragBullet = new FlakBulletType(4f, 5){{ diff --git a/core/src/mindustry/core/NetClient.java b/core/src/mindustry/core/NetClient.java index 6d01275325..a73db1295d 100644 --- a/core/src/mindustry/core/NetClient.java +++ b/core/src/mindustry/core/NetClient.java @@ -507,6 +507,11 @@ public class NetClient implements ApplicationListener{ } } + /** Resets the world data timeout counter. */ + public void resetTimeout(){ + timeoutTime = 0f; + } + public boolean isConnecting(){ return connecting; } diff --git a/core/src/mindustry/core/UI.java b/core/src/mindustry/core/UI.java index 3e80cb9011..7045a20d39 100644 --- a/core/src/mindustry/core/UI.java +++ b/core/src/mindustry/core/UI.java @@ -130,7 +130,7 @@ public class UI implements ApplicationListener, Loadable{ @Override public Seq getDependencies(){ - return Seq.with(new AssetDescriptor<>(Control.class), new AssetDescriptor<>("outline", Font.class), new AssetDescriptor<>("default", Font.class), new AssetDescriptor<>("chat", Font.class)); + return Seq.with(new AssetDescriptor<>(Control.class), new AssetDescriptor<>("outline", Font.class), new AssetDescriptor<>("default", Font.class)); } @Override diff --git a/core/src/mindustry/core/World.java b/core/src/mindustry/core/World.java index ada34573b3..cd3cc83ada 100644 --- a/core/src/mindustry/core/World.java +++ b/core/src/mindustry/core/World.java @@ -328,8 +328,8 @@ public class World{ invalidMap = false; if(!headless){ - if(state.teams.playerCores().size == 0 && !checkRules.pvp){ - ui.showErrorMessage("@map.nospawn"); + if(state.teams.cores(checkRules.defaultTeam).size == 0 && !checkRules.pvp){ + ui.showErrorMessage(Core.bundle.format("map.nospawn", checkRules.defaultTeam.color, checkRules.defaultTeam.localized())); invalidMap = true; }else if(checkRules.pvp){ //pvp maps need two cores to be valid if(state.teams.getActive().count(TeamData::hasCore) < 2){ @@ -339,7 +339,7 @@ public class World{ }else if(checkRules.attackMode){ //attack maps need two cores to be valid invalidMap = state.rules.waveTeam.data().noCores(); if(invalidMap){ - ui.showErrorMessage("@map.nospawn.attack"); + ui.showErrorMessage(Core.bundle.format("map.nospawn.attack", checkRules.waveTeam.color, checkRules.waveTeam.localized())); } } }else{ diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index 9b51df514b..213e4e4a83 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -42,7 +42,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ private BaseDialog menu; private Table blockSelection; private Rules lastSavedRules; - private boolean saved = false; + private boolean saved = false; //currently never read private boolean shownWithMap = false; private Seq blocksOut = new Seq<>(); diff --git a/core/src/mindustry/editor/MapView.java b/core/src/mindustry/editor/MapView.java index 3dc9f8e239..4b603ddb28 100644 --- a/core/src/mindustry/editor/MapView.java +++ b/core/src/mindustry/editor/MapView.java @@ -196,7 +196,7 @@ public class MapView extends Element implements GestureListener{ if(Core.scene.getScrollFocus() != this) return; - zoom += Core.input.axis(KeyCode.scroll) / 10f * zoom; + zoom += Core.input.axis(Binding.zoom) / 10f * zoom; clampZoom(); } diff --git a/core/src/mindustry/entities/abilities/UnitSpawnAbility.java b/core/src/mindustry/entities/abilities/UnitSpawnAbility.java index b6f8561056..c3f826e5a5 100644 --- a/core/src/mindustry/entities/abilities/UnitSpawnAbility.java +++ b/core/src/mindustry/entities/abilities/UnitSpawnAbility.java @@ -32,7 +32,7 @@ public class UnitSpawnAbility extends Ability{ @Override public void update(Unit unit){ - timer += Time.delta * state.rules.unitBuildSpeedMultiplier; + timer += Time.delta * state.rules.unitBuildSpeed(unit.team); if(timer >= spawnTime && Units.canCreate(unit.team, this.unit)){ float x = unit.x + Angles.trnsx(unit.rotation, spawnY, spawnX), y = unit.y + Angles.trnsy(unit.rotation, spawnY, spawnX); diff --git a/core/src/mindustry/entities/comp/BuilderComp.java b/core/src/mindustry/entities/comp/BuilderComp.java index 288150e938..81b59a632f 100644 --- a/core/src/mindustry/entities/comp/BuilderComp.java +++ b/core/src/mindustry/entities/comp/BuilderComp.java @@ -124,11 +124,13 @@ abstract class BuilderComp implements Posc, Statusc, Teamc, Rotc{ return; } + float bs = 1f / entity.buildCost * Time.delta * type.buildSpeed * buildSpeedMultiplier * state.rules.buildSpeed(team); + //otherwise, update it. if(current.breaking){ - entity.deconstruct(self(), core, 1f / entity.buildCost * Time.delta * type.buildSpeed * buildSpeedMultiplier * state.rules.buildSpeedMultiplier); + entity.deconstruct(self(), core, bs); }else{ - entity.construct(self(), core, 1f / entity.buildCost * Time.delta * type.buildSpeed * buildSpeedMultiplier * state.rules.buildSpeedMultiplier, current.config); + entity.construct(self(), core, bs, current.config); } current.stuck = Mathf.equal(current.progress, entity.progress); diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index 5dc11a407e..d4ce1bdf9c 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -1378,10 +1378,12 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, public void damage(float damage){ if(dead()) return; - if(Mathf.zero(state.rules.blockHealthMultiplier)){ + float dm = state.rules.blockHealth(team); + + if(Mathf.zero(dm)){ damage = health + 1; }else{ - damage /= state.rules.blockHealthMultiplier; + damage /= dm; } Call.tileDamage(self(), health - handleDamage(damage)); diff --git a/core/src/mindustry/entities/comp/BulletComp.java b/core/src/mindustry/entities/comp/BulletComp.java index 86b779b82d..3d4f209734 100644 --- a/core/src/mindustry/entities/comp/BulletComp.java +++ b/core/src/mindustry/entities/comp/BulletComp.java @@ -68,8 +68,8 @@ abstract class BulletComp implements Timedc, Damagec, Hitboxc, Teamc, Posc, Draw @Override public float damageMultiplier(){ - if(owner instanceof Unit u) return u.damageMultiplier() * state.rules.unitDamageMultiplier; - if(owner instanceof Building) return state.rules.blockDamageMultiplier; + if(owner instanceof Unit u) return u.damageMultiplier() * state.rules.unitDamage(team); + if(owner instanceof Building) return state.rules.blockDamage(team); return 1f; } diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index ad70638368..3354f223f4 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -140,6 +140,26 @@ public class Rules{ } } + public float unitBuildSpeed(Team team){ + return unitBuildSpeedMultiplier * teams.get(team).unitBuildSpeedMultiplier; + } + + public float unitDamage(Team team){ + return unitDamageMultiplier * teams.get(team).unitDamageMultiplier; + } + + public float blockHealth(Team team){ + return blockHealthMultiplier * teams.get(team).blockHealthMultiplier; + } + + public float blockDamage(Team team){ + return blockDamageMultiplier * teams.get(team).blockDamageMultiplier; + } + + public float buildSpeed(Team team){ + return buildSpeedMultiplier * teams.get(team).buildSpeedMultiplier; + } + /** A team-specific ruleset. */ public static class TeamRule{ /** Whether to use building AI. */ @@ -154,6 +174,19 @@ public class Rules{ public boolean infiniteResources; /** If true, this team has infinite unit ammo. */ public boolean infiniteAmmo; + + /** How fast unit factories build units. */ + public float unitBuildSpeedMultiplier = 1f; + /** How much damage any other units deal. */ + public float unitDamageMultiplier = 1f; + /** How much health blocks start with. */ + public float blockHealthMultiplier = 1f; + /** How much damage blocks (turrets) deal. */ + public float blockDamageMultiplier = 1f; + /** Multiplier for building speed. */ + public float buildSpeedMultiplier = 1f; + + //build cost disabled due to technical complexity } /** A simple map for storing TeamRules in an efficient way without hashing. */ diff --git a/core/src/mindustry/graphics/Pixelator.java b/core/src/mindustry/graphics/Pixelator.java index 5bce6721e3..7d40dc8ff5 100644 --- a/core/src/mindustry/graphics/Pixelator.java +++ b/core/src/mindustry/graphics/Pixelator.java @@ -30,8 +30,11 @@ public class Pixelator implements Disposable{ py = Core.camera.position.y; Core.camera.position.set((int)px + ((int)(camera.width) % 2 == 0 ? 0 : 0.5f), (int)py + ((int)(camera.height) % 2 == 0 ? 0 : 0.5f)); - int w = (int)(Core.camera.width * renderer.landScale()); - int h = (int)(Core.camera.height * renderer.landScale()); + int w = (int)Core.camera.width, h = (int)Core.camera.height; + if(renderer.isCutscene()){ + w = (int)(Core.camera.width * renderer.landScale() / renderer.getScale()); + h = (int)(Core.camera.height * renderer.landScale() / renderer.getScale()); + } buffer.resize(w, h); diff --git a/core/src/mindustry/input/DesktopInput.java b/core/src/mindustry/input/DesktopInput.java index efe122e893..acb3795aff 100644 --- a/core/src/mindustry/input/DesktopInput.java +++ b/core/src/mindustry/input/DesktopInput.java @@ -646,13 +646,6 @@ public class DesktopInput extends InputHandler{ unit.moveAt(movement); }else{ unit.rotateMove(movement); - - unit.moveAt(Tmp.v2.trns(unit.rotation, movement.len())); - - //problem: actual unit rotation is controlled by velocity, but velocity is 1) unpredictable and 2) can be set to 0 - if(!movement.isZero()){ - unit.rotation = Angles.moveToward(unit.rotation, movement.angle(), unit.type.rotateSpeed * Math.max(Time.delta, 1)); - } } unit.aim(unit.type.faceTarget ? Core.input.mouseWorld() : Tmp.v1.trns(unit.rotation, Core.input.mouseWorld().dst(unit)).add(unit.x, unit.y)); diff --git a/core/src/mindustry/input/InputHandler.java b/core/src/mindustry/input/InputHandler.java index f97385122c..0b5f2bef99 100644 --- a/core/src/mindustry/input/InputHandler.java +++ b/core/src/mindustry/input/InputHandler.java @@ -454,6 +454,10 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ public void update(){ player.typing = ui.chatfrag.shown(); + if(player.dead()){ + droppingItem = false; + } + if(player.isBuilder()){ player.unit().updateBuilding(isBuilding); } diff --git a/core/src/mindustry/net/Net.java b/core/src/mindustry/net/Net.java index 0dc711ea3d..9081b194f4 100644 --- a/core/src/mindustry/net/Net.java +++ b/core/src/mindustry/net/Net.java @@ -272,6 +272,10 @@ public class Net{ throw new RuntimeException("Received stream chunk without a StreamBegin beforehand!"); } builder.add(c.data); + + ui.loadfrag.setProgress(builder.progress()); + netClient.resetTimeout(); + if(builder.isDone()){ streams.remove(builder.id); handleClientReceived(builder.build()); diff --git a/core/src/mindustry/type/Sector.java b/core/src/mindustry/type/Sector.java index a2111160e9..0637ed8c2b 100644 --- a/core/src/mindustry/type/Sector.java +++ b/core/src/mindustry/type/Sector.java @@ -135,7 +135,7 @@ public class Sector{ @Nullable public String iconChar(){ if(info.contentIcon != null) return info.contentIcon.emoji(); - if(info.icon != null) return Iconc.codes.get(info.icon) + ""; + if(info.icon != null) return (char)Iconc.codes.get(info.icon) + ""; return null; } diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index 1ea7acc16b..f470140bf3 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -331,7 +331,7 @@ public class UnitType extends UnlockableContent{ singleTarget = weapons.size <= 1 && !forceMultiTarget; if(itemCapacity < 0){ - itemCapacity = Math.max(Mathf.round((int)(hitSize * 4.3), 10), 10); + itemCapacity = Math.max(Mathf.round((int)(hitSize * 4f), 10), 10); } //assume slight range margin diff --git a/core/src/mindustry/ui/Fonts.java b/core/src/mindustry/ui/Fonts.java index bbd55bbd95..9785619cba 100644 --- a/core/src/mindustry/ui/Fonts.java +++ b/core/src/mindustry/ui/Fonts.java @@ -37,7 +37,6 @@ public class Fonts{ public static Font def; public static Font outline; - public static Font chat; public static Font icon; public static Font iconLarge; public static Font tech; @@ -76,7 +75,6 @@ public class Fonts{ FreeTypeFontParameter param = fontParameter(); Core.assets.load("default", Font.class, new FreeTypeFontLoaderParameter(mainFont, param)).loaded = f -> Fonts.def = (Font)f; - Core.assets.load("chat", Font.class, new FreeTypeFontLoaderParameter(mainFont, param)).loaded = f -> Fonts.chat = (Font)f; Core.assets.load("icon", Font.class, new FreeTypeFontLoaderParameter("fonts/icon.ttf", new FreeTypeFontParameter(){{ size = 30; incremental = true; @@ -104,7 +102,7 @@ public class Fonts{ } public static void loadContentIcons(){ - Seq fonts = Seq.with(Fonts.chat, Fonts.def, Fonts.outline); + Seq fonts = Seq.with(Fonts.def, Fonts.outline); Texture uitex = Core.atlas.find("logo").texture; int size = (int)(Fonts.def.getData().lineHeight/Fonts.def.getData().scaleY); diff --git a/core/src/mindustry/ui/Styles.java b/core/src/mindustry/ui/Styles.java index 36a3ace7d2..f6b212fa06 100644 --- a/core/src/mindustry/ui/Styles.java +++ b/core/src/mindustry/ui/Styles.java @@ -26,8 +26,8 @@ import static mindustry.gen.Tex.*; public class Styles{ //TODO all these names are inconsistent and not descriptive public static Drawable black, black9, black8, black6, black3, black5, none, flatDown, flatOver, accentDrawable; - public static ButtonStyle defaultb, waveb, modsb; - public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, nonet, infot, clearPartialt, clearTogglet, logicTogglet, clearToggleMenut, togglet, transt, fullTogglet, logict; + public static ButtonStyle defaultb, waveb, modsb, underlineb; + public static TextButtonStyle defaultt, squaret, nodet, cleart, discordt, nonet, infot, clearPartialt, clearTogglet, logicTogglet, clearToggleMenut, togglet, transt, fullTogglet, squareTogglet, logict; public static ImageButtonStyle defaulti, nodei, righti, emptyi, emptytogglei, selecti, logici, geni, colori, accenti, cleari, clearFulli, clearPartiali, clearPartial2i, clearTogglei, clearTransi, clearToggleTransi, clearTogglePartiali; public static ScrollPaneStyle defaultPane, horizontalPane, smallPane, nonePane; public static KeybindDialog.KeybindDialogStyle defaultKeybindDialog; @@ -62,7 +62,14 @@ public class Styles{ modsb = new ButtonStyle(){{ down = flatOver; up = underline; - over = underlineWhite; + over = underline2; + }}; + + underlineb = new ButtonStyle(){{ + down = flatOver; + up = sideline; + over = sidelineOver; + checked = flatOver; }}; waveb = new ButtonStyle(){{ @@ -196,6 +203,16 @@ public class Styles{ disabled = black; disabledFontColor = Color.gray; }}; + squareTogglet = new TextButtonStyle(){{ + font = Fonts.def; + fontColor = Color.white; + checked = flatOver; + down = flatOver; + up = pane; + over = flatOver; + disabled = black; + disabledFontColor = Color.gray; + }}; defaulti = new ImageButtonStyle(){{ down = buttonDown; up = button; @@ -340,7 +357,7 @@ public class Styles{ }}; defaultField = new TextFieldStyle(){{ - font = Fonts.chat; + font = Fonts.def; fontColor = Color.white; disabledFontColor = Color.gray; disabledBackground = underlineDisabled; @@ -353,7 +370,7 @@ public class Styles{ }}; nodeField = new TextFieldStyle(){{ - font = Fonts.chat; + font = Fonts.def; fontColor = Color.white; disabledFontColor = Color.gray; disabledBackground = underlineDisabled; @@ -366,7 +383,7 @@ public class Styles{ }}; areaField = new TextFieldStyle(){{ - font = Fonts.chat; + font = Fonts.def; fontColor = Color.white; disabledFontColor = Color.gray; selection = Tex.selection; @@ -377,7 +394,7 @@ public class Styles{ }}; nodeArea = new TextFieldStyle(){{ - font = Fonts.chat; + font = Fonts.def; fontColor = Color.white; disabledFontColor = Color.gray; selection = Tex.selection; diff --git a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java index 0bee65257d..3a7086e727 100644 --- a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java +++ b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java @@ -13,6 +13,7 @@ import arc.util.*; import mindustry.content.*; import mindustry.ctype.*; import mindustry.game.*; +import mindustry.game.Rules.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.type.*; @@ -200,6 +201,53 @@ public class CustomRulesDialog extends BaseDialog{ }, () -> ui.picker.show(rules.ambientLight, rules.ambientLight::set)).left().width(250f).row(); main.button("@rules.weather", this::weatherDialog).width(250f).left().row(); + + title("@rules.title.teams"); + + team("@rules.playerteam", t -> rules.defaultTeam = t, () -> rules.defaultTeam); + team("@rules.enemyteam", t -> rules.waveTeam = t, () -> rules.waveTeam); + + for(Team team : Team.baseTeams){ + boolean[] shown = {false}; + Table wasMain = main; + + main.button("[#" + team.color + "]" + team.localized() + (team.emoji.isEmpty() ? "" : "[] " + team.emoji), Icon.downOpen, Styles.togglet, () -> { + shown[0] = !shown[0]; + }).marginLeft(14f).width(260f).height(55f).checked(a -> shown[0]).row(); + + main.collapser(t -> { + t.left().defaults().fillX().left().pad(5); + main = t; + TeamRule teams = rules.teams.get(team); + + number("@rules.blockhealthmultiplier", f -> teams.blockHealthMultiplier = f, () -> teams.blockHealthMultiplier); + number("@rules.blockdamagemultiplier", f -> teams.blockDamageMultiplier = f, () -> teams.blockDamageMultiplier); + + check("@rules.buildai", b -> teams.ai = b, () -> teams.ai, () -> team != rules.defaultTeam); + number("@rules.aitier", false, f -> teams.aiTier = f, () -> teams.aiTier, () -> teams.ai, 0, 1); + + check("@rules.infiniteresources", b -> teams.infiniteResources = b, () -> teams.infiniteResources); + number("@rules.buildspeedmultiplier", f -> teams.buildSpeedMultiplier = f, () -> teams.buildSpeedMultiplier, 0.001f, 50f); + + number("@rules.unitdamagemultiplier", f -> teams.unitDamageMultiplier = f, () -> teams.unitDamageMultiplier); + number("@rules.unitbuildspeedmultiplier", f -> teams.unitBuildSpeedMultiplier = f, () -> teams.unitBuildSpeedMultiplier, 0.001f, 50f); + + main = wasMain; + }, () -> shown[0]).growX().row(); + } + } + + void team(String text, Cons cons, Prov prov){ + main.table(t -> { + t.left(); + t.add(text).left().padRight(5); + + for(Team team : Team.baseTeams){ + t.button(Tex.whiteui, Styles.clearTogglei, 38f, () -> { + cons.get(team); + }).pad(1f).checked(b -> prov.get() == team).size(60f).tooltip(team.localized()).with(i -> i.getStyle().imageUpColor = team.color); + } + }).padTop(0).row(); } void number(String text, Floatc cons, Floatp prov){ @@ -218,15 +266,15 @@ public class CustomRulesDialog extends BaseDialog{ number(text, false, cons, prov, condition, 0, Float.MAX_VALUE); } + //TODO integer param unused void number(String text, boolean integer, Intc cons, Intp prov, int min, int max){ main.table(t -> { t.left(); t.add(text).left().padRight(5); - t.field((integer ? prov.get() : prov.get()) + "", s -> cons.get(Strings.parseInt(s))) + t.field((prov.get()) + "", s -> cons.get(Strings.parseInt(s))) .padRight(100f) .valid(f -> Strings.parseInt(f) >= min && Strings.parseInt(f) <= max).width(120f).left().addInputDialog(); - }).padTop(0); - main.row(); + }).padTop(0).row(); } void number(String text, boolean integer, Floatc cons, Floatp prov, Boolp condition, float min, float max){ diff --git a/core/src/mindustry/ui/dialogs/DatabaseDialog.java b/core/src/mindustry/ui/dialogs/DatabaseDialog.java index ede404aa9a..c94f69f2e2 100644 --- a/core/src/mindustry/ui/dialogs/DatabaseDialog.java +++ b/core/src/mindustry/ui/dialogs/DatabaseDialog.java @@ -20,6 +20,8 @@ import mindustry.world.*; import static mindustry.Vars.*; public class DatabaseDialog extends BaseDialog{ + private TextField search; + private Table all = new Table(); public DatabaseDialog(){ super("@database"); @@ -28,28 +30,38 @@ public class DatabaseDialog extends BaseDialog{ addCloseButton(); shown(this::rebuild); onResize(this::rebuild); + + all.margin(20).marginTop(0f); + + cont.table(s -> { + s.image(Icon.zoom).padRight(8); + search = s.field(null, text -> rebuild()).growX().get(); + search.setMessageText(Core.bundle.get("players.search")); + }).fillX().padBottom(4).row(); + + cont.pane(all); } void rebuild(){ - cont.clear(); - - Table table = new Table(); - table.margin(20); - ScrollPane pane = new ScrollPane(table); + all.clear(); + var text = search.getText(); Seq[] allContent = Vars.content.getContentMap(); for(int j = 0; j < allContent.length; j++){ ContentType type = ContentType.all[j]; - Seq array = allContent[j].select(c -> c instanceof UnlockableContent u && (!u.isHidden() || u.node() != null)); + Seq array = allContent[j] + .select(c -> c instanceof UnlockableContent u && + (!u.isHidden() || u.node() != null) && + (text.isEmpty() || u.localizedName.toLowerCase().contains(text.toLowerCase()))); if(array.size == 0) continue; - table.add("@content." + type.name() + ".name").growX().left().color(Pal.accent); - table.row(); - table.image().growX().pad(5).padLeft(0).padRight(0).height(3).color(Pal.accent); - table.row(); - table.table(list -> { + all.add("@content." + type.name() + ".name").growX().left().color(Pal.accent); + all.row(); + all.image().growX().pad(5).padLeft(0).padRight(0).height(3).color(Pal.accent); + all.row(); + all.table(list -> { list.left(); int cols = (int)Mathf.clamp((Core.graphics.getWidth() - Scl.scl(30)) / Scl.scl(32 + 10), 1, 22); @@ -94,10 +106,12 @@ public class DatabaseDialog extends BaseDialog{ } } }).growX().left().padBottom(10); - table.row(); + all.row(); } - cont.add(pane); + if(all.getChildren().isEmpty()){ + all.add("@none.found"); + } } boolean unlocked(UnlockableContent content){ diff --git a/core/src/mindustry/ui/dialogs/PausedDialog.java b/core/src/mindustry/ui/dialogs/PausedDialog.java index 1226d59324..e1a0da90bb 100644 --- a/core/src/mindustry/ui/dialogs/PausedDialog.java +++ b/core/src/mindustry/ui/dialogs/PausedDialog.java @@ -53,11 +53,11 @@ public class PausedDialog extends BaseDialog{ ui.host.show(); } } - }).disabled(b -> !((steam && net.server()) || !net.active())).colspan(2).width(dw * 2 + 20f).update(e -> e.setText(net.server() && steam ? "@invitefriends" : "@hostserver")); + }).disabled(b -> !((steam && net.server()) || !net.active())).colspan(2).width(dw * 2 + 10f).update(e -> e.setText(net.server() && steam ? "@invitefriends" : "@hostserver")); cont.row(); - cont.button("@quit", Icon.exit, this::showQuitConfirm).colspan(2).width(dw + 20f).update(s -> s.setText(control.saves.getCurrent() != null && control.saves.getCurrent().isAutosave() ? "@save.quit" : "@quit")); + cont.button("@quit", Icon.exit, this::showQuitConfirm).colspan(2).width(dw + 10f).update(s -> s.setText(control.saves.getCurrent() != null && control.saves.getCurrent().isAutosave() ? "@save.quit" : "@quit")); }else{ cont.defaults().size(130f).pad(5); diff --git a/core/src/mindustry/ui/dialogs/PlanetDialog.java b/core/src/mindustry/ui/dialogs/PlanetDialog.java index 73992fb3be..a6bfea97aa 100644 --- a/core/src/mindustry/ui/dialogs/PlanetDialog.java +++ b/core/src/mindustry/ui/dialogs/PlanetDialog.java @@ -62,9 +62,10 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ public Seq newPresets = new Seq<>(); public float presetShow = 0f; - public boolean showed = false; + public boolean showed = false, sectorsShown; + public String searchText = ""; - public Table sectorTop = new Table(); + public Table sectorTop = new Table(), notifs; public Label hoverLabel = new Label(""); public PlanetDialog(){ @@ -74,17 +75,22 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ planets.planet = content.getByName(ContentType.planet, Core.settings.getString("lastplanet", "serpulo")); if(planets.planet == null) planets.planet = Planets.serpulo; - keyDown(key -> { - if(key == KeyCode.escape || key == KeyCode.back || key == Core.keybinds.get(Binding.planet_map).key){ - if(showing() && newPresets.size > 1){ - //clear all except first, which is the last sector. - newPresets.truncate(1); - }else if(selected != null){ - selected = null; - updateSelected(); - }else{ - Core.app.post(this::hide); + addListener(new InputListener(){ + @Override + public boolean keyDown(InputEvent event, KeyCode key){ + if(event.targetActor == PlanetDialog.this && (key == KeyCode.escape || key == KeyCode.back || key == Core.keybinds.get(Binding.planet_map).key)){ + if(showing() && newPresets.size > 1){ + //clear all except first, which is the last sector. + newPresets.truncate(1); + }else if(selected != null){ + selected = null; + updateSelected(); + }else{ + Core.app.post(() -> hide()); + } + return true; } + return false; } }); @@ -121,8 +127,14 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ pos.rotate(Tmp.v31.set(planets.cam.up).rotate(planets.cam.direction, 90), amount); }); - scrolled(value -> { - zoom = Mathf.clamp(zoom + value / 10f, planets.planet.minZoom, 2f); + addListener(new InputListener(){ + @Override + public boolean scrolled(InputEvent event, float x, float y, float amountX, float amountY){ + if(event.targetActor == PlanetDialog.this){ + zoom = Mathf.clamp(zoom + y / 10f, planets.planet.minZoom, 2f); + } + return true; + } }); addCaptureListener(new ElementGestureListener(){ @@ -452,6 +464,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ } void setup(){ + searchText = ""; zoom = planets.zoom = 1f; selectAlpha = 1f; ui.minimapfrag.hide(); @@ -484,13 +497,19 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ }); } + @Override + public void act(float delta){ + if(scene.getDialog() == PlanetDialog.this && !scene.hit(input.mouseX(), input.mouseY(), true).isDescendantOf(e -> e instanceof ScrollPane)){ + scene.setScrollFocus(PlanetDialog.this); + } + + super.act(delta); + } + @Override public void draw(){ planets.orbitAlpha = selectAlpha; planets.render(PlanetDialog.this); - if(Core.scene.getDialog() == PlanetDialog.this){ - Core.scene.setScrollFocus(PlanetDialog.this); - } } }, //info text @@ -516,7 +535,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ selected = null; launchSector = null; renderer.planets.planet = planet; - Core.settings.put("lastplanet", planet.name); + settings.put("lastplanet", planet.name); }).width(200).height(40).growX().update(bb -> bb.setChecked(renderer.planets.planet == planet)); pt.row(); } @@ -525,11 +544,95 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ } }), - new Table(t -> { - t.top(); - //t.add(sectorTop); - })).grow(); + new Table(c -> { + if(!(graphics.isPortrait() && mobile) && planets.planet.sectors.contains(Sector::hasBase)){ + int attacked = planets.planet.sectors.count(Sector::isAttacked); + //sector notifications & search + c.top().right(); + c.defaults().width(280f); + + c.button(bundle.get("sectorlist") + + (attacked == 0 ? "" : "\n[red]⚠[lightgray] " + bundle.format("sectorlist.attacked", "[red]" + attacked + "[]")), + Icon.downOpen, Styles.squareTogglet, () -> sectorsShown = !sectorsShown) + .height(60f).checked(b -> { + Image image = (Image)b.getCells().first().get(); + image.setDrawable(sectorsShown ? Icon.upOpen : Icon.downOpen); + return sectorsShown; + }).with(t -> t.left().margin(7f)).with(t -> t.getLabelCell().grow().left()).row(); + + c.collapser(t -> { + t.background(Styles.black8); + + notifs = t; + rebuildList(); + }, false, () -> sectorsShown).padBottom(64f).row(); + } + })).grow(); + } + + //TODO + void rebuildList(){ + notifs.clear(); + + var all = planets.planet.sectors.select(Sector::hasBase); + all.sort(Structs.comps(Structs.comparingBool(s -> !s.isAttacked()), Structs.comparingInt(s -> s.save == null ? 0 : -(int)s.save.meta.timePlayed))); + + notifs.pane(p -> { + Runnable[] readd = {null}; + + p.table(s -> { + s.image(Icon.zoom).padRight(4); + s.field(searchText, t -> { + searchText = t; + readd[0].run(); + }).growX().height(50f).addInputDialog(); + }).growX().row(); + + Table con = p.table().growX().get(); + con.touchable = Touchable.enabled; + + readd[0] = () -> { + con.clearChildren(); + for(Sector sec : all){ + if(sec.hasBase() && (searchText.isEmpty() || sec.name().toLowerCase().contains(searchText.toLowerCase()))){ + con.button(t -> { + t.left(); + t.defaults().growX(); + + t.table(head -> { + head.left().defaults(); + + if(sec.isAttacked()){ + head.image(Icon.warningSmall).update(i -> { + i.color.set(Pal.accent).lerp(Pal.remove, Mathf.absin(Time.globalTime, 9f, 1f)); + }).padRight(4f); + } + + String ic = sec.iconChar() == null ? "" : sec.iconChar() + " "; + + head.add(ic + sec.name()).growX().wrap(); + }).growX().row(); + + if(sec.isAttacked()){ + addSurvivedInfo(sec, t, true); + } + }, Styles.underlineb, () -> { + lookAt(sec); + selected = sec; + updateSelected(); + }).margin(8f).marginLeft(13f).marginBottom(6f).marginTop(6f).padBottom(3f).padTop(3f).growX().checked(b -> selected == sec).row(); + //for resources: .tooltip(sec.info.resources.toString("", u -> u.emoji())) + } + } + + if(con.getChildren().isEmpty()){ + con.add("@none.found").pad(10f); + } + }; + + readd[0].run(); + }).grow().get().setScrollingDisabled(true, false); } @Override @@ -738,6 +841,19 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ dialog.show(); } + void addSurvivedInfo(Sector sector, Table table, boolean wrap){ + if(!wrap){ + table.add(Core.bundle.format("sectors.underattack", (int)(sector.info.damage * 100))).wrapLabel(wrap).row(); + } + + if(sector.info.wavesSurvived >= 0 && sector.info.wavesSurvived - sector.info.wavesPassed >= 0 && !sector.isBeingPlayed()){ + int toCapture = sector.info.attack || sector.info.winWave <= 1 ? -1 : sector.info.winWave - (sector.info.wave + sector.info.wavesPassed); + boolean plus = (sector.info.wavesSurvived - sector.info.wavesPassed) >= SectorDamage.maxRetWave - 1; + table.add(Core.bundle.format("sectors.survives", Math.min(sector.info.wavesSurvived - sector.info.wavesPassed, toCapture <= 0 ? 200 : toCapture) + + (plus ? "+" : "") + (toCapture < 0 ? "" : "/" + toCapture))).wrapLabel(wrap).row(); + } + } + void updateSelected(){ Sector sector = selected; Table stable = sectorTop; @@ -762,6 +878,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ ui.showTextInput("@sectors.rename", "@name", 20, sector.name(), v -> { sector.setName(v); updateSelected(); + rebuildList(); }); }).size(40f).padLeft(4); } @@ -774,6 +891,14 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ new Dialog(""){{ closeOnBack(); setFillParent(true); + + Runnable refresh = () -> { + sector.saveInfo(); + hide(); + updateSelected(); + rebuildList(); + }; + cont.pane(t -> { resized(true, () -> { t.clearChildren(); @@ -783,9 +908,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ t.button(Icon.none, Styles.clearTogglei, () -> { sector.info.icon = null; sector.info.contentIcon = null; - sector.saveInfo(); - hide(); - updateSelected(); + refresh.run(); }).checked(sector.info.icon == null && sector.info.contentIcon == null); int cols = (int)Math.min(20, Core.graphics.getWidth() / Scl.scl(52f)); @@ -797,9 +920,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ t.button(value, Styles.clearTogglei, () -> { sector.info.icon = key; sector.info.contentIcon = null; - sector.saveInfo(); - hide(); - updateSelected(); + refresh.run(); }).checked(key.equals(sector.info.icon)); if(++i % cols == 0) t.row(); @@ -816,9 +937,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ t.button(new TextureRegionDrawable(u.uiIcon), Styles.clearTogglei, iconMed, () -> { sector.info.icon = null; sector.info.contentIcon = u; - sector.saveInfo(); - hide(); - updateSelected(); + refresh.run(); }).checked(sector.info.contentIcon == u); if(++i % cols == 0) t.row(); @@ -853,16 +972,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ } if(sector.isAttacked()){ - stable.add(Core.bundle.format("sectors.underattack", (int)(sector.info.damage * 100))); - stable.row(); - - if(sector.info.wavesSurvived >= 0 && sector.info.wavesSurvived - sector.info.wavesPassed >= 0 && !sector.isBeingPlayed()){ - int toCapture = sector.info.attack || sector.info.winWave <= 1 ? -1 : sector.info.winWave - (sector.info.wave + sector.info.wavesPassed); - boolean plus = (sector.info.wavesSurvived - sector.info.wavesPassed) >= SectorDamage.maxRetWave - 1; - stable.add(Core.bundle.format("sectors.survives", Math.min(sector.info.wavesSurvived - sector.info.wavesPassed, toCapture <= 0 ? 200 : toCapture) + - (plus ? "+" : "") + (toCapture < 0 ? "" : "/" + toCapture))); - stable.row(); - } + addSurvivedInfo(sector, stable, false); }else if(sector.hasBase() && sector.near().contains(Sector::hasEnemyBase)){ stable.add("@sectors.vulnerable"); stable.row(); @@ -899,6 +1009,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ stable.pack(); stable.setPosition(x, y, Align.center); + //do not fade out for now, TODO remove? + /* stable.update(() -> { if(selected != null){ if(launching){ @@ -918,7 +1030,7 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{ } } } - }); + });*/ stable.act(0f); } diff --git a/core/src/mindustry/ui/dialogs/SchematicsDialog.java b/core/src/mindustry/ui/dialogs/SchematicsDialog.java index cdafcf0e80..e054772b62 100644 --- a/core/src/mindustry/ui/dialogs/SchematicsDialog.java +++ b/core/src/mindustry/ui/dialogs/SchematicsDialog.java @@ -69,7 +69,7 @@ public class SchematicsDialog extends BaseDialog{ searchField = s.field(search, res -> { search = res; rebuildPane.run(); - }).growX().get(); + }).growX().addInputDialog().get(); }).fillX().padBottom(4); cont.row(); diff --git a/core/src/mindustry/ui/fragments/ChatFragment.java b/core/src/mindustry/ui/fragments/ChatFragment.java index 4b4bd3e46d..c39233a8e5 100644 --- a/core/src/mindustry/ui/fragments/ChatFragment.java +++ b/core/src/mindustry/ui/fragments/ChatFragment.java @@ -9,6 +9,7 @@ import arc.math.*; import arc.scene.*; import arc.scene.ui.*; import arc.scene.ui.Label.*; +import arc.scene.ui.TextField.*; import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; @@ -18,7 +19,6 @@ import mindustry.input.*; import mindustry.ui.*; import static arc.Core.*; -import static mindustry.Vars.net; import static mindustry.Vars.*; public class ChatFragment extends Table{ @@ -104,10 +104,9 @@ public class ChatFragment extends Table{ fieldlabel.getStyle().font = font; fieldlabel.setStyle(fieldlabel.getStyle()); - chatfield = new TextField("", new TextField.TextFieldStyle(scene.getStyle(TextField.TextFieldStyle.class))); + chatfield = new TextField("", new TextFieldStyle(scene.getStyle(TextFieldStyle.class))); chatfield.setMaxLength(Vars.maxTextLength); chatfield.getStyle().background = null; - chatfield.getStyle().font = Fonts.chat; chatfield.getStyle().fontColor = Color.white; chatfield.setStyle(chatfield.getStyle()); diff --git a/core/src/mindustry/ui/fragments/HintsFragment.java b/core/src/mindustry/ui/fragments/HintsFragment.java index b548a5536c..059af19994 100644 --- a/core/src/mindustry/ui/fragments/HintsFragment.java +++ b/core/src/mindustry/ui/fragments/HintsFragment.java @@ -48,7 +48,7 @@ public class HintsFragment extends Fragment{ }else if(!current.show()){ //current became hidden hide(); } - }else if(hints.size > 0){ + }else if(hints.size > 0 && !renderer.isCutscene()){ //check one hint each frame to see if it should be shown. Hint hint = hints.find(Hint::show); if(hint != null && hint.complete()){ @@ -163,7 +163,7 @@ public class HintsFragment extends Fragment{ schematicSelect(visibleDesktop, () -> ui.hints.placedBlocks.contains(Blocks.router), () -> Core.input.keyRelease(Binding.schematic_select) || Core.input.keyTap(Binding.pick)), conveyorPathfind(() -> control.input.block == Blocks.titaniumConveyor, () -> Core.input.keyRelease(Binding.diagonal_placement) || (mobile && Core.settings.getBool("swapdiagonal"))), boost(visibleDesktop, () -> !player.dead() && player.unit().type.canBoost, () -> Core.input.keyDown(Binding.boost)), - blockInfo(() -> true, () -> ui.content.isShown()), + blockInfo(() -> !(state.isCampaign() && state.rules.sector == SectorPresets.groundZero.sector && state.wave < 3), () -> ui.content.isShown()), derelict(() -> ui.hints.events.contains("derelictmouse"), () -> false), command(() -> state.rules.defaultTeam.data().units.size > 3 && !net.active(), () -> player.unit().isCommanding()), payloadPickup(() -> !player.unit().dead && player.unit() instanceof Payloadc p && p.payloads().isEmpty(), () -> player.unit() instanceof Payloadc p && p.payloads().any()), diff --git a/core/src/mindustry/ui/fragments/LoadingFragment.java b/core/src/mindustry/ui/fragments/LoadingFragment.java index a5ab8eeff7..fcd18dfcbe 100644 --- a/core/src/mindustry/ui/fragments/LoadingFragment.java +++ b/core/src/mindustry/ui/fragments/LoadingFragment.java @@ -17,6 +17,7 @@ public class LoadingFragment extends Fragment{ private TextButton button; private Bar bar; private Label nameLabel; + private float progValue; @Override public void build(Group parent){ @@ -55,6 +56,13 @@ public class LoadingFragment extends Fragment{ bar.set(() -> ((int)(progress.get() * 100) + "%"), progress, Pal.accent); } + public void setProgress(float progress){ + progValue = progress; + if(!bar.visible){ + setProgress(() -> progValue); + } + } + public void setButton(Runnable listener){ button.visible = true; button.getListeners().remove(button.getListeners().size - 1); diff --git a/core/src/mindustry/ui/fragments/PlayerListFragment.java b/core/src/mindustry/ui/fragments/PlayerListFragment.java index 67b101c6ab..32115c7cea 100644 --- a/core/src/mindustry/ui/fragments/PlayerListFragment.java +++ b/core/src/mindustry/ui/fragments/PlayerListFragment.java @@ -20,7 +20,7 @@ public class PlayerListFragment extends Fragment{ public Table content = new Table().marginRight(13f).marginLeft(13f); private boolean visible = false; private Interval timer = new Interval(); - private TextField sField; + private TextField search; private Seq players = new Seq<>(); @Override @@ -47,12 +47,9 @@ public class PlayerListFragment extends Fragment{ cont.table(Tex.buttonTrans, pane -> { pane.label(() -> Core.bundle.format(Groups.player.size() == 1 ? "players.single" : "players", Groups.player.size())); pane.row(); - sField = pane.field(null, text -> { - rebuild(); - }).grow().pad(8).get(); - sField.name = "search"; - sField.setMaxLength(maxNameLength); - sField.setMessageText(Core.bundle.format("players.search")); + + search = pane.field(null, text -> rebuild()).grow().pad(8).name("search").maxTextLength(maxNameLength).get(); + search.setMessageText(Core.bundle.get("players.search")); pane.row(); pane.pane(content).grow().get().setScrollingDisabled(true, false); @@ -83,8 +80,8 @@ public class PlayerListFragment extends Fragment{ Groups.player.copy(players); players.sort(Structs.comps(Structs.comparing(Player::team), Structs.comparingBool(p -> !p.admin))); - if(sField.getText().length() > 0){ - players.filter(p -> Strings.stripColors(p.name().toLowerCase()).contains(sField.getText().toLowerCase())); + if(search.getText().length() > 0){ + players.filter(p -> Strings.stripColors(p.name().toLowerCase()).contains(search.getText().toLowerCase())); } for(var user : players){ @@ -181,7 +178,7 @@ public class PlayerListFragment extends Fragment{ rebuild(); }else{ Core.scene.setKeyboardFocus(null); - sField.clearText(); + search.clearText(); } } diff --git a/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java b/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java index 71704dc5e7..76e856e437 100644 --- a/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java +++ b/core/src/mindustry/ui/fragments/ScriptConsoleFragment.java @@ -8,6 +8,7 @@ import arc.math.*; import arc.scene.*; import arc.scene.ui.*; import arc.scene.ui.Label.*; +import arc.scene.ui.TextField.*; import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; @@ -93,9 +94,8 @@ public class ScriptConsoleFragment extends Table{ fieldlabel.getStyle().font = font; fieldlabel.setStyle(fieldlabel.getStyle()); - chatfield = new TextField("", new TextField.TextFieldStyle(scene.getStyle(TextField.TextFieldStyle.class))); + chatfield = new TextField("", new TextFieldStyle(scene.getStyle(TextFieldStyle.class))); chatfield.getStyle().background = null; - chatfield.getStyle().font = Fonts.chat; chatfield.getStyle().fontColor = Color.white; chatfield.setStyle(chatfield.getStyle()); diff --git a/core/src/mindustry/world/blocks/campaign/LaunchPad.java b/core/src/mindustry/world/blocks/campaign/LaunchPad.java index 8f10c7b5b9..12bcb762b3 100644 --- a/core/src/mindustry/world/blocks/campaign/LaunchPad.java +++ b/core/src/mindustry/world/blocks/campaign/LaunchPad.java @@ -141,7 +141,7 @@ public class LaunchPad extends Block{ public void display(Table table){ super.display(table); - if(!state.isCampaign() || net.client()) return; + if(!state.isCampaign() || net.client() || team != player.team()) return; table.row(); table.label(() -> { diff --git a/core/src/mindustry/world/blocks/logic/MessageBlock.java b/core/src/mindustry/world/blocks/logic/MessageBlock.java index 6964f2c4f6..3a982c37cb 100644 --- a/core/src/mindustry/world/blocks/logic/MessageBlock.java +++ b/core/src/mindustry/world/blocks/logic/MessageBlock.java @@ -93,7 +93,9 @@ public class MessageBlock extends Block{ text = message.toString(); multiline = true; maxLength = maxTextLength; - accepted = str -> configure(str); + accepted = str -> { + if(!str.equals(text)) configure(str); + }; }}); }else{ BaseDialog dialog = new BaseDialog("@editmessage"); @@ -113,7 +115,7 @@ public class MessageBlock extends Block{ }); a.setMaxLength(maxTextLength); dialog.buttons.button("@ok", () -> { - configure(a.getText()); + if(!a.getText().equals(message.toString())) configure(a.getText()); dialog.hide(); }).size(130f, 60f); dialog.update(() -> { diff --git a/core/src/mindustry/world/blocks/units/Reconstructor.java b/core/src/mindustry/world/blocks/units/Reconstructor.java index 9521a6c87a..b8ee614f50 100644 --- a/core/src/mindustry/world/blocks/units/Reconstructor.java +++ b/core/src/mindustry/world/blocks/units/Reconstructor.java @@ -197,7 +197,7 @@ public class Reconstructor extends UnitBlock{ if(moveInPayload()){ if(consValid()){ valid = true; - progress += edelta() * state.rules.unitBuildSpeedMultiplier; + progress += edelta() * state.rules.unitBuildSpeed(team); } //upgrade the unit @@ -214,7 +214,7 @@ public class Reconstructor extends UnitBlock{ } speedScl = Mathf.lerpDelta(speedScl, Mathf.num(valid), 0.05f); - time += edelta() * speedScl * state.rules.unitBuildSpeedMultiplier; + time += edelta() * speedScl * state.rules.unitBuildSpeed(team); } @Override diff --git a/core/src/mindustry/world/blocks/units/UnitFactory.java b/core/src/mindustry/world/blocks/units/UnitFactory.java index bbef9cb456..c614ad9e4c 100644 --- a/core/src/mindustry/world/blocks/units/UnitFactory.java +++ b/core/src/mindustry/world/blocks/units/UnitFactory.java @@ -213,8 +213,8 @@ public class UnitFactory extends UnitBlock{ } if(consValid() && currentPlan != -1){ - time += edelta() * speedScl * Vars.state.rules.unitBuildSpeedMultiplier; - progress += edelta() * Vars.state.rules.unitBuildSpeedMultiplier; + time += edelta() * speedScl * Vars.state.rules.unitBuildSpeed(team); + progress += edelta() * Vars.state.rules.unitBuildSpeed(team); speedScl = Mathf.lerpDelta(speedScl, 1f, 0.05f); }else{ speedScl = Mathf.lerpDelta(speedScl, 0f, 0.05f); diff --git a/core/src/mindustry/world/meta/StatValues.java b/core/src/mindustry/world/meta/StatValues.java index 534b935444..a5ff702798 100644 --- a/core/src/mindustry/world/meta/StatValues.java +++ b/core/src/mindustry/world/meta/StatValues.java @@ -49,11 +49,7 @@ public class StatValues{ public static StatValue liquids(Boolf filter, float amount, boolean perSecond){ return table -> { - Seq list = new Seq<>(); - - for(Liquid item : content.liquids()){ - if(!item.isHidden() && filter.get(item)) list.add(item); - } + Seq list = content.liquids().select(i -> filter.get(i) && i.unlockedNow()); for(int i = 0; i < list.size; i++){ table.add(new LiquidDisplay(list.get(i), amount, perSecond)).padRight(5); @@ -91,7 +87,7 @@ public class StatValues{ public static StatValue items(float timePeriod, Boolf filter){ return table -> { - Seq list = content.items().select(filter); + Seq list = content.items().select(i -> filter.get(i) && i.unlockedNow()); for(int i = 0; i < list.size; i++){ Item item = list.get(i); diff --git a/gradle.properties b/gradle.properties index 2917c3abef..cec569e049 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,4 +11,4 @@ android.useAndroidX=true #used for slow jitpack builds; TODO see if this actually works http.socketTimeout=80000 http.connectionTimeout=80000 -archash=40c21b302ccc1e74f4c2a37f937c88acaec99254 +archash=fbbdf8776142ba1980855c954dcfbf00e96cbeb7 diff --git a/servers_v6.json b/servers_v6.json index 1c9ccc0590..dc06079f12 100644 --- a/servers_v6.json +++ b/servers_v6.json @@ -98,5 +98,9 @@ { "name": "Xpdustry", "address": ["xpdustry.fr"] + }, + { + "name": "CxZx", + "address": ["usfr2.forcehost.net:25578"] } ] diff --git a/servers_v7.json b/servers_v7.json index 4e34aeb15b..01fef15fc5 100644 --- a/servers_v7.json +++ b/servers_v7.json @@ -13,7 +13,7 @@ }, { "name": "Omega", - "address": ["185.86.230.61:25571", "185.86.230.61:25570", "185.86.230.62:25572","mindustry.me:7175"] + "address": ["185.86.230.61:25571", "185.86.230.61:25570", "185.86.230.62:25572","yeet.mindustry.me:6567"] }, { "name": "MeowLand",