setCritical($critical); } protected function initEntity() : void{ parent::initEntity(); $this->pickupMode = $this->namedtag->getByte(self::TAG_PICKUP, self::PICKUP_ANY, true); $this->collideTicks = $this->namedtag->getShort("life", $this->collideTicks); } public function saveNBT() : void{ parent::saveNBT(); $this->namedtag->setByte(self::TAG_PICKUP, $this->pickupMode, true); $this->namedtag->setShort("life", $this->collideTicks); } public function isCritical() : bool{ return $this->getGenericFlag(self::DATA_FLAG_CRITICAL); } public function setCritical(bool $value = true) : void{ $this->setGenericFlag(self::DATA_FLAG_CRITICAL, $value); } public function getResultDamage() : int{ $base = parent::getResultDamage(); if($this->isCritical()){ return ($base + mt_rand(0, (int) ($base / 2) + 1)); }else{ return $base; } } public function getPunchKnockback() : float{ return $this->punchKnockback; } public function setPunchKnockback(float $punchKnockback) : void{ $this->punchKnockback = $punchKnockback; } public function entityBaseTick(int $tickDiff = 1) : bool{ if($this->closed){ return false; } $hasUpdate = parent::entityBaseTick($tickDiff); if($this->blockHit !== null){ $this->collideTicks += $tickDiff; if($this->collideTicks > 1200){ $this->flagForDespawn(); $hasUpdate = true; } }else{ $this->collideTicks = 0; } return $hasUpdate; } protected function onHit(ProjectileHitEvent $event) : void{ $this->setCritical(false); $this->level->broadcastLevelSoundEvent($this, LevelSoundEventPacket::SOUND_BOW_HIT); } protected function onHitBlock(Block $blockHit, RayTraceResult $hitResult) : void{ parent::onHitBlock($blockHit, $hitResult); $this->broadcastEntityEvent(ActorEventPacket::ARROW_SHAKE, 7); //7 ticks } protected function onHitEntity(Entity $entityHit, RayTraceResult $hitResult) : void{ parent::onHitEntity($entityHit, $hitResult); if($this->punchKnockback > 0){ $horizontalSpeed = sqrt($this->motion->x ** 2 + $this->motion->z ** 2); if($horizontalSpeed > 0){ $multiplier = $this->punchKnockback * 0.6 / $horizontalSpeed; $entityHit->setMotion($entityHit->getMotion()->add($this->motion->x * $multiplier, 0.1, $this->motion->z * $multiplier)); } } } public function getPickupMode() : int{ return $this->pickupMode; } public function setPickupMode(int $pickupMode) : void{ $this->pickupMode = $pickupMode; } public function onCollideWithPlayer(Player $player) : void{ if($this->blockHit === null){ return; } $item = ItemFactory::get(Item::ARROW, 0, 1); $playerInventory = $player->getInventory(); if($player->isSurvival() and !$playerInventory->canAddItem($item)){ return; } $ev = new InventoryPickupArrowEvent($playerInventory, $this); if($this->pickupMode === self::PICKUP_NONE or ($this->pickupMode === self::PICKUP_CREATIVE and !$player->isCreative())){ $ev->setCancelled(); } $ev->call(); if($ev->isCancelled()){ return; } $pk = new TakeItemActorPacket(); $pk->eid = $player->getId(); $pk->target = $this->getId(); $this->server->broadcastPacket($this->getViewers(), $pk); $playerInventory->addItem(clone $item); $this->flagForDespawn(); } }