Almost finsihed! Just need to do testing + finishing the reward item.

This commit is contained in:
Adsooi 2017-10-29 18:27:35 +01:00
parent 5dd7716e88
commit f276b9aedf
5 changed files with 226 additions and 22 deletions

View file

@ -1,7 +1,12 @@
# Spooky # Spooky
Halloween plugin. Halloween plugin.
A new bossfight's waiting for you and your players. <b>The GHost is <i>here</i></b>.
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>
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
Niviro's website: https://www.djniviro.com Niviro's website: https://www.djniviro.com

View file

@ -5,7 +5,10 @@ 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\event\Listener;
use pocketmine\item\enchantment\Enchantment; use pocketmine\item\enchantment\Enchantment;
use pocketmine\event\block\BlockPlaceEvent;
use pocketmine\block\Block;
use pocketmine\nbt\tag\ListTag; use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\CompoundTag; use pocketmine\nbt\tag\CompoundTag;
@ -18,7 +21,7 @@ use Ad5001\Spooky\entity\Ghost;
use Ad5001\Spooky\tasks\TickTask; use Ad5001\Spooky\tasks\TickTask;
class Main extends PluginBase{ class Main extends PluginBase implements Listener{
public $ghosts = []; public $ghosts = [];
@ -29,8 +32,9 @@ class Main extends PluginBase{
*/ */
public function onEnable(){ public function onEnable(){
// Registering some enchants // Registering some enchants
Enchantement::registerEnchantment(new Enchantement(Enchantement::SHARPNESS, "%enchantment.attack.sharpness", Enchantement::RARITY_COMMON, Enchantement::SLOT_SWORD)); Enchantment::registerEnchantment(new Enchantment(Enchantment::SHARPNESS, "%enchantment.attack.sharpness", Enchantment::ACTIVATION_HELD, Enchantment::RARITY_COMMON, Enchantment::SLOT_SWORD));
// $this->getServer()->getScheduler()->scheduler<Delayed or Repeating>Task(new Task1($this), <TIME>); $this->getServer()->getScheduler()->scheduleRepeatingTask(new TickTask($this), 2);
$this->getServer()->getPluginManager()->registerEvents($this, $this);
} }
/** /**
@ -51,7 +55,57 @@ class Main extends PluginBase{
} }
public function onBlockPlace(BlockPlaceEvent $event) {
// Checking the pumpkin at the top
$found = false;
if($event->getBlock()->getId() == Block::PUMPKIN){
$under = $event->getBlock()->asVector3();
$under->y--;
// Hay bale for the body
if($event->getBlock()->getLevel()->getBlock($under)->getId() == Block::HAY_BALE) {
$under2 = $event->getBlock()->asVector3();
$under2->y--;
// Fence for the bottom
if($event->getBlock()->getLevel()->getBlock($under2)->getId() == Block::FENCE){
// Fences for the sides.
$side1 = $under->asVector3();
$side1->x++;
$side2 = $under->asVector3();
$side2->x--;
if($event->getBlock()->getLevel()->getBlock($side1)->getId() == Block::FENCE && $event->getBlock()->getLevel()->getBlock($side1)->getId() == Block::FENCE) {
$found = true;
} else {
$side1 = $under->asVector3();
$side1->z++;
$side2 = $under->asVector3();
$side2->z--;
if($event->getBlock()->getLevel()->getBlock($side1)->getId() == Block::FENCE && $event->getBlock()->getLevel()->getBlock($side1)->getId() == Block::FENCE) {
$found = true;
}
}
}
}
}
// If everything's right, we can destroy the structure & generate the ghost
if($found){
$event->setCancelled();
$event->getBlock()->getLevel()->setBlock($under, 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($side2, Block::get(Block::AIR));
if($event->getPlayer()){
$this->spawnGhost($event->getPlayer());
}
}
}
/**
* Spawns a ghost
*
* @param Player $p
* @return void
*/
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);

View file

@ -17,6 +17,7 @@ use pocketmine\nbt\tag\FloatTag;
use pocketmine\nbt\tag\ListTag; 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\entity\Effect; use pocketmine\entity\Effect;
use Ad5001\Spooky\Main; use Ad5001\Spooky\Main;
@ -47,7 +48,7 @@ class Ghost extends Human {
$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->addEnchantement(Enchantement::getEnchantement(Enchantement::SHARPNESS)); $it->addEnchantment(Enchantment::getEnchantment(Enchantment::SHARPNESS));
$this->getInventory()->setItemInHand($it); $this->getInventory()->setItemInHand($it);
} }
@ -97,6 +98,7 @@ 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;
} }
/** /**
@ -118,7 +120,7 @@ class Ghost extends Human {
public function blackOutEnterPhase(){ public function blackOutEnterPhase(){
if(!$this->checkIfConnected()) return; if(!$this->checkIfConnected()) return;
$this->fightType = 0; $this->fightType = 0;
$spawnBlock = $this->getPlayer()->getLineOfSight(2, 3, []); $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::getEffectById(Effect::BLINDNESS)->setDuration(30*20)->setAmplifier(4)->setVisible(false)
@ -243,14 +245,18 @@ class Ghost extends Human {
/** /**
* Check the damage to reduce it by 25% * Check the damage to reduce it by 25%
* *
* @param EntityDamageEvent $source * @param EntityDamageEvent $event
*/ */
public function attack(EntityDamageEvent $source) { 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()){
$source->setDamage($source->getDamage() * 0.75); $event->setDamage($event->getDamage() * 0.75);
} else { } else {
$event->setCancelled(true); $event->setCancelled(true);
$event->getDamager()->motionY = 12;
$event->getDamager()->addEffect(
Effect::getEffectById(Effect::NAUSEA)->setDuration(30*20)->setAmplifier(99)->setVisible(false)
);
} }
} }
} }
@ -262,19 +268,62 @@ class Ghost extends Human {
* @return bool * @return bool
*/ */
public function onUpdate(int $currentTick): bool { public function onUpdate(int $currentTick): bool {
if(!$this->checkIfConnected()) return; if(!$this->checkIfConnected()) return false;
if($this->fightType == 0) return false;
// 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];
$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;
}
$this->teleport(new Vector3($x, $y, $z));
}
}
// 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
if($this->distanceSquared($this->associatedPlayer) <= 1){ if($this->distanceSquared($this->associatedPlayer) <= 1){
$this->attackEntity($this->associatedPlayer); $this->attackEntity($this->associatedPlayer);
} }
// If not, try moving torowards him
if ($diff > 0) { if ($diff > 0) {
$this->motionX = $this->getSpeed() * 0.15 * ($x / $diff); $this->motionX = $this->getSpeed() * 0.15 * ($diffV3->x / $distDiff);
$this->motionZ = $this->getSpeed() * 0.15 * ($z / $diff); $this->motionZ = $this->getSpeed() * 0.15 * ($diffV3->z / $distDiff);
$this->yaw = rad2deg(-atan2($x / $diff, $z / $diff)); $this->yaw = rad2deg(-atan2($diffV3->x / $distDiff, $diffV3->z / $distDiff));
}
if($y == 0){
$this->pitch = 0;
} else {
$this->pitch = rad2deg(-atan2($diffV3->y, sqrt($diffV3->x ** 2 + $distDiff->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()){
$targetB = $this->getTargetBlock(2);
} else {
$targetB = $currentB;
}
$canJump = true;
// Check 3 blocks up that position (to see if the entity can go up)
for($i = 1; $i <= 3; $i++){
$blockUp = $targetB->asVector3();
$blockUp->y += $i;
if(!$this->getLevel()->getBlock($blockUp)->canPassThought()) $canJump = false;
}
// FInally, jump if possible
if($canJump && $this->gravity * 3.2 > $this->motionY) $this->motionY = $this->gravity * 3.2;
} }
$this->pitch = $y == 0 ? 0 : rad2deg(-atan2($y, sqrt($x * $x + $z * $z)));
} }
/** /**
@ -284,9 +333,18 @@ class Ghost extends Human {
* @return void * @return void
*/ */
public function attackEntity(Entity $et){ public function attackEntity(Entity $et){
$ev = new EntityDamageByEntityEvent($this, $this->associatedPlayer, EntityDamageEvent::CAUSE_ENTITY_ATTACK if($et instanceof Player){
/* Todo Calcule armor */); $damage = [
$et->attack($ev); EntityDamageEvent::MODIFIER_BASE => 10 // Two hit a player which has no armor
];
$points = 0;
foreach($et->getInventory()->getArmorContents() as $armorItem){
$points += $armorItem->getDefensePoints();
}
$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);
}
} }
/** /**
@ -295,7 +353,13 @@ class Ghost extends Human {
* @return array * @return array
*/ */
public function getDrops() : array{ public function getDrops() : array{
return $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];
} }

View file

@ -33,6 +33,87 @@ 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){
case 48: // 0m48s
self::$ghosts[$i]->getPlayer()->getLevel()->setTime(16000); // Set time to night
break;
case 64: // 1m04s
self::$ghosts[$i]->blackOutEnterPhase();
break;
case 66: // 1m06s
self::$ghosts[$i]->blackOutExitPhase();
self::$ghosts[$i]->intenseFight();
break;
case 82: // 1m22s
self::$ghosts[$i]->movePlayerRandomly();
self::$ghosts[$i]->repeatFunc = "move";
break;
case 88: // 1m28s
self::$ghosts[$i]->calmFight();
self::$ghosts[$i]->repeatFunc = null;
break;
case 95: // 1m35s
self::$ghosts[$i]->destroyBlocksRandomly();
self::$ghosts[$i]->repeatFunc = "blockdis";
break;
case 100: // 1m40s
self::$ghosts[$i]->repeatFunc = null;
self::$ghosts[$i]->blackOutEnterPhase();
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();
break;
case 153: // 2m33s
self::$ghosts[$i]->blackOutExitPhase();
self::$ghosts[$i]->intenseFight();
break;
case 168: // 2m48s
self::$ghosts[$i]->movePlayerRandomly();
self::$ghosts[$i]->repeatFunc = "move";
break;
case 176: // 2m56s
self::$ghosts[$i]->destroyBlocksRandomly();
self::$ghosts[$i]->repeatFunc = "blockdis";
break;
case 183: // 3m03s
self::$ghosts[$i]->repeatFunc = null;
self::$ghosts[$i]->intenseFight();
break;
case 197: // 3m17s
self::$ghosts[$i]->blackOutEnterPhase();
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]->close();
break;
default:
switch(self::$ghosts[$i]->repeatFunc){
case "move":
self::$ghosts[$i]->movePlayerRandomly();
break;
case "blockdis":
self::$ghosts[$i]->destroyBlocksRandomly();
break;
}
break;
}
} }
} }
@ -44,6 +125,7 @@ class TickTask extends PluginTask {
*/ */
public static function registerGhost(Ghost $g){ public static function registerGhost(Ghost $g){
$g->currentSec = 0; $g->currentSec = 0;
$g->repeatFunc = null;
self::$ghosts[$g->getId()] = $g; self::$ghosts[$g->getId()] = $g;
} }

7
timing
View file

@ -17,10 +17,9 @@ Phase 7: 3:47 -> 4:22 (35 secs, more calm period)
If killed before the end, gets reward, otherwise, nothing happends. If killed before the end, gets reward, otherwise, nothing happends.
Reward: Hat of despair: Reward: Soul Stealer:
Pumpkin: Gold hoe (weapon):
- Night vision, - Night vision,
- when sneak, diseapears (!== invisibility, he cannot be seen nor hit), - when sneak, diseapears (!== invisibility, he cannot be seen nor hit),
- if he sneaks more than 12 seconds, having nausea - if he sneaks more than 12 seconds, having nausea (high so that the screen shakes)
- If he strikes someone while being invisible, he'll loose invisility
- if he strikes someone otherwise, the person will get a big creepy sound - if he strikes someone otherwise, the person will get a big creepy sound