Recipe class removed completely

This commit is contained in:
Anuken
2019-01-20 13:49:53 -05:00
parent 750388a425
commit 0478af2564
33 changed files with 285 additions and 471 deletions

View File

@@ -416,7 +416,7 @@ mode.attack.descrption = No waves, with the goal to destroy the enemy base.
content.item.name = Items content.item.name = Items
content.liquid.name = Liquids content.liquid.name = Liquids
content.unit.name = Units content.unit.name = Units
content.recipe.name = Blocks content.block.name = Blocks
content.mech.name = Mechs content.mech.name = Mechs
item.copper.name = Copper item.copper.name = Copper
item.copper.description = A useful structure material. Used extensively in all types of blocks. item.copper.description = A useful structure material. Used extensively in all types of blocks.

View File

@@ -729,6 +729,7 @@ public class Blocks implements ContentList{
launchThreshold = 500; launchThreshold = 500;
launchTime = 60f * 10; launchTime = 60f * 10;
launchChunkSize = 100; launchChunkSize = 100;
alwaysUnlocked = true;
}}; }};
vault = new Vault("vault"){{ vault = new Vault("vault"){{

View File

@@ -1,16 +1,12 @@
package io.anuke.mindustry.content; package io.anuke.mindustry.content;
import io.anuke.mindustry.game.ContentList; import io.anuke.mindustry.game.ContentList;
import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.type.Recipe.RecipeVisibility;
import static io.anuke.mindustry.type.Category.*;
public class Recipes implements ContentList{ public class Recipes implements ContentList{
@Override @Override
public void load(){ public void load(){
/*
//DEBUG //DEBUG
new Recipe(distribution, Blocks.itemSource).setVisible(RecipeVisibility.sandboxOnly).setHidden(true).setAlwaysUnlocked(true); new Recipe(distribution, Blocks.itemSource).setVisible(RecipeVisibility.sandboxOnly).setHidden(true).setAlwaysUnlocked(true);
new Recipe(distribution, Blocks.itemVoid).setVisible(RecipeVisibility.sandboxOnly).setHidden(true).setAlwaysUnlocked(true); new Recipe(distribution, Blocks.itemVoid).setVisible(RecipeVisibility.sandboxOnly).setHidden(true).setAlwaysUnlocked(true);
@@ -174,5 +170,6 @@ public class Recipes implements ContentList{
new Recipe(liquid, Blocks.mechanicalPump, new ItemStack(Items.copper, 30), new ItemStack(Items.lead, 20)); new Recipe(liquid, Blocks.mechanicalPump, new ItemStack(Items.copper, 30), new ItemStack(Items.lead, 20));
new Recipe(liquid, Blocks.rotaryPump, new ItemStack(Items.copper, 140), new ItemStack(Items.lead, 100), new ItemStack(Items.silicon, 40), new ItemStack(Items.titanium, 70)); new Recipe(liquid, Blocks.rotaryPump, new ItemStack(Items.copper, 140), new ItemStack(Items.lead, 100), new ItemStack(Items.silicon, 40), new ItemStack(Items.titanium, 70));
new Recipe(liquid, Blocks.thermalPump, new ItemStack(Items.copper, 160), new ItemStack(Items.lead, 130), new ItemStack(Items.silicon, 60), new ItemStack(Items.titanium, 80), new ItemStack(Items.thorium, 70)); new Recipe(liquid, Blocks.thermalPump, new ItemStack(Items.copper, 160), new ItemStack(Items.lead, 130), new ItemStack(Items.silicon, 60), new ItemStack(Items.titanium, 80), new ItemStack(Items.thorium, 70));
*/
} }
} }

View File

@@ -3,7 +3,6 @@ package io.anuke.mindustry.content;
import io.anuke.arc.collection.Array; import io.anuke.arc.collection.Array;
import io.anuke.mindustry.game.ContentList; import io.anuke.mindustry.game.ContentList;
import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Block;
import static io.anuke.mindustry.type.ItemStack.with; import static io.anuke.mindustry.type.ItemStack.with;
@@ -264,7 +263,6 @@ public class TechTree implements ContentList{
public final Array<TechNode> children = new Array<>(); public final Array<TechNode> children = new Array<>();
TechNode(Block block, ItemStack[] requirements, Runnable children){ TechNode(Block block, ItemStack[] requirements, Runnable children){
if(block != null && Recipe.getByResult(block) == null) throw new IllegalArgumentException("Block " + block + " does not have a recipe.");
if(context != null){ if(context != null){
context.children.add(this); context.children.add(this);
} }
@@ -277,9 +275,5 @@ public class TechTree implements ContentList{
children.run(); children.run();
context = last; context = last;
} }
public Recipe recipe(){
return Recipe.getByResult(block);
}
} }
} }

View File

@@ -44,7 +44,6 @@ public class ContentLoader{
new Mechs(), new Mechs(),
new UnitTypes(), new UnitTypes(),
new Blocks(), new Blocks(),
new Recipes(),
new TechTree(), new TechTree(),
new Zones(), new Zones(),
@@ -185,14 +184,6 @@ public class ContentLoader{
return (Block) getByID(ContentType.block, id); return (Block) getByID(ContentType.block, id);
} }
public Array<Recipe> recipes(){
return getBy(ContentType.recipe);
}
public Recipe recipe(int id){
return (Recipe) getByID(ContentType.recipe, id);
}
public Array<Item> items(){ public Array<Item> items(){
return getBy(ContentType.item); return getBy(ContentType.item);
} }

View File

@@ -13,7 +13,6 @@ import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.game.*; import io.anuke.mindustry.game.*;
import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.EventType.*;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -30,8 +29,8 @@ public class Logic implements ApplicationListener{
public Logic(){ public Logic(){
Events.on(TileChangeEvent.class, event -> { Events.on(TileChangeEvent.class, event -> {
if(event.tile.getTeam() == defaultTeam && Recipe.getByResult(event.tile.block()) != null){ if(event.tile.getTeam() == defaultTeam && event.tile.block().isVisible()){
handleContent(Recipe.getByResult(event.tile.block())); handleContent(event.tile.block());
} }
}); });
} }

View File

@@ -296,7 +296,7 @@ public class NetServer implements ApplicationListener{
//auto-skip done requests //auto-skip done requests
if(req.breaking && world.tile(req.x, req.y).block() == Blocks.air){ if(req.breaking && world.tile(req.x, req.y).block() == Blocks.air){
continue; continue;
}else if(!req.breaking && world.tile(req.x, req.y).block() == req.recipe.result && (!req.recipe.result.rotate || world.tile(req.x, req.y).getRotation() == req.rotation)){ }else if(!req.breaking && world.tile(req.x, req.y).block() == req.block && (!req.block.rotate || world.tile(req.x, req.y).getRotation() == req.rotation)){
continue; continue;
} }
player.getPlaceQueue().addLast(req); player.getPlaceQueue().addLast(req);

View File

@@ -461,28 +461,28 @@ public class Player extends Unit implements BuilderTrait, CarryTrait, ShooterTra
request.y * tilesize + block.offset(), request.y * tilesize + block.offset(),
rad); rad);
}else{ }else{
float rad = Mathf.absin(Time.time(), 7f, 1f) - 1.5f + request.recipe.result.size * tilesize / 2f; float rad = Mathf.absin(Time.time(), 7f, 1f) - 1.5f + request.block.size * tilesize / 2f;
//draw place request //draw place request
Lines.stroke(1f, Palette.accentBack); Lines.stroke(1f, Palette.accentBack);
Lines.square( Lines.square(
request.x * tilesize + request.recipe.result.offset(), request.x * tilesize + request.block.offset(),
request.y * tilesize + request.recipe.result.offset() - 1, request.y * tilesize + request.block.offset() - 1,
rad); rad);
Draw.color(); Draw.color();
Draw.rect(request.recipe.result.icon(Icon.full), Draw.rect(request.block.icon(Icon.full),
request.x * tilesize + request.recipe.result.offset(), request.x * tilesize + request.block.offset(),
request.y * tilesize + request.recipe.result.offset(), rad*2, rad*2, request.rotation * 90); request.y * tilesize + request.block.offset(), rad*2, rad*2, request.rotation * 90);
Draw.color(Palette.accent); Draw.color(Palette.accent);
Lines.square( Lines.square(
request.x * tilesize + request.recipe.result.offset(), request.x * tilesize + request.block.offset(),
request.y * tilesize + request.recipe.result.offset(), request.y * tilesize + request.block.offset(),
rad); rad);
} }
} }

View File

@@ -26,7 +26,7 @@ import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.graphics.Shapes; import io.anuke.mindustry.graphics.Shapes;
import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.Recipe; import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Build; import io.anuke.mindustry.world.Build;
import io.anuke.mindustry.world.Pos; import io.anuke.mindustry.world.Pos;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
@@ -81,7 +81,7 @@ public interface BuilderTrait extends Entity{
output.writeInt(Pos.get(request.x, request.y)); output.writeInt(Pos.get(request.x, request.y));
output.writeFloat(request.progress); output.writeFloat(request.progress);
if(!request.breaking){ if(!request.breaking){
output.writeByte(request.recipe.id); output.writeByte(request.block.id);
output.writeByte(request.rotation); output.writeByte(request.rotation);
} }
}else{ }else{
@@ -105,9 +105,9 @@ public interface BuilderTrait extends Entity{
if(type == 1){ //remove if(type == 1){ //remove
request = new BuildRequest(Pos.x(position), Pos.y(position)); request = new BuildRequest(Pos.x(position), Pos.y(position));
}else{ //place }else{ //place
byte recipe = input.readByte(); byte block = input.readByte();
byte rotation = input.readByte(); byte rotation = input.readByte();
request = new BuildRequest(Pos.x(position), Pos.y(position), rotation, content.recipe(recipe)); request = new BuildRequest(Pos.x(position), Pos.y(position), rotation, content.block(block));
} }
request.progress = progress; request.progress = progress;
@@ -129,7 +129,7 @@ public interface BuilderTrait extends Entity{
* If a place request matching this signature is present, it is removed. * If a place request matching this signature is present, it is removed.
* Otherwise, a new place request is added to the queue. * Otherwise, a new place request is added to the queue.
*/ */
default void replaceBuilding(int x, int y, int rotation, Recipe recipe){ default void replaceBuilding(int x, int y, int rotation, Block block){
for(BuildRequest request : getPlaceQueue()){ for(BuildRequest request : getPlaceQueue()){
if(request.x == x && request.y == y){ if(request.x == x && request.y == y){
clearBuilding(); clearBuilding();
@@ -138,7 +138,7 @@ public interface BuilderTrait extends Entity{
} }
} }
addBuildRequest(new BuildRequest(x, y, rotation, recipe)); addBuildRequest(new BuildRequest(x, y, rotation, block));
} }
/**Clears the placement queue.*/ /**Clears the placement queue.*/
@@ -184,8 +184,8 @@ public interface BuilderTrait extends Entity{
for(BuildRequest request : removal){ for(BuildRequest request : removal){
if(!((request.breaking && world.tile(request.x, request.y).block() == Blocks.air) || if(!((request.breaking && world.tile(request.x, request.y).block() == Blocks.air) ||
(!request.breaking && (!request.breaking &&
(world.tile(request.x, request.y).getRotation() == request.rotation || !request.recipe.result.rotate) (world.tile(request.x, request.y).getRotation() == request.rotation || !request.block.rotate)
&& world.tile(request.x, request.y).block() == request.recipe.result))){ && world.tile(request.x, request.y).block() == request.block))){
getPlaceQueue().addLast(request); getPlaceQueue().addLast(request);
} }
} }
@@ -209,8 +209,8 @@ public interface BuilderTrait extends Entity{
} }
if(!(tile.block() instanceof BuildBlock)){ if(!(tile.block() instanceof BuildBlock)){
if(canCreateBlocks() && !current.breaking && Build.validPlace(unit.getTeam(), current.x, current.y, current.recipe.result, current.rotation)){ if(canCreateBlocks() && !current.breaking && Build.validPlace(unit.getTeam(), current.x, current.y, current.block, current.rotation)){
Build.beginPlace(unit.getTeam(), current.x, current.y, current.recipe, current.rotation); Build.beginPlace(unit.getTeam(), current.x, current.y, current.block, current.rotation);
}else if(canCreateBlocks() && current.breaking && Build.validBreak(unit.getTeam(), current.x, current.y)){ }else if(canCreateBlocks() && current.breaking && Build.validBreak(unit.getTeam(), current.x, current.y)){
Build.beginBreak(unit.getTeam(), current.x, current.y); Build.beginBreak(unit.getTeam(), current.x, current.y);
}else{ }else{
@@ -370,18 +370,18 @@ public interface BuilderTrait extends Entity{
/**Class for storing build requests. Can be either a place or remove request.*/ /**Class for storing build requests. Can be either a place or remove request.*/
class BuildRequest{ class BuildRequest{
public final int x, y, rotation; public final int x, y, rotation;
public final Recipe recipe; public final Block block;
public final boolean breaking; public final boolean breaking;
public float progress; public float progress;
public boolean initialized; public boolean initialized;
/**This creates a build request.*/ /**This creates a build request.*/
public BuildRequest(int x, int y, int rotation, Recipe recipe){ public BuildRequest(int x, int y, int rotation, Block block){
this.x = x; this.x = x;
this.y = y; this.y = y;
this.rotation = rotation; this.rotation = rotation;
this.recipe = recipe; this.block = block;
this.breaking = false; this.breaking = false;
} }
@@ -390,7 +390,7 @@ public interface BuilderTrait extends Entity{
this.x = x; this.x = x;
this.y = y; this.y = y;
this.rotation = -1; this.rotation = -1;
this.recipe = Recipe.getByResult(world.tile(x, y).block()); this.block = world.tile(x, y).block();
this.breaking = true; this.breaking = true;
} }
@@ -400,7 +400,7 @@ public interface BuilderTrait extends Entity{
"x=" + x + "x=" + x +
", y=" + y + ", y=" + y +
", rotation=" + rotation + ", rotation=" + rotation +
", recipe=" + recipe + ", recipe=" + block +
", breaking=" + breaking + ", breaking=" + breaking +
", progress=" + progress + ", progress=" + progress +
", initialized=" + initialized + ", initialized=" + initialized +

View File

@@ -65,13 +65,13 @@ public class Drone extends FlyingUnit implements BuilderTrait{
if(isBreaking){ if(isBreaking){
getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y)); getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y));
}else{ }else{
getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.getRotation(), entity.recipe)); getPlaceQueue().addLast(new BuildRequest(entity.tile.x, entity.tile.y, entity.tile.getRotation(), entity.block));
} }
} }
//if it's missing requirements, try and mine them //if it's missing requirements, try and mine them
if(entity.recipe != null){ if(entity.block != null){
for(ItemStack stack : entity.recipe.requirements){ for(ItemStack stack : entity.block.buildRequirements){
if(!core.items.has(stack.item, stack.amount) && type.toMine.contains(stack.item)){ if(!core.items.has(stack.item, stack.amount) && type.toMine.contains(stack.item)){
targetItem = stack.item; targetItem = stack.item;
getPlaceQueue().clear(); getPlaceQueue().clear();

View File

@@ -89,7 +89,7 @@ public class OverlayRenderer{
Draw.reset(); Draw.reset();
//draw selected block bars and info //draw selected block bars and info
if(input.recipe == null && !Core.scene.hasMouse()){ if(input.block == null && !Core.scene.hasMouse()){
Vector2 vec = Core.input.mouseWorld(input.getMouseX(), input.getMouseY()); Vector2 vec = Core.input.mouseWorld(input.getMouseX(), input.getMouseY());
Tile tile = world.tileWorld(vec.x, vec.y); Tile tile = world.tileWorld(vec.x, vec.y);

View File

@@ -41,7 +41,7 @@ public class Palette{
heal = Color.valueOf("98ffa9"), heal = Color.valueOf("98ffa9"),
bar = Color.SLATE, bar = Color.SLATE,
accent = Color.valueOf("ffd37f"), accent = Color.valueOf("ffd37f"),
locked = Color.valueOf("6b6b6b"), locked = Color.valueOf("989aa4"),
accentBack = Color.valueOf("d4816b"), accentBack = Color.valueOf("d4816b"),
place = Color.valueOf("6335f8"), place = Color.valueOf("6335f8"),
remove = Color.valueOf("e55454"), remove = Color.valueOf("e55454"),

View File

@@ -60,7 +60,7 @@ public class DesktopInput extends InputHandler{
@Override @Override
public boolean isDrawing(){ public boolean isDrawing(){
return mode != none || recipe != null; return mode != none || block != null;
} }
@Override @Override
@@ -70,30 +70,30 @@ public class DesktopInput extends InputHandler{
int cursorY = tileY(Core.input.mouseY()); int cursorY = tileY(Core.input.mouseY());
//draw selection(s) //draw selection(s)
if(mode == placing && recipe != null){ if(mode == placing && block != null){
NormalizeResult result = PlaceUtils.normalizeArea(selectX, selectY, cursorX, cursorY, rotation, true, maxLength); NormalizeResult result = PlaceUtils.normalizeArea(selectX, selectY, cursorX, cursorY, rotation, true, maxLength);
for(int i = 0; i <= result.getLength(); i += recipe.result.size){ for(int i = 0; i <= result.getLength(); i += block.size){
int x = selectX + i * Mathf.sign(cursorX - selectX) * Mathf.num(result.isX()); int x = selectX + i * Mathf.sign(cursorX - selectX) * Mathf.num(result.isX());
int y = selectY + i * Mathf.sign(cursorY - selectY) * Mathf.num(!result.isX()); int y = selectY + i * Mathf.sign(cursorY - selectY) * Mathf.num(!result.isX());
if(i + recipe.result.size > result.getLength() && recipe.result.rotate){ if(i + block.size > result.getLength() && block.rotate){
Draw.color(!validPlace(x, y, recipe.result, result.rotation) ? Palette.removeBack : Palette.accentBack); Draw.color(!validPlace(x, y, block, result.rotation) ? Palette.removeBack : Palette.accentBack);
Draw.rect(Core.atlas.find("place-arrow"), Draw.rect(Core.atlas.find("place-arrow"),
x * tilesize + recipe.result.offset(), x * tilesize + block.offset(),
y * tilesize + recipe.result.offset() - 1, y * tilesize + block.offset() - 1,
Core.atlas.find("place-arrow").getWidth() * Draw.scl, Core.atlas.find("place-arrow").getWidth() * Draw.scl,
Core.atlas.find("place-arrow").getHeight() * Draw.scl, result.rotation * 90 - 90); Core.atlas.find("place-arrow").getHeight() * Draw.scl, result.rotation * 90 - 90);
Draw.color(!validPlace(x, y, recipe.result, result.rotation) ? Palette.remove : Palette.accent); Draw.color(!validPlace(x, y, block, result.rotation) ? Palette.remove : Palette.accent);
Draw.rect(Core.atlas.find("place-arrow"), Draw.rect(Core.atlas.find("place-arrow"),
x * tilesize + recipe.result.offset(), x * tilesize + block.offset(),
y * tilesize + recipe.result.offset(), y * tilesize + block.offset(),
Core.atlas.find("place-arrow").getWidth() * Draw.scl, Core.atlas.find("place-arrow").getWidth() * Draw.scl,
Core.atlas.find("place-arrow").getHeight() * Draw.scl, result.rotation * 90 - 90); Core.atlas.find("place-arrow").getHeight() * Draw.scl, result.rotation * 90 - 90);
} }
drawPlace(x, y, recipe.result, result.rotation); drawPlace(x, y, block, result.rotation);
} }
Draw.reset(); Draw.reset();
@@ -119,23 +119,23 @@ public class DesktopInput extends InputHandler{
Draw.color(Palette.remove); Draw.color(Palette.remove);
Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y); Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y);
}else if(isPlacing()){ }else if(isPlacing()){
if(recipe.result.rotate){ if(block.rotate){
Draw.color(!validPlace(cursorX, cursorY, recipe.result, rotation) ? Palette.removeBack : Palette.accentBack); Draw.color(!validPlace(cursorX, cursorY, block, rotation) ? Palette.removeBack : Palette.accentBack);
Draw.rect(Core.atlas.find("place-arrow"), Draw.rect(Core.atlas.find("place-arrow"),
cursorX * tilesize + recipe.result.offset(), cursorX * tilesize + block.offset(),
cursorY * tilesize + recipe.result.offset() - 1, cursorY * tilesize + block.offset() - 1,
Core.atlas.find("place-arrow").getWidth() * Draw.scl, Core.atlas.find("place-arrow").getWidth() * Draw.scl,
Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90); Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90);
Draw.color(!validPlace(cursorX, cursorY, recipe.result, rotation) ? Palette.remove : Palette.accent); Draw.color(!validPlace(cursorX, cursorY, block, rotation) ? Palette.remove : Palette.accent);
Draw.rect(Core.atlas.find("place-arrow"), Draw.rect(Core.atlas.find("place-arrow"),
cursorX * tilesize + recipe.result.offset(), cursorX * tilesize + block.offset(),
cursorY * tilesize + recipe.result.offset(), cursorY * tilesize + block.offset(),
Core.atlas.find("place-arrow").getWidth() * Draw.scl, Core.atlas.find("place-arrow").getWidth() * Draw.scl,
Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90); Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90);
} }
drawPlace(cursorX, cursorY, recipe.result, rotation); drawPlace(cursorX, cursorY, block, rotation);
recipe.result.drawPlace(cursorX, cursorY, rotation, validPlace(cursorX, cursorY, recipe.result, rotation)); block.drawPlace(cursorX, cursorY, rotation, validPlace(cursorX, cursorY, block, rotation));
} }
Draw.reset(); Draw.reset();
@@ -234,13 +234,13 @@ public class DesktopInput extends InputHandler{
}else if(!ui.chatfrag.chatOpen()){ //if it's out of bounds, shooting is just fine }else if(!ui.chatfrag.chatOpen()){ //if it's out of bounds, shooting is just fine
player.isShooting = true; player.isShooting = true;
} }
}else if(Core.input.keyTap(Binding.deselect) && (recipe != null || mode != none || player.isBuilding()) && }else if(Core.input.keyTap(Binding.deselect) && (block != null || mode != none || player.isBuilding()) &&
!(player.getCurrentRequest() != null && player.getCurrentRequest().breaking && Core.keybinds.get(Binding.deselect) == Core.keybinds.get(Binding.break_block))){ !(player.getCurrentRequest() != null && player.getCurrentRequest().breaking && Core.keybinds.get(Binding.deselect) == Core.keybinds.get(Binding.break_block))){
if(recipe == null){ if(block == null){
player.clearBuilding(); player.clearBuilding();
} }
recipe = null; block = null;
mode = none; mode = none;
}else if(Core.input.keyTap(Binding.break_block) && !Core.scene.hasMouse()){ }else if(Core.input.keyTap(Binding.break_block) && !Core.scene.hasMouse()){
//is recalculated because setting the mode to breaking removes potential multiblock cursor offset //is recalculated because setting the mode to breaking removes potential multiblock cursor offset
@@ -252,10 +252,10 @@ public class DesktopInput extends InputHandler{
if(Core.input.keyRelease(Binding.break_block) || Core.input.keyRelease(Binding.select)){ if(Core.input.keyRelease(Binding.break_block) || Core.input.keyRelease(Binding.select)){
if(mode == placing && recipe != null){ //touch up while placing, place everything in selection if(mode == placing && block != null){ //touch up while placing, place everything in selection
NormalizeResult result = PlaceUtils.normalizeArea(selectX, selectY, cursorX, cursorY, rotation, true, maxLength); NormalizeResult result = PlaceUtils.normalizeArea(selectX, selectY, cursorX, cursorY, rotation, true, maxLength);
for(int i = 0; i <= result.getLength(); i += recipe.result.size){ for(int i = 0; i <= result.getLength(); i += block.size){
int x = selectX + i * Mathf.sign(cursorX - selectX) * Mathf.num(result.isX()); int x = selectX + i * Mathf.sign(cursorX - selectX) * Mathf.num(result.isX());
int y = selectY + i * Mathf.sign(cursorY - selectY) * Mathf.num(!result.isX()); int y = selectY + i * Mathf.sign(cursorY - selectY) * Mathf.num(!result.isX());

View File

@@ -21,7 +21,6 @@ import io.anuke.mindustry.net.Net;
import io.anuke.mindustry.net.ValidateException; import io.anuke.mindustry.net.ValidateException;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.ui.fragments.OverlayFragment; import io.anuke.mindustry.ui.fragments.OverlayFragment;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Build; import io.anuke.mindustry.world.Build;
@@ -41,7 +40,7 @@ public abstract class InputHandler implements InputProcessor{
public final Player player; public final Player player;
public final OverlayFragment frag = new OverlayFragment(this); public final OverlayFragment frag = new OverlayFragment(this);
public Recipe recipe; public Block block;
public int rotation; public int rotation;
public boolean droppingItem; public boolean droppingItem;
@@ -199,7 +198,7 @@ public abstract class InputHandler implements InputProcessor{
if(!consumed && player.isBuilding()){ if(!consumed && player.isBuilding()){
player.clearBuilding(); player.clearBuilding();
recipe = null; block = null;
return true; return true;
} }
@@ -245,7 +244,7 @@ public abstract class InputHandler implements InputProcessor{
int tileX(float cursorX){ int tileX(float cursorX){
Vector2 vec = Core.input.mouseWorld(cursorX, 0); Vector2 vec = Core.input.mouseWorld(cursorX, 0);
if(selectedBlock()){ if(selectedBlock()){
vec.sub(recipe.result.offset(), recipe.result.offset()); vec.sub(block.offset(), block.offset());
} }
return world.toTile(vec.x); return world.toTile(vec.x);
} }
@@ -253,7 +252,7 @@ public abstract class InputHandler implements InputProcessor{
int tileY(float cursorY){ int tileY(float cursorY){
Vector2 vec = Core.input.mouseWorld(0, cursorY); Vector2 vec = Core.input.mouseWorld(0, cursorY);
if(selectedBlock()){ if(selectedBlock()){
vec.sub(recipe.result.offset(), recipe.result.offset()); vec.sub(block.offset(), block.offset());
} }
return world.toTile(vec.y); return world.toTile(vec.y);
} }
@@ -263,7 +262,7 @@ public abstract class InputHandler implements InputProcessor{
} }
public boolean isPlacing(){ public boolean isPlacing(){
return recipe != null; return block != null;
} }
public float mouseAngle(float x, float y){ public float mouseAngle(float x, float y){
@@ -276,7 +275,7 @@ public abstract class InputHandler implements InputProcessor{
} }
public boolean canShoot(){ public boolean canShoot(){
return recipe == null && !Core.scene.hasMouse() && !onConfigurable() && !isDroppingItem(); return block == null && !Core.scene.hasMouse() && !onConfigurable() && !isDroppingItem();
} }
public boolean onConfigurable(){ public boolean onConfigurable(){
@@ -309,8 +308,8 @@ public abstract class InputHandler implements InputProcessor{
} }
public void tryPlaceBlock(int x, int y){ public void tryPlaceBlock(int x, int y){
if(recipe != null && validPlace(x, y, recipe.result, rotation) && cursorNear()){ if(block != null && validPlace(x, y, block, rotation) && cursorNear()){
placeBlock(x, y, recipe, rotation); placeBlock(x, y, block, rotation);
} }
} }
@@ -329,8 +328,8 @@ public abstract class InputHandler implements InputProcessor{
return Build.validBreak(player.getTeam(), x, y) && Mathf.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance; return Build.validBreak(player.getTeam(), x, y) && Mathf.dst(player.x, player.y, x * tilesize, y * tilesize) < Player.placeDistance;
} }
public void placeBlock(int x, int y, Recipe recipe, int rotation){ public void placeBlock(int x, int y, Block block, int rotation){
player.addBuildRequest(new BuildRequest(x, y, rotation, recipe)); player.addBuildRequest(new BuildRequest(x, y, rotation, block));
} }
public void breakBlock(int x, int y){ public void breakBlock(int x, int y){

View File

@@ -30,7 +30,6 @@ import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.graphics.Shaders; import io.anuke.mindustry.graphics.Shaders;
import io.anuke.mindustry.input.PlaceUtils.NormalizeDrawResult; import io.anuke.mindustry.input.PlaceUtils.NormalizeDrawResult;
import io.anuke.mindustry.input.PlaceUtils.NormalizeResult; import io.anuke.mindustry.input.PlaceUtils.NormalizeResult;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.ui.dialogs.FloatingDialog; import io.anuke.mindustry.ui.dialogs.FloatingDialog;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Block.Icon; import io.anuke.mindustry.world.Block.Icon;
@@ -73,7 +72,7 @@ public class MobileInput extends InputHandler implements GestureListener{
/** Current place mode. */ /** Current place mode. */
private PlaceMode mode = none; private PlaceMode mode = none;
/** Whether no recipe was available when switching to break mode. */ /** Whether no recipe was available when switching to break mode. */
private Recipe lastRecipe; private Block lastBlock;
/** Last placed request. Used for drawing block overlay. */ /** Last placed request. Used for drawing block overlay. */
private PlaceRequest lastPlaced; private PlaceRequest lastPlaced;
@@ -121,8 +120,8 @@ public class MobileInput extends InputHandler implements GestureListener{
if(other == null || req.remove) continue; if(other == null || req.remove) continue;
r1.setSize(req.recipe.result.size * tilesize); r1.setSize(req.block.size * tilesize);
r1.setCenter(other.worldx() + req.recipe.result.offset(), other.worldy() + req.recipe.result.offset()); r1.setCenter(other.worldx() + req.block.offset(), other.worldy() + req.block.offset());
if(r2.overlaps(r1)){ if(r2.overlaps(r1)){
return true; return true;
@@ -142,8 +141,8 @@ public class MobileInput extends InputHandler implements GestureListener{
if(other == null) continue; if(other == null) continue;
if(!req.remove){ if(!req.remove){
r1.setSize(req.recipe.result.size * tilesize); r1.setSize(req.block.size * tilesize);
r1.setCenter(other.worldx() + req.recipe.result.offset(), other.worldy() + req.recipe.result.offset()); r1.setCenter(other.worldx() + req.block.offset(), other.worldy() + req.block.offset());
if(r2.overlaps(r1)){ if(r2.overlaps(r1)){
return req; return req;
@@ -171,8 +170,8 @@ public class MobileInput extends InputHandler implements GestureListener{
if(!request.remove){ if(!request.remove){
//draw placing request //draw placing request
float offset = request.recipe.result.offset(); float offset = request.block.offset();
TextureRegion region = request.recipe.result.icon(Icon.full); TextureRegion region = request.block.icon(Icon.full);
Draw.alpha(Mathf.clamp((1f - request.scale) / 0.5f)); Draw.alpha(Mathf.clamp((1f - request.scale) / 0.5f));
Draw.tint(Color.WHITE, Palette.breakInvalid, request.redness); Draw.tint(Color.WHITE, Palette.breakInvalid, request.redness);
@@ -180,7 +179,7 @@ public class MobileInput extends InputHandler implements GestureListener{
Draw.rect(region, tile.worldx() + offset, tile.worldy() + offset, Draw.rect(region, tile.worldx() + offset, tile.worldy() + offset,
region.getWidth() * request.scale * Draw.scl, region.getWidth() * request.scale * Draw.scl,
region.getHeight() * request.scale * Draw.scl, region.getHeight() * request.scale * Draw.scl,
request.recipe.result.rotate ? request.rotation * 90 : 0); request.block.rotate ? request.rotation * 90 : 0);
}else{ }else{
float rad = (tile.block().size * tilesize / 2f - 1) * request.scale; float rad = (tile.block().size * tilesize / 2f - 1) * request.scale;
Draw.alpha(0f); Draw.alpha(0f);
@@ -219,8 +218,8 @@ public class MobileInput extends InputHandler implements GestureListener{
table.left().margin(0f).defaults().size(48f); table.left().margin(0f).defaults().size(48f);
table.addImageButton("icon-break", "clear-toggle-partial", 16 * 2f, () -> { table.addImageButton("icon-break", "clear-toggle-partial", 16 * 2f, () -> {
mode = mode == breaking ? recipe == null ? none : placing : breaking; mode = mode == breaking ? block == null ? none : placing : breaking;
lastRecipe = recipe; lastBlock = block;
if(mode == breaking){ if(mode == breaking){
showGuide("deconstruction"); showGuide("deconstruction");
} }
@@ -230,13 +229,13 @@ public class MobileInput extends InputHandler implements GestureListener{
table.addImageButton("icon-cancel", "clear-partial", 16 * 2f, () -> { table.addImageButton("icon-cancel", "clear-partial", 16 * 2f, () -> {
player.clearBuilding(); player.clearBuilding();
mode = none; mode = none;
recipe = null; block = null;
}).visible(() -> player.isBuilding() || recipe != null || mode == breaking); }).visible(() -> player.isBuilding() || block != null || mode == breaking);
//rotate button //rotate button
table.addImageButton("icon-arrow", "clear-partial", 16 * 2f, () -> rotation = Mathf.mod(rotation + 1, 4)) table.addImageButton("icon-arrow", "clear-partial", 16 * 2f, () -> rotation = Mathf.mod(rotation + 1, 4))
.update(i -> i.getImage().setRotationOrigin(rotation * 90, Align.center)) .update(i -> i.getImage().setRotationOrigin(rotation * 90, Align.center))
.visible(() -> recipe != null && recipe.result.rotate); .visible(() -> block != null && block.rotate);
//confirm button //confirm button
table.addImageButton("icon-check", "clear-partial", 16 * 2f, () -> { table.addImageButton("icon-check", "clear-partial", 16 * 2f, () -> {
@@ -247,10 +246,10 @@ public class MobileInput extends InputHandler implements GestureListener{
if(tile != null){ if(tile != null){
if(!request.remove){ if(!request.remove){
rotation = request.rotation; rotation = request.rotation;
Recipe before = recipe; Block before = block;
recipe = request.recipe; block = request.block;
tryPlaceBlock(tile.x, tile.y); tryPlaceBlock(tile.x, tile.y);
recipe = before; block = before;
}else{ }else{
tryBreakBlock(tile.x, tile.y); tryBreakBlock(tile.x, tile.y);
} }
@@ -299,7 +298,7 @@ public class MobileInput extends InputHandler implements GestureListener{
if(tile == null) continue; if(tile == null) continue;
if((!request.remove && validPlace(tile.x, tile.y, request.recipe.result, request.rotation)) if((!request.remove && validPlace(tile.x, tile.y, request.block, request.rotation))
|| (request.remove && validBreak(tile.x, tile.y))){ || (request.remove && validBreak(tile.x, tile.y))){
request.scale = Mathf.lerpDelta(request.scale, 1f, 0.2f); request.scale = Mathf.lerpDelta(request.scale, 1f, 0.2f);
request.redness = Mathf.lerpDelta(request.redness, 0f, 0.2f); request.redness = Mathf.lerpDelta(request.redness, 0f, 0.2f);
@@ -312,8 +311,8 @@ public class MobileInput extends InputHandler implements GestureListener{
drawRequest(request); drawRequest(request);
//draw last placed request //draw last placed request
if(!request.remove && request == lastPlaced && request.recipe != null){ if(!request.remove && request == lastPlaced && request.block != null){
request.recipe.result.drawPlace(tile.x, tile.y, rotation, validPlace(tile.x, tile.y, request.recipe.result, rotation)); request.block.drawPlace(tile.x, tile.y, rotation, validPlace(tile.x, tile.y, request.block, rotation));
} }
} }
@@ -327,32 +326,32 @@ public class MobileInput extends InputHandler implements GestureListener{
int tileY = tileY(Core.input.mouseY()); int tileY = tileY(Core.input.mouseY());
//draw placing //draw placing
if(mode == placing && recipe != null){ if(mode == placing && block != null){
NormalizeDrawResult dresult = PlaceUtils.normalizeDrawArea(recipe.result, lineStartX, lineStartY, tileX, tileY, true, maxLength, lineScale); NormalizeDrawResult dresult = PlaceUtils.normalizeDrawArea(block, lineStartX, lineStartY, tileX, tileY, true, maxLength, lineScale);
Lines.rect(dresult.x, dresult.y, dresult.x2 - dresult.x, dresult.y2 - dresult.y); Lines.rect(dresult.x, dresult.y, dresult.x2 - dresult.x, dresult.y2 - dresult.y);
NormalizeResult result = PlaceUtils.normalizeArea(lineStartX, lineStartY, tileX, tileY, rotation, true, maxLength); NormalizeResult result = PlaceUtils.normalizeArea(lineStartX, lineStartY, tileX, tileY, rotation, true, maxLength);
//go through each cell and draw the block to place if valid //go through each cell and draw the block to place if valid
for(int i = 0; i <= result.getLength(); i += recipe.result.size){ for(int i = 0; i <= result.getLength(); i += block.size){
int x = lineStartX + i * Mathf.sign(tileX - lineStartX) * Mathf.num(result.isX()); int x = lineStartX + i * Mathf.sign(tileX - lineStartX) * Mathf.num(result.isX());
int y = lineStartY + i * Mathf.sign(tileY - lineStartY) * Mathf.num(!result.isX()); int y = lineStartY + i * Mathf.sign(tileY - lineStartY) * Mathf.num(!result.isX());
if(!checkOverlapPlacement(x, y, recipe.result) && validPlace(x, y, recipe.result, result.rotation)){ if(!checkOverlapPlacement(x, y, block) && validPlace(x, y, block, result.rotation)){
Draw.color(); Draw.color();
TextureRegion region = recipe.result.icon(Icon.full); TextureRegion region = block.icon(Icon.full);
Draw.rect(region, x * tilesize + recipe.result.offset(), y * tilesize + recipe.result.offset(), Draw.rect(region, x * tilesize + block.offset(), y * tilesize + block.offset(),
region.getWidth() * lineScale * Draw.scl, region.getWidth() * lineScale * Draw.scl,
region.getHeight() * lineScale * Draw.scl, region.getHeight() * lineScale * Draw.scl,
recipe.result.rotate ? result.rotation * 90 : 0); block.rotate ? result.rotation * 90 : 0);
}else{ }else{
Draw.color(Palette.removeBack); Draw.color(Palette.removeBack);
Lines.square(x * tilesize + recipe.result.offset(), y * tilesize + recipe.result.offset() - 1, recipe.result.size * tilesize / 2f); Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset() - 1, block.size * tilesize / 2f);
Draw.color(Palette.remove); Draw.color(Palette.remove);
Lines.square(x * tilesize + recipe.result.offset(), y * tilesize + recipe.result.offset(), recipe.result.size * tilesize / 2f); Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset(), block.size * tilesize / 2f);
} }
} }
@@ -441,7 +440,7 @@ public class MobileInput extends InputHandler implements GestureListener{
int tileX = tileX(screenX); int tileX = tileX(screenX);
int tileY = tileY(screenY); int tileY = tileY(screenY);
if(mode == placing && recipe != null){ if(mode == placing && block != null){
//normalize area //normalize area
NormalizeResult result = PlaceUtils.normalizeArea(lineStartX, lineStartY, tileX, tileY, rotation, true, 100); NormalizeResult result = PlaceUtils.normalizeArea(lineStartX, lineStartY, tileX, tileY, rotation, true, 100);
@@ -449,12 +448,12 @@ public class MobileInput extends InputHandler implements GestureListener{
rotation = result.rotation; rotation = result.rotation;
//place blocks on line //place blocks on line
for(int i = 0; i <= result.getLength(); i += recipe.result.size){ for(int i = 0; i <= result.getLength(); i += block.size){
int x = lineStartX + i * Mathf.sign(tileX - lineStartX) * Mathf.num(result.isX()); int x = lineStartX + i * Mathf.sign(tileX - lineStartX) * Mathf.num(result.isX());
int y = lineStartY + i * Mathf.sign(tileY - lineStartY) * Mathf.num(!result.isX()); int y = lineStartY + i * Mathf.sign(tileY - lineStartY) * Mathf.num(!result.isX());
if(!checkOverlapPlacement(x, y, recipe.result) && validPlace(x, y, recipe.result, result.rotation)){ if(!checkOverlapPlacement(x, y, block) && validPlace(x, y, block, result.rotation)){
PlaceRequest request = new PlaceRequest(x * tilesize + recipe.result.offset(), y * tilesize + recipe.result.offset(), recipe, result.rotation); PlaceRequest request = new PlaceRequest(x * tilesize + block.offset(), y * tilesize + block.offset(), block, result.rotation);
request.scale = 1f; request.scale = 1f;
selection.add(request); selection.add(request);
} }
@@ -517,8 +516,8 @@ public class MobileInput extends InputHandler implements GestureListener{
if(mode == breaking){ if(mode == breaking){
Effects.effect(Fx.tapBlock, cursor.worldx(), cursor.worldy(), 1f); Effects.effect(Fx.tapBlock, cursor.worldx(), cursor.worldy(), 1f);
}else if(recipe != null){ }else if(block != null){
Effects.effect(Fx.tapBlock, cursor.worldx() + recipe.result.offset(), cursor.worldy() + recipe.result.offset(), recipe.result.size); Effects.effect(Fx.tapBlock, cursor.worldx() + block.offset(), cursor.worldy() + block.offset(), block.size);
} }
return false; return false;
@@ -541,9 +540,9 @@ public class MobileInput extends InputHandler implements GestureListener{
//remove if request present //remove if request present
if(hasRequest(cursor)){ if(hasRequest(cursor)){
removeRequest(getRequest(cursor)); removeRequest(getRequest(cursor));
}else if(mode == placing && isPlacing() && validPlace(cursor.x, cursor.y, recipe.result, rotation) && !checkOverlapPlacement(cursor.x, cursor.y, recipe.result)){ }else if(mode == placing && isPlacing() && validPlace(cursor.x, cursor.y, block, rotation) && !checkOverlapPlacement(cursor.x, cursor.y, block)){
//add to selection queue if it's a valid place position //add to selection queue if it's a valid place position
selection.add(lastPlaced = new PlaceRequest(cursor.worldx() + recipe.result.offset(), cursor.worldy() + recipe.result.offset(), recipe, rotation)); selection.add(lastPlaced = new PlaceRequest(cursor.worldx() + block.offset(), cursor.worldy() + block.offset(), block, rotation));
}else if(mode == breaking && validBreak(cursor.target().x, cursor.target().y) && !hasRequest(cursor.target())){ }else if(mode == breaking && validBreak(cursor.target().x, cursor.target().y) && !hasRequest(cursor.target())){
//add to selection queue if it's a valid BREAK position //add to selection queue if it's a valid BREAK position
cursor = cursor.target(); cursor = cursor.target();
@@ -590,27 +589,27 @@ public class MobileInput extends InputHandler implements GestureListener{
selection.clear(); selection.clear();
} }
if(lineMode && mode == placing && recipe == null){ if(lineMode && mode == placing && block == null){
lineMode = false; lineMode = false;
} }
//if there is no mode and there's a recipe, switch to placing //if there is no mode and there's a recipe, switch to placing
if(recipe != null && mode == none){ if(block != null && mode == none){
mode = placing; mode = placing;
} }
if(recipe != null){ if(block != null){
showGuide("construction"); showGuide("construction");
} }
if(recipe == null && mode == placing){ if(block == null && mode == placing){
mode = none; mode = none;
} }
//automatically switch to placing after a new recipe is selected //automatically switch to placing after a new recipe is selected
if(lastRecipe != recipe && mode == breaking && recipe != null){ if(lastBlock != block && mode == breaking && block != null){
mode = placing; mode = placing;
lastRecipe = recipe; lastBlock = block;
} }
if(lineMode){ if(lineMode){
@@ -712,7 +711,7 @@ public class MobileInput extends InputHandler implements GestureListener{
class PlaceRequest{ class PlaceRequest{
float x, y; float x, y;
Recipe recipe; Block block;
int rotation; int rotation;
boolean remove; boolean remove;
@@ -720,10 +719,10 @@ public class MobileInput extends InputHandler implements GestureListener{
float scale; float scale;
float redness; float redness;
PlaceRequest(float x, float y, Recipe recipe, int rotation){ PlaceRequest(float x, float y, Block block, int rotation){
this.x = x; this.x = x;
this.y = y; this.y = y;
this.recipe = recipe; this.block = block;
this.rotation = rotation; this.rotation = rotation;
this.remove = false; this.remove = false;
} }
@@ -735,7 +734,7 @@ public class MobileInput extends InputHandler implements GestureListener{
} }
Tile tile(){ Tile tile(){
return world.tileWorld(x - (recipe == null ? 0 : recipe.result.offset()), y - (recipe == null ? 0 : recipe.result.offset())); return world.tileWorld(x - (block == null ? 0 : block.offset()), y - (block == null ? 0 : block.offset()));
} }
} }
} }

View File

@@ -172,7 +172,7 @@ public class TypeIO{
buffer.put(request.breaking ? (byte) 1 : 0); buffer.put(request.breaking ? (byte) 1 : 0);
buffer.putInt(Pos.get(request.x, request.y)); buffer.putInt(Pos.get(request.x, request.y));
if(!request.breaking){ if(!request.breaking){
buffer.put(request.recipe.id); buffer.put(request.block.id);
buffer.put((byte) request.rotation); buffer.put((byte) request.rotation);
} }
} }
@@ -190,9 +190,9 @@ public class TypeIO{
if(type == 1){ //remove if(type == 1){ //remove
currentRequest = new BuildRequest(Pos.x(position), Pos.y(position)); currentRequest = new BuildRequest(Pos.x(position), Pos.y(position));
}else{ //place }else{ //place
byte recipe = buffer.get(); byte block = buffer.get();
byte rotation = buffer.get(); byte rotation = buffer.get();
currentRequest = new BuildRequest(Pos.x(position), Pos.y(position), rotation, content.recipe(recipe)); currentRequest = new BuildRequest(Pos.x(position), Pos.y(position), rotation, content.block(block));
} }
reqs[i] = (currentRequest); reqs[i] = (currentRequest);
@@ -302,16 +302,6 @@ public class TypeIO{
return id == -1 ? null : content.item(id); return id == -1 ? null : content.item(id);
} }
@WriteClass(Recipe.class)
public static void writeRecipe(ByteBuffer buffer, Recipe recipe){
buffer.put(recipe.id);
}
@ReadClass(Recipe.class)
public static Recipe readRecipe(ByteBuffer buffer){
return content.recipe(buffer.get());
}
@WriteClass(String.class) @WriteClass(String.class)
public static void writeString(ByteBuffer buffer, String string){ public static void writeString(ByteBuffer buffer, String string){
if(string != null){ if(string != null){

View File

@@ -3,7 +3,6 @@ package io.anuke.mindustry.type;
/**Do not rearrange, ever!*/ /**Do not rearrange, ever!*/
public enum ContentType { public enum ContentType {
item, item,
recipe,
block, block,
mech, mech,
bullet, bullet,

View File

@@ -1,170 +0,0 @@
package io.anuke.mindustry.type;
import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.ObjectMap;
import io.anuke.arc.collection.OrderedMap;
import io.anuke.arc.graphics.g2d.TextureRegion;
import io.anuke.arc.scene.ui.layout.Table;
import io.anuke.arc.util.Log;
import io.anuke.arc.util.Strings;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.mindustry.ui.ContentDisplay;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Block.Icon;
import io.anuke.mindustry.world.meta.BlockStat;
import io.anuke.mindustry.world.meta.ContentStatValue;
import io.anuke.mindustry.world.meta.StatValue;
import java.util.Arrays;
import static io.anuke.mindustry.Vars.*;
public class Recipe extends UnlockableContent{
private static ObjectMap<Block, Recipe> recipeMap = new ObjectMap<>();
private static Array<Recipe> returnArray = new Array<>();
public final Block result;
public final ItemStack[] requirements;
public final Category category;
public final float cost;
public RecipeVisibility visibility = RecipeVisibility.all;
public boolean hidden;
public boolean alwaysUnlocked;
public Recipe(Category category, Block result, ItemStack... requirements){
this.result = result;
this.requirements = requirements;
this.category = category;
Arrays.sort(requirements, (a, b) -> Integer.compare(a.item.id, b.item.id));
float timeToPlace = 0f;
for(ItemStack stack : requirements){
timeToPlace += stack.amount * stack.item.cost;
}
this.cost = timeToPlace;
recipeMap.put(result, this);
}
/**Returns all non-hidden recipes in a category.*/
public static Array<Recipe> getByCategory(Category category){
returnArray.clear();
for(Recipe recipe : content.recipes()){
if(recipe.category == category && recipe.visibility.shown()){
returnArray.add(recipe);
}
}
return returnArray;
}
public static Recipe getByResult(Block block){
return recipeMap.get(block);
}
public Recipe setVisible(RecipeVisibility visibility){
this.visibility = visibility;
return this;
}
public Recipe setHidden(boolean hidden){
this.hidden = hidden;
return this;
}
public Recipe setAlwaysUnlocked(boolean unlocked){
this.alwaysUnlocked = unlocked;
return this;
}
@Override
public boolean alwaysUnlocked(){
return alwaysUnlocked;
}
@Override
public boolean isHidden(){
return !visibility.shown() || hidden;
}
@Override
public void displayInfo(Table table){
ContentDisplay.displayBlock(table, result);
}
@Override
public String localizedName(){
return result.formalName;
}
@Override
public TextureRegion getContentIcon(){
return result.icon(Icon.large);
}
@Override
public void init(){
if(!Core.bundle.has("block." + result.name + ".name")){
Log.err("WARNING: Recipe block '{0}' does not have a formal name defined. Add the following to bundle.properties:", result.name);
Log.err("block.{0}.name={1}", result.name, Strings.capitalize(result.name.replace('-', '_')));
}/*else if(result.fullDescription == null){
Log.err("WARNING: Recipe block '{0}' does not have a description defined.", result.name);
}*/
}
@Override
public String getContentName(){
return result.name;
}
@Override
public ContentType getContentType(){
return ContentType.recipe;
}
@Override
public void onUnlock(){
for(OrderedMap<BlockStat, StatValue> map : result.stats.toMap().values()){
for(StatValue value : map.values()){
if(value instanceof ContentStatValue){
ContentStatValue stat = (ContentStatValue) value;
UnlockableContent[] content = stat.getValueContent();
for(UnlockableContent c : content){
data.unlockContent(c);
}
}
}
}
}
public enum RecipeVisibility{
mobileOnly(true, false),
desktopOnly(false, true),
all(true, true),
sandboxOnly(true, true){
@Override
public boolean usable(){
return state.rules.infiniteResources;
}
};
public final boolean mobile, desktop;
RecipeVisibility(boolean mobile, boolean desktop){
this.mobile = mobile;
this.desktop = desktop;
}
public boolean usable(){
return true;
}
public boolean shown(){
return usable() && ((Vars.mobile && mobile) || (!Vars.mobile && desktop));
}
}
}

View File

@@ -24,10 +24,9 @@ import io.anuke.mindustry.content.TechTree;
import io.anuke.mindustry.content.TechTree.TechNode; import io.anuke.mindustry.content.TechTree.TechNode;
import io.anuke.mindustry.graphics.Palette; import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.type.Recipe.RecipeVisibility;
import io.anuke.mindustry.ui.TreeLayout; import io.anuke.mindustry.ui.TreeLayout;
import io.anuke.mindustry.ui.TreeLayout.TreeNode; import io.anuke.mindustry.ui.TreeLayout.TreeNode;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Block.Icon; import io.anuke.mindustry.world.Block.Icon;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -50,15 +49,15 @@ public class TechTreeDialog extends FloatingDialog{
cont.add(new View()).grow(); cont.add(new View()).grow();
{ //debug code; TODO remove { //debug code; TODO remove
ObjectSet<Recipe> used = new ObjectSet<Recipe>().select(t -> true); ObjectSet<Block> used = new ObjectSet<Block>().select(t -> true);
for(TechTreeNode node : nodes){ for(TechTreeNode node : nodes){
used.add(node.node.recipe()); used.add(node.node.block);
} }
Array<Recipe> recipes = content.recipes().select(r -> r.visibility == RecipeVisibility.all && !used.contains(r)); Array<Block> recipes = content.blocks().select(r -> r.isVisible() && !used.contains(r));
recipes.sort(Structs.comparing(r -> r.cost)); recipes.sort(Structs.comparing(r -> r.buildCost));
if(recipes.size > 0){ if(recipes.size > 0){
Log.info("Recipe tree coverage: {0}%", (int)((float)nodes.size / content.recipes().select(r -> r.visibility == RecipeVisibility.all).size * 100)); Log.info("Recipe tree coverage: {0}%", (int)((float)nodes.size / content.blocks().select(Block::isVisible).size * 100));
Log.info("Missing items: "); Log.info("Missing items: ");
recipes.forEach(r -> Log.info(" {0}", r)); recipes.forEach(r -> Log.info(" {0}", r));
} }
@@ -111,7 +110,7 @@ public class TechTreeDialog extends FloatingDialog{
} }
boolean locked(TechNode node){ boolean locked(TechNode node){
return !data.isUnlocked(node.recipe()); return !data.isUnlocked(node.block);
} }
class TechTreeNode extends TreeNode{ class TechTreeNode extends TreeNode{
@@ -199,7 +198,7 @@ public class TechTreeDialog extends FloatingDialog{
} }
void unlock(TechNode node){ void unlock(TechNode node){
data.unlockContent(node.recipe()); data.unlockContent(node.block);
data.removeItems(node.requirements); data.removeItems(node.requirements);
showToast(Core.bundle.format("researched", node.block.formalName)); showToast(Core.bundle.format("researched", node.block.formalName));
checkNodes(root); checkNodes(root);
@@ -230,7 +229,7 @@ public class TechTreeDialog extends FloatingDialog{
infoTable.margin(0).left().defaults().left(); infoTable.margin(0).left().defaults().left();
infoTable.addImageButton("icon-info", "node", 14*2, () -> ui.content.show(node.recipe())).growY().width(50f); infoTable.addImageButton("icon-info", "node", 14*2, () -> ui.content.show(node.block)).growY().width(50f);
infoTable.add().grow(); infoTable.add().grow();

View File

@@ -22,7 +22,6 @@ import io.anuke.mindustry.input.Binding;
import io.anuke.mindustry.input.InputHandler; import io.anuke.mindustry.input.InputHandler;
import io.anuke.mindustry.type.Category; import io.anuke.mindustry.type.Category;
import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Block.Icon; import io.anuke.mindustry.world.Block.Icon;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
@@ -33,6 +32,7 @@ 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<Block> returnArray = new Array<>();
Category currentCategory = Category.turret; Category currentCategory = Category.turret;
Block hovered, lastDisplay; Block hovered, lastDisplay;
Tile hoverTile; Tile hoverTile;
@@ -68,8 +68,8 @@ public class PlacementFragment extends Fragment{
int i = 0; int i = 0;
for(KeyCode key : inputCatGrid){ for(KeyCode key : inputCatGrid){
if(Core.input.keyDown(key)){ if(Core.input.keyDown(key)){
input.recipe = Recipe.getByCategory(Category.values()[i]).first(); input.block = getByCategory(Category.values()[i]).first();
currentCategory = input.recipe.category; currentCategory = input.block.buildCategory;
} }
i++; i++;
} }
@@ -79,19 +79,19 @@ public class PlacementFragment extends Fragment{
if(tile != null){ if(tile != null){
tile = tile.target(); tile = tile.target();
Recipe tryRecipe = Recipe.getByResult(tile.block()); Block tryRecipe = tile.block();
if(tryRecipe != null && data.isUnlocked(tryRecipe)){ if(tryRecipe.isVisible() && data.isUnlocked(tryRecipe)){
input.recipe = tryRecipe; input.block = tryRecipe;
currentCategory = input.recipe.category; currentCategory = input.block.buildCategory;
return true; return true;
} }
} }
}else{ //select block }else{ //select block
int i = 0; int i = 0;
Array<Recipe> recipes = Recipe.getByCategory(currentCategory); Array<Block> recipes = getByCategory(currentCategory);
for(KeyCode key : inputGrid){ for(KeyCode key : inputGrid){
if(Core.input.keyDown(key)) if(Core.input.keyDown(key))
input.recipe = (i < recipes.size && data.isUnlocked(recipes.get(i))) ? recipes.get(i) : null; input.block = (i < recipes.size && data.isUnlocked(recipes.get(i))) ? recipes.get(i) : null;
i++; i++;
} }
} }
@@ -117,7 +117,7 @@ public class PlacementFragment extends Fragment{
ButtonGroup<ImageButton> group = new ButtonGroup<>(); ButtonGroup<ImageButton> group = new ButtonGroup<>();
group.setMinCheckCount(0); group.setMinCheckCount(0);
for(Recipe recipe : Recipe.getByCategory(currentCategory)){ for(Block block : getByCategory(currentCategory)){
if(index++ % rowWidth == 0){ if(index++ % rowWidth == 0){
blockTable.row(); blockTable.row();
@@ -126,17 +126,17 @@ public class PlacementFragment extends Fragment{
boolean[] unlocked = {false}; boolean[] unlocked = {false};
ImageButton button = blockTable.addImageButton("icon-locked", "select", 8 * 4, () -> { ImageButton button = blockTable.addImageButton("icon-locked", "select", 8 * 4, () -> {
if(data.isUnlocked(recipe)){ if(data.isUnlocked(block)){
input.recipe = input.recipe == recipe ? null : recipe; input.block = input.block == block ? null : block;
} }
}).size(46f).group(group).get(); }).size(46f).group(group).get();
button.update(() -> { //color unplacable things gray button.update(() -> { //color unplacable things gray
boolean ulock = data.isUnlocked(recipe); boolean ulock = data.isUnlocked(block);
TileEntity core = players[0].getClosestCore(); TileEntity core = players[0].getClosestCore();
Color color = core != null && (core.items.has(recipe.requirements) || state.rules.infiniteResources) ? Color.WHITE : ulock ? Color.GRAY : Color.WHITE; Color color = core != null && (core.items.has(block.buildRequirements) || state.rules.infiniteResources) ? Color.WHITE : ulock ? Color.GRAY : Color.WHITE;
button.forEach(elem -> elem.setColor(color)); button.forEach(elem -> elem.setColor(color));
button.setChecked(input.recipe == recipe); button.setChecked(input.block == block);
if(ulock == unlocked[0]) return; if(ulock == unlocked[0]) return;
unlocked[0] = ulock; unlocked[0] = ulock;
@@ -144,13 +144,13 @@ public class PlacementFragment extends Fragment{
if(!ulock){ if(!ulock){
button.replaceImage(new Image("icon-locked")); button.replaceImage(new Image("icon-locked"));
}else{ }else{
button.replaceImage(new Image(recipe.result.icon(Icon.medium))); button.replaceImage(new Image(block.icon(Icon.medium)));
} }
}); });
button.hovered(() -> hovered = recipe.result); button.hovered(() -> hovered = block);
button.exited(() -> { button.exited(() -> {
if(hovered == recipe.result){ if(hovered == block){
hovered = null; hovered = null;
} }
}); });
@@ -176,11 +176,11 @@ public class PlacementFragment extends Fragment{
header.left(); header.left();
header.add(new Image(lastDisplay.icon(Icon.medium))).size(8 * 4); header.add(new Image(lastDisplay.icon(Icon.medium))).size(8 * 4);
header.labelWrap(() -> header.labelWrap(() ->
!data.isUnlocked(Recipe.getByResult(lastDisplay)) ? Core.bundle.get("blocks.unknown") : lastDisplay.formalName) !data.isUnlocked(lastDisplay) ? Core.bundle.get("blocks.unknown") : lastDisplay.formalName)
.left().width(190f).padLeft(5); .left().width(190f).padLeft(5);
header.add().growX(); header.add().growX();
if(data.isUnlocked(Recipe.getByResult(lastDisplay))){ if(data.isUnlocked(lastDisplay)){
header.addButton("?", "clear-partial", () -> ui.content.show(Recipe.getByResult(lastDisplay))) header.addButton("?", "clear-partial", () -> ui.content.show(lastDisplay))
.size(8 * 5).padTop(-5).padRight(-5).right().grow(); .size(8 * 5).padTop(-5).padRight(-5).right().grow();
} }
}).growX().left(); }).growX().left();
@@ -189,7 +189,7 @@ public class PlacementFragment extends Fragment{
topTable.table(req -> { topTable.table(req -> {
req.top().left(); req.top().left();
for(ItemStack stack : Recipe.getByResult(lastDisplay).requirements){ for(ItemStack stack : lastDisplay.buildRequirements){
req.table(line -> { req.table(line -> {
line.left(); line.left();
line.addImage(stack.item.region).size(8 * 2); line.addImage(stack.item.region).size(8 * 2);
@@ -230,7 +230,7 @@ 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(Recipe.getByCategory(cat).isEmpty()) continue; if(getByCategory(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;
@@ -249,6 +249,16 @@ public class PlacementFragment extends Fragment{
}); });
} }
Array<Block> getByCategory(Category cat){
returnArray.clear();
for(Block block : content.blocks()){
if(block.buildCategory == cat && block.isVisible()){
returnArray.add(block);
}
}
return returnArray;
}
/** Returns the currently displayed block in the top box. */ /** Returns the currently displayed block in the top box. */
Block getSelected(){ Block getSelected(){
Block toDisplay = null; Block toDisplay = null;
@@ -268,8 +278,8 @@ public class PlacementFragment extends Fragment{
} }
//block currently selected //block currently selected
if(control.input(0).recipe != null){ if(control.input(0).block != null){
toDisplay = control.input(0).recipe.result; toDisplay = control.input(0).block;
} }
//block hovered on in build menu //block hovered on in build menu

View File

@@ -6,6 +6,7 @@ import io.anuke.arc.Graphics.Cursor.SystemCursor;
import io.anuke.arc.collection.Array; import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.EnumSet; import io.anuke.arc.collection.EnumSet;
import io.anuke.arc.collection.IntArray; import io.anuke.arc.collection.IntArray;
import io.anuke.arc.function.BooleanProvider;
import io.anuke.arc.graphics.Color; import io.anuke.arc.graphics.Color;
import io.anuke.arc.graphics.g2d.Draw; import io.anuke.arc.graphics.g2d.Draw;
import io.anuke.arc.graphics.g2d.Lines; import io.anuke.arc.graphics.g2d.Lines;
@@ -20,19 +21,26 @@ import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.bullet.Bullet; import io.anuke.mindustry.entities.bullet.Bullet;
import io.anuke.mindustry.entities.effect.Puddle; import io.anuke.mindustry.entities.effect.Puddle;
import io.anuke.mindustry.entities.effect.RubbleDecal; import io.anuke.mindustry.entities.effect.RubbleDecal;
import io.anuke.mindustry.game.Content;
import io.anuke.mindustry.game.UnlockableContent; import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.mindustry.graphics.CacheLayer; import io.anuke.mindustry.graphics.CacheLayer;
import io.anuke.mindustry.graphics.Layer; import io.anuke.mindustry.graphics.Layer;
import io.anuke.mindustry.graphics.Palette; import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.type.Category;
import io.anuke.mindustry.type.ContentType; import io.anuke.mindustry.type.ContentType;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.ui.ContentDisplay;
import io.anuke.mindustry.world.consumers.ConsumePower; import io.anuke.mindustry.world.consumers.ConsumePower;
import io.anuke.mindustry.world.meta.*; import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.mindustry.world.meta.BlockGroup;
import io.anuke.mindustry.world.meta.BlockStat;
import io.anuke.mindustry.world.meta.StatUnit;
import java.util.Arrays;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
public class Block extends BaseBlock { public class Block extends BlockStorage{
/** internal name */ /** internal name */
public final String name; public final String name;
/** display name */ /** display name */
@@ -77,8 +85,6 @@ public class Block extends BaseBlock {
public boolean instantTransfer = false; public boolean instantTransfer = false;
/** The block group. Unless {@link #canReplace} is overriden, blocks in the same group can replace each other. */ /** The block group. Unless {@link #canReplace} is overriden, blocks in the same group can replace each other. */
public BlockGroup group = BlockGroup.none; public BlockGroup group = BlockGroup.none;
/** List of block stats. */
public BlockStats stats = new BlockStats(this);
/** List of block flags. Used for AI indexing. */ /** List of block flags. Used for AI indexing. */
public EnumSet<BlockFlag> flags; public EnumSet<BlockFlag> flags;
/** Whether the block can be tapped and selected to configure. */ /** Whether the block can be tapped and selected to configure. */
@@ -92,6 +98,16 @@ public class Block extends BaseBlock {
/**Whether the overdrive core has any effect on this block.*/ /**Whether the overdrive core has any effect on this block.*/
public boolean canOverdrive = true; public boolean canOverdrive = true;
/**Cost of constructing this block.*/
public ItemStack[] buildRequirements = new ItemStack[]{};
/**Category in place menu.*/
public Category buildCategory = Category.distribution;
/**Cost of building this block; do not modify directly!*/
public float buildCost;
/**Whether this block is visible and can currently be built.*/
public BooleanProvider buildVisibility = () -> false;
public boolean alwaysUnlocked = false;
protected Array<Tile> tempTiles = new Array<>(); protected Array<Tile> tempTiles = new Array<>();
protected TextureRegion[] icons = new TextureRegion[Icon.values().length]; protected TextureRegion[] icons = new TextureRegion[Icon.values().length];
protected TextureRegion[] generatedIcons; protected TextureRegion[] generatedIcons;
@@ -104,16 +120,6 @@ public class Block extends BaseBlock {
this.solid = false; this.solid = false;
} }
/**Populates the array with all blocks that produce this content.*/
public static void getByProduction(Array<Block> arr, Content result){
arr.clear();
for(Block block : content.blocks()){
if(block.produces.get() == result){
arr.add(block);
}
}
}
public boolean canBreak(Tile tile){ public boolean canBreak(Tile tile){
return true; return true;
} }
@@ -194,6 +200,14 @@ public class Block extends BaseBlock {
public void drawPlace(int x, int y, int rotation, boolean valid){ public void drawPlace(int x, int y, int rotation, boolean valid){
} }
public void draw(Tile tile){
Draw.rect(region, tile.drawx(), tile.drawy(), rotate ? tile.getRotation() * 90 : 0);
}
public void drawShadow(Tile tile){
draw(tile);
}
/** Called after the block is placed by this client. */ /** Called after the block is placed by this client. */
public void playerPlaced(Tile tile){ public void playerPlaced(Tile tile){
} }
@@ -221,6 +235,21 @@ public class Block extends BaseBlock {
} }
} }
@Override
public String localizedName(){
return formalName;
}
@Override
public TextureRegion getContentIcon(){
return icon(Icon.medium);
}
@Override
public void displayInfo(Table table){
ContentDisplay.displayBlock(table, this);
}
@Override @Override
public ContentType getContentType(){ public ContentType getContentType(){
return ContentType.block; return ContentType.block;
@@ -239,6 +268,11 @@ public class Block extends BaseBlock {
health = size * size * 40; health = size * size * 40;
} }
buildCost = 0f;
for(ItemStack stack : buildRequirements){
buildCost += stack.amount * stack.item.cost;
}
setStats(); setStats();
consumes.checkRequired(this); consumes.checkRequired(this);
@@ -319,10 +353,6 @@ public class Block extends BaseBlock {
if(hasItems) stats.add(BlockStat.itemCapacity, itemCapacity, StatUnit.items); if(hasItems) stats.add(BlockStat.itemCapacity, itemCapacity, StatUnit.items);
} }
public String name(){
return name;
}
public boolean isSolidFor(Tile tile){ public boolean isSolidFor(Tile tile){
return false; return false;
} }
@@ -458,14 +488,6 @@ public class Block extends BaseBlock {
return new TileEntity(); return new TileEntity();
} }
public void draw(Tile tile){
Draw.rect(region, tile.drawx(), tile.drawy(), rotate ? tile.getRotation() * 90 : 0);
}
public void drawShadow(Tile tile){
draw(tile);
}
/** Offset for placing and drawing multiblocks. */ /** Offset for placing and drawing multiblocks. */
public float offset(){ public float offset(){
return ((size + 1) % 2) * tilesize / 2f; return ((size + 1) % 2) * tilesize / 2f;
@@ -475,19 +497,26 @@ public class Block extends BaseBlock {
return size > 1; return size > 1;
} }
public Array<Object> getDebugInfo(Tile tile){ public boolean isVisible(){
return Array.with( return buildVisibility.get() && !isHidden();
"block", tile.block().name, }
"floor", tile.floor().name,
"x", tile.x, @Override
"y", tile.y, public boolean alwaysUnlocked(){
"entity.name", tile.entity.getClass(), return alwaysUnlocked;
"entity.x", tile.entity.x, }
"entity.y", tile.entity.y,
"entity.id", tile.entity.id, protected void requirements(Category cat, ItemStack[] stacks){
"entity.items.total", hasItems ? tile.entity.items.total() : null, requirements(cat, () -> true, stacks);
"entity.graph", tile.entity.power != null && tile.entity.power.graph != null ? tile.entity.power.graph.getID() : null }
);
/**Sets up requirements. Use only this method to set up requirements.*/
protected void requirements(Category cat, BooleanProvider visible, ItemStack[] stacks){
this.buildCategory = cat;
this.buildRequirements = stacks;
this.buildVisibility = visible;
Arrays.sort(buildRequirements, (a, b) -> Integer.compare(a.item.id, b.item.id));
} }
public enum Icon{ public enum Icon{

View File

@@ -10,15 +10,16 @@ import io.anuke.mindustry.content.Fx;
import io.anuke.mindustry.entities.TileEntity; import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.Unit; import io.anuke.mindustry.entities.Unit;
import io.anuke.mindustry.entities.effect.Puddle; import io.anuke.mindustry.entities.effect.Puddle;
import io.anuke.mindustry.game.MappableContent; import io.anuke.mindustry.game.UnlockableContent;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.world.consumers.ConsumeItem; import io.anuke.mindustry.world.consumers.ConsumeItem;
import io.anuke.mindustry.world.consumers.ConsumeLiquid; import io.anuke.mindustry.world.consumers.ConsumeLiquid;
import io.anuke.mindustry.world.consumers.Consumers; import io.anuke.mindustry.world.consumers.Consumers;
import io.anuke.mindustry.world.meta.BlockStats;
import io.anuke.mindustry.world.meta.Producers; import io.anuke.mindustry.world.meta.Producers;
public abstract class BaseBlock extends MappableContent{ public abstract class BlockStorage extends UnlockableContent{
public boolean hasItems; public boolean hasItems;
public boolean hasLiquids; public boolean hasLiquids;
public boolean hasPower; public boolean hasPower;
@@ -32,6 +33,7 @@ public abstract class BaseBlock extends MappableContent{
public float liquidCapacity = 10f; public float liquidCapacity = 10f;
public float liquidFlowFactor = 4.9f; public float liquidFlowFactor = 4.9f;
public BlockStats stats = new BlockStats();
public Consumers consumes = new Consumers(); public Consumers consumes = new Consumers();
public Producers produces = new Producers(); public Producers produces = new Producers();

View File

@@ -11,7 +11,6 @@ import io.anuke.mindustry.entities.Units;
import io.anuke.mindustry.game.EventType.BlockBuildBeginEvent; import io.anuke.mindustry.game.EventType.BlockBuildBeginEvent;
import io.anuke.mindustry.game.Team; import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.type.ContentType; import io.anuke.mindustry.type.ContentType;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity; import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
@@ -64,8 +63,8 @@ public class Build{
} }
/**Places a BuildBlock at this location.*/ /**Places a BuildBlock at this location.*/
public static void beginPlace(Team team, int x, int y, Recipe recipe, int rotation){ public static void beginPlace(Team team, int x, int y, Block result, int rotation){
if(!validPlace(team, x, y, recipe.result, rotation)){ if(!validPlace(team, x, y, result, rotation)){
return; return;
} }
@@ -74,13 +73,12 @@ public class Build{
//just in case //just in case
if(tile == null) return; if(tile == null) return;
Block result = recipe.result;
Block previous = tile.block(); Block previous = tile.block();
Block sub = content.getByName(ContentType.block, "build" + result.size); Block sub = content.getByName(ContentType.block, "build" + result.size);
tile.setBlock(sub, rotation); tile.setBlock(sub, rotation);
tile.<BuildEntity>entity().setConstruct(previous, recipe); tile.<BuildEntity>entity().setConstruct(previous, result);
tile.setTeam(team); tile.setTeam(team);
if(result.isMultiblock()){ if(result.isMultiblock()){
@@ -107,9 +105,7 @@ public class Build{
/**Returns whether a tile can be placed at this location by this team.*/ /**Returns whether a tile can be placed at this location by this team.*/
public static boolean validPlace(Team team, int x, int y, Block type, int rotation){ public static boolean validPlace(Team team, int x, int y, Block type, int rotation){
Recipe recipe = Recipe.getByResult(type); if(!type.isVisible() || type.isHidden()){
if(recipe == null || (!recipe.visibility.usable())){
return false; return false;
} }

View File

@@ -418,7 +418,7 @@ public class Tile implements Position, TargetTrait{
Block block = block(); Block block = block();
Block floor = floor(); Block floor = floor();
return floor.name() + ":" + block.name() + "[" + x + "," + y + "] " + "entity=" + (entity == null ? "null" : (entity.getClass())) + return floor.name + ":" + block.name + "[" + x + "," + y + "] " + "entity=" + (entity == null ? "null" : (entity.getClass())) +
(link != 0 ? " link=[" + (Pack.leftByte(link) - 8) + ", " + (Pack.rightByte(link) - 8) + "]" : ""); (link != 0 ? " link=[" + (Pack.leftByte(link) - 8) + ", " + (Pack.rightByte(link) - 8) + "]" : "");
} }
} }

View File

@@ -23,7 +23,6 @@ import io.anuke.mindustry.graphics.Layer;
import io.anuke.mindustry.graphics.Palette; import io.anuke.mindustry.graphics.Palette;
import io.anuke.mindustry.graphics.Shaders; import io.anuke.mindustry.graphics.Shaders;
import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.modules.ItemModule; import io.anuke.mindustry.world.modules.ItemModule;
@@ -74,19 +73,19 @@ public class BuildBlock extends Block{
@Override @Override
public String getDisplayName(Tile tile){ public String getDisplayName(Tile tile){
BuildEntity entity = tile.entity(); BuildEntity entity = tile.entity();
return Core.bundle.format("block.constructing", entity.recipe == null ? entity.previous.formalName : entity.recipe.result.formalName); return Core.bundle.format("block.constructing", entity.block == null ? entity.previous.formalName : entity.block.formalName);
} }
@Override @Override
public TextureRegion getDisplayIcon(Tile tile){ public TextureRegion getDisplayIcon(Tile tile){
BuildEntity entity = tile.entity(); BuildEntity entity = tile.entity();
return (entity.recipe == null ? entity.previous : entity.recipe.result).icon(Icon.full); return (entity.block == null ? entity.previous : entity.block).icon(Icon.full);
} }
@Override @Override
public boolean isSolidFor(Tile tile){ public boolean isSolidFor(Tile tile){
BuildEntity entity = tile.entity(); BuildEntity entity = tile.entity();
return entity == null || (entity.recipe != null && entity.recipe.result.solid) || entity.previous == null || entity.previous.solid; return entity == null || (entity.block != null && entity.block.solid) || entity.previous == null || entity.previous.solid;
} }
@Override @Override
@@ -99,9 +98,9 @@ public class BuildBlock extends Block{
BuildEntity entity = tile.entity(); BuildEntity entity = tile.entity();
//if the target is constructible, begin constructing //if the target is constructible, begin constructing
if(entity.recipe != null){ if(entity.block != null){
player.clearBuilding(); player.clearBuilding();
player.addBuildRequest(new BuildRequest(tile.x, tile.y, tile.getRotation(), entity.recipe)); player.addBuildRequest(new BuildRequest(tile.x, tile.y, tile.getRotation(), entity.block));
} }
} }
@@ -119,7 +118,7 @@ public class BuildBlock extends Block{
BuildEntity entity = tile.entity(); BuildEntity entity = tile.entity();
//When breaking, don't draw the previous block... since it's the thing you were breaking //When breaking, don't draw the previous block... since it's the thing you were breaking
if(entity.recipe != null && entity.previous == entity.recipe.result){ if(entity.block != null && entity.previous == entity.block){
return; return;
} }
@@ -135,7 +134,7 @@ public class BuildBlock extends Block{
Shaders.blockbuild.color = Palette.accent; Shaders.blockbuild.color = Palette.accent;
Block target = entity.recipe == null ? entity.previous : entity.recipe.result; Block target = entity.block == null ? entity.previous : entity.block;
if(target == null) return; if(target == null) return;
@@ -163,7 +162,7 @@ public class BuildBlock extends Block{
* The recipe of the block that is being constructed. * The recipe of the block that is being constructed.
* If there is no recipe for this block, as is the case with rocks, 'previous' is used. * If there is no recipe for this block, as is the case with rocks, 'previous' is used.
*/ */
public Recipe recipe; public Block block;
public float progress = 0; public float progress = 0;
public float buildCost; public float buildCost;
@@ -178,16 +177,16 @@ public class BuildBlock extends Block{
private float[] totalAccumulator; private float[] totalAccumulator;
public void construct(Unit builder, TileEntity core, float amount){ public void construct(Unit builder, TileEntity core, float amount){
if(recipe == null){ if(block == null){
damage(99999); damage(99999);
return; return;
} }
float maxProgress = checkRequired(core.items, amount, false); float maxProgress = checkRequired(core.items, amount, false);
for(int i = 0; i < recipe.requirements.length; i++){ for(int i = 0; i < block.buildRequirements.length; i++){
accumulator[i] += Math.min(recipe.requirements[i].amount * maxProgress, recipe.requirements[i].amount - totalAccumulator[i] + 0.00001f); //add min amount progressed to the accumulator accumulator[i] += Math.min(block.buildRequirements[i].amount * maxProgress, block.buildRequirements[i].amount - totalAccumulator[i] + 0.00001f); //add min amount progressed to the accumulator
totalAccumulator[i] = Math.min(totalAccumulator[i] + recipe.requirements[i].amount * maxProgress, recipe.requirements[i].amount); totalAccumulator[i] = Math.min(totalAccumulator[i] + block.buildRequirements[i].amount * maxProgress, block.buildRequirements[i].amount);
} }
maxProgress = checkRequired(core.items, maxProgress, true); maxProgress = checkRequired(core.items, maxProgress, true);
@@ -199,24 +198,23 @@ public class BuildBlock extends Block{
} }
if(progress >= 1f || state.rules.infiniteResources){ if(progress >= 1f || state.rules.infiniteResources){
Call.onConstructFinish(tile, recipe.result, builderID, tile.getRotation(), builder.getTeam()); Call.onConstructFinish(tile, block, builderID, tile.getRotation(), builder.getTeam());
} }
} }
public void deconstruct(Unit builder, TileEntity core, float amount){ public void deconstruct(Unit builder, TileEntity core, float amount){
Recipe recipe = Recipe.getByResult(previous);
if(recipe != null){ if(block != null){
ItemStack[] requirements = recipe.requirements; ItemStack[] requirements = block.buildRequirements;
if(requirements.length != accumulator.length || totalAccumulator.length != requirements.length){ if(requirements.length != accumulator.length || totalAccumulator.length != requirements.length){
setDeconstruct(previous); setDeconstruct(previous);
} }
for(int i = 0; i < requirements.length; i++){ for(int i = 0; i < requirements.length; i++){
accumulator[i] += Math.min(requirements[i].amount * amount / 2f, requirements[i].amount/2f - totalAccumulator[i]); //add scaled amount progressed to the accumulator accumulator[i] += Math.min(requirements[i].amount * amount / 2f, requirements[i].amount / 2f - totalAccumulator[i]); //add scaled amount progressed to the accumulator
totalAccumulator[i] = Math.min(totalAccumulator[i] + requirements[i].amount * amount / 2f, requirements[i].amount); totalAccumulator[i] = Math.min(totalAccumulator[i] + requirements[i].amount * amount / 2f, requirements[i].amount);
int accumulated = (int) (accumulator[i]); //get amount int accumulated = (int)(accumulator[i]); //get amount
if(amount > 0 && accumulated > 0){ //if it's positive, add it to the core if(amount > 0 && accumulated > 0){ //if it's positive, add it to the core
int accepting = core.tile.block().acceptStack(requirements[i].item, accumulated, core.tile, builder); int accepting = core.tile.block().acceptStack(requirements[i].item, accumulated, core.tile, builder);
@@ -230,21 +228,21 @@ public class BuildBlock extends Block{
progress = Mathf.clamp(progress - amount); progress = Mathf.clamp(progress - amount);
if(progress <= 0 || state.rules.infiniteResources){ if(progress <= 0 || state.rules.infiniteResources){
Call.onDeconstructFinish(tile, this.recipe == null ? previous : this.recipe.result); Call.onDeconstructFinish(tile, this.block == null ? previous : this.block);
} }
} }
private float checkRequired(ItemModule inventory, float amount, boolean remove){ private float checkRequired(ItemModule inventory, float amount, boolean remove){
float maxProgress = amount; float maxProgress = amount;
for(int i = 0; i < recipe.requirements.length; i++){ for(int i = 0; i < block.buildRequirements.length; i++){
int required = (int) (accumulator[i]); //calculate items that are required now int required = (int) (accumulator[i]); //calculate items that are required now
if(inventory.get(recipe.requirements[i].item) == 0){ if(inventory.get(block.buildRequirements[i].item) == 0){
maxProgress = 0f; maxProgress = 0f;
}else if(required > 0){ //if this amount is positive... }else if(required > 0){ //if this amount is positive...
//calculate how many items it can actually use //calculate how many items it can actually use
int maxUse = Math.min(required, inventory.get(recipe.requirements[i].item)); int maxUse = Math.min(required, inventory.get(block.buildRequirements[i].item));
//get this as a fraction //get this as a fraction
float fraction = maxUse / (float) required; float fraction = maxUse / (float) required;
@@ -255,7 +253,7 @@ public class BuildBlock extends Block{
//remove stuff that is actually used //remove stuff that is actually used
if(remove){ if(remove){
inventory.remove(recipe.requirements[i].item, maxUse); inventory.remove(block.buildRequirements[i].item, maxUse);
} }
} }
//else, no items are required yet, so just keep going //else, no items are required yet, so just keep going
@@ -268,24 +266,24 @@ public class BuildBlock extends Block{
return progress; return progress;
} }
public void setConstruct(Block previous, Recipe recipe){ public void setConstruct(Block previous, Block block){
this.recipe = recipe; this.block = block;
this.previous = previous; this.previous = previous;
this.accumulator = new float[recipe.requirements.length]; this.accumulator = new float[block.buildRequirements.length];
this.totalAccumulator = new float[recipe.requirements.length]; this.totalAccumulator = new float[block.buildRequirements.length];
this.buildCost = recipe.cost; this.buildCost = block.buildCost;
} }
public void setDeconstruct(Block previous){ public void setDeconstruct(Block previous){
this.previous = previous; this.previous = previous;
this.progress = 1f; this.progress = 1f;
if(Recipe.getByResult(previous) != null){ if(previous.buildCost > 1f){
this.recipe = Recipe.getByResult(previous); this.block = previous;
this.accumulator = new float[Recipe.getByResult(previous).requirements.length]; this.accumulator = new float[previous.buildRequirements.length];
this.totalAccumulator = new float[Recipe.getByResult(previous).requirements.length]; this.totalAccumulator = new float[previous.buildRequirements.length];
this.buildCost = Recipe.getByResult(previous).cost; this.buildCost = previous.buildCost;
}else{ }else{
this.buildCost = 20f; //default no-recipe build cost is 20 this.buildCost = 20f; //default no-requirement build cost is 20
} }
} }
@@ -293,7 +291,7 @@ public class BuildBlock extends Block{
public void write(DataOutput stream) throws IOException{ public void write(DataOutput stream) throws IOException{
stream.writeFloat(progress); stream.writeFloat(progress);
stream.writeShort(previous == null ? -1 : previous.id); stream.writeShort(previous == null ? -1 : previous.id);
stream.writeShort(recipe == null ? -1 : recipe.result.id); stream.writeShort(block == null ? -1 : block.id);
if(accumulator == null){ if(accumulator == null){
stream.writeByte(-1); stream.writeByte(-1);
@@ -323,10 +321,10 @@ public class BuildBlock extends Block{
} }
if(pid != -1) previous = content.block(pid); if(pid != -1) previous = content.block(pid);
if(rid != -1) recipe = Recipe.getByResult(content.block(rid)); if(rid != -1) block = content.block(rid);
if(recipe != null){ if(block != null){
buildCost = recipe.cost; buildCost = block.buildCost;
}else{ }else{
buildCost = 20f; buildCost = 20f;
} }

View File

@@ -31,7 +31,7 @@ public class LiquidBlock extends Block{
@Override @Override
public TextureRegion[] generateIcons(){ public TextureRegion[] generateIcons(){
return new TextureRegion[]{Core.atlas.find(name() + "-bottom"), Core.atlas.find(name() + "-top")}; return new TextureRegion[]{Core.atlas.find(name + "-bottom"), Core.atlas.find(name + "-top")};
} }
@Override @Override

View File

@@ -1,7 +1,6 @@
package io.anuke.mindustry.world.blocks.distribution; package io.anuke.mindustry.world.blocks.distribution;
import io.anuke.arc.Core; import io.anuke.arc.Core;
import io.anuke.arc.collection.Array;
import io.anuke.arc.collection.LongArray; import io.anuke.arc.collection.LongArray;
import io.anuke.arc.graphics.g2d.Draw; import io.anuke.arc.graphics.g2d.Draw;
import io.anuke.arc.graphics.g2d.TextureRegion; import io.anuke.arc.graphics.g2d.TextureRegion;
@@ -333,17 +332,6 @@ public class Conveyor extends Block{
entity.lastInserted = (byte)(entity.convey.size-1); entity.lastInserted = (byte)(entity.convey.size-1);
} }
@Override
public Array<Object> getDebugInfo(Tile tile){
ConveyorEntity entity = tile.entity();
Array<Object> arr = super.getDebugInfo(tile);
arr.addAll(Array.<Object>with(
"clogHeat", entity.clogHeat,
"sleeping", entity.isSleeping()
));
return arr;
}
@Override @Override
public TileEntity newEntity(){ public TileEntity newEntity(){
return new ConveyorEntity(); return new ConveyorEntity();

View File

@@ -23,7 +23,7 @@ public class LiquidJunction extends LiquidBlock{
@Override @Override
public void draw(Tile tile){ public void draw(Tile tile){
Draw.rect(name(), tile.worldx(), tile.worldy()); Draw.rect(name, tile.worldx(), tile.worldy());
} }
@Override @Override

View File

@@ -50,7 +50,7 @@ public class GenericCrafter extends Block{
@Override @Override
public void draw(Tile tile){ public void draw(Tile tile){
Draw.rect(name(), tile.drawx(), tile.drawy()); Draw.rect(name, tile.drawx(), tile.drawy());
if(!hasLiquids) return; if(!hasLiquids) return;

View File

@@ -47,7 +47,7 @@ public class Pump extends LiquidBlock{
@Override @Override
public void draw(Tile tile){ public void draw(Tile tile){
Draw.rect(name(), tile.drawx(), tile.drawy()); Draw.rect(name, tile.drawx(), tile.drawy());
Draw.color(tile.entity.liquids.current().color); Draw.color(tile.entity.liquids.current().color);
Draw.alpha(tile.entity.liquids.total() / liquidCapacity); Draw.alpha(tile.entity.liquids.total() / liquidCapacity);

View File

@@ -103,7 +103,7 @@ public class UnitFactory extends Block{
UnitFactoryEntity entity = tile.entity(); UnitFactoryEntity entity = tile.entity();
TextureRegion region = type.iconRegion; TextureRegion region = type.iconRegion;
Draw.rect(name(), tile.drawx(), tile.drawy()); Draw.rect(name, tile.drawx(), tile.drawy());
Shaders.build.region = region; Shaders.build.region = region;
Shaders.build.progress = entity.buildTime / produceTime; Shaders.build.progress = entity.buildTime / produceTime;

View File

@@ -7,7 +7,6 @@ import io.anuke.arc.util.Log;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.ItemStack; import io.anuke.mindustry.type.ItemStack;
import io.anuke.mindustry.type.Liquid; import io.anuke.mindustry.type.Liquid;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.meta.values.*; import io.anuke.mindustry.world.meta.values.*;
import java.util.Locale; import java.util.Locale;
@@ -17,13 +16,8 @@ public class BlockStats{
private static final boolean errorWhenMissing = false; private static final boolean errorWhenMissing = false;
private final OrderedMap<StatCategory, OrderedMap<BlockStat, StatValue>> map = new OrderedMap<>(); private final OrderedMap<StatCategory, OrderedMap<BlockStat, StatValue>> map = new OrderedMap<>();
private final Block block;
private boolean dirty; private boolean dirty;
public BlockStats(Block block){
this.block = block;
}
/**Adds a single float value with this stat, formatted to 2 decimal places.*/ /**Adds a single float value with this stat, formatted to 2 decimal places.*/
public void add(BlockStat stat, float value, StatUnit unit){ public void add(BlockStat stat, float value, StatUnit unit){
add(stat, new NumberValue(value, unit)); add(stat, new NumberValue(value, unit));
@@ -73,7 +67,7 @@ public class BlockStats{
} }
if(map.containsKey(stat.category) && map.get(stat.category).containsKey(stat)){ if(map.containsKey(stat.category) && map.get(stat.category).containsKey(stat)){
throw new RuntimeException("Duplicate stat entry: \"" + stat + "\" in block '" + block.name + "'"); throw new RuntimeException("Duplicate stat entry: \"" + stat + "\" in block.");
} }
if(!map.containsKey(stat.category)){ if(!map.containsKey(stat.category)){
@@ -88,7 +82,7 @@ public class BlockStats{
/**Removes a stat, if it exists.*/ /**Removes a stat, if it exists.*/
public void remove(BlockStat stat){ public void remove(BlockStat stat){
if(!map.containsKey(stat.category) || !map.get(stat.category).containsKey(stat)){ if(!map.containsKey(stat.category) || !map.get(stat.category).containsKey(stat)){
throw new RuntimeException("No stat entry found: \"" + stat + "\" in block '" + block.name + "'!"); throw new RuntimeException("No stat entry found: \"" + stat + "\" in block.");
} }
map.get(stat.category).remove(stat); map.get(stat.category).remove(stat);

View File

@@ -22,7 +22,6 @@ import io.anuke.mindustry.io.SaveIO;
import io.anuke.mindustry.maps.Map; import io.anuke.mindustry.maps.Map;
import io.anuke.mindustry.type.ContentType; import io.anuke.mindustry.type.ContentType;
import io.anuke.mindustry.type.Item; import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.type.Recipe;
import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Edges; import io.anuke.mindustry.world.Edges;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;