Files
Applied-Energistics-2/src/main/java/appeng/items/tools/powered/ToolMatterCannon.java
T
2020-06-16 21:45:35 +02:00

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