Implement anvil fall damage (#5312)

This commit is contained in:
IvanCraft623 2023-03-27 14:17:08 -05:00 committed by GitHub
parent 04197d6b80
commit bea878e9e9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 76 additions and 2 deletions

View File

@ -107,6 +107,14 @@ class Anvil extends Transparent implements Fallable{
return true; return true;
} }
public function getFallDamagePerBlock() : float{
return 2.0;
}
public function getMaxFallDamage() : float{
return 40.0;
}
public function getLandSound() : ?Sound{ public function getLandSound() : ?Sound{
return new AnvilFallSound(); return new AnvilFallSound();
} }

View File

@ -42,6 +42,18 @@ interface Fallable{
*/ */
public function onHitGround(FallingBlock $blockEntity) : bool; public function onHitGround(FallingBlock $blockEntity) : bool;
/**
* Returns the damage caused per fallen block. This is multiplied by the fall distance (and capped according to
* {@link Fallable::getMaxFallDamage()}) to calculate the damage dealt to any entities who intersect with the block
* when it hits the ground.
*/
public function getFallDamagePerBlock() : float;
/**
* Returns the maximum damage the block can deal to an entity when it hits the ground.
*/
public function getMaxFallDamage() : float;
/** /**
* Returns the sound that will be played when FallingBlock hits the ground. * Returns the sound that will be played when FallingBlock hits the ground.
*/ */

View File

@ -64,6 +64,14 @@ trait FallableTrait{
return true; return true;
} }
public function getFallDamagePerBlock() : float{
return 0.0;
}
public function getMaxFallDamage() : float{
return 0.0;
}
public function getLandSound() : ?Sound{ public function getLandSound() : ?Sound{
return null; return null;
} }

View File

@ -73,6 +73,7 @@ use function max;
use function min; use function min;
use function mt_getrandmax; use function mt_getrandmax;
use function mt_rand; use function mt_rand;
use function round;
use function sqrt; use function sqrt;
use const M_PI; use const M_PI;
@ -429,6 +430,10 @@ abstract class Living extends Entity{
$source->setModifier(-$source->getFinalDamage() * min(ceil(min($totalEpf, 25) * (mt_rand(50, 100) / 100)), 20) * 0.04, EntityDamageEvent::MODIFIER_ARMOR_ENCHANTMENTS); $source->setModifier(-$source->getFinalDamage() * min(ceil(min($totalEpf, 25) * (mt_rand(50, 100) / 100)), 20) * 0.04, EntityDamageEvent::MODIFIER_ARMOR_ENCHANTMENTS);
$source->setModifier(-min($this->getAbsorption(), $source->getFinalDamage()), EntityDamageEvent::MODIFIER_ABSORPTION); $source->setModifier(-min($this->getAbsorption(), $source->getFinalDamage()), EntityDamageEvent::MODIFIER_ABSORPTION);
if($cause === EntityDamageEvent::CAUSE_FALLING_BLOCK && $this->armorInventory->getHelmet() instanceof Armor){
$source->setModifier(-($source->getFinalDamage() / 4), EntityDamageEvent::MODIFIER_ARMOR_HELMET);
}
} }
/** /**
@ -460,6 +465,15 @@ abstract class Living extends Entity{
if($damage > 0){ if($damage > 0){
$attacker->attack(new EntityDamageByEntityEvent($this, $attacker, EntityDamageEvent::CAUSE_MAGIC, $damage)); $attacker->attack(new EntityDamageByEntityEvent($this, $attacker, EntityDamageEvent::CAUSE_MAGIC, $damage));
} }
if($source->getModifier(EntityDamageEvent::MODIFIER_ARMOR_HELMET) < 0){
$helmet = $this->armorInventory->getHelmet();
if($helmet instanceof Armor){
$finalDamage = $source->getFinalDamage();
$this->damageItem($helmet, (int) round($finalDamage * 4 + lcg_value() * $finalDamage * 2));
$this->armorInventory->setHelmet($helmet);
}
}
} }
} }

View File

@ -30,8 +30,10 @@ use pocketmine\data\bedrock\block\BlockStateDeserializeException;
use pocketmine\data\SavedDataLoadingException; use pocketmine\data\SavedDataLoadingException;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\entity\EntitySizeInfo; use pocketmine\entity\EntitySizeInfo;
use pocketmine\entity\Living;
use pocketmine\entity\Location; use pocketmine\entity\Location;
use pocketmine\event\entity\EntityBlockChangeEvent; use pocketmine\event\entity\EntityBlockChangeEvent;
use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\math\Vector3; use pocketmine\math\Vector3;
use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\ByteTag;
@ -44,6 +46,8 @@ use pocketmine\network\mcpe\protocol\types\entity\EntityMetadataProperties;
use pocketmine\world\format\io\GlobalBlockStateHandlers; use pocketmine\world\format\io\GlobalBlockStateHandlers;
use pocketmine\world\sound\BlockBreakSound; use pocketmine\world\sound\BlockBreakSound;
use function abs; use function abs;
use function min;
use function round;
class FallingBlock extends Entity{ class FallingBlock extends Entity{
private const TAG_FALLING_BLOCK = "FallingBlock"; //TAG_Compound private const TAG_FALLING_BLOCK = "FallingBlock"; //TAG_Compound
@ -156,8 +160,20 @@ class FallingBlock extends Entity{
} }
protected function onHitGround() : ?float{ protected function onHitGround() : ?float{
if($this->block instanceof Fallable && !$this->block->onHitGround($this)){ if($this->block instanceof Fallable){
$this->flagForDespawn(); $damagePerBlock = $this->block->getFallDamagePerBlock();
if($damagePerBlock > 0 && ($fallenBlocks = round($this->fallDistance) - 1) > 0){
$damage = min($fallenBlocks * $damagePerBlock, $this->block->getMaxFallDamage());
foreach($this->getWorld()->getCollidingEntities($this->getBoundingBox()) as $entity){
if($entity instanceof Living){
$ev = new EntityDamageByEntityEvent($this, $entity, EntityDamageEvent::CAUSE_FALLING_BLOCK, $damage);
$entity->attack($ev);
}
}
}
if(!$this->block->onHitGround($this)){
$this->flagForDespawn();
}
} }
return null; return null;
} }

View File

@ -46,6 +46,7 @@ class EntityDamageEvent extends EntityEvent implements Cancellable{
public const MODIFIER_TOTEM = 8; public const MODIFIER_TOTEM = 8;
public const MODIFIER_WEAPON_ENCHANTMENTS = 9; public const MODIFIER_WEAPON_ENCHANTMENTS = 9;
public const MODIFIER_PREVIOUS_DAMAGE_COOLDOWN = 10; public const MODIFIER_PREVIOUS_DAMAGE_COOLDOWN = 10;
public const MODIFIER_ARMOR_HELMET = 11;
public const CAUSE_CONTACT = 0; public const CAUSE_CONTACT = 0;
public const CAUSE_ENTITY_ATTACK = 1; public const CAUSE_ENTITY_ATTACK = 1;
@ -63,6 +64,7 @@ class EntityDamageEvent extends EntityEvent implements Cancellable{
public const CAUSE_MAGIC = 13; public const CAUSE_MAGIC = 13;
public const CAUSE_CUSTOM = 14; public const CAUSE_CUSTOM = 14;
public const CAUSE_STARVATION = 15; public const CAUSE_STARVATION = 15;
public const CAUSE_FALLING_BLOCK = 16;
private float $baseDamage; private float $baseDamage;
private float $originalBase; private float $originalBase;

View File

@ -25,6 +25,7 @@ namespace pocketmine\event\player;
use pocketmine\block\BlockTypeIds; use pocketmine\block\BlockTypeIds;
use pocketmine\entity\Living; use pocketmine\entity\Living;
use pocketmine\entity\object\FallingBlock;
use pocketmine\event\entity\EntityDamageByBlockEvent; use pocketmine\event\entity\EntityDamageByBlockEvent;
use pocketmine\event\entity\EntityDamageByEntityEvent; use pocketmine\event\entity\EntityDamageByEntityEvent;
use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityDamageEvent;
@ -155,6 +156,19 @@ class PlayerDeathEvent extends EntityDeathEvent{
case EntityDamageEvent::CAUSE_MAGIC: case EntityDamageEvent::CAUSE_MAGIC:
return KnownTranslationFactory::death_attack_magic($name); return KnownTranslationFactory::death_attack_magic($name);
case EntityDamageEvent::CAUSE_FALLING_BLOCK:
if($deathCause instanceof EntityDamageByEntityEvent){
$e = $deathCause->getDamager();
if($e instanceof FallingBlock){
if($e->getBlock()->getTypeId() === BlockTypeIds::ANVIL){
return KnownTranslationFactory::death_attack_anvil($name);
}else{
return KnownTranslationFactory::death_attack_fallingBlock($name);
}
}
}
break;
case EntityDamageEvent::CAUSE_CUSTOM: case EntityDamageEvent::CAUSE_CUSTOM:
break; break;