Research system progress

This commit is contained in:
Anuken
2020-06-19 19:31:14 -04:00
parent 08ac91359b
commit 6bcc103cf7
59 changed files with 393 additions and 415 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

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