diff --git a/core/src/mindustry/content/TechTree.java b/core/src/mindustry/content/TechTree.java index da36956a4d..76c234e70d 100644 --- a/core/src/mindustry/content/TechTree.java +++ b/core/src/mindustry/content/TechTree.java @@ -471,6 +471,8 @@ public class TechTree implements ContentList{ public UnlockableContent content; /** Item requirements for this content. */ public ItemStack[] requirements; + /** Requirements that have been fulfilled. Always the same length as the requirement array. */ + public final ItemStack[] finishedRequirements; /** Extra objectives needed to research this. TODO implement */ public Seq objectives = new Seq<>(); /** Time required to research this content, in seconds. */ @@ -491,6 +493,12 @@ public class TechTree implements ContentList{ this.depth = parent == null ? 0 : parent.depth + 1; this.progress = Core.settings == null ? 0 : Core.settings.getFloat("research-" + content.name, 0f); this.time = Seq.with(requirements).mapFloat(i -> i.item.cost * i.amount).sum() * 10; + this.finishedRequirements = new ItemStack[requirements.length]; + + //load up the requirements that have been finished if settings are available + for(int i = 0; i < requirements.length; i++){ + finishedRequirements[i] = new ItemStack(requirements[i].item, Core.settings == null ? 0 : Core.settings.getInt("req-" + content.name + "-" + requirements[i].item.name)); + } //add dependencies as objectives. content.getDependencies(d -> objectives.add(new Research(d))); @@ -509,6 +517,11 @@ public class TechTree implements ContentList{ /** Flushes research progress to settings. */ public void save(){ Core.settings.put("research-" + content.name, progress); + + //save finished requirements by item type + for(ItemStack stack : finishedRequirements){ + Core.settings.put("req-" + content.name + "-" + stack.item.name, stack.amount); + } } } } diff --git a/core/src/mindustry/ui/dialogs/ResearchDialog.java b/core/src/mindustry/ui/dialogs/ResearchDialog.java index 6e28a421e7..741c807240 100644 --- a/core/src/mindustry/ui/dialogs/ResearchDialog.java +++ b/core/src/mindustry/ui/dialogs/ResearchDialog.java @@ -14,6 +14,7 @@ import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; +import arc.util.ArcAnnotate.*; import mindustry.content.*; import mindustry.content.TechTree.*; import mindustry.core.*; @@ -262,8 +263,8 @@ public class ResearchDialog extends BaseDialog{ } }); } - }else if(canUnlock(node.node) && locked(node.node)){ - unlock(node.node); + }else if(canSpend(node.node) && locked(node.node)){ + spend(node.node); } }); button.hovered(() -> { @@ -284,7 +285,7 @@ public class ResearchDialog extends BaseDialog{ button.update(() -> { float offset = (Core.graphics.getHeight() % 2) / 2f; button.setPosition(node.x + panX + width / 2f, node.y + panY + height / 2f + offset, Align.center); - button.getStyle().up = !locked(node.node) ? Tex.buttonOver : selectable(node.node) && !items().has(node.node.requirements) ? Tex.buttonRed : Tex.button; + button.getStyle().up = !locked(node.node) ? Tex.buttonOver : selectable(node.node) && !canSpend(node.node) ? Tex.buttonRed : Tex.button; ((TextureRegionDrawable)button.getStyle().imageUp).setRegion(node.selectable ? node.node.content.icon(Cicon.medium) : Icon.lock.getRegion()); button.getImage().setColor(!locked(node.node) ? Color.white : node.selectable ? Color.gray : Pal.gray); @@ -323,6 +324,40 @@ public class ResearchDialog extends BaseDialog{ return items().has(node.requirements) && selectable(node); } + boolean canSpend(TechNode node){ + //can spend when there's at least 1 item that can be spent + return selectable(node) && (node.requirements.length == 0 || Structs.contains(node.requirements, i -> items().has(i.item))); + } + + void spend(TechNode node){ + boolean complete = true; + + boolean[] shine = new boolean[node.requirements.length]; + + for(int i = 0; i < node.requirements.length; i++){ + ItemStack req = node.requirements[i]; + ItemStack completed = node.finishedRequirements[i]; + + //amount actually taken from inventory + int used = Math.min(req.amount - completed.amount, items().get(req.item)); + completed.amount += used; + + if(used > 0) shine[i] = true; + + //disable completion if the completed amount has not reached requirements + if(completed.amount < req.amount){ + complete = false; + } + } + + if(complete){ + unlock(node); + } + + node.save(); + rebuild(shine); + } + void unlock(TechNode node){ node.content.unlock(); items().remove(node.requirements); @@ -337,6 +372,11 @@ public class ResearchDialog extends BaseDialog{ } void rebuild(){ + rebuild(null); + } + + //pass an array of stack indexes that should shine here + void rebuild(@Nullable boolean[] shine){ ImageButton button = hoverNode; infoTable.remove(); @@ -377,13 +417,35 @@ public class ResearchDialog extends BaseDialog{ desc.table(t -> { t.left(); if(selectable){ - for(ItemStack req : node.requirements){ + for(int i = 0; i < node.requirements.length; i++){ + ItemStack req = node.requirements[i]; + ItemStack completed = node.finishedRequirements[i]; + + //skip finished stacks + if(req.amount <= completed.amount) continue; + boolean shiny = shine != null && shine[i]; + t.table(list -> { + int reqAmount = req.amount - completed.amount; + list.left(); list.image(req.item.icon(Cicon.small)).size(8 * 3).padRight(3); list.add(req.item.localizedName).color(Color.lightGray); - list.label(() -> " " + (player.team().core() != null ? UI.formatAmount(Math.min(player.team().core().items.get(req.item), req.amount)) + " / " : "") + UI.formatAmount(req.amount)) - .update(l -> l.setColor(items().has(req.item, req.amount) ? Color.lightGray : Color.scarlet));//TODO + Label label = list.label(() -> " " + + (player.team().core() != null ? + UI.formatAmount(Math.min(player.team().core().items.get(req.item), reqAmount)) + " / " : + "") + + UI.formatAmount(reqAmount)).get(); + + Color targetColor = items().has(req.item) ? Color.lightGray : Color.scarlet; + + if(shiny){ + label.setColor(Pal.accent); + label.actions(Actions.color(targetColor, 0.75f, Interp.fade)); + }else{ + label.setColor(targetColor); + } + }).fillX().left(); t.row(); } @@ -409,8 +471,8 @@ public class ResearchDialog extends BaseDialog{ if(mobile && locked(node)){ b.row(); - b.button("$research", Icon.ok, Styles.nodet, () -> unlock(node)) - .disabled(i -> !canUnlock(node)).growX().height(44f).colspan(3); + b.button("$research", Icon.ok, Styles.nodet, () -> spend(node)) + .disabled(i -> !canSpend(node)).growX().height(44f).colspan(3); } }); diff --git a/gradle.properties b/gradle.properties index 019171b64b..25e9dede97 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ org.gradle.daemon=true org.gradle.jvmargs=-Xms256m -Xmx1024m -archash=9758a12fe9090a08fead6186fe49b7c347180f2e +archash=9947972b4ee3f60df35ba3d8be42ad5c287c9a43