Merge branches 'master' and 'mech-rework' of https://github.com/Anuken/Mindustry into mech-rework
# Conflicts: # core/assets/sprites/block_colors.png # core/assets/sprites/sprites.atlas # core/assets/sprites/sprites.png # core/assets/sprites/sprites3.png # core/assets/sprites/sprites5.png # core/src/io/anuke/mindustry/world/blocks/defense/MendProjector.java # gradle.properties
This commit is contained in:
@@ -104,7 +104,7 @@ public abstract class ClientLauncher extends ApplicationCore implements Platform
|
||||
public void resize(int width, int height){
|
||||
if(assets == null) return;
|
||||
|
||||
if(!assets.isFinished()){
|
||||
if(!finished){
|
||||
Draw.proj().setOrtho(0, 0, width, height);
|
||||
}else{
|
||||
super.resize(width, height);
|
||||
|
||||
@@ -31,8 +31,6 @@ import static io.anuke.arc.Core.*;
|
||||
public class Vars implements Loadable{
|
||||
/** Whether to load locales.*/
|
||||
public static boolean loadLocales = true;
|
||||
/** Maximum number of broken blocks. TODO implement or remove.*/
|
||||
public static final int maxBrokenBlocks = 256;
|
||||
/** Maximum schematic size.*/
|
||||
public static final int maxSchematicSize = 32;
|
||||
/** All schematic base64 starts with this string.*/
|
||||
@@ -48,13 +46,15 @@ public class Vars implements Loadable{
|
||||
/** URL for discord invite. */
|
||||
public static final String discordURL = "https://discord.gg/mindustry";
|
||||
/** URL for sending crash reports to */
|
||||
public static final String crashReportURL = "http://mins.us.to/report";
|
||||
public static final String crashReportURL = "http://192.99.169.18/report";
|
||||
/** URL the links to the wiki's modding guide.*/
|
||||
public static final String modGuideURL = "https://mindustrygame.github.io/wiki/modding/";
|
||||
/** URL to the JSON file containing all the global, public servers. */
|
||||
public static final String serverJsonURL = "https://raw.githubusercontent.com/Anuken/Mindustry/master/servers.json";
|
||||
/** URL the links to the wiki's modding guide.*/
|
||||
public static final String reportIssueURL = "https://github.com/Anuken/Mindustry/issues/new?template=bug_report.md";
|
||||
/** list of built-in servers.*/
|
||||
public static final Array<String> defaultServers = Array.with(/*"mins.us.to"*/);
|
||||
public static final Array<String> defaultServers = Array.with();
|
||||
/** maximum distance between mine and core that supports automatic transferring */
|
||||
public static final float mineTransferRange = 220f;
|
||||
/** team of the player by default */
|
||||
|
||||
@@ -19,6 +19,8 @@ import io.anuke.mindustry.world.blocks.*;
|
||||
import io.anuke.mindustry.world.blocks.defense.*;
|
||||
import io.anuke.mindustry.world.blocks.defense.turrets.*;
|
||||
import io.anuke.mindustry.world.blocks.distribution.*;
|
||||
import io.anuke.mindustry.world.blocks.liquid.Conduit;
|
||||
import io.anuke.mindustry.world.blocks.liquid.LiquidTank;
|
||||
import io.anuke.mindustry.world.blocks.logic.*;
|
||||
import io.anuke.mindustry.world.blocks.power.*;
|
||||
import io.anuke.mindustry.world.blocks.production.*;
|
||||
@@ -48,22 +50,22 @@ public class Blocks implements ContentList{
|
||||
melter, separator, sporePress, pulverizer, incinerator, coalCentrifuge,
|
||||
|
||||
//sandbox
|
||||
powerVoid, powerSource, itemSource, liquidSource, itemVoid, message,
|
||||
powerSource, powerVoid, itemSource, itemVoid, liquidSource, message, illuminator,
|
||||
|
||||
//defense
|
||||
scrapWall, scrapWallLarge, scrapWallHuge, scrapWallGigantic, thruster, //ok, these names are getting ridiculous, but at least I don't have humongous walls yet
|
||||
copperWall, copperWallLarge, titaniumWall, titaniumWallLarge, plastaniumWall, plastaniumWallLarge, thoriumWall, thoriumWallLarge, door, doorLarge,
|
||||
phaseWall, phaseWallLarge, surgeWall, surgeWallLarge, mender, mendProjector, overdriveProjector, forceProjector, shockMine,
|
||||
scrapWall, scrapWallLarge, scrapWallHuge, scrapWallGigantic, thruster, //ok, these names are getting ridiculous, but at least I don't have humongous walls yet
|
||||
|
||||
//transport
|
||||
conveyor, titaniumConveyor, armoredConveyor, distributor, junction, itemBridge, phaseConveyor, sorter, invertedSorter, router, overflowGate, massDriver,
|
||||
|
||||
//liquids
|
||||
mechanicalPump, rotaryPump, thermalPump, conduit, pulseConduit, liquidRouter, liquidTank, liquidJunction, bridgeConduit, phaseConduit,
|
||||
mechanicalPump, rotaryPump, thermalPump, conduit, pulseConduit, platedConduit, liquidRouter, liquidTank, liquidJunction, bridgeConduit, phaseConduit,
|
||||
|
||||
//power
|
||||
combustionGenerator, thermalGenerator, turbineGenerator, differentialGenerator, rtgGenerator, solarPanel, largeSolarPanel, thoriumReactor,
|
||||
impactReactor, battery, batteryLarge, powerNode, powerNodeLarge, surgeTower,
|
||||
impactReactor, battery, batteryLarge, powerNode, powerNodeLarge, surgeTower, diode,
|
||||
|
||||
//production
|
||||
mechanicalDrill, pneumaticDrill, laserDrill, blastDrill, waterExtractor, oilExtractor, cultivator,
|
||||
@@ -505,7 +507,7 @@ public class Blocks implements ContentList{
|
||||
|
||||
int bottomRegion = reg("-bottom"), weaveRegion = reg("-weave");
|
||||
|
||||
drawIcons = () -> new TextureRegion[]{Core.atlas.find(name + "-bottom"), Core.atlas.find(name)};
|
||||
drawIcons = () -> new TextureRegion[]{Core.atlas.find(name + "-bottom"), Core.atlas.find(name), Core.atlas.find(name + "-weave")};
|
||||
|
||||
drawer = tile -> {
|
||||
GenericCrafterEntity entity = tile.entity();
|
||||
@@ -537,7 +539,7 @@ public class Blocks implements ContentList{
|
||||
hasPower = true;
|
||||
|
||||
consumes.power(4f);
|
||||
consumes.items(new ItemStack(Items.titanium, 2), new ItemStack(Items.lead, 4), new ItemStack(Items.silicon, 3), new ItemStack(Items.copper, 3));
|
||||
consumes.items(new ItemStack(Items.copper, 3), new ItemStack(Items.lead, 4), new ItemStack(Items.titanium, 2), new ItemStack(Items.silicon, 3));
|
||||
}};
|
||||
|
||||
cryofluidMixer = new LiquidConverter("cryofluidmixer"){{
|
||||
@@ -710,69 +712,11 @@ public class Blocks implements ContentList{
|
||||
consumes.power(0.50f);
|
||||
}};
|
||||
|
||||
//endregion
|
||||
//region sandbox
|
||||
|
||||
powerVoid = new PowerVoid("power-void"){{
|
||||
requirements(Category.power, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
powerSource = new PowerSource("power-source"){{
|
||||
requirements(Category.power, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
itemSource = new ItemSource("item-source"){{
|
||||
requirements(Category.distribution, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
itemVoid = new ItemVoid("item-void"){{
|
||||
requirements(Category.distribution, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
liquidSource = new LiquidSource("liquid-source"){{
|
||||
requirements(Category.liquid, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
message = new MessageBlock("message"){{
|
||||
requirements(Category.effect, ItemStack.with(Items.graphite, 5));
|
||||
}};
|
||||
|
||||
//endregion
|
||||
//region defense
|
||||
|
||||
int wallHealthMultiplier = 4;
|
||||
|
||||
scrapWall = new Wall("scrap-wall"){{
|
||||
requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
health = 60 * wallHealthMultiplier;
|
||||
variants = 5;
|
||||
}};
|
||||
|
||||
scrapWallLarge = new Wall("scrap-wall-large"){{
|
||||
requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
health = 60 * 4 * wallHealthMultiplier;
|
||||
size = 2;
|
||||
variants = 4;
|
||||
}};
|
||||
|
||||
scrapWallHuge = new Wall("scrap-wall-huge"){{
|
||||
requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
health = 60 * 9 * wallHealthMultiplier;
|
||||
size = 3;
|
||||
variants = 3;
|
||||
}};
|
||||
|
||||
scrapWallGigantic = new Wall("scrap-wall-gigantic"){{
|
||||
requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
health = 60 * 16 * wallHealthMultiplier;
|
||||
size = 4;
|
||||
}};
|
||||
|
||||
thruster = new Wall("thruster"){{
|
||||
health = 55 * 16 * wallHealthMultiplier;
|
||||
size = 4;
|
||||
}};
|
||||
|
||||
copperWall = new Wall("copper-wall"){{
|
||||
requirements(Category.defense, ItemStack.with(Items.copper, 6));
|
||||
health = 80 * wallHealthMultiplier;
|
||||
@@ -854,6 +798,37 @@ public class Blocks implements ContentList{
|
||||
size = 2;
|
||||
}};
|
||||
|
||||
scrapWall = new Wall("scrap-wall"){{
|
||||
requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
health = 60 * wallHealthMultiplier;
|
||||
variants = 5;
|
||||
}};
|
||||
|
||||
scrapWallLarge = new Wall("scrap-wall-large"){{
|
||||
requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
health = 60 * 4 * wallHealthMultiplier;
|
||||
size = 2;
|
||||
variants = 4;
|
||||
}};
|
||||
|
||||
scrapWallHuge = new Wall("scrap-wall-huge"){{
|
||||
requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
health = 60 * 9 * wallHealthMultiplier;
|
||||
size = 3;
|
||||
variants = 3;
|
||||
}};
|
||||
|
||||
scrapWallGigantic = new Wall("scrap-wall-gigantic"){{
|
||||
requirements(Category.defense, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
health = 60 * 16 * wallHealthMultiplier;
|
||||
size = 4;
|
||||
}};
|
||||
|
||||
thruster = new Wall("thruster"){{
|
||||
health = 55 * 16 * wallHealthMultiplier;
|
||||
size = 4;
|
||||
}};
|
||||
|
||||
mender = new MendProjector("mender"){{
|
||||
requirements(Category.effect, ItemStack.with(Items.lead, 30, Items.copper, 25));
|
||||
consumes.power(0.3f);
|
||||
@@ -918,7 +893,7 @@ public class Blocks implements ContentList{
|
||||
}};
|
||||
|
||||
armoredConveyor = new ArmoredConveyor("armored-conveyor"){{
|
||||
requirements(Category.distribution, ItemStack.with(Items.metaglass, 1, Items.thorium, 1));
|
||||
requirements(Category.distribution, ItemStack.with(Items.plastanium, 1, Items.thorium, 1, Items.metaglass, 1));
|
||||
health = 180;
|
||||
speed = 0.08f;
|
||||
}};
|
||||
@@ -1002,7 +977,7 @@ public class Blocks implements ContentList{
|
||||
size = 3;
|
||||
}};
|
||||
|
||||
conduit = new Conduit("conduit"){{
|
||||
conduit = new io.anuke.mindustry.world.blocks.liquid.Conduit("conduit"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.metaglass, 1));
|
||||
health = 45;
|
||||
}};
|
||||
@@ -1010,10 +985,18 @@ public class Blocks implements ContentList{
|
||||
pulseConduit = new Conduit("pulse-conduit"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.titanium, 2, Items.metaglass, 1));
|
||||
liquidCapacity = 16f;
|
||||
liquidPressure = 1.025f;
|
||||
health = 90;
|
||||
}};
|
||||
|
||||
liquidRouter = new LiquidRouter("liquid-router"){{
|
||||
platedConduit = new io.anuke.mindustry.world.blocks.liquid.ArmoredConduit("plated-conduit"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.thorium, 2, Items.metaglass, 1));
|
||||
liquidCapacity = 16f;
|
||||
liquidPressure = 1.025f;
|
||||
health = 220;
|
||||
}};
|
||||
|
||||
liquidRouter = new io.anuke.mindustry.world.blocks.liquid.LiquidRouter("liquid-router"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.graphite, 4, Items.metaglass, 2));
|
||||
liquidCapacity = 20f;
|
||||
}};
|
||||
@@ -1025,17 +1008,17 @@ public class Blocks implements ContentList{
|
||||
health = 500;
|
||||
}};
|
||||
|
||||
liquidJunction = new LiquidJunction("liquid-junction"){{
|
||||
liquidJunction = new io.anuke.mindustry.world.blocks.liquid.LiquidJunction("liquid-junction"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.graphite, 2, Items.metaglass, 2));
|
||||
}};
|
||||
|
||||
bridgeConduit = new LiquidExtendingBridge("bridge-conduit"){{
|
||||
bridgeConduit = new io.anuke.mindustry.world.blocks.liquid.LiquidExtendingBridge("bridge-conduit"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.graphite, 4, Items.metaglass, 8));
|
||||
range = 4;
|
||||
hasPower = false;
|
||||
}};
|
||||
|
||||
phaseConduit = new LiquidBridge("phase-conduit"){{
|
||||
phaseConduit = new io.anuke.mindustry.world.blocks.liquid.LiquidBridge("phase-conduit"){{
|
||||
requirements(Category.liquid, ItemStack.with(Items.phasefabric, 5, Items.silicon, 7, Items.metaglass, 20, Items.titanium, 10));
|
||||
range = 12;
|
||||
hasPower = true;
|
||||
@@ -1065,6 +1048,10 @@ public class Blocks implements ContentList{
|
||||
laserRange = 30f;
|
||||
}};
|
||||
|
||||
diode = new PowerDiode("diode"){{
|
||||
requirements(Category.power, ItemStack.with(Items.silicon, 10, Items.plastanium, 5, Items.metaglass, 10));
|
||||
}};
|
||||
|
||||
battery = new Battery("battery"){{
|
||||
requirements(Category.power, ItemStack.with(Items.copper, 4, Items.lead, 20));
|
||||
consumes.powerBuffered(4000f);
|
||||
@@ -1136,7 +1123,7 @@ public class Blocks implements ContentList{
|
||||
powerProduction = 14f;
|
||||
consumes.item(Items.thorium);
|
||||
heating = 0.02f;
|
||||
consumes.liquid(Liquids.cryofluid, 0.1f).update(false);
|
||||
consumes.liquid(Liquids.cryofluid, heating / coolantPower).update(false);
|
||||
}};
|
||||
|
||||
impactReactor = new ImpactReactor("impact-reactor"){{
|
||||
@@ -1817,6 +1804,45 @@ public class Blocks implements ContentList{
|
||||
consumes.power(1.2f);
|
||||
}};
|
||||
|
||||
//endregion
|
||||
//region sandbox
|
||||
|
||||
powerSource = new PowerSource("power-source"){{
|
||||
requirements(Category.power, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
|
||||
powerVoid = new PowerVoid("power-void"){{
|
||||
requirements(Category.power, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
|
||||
itemSource = new ItemSource("item-source"){{
|
||||
requirements(Category.distribution, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
|
||||
itemVoid = new ItemVoid("item-void"){{
|
||||
requirements(Category.distribution, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
|
||||
liquidSource = new LiquidSource("liquid-source"){{
|
||||
requirements(Category.liquid, BuildVisibility.sandboxOnly, ItemStack.with());
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
|
||||
message = new MessageBlock("message"){{
|
||||
requirements(Category.effect, ItemStack.with(Items.graphite, 5));
|
||||
}};
|
||||
|
||||
illuminator = new LightBlock("illuminator"){{
|
||||
requirements(Category.effect, BuildVisibility.lightingOnly, ItemStack.with(Items.graphite, 4, Items.silicon, 2));
|
||||
brightness = 0.67f;
|
||||
radius = 120f;
|
||||
consumes.power(0.05f);
|
||||
}};
|
||||
|
||||
//endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.ui.Cicon;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Fx implements ContentList{
|
||||
public static Effect
|
||||
@@ -463,6 +463,8 @@ public class Fx implements ContentList{
|
||||
});
|
||||
|
||||
Draw.color();
|
||||
|
||||
renderer.lights.add(e.x, e.y, 20f * e.fslope(), Pal.lightFlame, 0.5f);
|
||||
});
|
||||
|
||||
fireSmoke = new Effect(35f, e -> {
|
||||
|
||||
@@ -19,6 +19,7 @@ public class Liquids implements ContentList{
|
||||
temperature = 1f;
|
||||
viscosity = 0.8f;
|
||||
effect = StatusEffects.melting;
|
||||
lightColor = Color.valueOf("f0511d").a(0.4f);
|
||||
}};
|
||||
|
||||
oil = new Liquid("oil", Color.valueOf("313131")){{
|
||||
@@ -34,6 +35,7 @@ public class Liquids implements ContentList{
|
||||
heatCapacity = 0.9f;
|
||||
temperature = 0.25f;
|
||||
effect = StatusEffects.freezing;
|
||||
lightColor = Color.valueOf("0097f5").a(0.2f);
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,6 +199,10 @@ public class TechTree implements ContentList{
|
||||
node(phaseConduit, () -> {
|
||||
|
||||
});
|
||||
|
||||
node(platedConduit, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(rotaryPump, () -> {
|
||||
@@ -215,8 +219,10 @@ public class TechTree implements ContentList{
|
||||
node(combustionGenerator, () -> {
|
||||
node(powerNode, () -> {
|
||||
node(powerNodeLarge, () -> {
|
||||
node(surgeTower, () -> {
|
||||
node(diode, () -> {
|
||||
node(surgeTower, () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -189,7 +189,6 @@ public class Zones implements ContentList{
|
||||
startingItems = list(copper, 250, lead, 100);
|
||||
conditionWave = 15;
|
||||
launchPeriod = 10;
|
||||
requirements = with(new ZoneWave(ruinousShores, 20));
|
||||
resources = with(copper, scrap, lead, coal, titanium, thorium, sand);
|
||||
requirements = with(
|
||||
new ZoneWave(ruinousShores, 20),
|
||||
|
||||
@@ -5,7 +5,7 @@ import io.anuke.arc.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.core.GameState.*;
|
||||
import io.anuke.mindustry.ctype.UnlockableContent;
|
||||
import io.anuke.mindustry.ctype.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
@@ -189,6 +189,7 @@ public class Logic implements ApplicationListener{
|
||||
for(Item item : content.items()){
|
||||
if(tile == null || tile.entity == null || tile.entity.items == null) continue;
|
||||
data.addItem(item, tile.entity.items.get(item));
|
||||
Events.fire(new LaunchItemEvent(item, tile.entity.items.get(item)));
|
||||
}
|
||||
world.removeBlock(tile);
|
||||
}
|
||||
|
||||
@@ -292,7 +292,7 @@ public class NetServer implements ApplicationListener{
|
||||
}
|
||||
|
||||
//cooldown between votes
|
||||
int voteTime = 60 * 5;
|
||||
int voteTime = 60 * 3;
|
||||
Timekeeper vtime = new Timekeeper(voteTime);
|
||||
//current kick sessions
|
||||
VoteSession[] currentlyKicking = {null};
|
||||
@@ -484,7 +484,7 @@ public class NetServer implements ApplicationListener{
|
||||
for(BuildRequest req : requests){
|
||||
if(req == null) continue;
|
||||
Tile tile = world.tile(req.x, req.y);
|
||||
if(tile == null) continue;
|
||||
if(tile == null || (!req.breaking && req.block == null)) continue;
|
||||
//auto-skip done requests
|
||||
if(req.breaking && tile.block() == Blocks.air){
|
||||
continue;
|
||||
|
||||
@@ -32,6 +32,7 @@ public class Renderer implements ApplicationListener{
|
||||
public final BlockRenderer blocks = new BlockRenderer();
|
||||
public final MinimapRenderer minimap = new MinimapRenderer();
|
||||
public final OverlayRenderer overlays = new OverlayRenderer();
|
||||
public final LightRenderer lights = new LightRenderer();
|
||||
public final Pixelator pixelator = new Pixelator();
|
||||
|
||||
public FrameBuffer shieldBuffer = new FrameBuffer(2, 2);
|
||||
@@ -256,6 +257,7 @@ public class Renderer implements ApplicationListener{
|
||||
drawFlyerShadows();
|
||||
|
||||
blocks.drawBlocks(Layer.power);
|
||||
blocks.drawBlocks(Layer.lights);
|
||||
|
||||
drawAllTeams(true);
|
||||
|
||||
@@ -298,6 +300,10 @@ public class Renderer implements ApplicationListener{
|
||||
|
||||
playerGroup.draw(p -> !p.isDead(), Player::drawName);
|
||||
|
||||
if(state.rules.lighting){
|
||||
lights.draw();
|
||||
}
|
||||
|
||||
drawLanding();
|
||||
|
||||
Draw.color();
|
||||
|
||||
@@ -70,6 +70,7 @@ public class UI implements ApplicationListener, Loadable{
|
||||
public MinimapDialog minimap;
|
||||
public SchematicsDialog schematics;
|
||||
public ModsDialog mods;
|
||||
public ColorPicker picker;
|
||||
|
||||
public Cursor drillCursor, unloadCursor;
|
||||
|
||||
@@ -211,6 +212,7 @@ public class UI implements ApplicationListener, Loadable{
|
||||
listfrag = new PlayerListFragment();
|
||||
loadfrag = new LoadingFragment();
|
||||
|
||||
picker = new ColorPicker();
|
||||
editor = new MapEditorDialog();
|
||||
controls = new ControlsDialog();
|
||||
restart = new GameOverDialog();
|
||||
@@ -427,12 +429,15 @@ public class UI implements ApplicationListener, Loadable{
|
||||
}
|
||||
|
||||
|
||||
public void showCustomConfirm(String title, String text, String yes, String no, Runnable confirmed){
|
||||
public void showCustomConfirm(String title, String text, String yes, String no, Runnable confirmed, Runnable denied){
|
||||
FloatingDialog dialog = new FloatingDialog(title);
|
||||
dialog.cont.add(text).width(mobile ? 400f : 500f).wrap().pad(4f).get().setAlignment(Align.center, Align.center);
|
||||
dialog.buttons.defaults().size(200f, 54f).pad(2f);
|
||||
dialog.setFillParent(false);
|
||||
dialog.buttons.addButton(no, dialog::hide);
|
||||
dialog.buttons.addButton(no, () -> {
|
||||
dialog.hide();
|
||||
denied.run();
|
||||
});
|
||||
dialog.buttons.addButton(yes, () -> {
|
||||
dialog.hide();
|
||||
confirmed.run();
|
||||
@@ -456,11 +461,11 @@ public class UI implements ApplicationListener, Loadable{
|
||||
|
||||
public String formatAmount(int number){
|
||||
if(number >= 1000000){
|
||||
return Strings.fixed(number / 1000000f, 1) + "[gray]mil[]";
|
||||
return Strings.fixed(number / 1000000f, 1) + "[gray]" + Core.bundle.getOrNull("unit.millions") + "[]";
|
||||
}else if(number >= 10000){
|
||||
return number / 1000 + "[gray]k[]";
|
||||
}else if(number >= 1000){
|
||||
return Strings.fixed(number / 1000f, 1) + "[gray]k[]";
|
||||
return Strings.fixed(number / 1000f, 1) + "[gray]" + Core.bundle.getOrNull("unit.thousands") + "[]";
|
||||
}else{
|
||||
return number + "";
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import io.anuke.arc.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.ui.Cicon;
|
||||
|
||||
/** Base interface for an unlockable content type. */
|
||||
@@ -25,7 +26,7 @@ public abstract class UnlockableContent extends MappableContent{
|
||||
|
||||
/** Generate any special icons for this content. Called asynchronously.*/
|
||||
@CallSuper
|
||||
public void createIcons(PixmapPacker out, PixmapPacker editor){
|
||||
public void createIcons(MultiPacker packer){
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -103,6 +103,7 @@ public class EditorTile extends Tile{
|
||||
return;
|
||||
}
|
||||
|
||||
if(floor.isLiquid) return;
|
||||
if(overlayID() == overlay) return;
|
||||
op(OpType.overlay, this.overlay.id);
|
||||
super.setOverlayID(overlay);
|
||||
|
||||
@@ -186,7 +186,7 @@ public class WaveInfoDialog extends FloatingDialog{
|
||||
}).width(80f);
|
||||
|
||||
a.add(" + ");
|
||||
a.addField(Strings.fixed(Math.max((Mathf.isZero(group.unitScaling) ? 0 : 1f / group.unitScaling), 0), 2), TextFieldFilter.floatsOnly, text -> {
|
||||
a.addField(Strings.fixed(Math.max((Mathf.zero(group.unitScaling) ? 0 : 1f / group.unitScaling), 0), 2), TextFieldFilter.floatsOnly, text -> {
|
||||
if(Strings.canParsePositiveFloat(text)){
|
||||
group.unitScaling = 1f / Strings.parseFloat(text);
|
||||
updateWaves();
|
||||
@@ -217,21 +217,23 @@ public class WaveInfoDialog extends FloatingDialog{
|
||||
|
||||
void showUpdate(SpawnGroup group){
|
||||
FloatingDialog dialog = new FloatingDialog("");
|
||||
dialog.setFillParent(false);
|
||||
int i = 0;
|
||||
for(UnitType type : content.units()){
|
||||
dialog.cont.addButton(t -> {
|
||||
t.left();
|
||||
t.addImage(type.icon(io.anuke.mindustry.ui.Cicon.medium)).size(40f).padRight(2f);
|
||||
t.add(type.localizedName);
|
||||
}, () -> {
|
||||
lastType = type;
|
||||
group.type = type;
|
||||
dialog.hide();
|
||||
buildGroups();
|
||||
}).pad(2).margin(12f).fillX();
|
||||
if(++i % 3 == 0) dialog.cont.row();
|
||||
}
|
||||
dialog.setFillParent(true);
|
||||
dialog.cont.pane(p -> {
|
||||
int i = 0;
|
||||
for(UnitType type : content.units()){
|
||||
p.addButton(t -> {
|
||||
t.left();
|
||||
t.addImage(type.icon(io.anuke.mindustry.ui.Cicon.medium)).size(40f).padRight(2f);
|
||||
t.add(type.localizedName);
|
||||
}, () -> {
|
||||
lastType = type;
|
||||
group.type = type;
|
||||
dialog.hide();
|
||||
buildGroups();
|
||||
}).pad(2).margin(12f).fillX();
|
||||
if(++i % 3 == 0) p.row();
|
||||
}
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
|
||||
@@ -237,6 +237,12 @@ public class Puddle extends SolidEntity implements SaveTrait, Poolable, DrawTrai
|
||||
seeds++;
|
||||
});
|
||||
Draw.color();
|
||||
|
||||
if(liquid.lightColor.a > 0.001f && f > 0){
|
||||
Color color = liquid.lightColor;
|
||||
float opacity = color.a * f;
|
||||
renderer.lights.add(tile.drawx(), tile.drawy(), 30f * f, color, opacity * 0.8f);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -34,39 +34,38 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
||||
default void updateBuilding(){
|
||||
float finalPlaceDst = state.rules.infiniteResources ? Float.MAX_VALUE : placeDistance;
|
||||
Unit unit = (Unit)this;
|
||||
//remove already completed build requests
|
||||
removal.clear();
|
||||
for(BuildRequest req : buildQueue()){
|
||||
removal.add(req);
|
||||
|
||||
Iterator<BuildRequest> it = buildQueue().iterator();
|
||||
while(it.hasNext()){
|
||||
BuildRequest req = it.next();
|
||||
Tile tile = world.tile(req.x, req.y);
|
||||
if(tile == null || (req.breaking && tile.block() == Blocks.air) || (!req.breaking && (tile.rotation() == req.rotation || !req.block.rotate) && tile.block() == req.block)){
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
|
||||
buildQueue().clear();
|
||||
TileEntity core = unit.getClosestCore();
|
||||
|
||||
for(BuildRequest request : removal){
|
||||
Tile tile = world.tile(request.x, request.y);
|
||||
//nothing to build.
|
||||
if(buildRequest() == null) return;
|
||||
|
||||
if(!(tile == null || (request.breaking && tile.block() == Blocks.air) ||
|
||||
(!request.breaking && (tile.rotation() == request.rotation || !request.block.rotate) && tile.block() == request.block))){
|
||||
buildQueue().addLast(request);
|
||||
//find the next build request
|
||||
if(buildQueue().size > 1){
|
||||
int total = 0;
|
||||
BuildRequest req;
|
||||
while((dst((req = buildRequest()).tile()) > finalPlaceDst || shouldSkip(req, core)) && total < buildQueue().size){
|
||||
buildQueue().removeFirst();
|
||||
buildQueue().addLast(req);
|
||||
total++;
|
||||
}
|
||||
}
|
||||
|
||||
BuildRequest current = buildRequest();
|
||||
|
||||
if(current == null){
|
||||
return;
|
||||
}
|
||||
if(dst(current.tile()) > finalPlaceDst) return;
|
||||
|
||||
Tile tile = world.tile(current.x, current.y);
|
||||
|
||||
if(dst(tile) > finalPlaceDst){
|
||||
if(buildQueue().size > 1){
|
||||
buildQueue().removeFirst();
|
||||
buildQueue().addLast(current);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(tile.block() instanceof BuildBlock)){
|
||||
if(!current.initialized && canCreateBlocks() && !current.breaking && Build.validPlace(getTeam(), current.x, current.y, current.block, current.rotation)){
|
||||
Call.beginPlace(getTeam(), current.x, current.y, current.block, current.rotation);
|
||||
@@ -78,8 +77,6 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
||||
}
|
||||
}
|
||||
|
||||
TileEntity core = unit.getClosestCore();
|
||||
|
||||
if(tile.entity instanceof BuildEntity && !current.initialized){
|
||||
Core.app.post(() -> Events.fire(new BuildSelectEvent(tile, unit.getTeam(), this, current.breaking)));
|
||||
current.initialized = true;
|
||||
@@ -111,9 +108,17 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
||||
}
|
||||
}
|
||||
|
||||
current.stuck = Mathf.equal(current.progress, entity.progress);
|
||||
current.progress = entity.progress;
|
||||
}
|
||||
|
||||
/** @return whether this request should be skipped, in favor of the next one. */
|
||||
default boolean shouldSkip(BuildRequest request, @Nullable TileEntity core){
|
||||
//requests that you have at least *started* are considered
|
||||
if(state.rules.infiniteResources || request.breaking || !request.initialized || core == null) return false;
|
||||
return request.stuck && !core.items.has(request.block.requirements);
|
||||
}
|
||||
|
||||
/** Returns the queue for storing build requests. */
|
||||
Queue<BuildRequest> buildQueue();
|
||||
|
||||
@@ -225,7 +230,6 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
||||
|
||||
//due to iOS weirdness, this is apparently required
|
||||
class BuildDataStatic{
|
||||
static Array<BuildRequest> removal = new Array<>();
|
||||
static Vector2[] tmptr = new Vector2[]{new Vector2(), new Vector2(), new Vector2(), new Vector2()};
|
||||
}
|
||||
|
||||
@@ -287,8 +291,8 @@ public interface BuilderTrait extends Entity, TeamTrait{
|
||||
|
||||
/** Last progress.*/
|
||||
public float progress;
|
||||
/** Whether construction has started for this request.*/
|
||||
public boolean initialized, worldContext = true;
|
||||
/** Whether construction has started for this request, and other special variables.*/
|
||||
public boolean initialized, worldContext = true, stuck;
|
||||
|
||||
/** Visual scale. Used only for rendering.*/
|
||||
public float animScale = 0f;
|
||||
|
||||
@@ -11,6 +11,7 @@ import io.anuke.mindustry.entities.bullet.*;
|
||||
import io.anuke.mindustry.entities.effect.*;
|
||||
import io.anuke.mindustry.entities.traits.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@@ -294,6 +295,7 @@ public class Bullet extends SolidEntity implements DamageTrait, ScaleTrait, Pool
|
||||
@Override
|
||||
public void draw(){
|
||||
type.draw(this);
|
||||
renderer.lights.add(x, y, 16f, Pal.powerLight, 0.3f);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -354,6 +354,7 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{
|
||||
Draw.rect(getPowerCellRegion(), x + Angles.trnsx(rotation, mech.cellTrnsY, 0f), y + Angles.trnsy(rotation, mech.cellTrnsY, 0f), rotation - 90);
|
||||
Draw.reset();
|
||||
drawBackItems(itemtime, isLocal);
|
||||
drawLight();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -14,6 +14,7 @@ import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.game.EventType.BlockDestroyEvent;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.consumers.*;
|
||||
import io.anuke.mindustry.world.modules.*;
|
||||
|
||||
import java.io.*;
|
||||
@@ -86,6 +87,11 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait,
|
||||
return Time.delta() * timeScale;
|
||||
}
|
||||
|
||||
/** Base efficiency. If this entity has non-buffered power, returns the power %, otherwise returns 1. */
|
||||
public float efficiency(){
|
||||
return power != null && (block.consumes.has(ConsumeType.power) && !block.consumes.getPower().buffered) ? power.status : 1f;
|
||||
}
|
||||
|
||||
/** Call when nothing is happening to the entity. This increments the internal sleep timer. */
|
||||
public void sleep(){
|
||||
sleepTime += Time.delta();
|
||||
@@ -305,13 +311,17 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait,
|
||||
loops.play(block.idleSound, this, block.idleSoundVolume);
|
||||
}
|
||||
|
||||
Block previous = block;
|
||||
block.update(tile);
|
||||
if(block == previous && cons != null){
|
||||
|
||||
if(liquids != null){
|
||||
liquids.update();
|
||||
}
|
||||
|
||||
if(cons != null){
|
||||
cons.update();
|
||||
}
|
||||
|
||||
if(block == previous && power != null){
|
||||
if(power != null){
|
||||
power.graph.update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,6 +167,8 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
}
|
||||
|
||||
public void writeSave(DataOutput stream, boolean net) throws IOException{
|
||||
if(item.item == null) item.item = Items.copper;
|
||||
|
||||
stream.writeByte(team.ordinal());
|
||||
stream.writeBoolean(isDead());
|
||||
stream.writeFloat(net ? interpolator.target.x : x);
|
||||
@@ -399,6 +401,12 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
|
||||
Draw.color();
|
||||
|
||||
drawBackItems(item.amount > 0 ? 1f : 0f, false);
|
||||
|
||||
drawLight();
|
||||
}
|
||||
|
||||
public void drawLight(){
|
||||
renderer.lights.add(x, y, 50f, Pal.powerLight, 0.6f);
|
||||
}
|
||||
|
||||
public void drawBackItems(float itemtime, boolean number){
|
||||
|
||||
@@ -27,7 +27,8 @@ public class EventType{
|
||||
drown,
|
||||
exclusionDeath,
|
||||
suicideBomb,
|
||||
openWiki
|
||||
openWiki,
|
||||
teamCoreDamage
|
||||
}
|
||||
|
||||
public static class WinEvent{}
|
||||
@@ -36,6 +37,14 @@ public class EventType{
|
||||
|
||||
public static class LaunchEvent{}
|
||||
|
||||
public static class LaunchItemEvent{
|
||||
public final ItemStack stack;
|
||||
|
||||
public LaunchItemEvent(Item item, int amount){
|
||||
this.stack = new ItemStack(item, amount);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MapMakeEvent{}
|
||||
|
||||
public static class MapPublishEvent{}
|
||||
@@ -137,7 +146,7 @@ public class EventType{
|
||||
public final Player player;
|
||||
public final Item item;
|
||||
public final int amount;
|
||||
|
||||
|
||||
public DepositEvent(Tile tile, Player player, Item item, int amount){
|
||||
this.tile = tile;
|
||||
this.player = player;
|
||||
@@ -145,7 +154,7 @@ public class EventType{
|
||||
this.amount = amount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Called when the player taps a block. */
|
||||
public static class TapEvent{
|
||||
public final Tile tile;
|
||||
@@ -156,7 +165,7 @@ public class EventType{
|
||||
this.player = player;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Called when the player sets a specific block. */
|
||||
public static class TapConfigEvent{
|
||||
public final Tile tile;
|
||||
@@ -309,7 +318,7 @@ public class EventType{
|
||||
/** Called after connecting; when a player recieves world data and is ready to play.*/
|
||||
public static class PlayerJoin{
|
||||
public final Player player;
|
||||
|
||||
|
||||
public PlayerJoin(Player player){
|
||||
this.player = player;
|
||||
}
|
||||
@@ -326,11 +335,45 @@ public class EventType{
|
||||
|
||||
public static class PlayerLeave{
|
||||
public final Player player;
|
||||
|
||||
|
||||
public PlayerLeave(Player player){
|
||||
this.player = player;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class PlayerBanEvent{
|
||||
public final Player player;
|
||||
|
||||
public PlayerBanEvent(Player player){
|
||||
this.player = player;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlayerUnbanEvent{
|
||||
public final Player player;
|
||||
|
||||
public PlayerUnbanEvent(Player player){
|
||||
this.player = player;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlayerIpBanEvent{
|
||||
public final String ip;
|
||||
|
||||
|
||||
public PlayerIpBanEvent(String ip){
|
||||
this.ip = ip;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PlayerIpUnbanEvent{
|
||||
public final String ip;
|
||||
|
||||
|
||||
public PlayerIpUnbanEvent(String ip){
|
||||
this.ip = ip;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ public class LoopControl{
|
||||
data.curVolume = Mathf.lerpDelta(data.curVolume, data.volume * avol, 0.2f);
|
||||
|
||||
boolean play = data.curVolume > 0.01f;
|
||||
float pan = Mathf.isZero(data.total, 0.0001f) ? 0f : sound.calcPan(data.sum.x / data.total, data.sum.y / data.total);
|
||||
float pan = Mathf.zero(data.total, 0.0001f) ? 0f : sound.calcPan(data.sum.x / data.total, data.sum.y / data.total);
|
||||
if(data.soundID <= 0){
|
||||
if(play){
|
||||
data.soundID = sound.loop(data.curVolume, 1f, pan);
|
||||
|
||||
@@ -2,6 +2,7 @@ package io.anuke.mindustry.game;
|
||||
|
||||
import io.anuke.annotations.Annotations.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.io.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
@@ -25,6 +26,8 @@ public class Rules{
|
||||
public boolean pvp;
|
||||
/** Whether enemy units drop random items on death. */
|
||||
public boolean unitDrops = true;
|
||||
/** Whether reactors can explode and damage other blocks. */
|
||||
public boolean reactorExplosions = true;
|
||||
/** How fast unit pads build units. */
|
||||
public float unitBuildSpeedMultiplier = 1f;
|
||||
/** How much health units start with. */
|
||||
@@ -65,12 +68,16 @@ public class Rules{
|
||||
public boolean attackMode = false;
|
||||
/** Whether this is the editor gamemode. */
|
||||
public boolean editor = false;
|
||||
/** Whether the tutorial is enabled. False by default.*/
|
||||
/** Whether the tutorial is enabled. False by default. */
|
||||
public boolean tutorial = false;
|
||||
/** Starting items put in cores */
|
||||
public Array<ItemStack> loadout = Array.with(ItemStack.with(Items.copper, 100));
|
||||
/** Blocks that cannot be placed. */
|
||||
public ObjectSet<Block> bannedBlocks = new ObjectSet<>();
|
||||
/** Whether everything is dark. Enables lights. Experimental. */
|
||||
public boolean lighting = false;
|
||||
/** Ambient light color, used when lighting is enabled. */
|
||||
public Color ambientLight = new Color(0.01f, 0.01f, 0.04f, 0.99f);
|
||||
|
||||
/** Copies this ruleset exactly. Not very efficient at all, do not use often. */
|
||||
public Rules copy(){
|
||||
|
||||
@@ -9,7 +9,7 @@ import io.anuke.mindustry.type.*;
|
||||
@Serialize
|
||||
public class Stats{
|
||||
/** Items delivered to global resoure counter. Zones only. */
|
||||
public transient ObjectIntMap<Item> itemsDelivered = new ObjectIntMap<>();
|
||||
public ObjectIntMap<Item> itemsDelivered = new ObjectIntMap<>();
|
||||
/** Enemy (red team) units destroyed. */
|
||||
public int enemyUnitsDestroyed;
|
||||
/** Total waves lasted. */
|
||||
|
||||
@@ -9,11 +9,11 @@ import io.anuke.arc.graphics.glutils.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.game.Teams.*;
|
||||
import io.anuke.mindustry.ui.Cicon;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
|
||||
import static io.anuke.arc.Core.camera;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
@@ -219,6 +219,10 @@ public class BlockRenderer implements Disposable{
|
||||
addRequest(tile, Layer.block);
|
||||
}
|
||||
|
||||
if(state.rules.lighting && tile.block().synthetic() && !(tile.block() instanceof BlockPart)){
|
||||
addRequest(tile, Layer.lights);
|
||||
}
|
||||
|
||||
if(block.expanded || !expanded){
|
||||
|
||||
if(block.layer != null){
|
||||
@@ -274,6 +278,9 @@ public class BlockRenderer implements Disposable{
|
||||
if(block.synthetic() && request.tile.getTeam() != player.getTeam()){
|
||||
block.drawTeam(request.tile);
|
||||
}
|
||||
|
||||
}else if(request.layer == Layer.lights){
|
||||
block.drawLight(request.tile);
|
||||
}else if(request.layer == block.layer){
|
||||
block.drawLayer(request.tile);
|
||||
}else if(request.layer == block.layer2){
|
||||
@@ -282,39 +289,6 @@ public class BlockRenderer implements Disposable{
|
||||
}
|
||||
}
|
||||
|
||||
public void drawTeamBlocks(Layer layer, Team team){
|
||||
int index = this.iterateidx;
|
||||
|
||||
for(; index < requestidx; index++){
|
||||
|
||||
if(index < requests.size && requests.get(index).layer.ordinal() > layer.ordinal()){
|
||||
break;
|
||||
}
|
||||
|
||||
BlockRequest req = requests.get(index);
|
||||
if(req.tile.getTeam() != team) continue;
|
||||
|
||||
Block block = req.tile.block();
|
||||
|
||||
if(req.layer == Layer.block){
|
||||
block.draw(req.tile);
|
||||
}else if(req.layer == block.layer){
|
||||
block.drawLayer(req.tile);
|
||||
}else if(req.layer == block.layer2){
|
||||
block.drawLayer2(req.tile);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void skipLayer(Layer stopAt){
|
||||
for(; iterateidx < requestidx; iterateidx++){
|
||||
if(iterateidx < requests.size && requests.get(iterateidx).layer.ordinal() > stopAt.ordinal()){
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addRequest(Tile tile, Layer layer){
|
||||
if(requestidx >= requests.size){
|
||||
requests.add(new BlockRequest());
|
||||
|
||||
@@ -6,6 +6,8 @@ import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.util.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.renderer;
|
||||
|
||||
public class Drawf{
|
||||
|
||||
public static void dashCircle(float x, float y, float rad, Color color){
|
||||
@@ -40,15 +42,6 @@ public class Drawf{
|
||||
square(x, y, radius, Pal.accent);
|
||||
}
|
||||
|
||||
/*
|
||||
public static void square(float x, float y, float radius){
|
||||
Lines.stroke(1f, Pal.gray);
|
||||
Lines.square(x, y - 1f, radius + 1f, 45);
|
||||
Lines.stroke(1f, Pal.accent);
|
||||
Lines.square(x, y, radius + 1f, 45);
|
||||
Draw.reset();
|
||||
}*/
|
||||
|
||||
public static void arrow(float x, float y, float x2, float y2, float length, float radius){
|
||||
float angle = Angles.angle(x, y, x2, y2);
|
||||
float space = 2f;
|
||||
@@ -81,6 +74,8 @@ public class Drawf{
|
||||
Lines.line(line, x + Tmp.v1.x, y + Tmp.v1.y, x2 - Tmp.v1.x, y2 - Tmp.v1.y, CapStyle.none, 0f);
|
||||
Lines.precise(false);
|
||||
Lines.stroke(1f);
|
||||
|
||||
renderer.lights.line(x, y, x2, y2);
|
||||
}
|
||||
|
||||
public static void tri(float x, float y, float width, float length, float rotation){
|
||||
|
||||
@@ -10,5 +10,7 @@ public enum Layer{
|
||||
/** "High" blocks, like turrets. */
|
||||
turret,
|
||||
/** Power lasers. */
|
||||
power
|
||||
power,
|
||||
/** Extra layer that's always on top.*/
|
||||
lights
|
||||
}
|
||||
|
||||
199
core/src/io/anuke/mindustry/graphics/LightRenderer.java
Normal file
199
core/src/io/anuke/mindustry/graphics/LightRenderer.java
Normal file
@@ -0,0 +1,199 @@
|
||||
package io.anuke.mindustry.graphics;
|
||||
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.graphics.glutils.*;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.math.geom.*;
|
||||
import io.anuke.arc.util.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.state;
|
||||
|
||||
/** Renders overlay lights. Client only. */
|
||||
public class LightRenderer{
|
||||
private static final int scaling = 4;
|
||||
private float[] vertices = new float[24];
|
||||
private FrameBuffer buffer = new FrameBuffer(2, 2);
|
||||
private Array<Runnable> lights = new Array<>();
|
||||
|
||||
public void add(Runnable run){
|
||||
if(!enabled()) return;
|
||||
|
||||
lights.add(run);
|
||||
}
|
||||
|
||||
public void add(float x, float y, float radius, Color color, float opacity){
|
||||
if(!enabled()) return;
|
||||
|
||||
float res = color.toFloatBits();
|
||||
add(() -> {
|
||||
Draw.color(res);
|
||||
Draw.alpha(opacity);
|
||||
Draw.rect("circle-shadow", x, y, radius * 2, radius * 2);
|
||||
});
|
||||
}
|
||||
|
||||
public void add(float x, float y, TextureRegion region, Color color, float opacity){
|
||||
if(!enabled()) return;
|
||||
|
||||
float res = color.toFloatBits();
|
||||
add(() -> {
|
||||
Draw.color(res);
|
||||
Draw.alpha(opacity);
|
||||
Draw.rect(region, x, y);
|
||||
});
|
||||
}
|
||||
|
||||
public void line(float x, float y, float x2, float y2){
|
||||
if(!enabled()) return;
|
||||
|
||||
add(() -> {
|
||||
Draw.color(Color.orange, 0.3f);
|
||||
|
||||
float stroke = 30f;
|
||||
float rot = Mathf.angleExact(x2 - x, y2 - y);
|
||||
TextureRegion ledge = Core.atlas.find("circle-end"), lmid = Core.atlas.find("circle-mid");
|
||||
|
||||
float color = Draw.getColor().toFloatBits();
|
||||
float u = lmid.getU();
|
||||
float v = lmid.getV2();
|
||||
float u2 = lmid.getU2();
|
||||
float v2 = lmid.getV();
|
||||
|
||||
|
||||
Vector2 v1 = Tmp.v1.trnsExact(rot + 90f, stroke);
|
||||
float lx1 = x - v1.x, ly1 = y - v1.y,
|
||||
lx2 = x + v1.x, ly2 = y + v1.y,
|
||||
lx3 = x2 + v1.x, ly3 = y2 + v1.y,
|
||||
lx4 = x2 - v1.x, ly4 = y2 - v1.y;
|
||||
|
||||
vertices[0] = lx1;
|
||||
vertices[1] = ly1;
|
||||
vertices[2] = color;
|
||||
vertices[3] = u;
|
||||
vertices[4] = v;
|
||||
vertices[5] = 0;
|
||||
|
||||
vertices[6] = lx2;
|
||||
vertices[7] = ly2;
|
||||
vertices[8] = color;
|
||||
vertices[9] = u;
|
||||
vertices[10] = v2;
|
||||
vertices[11] = 0;
|
||||
|
||||
vertices[12] = lx3;
|
||||
vertices[13] = ly3;
|
||||
vertices[14] = color;
|
||||
vertices[15] = u2;
|
||||
vertices[16] = v2;
|
||||
vertices[17] = 0;
|
||||
|
||||
vertices[18] = lx4;
|
||||
vertices[19] = ly4;
|
||||
vertices[20] = color;
|
||||
vertices[21] = u2;
|
||||
vertices[22] = v;
|
||||
vertices[23] = 0;
|
||||
|
||||
Draw.vert(ledge.getTexture(), vertices, 0, vertices.length);
|
||||
|
||||
|
||||
Vector2 v3 = Tmp.v2.trnsExact(rot, stroke);
|
||||
|
||||
u = ledge.getU();
|
||||
v = ledge.getV2();
|
||||
u2 = ledge.getU2();
|
||||
v2 = ledge.getV();
|
||||
|
||||
vertices[0] = lx4;
|
||||
vertices[1] = ly4;
|
||||
vertices[2] = color;
|
||||
vertices[3] = u;
|
||||
vertices[4] = v;
|
||||
vertices[5] = 0;
|
||||
|
||||
vertices[6] = lx3;
|
||||
vertices[7] = ly3;
|
||||
vertices[8] = color;
|
||||
vertices[9] = u;
|
||||
vertices[10] = v2;
|
||||
vertices[11] = 0;
|
||||
|
||||
vertices[12] = lx3 + v3.x;
|
||||
vertices[13] = ly3 + v3.y;
|
||||
vertices[14] = color;
|
||||
vertices[15] = u2;
|
||||
vertices[16] = v2;
|
||||
vertices[17] = 0;
|
||||
|
||||
vertices[18] = lx4 + v3.x;
|
||||
vertices[19] = ly4 + v3.y;
|
||||
vertices[20] = color;
|
||||
vertices[21] = u2;
|
||||
vertices[22] = v;
|
||||
vertices[23] = 0;
|
||||
|
||||
Draw.vert(ledge.getTexture(), vertices, 0, vertices.length);
|
||||
|
||||
vertices[0] = lx2;
|
||||
vertices[1] = ly2;
|
||||
vertices[2] = color;
|
||||
vertices[3] = u;
|
||||
vertices[4] = v;
|
||||
vertices[5] = 0;
|
||||
|
||||
vertices[6] = lx1;
|
||||
vertices[7] = ly1;
|
||||
vertices[8] = color;
|
||||
vertices[9] = u;
|
||||
vertices[10] = v2;
|
||||
vertices[11] = 0;
|
||||
|
||||
vertices[12] = lx1 - v3.x;
|
||||
vertices[13] = ly1 - v3.y;
|
||||
vertices[14] = color;
|
||||
vertices[15] = u2;
|
||||
vertices[16] = v2;
|
||||
vertices[17] = 0;
|
||||
|
||||
vertices[18] = lx2 - v3.x;
|
||||
vertices[19] = ly2 - v3.y;
|
||||
vertices[20] = color;
|
||||
vertices[21] = u2;
|
||||
vertices[22] = v;
|
||||
vertices[23] = 0;
|
||||
|
||||
Draw.vert(ledge.getTexture(), vertices, 0, vertices.length);
|
||||
});
|
||||
}
|
||||
|
||||
public boolean enabled(){
|
||||
return state.rules.lighting;
|
||||
}
|
||||
|
||||
public void draw(){
|
||||
if(buffer.getWidth() != Core.graphics.getWidth()/scaling || buffer.getHeight() != Core.graphics.getHeight()/scaling){
|
||||
buffer.resize(Core.graphics.getWidth()/scaling, Core.graphics.getHeight()/scaling);
|
||||
}
|
||||
|
||||
Draw.color();
|
||||
buffer.beginDraw(Color.clear);
|
||||
Draw.blend(Blending.normal);
|
||||
for(Runnable run : lights){
|
||||
run.run();
|
||||
}
|
||||
Draw.reset();
|
||||
Draw.blend();
|
||||
buffer.endDraw();
|
||||
|
||||
Draw.color();
|
||||
Shaders.light.ambient.set(state.rules.ambientLight);
|
||||
Draw.shader(Shaders.light);
|
||||
Draw.rect(Draw.wrap(buffer.getTexture()), Core.camera.position.x, Core.camera.position.y, Core.camera.width, -Core.camera.height);
|
||||
Draw.shader();
|
||||
|
||||
lights.clear();
|
||||
}
|
||||
}
|
||||
61
core/src/io/anuke/mindustry/graphics/MultiPacker.java
Normal file
61
core/src/io/anuke/mindustry/graphics/MultiPacker.java
Normal file
@@ -0,0 +1,61 @@
|
||||
package io.anuke.mindustry.graphics;
|
||||
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.Pixmap.*;
|
||||
import io.anuke.arc.graphics.Texture.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.util.*;
|
||||
|
||||
public class MultiPacker implements Disposable{
|
||||
private PixmapPacker[] packers = new PixmapPacker[PageType.all.length];
|
||||
|
||||
public MultiPacker(){
|
||||
for(int i = 0; i < packers.length; i++){
|
||||
int pageSize = 2048;
|
||||
packers[i] = new PixmapPacker(pageSize, pageSize, Format.RGBA8888, 2, true);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean has(PageType type, String name){
|
||||
return packers[type.ordinal()].getRect(name) != null;
|
||||
}
|
||||
|
||||
public void add(PageType type, String name, PixmapRegion region){
|
||||
packers[type.ordinal()].pack(name, region);
|
||||
}
|
||||
|
||||
public void add(PageType type, String name, Pixmap pix){
|
||||
packers[type.ordinal()].pack(name, pix);
|
||||
}
|
||||
|
||||
public TextureAtlas flush(TextureFilter filter, TextureAtlas atlas){
|
||||
for(PixmapPacker p : packers){
|
||||
p.updateTextureAtlas(atlas, filter, filter, false, false);
|
||||
}
|
||||
return atlas;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose(){
|
||||
for(PixmapPacker packer : packers){
|
||||
packer.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//There are several pages for sprites.
|
||||
//main page (sprites.png) - all sprites for units, weapons, placeable blocks, effects, bullets, etc
|
||||
//environment page (sprites2.png) - all sprites for things in the environmental cache layer
|
||||
//editor page (sprites3.png) - all sprites needed for rendering in the editor, including block icons and a few minor sprites
|
||||
//zone page (sprites4.png) - zone previews
|
||||
//ui page (sprites5.png) - content icons, white icons and UI elements
|
||||
public enum PageType{
|
||||
main,
|
||||
environment,
|
||||
editor,
|
||||
zone,
|
||||
ui;
|
||||
|
||||
public static final PageType[] all = values();
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ public class OverlayRenderer{
|
||||
if(!rect.setSize(Core.camera.width * 0.9f, Core.camera.height * 0.9f)
|
||||
.setCenter(Core.camera.position.x, Core.camera.position.y).contains(mechpad.x, mechpad.y)){
|
||||
|
||||
Tmp.v1.set(mechpad.worldx(), mechpad.worldy()).sub(Core.camera.position.x, Core.camera.position.y).setLength(indicatorLength);
|
||||
Tmp.v1.set(mechpad.drawx(), mechpad.drawy()).sub(Core.camera.position.x, Core.camera.position.y).setLength(indicatorLength);
|
||||
|
||||
Lines.stroke(2f, ((MechPad) mechpad.block()).mech.engineColor);
|
||||
Lines.lineAngle(Core.camera.position.x + Tmp.v1.x, Core.camera.position.y + Tmp.v1.y, Tmp.v1.angle(), 0.5f);
|
||||
@@ -157,5 +157,4 @@ public class OverlayRenderer{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ public class Shaders{
|
||||
public static UnitBuild build;
|
||||
public static FogShader fog;
|
||||
public static MenuShader menu;
|
||||
public static LightShader light;
|
||||
public static SurfaceShader water, tar;
|
||||
|
||||
public static void init(){
|
||||
@@ -31,10 +32,25 @@ public class Shaders{
|
||||
build = new UnitBuild();
|
||||
fog = new FogShader();
|
||||
menu = new MenuShader();
|
||||
light = new LightShader();
|
||||
water = new SurfaceShader("water");
|
||||
tar = new SurfaceShader("tar");
|
||||
}
|
||||
|
||||
public static class LightShader extends LoadShader{
|
||||
public Color ambient = new Color(0.01f, 0.01f, 0.04f, 0.99f);
|
||||
|
||||
public LightShader(){
|
||||
super("light", "default");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(){
|
||||
setUniformf("u_ambient", ambient);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class MenuShader extends LoadShader{
|
||||
float time = 0f;
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ public enum Binding implements KeyBind{
|
||||
move_x(new Axis(KeyCode.A, KeyCode.D), "general"),
|
||||
move_y(new Axis(KeyCode.S, KeyCode.W)),
|
||||
mouse_move(KeyCode.MOUSE_BACK),
|
||||
dash(KeyCode.SHIFT_LEFT),
|
||||
select(KeyCode.MOUSE_LEFT),
|
||||
deselect(KeyCode.MOUSE_RIGHT),
|
||||
break_block(KeyCode.MOUSE_RIGHT),
|
||||
@@ -23,7 +24,22 @@ public enum Binding implements KeyBind{
|
||||
schematic_flip_x(KeyCode.Z),
|
||||
schematic_flip_y(KeyCode.X),
|
||||
schematic_menu(KeyCode.T),
|
||||
dash(KeyCode.SHIFT_LEFT),
|
||||
category_prev(KeyCode.COMMA),
|
||||
category_next(KeyCode.PERIOD),
|
||||
block_select_left(KeyCode.LEFT),
|
||||
block_select_right(KeyCode.RIGHT),
|
||||
block_select_up(KeyCode.UP),
|
||||
block_select_down(KeyCode.DOWN),
|
||||
block_select_01(KeyCode.NUM_1),
|
||||
block_select_02(KeyCode.NUM_2),
|
||||
block_select_03(KeyCode.NUM_3),
|
||||
block_select_04(KeyCode.NUM_4),
|
||||
block_select_05(KeyCode.NUM_5),
|
||||
block_select_06(KeyCode.NUM_6),
|
||||
block_select_07(KeyCode.NUM_7),
|
||||
block_select_08(KeyCode.NUM_8),
|
||||
block_select_09(KeyCode.NUM_9),
|
||||
block_select_10(KeyCode.NUM_0),
|
||||
zoom_hold(KeyCode.CONTROL_LEFT, "view"),
|
||||
zoom(new Axis(KeyCode.SCROLL)),
|
||||
menu(Core.app.getType() == ApplicationType.Android ? KeyCode.BACK : KeyCode.ESCAPE),
|
||||
|
||||
@@ -50,9 +50,9 @@ public class DesktopInput extends InputHandler{
|
||||
b.defaults().left();
|
||||
b.label(() -> Core.bundle.format(!player.isBuilding ? "resumebuilding" : "pausebuilding", Core.keybinds.get(Binding.pause_building).key.toString())).style(Styles.outlineLabel);
|
||||
b.row();
|
||||
b.add(Core.bundle.format("cancelbuilding", Core.keybinds.get(Binding.clear_building).key.toString())).style(Styles.outlineLabel);
|
||||
b.label(() -> Core.bundle.format("cancelbuilding", Core.keybinds.get(Binding.clear_building).key.toString())).style(Styles.outlineLabel);
|
||||
b.row();
|
||||
b.add(Core.bundle.format("selectschematic", Core.keybinds.get(Binding.schematic_select).key.toString())).style(Styles.outlineLabel);
|
||||
b.label(() -> Core.bundle.format("selectschematic", Core.keybinds.get(Binding.schematic_select).key.toString())).style(Styles.outlineLabel);
|
||||
}).margin(10f);
|
||||
});
|
||||
|
||||
@@ -61,7 +61,7 @@ public class DesktopInput extends InputHandler{
|
||||
t.bottom();
|
||||
t.table(Styles.black6, b -> {
|
||||
b.defaults().left();
|
||||
b.add(Core.bundle.format("schematic.flip",
|
||||
b.label( () -> Core.bundle.format("schematic.flip",
|
||||
Core.keybinds.get(Binding.schematic_flip_x).key.toString(),
|
||||
Core.keybinds.get(Binding.schematic_flip_y).key.toString())).style(Styles.outlineLabel);
|
||||
b.row();
|
||||
|
||||
@@ -455,7 +455,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
}
|
||||
|
||||
protected void drawRequest(BuildRequest request){
|
||||
drawRequest(request.x, request.y, request.block, request.rotation);
|
||||
request.block.drawRequest(request, allRequests(), validPlace(request.x, request.y, request.block, request.rotation));
|
||||
}
|
||||
|
||||
/** Draws a placement icon for a specific block. */
|
||||
|
||||
@@ -4,7 +4,7 @@ import io.anuke.arc.util.serialization.*;
|
||||
import io.anuke.arc.util.serialization.Json.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.MappableContent;
|
||||
import io.anuke.mindustry.ctype.*;
|
||||
import io.anuke.mindustry.game.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
@@ -29,8 +29,20 @@ public class JsonIO{
|
||||
super.writeValue(value, knownType, elementType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String convertToString(Object object){
|
||||
if(object instanceof MappableContent){
|
||||
return ((MappableContent)object).name;
|
||||
}
|
||||
return super.convertToString(object);
|
||||
}
|
||||
};
|
||||
|
||||
public static Json json(){
|
||||
return json;
|
||||
}
|
||||
|
||||
public static String write(Object object){
|
||||
return json.toJson(object, object.getClass());
|
||||
}
|
||||
|
||||
@@ -8,10 +8,12 @@ import io.anuke.arc.collection.IntSet.*;
|
||||
import io.anuke.arc.files.*;
|
||||
import io.anuke.arc.func.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.async.*;
|
||||
import io.anuke.arc.util.io.*;
|
||||
import io.anuke.arc.util.serialization.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.ctype.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
@@ -34,9 +36,30 @@ public class Maps{
|
||||
/** Serializer for meta. */
|
||||
private Json json = new Json();
|
||||
|
||||
private ShuffleMode shuffleMode = ShuffleMode.all;
|
||||
private @Nullable MapProvider shuffler;
|
||||
|
||||
private AsyncExecutor executor = new AsyncExecutor(2);
|
||||
private ObjectSet<Map> previewList = new ObjectSet<>();
|
||||
|
||||
public ShuffleMode getShuffleMode(){
|
||||
return shuffleMode;
|
||||
}
|
||||
|
||||
public void setShuffleMode(ShuffleMode mode){
|
||||
this.shuffleMode = mode;
|
||||
}
|
||||
|
||||
/** Set the provider for the map(s) to be played on. Will override the default shuffle mode setting.*/
|
||||
public void setMapProvider(MapProvider provider){
|
||||
this.shuffler = provider;
|
||||
}
|
||||
|
||||
/** @return the next map to shuffle to. May be null, in which case the server should be stopped. */
|
||||
public @Nullable Map getNextMap(@Nullable Map previous){
|
||||
return shuffler != null ? shuffler.next(previous) : shuffleMode.next(previous);
|
||||
}
|
||||
|
||||
/** Returns a list of all maps, including custom ones. */
|
||||
public Array<Map> all(){
|
||||
return maps;
|
||||
@@ -422,4 +445,37 @@ public class Maps{
|
||||
return map;
|
||||
}
|
||||
|
||||
public interface MapProvider{
|
||||
@Nullable Map next(@Nullable Map previous);
|
||||
}
|
||||
|
||||
public enum ShuffleMode implements MapProvider{
|
||||
none(map -> null),
|
||||
all(prev -> {
|
||||
Array<Map> maps = Array.withArrays(Vars.maps.defaultMaps(), Vars.maps.customMaps());
|
||||
maps.shuffle();
|
||||
return maps.find(m -> m != prev || maps.size == 1);
|
||||
}),
|
||||
custom(prev -> {
|
||||
Array<Map> maps = Array.withArrays(Vars.maps.customMaps().isEmpty() ? Vars.maps.defaultMaps() : Vars.maps.customMaps());
|
||||
maps.shuffle();
|
||||
return maps.find(m -> m != prev || maps.size == 1);
|
||||
}),
|
||||
builtin(prev -> {
|
||||
Array<Map> maps = Array.withArrays(Vars.maps.defaultMaps());
|
||||
maps.shuffle();
|
||||
return maps.find(m -> m != prev || maps.size == 1);
|
||||
});
|
||||
|
||||
private final MapProvider provider;
|
||||
|
||||
ShuffleMode(MapProvider provider){
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map next(@Nullable Map previous){
|
||||
return provider.next(previous);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.anuke.mindustry.mod;
|
||||
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.assets.*;
|
||||
import io.anuke.arc.audio.*;
|
||||
import io.anuke.arc.audio.mock.*;
|
||||
import io.anuke.arc.collection.Array;
|
||||
@@ -10,10 +11,9 @@ import io.anuke.arc.func.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.reflect.Field;
|
||||
import io.anuke.arc.util.reflect.*;
|
||||
import io.anuke.arc.util.serialization.*;
|
||||
import io.anuke.arc.util.serialization.Json.*;
|
||||
import io.anuke.arc.util.serialization.Jval.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.content.TechTree.*;
|
||||
@@ -70,9 +70,9 @@ public class ContentParser{
|
||||
String name = "sounds/" + data.asString();
|
||||
String path = Vars.tree.get(name + ".ogg").exists() && !Vars.ios ? name + ".ogg" : name + ".mp3";
|
||||
ModLoadingSound sound = new ModLoadingSound();
|
||||
Core.assets.load(path, Sound.class).loaded = result -> {
|
||||
sound.sound = (Sound)result;
|
||||
};
|
||||
AssetDescriptor<?> desc = Core.assets.load(path, Sound.class);
|
||||
desc.loaded = result -> sound.sound = (Sound)result;
|
||||
desc.errored = Throwable::printStackTrace;
|
||||
return sound;
|
||||
});
|
||||
put(Objective.class, (type, data) -> {
|
||||
@@ -105,7 +105,7 @@ public class ContentParser{
|
||||
return t;
|
||||
}
|
||||
|
||||
private <T> T internalRead(Class<T> type, Class elementType, JsonValue jsonData, Class keyType){
|
||||
private <T> T internalRead(Class<T> type, Class elementType, JsonValue jsonData, Class keyType){
|
||||
if(type != null){
|
||||
if(classParsers.containsKey(type)){
|
||||
try{
|
||||
@@ -115,6 +115,29 @@ public class ContentParser{
|
||||
}
|
||||
}
|
||||
|
||||
//try to parse "item/amount" syntax
|
||||
try{
|
||||
if(type == ItemStack.class && jsonData.isString() && jsonData.asString().contains("/")){
|
||||
String[] split = jsonData.asString().split("/");
|
||||
|
||||
return (T)fromJson(ItemStack.class, "{item: " + split[0] + ", amount: " + split[1] + "}");
|
||||
}
|
||||
}catch(Throwable ignored){
|
||||
}
|
||||
|
||||
//try to parse "liquid/amount" syntax
|
||||
try{
|
||||
if(jsonData.isString() && jsonData.asString().contains("/")){
|
||||
String[] split = jsonData.asString().split("/");
|
||||
if(type == LiquidStack.class){
|
||||
return (T)fromJson(LiquidStack.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}");
|
||||
}else if(type == ConsumeLiquid.class){
|
||||
return (T)fromJson(ConsumeLiquid.class, "{liquid: " + split[0] + ", amount: " + split[1] + "}");
|
||||
}
|
||||
}
|
||||
}catch(Throwable ignored){
|
||||
}
|
||||
|
||||
if(Content.class.isAssignableFrom(type)){
|
||||
ContentType ctype = contentTypes.getThrow(type, () -> new IllegalArgumentException("No content type for class: " + type.getSimpleName()));
|
||||
String prefix = currentMod != null ? currentMod.name + "-" : "";
|
||||
@@ -151,6 +174,7 @@ public class ContentParser{
|
||||
"io.anuke.mindustry.world.blocks.defense",
|
||||
"io.anuke.mindustry.world.blocks.defense.turrets",
|
||||
"io.anuke.mindustry.world.blocks.distribution",
|
||||
"io.anuke.mindustry.world.blocks.liquid",
|
||||
"io.anuke.mindustry.world.blocks.logic",
|
||||
"io.anuke.mindustry.world.blocks.power",
|
||||
"io.anuke.mindustry.world.blocks.production",
|
||||
@@ -182,7 +206,7 @@ public class ContentParser{
|
||||
}else if(child.name.equals("liquid")){
|
||||
block.consumes.add((Consume)parser.readValue(ConsumeLiquid.class, child));
|
||||
}else if(child.name.equals("power")){
|
||||
if(child.isDouble()){
|
||||
if(child.isNumber()){
|
||||
block.consumes.power(child.asFloat());
|
||||
}else{
|
||||
block.consumes.add((Consume)parser.readValue(ConsumePower.class, child));
|
||||
@@ -205,6 +229,9 @@ public class ContentParser{
|
||||
|
||||
postreads.add(() -> {
|
||||
TechNode parnode = TechTree.all.find(t -> t.block == parent);
|
||||
if(parnode == null){
|
||||
throw new ModLoadException("Block '" + parent.name + "' isn't in the tech tree, but '" + block.name + "' requires it to be researched.", block);
|
||||
}
|
||||
if(!parnode.children.contains(baseNode)){
|
||||
parnode.children.add(baseNode);
|
||||
}
|
||||
@@ -342,10 +369,13 @@ public class ContentParser{
|
||||
init();
|
||||
}
|
||||
|
||||
//add comments starting with //, but ignore links
|
||||
json = json.replace("http://", "http:~~").replace("https://", "https:~~").replaceAll("//.*?\n","\n").replace("http:~~", "http://").replace("https:~~", "https://");
|
||||
//remove extra # characters to make it valid json... apparently some people have *unquoted* # characters in their json
|
||||
if(file.extension().equals("json")){
|
||||
json = json.replace("#", "\\#");
|
||||
}
|
||||
|
||||
JsonValue value = parser.fromJson(null, Jval.read(json).toString(Jformat.plain));
|
||||
|
||||
JsonValue value = parser.fromJson(null, json);
|
||||
if(!parsers.containsKey(type)){
|
||||
throw new SerializationException("No parsers for content type '" + type + "'");
|
||||
}
|
||||
@@ -363,7 +393,7 @@ public class ContentParser{
|
||||
|
||||
private <T> T make(Class<T> type){
|
||||
try{
|
||||
java.lang.reflect.Constructor<T> cons = type.getDeclaredConstructor();
|
||||
Constructor<T> cons = type.getDeclaredConstructor();
|
||||
cons.setAccessible(true);
|
||||
return cons.newInstance();
|
||||
}catch(Exception e){
|
||||
@@ -373,7 +403,7 @@ public class ContentParser{
|
||||
|
||||
private <T> T make(Class<T> type, String name){
|
||||
try{
|
||||
java.lang.reflect.Constructor<T> cons = type.getDeclaredConstructor(String.class);
|
||||
Constructor<T> cons = type.getDeclaredConstructor(String.class);
|
||||
cons.setAccessible(true);
|
||||
return cons.newInstance(name);
|
||||
}catch(Exception e){
|
||||
@@ -383,7 +413,7 @@ public class ContentParser{
|
||||
|
||||
private <T> Prov<T> supply(Class<T> type){
|
||||
try{
|
||||
java.lang.reflect.Constructor<T> cons = type.getDeclaredConstructor();
|
||||
Constructor<T> cons = type.getDeclaredConstructor();
|
||||
return () -> {
|
||||
try{
|
||||
return cons.newInstance();
|
||||
@@ -459,7 +489,7 @@ public class ContentParser{
|
||||
Field field = metadata.field;
|
||||
try{
|
||||
field.set(object, parser.readValue(field.getType(), metadata.elementType, child, metadata.keyType));
|
||||
}catch(ReflectionException ex){
|
||||
}catch(IllegalAccessException ex){
|
||||
throw new SerializationException("Error accessing field: " + field.getName() + " (" + type.getName() + ")", ex);
|
||||
}catch(SerializationException ex){
|
||||
ex.addTrace(field.getName() + " (" + type.getName() + ")");
|
||||
|
||||
@@ -6,7 +6,6 @@ import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.files.*;
|
||||
import io.anuke.arc.func.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.Pixmap.*;
|
||||
import io.anuke.arc.graphics.Texture.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.graphics.g2d.TextureAtlas.*;
|
||||
@@ -14,10 +13,13 @@ import io.anuke.arc.util.ArcAnnotate.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.io.*;
|
||||
import io.anuke.arc.util.serialization.*;
|
||||
import io.anuke.arc.util.serialization.Jval.*;
|
||||
import io.anuke.mindustry.core.*;
|
||||
import io.anuke.mindustry.ctype.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.graphics.MultiPacker.*;
|
||||
import io.anuke.mindustry.plugin.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
|
||||
@@ -33,7 +35,7 @@ public class Mods implements Loadable{
|
||||
private ObjectSet<String> specialFolders = ObjectSet.with("bundles", "sprites");
|
||||
|
||||
private int totalSprites;
|
||||
private PixmapPacker packer;
|
||||
private MultiPacker packer;
|
||||
|
||||
private Array<LoadedMod> loaded = new Array<>();
|
||||
private Array<LoadedMod> disabled = new Array<>();
|
||||
@@ -50,7 +52,7 @@ public class Mods implements Loadable{
|
||||
|
||||
/** @return the loaded mod found by class, or null if not found. */
|
||||
public @Nullable LoadedMod getMod(Class<? extends Mod> type){
|
||||
return loaded.find(l -> l.mod.getClass() == type);
|
||||
return loaded.find(l -> l.mod != null && l.mod.getClass() == type);
|
||||
}
|
||||
|
||||
/** Imports an external mod file.*/
|
||||
@@ -79,68 +81,71 @@ public class Mods implements Loadable{
|
||||
if(loaded.isEmpty()) return;
|
||||
Time.mark();
|
||||
|
||||
packer = new PixmapPacker(2048, 2048, Format.RGBA8888, 2, true);
|
||||
packer = new MultiPacker();
|
||||
|
||||
for(LoadedMod mod : loaded){
|
||||
int[] packed = {0};
|
||||
boolean[] failed = {false};
|
||||
mod.root.child("sprites").walk(file -> {
|
||||
if(failed[0]) return;
|
||||
if(file.extension().equals("png")){
|
||||
try(InputStream stream = file.read()){
|
||||
byte[] bytes = Streams.copyStreamToByteArray(stream, Math.max((int)file.length(), 512));
|
||||
Pixmap pixmap = new Pixmap(bytes, 0, bytes.length);
|
||||
packer.pack(mod.name + "-" + file.nameWithoutExtension(), pixmap);
|
||||
pixmap.dispose();
|
||||
packed[0] ++;
|
||||
totalSprites ++;
|
||||
}catch(IOException e){
|
||||
failed[0] = true;
|
||||
Core.app.post(() -> {
|
||||
Log.err("Error packing images for mod: {0}", mod.meta.name);
|
||||
e.printStackTrace();
|
||||
if(!headless) ui.showException(e);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
Log.info("Packed {0} images for mod '{1}'.", packed[0], mod.meta.name);
|
||||
Array<FileHandle> sprites = mod.root.child("sprites").findAll(f -> f.extension().equals("png"));
|
||||
Array<FileHandle> overrides = mod.root.child("sprites-override").findAll(f -> f.extension().equals("png"));
|
||||
packSprites(sprites, mod, true);
|
||||
packSprites(overrides, mod, false);
|
||||
Log.info("Packed {0} images for mod '{1}'.", sprites.size + overrides.size, mod.meta.name);
|
||||
totalSprites += sprites.size + overrides.size;
|
||||
}
|
||||
|
||||
for(AtlasRegion region : Core.atlas.getRegions()){
|
||||
PageType type = getPage(region);
|
||||
if(!packer.has(type, region.name)){
|
||||
packer.add(type, region.name, Core.atlas.getPixmap(region));
|
||||
}
|
||||
}
|
||||
|
||||
Log.info("Time to pack textures: {0}", Time.elapsed());
|
||||
}
|
||||
|
||||
private void packSprites(Array<FileHandle> sprites, LoadedMod mod, boolean prefix){
|
||||
for(FileHandle file : sprites){
|
||||
try(InputStream stream = file.read()){
|
||||
byte[] bytes = Streams.copyStreamToByteArray(stream, Math.max((int)file.length(), 512));
|
||||
Pixmap pixmap = new Pixmap(bytes, 0, bytes.length);
|
||||
packer.add(getPage(file), (prefix ? mod.name + "-" : "") + file.nameWithoutExtension(), new PixmapRegion(pixmap));
|
||||
pixmap.dispose();
|
||||
}catch(IOException e){
|
||||
Core.app.post(() -> {
|
||||
Log.err("Error packing images for mod: {0}", mod.meta.name);
|
||||
e.printStackTrace();
|
||||
if(!headless) ui.showException(e);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
totalSprites += sprites.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSync(){
|
||||
if(packer == null) return;
|
||||
Time.mark();
|
||||
|
||||
Texture editor = Core.atlas.find("clear-editor").getTexture();
|
||||
PixmapPacker editorPacker = new PixmapPacker(2048, 2048, Format.RGBA8888, 2, true);
|
||||
|
||||
for(AtlasRegion region : Core.atlas.getRegions()){
|
||||
if(region.getTexture() == editor){
|
||||
editorPacker.pack(region.name, Core.atlas.getPixmap(region).crop());
|
||||
}
|
||||
}
|
||||
|
||||
//get textures packed
|
||||
if(totalSprites > 0){
|
||||
TextureFilter filter = Core.settings.getBool("linear") ? TextureFilter.Linear : TextureFilter.Nearest;
|
||||
|
||||
packer.updateTextureAtlas(Core.atlas, filter, filter, false);
|
||||
//flush so generators can use these sprites
|
||||
packer.flush(filter, Core.atlas);
|
||||
|
||||
//generate new icons
|
||||
for(Array<Content> arr : content.getContentMap()){
|
||||
arr.each(c -> {
|
||||
if(c instanceof UnlockableContent && c.mod != null){
|
||||
UnlockableContent u = (UnlockableContent)c;
|
||||
u.createIcons(packer, editorPacker);
|
||||
u.createIcons(packer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
editorPacker.updateTextureAtlas(Core.atlas, filter, filter, false);
|
||||
packer.updateTextureAtlas(Core.atlas, filter, filter, false);
|
||||
Core.atlas = packer.flush(filter, new TextureAtlas());
|
||||
Core.atlas.setErrorRegion("error");
|
||||
Log.info("Total pages: {0}", Core.atlas.getTextures().size);
|
||||
}
|
||||
|
||||
packer.dispose();
|
||||
@@ -148,6 +153,26 @@ public class Mods implements Loadable{
|
||||
Log.info("Time to update textures: {0}", Time.elapsed());
|
||||
}
|
||||
|
||||
private PageType getPage(AtlasRegion region){
|
||||
return
|
||||
region.getTexture() == Core.atlas.find("white").getTexture() ? PageType.main :
|
||||
region.getTexture() == Core.atlas.find("stone1").getTexture() ? PageType.environment :
|
||||
region.getTexture() == Core.atlas.find("clear-editor").getTexture() ? PageType.editor :
|
||||
region.getTexture() == Core.atlas.find("zone-groundZero").getTexture() ? PageType.zone :
|
||||
region.getTexture() == Core.atlas.find("whiteui").getTexture() ? PageType.ui :
|
||||
PageType.main;
|
||||
}
|
||||
|
||||
private PageType getPage(FileHandle file){
|
||||
String parent = file.parent().name();
|
||||
return
|
||||
parent.equals("environment") ? PageType.environment :
|
||||
parent.equals("editor") ? PageType.editor :
|
||||
parent.equals("zones") ? PageType.zone :
|
||||
parent.equals("ui") || file.parent().parent().name().equals("ui") ? PageType.ui :
|
||||
PageType.main;
|
||||
}
|
||||
|
||||
/** Removes a mod file and marks it for requiring a restart. */
|
||||
public void removeMod(LoadedMod mod){
|
||||
if(mod.root instanceof ZipFileHandle){
|
||||
@@ -172,8 +197,7 @@ public class Mods implements Loadable{
|
||||
/** Loads all mods from the folder, but does not call any methods on them.*/
|
||||
public void load(){
|
||||
for(FileHandle file : modDirectory.list()){
|
||||
if(!file.extension().equals("jar") && !file.extension().equals("zip") && !(file.isDirectory() && file.child("mod.json").exists())) continue;
|
||||
|
||||
if(!file.extension().equals("jar") && !file.extension().equals("zip") && !(file.isDirectory() && (file.child("mod.json").exists() || file.child("mod.hjson").exists()))) continue;
|
||||
|
||||
Log.debug("[Mods] Loading mod {0}", file);
|
||||
try{
|
||||
@@ -206,6 +230,7 @@ public class Mods implements Loadable{
|
||||
}
|
||||
|
||||
resolveDependencies();
|
||||
|
||||
//sort mods to make sure servers handle them properly.
|
||||
loaded.sort(Structs.comparing(m -> m.name));
|
||||
|
||||
@@ -213,6 +238,10 @@ public class Mods implements Loadable{
|
||||
}
|
||||
|
||||
private void resolveDependencies(){
|
||||
Array<LoadedMod> incompatible = loaded.select(m -> !m.isSupported());
|
||||
loaded.removeAll(incompatible);
|
||||
disabled.addAll(incompatible);
|
||||
|
||||
for(LoadedMod mod : Array.<LoadedMod>withArrays(loaded, disabled)){
|
||||
updateDependencies(mod);
|
||||
}
|
||||
@@ -354,7 +383,7 @@ public class Mods implements Loadable{
|
||||
FileHandle folder = contentRoot.child(type.name().toLowerCase() + "s");
|
||||
if(folder.exists()){
|
||||
for(FileHandle file : folder.list()){
|
||||
if(file.extension().equals("json")){
|
||||
if(file.extension().equals("json") || file.extension().equals("hjson")){
|
||||
runs.add(new LoadRun(type, file, mod));
|
||||
}
|
||||
}
|
||||
@@ -482,13 +511,13 @@ public class Mods implements Loadable{
|
||||
zip = zip.list()[0];
|
||||
}
|
||||
|
||||
FileHandle metaf = zip.child("mod.json").exists() ? zip.child("mod.json") : zip.child("plugin.json");
|
||||
FileHandle metaf = zip.child("mod.json").exists() ? zip.child("mod.json") : zip.child("mod.hjson").exists() ? zip.child("mod.hjson") : zip.child("plugin.json");
|
||||
if(!metaf.exists()){
|
||||
Log.warn("Mod {0} doesn't have a 'mod.json'/'plugin.json' file, skipping.", sourceFile);
|
||||
Log.warn("Mod {0} doesn't have a 'mod.json'/'plugin.json'/'mod.js' file, skipping.", sourceFile);
|
||||
throw new IllegalArgumentException("No mod.json found.");
|
||||
}
|
||||
|
||||
ModMeta meta = json.fromJson(ModMeta.class, metaf.readString());
|
||||
ModMeta meta = json.fromJson(ModMeta.class, Jval.read(metaf.readString()).toString(Jformat.plain));
|
||||
String camelized = meta.name.replace(" ", "");
|
||||
String mainClass = meta.main == null ? camelized.toLowerCase() + "." + camelized + "Mod" : meta.main;
|
||||
String baseName = meta.name.toLowerCase().replace(" ", "-");
|
||||
@@ -563,6 +592,18 @@ public class Mods implements Loadable{
|
||||
return !missingDependencies.isEmpty();
|
||||
}
|
||||
|
||||
/** @return whether this mod is supported by the game verison */
|
||||
public boolean isSupported(){
|
||||
if(Version.build <= 0 || meta.minGameVersion == null) return true;
|
||||
if(meta.minGameVersion.contains(".")){
|
||||
String[] split = meta.minGameVersion.split("\\.");
|
||||
if(split.length == 2){
|
||||
return Version.build >= Strings.parseInt(split[0], 0) && Version.revision >= Strings.parseInt(split[1], 0);
|
||||
}
|
||||
}
|
||||
return Version.build >= Strings.parseInt(meta.minGameVersion, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSteamID(){
|
||||
return Core.settings.getString(name + "-steamid", null);
|
||||
@@ -632,7 +673,7 @@ public class Mods implements Loadable{
|
||||
|
||||
/** Plugin metadata information.*/
|
||||
public static class ModMeta{
|
||||
public String name, author, description, version, main;
|
||||
public String name, author, description, version, main, minGameVersion;
|
||||
public Array<String> dependencies = Array.with();
|
||||
/** Hidden mods are only server-side or client-side, and do not support adding new content. */
|
||||
public boolean hidden;
|
||||
@@ -662,5 +703,13 @@ public class Mods implements Loadable{
|
||||
this.mod = content.mod;
|
||||
}
|
||||
}
|
||||
|
||||
public ModLoadException(String message, @Nullable Content content){
|
||||
super(message);
|
||||
this.content = content;
|
||||
if(content != null){
|
||||
this.mod = content.mod;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,11 @@ package io.anuke.mindustry.net;
|
||||
import io.anuke.annotations.Annotations.*;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.mindustry.Vars;
|
||||
|
||||
|
||||
import static io.anuke.mindustry.Vars.headless;
|
||||
import static io.anuke.mindustry.game.EventType.*;
|
||||
|
||||
public class Administration{
|
||||
/** All player info. Maps UUIDs to info. This persists throughout restarts. */
|
||||
@@ -76,7 +79,7 @@ public class Administration{
|
||||
|
||||
bannedIPs.add(ip);
|
||||
save();
|
||||
|
||||
Events.fire(new PlayerIpBanEvent(ip));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -88,7 +91,7 @@ public class Administration{
|
||||
getCreateInfo(id).banned = true;
|
||||
|
||||
save();
|
||||
|
||||
Events.fire(new PlayerBanEvent(Vars.playerGroup.find(p -> id.equals(p.uuid))));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -108,8 +111,10 @@ public class Administration{
|
||||
|
||||
bannedIPs.removeValue(ip, false);
|
||||
|
||||
if(found) save();
|
||||
|
||||
if(found){
|
||||
save();
|
||||
Events.fire(new PlayerIpUnbanEvent(ip));
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -126,7 +131,7 @@ public class Administration{
|
||||
info.banned = false;
|
||||
bannedIPs.removeAll(info.ips, false);
|
||||
save();
|
||||
|
||||
Events.fire(new PlayerUnbanEvent(Vars.playerGroup.find(p -> id.equals(p.uuid))));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ public class Packets{
|
||||
buffer.put(mobile ? (byte)1 : 0);
|
||||
buffer.putInt(color);
|
||||
buffer.put(Base64Coder.decode(uuid));
|
||||
buffer.putInt(mods.size);
|
||||
buffer.put((byte)mods.size);
|
||||
for(int i = 0; i < mods.size; i++){
|
||||
TypeIO.writeString(buffer, mods.get(i));
|
||||
}
|
||||
@@ -97,7 +97,7 @@ public class Packets{
|
||||
byte[] idbytes = new byte[8];
|
||||
buffer.get(idbytes);
|
||||
uuid = new String(Base64Coder.encode(idbytes));
|
||||
int totalMods = buffer.getInt();
|
||||
int totalMods = buffer.get();
|
||||
mods = new Array<>(totalMods);
|
||||
for(int i = 0; i < totalMods; i++){
|
||||
mods.add(TypeIO.readString(buffer));
|
||||
|
||||
@@ -23,4 +23,12 @@ public enum Category{
|
||||
effect;
|
||||
|
||||
public static final Category[] all = values();
|
||||
|
||||
public Category prev(){
|
||||
return all[(this.ordinal() - 1 + all.length) % all.length];
|
||||
}
|
||||
|
||||
public Category next(){
|
||||
return all[(this.ordinal() + 1) % all.length];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ public class Liquid extends UnlockableContent{
|
||||
|
||||
/** Color used in bars. */
|
||||
public @Nullable Color barColor;
|
||||
/** Color used to draw lights. Note that the alpha channel is used to dictate brightness. */
|
||||
public Color lightColor = Color.clear.cpy();
|
||||
/** 0-1, 0 is completely inflammable, anything above that may catch fire when exposed to heat, 0.5+ is very flammable. */
|
||||
public float flammability;
|
||||
/** temperature: 0.5 is 'room' temperature, 0 is very cold, 1 is molten hot */
|
||||
|
||||
@@ -63,7 +63,7 @@ public class Bar extends Element{
|
||||
if(fraction == null) return;
|
||||
|
||||
float computed = Mathf.clamp(fraction.get());
|
||||
if(!Mathf.isEqual(lastValue, computed)){
|
||||
if(!Mathf.equal(lastValue, computed)){
|
||||
blink = 1f;
|
||||
lastValue = computed;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,9 @@ public class ContentDisplay{
|
||||
|
||||
table.left().defaults().fillX();
|
||||
|
||||
table.add(Core.bundle.format("item.corestorable", item.type == ItemType.material ? Core.bundle.format("yes") : Core.bundle.format("no")));
|
||||
table.row();
|
||||
|
||||
table.add(Core.bundle.format("item.explosiveness", (int)(item.explosiveness * 100)));
|
||||
table.row();
|
||||
table.add(Core.bundle.format("item.flammability", (int)(item.flammability * 100)));
|
||||
|
||||
@@ -17,6 +17,7 @@ public class Links{
|
||||
new LinkEntry("reddit", "https://www.reddit.com/r/Mindustry/", Color.valueOf("ee593b")),
|
||||
new LinkEntry("itch.io", "https://anuke.itch.io/mindustry", Color.valueOf("fa5c5c")),
|
||||
new LinkEntry("google-play", "https://play.google.com/store/apps/details?id=io.anuke.mindustry", Color.valueOf("689f38")),
|
||||
new LinkEntry("f-droid", "https://f-droid.org/packages/io.anuke.mindustry/", Color.valueOf("026aa7")),
|
||||
new LinkEntry("github", "https://github.com/Anuken/Mindustry/", Color.valueOf("24292e")),
|
||||
new LinkEntry("dev-builds", "https://github.com/Anuken/MindustryBuilds", Color.valueOf("fafbfc"))
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class AboutDialog extends FloatingDialog{
|
||||
private Array<String> contributors = new Array<>();
|
||||
private static ObjectSet<String> bannedItems = ObjectSet.with("google-play", "itch.io", "dev-builds");
|
||||
private static ObjectSet<String> bannedItems = ObjectSet.with("google-play", "itch.io", "dev-builds", "f-droid");
|
||||
|
||||
public AboutDialog(){
|
||||
super("$about.button");
|
||||
|
||||
63
core/src/io/anuke/mindustry/ui/dialogs/ColorPicker.java
Normal file
63
core/src/io/anuke/mindustry/ui/dialogs/ColorPicker.java
Normal file
@@ -0,0 +1,63 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.func.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
|
||||
public class ColorPicker extends FloatingDialog{
|
||||
private Cons<Color> cons = c -> {};
|
||||
private Color current = new Color();
|
||||
|
||||
public ColorPicker(){
|
||||
super("$pickcolor");
|
||||
}
|
||||
|
||||
public void show(Color color, Cons<Color> consumer){
|
||||
show(color, true, consumer);
|
||||
}
|
||||
|
||||
public void show(Color color, boolean alpha, Cons<Color> consumer){
|
||||
this.current.set(color);
|
||||
this.cons = consumer;
|
||||
show();
|
||||
|
||||
cont.clear();
|
||||
cont.pane(t -> {
|
||||
t.table(Tex.pane, i -> {
|
||||
i.stack(new Image(Tex.alphaBg), new Image(){{
|
||||
setColor(current);
|
||||
update(() -> setColor(current));
|
||||
}}).size(200f);
|
||||
}).colspan(2).padBottom(5);
|
||||
|
||||
float w = 150f;
|
||||
|
||||
t.row();
|
||||
|
||||
t.defaults().padBottom(4);
|
||||
t.add("R").color(Pal.remove);
|
||||
t.addSlider(0f, 1f, 0.01f, current.r, current::r).width(w);
|
||||
t.row();
|
||||
t.add("G").color(Color.lime);
|
||||
t.addSlider(0f, 1f, 0.01f, current.g, current::g).width(w);
|
||||
t.row();
|
||||
t.add("B").color(Color.royal);
|
||||
t.addSlider(0f, 1f, 0.01f, current.b, current::b).width(w);
|
||||
t.row();
|
||||
if(alpha){
|
||||
t.add("A");
|
||||
t.addSlider(0f, 1f, 0.01f, current.a, current::a).width(w);
|
||||
t.row();
|
||||
}
|
||||
});
|
||||
|
||||
buttons.clear();
|
||||
addCloseButton();
|
||||
buttons.addImageTextButton("$ok", Icon.checkSmall, () -> {
|
||||
cons.get(current);
|
||||
hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -116,7 +116,7 @@ public class CustomRulesDialog extends FloatingDialog{
|
||||
|
||||
void setup(){
|
||||
cont.clear();
|
||||
cont.pane(m -> main = m);
|
||||
cont.pane(m -> main = m).get().setScrollingDisabled(true, false);
|
||||
main.margin(10f);
|
||||
main.addButton("$settings.reset", () -> {
|
||||
rules = resetter.get();
|
||||
@@ -135,13 +135,11 @@ public class CustomRulesDialog extends FloatingDialog{
|
||||
number("$rules.dropzoneradius", false, f -> rules.dropZoneRadius = f * tilesize, () -> rules.dropZoneRadius / tilesize, () -> true);
|
||||
|
||||
title("$rules.title.respawns");
|
||||
//limited respawns don't work on PvP, commented out until they're fixed
|
||||
//check("$rules.limitedRespawns", b -> rules.limitedRespawns = b, () -> rules.limitedRespawns);
|
||||
//number("$rules.respawns", true, f -> rules.respawns = (int)f, () -> rules.respawns, () -> rules.limitedRespawns);
|
||||
number("$rules.respawntime", f -> rules.respawnTime = f * 60f, () -> rules.respawnTime / 60f);
|
||||
|
||||
title("$rules.title.resourcesbuilding");
|
||||
check("$rules.infiniteresources", b -> rules.infiniteResources = b, () -> rules.infiniteResources);
|
||||
check("$rules.reactorexplosions", b -> rules.reactorExplosions = b, () -> rules.reactorExplosions);
|
||||
number("$rules.buildcostmultiplier", false, f -> rules.buildCostMultiplier = f, () -> rules.buildCostMultiplier, () -> !rules.infiniteResources);
|
||||
number("$rules.buildspeedmultiplier", f -> rules.buildSpeedMultiplier = f, () -> rules.buildSpeedMultiplier);
|
||||
|
||||
@@ -171,6 +169,20 @@ public class CustomRulesDialog extends FloatingDialog{
|
||||
check("$rules.attack", b -> rules.attackMode = b, () -> rules.attackMode);
|
||||
check("$rules.enemyCheat", b -> rules.enemyCheat = b, () -> rules.enemyCheat);
|
||||
number("$rules.enemycorebuildradius", f -> rules.enemyCoreBuildRadius = f * tilesize, () -> Math.min(rules.enemyCoreBuildRadius / tilesize, 200));
|
||||
|
||||
title("$rules.title.experimental");
|
||||
check("$rules.lighting", b -> rules.lighting = b, () -> rules.lighting);
|
||||
|
||||
main.addButton(b -> {
|
||||
b.left();
|
||||
b.table(Tex.pane, in -> {
|
||||
in.stack(new Image(Tex.alphaBg), new Image(Tex.whiteui){{
|
||||
update(() -> setColor(rules.ambientLight));
|
||||
}}).grow();
|
||||
}).margin(4).size(50f).padRight(10);
|
||||
b.add("$rules.ambientlight");
|
||||
}, () -> ui.picker.show(rules.ambientLight, rules.ambientLight::set)).left().width(250f);
|
||||
main.row();
|
||||
}
|
||||
|
||||
void number(String text, Floatc cons, Floatp prov){
|
||||
@@ -200,7 +212,9 @@ public class CustomRulesDialog extends FloatingDialog{
|
||||
}
|
||||
|
||||
void title(String text){
|
||||
main.add(text).color(Pal.accent).padTop(20).padBottom(20).padRight(100f);
|
||||
main.add(text).color(Pal.accent).padTop(20).padRight(100f).padBottom(-3);
|
||||
main.row();
|
||||
main.addImage().color(Pal.accent).height(3f).padRight(100f).padBottom(20);
|
||||
main.row();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public class HostDialog extends FloatingDialog{
|
||||
}).grow().pad(8).get().setMaxLength(40);
|
||||
|
||||
ImageButton button = t.addImageButton(Tex.whiteui, Styles.clearFulli, 40, () -> {
|
||||
new ColorPickDialog().show(color -> {
|
||||
new PaletteDialog().show(color -> {
|
||||
player.color.set(color);
|
||||
Core.settings.put("color-0", Color.rgba8888(color));
|
||||
Core.settings.save();
|
||||
@@ -74,6 +74,9 @@ public class HostDialog extends FloatingDialog{
|
||||
ui.showCustomConfirm("$setting.publichost.name", "$public.confirm", "$yes", "$no", () -> {
|
||||
Core.settings.putSave("publichost", true);
|
||||
platform.updateLobby();
|
||||
}, () -> {
|
||||
Core.settings.putSave("publichost", false);
|
||||
platform.updateLobby();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.serialization.*;
|
||||
import io.anuke.mindustry.*;
|
||||
import io.anuke.mindustry.core.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
@@ -32,14 +33,14 @@ public class JoinDialog extends FloatingDialog{
|
||||
|
||||
loadServers();
|
||||
|
||||
buttons.add().width(60f);
|
||||
buttons.add().growX();
|
||||
if(!steam) buttons.add().width(60f);
|
||||
buttons.add().growX().width(-1);
|
||||
|
||||
addCloseButton();
|
||||
|
||||
buttons.add().growX();
|
||||
buttons.add().growX().width(-1);
|
||||
if(!steam){
|
||||
buttons.addButton("?", () -> ui.showInfo("$join.info")).size(60f, 64f);
|
||||
buttons.addButton("?", () -> ui.showInfo("$join.info")).size(60f, 64f).width(-1);
|
||||
}
|
||||
|
||||
add = new FloatingDialog("$joingame.title");
|
||||
@@ -247,7 +248,7 @@ public class JoinDialog extends FloatingDialog{
|
||||
}
|
||||
|
||||
ImageButton button = t.addImageButton(Tex.whiteui, Styles.clearFulli, 40, () -> {
|
||||
new ColorPickDialog().show(color -> {
|
||||
new PaletteDialog().show(color -> {
|
||||
player.color.set(color);
|
||||
Core.settings.put("color-0", Color.rgba8888(color));
|
||||
Core.settings.save();
|
||||
@@ -271,7 +272,7 @@ public class JoinDialog extends FloatingDialog{
|
||||
|
||||
Cell cell = ((Table)pane.getParent()).getCell(button);
|
||||
|
||||
if(!Mathf.isEqual(cell.minWidth(), pw)){
|
||||
if(!Mathf.equal(cell.minWidth(), pw)){
|
||||
cell.width(pw);
|
||||
cell.padLeft(pad);
|
||||
pane.getParent().invalidateHierarchy();
|
||||
@@ -359,6 +360,20 @@ public class JoinDialog extends FloatingDialog{
|
||||
@SuppressWarnings("unchecked")
|
||||
private void loadServers(){
|
||||
servers = Core.settings.getObject("server-list", Array.class, Array::new);
|
||||
|
||||
//get servers
|
||||
Core.net.httpGet(serverJsonURL, result -> {
|
||||
try{
|
||||
Jval val = Jval.read(result.getResultAsString());
|
||||
Core.app.post(() -> {
|
||||
try{
|
||||
defaultServers.clear();
|
||||
val.asArray().each(child -> defaultServers.add(child.getString("address", "<invalid>")));
|
||||
Log.info("Fetched {0} global servers.", defaultServers.size);
|
||||
}catch(Throwable ignored){}
|
||||
});
|
||||
}catch(Throwable ignored){}
|
||||
}, t -> {});
|
||||
}
|
||||
|
||||
private void saveServers(){
|
||||
|
||||
@@ -132,7 +132,7 @@ public class ModsDialog extends FloatingDialog{
|
||||
title.addImageTextButton(mod.enabled() ? "$mod.disable" : "$mod.enable", mod.enabled() ? Icon.arrowDownSmall : Icon.arrowUpSmall, Styles.cleart, () -> {
|
||||
mods.setEnabled(mod, !mod.enabled());
|
||||
setup();
|
||||
}).height(50f).margin(8f).width(130f);
|
||||
}).height(50f).margin(8f).width(130f).disabled(!mod.isSupported());
|
||||
|
||||
if(steam && !mod.hasSteamID()){
|
||||
title.addImageButton(Icon.loadMapSmall, Styles.cleari, () -> {
|
||||
@@ -161,7 +161,10 @@ public class ModsDialog extends FloatingDialog{
|
||||
t.labelWrap("[lightgray]" + mod.meta.description).growX();
|
||||
t.row();
|
||||
}
|
||||
if(mod.hasUnmetDependencies()){
|
||||
if(!mod.isSupported()){
|
||||
t.labelWrap(Core.bundle.format("mod.requiresversion", mod.meta.minGameVersion)).growX();
|
||||
t.row();
|
||||
}else if(mod.hasUnmetDependencies()){
|
||||
t.labelWrap(Core.bundle.format("mod.missingdependencies", mod.missingDependencies.toString(", "))).growX();
|
||||
t.row();
|
||||
}
|
||||
|
||||
@@ -10,10 +10,10 @@ import io.anuke.mindustry.ui.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class ColorPickDialog extends Dialog{
|
||||
public class PaletteDialog extends Dialog{
|
||||
private Cons<Color> cons;
|
||||
|
||||
public ColorPickDialog(){
|
||||
public PaletteDialog(){
|
||||
super("");
|
||||
build();
|
||||
}
|
||||
@@ -62,12 +62,12 @@ public class SchematicsDialog extends FloatingDialog{
|
||||
t.clear();
|
||||
int i = 0;
|
||||
|
||||
if(!schematics.all().contains(s -> search.isEmpty() || s.name().contains(search))){
|
||||
if(!schematics.all().contains(s -> search.isEmpty() || s.name().toLowerCase().contains(search.toLowerCase()))){
|
||||
t.add("$none");
|
||||
}
|
||||
|
||||
for(Schematic s : schematics.all()){
|
||||
if(!search.isEmpty() && !s.name().contains(search)) continue;
|
||||
if(!search.isEmpty() && !s.name().toLowerCase().contains(search.toLowerCase())) continue;
|
||||
|
||||
Button[] sel = {null};
|
||||
sel[0] = t.addButton(b -> {
|
||||
|
||||
@@ -218,9 +218,11 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
control.setInput(new MobileInput());
|
||||
}
|
||||
}*/
|
||||
game.sliderPref("saveinterval", 60, 10, 5 * 120, i -> Core.bundle.format("setting.seconds", i));
|
||||
game.sliderPref("saveinterval", 60, 10, 5 * 120, 10, i -> Core.bundle.format("setting.seconds", i));
|
||||
|
||||
if(!mobile){
|
||||
game.sliderPref("blockselecttimeout", 750, 0, 2000, 50, i -> Core.bundle.format("setting.milliseconds", i));
|
||||
|
||||
game.checkPref("crashreport", true);
|
||||
}
|
||||
|
||||
@@ -251,7 +253,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
}
|
||||
});
|
||||
|
||||
graphics.sliderPref("uiscale", 100, 25, 400, 5, s -> {
|
||||
graphics.sliderPref("uiscale", 100, 25, 300, 25, s -> {
|
||||
if(ui.settings != null){
|
||||
Core.settings.put("uiscalechanged", true);
|
||||
}
|
||||
@@ -306,6 +308,9 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
graphics.checkPref("minimap", !mobile);
|
||||
graphics.checkPref("position", false);
|
||||
graphics.checkPref("fps", false);
|
||||
if(!mobile){
|
||||
graphics.checkPref("blockselectkeys", true);
|
||||
}
|
||||
graphics.checkPref("indicators", true);
|
||||
graphics.checkPref("animatedwater", !mobile);
|
||||
if(Shaders.shield != null){
|
||||
@@ -360,7 +365,11 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
|
||||
keyDown(key -> {
|
||||
if(key == KeyCode.ESCAPE || key == KeyCode.BACK){
|
||||
hide();
|
||||
if(prefs.getChildren().first() != menu){
|
||||
back();
|
||||
}else{
|
||||
hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -189,9 +189,9 @@ public class BlockInventoryFragment extends Fragment{
|
||||
private String round(float f){
|
||||
f = (int)f;
|
||||
if(f >= 1000000){
|
||||
return (int)(f / 1000000f) + "[gray]mil[]";
|
||||
return (int)(f / 1000000f) + "[gray]" + Core.bundle.getOrNull("unit.millions") + "[]";
|
||||
}else if(f >= 1000){
|
||||
return (int)(f / 1000) + "k";
|
||||
return (int)(f / 1000) + Core.bundle.getOrNull("unit.thousands");
|
||||
}else{
|
||||
return (int)f + "";
|
||||
}
|
||||
|
||||
@@ -42,10 +42,6 @@ public class HudFragment extends Fragment{
|
||||
private boolean shown = true;
|
||||
private float dsize = 47.2f;
|
||||
|
||||
private float coreAttackTime;
|
||||
private float lastCoreHP;
|
||||
private Team lastTeam;
|
||||
private float coreAttackOpacity = 0f;
|
||||
private long lastToast;
|
||||
|
||||
public void build(Group parent){
|
||||
@@ -68,9 +64,7 @@ public class HudFragment extends Fragment{
|
||||
select.addImageButton(Icon.menuLargeSmall, style, ui.paused::show);
|
||||
flip = select.addImageButton(Icon.arrowUpSmall, style, this::toggleMenus).get();
|
||||
|
||||
select.addImageButton(Icon.pasteSmall, style, () -> {
|
||||
ui.schematics.show();
|
||||
});
|
||||
select.addImageButton(Icon.pasteSmall, style, ui.schematics::show);
|
||||
|
||||
select.addImageButton(Icon.pauseSmall, style, () -> {
|
||||
if(net.active()){
|
||||
@@ -284,44 +278,29 @@ public class HudFragment extends Fragment{
|
||||
parent.fill(t -> {
|
||||
t.touchable(Touchable.disabled);
|
||||
float notifDuration = 240f;
|
||||
float[] coreAttackTime = {0};
|
||||
float[] coreAttackOpacity = {0};
|
||||
|
||||
Events.on(StateChangeEvent.class, event -> {
|
||||
if(event.to == State.menu || event.from == State.menu){
|
||||
coreAttackTime = 0f;
|
||||
lastCoreHP = Float.NaN;
|
||||
}
|
||||
Events.on(Trigger.teamCoreDamage, () -> {
|
||||
coreAttackTime[0] = notifDuration;
|
||||
});
|
||||
|
||||
t.top().visible(() -> {
|
||||
if(state.is(State.menu) || state.teams.get(player.getTeam()).cores.size == 0 || state.teams.get(player.getTeam()).cores.first().entity == null){
|
||||
coreAttackTime = 0f;
|
||||
coreAttackTime[0] = 0f;
|
||||
return false;
|
||||
}
|
||||
|
||||
float curr = state.teams.get(player.getTeam()).cores.first().entity.health;
|
||||
|
||||
if(lastTeam != player.getTeam()){
|
||||
lastCoreHP = curr;
|
||||
lastTeam = player.getTeam();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!Float.isNaN(lastCoreHP) && curr < lastCoreHP){
|
||||
coreAttackTime = notifDuration;
|
||||
}
|
||||
lastCoreHP = curr;
|
||||
|
||||
t.getColor().a = coreAttackOpacity;
|
||||
if(coreAttackTime > 0){
|
||||
coreAttackOpacity = Mathf.lerpDelta(coreAttackOpacity, 1f, 0.1f);
|
||||
t.getColor().a = coreAttackOpacity[0];
|
||||
if(coreAttackTime[0] > 0){
|
||||
coreAttackOpacity[0] = Mathf.lerpDelta(coreAttackOpacity[0], 1f, 0.1f);
|
||||
}else{
|
||||
coreAttackOpacity = Mathf.lerpDelta(coreAttackOpacity, 0f, 0.1f);
|
||||
coreAttackOpacity[0] = Mathf.lerpDelta(coreAttackOpacity[0], 0f, 0.1f);
|
||||
}
|
||||
|
||||
coreAttackTime -= Time.delta();
|
||||
lastTeam = player.getTeam();
|
||||
coreAttackTime[0] -= Time.delta();
|
||||
|
||||
return coreAttackOpacity > 0;
|
||||
return coreAttackOpacity[0] > 0;
|
||||
});
|
||||
t.table(Tex.button, top -> top.add("$coreattack").pad(2)
|
||||
.update(label -> label.getColor().set(Color.orange).lerp(Color.scarlet, Mathf.absin(Time.time(), 2f, 1f)))).touchable(Touchable.disabled);
|
||||
@@ -366,7 +345,7 @@ public class HudFragment extends Fragment{
|
||||
|
||||
@Remote(targets = Loc.both, forward = true, called = Loc.both)
|
||||
public static void setPlayerTeamEditor(Player player, Team team){
|
||||
if(state.isEditor()){
|
||||
if(state.isEditor() && player != null){
|
||||
player.setTeam(team);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
|
||||
import static io.anuke.arc.Core.assets;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class MenuFragment extends Fragment{
|
||||
@@ -26,8 +25,6 @@ public class MenuFragment extends Fragment{
|
||||
private MenuRenderer renderer;
|
||||
|
||||
public MenuFragment(){
|
||||
assets.load("sprites/logo.png", Texture.class);
|
||||
assets.finishLoading();
|
||||
Events.on(DisposeEvent.class, event -> {
|
||||
renderer.dispose();
|
||||
});
|
||||
@@ -67,7 +64,7 @@ public class MenuFragment extends Fragment{
|
||||
String versionText = "[#ffffffba]" + ((Version.build == -1) ? "[#fc8140aa]custom build" : (Version.type.equals("official") ? Version.modifier : Version.type) + " build " + Version.build + (Version.revision == 0 ? "" : "." + Version.revision));
|
||||
|
||||
parent.fill((x, y, w, h) -> {
|
||||
Texture logo = Core.assets.get("sprites/logo.png");
|
||||
TextureRegion logo = Core.atlas.find("logo");
|
||||
float logoscl = Scl.scl(1);
|
||||
float logow = Math.min(logo.getWidth() * logoscl, Core.graphics.getWidth() - Scl.scl(20));
|
||||
float logoh = logow * (float)logo.getHeight() / logo.getWidth();
|
||||
@@ -76,7 +73,7 @@ public class MenuFragment extends Fragment{
|
||||
float fy = (int)(Core.graphics.getHeight() - 6 - logoh) + logoh / 2 - (Core.graphics.isPortrait() ? Scl.scl(30f) : 0f);
|
||||
|
||||
Draw.color();
|
||||
Draw.rect(Draw.wrap(logo), fx, fy, logow, logoh);
|
||||
Draw.rect(logo, fx, fy, logow, logoh);
|
||||
|
||||
Fonts.def.setColor(Color.white);
|
||||
Fonts.def.draw(versionText, fx, fy - logoh/2f, Align.center);
|
||||
|
||||
@@ -36,6 +36,25 @@ public class PlacementFragment extends Fragment{
|
||||
Tile hoverTile;
|
||||
Table blockTable, toggler, topTable;
|
||||
boolean lastGround;
|
||||
boolean blockSelectEnd;
|
||||
int blockSelectSeq;
|
||||
long blockSelectSeqMillis;
|
||||
Binding[] blockSelect = {
|
||||
Binding.block_select_01,
|
||||
Binding.block_select_02,
|
||||
Binding.block_select_03,
|
||||
Binding.block_select_04,
|
||||
Binding.block_select_05,
|
||||
Binding.block_select_06,
|
||||
Binding.block_select_07,
|
||||
Binding.block_select_08,
|
||||
Binding.block_select_09,
|
||||
Binding.block_select_10,
|
||||
Binding.block_select_left,
|
||||
Binding.block_select_right,
|
||||
Binding.block_select_up,
|
||||
Binding.block_select_down
|
||||
};
|
||||
|
||||
public PlacementFragment(){
|
||||
Events.on(WorldLoadEvent.class, event -> {
|
||||
@@ -83,6 +102,78 @@ public class PlacementFragment extends Fragment{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(ui.chatfrag.chatOpen()) return false;
|
||||
for(int i = 0; i < blockSelect.length; i++){
|
||||
if(Core.input.keyTap(blockSelect[i])){
|
||||
if(i > 9) { //select block directionally
|
||||
Array<Block> blocks = getByCategory(currentCategory);
|
||||
Block currentBlock = getSelectedBlock(currentCategory);
|
||||
for(int j = 0; j < blocks.size; j++){
|
||||
if(blocks.get(j) == currentBlock){
|
||||
switch(i){
|
||||
case 10: //left
|
||||
j = (j - 1 + blocks.size) % blocks.size;
|
||||
break;
|
||||
case 11: //right
|
||||
j = (j + 1) % blocks.size;
|
||||
break;
|
||||
case 12: //up
|
||||
j = (j > 3 ? j - 4 : blocks.size - blocks.size % 4 + j);
|
||||
j -= (j < blocks.size ? 0 : 4);
|
||||
break;
|
||||
case 13: //down
|
||||
j = (j < blocks.size - 4 ? j + 4 : j % 4);
|
||||
}
|
||||
input.block = blocks.get(j);
|
||||
selectedBlocks.put(currentCategory, input.block);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}else if(blockSelectEnd || Time.timeSinceMillis(blockSelectSeqMillis) > Core.settings.getInt("blockselecttimeout")){ //1st number of combo, select category
|
||||
//select only visible categories
|
||||
if(!getByCategory(Category.all[i]).isEmpty()){
|
||||
currentCategory = Category.all[i];
|
||||
if(input.block != null){
|
||||
input.block = getSelectedBlock(currentCategory);
|
||||
}
|
||||
blockSelectEnd = false;
|
||||
blockSelectSeq = 0;
|
||||
blockSelectSeqMillis = Time.millis();
|
||||
}
|
||||
}else{ //select block
|
||||
if(blockSelectSeq == 0){ //2nd number of combo
|
||||
blockSelectSeq = i + 1;
|
||||
}else{ //3rd number of combo
|
||||
//entering "X,1,0" selects the same block as "X,0"
|
||||
i += (blockSelectSeq - (i != 9 ? 0 : 1)) * 10;
|
||||
blockSelectEnd = true;
|
||||
}
|
||||
Array<Block> blocks = getByCategory(currentCategory);
|
||||
input.block = (i < blocks.size) ? blocks.get(i) : null;
|
||||
selectedBlocks.put(currentCategory, input.block);
|
||||
blockSelectSeqMillis = Time.millis();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(Core.input.keyTap(Binding.category_prev)){
|
||||
do{
|
||||
currentCategory = currentCategory.prev();
|
||||
}while(categoryEmpty[currentCategory.ordinal()]);
|
||||
input.block = getSelectedBlock(currentCategory);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(Core.input.keyTap(Binding.category_next)){
|
||||
do{
|
||||
currentCategory = currentCategory.next();
|
||||
}while(categoryEmpty[currentCategory.ordinal()]);
|
||||
input.block = getSelectedBlock(currentCategory);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -109,11 +200,6 @@ public class PlacementFragment extends Fragment{
|
||||
blockTable.row();
|
||||
}
|
||||
|
||||
if(!unlocked(block)){
|
||||
blockTable.add().size(46);
|
||||
continue;
|
||||
}
|
||||
|
||||
ImageButton button = blockTable.addImageButton(Icon.lockedSmall, Styles.selecti, () -> {
|
||||
if(unlocked(block)){
|
||||
control.input.block = control.input.block == block ? null : block;
|
||||
@@ -170,9 +256,22 @@ public class PlacementFragment extends Fragment{
|
||||
lastGround = false;
|
||||
|
||||
topTable.table(header -> {
|
||||
String keyCombo = "";
|
||||
if(!mobile && Core.settings.getBool("blockselectkeys")){
|
||||
Array<Block> blocks = getByCategory(currentCategory);
|
||||
for(int i = 0; i < blocks.size; i++){
|
||||
if(blocks.get(i) == lastDisplay){
|
||||
keyCombo = Core.bundle.format("placement.blockselectkeys", Core.keybinds.get(blockSelect[currentCategory.ordinal()]).key.toString())
|
||||
+ (i < 10 ? "" : Core.keybinds.get(blockSelect[(i + 1) / 10 - 1]).key.toString() + ",")
|
||||
+ Core.keybinds.get(blockSelect[i % 10]).key.toString() + "]";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
final String keyComboFinal = keyCombo;
|
||||
header.left();
|
||||
header.add(new Image(lastDisplay.icon(Cicon.medium))).size(8 * 4);
|
||||
header.labelWrap(() -> !unlocked(lastDisplay) ? Core.bundle.get("block.unknown") : lastDisplay.localizedName)
|
||||
header.labelWrap(() -> !unlocked(lastDisplay) ? Core.bundle.get("block.unknown") : lastDisplay.localizedName + keyComboFinal)
|
||||
.left().width(190f).padLeft(5);
|
||||
header.add().growX();
|
||||
if(unlocked(lastDisplay)){
|
||||
@@ -265,7 +364,7 @@ public class PlacementFragment extends Fragment{
|
||||
//update category empty values
|
||||
for(Category cat : Category.all){
|
||||
Array<Block> blocks = getByCategory(cat);
|
||||
categoryEmpty[cat.ordinal()] = blocks.isEmpty() || !unlocked(blocks.first());
|
||||
categoryEmpty[cat.ordinal()] = blocks.isEmpty();
|
||||
}
|
||||
|
||||
int f = 0;
|
||||
@@ -280,10 +379,7 @@ public class PlacementFragment extends Fragment{
|
||||
categories.addImageButton(Core.atlas.drawable("icon-" + cat.name() + "-smaller"), Styles.clearToggleTransi, () -> {
|
||||
currentCategory = cat;
|
||||
if(control.input.block != null){
|
||||
if(selectedBlocks.get(currentCategory) == null){
|
||||
selectedBlocks.put(currentCategory, getByCategory(currentCategory).find(this::unlocked));
|
||||
}
|
||||
control.input.block = selectedBlocks.get(currentCategory);
|
||||
control.input.block = getSelectedBlock(currentCategory);
|
||||
}
|
||||
rebuildCategory.run();
|
||||
}).group(group).update(i -> i.setChecked(currentCategory == cat)).name("category-" + cat.name());
|
||||
@@ -308,7 +404,7 @@ public class PlacementFragment extends Fragment{
|
||||
Array<Block> getByCategory(Category cat){
|
||||
returnArray.clear();
|
||||
for(Block block : content.blocks()){
|
||||
if(block.category == cat && block.isVisible()){
|
||||
if(block.category == cat && block.isVisible() && unlocked(block)){
|
||||
returnArray.add(block);
|
||||
}
|
||||
}
|
||||
@@ -320,6 +416,13 @@ public class PlacementFragment extends Fragment{
|
||||
return returnArray;
|
||||
}
|
||||
|
||||
Block getSelectedBlock(Category cat){
|
||||
if(selectedBlocks.get(cat) == null){
|
||||
selectedBlocks.put(cat, getByCategory(cat).find(this::unlocked));
|
||||
}
|
||||
return selectedBlocks.get(cat);
|
||||
}
|
||||
|
||||
boolean unlocked(Block block){
|
||||
return !world.isZone() || data.isUnlocked(block);
|
||||
}
|
||||
@@ -359,4 +462,4 @@ public class PlacementFragment extends Fragment{
|
||||
Block tileDisplayBlock(){
|
||||
return hoverTile == null ? null : hoverTile.block().synthetic() ? hoverTile.block() : hoverTile.drop() != null ? hoverTile.overlay().itemDrop != null ? hoverTile.overlay() : hoverTile.floor() : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import io.anuke.mindustry.entities.traits.BuilderTrait.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.graphics.MultiPacker.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
@@ -89,6 +90,8 @@ public class Block extends BlockStorage{
|
||||
public boolean configurable;
|
||||
/** Whether this block consumes touchDown events when tapped. */
|
||||
public boolean consumesTap;
|
||||
/** Whether to draw the glow of the liquid for this block, if it has one. */
|
||||
public boolean drawLiquidLight = true;
|
||||
/** Whether the config is positional and needs to be shifted. */
|
||||
public boolean posConfig;
|
||||
/** Whether this block uses conveyor-type placement mode.*/
|
||||
@@ -137,6 +140,7 @@ public class Block extends BlockStorage{
|
||||
|
||||
protected TextureRegion[] cacheRegions = {};
|
||||
protected Array<String> cacheRegionStrings = new Array<>();
|
||||
protected Prov<TileEntity> entityType = TileEntity::new;
|
||||
|
||||
protected Array<Tile> tempTiles = new Array<>();
|
||||
protected TextureRegion[] generatedIcons;
|
||||
@@ -207,7 +211,8 @@ public class Block extends BlockStorage{
|
||||
if(tile == null || tile.entity == null || tile.entity.power == null) return out;
|
||||
|
||||
for(Tile other : tile.entity.proximity()){
|
||||
if(other != null && other.entity != null && other.entity.power != null && !(consumesPower && other.block().consumesPower && !outputsPower && !other.block().outputsPower)
|
||||
if(other != null && other.entity != null && other.entity.power != null
|
||||
&& !(consumesPower && other.block().consumesPower && !outputsPower && !other.block().outputsPower)
|
||||
&& !tile.entity.power.links.contains(other.pos())){
|
||||
out.add(other);
|
||||
}
|
||||
@@ -221,11 +226,7 @@ public class Block extends BlockStorage{
|
||||
}
|
||||
|
||||
protected float getProgressIncrease(TileEntity entity, float baseTime){
|
||||
float progressIncrease = 1f / baseTime * entity.delta();
|
||||
if(hasPower){
|
||||
progressIncrease *= entity.power.satisfaction; // Reduced increase in case of low power
|
||||
}
|
||||
return progressIncrease;
|
||||
return 1f / baseTime * entity.delta() * entity.efficiency();
|
||||
}
|
||||
|
||||
/** @return whether this block should play its active sound.*/
|
||||
@@ -295,6 +296,23 @@ public class Block extends BlockStorage{
|
||||
Draw.rect(region, tile.drawx(), tile.drawy(), rotate ? tile.rotation() * 90 : 0);
|
||||
}
|
||||
|
||||
public void drawLight(Tile tile){
|
||||
if(tile.entity != null && hasLiquids && drawLiquidLight && tile.entity.liquids.current().lightColor.a > 0.001f){
|
||||
drawLiquidLight(tile, tile.entity.liquids.current(), tile.entity.liquids.smoothAmount());
|
||||
}
|
||||
}
|
||||
|
||||
public void drawLiquidLight(Tile tile, Liquid liquid, float amount){
|
||||
if(amount > 0.01f){
|
||||
Color color = liquid.lightColor;
|
||||
float fract = 1f;
|
||||
float opacity = color.a * fract;
|
||||
if(opacity > 0.001f){
|
||||
renderer.lights.add(tile.drawx(), tile.drawy(), size * 30f * fract, color, opacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void drawTeam(Tile tile){
|
||||
Draw.color(tile.getTeam().color);
|
||||
Draw.rect("block-border", tile.drawx() - size * tilesize / 2f + 4, tile.drawy() - size * tilesize / 2f + 4);
|
||||
@@ -366,6 +384,16 @@ public class Block extends BlockStorage{
|
||||
return sum;
|
||||
}
|
||||
|
||||
public float percentSolid(int x, int y){
|
||||
Tile tile = world.tile(x, y);
|
||||
if(tile == null) return 0;
|
||||
float sum = 0;
|
||||
for(Tile other : tile.getLinkedTilesAs(this, tempTiles)){
|
||||
sum += !other.floor.isLiquid ? 1f : 0f;
|
||||
}
|
||||
return sum / size / size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void displayInfo(Table table){
|
||||
ContentDisplay.displayBlock(table, this);
|
||||
@@ -527,8 +555,8 @@ public class Block extends BlockStorage{
|
||||
boolean buffered = cons.buffered;
|
||||
float capacity = cons.capacity;
|
||||
|
||||
bars.add("power", entity -> new Bar(() -> buffered ? Core.bundle.format("bar.poweramount", Float.isNaN(entity.power.satisfaction * capacity) ? "<ERROR>" : (int)(entity.power.satisfaction * capacity)) :
|
||||
Core.bundle.get("bar.power"), () -> Pal.powerBar, () -> Mathf.isZero(cons.requestedPower(entity)) && entity.power.graph.getPowerProduced() + entity.power.graph.getBatteryStored() > 0f ? 1f : entity.power.satisfaction));
|
||||
bars.add("power", entity -> new Bar(() -> buffered ? Core.bundle.format("bar.poweramount", Float.isNaN(entity.power.status * capacity) ? "<ERROR>" : (int)(entity.power.status * capacity)) :
|
||||
Core.bundle.get("bar.power"), () -> Pal.powerBar, () -> Mathf.zero(cons.requestedPower(entity)) && entity.power.graph.getPowerProduced() + entity.power.graph.getBatteryStored() > 0f ? 1f : entity.power.status));
|
||||
}
|
||||
|
||||
if(hasItems && configurable){
|
||||
@@ -589,12 +617,12 @@ public class Block extends BlockStorage{
|
||||
}
|
||||
|
||||
if(consumes.hasPower() && consumes.getPower().buffered){
|
||||
power += tile.entity.power.satisfaction * consumes.getPower().capacity;
|
||||
power += tile.entity.power.status * consumes.getPower().capacity;
|
||||
}
|
||||
|
||||
if(hasLiquids){
|
||||
|
||||
tile.entity.liquids.forEach((liquid, amount) -> {
|
||||
tile.entity.liquids.each((liquid, amount) -> {
|
||||
float splash = Mathf.clamp(amount / 4f, 0f, 10f);
|
||||
|
||||
for(int i = 0; i < Mathf.clamp(amount / 5, 0, 30); i++){
|
||||
@@ -704,10 +732,12 @@ public class Block extends BlockStorage{
|
||||
Color color = content instanceof Item ? ((Item)content).color : content instanceof Liquid ? ((Liquid)content).color : null;
|
||||
if(color == null) return;
|
||||
|
||||
float prev = Draw.scl;
|
||||
|
||||
Draw.color(color);
|
||||
Draw.scl *= req.animScale;
|
||||
Draw.rect(region, req.drawx(), req.drawy());
|
||||
Draw.scl /= req.animScale;
|
||||
Draw.scl = prev;
|
||||
Draw.color();
|
||||
}
|
||||
|
||||
@@ -721,10 +751,10 @@ public class Block extends BlockStorage{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createIcons(PixmapPacker packer, PixmapPacker editor){
|
||||
super.createIcons(packer, editor);
|
||||
public void createIcons(MultiPacker packer){
|
||||
super.createIcons(packer);
|
||||
|
||||
editor.pack(name + "-icon-editor", Core.atlas.getPixmap((AtlasRegion)icon(Cicon.full)).crop());
|
||||
packer.add(PageType.editor, name + "-icon-editor", Core.atlas.getPixmap((AtlasRegion)icon(Cicon.full)));
|
||||
|
||||
if(!synthetic()){
|
||||
PixmapRegion image = Core.atlas.getPixmap((AtlasRegion)icon(Cicon.full));
|
||||
@@ -764,7 +794,7 @@ public class Block extends BlockStorage{
|
||||
}
|
||||
last = out;
|
||||
|
||||
packer.pack(name, out);
|
||||
packer.add(PageType.main, name, out);
|
||||
}
|
||||
|
||||
if(generatedIcons.length > 1){
|
||||
@@ -776,7 +806,7 @@ public class Block extends BlockStorage{
|
||||
base.draw(Core.atlas.getPixmap(generatedIcons[i]));
|
||||
}
|
||||
}
|
||||
packer.pack("block-" + name + "-full", base);
|
||||
packer.add(PageType.main, "block-" + name + "-full", base);
|
||||
generatedIcons = null;
|
||||
Arrays.fill(cicons, null);
|
||||
}
|
||||
@@ -823,8 +853,8 @@ public class Block extends BlockStorage{
|
||||
return destructible || update;
|
||||
}
|
||||
|
||||
public TileEntity newEntity(){
|
||||
return new TileEntity();
|
||||
public final TileEntity newEntity(){
|
||||
return entityType.get();
|
||||
}
|
||||
|
||||
/** Offset for placing and drawing multiblocks. */
|
||||
|
||||
@@ -28,6 +28,7 @@ public abstract class BlockStorage extends UnlockableContent{
|
||||
|
||||
public int itemCapacity = 10;
|
||||
public float liquidCapacity = 10f;
|
||||
public float liquidPressure = 1f;
|
||||
|
||||
public final BlockStats stats = new BlockStats();
|
||||
public final BlockBars bars = new BlockBars();
|
||||
@@ -115,9 +116,9 @@ public abstract class BlockStorage extends UnlockableContent{
|
||||
Tile other = proximity.get((i + dump) % proximity.size);
|
||||
Tile in = Edges.getFacingEdge(tile, other);
|
||||
|
||||
other = other.block().getLiquidDestination(other, tile);
|
||||
other = other.block().getLiquidDestination(other, in, liquid);
|
||||
|
||||
if(other.getTeam() == tile.getTeam() && other.block().hasLiquids && canDumpLiquid(tile, other, liquid) && other.entity.liquids != null){
|
||||
if(other != null && other.getTeam() == tile.getTeam() && other.block().hasLiquids && canDumpLiquid(tile, other, liquid) && other.entity.liquids != null){
|
||||
float ofract = other.entity.liquids.get(liquid) / other.block().liquidCapacity;
|
||||
float fract = tile.entity.liquids.get(liquid) / liquidCapacity;
|
||||
|
||||
@@ -141,16 +142,20 @@ public abstract class BlockStorage extends UnlockableContent{
|
||||
}
|
||||
|
||||
public float tryMoveLiquid(Tile tile, Tile next, boolean leak, Liquid liquid){
|
||||
return tryMoveLiquid(tile, next, leak ? 1.5f : 100, liquid);
|
||||
}
|
||||
|
||||
public float tryMoveLiquid(Tile tile, Tile next, float leakResistance, Liquid liquid){
|
||||
if(next == null) return 0;
|
||||
|
||||
next = next.link();
|
||||
next = next.block().getLiquidDestination(next, tile);
|
||||
next = next.block().getLiquidDestination(next, tile, liquid);
|
||||
|
||||
if(next.getTeam() == tile.getTeam() && next.block().hasLiquids && tile.entity.liquids.get(liquid) > 0f){
|
||||
|
||||
if(next.block().acceptLiquid(next, tile, liquid, 0f)){
|
||||
float ofract = next.entity.liquids.get(liquid) / next.block().liquidCapacity;
|
||||
float fract = tile.entity.liquids.get(liquid) / liquidCapacity;
|
||||
float fract = tile.entity.liquids.get(liquid) / liquidCapacity * liquidPressure;
|
||||
float flow = Math.min(Mathf.clamp((fract - ofract) * (1f)) * (liquidCapacity), tile.entity.liquids.get(liquid));
|
||||
flow = Math.min(flow, next.block().liquidCapacity - next.entity.liquids.get(liquid) - 0.001f);
|
||||
|
||||
@@ -174,15 +179,15 @@ public abstract class BlockStorage extends UnlockableContent{
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if(leak && !next.block().solid && !next.block().hasLiquids){
|
||||
float leakAmount = tile.entity.liquids.get(liquid) / 1.5f;
|
||||
}else if(leakResistance != 100f && !next.block().solid && !next.block().hasLiquids){
|
||||
float leakAmount = tile.entity.liquids.get(liquid) / leakResistance;
|
||||
Puddle.deposit(next, tile, liquid, leakAmount);
|
||||
tile.entity.liquids.remove(liquid, leakAmount);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Tile getLiquidDestination(Tile tile, Tile from){
|
||||
public Tile getLiquidDestination(Tile tile, Tile from, Liquid liquid){
|
||||
return tile;
|
||||
}
|
||||
|
||||
|
||||
@@ -318,6 +318,31 @@ public class Tile implements Position, TargetTrait{
|
||||
return null;
|
||||
}
|
||||
|
||||
public Tile getNearbyLink(int rotation){
|
||||
if(rotation == 0) return world.ltile(x + 1, y);
|
||||
if(rotation == 1) return world.ltile(x, y + 1);
|
||||
if(rotation == 2) return world.ltile(x - 1, y);
|
||||
if(rotation == 3) return world.ltile(x, y - 1);
|
||||
return null;
|
||||
}
|
||||
|
||||
// ▲ ▲ ▼ ▼ ◀ ▶ ◀ ▶ B A
|
||||
public @Nullable Tile front(){
|
||||
return getNearbyLink((rotation + 4) % 4);
|
||||
}
|
||||
|
||||
public @Nullable Tile right(){
|
||||
return getNearbyLink((rotation + 3) % 4);
|
||||
}
|
||||
|
||||
public @Nullable Tile back(){
|
||||
return getNearbyLink((rotation + 2) % 4);
|
||||
}
|
||||
|
||||
public @Nullable Tile left(){
|
||||
return getNearbyLink((rotation + 1) % 4);
|
||||
}
|
||||
|
||||
public boolean interactable(Team team){
|
||||
return getTeam() == Team.derelict || team == getTeam();
|
||||
}
|
||||
|
||||
@@ -87,6 +87,12 @@ public interface Autotiler{
|
||||
return other != null && blends(tile, rotation, other.x, other.y, other.rotation(), other.block());
|
||||
}
|
||||
|
||||
default boolean blendsArmored(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
|
||||
return (Point2.equals(tile.x + Geometry.d4(rotation).x, tile.y + Geometry.d4(rotation).y, otherx, othery)
|
||||
|| ((!otherblock.rotate && Edges.getFacingEdge(otherblock, otherx, othery, tile) != null &&
|
||||
Edges.getFacingEdge(otherblock, otherx, othery, tile).relativeTo(tile) == rotation) || (otherblock.rotate && Point2.equals(otherx + Geometry.d4(otherrot).x, othery + Geometry.d4(otherrot).y, tile.x, tile.y))));
|
||||
}
|
||||
|
||||
default boolean lookingAt(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
|
||||
return (Point2.equals(tile.x + Geometry.d4(rotation).x, tile.y + Geometry.d4(rotation).y, otherx, othery)
|
||||
|| (!otherblock.rotate || Point2.equals(otherx + Geometry.d4(otherrot).x, othery + Geometry.d4(otherrot).y, tile.x, tile.y)));
|
||||
|
||||
@@ -42,6 +42,7 @@ public class BuildBlock extends Block{
|
||||
layer = Layer.placement;
|
||||
consumesTap = true;
|
||||
solidifes = true;
|
||||
entityType = BuildEntity::new;
|
||||
|
||||
buildBlocks[size - 1] = this;
|
||||
}
|
||||
@@ -197,11 +198,6 @@ public class BuildBlock extends Block{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new BuildEntity();
|
||||
}
|
||||
|
||||
public class BuildEntity extends TileEntity{
|
||||
/**
|
||||
* The recipe of the block that is being constructed.
|
||||
|
||||
@@ -9,8 +9,10 @@ import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.math.geom.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.entities.Effects.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.graphics.MultiPacker.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.ui.Cicon;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
@@ -86,9 +88,9 @@ public class Floor extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createIcons(PixmapPacker out, PixmapPacker editor){
|
||||
super.createIcons(out, editor);
|
||||
editor.pack("editor-" + name, Core.atlas.getPixmap((AtlasRegion)icon(Cicon.full)).crop());
|
||||
public void createIcons(MultiPacker packer){
|
||||
super.createIcons(packer);
|
||||
packer.add(PageType.editor, "editor-" + name, Core.atlas.getPixmap((AtlasRegion)icon(Cicon.full)).crop());
|
||||
|
||||
if(blendGroup != this){
|
||||
return;
|
||||
@@ -97,7 +99,7 @@ public class Floor extends Block{
|
||||
if(variants > 0){
|
||||
for(int i = 0; i < variants; i++){
|
||||
String rname = name + (i + 1);
|
||||
editor.pack("editor-" + rname, Core.atlas.getPixmap(rname).crop());
|
||||
packer.add(PageType.editor, "editor-" + rname, Core.atlas.getPixmap(rname).crop());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +116,7 @@ public class Floor extends Block{
|
||||
}
|
||||
}
|
||||
|
||||
out.pack(name + "-edge", result);
|
||||
packer.add(PageType.environment, name + "-edge", result);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -4,6 +4,8 @@ import io.anuke.annotations.Annotations.*;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.graphics.MultiPacker.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
@@ -34,7 +36,7 @@ public class OreBlock extends OverlayFloor{
|
||||
|
||||
@Override
|
||||
@OverrideCallSuper
|
||||
public void createIcons(PixmapPacker out, PixmapPacker editor){
|
||||
public void createIcons(MultiPacker packer){
|
||||
for(int i = 0; i < variants; i++){
|
||||
Pixmap image = new Pixmap(32, 32);
|
||||
PixmapRegion shadow = Core.atlas.getPixmap(itemDrop.name + (i + 1));
|
||||
@@ -55,12 +57,12 @@ public class OreBlock extends OverlayFloor{
|
||||
|
||||
image.draw(shadow);
|
||||
|
||||
out.pack(name + (i + 1), image);
|
||||
editor.pack("editor-" + name + (i + 1), image);
|
||||
packer.add(PageType.environment, name + (i + 1), image);
|
||||
packer.add(PageType.editor, "editor-" + name + (i + 1), image);
|
||||
|
||||
if(i == 0){
|
||||
editor.pack("editor-block-" + name + "-full", image);
|
||||
out.pack("block-" + name + "-full", image);
|
||||
packer.add(PageType.editor, "editor-block-" + name + "-full", image);
|
||||
packer.add(PageType.main, "block-" + name + "-full", image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ public class DeflectorWall extends Wall{
|
||||
|
||||
public DeflectorWall(String name){
|
||||
super(name);
|
||||
entityType = DeflectorEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,11 +73,6 @@ public class DeflectorWall extends Wall{
|
||||
((DeflectorEntity)entity).hit = 1f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new DeflectorEntity();
|
||||
}
|
||||
|
||||
public static class DeflectorEntity extends TileEntity{
|
||||
public float hit;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ public class Door extends Wall{
|
||||
solid = false;
|
||||
solidifes = true;
|
||||
consumesTap = true;
|
||||
entityType = DoorEntity::new;
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server)
|
||||
@@ -89,11 +90,6 @@ public class Door extends Wall{
|
||||
Call.onDoorToggle(null, tile, !entity.open);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new DoorEntity();
|
||||
}
|
||||
|
||||
public class DoorEntity extends TileEntity{
|
||||
public boolean open = false;
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ public class ForceProjector extends Block{
|
||||
hasLiquids = true;
|
||||
hasItems = true;
|
||||
consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.1f)).boost().update(false);
|
||||
entityType = ForceEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,7 +99,7 @@ public class ForceProjector extends Block{
|
||||
|
||||
entity.phaseHeat = Mathf.lerpDelta(entity.phaseHeat, Mathf.num(phaseValid), 0.1f);
|
||||
|
||||
if(phaseValid && !entity.broken && entity.timer.get(timerUse, phaseUseTime)){
|
||||
if(phaseValid && !entity.broken && entity.timer.get(timerUse, phaseUseTime) && entity.efficiency() > 0){
|
||||
entity.cons.trigger();
|
||||
}
|
||||
|
||||
@@ -108,12 +109,12 @@ public class ForceProjector extends Block{
|
||||
Effects.effect(Fx.reactorsmoke, tile.drawx() + Mathf.range(tilesize / 2f), tile.drawy() + Mathf.range(tilesize / 2f));
|
||||
}
|
||||
|
||||
entity.warmup = Mathf.lerpDelta(entity.warmup, entity.power.satisfaction, 0.1f);
|
||||
entity.warmup = Mathf.lerpDelta(entity.warmup, entity.efficiency(), 0.1f);
|
||||
|
||||
/*
|
||||
if(entity.power.satisfaction < relativePowerDraw){
|
||||
if(entity.power.status < relativePowerDraw){
|
||||
entity.warmup = Mathf.lerpDelta(entity.warmup, 0f, 0.15f);
|
||||
entity.power.satisfaction = 0f;
|
||||
entity.power.status = 0f;
|
||||
if(entity.warmup <= 0.09f){
|
||||
entity.broken = true;
|
||||
}
|
||||
@@ -179,11 +180,6 @@ public class ForceProjector extends Block{
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new ForceEntity();
|
||||
}
|
||||
|
||||
class ForceEntity extends TileEntity{
|
||||
ShieldEntity shield;
|
||||
boolean broken = true;
|
||||
|
||||
@@ -36,6 +36,7 @@ public class MendProjector extends Block{
|
||||
update = true;
|
||||
hasPower = true;
|
||||
hasItems = true;
|
||||
entityType = MendEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -68,7 +69,7 @@ public class MendProjector extends Block{
|
||||
|
||||
entity.phaseHeat = Mathf.lerpDelta(entity.phaseHeat, Mathf.num(entity.cons.optionalValid()), 0.1f);
|
||||
|
||||
if(entity.cons.optionalValid() && entity.timer.get(timerUse, useTime) && entity.power.satisfaction > 0){
|
||||
if(entity.cons.optionalValid() && entity.timer.get(timerUse, useTime) && entity.efficiency() > 0){
|
||||
entity.cons.trigger();
|
||||
}
|
||||
|
||||
@@ -77,7 +78,7 @@ public class MendProjector extends Block{
|
||||
entity.charge = 0f;
|
||||
|
||||
indexer.eachBlock(entity, realRange, other -> other.entity.damaged(), other -> {
|
||||
other.entity.healBy(other.entity.maxHealth() * (healPercent + entity.phaseHeat * phaseBoost) / 100f * entity.power.satisfaction);
|
||||
other.entity.healBy(other.entity.maxHealth() * (healPercent + entity.phaseHeat * phaseBoost) / 100f * entity.efficiency());
|
||||
Effects.effect(Fx.healBlockFull, Tmp.c1.set(color).lerp(phase, entity.phaseHeat), other.drawx(), other.drawy(), other.block().size);
|
||||
});
|
||||
}
|
||||
@@ -117,8 +118,8 @@ public class MendProjector extends Block{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new MendEntity();
|
||||
public void drawLight(Tile tile){
|
||||
renderer.lights.add(tile.drawx(), tile.drawy(), 50f * tile.entity.efficiency(), color, 0.7f * tile.entity.efficiency());
|
||||
}
|
||||
|
||||
class MendEntity extends TileEntity{
|
||||
|
||||
@@ -37,6 +37,7 @@ public class OverdriveProjector extends Block{
|
||||
hasPower = true;
|
||||
hasItems = true;
|
||||
canOverdrive = false;
|
||||
entityType = OverdriveEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -66,6 +67,11 @@ public class OverdriveProjector extends Block{
|
||||
stats.add(BlockStat.boostEffect, (int)((speedBoost + speedBoostPhase) * 100f), StatUnit.percent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawLight(Tile tile){
|
||||
renderer.lights.add(tile.drawx(), tile.drawy(), 50f * tile.entity.efficiency(), color, 0.7f * tile.entity.efficiency());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Tile tile){
|
||||
OverdriveEntity entity = tile.entity();
|
||||
@@ -74,13 +80,13 @@ public class OverdriveProjector extends Block{
|
||||
|
||||
entity.phaseHeat = Mathf.lerpDelta(entity.phaseHeat, Mathf.num(entity.cons.optionalValid()), 0.1f);
|
||||
|
||||
if(entity.timer.get(timerUse, useTime) && entity.power.satisfaction > 0){
|
||||
if(entity.timer.get(timerUse, useTime) && entity.efficiency() > 0){
|
||||
entity.cons.trigger();
|
||||
}
|
||||
|
||||
if(entity.charge >= reload){
|
||||
float realRange = range + entity.phaseHeat * phaseRangeBoost;
|
||||
float realBoost = (speedBoost + entity.phaseHeat * speedBoostPhase) * entity.power.satisfaction;
|
||||
float realBoost = (speedBoost + entity.phaseHeat * speedBoostPhase) * entity.efficiency();
|
||||
|
||||
entity.charge = 0f;
|
||||
indexer.eachBlock(entity, realRange, other -> other.entity.timeScale <= realBoost, other -> {
|
||||
@@ -115,11 +121,6 @@ public class OverdriveProjector extends Block{
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new OverdriveEntity();
|
||||
}
|
||||
|
||||
class OverdriveEntity extends TileEntity{
|
||||
float heat;
|
||||
float charge = Mathf.random(reload);
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package io.anuke.mindustry.world.blocks.defense.turrets;
|
||||
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.Effects.Effect;
|
||||
import io.anuke.mindustry.entities.bullet.BulletType;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.Effects.*;
|
||||
import io.anuke.mindustry.entities.bullet.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
|
||||
@@ -21,6 +20,7 @@ public class ChargeTurret extends PowerTurret{
|
||||
|
||||
public ChargeTurret(String name){
|
||||
super(name);
|
||||
entityType = LaserTurretEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -59,11 +59,6 @@ public class ChargeTurret extends PowerTurret{
|
||||
return !entity.shooting;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new LaserTurretEntity();
|
||||
}
|
||||
|
||||
public class LaserTurretEntity extends TurretEntity{
|
||||
public boolean shooting;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ public class ItemTurret extends CooledTurret{
|
||||
public ItemTurret(String name){
|
||||
super(name);
|
||||
hasItems = true;
|
||||
entityType = ItemTurretEntity::new;
|
||||
}
|
||||
|
||||
/** Initializes accepted ammo map. Format: [item1, bullet1, item2, bullet2...] */
|
||||
@@ -148,11 +149,6 @@ public class ItemTurret extends CooledTurret{
|
||||
return ammo != null && ammo.get(item) != null && entity.totalAmmo + ammo.get(item).ammoMultiplier <= maxAmmo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new ItemTurretEntity();
|
||||
}
|
||||
|
||||
public class ItemTurretEntity extends TurretEntity{
|
||||
@Override
|
||||
public void write(DataOutput stream) throws IOException{
|
||||
|
||||
@@ -23,6 +23,7 @@ public class LaserTurret extends PowerTurret{
|
||||
|
||||
consumes.add(new ConsumeLiquidFilter(liquid -> liquid.temperature <= 0.5f && liquid.flammability < 0.1f, 0.01f)).update(false);
|
||||
coolantMultiplier = 1f;
|
||||
entityType = LaserTurretEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -99,11 +100,6 @@ public class LaserTurret extends PowerTurret{
|
||||
entity.bulletLife = shootDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new LaserTurretEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldActiveSound(Tile tile){
|
||||
LaserTurretEntity entity = tile.entity();
|
||||
|
||||
@@ -47,6 +47,6 @@ public class PowerTurret extends CooledTurret{
|
||||
|
||||
@Override
|
||||
protected float baseReloadSpeed(Tile tile){
|
||||
return tile.isEnemyCheat() ? 1f : tile.entity.power.satisfaction;
|
||||
return tile.isEnemyCheat() ? 1f : tile.entity.power.status;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +79,7 @@ public abstract class Turret extends Block{
|
||||
group = BlockGroup.turrets;
|
||||
flags = EnumSet.of(BlockFlag.turret);
|
||||
outlineIcon = true;
|
||||
entityType = TurretEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -305,11 +306,6 @@ public abstract class Turret extends Block{
|
||||
return (tile.entity instanceof TurretEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new TurretEntity();
|
||||
}
|
||||
|
||||
public static abstract class AmmoEntry{
|
||||
public int amount;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.anuke.mindustry.world.blocks.distribution;
|
||||
|
||||
import io.anuke.arc.math.geom.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
@@ -16,9 +15,7 @@ public class ArmoredConveyor extends Conveyor{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
|
||||
return otherblock.outputsItems() && (Point2.equals(tile.x + Geometry.d4(rotation).x, tile.y + Geometry.d4(rotation).y, otherx, othery)
|
||||
|| ((!otherblock.rotate && Edges.getFacingEdge(otherblock, otherx, othery, tile) != null &&
|
||||
Edges.getFacingEdge(otherblock, otherx, othery, tile).relativeTo(tile) == rotation) || (otherblock.rotate && Point2.equals(otherx + Geometry.d4(otherrot).x, othery + Geometry.d4(otherrot).y, tile.x, tile.y))));
|
||||
public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock) {
|
||||
return otherblock.outputsItems() && blendsArmored(tile, rotation, otherx, othery, otherrot, otherblock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package io.anuke.mindustry.world.blocks.distribution;
|
||||
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.world.ItemBuffer;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
@@ -18,6 +16,7 @@ public class BufferedItemBridge extends ExtendingItemBridge{
|
||||
super(name);
|
||||
hasPower = false;
|
||||
hasItems = true;
|
||||
entityType = BufferedItemBridgeEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -38,11 +37,6 @@ public class BufferedItemBridge extends ExtendingItemBridge{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new BufferedItemBridgeEntity();
|
||||
}
|
||||
|
||||
class BufferedItemBridgeEntity extends ItemBridgeEntity{
|
||||
ItemBuffer buffer = new ItemBuffer(bufferCapacity, speed);
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ public class Conveyor extends Block implements Autotiler{
|
||||
hasItems = true;
|
||||
itemCapacity = 4;
|
||||
conveyorPlacement = true;
|
||||
entityType = ConveyorEntity::new;
|
||||
|
||||
idleSound = Sounds.conveyor;
|
||||
idleSoundVolume = 0.004f;
|
||||
@@ -200,7 +201,7 @@ public class Conveyor extends Block implements Autotiler{
|
||||
|
||||
if(maxmove > minmove){
|
||||
pos.y += maxmove;
|
||||
if(Mathf.isEqual(pos.x, 0, 0.1f)){
|
||||
if(Mathf.equal(pos.x, 0, 0.1f)){
|
||||
pos.x = 0f;
|
||||
}
|
||||
pos.x = Mathf.lerpDelta(pos.x, 0, 0.1f);
|
||||
@@ -342,11 +343,6 @@ public class Conveyor extends Block implements Autotiler{
|
||||
entity.lastInserted = (byte)(entity.convey.size - 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new ConveyorEntity();
|
||||
}
|
||||
|
||||
public static class ConveyorEntity extends TileEntity{
|
||||
|
||||
LongArray convey = new LongArray();
|
||||
|
||||
@@ -41,22 +41,12 @@ public class ItemBridge extends Block{
|
||||
hasItems = true;
|
||||
unloadable = false;
|
||||
group = BlockGroup.transportation;
|
||||
entityType = ItemBridgeEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configured(Tile tile, Player player, int value){
|
||||
ItemBridgeEntity entity = tile.entity();
|
||||
|
||||
if(world.tile(entity.link) != null && world.tile(entity.link).entity instanceof ItemBridgeEntity){
|
||||
ItemBridgeEntity oe = world.tile(entity.link).entity();
|
||||
oe.incoming.remove(tile.pos());
|
||||
}
|
||||
|
||||
entity.link = value;
|
||||
|
||||
if(world.tile(value) != null && world.tile(value).entity instanceof ItemBridgeEntity){
|
||||
((ItemBridgeEntity)world.tile(value).entity).incoming.add(tile.pos());
|
||||
}
|
||||
tile.<ItemBridgeEntity>entity().link = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -185,7 +175,7 @@ public class ItemBridge extends Block{
|
||||
while(it.hasNext){
|
||||
int i = it.next();
|
||||
Tile other = world.tile(i);
|
||||
if(!linkValid(tile, other, false)){
|
||||
if(!linkValid(tile, other, false) || other.<ItemBridgeEntity>entity().link != tile.pos()){
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
@@ -195,8 +185,9 @@ public class ItemBridge extends Block{
|
||||
tryDump(tile);
|
||||
entity.uptime = 0f;
|
||||
}else{
|
||||
((ItemBridgeEntity)world.tile(entity.link).entity).incoming.add(tile.pos());
|
||||
|
||||
if(entity.cons.valid() && (!hasPower || Mathf.isZero(1f - entity.power.satisfaction))){
|
||||
if(entity.cons.valid() && Mathf.zero(1f - entity.efficiency())){
|
||||
entity.uptime = Mathf.lerpDelta(entity.uptime, 1f, 0.04f);
|
||||
}else{
|
||||
entity.uptime = Mathf.lerpDelta(entity.uptime, 0f, 0.02f);
|
||||
@@ -307,7 +298,7 @@ public class ItemBridge extends Block{
|
||||
|
||||
@Override
|
||||
public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){
|
||||
if(tile.getTeam() != source.getTeam()) return false;
|
||||
if(tile.getTeam() != source.getTeam() || !hasLiquids) return false;
|
||||
|
||||
ItemBridgeEntity entity = tile.entity();
|
||||
Tile other = world.tile(entity.link);
|
||||
@@ -350,11 +341,6 @@ public class ItemBridge extends Block{
|
||||
return rel != rel2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new ItemBridgeEntity();
|
||||
}
|
||||
|
||||
public boolean linkValid(Tile tile, Tile other){
|
||||
return linkValid(tile, other, true);
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ public class Junction extends Block{
|
||||
instantTransfer = true;
|
||||
group = BlockGroup.transportation;
|
||||
unloadable = false;
|
||||
entityType = JunctionEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,11 +88,6 @@ public class Junction extends Block{
|
||||
return to != null && to.link().entity != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new JunctionEntity();
|
||||
}
|
||||
|
||||
class JunctionEntity extends TileEntity{
|
||||
DirectionalItemBuffer buffer = new DirectionalItemBuffer(capacity, speed);
|
||||
|
||||
|
||||
@@ -42,16 +42,9 @@ public class MassDriver extends Block{
|
||||
layer = Layer.turret;
|
||||
hasPower = true;
|
||||
outlineIcon = true;
|
||||
entityType = MassDriverEntity::new;
|
||||
}
|
||||
|
||||
/*
|
||||
@Remote(targets = Loc.both, called = Loc.server, forward = true)
|
||||
public static void linkMassDriver(Player player, Tile tile, int position){
|
||||
if(!Units.canInteract(player, tile)) return;
|
||||
MassDriverEntity entity = tile.entity();
|
||||
entity.link = position;
|
||||
}*/
|
||||
|
||||
@Override
|
||||
public void configured(Tile tile, Player player, int value){
|
||||
tile.<MassDriverEntity>entity().link = value;
|
||||
@@ -77,7 +70,7 @@ public class MassDriver extends Block{
|
||||
|
||||
//reload regardless of state
|
||||
if(entity.reload > 0f){
|
||||
entity.reload = Mathf.clamp(entity.reload - entity.delta() / reloadTime * entity.power.satisfaction);
|
||||
entity.reload = Mathf.clamp(entity.reload - entity.delta() / reloadTime * entity.efficiency());
|
||||
}
|
||||
|
||||
//cleanup waiting shooters that are not valid
|
||||
@@ -113,7 +106,7 @@ public class MassDriver extends Block{
|
||||
}
|
||||
|
||||
//align to shooter rotation
|
||||
entity.rotation = Mathf.slerpDelta(entity.rotation, tile.angleTo(entity.currentShooter()), rotateSpeed * entity.power.satisfaction);
|
||||
entity.rotation = Mathf.slerpDelta(entity.rotation, tile.angleTo(entity.currentShooter()), rotateSpeed * entity.efficiency());
|
||||
}else if(entity.state == DriverState.shooting){
|
||||
//if there's nothing to shoot at OR someone wants to shoot at this thing, bail
|
||||
if(!hasLink || (!entity.waitingShooters.isEmpty() && (itemCapacity - entity.items.total() >= minDistribute))){
|
||||
@@ -133,7 +126,7 @@ public class MassDriver extends Block{
|
||||
if(entity.reload <= 0.0001f){
|
||||
|
||||
//align to target location
|
||||
entity.rotation = Mathf.slerpDelta(entity.rotation, targetRotation, rotateSpeed * entity.power.satisfaction);
|
||||
entity.rotation = Mathf.slerpDelta(entity.rotation, targetRotation, rotateSpeed * entity.efficiency());
|
||||
|
||||
//fire when it's the first in the queue and angles are ready.
|
||||
if(other.currentShooter() == tile &&
|
||||
@@ -213,11 +206,6 @@ public class MassDriver extends Block{
|
||||
return tile.entity.items.total() < itemCapacity && linkValid(tile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new MassDriverEntity();
|
||||
}
|
||||
|
||||
protected void fire(Tile tile, Tile target){
|
||||
MassDriverEntity entity = tile.entity();
|
||||
MassDriverEntity other = target.entity();
|
||||
|
||||
@@ -19,6 +19,7 @@ public class OverflowGate extends Block{
|
||||
update = true;
|
||||
group = BlockGroup.transportation;
|
||||
unloadable = false;
|
||||
entityType = OverflowGateEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -108,11 +109,6 @@ public class OverflowGate extends Block{
|
||||
return to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new OverflowGateEntity();
|
||||
}
|
||||
|
||||
public class OverflowGateEntity extends TileEntity{
|
||||
Item lastItem;
|
||||
Tile lastInput;
|
||||
|
||||
@@ -19,6 +19,7 @@ public class Router extends Block{
|
||||
itemCapacity = 1;
|
||||
group = BlockGroup.transportation;
|
||||
unloadable = false;
|
||||
entityType = RouterEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -82,11 +83,6 @@ public class Router extends Block{
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new RouterEntity();
|
||||
}
|
||||
|
||||
public class RouterEntity extends TileEntity{
|
||||
Item lastItem;
|
||||
Tile lastInput;
|
||||
|
||||
@@ -28,6 +28,7 @@ public class Sorter extends Block{
|
||||
group = BlockGroup.transportation;
|
||||
configurable = true;
|
||||
unloadable = false;
|
||||
entityType = SorterEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,7 +85,7 @@ public class Sorter extends Block{
|
||||
}
|
||||
|
||||
boolean isSame(Tile tile, Tile other){
|
||||
return other != null && other.block() instanceof Sorter && other.<SorterEntity>entity().sortItem == tile.<SorterEntity>entity().sortItem;
|
||||
return other != null && other.block() instanceof Sorter;
|
||||
}
|
||||
|
||||
Tile getTileTarget(Item item, Tile dest, Tile source, boolean flip){
|
||||
@@ -137,12 +138,6 @@ public class Sorter extends Block{
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new SorterEntity();
|
||||
}
|
||||
|
||||
|
||||
public class SorterEntity extends TileEntity{
|
||||
@Nullable Item sortItem;
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package io.anuke.mindustry.world.blocks.liquid;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.mindustry.type.Liquid;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Edges;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
public class ArmoredConduit extends Conduit{
|
||||
protected TextureRegion capRegion;
|
||||
|
||||
public ArmoredConduit(String name){
|
||||
super(name);
|
||||
leakResistance = 10f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
super.load();
|
||||
capRegion = Core.atlas.find(name + "-cap");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Tile tile){
|
||||
super.draw(tile);
|
||||
|
||||
// draw the cap when a conduit would normally leak
|
||||
Tile next = tile.front();
|
||||
if(next != null && next.getTeam() == tile.getTeam() && next.block().hasLiquids) return;
|
||||
|
||||
Draw.rect(capRegion, tile.drawx(), tile.drawy(), tile.rotation() * 90);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean acceptLiquid(Tile tile, Tile source, Liquid liquid, float amount){
|
||||
return super.acceptLiquid(tile, source, liquid, amount) && (source.block() instanceof Conduit) || Edges.getFacingEdge(source, tile).relativeTo(tile) == tile.rotation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
|
||||
return otherblock.outputsLiquid && blendsArmored(tile, rotation, otherx, othery, otherrot, otherblock);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.anuke.mindustry.world.blocks.distribution;
|
||||
package io.anuke.mindustry.world.blocks.liquid;
|
||||
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
@@ -21,12 +21,15 @@ public class Conduit extends LiquidBlock implements Autotiler{
|
||||
protected TextureRegion[] topRegions = new TextureRegion[7];
|
||||
protected TextureRegion[] botRegions = new TextureRegion[7];
|
||||
|
||||
protected float leakResistance = 1.5f;
|
||||
|
||||
public Conduit(String name){
|
||||
super(name);
|
||||
rotate = true;
|
||||
solid = false;
|
||||
floating = true;
|
||||
conveyorPlacement = true;
|
||||
entityType = ConduitEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -109,7 +112,7 @@ public class Conduit extends LiquidBlock implements Autotiler{
|
||||
entity.smoothLiquid = Mathf.lerpDelta(entity.smoothLiquid, entity.liquids.total() / liquidCapacity, 0.05f);
|
||||
|
||||
if(tile.entity.liquids.total() > 0.001f && tile.entity.timer.get(timerFlow, 1)){
|
||||
tryMoveLiquid(tile, tile.getNearby(tile.rotation()), true, tile.entity.liquids.current());
|
||||
tryMoveLiquid(tile, tile.getNearby(tile.rotation()), leakResistance, tile.entity.liquids.current());
|
||||
entity.noSleep();
|
||||
}else{
|
||||
entity.sleep();
|
||||
@@ -128,11 +131,6 @@ public class Conduit extends LiquidBlock implements Autotiler{
|
||||
&& ((source.absoluteRelativeTo(tile.x, tile.y) + 2) % 4 != tile.rotation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new ConduitEntity();
|
||||
}
|
||||
|
||||
public static class ConduitEntity extends TileEntity{
|
||||
public float smoothLiquid;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package io.anuke.mindustry.world.blocks.distribution;
|
||||
package io.anuke.mindustry.world.blocks.liquid;
|
||||
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.blocks.distribution.*;
|
||||
import io.anuke.mindustry.world.meta.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
@@ -29,10 +30,12 @@ public class LiquidBridge extends ItemBridge{
|
||||
if(!linkValid(tile, other)){
|
||||
tryDumpLiquid(tile, entity.liquids.current());
|
||||
}else{
|
||||
((ItemBridgeEntity)world.tile(entity.link).entity).incoming.add(tile.pos());
|
||||
|
||||
if(entity.cons.valid()){
|
||||
float alpha = 0.04f;
|
||||
if(hasPower){
|
||||
alpha *= entity.power.satisfaction; // Exceed boot time unless power is at max.
|
||||
alpha *= entity.efficiency(); // Exceed boot time unless power is at max.
|
||||
}
|
||||
entity.uptime = Mathf.lerpDelta(entity.uptime, 1f, alpha);
|
||||
}else{
|
||||
@@ -1,9 +1,10 @@
|
||||
package io.anuke.mindustry.world.blocks.distribution;
|
||||
package io.anuke.mindustry.world.blocks.liquid;
|
||||
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.blocks.distribution.*;
|
||||
import io.anuke.mindustry.world.meta.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
@@ -29,6 +30,8 @@ public class LiquidExtendingBridge extends ExtendingItemBridge{
|
||||
if(!linkValid(tile, other)){
|
||||
tryDumpLiquid(tile, entity.liquids.current());
|
||||
}else{
|
||||
((ItemBridgeEntity)world.tile(entity.link).entity).incoming.add(tile.pos());
|
||||
|
||||
if(entity.cons.valid()){
|
||||
entity.uptime = Mathf.lerpDelta(entity.uptime, 1f, 0.04f);
|
||||
}else{
|
||||
@@ -1,7 +1,8 @@
|
||||
package io.anuke.mindustry.world.blocks.distribution;
|
||||
package io.anuke.mindustry.world.blocks.liquid;
|
||||
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
import io.anuke.mindustry.world.meta.*;
|
||||
@@ -35,10 +36,13 @@ public class LiquidJunction extends LiquidBlock{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tile getLiquidDestination(Tile tile, Tile source){
|
||||
public Tile getLiquidDestination(Tile tile, Tile source, Liquid liquid){
|
||||
int dir = source.relativeTo(tile.x, tile.y);
|
||||
dir = (dir + 4) % 4;
|
||||
Tile next = tile.getNearby(dir).link();
|
||||
return next.block().getLiquidDestination(next, tile);
|
||||
if(!next.block().acceptLiquid(next, tile, liquid, 0f) && !(next.block() instanceof LiquidJunction)){
|
||||
return tile;
|
||||
}
|
||||
return next.block().getLiquidDestination(next, tile, liquid);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package io.anuke.mindustry.world.blocks.liquid;
|
||||
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.blocks.*;
|
||||
import io.anuke.mindustry.world.meta.*;
|
||||
|
||||
//TODO implement later
|
||||
public class LiquidOverflowGate extends LiquidBlock{
|
||||
int topRegion;
|
||||
|
||||
public LiquidOverflowGate(String name){
|
||||
super(name);
|
||||
rotate = true;
|
||||
topRegion = reg("-top");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
stats.remove(BlockStat.liquidCapacity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBars(){
|
||||
super.setBars();
|
||||
bars.remove("liquid");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Tile tile){
|
||||
Draw.rect(name, tile.drawx(), tile.drawy());
|
||||
Draw.rect(reg(topRegion), tile.drawx(), tile.drawy(), tile.rotation() * 90);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion[] generateIcons(){
|
||||
return new TextureRegion[]{Core.atlas.find(name), Core.atlas.find(name + "-top")};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tile getLiquidDestination(Tile tile, Tile source, Liquid liquid){
|
||||
int dir = source.relativeTo(tile.x, tile.y);
|
||||
dir = (dir + 4) % 4;
|
||||
Tile next = tile.getNearby(dir).link();
|
||||
if(!next.block().acceptLiquid(next, tile, liquid, 0.0001f) && !(next.block() instanceof LiquidOverflowGate || next.block() instanceof LiquidJunction)){
|
||||
return tile;
|
||||
}
|
||||
return next.block().getLiquidDestination(next, tile, liquid);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.anuke.mindustry.world.blocks.distribution;
|
||||
package io.anuke.mindustry.world.blocks.liquid;
|
||||
|
||||
import io.anuke.mindustry.type.Liquid;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
@@ -1,4 +1,4 @@
|
||||
package io.anuke.mindustry.world.blocks.distribution;
|
||||
package io.anuke.mindustry.world.blocks.liquid;
|
||||
|
||||
public class LiquidTank extends LiquidRouter{
|
||||
|
||||
@@ -7,14 +7,12 @@ import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.geom.*;
|
||||
import io.anuke.arc.scene.ui.*;
|
||||
import io.anuke.arc.scene.ui.TextField.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.arc.util.pooling.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.net.*;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
import io.anuke.mindustry.ui.dialogs.*;
|
||||
@@ -33,6 +31,7 @@ public class MessageBlock extends Block{
|
||||
configurable = true;
|
||||
solid = true;
|
||||
destructible = true;
|
||||
entityType = MessageBlockEntity::new;
|
||||
}
|
||||
|
||||
@Remote(targets = Loc.both, called = Loc.both, forward = true)
|
||||
@@ -99,7 +98,7 @@ public class MessageBlock extends Block{
|
||||
public void buildTable(Tile tile, Table table){
|
||||
MessageBlockEntity entity = tile.entity();
|
||||
|
||||
table.addImageButton(io.anuke.mindustry.gen.Icon.pencilSmall, () -> {
|
||||
table.addImageButton(Icon.pencilSmall, () -> {
|
||||
if(mobile){
|
||||
Core.input.getTextInput(new TextInput(){{
|
||||
text = entity.message;
|
||||
@@ -147,11 +146,6 @@ public class MessageBlock extends Block{
|
||||
table.setPosition(pos.x, pos.y, Align.bottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new MessageBlockEntity();
|
||||
}
|
||||
|
||||
public class MessageBlockEntity extends TileEntity{
|
||||
protected String message = "";
|
||||
protected String[] lines = {""};
|
||||
|
||||
@@ -7,7 +7,6 @@ import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
@@ -17,7 +16,7 @@ import io.anuke.mindustry.world.meta.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class ImpactReactor extends PowerGenerator{
|
||||
protected int timerUse = timers++;
|
||||
@@ -39,6 +38,7 @@ public class ImpactReactor extends PowerGenerator{
|
||||
liquidCapacity = 30f;
|
||||
hasItems = true;
|
||||
outputsPower = consumesPower = true;
|
||||
entityType = FusionReactorEntity::new;
|
||||
|
||||
bottomRegion = reg("-bottom");
|
||||
plasmaRegions = new int[plasmas];
|
||||
@@ -71,11 +71,11 @@ public class ImpactReactor extends PowerGenerator{
|
||||
public void update(Tile tile){
|
||||
FusionReactorEntity entity = tile.entity();
|
||||
|
||||
if(entity.cons.valid() && entity.power.satisfaction >= 0.99f){
|
||||
if(entity.cons.valid() && entity.power.status >= 0.99f){
|
||||
boolean prevOut = getPowerProduction(tile) <= consumes.getPower().requestedPower(entity);
|
||||
|
||||
entity.warmup = Mathf.lerpDelta(entity.warmup, 1f, warmupSpeed);
|
||||
if(Mathf.isEqual(entity.warmup, 1f, 0.001f)){
|
||||
if(Mathf.equal(entity.warmup, 1f, 0.001f)){
|
||||
entity.warmup = 1f;
|
||||
}
|
||||
|
||||
@@ -117,13 +117,14 @@ public class ImpactReactor extends PowerGenerator{
|
||||
}
|
||||
|
||||
@Override
|
||||
public TextureRegion[] generateIcons(){
|
||||
return new TextureRegion[]{Core.atlas.find(name + "-bottom"), Core.atlas.find(name)};
|
||||
public void drawLight(Tile tile){
|
||||
float fract = tile.<FusionReactorEntity>entity().warmup;
|
||||
renderer.lights.add(tile.drawx(), tile.drawy(), (110f + Mathf.absin(5, 5f)) * fract, Tmp.c1.set(plasma2).lerp(plasma1, Mathf.absin(7f, 0.2f)), 0.8f * fract);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new FusionReactorEntity();
|
||||
public TextureRegion[] generateIcons(){
|
||||
return new TextureRegion[]{Core.atlas.find(name + "-bottom"), Core.atlas.find(name)};
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,7 +133,7 @@ public class ImpactReactor extends PowerGenerator{
|
||||
|
||||
FusionReactorEntity entity = tile.entity();
|
||||
|
||||
if(entity.warmup < 0.4f) return;
|
||||
if(entity.warmup < 0.4f || !state.rules.reactorExplosions) return;
|
||||
|
||||
Sounds.explosionbig.at(tile);
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.entities.Effects.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.consumers.*;
|
||||
@@ -37,15 +36,15 @@ public class ItemLiquidGenerator extends PowerGenerator{
|
||||
protected boolean defaults = false;
|
||||
|
||||
public ItemLiquidGenerator(boolean hasItems, boolean hasLiquids, String name){
|
||||
super(name);
|
||||
this(name);
|
||||
this.hasItems = hasItems;
|
||||
this.hasLiquids = hasLiquids;
|
||||
|
||||
setDefaults();
|
||||
}
|
||||
|
||||
public ItemLiquidGenerator(String name){
|
||||
super(name);
|
||||
this.entityType = ItemLiquidGeneratorEntity::new;
|
||||
}
|
||||
|
||||
protected void setDefaults(){
|
||||
@@ -140,7 +139,7 @@ public class ItemLiquidGenerator extends PowerGenerator{
|
||||
if(entity.generateTime > 0f){
|
||||
entity.generateTime -= Math.min(1f / itemDuration * entity.delta(), entity.generateTime);
|
||||
|
||||
if(randomlyExplode && Mathf.chance(entity.delta() * 0.06 * Mathf.clamp(entity.explosiveness - 0.5f))){
|
||||
if(randomlyExplode && state.rules.reactorExplosions && Mathf.chance(entity.delta() * 0.06 * Mathf.clamp(entity.explosiveness - 0.5f))){
|
||||
//this block is run last so that in the event of a block destruction, no code relies on the block type
|
||||
Core.app.post(() -> {
|
||||
entity.damage(Mathf.random(11f));
|
||||
@@ -174,6 +173,13 @@ public class ItemLiquidGenerator extends PowerGenerator{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawLight(Tile tile){
|
||||
ItemLiquidGeneratorEntity entity = tile.entity();
|
||||
|
||||
renderer.lights.add(tile.drawx(), tile.drawy(), (60f + Mathf.absin(10f, 5f)) * entity.productionEfficiency * size, Color.orange, 0.5f);
|
||||
}
|
||||
|
||||
protected float getItemEfficiency(Item item){
|
||||
return 0.0f;
|
||||
}
|
||||
@@ -182,11 +188,6 @@ public class ItemLiquidGenerator extends PowerGenerator{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new ItemLiquidGeneratorEntity();
|
||||
}
|
||||
|
||||
public static class ItemLiquidGeneratorEntity extends GeneratorEntity{
|
||||
public float explosiveness;
|
||||
public float heat;
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
package io.anuke.mindustry.world.blocks.power;
|
||||
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.scene.ui.layout.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.entities.type.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class LightBlock extends Block{
|
||||
private static int lastColor = 0;
|
||||
|
||||
protected float brightness = 0.9f;
|
||||
protected float radius = 200f;
|
||||
protected int topRegion;
|
||||
|
||||
public LightBlock(String name){
|
||||
super(name);
|
||||
hasPower = true;
|
||||
update = true;
|
||||
topRegion = reg("-top");
|
||||
configurable = true;
|
||||
entityType = LightEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playerPlaced(Tile tile){
|
||||
if(lastColor != 0){
|
||||
tile.configure(lastColor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Tile tile){
|
||||
super.draw(tile);
|
||||
LightEntity entity = tile.entity();
|
||||
|
||||
Draw.blend(Blending.additive);
|
||||
Draw.color(Tmp.c1.set(entity.color), entity.efficiency() * 0.3f);
|
||||
Draw.rect(reg(topRegion), tile.drawx(), tile.drawy());
|
||||
Draw.color();
|
||||
Draw.blend();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildTable(Tile tile, Table table){
|
||||
LightEntity entity = tile.entity();
|
||||
|
||||
table.addImageButton(Icon.pencilSmall, () -> {
|
||||
ui.picker.show(Tmp.c1.set(entity.color).a(0.5f), false, res -> {
|
||||
entity.color = res.rgba();
|
||||
lastColor = entity.color;
|
||||
});
|
||||
control.input.frag.config.hideConfig();
|
||||
}).size(40f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configured(Tile tile, Player player, int value){
|
||||
tile.<LightEntity>entity().color = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawLight(Tile tile){
|
||||
LightEntity entity = tile.entity();
|
||||
renderer.lights.add(tile.drawx(), tile.drawy(), radius, Tmp.c1.set(entity.color), brightness * tile.entity.efficiency());
|
||||
}
|
||||
|
||||
public class LightEntity extends TileEntity{
|
||||
public int color = Pal.accent.rgba();
|
||||
|
||||
@Override
|
||||
public int config(){
|
||||
return color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(DataOutput stream) throws IOException{
|
||||
super.write(stream);
|
||||
stream.writeInt(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void read(DataInput stream, byte revision) throws IOException{
|
||||
super.read(stream, revision);
|
||||
color = stream.readInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +1,32 @@
|
||||
package io.anuke.mindustry.world.blocks.power;
|
||||
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.graphics.Color;
|
||||
import io.anuke.arc.graphics.*;
|
||||
import io.anuke.arc.graphics.g2d.*;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.content.Fx;
|
||||
import io.anuke.mindustry.entities.Damage;
|
||||
import io.anuke.mindustry.entities.Effects;
|
||||
import io.anuke.mindustry.entities.type.TileEntity;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.math.geom.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.content.*;
|
||||
import io.anuke.mindustry.entities.*;
|
||||
import io.anuke.mindustry.game.EventType.*;
|
||||
import io.anuke.mindustry.gen.*;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.type.Item;
|
||||
import io.anuke.mindustry.type.Liquid;
|
||||
import io.anuke.mindustry.ui.Bar;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.graphics.*;
|
||||
import io.anuke.mindustry.type.*;
|
||||
import io.anuke.mindustry.ui.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.consumers.*;
|
||||
import io.anuke.mindustry.world.meta.BlockStat;
|
||||
import io.anuke.mindustry.world.meta.StatUnit;
|
||||
import io.anuke.mindustry.world.meta.*;
|
||||
|
||||
import java.io.*;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class NuclearReactor extends PowerGenerator{
|
||||
protected final int timerFuel = timers++;
|
||||
|
||||
protected final Vector2 tr = new Vector2();
|
||||
|
||||
protected Color lightColor = Color.valueOf("7f19ea");
|
||||
protected Color coolColor = new Color(1, 1, 1, 0f);
|
||||
protected Color hotColor = Color.valueOf("ff9575a3");
|
||||
protected float itemDuration = 120; //time to consume 1 fuel
|
||||
@@ -48,6 +45,7 @@ public class NuclearReactor extends PowerGenerator{
|
||||
liquidCapacity = 30;
|
||||
hasItems = true;
|
||||
hasLiquids = true;
|
||||
entityType = NuclearReactorEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -93,10 +91,9 @@ public class NuclearReactor extends PowerGenerator{
|
||||
}
|
||||
|
||||
Liquid liquid = cliquid.liquid;
|
||||
float liquidAmount = cliquid.amount;
|
||||
|
||||
if(entity.heat > 0){
|
||||
float maxUsed = Math.min(Math.min(entity.liquids.get(liquid), entity.heat / coolantPower), liquidAmount * entity.delta());
|
||||
float maxUsed = Math.min(entity.liquids.get(liquid), entity.heat / coolantPower);
|
||||
entity.heat -= maxUsed * coolantPower;
|
||||
entity.liquids.remove(liquid, maxUsed);
|
||||
}
|
||||
@@ -127,7 +124,7 @@ public class NuclearReactor extends PowerGenerator{
|
||||
|
||||
int fuel = entity.items.get(consumes.<ConsumeItems>get(ConsumeType.item).items[0].item);
|
||||
|
||||
if(fuel < 5 && entity.heat < 0.5f) return;
|
||||
if((fuel < 5 && entity.heat < 0.5f) || !state.rules.reactorExplosions) return;
|
||||
|
||||
Effects.shake(6f, 16f, tile.worldx(), tile.worldy());
|
||||
Effects.effect(Fx.nuclearShockwave, tile.worldx(), tile.worldy());
|
||||
@@ -152,6 +149,13 @@ public class NuclearReactor extends PowerGenerator{
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawLight(Tile tile){
|
||||
NuclearReactorEntity entity = tile.entity();
|
||||
float fract = entity.productionEfficiency;
|
||||
renderer.lights.add(tile.drawx(), tile.drawy(), (90f + Mathf.absin(5, 5f)) * fract, Tmp.c1.set(lightColor).lerp(Color.scarlet, entity.heat), 0.6f * fract);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Tile tile){
|
||||
super.draw(tile);
|
||||
@@ -176,11 +180,6 @@ public class NuclearReactor extends PowerGenerator{
|
||||
Draw.reset();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new NuclearReactorEntity();
|
||||
}
|
||||
|
||||
public static class NuclearReactorEntity extends GeneratorEntity{
|
||||
public float heat;
|
||||
public float flash;
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
package io.anuke.mindustry.world.blocks.power;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.mindustry.ui.Bar;
|
||||
import io.anuke.arc.util.Eachable;
|
||||
import io.anuke.mindustry.ui.Cicon;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.arc.graphics.g2d.TextureRegion;
|
||||
import io.anuke.mindustry.entities.traits.BuilderTrait;
|
||||
|
||||
public class PowerDiode extends Block{
|
||||
protected TextureRegion arrow;
|
||||
|
||||
public PowerDiode(String name){
|
||||
super(name);
|
||||
rotate = true;
|
||||
update = true;
|
||||
solid = true;
|
||||
insulated = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(Tile tile){
|
||||
super.update(tile);
|
||||
|
||||
if(tile.front() == null || tile.back() == null || !tile.back().block().hasPower || !tile.front().block().hasPower) return;
|
||||
|
||||
PowerGraph backGraph = tile.back().entity.power.graph;
|
||||
PowerGraph frontGraph = tile.front().entity.power.graph;
|
||||
if(backGraph == frontGraph) return;
|
||||
|
||||
// 0f - 1f of battery capacity in use
|
||||
float backStored = backGraph.getBatteryStored() / backGraph.getTotalBatteryCapacity();
|
||||
float frontStored = frontGraph.getBatteryStored() / frontGraph.getTotalBatteryCapacity();
|
||||
|
||||
// try to send if the back side has more % capacity stored than the front side
|
||||
if(backStored > frontStored) {
|
||||
// send half of the difference
|
||||
float amount = backGraph.getBatteryStored() * (backStored - frontStored) / 2;
|
||||
// prevent sending more than the front can handle
|
||||
amount = Mathf.clamp(amount, 0, frontGraph.getTotalBatteryCapacity() * (1 - frontStored));
|
||||
|
||||
backGraph.useBatteries(amount);
|
||||
frontGraph.chargeBatteries(amount);
|
||||
}
|
||||
}
|
||||
|
||||
// battery % of the graph on either side, defaults to zero
|
||||
protected float bar(Tile tile){
|
||||
return (tile != null && tile.block().hasPower) ? tile.entity.power.graph.getBatteryStored() / tile.entity.power.graph.getTotalBatteryCapacity() : 0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBars(){
|
||||
super.setBars();
|
||||
|
||||
bars.add("back", entity -> new Bar("bar.input", Pal.powerBar, () -> bar(entity.tile.back())));
|
||||
bars.add("front", entity -> new Bar("bar.output", Pal.powerBar, () -> bar(entity.tile.front())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
super.load();
|
||||
arrow = Core.atlas.find(name + "-arrow");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Tile tile){
|
||||
Draw.rect(region, tile.drawx(), tile.drawy(), 0);
|
||||
Draw.rect(arrow, tile.drawx(), tile.drawy(), rotate ? tile.rotation() * 90 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawRequestRegion(BuilderTrait.BuildRequest req, Eachable<BuilderTrait.BuildRequest> list) {
|
||||
TextureRegion reg = icon(Cicon.full);
|
||||
Draw.rect(icon(Cicon.full), req.drawx(), req.drawy(),
|
||||
reg.getWidth() * req.animScale * Draw.scl,
|
||||
reg.getHeight() * req.animScale * Draw.scl,
|
||||
0);
|
||||
Draw.rect(arrow, req.drawx(), req.drawy(),
|
||||
arrow.getWidth() * req.animScale * Draw.scl,
|
||||
arrow.getHeight() * req.animScale * Draw.scl,
|
||||
!rotate ? 0 : req.rotation * 90);
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ public class PowerGenerator extends PowerDistributor{
|
||||
super(name);
|
||||
baseExplosiveness = 5f;
|
||||
flags = EnumSet.of(BlockFlag.producer);
|
||||
entityType = GeneratorEntity::new;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -51,11 +52,6 @@ public class PowerGenerator extends PowerDistributor{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TileEntity newEntity(){
|
||||
return new GeneratorEntity();
|
||||
}
|
||||
|
||||
public static class GeneratorEntity extends TileEntity{
|
||||
public float generateTime;
|
||||
/** The efficiency of the producer. An efficiency of 1.0 means 100% */
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package io.anuke.mindustry.world.blocks.power;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.*;
|
||||
import io.anuke.arc.collection.*;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.WindowedMean;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.arc.math.*;
|
||||
import io.anuke.arc.util.*;
|
||||
import io.anuke.mindustry.world.*;
|
||||
import io.anuke.mindustry.world.consumers.*;
|
||||
|
||||
public class PowerGraph{
|
||||
@@ -47,9 +46,9 @@ public class PowerGraph{
|
||||
}
|
||||
|
||||
public float getSatisfaction(){
|
||||
if(Mathf.isZero(lastPowerProduced)){
|
||||
if(Mathf.zero(lastPowerProduced)){
|
||||
return 0f;
|
||||
}else if(Mathf.isZero(lastPowerNeeded)){
|
||||
}else if(Mathf.zero(lastPowerNeeded)){
|
||||
return 1f;
|
||||
}
|
||||
return Mathf.clamp(lastPowerProduced / lastPowerNeeded);
|
||||
@@ -83,7 +82,7 @@ public class PowerGraph{
|
||||
for(Tile battery : batteries){
|
||||
Consumers consumes = battery.block().consumes;
|
||||
if(consumes.hasPower()){
|
||||
totalAccumulator += battery.entity.power.satisfaction * consumes.getPower().capacity;
|
||||
totalAccumulator += battery.entity.power.status * consumes.getPower().capacity;
|
||||
}
|
||||
}
|
||||
return totalAccumulator;
|
||||
@@ -94,7 +93,7 @@ public class PowerGraph{
|
||||
for(Tile battery : batteries){
|
||||
if(battery.block().consumes.hasPower()){
|
||||
ConsumePower power = battery.block().consumes.getPower();
|
||||
totalCapacity += (1f - battery.entity.power.satisfaction) * power.capacity;
|
||||
totalCapacity += (1f - battery.entity.power.status) * power.capacity;
|
||||
}
|
||||
}
|
||||
return totalCapacity;
|
||||
@@ -112,14 +111,14 @@ public class PowerGraph{
|
||||
|
||||
public float useBatteries(float needed){
|
||||
float stored = getBatteryStored();
|
||||
if(Mathf.isEqual(stored, 0f)) return 0f;
|
||||
if(Mathf.equal(stored, 0f)) return 0f;
|
||||
|
||||
float used = Math.min(stored, needed);
|
||||
float consumedPowerPercentage = Math.min(1.0f, needed / stored);
|
||||
for(Tile battery : batteries){
|
||||
Consumers consumes = battery.block().consumes;
|
||||
if(consumes.hasPower()){
|
||||
battery.entity.power.satisfaction *= (1f-consumedPowerPercentage);
|
||||
battery.entity.power.status *= (1f-consumedPowerPercentage);
|
||||
}
|
||||
}
|
||||
return used;
|
||||
@@ -129,14 +128,14 @@ public class PowerGraph{
|
||||
float capacity = getBatteryCapacity();
|
||||
//how much of the missing in each battery % is charged
|
||||
float chargedPercent = Math.min(excess/capacity, 1f);
|
||||
if(Mathf.isEqual(capacity, 0f)) return 0f;
|
||||
if(Mathf.equal(capacity, 0f)) return 0f;
|
||||
|
||||
for(Tile battery : batteries){
|
||||
Consumers consumes = battery.block().consumes;
|
||||
if(consumes.hasPower()){
|
||||
ConsumePower consumePower = consumes.getPower();
|
||||
if(consumePower.capacity > 0f){
|
||||
battery.entity.power.satisfaction += (1f-battery.entity.power.satisfaction) * chargedPercent;
|
||||
battery.entity.power.status += (1f-battery.entity.power.status) * chargedPercent;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -145,26 +144,26 @@ public class PowerGraph{
|
||||
|
||||
public void distributePower(float needed, float produced){
|
||||
//distribute even if not needed. this is because some might be requiring power but not using it; it updates consumers
|
||||
float coverage = Mathf.isZero(needed) && Mathf.isZero(produced) ? 0f : Mathf.isZero(needed) ? 1f : Math.min(1, produced / needed);
|
||||
float coverage = Mathf.zero(needed) && Mathf.zero(produced) ? 0f : Mathf.zero(needed) ? 1f : Math.min(1, produced / needed);
|
||||
for(Tile consumer : consumers){
|
||||
Consumers consumes = consumer.block().consumes;
|
||||
if(consumes.hasPower()){
|
||||
ConsumePower consumePower = consumes.getPower();
|
||||
if(consumePower.buffered){
|
||||
if(!Mathf.isZero(consumePower.capacity)){
|
||||
if(!Mathf.zero(consumePower.capacity)){
|
||||
// Add an equal percentage of power to all buffers, based on the global power coverage in this graph
|
||||
float maximumRate = consumePower.requestedPower(consumer.entity) * coverage * consumer.entity.delta();
|
||||
consumer.entity.power.satisfaction = Mathf.clamp(consumer.entity.power.satisfaction + maximumRate / consumePower.capacity);
|
||||
consumer.entity.power.status = Mathf.clamp(consumer.entity.power.status + maximumRate / consumePower.capacity);
|
||||
}
|
||||
}else{
|
||||
//valid consumers get power as usual
|
||||
if(otherConsumersAreValid(consumer, consumePower)){
|
||||
consumer.entity.power.satisfaction = coverage;
|
||||
consumer.entity.power.status = coverage;
|
||||
}else{ //invalid consumers get an estimate, if they were to activate
|
||||
consumer.entity.power.satisfaction = Math.min(1, produced / (needed + consumePower.usage * consumer.entity.delta()));
|
||||
consumer.entity.power.status = Math.min(1, produced / (needed + consumePower.usage * consumer.entity.delta()));
|
||||
//just in case
|
||||
if(Float.isNaN(consumer.entity.power.satisfaction)){
|
||||
consumer.entity.power.satisfaction = 0f;
|
||||
if(Float.isNaN(consumer.entity.power.status)){
|
||||
consumer.entity.power.status = 0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,11 +175,12 @@ public class PowerGraph{
|
||||
if(Core.graphics.getFrameId() == lastFrameUpdated){
|
||||
return;
|
||||
}else if(!consumers.isEmpty() && consumers.first().isEnemyCheat()){
|
||||
//when cheating, just set satisfaction to 1
|
||||
//when cheating, just set status to 1
|
||||
for(Tile tile : consumers){
|
||||
tile.entity.power.satisfaction = 1f;
|
||||
tile.entity.power.status = 1f;
|
||||
}
|
||||
|
||||
lastPowerNeeded = lastPowerProduced = 1f;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -192,21 +192,22 @@ public class PowerGraph{
|
||||
lastPowerNeeded = powerNeeded;
|
||||
lastPowerProduced = powerProduced;
|
||||
|
||||
powerBalance.addValue((powerProduced - powerNeeded) / Time.delta());
|
||||
if(!(consumers.size == 0 && producers.size == 0 && batteries.size == 0)){
|
||||
|
||||
if(consumers.size == 0 && producers.size == 0 && batteries.size == 0){
|
||||
return;
|
||||
}
|
||||
|
||||
if(!Mathf.isEqual(powerNeeded, powerProduced)){
|
||||
if(powerNeeded > powerProduced){
|
||||
powerProduced += useBatteries(powerNeeded - powerProduced);
|
||||
}else if(powerProduced > powerNeeded){
|
||||
powerProduced -= chargeBatteries(powerProduced - powerNeeded);
|
||||
if(!Mathf.equal(powerNeeded, powerProduced)){
|
||||
if(powerNeeded > powerProduced){
|
||||
float powerBatteryUsed = useBatteries(powerNeeded - powerProduced);
|
||||
powerProduced += powerBatteryUsed;
|
||||
lastPowerProduced += powerBatteryUsed;
|
||||
}else if(powerProduced > powerNeeded){
|
||||
powerProduced -= chargeBatteries(powerProduced - powerNeeded);
|
||||
}
|
||||
}
|
||||
|
||||
distributePower(powerNeeded, powerProduced);
|
||||
}
|
||||
|
||||
distributePower(powerNeeded, powerProduced);
|
||||
powerBalance.addValue((lastPowerProduced - lastPowerNeeded) / Time.delta());
|
||||
}
|
||||
|
||||
public void add(PowerGraph graph){
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user