diff --git a/core/assets-raw/sprites/blocks/distribution/mass-driver-turret.png b/core/assets-raw/sprites/blocks/distribution/mass-driver-turret.png new file mode 100644 index 0000000000..350e7c66f4 Binary files /dev/null and b/core/assets-raw/sprites/blocks/distribution/mass-driver-turret.png differ diff --git a/core/assets-raw/sprites/blocks/distribution/mass-driver.png b/core/assets-raw/sprites/blocks/distribution/mass-driver.png new file mode 100644 index 0000000000..f1d779149d Binary files /dev/null and b/core/assets-raw/sprites/blocks/distribution/mass-driver.png differ diff --git a/core/assets/sprites/sprites.atlas b/core/assets/sprites/sprites.atlas index 54609c768c..f596c4078c 100644 --- a/core/assets/sprites/sprites.atlas +++ b/core/assets/sprites/sprites.atlas @@ -39,6 +39,20 @@ laserconveyor-end orig: 8, 8 offset: 0, 0 index: -1 +mass-driver-turret + rotate: false + xy: 281, 135 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +ripple + rotate: false + xy: 281, 135 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 poweredconveyormove rotate: false xy: 709, 199 @@ -111,56 +125,56 @@ laserdrill-top index: -1 nucleardrill rotate: false - xy: 281, 135 + xy: 307, 135 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 nucleardrill-rim rotate: false - xy: 307, 135 + xy: 333, 135 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 nucleardrill-rotator rotate: false - xy: 333, 135 + xy: 359, 135 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 nucleardrill-top rotate: false - xy: 359, 135 + xy: 385, 135 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 oilextractor rotate: false - xy: 437, 136 + xy: 587, 232 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 oilextractor-liquid rotate: false - xy: 587, 232 + xy: 613, 232 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 oilextractor-rotator rotate: false - xy: 613, 232 + xy: 607, 206 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 oilextractor-top rotate: false - xy: 607, 206 + xy: 597, 180 size: 24, 24 orig: 24, 24 offset: 0, 0 @@ -1252,14 +1266,14 @@ fusionreactor-top index: -1 nuclearreactor-center rotate: false - xy: 385, 135 + xy: 411, 135 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 nuclearreactor-lights rotate: false - xy: 411, 135 + xy: 437, 136 size: 24, 24 orig: 24, 24 offset: 0, 0 @@ -1503,13 +1517,6 @@ siliconextractor offset: 0, 0 index: -1 core-open - rotate: false - xy: 545, 157 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 -core-top rotate: false xy: 571, 157 size: 24, 24 @@ -1649,13 +1656,6 @@ meltdown orig: 32, 32 offset: 0, 0 index: -1 -ripple - rotate: false - xy: 597, 180 - size: 24, 24 - orig: 24, 24 - offset: 0, 0 - index: -1 scatter rotate: false xy: 641, 192 @@ -2496,6 +2496,27 @@ block-icon-liquidtank orig: 24, 24 offset: 0, 0 index: -1 +block-icon-mass-driver + rotate: false + xy: 493, 183 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +mass-driver + rotate: false + xy: 493, 183 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 +core-top + rotate: false + xy: 493, 183 + size: 24, 24 + orig: 24, 24 + offset: 0, 0 + index: -1 block-icon-mechanical-pump rotate: false xy: 903, 427 @@ -2561,21 +2582,21 @@ multiplexer index: -1 block-icon-nucleardrill rotate: false - xy: 493, 183 + xy: 519, 183 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 block-icon-nuclearreactor rotate: false - xy: 519, 183 + xy: 545, 183 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 nuclearreactor rotate: false - xy: 519, 183 + xy: 545, 183 size: 24, 24 orig: 24, 24 offset: 0, 0 @@ -2596,7 +2617,7 @@ oil index: -1 block-icon-oilextractor rotate: false - xy: 545, 183 + xy: 571, 183 size: 24, 24 orig: 24, 24 offset: 0, 0 @@ -2771,7 +2792,7 @@ resupplypoint index: -1 block-icon-ripple rotate: false - xy: 571, 183 + xy: 467, 150 size: 24, 24 orig: 24, 24 offset: 0, 0 @@ -3114,14 +3135,14 @@ block-icon-swarmer index: -1 block-icon-teleporter rotate: false - xy: 467, 150 + xy: 493, 157 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 teleporter rotate: false - xy: 467, 150 + xy: 493, 157 size: 24, 24 orig: 24, 24 offset: 0, 0 @@ -3233,14 +3254,14 @@ unloader index: -1 block-icon-vault rotate: false - xy: 493, 157 + xy: 519, 157 size: 24, 24 orig: 24, 24 offset: 0, 0 index: -1 vault rotate: false - xy: 493, 157 + xy: 519, 157 size: 24, 24 orig: 24, 24 offset: 0, 0 @@ -3598,7 +3619,7 @@ button-map-over index: -1 button-select rotate: false - xy: 519, 157 + xy: 545, 157 size: 24, 24 split: 4, 4, 4, 4 orig: 24, 24 diff --git a/core/assets/sprites/sprites.png b/core/assets/sprites/sprites.png index 082cb512d2..800c2ce817 100644 Binary files a/core/assets/sprites/sprites.png and b/core/assets/sprites/sprites.png differ diff --git a/core/src/io/anuke/mindustry/content/Recipes.java b/core/src/io/anuke/mindustry/content/Recipes.java index caa2cdc924..daaf9071d2 100644 --- a/core/src/io/anuke/mindustry/content/Recipes.java +++ b/core/src/io/anuke/mindustry/content/Recipes.java @@ -39,6 +39,7 @@ public class Recipes implements ContentList{ new Recipe(distribution, StorageBlocks.sortedunloader, new ItemStack(Items.steel, 5)); new Recipe(distribution, DistributionBlocks.bridgeconveyor, new ItemStack(Items.steel, 5)); new Recipe(distribution, DistributionBlocks.laserconveyor, new ItemStack(Items.steel, 5)); + new Recipe(distribution, DistributionBlocks.massdriver, new ItemStack(Items.steel, 1)); new Recipe(weapon, WeaponBlocks.duo, new ItemStack(Items.iron, 7)); new Recipe(weapon, WeaponBlocks.scatter, new ItemStack(Items.iron, 8)); diff --git a/core/src/io/anuke/mindustry/content/blocks/DistributionBlocks.java b/core/src/io/anuke/mindustry/content/blocks/DistributionBlocks.java index 5ca43c60c4..38bf5cbf9f 100644 --- a/core/src/io/anuke/mindustry/content/blocks/DistributionBlocks.java +++ b/core/src/io/anuke/mindustry/content/blocks/DistributionBlocks.java @@ -5,7 +5,8 @@ import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.blocks.distribution.*; public class DistributionBlocks extends BlockList implements ContentList{ - public static Block conveyor, steelconveyor, pulseconveyor, router, multiplexer, junction, bridgeconveyor, laserconveyor, sorter, splitter, overflowgate; + public static Block conveyor, steelconveyor, pulseconveyor, router, multiplexer, junction, + bridgeconveyor, laserconveyor, sorter, splitter, overflowgate, massdriver; @Override public void load() { @@ -51,5 +52,11 @@ public class DistributionBlocks extends BlockList implements ContentList{ splitter = new Splitter("splitter"); overflowgate = new OverflowGate("overflowgate"); + + massdriver = new MassDriver("mass-driver"){{ + size = 3; + itemCapacity = 80; + range = 300f; + }}; } } diff --git a/core/src/io/anuke/mindustry/content/bullets/TurretBullets.java b/core/src/io/anuke/mindustry/content/bullets/TurretBullets.java index fa7c235420..529a2b3720 100644 --- a/core/src/io/anuke/mindustry/content/bullets/TurretBullets.java +++ b/core/src/io/anuke/mindustry/content/bullets/TurretBullets.java @@ -3,29 +3,34 @@ package io.anuke.mindustry.content.bullets; import com.badlogic.gdx.graphics.Color; import io.anuke.mindustry.content.Liquids; import io.anuke.mindustry.content.StatusEffects; +import io.anuke.mindustry.content.fx.BlockFx; import io.anuke.mindustry.content.fx.BulletFx; import io.anuke.mindustry.content.fx.EnvironmentFx; import io.anuke.mindustry.content.fx.Fx; +import io.anuke.mindustry.entities.Damage; import io.anuke.mindustry.entities.bullet.Bullet; import io.anuke.mindustry.entities.bullet.BulletType; import io.anuke.mindustry.entities.bullet.LiquidBulletType; -import io.anuke.mindustry.entities.Damage; import io.anuke.mindustry.entities.effect.Fire; import io.anuke.mindustry.entities.effect.Lightning; +import io.anuke.mindustry.gen.CallEntity; import io.anuke.mindustry.graphics.Palette; import io.anuke.mindustry.type.ContentList; +import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.Tile; +import io.anuke.mindustry.world.blocks.distribution.MassDriver.DriverBulletData; import io.anuke.ucore.core.Effects; 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.util.Angles; import io.anuke.ucore.util.Mathf; import static io.anuke.mindustry.Vars.world; public class TurretBullets extends BulletList implements ContentList { - public static BulletType fireball, basicFlame, lancerLaser, fuseShot, waterShot, cryoShot, lavaShot, oilShot, lightning; + public static BulletType fireball, basicFlame, lancerLaser, fuseShot, waterShot, cryoShot, lavaShot, oilShot, lightning, driverBolt; @Override public void load() { @@ -171,5 +176,96 @@ public class TurretBullets extends BulletList implements ContentList { Lightning.create(b.getTeam(), hiteffect, Palette.lancerLaser, damage, b.x, b.y, b.angle(), 30); } }; + + driverBolt = new BulletType(5f, 20) { + { + collidesTiles = false; + lifetime = 200f; + despawneffect = BlockFx.smeltsmoke; + hiteffect = BulletFx.hitBulletBig; + drag = 0.02f; + } + + @Override + public void draw(Bullet b) { + Draw.color(Color.LIGHT_GRAY); + Fill.square(b.x, b.y, 3f, b.angle()); + + Draw.color(Palette.lighterOrange); + Fill.square(b.x, b.y, 2f, b.angle()); + Draw.reset(); + } + + @Override + public void update(Bullet b) { + //data MUST be an instance of DriverBulletData + if(!(b.getData() instanceof DriverBulletData)){ + hit(b); + return; + } + + float hitDst = 7f; + + DriverBulletData data = (DriverBulletData)b.getData(); + + //if the target is dead, just keep flying until the bullet explodes + if(data.to.isDead()){ + return; + } + + float baseDst = data.from.distanceTo(data.to); + float dst1 = b.distanceTo(data.from); + float dst2 = b.distanceTo(data.to); + + boolean intersect = false; + + //bullet has gone past the destination point: but did it intersect it? + if(dst1 > baseDst){ + float angleTo = b.angleTo(data.to); + float baseAngle = data.to.angleTo(data.from); + + //if angles are nearby, then yes, it did + if(Mathf.angNear(angleTo, baseAngle, 2f)){ + intersect = true; + //snap bullet position back; this is used for low-FPS situations + b.set(data.to.x + Angles.trnsx(baseAngle, hitDst), data.to.y + Angles.trnsy(baseAngle, hitDst)); + } + } + + //if on course and it's in range of the target + if(Math.abs(dst1 + dst2 - baseDst) < 4f && dst2 <= hitDst){ + intersect = true; + } //else, bullet has gone off course, does not get recieved. + + if(intersect){ + data.to.handlePayload(b, data); + } + } + + @Override + public void despawned(Bullet b) { + super.despawned(b); + + if(!(b.getData() instanceof DriverBulletData)) return; + + DriverBulletData data = (DriverBulletData)b.getData(); + data.to.isRecieving = false; + + for(int i = 0; i < data.items.length; i ++){ + int amountDropped = Mathf.random(0, data.items[i]); + if(amountDropped > 0){ + float angle = b.angle() + Mathf.range(100f); + float vs = Mathf.random(0f, 4f); + CallEntity.createItemDrop(Item.getByID(i), amountDropped, b.x, b.y, Angles.trnsx(angle, vs), Angles.trnsy(angle, vs)); + } + } + } + + @Override + public void hit(Bullet b, float hitx, float hity) { + super.hit(b, hitx, hity); + despawned(b); + } + }; } } diff --git a/core/src/io/anuke/mindustry/entities/Player.java b/core/src/io/anuke/mindustry/entities/Player.java index da4e1b6b1a..17f33332f4 100644 --- a/core/src/io/anuke/mindustry/entities/Player.java +++ b/core/src/io/anuke/mindustry/entities/Player.java @@ -628,6 +628,7 @@ public class Player extends Unit implements BuilderTrait, CarryTrait { if(local){ int index = stream.readByte(); players[index].readSaveSuper(stream); + dead = false; } } diff --git a/core/src/io/anuke/mindustry/entities/bullet/Bullet.java b/core/src/io/anuke/mindustry/entities/bullet/Bullet.java index 69ec44dcaa..b7d2509016 100644 --- a/core/src/io/anuke/mindustry/entities/bullet/Bullet.java +++ b/core/src/io/anuke/mindustry/entities/bullet/Bullet.java @@ -30,6 +30,7 @@ public class Bullet extends BulletEntity implements TeamTrait, SyncT private static Vector2 vector = new Vector2(); private Team team; + private Object data; private boolean supressCollision; public Timer timer = new Timer(3); @@ -43,9 +44,14 @@ public class Bullet extends BulletEntity implements TeamTrait, SyncT } public static void create (BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl){ + create(type, owner, team, x, y, angle, velocityScl, null); + } + + public static void create (BulletType type, Entity owner, Team team, float x, float y, float angle, float velocityScl, Object data){ Bullet bullet = Pools.obtain(Bullet.class); bullet.type = type; bullet.owner = owner; + bullet.data = data; bullet.velocity.set(0, type.speed).setAngle(angle).scl(velocityScl); bullet.velocity.add(owner instanceof VelocityTrait ? ((VelocityTrait)owner).getVelocity() : Vector2.Zero); @@ -90,6 +96,10 @@ public class Bullet extends BulletEntity implements TeamTrait, SyncT time += add; } + public Object getData() { + return data; + } + @Override public int getTypeID() { return typeID; @@ -185,6 +195,7 @@ public class Bullet extends BulletEntity implements TeamTrait, SyncT super.reset(); timer.clear(); team = null; + data = null; } @Override diff --git a/core/src/io/anuke/mindustry/entities/effect/ItemDrop.java b/core/src/io/anuke/mindustry/entities/effect/ItemDrop.java index e8dd2d8557..1f145d2d97 100644 --- a/core/src/io/anuke/mindustry/entities/effect/ItemDrop.java +++ b/core/src/io/anuke/mindustry/entities/effect/ItemDrop.java @@ -55,6 +55,11 @@ public class ItemDrop extends SolidEntity implements SyncTrait, DrawTrait, Veloc return drop; } + @Remote(called = Loc.server, in = In.entities) + public static void createItemDrop(Item item, int amount, float x, float y, float velocityX, float velocityY){ + create(item, amount, x, y, 0).getVelocity().set(velocityX, velocityY); + } + @Remote(called = Loc.server, in = In.entities) public static void onPickup(int itemid){ itemGroup.removeByID(itemid); diff --git a/core/src/io/anuke/mindustry/game/TeamInfo.java b/core/src/io/anuke/mindustry/game/TeamInfo.java index 241b65ab37..ee92297f92 100644 --- a/core/src/io/anuke/mindustry/game/TeamInfo.java +++ b/core/src/io/anuke/mindustry/game/TeamInfo.java @@ -77,8 +77,7 @@ public class TeamInfo { } /**Returns a set of all teams that are enemies of this team. - * For teams not active, an empty set is returned. - */ + * For teams not active, an empty set is returned.*/ public ObjectSet enemyDataOf(Team team) { boolean ally = allies.contains(team); boolean enemy = enemies.contains(team); diff --git a/core/src/io/anuke/mindustry/world/blocks/defense/DeflectorWall.java b/core/src/io/anuke/mindustry/world/blocks/defense/DeflectorWall.java index 67db17e2af..fceba0722b 100644 --- a/core/src/io/anuke/mindustry/world/blocks/defense/DeflectorWall.java +++ b/core/src/io/anuke/mindustry/world/blocks/defense/DeflectorWall.java @@ -25,7 +25,6 @@ public class DeflectorWall extends Wall { public DeflectorWall(String name) { super(name); - update = false; } @Override diff --git a/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java b/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java index 3e2f71eaac..71f3e080ca 100644 --- a/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java +++ b/core/src/io/anuke/mindustry/world/blocks/distribution/MassDriver.java @@ -1,13 +1,280 @@ package io.anuke.mindustry.world.blocks.distribution; +import com.badlogic.gdx.utils.ObjectSet; +import com.badlogic.gdx.utils.Pool.Poolable; +import com.badlogic.gdx.utils.Pools; +import io.anuke.annotations.Annotations.Loc; +import io.anuke.annotations.Annotations.Remote; +import io.anuke.mindustry.content.bullets.TurretBullets; +import io.anuke.mindustry.content.fx.BlockFx; +import io.anuke.mindustry.content.fx.ShootFx; +import io.anuke.mindustry.entities.Player; +import io.anuke.mindustry.entities.TileEntity; +import io.anuke.mindustry.entities.bullet.Bullet; +import io.anuke.mindustry.gen.CallBlocks; +import io.anuke.mindustry.gen.CallEntity; +import io.anuke.mindustry.graphics.Layer; +import io.anuke.mindustry.graphics.Palette; +import io.anuke.mindustry.net.In; +import io.anuke.mindustry.type.Item; import io.anuke.mindustry.world.Block; +import io.anuke.mindustry.world.Tile; +import io.anuke.ucore.core.Effects; +import io.anuke.ucore.core.Effects.Effect; +import io.anuke.ucore.core.Timers; +import io.anuke.ucore.graphics.Draw; +import io.anuke.ucore.graphics.Lines; +import io.anuke.ucore.util.Angles; +import io.anuke.ucore.util.Mathf; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import static io.anuke.mindustry.Vars.*; public class MassDriver extends Block { protected float range; + protected float rotateSpeed = 0.04f; + protected float translation = 7f; + //minimum amount of items needed to begin firing + protected int minDistribute = 10; + protected float knockback = 4f; + protected float reloadTime = 80f; + protected Effect shootEffect = ShootFx.shootBig2; + protected Effect smokeEffect = ShootFx.shootBigSmoke2; + protected Effect recieveEffect = BlockFx.smeltsmoke; + protected float shake = 3f; public MassDriver(String name) { super(name); update = true; solid = true; + configurable = true; + hasItems = true; + itemCapacity = 50; + layer = Layer.turret; + hasPower = true; + } + + @Override + public void update(Tile tile) { + MassDriverEntity entity = tile.entity(); + + Tile link = world.tile(entity.link); + + if(entity.isUnloading){ + tryDump(tile); + if(entity.items.totalItems() <= 0){ + entity.isUnloading = false; + } + } + + if(entity.reload > 0f){ + entity.reload = Mathf.clamp(entity.reload - Timers.delta()/reloadTime); + } + + if(!entity.isRecieving) { + + if (entity.waiting.size > 0) { //accepting takes priority over shooting + Tile waiter = entity.waiting.first(); + + entity.rotation = Mathf.slerpDelta(entity.rotation, tile.angleTo(waiter), rotateSpeed); + }else if (tile.entity.items.totalItems() >= minDistribute && + linkValid(tile) && //only fire when at least at half-capacity and power + tile.entity.power.amount >= powerCapacity && + link.block().itemCapacity - link.entity.items.totalItems() >= minDistribute && entity.reload <= 0.0001f) { + + MassDriverEntity other = link.entity(); + other.waiting.add(tile); + + float target = tile.angleTo(link); + + entity.rotation = Mathf.slerpDelta(entity.rotation, target, rotateSpeed); + + if (Mathf.angNear(entity.rotation, target, 1f) && + Mathf.angNear(other.rotation, target + 180f, 1f)) { + CallBlocks.onMassDriverFire(tile, link); + } + } + } + + entity.waiting.clear(); + } + + @Override + public void drawLayer(Tile tile) { + MassDriverEntity entity = tile.entity(); + + Draw.rect(name + "-turret", + tile.drawx() + Angles.trnsx(entity.rotation + 180f, entity.reload * knockback), + tile.drawy() + Angles.trnsy(entity.rotation + 180f, entity.reload * knockback), + entity.rotation - 90); + } + + @Override + public void drawConfigure(Tile tile) { + super.drawConfigure(tile); + + MassDriverEntity entity = tile.entity(); + + if(linkValid(tile)){ + Tile target = world.tile(entity.link); + + Draw.color(Palette.place); + Lines.square(target.drawx(), target.drawy(), + target.block().size * tilesize / 2f + 1f); + Draw.reset(); + } + + Draw.color(Palette.accent); + Lines.dashCircle(tile.drawx(), tile.drawy(), range); + Draw.color(); + } + + @Override + public boolean onConfigureTileTapped(Tile tile, Tile other){ + MassDriverEntity entity = tile.entity(); + + if(entity.link == other.packedPosition()) { + CallBlocks.linkMassDriver(null, tile, -1); + return false; + }else if(other.block() instanceof MassDriver && other.distanceTo(tile) <= range){ + CallBlocks.linkMassDriver(null, tile, other.packedPosition()); + return false; + } + + return true; + } + + @Override + public boolean acceptItem(Item item, Tile tile, Tile source) { + return tile.entity.items.totalItems() < itemCapacity; + } + + @Override + public TileEntity getEntity() { + return new MassDriverEntity(); + } + + protected boolean linkValid(Tile tile){ + MassDriverEntity entity = tile.entity(); + if(entity.link == -1) return false; + Tile link = world.tile(entity.link); + + return link != null && link.block() instanceof MassDriver && tile.distanceTo(link) <= range; + } + + @Remote(targets = Loc.both, called = Loc.server, in = In.blocks, forward = true) + public static void linkMassDriver(Player player, Tile tile, int position){ + MassDriverEntity entity = tile.entity(); + + //called in main thread to prevent issues + threads.run(() -> entity.link = position); + } + + @Remote(called = Loc.server, in = In.blocks) + public static void onMassDriverFire(Tile tile, Tile target){ + //just in case the client has invalid data + if(!(tile.entity instanceof MassDriverEntity) || !(target.entity instanceof MassDriverEntity)) return; + + MassDriver driver = (MassDriver)tile.block(); + + MassDriverEntity entity = tile.entity(); + MassDriverEntity other = target.entity(); + + entity.reload = 1f; + + DriverBulletData data = Pools.obtain(DriverBulletData.class); + data.from = entity; + data.to = other; + System.arraycopy(entity.items.items, 0, data.items, 0, data.items.length); + entity.items.clear(); + + float angle = tile.angleTo(target); + + other.isRecieving = true; + Bullet.create(TurretBullets.driverBolt, entity, entity.getTeam(), + tile.drawx() + Angles.trnsx(angle, driver.translation), tile.drawy() + Angles.trnsy(angle, driver.translation), + angle, 1f, data); + + Effects.effect(driver.shootEffect, tile.drawx() + Angles.trnsx(angle, driver.translation), + tile.drawy() + Angles.trnsy(angle, driver.translation), angle); + + Effects.effect(driver.smokeEffect, tile.drawx() + Angles.trnsx(angle, driver.translation), + tile.drawy() + Angles.trnsy(angle, driver.translation), angle); + + Effects.shake(driver.shake, driver.shake, entity); + } + + public class MassDriverEntity extends TileEntity{ + public int link = -1; + public float rotation = 90; + //set of tiles that currently want to distribute to this tile + public ObjectSet waiting = new ObjectSet<>(); + //whether this mass driver is waiting for a bullet to hit it and deliver items + public boolean isRecieving; + //whether this driver just recieved some items and is now unloading + public boolean isUnloading; + + public float reload = 0f; + + public void handlePayload(Bullet bullet, DriverBulletData data){ + int totalItems = items.totalItems(); + + //add all the items possible + for(int i = 0; i < data.items.length; i ++){ + int maxAdd = Math.min(data.items[i], itemCapacity - totalItems); + items.items[i] += maxAdd; + data.items[i] -= maxAdd; + totalItems += maxAdd; + + if(totalItems >= itemCapacity){ + break; + } + } + + //drop all items remaining on the ground + for(int i = 0; i < data.items.length; i ++){ + int amountDropped = Mathf.random(0, data.items[i]); + if(amountDropped > 0){ + float angle = Mathf.range(180f); + float vs = Mathf.random(0f, 4f); + CallEntity.createItemDrop(Item.getByID(i), amountDropped, bullet.x, bullet.y, Angles.trnsx(angle, vs), Angles.trnsy(angle, vs)); + } + } + + reload = 1f; + Effects.shake(shake, shake, this); + Effects.effect(recieveEffect, bullet); + + isRecieving = false; + bullet.remove(); + + if(!linkValid(tile)){ + isUnloading = true; + } + } + + @Override + public void write(DataOutputStream stream) throws IOException { + stream.writeInt(link); + } + + @Override + public void read(DataInputStream stream) throws IOException { + link = stream.readInt(); + } + } + + public static class DriverBulletData implements Poolable{ + public MassDriverEntity from, to; + public int[] items = new int[Item.all().size]; + + @Override + public void reset() { + from = null; + to = null;; + } } }