Fixing bugs AF

This commit is contained in:
Ad5001 2017-10-31 00:03:54 +01:00
parent f276b9aedf
commit 9a4082a6f6
8 changed files with 257 additions and 129 deletions

View file

@ -5,7 +5,7 @@ Build a structure like this one: (be sure to place the pumpkin in last!)
<img src="https://raw.githubusercontent.com/Ad5001/Spooky/master/img/struct.png"></img> <img src="https://raw.githubusercontent.com/Ad5001/Spooky/master/img/struct.png"></img>
Afterwards let the boss fight go! Afterwards let the boss fight go!
Music used here: NIVIRO - The Return Music used here: NIVIRO - The Return
Track's link: https://soundcloud.com/djniviro/thereturn Track's link: https://soundcloud.com/djniviro/thereturn

View file

@ -1,3 +0,0 @@
---
# This is the default config generated with ImagicalPlugCreator. (C) ImagicalPlugCreator - Ad5001 2016
...

BIN
resources/Spooky.mcpack Normal file

Binary file not shown.

View file

@ -1,3 +0,0 @@
---
# This is the default config generated with ImagicalPlugCreator. (C) ImagicalPlugCreator - Ad5001 2016
...

View file

@ -5,15 +5,20 @@ use pocketmine\command\Command;
use pocketmine\plugin\PluginBase; use pocketmine\plugin\PluginBase;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\Player; use pocketmine\Player;
use pocketmine\entity\Entity;
use pocketmine\event\Listener; use pocketmine\event\Listener;
use pocketmine\item\enchantment\Enchantment; use pocketmine\item\enchantment\Enchantment;
use pocketmine\event\block\BlockPlaceEvent; use pocketmine\event\block\BlockPlaceEvent;
use pocketmine\network\mcpe\protocol\PlaySoundPacket;
use pocketmine\block\Block; use pocketmine\block\Block;
use pocketmine\resourcepacks\ZippedResourcePack;
use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\tag\StringTag;
use pocketmine\nbt\tag\FloatTag; use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\ShortTag;
use pocketmine\nbt\NBT; use pocketmine\nbt\NBT;
@ -33,8 +38,30 @@ class Main extends PluginBase implements Listener{
public function onEnable(){ public function onEnable(){
// Registering some enchants // Registering some enchants
Enchantment::registerEnchantment(new Enchantment(Enchantment::SHARPNESS, "%enchantment.attack.sharpness", Enchantment::ACTIVATION_HELD, Enchantment::RARITY_COMMON, Enchantment::SLOT_SWORD)); 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()->getScheduler()->scheduleRepeatingTask(new TickTask($this), 2);
$this->getServer()->getPluginManager()->registerEvents($this, $this); $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--; $under->y--;
// Hay bale for the body // Hay bale for the body
if($event->getBlock()->getLevel()->getBlock($under)->getId() == Block::HAY_BALE) { if($event->getBlock()->getLevel()->getBlock($under)->getId() == Block::HAY_BALE) {
$under2 = $event->getBlock()->asVector3(); $under2 = $under->asVector3();
$under2->y--; $under2->y--;
// Fence for the bottom // Fence for the bottom
if($event->getBlock()->getLevel()->getBlock($under2)->getId() == Block::FENCE){ 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($under2, Block::get(Block::AIR));
$event->getBlock()->getLevel()->setBlock($side1, Block::get(Block::AIR)); $event->getBlock()->getLevel()->setBlock($side1, Block::get(Block::AIR));
$event->getBlock()->getLevel()->setBlock($side2, Block::get(Block::AIR)); $event->getBlock()->getLevel()->setBlock($side2, Block::get(Block::AIR));
if($event->getPlayer()){ if($event->getPlayer() !== null){
$this->spawnGhost($event->getPlayer()); $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){ public function spawnGhost(Player $p){
// Getting the skin // Getting the skin
$nbtSkin = new NBT(NBT::BIG_ENDIAN); $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 = new CompoundTag();
$nbt->Pos = new ListTag("Pos", [ $nbt->Pos = new ListTag("Pos", [
new DoubleTag("", $player->getX()), new DoubleTag("", $p->getX()),
new DoubleTag("", $player->getY()), new DoubleTag("", $p->getY()),
new DoubleTag("", $player->getZ()) new DoubleTag("", $p->getZ())
]); ]);
$nbt->Motion = new ListTag("Motion", [ $nbt->Motion = new ListTag("Motion", [
new DoubleTag("", 0), new DoubleTag("", 0),
@ -122,15 +157,35 @@ class Main extends PluginBase implements Listener{
new DoubleTag("", 0) new DoubleTag("", 0)
]); ]);
$nbt->Rotation = new ListTag("Rotation", [ $nbt->Rotation = new ListTag("Rotation", [
new FloatTag("", $player->getYaw()), new FloatTag("", $p->getYaw()),
new FloatTag("", $player->getPitch()) new FloatTag("", $p->getPitch())
]); ]);
// var_dump($nbtSkin);
$nbt->Health = new ShortTag("Health", 20); $nbt->Health = new ShortTag("Health", 20);
$player->saveNBT(); $nbt->Skin = clone $nbtSkin->getData()->Skin;
$nbt->Skin = clone $nbtSkin->Skin; $nbt->Inventory = clone $nbtSkin->getData()->Inventory;
$nbt->Inventory = clone $nbtSkin->Inventory; $g = Entity::createEntity("Ghost", $p->getLevel(), $nbt);
$g = new Ghost($p->getLevel(), $nbt);
$g->startFight($p); $g->startFight($p);
$this->ghosts[$p->getName()] = $g; $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);
}
}
}
} }

View file

@ -5,10 +5,16 @@ use pocketmine\Player;
use pocketmine\entity\Entity; use pocketmine\entity\Entity;
use pocketmine\item\Item; use pocketmine\item\Item;
use pocketmine\item\enchantment\Enchantment; use pocketmine\item\enchantment\Enchantment;
use pocketmine\level\Level;
use pocketmine\entity\Human; use pocketmine\entity\Human;
use pocketmine\block\Block;
use pocketmine\event\entity\EntityDamageEvent; use pocketmine\event\entity\EntityDamageEvent;
use pocketmine\event\entity\EntityDamageByEntityEvent; 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; use pocketmine\math\Vector3;
@ -18,6 +24,7 @@ use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\DoubleTag; use pocketmine\nbt\tag\DoubleTag;
use pocketmine\nbt\tag\ByteTag; use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\StringTag; use pocketmine\nbt\tag\StringTag;
use pocketmine\nbt\tag\CompoundTag;
use pocketmine\entity\Effect; use pocketmine\entity\Effect;
use Ad5001\Spooky\Main; use Ad5001\Spooky\Main;
@ -28,16 +35,16 @@ use Ad5001\Spooky\tasks\TickTask;
class Ghost extends Human { class Ghost extends Human {
/** const NETWORK_ID = -1;
* 0: Not fighting
* 1: Simple fight
*
* @var integer
*/
protected $fightType = 0;
protected $associatedPlayer = null; protected $associatedPlayer = null;
protected $moveTime = 0;
public $attCooldown = 0;
public $attackCooldown = 0;
/** /**
* Constructs the class * Constructs the class
* *
@ -45,7 +52,7 @@ class Ghost extends Human {
* @param CompoundTag $nbt * @param CompoundTag $nbt
*/ */
public function __construct(Level $level, 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); parent::__construct($level, $nbt);
$it = Item::get(Item::GOLDEN_HOE, 0); $it = Item::get(Item::GOLDEN_HOE, 0);
$it->addEnchantment(Enchantment::getEnchantment(Enchantment::SHARPNESS)); $it->addEnchantment(Enchantment::getEnchantment(Enchantment::SHARPNESS));
@ -67,7 +74,7 @@ class Ghost extends Human {
* @return float * @return float
*/ */
public function getSpeed(): float { public function getSpeed(): float {
return $this->fightType * 2; return 2;
} }
@ -81,13 +88,20 @@ class Ghost extends Human {
* @param Player $player * @param Player $player
*/ */
public function startFight(Player $p) { 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. // Only after the ghost appeared, we can remove it.
Effect::getEffectById(Effect::BLINDNESS)->setDuration(66*20)->setVisible(false)->add($p); Effect::getEffect(Effect::BLINDNESS)->setDuration(66*20)->setVisible(false)->add($p);
Effect::getEffectById(Effect::INVISIBILITY)->setDuration(63*20)->setVisible(false)->add($this); // $p->addEffect(Effect::getEffect(Effect::SLOWNESS)->setDuration(30*20)->setAmplifier(5)->setVisible(false));
$this->spawnTo($p);
$this->associatedPlayer = $p; $this->associatedPlayer = $p;
TickTask::registerGhost($this); TickTask::registerGhost($this);
$p->sendPopup("Music: The Return by Niviro, www.djniviro.com");
} }
/** /**
@ -98,7 +112,6 @@ class Ghost extends Human {
public function intenseFight(){ public function intenseFight(){
if(!$this->checkIfConnected()) return; if(!$this->checkIfConnected()) return;
// TODO: Custom intense fight // TODO: Custom intense fight
$this->fightType = 1;
} }
/** /**
@ -108,7 +121,6 @@ class Ghost extends Human {
*/ */
public function calmFight(){ public function calmFight(){
if(!$this->checkIfConnected()) return; if(!$this->checkIfConnected()) return;
$this->fightType = 1;
} }
/** /**
@ -117,35 +129,25 @@ class Ghost extends Human {
* in front of the player. * in front of the player.
* @return void * @return void
*/ */
public function blackOutEnterPhase(){ public function scareEnterPhase(){
if(!$this->checkIfConnected()) return; if(!$this->checkIfConnected()) return;
$this->fightType = 0;
$spawnBlock = $this->getPlayer()->getLineOfSight(2); $spawnBlock = $this->getPlayer()->getLineOfSight(2);
$spawnBlock = $spawnBlock[count($spawnBlock) -1]; $spawnBlock = $spawnBlock[count($spawnBlock) -1];
$this->getPlayer()->addEffect( $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( $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( if($this->getLevel()->getBlock(new Vector3($spawnBlock->x, $spawnBlock->y, $spawnBlock->z))->getId() !== 0) {
Effect::getEffectById(Effect::NAUSEA)->setDuration(30*20)->setAmplifier(99)->setVisible(false) $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->teleport(new Vector3($spawnBlock->x, $spawnBlock->y, $spawnBlock->z), abs($this->getPlayer()->getYaw() - 180));
$this->removeEffect(Effect::INVISIBILITY); }
} $this->broadcastNewPos();
/**
* 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);
} }
/** /**
@ -156,9 +158,9 @@ class Ghost extends Human {
*/ */
public function movePlayerRandomly(){ public function movePlayerRandomly(){
if(!$this->checkIfConnected()) return; if(!$this->checkIfConnected()) return;
$this->fightType = 0; if(rand(0,20) == 1) {
for($i = 0; $i < 10; $i++){ echo "\nMove ya!\n";
$this->associatedPlayer->setMotion(new Vector3(rand() - rand(), 0, rand() - rand())); $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(){ public function destroyBlocksRandomly(){
if(!$this->checkIfConnected()) return; if(!$this->checkIfConnected()) return;
$this->fightType = 0; $this->teleport(new Vector3($this->getPlayer()->x, $this->getPlayer()->y + 3, $this->getPlayer()->z), $this->yaw == 0 ? 359 : $this->yaw - 1, 130);
$this->teleport(new Vector3($this->getPlayer()->x, $this->getPlayer()->y + 7, $this->getPlayer()->z), $this->yaw == 0 ? 359 : $this->yaw - 1, 130); srand(time());
srand(hash("sha512", time()));
foreach($this->getLevel()->getEntities() as $et){ foreach($this->getLevel()->getEntities() as $et){
if($et instanceof \pocketmine\entity\FallingSand && $et->namedtag->getInt("SpawnTime") !== $null){ if($et instanceof \pocketmine\entity\FallingSand && $et->namedtag->getInt("SpawnTime") !== $null){
$diffTime = time() - $et->namedtag->getInt("SpawnTime"); $diffTime = time() - $et->namedtag->getInt("SpawnTime");
@ -180,12 +181,27 @@ class Ghost extends Human {
} }
} }
for($i = 0; $i < 3; $i++) { for($i = 0; $i < 3; $i++) {
$rx = rand(0, 12) - 6; $rx = rand(0, 12) - 6 + $this->getPlayer()->x;
$rz = rand(0, 12) - 6; $rz = rand(0, 12) - 6 + $this->getPlayer()->z;
for($ry = 128; $this->getLevel()->getBlock($rx, $ry, $rz)->getId() !== 0 || $ry == 0; $ry--){} // Determining y from the higthest workable block 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($rx, $ry, $rz); $b = $this->getLevel()->getBlock(new Vector3($rx, $ry, $rz));
// Creating falling sand block // 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("TileID", $b->getId());
$nbt->setInt("SpawnTime", time()); $nbt->setInt("SpawnTime", time());
$nbt->setByte("Data", $b->getDamage()); $nbt->setByte("Data", $b->getDamage());
@ -194,6 +210,7 @@ class Ghost extends Human {
if($fall !== null){ if($fall !== null){
$fall->spawnToAll(); $fall->spawnToAll();
} }
$this->getLevel()->setBlock(new Vector3($rx, $ry, $rz), Block::get(Block::AIR));
} }
} }
@ -204,7 +221,7 @@ class Ghost extends Human {
* @return void * @return void
*/ */
public function checkIfConnected(){ public function checkIfConnected(){
if(!$this->associatedPlayer->isOnline()){ if($this->associatedPlayer == null || !$this->associatedPlayer->isOnline()){
TickTask::unregisterGhost($this); TickTask::unregisterGhost($this);
$this->close(); $this->close();
return false; return false;
@ -222,40 +239,54 @@ class Ghost extends Human {
if(!isset($this->hasSpawned[$player->getLoaderId()]) && if(!isset($this->hasSpawned[$player->getLoaderId()]) &&
isset($player->usedChunks[Level::chunkHash($this->chunk->getX(), $this->chunk->getZ())])) { isset($player->usedChunks[Level::chunkHash($this->chunk->getX(), $this->chunk->getZ())])) {
$this->hasSpawned[$player->getLoaderId()] = $player; $this->hasSpawned[$player->getLoaderId()] = $player;
$uuid = $this->getUniqueId();
$entityId = $this->getId();
$pk = new AddPlayerPacket(); $pk = new AddPlayerPacket();
$pk->uuid = $uuid;
$pk->username = ""; $pk->username = "";
$pk->entityRuntimeId = $entityId; $pk->uuid = $this->getUniqueId();
$pk->entityRuntimeId = $this->getId();
$pk->position = $this->asVector3(); $pk->position = $this->asVector3();
$pk->yaw = $this->yaw; $pk->yaw = $this->yaw;
$pk->pitch = $this->pitch; $pk->pitch = $this->pitch;
$pk->item = $this->getInventory()->getItemInHand(); $pk->item = $this->getInventory()->getItemInHand();
$pk->metadata = $this->dataProperties; $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); $player->dataPacket($pk);
$this->inventory->sendArmorContents($player); $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 // Event listeners
/** /**
* Check the damage to reduce it by 25% * Check the damage to reduce it by 55%
* *
* @param EntityDamageEvent $event * @param EntityDamageEvent $event
*/ */
public function attack(EntityDamageEvent $event) { public function attack(EntityDamageEvent $event) {
if($event instanceof EntityDamageByEntityEvent) { if($event instanceof EntityDamageByEntityEvent) {
if($event->getDamager() instanceof Player && $event->getDamager()){ if($event->getDamager() instanceof Player && $event->getDamager()->getName() == $this->getPlayer()->getName()){
$event->setDamage($event->getDamage() * 0.75); 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 { } else {
$event->setCancelled(true); $event->setCancelled(true);
$event->getDamager()->motionY = 12;
$event->getDamager()->addEffect( $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 { public function onUpdate(int $currentTick): bool {
if(!$this->checkIfConnected()) return false; if(!$this->checkIfConnected()) return false;
if($this->fightType == 0) return false; if($this->attCooldown > 0) $this->attCooldown--;
if($this->attackCooldown > 0) $this->attackCooldown--;
// Teleportation // Teleportation
if(rand(0, 200) == 0) { // Do we do teleportation? if(rand(0, 200) == 0) { // Do we do teleportation?
if(rand(0,1) == 0){ // Which kind of tp? Random around or forward? if(rand(0,1) == 0){ // Which kind of tp? Random around or forward?
$los = $this->getLineOfSight(10); $los = $this->getLineOfSight(10);
$b = $los[count($los) - 1]; $b = $los[count($los) - 1];
$b->y++;
$this->teleport($b); $this->teleport($b);
} else { } else {
$x = rand($this->x + 8, $this->x - 8); $x = rand($this->x + 8, $this->x - 8);
$z = rand($this->z + 8, $this->z - 8); $z = rand($this->z + 8, $this->z - 8);
for($y = $this->y + 16; $y > $this->y - 16; $this->y--){ for($y = $this->y + 16; $y > $this->y - 16; $y--){
if($this->getLevel()->getBlock($x, $y -1, $z)->getId() !== 0) break; if($this->getLevel()->getBlock(new Vector3($x, $y -1, $z))->getId() !== 0) break;
} }
$this->teleport(new Vector3($x, $y, $z)); $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 // Setting specific motion
$diffV3 = $this->associatedPlayer->asVector3()->subtract($this->asVector3()); $diffV3 = $this->associatedPlayer->asVector3()->subtract($this->asVector3());
$distDiff = $diffV3->asVector3()->abs(); $distDiff = $diffV3->asVector3()->abs();
$distDiff = $distDiff->x + $distDiff->z; $distDiff = $distDiff->x + $distDiff->z;
// Check if we can attack the player // Check if we can attack the player
if($this->distanceSquared($this->associatedPlayer) <= 1){ if($this->distanceSquared($this->associatedPlayer) <= 2){
$this->attackEntity($this->associatedPlayer); $this->attackEntity($this->associatedPlayer);
} }
// If not, try moving torowards him // If not, try moving torowards him
if ($diff > 0) { if ($distDiff > 0) {
$this->motionX = $this->getSpeed() * 0.15 * ($diffV3->x / $distDiff); $this->motionX = $this->getSpeed() * 0.15 * ($diffV3->x / $distDiff);
$this->motionZ = $this->getSpeed() * 0.15 * ($diffV3->z / $distDiff); $this->motionZ = $this->getSpeed() * 0.15 * ($diffV3->z / $distDiff);
$this->yaw = rad2deg(-atan2($diffV3->x / $distDiff, $diffV3->z / $distDiff)); $this->yaw = rad2deg(-atan2($diffV3->x / $distDiff, $diffV3->z / $distDiff));
} }
if($y == 0){ if($diffV3->y == 0){
$this->pitch = 0; $this->pitch = 0;
} else { } 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()); $currentB = $this->getLevel()->getBlock($this->asVector3());
if($currentB instanceof \pocketmine\block\Liquid){ // in water, we need to get it floating if($currentB instanceof \pocketmine\block\Liquid){ // in water, we need to get it floating
$this->motionY = $this->gravity * 2; $this->motionY = $this->gravity * 2;
} else { } 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. // 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); $targetB = $this->getTargetBlock(2);
} else { } else {
$targetB = $currentB; $targetB = $currentB;
@ -319,11 +367,26 @@ class Ghost extends Human {
for($i = 1; $i <= 3; $i++){ for($i = 1; $i <= 3; $i++){
$blockUp = $targetB->asVector3(); $blockUp = $targetB->asVector3();
$blockUp->y += $i; $blockUp->y += $i;
if(!$this->getLevel()->getBlock($blockUp)->canPassThought()) $canJump = false; if(!$this->getLevel()->getBlock($blockUp)->canPassThrough()) $canJump = false;
} }
// FInally, jump if possible // 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 * @return void
*/ */
public function attackEntity(Entity $et){ public function attackEntity(Entity $et){
if($et instanceof Player){ if($et instanceof Player && $this->attackCooldown == 0){
$damage = [ $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; $points = 0;
foreach($et->getInventory()->getArmorContents() as $armorItem){ 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); $damage[EntityDamageEvent::MODIFIER_ARMOR] = -($damage[EntityDamageEvent::MODIFIER_BASE] * $points * 0.04);
$ev = new EntityDamageByEntityEvent($this, $this->associatedPlayer, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $damage); $ev = new EntityDamageByEntityEvent($this, $this->associatedPlayer, EntityDamageEvent::CAUSE_ENTITY_ATTACK, $damage);
$et->attack($ev); $et->attack($ev);
$this->attackCooldown = 10; // 0.5s
} }
} }
@ -353,13 +417,40 @@ class Ghost extends Human {
* @return array * @return array
*/ */
public function getDrops() : array{ public function getDrops() : array{
$it = Item::get(Item::GOLDEN_HOE, 0); switch(rand(0, 2)){
$it->setCustomName("§r§cSoul Stealer"); case 0:
$it->setNamedTagEntry(new StringTag("customDamage", 10)); $it = Item::get(Item::GOLDEN_HOE, 0);
$e = Enchantment::getEnchantment(Enchantment::SHARPNESS); $it->setCustomName("§r§cSoul Stealer");
$e->setLevel(10); $it->setNamedTagEntry(new IntTag("customDamage", 10));
$it->addEnchantment($e); $it->setNamedTagEntry(new IntTag("sneakInvisible", 1));
return [$it]; $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");
} }

View file

@ -1,15 +0,0 @@
<?php
namespace Ad5001\Spooky\sounds;
use pocketmine\math\Vector3;
use pocketmine\network\mcpe\protocol\LevelEventPacket;
use pocketmine\level\sound\GenericSound;
class TheReturnMusicPlay extends GenericSound{
public function __construct(Vector3 $pos, $pitch = 1){
parent::__construct($pos, LevelEventPacket::EVENT_SOUND_ARMOR_STAND_HIT, $pitch);
}
}

View file

@ -4,6 +4,8 @@ namespace Ad5001\Spooky\tasks;
use pocketmine\Server; use pocketmine\Server;
use pocketmine\scheduler\PluginTask; use pocketmine\scheduler\PluginTask;
use pocketmine\Player; use pocketmine\Player;
use pocketmine\network\mcpe\protocol\PlaySoundPacket;
use pocketmine\entity\Effect;
use Ad5001\Spooky\Main; use Ad5001\Spooky\Main;
use Ad5001\Spooky\entity\Ghost; use Ad5001\Spooky\entity\Ghost;
@ -33,15 +35,15 @@ class TickTask extends PluginTask {
public function onRun(int $tick) { public function onRun(int $tick) {
foreach(self::$ghosts as $i => $g){ foreach(self::$ghosts as $i => $g){
self::$ghosts[$i]->currentSec += 0.1; self::$ghosts[$i]->currentSec += 0.1;
switch(self::$ghosts[$i]->currentSec){ switch(round(self::$ghosts[$i]->currentSec, 1)){
case 48: // 0m48s 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; break;
case 64: // 1m04s case 64: // 1m04s
self::$ghosts[$i]->blackOutEnterPhase(); self::$ghosts[$i]->spawnTo(self::$ghosts[$i]->getPlayer());
self::$ghosts[$i]->scareEnterPhase();
break; break;
case 66: // 1m06s case 66: // 1m06s
self::$ghosts[$i]->blackOutExitPhase();
self::$ghosts[$i]->intenseFight(); self::$ghosts[$i]->intenseFight();
break; break;
case 82: // 1m22s case 82: // 1m22s
@ -58,23 +60,18 @@ class TickTask extends PluginTask {
break; break;
case 100: // 1m40s case 100: // 1m40s
self::$ghosts[$i]->repeatFunc = null; self::$ghosts[$i]->repeatFunc = null;
self::$ghosts[$i]->blackOutEnterPhase(); self::$ghosts[$i]->scareEnterPhase();
break; break;
case 103: // 1m43s case 103: // 1m43s
self::$ghosts[$i]->blackOutExitPhase();
self::$ghosts[$i]->intenseFight(); self::$ghosts[$i]->intenseFight();
break; break;
case 136: // 2m16s case 136: // 2m16s
self::$ghosts[$i]->calmFight(); self::$ghosts[$i]->calmFight();
break; break;
case 151: // 2m31s case 151: // 2m31s
self::$ghosts[$i]->fightType = 0; self::$ghosts[$i]->scareEnterPhase();
break;
case 152: // 2m32s
self::$ghosts[$i]->blackOutEnterPhase();
break; break;
case 153: // 2m33s case 153: // 2m33s
self::$ghosts[$i]->blackOutExitPhase();
self::$ghosts[$i]->intenseFight(); self::$ghosts[$i]->intenseFight();
break; break;
case 168: // 2m48s case 168: // 2m48s
@ -90,18 +87,18 @@ class TickTask extends PluginTask {
self::$ghosts[$i]->intenseFight(); self::$ghosts[$i]->intenseFight();
break; break;
case 197: // 3m17s case 197: // 3m17s
self::$ghosts[$i]->blackOutEnterPhase(); self::$ghosts[$i]->scareEnterPhase();
break; break;
case 198: // 3m18s case 198: // 3m18s
self::$ghosts[$i]->blackOutExitPhase();
self::$ghosts[$i]->intenseFight(); self::$ghosts[$i]->intenseFight();
break; break;
case 227: // 3m47s case 227: // 3m47s
self::$ghosts[$i]->calmFight(); self::$ghosts[$i]->calmFight();
break; break;
case 262: // 4m22 case 262: // 4m22
self::unregisterGhost(self::$ghosts[$i]); self::$ghosts[$i]->getPlayer()->sendMessage("Mwahahahaha... Try being faster next time!");
self::$ghosts[$i]->close(); self::$ghosts[$i]->close();
self::unregisterGhost(self::$ghosts[$i]);
break; break;
default: default:
switch(self::$ghosts[$i]->repeatFunc){ switch(self::$ghosts[$i]->repeatFunc){
@ -115,6 +112,12 @@ class TickTask extends PluginTask {
break; 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 * @return void
*/ */
public static function registerGhost(Ghost $g){ public static function registerGhost(Ghost $g){
$g->currentSec = 0; $g->currentSec = 0.0;
$g->repeatFunc = null; $g->repeatFunc = null;
self::$ghosts[$g->getId()] = $g; self::$ghosts[$g->getId()] = $g;
} }