Untangle conveyor entanglement

Made track a standalone block due to the influx of conveyor code changes, and if it were ever to return it would make sense to also include the conduits in one form or another, like a 🐍 class/trait/abstract/method/etc
This commit is contained in:
Patrick 'Quezler' Mounier
2020-01-28 10:41:30 +01:00
parent af83d08fb1
commit 683211cb1f
6 changed files with 220 additions and 196 deletions

View File

@ -899,28 +899,28 @@ public class Blocks implements ContentList{
//endregion
//region distribution
conveyor = new ItemConveyor("conveyor"){{
conveyor = new Conveyor("conveyor"){{
requirements(Category.distribution, ItemStack.with(Items.copper, 1), true);
health = 45;
speed = 0.03f;
displayedSpeed = 4.2f;
}};
titaniumConveyor = new ItemConveyor("titanium-conveyor"){{
titaniumConveyor = new Conveyor("titanium-conveyor"){{
requirements(Category.distribution, ItemStack.with(Items.copper, 1, Items.lead, 1, Items.titanium, 1));
health = 65;
speed = 0.08f;
displayedSpeed = 10f;
}};
plastaniumConveyor = new CraterConveyor("plastanium-conveyor"){{
plastaniumConveyor = new Track("plastanium-conveyor"){{
requirements(Category.distribution, ItemStack.with(Items.plastanium, 1, Items.silicon, 1, Items.graphite, 1));
itemCapacity = 8;
speed = 0.04f;
health = 75;
}};
armoredConveyor = new ArmoredItemConveyor("armored-conveyor"){{
armoredConveyor = new ArmoredConveyor("armored-conveyor"){{
requirements(Category.distribution, ItemStack.with(Items.plastanium, 1, Items.thorium, 1, Items.metaglass, 1));
health = 180;
speed = 0.08f;

View File

@ -3,15 +3,15 @@ package mindustry.world.blocks.distribution;
import mindustry.type.*;
import mindustry.world.*;
public class ArmoredItemConveyor extends ItemConveyor{
public class ArmoredConveyor extends Conveyor{
public ArmoredItemConveyor(String name){
public ArmoredConveyor(String name){
super(name);
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
return super.acceptItem(item, tile, source) && (source.block() instanceof ItemConveyor || Edges.getFacingEdge(source, tile).relativeTo(tile) == tile.rotation());
return super.acceptItem(item, tile, source) && (source.block() instanceof Conveyor || Edges.getFacingEdge(source, tile).relativeTo(tile) == tile.rotation());
}
@Override

View File

@ -1,97 +0,0 @@
package mindustry.world.blocks.distribution;
import arc.*;
import arc.math.*;
import arc.util.*;
import mindustry.gen.*;
import mindustry.world.*;
import arc.graphics.g2d.*;
import mindustry.graphics.*;
import mindustry.world.meta.*;
import mindustry.world.blocks.*;
import mindustry.entities.type.*;
import mindustry.entities.traits.BuilderTrait.*;
import static mindustry.Vars.tilesize;
abstract public class BaseConveyor extends Block implements Autotiler{
TextureRegion[][] regions = new TextureRegion[7][4];
public float speed = 0f;
public BaseConveyor(String name){
super(name);
rotate = true;
update = true;
layer = Layer.overlay;
group = BlockGroup.transportation;
hasItems = true;
itemCapacity = 4;
conveyorPlacement = true;
entityType = BaseConveyorEntity::new;
idleSound = Sounds.conveyor;
idleSoundVolume = 0.004f;
unloadable = false;
}
@Override
public void draw(Tile tile){
BaseConveyorEntity entity = tile.ent();
byte rotation = tile.rotation();
int frame = entity.clogHeat <= 0.5f ? (int)(((Time.time() * speed * 8f * entity.timeScale)) % 4) : 0;
Draw.rect(regions[Mathf.clamp(entity.blendbits, 0, regions.length - 1)][Mathf.clamp(frame, 0, regions[0].length - 1)], tile.drawx(), tile.drawy(),
tilesize * entity.blendsclx, tilesize * entity.blendscly, rotation * 90);
}
@Override
public void drawRequestRegion(BuildRequest req, Eachable<BuildRequest> list){
int[] bits = getTiling(req, list);
if(bits == null) return;
TextureRegion region = regions[bits[0]][0];
Draw.rect(region, req.drawx(), req.drawy(), region.getWidth() * bits[1] * Draw.scl * req.animScale, region.getHeight() * bits[2] * Draw.scl * req.animScale, req.rotation * 90);
}
@Override
public void onProximityUpdate(Tile tile){
super.onProximityUpdate(tile);
BaseConveyorEntity entity = tile.ent();
int[] bits = buildBlending(tile, tile.rotation(), null, true);
entity.blendbits = bits[0];
entity.blendsclx = bits[1];
entity.blendscly = bits[2];
}
@Override
public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
return otherblock.outputsItems() && lookingAt(tile, rotation, otherx, othery, otherrot, otherblock);
}
@Override
public TextureRegion[] generateIcons(){
return new TextureRegion[]{Core.atlas.find(name + "-0-0")};
}
@Override
public boolean shouldIdleSound(Tile tile){
BaseConveyorEntity entity = tile.ent();
return entity.clogHeat <= 0.5f;
}
@Override
public boolean isAccessible(){
return true;
}
static class BaseConveyorEntity extends TileEntity{
int blendbits;
int blendsclx, blendscly;
float clogHeat = 0f;
}
}

View File

@ -11,6 +11,8 @@ import arc.util.*;
import mindustry.content.*;
import mindustry.entities.traits.BuilderTrait.*;
import mindustry.entities.type.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.*;
@ -21,25 +23,37 @@ import java.io.*;
import static mindustry.Vars.*;
public class ItemConveyor extends BaseConveyor implements Autotiler{
public class Conveyor extends Block implements Autotiler{
private static final float itemSpace = 0.4f;
private static final int capacity = 4;
private final Vec2 tr1 = new Vec2();
private final Vec2 tr2 = new Vec2();
private TextureRegion[][] regions = new TextureRegion[7][4];
public float speed = 0f;
public float displayedSpeed = 0f;
protected ItemConveyor(String name){
protected Conveyor(String name){
super(name);
entityType = ItemConveyorEntity::new;
rotate = true;
update = true;
layer = Layer.overlay;
group = BlockGroup.transportation;
hasItems = true;
itemCapacity = 4;
conveyorPlacement = true;
entityType = ConveyorEntity::new;
idleSound = Sounds.conveyor;
idleSoundVolume = 0.004f;
unloadable = false;
}
@Override
public void setStats(){
super.setStats();
//have to add a custom calculated speed, since the actual movement speed is apparently not linear
stats.add(BlockStat.itemsMoved, displayedSpeed, StatUnit.itemsSecond);
stats.add(BlockStat.boostEffect, "$blocks.itemsmoved");
@ -56,22 +70,62 @@ public class ItemConveyor extends BaseConveyor implements Autotiler{
}
}
@Override
public void draw(Tile tile){
ConveyorEntity entity = tile.ent();
byte rotation = tile.rotation();
int frame = entity.clogHeat <= 0.5f ? (int)(((Time.time() * speed * 8f * entity.timeScale)) % 4) : 0;
Draw.rect(regions[Mathf.clamp(entity.blendbits, 0, regions.length - 1)][Mathf.clamp(frame, 0, regions[0].length - 1)], tile.drawx(), tile.drawy(),
tilesize * entity.blendsclx, tilesize * entity.blendscly, rotation * 90);
}
@Override
public boolean shouldIdleSound(Tile tile){
ConveyorEntity entity = tile.ent();
return entity.clogHeat <= 0.5f ;
}
@Override
public void onProximityUpdate(Tile tile){
super.onProximityUpdate(tile);
ItemConveyorEntity entity = tile.ent();
ConveyorEntity entity = tile.ent();
int[] bits = buildBlending(tile, tile.rotation(), null, true);
entity.blendbits = bits[0];
entity.blendsclx = bits[1];
entity.blendscly = bits[2];
if(tile.front() != null && tile.front().entity != null){
entity.next = tile.front().entity;
entity.nextc = entity.next instanceof ItemConveyorEntity && entity.next.getTeam() == tile.getTeam() ? (ItemConveyorEntity)entity.next : null;
entity.nextc = entity.next instanceof ConveyorEntity && entity.next.getTeam() == tile.getTeam() ? (ConveyorEntity)entity.next : null;
entity.aligned = entity.nextc != null && tile.rotation() == entity.next.tile.rotation();
}
}
@Override
public void drawRequestRegion(BuildRequest req, Eachable<BuildRequest> list){
int[] bits = getTiling(req, list);
if(bits == null) return;
TextureRegion region = regions[bits[0]][0];
Draw.rect(region, req.drawx(), req.drawy(), region.getWidth() * bits[1] * Draw.scl * req.animScale, region.getHeight() * bits[2] * Draw.scl * req.animScale, req.rotation * 90);
}
@Override
public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock){
return otherblock.outputsItems() && lookingAt(tile, rotation, otherx, othery, otherrot, otherblock);
}
@Override
public TextureRegion[] generateIcons(){
return new TextureRegion[]{Core.atlas.find(name + "-0-0")};
}
@Override
public void drawLayer(Tile tile){
ItemConveyorEntity e = tile.ent();
ConveyorEntity e = tile.ent();
byte rotation = tile.rotation();
for(int i = 0; i < e.len; i++){
@ -87,7 +141,7 @@ public class ItemConveyor extends BaseConveyor implements Autotiler{
@Override
public void unitOn(Tile tile, Unit unit){
ItemConveyorEntity entity = tile.ent();
ConveyorEntity entity = tile.ent();
if(entity.clogHeat > 0.5f){
return;
@ -117,7 +171,7 @@ public class ItemConveyor extends BaseConveyor implements Autotiler{
@Override
public void update(Tile tile){
ItemConveyorEntity e = tile.ent();
ConveyorEntity e = tile.ent();
e.minitem = 1f;
e.mid = 0;
@ -162,19 +216,24 @@ public class ItemConveyor extends BaseConveyor implements Autotiler{
e.noSleep();
}
@Override
public boolean isAccessible(){
return true;
}
@Override
public Block getReplacement(BuildRequest req, Array<BuildRequest> requests){
Boolf<Point2> cont = p -> requests.contains(o -> o.x == req.x + p.x && o.y == req.y + p.y && o.rotation == req.rotation && (req.block instanceof ItemConveyor || req.block instanceof Junction));
Boolf<Point2> cont = p -> requests.contains(o -> o.x == req.x + p.x && o.y == req.y + p.y && o.rotation == req.rotation && (req.block instanceof Conveyor || req.block instanceof Junction));
return cont.get(Geometry.d4(req.rotation)) &&
cont.get(Geometry.d4(req.rotation - 2)) &&
req.tile() != null &&
req.tile().block() instanceof ItemConveyor &&
req.tile().block() instanceof Conveyor &&
Mathf.mod(req.tile().rotation() - req.rotation, 2) == 1 ? Blocks.junction : this;
}
@Override
public int removeStack(Tile tile, Item item, int amount){
ItemConveyorEntity e = tile.ent();
ConveyorEntity e = tile.ent();
e.noSleep();
int removed = 0;
@ -200,13 +259,13 @@ public class ItemConveyor extends BaseConveyor implements Autotiler{
@Override
public int acceptStack(Item item, int amount, Tile tile, Unit source){
ItemConveyorEntity entity = tile.ent();
ConveyorEntity entity = tile.ent();
return Math.min((int)(entity.minitem / itemSpace), amount);
}
@Override
public void handleStack(Item item, int amount, Tile tile, Unit source){
ItemConveyorEntity e = tile.ent();
ConveyorEntity e = tile.ent();
for(int i = amount - 1; i >= 0; i--){
e.add(0);
@ -221,7 +280,7 @@ public class ItemConveyor extends BaseConveyor implements Autotiler{
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
ItemConveyorEntity e = tile.ent();
ConveyorEntity e = tile.ent();
if(e.len >= capacity) return false;
int direction = source == null ? 0 : Math.abs(source.relativeTo(tile.x, tile.y) - tile.rotation());
return (((direction == 0) && e.minitem >= itemSpace) || ((direction % 2 == 1) && e.minitem > 0.7f)) && (source == null || !(source.block().rotate && (source.rotation() + 2) % 4 == tile.rotation()));
@ -229,7 +288,7 @@ public class ItemConveyor extends BaseConveyor implements Autotiler{
@Override
public void handleItem(Item item, Tile tile, Tile source){
ItemConveyorEntity e = tile.ent();
ConveyorEntity e = tile.ent();
if(e.len >= capacity) return;
byte r = tile.rotation();
@ -252,7 +311,7 @@ public class ItemConveyor extends BaseConveyor implements Autotiler{
}
}
public static class ItemConveyorEntity extends BaseConveyorEntity{
public static class ConveyorEntity extends TileEntity{
//parallel array data
Item[] ids = new Item[capacity];
float[] xs = new float[capacity];
@ -261,13 +320,18 @@ public class ItemConveyor extends BaseConveyor implements Autotiler{
int len = 0;
//next entity
@Nullable TileEntity next;
@Nullable ItemConveyorEntity nextc;
@Nullable ConveyorEntity nextc;
//whether the next conveyor's rotation == tile rotation
boolean aligned;
int lastInserted, mid;
float minitem = 1;
int blendbits;
int blendsclx, blendscly;
float clogHeat = 0f;
final void add(int o){
for(int i = Math.max(o + 1, len); i > o; i--){
ids[i] = ids[i - 1];

View File

@ -1,42 +1,54 @@
package mindustry.world.blocks.distribution;
import arc.*;
import arc.graphics.g2d.*;
import arc.math.*;
import arc.util.*;
import mindustry.ui.*;
import mindustry.type.*;
import mindustry.world.*;
import arc.graphics.g2d.*;
import mindustry.content.*;
import mindustry.entities.*;
import mindustry.entities.traits.BuilderTrait.*;
import mindustry.entities.type.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import arc.scene.ui.layout.*;
import mindustry.type.*;
import mindustry.ui.*;
import mindustry.world.*;
import mindustry.world.blocks.*;
import mindustry.world.meta.*;
import java.io.*;
import static mindustry.Vars.*;
public class CraterConveyor extends BaseConveyor{
private TextureRegion start, end, crater;
public class Track extends Block implements Autotiler{
private TextureRegion[] regions = new TextureRegion[7];
private TextureRegion crater;
public CraterConveyor(String name){
public float speed = 0f;
public Track(String name){
super(name);
entityType = CraterConveyorEntity::new;
rotate = true;
update = true;
layer = Layer.overlay;
group = BlockGroup.transportation;
hasItems = true;
itemCapacity = 4;
conveyorPlacement = true;
entityType = TrackEntity::new;
idleSound = Sounds.conveyor;
idleSoundVolume = 0.004f;
unloadable = false;
}
@Override
public void load(){
int i;
for(i = 0; i < regions.length; i++){
for(int j = 0; j < 4; j++){
regions[i][j] = Core.atlas.find(name + "-" + i + "-" + 0);
}
for(int i = 0; i < regions.length; i++){
regions[i] = Core.atlas.find(name + "-" + i + "-" + 0);
}
start = Core.atlas.find(name + "-5-0");
end = Core.atlas.find(name + "-6-0");
crater = Core.atlas.find("crater");
}
@ -48,23 +60,91 @@ public class CraterConveyor extends BaseConveyor{
stats.add(BlockStat.boostEffect, "$blocks.itemcapacity");
}
@Override
public void drawRequestRegion(BuildRequest req, Eachable<BuildRequest> list){
int[] bits = getTiling(req, list);
if(bits == null) return;
TextureRegion region = regions[bits[0]];
Draw.rect(region, req.drawx(), req.drawy(), region.getWidth() * bits[1] * Draw.scl * req.animScale, region.getHeight() * bits[2] * Draw.scl * req.animScale, req.rotation * 90);
}
@Override
public void onProximityUpdate(Tile tile){
super.onProximityUpdate(tile);
TrackEntity entity = tile.ent();
int[] bits = buildBlending(tile, tile.rotation(), null, true);
entity.blendbits = bits[0];
entity.blendsclx = bits[1];
entity.blendscly = bits[2];
}
@Override
public TextureRegion[] generateIcons(){
return new TextureRegion[]{Core.atlas.find(name + "-0-0")};
}
@Override
public boolean shouldIdleSound(Tile tile){
return false;
}
@Override
public boolean isAccessible(){
return true;
}
class TrackEntity extends TileEntity{
int blendbits;
int blendsclx, blendscly;
int from = Pos.invalid;
float reload;
float lastFrameUpdated = -1;
@Override
public void write(DataOutput stream) throws IOException{
super.write(stream);
stream.writeInt(from);
stream.writeFloat(reload);
}
@Override
public void read(DataInput stream, byte revision) throws IOException{
super.read(stream, revision);
from = stream.readInt();
reload = stream.readFloat();
}
}
//
@Override
public void draw(Tile tile){
super.draw(tile);
TrackEntity entity = tile.ent();
byte rotation = tile.rotation();
Draw.rect(regions[Mathf.clamp(entity.blendbits, 0, regions.length - 1)], tile.drawx(), tile.drawy(), tilesize * entity.blendsclx, tilesize * entity.blendscly, rotation * 90);
// don't draw if its just one lone tile
if(isStart(tile) && isEnd(tile)) return;
if(isStart(tile)) Draw.rect(start, tile.drawx(), tile.drawy(), tile.rotation() * 90);
if(isEnd(tile)) Draw.rect(end, tile.drawx(), tile.drawy(), tile.rotation() * 90);
if(isStart(tile)) Draw.rect(regions[5], tile.drawx(), tile.drawy(), tile.rotation() * 90);
if(isEnd(tile)) Draw.rect(regions[6], tile.drawx(), tile.drawy(), tile.rotation() * 90);
}
@Override
public void drawLayer(Tile tile){
CraterConveyorEntity entity = tile.ent();
TrackEntity entity = tile.ent();
if(entity.link == Pos.invalid) return;
Tile from = world.tile(entity.link);
// no from == no crater
if(entity.from == Pos.invalid) return;
Tile from = world.tile(entity.from);
Tmp.v1.set(from.getX(), from.getY());
Tmp.v2.set(tile.drawx(), tile.drawy());
Tmp.v1.interpolate(Tmp.v2, 1f - entity.reload, Interpolation.linear);
@ -80,18 +160,18 @@ public class CraterConveyor extends BaseConveyor{
Draw.rect(crater, Tmp.v1.x, Tmp.v1.y, rotation - 90);
// failsafe
if(entity.dominant() == null) return;
if(entity.items.first() == null) return;
// draw resource
float size = itemSize / 2f;
size += entity.items.total() * 0.1f / (itemCapacity / 8f);
Draw.rect(entity.dominant().icon(Cicon.medium), Tmp.v1.x, Tmp.v1.y, size, size, 0);
Draw.rect(entity.items.first().icon(Cicon.medium), Tmp.v1.x, Tmp.v1.y, size, size, 0);
}
@Override
public void update(Tile tile){
CraterConveyorEntity entity = tile.ent();
TrackEntity entity = tile.ent();
// only update once per frame
if(entity.lastFrameUpdated == Core.graphics.getFrameId()) return;
@ -100,15 +180,15 @@ public class CraterConveyor extends BaseConveyor{
entity.reload = Mathf.clamp(entity.reload - speed, 0f, 1f);
// ensure a crater exists below this block
if(entity.link == Pos.invalid){
if(entity.from == Pos.invalid){
// poof in crater
if(entity.items.total() <= 0 || entity.reload > 0) return;
Effects.effect(Fx.plasticburn, tile.drawx(), tile.drawy());
entity.link = tile.pos();
entity.from = tile.pos();
}else{
// poof out crater
if(entity.items.total() == 0){
entity.link = Pos.invalid;
entity.from = Pos.invalid;
return;
}
}
@ -127,22 +207,22 @@ public class CraterConveyor extends BaseConveyor{
// when near the center of the target tile...
if(entity.reload < 0.25f){
if(!(destination.block() instanceof CraterConveyor) && (entity.link != tile.pos() || !isStart(tile))){ // ...and if its not a crater conveyor, start unloading (everything)
while(entity.items.total() > 0 && entity.dominant() != null && offloadDir(tile, entity.dominant())) entity.items.remove(entity.dominant(), 1);
if(!(destination.block() instanceof Track) && (entity.from != tile.pos() || !isStart(tile))){ // ...and if its not a crater conveyor, start unloading (everything)
while(entity.items.total() > 0 && entity.items.first() != null && offloadDir(tile, entity.items.first())) entity.items.remove(entity.items.first(), 1);
if(entity.items.total() == 0) Effects.effect(Fx.plasticburn, tile.drawx(), tile.drawy());
}
}
// when basically exactly on the center:
if(entity.reload == 0){
if(destination.block() instanceof CraterConveyor){
CraterConveyorEntity e = destination.ent();
if(destination.block() instanceof Track){
TrackEntity e = destination.ent();
// check if next crater conveyor is not occupied
if(e.items.total() == 0){
// transfer ownership of crater
entity.link = Pos.invalid;
e.link = tile.pos();
entity.from = Pos.invalid;
e.from = tile.pos();
// prevent this tile from spawning a new crater to avoid collisions
entity.reload = 1;
@ -157,41 +237,11 @@ public class CraterConveyor extends BaseConveyor{
}
}
class CraterConveyorEntity extends BaseConveyorEntity{
float lastFrameUpdated = -1;
int link = Pos.invalid;
float reload;
@Override
public void write(DataOutput stream) throws IOException{
super.write(stream);
stream.writeInt(link);
stream.writeFloat(reload);
}
@Override
public void read(DataInput stream, byte revision) throws IOException{
super.read(stream, revision);
link = stream.readInt();
reload = stream.readFloat();
}
public Item dominant(){ // fixme: do this better
if(tile.entity.items.total() == 0) return null;
Item item = tile.entity.items.take();
tile.entity.items.add(item, 1);
return item;
}
}
@Override
public boolean acceptItem(Item item, Tile tile, Tile source){
CraterConveyorEntity entity = tile.ent();
TrackEntity entity = tile.ent();
if(!isStart(tile) && !(source.block() instanceof CraterConveyor)) return false;
if(!isStart(tile) && !(source.block() instanceof Track)) return false;
if(entity.items.total() > 0 && !entity.items.has(item)) return false;
if(entity.items.total() >= getMaximumAccepted(tile, item)) return false;
if(tile.front() == source) return false;
@ -212,27 +262,27 @@ public class CraterConveyor extends BaseConveyor{
}
public boolean shouldLaunch(Tile tile){
CraterConveyorEntity entity = tile.ent();
TrackEntity entity = tile.ent();
// its not a start tile so it should be moving
if(!isStart(tile)) return true;
// its considered full
if(entity.items.total() >= getMaximumAccepted(tile, entity.dominant())) return true;
if(entity.items.total() >= getMaximumAccepted(tile, entity.items.first())) return true;
return false;
}
@Override
public boolean blends(Tile tile, int rotation, int otherx, int othery, int otherrot, Block otherblock) {
return otherblock.outputsItems() && blendsArmored(tile, rotation, otherx, othery, otherrot, otherblock) && otherblock instanceof CraterConveyor;
return otherblock.outputsItems() && blendsArmored(tile, rotation, otherx, othery, otherrot, otherblock) && otherblock instanceof Track;
}
// has no crater conveyors facing into it
private boolean isStart(Tile tile){
Tile[] inputs = new Tile[]{tile.back(), tile.left(), tile.right()};
for(Tile input : inputs){
if(input != null && input.getTeam() == tile.getTeam() && input.block() instanceof CraterConveyor && input.front() == tile) return false;
if(input != null && input.getTeam() == tile.getTeam() && input.block() instanceof Track && input.front() == tile) return false;
}
return true;
@ -242,7 +292,7 @@ public class CraterConveyor extends BaseConveyor{
private boolean isEnd(Tile tile){
if(tile.front() == null) return true;
if(tile.getTeam() != tile.front().getTeam()) return true;
if(!(tile.front().block() instanceof CraterConveyor)) return true;
if(!(tile.front().block() instanceof Track)) return true;
return false;
}

View File

@ -66,6 +66,13 @@ public class ItemModule extends BlockModule{
return total;
}
public Item first(){
for(int i = 0; i < items.length; i++){
if(items[i] > 0) return content.item(i);
}
return null;
}
public Item take(){
for(int i = 0; i < items.length; i++){
if(items[i] > 0){