Implemented unlocks for placement
This commit is contained in:
@@ -290,6 +290,7 @@ text.no = No
|
|||||||
text.info.title = Info
|
text.info.title = Info
|
||||||
text.error.title = [crimson]An error has occured
|
text.error.title = [crimson]An error has occured
|
||||||
text.error.crashtitle = An error has occured
|
text.error.crashtitle = An error has occured
|
||||||
|
text.blocks.unknown=[LIGHT_GRAY]???
|
||||||
text.blocks.blockinfo = Block Info
|
text.blocks.blockinfo = Block Info
|
||||||
text.blocks.powercapacity = Power Capacity
|
text.blocks.powercapacity = Power Capacity
|
||||||
text.blocks.powershot = Power/Shot
|
text.blocks.powershot = Power/Shot
|
||||||
@@ -408,8 +409,6 @@ mode.waves.name = waves
|
|||||||
mode.waves.description = the normal mode. limited resources and automatic incoming waves.
|
mode.waves.description = the normal mode. limited resources and automatic incoming waves.
|
||||||
mode.sandbox.name = sandbox
|
mode.sandbox.name = sandbox
|
||||||
mode.sandbox.description = infinite resources and no timer for waves.
|
mode.sandbox.description = infinite resources and no timer for waves.
|
||||||
mode.custom.warning = [scarlet]UNLOCKS IN CUSTOM GAMES OR SERVERS ARE NOT SAVED.[]\n\nPlay in sectors to unlock things.
|
|
||||||
mode.custom.warning.read = Just to make sure you've read it\:\n[scarlet]UNLOCKS IN CUSTOM GAMES DO NOT CARRY OVER TO SECTORS OR OTHER MODES\!\n\n[LIGHT_GRAY](I wish this wasn't necessary, but apparently it is)
|
|
||||||
mode.freebuild.name = freebuild
|
mode.freebuild.name = freebuild
|
||||||
mode.freebuild.description = limited resources and no timer for waves.
|
mode.freebuild.description = limited resources and no timer for waves.
|
||||||
mode.pvp.name = PvP
|
mode.pvp.name = PvP
|
||||||
|
|||||||
@@ -111,15 +111,6 @@ public class Control extends Module{
|
|||||||
}
|
}
|
||||||
|
|
||||||
state.set(State.playing);
|
state.set(State.playing);
|
||||||
|
|
||||||
if(world.getSector() == null && !Settings.getBool("custom-warning-for-real-1", false)){
|
|
||||||
threads.runGraphics(() -> ui.showInfo("$mode.custom.warning", () ->
|
|
||||||
ui.showInfo("$mode.custom.warning.read", () -> {
|
|
||||||
Settings.putBool("custom-warning-for-real-1", true);
|
|
||||||
Settings.save();
|
|
||||||
})));
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Events.on(WorldLoadGraphicsEvent.class, event -> {
|
Events.on(WorldLoadGraphicsEvent.class, event -> {
|
||||||
|
|||||||
@@ -4,16 +4,12 @@ import com.badlogic.gdx.utils.Array;
|
|||||||
import com.badlogic.gdx.utils.ObjectMap;
|
import com.badlogic.gdx.utils.ObjectMap;
|
||||||
import com.badlogic.gdx.utils.ObjectMap.Entry;
|
import com.badlogic.gdx.utils.ObjectMap.Entry;
|
||||||
import com.badlogic.gdx.utils.ObjectSet;
|
import com.badlogic.gdx.utils.ObjectSet;
|
||||||
import io.anuke.mindustry.core.GameState.State;
|
|
||||||
import io.anuke.mindustry.net.Net;
|
|
||||||
import io.anuke.mindustry.type.ContentType;
|
import io.anuke.mindustry.type.ContentType;
|
||||||
import io.anuke.ucore.core.Settings;
|
import io.anuke.ucore.core.Settings;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
|
||||||
|
|
||||||
/**Stores player unlocks. Clientside only.*/
|
/**Stores player unlocks. Clientside only.*/
|
||||||
public class Unlocks{
|
public class Unlocks{
|
||||||
private ObjectMap<String, ContentUnlockSet> sets = new ObjectMap<>();
|
ContentUnlockSet set = new ContentUnlockSet();
|
||||||
|
|
||||||
static{
|
static{
|
||||||
Settings.setSerializer(ContentType.class, (stream, t) -> stream.writeInt(t.ordinal()), stream -> ContentType.values()[stream.readInt()]);
|
Settings.setSerializer(ContentType.class, (stream, t) -> stream.writeInt(t.ordinal()), stream -> ContentType.values()[stream.readInt()]);
|
||||||
@@ -21,7 +17,7 @@ public class Unlocks{
|
|||||||
|
|
||||||
/** Returns whether or not this piece of content is unlocked yet.*/
|
/** Returns whether or not this piece of content is unlocked yet.*/
|
||||||
public boolean isUnlocked(UnlockableContent content){
|
public boolean isUnlocked(UnlockableContent content){
|
||||||
return rootSet().isUnlocked(content) || currentSet().isUnlocked(content);
|
return set.isUnlocked(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,77 +28,42 @@ public class Unlocks{
|
|||||||
* @return whether or not this content was newly unlocked.
|
* @return whether or not this content was newly unlocked.
|
||||||
*/
|
*/
|
||||||
public boolean unlockContent(UnlockableContent content){
|
public boolean unlockContent(UnlockableContent content){
|
||||||
return !rootSet().isUnlocked(content) && currentSet().unlockContent(content);
|
return !set.isUnlocked(content) && currentSet().unlockContent(content);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ContentUnlockSet currentSet(){
|
private ContentUnlockSet currentSet(){
|
||||||
//client connected to server: always return the IP-specific set
|
return set;
|
||||||
if(Net.client()){
|
|
||||||
return getSet(Net.getLastIP());
|
|
||||||
}else if((world.getSector() != null || state.mode.infiniteResources) || state.is(State.menu)){ //sector-sandbox have shared set
|
|
||||||
return rootSet();
|
|
||||||
}else{ //per-mode set
|
|
||||||
return getSet(state.mode.name());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ContentUnlockSet rootSet(){
|
|
||||||
return getSet("root");
|
|
||||||
}
|
|
||||||
|
|
||||||
private ContentUnlockSet getSet(String name){
|
|
||||||
if(!sets.containsKey(name)){
|
|
||||||
sets.put(name, new ContentUnlockSet());
|
|
||||||
}
|
|
||||||
return sets.get(name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns whether unlockables have changed since the last save.*/
|
/** Returns whether unlockables have changed since the last save.*/
|
||||||
public boolean isDirty(){
|
public boolean isDirty(){
|
||||||
for(ContentUnlockSet set : sets.values()){
|
return set.isDirty();
|
||||||
if(set.isDirty()){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Clears all unlocked content. Automatically saves.*/
|
/** Clears all unlocked content. Automatically saves.*/
|
||||||
public void reset(){
|
public void reset(){
|
||||||
sets.clear();
|
|
||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void load(){
|
public void load(){
|
||||||
sets.clear();
|
ObjectMap<ContentType, Array<String>> outer = Settings.getObject("unlocks", ObjectMap.class, ObjectMap::new);
|
||||||
|
ContentUnlockSet cset = new ContentUnlockSet();
|
||||||
|
|
||||||
ObjectMap<String, ObjectMap<ContentType, Array<String>>> result = Settings.getObject("content-sets", ObjectMap.class, ObjectMap::new);
|
for (Entry<ContentType, Array<String>> entry : outer.entries()){
|
||||||
|
ObjectSet<String> set = new ObjectSet<>();
|
||||||
for(Entry<String, ObjectMap<ContentType, Array<String>>> outer : result.entries()){
|
set.addAll(entry.value);
|
||||||
ContentUnlockSet cset = new ContentUnlockSet();
|
cset.getUnlocked().put(entry.key, set);
|
||||||
for (Entry<ContentType, Array<String>> entry : outer.value.entries()){
|
|
||||||
ObjectSet<String> set = new ObjectSet<>();
|
|
||||||
set.addAll(entry.value);
|
|
||||||
cset.getUnlocked().put(entry.key, set);
|
|
||||||
}
|
|
||||||
sets.put(outer.key, cset);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save(){
|
public void save(){
|
||||||
ObjectMap<String, ObjectMap<ContentType, Array<String>>> output = new ObjectMap<>();
|
ObjectMap<ContentType, Array<String>> write = new ObjectMap<>();
|
||||||
|
|
||||||
for(Entry<String, ContentUnlockSet> centry : sets.entries()){
|
for(Entry<ContentType, ObjectSet<String>> entry : set.getUnlocked().entries()){
|
||||||
ObjectMap<ContentType, Array<String>> write = new ObjectMap<>();
|
write.put(entry.key, entry.value.iterator().toArray());
|
||||||
|
|
||||||
for(Entry<ContentType, ObjectSet<String>> entry : centry.value.getUnlocked().entries()){
|
|
||||||
write.put(entry.key, entry.value.iterator().toArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
output.put(centry.key, write);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Settings.putObject("content-sets", output);
|
Settings.putObject("unlocks", write);
|
||||||
Settings.save();
|
Settings.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ public class Palette{
|
|||||||
|
|
||||||
lightishGray = Color.valueOf("a2a2a2"),
|
lightishGray = Color.valueOf("a2a2a2"),
|
||||||
darkishGray = new Color(0.3f, 0.3f, 0.3f, 1f),
|
darkishGray = new Color(0.3f, 0.3f, 0.3f, 1f),
|
||||||
|
darkerGray = new Color(0.2f, 0.2f, 0.2f, 1f),
|
||||||
|
|
||||||
boostTo = Color.valueOf("ffad4d"),
|
boostTo = Color.valueOf("ffad4d"),
|
||||||
boostFrom = Color.valueOf("ff7f57"),
|
boostFrom = Color.valueOf("ff7f57"),
|
||||||
|
|||||||
@@ -224,7 +224,6 @@ public class HudFragment extends Fragment{
|
|||||||
|
|
||||||
/**Show unlock notification for a new recipe.*/
|
/**Show unlock notification for a new recipe.*/
|
||||||
public void showUnlock(Recipe recipe){
|
public void showUnlock(Recipe recipe){
|
||||||
blockfrag.rebuild();
|
|
||||||
|
|
||||||
//if there's currently no unlock notification...
|
//if there's currently no unlock notification...
|
||||||
if(lastUnlockTable == null){
|
if(lastUnlockTable == null){
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package io.anuke.mindustry.ui.fragments;
|
|||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
import com.badlogic.gdx.graphics.Color;
|
||||||
import com.badlogic.gdx.math.Interpolation;
|
import com.badlogic.gdx.math.Interpolation;
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
import io.anuke.mindustry.core.GameState.State;
|
import io.anuke.mindustry.core.GameState.State;
|
||||||
import io.anuke.mindustry.entities.TileEntity;
|
import io.anuke.mindustry.entities.TileEntity;
|
||||||
import io.anuke.mindustry.graphics.Palette;
|
import io.anuke.mindustry.graphics.Palette;
|
||||||
@@ -17,14 +18,17 @@ import io.anuke.ucore.core.Graphics;
|
|||||||
import io.anuke.ucore.scene.Group;
|
import io.anuke.ucore.scene.Group;
|
||||||
import io.anuke.ucore.scene.event.Touchable;
|
import io.anuke.ucore.scene.event.Touchable;
|
||||||
import io.anuke.ucore.scene.ui.ButtonGroup;
|
import io.anuke.ucore.scene.ui.ButtonGroup;
|
||||||
|
import io.anuke.ucore.scene.ui.Image;
|
||||||
import io.anuke.ucore.scene.ui.ImageButton;
|
import io.anuke.ucore.scene.ui.ImageButton;
|
||||||
import io.anuke.ucore.scene.ui.layout.Table;
|
import io.anuke.ucore.scene.ui.layout.Table;
|
||||||
|
import io.anuke.ucore.util.Bundles;
|
||||||
|
|
||||||
import static io.anuke.mindustry.Vars.*;
|
import static io.anuke.mindustry.Vars.*;
|
||||||
|
|
||||||
public class PlacementFragment extends Fragment{
|
public class PlacementFragment extends Fragment{
|
||||||
final int rowWidth = 4;
|
final int rowWidth = 4;
|
||||||
|
|
||||||
|
Array<Recipe> returned = new Array<>();
|
||||||
Category currentCategory = Category.turret;
|
Category currentCategory = Category.turret;
|
||||||
Block hovered;
|
Block hovered;
|
||||||
Block lastDisplay;
|
Block lastDisplay;
|
||||||
@@ -33,34 +37,50 @@ public class PlacementFragment extends Fragment{
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void build(Group parent){
|
public void build(Group parent){
|
||||||
InputHandler input = control.input(0);
|
|
||||||
|
|
||||||
parent.fill(frame -> {
|
parent.fill(frame -> {
|
||||||
|
frame.clear();
|
||||||
|
InputHandler input = control.input(0);
|
||||||
|
|
||||||
//rebuilds the category table with the correct recipes
|
//rebuilds the category table with the correct recipes
|
||||||
Runnable rebuildCategory = () -> {
|
Runnable rebuildCategory = () -> {
|
||||||
blockTable.clear();
|
blockTable.clear();
|
||||||
blockTable.top().margin(5);
|
blockTable.top().margin(5);
|
||||||
|
|
||||||
//blockTable.add(currentCategory.name()).colspan(rowWidth).growX(); //TODO localize
|
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||||
group.setMinCheckCount(0);
|
group.setMinCheckCount(0);
|
||||||
|
|
||||||
for(Recipe recipe : content.recipes()){
|
for(Recipe recipe : recipes(currentCategory)){
|
||||||
if(recipe.category != currentCategory) continue;
|
|
||||||
|
|
||||||
if(index++ % rowWidth == 0){
|
if(index++ % rowWidth == 0){
|
||||||
blockTable.row();
|
blockTable.row();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageButton button = blockTable.addImageButton("blank", "select", 8*4,
|
boolean[] unlocked = {false};
|
||||||
() -> input.recipe = input.recipe == recipe ? null : recipe)
|
|
||||||
.size(50f).group(group).update(b -> b.setChecked(input.recipe == recipe)).get();
|
|
||||||
|
|
||||||
button.replaceImage(new ImageStack(recipe.result.getCompactIcon()));
|
ImageButton button = blockTable.addImageButton("icon-locked", "select", 8*4, () -> {
|
||||||
|
if(control.unlocks.isUnlocked(recipe)){
|
||||||
|
input.recipe = input.recipe == recipe ? null : recipe;
|
||||||
|
}
|
||||||
|
}).size(50f).group(group).get();
|
||||||
|
|
||||||
|
button.update(() -> { //color unplacable things gray
|
||||||
|
boolean ulock = control.unlocks.isUnlocked(recipe);
|
||||||
|
TileEntity core = players[0].getClosestCore();
|
||||||
|
Color color = core != null && core.items.has(recipe.requirements) ? Color.WHITE : ulock ? Color.GRAY : Color.WHITE;
|
||||||
|
button.forEach(elem -> elem.setColor(color));
|
||||||
|
button.setChecked(input.recipe == recipe);
|
||||||
|
|
||||||
|
if(ulock == unlocked[0]) return;
|
||||||
|
unlocked[0] = ulock;
|
||||||
|
|
||||||
|
if(!ulock){
|
||||||
|
button.replaceImage(new Image("icon-locked"));
|
||||||
|
}else{
|
||||||
|
button.replaceImage(new ImageStack(recipe.result.getCompactIcon()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if(!mobile){
|
if(!mobile){
|
||||||
button.hovered(() -> hovered = recipe.result);
|
button.hovered(() -> hovered = recipe.result);
|
||||||
@@ -71,6 +91,8 @@ public class PlacementFragment extends Fragment{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blockTable.act(0f);
|
||||||
};
|
};
|
||||||
|
|
||||||
frame.bottom().left().visible(() -> !state.is(State.menu));
|
frame.bottom().left().visible(() -> !state.is(State.menu));
|
||||||
@@ -78,7 +100,7 @@ public class PlacementFragment extends Fragment{
|
|||||||
frame.table("clear", top -> {
|
frame.table("clear", top -> {
|
||||||
top.add(new Table()).growX().update(topTable -> {
|
top.add(new Table()).growX().update(topTable -> {
|
||||||
if((tileDisplayBlock() == null && lastDisplay == getSelected()) ||
|
if((tileDisplayBlock() == null && lastDisplay == getSelected()) ||
|
||||||
(tileDisplayBlock() != null && lastDisplay == tileDisplayBlock())) return;
|
(tileDisplayBlock() != null && lastDisplay == tileDisplayBlock())) return;
|
||||||
|
|
||||||
topTable.clear();
|
topTable.clear();
|
||||||
topTable.top().left().margin(5);
|
topTable.top().left().margin(5);
|
||||||
@@ -89,7 +111,9 @@ public class PlacementFragment extends Fragment{
|
|||||||
topTable.table(header -> {
|
topTable.table(header -> {
|
||||||
header.left();
|
header.left();
|
||||||
header.add(new ImageStack(lastDisplay.getCompactIcon())).size(8*4);
|
header.add(new ImageStack(lastDisplay.getCompactIcon())).size(8*4);
|
||||||
header.labelWrap(lastDisplay.formalName).left().width(200f).padLeft(5);
|
header.labelWrap(() ->
|
||||||
|
!control.unlocks.isUnlocked(Recipe.getByResult(lastDisplay)) ? Bundles.get("text.blocks.unknown") : lastDisplay.formalName)
|
||||||
|
.left().width(200f).padLeft(5);
|
||||||
}).growX().left();
|
}).growX().left();
|
||||||
topTable.row();
|
topTable.row();
|
||||||
//add requirement table
|
//add requirement table
|
||||||
@@ -118,7 +142,7 @@ public class PlacementFragment extends Fragment{
|
|||||||
}else if(tileDisplayBlock() != null){ //show selected tile
|
}else if(tileDisplayBlock() != null){ //show selected tile
|
||||||
lastDisplay = tileDisplayBlock();
|
lastDisplay = tileDisplayBlock();
|
||||||
topTable.add(new ImageStack(lastDisplay.getDisplayIcon(hoverTile))).size(8*4);
|
topTable.add(new ImageStack(lastDisplay.getDisplayIcon(hoverTile))).size(8*4);
|
||||||
topTable.labelWrap(lastDisplay.getDisplayName(hoverTile)).left().width(150f).padLeft(5);
|
topTable.labelWrap(lastDisplay.getDisplayName(hoverTile)).left().width(200f).padLeft(5);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
top.row();
|
top.row();
|
||||||
@@ -131,6 +155,8 @@ public class PlacementFragment extends Fragment{
|
|||||||
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
ButtonGroup<ImageButton> group = new ButtonGroup<>();
|
||||||
|
|
||||||
for(Category cat : Category.values()){
|
for(Category cat : Category.values()){
|
||||||
|
if(recipes(cat).isEmpty()) continue;
|
||||||
|
|
||||||
categories.addImageButton("icon-" + cat.name(), "clear-toggle", 16*2, () -> {
|
categories.addImageButton("icon-" + cat.name(), "clear-toggle", 16*2, () -> {
|
||||||
currentCategory = cat;
|
currentCategory = cat;
|
||||||
rebuildCategory.run();
|
rebuildCategory.run();
|
||||||
@@ -181,9 +207,13 @@ public class PlacementFragment extends Fragment{
|
|||||||
return hoverTile == null ? null : hoverTile.block().synthetic() ? hoverTile.block() : hoverTile.floor() instanceof OreBlock ? hoverTile.floor() : null;
|
return hoverTile == null ? null : hoverTile.block().synthetic() ? hoverTile.block() : hoverTile.floor() instanceof OreBlock ? hoverTile.floor() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Rebuilds the whole placement menu, attempting to preserve previous state.*/
|
Array<Recipe> recipes(Category cat){
|
||||||
void rebuild(){
|
returned.clear();
|
||||||
|
for(Recipe recipe : content.recipes()){
|
||||||
|
if(recipe.category != cat || recipe.isHidden()) continue;
|
||||||
|
returned.add(recipe);
|
||||||
|
}
|
||||||
|
return returned;
|
||||||
}
|
}
|
||||||
|
|
||||||
void toggle(float t, Interpolation ip){
|
void toggle(float t, Interpolation ip){
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import io.anuke.ucore.scene.ui.layout.Table;
|
|||||||
public interface StatValue{
|
public interface StatValue{
|
||||||
/**
|
/**
|
||||||
* This method should provide all elements necessary to display this stat to the specified table.
|
* This method should provide all elements necessary to display this stat to the specified table.
|
||||||
* For example, a stat that is just text would add label to the table.
|
* For example, a stat that is just text would add a label to the table.
|
||||||
*/
|
*/
|
||||||
void display(Table table);
|
void display(Table table);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user