package pneumaticCraft.common;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import net.minecraft.block.Block;
import net.minecraft.block.BlockGrass;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.monster.EntityGolem;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.monster.EntitySlime;
import net.minecraft.entity.passive.EntitySquid;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.MovingObjectPosition;
import net.minecraft.util.StatCollector;
import net.minecraft.world.ChunkPosition;
import net.minecraft.world.World;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.event.ServerChatEvent;
import net.minecraftforge.event.entity.EntityEvent.EntityConstructing;
import net.minecraftforge.event.entity.living.EnderTeleportEvent;
import net.minecraftforge.event.entity.living.LivingDeathEvent;
import net.minecraftforge.event.entity.living.LivingSetAttackTargetEvent;
import net.minecraftforge.event.entity.player.BonemealEvent;
import net.minecraftforge.event.entity.player.EntityItemPickupEvent;
import net.minecraftforge.event.entity.player.FillBucketEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.event.world.ExplosionEvent;
import net.minecraftforge.event.world.WorldEvent;
import net.minecraftforge.fluids.FluidStack;
import pneumaticCraft.api.PneumaticRegistry;
import pneumaticCraft.api.block.IPneumaticWrenchable;
import pneumaticCraft.api.client.pneumaticHelmet.EntityTrackEvent;
import pneumaticCraft.api.client.pneumaticHelmet.InventoryTrackEvent;
import pneumaticCraft.api.drone.AmadronRetrievalEvent;
import pneumaticCraft.api.drone.DroneConstructingEvent;
import pneumaticCraft.api.drone.DroneSuicideEvent;
import pneumaticCraft.api.item.IPressurizable;
import pneumaticCraft.client.gui.widget.GuiKeybindCheckBox;
import pneumaticCraft.client.render.pneumaticArmor.EntityTrackUpgradeHandler;
import pneumaticCraft.client.render.pneumaticArmor.HUDHandler;
import pneumaticCraft.client.render.pneumaticArmor.hacking.HackableHandler;
import pneumaticCraft.client.render.pneumaticArmor.hacking.entity.HackableEnderman;
import pneumaticCraft.common.ai.IDroneBase;
import pneumaticCraft.common.block.Blockss;
import pneumaticCraft.common.block.pneumaticPlants.BlockPlants;
import pneumaticCraft.common.block.pneumaticPlants.BlockPneumaticPlantBase;
import pneumaticCraft.common.config.Config;
import pneumaticCraft.common.entity.EntityProgrammableController;
import pneumaticCraft.common.entity.living.EntityDrone;
import pneumaticCraft.common.fluid.Fluids;
import pneumaticCraft.common.item.ItemAmadronTablet;
import pneumaticCraft.common.item.ItemMachineUpgrade;
import pneumaticCraft.common.item.ItemPlasticPlants;
import pneumaticCraft.common.item.ItemPneumaticArmor;
import pneumaticCraft.common.item.Itemss;
import pneumaticCraft.common.network.NetworkHandler;
import pneumaticCraft.common.network.PacketPlaySound;
import pneumaticCraft.common.network.PacketSetMobTarget;
import pneumaticCraft.common.recipes.AmadronOffer;
import pneumaticCraft.common.recipes.AmadronOfferCustom;
import pneumaticCraft.common.recipes.AmadronOfferManager;
import pneumaticCraft.common.remote.GlobalVariableManager;
import pneumaticCraft.common.thirdparty.ModInteractionUtilImplementation;
import pneumaticCraft.common.tileentity.TileEntityProgrammer;
import pneumaticCraft.common.util.PneumaticCraftUtils;
import pneumaticCraft.lib.TileEntityConstants;
import cpw.mods.fml.client.FMLClientHandler;
import cpw.mods.fml.common.eventhandler.Event.Result;
import cpw.mods.fml.common.eventhandler.EventPriority;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class EventHandlerPneumaticCraft{
private static ItemStack IRON_INGOT = new ItemStack(Items.iron_ingot);
private static ItemStack IRON_BLOCK = new ItemStack(Blocks.iron_block);
@SubscribeEvent
public void handleIronExplosions(ExplosionEvent.Detonate event){
Iterator<Entity> iterator = event.getAffectedEntities().iterator();
while(iterator.hasNext()) {
Entity entity = iterator.next();
if(entity instanceof EntityItem) {
ItemStack stack = ((EntityItem)entity).getEntityItem();
if(stack != null && !entity.isDead && PneumaticCraftUtils.isSameOreDictStack(stack, IRON_INGOT) || PneumaticCraftUtils.isSameOreDictStack(stack, IRON_BLOCK)) {
Random rand = new Random();
if(stack.stackSize >= 3 || rand.nextDouble() >= Config.configCompressedIngotLossRate / 100D) {
Item newItem = PneumaticCraftUtils.isSameOreDictStack(stack, IRON_INGOT) ? Itemss.ingotIronCompressed : Item.getItemFromBlock(Blockss.compressedIron);
ItemStack newStack = new ItemStack(newItem, stack.stackSize, stack.getItemDamage());
if(stack.stackSize >= 3) {
newStack.stackSize = (int)(stack.stackSize * (rand.nextDouble() * Math.min(Config.configCompressedIngotLossRate * 0.02D, 0.2D) + (Math.max(0.9D, 1D - Config.configCompressedIngotLossRate * 0.01D) - Config.configCompressedIngotLossRate * 0.01D)));
}
((EntityItem)entity).setEntityItemStack(newStack);
iterator.remove();
for(EntityPlayer player : (List<EntityPlayer>)event.world.getEntitiesWithinAABB(EntityPlayer.class, AxisAlignedBB.getBoundingBox(event.explosion.explosionX - 32, event.explosion.explosionY - 32, event.explosion.explosionZ - 32, event.explosion.explosionX + 32, event.explosion.explosionY + 32, event.explosion.explosionZ + 32))) {
AchievementHandler.giveAchievement(player, newStack);
}
}
}
}
}
}
@SubscribeEvent
public void onEntityConstruction(EntityConstructing event){
HackableHandler.onEntityConstruction(event.entity);
ItemPlasticPlants.onEntityConstruction(event.entity);
if(event.entity instanceof IDroneBase) {
MinecraftForge.EVENT_BUS.post(new DroneConstructingEvent((IDroneBase)event.entity));
}
}
@SubscribeEvent
public void onPlayerPickup(EntityItemPickupEvent event){
if(event.item != null && event.entityPlayer != null) AchievementHandler.giveAchievement(event.entityPlayer, event.item.getEntityItem());
}
// add slime seeds as mobdrop to Slimes.
@SubscribeEvent
public void onEntityDeath(LivingDeathEvent event){
if(!event.entity.worldObj.isRemote) {
if(Config.enableSlimeSeedDrop && event.entity instanceof EntitySlime && Math.random() < 0.1D) {
ItemPlasticPlants.markInactive(event.entity.entityDropItem(new ItemStack(Itemss.plasticPlant, 1, ItemPlasticPlants.SLIME_PLANT_DAMAGE), 0));
} else if(Config.enableCreeperSeedDrop && event.entity instanceof EntityCreeper && Math.random() < 0.05D) {
if(Config.enableCreeperDropExplosion) event.entity.worldObj.createExplosion(event.entity, event.entity.posX, event.entity.posY + event.entityLiving.height / 2D, event.entity.posZ, 0.5F, event.entity.worldObj.getGameRules().getGameRuleBooleanValue("mobGriefing"));
int dropAmount = (int)(Math.random() * 3D) + 1;
for(int i = 0; i < dropAmount; i++)
ItemPlasticPlants.markInactive(event.entity.entityDropItem(new ItemStack(Itemss.plasticPlant, 1, ItemPlasticPlants.CREEPER_PLANT_DAMAGE), 0));
} else if(Config.enableSquidSeedDrop && event.entity instanceof EntitySquid && Math.random() < 0.05D) {
ItemPlasticPlants.markInactive(event.entity.entityDropItem(new ItemStack(Itemss.plasticPlant, 1, ItemPlasticPlants.SQUID_PLANT_DAMAGE), 0));
}
}
}
@SubscribeEvent(priority = EventPriority.LOWEST)
public void onEnderTeleport(EnderTeleportEvent event){
if(!HackableEnderman.onEndermanTeleport(event.entity)) {
event.setCanceled(true);
} else {
if(Config.enableEndermanSeedDrop && Math.random() < 0.05D) {
if(!event.entity.worldObj.isRemote) ItemPlasticPlants.markInactive(event.entity.entityDropItem(new ItemStack(Itemss.plasticPlant, 1, ItemPlasticPlants.ENDER_PLANT_DAMAGE), 0));
}
}
}
// bone meal event, to grow plants
@SubscribeEvent
public void onFertilization(BonemealEvent event){
if(event.world.isRemote) return; // why would we want to handle this on the client-side?
if(event.block == Blocks.netherrack || event.block == Blocks.end_stone || event.block.canSustainPlant(event.world, event.x, event.y, event.z, ForgeDirection.UP, Blocks.red_flower)) { // can bonemeal Biomes O' Plenty grass, etc.
boolean onGrass = event.block instanceof BlockGrass;
if(onGrass && Config.includePlantsOnBonemeal || !onGrass && Config.allowDirtBonemealing) {
// we'll try to spawn plants in a 5x5 area which is centered on the block that has been bonemealed
for(int x = event.x - 2; x < event.x + 3; x++) {
for(int z = event.z - 2; z < event.z + 3; z++) {
if(event.world.isAirBlock(x, event.y + 1, z)) {
if(event.world.rand.nextInt(8) == 1) { // increase .nextInt(x) to lower the chances of spawning a plant
BlockPneumaticPlantBase trySpawn = BlockPlants.allPlants.get(event.world.rand.nextInt(BlockPlants.allPlants.size() - 1)); // select a random plant
if(trySpawn.canPlantGrowOnThisBlock(event.world.getBlock(x, event.y, z), event.world, x, event.y, z)) { // make sure that the plant we selected can grow on the soil
event.world.setBlock(x, event.y + (trySpawn.isPlantHanging() ? -1 : 1), z, trySpawn);
}
}
}
}
/*
* vanilla mechanics will spawn flowers etc. when bonemeal is used on grass,
* so we cannot set Result.ALLOW in this case because it would stop event-propagation
*/
if(!onGrass) event.setResult(Result.ALLOW);
}
}
}
}
@SubscribeEvent
public void FillBucket(FillBucketEvent event){
MovingObjectPosition p = event.target;
if(event.current == null || event.current.getItem() != Items.bucket || event.world.getBlockMetadata(p.blockX, p.blockY, p.blockZ) != 0) return;
ItemStack result = attemptFill(event.world, event.target);
if(result != null) {
event.result = result;
AchievementHandler.giveAchievement(event.entityPlayer, result);
event.setResult(Result.ALLOW);
}
}
private ItemStack attemptFill(World world, MovingObjectPosition p){
Block id = world.getBlock(p.blockX, p.blockY, p.blockZ);
for(Map.Entry<Block, Item> entry : Fluids.fluidBlockToBucketMap.entrySet()) {
if(id == entry.getKey()) {
world.setBlock(p.blockX, p.blockY, p.blockZ, Blocks.air);
return new ItemStack(entry.getValue());
}
}
return null;
}
@SubscribeEvent
public void onPlayerClick(PlayerInteractEvent event){
Block interactedBlock = event.world.getBlock(event.x, event.y, event.z);
if(!event.entityPlayer.capabilities.isCreativeMode || !event.entityPlayer.canCommandSenderUseCommand(2, "securityStation")) {
if(event.action != PlayerInteractEvent.Action.RIGHT_CLICK_AIR && event.world != null && !event.world.isRemote) {
if(interactedBlock != Blockss.securityStation || event.action == PlayerInteractEvent.Action.LEFT_CLICK_BLOCK) {
ItemStack heldItem = event.entityPlayer.getCurrentEquippedItem();
boolean tryingToPlaceSecurityStation = heldItem != null && heldItem.getItem() instanceof ItemBlock && ((ItemBlock)heldItem.getItem()).field_150939_a == Blockss.securityStation;
int blockingStations = PneumaticCraftUtils.getProtectingSecurityStations(event.entity.worldObj, event.x, event.y, event.z, event.entityPlayer, true, tryingToPlaceSecurityStation);
if(blockingStations > 0) {
event.setCanceled(true);
event.entityPlayer.addChatComponentMessage(new ChatComponentText(StatCollector.translateToLocalFormatted(tryingToPlaceSecurityStation ? "message.securityStation.stationPlacementPrevented" : "message.securityStation.accessPrevented", blockingStations)));
}
}
}
}
/**
* Due to some weird quirk that causes Block#onBlockActivated not getting called on the server when the player is sneaking, this is a workaround.
*/
if(!event.isCanceled() && event.action == PlayerInteractEvent.Action.RIGHT_CLICK_BLOCK && !event.world.isRemote) {
if(event.entityPlayer.isSneaking() && (interactedBlock == Blockss.elevatorCaller || interactedBlock == Blockss.chargingStation)) {
event.setCanceled(interactedBlock.onBlockActivated(event.world, event.x, event.y, event.z, event.entityPlayer, event.face, 0, 0, 0));
} else if(event.entityPlayer.getCurrentEquippedItem() != null && ModInteractionUtilImplementation.getInstance().isModdedWrench(event.entityPlayer.getCurrentEquippedItem().getItem())) {
if(interactedBlock instanceof IPneumaticWrenchable) {
((IPneumaticWrenchable)interactedBlock).rotateBlock(event.world, event.entityPlayer, event.x, event.y, event.z, ForgeDirection.getOrientation(event.face));
}
}
}
if(!event.isCanceled() && interactedBlock == Blocks.cobblestone) {
AchievementHandler.checkFor9x9(event.entityPlayer, event.x, event.y, event.z);
}
}
/**
* Used by PneumaticHelmet
* @param event
*/
@SubscribeEvent
public void onMobTargetSet(LivingSetAttackTargetEvent event){
if(event.entity instanceof EntityCreature) {
if(!event.entity.worldObj.isRemote) {
NetworkHandler.sendToAllAround(new PacketSetMobTarget((EntityCreature)event.entity, event.target), new NetworkRegistry.TargetPoint(event.entity.worldObj.provider.dimensionId, event.entity.posX, event.entity.posY, event.entity.posZ, TileEntityConstants.PACKET_UPDATE_DISTANCE));
} else {
warnPlayerIfNecessary(event);
}
}
}
@SideOnly(Side.CLIENT)
private void warnPlayerIfNecessary(LivingSetAttackTargetEvent event){
EntityPlayer player = FMLClientHandler.instance().getClient().thePlayer;
if(event.target == player && (event.entityLiving instanceof EntityGolem || event.entityLiving instanceof EntityMob)) {
ItemStack helmetStack = player.getCurrentArmor(3);
if(helmetStack != null && helmetStack.getItem() == Itemss.pneumaticHelmet && ((IPressurizable)helmetStack.getItem()).getPressure(helmetStack) > 0 && ItemPneumaticArmor.getUpgrades(ItemMachineUpgrade.UPGRADE_ENTITY_TRACKER, helmetStack) > 0 && GuiKeybindCheckBox.trackedCheckboxes.get("pneumaticHelmet.upgrade.coreComponents").checked && GuiKeybindCheckBox.trackedCheckboxes.get("pneumaticHelmet.upgrade." + EntityTrackUpgradeHandler.UPGRADE_NAME).checked) {
HUDHandler.instance().getSpecificRenderer(EntityTrackUpgradeHandler.class).warnIfNecessary(event.entityLiving);
}
} else {
HUDHandler.instance().getSpecificRenderer(EntityTrackUpgradeHandler.class).removeTargetingEntity(event.entityLiving);
}
}
@SubscribeEvent
public void quetziMoo(ServerChatEvent event){
if(event.username.equals("Quetzz") && event.message.equals("m00")) {
for(int i = 0; i < 4; i++)
NetworkHandler.sendTo(new PacketPlaySound("mob.cow.say", event.player.posX, event.player.posY, event.player.posZ, 1, 1, true), event.player);
}
}
@SubscribeEvent
public void onWorldLoad(WorldEvent.Load event){
if(!event.world.isRemote) {
if(event.world.provider.dimensionId == 0) {
GlobalVariableManager.overworld = event.world;
event.world.loadItemData(GlobalVariableManager.class, GlobalVariableManager.DATA_KEY);
}
}
}
@SubscribeEvent
public void onEntityTracking(EntityTrackEvent event){
if(event.trackingEntity instanceof EntityProgrammableController) event.setCanceled(true);
}
@SubscribeEvent
public void onInventoryTracking(InventoryTrackEvent event){
if(event.getTileEntity() instanceof TileEntityProgrammer) event.setCanceled(true);
}
@SubscribeEvent
public void onDroneSuicide(DroneSuicideEvent event){
if(event.drone instanceof EntityDrone) {
EntityDrone drone = (EntityDrone)event.drone;
AmadronOffer offer = drone.getHandlingOffer();
if(offer != null) {
int times = drone.getOfferTimes();
if(offer.getInput() instanceof ItemStack) {
int requiredCount = ((ItemStack)offer.getInput()).stackSize * times;
for(int i = 0; i < drone.getInventory().getSizeInventory(); i++) {
if(drone.getInventory().getStackInSlot(i) != null) {
requiredCount -= drone.getInventory().getStackInSlot(i).stackSize;
}
}
if(requiredCount <= 0) {
for(int i = 0; i < drone.getInventory().getSizeInventory(); i++) {
drone.getInventory().setInventorySlotContents(i, null);
}
MinecraftForge.EVENT_BUS.post(new AmadronRetrievalEvent(event.drone));
}
} else {
int requiredCount = ((FluidStack)offer.getInput()).amount * times;
if(drone.getTank().getFluidAmount() >= requiredCount) {
MinecraftForge.EVENT_BUS.post(new AmadronRetrievalEvent(event.drone));
}
}
}
}
}
@SubscribeEvent
public void onAmadronSuccess(AmadronRetrievalEvent event){
EntityDrone drone = (EntityDrone)event.drone;
AmadronOffer offer = drone.getHandlingOffer();
boolean shouldDeliver = false;
if(offer instanceof AmadronOfferCustom) {
AmadronOffer realOffer = AmadronOfferManager.getInstance().get(offer);
if(realOffer != null) {//If we find the non-inverted offer, that means the Drone just has completed trading with a different player.
((AmadronOfferCustom)realOffer).addPayment(drone.getOfferTimes());
((AmadronOfferCustom)realOffer).addStock(-drone.getOfferTimes());
realOffer.onTrade(drone.getOfferTimes(), drone.getBuyingPlayer());
shouldDeliver = true;
}
realOffer = AmadronOfferManager.getInstance().get(((AmadronOfferCustom)offer).copy().invert());
if(realOffer != null) {//If we find the inverted offer, that means the Drone has just restocked.
((AmadronOfferCustom)realOffer).addStock(drone.getOfferTimes());
}
} else {
shouldDeliver = true;
}
if(shouldDeliver) {
ItemStack usedTablet = drone.getUsedTablet();
if(offer.getOutput() instanceof ItemStack) {
ItemStack offeringItems = (ItemStack)offer.getOutput();
int producedItems = offeringItems.stackSize * drone.getOfferTimes();
List<ItemStack> stacks = new ArrayList<ItemStack>();
while(producedItems > 0) {
ItemStack stack = offeringItems.copy();
stack.stackSize = Math.min(producedItems, stack.getMaxStackSize());
stacks.add(stack);
producedItems -= stack.stackSize;
}
ChunkPosition pos = ItemAmadronTablet.getItemProvidingLocation(usedTablet);
if(pos != null) {
World world = PneumaticCraftUtils.getWorldForDimension(ItemAmadronTablet.getItemProvidingDimension(usedTablet));
PneumaticRegistry.getInstance().deliverItemsAmazonStyle(world, pos.chunkPosX, pos.chunkPosY, pos.chunkPosZ, stacks.toArray(new ItemStack[stacks.size()]));
}
} else {
FluidStack offeringFluid = ((FluidStack)offer.getOutput()).copy();
offeringFluid.amount *= drone.getOfferTimes();
ChunkPosition pos = ItemAmadronTablet.getLiquidProvidingLocation(usedTablet);
if(pos != null) {
World world = PneumaticCraftUtils.getWorldForDimension(ItemAmadronTablet.getLiquidProvidingDimension(usedTablet));
PneumaticRegistry.getInstance().deliverFluidAmazonStyle(world, pos.chunkPosX, pos.chunkPosY, pos.chunkPosZ, offeringFluid);
}
}
}
}
}