From 2f70a1eefb801341cbc374bf4981f8050f99df4d Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 23 Jun 2018 13:36:58 +0100 Subject: [PATCH 1/5] Implemented Thorns enchantment (#2258) This implementation is rough and can probably be improved to make it extendable, but this works for now and can be improved later. --- src/pocketmine/entity/Living.php | 33 ++++++++++++++++--- .../item/enchantment/Enchantment.php | 2 +- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/pocketmine/entity/Living.php b/src/pocketmine/entity/Living.php index 6202e9ee48..c4a354b139 100644 --- a/src/pocketmine/entity/Living.php +++ b/src/pocketmine/entity/Living.php @@ -34,6 +34,7 @@ use pocketmine\inventory\ArmorInventory; use pocketmine\inventory\ArmorInventoryEventProcessor; use pocketmine\item\Armor; use pocketmine\item\Consumable; +use pocketmine\item\Durable; use pocketmine\item\enchantment\Enchantment; use pocketmine\item\Item; use pocketmine\math\Vector3; @@ -476,6 +477,26 @@ abstract class Living extends Entity implements Damageable{ protected function applyPostDamageEffects(EntityDamageEvent $source) : void{ $this->setAbsorption(max(0, $this->getAbsorption() + $source->getModifier(EntityDamageEvent::MODIFIER_ABSORPTION))); $this->damageArmor($source->getBaseDamage()); + + if($source instanceof EntityDamageByEntityEvent){ + $damage = 0; + foreach($this->armorInventory->getContents() as $k => $item){ + if($item instanceof Armor and ($thornsLevel = $item->getEnchantmentLevel(Enchantment::THORNS)) > 0){ + if(mt_rand(0, 99) < $thornsLevel * 15){ + $this->damageItem($item, 3); + $damage += ($thornsLevel > 10 ? $thornsLevel - 10 : 1 + mt_rand(0, 3)); + }else{ + $this->damageItem($item, 1); //thorns causes an extra +1 durability loss even if it didn't activate + } + + $this->armorInventory->setItem($k, $item); + } + } + + if($damage > 0){ + $source->getDamager()->attack(new EntityDamageByEntityEvent($this, $source->getDamager(), EntityDamageEvent::CAUSE_MAGIC, $damage)); + } + } } /** @@ -490,16 +511,20 @@ abstract class Living extends Entity implements Damageable{ $armor = $this->armorInventory->getContents(true); foreach($armor as $item){ if($item instanceof Armor){ - $item->applyDamage($durabilityRemoved); - if($item->isBroken()){ - $this->level->broadcastLevelSoundEvent($this, LevelSoundEventPacket::SOUND_BREAK); - } + $this->damageItem($item, $durabilityRemoved); } } $this->armorInventory->setContents($armor); } + private function damageItem(Durable $item, int $durabilityRemoved) : void{ + $item->applyDamage($durabilityRemoved); + if($item->isBroken()){ + $this->level->broadcastLevelSoundEvent($this, LevelSoundEventPacket::SOUND_BREAK); + } + } + public function attack(EntityDamageEvent $source) : void{ if($this->attackTime > 0 or $this->noDamageTicks > 0){ $lastCause = $this->getLastDamageCause(); diff --git a/src/pocketmine/item/enchantment/Enchantment.php b/src/pocketmine/item/enchantment/Enchantment.php index 9d40e7758b..e410a0d165 100644 --- a/src/pocketmine/item/enchantment/Enchantment.php +++ b/src/pocketmine/item/enchantment/Enchantment.php @@ -114,7 +114,7 @@ class Enchantment{ self::registerEnchantment(new ProtectionEnchantment(self::PROJECTILE_PROTECTION, "%enchantment.protect.projectile", self::RARITY_UNCOMMON, self::SLOT_ARMOR, self::SLOT_NONE, 4, 1.5, [ EntityDamageEvent::CAUSE_PROJECTILE ])); - + self::registerEnchantment(new Enchantment(self::THORNS, "%enchantment.thorns", self::RARITY_MYTHIC, self::SLOT_TORSO, self::SLOT_HEAD | self::SLOT_LEGS | self::SLOT_FEET, 3)); self::registerEnchantment(new Enchantment(self::RESPIRATION, "%enchantment.oxygen", self::RARITY_RARE, self::SLOT_HEAD, self::SLOT_NONE, 3)); self::registerEnchantment(new Enchantment(self::EFFICIENCY, "%enchantment.digging", self::RARITY_COMMON, self::SLOT_DIG, self::SLOT_SHEARS, 5)); From 0081e30a896a730f9598353353f6ee258803850e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 23 Jun 2018 14:30:26 +0100 Subject: [PATCH 2/5] Living: fix knockback condition, take 2 onGround doesn't necessarily reflect 0 motion, because something else could change the motion prior to the onGround flag getting updated - for example 2 knockbacks in a row. --- src/pocketmine/entity/Living.php | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/pocketmine/entity/Living.php b/src/pocketmine/entity/Living.php index 6202e9ee48..bb39d4c5ce 100644 --- a/src/pocketmine/entity/Living.php +++ b/src/pocketmine/entity/Living.php @@ -577,14 +577,17 @@ abstract class Living extends Entity implements Damageable{ $motion = clone $this->motion; $motion->x /= 2; - $motion->y /= 2; $motion->z /= 2; $motion->x += $x * $f * $base; - $motion->y += $base; $motion->z += $z * $f * $base; - if($motion->y > $base){ - $motion->y = $base; + if($this->onGround){ + $motion->y /= 2; + $motion->y += $base; + + if($motion->y > 0.4){ //this is hardcoded in vanilla + $motion->y = 0.4; + } } $this->setMotion($motion); From d3e54db1462a312a9b075a9f761a60c4e48e35c9 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 23 Jun 2018 16:41:21 +0100 Subject: [PATCH 3/5] ExperienceOrb: stop tracking targets if they die while being tracked --- src/pocketmine/entity/object/ExperienceOrb.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pocketmine/entity/object/ExperienceOrb.php b/src/pocketmine/entity/object/ExperienceOrb.php index c73edb4148..729f9509c3 100644 --- a/src/pocketmine/entity/object/ExperienceOrb.php +++ b/src/pocketmine/entity/object/ExperienceOrb.php @@ -165,7 +165,7 @@ class ExperienceOrb extends Entity{ } $currentTarget = $this->getTargetPlayer(); - if($currentTarget !== null and $currentTarget->distanceSquared($this) > self::MAX_TARGET_DISTANCE ** 2){ + if($currentTarget !== null and (!$currentTarget->isAlive() or $currentTarget->distanceSquared($this) > self::MAX_TARGET_DISTANCE ** 2)){ $currentTarget = null; } From 85a3c0e7dcfacc8dd76feb1786eadaad2b99aea8 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 23 Jun 2018 17:11:20 +0100 Subject: [PATCH 4/5] Implemented Flame enchantment --- src/pocketmine/item/Bow.php | 3 +++ src/pocketmine/item/enchantment/Enchantment.php | 1 + 2 files changed, 4 insertions(+) diff --git a/src/pocketmine/item/Bow.php b/src/pocketmine/item/Bow.php index 39e11a4c18..fb0c382043 100644 --- a/src/pocketmine/item/Bow.php +++ b/src/pocketmine/item/Bow.php @@ -73,6 +73,9 @@ class Bow extends Tool{ if(($powerLevel = $this->getEnchantmentLevel(Enchantment::POWER)) > 0){ $entity->setBaseDamage($entity->getBaseDamage() + (($powerLevel + 1) / 2)); } + if($this->hasEnchantment(Enchantment::FLAME)){ + $entity->setOnFire($entity->getFireTicks() * 20 + 100); + } $ev = new EntityShootBowEvent($player, $this, $entity, $force); if($force < 0.1 or $diff < 5){ diff --git a/src/pocketmine/item/enchantment/Enchantment.php b/src/pocketmine/item/enchantment/Enchantment.php index e410a0d165..f92937a79f 100644 --- a/src/pocketmine/item/enchantment/Enchantment.php +++ b/src/pocketmine/item/enchantment/Enchantment.php @@ -123,6 +123,7 @@ class Enchantment{ self::registerEnchantment(new Enchantment(self::POWER, "%enchantment.arrowDamage", self::RARITY_COMMON, self::SLOT_BOW, self::SLOT_NONE, 5)); + self::registerEnchantment(new Enchantment(self::FLAME, "%enchantment.arrowFire", self::RARITY_RARE, self::SLOT_BOW, self::SLOT_NONE, 1)); self::registerEnchantment(new Enchantment(self::INFINITY, "%enchantment.arrowInfinite", self::RARITY_MYTHIC, self::SLOT_BOW, self::SLOT_NONE, 1)); self::registerEnchantment(new Enchantment(self::VANISHING, "%enchantment.curse.vanishing", self::RARITY_MYTHIC, self::SLOT_NONE, self::SLOT_ALL, 1)); From 97c267c70cc2e5df25a147482b36e8825250b4c6 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sat, 23 Jun 2018 17:40:01 +0100 Subject: [PATCH 5/5] Implemented Punch enchantment --- src/pocketmine/entity/projectile/Arrow.php | 28 +++++++++++++++++++ src/pocketmine/item/Bow.php | 9 ++++-- .../item/enchantment/Enchantment.php | 2 +- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/src/pocketmine/entity/projectile/Arrow.php b/src/pocketmine/entity/projectile/Arrow.php index 5842149a96..3db4e26a50 100644 --- a/src/pocketmine/entity/projectile/Arrow.php +++ b/src/pocketmine/entity/projectile/Arrow.php @@ -31,6 +31,7 @@ use pocketmine\item\Item; use pocketmine\item\ItemFactory; use pocketmine\level\Level; use pocketmine\math\RayTraceResult; +use pocketmine\math\Vector3; use pocketmine\nbt\tag\CompoundTag; use pocketmine\network\mcpe\protocol\EntityEventPacket; use pocketmine\network\mcpe\protocol\LevelSoundEventPacket; @@ -58,6 +59,9 @@ class Arrow extends Projectile{ /** @var int */ protected $pickupMode = self::PICKUP_ANY; + /** @var float */ + protected $punchKnockback = 0.0; + public function __construct(Level $level, CompoundTag $nbt, ?Entity $shootingEntity = null, bool $critical = false){ parent::__construct($level, $nbt, $shootingEntity); $this->setCritical($critical); @@ -92,6 +96,20 @@ class Arrow extends Projectile{ } } + /** + * @return float + */ + public function getPunchKnockback() : float{ + return $this->punchKnockback; + } + + /** + * @param float $punchKnockback + */ + public function setPunchKnockback(float $punchKnockback) : void{ + $this->punchKnockback = $punchKnockback; + } + public function entityBaseTick(int $tickDiff = 1) : bool{ if($this->closed){ return false; @@ -117,6 +135,16 @@ class Arrow extends Projectile{ $this->broadcastEntityEvent(EntityEventPacket::ARROW_SHAKE, 7); //7 ticks } + protected function onHitEntity(Entity $entityHit, RayTraceResult $hitResult) : void{ + parent::onHitEntity($entityHit, $hitResult); + if($this->punchKnockback > 0){ + $mot = $entityHit->getMotion(); + $multiplier = $this->punchKnockback * 0.6 / $mot->length(); + + $entityHit->setMotion($mot->add($mot->x * $multiplier, 0.1, $mot->z * $multiplier)); + } + } + /** * @return int */ diff --git a/src/pocketmine/item/Bow.php b/src/pocketmine/item/Bow.php index fb0c382043..3e785c71d7 100644 --- a/src/pocketmine/item/Bow.php +++ b/src/pocketmine/item/Bow.php @@ -67,8 +67,13 @@ class Bow extends Tool{ $entity = Entity::createEntity("Arrow", $player->getLevel(), $nbt, $player, $force == 2); if($entity instanceof Projectile){ $infinity = $this->hasEnchantment(Enchantment::INFINITY); - if($infinity and $entity instanceof ArrowEntity){ - $entity->setPickupMode(ArrowEntity::PICKUP_CREATIVE); + if($entity instanceof ArrowEntity){ + if($infinity){ + $entity->setPickupMode(ArrowEntity::PICKUP_CREATIVE); + } + if(($punchLevel = $this->getEnchantmentLevel(Enchantment::PUNCH)) > 0){ + $entity->setPunchKnockback($punchLevel); + } } if(($powerLevel = $this->getEnchantmentLevel(Enchantment::POWER)) > 0){ $entity->setBaseDamage($entity->getBaseDamage() + (($powerLevel + 1) / 2)); diff --git a/src/pocketmine/item/enchantment/Enchantment.php b/src/pocketmine/item/enchantment/Enchantment.php index f92937a79f..9b4e7f461f 100644 --- a/src/pocketmine/item/enchantment/Enchantment.php +++ b/src/pocketmine/item/enchantment/Enchantment.php @@ -122,7 +122,7 @@ class Enchantment{ self::registerEnchantment(new Enchantment(self::UNBREAKING, "%enchantment.durability", self::RARITY_UNCOMMON, self::SLOT_DIG | self::SLOT_ARMOR | self::SLOT_FISHING_ROD | self::SLOT_BOW, self::SLOT_TOOL | self::SLOT_CARROT_STICK | self::SLOT_ELYTRA, 3)); self::registerEnchantment(new Enchantment(self::POWER, "%enchantment.arrowDamage", self::RARITY_COMMON, self::SLOT_BOW, self::SLOT_NONE, 5)); - + self::registerEnchantment(new Enchantment(self::PUNCH, "%enchantment.arrowKnockback", self::RARITY_RARE, self::SLOT_BOW, self::SLOT_NONE, 2)); self::registerEnchantment(new Enchantment(self::FLAME, "%enchantment.arrowFire", self::RARITY_RARE, self::SLOT_BOW, self::SLOT_NONE, 1)); self::registerEnchantment(new Enchantment(self::INFINITY, "%enchantment.arrowInfinite", self::RARITY_MYTHIC, self::SLOT_BOW, self::SLOT_NONE, 1));