Balancing, fixed drone AI, fixed placement, fixed stacking effects

This commit is contained in:
Anuken
2018-06-25 22:47:18 -04:00
parent 5d70b4b95b
commit 91501d39ee
17 changed files with 187 additions and 133 deletions

View File

@@ -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<>());

View File

@@ -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));

View File

@@ -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;

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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;
}*/
}
}

View File

@@ -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);

View File

@@ -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();

View File

@@ -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;
}

View File

@@ -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;