Tech tree filled out
Before Width: | Height: | Size: 139 B After Width: | Height: | Size: 193 B |
Before Width: | Height: | Size: 192 B |
Before Width: | Height: | Size: 115 B |
Before Width: | Height: | Size: 155 B |
Before Width: | Height: | Size: 94 B |
BIN
core/assets-raw/sprites/blocks/walls/titanium-wall-large.png
Normal file
After Width: | Height: | Size: 239 B |
BIN
core/assets-raw/sprites/blocks/walls/titanium-wall.png
Normal file
After Width: | Height: | Size: 156 B |
Before Width: | Height: | Size: 969 KiB After Width: | Height: | Size: 966 KiB |
@ -61,7 +61,7 @@ public class Blocks implements ContentList{
|
||||
core, vault, container, unloader, launchPad,
|
||||
|
||||
//turrets
|
||||
duo, scorch, hail, wave, lancer, arc, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown,
|
||||
duo, hail, arc, wave, lancer, swarmer, salvo, fuse, ripple, cyclone, spectre, meltdown,
|
||||
|
||||
//units
|
||||
spiritFactory, phantomFactory, wraithFactory, ghoulFactory, revenantFactory, daggerFactory, titanFactory,
|
||||
@ -787,15 +787,6 @@ public class Blocks implements ContentList{
|
||||
health = 120;
|
||||
}};
|
||||
|
||||
scorch = new LiquidTurret("scorch"){{
|
||||
ammo(Liquids.oil, Bullets.basicFlame);
|
||||
recoil = 0f;
|
||||
reload = 4f;
|
||||
shootCone = 50f;
|
||||
ammoUseEffect = Fx.shellEjectSmall;
|
||||
health = 160;
|
||||
}};
|
||||
|
||||
wave = new LiquidTurret("wave"){{
|
||||
ammo(
|
||||
Liquids.water, Bullets.waterShot,
|
||||
|
@ -1,7 +1,9 @@
|
||||
package io.anuke.mindustry.content;
|
||||
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.mindustry.game.ContentList;
|
||||
import io.anuke.mindustry.type.ItemStack;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
|
||||
import static io.anuke.mindustry.type.ItemStack.with;
|
||||
@ -11,43 +13,273 @@ public class TechTree implements ContentList{
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
root = new TechNode(null, with(),
|
||||
new TechNode(Blocks.copperWall, with(Items.copper, 100),
|
||||
new TechNode(Blocks.copperWallLarge, with(Items.copper, 100))
|
||||
),
|
||||
root = node(null, with(), () -> {
|
||||
|
||||
new TechNode(Blocks.conveyor, with(Items.copper, 10),
|
||||
new TechNode(Blocks.router, with(Items.copper, 10),
|
||||
new TechNode(Blocks.distributor, with(Items.copper, 10)),
|
||||
new TechNode(Blocks.overflowGate, with(Items.copper, 10)),
|
||||
new TechNode(Blocks.sorter, with(Items.copper, 10))
|
||||
),
|
||||
new TechNode(Blocks.junction, with(Items.copper, 10)),
|
||||
new TechNode(Blocks.itemBridge, with(Items.copper, 10))
|
||||
),
|
||||
node(Blocks.conveyor, with(Items.copper, 100), () -> {
|
||||
node(Blocks.launchPad, with(Items.copper, 100), () -> {
|
||||
|
||||
new TechNode(Blocks.conduit, with(Items.metaglass, 10),
|
||||
new TechNode(Blocks.liquidJunction, with(Items.metaglass, 10)),
|
||||
new TechNode(Blocks.liquidRouter, with(Items.metaglass, 10),
|
||||
new TechNode(Blocks.liquidTank, with(Items.metaglass, 10))
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
node(Blocks.junction, with(Items.copper, 100), () -> {
|
||||
node(Blocks.itemBridge, with(Items.copper, 100));
|
||||
node(Blocks.router, with(Items.copper, 100), () -> {
|
||||
node(Blocks.distributor, with(Items.copper, 100));
|
||||
node(Blocks.overflowGate, with(Items.copper, 100));
|
||||
node(Blocks.sorter, with(Items.copper, 100));
|
||||
node(Blocks.container, with(Items.copper, 100), () -> {
|
||||
node(Blocks.unloader, with(Items.copper, 100));
|
||||
node(Blocks.vault, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
node(Blocks.titaniumConveyor, with(Items.copper, 100), () -> {
|
||||
node(Blocks.phaseConveyor, with(Items.copper, 100), () -> {
|
||||
node(Blocks.massDriver, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.duo, with(Items.copper, 100), () -> {
|
||||
node(Blocks.hail, with(Items.copper, 100), () -> {
|
||||
|
||||
node(Blocks.salvo, with(Items.copper, 100), () -> {
|
||||
node(Blocks.swarmer, with(Items.copper, 100), () -> {
|
||||
node(Blocks.cyclone, with(Items.copper, 100), () -> {
|
||||
node(Blocks.spectre, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.ripple, with(Items.copper, 100), () -> {
|
||||
node(Blocks.fuse, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.arc, with(Items.copper, 100), () -> {
|
||||
node(Blocks.wave, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
|
||||
node(Blocks.lancer, with(Items.copper, 100), () -> {
|
||||
node(Blocks.meltdown, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
|
||||
node(Blocks.shockMine, with(Items.metaglass, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.copperWall, with(Items.copper, 100), () -> {
|
||||
node(Blocks.copperWallLarge, with(Items.copper, 100));
|
||||
node(Blocks.titaniumWall, with(Items.copper, 100), () -> {
|
||||
node(Blocks.door, with(Items.copper, 100), () -> {
|
||||
node(Blocks.doorLarge, with(Items.copper, 100));
|
||||
});
|
||||
node(Blocks.titaniumWallLarge, with(Items.copper, 100));
|
||||
node(Blocks.thoriumWall, with(Items.copper, 100), () -> {
|
||||
node(Blocks.thoriumWallLarge, with(Items.copper, 100));
|
||||
node(Blocks.surgeWall, with(Items.copper, 100), () -> {
|
||||
node(Blocks.surgeWallLarge, with(Items.copper, 100));
|
||||
node(Blocks.phaseWall, with(Items.copper, 100), () -> {
|
||||
node(Blocks.phaseWallLarge, with(Items.copper, 100));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.mechanicalDrill, with(Items.copper, 100), () -> {
|
||||
node(Blocks.pneumaticDrill, with(Items.copper, 100), () -> {
|
||||
node(Blocks.cultivator, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
|
||||
node(Blocks.laserDrill, with(Items.copper, 100), () -> {
|
||||
node(Blocks.blastDrill, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
|
||||
node(Blocks.waterExtractor, with(Items.copper, 100), () -> {
|
||||
node(Blocks.oilExtractor, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.siliconSmelter, with(Items.copper, 100), () -> {
|
||||
|
||||
node(Blocks.pyratiteMixer, with(Items.copper, 100), () -> {
|
||||
node(Blocks.blastMixer, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.biomatterCompressor, with(Items.copper, 100), () -> {
|
||||
node(Blocks.plastaniumCompressor, with(Items.copper, 100), () -> {
|
||||
node(Blocks.phaseWeaver, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.incinerator, with(Items.copper, 100), () -> {
|
||||
node(Blocks.melter, with(Items.copper, 100), () -> {
|
||||
node(Blocks.surgeSmelter, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
|
||||
node(Blocks.separator, with(Items.copper, 100), () -> {
|
||||
node(Blocks.pulverizer, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.cryofluidMixer, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.mechanicalPump, with(Items.metaglass, 100), () -> {
|
||||
node(Blocks.conduit, with(Items.metaglass, 100), () -> {
|
||||
node(Blocks.liquidJunction, with(Items.metaglass, 100), () -> {
|
||||
node(Blocks.liquidRouter, with(Items.metaglass, 100), () -> {
|
||||
node(Blocks.liquidTank, with(Items.metaglass, 100));
|
||||
|
||||
node(Blocks.pulseConduit, with(Items.metaglass, 100), () -> {
|
||||
node(Blocks.phaseConduit, with(Items.metaglass, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.rotaryPump, with(Items.metaglass, 100), () -> {
|
||||
node(Blocks.thermalPump, with(Items.metaglass, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
node(Blocks.bridgeConduit, with(Items.metaglass, 100));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.powerNode, with(Items.copper, 100), () -> {
|
||||
node(Blocks.combustionGenerator, with(Items.copper, 100), () -> {
|
||||
node(Blocks.powerNodeLarge, with(Items.copper, 100), () -> {
|
||||
node(Blocks.battery, with(Items.copper, 100), () -> {
|
||||
node(Blocks.batteryLarge, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.mendProjector, with(Items.copper, 100), () -> {
|
||||
node(Blocks.forceProjector, with(Items.copper, 100), () -> {
|
||||
node(Blocks.overdriveProjector, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.repairPoint, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.turbineGenerator, with(Items.copper, 100), () -> {
|
||||
node(Blocks.thermalGenerator, with(Items.copper, 100), () -> {
|
||||
node(Blocks.rtgGenerator, with(Items.copper, 100), () -> {
|
||||
node(Blocks.thoriumReactor, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.solarPanel, with(Items.copper, 100), () -> {
|
||||
node(Blocks.largeSolarPanel, with(Items.copper, 100), () -> {
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.alphaPad, with(Items.copper, 100), () -> {
|
||||
node(Blocks.dartPad, with(Items.copper, 100));
|
||||
node(Blocks.deltaPad, with(Items.copper, 100), () -> {
|
||||
node(Blocks.javelinPad, with(Items.copper, 100));
|
||||
node(Blocks.tauPad, with(Items.copper, 100), () -> {
|
||||
node(Blocks.tridentPad, with(Items.copper, 100));
|
||||
node(Blocks.omegaPad, with(Items.copper, 100), () -> {
|
||||
node(Blocks.glaivePad, with(Items.copper, 100));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
node(Blocks.spiritFactory, with(Items.copper, 100), () -> {
|
||||
node(Blocks.daggerFactory, with(Items.copper, 100), () -> {
|
||||
node(Blocks.daggerFactory, with(Items.copper, 100), () -> {
|
||||
node(Blocks.titanFactory, with(Items.copper, 100), () -> {
|
||||
node(Blocks.fortressFactory, with(Items.copper, 100));
|
||||
});
|
||||
node(Blocks.wraithFactory, with(Items.copper, 100), () -> {
|
||||
node(Blocks.phantomFactory, with(Items.copper, 100));
|
||||
node(Blocks.ghoulFactory, with(Items.copper, 100), () -> {
|
||||
node(Blocks.revenantFactory, with(Items.copper, 100));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private TechNode node(Block block, ItemStack[] requirements, Runnable children){
|
||||
return new TechNode(block, requirements, children);
|
||||
}
|
||||
|
||||
private TechNode node(Block block, ItemStack[] requirements){
|
||||
return new TechNode(block, requirements, () -> {});
|
||||
}
|
||||
|
||||
private TechNode node(Block block){
|
||||
return new TechNode(block, with(), () -> {});
|
||||
}
|
||||
|
||||
public static class TechNode{
|
||||
static TechNode context;
|
||||
|
||||
public final Block block;
|
||||
public final ItemStack[] requirements;
|
||||
public final TechNode[] children;
|
||||
public TechNode parent;
|
||||
public final Array<TechNode> children = new Array<>();
|
||||
|
||||
TechNode(Block block, ItemStack[] requirements, Runnable children){
|
||||
if(block != null && Recipe.getByResult(block) == null) throw new IllegalArgumentException("Block " + block + " does not have a recipe.");
|
||||
if(context != null){
|
||||
context.children.add(this);
|
||||
}
|
||||
|
||||
TechNode(Block block, ItemStack[] requirements, TechNode... children){
|
||||
this.block = block;
|
||||
this.requirements = requirements;
|
||||
this.children = children;
|
||||
for(TechNode node : children){
|
||||
node.parent = this;
|
||||
}
|
||||
|
||||
TechNode last = context;
|
||||
context = this;
|
||||
children.run();
|
||||
context = last;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ public class TreeLayout{
|
||||
}
|
||||
|
||||
public Rectangle getBounds(){
|
||||
return new Rectangle(0, 0, boundsRight - boundsLeft, boundsBottom - boundsTop);
|
||||
return new Rectangle(boundsLeft, boundsBottom, boundsRight - boundsLeft, boundsTop - boundsBottom);
|
||||
}
|
||||
|
||||
private void calcSizeOfLevels(TreeNode node, int level){
|
||||
|
@ -1,6 +1,6 @@
|
||||
package io.anuke.mindustry.ui.dialogs;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.collection.ObjectSet;
|
||||
import io.anuke.arc.graphics.g2d.Draw;
|
||||
import io.anuke.arc.graphics.g2d.Lines;
|
||||
@ -12,31 +12,46 @@ import io.anuke.arc.scene.Element;
|
||||
import io.anuke.arc.scene.event.InputEvent;
|
||||
import io.anuke.arc.scene.event.InputListener;
|
||||
import io.anuke.arc.util.Log;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.arc.util.Structs;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.content.TechTree;
|
||||
import io.anuke.mindustry.content.TechTree.TechNode;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.type.Recipe;
|
||||
import io.anuke.mindustry.type.Recipe.RecipeVisibility;
|
||||
import io.anuke.mindustry.ui.TreeLayout;
|
||||
import io.anuke.mindustry.ui.TreeLayout.TreeNode;
|
||||
import io.anuke.mindustry.world.Block.Icon;
|
||||
|
||||
import static io.anuke.mindustry.Vars.content;
|
||||
|
||||
public class TechTreeDialog extends FloatingDialog{
|
||||
private TreeLayout layout;
|
||||
private ObjectSet<TechTreeNode> nodes = new ObjectSet<>();
|
||||
private static final float nodeSize = 60f;
|
||||
|
||||
public TechTreeDialog(){
|
||||
super("$techtree");
|
||||
|
||||
layout = new TreeLayout();
|
||||
TreeLayout layout = new TreeLayout();
|
||||
layout.gapBetweenLevels = 60f;
|
||||
layout.gapBetweenNodes = 40f;
|
||||
layout.layout(new TechTreeNode(TechTree.root, null));
|
||||
cont.add(new View()).grow();
|
||||
|
||||
double total = Vars.content.recipes().count(r -> r.visibility == RecipeVisibility.all);
|
||||
if(total > nodes.size) Log.err("Recipe tree coverage: {0}%", (int)(nodes.size / total * 100));
|
||||
{ //debug code
|
||||
ObjectSet<Recipe> used = new ObjectSet<>();
|
||||
for(TechTreeNode node : nodes){
|
||||
if(node.node.block != null) used.add(Recipe.getByResult(node.node.block));
|
||||
}
|
||||
Array<Recipe> recipes = content.recipes().select(r -> r.visibility == RecipeVisibility.all && !used.contains(r));
|
||||
recipes.sort(Structs.comparing(r -> r.cost));
|
||||
|
||||
if(recipes.size > 0){
|
||||
Log.info("Recipe tree coverage: {0}%", (int)((float)nodes.size / content.recipes().select(r -> r.visibility == RecipeVisibility.all).size * 100));
|
||||
Log.info("Missing items: ");
|
||||
recipes.forEach(r -> Log.info(" {0}", r));
|
||||
}
|
||||
}
|
||||
|
||||
addCloseButton();
|
||||
}
|
||||
@ -47,12 +62,12 @@ public class TechTreeDialog extends FloatingDialog{
|
||||
public TechTreeNode(TechNode node, TreeNode parent){
|
||||
this.node = node;
|
||||
this.parent = parent;
|
||||
this.width = this.height = 60f;
|
||||
this.width = this.height = nodeSize;
|
||||
nodes.add(this);
|
||||
if(node.children != null){
|
||||
children = new TechTreeNode[node.children.length];
|
||||
children = new TechTreeNode[node.children.size];
|
||||
for(int i = 0; i < children.length; i++){
|
||||
children[i] = new TechTreeNode(node.children[i], this);
|
||||
children[i] = new TechTreeNode(node.children.get(i), this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -64,15 +79,19 @@ public class TechTreeDialog extends FloatingDialog{
|
||||
|
||||
{
|
||||
addListener(new InputListener(){
|
||||
float lastX, lastY;
|
||||
@Override
|
||||
public void touchDragged(InputEvent event, float x, float y, int pointer){
|
||||
super.touchDragged(event, x, y, pointer);
|
||||
panX += Core.input.deltaX(pointer);
|
||||
panY += Core.input.deltaY(pointer);
|
||||
public void touchDragged(InputEvent event, float mx, float my, int pointer){
|
||||
panX -= lastX - mx;
|
||||
panY -= lastY - my;
|
||||
lastX = mx;
|
||||
lastY = my;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){
|
||||
lastX = x;
|
||||
lastY = y;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@ -97,7 +116,7 @@ public class TechTreeDialog extends FloatingDialog{
|
||||
Draw.color();
|
||||
|
||||
for(TechTreeNode node : nodes){
|
||||
Draw.drawable("content-background", node.x + offsetX - node.width/2f, node.y + offsetY - node.height/2f, node.width, node.height);
|
||||
Draw.drawable("content-background", node.x + offsetX - nodeSize/2f, node.y + offsetY - nodeSize/2f, nodeSize, nodeSize);
|
||||
|
||||
TextureRegion region = node.node.block == null ? Blocks.core.icon(Icon.medium) : node.node.block.icon(Icon.medium);
|
||||
Draw.rect(region, node.x + offsetX, node.y + offsetY - 0.5f, region.getWidth(), region.getHeight());
|
||||
|
@ -19,6 +19,18 @@ public class MenuFragment extends Fragment{
|
||||
|
||||
@Override
|
||||
public void build(Group parent){
|
||||
|
||||
if(true){
|
||||
parent.fill(t -> {
|
||||
t.add("do not play the bleeding edge").get().setFontScale(2f);
|
||||
t.row();
|
||||
t.add("none of it is playable yet");
|
||||
t.row();
|
||||
t.add("something usable will be released 'soon' (TM)").get().setFontScale(0.5f);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
parent.fill(c -> {
|
||||
container = c;
|
||||
container.visible(() -> state.is(State.menu));
|
||||
|