diff --git a/README.md b/README.md index 591c89b..78b7842 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Build a structure like this one: (be sure to place the pumpkin in last!) -Afterwards let the boss fight go! +Afterwards let the boss fight go! Music used here: NIVIRO - The Return Track's link: https://soundcloud.com/djniviro/thereturn diff --git a/config.yml b/config.yml deleted file mode 100644 index 22d7e6e..0000000 --- a/config.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -# This is the default config generated with ImagicalPlugCreator. (C) ImagicalPlugCreator - Ad5001 2016 -... \ No newline at end of file diff --git a/resources/Spooky.mcpack b/resources/Spooky.mcpack new file mode 100644 index 0000000..87fb71f Binary files /dev/null and b/resources/Spooky.mcpack differ diff --git a/resources/config.yml b/resources/config.yml deleted file mode 100644 index 22d7e6e..0000000 --- a/resources/config.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -# This is the default config generated with ImagicalPlugCreator. (C) ImagicalPlugCreator - Ad5001 2016 -... \ No newline at end of file diff --git a/src/Ad5001/Spooky/Main.php b/src/Ad5001/Spooky/Main.php index 183d621..aecc7fb 100644 --- a/src/Ad5001/Spooky/Main.php +++ b/src/Ad5001/Spooky/Main.php @@ -5,15 +5,20 @@ use pocketmine\command\Command; use pocketmine\plugin\PluginBase; use pocketmine\Server; use pocketmine\Player; +use pocketmine\entity\Entity; use pocketmine\event\Listener; use pocketmine\item\enchantment\Enchantment; use pocketmine\event\block\BlockPlaceEvent; +use pocketmine\network\mcpe\protocol\PlaySoundPacket; use pocketmine\block\Block; +use pocketmine\resourcepacks\ZippedResourcePack; use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\tag\FloatTag; +use pocketmine\nbt\tag\DoubleTag; +use pocketmine\nbt\tag\ShortTag; use pocketmine\nbt\NBT; @@ -33,8 +38,30 @@ class Main extends PluginBase implements Listener{ public function onEnable(){ // Registering some enchants Enchantment::registerEnchantment(new Enchantment(Enchantment::SHARPNESS, "%enchantment.attack.sharpness", Enchantment::ACTIVATION_HELD, Enchantment::RARITY_COMMON, Enchantment::SLOT_SWORD)); + Entity::registerEntity(Ghost::class, true, ['Ghost', 'minecraft:ghost']); $this->getServer()->getScheduler()->scheduleRepeatingTask(new TickTask($this), 2); $this->getServer()->getPluginManager()->registerEvents($this, $this); + // Resource pack + $this->saveResource("Spooky.mcpack"); + $pack = new ZippedResourcePack($this->getDataFolder() . "Spooky.mcpack"); + $r = new \ReflectionClass("pocketmine\\resourcepacks\\ResourcePackManager"); + if($pack instanceof \pocketmine\resourcepacks\ResourcePack){ + // Reflection because devs thought it was a great idea to not let plugins manage resource packs :/ + $resourcePacks = $r->getProperty("resourcePacks"); + $resourcePacks->setAccessible(true); + $rps = $resourcePacks->getValue($this->getServer()->getResourceManager()); + $rps[] = $pack; + $resourcePacks->setValue($this->getServer()->getResourceManager(), $rps); + $resourceUuids = $r->getProperty("uuidList"); + $resourceUuids->setAccessible(true); + $uuids = $resourceUuids->getValue($this->getServer()->getResourceManager()); + $uuids[$pack->getPackId()] = $pack; + $resourceUuids->setValue($this->getServer()->getResourceManager(), $uuids); + // Forcing resource packs. We want the client to hear the music! + $forceResources = $r->getProperty("serverForceResources"); + $forceResources->setAccessible(true); + $forceResources->setValue($this->getServer()->getResourceManager(), true); + } } /** @@ -63,7 +90,7 @@ class Main extends PluginBase implements Listener{ $under->y--; // Hay bale for the body if($event->getBlock()->getLevel()->getBlock($under)->getId() == Block::HAY_BALE) { - $under2 = $event->getBlock()->asVector3(); + $under2 = $under->asVector3(); $under2->y--; // Fence for the bottom if($event->getBlock()->getLevel()->getBlock($under2)->getId() == Block::FENCE){ @@ -93,8 +120,16 @@ class Main extends PluginBase implements Listener{ $event->getBlock()->getLevel()->setBlock($under2, Block::get(Block::AIR)); $event->getBlock()->getLevel()->setBlock($side1, Block::get(Block::AIR)); $event->getBlock()->getLevel()->setBlock($side2, Block::get(Block::AIR)); - if($event->getPlayer()){ + if($event->getPlayer() !== null){ $this->spawnGhost($event->getPlayer()); + // Spawning an another ghost for the surround players. It's more challenging :p + foreach($this->getServer()->getOnlinePlayers() as $p) { + if($p->getLevel()->getName() == $event->getPlayer()->getLevel()->getName() && $p->getName() !== $event->getPlayer()->getName()) { + if($p->distance($event->getPlayer()) <= 10) { + $this->spawnGhost($p); + } + } + } } } } @@ -109,12 +144,12 @@ class Main extends PluginBase implements Listener{ public function spawnGhost(Player $p){ // Getting the skin $nbtSkin = new NBT(NBT::BIG_ENDIAN); - $nbtSkin->readCompressed(fread($this->getResource("ghost_player_data.dat"))); + $nbtSkin->readCompressed(file_get_contents($this->getFile() . "resources/ghost_player_data.dat")); $nbt = new CompoundTag(); $nbt->Pos = new ListTag("Pos", [ - new DoubleTag("", $player->getX()), - new DoubleTag("", $player->getY()), - new DoubleTag("", $player->getZ()) + new DoubleTag("", $p->getX()), + new DoubleTag("", $p->getY()), + new DoubleTag("", $p->getZ()) ]); $nbt->Motion = new ListTag("Motion", [ new DoubleTag("", 0), @@ -122,15 +157,35 @@ class Main extends PluginBase implements Listener{ new DoubleTag("", 0) ]); $nbt->Rotation = new ListTag("Rotation", [ - new FloatTag("", $player->getYaw()), - new FloatTag("", $player->getPitch()) - ]); + new FloatTag("", $p->getYaw()), + new FloatTag("", $p->getPitch()) + ]); + // var_dump($nbtSkin); $nbt->Health = new ShortTag("Health", 20); - $player->saveNBT(); - $nbt->Skin = clone $nbtSkin->Skin; - $nbt->Inventory = clone $nbtSkin->Inventory; - $g = new Ghost($p->getLevel(), $nbt); + $nbt->Skin = clone $nbtSkin->getData()->Skin; + $nbt->Inventory = clone $nbtSkin->getData()->Inventory; + $g = Entity::createEntity("Ghost", $p->getLevel(), $nbt); $g->startFight($p); $this->ghosts[$p->getName()] = $g; } + + + + public function onEntityDamage(\pocketmine\event\entity\EntityDamageEvent $event){ + if($event instanceof \pocketmine\event\entity\EntityDamageByEntityEvent && $event->getDamager() instanceof Player){ + if(isset($event->getDamager()->getInventory()->getItemInHand()->getNamedTag()->customDamage)) { + $event->setDamage($event->getDamager()->getInventory()->getItemInHand()->namedtag->customDamage->getValue()); + } + if(isset($event->getDamager()->getInventory()->getItemInHand()->getNamedTag()->sneakInvisible) && $event->getEntity() instanceof Player) { + $pk = new PlaySoundPacket(); + $pk->soundName = "mob.wither.death"; + $pk->x = (int)$event->getEntity()->x; + $pk->y = (int)$event->getEntity()->y; + $pk->z = (int)$event->getEntity()->z; + $pk->volume = 3; + $pk->pitch = 1; + $event->getEntity()->dataPacket($pk); + } + } + } } \ No newline at end of file diff --git a/src/Ad5001/Spooky/entity/Ghost.php b/src/Ad5001/Spooky/entity/Ghost.php index dcd8653..0106e3e 100644 --- a/src/Ad5001/Spooky/entity/Ghost.php +++ b/src/Ad5001/Spooky/entity/Ghost.php @@ -5,10 +5,16 @@ use pocketmine\Player; use pocketmine\entity\Entity; use pocketmine\item\Item; use pocketmine\item\enchantment\Enchantment; +use pocketmine\level\Level; use pocketmine\entity\Human; +use pocketmine\block\Block; use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityDamageByEntityEvent; +use pocketmine\network\mcpe\protocol\AddPlayerPacket; +use pocketmine\network\mcpe\protocol\PlaySoundPacket; +use pocketmine\network\mcpe\protocol\EntityEventPacket; +use pocketmine\network\mcpe\protocol\MovePlayerPacket; use pocketmine\math\Vector3; @@ -18,6 +24,7 @@ use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\DoubleTag; use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\StringTag; +use pocketmine\nbt\tag\CompoundTag; use pocketmine\entity\Effect; use Ad5001\Spooky\Main; @@ -28,16 +35,16 @@ use Ad5001\Spooky\tasks\TickTask; class Ghost extends Human { - /** - * 0: Not fighting - * 1: Simple fight - * - * @var integer - */ - protected $fightType = 0; + const NETWORK_ID = -1; + protected $associatedPlayer = null; + protected $moveTime = 0; + + public $attCooldown = 0; + public $attackCooldown = 0; + /** * Constructs the class * @@ -45,7 +52,7 @@ class Ghost extends Human { * @param CompoundTag $nbt */ public function __construct(Level $level, CompoundTag $nbt) { - $this->setDataProperty(self::DATA_SCALE, self::DATA_TYPE_FLOAT, new FloatTag("Scale", 1.2)); + $this->setDataProperty(self::DATA_SCALE, self::DATA_TYPE_FLOAT, /*new FloatTag("Scale", */1.2); parent::__construct($level, $nbt); $it = Item::get(Item::GOLDEN_HOE, 0); $it->addEnchantment(Enchantment::getEnchantment(Enchantment::SHARPNESS)); @@ -67,7 +74,7 @@ class Ghost extends Human { * @return float */ public function getSpeed(): float { - return $this->fightType * 2; + return 2; } @@ -81,13 +88,20 @@ class Ghost extends Human { * @param Player $player */ public function startFight(Player $p) { - $p->getLevel()->addSound(new TheReturnMusicPlay($p->asVector3()), [$p->getViewers()]); + $pk = new PlaySoundPacket(); + $pk->soundName = "mob.armor_stand.hit"; + $pk->x = (int)$p->x; + $pk->y = (int)$p->y; + $pk->z = (int)$p->z; + $pk->volume = 500; + $pk->pitch = 1; + $p->dataPacket($pk); // Only after the ghost appeared, we can remove it. - Effect::getEffectById(Effect::BLINDNESS)->setDuration(66*20)->setVisible(false)->add($p); - Effect::getEffectById(Effect::INVISIBILITY)->setDuration(63*20)->setVisible(false)->add($this); - $this->spawnTo($p); + Effect::getEffect(Effect::BLINDNESS)->setDuration(66*20)->setVisible(false)->add($p); + // $p->addEffect(Effect::getEffect(Effect::SLOWNESS)->setDuration(30*20)->setAmplifier(5)->setVisible(false)); $this->associatedPlayer = $p; TickTask::registerGhost($this); + $p->sendPopup("Music: The Return by Niviro, www.djniviro.com"); } /** @@ -98,7 +112,6 @@ class Ghost extends Human { public function intenseFight(){ if(!$this->checkIfConnected()) return; // TODO: Custom intense fight - $this->fightType = 1; } /** @@ -108,7 +121,6 @@ class Ghost extends Human { */ public function calmFight(){ if(!$this->checkIfConnected()) return; - $this->fightType = 1; } /** @@ -117,35 +129,25 @@ class Ghost extends Human { * in front of the player. * @return void */ - public function blackOutEnterPhase(){ + public function scareEnterPhase(){ if(!$this->checkIfConnected()) return; - $this->fightType = 0; $spawnBlock = $this->getPlayer()->getLineOfSight(2); $spawnBlock = $spawnBlock[count($spawnBlock) -1]; $this->getPlayer()->addEffect( - Effect::getEffectById(Effect::BLINDNESS)->setDuration(30*20)->setAmplifier(4)->setVisible(false) + Effect::getEffect(Effect::BLINDNESS)->setDuration(3*20)->setAmplifier(4)->setVisible(false) ); + /*$this->getPlayer()->addEffect( + Effect::getEffect(Effect::SLOWNESS)->setDuration(3*20)->setAmplifier(10)->setVisible(false) + );*/ $this->getPlayer()->addEffect( - Effect::getEffectById(Effect::SLOWNESS)->setDuration(30*20)->setAmplifier(99)->setVisible(false) + Effect::getEffect(Effect::NAUSEA)->setDuration(3*20)->setAmplifier(10)->setVisible(false) ); - $this->getPlayer()->addEffect( - Effect::getEffectById(Effect::NAUSEA)->setDuration(30*20)->setAmplifier(99)->setVisible(false) - ); - $this->teleport(new Vector3($spawnBlock->x, $spawnBlock->y, $spawnBlock->z), abs($this->getPlayer()->getYaw() - 180)); - $this->removeEffect(Effect::INVISIBILITY); - } - - /** - * Ends a sequence where the ghost blinds the player, - * slows him down (zooming effect w/ fov) and he appears invuulnerable - * in front of the player. - * @return void - */ - public function blackOutExitPhase(){ - if(!$this->checkIfConnected()) return; - $this->getPlayer()->removeEffect(Effect::BLINDNESS); - $this->getPlayer()->removeEffect(Effect::NAUSEA); - $this->getPlayer()->removeEffect(Effect::SLOWNESS); + if($this->getLevel()->getBlock(new Vector3($spawnBlock->x, $spawnBlock->y, $spawnBlock->z))->getId() !== 0) { + $this->teleport(new Vector3($spawnBlock->x, $spawnBlock->y + 1, $spawnBlock->z), abs($this->getPlayer()->getYaw() - 180)); + } else { + $this->teleport(new Vector3($spawnBlock->x, $spawnBlock->y, $spawnBlock->z), abs($this->getPlayer()->getYaw() - 180)); + } + $this->broadcastNewPos(); } /** @@ -156,9 +158,9 @@ class Ghost extends Human { */ public function movePlayerRandomly(){ if(!$this->checkIfConnected()) return; - $this->fightType = 0; - for($i = 0; $i < 10; $i++){ - $this->associatedPlayer->setMotion(new Vector3(rand() - rand(), 0, rand() - rand())); + if(rand(0,20) == 1) { + echo "\nMove ya!\n"; + $this->associatedPlayer->teleport(new Vector3($this->associatedPlayer->x + rand(0, 3) - rand(0, 3), $this->associatedPlayer->y, $this->associatedPlayer->z + rand(0, 3) - rand(0, 3))); } } @@ -170,9 +172,8 @@ class Ghost extends Human { */ public function destroyBlocksRandomly(){ if(!$this->checkIfConnected()) return; - $this->fightType = 0; - $this->teleport(new Vector3($this->getPlayer()->x, $this->getPlayer()->y + 7, $this->getPlayer()->z), $this->yaw == 0 ? 359 : $this->yaw - 1, 130); - srand(hash("sha512", time())); + $this->teleport(new Vector3($this->getPlayer()->x, $this->getPlayer()->y + 3, $this->getPlayer()->z), $this->yaw == 0 ? 359 : $this->yaw - 1, 130); + srand(time()); foreach($this->getLevel()->getEntities() as $et){ if($et instanceof \pocketmine\entity\FallingSand && $et->namedtag->getInt("SpawnTime") !== $null){ $diffTime = time() - $et->namedtag->getInt("SpawnTime"); @@ -180,12 +181,27 @@ class Ghost extends Human { } } for($i = 0; $i < 3; $i++) { - $rx = rand(0, 12) - 6; - $rz = rand(0, 12) - 6; - for($ry = 128; $this->getLevel()->getBlock($rx, $ry, $rz)->getId() !== 0 || $ry == 0; $ry--){} // Determining y from the higthest workable block - $b = $this->getLevel()->getBlock($rx, $ry, $rz); + $rx = rand(0, 12) - 6 + $this->getPlayer()->x; + $rz = rand(0, 12) - 6 + $this->getPlayer()->z; + for($ry = 128; $this->getLevel()->getBlock(new Vector3($rx, $ry, $rz))->getId() !== 0 || $ry == 0; $ry--){} // Determining y from the higthest workable block + $b = $this->getLevel()->getBlock(new Vector3($rx, $ry, $rz)); // Creating falling sand block - $nbt = Entity::createBaseNBT($b->asVector3()->add(0.5, 0, 0.5)); + $nbt = new CompoundTag("", [ + new ListTag("Pos", [ + new DoubleTag("", $b->x + 0,5), + new DoubleTag("", $b->y), + new DoubleTag("", $b->z + 0,5) + ]), + new ListTag("Motion", [ + new DoubleTag("", 0), + new DoubleTag("", 10), + new DoubleTag("", 0) + ]), + new ListTag("Rotation", [ + new FloatTag("", 0), + new FloatTag("", 0) + ]) + ]);; $nbt->setInt("TileID", $b->getId()); $nbt->setInt("SpawnTime", time()); $nbt->setByte("Data", $b->getDamage()); @@ -194,6 +210,7 @@ class Ghost extends Human { if($fall !== null){ $fall->spawnToAll(); } + $this->getLevel()->setBlock(new Vector3($rx, $ry, $rz), Block::get(Block::AIR)); } } @@ -204,7 +221,7 @@ class Ghost extends Human { * @return void */ public function checkIfConnected(){ - if(!$this->associatedPlayer->isOnline()){ + if($this->associatedPlayer == null || !$this->associatedPlayer->isOnline()){ TickTask::unregisterGhost($this); $this->close(); return false; @@ -222,40 +239,54 @@ class Ghost extends Human { if(!isset($this->hasSpawned[$player->getLoaderId()]) && isset($player->usedChunks[Level::chunkHash($this->chunk->getX(), $this->chunk->getZ())])) { $this->hasSpawned[$player->getLoaderId()] = $player; - $uuid = $this->getUniqueId(); - $entityId = $this->getId(); $pk = new AddPlayerPacket(); - $pk->uuid = $uuid; $pk->username = ""; - $pk->entityRuntimeId = $entityId; + $pk->uuid = $this->getUniqueId(); + $pk->entityRuntimeId = $this->getId(); $pk->position = $this->asVector3(); $pk->yaw = $this->yaw; $pk->pitch = $this->pitch; $pk->item = $this->getInventory()->getItemInHand(); $pk->metadata = $this->dataProperties; - $pk->metadata[self::DATA_NAMETAG] = [self::DATA_TYPE_STRING, $this->getDisplayName($player)]; + $pk->metadata[self::DATA_NAMETAG] = [self::DATA_TYPE_STRING, "§kThe Ghost"]; $player->dataPacket($pk); $this->inventory->sendArmorContents($player); - $player->getServer()->updatePlayerListData($uuid, $entityId, "The Ghost", $this->skinId, $this->skin, [$player]); + $player->getServer()->updatePlayerListData($this->getUniqueId(), $this->getId(), "§kThe Ghost", $this->skin, [$player]); } } // Event listeners /** - * Check the damage to reduce it by 25% + * Check the damage to reduce it by 55% * * @param EntityDamageEvent $event */ public function attack(EntityDamageEvent $event) { if($event instanceof EntityDamageByEntityEvent) { - if($event->getDamager() instanceof Player && $event->getDamager()){ - $event->setDamage($event->getDamage() * 0.75); + if($event->getDamager() instanceof Player && $event->getDamager()->getName() == $this->getPlayer()->getName()){ + if($this->attCooldown == 0){ + $event->setDamage($event->getDamage() * 0.083); + $deltaX = $this->x - $event->getDamager()->x; + $deltaZ = $this->z - $event->getDamager()->z; + $this->knockBack($event->getDamager(), $event->getDamage(), $this->x - $event->getDamager()->x, $this->z - $event->getDamager()->z, $event->getKnockBack()); + $this->setLastDamageCause($event); + $this->setHealth($this->getHealth() - $event->getFinalDamage()); + $pk = new EntityEventPacket(); + $pk->entityRuntimeId = $this->getId(); + $pk->event = $this->getHealth() <= 0 ? EntityEventPacket::DEATH_ANIMATION : EntityEventPacket::HURT_ANIMATION; //Ouch! + $this->getPlayer()->dataPacket($pk); + if(!$this->isAlive()) { + $this->getPlayer()->sendMessage("You got me! Happy halloween!"); + $this->close(); + TickTask::unregisterGhost($this); + } + $this->attCooldown = 5; //0.25s + } } else { $event->setCancelled(true); - $event->getDamager()->motionY = 12; $event->getDamager()->addEffect( - Effect::getEffectById(Effect::NAUSEA)->setDuration(30*20)->setAmplifier(99)->setVisible(false) + Effect::getEffect(Effect::NAUSEA)->setDuration(30*20)->setAmplifier(99)->setVisible(false) ); } } @@ -269,47 +300,64 @@ class Ghost extends Human { */ public function onUpdate(int $currentTick): bool { if(!$this->checkIfConnected()) return false; - if($this->fightType == 0) return false; + if($this->attCooldown > 0) $this->attCooldown--; + if($this->attackCooldown > 0) $this->attackCooldown--; // Teleportation if(rand(0, 200) == 0) { // Do we do teleportation? if(rand(0,1) == 0){ // Which kind of tp? Random around or forward? $los = $this->getLineOfSight(10); $b = $los[count($los) - 1]; + $b->y++; $this->teleport($b); } else { $x = rand($this->x + 8, $this->x - 8); $z = rand($this->z + 8, $this->z - 8); - for($y = $this->y + 16; $y > $this->y - 16; $this->y--){ - if($this->getLevel()->getBlock($x, $y -1, $z)->getId() !== 0) break; + for($y = $this->y + 16; $y > $this->y - 16; $y--){ + if($this->getLevel()->getBlock(new Vector3($x, $y -1, $z))->getId() !== 0) break; } $this->teleport(new Vector3($x, $y, $z)); } } + if($this->moveTime !== 0){ + $this->moveTime--; + return true; + } + if(abs($this->x - $this->getPlayer()->x) > 50 || abs($this->z - $this->getPlayer()->z) > 50) { // Too far away, teleporting him in front of the player + $spawnBlock = $this->getPlayer()->getLineOfSight(2); + $spawnBlock = $spawnBlock[count($spawnBlock) -1]; + if($this->getLevel()->getBlock(new Vector3($spawnBlock->x, $spawnBlock->y, $spawnBlock->z))->getId() !== 0) { + $this->teleport(new Vector3($spawnBlock->x, $spawnBlock->y + 1, $spawnBlock->z), abs($this->getPlayer()->getYaw() - 180)); + } else { + $this->teleport(new Vector3($spawnBlock->x, $spawnBlock->y, $spawnBlock->z), abs($this->getPlayer()->getYaw() - 180)); + } + $this->broadcastNewPos(); + } + $this->moveTime = 1; // Setting specific motion $diffV3 = $this->associatedPlayer->asVector3()->subtract($this->asVector3()); $distDiff = $diffV3->asVector3()->abs(); $distDiff = $distDiff->x + $distDiff->z; // Check if we can attack the player - if($this->distanceSquared($this->associatedPlayer) <= 1){ + if($this->distanceSquared($this->associatedPlayer) <= 2){ $this->attackEntity($this->associatedPlayer); } // If not, try moving torowards him - if ($diff > 0) { + if ($distDiff > 0) { $this->motionX = $this->getSpeed() * 0.15 * ($diffV3->x / $distDiff); $this->motionZ = $this->getSpeed() * 0.15 * ($diffV3->z / $distDiff); $this->yaw = rad2deg(-atan2($diffV3->x / $distDiff, $diffV3->z / $distDiff)); } - if($y == 0){ + if($diffV3->y == 0){ $this->pitch = 0; } else { - $this->pitch = rad2deg(-atan2($diffV3->y, sqrt($diffV3->x ** 2 + $distDiff->z ** 2)));; + $this->pitch = rad2deg(-atan2($diffV3->y, sqrt($diffV3->x ** 2 + $diffV3->z ** 2)));; } $currentB = $this->getLevel()->getBlock($this->asVector3()); if($currentB instanceof \pocketmine\block\Liquid){ // in water, we need to get it floating $this->motionY = $this->gravity * 2; } else { // Check if the ghost is in air and not stuck in the ground. Then, we'll get the target block to check if it's possible to jump. - if($currentB->canPassThought()){ + if($currentB->canPassThrough()){ $targetB = $this->getTargetBlock(2); } else { $targetB = $currentB; @@ -319,11 +367,26 @@ class Ghost extends Human { for($i = 1; $i <= 3; $i++){ $blockUp = $targetB->asVector3(); $blockUp->y += $i; - if(!$this->getLevel()->getBlock($blockUp)->canPassThought()) $canJump = false; + if(!$this->getLevel()->getBlock($blockUp)->canPassThrough()) $canJump = false; } // FInally, jump if possible - if($canJump && $this->gravity * 3.2 > $this->motionY) $this->motionY = $this->gravity * 3.2; + $under = $this->asVector3()->floor(); + $under->y--; + if($canJump && $this->gravity * 3.2 > $this->motionY) { + $this->motionY = $this->gravity * 3.2; + } elseif ($this->getLevel()->getBlock($under)->getId() == 0 ) { + $this->motionY = -$this->gravity * 3.2; + } else { + $this->motionY = 0; + } } + if(!isset($this->lastUpdate)) $this->lastUpdate = $currentTick - 1; + $tickDiff = abs($currentTick - $this->lastUpdate); + $this->lastUpdate = $currentTick; + $this->fastMove($this->motionX * $tickDiff, $this->motionY, $this->motionZ * $tickDiff); + $this->updateMovement(); + $this->broadcastNewPos(); + return true; } /** @@ -333,9 +396,9 @@ class Ghost extends Human { * @return void */ public function attackEntity(Entity $et){ - if($et instanceof Player){ + if($et instanceof Player && $this->attackCooldown == 0){ $damage = [ - EntityDamageEvent::MODIFIER_BASE => 10 // Two hit a player which has no armor + EntityDamageEvent::MODIFIER_BASE => 3 // Two hit a player which has no armor ]; $points = 0; foreach($et->getInventory()->getArmorContents() as $armorItem){ @@ -344,6 +407,7 @@ class Ghost extends Human { $damage[EntityDamageEvent::MODIFIER_ARMOR] = -($damage[EntityDamageEvent::MODIFIER_BASE] * $points * 0.04); $ev = new EntityDamageByEntityEvent($this, $this->associatedPlayer, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $damage); $et->attack($ev); + $this->attackCooldown = 10; // 0.5s } } @@ -353,13 +417,40 @@ class Ghost extends Human { * @return array */ public function getDrops() : array{ - $it = Item::get(Item::GOLDEN_HOE, 0); - $it->setCustomName("§r§cSoul Stealer"); - $it->setNamedTagEntry(new StringTag("customDamage", 10)); - $e = Enchantment::getEnchantment(Enchantment::SHARPNESS); - $e->setLevel(10); - $it->addEnchantment($e); - return [$it]; + switch(rand(0, 2)){ + case 0: + $it = Item::get(Item::GOLDEN_HOE, 0); + $it->setCustomName("§r§cSoul Stealer"); + $it->setNamedTagEntry(new IntTag("customDamage", 10)); + $it->setNamedTagEntry(new IntTag("sneakInvisible", 1)); + $e = Enchantment::getEnchantment(Enchantment::SHARPNESS); + $e->setLevel(10); + $it->addEnchantment($e); + return [$it]; + break; + case 1: + break; + case 2: + return []; + break; + } + } + + + /** + * Broadcats the new position to the player. + * + * @return void + */ + public function broadcastNewPos(){ + $pk = new MovePlayerPacket(); + $pk->entityRuntimeId = $this->getId(); + $pk->position = $this->asVector3(); + $pk->yaw = $this->yaw; + $pk->headYaw = $this->yaw; + $pk->pitch = $this->pitch; + $this->getPlayer()->dataPacket($pk); + $this->getPlayer()->sendPopup("He's " . ($this->x - $this->getPlayer()->x) . ", " . ($this->y - $this->getPlayer()->y) . ", " . ($this->z - $this->getPlayer()->z) . " blocks away"); } diff --git a/src/Ad5001/Spooky/sounds/TheReturnMusicPlay.php b/src/Ad5001/Spooky/sounds/TheReturnMusicPlay.php deleted file mode 100644 index 2dd0530..0000000 --- a/src/Ad5001/Spooky/sounds/TheReturnMusicPlay.php +++ /dev/null @@ -1,15 +0,0 @@ - $g){ self::$ghosts[$i]->currentSec += 0.1; - switch(self::$ghosts[$i]->currentSec){ + switch(round(self::$ghosts[$i]->currentSec, 1)){ case 48: // 0m48s - self::$ghosts[$i]->getPlayer()->getLevel()->setTime(16000); // Set time to night + self::$ghosts[$i]->getPlayer()->getLevel()->setTime(13000); // Set time to night break; case 64: // 1m04s - self::$ghosts[$i]->blackOutEnterPhase(); + self::$ghosts[$i]->spawnTo(self::$ghosts[$i]->getPlayer()); + self::$ghosts[$i]->scareEnterPhase(); break; case 66: // 1m06s - self::$ghosts[$i]->blackOutExitPhase(); self::$ghosts[$i]->intenseFight(); break; case 82: // 1m22s @@ -58,23 +60,18 @@ class TickTask extends PluginTask { break; case 100: // 1m40s self::$ghosts[$i]->repeatFunc = null; - self::$ghosts[$i]->blackOutEnterPhase(); + self::$ghosts[$i]->scareEnterPhase(); break; case 103: // 1m43s - self::$ghosts[$i]->blackOutExitPhase(); self::$ghosts[$i]->intenseFight(); break; case 136: // 2m16s self::$ghosts[$i]->calmFight(); break; case 151: // 2m31s - self::$ghosts[$i]->fightType = 0; - break; - case 152: // 2m32s - self::$ghosts[$i]->blackOutEnterPhase(); + self::$ghosts[$i]->scareEnterPhase(); break; case 153: // 2m33s - self::$ghosts[$i]->blackOutExitPhase(); self::$ghosts[$i]->intenseFight(); break; case 168: // 2m48s @@ -90,18 +87,18 @@ class TickTask extends PluginTask { self::$ghosts[$i]->intenseFight(); break; case 197: // 3m17s - self::$ghosts[$i]->blackOutEnterPhase(); + self::$ghosts[$i]->scareEnterPhase(); break; case 198: // 3m18s - self::$ghosts[$i]->blackOutExitPhase(); self::$ghosts[$i]->intenseFight(); break; case 227: // 3m47s self::$ghosts[$i]->calmFight(); break; case 262: // 4m22 - self::unregisterGhost(self::$ghosts[$i]); + self::$ghosts[$i]->getPlayer()->sendMessage("Mwahahahaha... Try being faster next time!"); self::$ghosts[$i]->close(); + self::unregisterGhost(self::$ghosts[$i]); break; default: switch(self::$ghosts[$i]->repeatFunc){ @@ -115,6 +112,12 @@ class TickTask extends PluginTask { break; } } + // Setting invisibility + foreach(Server::getInstance()->getOnlinePlayers() as $p){ + if(isset($p->getInventory()->getItemInHand()->getNamedTag()->sneakInvisible) && $p->isSneaking()) { + $p->addEffect(Effect::getEffect(Effect::INVISIBILITY)->setDuration(3)->setVisible(false)); + } + } } /** @@ -124,7 +127,7 @@ class TickTask extends PluginTask { * @return void */ public static function registerGhost(Ghost $g){ - $g->currentSec = 0; + $g->currentSec = 0.0; $g->repeatFunc = null; self::$ghosts[$g->getId()] = $g; }