459 lines
19 KiB
Java
459 lines
19 KiB
Java
/*
|
|
* This file is part of Applied Energistics 2.
|
|
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
|
|
*
|
|
* Applied Energistics 2 is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Applied Energistics 2 is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
|
|
*/
|
|
|
|
package appeng.items.tools.powered;
|
|
|
|
import java.util.List;
|
|
|
|
import javax.annotation.Nullable;
|
|
|
|
import net.minecraft.block.BlockState;
|
|
import net.minecraft.client.util.ITooltipFlag;
|
|
import net.minecraft.entity.Entity;
|
|
import net.minecraft.entity.LivingEntity;
|
|
import net.minecraft.entity.item.ItemEntity;
|
|
import net.minecraft.entity.passive.SheepEntity;
|
|
import net.minecraft.entity.player.PlayerEntity;
|
|
import net.minecraft.item.Item;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.tileentity.TileEntity;
|
|
import net.minecraft.util.*;
|
|
import net.minecraft.util.math.*;
|
|
import net.minecraft.util.text.ITextComponent;
|
|
import net.minecraft.world.World;
|
|
import net.minecraftforge.api.distmarker.Dist;
|
|
import net.minecraftforge.api.distmarker.OnlyIn;
|
|
import net.minecraftforge.items.IItemHandler;
|
|
|
|
import appeng.api.AEApi;
|
|
import appeng.api.config.Actionable;
|
|
import appeng.api.config.FuzzyMode;
|
|
import appeng.api.config.Upgrades;
|
|
import appeng.api.features.AEFeature;
|
|
import appeng.api.implementations.items.IStorageCell;
|
|
import appeng.api.storage.ICellInventoryHandler;
|
|
import appeng.api.storage.IStorageChannel;
|
|
import appeng.api.storage.channels.IItemStorageChannel;
|
|
import appeng.api.storage.data.IAEItemStack;
|
|
import appeng.api.storage.data.IItemList;
|
|
import appeng.api.util.AEColor;
|
|
import appeng.api.util.DimensionalCoord;
|
|
import appeng.core.AEConfig;
|
|
import appeng.core.AELog;
|
|
import appeng.core.AppEng;
|
|
import appeng.core.localization.PlayerMessages;
|
|
import appeng.core.sync.network.NetworkHandler;
|
|
import appeng.core.sync.packets.PacketMatterCannon;
|
|
import appeng.hooks.TickHandler;
|
|
import appeng.hooks.TickHandler.PlayerColor;
|
|
import appeng.items.contents.CellConfig;
|
|
import appeng.items.contents.CellUpgrades;
|
|
import appeng.items.misc.ItemPaintBall;
|
|
import appeng.items.tools.powered.powersink.AEBasePoweredItem;
|
|
import appeng.me.helpers.PlayerSource;
|
|
import appeng.tile.misc.TilePaint;
|
|
import appeng.util.LookDirection;
|
|
import appeng.util.Platform;
|
|
|
|
public class ToolMatterCannon extends AEBasePoweredItem implements IStorageCell<IAEItemStack> {
|
|
|
|
public ToolMatterCannon(Item.Properties props) {
|
|
super(AEConfig.instance().getMatterCannonBattery(), props);
|
|
}
|
|
|
|
@OnlyIn(Dist.CLIENT)
|
|
@Override
|
|
public void addInformation(final ItemStack stack, final World world, final List<ITextComponent> lines,
|
|
final ITooltipFlag advancedTooltips) {
|
|
super.addInformation(stack, world, lines, advancedTooltips);
|
|
|
|
final ICellInventoryHandler<IAEItemStack> cdi = AEApi.instance().registries().cell().getCellInventory(stack,
|
|
null, AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
|
|
|
|
AEApi.instance().client().addCellInformation(cdi, lines);
|
|
}
|
|
|
|
@Override
|
|
public ActionResult<ItemStack> onItemRightClick(final World w, final PlayerEntity p, final @Nullable Hand hand) {
|
|
if (this.getAECurrentPower(p.getHeldItem(hand)) > 1600) {
|
|
int shots = 1;
|
|
|
|
final CellUpgrades cu = (CellUpgrades) this.getUpgradesInventory(p.getHeldItem(hand));
|
|
if (cu != null) {
|
|
shots += cu.getInstalledUpgrades(Upgrades.SPEED);
|
|
}
|
|
|
|
final ICellInventoryHandler<IAEItemStack> inv = AEApi.instance().registries().cell().getCellInventory(
|
|
p.getHeldItem(hand), null, AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class));
|
|
if (inv != null) {
|
|
final IItemList<IAEItemStack> itemList = inv.getAvailableItems(
|
|
AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class).createList());
|
|
IAEItemStack req = itemList.getFirstItem();
|
|
if (req instanceof IAEItemStack) {
|
|
shots = Math.min(shots, (int) req.getStackSize());
|
|
for (int sh = 0; sh < shots; sh++) {
|
|
IAEItemStack aeAmmo = req.copy();
|
|
this.extractAEPower(p.getHeldItem(hand), 1600, Actionable.MODULATE);
|
|
|
|
if (Platform.isClient()) {
|
|
return new ActionResult<>(ActionResultType.SUCCESS, p.getHeldItem(hand));
|
|
}
|
|
|
|
aeAmmo.setStackSize(1);
|
|
final ItemStack ammo = aeAmmo.createItemStack();
|
|
if (ammo == null) {
|
|
return new ActionResult<>(ActionResultType.SUCCESS, p.getHeldItem(hand));
|
|
}
|
|
|
|
aeAmmo = inv.extractItems(aeAmmo, Actionable.MODULATE, new PlayerSource(p, null));
|
|
if (aeAmmo == null) {
|
|
return new ActionResult<>(ActionResultType.SUCCESS, p.getHeldItem(hand));
|
|
}
|
|
|
|
final LookDirection dir = Platform.getPlayerRay(p);
|
|
|
|
final Vec3d Vec3d = dir.getA();
|
|
final Vec3d Vec3d1 = dir.getB();
|
|
final Vec3d direction = Vec3d1.subtract(Vec3d);
|
|
direction.normalize();
|
|
|
|
final double d0 = Vec3d.x;
|
|
final double d1 = Vec3d.y;
|
|
final double d2 = Vec3d.z;
|
|
|
|
final float penetration = AEApi.instance().registries().matterCannon().getPenetration(ammo); // 196.96655f;
|
|
if (penetration <= 0) {
|
|
final ItemStack type = aeAmmo.asItemStackRepresentation();
|
|
if (type.getItem() instanceof ItemPaintBall) {
|
|
this.shootPaintBalls(type, w, p, Vec3d, Vec3d1, direction, d0, d1, d2);
|
|
}
|
|
return new ActionResult<>(ActionResultType.SUCCESS, p.getHeldItem(hand));
|
|
} else {
|
|
this.standardAmmo(penetration, w, p, Vec3d, Vec3d1, direction, d0, d1, d2);
|
|
}
|
|
}
|
|
} else {
|
|
if (Platform.isServer()) {
|
|
p.sendMessage(PlayerMessages.AmmoDepleted.get());
|
|
}
|
|
return new ActionResult<>(ActionResultType.SUCCESS, p.getHeldItem(hand));
|
|
}
|
|
}
|
|
}
|
|
return new ActionResult<>(ActionResultType.FAIL, p.getHeldItem(hand));
|
|
}
|
|
|
|
private void shootPaintBalls(final ItemStack type, final World w, final PlayerEntity p, final Vec3d Vec3d,
|
|
final Vec3d Vec3d1, final Vec3d direction, final double d0, final double d1, final double d2) {
|
|
final AxisAlignedBB bb = new AxisAlignedBB(Math.min(Vec3d.x, Vec3d1.x), Math.min(Vec3d.y, Vec3d1.y),
|
|
Math.min(Vec3d.z, Vec3d1.z), Math.max(Vec3d.x, Vec3d1.x), Math.max(Vec3d.y, Vec3d1.y),
|
|
Math.max(Vec3d.z, Vec3d1.z)).grow(16, 16, 16);
|
|
|
|
Entity entity = null;
|
|
Vec3d entityIntersection = null;
|
|
final List list = w.getEntitiesWithinAABBExcludingEntity(p, bb);
|
|
double closest = 9999999.0D;
|
|
|
|
for (int l = 0; l < list.size(); ++l) {
|
|
final Entity entity1 = (Entity) list.get(l);
|
|
|
|
if (!entity1.isAlive() && entity1 != p && !(entity1 instanceof ItemEntity)) {
|
|
if (entity1.isAlive()) {
|
|
// prevent killing / flying of mounts.
|
|
if (entity1.isRidingOrBeingRiddenBy(p)) {
|
|
continue;
|
|
}
|
|
|
|
final float f1 = 0.3F;
|
|
|
|
final AxisAlignedBB boundingBox = entity1.getBoundingBox().grow(f1, f1, f1);
|
|
final Vec3d intersection = boundingBox.rayTrace(Vec3d, Vec3d1).orElse(null);
|
|
|
|
if (intersection != null) {
|
|
final double nd = Vec3d.squareDistanceTo(intersection);
|
|
|
|
if (nd < closest) {
|
|
entity = entity1;
|
|
entityIntersection = intersection;
|
|
closest = nd;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RayTraceContext rayTraceContext = new RayTraceContext(Vec3d, Vec3d1, RayTraceContext.BlockMode.COLLIDER,
|
|
RayTraceContext.FluidMode.NONE, p);
|
|
RayTraceResult pos = w.rayTraceBlocks(rayTraceContext);
|
|
|
|
final Vec3d vec = new Vec3d(d0, d1, d2);
|
|
if (entity != null && pos.getType() != RayTraceResult.Type.MISS
|
|
&& pos.getHitVec().squareDistanceTo(vec) > closest) {
|
|
pos = new EntityRayTraceResult(entity, entityIntersection);
|
|
} else if (entity != null && pos.getType() == RayTraceResult.Type.MISS) {
|
|
pos = new EntityRayTraceResult(entity, entityIntersection);
|
|
}
|
|
|
|
try {
|
|
AppEng.proxy.sendToAllNearExcept(null, d0, d1, d2, 128, w,
|
|
new PacketMatterCannon(d0, d1, d2, (float) direction.x, (float) direction.y, (float) direction.z,
|
|
(byte) (pos.getType() == RayTraceResult.Type.MISS ? 32
|
|
: pos.getHitVec().squareDistanceTo(vec) + 1)));
|
|
} catch (final Exception err) {
|
|
AELog.debug(err);
|
|
}
|
|
|
|
if (pos.getType() != RayTraceResult.Type.MISS && type != null && type.getItem() instanceof ItemPaintBall) {
|
|
final ItemPaintBall ipb = (ItemPaintBall) type.getItem();
|
|
|
|
final AEColor col = ipb.getColor();
|
|
// boolean lit = ipb.isLumen( type );
|
|
|
|
if (pos instanceof EntityRayTraceResult) {
|
|
EntityRayTraceResult entityResult = (EntityRayTraceResult) pos;
|
|
Entity entityHit = entityResult.getEntity();
|
|
|
|
final int id = entityHit.getEntityId();
|
|
final PlayerColor marker = new PlayerColor(id, col, 20 * 30);
|
|
TickHandler.INSTANCE.getPlayerColors().put(id, marker);
|
|
|
|
if (entityHit instanceof SheepEntity) {
|
|
final SheepEntity sh = (SheepEntity) entityHit;
|
|
sh.setFleeceColor(col.dye);
|
|
}
|
|
|
|
entityHit.attackEntityFrom(DamageSource.causePlayerDamage(p), 0);
|
|
NetworkHandler.instance().sendToAll(marker.getPacket());
|
|
} else if (pos instanceof BlockRayTraceResult) {
|
|
BlockRayTraceResult blockResult = (BlockRayTraceResult) pos;
|
|
final Direction side = blockResult.getFace();
|
|
final BlockPos hitPos = blockResult.getPos().offset(side);
|
|
|
|
if (!Platform.hasPermissions(new DimensionalCoord(w, hitPos), p)) {
|
|
return;
|
|
}
|
|
|
|
final BlockState whatsThere = w.getBlockState(hitPos);
|
|
if (whatsThere.getMaterial().isReplaceable() && w.isAirBlock(hitPos)) {
|
|
AEApi.instance().definitions().blocks().paint().maybeBlock().ifPresent(paintBlock -> {
|
|
w.setBlockState(hitPos, paintBlock.getDefaultState(), 3);
|
|
});
|
|
}
|
|
|
|
final TileEntity te = w.getTileEntity(hitPos);
|
|
if (te instanceof TilePaint) {
|
|
final Vec3d hp = pos.getHitVec().subtract(hitPos.getX(), hitPos.getY(), hitPos.getZ());
|
|
((TilePaint) te).addBlot(type, side.getOpposite(), hp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void standardAmmo(float penetration, final World w, final PlayerEntity p, final Vec3d Vec3d,
|
|
final Vec3d Vec3d1, final Vec3d direction, final double d0, final double d1, final double d2) {
|
|
boolean hasDestroyed = true;
|
|
while (penetration > 0 && hasDestroyed) {
|
|
hasDestroyed = false;
|
|
|
|
final AxisAlignedBB bb = new AxisAlignedBB(Math.min(Vec3d.x, Vec3d1.x), Math.min(Vec3d.y, Vec3d1.y),
|
|
Math.min(Vec3d.z, Vec3d1.z), Math.max(Vec3d.x, Vec3d1.x), Math.max(Vec3d.y, Vec3d1.y),
|
|
Math.max(Vec3d.z, Vec3d1.z)).grow(16, 16, 16);
|
|
|
|
Entity entity = null;
|
|
Vec3d entityIntersection = null;
|
|
final List list = w.getEntitiesWithinAABBExcludingEntity(p, bb);
|
|
double closest = 9999999.0D;
|
|
|
|
for (int l = 0; l < list.size(); ++l) {
|
|
final Entity entity1 = (Entity) list.get(l);
|
|
|
|
if (entity1.isAlive() && entity1 != p && !(entity1 instanceof ItemEntity)) {
|
|
if (entity1.isAlive()) {
|
|
// prevent killing / flying of mounts.
|
|
if (entity1.isRidingOrBeingRiddenBy(p)) {
|
|
continue;
|
|
}
|
|
|
|
final float f1 = 0.3F;
|
|
|
|
final AxisAlignedBB boundingBox = entity1.getBoundingBox().grow(f1, f1, f1);
|
|
final Vec3d intersection = boundingBox.rayTrace(Vec3d, Vec3d1).orElse(null);
|
|
|
|
if (intersection != null) {
|
|
final double nd = Vec3d.squareDistanceTo(intersection);
|
|
|
|
if (nd < closest) {
|
|
entity = entity1;
|
|
entityIntersection = intersection;
|
|
closest = nd;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
RayTraceContext rayTraceContext = new RayTraceContext(Vec3d, Vec3d1, RayTraceContext.BlockMode.COLLIDER,
|
|
RayTraceContext.FluidMode.NONE, p);
|
|
final Vec3d vec = new Vec3d(d0, d1, d2);
|
|
RayTraceResult pos = w.rayTraceBlocks(rayTraceContext);
|
|
if (entity != null && pos.getType() != RayTraceResult.Type.MISS
|
|
&& pos.getHitVec().squareDistanceTo(vec) > closest) {
|
|
pos = new EntityRayTraceResult(entity, entityIntersection);
|
|
} else if (entity != null && pos.getType() == RayTraceResult.Type.MISS) {
|
|
pos = new EntityRayTraceResult(entity, entityIntersection);
|
|
}
|
|
|
|
try {
|
|
AppEng.proxy.sendToAllNearExcept(null, d0, d1, d2, 128, w,
|
|
new PacketMatterCannon(d0, d1, d2, (float) direction.x, (float) direction.y,
|
|
(float) direction.z, (byte) (pos.getType() == RayTraceResult.Type.MISS ? 32
|
|
: pos.getHitVec().squareDistanceTo(vec) + 1)));
|
|
} catch (final Exception err) {
|
|
AELog.debug(err);
|
|
}
|
|
|
|
if (pos.getType() != RayTraceResult.Type.MISS) {
|
|
final DamageSource dmgSrc = new EntityDamageSource("matter_cannon", p);
|
|
|
|
if (pos instanceof EntityRayTraceResult) {
|
|
EntityRayTraceResult entityResult = (EntityRayTraceResult) pos;
|
|
Entity entityHit = entityResult.getEntity();
|
|
|
|
final int dmg = (int) Math.ceil(penetration / 20.0f);
|
|
if (entityHit instanceof LivingEntity) {
|
|
final LivingEntity el = (LivingEntity) entityHit;
|
|
penetration -= dmg;
|
|
el.knockBack(p, 0, -direction.x, -direction.z);
|
|
// el.knockBack( p, 0, Vec3d.x,
|
|
// Vec3d.z );
|
|
el.attackEntityFrom(dmgSrc, dmg);
|
|
if (!el.isAlive()) {
|
|
hasDestroyed = true;
|
|
}
|
|
} else if (entityHit instanceof ItemEntity) {
|
|
hasDestroyed = true;
|
|
entityHit.remove();
|
|
} else if (entityHit.attackEntityFrom(dmgSrc, dmg)) {
|
|
hasDestroyed = true;
|
|
}
|
|
} else if (pos instanceof BlockRayTraceResult) {
|
|
BlockRayTraceResult blockResult = (BlockRayTraceResult) pos;
|
|
|
|
if (!AEConfig.instance().isFeatureEnabled(AEFeature.MASS_CANNON_BLOCK_DAMAGE)) {
|
|
penetration = 0;
|
|
} else {
|
|
BlockPos blockPos = blockResult.getPos();
|
|
final BlockState bs = w.getBlockState(blockPos);
|
|
|
|
final float hardness = bs.getBlockHardness(w, blockPos) * 9.0f;
|
|
if (hardness >= 0.0) {
|
|
if (penetration > hardness
|
|
&& Platform.hasPermissions(new DimensionalCoord(w, blockPos), p)) {
|
|
hasDestroyed = true;
|
|
penetration -= hardness;
|
|
penetration *= 0.60;
|
|
w.destroyBlock(blockPos, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean isEditable(final ItemStack is) {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public IItemHandler getUpgradesInventory(final ItemStack is) {
|
|
return new CellUpgrades(is, 4);
|
|
}
|
|
|
|
@Override
|
|
public IItemHandler getConfigInventory(final ItemStack is) {
|
|
return new CellConfig(is);
|
|
}
|
|
|
|
@Override
|
|
public FuzzyMode getFuzzyMode(final ItemStack is) {
|
|
final String fz = is.getOrCreateTag().getString("FuzzyMode");
|
|
try {
|
|
return FuzzyMode.valueOf(fz);
|
|
} catch (final Throwable t) {
|
|
return FuzzyMode.IGNORE_ALL;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void setFuzzyMode(final ItemStack is, final FuzzyMode fzMode) {
|
|
is.getOrCreateTag().putString("FuzzyMode", fzMode.name());
|
|
}
|
|
|
|
@Override
|
|
public int getBytes(final ItemStack cellItem) {
|
|
return 512;
|
|
}
|
|
|
|
@Override
|
|
public int getBytesPerType(final ItemStack cellItem) {
|
|
return 8;
|
|
}
|
|
|
|
@Override
|
|
public int getTotalTypes(final ItemStack cellItem) {
|
|
return 1;
|
|
}
|
|
|
|
@Override
|
|
public boolean isBlackListed(final ItemStack cellItem, final IAEItemStack requestedAddition) {
|
|
final float pen = AEApi.instance().registries().matterCannon()
|
|
.getPenetration(requestedAddition.createItemStack());
|
|
if (pen > 0) {
|
|
return false;
|
|
}
|
|
|
|
if (requestedAddition.getItem() instanceof ItemPaintBall) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean storableInStorageCell() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean isStorageCell(final ItemStack i) {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public double getIdleDrain() {
|
|
return 0.5;
|
|
}
|
|
|
|
@Override
|
|
public IStorageChannel<IAEItemStack> getChannel() {
|
|
return AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class);
|
|
}
|
|
}
|