Functional tech tree

This commit is contained in:
Anuken
2019-01-19 22:16:28 -05:00
parent 093043750b
commit d34f228d2f
18 changed files with 1217 additions and 1079 deletions

View File

@@ -34,7 +34,7 @@ public class DeployDialog extends FloatingDialog{
ObjectIntMap<Item> items = data.items();
for(Item item : Vars.content.items()){
if(item.type == ItemType.material && data.isUnlocked(item)){
add(items.get(item, 0) + "").left();
label(() -> items.get(item, 0) + "").left();
addImage(item.region).size(8*4).pad(4);
add("[LIGHT_GRAY]" + item.localizedName()).left();
row();

View File

@@ -1,34 +1,42 @@
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.Color;
import io.anuke.arc.graphics.g2d.Lines;
import io.anuke.arc.graphics.g2d.ScissorStack;
import io.anuke.arc.input.KeyCode;
import io.anuke.arc.math.Interpolation;
import io.anuke.arc.math.geom.Rectangle;
import io.anuke.arc.scene.Group;
import io.anuke.arc.scene.actions.Actions;
import io.anuke.arc.scene.event.InputEvent;
import io.anuke.arc.scene.event.InputListener;
import io.anuke.arc.scene.event.Touchable;
import io.anuke.arc.scene.style.TextureRegionDrawable;
import io.anuke.arc.scene.ui.ImageButton;
import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.arc.util.Align;
import io.anuke.arc.util.Log;
import io.anuke.arc.util.Structs;
import io.anuke.mindustry.Vars;
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.ItemStack;
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;
import static io.anuke.mindustry.Vars.*;
public class TechTreeDialog extends FloatingDialog{
private ObjectSet<TechTreeNode> nodes = new ObjectSet<>();
private TechTreeNode root = new TechTreeNode(TechTree.root, null);
private static final float nodeSize = 60f;
private int toasts;
public TechTreeDialog(){
super("$techtree");
@@ -36,14 +44,14 @@ public class TechTreeDialog extends FloatingDialog{
TreeLayout layout = new TreeLayout();
layout.gapBetweenLevels = 60f;
layout.gapBetweenNodes = 40f;
layout.layout(new TechTreeNode(TechTree.root, null));
layout.layout(root);
cont.add(new View()).grow();
{ //debug code; TODO remove
ObjectSet<Recipe> used = new ObjectSet<Recipe>().select(t -> true);
for(TechTreeNode node : nodes){
if(node.node.block != null) used.add(Recipe.getByResult(node.node.block));
used.add(node.node.recipe());
}
Array<Recipe> recipes = content.recipes().select(r -> r.visibility == RecipeVisibility.all && !used.contains(r));
recipes.sort(Structs.comparing(r -> r.cost));
@@ -55,11 +63,44 @@ public class TechTreeDialog extends FloatingDialog{
}
}
shown(() -> checkNodes(root));
addCloseButton();
}
void checkNodes(TechTreeNode node){
boolean locked = locked(node);
if(!locked) node.visible = true;
for(TreeNode child : node.children){
TechTreeNode l = (TechTreeNode)child;
l.visible = !locked;
checkNodes(l);
}
}
void showToast(String info){
toasts ++;
int t = toasts;
Table table = new Table();
table.actions(Actions.fadeOut(7f, Interpolation.fade), Actions.run(() -> toasts --), Actions.removeActor());
table.top().add(info);
table.update(() -> {
table.toFront();
table.setPosition(Core.graphics.getWidth()/2f, Core.graphics.getHeight() - 21 - t*20f, Align.top);
});
Core.scene.add(table);
}
boolean locked(TreeNode node){
return locked(((TechTreeNode)node).node);
}
boolean locked(TechNode node){
return !data.isUnlocked(node.recipe());
}
class TechTreeNode extends TreeNode{
final TechNode node;
boolean visible = true;
public TechTreeNode(TechNode node, TreeNode parent){
this.node = node;
@@ -77,21 +118,47 @@ public class TechTreeDialog extends FloatingDialog{
class View extends Group{
float panX = 0, panY = 0;
Rectangle clip = new Rectangle();
boolean moved = false;
Rectangle clip = new Rectangle();
ImageButton hoverNode;
Table infoTable = new Table();
{
infoTable.touchable(Touchable.enabled);
for(TechTreeNode node : nodes){
ImageButton button = new ImageButton(node.node.block == null ? Blocks.core.icon(Icon.medium) : node.node.block.icon(Icon.medium), "node");
ImageButton button = new ImageButton(node.node.block.icon(Icon.medium), "node");
button.clicked(() -> {
if(moved) return;
Vars.ui.content.show(Recipe.getByResult(node.node.block == null ? Blocks.conveyor : node.node.block));
if(mobile){
hoverNode = button;
rebuild();
}else if(data.hasItems(node.node.requirements) && locked(node)){
unlock(node.node);
}
});
button.tapped(() -> {
moved = false;
button.hovered(() -> {
if(!mobile && hoverNode != button && node.visible){
hoverNode = button;
rebuild();
}
});
button.exited(() -> {
if(hoverNode == button && !infoTable.hasMouse() && !hoverNode.hasMouse()){
hoverNode = null;
rebuild();
}
});
button.touchable(() -> !node.visible ? Touchable.disabled : Touchable.enabled);
button.setUserObject(node.node);
button.tapped(() -> moved = false);
button.setSize(nodeSize, nodeSize);
button.update(() -> button.setPosition(node.x + panX + width/2f, node.y + panY + height/2f - 0.5f, Align.center));
button.update(() -> {
button.setPosition(node.x + panX + width/2f, node.y + panY + height/2f - 0.5f, Align.center);
button.getStyle().up = Core.scene.skin.getDrawable(!locked(node) ? "content-background" : "content-background-locked");
((TextureRegionDrawable)button.getStyle().imageUp)
.setRegion(node.visible ? node.node.block.icon(Icon.medium) : Core.atlas.find("icon-tree-locked"));
button.getImage().setColor(!locked(node) ? Color.WHITE : Color.GRAY);
});
addChild(button);
}
@@ -115,6 +182,75 @@ public class TechTreeDialog extends FloatingDialog{
});
}
void unlock(TechNode node){
data.unlockContent(node.recipe());
data.removeItems(node.requirements);
showToast(Core.bundle.format("researched", node.block.formalName));
checkNodes(root);
hoverNode = null;
rebuild();
}
void rebuild(){
ImageButton button = hoverNode;
infoTable.remove();
infoTable.clear();
infoTable.update(null);
if(button == null) return;
TechNode node = (TechNode)button.getUserObject();
infoTable.exited(() -> {
if(hoverNode == button && !infoTable.hasMouse() && !hoverNode.hasMouse()){
hoverNode = null;
rebuild();
}
});
infoTable.background("content-background");
infoTable.update(() -> infoTable.setPosition(button.getX() + button.getWidth(), button.getY() + button.getHeight(), Align.topLeft));
infoTable.margin(0).left().defaults().left();
infoTable.addImageButton("icon-info", "node", 14*2, () -> ui.content.show(node.recipe())).growY().width(50f);
infoTable.add().grow();
infoTable.table(desc -> {
desc.left().defaults().left();
desc.add(node.block.formalName);
desc.row();
if(locked(node)){
desc.table(t -> {
t.left();
for(ItemStack req : node.requirements){
t.table(list -> {
list.left();
list.addImage(req.item.getContentIcon()).size(8 * 3).padRight(3);
list.add(req.item.localizedName()).color(Color.LIGHT_GRAY);
list.add(" " + Math.min(data.items().get(req.item, 0), req.amount) + " / " + req.amount)
.color(data.has(req.item, req.amount) ? Color.LIGHT_GRAY : Color.SCARLET);
}).fillX().left();
t.row();
}
});
}else{
desc.add("$completed");
}
}).pad(9);
if(mobile && locked(node)){
infoTable.row();
infoTable.addImageTextButton("$research", "icon-check", "node", 16*2, () -> unlock(node))
.disabled(b -> !data.hasItems(node.requirements)).growX().height(44f).colspan(3);
}
addChild(infoTable);
infoTable.pack();
}
@Override
public void draw(){
if(!ScissorStack.pushScissors(clip.set(x, y, width, height))){
@@ -123,26 +259,16 @@ public class TechTreeDialog extends FloatingDialog{
float offsetX = panX + width/2f + x, offsetY = panY + height/2f + y;
Lines.stroke(3f, Palette.accent);
for(TreeNode node : nodes){
for(TreeNode child : node.children){
Lines.stroke(3f, locked(node) || locked(child) ? Palette.locked : Palette.accent);
Lines.line(node.x + offsetX, node.y + offsetY, child.x + offsetX, child.y + offsetY);
}
}
super.draw();
/*
Draw.color();
for(TechTreeNode node : nodes){
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());
}*/
ScissorStack.popScissors();
}
}