Merge branch 'master' of https://github.com/Anuken/Mindustry into 7.0-features
Conflicts: core/src/mindustry/ui/dialogs/PlanetDialog.java
|
Before Width: | Height: | Size: 144 B After Width: | Height: | Size: 262 B |
BIN
core/assets-raw/sprites/blocks/turrets/fuse-heat.png
Normal file
|
After Width: | Height: | Size: 833 B |
|
Before Width: | Height: | Size: 148 B After Width: | Height: | Size: 226 B |
|
Before Width: | Height: | Size: 214 B After Width: | Height: | Size: 363 B |
|
Before Width: | Height: | Size: 889 B After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 333 B After Width: | Height: | Size: 795 B |
|
Before Width: | Height: | Size: 278 B After Width: | Height: | Size: 517 B |
|
Before Width: | Height: | Size: 233 B After Width: | Height: | Size: 329 B |
BIN
core/assets-raw/sprites/blocks/turrets/spectre-heat.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 608 B After Width: | Height: | Size: 503 B |
BIN
core/assets-raw/sprites/ui/sideline-over.9.png
Normal file
|
After Width: | Height: | Size: 241 B |
BIN
core/assets-raw/sprites/ui/sideline.9.png
Normal file
|
After Width: | Height: | Size: 256 B |
BIN
core/assets-raw/sprites/ui/underline-over.9.png
Normal file
|
After Width: | Height: | Size: 206 B |
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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){{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ public class UI implements ApplicationListener, Loadable{
|
||||
|
||||
@Override
|
||||
public Seq<AssetDescriptor> 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
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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<Block> blocksOut = new Seq<>();
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<Font> fonts = Seq.with(Fonts.chat, Fonts.def, Fonts.outline);
|
||||
Seq<Font> 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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<Team> cons, Prov<Team> 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){
|
||||
|
||||
@@ -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<Content>[] allContent = Vars.content.getContentMap();
|
||||
|
||||
for(int j = 0; j < allContent.length; j++){
|
||||
ContentType type = ContentType.all[j];
|
||||
|
||||
Seq<Content> array = allContent[j].select(c -> c instanceof UnlockableContent u && (!u.isHidden() || u.node() != null));
|
||||
Seq<Content> 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){
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -62,9 +62,10 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
||||
|
||||
public Seq<Sector> 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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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()),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<Player> 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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(() -> {
|
||||
|
||||
@@ -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(() -> {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -49,11 +49,7 @@ public class StatValues{
|
||||
|
||||
public static StatValue liquids(Boolf<Liquid> filter, float amount, boolean perSecond){
|
||||
return table -> {
|
||||
Seq<Liquid> list = new Seq<>();
|
||||
|
||||
for(Liquid item : content.liquids()){
|
||||
if(!item.isHidden() && filter.get(item)) list.add(item);
|
||||
}
|
||||
Seq<Liquid> 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<Item> filter){
|
||||
return table -> {
|
||||
Seq<Item> list = content.items().select(filter);
|
||||
Seq<Item> list = content.items().select(i -> filter.get(i) && i.unlockedNow());
|
||||
|
||||
for(int i = 0; i < list.size; i++){
|
||||
Item item = list.get(i);
|
||||
|
||||