Merge branches '6.0' and 'master' of https://github.com/Anuken/Mindustry into 6.0

# 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/graphics/Shaders.java
#	gradle.properties
This commit is contained in:
Anuken
2019-12-01 17:42:56 -05:00
178 changed files with 4412 additions and 1699 deletions

View File

@@ -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);

View File

@@ -32,8 +32,6 @@ import static io.anuke.arc.Core.settings;
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.*/
@@ -49,13 +47,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 */

View File

@@ -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,18 +50,18 @@ public class Blocks implements ContentList{
melter, separator, sporePress, pulverizer, incinerator, coalCentrifuge,
//sandbox
powerSource, powerVoid, itemSource, itemVoid, liquidSource, 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,
@@ -516,7 +518,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();
@@ -721,69 +723,11 @@ public class Blocks implements ContentList{
consumes.power(0.50f);
}};
//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));
}};
//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;
@@ -865,6 +809,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);
@@ -929,7 +904,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;
}};
@@ -1013,7 +988,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;
}};
@@ -1025,7 +1000,14 @@ public class Blocks implements ContentList{
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;
}};
@@ -1037,17 +1019,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;
@@ -1152,7 +1134,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"){{
@@ -1821,6 +1803,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
}
}

View File

@@ -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
@@ -456,6 +456,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 -> {

View File

@@ -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);
}};
}
}

View File

@@ -199,6 +199,10 @@ public class TechTree implements ContentList{
node(phaseConduit, () -> {
});
node(platedConduit, () -> {
});
});
node(rotaryPump, () -> {

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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();

View File

@@ -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 + "";
}

View File

@@ -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){
}

View File

@@ -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

View File

@@ -35,14 +35,14 @@ public interface BuilderTrait extends Entity, TeamTrait{
float finalPlaceDst = state.rules.infiniteResources ? Float.MAX_VALUE : placeDistance;
Unit unit = (Unit)this;
//remove already completed build requests
removal.clear();
removal.addAll(buildQueue());
Structs.filter(buildQueue(), req -> {
Iterator<BuildRequest> it = buildQueue().iterator();
while(it.hasNext()){
BuildRequest req = it.next();
Tile tile = world.tile(req.x, req.y);
return tile == null || (req.breaking && tile.block() == Blocks.air) || (!req.breaking && (tile.rotation() == req.rotation || !req.block.rotate) && tile.block() == req.block);
});
if(tile == null || (req.breaking && tile.block() == Blocks.air) || (!req.breaking && (tile.rotation() == req.rotation || !req.block.rotate) && tile.block() == req.block)){
it.remove();
}
}
TileEntity core = unit.getClosestCore();
@@ -62,6 +62,8 @@ public interface BuilderTrait extends Entity, TeamTrait{
BuildRequest current = buildRequest();
if(dst(current.tile()) > finalPlaceDst) return;
Tile tile = world.tile(current.x, current.y);
if(!(tile.block() instanceof BuildBlock)){
@@ -113,7 +115,7 @@ public interface BuilderTrait extends Entity, TeamTrait{
/** @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) return false;
if(state.rules.infiniteResources || request.breaking || !request.initialized || core == null) return false;
return request.stuck && !core.items.has(request.block.requirements);
}
@@ -228,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()};
}

View File

@@ -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

View File

@@ -24,9 +24,7 @@ import io.anuke.mindustry.io.*;
import io.anuke.mindustry.net.Administration.*;
import io.anuke.mindustry.net.*;
import io.anuke.mindustry.type.*;
import io.anuke.mindustry.type.TypeID;
import io.anuke.mindustry.ui.*;
import io.anuke.mindustry.ui.Cicon;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.blocks.*;
@@ -352,6 +350,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

View File

@@ -15,6 +15,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.*;
@@ -89,7 +90,7 @@ public class TileEntity extends BaseEntity implements TargetTrait, HealthTrait{
/** Base efficiency. If this entity has non-buffered power, returns the power %, otherwise returns 1. */
public float efficiency(){
return power != null && !block.consumes.getPower().buffered ? power.status : 1f;
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. */
@@ -311,13 +312,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();
}
}

View File

@@ -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){

View File

@@ -37,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{}
@@ -138,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;
@@ -146,7 +154,7 @@ public class EventType{
this.amount = amount;
}
}
/** Called when the player taps a block. */
public static class TapEvent{
public final Tile tile;
@@ -157,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;
@@ -310,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;
}
@@ -327,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;
}
}
}

View File

@@ -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(){

View File

@@ -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. */

View File

@@ -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());

View File

@@ -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){

View File

@@ -10,5 +10,7 @@ public enum Layer{
/** "High" blocks, like turrets. */
turret,
/** Power lasers. */
power
power,
/** Extra layer that's always on top.*/
lights
}

View 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();
}
}

View 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();
}
}

View File

@@ -15,6 +15,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, slag;
public static void init(){
@@ -30,11 +31,26 @@ public class Shaders{
build = new UnitBuild();
fog = new FogShader();
menu = new MenuShader();
light = new LightShader();
water = new SurfaceShader("water");
tar = new SurfaceShader("tar");
slag = new SurfaceShader("slag");
}
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;

View File

@@ -24,6 +24,22 @@ public enum Binding implements KeyBind{
schematic_flip_x(KeyCode.Z),
schematic_flip_y(KeyCode.X),
schematic_menu(KeyCode.T),
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),

View File

@@ -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. */

View File

@@ -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());
}

View File

@@ -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);
}
}
}

View File

@@ -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,8 +11,6 @@ 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.*;
@@ -71,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) -> {
@@ -106,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{
@@ -116,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 + "-" : "";
@@ -152,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",
@@ -206,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);
}
@@ -343,7 +369,13 @@ public class ContentParser{
init();
}
//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));
if(!parsers.containsKey(type)){
throw new SerializationException("No parsers for content type '" + type + "'");
}
@@ -361,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){
@@ -371,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){
@@ -381,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();
@@ -457,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() + ")");

View File

@@ -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") || file.extension().equals("hjson") || file.extension().equals("js")){
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;
}
}
}
}

View File

@@ -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;
}

View File

@@ -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));

View File

@@ -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];
}
}

View File

@@ -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 */

View File

@@ -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)));

View File

@@ -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"))
};

View File

@@ -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");

View 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();
});
}
}

View File

@@ -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();
}
}

View File

@@ -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();
});
}));
}

View File

@@ -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.*;
@@ -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();
@@ -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(){

View File

@@ -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();
}

View File

@@ -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();
}

View File

@@ -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 -> {

View File

@@ -221,6 +221,8 @@ public class SettingsMenuDialog extends SettingsDialog{
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){

View File

@@ -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 + "";
}

View File

@@ -64,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()){
@@ -347,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);
}
}

View File

@@ -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);

View File

@@ -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;
}
}
}

View File

@@ -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;
@@ -292,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);
@@ -363,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 String localizedName(){
return localizedName;
@@ -596,7 +627,7 @@ public class Block extends BlockStorage{
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++){
@@ -706,10 +737,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();
}
@@ -723,10 +756,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));
@@ -766,7 +799,7 @@ public class Block extends BlockStorage{
}
last = out;
packer.pack(name, out);
packer.add(PageType.main, name, out);
}
if(generatedIcons.length > 1){
@@ -778,7 +811,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);
}
@@ -825,8 +858,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. */

View File

@@ -116,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;
@@ -142,10 +142,14 @@ 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){
@@ -175,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;
}

View File

@@ -327,19 +327,19 @@ public class Tile implements Position, TargetTrait{
}
// ▲ ▲ ▼ ▼ ◀ ▶ ◀ ▶ B A
public Tile front(){
public @Nullable Tile front(){
return getNearbyLink((rotation + 4) % 4);
}
public Tile right(){
public @Nullable Tile right(){
return getNearbyLink((rotation + 3) % 4);
}
public Tile back(){
public @Nullable Tile back(){
return getNearbyLink((rotation + 2) % 4);
}
public Tile left(){
public @Nullable Tile left(){
return getNearbyLink((rotation + 1) % 4);
}

View File

@@ -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)));

View File

@@ -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.

View File

@@ -10,8 +10,10 @@ import io.anuke.arc.math.geom.*;
import io.anuke.arc.util.ArcAnnotate.*;
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;
@@ -87,9 +89,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;
@@ -98,7 +100,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());
}
}
@@ -115,7 +117,7 @@ public class Floor extends Block{
}
}
out.pack(name + "-edge", result);
packer.add(PageType.environment, name + "-edge", result);
}
@Override

View File

@@ -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);
}
}
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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();
}
@@ -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;

View File

@@ -38,6 +38,7 @@ public class MendProjector extends Block{
update = true;
hasPower = true;
hasItems = true;
entityType = MendEntity::new;
}
@Override
@@ -133,8 +134,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{

View File

@@ -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();
@@ -132,11 +138,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);

View File

@@ -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;
}

View File

@@ -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{

View File

@@ -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();

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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;
@@ -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();

View File

@@ -41,6 +41,7 @@ public class ItemBridge extends Block{
hasItems = true;
unloadable = false;
group = BlockGroup.transportation;
entityType = ItemBridgeEntity::new;
}
@Override
@@ -174,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();
}
}
@@ -297,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);
@@ -340,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);
}

View File

@@ -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);

View File

@@ -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;
@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -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 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){

View File

@@ -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{

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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;

View File

@@ -1,4 +1,4 @@
package io.anuke.mindustry.world.blocks.distribution;
package io.anuke.mindustry.world.blocks.liquid;
public class LiquidTank extends LiquidRouter{

View File

@@ -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 = {""};

View File

@@ -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];
@@ -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);

View File

@@ -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;

View File

@@ -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();
}
}
}

View File

@@ -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;

View File

@@ -27,7 +27,7 @@ public class PowerDiode extends Block{
public void update(Tile tile){
super.update(tile);
if(!tile.back().block().hasPower || !tile.front().block().hasPower) return;
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;
@@ -51,15 +51,15 @@ public class PowerDiode extends Block{
// battery % of the graph on either side, defaults to zero
protected float bar(Tile tile){
return tile.block().hasPower ? tile.entity.power.graph.getBatteryStored() / tile.entity.power.graph.getTotalBatteryCapacity() : 0f;
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.lighterOrange, () -> bar(entity.tile.back())) );
bars.add("front", entity -> new Bar("bar.output", Pal.lighterOrange, () -> bar(entity.tile.front())) );
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

View File

@@ -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% */

View File

@@ -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{
@@ -181,6 +180,7 @@ public class PowerGraph{
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.equal(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){

View File

@@ -91,7 +91,7 @@ public class PowerNode extends PowerBlock{
Core.bundle.format("bar.powerbalance",
((entity.power.graph.getPowerBalance() >= 0 ? "+" : "") + Strings.fixed(entity.power.graph.getPowerBalance() * 60, 1))),
() -> Pal.powerBar,
() -> Mathf.clamp(entity.power.graph.getPowerProduced() / entity.power.graph.getPowerNeeded())));
() -> Mathf.clamp(entity.power.graph.getLastPowerProduced() / entity.power.graph.getLastPowerNeeded())));
bars.add("batteries", entity -> new Bar(() ->
Core.bundle.format("bar.powerstored",

View File

@@ -1,8 +1,10 @@
package io.anuke.mindustry.world.blocks.power;
import io.anuke.arc.collection.EnumSet;
import io.anuke.mindustry.entities.type.TileEntity;
import io.anuke.mindustry.world.meta.StatUnit;
import io.anuke.arc.collection.*;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.meta.*;
import static io.anuke.mindustry.Vars.state;
public class SolarGenerator extends PowerGenerator{
@@ -10,6 +12,12 @@ public class SolarGenerator extends PowerGenerator{
super(name);
// Remove the BlockFlag.producer flag to make this a lower priority target than other generators.
flags = EnumSet.of();
entityType = GeneratorEntity::new;
}
@Override
public void update(Tile tile){
tile.<GeneratorEntity>entity().productionEfficiency = state.rules.lighting ? 1f - state.rules.ambientLight.a : 1f;
}
@Override
@@ -19,12 +27,4 @@ public class SolarGenerator extends PowerGenerator{
stats.remove(generationType);
stats.add(generationType, powerProduction * 60.0f, StatUnit.powerSecond);
}
@Override
public TileEntity newEntity(){
return new PowerGenerator.GeneratorEntity(){{
productionEfficiency = 1.0f;
}};
}
}

View File

@@ -1,12 +1,15 @@
package io.anuke.mindustry.world.blocks.power;
import io.anuke.arc.Core;
import io.anuke.arc.math.Mathf;
import io.anuke.mindustry.content.Fx;
import io.anuke.mindustry.entities.Effects;
import io.anuke.mindustry.entities.Effects.Effect;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.meta.Attribute;
import io.anuke.arc.*;
import io.anuke.arc.graphics.*;
import io.anuke.arc.math.*;
import io.anuke.mindustry.content.*;
import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.Effects.*;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.meta.*;
import static io.anuke.mindustry.Vars.renderer;
public class ThermalGenerator extends PowerGenerator{
protected Effect generateEffect = Fx.none;
@@ -29,6 +32,12 @@ public class ThermalGenerator extends PowerGenerator{
drawPlaceText(Core.bundle.formatFloat("bar.efficiency", sumAttribute(Attribute.heat, x, y) * 100, 1), x, y, valid);
}
@Override
public void drawLight(Tile tile){
GeneratorEntity entity = tile.entity();
renderer.lights.add(tile.drawx(), tile.drawy(), (40f + Mathf.absin(10f, 5f)) * entity.productionEfficiency * size, Color.scarlet, 0.4f);
}
@Override
public void onProximityAdded(Tile tile){
super.onProximityAdded(tile);

View File

@@ -28,6 +28,7 @@ public class Cultivator extends GenericCrafter{
public Cultivator(String name){
super(name);
craftEffect = Fx.none;
entityType = CultivatorEntity::new;
}
@Override
@@ -94,11 +95,6 @@ public class Cultivator extends GenericCrafter{
return new TextureRegion[]{Core.atlas.find(name), Core.atlas.find(name + "-top"),};
}
@Override
public TileEntity newEntity(){
return new CultivatorEntity();
}
@Override
public void onProximityAdded(Tile tile){
super.onProximityAdded(tile);

View File

@@ -66,6 +66,7 @@ public class Drill extends Block{
hasLiquids = true;
liquidCapacity = 5f;
hasItems = true;
entityType = DrillEntity::new;
idleSound = Sounds.drill;
idleSoundVolume = 0.003f;
@@ -133,6 +134,11 @@ public class Drill extends Block{
return tile.entity.items.total() < itemCapacity;
}
@Override
public boolean shouldIdleSound(Tile tile){
return tile.entity.efficiency() > 0.01f;
}
@Override
public void drawPlace(int x, int y, int rotation, boolean valid){
Tile tile = world.tile(x, y);
@@ -300,11 +306,6 @@ public class Drill extends Block{
}
}
@Override
public TileEntity newEntity(){
return new DrillEntity();
}
public int tier(){
return tier;
}

View File

@@ -2,7 +2,6 @@ package io.anuke.mindustry.world.blocks.production;
import io.anuke.arc.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.mindustry.entities.type.*;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.meta.*;
@@ -16,6 +15,7 @@ public class Fracker extends SolidPump{
public Fracker(String name){
super(name);
hasItems = true;
entityType = FrackerEntity::new;
}
@Override
@@ -85,11 +85,6 @@ public class Fracker extends SolidPump{
}
}
@Override
public TileEntity newEntity(){
return new FrackerEntity();
}
@Override
public float typeLiquid(Tile tile){
return tile.entity.liquids.get(result);

View File

@@ -36,6 +36,7 @@ public class GenericCrafter extends Block{
health = 60;
idleSound = Sounds.machine;
idleSoundVolume = 0.03f;
entityType = GenericCrafterEntity::new;
}
@Override
@@ -142,11 +143,6 @@ public class GenericCrafter extends Block{
return outputLiquid == null || !(tile.entity.liquids.get(outputLiquid.liquid) >= liquidCapacity);
}
@Override
public TileEntity newEntity(){
return new GenericCrafterEntity();
}
@Override
public int getMaximumAccepted(Tile tile, Item item){
return itemCapacity;

View File

@@ -1,11 +1,13 @@
package io.anuke.mindustry.world.blocks.production;
import io.anuke.arc.Core;
import io.anuke.arc.graphics.Color;
import io.anuke.arc.*;
import io.anuke.arc.graphics.*;
import io.anuke.arc.graphics.g2d.*;
import io.anuke.arc.math.Mathf;
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 static io.anuke.mindustry.Vars.renderer;
/** A GenericCrafter with a new glowing region drawn on top. */
public class GenericSmelter extends GenericCrafter{
@@ -45,4 +47,11 @@ public class GenericSmelter extends GenericCrafter{
Draw.color();
}
}
@Override
public void drawLight(Tile tile){
GenericCrafterEntity entity = tile.entity();
renderer.lights.add(tile.drawx(), tile.drawy(), (60f + Mathf.absin(10f, 5f)) * entity.warmup * size, flameColor, 0.65f);
}
}

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