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

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

View File

@ -1,6 +1,11 @@
# Spooky
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
Track's link: https://soundcloud.com/djniviro/thereturn

View File

@ -5,7 +5,10 @@ use pocketmine\command\Command;
use pocketmine\plugin\PluginBase;
use pocketmine\Server;
use pocketmine\Player;
use pocketmine\event\Listener;
use pocketmine\item\enchantment\Enchantment;
use pocketmine\event\block\BlockPlaceEvent;
use pocketmine\block\Block;
use pocketmine\nbt\tag\ListTag;
use pocketmine\nbt\tag\CompoundTag;
@ -18,7 +21,7 @@ use Ad5001\Spooky\entity\Ghost;
use Ad5001\Spooky\tasks\TickTask;
class Main extends PluginBase{
class Main extends PluginBase implements Listener{
public $ghosts = [];
@ -29,8 +32,9 @@ class Main extends PluginBase{
*/
public function onEnable(){
// Registering some enchants
Enchantement::registerEnchantment(new Enchantement(Enchantement::SHARPNESS, "%enchantment.attack.sharpness", Enchantement::RARITY_COMMON, Enchantement::SLOT_SWORD));
// $this->getServer()->getScheduler()->scheduler<Delayed or Repeating>Task(new Task1($this), <TIME>);
Enchantment::registerEnchantment(new Enchantment(Enchantment::SHARPNESS, "%enchantment.attack.sharpness", Enchantment::ACTIVATION_HELD, Enchantment::RARITY_COMMON, Enchantment::SLOT_SWORD));
$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){
// Getting the skin
$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\DoubleTag;
use pocketmine\nbt\tag\ByteTag;
use pocketmine\nbt\tag\StringTag;
use pocketmine\entity\Effect;
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));
parent::__construct($level, $nbt);
$it = Item::get(Item::GOLDEN_HOE, 0);
$it->addEnchantement(Enchantement::getEnchantement(Enchantement::SHARPNESS));
$it->addEnchantment(Enchantment::getEnchantment(Enchantment::SHARPNESS));
$this->getInventory()->setItemInHand($it);
}
@ -97,6 +98,7 @@ class Ghost extends Human {
public function intenseFight(){
if(!$this->checkIfConnected()) return;
// TODO: Custom intense fight
$this->fightType = 1;
}
/**
@ -118,7 +120,7 @@ class Ghost extends Human {
public function blackOutEnterPhase(){
if(!$this->checkIfConnected()) return;
$this->fightType = 0;
$spawnBlock = $this->getPlayer()->getLineOfSight(2, 3, []);
$spawnBlock = $this->getPlayer()->getLineOfSight(2);
$spawnBlock = $spawnBlock[count($spawnBlock) -1];
$this->getPlayer()->addEffect(
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%
*
* @param EntityDamageEvent $source
* @param EntityDamageEvent $event
*/
public function attack(EntityDamageEvent $source) {
public function attack(EntityDamageEvent $event) {
if($event instanceof EntityDamageByEntityEvent) {
if($event->getDamager() instanceof Player && $event->getDamager()){
$source->setDamage($source->getDamage() * 0.75);
$event->setDamage($event->getDamage() * 0.75);
} else {
$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
*/
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());
$distDiff = $diffV3->asVector3()->abs();
$distDiff = $distDiff->x + $distDiff->z;
// Check if we can attack the player
if($this->distanceSquared($this->associatedPlayer) <= 1){
$this->attackEntity($this->associatedPlayer);
}
// If not, try moving torowards him
if ($diff > 0) {
$this->motionX = $this->getSpeed() * 0.15 * ($x / $diff);
$this->motionZ = $this->getSpeed() * 0.15 * ($z / $diff);
$this->yaw = rad2deg(-atan2($x / $diff, $z / $diff));
$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){
$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
*/
public function attackEntity(Entity $et){
$ev = new EntityDamageByEntityEvent($this, $this->associatedPlayer, EntityDamageEvent::CAUSE_ENTITY_ATTACK
/* Todo Calcule armor */);
$et->attack($ev);
if($et instanceof Player){
$damage = [
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
*/
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) {
foreach(self::$ghosts as $i => $g){
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){
$g->currentSec = 0;
$g->repeatFunc = null;
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.
Reward: Hat of despair:
Pumpkin:
Reward: Soul Stealer:
Gold hoe (weapon):
- Night vision,
- when sneak, diseapears (!== invisibility, he cannot be seen nor hit),
- if he sneaks more than 12 seconds, having nausea
- If he strikes someone while being invisible, he'll loose invisility
- if he sneaks more than 12 seconds, having nausea (high so that the screen shakes)
- if he strikes someone otherwise, the person will get a big creepy sound