<?php

namespace bedwars\event;

use pocketmine\event\Listener;

use pocketmine\Player;

use pocketmine\event\player\PlayerInteractEvent;
use pocketmine\event\block\BlockBreakEvent;
use pocketmine\event\player\PlayerMoveEvent;
use pocketmine\event\player\PlayerItemConsumeEvent;
use pocketmine\event\player\PlayerDropItemEvent;

use pocketmine\inventory\PlayerInventory;

use pocketmine\event\inventory\InventoryTransactionEvent;
use pocketmine\event\inventory\InventoryPickupItemEvent;
use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityExplodeEvent;
use pocketmine\event\entity\EntityInventoryChangeEvent;

use pocketmine\event\block\BlockPlaceEvent;

use pocketmine\event\player\PlayerJoinEvent;
use pocketmine\event\player\PlayerQuitEvent;

use pocketmine\level\sound\ExpPickupSound;
use pocketmine\level\sound\SpellSound;
use pocketmine\level\sound\ExplodeSound;
use pocketmine\level\sound\EndermanTeleportSound;
use pocketmine\level\sound\TNTPrimeSound;
use pocketmine\level\sound\FizzSound;

use pocketmine\level\particle\ExplodeParticle;

use pocketmine\level\Level;

use pocketmine\inventory\FakeBlockMenu;

use pocketmine\block\Block;
use pocketmine\item\Item;

use pocketmine\math\Vector3;

use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\IntTag;

use pocketmine\entity\Entity;
use pocketmine\entity\Effect;
use pocketmine\entity\PrimedTNT;

use bedwars\entity\FireBall;
use bedwars\entity\EnderPearl;

use pocketmine\utils\Random;

use bedwars\util\Team;
use bedwars\BedWars;
use bedwars\game\Game;
use bedwars\inventory\Inventory;
use bedwars\util\VoxelRayTrace;

class Event implements Listener {

	/** @var BedWars */
	private $bedwars;

	/** @var array */
    private $players = array();

    /** @var array */
    private $placedBlocks = array();

    /** @var array */
    private $hits = array();

    /** @var array */
    private $useItem = [];

	/**
	* @param BedWars $plugin
	*/
	 public function __construct(BedWars $plugin) {
        $this->plugin = $plugin;

        $this->plugin->getServer()->getPluginManager()->registerEvents($this, $this->plugin);
    }
    
    /**
     * @param Player $player
     * @param string $type
     * @param bool $value
     */
    public function setActive(Player $player, string $type, $team, int $pos = 1) {
        $this->players[$player->getName()] = array($type, $team, $pos);
    }
    
   /**
    * @return string|null
    */
    public function getActive(Player $player) {
        if (isset($this->players[$player->getName()])) {
        	return $this->players[$player->getName()];
        } else {
        	return null;
        }
    }

    /**
     * @param EntityExplodeEvent $event
     * 
     * @return void
     */
    public function onExplode(EntityExplodeEvent $event) {
        $entity = $event->getEntity();
        $game = $this->plugin->getGame($entity, true);
            
        if (!($game instanceof Game)) {
            return false;
        }
        
        $blocks = array_filter($event->getBlockList(), function (Block $block) use($game) : bool {
            return isset($game->placedBlocks[$block->add(0)->__toString()]);
        });

        /** @var Block $block */
        foreach($blocks as $hash => $block) {
            if (!isset($blocks[$hash])) {
                continue; // elementos excluídos dentro do iterator (loop) são iteráveis no loop de qualquer forma...
            }
            
            if($block->getId() !== Block::GLASS && $block->getId() !== Block::BED_BLOCK) {
                $found = false;
                $_blocks = [];

                foreach(VoxelRayTrace::betweenPoints($block, $entity) as $point) {
                    if ($entity->getLevel()->getBlock($point)->getId() === Block::GLASS) {
                        $found = true;
                        break;
                    }
                    $_blocks[] = Level::blockHash($point->x, $point->y, $point->z);
                }
                
                if ($found && count($_blocks) > 0) {
                    foreach($_blocks as $_hash) unset($blocks[$_hash]);
                }
            } else {
                unset($blocks[$hash]);
            }
        }
        $event->setBlockList($blocks);
    }

    
    /**
    * @param PlayerInteractEvent $event 
    */
    public function move(PlayerMoveEvent $event) {
        $player = $event->getPlayer();
        $game = $this->plugin->getGame($player);

        if (!($game instanceof Game)) {
        	return false;
        }
        
        $playerTeam = $game->getTeam($player->getName());
        
        foreach ($game->teams as $name => $team) {
            if ($playerTeam->getName() == $name) {
                continue;
            }
            
            $bed = explode(":", $game->defaultTeams[$name]["beds"]);
            $vector = new Vector3($bed[0], $bed[1], $bed[2]);
            
            if ($player->distance($vector) <= 12) {
                $level = $game->getUpgradeLevel($name, 'trap');
                
                if ($level > 0) {
                    if ($team->canUseTrap()) {
                        $team->useTrap($level);
                        
                        $effect = Effect::getEffect(15);
                        $effect->setDuration(90);
                        $effect->setAmplifier(5);
                        $effect->setVisible(true);
                        $player->addEffect($effect);
                        
                        $effect = Effect::getEffect(2);
                        $effect->setDuration(90);
                        $effect->setAmplifier(1);
                        $effect->setVisible(true);
                        $player->addEffect($effect);
                        
                        $player->sendTip("§l§cTRAP HAS BEEN ACTIVATED!§r" . str_repeat("§r\n", 5));
                        $player->level->addSound((new EndermanTeleportSound($player)), [$player]);
                        
                        $message = "§l§cTRAP ACTIVATED!§r" . str_repeat("§r\n", 5);
                        
                        foreach ($team->getPlayers() as $pplayer) {
                            $pplayer->sendTip($message);
                            $pplayer->level->addSound((new EndermanTeleportSound($pplayer)), [$pplayer]);
                        }
                        break;
                    }
                }
            }
        }
    }

    /**
    * @param Player    $player
    * @param directory $projectile
    */
    public function getProjectile(Player $player, $projectile) {
        $nbt = new CompoundTag("", [
            "Pos" => new ListTag("Pos", [
                new DoubleTag(0, $player->x),
                new DoubleTag(1, $player->y + $player->getEyeHeight()),
                new DoubleTag(2, $player->z)
            ]),
            "Motion" => new ListTag("Motion", [
                new DoubleTag(0, -sin($player->yaw / 180 * M_PI) * cos($player->pitch / 180 * M_PI)),
                new DoubleTag(1, -sin($player->pitch / 180 * M_PI)),
                new DoubleTag(2, cos($player->yaw / 180 * M_PI) * cos($player->pitch / 180 * M_PI))
            ]),
            "Rotation" => new ListTag("Rotation", [
                new FloatTag(0, $player->yaw),
                new FloatTag(1, $player->pitch)
            ])
        ]);

        $f = 1.5;
        $projectile = new $projectile($player->chunk, $nbt, $player);
        $projectile->setMotion($projectile->getMotion()->multiply($f));
        return $projectile;
    }

    /**
    * @param Player $player
    * @param string $type
    */
    public function canUseItem(Player $player, string $type) : bool {
        if (isset($this->useItem[$player->getName()])) {
            if (isset($this->useItem[$player->getName()][$type])) {
                $timed = $this->useItem[$player->getName()][$type];

                if ((time() - $timed) >= 5) {
                    return true;
                } else {
                    return false;
                }
            } else {
                return true;
            }
        } else {
            return true;
        }
    }

    /**
    * @param Player $player
    * @param string $type
    */
    public function getTimeItem(Player $player, string $type) : int {
        if (isset($this->useItem[$player->getName()])) {
            if (isset($this->useItem[$player->getName()][$type])) {
                $timed = time();
                $timed -= $this->useItem[$player->getName()][$type];
                $timed = (5 - $timed);
                return $timed;
            } else {
                return 0;
            }
        } else {
            return 0;
        }
    }

    /**
    * @param PlayerJoinEvent $event 
    */
    public function onJoin(PlayerJoinEvent $event) {
        $player = $event->getPlayer();
        $key = $player->getName();
        
        $player->customInventory = null;

        if ($this->plugin->topWins->exists($key) === false) {
            $this->plugin->topWins->set($key, 0);
            $this->plugin->topWins->save(true);
        }
    }

    /**
    * @param Player $player
    * @param string $type
    */
    public function setTimeItem(Player $player, string $type) {
        $this->useItem[$player->getName()][$type] = time();
    }

    /**
    * @param PlayerItemConsumeEvent $event 
    */
    public function onItemConsume(PlayerItemConsumeEvent $event) {
        $player = $event->getPlayer();
        $item = $event->getItem();

        $game = $this->plugin->getGame($player);
        
        if (!($game instanceof Game)) {
            return false;
        }
        
        $namedtag = $item->getNamedTag();

        if ($namedtag instanceof CompoundTag) {
            if (($item->getId() === 373) and isset($namedtag["EffectId"], $namedtag["EffectTime"])) {
                $effectId = (int) $namedtag["EffectId"];
                $effectTime = (int) ($namedtag["EffectTime"] * 20);

                $event->setCancelled(true);

                $item->setCount($item->getCount() - 1);
                $player->getInventory()->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR));

                $effect = Effect::getEffect($effectId);
                $effect->setDuration($effectTime);
                $effect->setVisible(false);
                $effect->setAmplifier(1);
                $player->addEffect($effect);
            }
        } 
    }

    /**
    * @param PlayerInteractEvent $event 
    */
    public function onTap(PlayerInteractEvent $event) {
        $player = $event->getPlayer();
        $block = $event->getBlock();
        $item = $event->getItem();
        $action = $event->getAction();
        $namedtag = $item->getNamedTag();
        $game = $this->plugin->getGame($player);

        if (!($game instanceof Game)) {
            $this->manager($player, $block, $item, $event);
        	return false;
        }

        if ($block->getId() == 26) {
            $event->setCancelled(true);
        }

        if ($action >= 2) {
            if ($item->getId() === 351 and $item->getDamage() === 5) {
                $event->setCancelled(true);

                $projectile = $this->getProjectile($player, EnderPearl::class);
                $projectile->spawnToAll();
            
                $item->setCount($item->getCount() - 1);
                $player->getInventory()->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR));
                return true;
            } elseif ($item->getId() === 378) {
                $event->setCancelled(true);

                if ($this->canUseItem($player, "fireBall")) {
                    $projectile = $this->getProjectile($player, FireBall::class);
                    $projectile->spawnToAll();
                    $player->level->addSound(new FizzSound($player), [$player]);
                    $item->setCount($item->getCount() - 1);
                    $player->getInventory()->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR));
                    $this->setTimeItem($player, "fireBall");
                } else {
                    $secunds = $this->getTimeItem($player, "fireBall");
                    $player->sendMessage("§cWait {$secunds} Seconds to use the fireball");
                }
                return true;
            }
        }
        
        if ($namedtag instanceof CompoundTag) {
            if (isset($namedtag["Index"])) {
                switch ($namedtag["Index"]) {
                    case 0:
                        $inventory = new Inventory($player, "§l§eTeams§r");
                        $contents = array();
                        
                        foreach ($game->defaultTeams as $teamName => $args) {
                            $count = 1;
                            
                            if (isset($game->teams[$teamName])) {
                                $count = $game->teams[$teamName]->getCount();
                            }
                            
                            if ($count <= 0) {
                                $count = 1;
                            }
                            
                            $damage = $game->getDamage($teamName);
                            $color = $game->getColor($teamName);
                            
                            $itemTeam = Item::get(35, $damage, $count);
                            $itemTeam->setCustomName("§r§fTeams: " . $color . ucfirst($teamName) . "§r§f -§7 Click!");
                            $nbt = $itemTeam->getNamedTag();
                            $nbt->Team = new StringTag("Team", $teamName);
                            $itemTeam->setNamedTag($nbt);
                            $contents[] = $itemTeam;
                        }
                        
                        $inventory->setContents($contents);
                        $player->addWindow($inventory);
                        
                        $inventory->addEvent($player, function(Player $player, Item $item, Inventory $inventory) {
                            $namedtag = $item->getNamedTag();
                            
                            if ($namedtag instanceof CompoundTag) {
                                if (isset($namedtag->Team)) {
                                    $team = $namedtag["Team"];
                                    
                                    $game = BedWars::$loaded->getGame($player);
                                    
                                    if (!($game instanceof Game)) {
                                        return false;
                                    }
                                    
                                    $playerTeam = $game->getTeam($player->getName());
                                    
                                    if (isset($game->teams[$team]) === false) {
                                        $game->teams[$team] = new Team($team);
                                    }
                                    
                                    $newTeam = $game->teams[$team];
                                    $colored = $game->getColor($newTeam->getName()) . $newTeam->getName();
                                    
                                    if ($playerTeam->getName() === $newTeam->getName()) {
                                        $player->sendMessage("§c* You are already on the team {$colored}§c!");
                                    } else {
                                        if ($newTeam->getCount() >= $game::MODE_COUNT[$game->mode]) {
                                            $player->sendMessage("§c* The team {$colored} §cis logged in!");
                                        } else {
                                            $player->sendMessage("§7*§f You joined the team {$colored}§c!");
                                            
                                            $playerTeam->removePlayer($player);
                                            $newTeam->addPlayer($player);
                                            
                                            if ($playerTeam->getCount() > 0) {
                                                $game->teams[$playerTeam->getName()] = $playerTeam;
                                            } else {
                                                unset($game->teams[$playerTeam->getName()]);
                                            }
                                   
                                            $game->teams[$newTeam->getName()] = $newTeam;
                                            
                                            $game->players[$player->getName()] = $newTeam->getName();
                                        }
                                    }
                                }
                            }
                            
                            $player->removeWindow($inventory);
                        });
                        break;
                    
                    case 1:
                        $event->setCancelled(true);
                        $game->quit($player);
                        break;
                }
            }
        }
    }
    
    /**
    * @param Player $player
    * @param Block  $block
    * @param Item   $item
    */
    public function manager(Player $player, Block $block, Item $item, PlayerInteractEvent $event) {
        $game = $this->plugin->getGame($player, true);
        
        if (!($game instanceof Game)) {
            return false;
        }
        
        $args = $this->getActive($player);
        
        $toString = "$block->x:$block->y:$block->z";
        
        if (count($args) >= 3) {
        	$type = (string) $args[0];
	        $team = (string) $args[1];
	        $pos = (int) $args[2];
	        $teams = (array) $game->defaultTeams;
	        $generetors = array("§b" => "diamond", "§2" => "emerald");

	         if ($type == "generetors") {
	            foreach ($generetors as $key => $value) {
	                next($generetors);
	                
	                if ($value == $team) {
	                    $color = $key;
	                    $nextcolor = key($generetors);
	                    
	                    $game->setPosition($team, $type, $toString, $pos);
	                    
	                    $this->setActive($player, $type, $team, ($pos + 1));

	                    $event->setCancelled(true);

	                    if ($pos >= 4) {
	                        if ($value == "emerald") {
	                            $player->sendMessage("§aGenerator of " . $color . $team . " " . $pos . " §aset! §aTodos os geradores de " . $color . $team . " §aforam setados!");
	                            unset($this->players[$player->getName()]);
	                            break;
	                        }

	                        $player->sendMessage("§aGerador de " . $color . $team . " " . $pos++ . " §asetado! §aTodos os geradores de " . $color . $team . " §aforam setados! proximo " . $nextcolor . current($generetors) . " 1");
	                        $this->setActive($player, $type, current($generetors));
	                        break;
	                    }
	                    $player->sendMessage("§aGerador de " . $color . $team . " " . $pos . " §asetado! proximo " . $color . $team . " " . ($pos + 1));
	                    break;
	                }
	            }
	            return false;
	        }

	        foreach ($teams as $key => $value) {
	            next($teams);
	            $last = $key;
	            
	            if ($key == $team) {
	                if ($block->getId() != 26 and $type == "beds") {
	                	break;
	                }

	                $game->setPosition($team, $type, $toString);
	                $this->setActive($player, $type, key($teams));
	                
	                $event->setCancelled(true);
	                
	                if (current($teams) != "" and !empty(current($teams))) {
	                    $color = "§" . current($teams)["color"];
	                    $player->sendMessage("§a" . ucfirst($type) . " do time §" . $game->defaultTeams[$team]['color'] . $team . " §amarcado! proximo " . $color . key($teams));
	                } else {
	                    $player->sendMessage("§a" . ucfirst($type) . " do time §" . $game->defaultTeams[$team]['color'] . $team . " §amarcado! Todos os " . $type . " foram setados!");
	                    unset($this->players[$player->getName()]);
	                }
	                break;
	            }
	        }
        }
    }
    
    /**
    * @param PlayerBlockBreakEvent $event
    */
    public function onBreak(BlockBreakEvent $event) {
        $player = $event->getPlayer();
        $game = $this->plugin->getGame($player);
        
        if (!($game instanceof Game)) {
            return false;
        }
        
        if ($game->index == 3) {
            $block = $event->getBlock();
            $id = $block->getId();
            
            if ($this->is_placed($block, $game->placedBlocks) or ($id == 26)) {
                $event->setCancelled(false);
                
                if ($id === 26) {
                    $position = $block->add(0);
                    $playerTeam = $game->getTeam($player->getName());
                    
                    $event->setDrops([]);
                    
                    foreach ($game->teams as $name => $team) {
                        $bed = explode(":", $game->defaultTeams[$name]["beds"]);
                        $vector = new Vector3($bed[0], $bed[1], $bed[2]);
                        
                        if ($position->distance($vector) <= 1 and $team->isAlive()) {
                            if ($name == $playerTeam->getName()) {
                                $player->sendMessage("§r§cYou can't destroy your own bed!");
                                
                                $event->setCancelled(true);
                            } else {
                                $team->isAlive = false;
                                
                                $game->print("§r \n \n §fThe bed of " . $game->getColor($name) . ucfirst($name) . "§r§f Has been drestoyed by " . $game->getNameTag($player) . "§r \n \n");
                                
                                foreach ($team->getPlayers() as $player) {
                                    if (!($player instanceof Player)) {
                                        continue;
                                    }
                                    
                                    $player->sendTip("     §r§c§lYour bed has been drestroyed!§r\n§cYou cannot respawn anymore!§r\n\n\n\n");
                                }
                                
                                foreach ($game->getPlayers() as $player) {
                                    if (!$player instanceof Player) {
                                        continue;
                                    }

                                    $player->level->addSound(new ExplodeSound($player), array($player));
                                }
                            }
                            break;
                        }
                    }
                }
            } else {
                $event->setCancelled(true);
            }
        } else {
            $event->setCancelled(true);
        }
        
    }
    
    /**
     * @param Block $block
     */
    public function prime(Block $block, Player $player) {
        $mot = (new Random())->nextSignedFloat() * M_PI * 2;
        $tnt = Entity::createEntity("PrimedTNT", $block->level->getChunk($block->x >> 4, $block->z >> 4), new CompoundTag("", [
            "Pos" => new ListTag("Pos", [
                new DoubleTag(0, $block->x + 0.5),
                new DoubleTag(1, $block->y),
                new DoubleTag(2, $block->z + 0.5)
            ]),
            "Motion" => new ListTag("Motion", [
                new DoubleTag(0, -sin($mot) * 0.02),
                new DoubleTag(1, 0.2),
                new DoubleTag(2, -cos($mot) * 0.02)
            ]),
            "Rotation" => new ListTag("Rotation", [
                new FloatTag(0, 0),
                new FloatTag(1, 0)
            ]),
            "Fuse" => new ByteTag("Fuse", 50),
            "owner" => new StringTag("owner", $player->getName())
        ]), false);
        $tnt->spawnToAll();
        $block->level->addSound(new TNTPrimeSound($block));
    }
    
    /**
    * @param PlayerPlaceEvent $event
    */
    public function onPlace(BlockPlaceEvent $event) {
        $player = $event->getPlayer();
        $item = $event->getItem();
        $game = $this->plugin->getGame($player);
        
        if (!($game instanceof Game)) {
            return $game;
        }
        
        if ($game->index === 3) {
            $block = $event->getBlock();
            $id = $block->getId();
            
            if ($id === Block::TNT) {
                $event->setCancelled(true);
                
                $item->setCount($item->getCount());
                $player->getInventory()->setItemInHand($item->getCount() > 0 ? $item : Item::get(Item::AIR));
                
                $this->prime($block, $player);
                return true;
            }
            
            $position = $block->add(0);
            
            $event->setCancelled(false);
                
            foreach ($game->generetors as $type => $list) {
                foreach ($list as $key => $generetor) {
                    $args = explode(":", $generetor);
                    $vector = new Vector3($args[0], $args[1], $args[2]);
                        
                    if ($position->distance($vector) <= 3) {
                        $player->sendMessage("§cYou cannot put a block near the generator!");
                        
                        $event->setCancelled(true);
                        break 2;
                    }
                }
            }
            
            if ($event->isCancelled() == false) {
                $game->placedBlocks[$position->__toString()] = $id;
            }
        } else {
            $event->setCancelled(true);
        }
        
    }

    /**
    * @param Block  $block
    * @param array  $blocks
    */
    public function is_placed(Block $block, array $blocks) : bool {
        $position = $block->add(0);
        
        if (isset($blocks[$position->__toString()])) {
            $id = $blocks[$position->__toString()];
            
            if ($block->getId() == $id) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
    * @param PlayerQuitEvent $event
    */
    public function quit(PlayerQuitEvent $event) {
        $player = $event->getPlayer();
        $game = $this->plugin->getGame($player);

        if ($game instanceof Game) {
            $game->quit($player);
        }
    }
    
    /**
     * @param InventoryPickupItemEvent $event
     */
    public function onPickupItem(InventoryPickupItemEvent $event) {
        $player = $event->getInventory()->getHolder();
        $game = $this->plugin->getGame($player, true);
        
        if ($game instanceof Game) {
            if ($game->index < 3 or isset($game->espects[$player->getName()]) or isset($game->respawn[$player->getName()]) or $game->index == 4) {
                $event->setCancelled(true);
            }
        }
    }
    
    /**
     * @param PlayerDropItemEvent
     */
    public function onDropItem(PlayerDropItemEvent $event) {
        $player = $event->getPlayer();
        $item = $event->getItem();
        $namedtag = $item->getNamedTag();
        
        if ($namedtag instanceof CompoundTag) {
            if (isset($namedtag["EndBug"])) {
                $event->setCancelled(true);
                return false;
            }
        }
        
        $game = $this->plugin->getGame($player, true);
        
        if ($game instanceof Game) {
            if ($game->index < 3 or isset($game->espects[$player->getName()]) or isset($game->respawn[$player->getName()]) or $game->index == 4) {
                $event->setCancelled(true);
            }
        }
    }
    
    /**

     * @param EntityInventoryChangeEvent $event
     */
    public function onInventoryChange(EntityInventoryChangeEvent $event) {
        $entity = $event->getEntity();
        $newItem = $event->getNewItem();
        
        if ($entity instanceof Player) {
            $namedtag = $newItem->getNamedTag();
            
            if ($namedtag instanceof CompoundTag) {
                if (isset($namedtag["EndBug"])) {
                    $event->setCancelled(true);
                }
            }
        }
    }
    
    /**
    * @param EntityDamageEvent $event 
    */
    public function onDamage(EntityDamageEvent $event) {
        $entity = $event->getEntity();
        $cause = $event->getCause();
        $damager = null;
        
        if ($entity instanceof Player) {
            $game = $this->plugin->getGame($entity, true);

            if (!($game instanceof Game)) {
                return false;
            }

            $continue = ($this->plugin->getGame($entity) instanceof Game);
            
            if ($cause === EntityDamageEvent::CAUSE_FALL) {
                $event->setCancelled(true);
                return false;
            }

            if ($event instanceof EntityDamageByEntityEvent) {
                $damager = $event->getDamager();
                
                if ($damager instanceof Player) {
                    if (isset($game->espects[$damager->getName()]) or isset($game->respawn[$damager->getName()])) {
                        $event->setCancelled(true);
                        return true;
                    }
              
                    $this->hits[$entity->getName()] = array($damager, time());
                }
                
                if (isset($damager->namedtag["owner"])) {
                    $owner = $damager->namedtag["owner"];
                    
                    if (isset($game->players[$owner])) {
                        $pplayer = null;
                        
                        foreach ($entity->level->getPlayers() as $player) {
                            if ($player->getName() == $owner and $entity->getName() != $player->getName()) {
                                $damager = $player;
                                break;
                            }
                        }
                    }
                }
            }
            
            if (isset($this->hits[$entity->getName()]) and $damager == null) {
                $args = (array) $this->hits[$entity->getName()];
                
                if (((time() - $args[1]) <= 5) and ($args[0] instanceof Player)) {
                    $damager = $args[0];
                } 
            }
            
            if ($game->index >= 3) {
                $team = $game->getTeam($entity->getName());
                
                if (!($team instanceof Team)) {
                    return false;
                }
                
                if (isset($game->espects[$entity->getName()]) or isset($game->respawn[$entity->getName()])) {
                    $event->setCancelled(true);
                
                    if ($cause === EntityDamageEvent::CAUSE_VOID) {
                        if (isset($game->respawn[$entity->getName()])) {
                            $game->setContents($entity, 2);
                            $game->teleportToSpawn($entity, $team, true);
                        } else {
                            $game->setContents($entity, 2);
                            $game->teleportToHub($entity);
                        }
                    }
                    return true;
                }
            
                $finalDamage = round($event->getFinalDamage());
                
                if (($entity->getHealth() - $finalDamage) <= 1) {
                    $event->setCancelled(true);
                    
                    $oresMessage = '';
                    $message = $game->getNameTag($entity) . " §r§cFell Into The Void";
                   
                    if ($damager instanceof Player) {
                        $message = $game->getNameTag($entity) . " §r§7was killed by§r§f " . $game->getNameTag($damager) . "§r§7!";
                        $damager->level->addSound(new ExpPickupSound($damager), array($damager));
                        
                        //add ores
                        $contents = $entity->getInventory()->getContents();
                        $iron = 0;
                        $gold = 0;
                        $diamond = 0;
                        $emerald = 0;
                        
                        //filter
                        foreach ($contents as $slot => $item) {
                            $itemId = $item->getId();
                            $amount = $item->getCount();
                            
                            //265, 266, 264, 388
                            switch ($itemId) {
                                case 265:
                                    $iron += $amount;
                                    $damager->getInventory()->addItem(Item::get(265, 0, $amount));
                                    break;

                                case 266:
                                    $gold += $amount;
                                    $damager->getInventory()->addItem(Item::get(266, 0, $amount));
                                    break;
                                 
                                case 264:
                                    $diamond += $amount;
                                    $damager->getInventory()->addItem(Item::get(264, 0, $amount));
                                    break;

                                case 388:
                                    $emerald += $amount;
                                    $damager->getInventory()->addItem(Item::get(388, 0, $amount));
                                    break;
                            }
                        }
                        
                        if ($iron > 0) {
                            $oresMessage .= "\n§f+" . $iron . " iron!";
                        }
                        
                        if ($gold > 0) {
                            $oresMessage .= "\n§e+" . $gold . " gold!";
                        }
                        
                        if ($diamond > 0) {
                            $oresMessage .= "\n§b+" . $diamond . " diamonds!";
                        }
                        
                        if ($emerald > 0) {
                            $oresMessage .= "\n§a+" . $emerald . " emeralds!";
                        }
                    }

                    $entity->level->addSound(new SpellSound($entity), array($entity));
                    
                    if ($team->isAlive()) {
                        $game->respawn[$entity->getName()] = array($entity, 5);
                    } else {
                        $team->removeNecPlayer($entity);
                        $game->espects[$entity->getName()] = $entity;
                        $message .= " §r§l§cFinale Battle!";
                    }
                    $game->setContents($entity, 2);
                    $game->teleportToSpawn($entity, $game->getTeam($entity->getName()), true);
                    $game->print($message . $oresMessage . "\n");
                }
            } else {
                if ($continue) {
                    $event->setCancelled(true);
                
                    if ($cause === EntityDamageEvent::CAUSE_VOID) {
                        $game->teleportToHub($entity);
                        $game->setContents($entity, 0);
                    }
                }
            }
        }
    }

    public function inventory(InventoryTransactionEvent $event) {
        $transaction = $event->getTransaction();
        $transactions = $transaction->getTransactions();
        
        foreach ($transactions as $tran) {
            $inv = $tran->getInventory();
            
            if ($inv instanceof Inventory) {
                $viewers = $inv->getViewers();
                
                foreach ($viewers as $assumed) {
                    if ($assumed instanceof Player) {
                        $player = $assumed;
                        $item = $inv->getItem($tran->getSlot());
                        $inventory = $inv;
                        break;
                    }
                }
            }
        }
        
        if (isset($player, $item, $inventory) === false) {
            return false;
        }
        
        if ($player->customInventory instanceof Inventory) {
            $events = $inventory->getEvents();
            
            $event->setCancelled(true);
            
            if (count($events) <= 0) {
                return false;
            }
            
            if (isset($events[spl_object_hash($player)])) {
                $callback = $events[spl_object_hash($player)];
                
                if ($callback != null) {
                    $callback($player, $item, $inventory);
                }
            }
        }
    }
}
?>