Research system progress
This commit is contained in:
@@ -170,7 +170,7 @@ public class Vars implements Loadable{
|
||||
public static Net net;
|
||||
public static ContentLoader content;
|
||||
public static GameState state;
|
||||
public static GlobalData data;
|
||||
public static CampaignData data;
|
||||
public static EntityCollisions collisions;
|
||||
public static DefaultWaves defaultWaves;
|
||||
public static mindustry.audio.LoopControl loops;
|
||||
@@ -256,7 +256,7 @@ public class Vars implements Loadable{
|
||||
bases = new BaseRegistry();
|
||||
|
||||
state = new GameState();
|
||||
data = new GlobalData();
|
||||
data = new CampaignData();
|
||||
|
||||
mobile = Core.app.isMobile() || testMobile;
|
||||
ios = Core.app.isIOS();
|
||||
|
||||
@@ -1848,6 +1848,7 @@ public class Blocks implements ContentList{
|
||||
requirements(Category.effect, BuildVisibility.campaignOnly, ItemStack.with(Items.copper, 200, Items.lead, 100));
|
||||
|
||||
size = 3;
|
||||
alwaysUnlocked = true;
|
||||
}};
|
||||
|
||||
//endregion campaign
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package mindustry.content;
|
||||
|
||||
import arc.*;
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
@@ -11,12 +12,15 @@ import mindustry.world.*;
|
||||
import static mindustry.content.Blocks.*;
|
||||
|
||||
public class TechTree implements ContentList{
|
||||
private static ObjectMap<UnlockableContent, TechNode> map = new ObjectMap<>();
|
||||
|
||||
public static Seq<TechNode> all;
|
||||
public static TechNode root;
|
||||
|
||||
@Override
|
||||
public void load(){
|
||||
TechNode.context = null;
|
||||
map = new ObjectMap<>();
|
||||
all = new Seq<>();
|
||||
|
||||
root = node(coreShard, () -> {
|
||||
@@ -312,6 +316,14 @@ public class TechTree implements ContentList{
|
||||
return node(block, () -> {});
|
||||
}
|
||||
|
||||
public static @Nullable TechNode get(UnlockableContent content){
|
||||
return map.get(content);
|
||||
}
|
||||
|
||||
public static TechNode getNotNull(UnlockableContent content){
|
||||
return map.getThrow(content, () -> new RuntimeException(content + " does not have a tech node"));
|
||||
}
|
||||
|
||||
public static class TechNode{
|
||||
private static TechNode context;
|
||||
|
||||
@@ -325,12 +337,14 @@ public class TechTree implements ContentList{
|
||||
public ItemStack[] requirements;
|
||||
/** Extra objectives needed to research this. TODO implement */
|
||||
public Objective[] objectives = {};
|
||||
/** Research turns required to research this content. */
|
||||
public int turns = 3; //TODO keep track of turns that have been used so far
|
||||
/** Time required to research this content, in seconds. */
|
||||
public float time = 60; //TODO implement
|
||||
/** Nodes that depend on this node. */
|
||||
public final Seq<TechNode> children = new Seq<>();
|
||||
/** Research progress, in seconds. */
|
||||
public float progress;
|
||||
|
||||
TechNode(TechNode ccontext, UnlockableContent content, ItemStack[] requirements, Runnable children){
|
||||
TechNode(@Nullable TechNode ccontext, UnlockableContent content, ItemStack[] requirements, Runnable children){
|
||||
if(ccontext != null){
|
||||
ccontext.children.add(this);
|
||||
}
|
||||
@@ -339,7 +353,9 @@ public class TechTree implements ContentList{
|
||||
this.content = content;
|
||||
this.requirements = requirements;
|
||||
this.depth = parent == null ? 0 : parent.depth + 1;
|
||||
this.progress = Core.settings.getFloat("research-" + content.name, 0f);
|
||||
|
||||
map.put(content, this);
|
||||
context = this;
|
||||
children.run();
|
||||
context = ccontext;
|
||||
@@ -349,5 +365,10 @@ public class TechTree implements ContentList{
|
||||
TechNode(UnlockableContent content, ItemStack[] requirements, Runnable children){
|
||||
this(context, content, requirements, children);
|
||||
}
|
||||
|
||||
/** Flushes research progress to settings. */
|
||||
public void save(){
|
||||
Core.settings.put("research-" + content.name, progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,9 +459,6 @@ public class Control implements ApplicationListener, Loadable{
|
||||
|
||||
input.updateState();
|
||||
|
||||
//autosave global data if it's modified
|
||||
data.checkSave();
|
||||
|
||||
music.update();
|
||||
loops.update();
|
||||
Time.updateGlobal();
|
||||
|
||||
@@ -6,7 +6,6 @@ import arc.util.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.core.GameState.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.game.Teams.*;
|
||||
@@ -114,13 +113,6 @@ public class Logic implements ApplicationListener{
|
||||
|
||||
}
|
||||
|
||||
/** Handles the event of content being used by either the player or some block. */
|
||||
public void handleContent(UnlockableContent content){
|
||||
if(!headless){
|
||||
data.unlockContent(content);
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds starting items, resets wave time, and sets state to playing. */
|
||||
public void play(){
|
||||
state.set(State.playing);
|
||||
@@ -251,8 +243,9 @@ public class Logic implements ApplicationListener{
|
||||
Time.runTask(30f, () -> {
|
||||
for(Tilec entity : state.teams.playerCores()){
|
||||
for(Item item : content.items()){
|
||||
data.addItem(item, entity.items().get(item));
|
||||
Events.fire(new LaunchItemEvent(new ItemStack(item, entity.items().get(item))));
|
||||
//TODO where do the items go?
|
||||
//data.addItem(item, entity.items().get(item));
|
||||
//Events.fire(new LaunchItemEvent(new ItemStack(item, entity.items().get(item))));
|
||||
}
|
||||
entity.tile().remove();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package mindustry.ctype;
|
||||
|
||||
import arc.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import mindustry.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.ui.Cicon;
|
||||
import mindustry.ui.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
/** Base interface for an unlockable content type. */
|
||||
public abstract class UnlockableContent extends MappableContent{
|
||||
@@ -63,12 +64,12 @@ public abstract class UnlockableContent extends MappableContent{
|
||||
}
|
||||
|
||||
public final boolean unlocked(){
|
||||
return Vars.data.isUnlocked(this);
|
||||
return data.isUnlocked(this);
|
||||
}
|
||||
|
||||
/** @return whether this content is unlocked, or the player is in a custom game. */
|
||||
public final boolean unlockedCur(){
|
||||
return Vars.data.isUnlocked(this) || !Vars.state.isCampaign();
|
||||
/** @return whether this content is unlocked, or the player is in a custom (non-campaign) game. */
|
||||
public final boolean unlockedNow(){
|
||||
return data.isUnlocked(this) || !state.isCampaign();
|
||||
}
|
||||
|
||||
public final boolean locked(){
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
package mindustry.editor;
|
||||
|
||||
import arc.*;
|
||||
import arc.struct.IntSet;
|
||||
import arc.struct.IntSet.IntSetIterator;
|
||||
import arc.graphics.Color;
|
||||
import arc.graphics.Texture;
|
||||
import arc.graphics.g2d.Draw;
|
||||
import arc.graphics.g2d.TextureRegion;
|
||||
import arc.math.Mathf;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.content.Blocks;
|
||||
import mindustry.content.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.Team;
|
||||
import mindustry.graphics.IndexedRenderer;
|
||||
import mindustry.world.Block;
|
||||
import mindustry.world.Tile;
|
||||
import mindustry.game.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.world.*;
|
||||
|
||||
import static mindustry.Vars.tilesize;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class MapRenderer implements Disposable{
|
||||
private static final int chunkSize = 64;
|
||||
@@ -62,13 +58,7 @@ public class MapRenderer implements Disposable{
|
||||
public void draw(float tx, float ty, float tw, float th){
|
||||
Draw.flush();
|
||||
|
||||
IntSetIterator it = updates.iterator();
|
||||
while(it.hasNext){
|
||||
int i = it.next();
|
||||
int x = i % width;
|
||||
int y = i / width;
|
||||
render(x, y);
|
||||
}
|
||||
updates.each(i -> render(i % width, i / width));
|
||||
updates.clear();
|
||||
|
||||
updates.addAll(delayedUpdates);
|
||||
|
||||
@@ -18,7 +18,6 @@ import arc.util.io.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.audio.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.game.*;
|
||||
@@ -552,8 +551,6 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc, QuadTree
|
||||
public void offload(Item item){
|
||||
int dump = this.dump;
|
||||
|
||||
useContent(item);
|
||||
|
||||
for(int i = 0; i < proximity.size; i++){
|
||||
incrementDump(proximity.size);
|
||||
Tilec other = proximity.get((i + dump) % proximity.size);
|
||||
@@ -571,7 +568,6 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc, QuadTree
|
||||
*/
|
||||
public boolean put(Item item){
|
||||
int dump = this.dump;
|
||||
useContent(item);
|
||||
|
||||
for(int i = 0; i < proximity.size; i++){
|
||||
incrementDump(proximity.size);
|
||||
@@ -814,14 +810,6 @@ abstract class TileComp implements Posc, Teamc, Healthc, Tilec, Timerc, QuadTree
|
||||
public void unitRemoved(Unitc unit){
|
||||
}
|
||||
|
||||
/** Call when some content is produced. This unlocks the content if it is applicable. */
|
||||
public void useContent(UnlockableContent content){
|
||||
//only unlocks content in zones
|
||||
if(!headless && team() == player.team() && state.isCampaign()){
|
||||
logic.handleContent(content);
|
||||
}
|
||||
}
|
||||
|
||||
/** Called when arbitrary configuration is applied to a tile. */
|
||||
public void configured(@Nullable Playerc player, @Nullable Object value){
|
||||
//null is of type void.class; anonymous classes use their superclass.
|
||||
|
||||
47
core/src/mindustry/game/CampaignData.java
Normal file
47
core/src/mindustry/game/CampaignData.java
Normal file
@@ -0,0 +1,47 @@
|
||||
package mindustry.game;
|
||||
|
||||
import arc.*;
|
||||
import arc.struct.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.game.EventType.*;
|
||||
|
||||
/** Stores unlocks and tech tree state. */
|
||||
public class CampaignData{
|
||||
private ObjectSet<String> unlocked = new ObjectSet<>();
|
||||
|
||||
/** @return whether or not this piece of content is unlocked yet. */
|
||||
public boolean isUnlocked(UnlockableContent content){
|
||||
return content.alwaysUnlocked || unlocked.contains(content.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes this piece of content 'unlocked', if possible.
|
||||
* If this piece of content is already unlocked, nothing changes.
|
||||
*/
|
||||
public void unlockContent(UnlockableContent content){
|
||||
if(content.alwaysUnlocked) return;
|
||||
|
||||
//fire unlock event so other classes can use it
|
||||
if(unlocked.add(content.name)){
|
||||
content.onUnlock();
|
||||
Events.fire(new UnlockEvent(content));
|
||||
|
||||
save();
|
||||
}
|
||||
}
|
||||
|
||||
/** Clears all unlocked content. Automatically saves. */
|
||||
public void reset(){
|
||||
save();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void load(){
|
||||
unlocked = Core.settings.getJson("unlocked-content", ObjectSet.class, ObjectSet::new);
|
||||
}
|
||||
|
||||
public void save(){
|
||||
Core.settings.putJson("unlocked-content", String.class, unlocked);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
package mindustry.game;
|
||||
|
||||
import arc.*;
|
||||
import arc.files.*;
|
||||
import arc.math.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.io.*;
|
||||
import mindustry.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.type.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
/** Stores player unlocks. Clientside only. */
|
||||
public class GlobalData{
|
||||
private ObjectSet<String> unlocked = new ObjectSet<>();
|
||||
private ObjectIntMap<Item> items = new ObjectIntMap<>();
|
||||
private boolean modified;
|
||||
|
||||
public void exportData(Fi file) throws IOException{
|
||||
Seq<Fi> files = new Seq<>();
|
||||
files.add(Core.settings.getSettingsFile());
|
||||
files.addAll(customMapDirectory.list());
|
||||
files.addAll(saveDirectory.list());
|
||||
files.addAll(screenshotDirectory.list());
|
||||
files.addAll(modDirectory.list());
|
||||
files.addAll(schematicDirectory.list());
|
||||
String base = Core.settings.getDataDirectory().path();
|
||||
|
||||
try(OutputStream fos = file.write(false, 2048); ZipOutputStream zos = new ZipOutputStream(fos)){
|
||||
for(Fi add : files){
|
||||
if(add.isDirectory()) continue;
|
||||
zos.putNextEntry(new ZipEntry(add.path().substring(base.length())));
|
||||
Streams.copy(add.read(), zos);
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void importData(Fi file){
|
||||
Fi dest = Core.files.local("zipdata.zip");
|
||||
file.copyTo(dest);
|
||||
Fi zipped = new ZipFi(dest);
|
||||
|
||||
Fi base = Core.settings.getDataDirectory();
|
||||
if(!zipped.child("settings.bin").exists()){
|
||||
throw new IllegalArgumentException("Not valid save data.");
|
||||
}
|
||||
|
||||
//purge existing tmp data, keep everything else
|
||||
tmpDirectory.deleteDirectory();
|
||||
|
||||
zipped.walk(f -> f.copyTo(base.child(f.path())));
|
||||
dest.delete();
|
||||
}
|
||||
|
||||
public void modified(){
|
||||
modified = true;
|
||||
}
|
||||
|
||||
public int getItem(Item item){
|
||||
return items.get(item, 0);
|
||||
}
|
||||
|
||||
public void addItem(Item item, int amount){
|
||||
if(amount > 0){
|
||||
unlockContent(item);
|
||||
}
|
||||
amount = Math.max(amount, 0);
|
||||
|
||||
items.getAndIncrement(item, 0, amount);
|
||||
state.stats.itemsDelivered.getAndIncrement(item, 0, amount);
|
||||
|
||||
//clamp to capacity
|
||||
items.put(item, Mathf.clamp(items.get(item), 0, getItemCapacity()));
|
||||
|
||||
//clamp overflow
|
||||
if(state.stats.itemsDelivered.get(item, 0) < 0) state.stats.itemsDelivered.put(item, Integer.MAX_VALUE);
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
public boolean hasItems(Seq<ItemStack> stacks){
|
||||
return !stacks.contains(s -> items.get(s.item, 0) < s.amount);
|
||||
}
|
||||
|
||||
public boolean hasItems(ItemStack[] stacks){
|
||||
for(ItemStack stack : stacks){
|
||||
if(!has(stack.item, stack.amount)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void removeItems(ItemStack[] stacks){
|
||||
for(ItemStack stack : stacks){
|
||||
remove(stack.item, stack.amount);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeItems(Seq<ItemStack> stacks){
|
||||
for(ItemStack stack : stacks){
|
||||
remove(stack.item, stack.amount);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(Item item, int amount){
|
||||
items.getAndIncrement(item, 0, -amount);
|
||||
|
||||
modified = true;
|
||||
}
|
||||
|
||||
public boolean has(Item item, int amount){
|
||||
return items.get(item, 0) >= amount;
|
||||
}
|
||||
|
||||
//TODO: make it upgradeable
|
||||
public int getItemCapacity(){
|
||||
return 10000;
|
||||
}
|
||||
|
||||
/** Returns whether or not this piece of content is unlocked yet. */
|
||||
public boolean isUnlocked(UnlockableContent content){
|
||||
return content.alwaysUnlocked || unlocked.contains(content.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes this piece of content 'unlocked', if possible.
|
||||
* If this piece of content is already unlocked, nothing changes.
|
||||
* Results are not saved until you call {@link #save()}.
|
||||
*/
|
||||
public void unlockContent(UnlockableContent content){
|
||||
if(content.alwaysUnlocked) return;
|
||||
|
||||
//fire unlock event so other classes can use it
|
||||
if(unlocked.add(content.name)){
|
||||
modified = true;
|
||||
content.onUnlock();
|
||||
Events.fire(new UnlockEvent(content));
|
||||
}
|
||||
}
|
||||
|
||||
/** Clears all unlocked content. Automatically saves. */
|
||||
public void reset(){
|
||||
save();
|
||||
}
|
||||
|
||||
public void checkSave(){
|
||||
if(modified){
|
||||
save();
|
||||
modified = false;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void load(){
|
||||
items.clear();
|
||||
unlocked = Core.settings.getJson("unlocked-content", ObjectSet.class, ObjectSet::new);
|
||||
for(Item item : Vars.content.items()){
|
||||
items.put(item, Core.settings.getInt("item-" + item.name, 0));
|
||||
}
|
||||
|
||||
//set up default values
|
||||
if(!Core.settings.has("item-" + Items.copper.name)){
|
||||
addItem(Items.copper, 50);
|
||||
}
|
||||
}
|
||||
|
||||
public void save(){
|
||||
Core.settings.putJson("unlocked-content", String.class, unlocked);
|
||||
for(Item item : Vars.content.items()){
|
||||
Core.settings.put("item-" + item.name, items.get(item, 0));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -278,7 +278,7 @@ public class Schematics implements Loadable{
|
||||
/** Creates an array of build requests from a schematic's data, centered on the provided x+y coordinates. */
|
||||
public Seq<BuildPlan> toRequests(Schematic schem, int x, int y){
|
||||
return schem.tiles.map(t -> new BuildPlan(t.x + x - schem.width/2, t.y + y - schem.height/2, t.rotation, t.block).original(t.x, t.y, schem.width, schem.height).configure(t.config))
|
||||
.removeAll(s -> !s.block.isVisible() || !s.block.unlockedCur());
|
||||
.removeAll(s -> !s.block.isVisible() || !s.block.unlockedNow());
|
||||
}
|
||||
|
||||
/** Adds a schematic to the list, also copying it into the files.*/
|
||||
|
||||
@@ -24,6 +24,7 @@ public class Universe{
|
||||
load();
|
||||
}
|
||||
|
||||
/** Update regardless of whether the player is in the campaign. */
|
||||
public void updateGlobal(){
|
||||
//currently only updates one solar system
|
||||
updatePlanet(Planets.sun);
|
||||
@@ -40,6 +41,7 @@ public class Universe{
|
||||
}
|
||||
}
|
||||
|
||||
/** Update planet rotations, global time and relevant state. */
|
||||
public void update(){
|
||||
secondCounter += Time.delta() / 60f;
|
||||
|
||||
@@ -119,9 +121,11 @@ public class Universe{
|
||||
}
|
||||
|
||||
//calculate passive item generation
|
||||
//TODO make exports only update for sector with items
|
||||
//TODO items should be added directly to cores!
|
||||
int[] exports = getTotalExports();
|
||||
for(int i = 0; i < exports.length; i++){
|
||||
data.addItem(content.item(i), exports[i]);
|
||||
//data.addItem(content.item(i), exports[i]);
|
||||
}
|
||||
|
||||
Events.fire(new TurnEvent());
|
||||
|
||||
@@ -180,7 +180,7 @@ public class DesktopInput extends InputHandler{
|
||||
}
|
||||
|
||||
if((player.dead() || state.isPaused()) && !ui.chatfrag.shown()){
|
||||
if(!(scene.getKeyboardFocus() instanceof TextField)){
|
||||
if(!(scene.getKeyboardFocus() instanceof TextField) && !scene.hasDialog()){
|
||||
//move camera around
|
||||
float camSpeed = !Core.input.keyDown(Binding.boost) ? 3f : 8f;
|
||||
Core.camera.position.add(Tmp.v1.setZero().add(Core.input.axis(Binding.move_x), Core.input.axis(Binding.move_y)).nor().scl(Time.delta() * camSpeed));
|
||||
|
||||
@@ -651,7 +651,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{
|
||||
if(Core.settings.getBool("blockreplace")){
|
||||
lineRequests.each(req -> {
|
||||
Block replace = req.block.getReplacement(req, lineRequests);
|
||||
if(replace.unlockedCur()){
|
||||
if(replace.unlockedNow()){
|
||||
req.block = replace;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.content.TechTree.*;
|
||||
import mindustry.core.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.game.*;
|
||||
@@ -75,6 +76,11 @@ public abstract class SaveVersion extends SaveFileReader{
|
||||
state.secinfo.prepare();
|
||||
}
|
||||
|
||||
//flush tech node progress
|
||||
for(TechNode node : TechTree.all){
|
||||
node.save();
|
||||
}
|
||||
|
||||
writeStringMap(stream, StringMap.of(
|
||||
"saved", Time.millis(),
|
||||
"playtime", headless ? 0 : control.saves.getTotalPlaytime(),
|
||||
|
||||
@@ -7,6 +7,8 @@ import arc.util.io.*;
|
||||
import arc.util.pooling.*;
|
||||
import mindustry.ai.types.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.content.TechTree.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.entities.bullet.*;
|
||||
import mindustry.entities.units.*;
|
||||
@@ -67,6 +69,11 @@ public class TypeIO{
|
||||
for(int i = 0; i < ((Point2[])object).length; i++){
|
||||
write.i(((Point2[])object)[i].pack());
|
||||
}
|
||||
}else if(object instanceof TechNode){
|
||||
TechNode map = (TechNode)object;
|
||||
write.b(9);
|
||||
write.b((byte)map.content.getContentType().ordinal());
|
||||
write.s(map.content.id);
|
||||
}else{
|
||||
throw new IllegalArgumentException("Unknown object type: " + object.getClass());
|
||||
}
|
||||
@@ -84,6 +91,7 @@ public class TypeIO{
|
||||
case 6: short length = read.s(); IntSeq arr = new IntSeq(); for(int i = 0; i < length; i ++) arr.add(read.i()); return arr;
|
||||
case 7: return new Point2(read.i(), read.i());
|
||||
case 8: byte len = read.b(); Point2[] out = new Point2[len]; for(int i = 0; i < len; i ++) out[i] = Point2.unpack(read.i()); return out;
|
||||
case 9: return TechTree.getNotNull(content.getByID(ContentType.all[read.b()], read.s()));
|
||||
default: throw new IllegalArgumentException("Unknown object type: " + type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,7 +80,6 @@ public class Map implements Comparable<Map>, Publishable{
|
||||
|
||||
public void setHighScore(int score){
|
||||
Core.settings.put("hiscore" + file.nameWithoutExtension(), score);
|
||||
Vars.data.modified();
|
||||
}
|
||||
|
||||
/** Returns the result of applying this map's rules to the specified gamemode.*/
|
||||
|
||||
@@ -48,7 +48,7 @@ public class SectorPreset extends UnlockableContent{
|
||||
}
|
||||
|
||||
public boolean canUnlock(){
|
||||
return data.isUnlocked(this) || !requirements.contains(r -> !r.complete());
|
||||
return unlocked() || !requirements.contains(r -> !r.complete());
|
||||
}
|
||||
|
||||
public Seq<ItemStack> getLaunchCost(){
|
||||
@@ -74,7 +74,6 @@ public class SectorPreset extends UnlockableContent{
|
||||
public void setLaunched(){
|
||||
updateObjectives(() -> {
|
||||
Core.settings.put(name + "-launched", true);
|
||||
data.modified();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -84,7 +83,6 @@ public class SectorPreset extends UnlockableContent{
|
||||
if(value < wave){
|
||||
updateObjectives(() -> {
|
||||
Core.settings.put(name + "-wave", wave);
|
||||
data.modified();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -133,7 +131,6 @@ public class SectorPreset extends UnlockableContent{
|
||||
|
||||
stacks.sort();
|
||||
launchCost = stacks;
|
||||
data.modified();
|
||||
}
|
||||
|
||||
/** Whether this zone has met its condition; if true, the player can leave. */
|
||||
@@ -148,7 +145,6 @@ public class SectorPreset extends UnlockableContent{
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
|
||||
for(ItemStack stack : startingItems){
|
||||
defaultStartingItems.add(new ItemStack(stack.item, stack.amount));
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ public abstract class Weather extends MappableContent{
|
||||
private static final float fadeTime = 60 * 4;
|
||||
|
||||
Weather weather;
|
||||
float intensity = 1f, opacity = 1f, life;
|
||||
float intensity = 1f, opacity = 0f, life;
|
||||
|
||||
void init(Weather weather){
|
||||
this.weather = weather;
|
||||
|
||||
@@ -30,7 +30,7 @@ public class ItemsDisplay extends Table{
|
||||
t.marginRight(30f);
|
||||
t.left();
|
||||
for(Item item : content.items()){
|
||||
if(item.type == ItemType.material && data.isUnlocked(item)){
|
||||
if(item.type == ItemType.material && item.unlocked()){
|
||||
t.label(() -> format(item)).left();
|
||||
t.image(item.icon(Cicon.small)).size(8 * 3).padLeft(4).padRight(4);
|
||||
t.add(item.localizedName).color(Color.lightGray).left();
|
||||
@@ -51,10 +51,11 @@ public class ItemsDisplay extends Table{
|
||||
|
||||
private String format(Item item){
|
||||
builder.setLength(0);
|
||||
builder.append(ui.formatAmount(data.getItem(item)));
|
||||
if(state.isGame() && player.team().data().hasCore() && player.team().core().items().get(item) > 0){
|
||||
builder.append("[TODO implement]");
|
||||
//builder.append(ui.formatAmount(data.getItem(item)));
|
||||
if(state.isGame() && player.team().data().hasCore() && player.team().core().items.get(item) > 0){
|
||||
builder.append(" [unlaunched]+ ");
|
||||
builder.append(ui.formatAmount(state.teams.get(player.team()).core().items().get(item)));
|
||||
builder.append(ui.formatAmount(state.teams.get(player.team()).core().items.get(item)));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ public class LanguageDialog extends BaseDialog{
|
||||
Table langs = new Table();
|
||||
langs.marginRight(24f).marginLeft(24f);
|
||||
ScrollPane pane = new ScrollPane(langs);
|
||||
pane.setFadeScrollBars(false);
|
||||
pane.setScrollingDisabled(true, false);
|
||||
|
||||
ButtonGroup<TextButton> group = new ButtonGroup<>();
|
||||
|
||||
|
||||
@@ -40,11 +40,12 @@ public class PausedDialog extends BaseDialog{
|
||||
cont.button("$back", Icon.left, this::hide).colspan(2).width(dw * 2 + 20f);
|
||||
|
||||
cont.row();
|
||||
if(state.isCampaign()){
|
||||
cont.button("$techtree", Icon.tree, ui.tech::show);
|
||||
}else{
|
||||
cont.button("$database", Icon.book, ui.database::show);
|
||||
}
|
||||
//if(state.isCampaign()){
|
||||
// cont.button("$techtree", Icon.tree, ui.tech::show);
|
||||
//}else{
|
||||
// cont.button("$database", Icon.book, ui.database::show);
|
||||
//}
|
||||
cont.button("placeholder", Icon.warning, () -> ui.showInfo("go away"));
|
||||
cont.button("$settings", Icon.settings, ui.settings::show);
|
||||
|
||||
if(!state.rules.tutorial){
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package mindustry.ui.dialogs;
|
||||
|
||||
import arc.graphics.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
@@ -23,14 +22,15 @@ public class ResourcesDialog extends BaseDialog{
|
||||
t.margin(10f);
|
||||
int[] exports = universe.getTotalExports();
|
||||
for(Item item : content.items()){
|
||||
if(exports[item.id] > 0 || data.getItem(item) > 0){
|
||||
//TODO display total items
|
||||
if(exports[item.id] > 0){
|
||||
t.image(item.icon(Cicon.small)).padRight(4);
|
||||
t.add(ui.formatAmount(data.getItem(item))).color(Color.lightGray);
|
||||
if(exports[item.id] > 0){
|
||||
//t.add(ui.formatAmount(data.getItem(item))).color(Color.lightGray);
|
||||
//if(exports[item.id] > 0){
|
||||
t.add("+ [accent]" + ui.formatAmount(exports[item.id]) + " [lightgray]/T");
|
||||
}else{
|
||||
t.add();
|
||||
}
|
||||
//}else{
|
||||
// t.add();
|
||||
//}
|
||||
t.row();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import arc.scene.ui.TextButton.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import mindustry.core.GameState.*;
|
||||
import mindustry.core.*;
|
||||
import mindustry.game.EventType.*;
|
||||
@@ -21,7 +22,11 @@ import mindustry.graphics.*;
|
||||
import mindustry.input.*;
|
||||
import mindustry.ui.*;
|
||||
|
||||
import static arc.Core.bundle;
|
||||
import java.io.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
import static arc.Core.*;
|
||||
import static mindustry.Vars.net;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class SettingsMenuDialog extends SettingsDialog{
|
||||
@@ -107,7 +112,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
if(ios){
|
||||
Fi file = Core.files.local("mindustry-data-export.zip");
|
||||
try{
|
||||
data.exportData(file);
|
||||
exportData(file);
|
||||
}catch(Exception e){
|
||||
ui.showException(e);
|
||||
}
|
||||
@@ -115,7 +120,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
}else{
|
||||
platform.showFileChooser(false, "zip", file -> {
|
||||
try{
|
||||
data.exportData(file);
|
||||
exportData(file);
|
||||
ui.showInfo("$data.exported");
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
@@ -129,7 +134,7 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
|
||||
t.button("$data.import", Icon.download, style, () -> ui.showConfirm("$confirm", "$data.import.confirm", () -> platform.showFileChooser(true, "zip", file -> {
|
||||
try{
|
||||
data.importData(file);
|
||||
importData(file);
|
||||
Core.app.exit();
|
||||
}catch(IllegalArgumentException e){
|
||||
ui.showErrorMessage("$data.invalid");
|
||||
@@ -365,6 +370,43 @@ public class SettingsMenuDialog extends SettingsDialog{
|
||||
graphics.checkPref("flow", true);
|
||||
}
|
||||
|
||||
public void exportData(Fi file) throws IOException{
|
||||
Seq<Fi> files = new Seq<>();
|
||||
files.add(Core.settings.getSettingsFile());
|
||||
files.addAll(customMapDirectory.list());
|
||||
files.addAll(saveDirectory.list());
|
||||
files.addAll(screenshotDirectory.list());
|
||||
files.addAll(modDirectory.list());
|
||||
files.addAll(schematicDirectory.list());
|
||||
String base = Core.settings.getDataDirectory().path();
|
||||
|
||||
try(OutputStream fos = file.write(false, 2048); ZipOutputStream zos = new ZipOutputStream(fos)){
|
||||
for(Fi add : files){
|
||||
if(add.isDirectory()) continue;
|
||||
zos.putNextEntry(new ZipEntry(add.path().substring(base.length())));
|
||||
Streams.copy(add.read(), zos);
|
||||
zos.closeEntry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void importData(Fi file){
|
||||
Fi dest = Core.files.local("zipdata.zip");
|
||||
file.copyTo(dest);
|
||||
Fi zipped = new ZipFi(dest);
|
||||
|
||||
Fi base = Core.settings.getDataDirectory();
|
||||
if(!zipped.child("settings.bin").exists()){
|
||||
throw new IllegalArgumentException("Not valid save data.");
|
||||
}
|
||||
|
||||
//purge existing tmp data, keep everything else
|
||||
tmpDirectory.deleteDirectory();
|
||||
|
||||
zipped.walk(f -> f.copyTo(base.child(f.path())));
|
||||
dest.delete();
|
||||
}
|
||||
|
||||
private void back(){
|
||||
rebuildMenu();
|
||||
prefs.clearChildren();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package mindustry.ui.dialogs;
|
||||
|
||||
import arc.*;
|
||||
import arc.func.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.input.*;
|
||||
@@ -35,15 +36,17 @@ public class TechTreeDialog extends BaseDialog{
|
||||
private ObjectSet<TechTreeNode> nodes = new ObjectSet<>();
|
||||
private TechTreeNode root = new TechTreeNode(TechTree.root, null);
|
||||
private Rect bounds = new Rect();
|
||||
private ItemsDisplay items;
|
||||
private View view;
|
||||
private Cons<TechNode> selector = c -> {};
|
||||
|
||||
public TechTreeDialog(){
|
||||
super("");
|
||||
|
||||
titleTable.remove();
|
||||
margin(0f).marginBottom(8);
|
||||
Stack stack = cont.stack(view = new View(), items = new ItemsDisplay()).grow().get();
|
||||
Stack stack = cont.stack(view = new View()/*, items = new ItemsDisplay()*/).grow().get();
|
||||
|
||||
shouldPause = true;
|
||||
|
||||
Events.on(ContentReloadEvent.class, e -> {
|
||||
nodes.clear();
|
||||
@@ -72,7 +75,7 @@ public class TechTreeDialog extends BaseDialog{
|
||||
addListener(new InputListener(){
|
||||
@Override
|
||||
public boolean scrolled(InputEvent event, float x, float y, float amountX, float amountY){
|
||||
view.setScale(Mathf.clamp(view.getScaleX() - amountY / 40f, 0.25f, 1f));
|
||||
view.setScale(Mathf.clamp(view.getScaleX() - amountY / 10f * view.getScaleX(), 0.25f, 1f));
|
||||
view.setOrigin(Align.center);
|
||||
view.setTransform(true);
|
||||
return true;
|
||||
@@ -112,6 +115,15 @@ public class TechTreeDialog extends BaseDialog{
|
||||
});
|
||||
}
|
||||
|
||||
public Dialog show(Cons<TechNode> selector){
|
||||
this.selector = selector;
|
||||
return super.show();
|
||||
}
|
||||
|
||||
public Dialog show(){
|
||||
return show(c -> {});
|
||||
}
|
||||
|
||||
void treeLayout(){
|
||||
float spacing = 20f;
|
||||
LayoutNode node = new LayoutNode(root, null);
|
||||
@@ -163,8 +175,6 @@ public class TechTreeDialog extends BaseDialog{
|
||||
l.visible = !locked;
|
||||
checkNodes(l);
|
||||
}
|
||||
|
||||
items.rebuild();
|
||||
}
|
||||
|
||||
void showToast(String info){
|
||||
@@ -247,9 +257,13 @@ public class TechTreeDialog extends BaseDialog{
|
||||
}
|
||||
});
|
||||
}
|
||||
}else if(data.hasItems(node.node.requirements) && locked(node.node)){
|
||||
unlock(node.node);
|
||||
}else if(locked(node.node)){
|
||||
selector.get(node.node);
|
||||
}
|
||||
//TODO select it
|
||||
//else if(data.hasItems(node.node.requirements) && locked(node.node)){
|
||||
// unlock(node.node);
|
||||
//}
|
||||
});
|
||||
button.hovered(() -> {
|
||||
if(!mobile && hoverNode != button && node.visible){
|
||||
@@ -269,7 +283,7 @@ public class TechTreeDialog 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 : !data.hasItems(node.node.requirements) ? Tex.buttonRed : Tex.button;
|
||||
button.getStyle().up = !locked(node.node) ? Tex.buttonOver : Tex.button;
|
||||
((TextureRegionDrawable)button.getStyle().imageUp)
|
||||
.setRegion(node.visible ? node.node.content.icon(Cicon.medium) : Icon.lock.getRegion());
|
||||
button.getImage().setColor(!locked(node.node) ? Color.white : Color.gray);
|
||||
@@ -304,9 +318,11 @@ public class TechTreeDialog extends BaseDialog{
|
||||
panY = ry - bounds.y - oy;
|
||||
}
|
||||
|
||||
/*
|
||||
void unlock(TechNode node){
|
||||
data.unlockContent(node.content);
|
||||
data.removeItems(node.requirements);
|
||||
//TODO this should not happen
|
||||
//data.removeItems(node.requirements);
|
||||
showToast(Core.bundle.format("researched", node.content.localizedName));
|
||||
checkNodes(root);
|
||||
hoverNode = null;
|
||||
@@ -315,7 +331,7 @@ public class TechTreeDialog extends BaseDialog{
|
||||
Core.scene.act();
|
||||
Sounds.unlock.play();
|
||||
Events.fire(new ResearchEvent(node.content));
|
||||
}
|
||||
}*/
|
||||
|
||||
void rebuild(){
|
||||
ImageButton button = hoverNode;
|
||||
@@ -357,8 +373,8 @@ public class TechTreeDialog extends BaseDialog{
|
||||
list.left();
|
||||
list.image(req.item.icon(Cicon.small)).size(8 * 3).padRight(3);
|
||||
list.add(req.item.localizedName).color(Color.lightGray);
|
||||
list.label(() -> " " + Math.min(data.getItem(req.item), req.amount) + " / " + req.amount)
|
||||
.update(l -> l.setColor(data.has(req.item, req.amount) ? Color.lightGray : Color.scarlet));
|
||||
list.label(() -> " " + (player.team().core() != null ? Math.min(player.team().core().items.get(req.item), req.amount) + " / " : "") + req.amount)
|
||||
.update(l -> {}/*l.setColor(data.has(req.item, req.amount) ? Color.lightGray : Color.scarlet)*/);//TODO
|
||||
}).fillX().left();
|
||||
t.row();
|
||||
}
|
||||
@@ -383,11 +399,13 @@ public class TechTreeDialog extends BaseDialog{
|
||||
}
|
||||
}).pad(9);
|
||||
|
||||
//TODO research select button
|
||||
/*
|
||||
if(mobile && locked(node)){
|
||||
b.row();
|
||||
b.button("$research", Icon.ok, Styles.nodet, () -> unlock(node))
|
||||
.disabled(i -> !data.hasItems(node.requirements)).growX().height(44f).colspan(3);
|
||||
}
|
||||
}*/
|
||||
});
|
||||
|
||||
infoTable.row();
|
||||
|
||||
@@ -426,7 +426,7 @@ public class PlacementFragment extends Fragment{
|
||||
}
|
||||
|
||||
boolean unlocked(Block block){
|
||||
return !state.isCampaign() || data.isUnlocked(block);
|
||||
return block.unlockedNow();
|
||||
}
|
||||
|
||||
boolean hasInfoBox(){
|
||||
|
||||
@@ -388,12 +388,12 @@ public class Block extends UnlockableContent{
|
||||
}
|
||||
|
||||
/** Configure when a null value is passed.*/
|
||||
public void configClear(Cons<Tilec> cons){
|
||||
configurations.put(void.class, (tile, value) -> cons.get((Tilec)tile));
|
||||
public <E extends Tilec> void configClear(Cons<E> cons){
|
||||
configurations.put(void.class, (tile, value) -> cons.get((E)tile));
|
||||
}
|
||||
|
||||
/** Listen for a config by class type. */
|
||||
public <T> void config(Class<T> type, Cons2<Tilec, T> config){
|
||||
public <T, E extends Tilec> void config(Class<T> type, Cons2<E, T> config){
|
||||
configurations.put(type, config);
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ public class ItemSelection{
|
||||
int i = 0;
|
||||
|
||||
for(T item : items){
|
||||
if(!data.isUnlocked(item) && state.isCampaign()) continue;
|
||||
if(!item.unlockedNow()) continue;
|
||||
|
||||
ImageButton button = cont.button(Tex.whiteui, Styles.clearToggleTransi, 24, () -> control.input.frag.config.hideConfig()).group(group).get();
|
||||
button.changed(() -> consumer.get(button.isChecked() ? item : null));
|
||||
|
||||
@@ -177,7 +177,8 @@ public class LaunchPad extends Block{
|
||||
//actually launch the items upon removal
|
||||
if(team() == Vars.state.rules.defaultTeam){
|
||||
for(ItemStack stack : stacks){
|
||||
Vars.data.addItem(stack.item, stack.amount);
|
||||
//TODO where do the items go?
|
||||
//Vars.data.addItem(stack.item, stack.amount);
|
||||
Events.fire(new LaunchItemEvent(stack));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
package mindustry.world.blocks.campaign;
|
||||
|
||||
import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.scene.style.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
import arc.util.*;
|
||||
import arc.util.io.*;
|
||||
import mindustry.*;
|
||||
import mindustry.annotations.Annotations.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.content.TechTree.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.storage.*;
|
||||
import mindustry.world.consumers.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class ResearchBlock extends StorageBlock{
|
||||
public class ResearchBlock extends Block{
|
||||
public float researchSpeed = 1f;
|
||||
public @Load("@-top") TextureRegion topRegion;
|
||||
|
||||
@@ -31,7 +33,11 @@ public class ResearchBlock extends StorageBlock{
|
||||
hasPower = true;
|
||||
hasItems = true;
|
||||
configurable = true;
|
||||
itemCapacity = 0;
|
||||
itemCapacity = 100;
|
||||
|
||||
//TODO requirements shrink as time goes on
|
||||
consumes.add(new ConsumeItemDynamic((ResearchBlockEntity entity) -> entity.researching != null ? entity.researching.requirements : ItemStack.empty));
|
||||
config(TechNode.class, ResearchBlockEntity::setTo);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -40,33 +46,100 @@ public class ResearchBlock extends StorageBlock{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlaceOn(Tile tile, Team team){
|
||||
if(tile == null) return false;
|
||||
public void setBars(){
|
||||
super.setBars();
|
||||
|
||||
//only allow placing next to cores
|
||||
for(Point2 edge : Edges.getEdges(size)){
|
||||
Tile other = tile.getNearby(edge);
|
||||
if(other != null && other.block() instanceof CoreBlock && other.team() == team){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
bars.add("progress", (ResearchBlockEntity e) -> new Bar("bar.progress", Pal.ammo, () -> e.researching == null ? 0f : e.researching.progress / e.researching.time));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawPlace(int x, int y, int rotation, boolean valid){
|
||||
boolean hasCore = canPlaceOn(world.tile(x, y), player.team());
|
||||
if(!hasCore){
|
||||
drawPlaceText(Core.bundle.get("bar.corereq"), x, y, valid);
|
||||
}
|
||||
}
|
||||
public class ResearchBlockEntity extends TileEntity{
|
||||
public @Nullable TechNode researching;
|
||||
|
||||
public class ResearchBlockEntity extends StorageBlockEntity{
|
||||
public @Nullable UnlockableContent researching;
|
||||
public double[] accumulator;
|
||||
public double[] totalAccumulator;
|
||||
|
||||
@Override
|
||||
public void updateTile(){
|
||||
if(researching != null){
|
||||
double totalTicks = researching.time * 60.0;
|
||||
double amount = researchSpeed * edelta() / totalTicks;
|
||||
|
||||
double maxProgress = checkRequired(amount, false);
|
||||
|
||||
for(int i = 0; i < researching.requirements.length; i++){
|
||||
int reqamount = Math.round(state.rules.buildCostMultiplier * researching.requirements[i].amount);
|
||||
accumulator[i] += Math.min(reqamount * maxProgress, reqamount - totalAccumulator[i] + 0.00001); //add min amount progressed to the accumulator
|
||||
totalAccumulator[i] = Math.min(totalAccumulator[i] + reqamount * maxProgress, reqamount);
|
||||
}
|
||||
|
||||
maxProgress = checkRequired(maxProgress, true);
|
||||
|
||||
float increment = (float)(maxProgress * researching.time);
|
||||
researching.progress += increment;
|
||||
|
||||
//check if it has been researched
|
||||
if(researching.progress >= researching.time){
|
||||
data.unlockContent(researching.content);
|
||||
|
||||
setTo(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private double checkRequired(double amount, boolean remove){
|
||||
double maxProgress = amount;
|
||||
|
||||
for(int i = 0; i < researching.requirements.length; i++){
|
||||
int ramount = researching.requirements[i].amount;
|
||||
int required = (int)(accumulator[i]); //calculate items that are required now
|
||||
|
||||
if(!items.has(researching.requirements[i].item) && ramount > 0){
|
||||
maxProgress = 0f;
|
||||
}else if(required > 0){ //if this amount is positive...
|
||||
//calculate how many items it can actually use
|
||||
int maxUse = Math.min(required, items.get(researching.requirements[i].item));
|
||||
//get this as a fraction
|
||||
double fraction = maxUse / (double)required;
|
||||
|
||||
//move max progress down if this fraction is less than 1
|
||||
maxProgress = Math.min(maxProgress, maxProgress * fraction);
|
||||
|
||||
accumulator[i] -= maxUse;
|
||||
|
||||
//remove stuff that is actually used
|
||||
if(remove){
|
||||
items.remove(researching.requirements[i].item, maxUse);
|
||||
}
|
||||
}
|
||||
//else, no items are required yet, so just keep going
|
||||
}
|
||||
|
||||
return maxProgress;
|
||||
}
|
||||
|
||||
private void setTo(@Nullable TechNode value){
|
||||
researching = value;
|
||||
if(value != null){
|
||||
accumulator = new double[researching.requirements.length];
|
||||
totalAccumulator = new double[researching.requirements.length];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void display(Table table){
|
||||
super.display(table);
|
||||
|
||||
TextureRegionDrawable reg = new TextureRegionDrawable();
|
||||
|
||||
table.row();
|
||||
table.table(t -> {
|
||||
t.image().update(i -> {
|
||||
i.setDrawable(researching == null ? Icon.cancel : reg.set(researching.content.icon(Cicon.medium)));
|
||||
i.setScaling(Scaling.fit);
|
||||
i.setColor(researching == null ? Color.lightGray : Color.white);
|
||||
}).size(32).pad(3);
|
||||
t.label(() -> researching == null ? "$none" : researching.content.localizedName).color(Color.lightGray);
|
||||
}).left().padTop(4);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -85,14 +158,25 @@ public class ResearchBlock extends StorageBlock{
|
||||
|
||||
@Override
|
||||
public boolean acceptItem(Tilec source, Item item){
|
||||
//research blocks can only transfer items to the core
|
||||
return linkedCore != null && super.acceptItem(source, item);
|
||||
return items.get(item) < getMaximumAccepted(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaximumAccepted(Item item){
|
||||
if(researching == null) return 0;
|
||||
for(int i = 0; i < researching.requirements.length; i++){
|
||||
if(researching.requirements[i].item == item) return researching.requirements[i].amount;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean configTapped(){
|
||||
//TODO select target
|
||||
Vars.ui.tech.show();
|
||||
//configure with tech node
|
||||
ui.tech.show(node -> {
|
||||
configure(node);
|
||||
ui.tech.hide();
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -102,8 +186,8 @@ public class ResearchBlock extends StorageBlock{
|
||||
super.write(write);
|
||||
|
||||
if(researching != null){
|
||||
write.b(researching.getContentType().ordinal());
|
||||
write.s(researching.id);
|
||||
write.b(researching.content.getContentType().ordinal());
|
||||
write.s(researching.content.id);
|
||||
}else{
|
||||
write.b(-1);
|
||||
}
|
||||
@@ -115,7 +199,7 @@ public class ResearchBlock extends StorageBlock{
|
||||
|
||||
byte type = read.b();
|
||||
if(type != -1){
|
||||
researching = Vars.content.getByID(ContentType.all[type], read.s());
|
||||
setTo(TechTree.get(content.getByID(ContentType.all[type], read.s())));
|
||||
}else{
|
||||
researching = null;
|
||||
}
|
||||
|
||||
@@ -28,12 +28,11 @@ public class Door extends Wall{
|
||||
solidifes = true;
|
||||
consumesTap = true;
|
||||
|
||||
config(Boolean.class, (entity, open) -> {
|
||||
DoorEntity door = (DoorEntity)entity;
|
||||
door.open = open;
|
||||
pathfinder.updateTile(door.tile());
|
||||
(open ? closefx : openfx).at(door);
|
||||
Sounds.door.at(door);
|
||||
config(Boolean.class, (DoorEntity entity, Boolean open) -> {
|
||||
entity.open = open;
|
||||
pathfinder.updateTile(entity.tile());
|
||||
(open ? closefx : openfx).at(entity);
|
||||
Sounds.door.at(entity);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ public class ItemTurret extends Turret{
|
||||
@Override
|
||||
public void build(Tilec tile, Table table){
|
||||
MultiReqImage image = new MultiReqImage();
|
||||
content.items().each(i -> filter.get(i) && (!state.isCampaign() || data.isUnlocked(i)), item -> image.add(new ReqImage(new ItemImage(item.icon(Cicon.medium)),
|
||||
content.items().each(i -> filter.get(i) && i.unlockedNow(), item -> image.add(new ReqImage(new ItemImage(item.icon(Cicon.medium)),
|
||||
() -> tile != null && !((ItemTurretEntity)tile).ammo.isEmpty() && ((ItemEntry)((ItemTurretEntity)tile).ammo.peek()).item == item)));
|
||||
|
||||
table.add(image).size(8 * 4);
|
||||
|
||||
@@ -44,9 +44,9 @@ public class ItemBridge extends Block{
|
||||
canOverdrive = false;
|
||||
|
||||
//point2 config is relative
|
||||
config(Point2.class, (tile, i) -> ((ItemBridgeEntity)tile).link = Point2.pack(i.x + tile.tileX(), i.y + tile.tileY()));
|
||||
config(Point2.class, (ItemBridgeEntity tile, Point2 i) -> tile.link = Point2.pack(i.x + tile.tileX(), i.y + tile.tileY()));
|
||||
//integer is not
|
||||
config(Integer.class, (tile, i) -> ((ItemBridgeEntity)tile).link = i);
|
||||
config(Integer.class, (ItemBridgeEntity tile, Integer i) -> tile.link = i);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -42,8 +42,8 @@ public class MassDriver extends Block{
|
||||
hasPower = true;
|
||||
outlineIcon = true;
|
||||
//point2 is relative
|
||||
config(Point2.class, (tile, point) -> ((MassDriverEntity)tile).link = Point2.pack(point.x + tile.tileX(), point.y + tile.tileY()));
|
||||
config(Integer.class, (tile, point) -> ((MassDriverEntity)tile).link = point);
|
||||
config(Point2.class, (MassDriverEntity tile, Point2 point) -> tile.link = Point2.pack(point.x + tile.tileX(), point.y + tile.tileY()));
|
||||
config(Integer.class, (MassDriverEntity tile, Integer point) -> tile.link = point);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -28,8 +28,8 @@ public class Sorter extends Block{
|
||||
unloadable = false;
|
||||
saveConfig = true;
|
||||
|
||||
config(Item.class, (tile, item) -> ((SorterEntity)tile).sortItem = item);
|
||||
configClear(tile -> ((SorterEntity)tile).sortItem = null);
|
||||
config(Item.class, (SorterEntity tile, Item item) -> tile.sortItem = item);
|
||||
configClear((SorterEntity tile) -> tile.sortItem = null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -33,17 +33,9 @@ public class BlockForge extends PayloadAcceptor{
|
||||
hasPower = true;
|
||||
rotate = true;
|
||||
|
||||
config(Block.class, (tile, block) -> ((BlockForgeEntity)tile).recipe = block);
|
||||
config(Block.class, (BlockForgeEntity tile, Block block) -> tile.recipe = block);
|
||||
|
||||
consumes.add(new ConsumeItemDynamic(e -> {
|
||||
BlockForgeEntity entity = (BlockForgeEntity)e;
|
||||
|
||||
if(entity.recipe != null){
|
||||
return entity.recipe.requirements;
|
||||
}
|
||||
|
||||
return ItemStack.empty;
|
||||
}));
|
||||
consumes.add(new ConsumeItemDynamic((BlockForgeEntity e) -> e.recipe != null ? e.recipe.requirements : ItemStack.empty));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -43,11 +43,11 @@ public class ImpactReactor extends PowerGenerator{
|
||||
public void setBars(){
|
||||
super.setBars();
|
||||
|
||||
bars.add("poweroutput", entity -> new Bar(() ->
|
||||
bars.add("poweroutput", (GeneratorEntity entity) -> new Bar(() ->
|
||||
Core.bundle.format("bar.poweroutput",
|
||||
Strings.fixed(Math.max(entity.getPowerProduction() - consumes.getPower().usage, 0) * 60 * entity.timeScale(), 1)),
|
||||
() -> Pal.powerBar,
|
||||
() -> ((GeneratorEntity)entity).productionEfficiency));
|
||||
() -> entity.productionEfficiency));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -24,7 +24,7 @@ public class LightBlock extends Block{
|
||||
configurable = true;
|
||||
saveConfig = true;
|
||||
|
||||
config(Integer.class, (tile, value) -> ((LightEntity)tile).color = value);
|
||||
config(Integer.class, (LightEntity tile, Integer value) -> tile.color = value);
|
||||
}
|
||||
|
||||
public class LightEntity extends TileEntity{
|
||||
|
||||
@@ -60,7 +60,7 @@ public class NuclearReactor extends PowerGenerator{
|
||||
@Override
|
||||
public void setBars(){
|
||||
super.setBars();
|
||||
bars.add("heat", entity -> new Bar("bar.heat", Pal.lightOrange, () -> ((NuclearReactorEntity)entity).heat));
|
||||
bars.add("heat", (NuclearReactorEntity entity) -> new Bar("bar.heat", Pal.lightOrange, () -> entity.heat));
|
||||
}
|
||||
|
||||
public class NuclearReactorEntity extends GeneratorEntity{
|
||||
|
||||
@@ -32,11 +32,11 @@ public class PowerGenerator extends PowerDistributor{
|
||||
super.setBars();
|
||||
|
||||
if(hasPower && outputsPower && !consumes.hasPower()){
|
||||
bars.add("power", entity -> new Bar(() ->
|
||||
bars.add("power", (GeneratorEntity entity) -> new Bar(() ->
|
||||
Core.bundle.format("bar.poweroutput",
|
||||
Strings.fixed(entity.getPowerProduction() * 60 * entity.timeScale(), 1)),
|
||||
() -> Pal.powerBar,
|
||||
() -> ((GeneratorEntity)entity).productionEfficiency));
|
||||
() -> entity.productionEfficiency));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,11 +31,11 @@ public class Cultivator extends GenericCrafter{
|
||||
@Override
|
||||
public void setBars(){
|
||||
super.setBars();
|
||||
bars.add("multiplier", entity -> new Bar(() ->
|
||||
bars.add("multiplier", (CultivatorEntity entity) -> new Bar(() ->
|
||||
Core.bundle.formatFloat("bar.efficiency",
|
||||
((((CultivatorEntity)entity).boost + 1f) * ((CultivatorEntity)entity).warmup) * 100f, 1),
|
||||
((entity.boost + 1f) * entity.warmup) * 100f, 1),
|
||||
() -> Pal.ammo,
|
||||
() -> ((CultivatorEntity)entity).warmup));
|
||||
() -> entity.warmup));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -86,11 +86,8 @@ public class Drill extends Block{
|
||||
public void setBars(){
|
||||
super.setBars();
|
||||
|
||||
bars.add("drillspeed", e -> {
|
||||
DrillEntity entity = (DrillEntity)e;
|
||||
|
||||
return new Bar(() -> Core.bundle.format("bar.drillspeed", Strings.fixed(entity.lastDrillSpeed * 60 * entity.timeScale(), 2)), () -> Pal.ammo, () -> entity.warmup);
|
||||
});
|
||||
bars.add("drillspeed", (DrillEntity e) ->
|
||||
new Bar(() -> Core.bundle.format("bar.drillspeed", Strings.fixed(e.lastDrillSpeed * 60 * e.timeScale(), 2)), () -> Pal.ammo, () -> e.warmup));
|
||||
}
|
||||
|
||||
public Item getDrop(Tile tile){
|
||||
@@ -285,7 +282,6 @@ public class Drill extends Block{
|
||||
|
||||
if(dominantItems > 0 && progress >= delay && items.total() < itemCapacity){
|
||||
offload(dominantItem);
|
||||
useContent(dominantItem);
|
||||
|
||||
index ++;
|
||||
progress %= delay;
|
||||
|
||||
@@ -116,14 +116,12 @@ public class GenericCrafter extends Block{
|
||||
consume();
|
||||
|
||||
if(outputItem != null){
|
||||
useContent(outputItem.item);
|
||||
for(int i = 0; i < outputItem.amount; i++){
|
||||
offload(outputItem.item);
|
||||
}
|
||||
}
|
||||
|
||||
if(outputLiquid != null){
|
||||
useContent(outputLiquid.liquid);
|
||||
handleLiquid(this, outputLiquid.liquid, outputLiquid.amount);
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ public class LiquidConverter extends GenericCrafter{
|
||||
if(cons.valid()){
|
||||
float use = Math.min(cl.amount * edelta(), liquidCapacity - liquids.get(outputLiquid.liquid));
|
||||
|
||||
useContent(outputLiquid.liquid);
|
||||
progress += use / cl.amount;
|
||||
liquids.add(outputLiquid.liquid, use);
|
||||
if(progress >= craftTime){
|
||||
|
||||
@@ -13,8 +13,6 @@ import mindustry.world.meta.*;
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class Pump extends LiquidBlock{
|
||||
public final int timerContentCheck = timers++;
|
||||
|
||||
/** Pump amount, total. */
|
||||
protected float pumpAmount = 1f;
|
||||
|
||||
@@ -115,10 +113,6 @@ public class Pump extends LiquidBlock{
|
||||
liquids.add(liquidDrop, maxPump);
|
||||
}
|
||||
|
||||
if(liquids.currentAmount() > 0f && timer(timerContentCheck, 10)){
|
||||
useContent(liquids.current());
|
||||
}
|
||||
|
||||
dumpLiquid(liquids.current());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,11 +43,11 @@ public class SolidPump extends Pump{
|
||||
@Override
|
||||
public void setBars(){
|
||||
super.setBars();
|
||||
bars.add("efficiency", entity -> new Bar(() ->
|
||||
bars.add("efficiency", (SolidPumpEntity entity) -> new Bar(() ->
|
||||
Core.bundle.formatFloat("bar.pumpspeed",
|
||||
((SolidPumpEntity)entity).lastPump / Time.delta() * 60, 1),
|
||||
entity.lastPump / Time.delta() * 60, 1),
|
||||
() -> Pal.ammo,
|
||||
() -> ((SolidPumpEntity)entity).warmup));
|
||||
() -> entity.warmup));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -124,7 +124,6 @@ public class SolidPump extends Pump{
|
||||
liquids.add(result, maxPump);
|
||||
lastPump = maxPump;
|
||||
warmup = Mathf.lerpDelta(warmup, 1f, 0.02f);
|
||||
if(timer(timerContentCheck, 10)) useContent(result);
|
||||
if(Mathf.chance(delta() * updateEffectChance))
|
||||
updateEffect.at(getX() + Mathf.range(size * 2f), getY() + Mathf.range(size * 2f));
|
||||
}else{
|
||||
|
||||
@@ -24,8 +24,8 @@ public class ItemSource extends Block{
|
||||
configurable = true;
|
||||
saveConfig = true;
|
||||
|
||||
config(Item.class, (tile, item) -> ((ItemSourceEntity)tile).outputItem = item);
|
||||
configClear(tile -> ((ItemSourceEntity)tile).outputItem = null);
|
||||
config(Item.class, (ItemSourceEntity tile, Item item) -> tile.outputItem = item);
|
||||
configClear((ItemSourceEntity tile) -> tile.outputItem = null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -25,8 +25,8 @@ public class LiquidSource extends Block{
|
||||
outputsLiquid = true;
|
||||
saveConfig = true;
|
||||
|
||||
config(Liquid.class, (tile, l) -> ((LiquidSourceEntity)tile).source = l);
|
||||
configClear(tile -> ((LiquidSourceEntity)tile).source = null);
|
||||
config(Liquid.class, (LiquidSourceEntity tile, Liquid l) -> tile.source = l);
|
||||
configClear((LiquidSourceEntity tile) -> tile.source = null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -69,11 +69,11 @@ public class CoreBlock extends StorageBlock{
|
||||
public void setStats(){
|
||||
super.setStats();
|
||||
|
||||
bars.add("capacity", e ->
|
||||
bars.add("capacity", (CoreEntity e) ->
|
||||
new Bar(
|
||||
() -> Core.bundle.format("bar.capacity", ui.formatAmount(((CoreEntity)e).storageCapacity)),
|
||||
() -> Core.bundle.format("bar.capacity", ui.formatAmount(e.storageCapacity)),
|
||||
() -> Pal.items,
|
||||
() -> e.items().total() / (float)(((CoreEntity)e).storageCapacity * content.items().count(i -> i.type == ItemType.material))
|
||||
() -> e.items().total() / ((float)e.storageCapacity * content.items().count(i -> i.type == ItemType.material))
|
||||
));
|
||||
|
||||
bars.add("units", e ->
|
||||
|
||||
@@ -29,9 +29,7 @@ public class MessageBlock extends Block{
|
||||
solid = true;
|
||||
destructible = true;
|
||||
|
||||
config(String.class, (tile, text) -> {
|
||||
MessageBlockEntity entity = (MessageBlockEntity)tile;
|
||||
|
||||
config(String.class, (MessageBlockEntity tile, String text) -> {
|
||||
if(net.server() && text.length() > maxTextLength){
|
||||
throw new ValidateException(player, "Player has gone above text limit.");
|
||||
}
|
||||
@@ -51,8 +49,8 @@ public class MessageBlock extends Block{
|
||||
}
|
||||
}
|
||||
|
||||
entity.message = result.toString();
|
||||
entity.lines = entity.message.split("\n");
|
||||
tile.message = result.toString();
|
||||
tile.lines = tile.message.split("\n");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -27,12 +27,8 @@ public class Unloader extends Block{
|
||||
saveConfig = true;
|
||||
itemCapacity = 0;
|
||||
|
||||
config(Item.class, (tile, item) -> {
|
||||
tile.items().clear();
|
||||
((UnloaderEntity)tile).sortItem = item;
|
||||
});
|
||||
|
||||
configClear(tile -> ((UnloaderEntity)tile).sortItem = null);
|
||||
config(Item.class, (UnloaderEntity tile, Item item) -> tile.sortItem = item);
|
||||
configClear((UnloaderEntity tile) -> tile.sortItem = null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -41,7 +41,7 @@ public class Reconstructor extends UnitBlock{
|
||||
@Override
|
||||
public void setBars(){
|
||||
super.setBars();
|
||||
bars.add("progress", entity -> new Bar("bar.progress", Pal.ammo, ((ReconstructorEntity)entity)::fraction));
|
||||
bars.add("progress", (ReconstructorEntity entity) -> new Bar("bar.progress", Pal.ammo, entity::fraction));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -37,20 +37,12 @@ public class UnitFactory extends UnitBlock{
|
||||
outputsPayload = true;
|
||||
rotate = true;
|
||||
|
||||
config(Integer.class, (tile, i) -> {
|
||||
((UnitFactoryEntity)tile).currentPlan = i < 0 || i >= plans.length ? -1 : i;
|
||||
((UnitFactoryEntity)tile).progress = 0;
|
||||
config(Integer.class, (UnitFactoryEntity tile, Integer i) -> {
|
||||
tile.currentPlan = i < 0 || i >= plans.length ? -1 : i;
|
||||
tile.progress = 0;
|
||||
});
|
||||
|
||||
consumes.add(new ConsumeItemDynamic(e -> {
|
||||
UnitFactoryEntity entity = (UnitFactoryEntity)e;
|
||||
|
||||
if(entity.currentPlan != -1){
|
||||
return plans[entity.currentPlan].requirements;
|
||||
}
|
||||
|
||||
return ItemStack.empty;
|
||||
}));
|
||||
consumes.add(new ConsumeItemDynamic((UnitFactoryEntity e) -> e.currentPlan != -1 ? plans[e.currentPlan].requirements : ItemStack.empty));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,7 +61,7 @@ public class UnitFactory extends UnitBlock{
|
||||
@Override
|
||||
public void setBars(){
|
||||
super.setBars();
|
||||
bars.add("progress", entity -> new Bar("bar.progress", Pal.ammo, ((UnitFactoryEntity)entity)::fraction));
|
||||
bars.add("progress", (UnitFactoryEntity entity) -> new Bar("bar.progress", Pal.ammo, entity::fraction));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package mindustry.world.consumers;
|
||||
|
||||
import arc.func.*;
|
||||
import arc.math.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.ArcAnnotate.*;
|
||||
@@ -12,8 +13,8 @@ import mindustry.world.meta.*;
|
||||
public class ConsumeItemDynamic extends Consume{
|
||||
public final @NonNull Func<Tilec, ItemStack[]> items;
|
||||
|
||||
public ConsumeItemDynamic(Func<Tilec, ItemStack[]> items){
|
||||
this.items = items;
|
||||
public <T extends Tilec> ConsumeItemDynamic(Func<T, ItemStack[]> items){
|
||||
this.items = (Func<Tilec, ItemStack[]>)items;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -43,7 +44,7 @@ public class ConsumeItemDynamic extends Consume{
|
||||
private void rebuild(Tilec tile, Table table){
|
||||
for(ItemStack stack : items.get(tile)){
|
||||
table.add(new ReqImage(new ItemImage(stack.item.icon(Cicon.medium), stack.amount),
|
||||
() -> tile.items() != null && tile.items().has(stack.item, stack.amount))).size(8 * 4).padRight(5);
|
||||
() -> tile.items() != null && tile.items().has(stack.item, stack.amount))).size(8 * 4).padRight(6 * Mathf.digits(stack.amount));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ public class ConsumeItemFilter extends Consume{
|
||||
@Override
|
||||
public void build(Tilec tile, Table table){
|
||||
MultiReqImage image = new MultiReqImage();
|
||||
content.items().each(i -> filter.get(i) && (!state.isCampaign() || data.isUnlocked(i)), item -> image.add(new ReqImage(new ItemImage(item.icon(Cicon.medium), 1),
|
||||
content.items().each(i -> filter.get(i) && i.unlockedNow(), item -> image.add(new ReqImage(new ItemImage(item.icon(Cicon.medium), 1),
|
||||
() -> tile.items() != null && tile.items().has(item))));
|
||||
|
||||
table.add(image).size(8 * 4);
|
||||
|
||||
@@ -8,8 +8,8 @@ import mindustry.ui.Bar;
|
||||
public class BlockBars{
|
||||
private OrderedMap<String, Func<Tilec, Bar>> bars = new OrderedMap<>();
|
||||
|
||||
public void add(String name, Func<Tilec, Bar> sup){
|
||||
bars.put(name, sup);
|
||||
public <T extends Tilec> void add(String name, Func<T, Bar> sup){
|
||||
bars.put(name, (Func<Tilec, Bar>)sup);
|
||||
}
|
||||
|
||||
public void remove(String name){
|
||||
|
||||
Reference in New Issue
Block a user