diff --git a/src/pocketmine/Player.php b/src/pocketmine/Player.php index 9f7209b97..d8abaaac6 100644 --- a/src/pocketmine/Player.php +++ b/src/pocketmine/Player.php @@ -77,6 +77,8 @@ use pocketmine\inventory\transaction\InventoryTransaction; use pocketmine\inventory\transaction\TransactionValidationException; use pocketmine\item\Consumable; use pocketmine\item\Durable; +use pocketmine\item\enchantment\EnchantmentInstance; +use pocketmine\item\enchantment\MeleeWeaponEnchantment; use pocketmine\item\Item; use pocketmine\item\WritableBook; use pocketmine\item\WrittenBook; @@ -2502,6 +2504,19 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ } $ev = new EntityDamageByEntityEvent($this, $target, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $heldItem->getAttackPoints()); + + $meleeEnchantmentDamage = 0; + /** @var EnchantmentInstance[] $meleeEnchantments */ + $meleeEnchantments = []; + foreach($heldItem->getEnchantments() as $enchantment){ + $type = $enchantment->getType(); + if($type instanceof MeleeWeaponEnchantment and $type->isApplicableTo($target)){ + $meleeEnchantmentDamage += $type->getDamageBonus($enchantment->getLevel()); + $meleeEnchantments[] = $enchantment; + } + } + $ev->setModifier($meleeEnchantmentDamage, EntityDamageEvent::MODIFIER_WEAPON_ENCHANTMENTS); + if($cancelled){ $ev->setCancelled(); } @@ -2529,6 +2544,12 @@ class Player extends Human implements CommandSender, ChunkLoader, IPlayer{ } } + foreach($meleeEnchantments as $enchantment){ + $type = $enchantment->getType(); + assert($type instanceof MeleeWeaponEnchantment); + $type->onPostAttack($this, $target, $enchantment->getLevel()); + } + if($this->isAlive()){ //reactive damage like thorns might cause us to be killed by attacking another mob, which //would mean we'd already have dropped the inventory by the time we reached here diff --git a/src/pocketmine/entity/projectile/Arrow.php b/src/pocketmine/entity/projectile/Arrow.php index 3db4e26a5..71d5f5c07 100644 --- a/src/pocketmine/entity/projectile/Arrow.php +++ b/src/pocketmine/entity/projectile/Arrow.php @@ -138,10 +138,11 @@ class Arrow extends Projectile{ 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)); + $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)); + } } } diff --git a/src/pocketmine/event/entity/EntityDamageEvent.php b/src/pocketmine/event/entity/EntityDamageEvent.php index 7988dd411..fb448db95 100644 --- a/src/pocketmine/event/entity/EntityDamageEvent.php +++ b/src/pocketmine/event/entity/EntityDamageEvent.php @@ -38,6 +38,7 @@ class EntityDamageEvent extends EntityEvent implements Cancellable{ public const MODIFIER_ARMOR_ENCHANTMENTS = 6; public const MODIFIER_CRITICAL = 7; public const MODIFIER_TOTEM = 8; + public const MODIFIER_WEAPON_ENCHANTMENTS = 9; public const CAUSE_CONTACT = 0; public const CAUSE_ENTITY_ATTACK = 1; diff --git a/src/pocketmine/item/enchantment/Enchantment.php b/src/pocketmine/item/enchantment/Enchantment.php index 9b4e7f461..8deb17f40 100644 --- a/src/pocketmine/item/enchantment/Enchantment.php +++ b/src/pocketmine/item/enchantment/Enchantment.php @@ -117,6 +117,12 @@ class Enchantment{ 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 SharpnessEnchantment(self::SHARPNESS, "%enchantment.damage.all", self::RARITY_COMMON, self::SLOT_SWORD, self::SLOT_AXE, 5)); + //TODO: smite, bane of arthropods (these don't make sense now because their applicable mobs don't exist yet) + + self::registerEnchantment(new KnockbackEnchantment(self::KNOCKBACK, "%enchantment.knockback", self::RARITY_UNCOMMON, self::SLOT_SWORD, self::SLOT_NONE, 2)); + self::registerEnchantment(new FireAspectEnchantment(self::FIRE_ASPECT, "%enchantment.fire", self::RARITY_RARE, self::SLOT_SWORD, self::SLOT_NONE, 2)); + self::registerEnchantment(new Enchantment(self::EFFICIENCY, "%enchantment.digging", self::RARITY_COMMON, self::SLOT_DIG, self::SLOT_SHEARS, 5)); self::registerEnchantment(new Enchantment(self::SILK_TOUCH, "%enchantment.untouching", self::RARITY_MYTHIC, self::SLOT_DIG, self::SLOT_SHEARS, 1)); 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)); diff --git a/src/pocketmine/item/enchantment/FireAspectEnchantment.php b/src/pocketmine/item/enchantment/FireAspectEnchantment.php new file mode 100644 index 000000000..aaaccd8ae --- /dev/null +++ b/src/pocketmine/item/enchantment/FireAspectEnchantment.php @@ -0,0 +1,41 @@ +setOnFire($enchantmentLevel * 4); + } +} diff --git a/src/pocketmine/item/enchantment/KnockbackEnchantment.php b/src/pocketmine/item/enchantment/KnockbackEnchantment.php new file mode 100644 index 000000000..04cb92fe5 --- /dev/null +++ b/src/pocketmine/item/enchantment/KnockbackEnchantment.php @@ -0,0 +1,44 @@ +knockBack($attacker, 0, $victim->x - $attacker->x, $victim->z - $attacker->z, $enchantmentLevel * 0.5); + } + } +} diff --git a/src/pocketmine/item/enchantment/MeleeWeaponEnchantment.php b/src/pocketmine/item/enchantment/MeleeWeaponEnchantment.php new file mode 100644 index 000000000..6d2c8a631 --- /dev/null +++ b/src/pocketmine/item/enchantment/MeleeWeaponEnchantment.php @@ -0,0 +1,63 @@ +stop){ return false; }elseif($d === false){ + if(socket_last_error($client) === SOCKET_ECONNRESET){ //client crashed, terminate connection + return false; + } return null; }elseif($d === "" or strlen($d) < 4){ return false;