Balancing, fixed drone AI, fixed placement, fixed stacking effects
This commit is contained in:
@@ -36,7 +36,9 @@ public class BlockIndexer {
|
||||
/**Set of all ores that are being scanned.*/
|
||||
private final ObjectSet<Item> scanOres = ObjectSet.with(Items.tungsten, Items.coal, Items.lead, Items.thorium, Items.titanium);
|
||||
/**Stores all ore quadtrants on the map.*/
|
||||
private ObjectMap<Item, ObjectSet<Tile>> ores = new ObjectMap<>();
|
||||
private ObjectMap<Item, ObjectSet<Tile>> ores;
|
||||
|
||||
private final ObjectSet<Item> itemSet = new ObjectSet<>();
|
||||
|
||||
/**Tags all quadrants.*/
|
||||
private Bits[] structQuadrants;
|
||||
@@ -68,7 +70,7 @@ public class BlockIndexer {
|
||||
enemyMap.clear();
|
||||
allyMap.clear();
|
||||
typeMap.clear();
|
||||
ores.clear();
|
||||
ores = null;
|
||||
|
||||
//create bitset for each team type that contains each quadrant
|
||||
structQuadrants = new Bits[Team.values().length];
|
||||
@@ -177,6 +179,37 @@ public class BlockIndexer {
|
||||
}
|
||||
typeMap.put(tile.packedPosition(), new TileIndex(tile.block().flags, tile.getTeam()));
|
||||
}
|
||||
|
||||
if(ores == null) return;
|
||||
|
||||
int quadrantX = tile.x / oreQuadrantSize;
|
||||
int quadrantY = tile.y / oreQuadrantSize;
|
||||
itemSet.clear();
|
||||
|
||||
Tile rounded = world.tile(Mathf.clamp(quadrantX * oreQuadrantSize + oreQuadrantSize /2, 0, world.width() - 1),
|
||||
Mathf.clamp(quadrantY * oreQuadrantSize + oreQuadrantSize /2, 0, world.height() - 1));
|
||||
|
||||
//find all items that this quadrant contains
|
||||
for (int x = quadrantX * structQuadrantSize; x < world.width() && x < (quadrantX + 1) * structQuadrantSize; x++) {
|
||||
for (int y = quadrantY * structQuadrantSize; y < world.height() && y < (quadrantY + 1) * structQuadrantSize; y++) {
|
||||
Tile result = world.tile(x, y);
|
||||
if(result.block().drops == null || !scanOres.contains(result.block().drops.item)) continue;
|
||||
|
||||
itemSet.add(result.block().drops.item);
|
||||
}
|
||||
}
|
||||
|
||||
//update quadrant at this position
|
||||
for (Item item : scanOres){
|
||||
ObjectSet<Tile> set = ores.get(item);
|
||||
|
||||
//update quadrant status depending on whether the item is in it
|
||||
if(!itemSet.contains(item)){
|
||||
set.remove(rounded);
|
||||
}else{
|
||||
set.add(rounded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateQuadrant(Tile tile){
|
||||
@@ -229,6 +262,8 @@ public class BlockIndexer {
|
||||
}
|
||||
|
||||
private void scanOres(){
|
||||
ores = new ObjectMap<>();
|
||||
|
||||
//initialize ore map with empty sets
|
||||
for(Item item : scanOres){
|
||||
ores.put(item, new ObjectSet<>());
|
||||
|
||||
@@ -48,7 +48,7 @@ public class Recipes implements ContentList{
|
||||
//CRAFTING
|
||||
|
||||
//smelting
|
||||
new Recipe(crafting, CraftingBlocks.smelter, new ItemStack(Items.tungsten, 60));
|
||||
new Recipe(crafting, CraftingBlocks.smelter, new ItemStack(Items.tungsten, 70));
|
||||
new Recipe(crafting, CraftingBlocks.arcsmelter, new ItemStack(Items.tungsten, 90), new ItemStack(Items.carbide, 60), new ItemStack(Items.lead, 50));
|
||||
new Recipe(crafting, CraftingBlocks.siliconsmelter, new ItemStack(Items.tungsten, 60), new ItemStack(Items.lead, 50));
|
||||
|
||||
@@ -91,8 +91,8 @@ public class Recipes implements ContentList{
|
||||
|
||||
//bodies
|
||||
|
||||
new Recipe(units, UpgradeBlocks.tridentFactory, new ItemStack(Items.lead, 150), new ItemStack(Items.silicon, 200), new ItemStack(Items.titanium, 240))
|
||||
.setDesktop(); //trident is desktop only, because it's the starter mobile ship
|
||||
new Recipe(units, UpgradeBlocks.dartFactory, new ItemStack(Items.lead, 150), new ItemStack(Items.silicon, 200), new ItemStack(Items.titanium, 240))
|
||||
.setDesktop(); //dart is desktop only, because it's the starter mobile ship
|
||||
|
||||
//new Recipe(units, UpgradeBlocks.deltaFactory, new ItemStack(Items.tungsten, 30), new ItemStack(Items.lead, 50), new ItemStack(Items.silicon, 30));
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ public class CraftingBlocks extends BlockList implements ContentList {
|
||||
inputs = new ItemStack[]{new ItemStack(Items.tungsten, 3)};
|
||||
fuel = Items.coal;
|
||||
result = Items.carbide;
|
||||
craftTime = 40f;
|
||||
craftTime = 45f;
|
||||
burnDuration = 35f;
|
||||
useFlux = true;
|
||||
}};
|
||||
|
||||
@@ -32,7 +33,7 @@ public class CraftingBlocks extends BlockList implements ContentList {
|
||||
inputs = new ItemStack[]{new ItemStack(Items.coal, 1), new ItemStack(Items.tungsten, 2)};
|
||||
result = Items.carbide;
|
||||
powerUse = 0.1f;
|
||||
craftTime = 25f;
|
||||
craftTime = 30f;
|
||||
size = 2;
|
||||
|
||||
useFlux = true;
|
||||
|
||||
@@ -115,6 +115,12 @@ public class StatusController implements Saveable{
|
||||
|
||||
@Override
|
||||
public void readSave(DataInput stream) throws IOException {
|
||||
for (StatusEntry effect : statuses){
|
||||
Pools.free(effect);
|
||||
}
|
||||
|
||||
statuses.clear();
|
||||
|
||||
byte amount = stream.readByte();
|
||||
for (int i = 0; i < amount; i++) {
|
||||
byte id = stream.readByte();
|
||||
|
||||
@@ -8,7 +8,6 @@ import io.anuke.mindustry.content.fx.BlockFx;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.game.EventType.BlockBuildEvent;
|
||||
import io.anuke.mindustry.gen.CallBlocks;
|
||||
import io.anuke.mindustry.gen.CallEntity;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
@@ -21,17 +20,20 @@ import io.anuke.mindustry.world.blocks.BreakBlock.BreakEntity;
|
||||
import io.anuke.mindustry.world.blocks.BuildBlock;
|
||||
import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity;
|
||||
import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.core.Events;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.graphics.Fill;
|
||||
import io.anuke.ucore.graphics.Lines;
|
||||
import io.anuke.ucore.graphics.Shapes;
|
||||
import io.anuke.ucore.util.*;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Geometry;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
import io.anuke.ucore.util.Translator;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
/**Interface for units that build, break or mine things.*/
|
||||
public interface BuilderTrait {
|
||||
@@ -76,7 +78,11 @@ public interface BuilderTrait {
|
||||
|
||||
/**Clears the placement queue.*/
|
||||
default void clearBuilding(){
|
||||
getPlaceQueue().clear();
|
||||
if(this instanceof Player) {
|
||||
CallBlocks.onBuildDeselect((Player) this);
|
||||
}else{
|
||||
getPlaceQueue().clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**Add another build requests to the tail of the queue.*/
|
||||
@@ -145,10 +151,12 @@ public interface BuilderTrait {
|
||||
if(Build.validPlace(unit.getTeam(), current.x, current.y, current.recipe.result, current.rotation)){
|
||||
//if it's valid, place it
|
||||
//FIXME a player instance is required here, but the the builder may not be a player
|
||||
CallBlocks.placeBlock((Player)unit, unit.getTeam(), current.x, current.y, current.recipe, current.rotation);
|
||||
|
||||
//fire build event
|
||||
threads.run(() -> Events.fire(BlockBuildEvent.class, unit.getTeam(), world.tile(current.x, current.y)));
|
||||
if(!current.requested){
|
||||
CallBlocks.placeBlock((Player)unit, unit.getTeam(), current.x, current.y, current.recipe, current.rotation);
|
||||
current.requested = true;
|
||||
}
|
||||
|
||||
}else{
|
||||
//otherwise, skip it
|
||||
getPlaceQueue().removeFirst();
|
||||
@@ -277,6 +285,7 @@ public interface BuilderTrait {
|
||||
public final int x, y, rotation;
|
||||
public final Recipe recipe;
|
||||
public final boolean remove;
|
||||
public boolean requested;
|
||||
|
||||
public float progress;
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package io.anuke.mindustry.entities.traits;
|
||||
|
||||
import com.badlogic.gdx.Gdx;
|
||||
import com.badlogic.gdx.utils.TimeUtils;
|
||||
import io.anuke.mindustry.net.Interpolator;
|
||||
import io.anuke.ucore.entities.trait.Entity;
|
||||
|
||||
@@ -25,8 +24,9 @@ public interface SyncTrait extends Entity, TypeTrait {
|
||||
if(getInterpolator() != null) {
|
||||
getInterpolator().target.set(x, y);
|
||||
getInterpolator().last.set(x, y);
|
||||
getInterpolator().pos.set(0, 0);
|
||||
getInterpolator().updateSpacing = 16;
|
||||
getInterpolator().lastUpdated = TimeUtils.millis();
|
||||
getInterpolator().lastUpdated = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -402,6 +402,8 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
||||
//get tile on cursor
|
||||
Tile cursor = tileAt(screenX, screenY);
|
||||
|
||||
float worldx = Graphics.world(screenX, screenY).x, worldy = Graphics.world(screenX, screenY).y;
|
||||
|
||||
//ignore off-screen taps
|
||||
if(cursor == null || ui.hasMouse(screenX, screenY)) return false;
|
||||
|
||||
@@ -410,7 +412,7 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
||||
|
||||
//call tap events
|
||||
if(pointer == 0 && !selecting && mode == none){
|
||||
if(!tileTapped(cursor.target())){
|
||||
if(!tileTapped(cursor.target()) && !tryTapPlayer(worldx, worldy)){
|
||||
tryBeginMine(cursor);
|
||||
}
|
||||
}
|
||||
@@ -475,6 +477,12 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
||||
}
|
||||
|
||||
lineMode = false;
|
||||
}else{
|
||||
Tile tile = tileAt(screenX, screenY);
|
||||
|
||||
if (tile == null) return false;
|
||||
|
||||
tryDropItems(tile.target(), Graphics.world(screenX, screenY).x, Graphics.world(screenX, screenY).y);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -524,7 +532,7 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
||||
}else if(mode == placing && isPlacing() && validPlace(cursor.x, cursor.y, recipe.result, rotation) && !checkOverlapPlacement(cursor.x, cursor.y, recipe.result)){
|
||||
//add to selection queue if it's a valid place position
|
||||
selection.add(lastPlaced = new PlaceRequest(cursor.worldx(), cursor.worldy(), recipe, rotation));
|
||||
}else if(mode == breaking && validBreak(cursor.x, cursor.y) && !hasRequest(cursor)){
|
||||
}else if(mode == breaking && validBreak(cursor.x, cursor.y) && !hasRequest(cursor)) {
|
||||
//add to selection queue if it's a valid BREAK position
|
||||
selection.add(new PlaceRequest(cursor.worldx(), cursor.worldy()));
|
||||
}else{ //else, try and carry units
|
||||
@@ -616,8 +624,8 @@ public class AndroidInput extends InputHandler implements GestureListener{
|
||||
public boolean pan(float x, float y, float deltaX, float deltaY){
|
||||
if(ui.hasMouse()) return false;
|
||||
|
||||
//can't pan in line mode with one finger!
|
||||
if(lineMode && !Gdx.input.isTouched(1)){
|
||||
//can't pan in line mode with one finger or while dropping items!
|
||||
if((lineMode && !Gdx.input.isTouched(1)) || droppingItem){
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,19 +31,18 @@ public class Interpolator {
|
||||
targets = new float[0];
|
||||
target.setZero();
|
||||
last.setZero();
|
||||
lastUpdated = updateSpacing = 0;
|
||||
lastUpdated = 0;
|
||||
updateSpacing = 16; //1 frame
|
||||
pos.setZero();
|
||||
}
|
||||
|
||||
public void update(){
|
||||
|
||||
if(lastUpdated != 0){
|
||||
if(lastUpdated != 0 && updateSpacing != 0){
|
||||
float timeSinceUpdate = TimeUtils.timeSinceMillis(lastUpdated);
|
||||
float alpha = Math.min(timeSinceUpdate / updateSpacing, 1f);
|
||||
float alpha = Math.min(timeSinceUpdate / updateSpacing, 2f);
|
||||
|
||||
Mathf.lerp2(last, target, alpha);
|
||||
|
||||
pos.set(last).lerp(target, alpha);
|
||||
Mathf.lerp2(pos.set(last), target, alpha);
|
||||
|
||||
if(values.length != targets.length){
|
||||
values = new float[targets.length];
|
||||
@@ -52,34 +51,9 @@ public class Interpolator {
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = Mathf.slerp(values[i], targets[i], alpha);
|
||||
}
|
||||
|
||||
if(target.dst(pos) > 128){
|
||||
pos.set(target);
|
||||
last.set(target);
|
||||
}
|
||||
}else{
|
||||
pos.set(target);
|
||||
}
|
||||
/*
|
||||
time += 1f / spacing * Math.min(Timers.delta(), 1f);
|
||||
|
||||
time = Mathf.clamp(time, 0, 2f);
|
||||
|
||||
Mathf.lerp2(pos.set(last), target, time);
|
||||
|
||||
if(values.length != targets.length){
|
||||
values = new float[targets.length];
|
||||
}
|
||||
|
||||
for(int i = 0; i < values.length; i ++){
|
||||
values[i] = Mathf.slerpDelta(values[i], targets[i], 0.6f);
|
||||
}
|
||||
|
||||
if(target.dst(pos) > 128){
|
||||
pos.set(target);
|
||||
last.set(target);
|
||||
time = 0f;
|
||||
}*/
|
||||
|
||||
}
|
||||
}
|
||||
@@ -141,7 +141,7 @@ public class BlockInventoryFragment implements Fragment {
|
||||
table.setPosition(v.x, v.y, Align.topLeft);
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, targets = Loc.both, in = In.blocks)
|
||||
@Remote(called = Loc.server, targets = Loc.both, in = In.blocks, forward = true)
|
||||
public static void requestItem(Player player, Tile tile, Item item, int amount){
|
||||
int removed = tile.block().removeStack(tile, item, amount);
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import io.anuke.mindustry.content.blocks.Blocks;
|
||||
import io.anuke.mindustry.entities.Player;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.entities.traits.BuilderTrait.BuildRequest;
|
||||
import io.anuke.mindustry.game.EventType.BlockBuildEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.net.In;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
@@ -15,11 +16,10 @@ import io.anuke.mindustry.world.blocks.BreakBlock;
|
||||
import io.anuke.mindustry.world.blocks.BreakBlock.BreakEntity;
|
||||
import io.anuke.mindustry.world.blocks.BuildBlock;
|
||||
import io.anuke.mindustry.world.blocks.BuildBlock.BuildEntity;
|
||||
import io.anuke.ucore.core.Events;
|
||||
import io.anuke.ucore.entities.Entities;
|
||||
|
||||
import static io.anuke.mindustry.Vars.debug;
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
import static io.anuke.mindustry.Vars.*;
|
||||
|
||||
public class Build {
|
||||
private static final Rectangle rect = new Rectangle();
|
||||
@@ -98,6 +98,8 @@ public class Build {
|
||||
//just in case
|
||||
if(tile == null) return;
|
||||
|
||||
threads.run(() -> Events.fire(BlockBuildEvent.class, team, tile));
|
||||
|
||||
Block result = recipe.result;
|
||||
Block previous = tile.block();
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ public class BreakBlock extends Block {
|
||||
public void drawShadow(Tile tile) {
|
||||
BreakEntity entity = tile.entity();
|
||||
|
||||
if(entity.previous instanceof BreakBlock){
|
||||
if(entity.previous instanceof BreakBlock || entity.previous == null || entity.previous.shadowRegion == null){
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -58,10 +58,7 @@ public class BuildBlock extends Block {
|
||||
|
||||
@Override
|
||||
public void tapped(Tile tile, Player player) {
|
||||
BuildEntity entity = tile.entity();
|
||||
|
||||
player.clearBuilding();
|
||||
player.addBuildRequest(new BuildRequest(tile.x, tile.y, tile.getRotation(), entity.recipe));
|
||||
CallBlocks.onBuildSelect(player, tile);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -166,6 +163,21 @@ public class BuildBlock extends Block {
|
||||
}
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, targets = Loc.both, in = In.blocks, forward = true)
|
||||
public static void onBuildSelect(Player player, Tile tile){
|
||||
if(player == null || !(tile.entity instanceof BuildEntity)) return;
|
||||
|
||||
BuildEntity entity = tile.entity();
|
||||
|
||||
player.clearBuilding();
|
||||
player.addBuildRequest(new BuildRequest(tile.x, tile.y, tile.getRotation(), entity.recipe));
|
||||
}
|
||||
|
||||
@Remote(called = Loc.server, targets = Loc.both, in = In.blocks, forward = true)
|
||||
public static void onBuildDeselect(Player player){
|
||||
player.getPlaceQueue().clear();
|
||||
}
|
||||
|
||||
public class BuildEntity extends TileEntity{
|
||||
public Recipe recipe;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user