mirror of
https://github.com/pmmp/PocketMine-MP.git
synced 2025-07-11 04:17:48 +00:00
Implement frost walker enchantment (#5497)
Co-authored-by: Dylan T. <dktapps@pmmp.io>
This commit is contained in:
parent
f3763ae691
commit
f1a3b42620
@ -39,7 +39,7 @@ class Magma extends Opaque{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function onEntityInside(Entity $entity) : bool{
|
public function onEntityInside(Entity $entity) : bool{
|
||||||
if($entity instanceof Living && !$entity->isSneaking()){
|
if($entity instanceof Living && !$entity->isSneaking() && $entity->getFrostWalkerLevel() === 0){
|
||||||
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
$ev = new EntityDamageByBlockEvent($this, $entity, EntityDamageEvent::CAUSE_FIRE, 1);
|
||||||
$entity->attack($ev);
|
$entity->attack($ev);
|
||||||
}
|
}
|
||||||
|
@ -66,5 +66,7 @@ final class EnchantmentIdMap{
|
|||||||
$this->register(EnchantmentIds::VANISHING, VanillaEnchantments::VANISHING());
|
$this->register(EnchantmentIds::VANISHING, VanillaEnchantments::VANISHING());
|
||||||
|
|
||||||
$this->register(EnchantmentIds::SWIFT_SNEAK, VanillaEnchantments::SWIFT_SNEAK());
|
$this->register(EnchantmentIds::SWIFT_SNEAK, VanillaEnchantments::SWIFT_SNEAK());
|
||||||
|
|
||||||
|
$this->register(EnchantmentIds::FROST_WALKER, VanillaEnchantments::FROST_WALKER());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,8 @@ namespace pocketmine\entity;
|
|||||||
|
|
||||||
use pocketmine\block\Block;
|
use pocketmine\block\Block;
|
||||||
use pocketmine\block\BlockTypeIds;
|
use pocketmine\block\BlockTypeIds;
|
||||||
|
use pocketmine\block\VanillaBlocks;
|
||||||
|
use pocketmine\block\Water;
|
||||||
use pocketmine\data\bedrock\EffectIdMap;
|
use pocketmine\data\bedrock\EffectIdMap;
|
||||||
use pocketmine\entity\animation\DeathAnimation;
|
use pocketmine\entity\animation\DeathAnimation;
|
||||||
use pocketmine\entity\animation\HurtAnimation;
|
use pocketmine\entity\animation\HurtAnimation;
|
||||||
@ -44,6 +46,7 @@ use pocketmine\item\Durable;
|
|||||||
use pocketmine\item\enchantment\Enchantment;
|
use pocketmine\item\enchantment\Enchantment;
|
||||||
use pocketmine\item\enchantment\VanillaEnchantments;
|
use pocketmine\item\enchantment\VanillaEnchantments;
|
||||||
use pocketmine\item\Item;
|
use pocketmine\item\Item;
|
||||||
|
use pocketmine\math\AxisAlignedBB;
|
||||||
use pocketmine\math\Vector3;
|
use pocketmine\math\Vector3;
|
||||||
use pocketmine\math\VoxelRayTrace;
|
use pocketmine\math\VoxelRayTrace;
|
||||||
use pocketmine\nbt\tag\CompoundTag;
|
use pocketmine\nbt\tag\CompoundTag;
|
||||||
@ -64,6 +67,7 @@ use pocketmine\world\sound\EntityLandSound;
|
|||||||
use pocketmine\world\sound\EntityLongFallSound;
|
use pocketmine\world\sound\EntityLongFallSound;
|
||||||
use pocketmine\world\sound\EntityShortFallSound;
|
use pocketmine\world\sound\EntityShortFallSound;
|
||||||
use pocketmine\world\sound\ItemBreakSound;
|
use pocketmine\world\sound\ItemBreakSound;
|
||||||
|
use function abs;
|
||||||
use function array_shift;
|
use function array_shift;
|
||||||
use function atan2;
|
use function atan2;
|
||||||
use function ceil;
|
use function ceil;
|
||||||
@ -128,6 +132,8 @@ abstract class Living extends Entity{
|
|||||||
protected bool $gliding = false;
|
protected bool $gliding = false;
|
||||||
protected bool $swimming = false;
|
protected bool $swimming = false;
|
||||||
|
|
||||||
|
private ?int $frostWalkerLevel = null;
|
||||||
|
|
||||||
protected function getInitialDragMultiplier() : float{ return 0.02; }
|
protected function getInitialDragMultiplier() : float{ return 0.02; }
|
||||||
|
|
||||||
protected function getInitialGravity() : float{ return 0.08; }
|
protected function getInitialGravity() : float{ return 0.08; }
|
||||||
@ -151,6 +157,14 @@ abstract class Living extends Entity{
|
|||||||
$this->getViewers(),
|
$this->getViewers(),
|
||||||
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onMobArmorChange($recipients, $this)
|
fn(EntityEventBroadcaster $broadcaster, array $recipients) => $broadcaster->onMobArmorChange($recipients, $this)
|
||||||
)));
|
)));
|
||||||
|
$this->armorInventory->getListeners()->add(new CallbackInventoryListener(
|
||||||
|
onSlotChange: function(Inventory $inventory, int $slot) : void{
|
||||||
|
if($slot === ArmorInventory::SLOT_FEET){
|
||||||
|
$this->frostWalkerLevel = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onContentChange: function() : void{ $this->frostWalkerLevel = null; }
|
||||||
|
));
|
||||||
|
|
||||||
$health = $this->getMaxHealth();
|
$health = $this->getMaxHealth();
|
||||||
|
|
||||||
@ -687,6 +701,47 @@ abstract class Living extends Entity{
|
|||||||
return $hasUpdate;
|
return $hasUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function move(float $dx, float $dy, float $dz) : void{
|
||||||
|
$oldX = $this->location->x;
|
||||||
|
$oldZ = $this->location->z;
|
||||||
|
|
||||||
|
parent::move($dx, $dy, $dz);
|
||||||
|
|
||||||
|
$frostWalkerLevel = $this->getFrostWalkerLevel();
|
||||||
|
if($frostWalkerLevel > 0 && (abs($this->location->x - $oldX) > self::MOTION_THRESHOLD || abs($this->location->z - $oldZ) > self::MOTION_THRESHOLD)){
|
||||||
|
$this->applyFrostWalker($frostWalkerLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function applyFrostWalker(int $level) : void{
|
||||||
|
$radius = $level + 2;
|
||||||
|
$world = $this->getWorld();
|
||||||
|
|
||||||
|
$baseX = $this->location->getFloorX();
|
||||||
|
$y = $this->location->getFloorY() - 1;
|
||||||
|
$baseZ = $this->location->getFloorZ();
|
||||||
|
|
||||||
|
$frostedIce = VanillaBlocks::FROSTED_ICE();
|
||||||
|
for($x = $baseX - $radius; $x <= $baseX + $radius; $x++){
|
||||||
|
for($z = $baseZ - $radius; $z <= $baseZ + $radius; $z++){
|
||||||
|
$block = $world->getBlockAt($x, $y, $z);
|
||||||
|
if(
|
||||||
|
!$block instanceof Water ||
|
||||||
|
!$block->isSource() ||
|
||||||
|
$world->getBlockAt($x, $y + 1, $z)->getTypeId() !== BlockTypeIds::AIR ||
|
||||||
|
count($world->getNearbyEntities(AxisAlignedBB::one()->offset($x, $y, $z))) !== 0
|
||||||
|
){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$world->setBlockAt($x, $y, $z, $frostedIce);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFrostWalkerLevel() : int{
|
||||||
|
return $this->frostWalkerLevel ??= $this->armorInventory->getBoots()->getEnchantmentLevel(VanillaEnchantments::FROST_WALKER());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ticks the entity's air supply, consuming it when underwater and regenerating it when out of water.
|
* Ticks the entity's air supply, consuming it when underwater and regenerating it when out of water.
|
||||||
*/
|
*/
|
||||||
|
@ -57,6 +57,7 @@ final class AvailableEnchantmentRegistry{
|
|||||||
$this->register(Enchantments::THORNS(), [Tags::CHESTPLATE], [Tags::HELMET, Tags::LEGGINGS, Tags::BOOTS]);
|
$this->register(Enchantments::THORNS(), [Tags::CHESTPLATE], [Tags::HELMET, Tags::LEGGINGS, Tags::BOOTS]);
|
||||||
$this->register(Enchantments::RESPIRATION(), [Tags::HELMET], []);
|
$this->register(Enchantments::RESPIRATION(), [Tags::HELMET], []);
|
||||||
$this->register(Enchantments::AQUA_AFFINITY(), [Tags::HELMET], []);
|
$this->register(Enchantments::AQUA_AFFINITY(), [Tags::HELMET], []);
|
||||||
|
$this->register(Enchantments::FROST_WALKER(), [/* no primary items */], [Tags::BOOTS]);
|
||||||
$this->register(Enchantments::SHARPNESS(), [Tags::SWORD, Tags::AXE], []);
|
$this->register(Enchantments::SHARPNESS(), [Tags::SWORD, Tags::AXE], []);
|
||||||
$this->register(Enchantments::KNOCKBACK(), [Tags::SWORD], []);
|
$this->register(Enchantments::KNOCKBACK(), [Tags::SWORD], []);
|
||||||
$this->register(Enchantments::FIRE_ASPECT(), [Tags::SWORD], []);
|
$this->register(Enchantments::FIRE_ASPECT(), [Tags::SWORD], []);
|
||||||
|
@ -44,6 +44,7 @@ final class StringToEnchantmentParser extends StringToTParser{
|
|||||||
$result->register("fire_protection", fn() => VanillaEnchantments::FIRE_PROTECTION());
|
$result->register("fire_protection", fn() => VanillaEnchantments::FIRE_PROTECTION());
|
||||||
$result->register("flame", fn() => VanillaEnchantments::FLAME());
|
$result->register("flame", fn() => VanillaEnchantments::FLAME());
|
||||||
$result->register("fortune", fn() => VanillaEnchantments::FORTUNE());
|
$result->register("fortune", fn() => VanillaEnchantments::FORTUNE());
|
||||||
|
$result->register("frost_walker", fn() => VanillaEnchantments::FROST_WALKER());
|
||||||
$result->register("infinity", fn() => VanillaEnchantments::INFINITY());
|
$result->register("infinity", fn() => VanillaEnchantments::INFINITY());
|
||||||
$result->register("knockback", fn() => VanillaEnchantments::KNOCKBACK());
|
$result->register("knockback", fn() => VanillaEnchantments::KNOCKBACK());
|
||||||
$result->register("mending", fn() => VanillaEnchantments::MENDING());
|
$result->register("mending", fn() => VanillaEnchantments::MENDING());
|
||||||
|
@ -41,6 +41,7 @@ use pocketmine\utils\RegistryTrait;
|
|||||||
* @method static ProtectionEnchantment FIRE_PROTECTION()
|
* @method static ProtectionEnchantment FIRE_PROTECTION()
|
||||||
* @method static Enchantment FLAME()
|
* @method static Enchantment FLAME()
|
||||||
* @method static Enchantment FORTUNE()
|
* @method static Enchantment FORTUNE()
|
||||||
|
* @method static Enchantment FROST_WALKER()
|
||||||
* @method static Enchantment INFINITY()
|
* @method static Enchantment INFINITY()
|
||||||
* @method static KnockbackEnchantment KNOCKBACK()
|
* @method static KnockbackEnchantment KNOCKBACK()
|
||||||
* @method static Enchantment MENDING()
|
* @method static Enchantment MENDING()
|
||||||
@ -145,6 +146,16 @@ final class VanillaEnchantments{
|
|||||||
fn(int $level) : int => 10 * $level,
|
fn(int $level) : int => 10 * $level,
|
||||||
30
|
30
|
||||||
));
|
));
|
||||||
|
|
||||||
|
self::register("FROST_WALKER", new Enchantment(
|
||||||
|
KnownTranslationFactory::enchantment_frostwalker(),
|
||||||
|
Rarity::RARE,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
2,
|
||||||
|
fn(int $level) : int => 10 * $level,
|
||||||
|
15
|
||||||
|
));
|
||||||
self::register("AQUA_AFFINITY", new Enchantment(
|
self::register("AQUA_AFFINITY", new Enchantment(
|
||||||
KnownTranslationFactory::enchantment_waterWorker(),
|
KnownTranslationFactory::enchantment_waterWorker(),
|
||||||
Rarity::RARE,
|
Rarity::RARE,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user